XEmacs 21.2.38 (Peisino)
[chise/xemacs-chise.git.1] / src / unexelfsgi.c
1 /* Copyright (C) 1985, 1986, 1987, 1988, 1990, 1992, 1999, 2000
2    Free Software Foundation, Inc.
3
4    This file is part of XEmacs.
5
6    XEmacs is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2, or (at your option)
9    any later version.
10
11    GNU Emacs is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with GNU Emacs; see the file COPYING.  If not, write to the
18    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.
20
21    In other words, you are welcome to use, share and improve this
22    program.  You are forbidden to forbid anyone else to use, share and
23    improve what you give them.  Help stamp out software-hoarding!  */
24
25
26 /*
27  * unexec.c - Convert a running program into an a.out file.
28  *
29  * Author:      Spencer W. Thomas
30  *              Computer Science Dept.
31  *              University of Utah
32  * Date:        Tue Mar  2 1982
33  * Modified heavily since then.
34  *
35  * Synopsis:
36  * void
37  * unexec (char *new_name,
38  *         char *old_name,
39  *         uintptr_t data_start,
40  *         uintptr_t bss_start,
41  *         uintptr_t entry_address)
42  *
43  * The basic idea is that we start with an ELF file which contains
44  * .bss (uninitialized global data) section which is normally not in
45  * the file. As we load lisp the variables, which were first set to 0,
46  * will change their values. We want to save those changed values into
47  * another ELF file, which will become a new xemacs image. To do this,
48  * we need to change several structures in the ELF file.
49  *
50  *   First of all, we need to change the programm header which tells
51  *   the linker how to load stuff into memory so that data will come
52  *   from the file and not from the /dev/zero. To do this, we find the
53  *   segment, which is marked as loadable (type PT_LOAD) and which
54  *   covers the old .bss section. We will next change the filesz and
55  *   memsz for that segment to extend over the new data section.
56  *
57  *   Next we have to make sure that section header for the stuff which
58  *   used to be uninitialized is changed to be initialized and to come
59  *   from the file. To do this, we change the size and the type of the old
60  *   .bss section (and all other section of the type SHT_NOBITS) to cover the
61  *   new section and to be of type SHT_PROCBITS.
62  *
63  *   We also insert a new SHT_NOBITS section to keep some tools, which expect
64  *   .bss happy.
65  *
66  *   Finally we need to patch up some references to the section
67  *   indexes since we change the order and undo the relocation info to
68  *   be the same as it was "before" because we actually used the data
69  *   from the memory which were changed by the run-time linker.
70  */
71 \f
72 #ifndef emacs
73 #define fatal(a, b, c) fprintf (stderr, a, b, c), exit (1)
74 #include <string.h>
75 #else
76 #include <config.h>
77 extern void fatal (const char *, ...);
78 #endif
79
80 #include <sys/types.h>
81 #include <stdio.h>
82 #include <sys/stat.h>
83 #include <memory.h>
84 #include <errno.h>
85 #include <unistd.h>
86 #include <fcntl.h>
87 #ifdef HAVE_ELF_H
88 #include <elf.h>
89 #endif
90 #include <sys/mman.h>
91 #if defined (__sony_news) && defined (_SYSTYPE_SYSV)
92 #include <sys/elf_mips.h>
93 #include <sym.h>
94 #endif /* __sony_news && _SYSTYPE_SYSV */
95 #if __sgi
96 #include <syms.h> /* for HDRR declaration */
97 #endif /* __sgi */
98
99 #if __GNU_LIBRARY__ - 0 >= 6
100 # include <link.h>      /* get ElfW etc */
101 #endif
102
103 #ifndef ElfW
104 # ifdef __STDC__
105 #  define ElfBitsW(bits, type) Elf##bits##_##type
106 # else
107 #  define ElfBitsW(bits, type) Elf/**/bits/**/_/**/type
108 # endif
109 # ifdef _LP64
110 #  define ELFSIZE 64
111 # else
112 #  define ELFSIZE 32
113 # endif
114   /* This macro expands `bits' before invoking ElfBitsW.  */
115 # define ElfExpandBitsW(bits, type) ElfBitsW (bits, type)
116 # define ElfW(type) ElfExpandBitsW (ELFSIZE, type)
117 #endif
118
119 #ifndef ELF_BSS_SECTION_NAME
120 #define ELF_BSS_SECTION_NAME ".bss"
121 #endif
122
123 /* Get the address of a particular section or program header entry,
124  * accounting for the size of the entries. */
125
126 #define OLD_SECTION_H(n) \
127      (*(ElfW(Shdr) *) ((byte *) old_section_h + old_file_h->e_shentsize * (n)))
128 #define NEW_SECTION_H(n) \
129      (*(ElfW(Shdr) *) ((byte *) new_section_h + new_file_h->e_shentsize * (n)))
130 #define OLD_PROGRAM_H(n) \
131      (*(ElfW(Phdr) *) ((byte *) old_program_h + old_file_h->e_phentsize * (n)))
132 #define NEW_PROGRAM_H(n) \
133      (*(ElfW(Phdr) *) ((byte *) new_program_h + new_file_h->e_phentsize * (n)))
134
135 #define PATCH_INDEX(n) \
136   do { \
137          if ((int) (n) >= growme_index) \
138            (n)++; } while (0)
139
140 typedef unsigned char byte;
141
142 /* Round X up to a multiple of Y.  */
143
144 static ElfW(Addr)
145 round_up (ElfW(Addr) x, ElfW(Addr) y)
146 {
147   int rem = x % y;
148   if (rem == 0)
149     return x;
150   return x - rem + y;
151 }
152
153 /* Return the index of the section named NAME.
154    SECTION_NAMES, FILE_NAME and FILE_H give information
155    about the file we are looking in.
156
157    If we don't find the section NAME, that is a fatal error
158    if NOERROR is 0; we return -1 if NOERROR is nonzero.  */
159
160 static int
161 find_section (char *name,
162               const char *section_names,
163               char *file_name,
164               ElfW(Ehdr) *old_file_h,
165               ElfW(Shdr) *old_section_h,
166               int noerror)
167 {
168   int idx;
169
170   for (idx = 1; idx < old_file_h->e_shnum; idx++)
171     {
172 #ifdef DEBUG
173       fprintf (stderr, "Looking for %s - found %s\n", name,
174                section_names + OLD_SECTION_H (idx).sh_name);
175 #endif
176       if (!strcmp (section_names + OLD_SECTION_H (idx).sh_name,
177                    name))
178           return idx;
179     }
180
181   /* If we're here, we found nothing or return did not work */
182   if ( ! noerror)
183       fatal ("Can't find %s in %s.\n", name, file_name);
184
185   return -1;
186 }
187
188 /* ****************************************************************
189  * unexec
190  *
191  * driving logic.
192  *
193  * In ELF, this works by replacing the old .bss section with a new
194  * .data section, and inserting an empty .bss immediately afterwards.
195  *
196  */
197 void
198 unexec (char *new_name,
199         char *old_name,
200         uintptr_t data_start,
201         uintptr_t bss_start,
202         uintptr_t entry_address)
203 {
204   int old_file;
205
206   struct stat stat_buf;
207   caddr_t old_base, new_base;
208
209   ElfW(Ehdr) *old_file_h, * new_file_h;
210   ElfW(Phdr) *old_program_h, * new_program_h;
211   ElfW(Shdr) *old_section_h, * new_section_h;
212   ElfW(Shdr) * growme = NULL, * grown = NULL;
213   ElfW(Addr) old_bss_addr = 0,  new_data2_addr = 0;
214
215   int growme_index = -1;
216   int n, nn;
217   const char *old_section_names;
218   int old_mdebug_index, old_data_index;
219   int new_bss_addr, new_data2_size, new_data2_offset, new_file, new_file_size;
220
221   /* Open the old file */
222   if ( (old_file = open (old_name, O_RDONLY)) < 0 )
223       fatal ("Can't open %s for reading: errno %d\n", old_name, errno);
224
225   if (fstat (old_file, &stat_buf) == -1)
226       fatal ("Can't fstat (%s): errno %d\n", old_name, errno);
227
228   /* map old file into the address space. */
229   if ( (old_base = (caddr_t) mmap ((caddr_t) 0, stat_buf.st_size,
230                                    PROT_READ, MAP_SHARED, old_file, 0)) < 0 )
231       fatal ("Can't mmap (%s): errno %d\n", old_name, errno);
232
233   old_file_h    = (ElfW(Ehdr) *) old_base;
234   old_program_h = (ElfW(Phdr) *) ((byte *) old_base + old_file_h->e_phoff);
235   old_section_h = (ElfW(Shdr) *) ((byte *) old_base + old_file_h->e_shoff);
236   old_section_names = (const char *) old_base
237       + OLD_SECTION_H (old_file_h->e_shstrndx).sh_offset;
238
239   /* Find a section which we will grow by looking for the SHT_NOBITS
240    * section with ALLOCATE flag and with the biggest address. */
241   for (n = 1; n < old_file_h->e_shnum; n++) {
242       ElfW(Shdr) * sh = & OLD_SECTION_H(n);
243
244       if ((sh->sh_type == SHT_NOBITS) && (sh->sh_flags & SHF_ALLOC)) {
245           if ( old_bss_addr < sh->sh_addr ) {
246               growme = sh;
247               growme_index = n;
248               new_data2_addr = old_bss_addr =  sh->sh_addr;
249           }
250       }
251   }
252
253   if (growme == NULL )
254       fatal ("Can't find a section to grow\n", 0, 0);
255
256   old_data_index = find_section (".data", old_section_names,
257                                  old_name, old_file_h, old_section_h, 0);
258
259   new_bss_addr = (ElfW(Addr)) sbrk (0);
260   new_data2_size = new_bss_addr - old_bss_addr;
261   new_data2_offset  = OLD_SECTION_H (old_data_index).sh_offset +
262       (new_data2_addr - OLD_SECTION_H (old_data_index).sh_addr);
263
264   if ( new_bss_addr < old_bss_addr + growme->sh_size )
265       fatal (".bss shrank when undumping???\n", 0, 0);
266
267   /* Set the output file to the right size and mmap it. */
268   if ( (new_file = open (new_name, O_RDWR | O_CREAT, 0666)) < 0 )
269       fatal ("Can't create (%s): errno %d\n", new_name, errno);
270
271   new_file_size = stat_buf.st_size +  old_file_h->e_shentsize + new_data2_size;
272
273   if (ftruncate (new_file, new_file_size))
274       fatal ("Can't ftruncate (%s): errno %d\n", new_name, errno);
275
276   new_base = (caddr_t) mmap ((caddr_t) 0, new_file_size,
277                              PROT_READ | PROT_WRITE,
278 #ifdef UNEXEC_USE_MAP_PRIVATE
279                              MAP_PRIVATE,
280 #else
281                              MAP_SHARED,
282 #endif
283                              new_file, 0);
284
285   if (new_base == (caddr_t) -1)
286       fatal ("Can't mmap (%s): errno %d\n", new_name, errno);
287
288   new_file_h = (ElfW(Ehdr) *) new_base;
289   new_program_h = (ElfW(Phdr) *) ((byte *) new_base + old_file_h->e_phoff);
290   new_section_h = (ElfW(Shdr) *) ((byte *) new_base + old_file_h->e_shoff +
291                                   new_data2_size);
292
293   /* Make our new file, program and section headers as copies of the
294    * originals.  */
295   memcpy (new_file_h, old_file_h, old_file_h->e_ehsize);
296   memcpy (new_program_h, old_program_h,
297           old_file_h->e_phnum * old_file_h->e_phentsize);
298
299   /* Modify the e_shstrndx if necessary. */
300   PATCH_INDEX (new_file_h->e_shstrndx);
301
302   /* Fix up file header.  We'll add one section.  Section header is
303    * further away now.  */
304   new_file_h->e_shoff += new_data2_size;
305   new_file_h->e_shnum += 1;
306
307   /* Fix up a new program header by extending the writable data
308    * segment so that the bss area is covered too. Find that segment by
309    * looking for one that starts before and ends after the .bss and is
310    * PT_LOADable. */
311   for (n = new_file_h->e_phnum - 1; n >= 0; n--) {
312       ElfW(Phdr) * ph = & NEW_PROGRAM_H(n);
313 #ifdef DEBUG
314       printf ("%d @ %0x + %0x against %0x + %0x",
315               n, ph->p_vaddr, ph->p_memsz,growme->sh_addr, growme->sh_size);
316 #endif
317       if ((ph->p_type == PT_LOAD) &&
318           (ph->p_vaddr <= growme->sh_addr) &&
319           ((ph->p_vaddr+ph->p_memsz) >= (growme->sh_addr + growme->sh_size))) {
320           /* Make sure that the size includes any padding before the
321            * old .bss section.  */
322           ph->p_memsz = ph->p_filesz = new_bss_addr - ph->p_vaddr;
323 #ifdef DEBUG
324           puts (" That's the one!");
325 #endif
326           break;
327       }
328 #ifdef DEBUG
329       putchar ('\n');
330 #endif
331   }
332
333   if (n < 0)
334       fatal ("Couldn't find segment which covers %s",
335              old_section_names + growme->sh_name);
336
337   /* Walk through all section headers, insert the new data2 section
338    * right before the new bss section. */
339   for (n = 1, nn = 1; n < (int) old_file_h->e_shnum;  n++, nn++) {
340       ElfW(Shdr) * nsec = & NEW_SECTION_H(nn);
341       ElfW(Shdr) * osec = & OLD_SECTION_H(n);
342
343       /* If this is the section we want to grow, insert the new data
344        * section before it. */
345       if ( osec == growme ) {
346           /* Steal the data section header for this data2 section but
347            * use the * 'grow' section's alignment. This * will assure
348            * that the new section * always be placed in the same spot
349            * * as the old section by any other * application. */
350           ElfW(Shdr) * od = &OLD_SECTION_H(old_data_index);
351
352           memcpy (nsec, od, new_file_h->e_shentsize);
353
354           nsec->sh_addr = new_data2_addr;
355           nsec->sh_offset =  new_data2_offset;
356           nsec->sh_size = new_data2_size;
357           nsec->sh_addralign = osec->sh_addralign;
358
359           /* Copy over what we have in memory now. */
360           memcpy (nsec->sh_offset + new_base, (caddr_t) osec->sh_addr,
361                   new_data2_size);
362           nn++;
363           grown = nsec++;
364       }
365
366       memcpy (nsec, osec, old_file_h->e_shentsize);
367
368       if ( osec == growme ) {
369           /* The new bss section's size is zero, and its file offset
370            * and virtual address should be off by NEW_DATA2_SIZE.  */
371           nsec->sh_offset = grown->sh_offset + new_data2_size;
372           nsec->sh_addr = grown->sh_addr + new_data2_size;
373
374           /* Let the new bss section address alignment be the same as
375            * the section address alignment followed the old bss
376            * section, so this section will be placed in exactly the
377            * same place. */
378           nsec->sh_addralign = osec->sh_addralign;
379           nsec->sh_size = 0;
380       } else {
381           /* Any section that was originally placed AFTER the bss
382            * section should now be off by NEW_DATA2_SIZE. */
383           if ( round_up (nsec->sh_offset, growme->sh_addralign) >=
384                new_data2_offset)
385               nsec->sh_offset += new_data2_size;
386       }
387
388       /* Any section that was originally placed after the section *
389        * header table should now be off by the size of one section
390        * header table entry.  */
391       if (nsec->sh_offset > new_file_h->e_shoff)
392           nsec->sh_offset += new_file_h->e_shentsize;
393
394
395       /* If any section hdr refers to the section after the new .data
396        * section, make it refer to next one because we have inserted a
397        * new section in between.  */
398       PATCH_INDEX (nsec->sh_link);
399
400       /* For symbol tables, info is a symbol table index, so don't
401        * change it.  */
402       if (nsec->sh_type != SHT_SYMTAB && nsec->sh_type != SHT_DYNSYM)
403           PATCH_INDEX (nsec->sh_info);
404
405       /* Any section which used to be NOBITS will now becomes PROGBITS
406        * if it's ALLOC-atable, unless, of cause, it's not the one we
407        * decided to grow */
408       if ( (osec->sh_type == SHT_NOBITS) && (osec->sh_flags & SHF_ALLOC) &&
409            (osec != growme ) ) {
410           nsec->sh_type = SHT_PROGBITS;
411       }
412
413       /* Now, start to copy the content of sections */
414       if ( nsec->sh_type != SHT_NULL || nsec->sh_type != SHT_NOBITS ) {
415
416           /* Write out the sections. .data and .data1 (and data2,
417            * called ".data" in the strings table) get copied from the
418            * current process instead of the old file.  */
419           caddr_t src =  old_base + osec->sh_offset;
420           const char * secname = old_section_names + nsec->sh_name;
421           const char * names[] = {
422               ".data",".sdata", ".lit4", ".lit8", ".sdata1", ".data1",
423               ".sbss", NULL};
424           int i;
425
426           for ( i=0; names[i] != NULL; i++ ) {
427               if ( ! strcmp (secname, names[i]) ) {
428                   src = (caddr_t) osec->sh_addr;
429                   break;
430               }
431           }
432
433           memcpy (nsec->sh_offset + new_base, src, nsec->sh_size);
434       }
435
436       old_mdebug_index = find_section (".mdebug", old_section_names,
437                                        old_name, old_file_h, old_section_h, 1);
438
439 #if defined (__sony_news) && defined (_SYSTYPE_SYSV)
440       if (nsec->sh_type == SHT_MIPS_DEBUG && old_mdebug_index != -1) {
441           int diff = nsec->sh_offset-OLD_SECTION_H(old_mdebug_index).sh_offset;
442           HDRR *phdr = (HDRR *)(nsec->sh_offset + new_base);
443
444           if (diff) {
445               phdr->cbLineOffset += diff;
446               phdr->cbDnOffset   += diff;
447               phdr->cbPdOffset   += diff;
448               phdr->cbSymOffset  += diff;
449               phdr->cbOptOffset  += diff;
450               phdr->cbAuxOffset  += diff;
451               phdr->cbSsOffset   += diff;
452               phdr->cbSsExtOffset += diff;
453               phdr->cbFdOffset   += diff;
454               phdr->cbRfdOffset  += diff;
455               phdr->cbExtOffset  += diff;
456           }
457       }
458 #endif /* __sony_news && _SYSTYPE_SYSV */
459
460 #if __sgi
461       /* Adjust the HDRR offsets in .mdebug and copy the line data if
462        * it's in its usual 'hole' in the object.  Makes the new file
463        * debuggable with dbx.  patches up two problems: the absolute
464        * file offsets in the HDRR record of .mdebug (see
465        * /usr/include/syms.h), and the ld bug that gets the line table
466        * in a hole in the elf file rather than in the .mdebug section
467        * proper.
468        *
469        * David Anderson. davea@sgi.com Jan 16,1994 */
470 #define MDEBUGADJUST(__ct,__fileaddr)           \
471   if (n_phdrr->__ct > 0)                        \
472     {                                           \
473       n_phdrr->__fileaddr += movement;          \
474     }
475
476       if (n == old_mdebug_index) {
477           HDRR * o_phdrr = (HDRR *)((byte *)old_base + osec->sh_offset);
478           HDRR * n_phdrr = (HDRR *)((byte *)new_base + nsec->sh_offset);
479           unsigned movement = new_data2_size;
480
481           MDEBUGADJUST (idnMax, cbDnOffset);
482           MDEBUGADJUST (ipdMax, cbPdOffset);
483           MDEBUGADJUST (isymMax, cbSymOffset);
484           MDEBUGADJUST (ioptMax, cbOptOffset);
485           MDEBUGADJUST (iauxMax, cbAuxOffset);
486           MDEBUGADJUST (issMax, cbSsOffset);
487           MDEBUGADJUST (issExtMax, cbSsExtOffset);
488           MDEBUGADJUST (ifdMax, cbFdOffset);
489           MDEBUGADJUST (crfd, cbRfdOffset);
490           MDEBUGADJUST (iextMax, cbExtOffset);
491
492           /* The Line Section, being possible off in a hole of the
493            * object, requires special handling.  */
494           if (n_phdrr->cbLine > 0) {
495               if (o_phdrr->cbLineOffset >
496                   osec->sh_offset+ osec->sh_size){
497                   /* line data is in a hole in elf. do special copy
498                    * and adjust for this ld mistake.  */
499                   n_phdrr->cbLineOffset += movement;
500
501                   memcpy (n_phdrr->cbLineOffset + new_base,
502                           o_phdrr->cbLineOffset + old_base, n_phdrr->cbLine);
503               } else {
504                   /* somehow line data is in .mdebug as it is supposed
505                    * to be.  */
506                   MDEBUGADJUST (cbLine, cbLineOffset);
507               }
508           }
509       }
510 #endif /* __sgi */
511       /* If it is the symbol table, its st_shndx field needs to be
512        * patched.  */
513       if (nsec->sh_type == SHT_SYMTAB || nsec->sh_type == SHT_DYNSYM) {
514           unsigned int num = nsec->sh_size / nsec->sh_entsize;
515           ElfW(Sym) * sym = (ElfW(Sym) *)(nsec->sh_offset + new_base);
516           byte *symnames = ((byte *) new_base +
517                             NEW_SECTION_H (nsec->sh_link).sh_offset);
518
519           for (; num--; sym++) {
520               const char * symnam = (char *) (symnames + sym->st_name);
521
522               /* Update the symbol values of _edata and _end. */
523               if (strcmp (symnam, "_end") == 0
524                   || strcmp (symnam, "end") == 0
525                   || strcmp (symnam, "_edata") == 0
526                   || strcmp (symnam, "edata") == 0)
527                   memcpy (&sym->st_value, &new_bss_addr,sizeof (new_bss_addr));
528
529
530               if ((sym->st_shndx == SHN_UNDEF) || (sym->st_shndx == SHN_ABS)
531                   || (sym->st_shndx == SHN_COMMON)
532                   || (sym->st_shndx >= SHN_LOPROC &&
533                       sym->st_shndx <= SHN_HIPROC))
534                   continue;
535
536               PATCH_INDEX (sym->st_shndx);
537           }
538       }
539   }
540
541   /* This loop seeks out relocation sections for the data section, so
542    * that it can undo relocations performed by the runtime linker.  */
543   for (n = new_file_h->e_shnum - 1; n; n--) {
544       ElfW(Shdr) section = NEW_SECTION_H (n);
545
546       if ( section.sh_type == SHT_REL || section.sh_type == SHT_RELA ) {
547           /* This code handles two different size structs, but there
548            * should be no harm in that provided that r_offset is
549            * always the first member.  */
550           ElfW(Shdr) * info = & NEW_SECTION_H(section.sh_info);
551           const char * nm = old_section_names + info->sh_name;
552
553           if (!strcmp (nm, ".data") || !strcmp (nm, ".sdata")
554               || !strcmp (nm, ".lit4") || !strcmp (nm, ".lit8")
555               || !strcmp (nm, ".sdata1") || !strcmp (nm, ".data1")) {
556               ElfW(Addr) offset =  info->sh_addr - info->sh_offset;
557               caddr_t end, reloc = old_base + section.sh_offset;
558
559               for (end = reloc + section.sh_size; reloc < end;
560                    reloc += section.sh_entsize) {
561                   ElfW(Addr) addr = ((ElfW(Rel) *) reloc)->r_offset - offset;
562 #ifdef __alpha__
563                   /* The Alpha ELF binutils currently have a bug that
564                    * sometimes results in relocs that contain all
565                    * zeroes.  Work around this for now...  */
566                   if (((ElfW(Rel) *) reloc)->r_offset == 0)
567                       continue;
568 #endif
569                   memcpy (new_base + addr, old_base + addr,
570                           sizeof(ElfW(Addr)));
571               }
572           }
573       }
574   }
575
576 #ifdef UNEXEC_USE_MAP_PRIVATE
577   if (lseek (new_file, 0, SEEK_SET) == -1)
578       fatal ("Can't rewind (%s): errno %d\n", new_name, errno);
579
580   if (write (new_file, new_base, new_file_size) != new_file_size)
581       fatal ("Can't write (%s): errno %d\n", new_name, errno);
582 #endif
583
584   /* Close the files and make the new file executable.  */
585   if (close (old_file))
586       fatal ("Can't close (%s): errno %d\n", old_name, errno);
587
588   if (close (new_file))
589       fatal ("Can't close (%s): errno %d\n", new_name, errno);
590
591   if (stat (new_name, &stat_buf) == -1)
592       fatal ("Can't stat (%s): errno %d\n", new_name, errno);
593
594   n = umask (777);
595   umask (n);
596   stat_buf.st_mode |= 0111 & ~n;
597   if (chmod (new_name, stat_buf.st_mode) == -1)
598       fatal ("Can't chmod (%s): errno %d\n", new_name, errno);
599 }