-/* Copyright (C) 1985-1988, 1990, 1992, 1999-2011
- Free Software Foundation, Inc.
+/* Copyright (C) 1985-1988, 1990, 1992, 1999-2014 Free Software
+ Foundation, Inc.
This file is part of GNU Emacs.
Instead we read the whole file, modify it, and write it out. */
#include <config.h>
-#include <unexec.h>
+#include "unexec.h"
+#include "lisp.h"
-extern void fatal (const char *msgid, ...);
-
-#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <memory.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/stat.h>
-#include <memory.h>
-#include <errno.h>
+#include <sys/types.h>
#include <unistd.h>
-#include <fcntl.h>
+
#if !defined (__NetBSD__) && !defined (__OpenBSD__)
#include <elf.h>
#endif /* not __NetBSD__ and not __OpenBSD__ */
long cbRfdOffset;
long cbExtOffset;
} HDRR, *pHDRR;
-#define cbHDRR sizeof(HDRR)
+#define cbHDRR sizeof (HDRR)
#define hdrNil ((pHDRR)0)
#endif
/*
* NetBSD does not have normal-looking user-land ELF support.
*/
-# if defined __alpha__ || defined __sparc_v9__
+# if defined __alpha__ || defined __sparc_v9__ || defined _LP64
# define ELFSIZE 64
# else
# define ELFSIZE 32
#endif
#ifndef ElfW
-# ifdef __STDC__
-# define ElfBitsW(bits, type) Elf##bits##_##type
-# else
-# define ElfBitsW(bits, type) Elf/**/bits/**/_/**/type
-# endif
-# ifdef _LP64
-# define ELFSIZE 64
-# else
-# define ELFSIZE 32
+# define ElfBitsW(bits, type) Elf##bits##_##type
+# ifndef ELFSIZE
+# ifdef _LP64
+# define ELFSIZE 64
+# else
+# define ELFSIZE 32
+# endif
# endif
/* This macro expands `bits' before invoking ElfBitsW. */
# define ElfExpandBitsW(bits, type) ElfBitsW (bits, type)
# define ElfW(type) ElfExpandBitsW (ELFSIZE, type)
#endif
+/* The code often converts ElfW (Half) values like e_shentsize to ptrdiff_t;
+ check that this doesn't lose information. */
+#include <intprops.h>
+#include <verify.h>
+verify ((! TYPE_SIGNED (ElfW (Half))
+ || PTRDIFF_MIN <= TYPE_MINIMUM (ElfW (Half)))
+ && TYPE_MAXIMUM (ElfW (Half)) <= PTRDIFF_MAX);
+
+#ifdef UNEXELF_DEBUG
+# define DEBUG_LOG(expr) fprintf (stderr, #expr " 0x%jx\n", (uintmax_t) (expr))
+#endif
+
/* Get the address of a particular section or program header entry,
* accounting for the size of the entries.
*/
Apr 23, 1996
*/
+static void *
+entry_address (void *section_h, ptrdiff_t idx, ptrdiff_t entsize)
+{
+ char *h = section_h;
+ return h + idx * entsize;
+}
+
#define OLD_SECTION_H(n) \
- (*(ElfW(Shdr) *) ((byte *) old_section_h + old_file_h->e_shentsize * (n)))
+ (*(ElfW (Shdr) *) entry_address (old_section_h, n, old_file_h->e_shentsize))
#define NEW_SECTION_H(n) \
- (*(ElfW(Shdr) *) ((byte *) new_section_h + new_file_h->e_shentsize * (n)))
+ (*(ElfW (Shdr) *) entry_address (new_section_h, n, new_file_h->e_shentsize))
#define NEW_PROGRAM_H(n) \
- (*(ElfW(Phdr) *) ((byte *) new_program_h + new_file_h->e_phentsize * (n)))
+ (*(ElfW (Phdr) *) entry_address (new_program_h, n, new_file_h->e_phentsize))
-#define PATCH_INDEX(n) \
- do { \
- if ((int) (n) >= old_bss_index) \
- (n)++; } while (0)
+#define PATCH_INDEX(n) ((n) += old_bss_index <= (n))
typedef unsigned char byte;
/* Round X up to a multiple of Y. */
-static ElfW(Addr)
-round_up (ElfW(Addr) x, ElfW(Addr) y)
+static ElfW (Addr)
+round_up (ElfW (Addr) x, ElfW (Addr) y)
{
- int rem = x % y;
+ ElfW (Addr) rem = x % y;
if (rem == 0)
return x;
return x - rem + y;
about the file we are looking in.
If we don't find the section NAME, that is a fatal error
- if NOERROR is 0; we return -1 if NOERROR is nonzero. */
+ if NOERROR is false; return -1 if NOERROR is true. */
-static int
+static ptrdiff_t
find_section (const char *name, const char *section_names, const char *file_name,
- ElfW(Ehdr) *old_file_h, ElfW(Shdr) *old_section_h, int noerror)
+ ElfW (Ehdr) *old_file_h, ElfW (Shdr) *old_section_h,
+ bool noerror)
{
- int idx;
+ ptrdiff_t idx;
for (idx = 1; idx < old_file_h->e_shnum; idx++)
{
-#ifdef DEBUG
- fprintf (stderr, "Looking for %s - found %s\n", name,
- section_names + OLD_SECTION_H (idx).sh_name);
+ char const *found_name = section_names + OLD_SECTION_H (idx).sh_name;
+#ifdef UNEXELF_DEBUG
+ fprintf (stderr, "Looking for %s - found %s\n", name, found_name);
#endif
- if (!strcmp (section_names + OLD_SECTION_H (idx).sh_name,
- name))
- break;
- }
- if (idx == old_file_h->e_shnum)
- {
- if (noerror)
- return -1;
- else
- fatal ("Can't find %s in %s.\n", name, file_name);
+ if (strcmp (name, found_name) == 0)
+ return idx;
}
- return idx;
+ if (! noerror)
+ fatal ("Can't find %s in %s", name, file_name);
+ return -1;
}
/* ****************************************************************
void
unexec (const char *new_name, const char *old_name)
{
- int new_file, old_file, new_file_size;
-
-#if defined (emacs) || !defined (DEBUG)
+ int new_file, old_file;
+ off_t new_file_size;
void *new_break;
-#endif
/* Pointers to the base of the image of the two files. */
caddr_t old_base, new_base;
/* Pointers to the file, program and section headers for the old and
new files. */
- ElfW(Ehdr) *old_file_h, *new_file_h;
- ElfW(Phdr) *old_program_h, *new_program_h;
- ElfW(Shdr) *old_section_h, *new_section_h;
+ ElfW (Ehdr) *old_file_h, *new_file_h;
+ ElfW (Phdr) *old_program_h, *new_program_h;
+ ElfW (Shdr) *old_section_h, *new_section_h;
/* Point to the section name table in the old file. */
char *old_section_names;
- ElfW(Addr) old_bss_addr, new_bss_addr;
- ElfW(Word) old_bss_size, new_data2_size;
- ElfW(Off) new_data2_offset;
- ElfW(Addr) new_data2_addr;
- ElfW(Off) old_bss_offset;
- ElfW(Word) new_data2_incr;
+ ElfW (Addr) old_bss_addr, new_bss_addr;
+ ElfW (Word) old_bss_size, new_data2_size;
+ ElfW (Off) new_data2_offset;
+ ElfW (Addr) new_data2_addr;
+ ElfW (Off) old_bss_offset;
+ ElfW (Word) new_data2_incr;
- int n, nn;
- int old_bss_index, old_sbss_index, old_plt_index;
- int old_data_index, new_data2_index;
+ ptrdiff_t n, nn;
+ ptrdiff_t old_bss_index, old_sbss_index, old_plt_index;
+ ptrdiff_t old_data_index, new_data2_index;
#if defined _SYSTYPE_SYSV || defined __sgi
- int old_mdebug_index;
+ ptrdiff_t old_mdebug_index;
#endif
struct stat stat_buf;
- int old_file_size;
+ off_t old_file_size;
+ int mask;
/* Open the old file, allocate a buffer of the right size, and read
in the file contents. */
- old_file = open (old_name, O_RDONLY);
+ old_file = emacs_open (old_name, O_RDONLY, 0);
if (old_file < 0)
- fatal ("Can't open %s for reading: errno %d\n", old_name, errno);
+ fatal ("Can't open %s for reading: %s", old_name, strerror (errno));
- if (fstat (old_file, &stat_buf) == -1)
- fatal ("Can't fstat (%s): errno %d\n", old_name, errno);
+ if (fstat (old_file, &stat_buf) != 0)
+ fatal ("Can't fstat (%s): %s", old_name, strerror (errno));
#if MAP_ANON == 0
- mmap_fd = open ("/dev/zero", O_RDONLY);
+ mmap_fd = emacs_open ("/dev/zero", O_RDONLY, 0);
if (mmap_fd < 0)
- fatal ("Can't open /dev/zero for reading: errno %d\n", errno, 0);
+ fatal ("Can't open /dev/zero for reading: %s", strerror (errno));
#endif
/* We cannot use malloc here because that may use sbrk. If it does,
extra careful to use the correct value of sbrk(0) after
allocating all buffers in the code below, which we aren't. */
old_file_size = stat_buf.st_size;
+ if (! (0 <= old_file_size && old_file_size <= SIZE_MAX))
+ fatal ("File size out of range");
old_base = mmap (NULL, old_file_size, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, mmap_fd, 0);
if (old_base == MAP_FAILED)
- fatal ("Can't allocate buffer for %s\n", old_name, 0);
+ fatal ("Can't allocate buffer for %s: %s", old_name, strerror (errno));
- if (read (old_file, old_base, stat_buf.st_size) != stat_buf.st_size)
- fatal ("Didn't read all of %s: errno %d\n", old_name, errno);
+ if (read (old_file, old_base, old_file_size) != old_file_size)
+ fatal ("Didn't read all of %s: %s", old_name, strerror (errno));
/* Get pointers to headers & section names */
- old_file_h = (ElfW(Ehdr) *) old_base;
- old_program_h = (ElfW(Phdr) *) ((byte *) old_base + old_file_h->e_phoff);
- old_section_h = (ElfW(Shdr) *) ((byte *) old_base + old_file_h->e_shoff);
+ old_file_h = (ElfW (Ehdr) *) old_base;
+ old_program_h = (ElfW (Phdr) *) ((byte *) old_base + old_file_h->e_phoff);
+ old_section_h = (ElfW (Shdr) *) ((byte *) old_base + old_file_h->e_shoff);
old_section_names = (char *) old_base
+ OLD_SECTION_H (old_file_h->e_shstrndx).sh_offset;
old_data_index = find_section (".data", old_section_names,
old_name, old_file_h, old_section_h, 0);
-#if defined (emacs) || !defined (DEBUG)
new_break = sbrk (0);
- new_bss_addr = (ElfW(Addr)) new_break;
-#else
- new_bss_addr = old_bss_addr + old_bss_size + 0x1234;
-#endif
+ new_bss_addr = (ElfW (Addr)) new_break;
new_data2_addr = old_bss_addr;
new_data2_size = new_bss_addr - old_bss_addr;
new_data2_offset = OLD_SECTION_H (old_data_index).sh_offset
section) was unaligned. */
new_data2_incr = new_data2_size + (new_data2_offset - old_bss_offset);
-#ifdef DEBUG
- fprintf (stderr, "old_bss_index %d\n", old_bss_index);
- fprintf (stderr, "old_bss_addr %x\n", old_bss_addr);
- fprintf (stderr, "old_bss_size %x\n", old_bss_size);
- fprintf (stderr, "old_bss_offset %x\n", old_bss_offset);
- fprintf (stderr, "new_bss_addr %x\n", new_bss_addr);
- fprintf (stderr, "new_data2_addr %x\n", new_data2_addr);
- fprintf (stderr, "new_data2_size %x\n", new_data2_size);
- fprintf (stderr, "new_data2_offset %x\n", new_data2_offset);
- fprintf (stderr, "new_data2_incr %x\n", new_data2_incr);
+#ifdef UNEXELF_DEBUG
+ fprintf (stderr, "old_bss_index %td\n", old_bss_index);
+ DEBUG_LOG (old_bss_addr);
+ DEBUG_LOG (old_bss_size);
+ DEBUG_LOG (old_bss_offset);
+ DEBUG_LOG (new_bss_addr);
+ DEBUG_LOG (new_data2_addr);
+ DEBUG_LOG (new_data2_size);
+ DEBUG_LOG (new_data2_offset);
+ DEBUG_LOG (new_data2_incr);
#endif
- if ((uintptr_t) new_bss_addr < (uintptr_t) old_bss_addr + old_bss_size)
- fatal (".bss shrank when undumping???\n", 0, 0);
+ if (new_bss_addr < old_bss_addr + old_bss_size)
+ fatal (".bss shrank when undumping");
/* Set the output file to the right size. Allocate a buffer to hold
the image of the new file. Set pointers to various interesting
- objects. stat_buf still has old_file data. */
+ objects. */
- new_file = open (new_name, O_RDWR | O_CREAT, 0666);
+ new_file = emacs_open (new_name, O_RDWR | O_CREAT, 0666);
if (new_file < 0)
- fatal ("Can't creat (%s): errno %d\n", new_name, errno);
+ fatal ("Can't creat (%s): %s", new_name, strerror (errno));
- new_file_size = stat_buf.st_size + old_file_h->e_shentsize + new_data2_incr;
+ new_file_size = old_file_size + old_file_h->e_shentsize + new_data2_incr;
if (ftruncate (new_file, new_file_size))
- fatal ("Can't ftruncate (%s): errno %d\n", new_name, errno);
+ fatal ("Can't ftruncate (%s): %s", new_name, strerror (errno));
new_base = mmap (NULL, new_file_size, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, mmap_fd, 0);
if (new_base == MAP_FAILED)
- fatal ("Can't allocate buffer for %s\n", old_name, 0);
+ fatal ("Can't allocate buffer for %s: %s", old_name, strerror (errno));
- new_file_h = (ElfW(Ehdr) *) new_base;
- new_program_h = (ElfW(Phdr) *) ((byte *) new_base + old_file_h->e_phoff);
- new_section_h = (ElfW(Shdr) *)
+ new_file_h = (ElfW (Ehdr) *) new_base;
+ new_program_h = (ElfW (Phdr) *) ((byte *) new_base + old_file_h->e_phoff);
+ new_section_h = (ElfW (Shdr) *)
((byte *) new_base + old_file_h->e_shoff + new_data2_incr);
/* Make our new file, program and section headers as copies of the
new_file_h->e_shoff += new_data2_incr;
new_file_h->e_shnum += 1;
-#ifdef DEBUG
- fprintf (stderr, "Old section offset %x\n", old_file_h->e_shoff);
- fprintf (stderr, "Old section count %d\n", old_file_h->e_shnum);
- fprintf (stderr, "New section offset %x\n", new_file_h->e_shoff);
- fprintf (stderr, "New section count %d\n", new_file_h->e_shnum);
+#ifdef UNEXELF_DEBUG
+ DEBUG_LOG (old_file_h->e_shoff);
+ fprintf (stderr, "Old section count %td\n", (ptrdiff_t) old_file_h->e_shnum);
+ DEBUG_LOG (new_file_h->e_shoff);
+ fprintf (stderr, "New section count %td\n", (ptrdiff_t) new_file_h->e_shnum);
#endif
/* Fix up a new program header. Extend the writable data segment so
to adjust the offset and address of any segment that is above
data2, just in case we decide to allow this later. */
- for (n = new_file_h->e_phnum - 1; n >= 0; n--)
+ for (n = new_file_h->e_phnum; --n >= 0; )
{
/* Compute maximum of all requirements for alignment of section. */
- ElfW(Word) alignment = (NEW_PROGRAM_H (n)).p_align;
+ ElfW (Word) alignment = (NEW_PROGRAM_H (n)).p_align;
if ((OLD_SECTION_H (old_bss_index)).sh_addralign > alignment)
alignment = OLD_SECTION_H (old_bss_index).sh_addralign;
> (old_sbss_index == -1
? old_bss_addr
: round_up (old_bss_addr, alignment)))
- fatal ("Program segment above .bss in %s\n", old_name, 0);
+ fatal ("Program segment above .bss in %s", old_name);
if (NEW_PROGRAM_H (n).p_type == PT_LOAD
&& (round_up ((NEW_PROGRAM_H (n)).p_vaddr
break;
}
if (n < 0)
- fatal ("Couldn't find segment next to .bss in %s\n", old_name, 0);
+ fatal ("Couldn't find segment next to .bss in %s", old_name);
/* Make sure that the size includes any padding before the old .bss
section. */
NEW_PROGRAM_H (n).p_memsz = NEW_PROGRAM_H (n).p_filesz;
#if 0 /* Maybe allow section after data2 - does this ever happen? */
- for (n = new_file_h->e_phnum - 1; n >= 0; n--)
+ for (n = new_file_h->e_phnum; --n >= 0; )
{
if (NEW_PROGRAM_H (n).p_vaddr
&& NEW_PROGRAM_H (n).p_vaddr >= new_data2_addr)
/* Walk through all section headers, insert the new data2 section right
before the new bss section. */
- for (n = 1, nn = 1; n < (int) old_file_h->e_shnum; n++, nn++)
+ for (n = 1, nn = 1; n < old_file_h->e_shnum; n++, nn++)
{
caddr_t src;
/* If it is (s)bss section, insert the new data2 section before it. */
/* The conditional bit below was in Oliva's original code
(1999-08-25) and seems to have been dropped by mistake
subsequently. It prevents a crash at startup under X in
- `IRIX64 6.5 6.5.17m', whether compiled on that relase or
+ `IRIX64 6.5 6.5.17m', whether compiled on that release or
an earlier one. It causes no trouble on the other ELF
platforms I could test (Irix 6.5.15m, Solaris 8, Debian
Potato x86, Debian Woody SPARC); however, it's reported
memcpy (NEW_SECTION_H (nn).sh_offset + new_base, src,
NEW_SECTION_H (nn).sh_size);
-#ifdef __alpha__
+#if defined __alpha__ && !defined __OpenBSD__
/* Update Alpha COFF symbol table: */
if (strcmp (old_section_names + OLD_SECTION_H (n).sh_name, ".mdebug")
== 0)
symhdr->cbRfdOffset += new_data2_size;
symhdr->cbExtOffset += new_data2_size;
}
-#endif /* __alpha__ */
+#endif /* __alpha__ && !__OpenBSD__ */
#if defined (_SYSTYPE_SYSV)
if (NEW_SECTION_H (nn).sh_type == SHT_MIPS_DEBUG
&& old_mdebug_index != -1)
{
- int diff = NEW_SECTION_H(nn).sh_offset
- - OLD_SECTION_H(old_mdebug_index).sh_offset;
+ ptrdiff_t new_offset = NEW_SECTION_H (nn).sh_offset;
+ ptrdiff_t old_offset = OLD_SECTION_H (old_mdebug_index).sh_offset;
+ ptrdiff_t diff = new_offset - old_offset;
HDRR *phdr = (HDRR *)(NEW_SECTION_H (nn).sh_offset + new_base);
if (diff)
if (NEW_SECTION_H (nn).sh_type == SHT_SYMTAB
|| NEW_SECTION_H (nn).sh_type == SHT_DYNSYM)
{
- ElfW(Shdr) *spt = &NEW_SECTION_H (nn);
- unsigned int num = spt->sh_size / spt->sh_entsize;
- ElfW(Sym) * sym = (ElfW(Sym) *) (NEW_SECTION_H (nn).sh_offset +
+ ElfW (Shdr) *spt = &NEW_SECTION_H (nn);
+ ptrdiff_t num = spt->sh_size / spt->sh_entsize;
+ ElfW (Sym) * sym = (ElfW (Sym) *) (NEW_SECTION_H (nn).sh_offset +
new_base);
for (; num--; sym++)
{
}
/* Update the symbol values of _edata and _end. */
- for (n = new_file_h->e_shnum - 1; n; n--)
+ for (n = new_file_h->e_shnum; 0 < --n; )
{
byte *symnames;
- ElfW(Sym) *symp, *symendp;
+ ElfW (Sym) *symp, *symendp;
if (NEW_SECTION_H (n).sh_type != SHT_DYNSYM
&& NEW_SECTION_H (n).sh_type != SHT_SYMTAB)
symnames = ((byte *) new_base
+ NEW_SECTION_H (NEW_SECTION_H (n).sh_link).sh_offset);
- symp = (ElfW(Sym) *) (NEW_SECTION_H (n).sh_offset + new_base);
- symendp = (ElfW(Sym) *) ((byte *)symp + NEW_SECTION_H (n).sh_size);
+ symp = (ElfW (Sym) *) (NEW_SECTION_H (n).sh_offset + new_base);
+ symendp = (ElfW (Sym) *) ((byte *)symp + NEW_SECTION_H (n).sh_size);
for (; symp < symendp; symp ++)
{
nn = symp->st_shndx;
if (nn > old_bss_index)
nn--;
- old = ((symp->st_value - NEW_SECTION_H (symp->st_shndx).sh_addr)
- + OLD_SECTION_H (nn).sh_offset + old_base);
- memcpy (new, old, symp->st_size);
+ if (nn == old_bss_index)
+ memset (new, 0, symp->st_size);
+ else
+ {
+ old = ((symp->st_value
+ - NEW_SECTION_H (symp->st_shndx).sh_addr)
+ + OLD_SECTION_H (nn).sh_offset + old_base);
+ memcpy (new, old, symp->st_size);
+ }
}
#endif
}
/* This loop seeks out relocation sections for the data section, so
that it can undo relocations performed by the runtime linker. */
- for (n = new_file_h->e_shnum - 1; n; n--)
+ for (n = new_file_h->e_shnum; 0 < --n; )
{
- ElfW(Shdr) section = NEW_SECTION_H (n);
+ ElfW (Shdr) section = NEW_SECTION_H (n);
/* Cause a compilation error if anyone uses n instead of nn below. */
#define n ((void) 0);
|| !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
".data1"))
{
- ElfW(Addr) offset = (NEW_SECTION_H (nn).sh_addr
+ ElfW (Addr) offset = (NEW_SECTION_H (nn).sh_addr
- NEW_SECTION_H (nn).sh_offset);
caddr_t reloc = old_base + section.sh_offset, end;
for (end = reloc + section.sh_size; reloc < end;
reloc += section.sh_entsize)
{
- ElfW(Addr) addr = ((ElfW(Rel) *) reloc)->r_offset - offset;
+ ElfW (Addr) addr = ((ElfW (Rel) *) reloc)->r_offset - offset;
#ifdef __alpha__
/* The Alpha ELF binutils currently have a bug that
sometimes results in relocs that contain all
zeroes. Work around this for now... */
- if (((ElfW(Rel) *) reloc)->r_offset == 0)
+ if (((ElfW (Rel) *) reloc)->r_offset == 0)
continue;
#endif
- memcpy (new_base + addr, old_base + addr, sizeof(ElfW(Addr)));
+ memcpy (new_base + addr, old_base + addr, sizeof (ElfW (Addr)));
}
}
break;
/* Write out new_file, and free the buffers. */
if (write (new_file, new_base, new_file_size) != new_file_size)
- fatal ("Didn't write %d bytes to %s: errno %d\n",
- new_file_size, new_name, errno);
+ fatal ("Didn't write %lu bytes to %s: %s",
+ (unsigned long) new_file_size, new_name, strerror (errno));
munmap (old_base, old_file_size);
munmap (new_base, new_file_size);
/* Close the files and make the new file executable. */
#if MAP_ANON == 0
- close (mmap_fd);
+ emacs_close (mmap_fd);
#endif
- if (close (old_file))
- fatal ("Can't close (%s): errno %d\n", old_name, errno);
+ if (emacs_close (old_file) != 0)
+ fatal ("Can't close (%s): %s", old_name, strerror (errno));
- if (close (new_file))
- fatal ("Can't close (%s): errno %d\n", new_name, errno);
+ if (emacs_close (new_file) != 0)
+ fatal ("Can't close (%s): %s", new_name, strerror (errno));
- if (stat (new_name, &stat_buf) == -1)
- fatal ("Can't stat (%s): errno %d\n", new_name, errno);
+ if (stat (new_name, &stat_buf) != 0)
+ fatal ("Can't stat (%s): %s", new_name, strerror (errno));
- n = umask (777);
- umask (n);
- stat_buf.st_mode |= 0111 & ~n;
- if (chmod (new_name, stat_buf.st_mode) == -1)
- fatal ("Can't chmod (%s): errno %d\n", new_name, errno);
+ mask = umask (777);
+ umask (mask);
+ stat_buf.st_mode |= 0111 & ~mask;
+ if (chmod (new_name, stat_buf.st_mode) != 0)
+ fatal ("Can't chmod (%s): %s", new_name, strerror (errno));
}