Annotation of GNUtools/emacs/src/unexconvex.c, revision 1.1

1.1     ! root        1: /* Modified version of unexec for convex machines.
        !             2:    Copyright (C) 1985, 1986, 1988 Free Software Foundation, Inc.
        !             3: 
        !             4:    Note that the GNU project considers support for the peculiarities
        !             5:    of the Convex operating system a peripheral activity which should
        !             6:    not be allowed to divert effort from development of the GNU system.
        !             7:    Changes in this code will be installed when Convex system
        !             8:    maintainers send them in, but aside from that we don't plan to
        !             9:    think about it, or about whether other Emacs maintenance might
        !            10:    break it.
        !            11: 
        !            12:     This program is free software; you can redistribute it and/or modify
        !            13:     it under the terms of the GNU General Public License as published by
        !            14:     the Free Software Foundation; either version 1, or (at your option)
        !            15:     any later version.
        !            16: 
        !            17:     This program is distributed in the hope that it will be useful,
        !            18:     but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            19:     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            20:     GNU General Public License for more details.
        !            21: 
        !            22:     You should have received a copy of the GNU General Public License
        !            23:     along with this program; if not, write to the Free Software
        !            24:     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
        !            25: 
        !            26: In other words, you are welcome to use, share and improve this program.
        !            27: You are forbidden to forbid anyone else to use, share and improve
        !            28: what you give them.   Help stamp out software-hoarding!  */
        !            29: 
        !            30: 
        !            31: /* modifyed for C-1 arch by jthomp@convex 871103 */
        !            32: /* Corrected to support convex SOFF object file formats and thread specific
        !            33:  * regions.  streepy@convex 890302
        !            34: */
        !            35: 
        !            36: /*
        !            37:  * unexec.c - Convert a running program into an a.out file.
        !            38:  *
        !            39:  * Author:     Spencer W. Thomas
        !            40:  *             Computer Science Dept.
        !            41:  *             University of Utah
        !            42:  * Date:       Tue Mar  2 1982
        !            43:  * Modified heavily since then.
        !            44:  *
        !            45:  * Synopsis:
        !            46:  *     unexec (new_name, a_name, data_start, bss_start, entry_address)
        !            47:  *     char *new_name, *a_name;
        !            48:  *     unsigned data_start, bss_start, entry_address;
        !            49:  *
        !            50:  * Takes a snapshot of the program and makes an a.out format file in the
        !            51:  * file named by the string argument new_name.
        !            52:  * If a_name is non-NULL, the symbol table will be taken from the given file.
        !            53:  * On some machines, an existing a_name file is required.
        !            54:  *
        !            55:  * The boundaries within the a.out file may be adjusted with the data_start
        !            56:  * and bss_start arguments.  Either or both may be given as 0 for defaults.
        !            57:  *
        !            58:  * Data_start gives the boundary between the text segment and the data
        !            59:  * segment of the program.  The text segment can contain shared, read-only
        !            60:  * program code and literal data, while the data segment is always unshared
        !            61:  * and unprotected.  Data_start gives the lowest unprotected address.
        !            62:  * The value you specify may be rounded down to a suitable boundary
        !            63:  * as required by the machine you are using.
        !            64:  *
        !            65:  * Specifying zero for data_start means the boundary between text and data
        !            66:  * should not be the same as when the program was loaded.
        !            67:  * If NO_REMAP is defined, the argument data_start is ignored and the
        !            68:  * segment boundaries are never changed.
        !            69:  *
        !            70:  * Bss_start indicates how much of the data segment is to be saved in the
        !            71:  * a.out file and restored when the program is executed.  It gives the lowest
        !            72:  * unsaved address, and is rounded up to a page boundary.  The default when 0
        !            73:  * is given assumes that the entire data segment is to be stored, including
        !            74:  * the previous data and bss as well as any additional storage allocated with
        !            75:  * break (2).
        !            76:  *
        !            77:  * The new file is set up to start at entry_address.
        !            78:  *
        !            79:  * If you make improvements I'd like to get them too.
        !            80:  * harpo!utah-cs!thomas, thomas@Utah-20
        !            81:  *
        !            82:  */
        !            83: 
        !            84: /* There are several compilation parameters affecting unexec:
        !            85: 
        !            86: * COFF
        !            87: 
        !            88: Define this if your system uses COFF for executables.
        !            89: Otherwise we assume you use Berkeley format.
        !            90: 
        !            91: * NO_REMAP
        !            92: 
        !            93: Define this if you do not want to try to save Emacs's pure data areas
        !            94: as part of the text segment.
        !            95: 
        !            96: Saving them as text is good because it allows users to share more.
        !            97: 
        !            98: However, on machines that locate the text area far from the data area,
        !            99: the boundary cannot feasibly be moved.  Such machines require
        !           100: NO_REMAP.
        !           101: 
        !           102: Also, remapping can cause trouble with the built-in startup routine
        !           103: /lib/crt0.o, which defines `environ' as an initialized variable.
        !           104: Dumping `environ' as pure does not work!  So, to use remapping,
        !           105: you must write a startup routine for your machine in Emacs's crt0.c.
        !           106: If NO_REMAP is defined, Emacs uses the system's crt0.o.
        !           107: 
        !           108: * SECTION_ALIGNMENT
        !           109: 
        !           110: Some machines that use COFF executables require that each section
        !           111: start on a certain boundary *in the COFF file*.  Such machines should
        !           112: define SECTION_ALIGNMENT to a mask of the low-order bits that must be
        !           113: zero on such a boundary.  This mask is used to control padding between
        !           114: segments in the COFF file.
        !           115: 
        !           116: If SECTION_ALIGNMENT is not defined, the segments are written
        !           117: consecutively with no attempt at alignment.  This is right for
        !           118: unmodified system V.
        !           119: 
        !           120: * SEGMENT_MASK
        !           121: 
        !           122: Some machines require that the beginnings and ends of segments
        !           123: *in core* be on certain boundaries.  For most machines, a page
        !           124: boundary is sufficient.  That is the default.  When a larger
        !           125: boundary is needed, define SEGMENT_MASK to a mask of
        !           126: the bits that must be zero on such a boundary.
        !           127: 
        !           128: * A_TEXT_OFFSET(HDR)
        !           129: 
        !           130: Some machines count the a.out header as part of the size of the text
        !           131: segment (a_text); they may actually load the header into core as the
        !           132: first data in the text segment.  Some have additional padding between
        !           133: the header and the real text of the program that is counted in a_text.
        !           134: 
        !           135: For these machines, define A_TEXT_OFFSET(HDR) to examine the header
        !           136: structure HDR and return the number of bytes to add to `a_text'
        !           137: before writing it (above and beyond the number of bytes of actual
        !           138: program text).  HDR's standard fields are already correct, except that
        !           139: this adjustment to the `a_text' field has not yet been made;
        !           140: thus, the amount of offset can depend on the data in the file.
        !           141:   
        !           142: * A_TEXT_SEEK(HDR)
        !           143: 
        !           144: If defined, this macro specifies the number of bytes to seek into the
        !           145: a.out file before starting to write the text segment.a
        !           146: 
        !           147: * EXEC_MAGIC
        !           148: 
        !           149: For machines using COFF, this macro, if defined, is a value stored
        !           150: into the magic number field of the output file.
        !           151: 
        !           152: * ADJUST_EXEC_HEADER
        !           153: 
        !           154: This macro can be used to generate statements to adjust or
        !           155: initialize nonstandard fields in the file header
        !           156: 
        !           157: * ADDR_CORRECT(ADDR)
        !           158: 
        !           159: Macro to correct an int which is the bit pattern of a pointer to a byte
        !           160: into an int which is the number of a byte.
        !           161: 
        !           162: This macro has a default definition which is usually right.
        !           163: This default definition is a no-op on most machines (where a
        !           164: pointer looks like an int) but not on all machines.
        !           165: 
        !           166: */
        !           167: 
        !           168: #include "config.h"
        !           169: #define PERROR(file) report_error (file, new)
        !           170: 
        !           171: #include <a.out.h>
        !           172: /* Define getpagesize () if the system does not.
        !           173:    Note that this may depend on symbols defined in a.out.h
        !           174:  */
        !           175: #include "getpagesize.h"
        !           176: 
        !           177: #include <sys/types.h>
        !           178: #include <stdio.h>
        !           179: #include <sys/stat.h>
        !           180: #include <errno.h>
        !           181: 
        !           182: extern char *start_of_text ();         /* Start of text */
        !           183: extern char *start_of_data ();         /* Start of initialized data */
        !           184: 
        !           185: #include <machine/filehdr.h>
        !           186: #include <machine/opthdr.h>
        !           187: #include <machine/scnhdr.h>
        !           188: #include <machine/pte.h>
        !           189: 
        !           190: static long block_copy_start;  /* Old executable start point */
        !           191: static struct filehdr f_hdr;   /* File header */
        !           192: static struct opthdr f_ohdr;   /* Optional file header (a.out) */
        !           193: long bias;                     /* Bias to add for growth */
        !           194: #define SYMS_START block_copy_start
        !           195: 
        !           196: static long text_scnptr;
        !           197: static long data_scnptr;
        !           198: 
        !           199: static int pagemask;
        !           200: static int pagesz;
        !           201: 
        !           202: static
        !           203: report_error (file, fd)
        !           204:      char *file;
        !           205:      int fd;
        !           206: {
        !           207:     if (fd)
        !           208:        close (fd);
        !           209:     error ("Failure operating on %s", file);
        !           210: }
        !           211: 
        !           212: #define ERROR0(msg) report_error_1 (new, msg, 0, 0); return -1
        !           213: #define ERROR1(msg,x) report_error_1 (new, msg, x, 0); return -1
        !           214: #define ERROR2(msg,x,y) report_error_1 (new, msg, x, y); return -1
        !           215: 
        !           216: static
        !           217: report_error_1 (fd, msg, a1, a2)
        !           218: int fd;
        !           219: char *msg;
        !           220: int a1, a2;
        !           221: {
        !           222:     close (fd);
        !           223:     error (msg, a1, a2);
        !           224: }
        !           225: 
        !           226: /* ****************************************************************
        !           227:  * unexec
        !           228:  *
        !           229:  * driving logic.
        !           230:  */
        !           231: unexec (new_name, a_name, data_start, bss_start, entry_address)
        !           232: char *new_name, *a_name;
        !           233: unsigned data_start, bss_start, entry_address;
        !           234: {
        !           235:     int new, a_out = -1;
        !           236: 
        !           237:     if (a_name && (a_out = open (a_name, 0)) < 0) {
        !           238:        PERROR (a_name);
        !           239:     }
        !           240:     if ((new = creat (new_name, 0666)) < 0) {
        !           241:        PERROR (new_name);
        !           242:     }
        !           243: 
        !           244:     if (make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) < 0
        !           245:       || copy_text_and_data (new) < 0
        !           246:       || copy_sym (new, a_out, a_name, new_name) < 0 ) {
        !           247:        close (new);
        !           248:        return -1;      
        !           249:     }
        !           250: 
        !           251:     close (new);
        !           252:     if (a_out >= 0)
        !           253:        close (a_out);
        !           254:     mark_x (new_name);
        !           255:     return 0;
        !           256: }
        !           257: 
        !           258: /* ****************************************************************
        !           259:  * make_hdr
        !           260:  *
        !           261:  * Make the header in the new a.out from the header in core.
        !           262:  * Modify the text and data sizes.
        !           263:  */
        !           264: 
        !           265:  struct scnhdr *stbl;          /* Table of all scnhdr's */
        !           266:  struct scnhdr *f_thdr;                /* Text section header */
        !           267:  struct scnhdr *f_dhdr;                /* Data section header */
        !           268:  struct scnhdr *f_tdhdr;       /* Thread Data section header */
        !           269:  struct scnhdr *f_bhdr;                /* Bss section header */
        !           270:  struct scnhdr *f_tbhdr;       /* Thread Bss section header */
        !           271: 
        !           272: static int
        !           273: make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
        !           274:      int new, a_out;
        !           275:      unsigned data_start, bss_start, entry_address;
        !           276:      char *a_name;
        !           277:      char *new_name;
        !           278: {
        !           279:     register int scns;
        !           280:     unsigned int bss_end;
        !           281:     unsigned int eo_data;      /* End of initialized data in new exec file */
        !           282:     int scntype;               /* Section type */
        !           283:     int i;                     /* Var for sorting by vaddr */
        !           284:     struct scnhdr scntemp;     /* For swapping entries in sort */
        !           285:     extern char *start_of_data();
        !           286: 
        !           287:     pagemask = (pagesz = getpagesize()) - 1;
        !           288: 
        !           289:     /* Adjust text/data boundary. */
        !           290:     if (!data_start)
        !           291:        data_start = (unsigned) start_of_data ();
        !           292: 
        !           293:     data_start = data_start & ~pagemask; /* (Down) to page boundary. */
        !           294: 
        !           295:     bss_end = (sbrk(0) + pagemask) & ~pagemask;
        !           296: 
        !           297:     /* Adjust data/bss boundary. */
        !           298:     if (bss_start != 0) {
        !           299:        bss_start = (bss_start + pagemask) & ~pagemask;/* (Up) to page bdry. */
        !           300:        if (bss_start > bss_end) {
        !           301:            ERROR1 ("unexec: Specified bss_start (%x) is past end of program",
        !           302:                    bss_start);
        !           303:        }
        !           304:     } else
        !           305:        bss_start = bss_end;
        !           306: 
        !           307:     if (data_start > bss_start)        { /* Can't have negative data size. */
        !           308:        ERROR2 ("unexec: data_start (%x) can't be greater than bss_start (%x)",
        !           309:                data_start, bss_start);
        !           310:     }
        !           311: 
        !           312:     /* Salvage as much info from the existing file as possible */
        !           313:     if (a_out < 0) {
        !           314:        ERROR0 ("can't build a COFF file from scratch yet");
        !           315:        /*NOTREACHED*/
        !           316:     }
        !           317: 
        !           318:     if (read (a_out, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr)) {
        !           319:        PERROR (a_name);
        !           320:     }
        !           321:     block_copy_start += sizeof (f_hdr);
        !           322:     if (f_hdr.h_opthdr > 0) {
        !           323:        if (read (a_out, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr)) {
        !           324:            PERROR (a_name);
        !           325:        }
        !           326:        block_copy_start += sizeof (f_ohdr);
        !           327:     }
        !           328: 
        !           329:     /* Allocate room for scn headers */
        !           330:     stbl = (struct scnhdr *)malloc( sizeof(struct scnhdr) * f_hdr.h_nscns );
        !           331:     if( stbl == NULL ) {
        !           332:        ERROR0( "unexec: malloc of stbl failed" );
        !           333:     }
        !           334: 
        !           335:     f_tdhdr = f_tbhdr = NULL;
        !           336: 
        !           337:     /* Loop through section headers, copying them in */
        !           338:     for (scns = 0; scns < f_hdr.h_nscns; scns++) {
        !           339: 
        !           340:        if( read( a_out, &stbl[scns], sizeof(*stbl)) != sizeof(*stbl)) {
        !           341:            PERROR (a_name);
        !           342:        }
        !           343: 
        !           344:        scntype = stbl[scns].s_flags & S_TYPMASK; /* What type of section */
        !           345: 
        !           346:        if( stbl[scns].s_scnptr > 0L) {
        !           347:            if( block_copy_start < stbl[scns].s_scnptr + stbl[scns].s_size )
        !           348:                block_copy_start = stbl[scns].s_scnptr + stbl[scns].s_size;
        !           349:        }
        !           350: 
        !           351:        if( scntype == S_TEXT) {
        !           352:            f_thdr = &stbl[scns];
        !           353:        } else if( scntype == S_DATA) {
        !           354:            f_dhdr = &stbl[scns];
        !           355: #ifdef S_TDATA
        !           356:        } else if( scntype == S_TDATA ) {
        !           357:            f_tdhdr = &stbl[scns];
        !           358:        } else if( scntype == S_TBSS ) {
        !           359:            f_tbhdr = &stbl[scns];
        !           360: #endif /* S_TDATA (thread stuff) */
        !           361: 
        !           362:        } else if( scntype == S_BSS) {
        !           363:            f_bhdr = &stbl[scns];
        !           364:        }
        !           365: 
        !           366:     }
        !           367: 
        !           368:     /* We will now convert TEXT and DATA into TEXT, BSS into DATA, and leave
        !           369:      * all thread stuff alone.
        !           370:      */
        !           371: 
        !           372:     /* Now we alter the contents of all the f_*hdr variables
        !           373:        to correspond to what we want to dump.  */
        !           374: 
        !           375:     f_thdr->s_vaddr = (long) start_of_text ();
        !           376:     f_thdr->s_size = data_start - f_thdr->s_vaddr;
        !           377:     f_thdr->s_scnptr = pagesz;
        !           378:     f_thdr->s_relptr = 0;
        !           379:     f_thdr->s_nrel = 0;
        !           380: 
        !           381:     eo_data = f_thdr->s_scnptr + f_thdr->s_size;
        !           382: 
        !           383:     if( f_tdhdr ) {            /* Process thread data */
        !           384: 
        !           385:        f_tdhdr->s_vaddr = data_start;
        !           386:        f_tdhdr->s_size += f_dhdr->s_size - (data_start - f_dhdr->s_vaddr);
        !           387:        f_tdhdr->s_scnptr = eo_data;
        !           388:        f_tdhdr->s_relptr = 0;
        !           389:        f_tdhdr->s_nrel = 0;
        !           390: 
        !           391:        eo_data += f_tdhdr->s_size;
        !           392: 
        !           393:        /* And now for DATA */
        !           394: 
        !           395:        f_dhdr->s_vaddr = f_bhdr->s_vaddr; /* Take BSS start address */
        !           396:        f_dhdr->s_size = bss_end - f_bhdr->s_vaddr;
        !           397:        f_dhdr->s_scnptr = eo_data;
        !           398:        f_dhdr->s_relptr = 0;
        !           399:        f_dhdr->s_nrel = 0;
        !           400: 
        !           401:        eo_data += f_dhdr->s_size;
        !           402: 
        !           403:     } else {
        !           404: 
        !           405:        f_dhdr->s_vaddr = data_start;
        !           406:        f_dhdr->s_size = bss_start - data_start;
        !           407:        f_dhdr->s_scnptr = eo_data;
        !           408:        f_dhdr->s_relptr = 0;
        !           409:        f_dhdr->s_nrel = 0;
        !           410: 
        !           411:        eo_data += f_dhdr->s_size;
        !           412: 
        !           413:     }
        !           414: 
        !           415:     f_bhdr->s_vaddr = bss_start;
        !           416:     f_bhdr->s_size = bss_end - bss_start + pagesz /* fudge */;
        !           417:     f_bhdr->s_scnptr = 0;
        !           418:     f_bhdr->s_relptr = 0;
        !           419:     f_bhdr->s_nrel = 0;
        !           420: 
        !           421:     text_scnptr = f_thdr->s_scnptr;
        !           422:     data_scnptr = f_dhdr->s_scnptr;
        !           423:     bias = eo_data - block_copy_start;
        !           424: 
        !           425:     if (f_ohdr.o_symptr > 0L) {
        !           426:        f_ohdr.o_symptr += bias;
        !           427:     }
        !           428: 
        !           429:     if (f_hdr.h_strptr > 0) {
        !           430:        f_hdr.h_strptr += bias;
        !           431:     }
        !           432: 
        !           433:     if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr)) {
        !           434:        PERROR (new_name);
        !           435:     }
        !           436: 
        !           437:     if (write (new, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr)) {
        !           438:        PERROR (new_name);
        !           439:     }
        !           440: 
        !           441:     for( scns = 0; scns < f_hdr.h_nscns; scns++ ) {
        !           442: 
        !           443:        /* This is a cheesey little loop to write out the section headers
        !           444:         * in order of increasing virtual address. Dull but effective.
        !           445:         */
        !           446: 
        !           447:        for( i = scns+1; i < f_hdr.h_nscns; i++ ) {
        !           448:            if( stbl[i].s_vaddr < stbl[scns].s_vaddr ) { /* Swap */
        !           449:                scntemp = stbl[i];
        !           450:                stbl[i] = stbl[scns];
        !           451:                stbl[scns] = scntemp;
        !           452:            }
        !           453:        }
        !           454: 
        !           455:     }
        !           456: 
        !           457:     for( scns = 0; scns < f_hdr.h_nscns; scns++ ) {
        !           458: 
        !           459:        if( write( new, &stbl[scns], sizeof(*stbl)) != sizeof(*stbl)) {
        !           460:            PERROR (new_name);
        !           461:        }
        !           462: 
        !           463:     }
        !           464: 
        !           465:     return (0);
        !           466: 
        !           467: }
        !           468: 
        !           469: /* ****************************************************************
        !           470:  * copy_text_and_data
        !           471:  *
        !           472:  * Copy the text and data segments from memory to the new a.out
        !           473:  */
        !           474: static int
        !           475: copy_text_and_data (new)
        !           476: int new;
        !           477: {
        !           478:     register int scns;
        !           479: 
        !           480:     for( scns = 0; scns < f_hdr.h_nscns; scns++ )
        !           481:        write_segment( new, &stbl[scns] );
        !           482: 
        !           483:     return 0;
        !           484: }
        !           485: 
        !           486: write_segment( new, sptr )
        !           487: int new;
        !           488: struct scnhdr *sptr;
        !           489: {
        !           490:     register char *ptr, *end;
        !           491:     register int nwrite, ret;
        !           492:     char buf[80];
        !           493:     extern int errno;
        !           494:     char zeros[128];
        !           495: 
        !           496:     if( sptr->s_scnptr == 0 )
        !           497:        return;                 /* Nothing to do */
        !           498: 
        !           499:     if( lseek( new, (long) sptr->s_scnptr, 0 ) == -1 )
        !           500:        PERROR( "unexecing" );
        !           501: 
        !           502:     bzero (zeros, sizeof zeros);
        !           503: 
        !           504:     ptr = (char *) sptr->s_vaddr;
        !           505:     end = ptr + sptr->s_size;
        !           506: 
        !           507:     while( ptr < end ) {
        !           508: 
        !           509:        /* distance to next multiple of 128.  */
        !           510:        nwrite = (((int) ptr + 128) & -128) - (int) ptr;
        !           511:        /* But not beyond specified end.  */
        !           512:        if (nwrite > end - ptr) nwrite = end - ptr;
        !           513:        ret = write (new, ptr, nwrite);
        !           514:        /* If write gets a page fault, it means we reached
        !           515:           a gap between the old text segment and the old data segment.
        !           516:           This gap has probably been remapped into part of the text segment.
        !           517:           So write zeros for it.  */
        !           518:        if (ret == -1 && errno == EFAULT)
        !           519:            write (new, zeros, nwrite);
        !           520:        else if (nwrite != ret) {
        !           521:            sprintf (buf,
        !           522:                     "unexec write failure: addr 0x%x, fileno %d, size 0x%x, wrote 0x%x, errno %d",
        !           523:                     ptr, new, nwrite, ret, errno);
        !           524:            PERROR (buf);
        !           525:        }
        !           526:        ptr += nwrite;
        !           527:     }
        !           528: }
        !           529: 
        !           530: /* ****************************************************************
        !           531:  * copy_sym
        !           532:  *
        !           533:  * Copy the relocation information and symbol table from the a.out to the new
        !           534:  */
        !           535: static int
        !           536: copy_sym (new, a_out, a_name, new_name)
        !           537:      int new, a_out;
        !           538:      char *a_name, *new_name;
        !           539: {
        !           540:     char page[1024];
        !           541:     int n;
        !           542: 
        !           543:     if (a_out < 0)
        !           544:        return 0;
        !           545: 
        !           546:     if (SYMS_START == 0L)
        !           547:        return 0;
        !           548: 
        !           549:     lseek (a_out, SYMS_START, 0);      /* Position a.out to symtab. */
        !           550:     lseek( new, (long)f_ohdr.o_symptr, 0 );
        !           551: 
        !           552:     while ((n = read (a_out, page, sizeof page)) > 0) {
        !           553:        if (write (new, page, n) != n) {
        !           554:            PERROR (new_name);
        !           555:        }
        !           556:     }
        !           557:     if (n < 0) {
        !           558:        PERROR (a_name);
        !           559:     }
        !           560:     return 0;
        !           561: }
        !           562: 
        !           563: /* ****************************************************************
        !           564:  * mark_x
        !           565:  *
        !           566:  * After succesfully building the new a.out, mark it executable
        !           567:  */
        !           568: static
        !           569: mark_x (name)
        !           570: char *name;
        !           571: {
        !           572:     struct stat sbuf;
        !           573:     int um;
        !           574:     int new = 0;  /* for PERROR */
        !           575: 
        !           576:     um = umask (777);
        !           577:     umask (um);
        !           578:     if (stat (name, &sbuf) == -1) {
        !           579:        PERROR (name);
        !           580:     }
        !           581:     sbuf.st_mode |= 0111 & ~um;
        !           582:     if (chmod (name, sbuf.st_mode) == -1)
        !           583:        PERROR (name);
        !           584: }
        !           585: 
        !           586: /* Find the first pty letter.  This is usually 'p', as in ptyp0, but
        !           587:    is sometimes configured down to 'm', 'n', or 'o' for some reason. */
        !           588: 
        !           589: first_pty_letter ()
        !           590: {
        !           591:   struct stat buf;
        !           592:   char pty_name[16];
        !           593:   char c;
        !           594: 
        !           595:   for (c = 'o'; c >= 'a'; c--)
        !           596:     {
        !           597:       sprintf (pty_name, "/dev/pty%c0", c);
        !           598:       if (stat (pty_name, &buf) < 0)
        !           599:        return c + 1;
        !           600:     }
        !           601:   return 'a';
        !           602: }
        !           603: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.