/** * @brief Check whether it is aout format * @param vp[in] pointer inode for reading exec file * @return 0 on success */ static int aout_check_binfmt(struct nucleos_binprm *param, struct vnode *vp) { /* Read the header and check the magic number. The standard MINIX header * is defined in <nucleos/a.out.h>. It consists of 8 chars followed by 6 longs. * Then come 4 more longs that are not used here. * Byte 0: magic number 0x01 * Byte 1: magic number 0x03 * Byte 2: normal = 0x10 (not checked, 0 is OK), separate I/D = 0x20 * Byte 3: CPU type, Intel 16 bit = 0x04, Intel 32 bit = 0x10, * Motorola = 0x0B, Sun SPARC = 0x17 * Byte 4: Header length = 0x20 * Bytes 5-7 are not used. * * Now come the 6 longs * Bytes 8-11: size of text segments in bytes * Bytes 12-15: size of initialized data segment in bytes * Bytes 16-19: size of bss in bytes * Bytes 20-23: program entry point * Bytes 24-27: total memory allocated to program (text, data + stack) * Bytes 28-31: size of symbol table in bytes * The longs are represented in a machine dependent order, * little-endian on the 8088, big-endian on the 68000. * The header is followed directly by the text and data segments, and the * symbol table (if any). The sizes are given in the header. Only the * text and data segments are copied into memory by exec. The header is * used here only. The symbol table is for the benefit of a debugger and * is ignored here. */ off_t pos; int err; u64_t new_pos; unsigned int cum_io_incr; struct exec hdr; /* Read from the start of the file */ pos = 0; /* Issue request */ err = req_readwrite(vp->v_fs_e, vp->v_inode_nr, cvul64(pos), READING, VFS_PROC_NR, (char*)&hdr, sizeof(struct exec), &new_pos, &cum_io_incr); if (err) { app_err("Can't read the file header\n"); return -1; } /* Interpreted script? */ if (((char*)&hdr)[0] == '#' && ((char*)&hdr)[1] == '!' && vp->v_size >= 2) { return ESCRIPT; } if (vp->v_size < A_MINHDR) return -1; if (BADMAG(hdr)) return -1; #ifdef CONFIG_X86_32 if (hdr.a_cpu != A_I8086 && hdr.a_cpu != A_I80386) return -1; #endif if ((hdr.a_flags & ~(A_NSYM | A_EXEC)) != 0) return -1; memcpy(param->buf, &hdr, hdr.a_hdrlen); param->vp = vp; return BINFMT_AOUT; }
int main(int argc, char *argv[]) { int a_out_fd; struct stat statbuf; char *a_out; struct exec *header; /*short img_ar[12]; */ ImgHeader imgHeader; FILE *img_fd; /* Embedded file info */ char aflName[20]; /* Name of file containing list of added files */ char afName[20]; /* Name of embedded file from .afl file */ int af; /* general purpose integer for add files routines */ FILE *afl_fd; /* The .afl FILE */ int af_fd; /* Each embedded file */ struct stat afstatbuf; /* Each embedded file */ unsigned short embeddedTotalLength, embeddedOffset; int afLen, numEmbeddedFiles; /* Default values for the configurable options */ unsigned short HeapParas = 128; unsigned short StackParas = 64; /* Is this the default SIBO SDK uses? */ unsigned short InitialIP = 0; unsigned short Priority = 128; unsigned short CodeVersion = 8204; int verbose = FALSE; int i; if (argc < 3) goto usage; if ((a_out_fd = open(argv[1], O_RDONLY | O_BINARY)) < 0) { fprintf(stderr, "imgconv: Couldn't open input file %s\n", argv[1]); exit(1); } if (fstat(a_out_fd, &statbuf) < 0) { fprintf(stderr, "imgconv: Couldn't fstat input file %s: ", argv[1]); perror(""); exit(1); } if ((a_out = malloc(statbuf.st_size)) == NULL) { fprintf(stderr, "imgconv: Couldn't allocate %ld bytes to read input file %s\n", statbuf.st_size, argv[1]); exit(1); } if (statbuf.st_size != read(a_out_fd, a_out, statbuf.st_size)) { fprintf(stderr, "imgconv: Couldn't read %ld bytes of input file %s: ", statbuf.st_size, argv[1]); perror(""); exit(1); } #ifdef MSDOS if (NULL == (img_fd = fopen(argv[2], "wb"))) { #else if (NULL == (img_fd = fopen(argv[2], "w"))) { #endif fprintf(stderr, "imgconv: Couldn't open %s for writing\n", argv[1]); exit(1); } /* Handle any extra command line options */ for (i = 3; i < argc; i++) { if (argv[i][0] != '-') { fprintf(stderr, "imgconv: %s is not a - option\n", argv[i]); goto usage; } switch (tolower(argv[i][1])) { case 'c': /* Specify code version */ if (sscanf(&argv[i][2], "%hu", &CodeVersion) != 1) goto usage; break; case 'h': /* Specify heap paragraphs */ if (sscanf(&argv[i][2], "%hu", &HeapParas) != 1) goto usage; break; case 'i': /* Specify initial IP */ if (sscanf(&argv[i][2], "%hu", &InitialIP) != 1) goto usage; break; case 'p': /* Specify priority */ if (sscanf(&argv[i][2], "%hu", &Priority) != 1) goto usage; break; case 's': /* Specify stack paragraphs */ if (sscanf(&argv[i][2], "%hu", &StackParas) != 1) goto usage; break; case 'v': /* Verbose */ verbose = TRUE; break; default: fprintf(stderr, "imgconv: unknown option %s\n", argv[i]); goto usage; } } header = (struct exec *) a_out; if (BADMAG(*header)) { fprintf(stderr, "imgconv: Bad Magic in input file %s\n", argv[1]); exit(1); } if (verbose) printf("%s info:\nText 0x%04lx, Data 0x%04lx, BSS 0x%04lx\n", argv[1], header->a_text, header->a_data, header->a_bss); a_out += header->a_hdrlen; /* Do we have an add file list? (.afl file) Try the base name of the * .img file, replacing .img with .afl... */ strcpy(aflName, argv[2]); for (af = 0; af < 16 && aflName[af] != '.'; af++); strcpy(aflName + af, ".afl"); embeddedTotalLength = numEmbeddedFiles = 0; #ifdef MSDOS if (NULL != (afl_fd = fopen(aflName, "rb"))) { #else if (NULL != (afl_fd = fopen(aflName, "r"))) { #endif if (verbose) printf("Adding embedded files from list held in %s\n", aflName); for (af = 0; af < MaxAddFiles; af++) { embeddedFiles[af].length = 0; embeddedFiles[af].data = NULL; /* What is the name of this embedded file? */ if (fgets(afName, 20, afl_fd) == NULL) continue; afLen = strlen(afName); if (afLen < 2) continue; if (afName[afLen - 1] == '\n') afName[afLen - 1] = '\0'; if ((af_fd = open(afName, O_RDONLY | O_BINARY)) < 0) { fprintf(stderr, "imgconv: Couldn't open embedded file %s\n", afName); exit(1); } if (fstat(af_fd, &afstatbuf) < 0) { fprintf(stderr, "imgconv: Couldn't fstat embedded file %s: ", afName); perror(""); exit(1); } /* Embedded files can be zero length */ embeddedFiles[af].length = afstatbuf.st_size; if (embeddedFiles[af].length > 0) { /* Allocate storage space */ if ((embeddedFiles[af].data = malloc(embeddedFiles[af].length)) == NULL) { fprintf(stderr, "imgconv: Couldn't allocate %d bytes to read embedded file %s\n", embeddedFiles[af].length, afName); exit(1); } if (embeddedFiles[af].length != read(af_fd, embeddedFiles[af].data, embeddedFiles[af].length)) { fprintf(stderr, "imgconv: Couldn't read %d bytes of embedded file %s: ", embeddedFiles[af].length, afName); perror(""); exit(1); } } close(af_fd); numEmbeddedFiles++; embeddedTotalLength += embeddedFiles[af].length; if (verbose) printf("Read in %d bytes from %s\n", embeddedFiles[af].length, afName); } if (verbose) printf("Embedded files take up %d bytes\n", embeddedTotalLength); } /* Olaf's original .img header... * fwrite( "ImageFileType**", 16, 1, img_fd); * img_ar[ 0] = 8207; * img_ar[ 1] = 64; * img_ar[ 2] = header->a_text / 16; * img_ar[ 3] = 0; * img_ar[ 4] = 1000; ** Stack Size ** * img_ar[ 5] = header->a_data / 16; * img_ar[ 6] = 128; * img_ar[ 7] = header->a_data; * img_ar[ 8] = chksum( (short *) a_out, header->a_text); * img_ar[ 9] = chksum( (short *)(a_out+header->a_text), header->a_data); * img_ar[ 10] = 128; ** Start up Priority ** * img_ar[ 11] = 8204; ** Version ?? ** */ strcpy(imgHeader.Signature, "ImageFileType**"); imgHeader.ImageVersion = 0x200f; imgHeader.HeaderSizeBytes = sizeof(ImgHeader) + embeddedTotalLength; imgHeader.CodeParas = header->a_text / 16; imgHeader.InitialIP = InitialIP; imgHeader.StackParas = StackParas; imgHeader.DataParas = (header->a_data + header->a_bss + 15) / 16; imgHeader.HeapParas = HeapParas; imgHeader.InitialisedData = header->a_data; imgHeader.CodeCheckSum = chksum((unsigned char *) a_out, header->a_text); imgHeader.DataCheckSum = chksum((unsigned char *) (a_out + header->a_text), header->a_data); imgHeader.CodeVersion = CodeVersion; imgHeader.Priority = Priority; embeddedOffset = embeddedTotalLength > 0 ? sizeof(ImgHeader) : 0; for (i = 0; i < MaxAddFiles; i++) { imgHeader.Add[i].offset = i < numEmbeddedFiles ? embeddedOffset : 0; imgHeader.Add[i].length = i < numEmbeddedFiles ? embeddedFiles[i].length : 0; embeddedOffset += embeddedFiles[i].length; } imgHeader.DylCount = 0; imgHeader.DylTableOffsetLo = 0; imgHeader.DylTableOffsetHi = 0; imgHeader.Spare = 0; /* Olaf missed the DylTableOffset off this, methinks... * fwrite( img_ar, 12, 2, img_fd); * for (i=0 ; i < 12; i++) * img_ar[i] = 0; * fwrite( img_ar, 12, 2, img_fd);*/ /* Write out the header structure */ fwrite((char *) &imgHeader, sizeof(imgHeader), 1, img_fd); /* Write out the embedded files, if any */ for (i = 0; i < MaxAddFiles; i++) if (embeddedFiles[i].length > 0) { fwrite((char *) embeddedFiles[i].data, embeddedFiles[i].length, 1, img_fd); free(embeddedFiles[i].data); } /* Write out the code segment */ fwrite(a_out, header->a_text, 1, img_fd); /* Write out the initialised data segment */ fwrite(a_out + header->a_text, header->a_data, 1, img_fd); fclose(img_fd); close(a_out_fd); exit(0); usage: /* Vile, nasty hack: I love it :) */ fprintf(stderr, "usage: imgconv a.out-file .img-file [options]\n\n"); fprintf(stderr, "imgconv converts an executable file in a.out format (as produced\n"); fprintf(stderr, "by the bcc toolset) into a Psion-compatible .img file.\n\n"); fprintf(stderr, "These options can be passed to this program with the -Y\n"); fprintf(stderr, "option of bcc, e.g. bcc prog.c -o prog.img -Y-p50\n\n"); fprintf(stderr, "options: all <num>'s are in decimal, defaults in brackets\n"); fprintf(stderr, " -C<num> Specify code version number (8204)\n"); fprintf(stderr, " -H<num> Specify number of heap paragraphs (128)\n"); fprintf(stderr, " -I<num> Specify initial value for IP (0)\n"); fprintf(stderr, " -P<num> Specify priority (128)\n"); fprintf(stderr, " -S<num> Specify number of stack paragraphs (64)\n"); fprintf(stderr, " -V Verbose mode: display code stats (Don't)\n\n"); fprintf(stderr, "Up to four files may be embedded inside the resultant\n"); fprintf(stderr, ".img file by placing their filenames on separate lines\n"); fprintf(stderr, "in a .afl file. This .afl file must have the same base\n"); fprintf(stderr, "name as the .img file. e.g. Create a file fred.afl containing:\n"); fprintf(stderr, " fred.pic\n fred.rsc\n fred.shd\n"); fprintf(stderr, "To have these files added to the fred.img file.\n"); exit(1); }
void exec_image(char *image) /* Get a Minix image into core, patch it up and execute. */ { int i; struct image_header hdr; char *buf; u32_t vsec, addr, limit, aout, n, totalmem = 0; struct process *procp; /* Process under construction. */ long a_text, a_data, a_bss, a_stack; int banner= 0; long processor= a2l(b_value("processor")); u16_t kmagic, mode; char *console; char params[SECTOR_SIZE]; extern char *sbrk(int); char *verb; /* The stack is pretty deep here, so check if heap and stack collide. */ (void) sbrk(0); if ((verb= b_value(VERBOSEBOOTVARNAME)) != nil) verboseboot = a2l(verb); printf("\nLoading "); pretty_image(image); printf(".\n"); vsec= 0; /* Load this sector from image next. */ addr= mem[0].base; /* Into this memory block. */ limit= mem[0].base + mem[0].size; if (limit > caddr) limit= caddr; /* Allocate and clear the area where the headers will be placed. */ aout = (limit -= PROCESS_MAX * A_MINHDR); /* Clear the area where the headers will be placed. */ raw_clear(aout, PROCESS_MAX * A_MINHDR); /* Read the many different processes: */ for (i= 0; vsec < image_size; i++) { u32_t startaddr; startaddr = addr; if (i == PROCESS_MAX) { printf("There are more then %d programs in %s\n", PROCESS_MAX, image); errno= 0; return; } procp= &process[i]; /* Read header. */ DEBUGEXTRA(("Reading header... ")); for (;;) { if ((buf= get_sector(vsec++)) == nil) return; memcpy(&hdr, buf, sizeof(hdr)); if (BADMAG(hdr.process)) { errno= ENOEXEC; return; } /* Check the optional label on the process. */ if (selected(hdr.name)) break; /* Bad label, skip this process. */ vsec+= proc_size(&hdr); } DEBUGEXTRA(("done\n")); /* Sanity check: an 8086 can't run a 386 kernel. */ if (hdr.process.a_cpu == A_I80386 && processor < 386) { printf("You can't run a 386 kernel on this 80%ld\n", processor); errno= 0; return; } /* Get the click shift from the kernel text segment. */ if (i == KERNEL_IDX) { if (!get_clickshift(vsec, &hdr)) return; addr= align(addr, click_size); /* big kernels must be loaded into extended memory */ if (k_flags & K_KHIGH) { addr= mem[1].base; limit= mem[1].base + mem[1].size; } } /* Save a copy of the header for the kernel, with a_syms * misused as the address where the process is loaded at. */ DEBUGEXTRA(("raw_copy(0x%x, 0x%lx, 0x%x)... ", aout + i * A_MINHDR, mon2abs(&hdr.process), A_MINHDR)); hdr.process.a_syms= addr; raw_copy(aout + i * A_MINHDR, mon2abs(&hdr.process), A_MINHDR); DEBUGEXTRA(("done\n")); if (!banner) { DEBUGBASIC((" cs ds text data bss")); if (k_flags & K_CHMEM) DEBUGBASIC((" stack")); DEBUGBASIC(("\n")); banner= 1; } /* Segment sizes. */ DEBUGEXTRA(("a_text=0x%lx; a_data=0x%lx; a_bss=0x%lx; a_flags=0x%x)\n", hdr.process.a_text, hdr.process.a_data, hdr.process.a_bss, hdr.process.a_flags)); a_text= hdr.process.a_text; a_data= hdr.process.a_data; a_bss= hdr.process.a_bss; if (k_flags & K_CHMEM) { a_stack= hdr.process.a_total - a_data - a_bss; if (!(hdr.process.a_flags & A_SEP)) a_stack-= a_text; } else { a_stack= 0; } /* Collect info about the process to be. */ procp->cs= addr; /* Process may be page aligned so that the text segment contains * the header, or have an unmapped zero page against vaxisms. */ procp->entry= hdr.process.a_entry; if (hdr.process.a_flags & A_PAL) a_text+= hdr.process.a_hdrlen; if (hdr.process.a_flags & A_UZP) procp->cs-= click_size; /* Separate I&D: two segments. Common I&D: only one. */ if (hdr.process.a_flags & A_SEP) { /* Read the text segment. */ DEBUGEXTRA(("get_segment(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n", vsec, a_text, addr, limit)); if (!get_segment(&vsec, &a_text, &addr, limit)) return; DEBUGEXTRA(("get_segment done vsec=0x%lx a_text=0x%lx " "addr=0x%lx\n", vsec, a_text, addr)); /* The data segment follows. */ procp->ds= addr; if (hdr.process.a_flags & A_UZP) procp->ds-= click_size; procp->data= addr; } else { /* Add text to data to form one segment. */ procp->data= addr + a_text; procp->ds= procp->cs; a_data+= a_text; } /* Read the data segment. */ DEBUGEXTRA(("get_segment(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n", vsec, a_data, addr, limit)); if (!get_segment(&vsec, &a_data, &addr, limit)) return; DEBUGEXTRA(("get_segment done vsec=0x%lx a_data=0x%lx " "addr=0x%lx\n", vsec, a_data, addr)); /* Make space for bss and stack unless... */ if (i != KERNEL_IDX && (k_flags & K_CLAIM)) a_bss= a_stack= 0; DEBUGBASIC(("%07lx %07lx %8ld %8ld %8ld", procp->cs, procp->ds, hdr.process.a_text, hdr.process.a_data, hdr.process.a_bss)); if (k_flags & K_CHMEM) DEBUGBASIC((" %8ld", a_stack)); /* Note that a_data may be negative now, but we can look at it * as -a_data bss bytes. */ /* Compute the number of bss clicks left. */ a_bss+= a_data; n= align(a_bss, click_size); a_bss-= n; /* Zero out bss. */ DEBUGEXTRA(("\nraw_clear(0x%lx, 0x%lx); limit=0x%lx... ", addr, n, limit)); if (addr + n > limit) { errno= ENOMEM; return; } raw_clear(addr, n); DEBUGEXTRA(("done\n")); addr+= n; /* And the number of stack clicks. */ a_stack+= a_bss; n= align(a_stack, click_size); a_stack-= n; /* Add space for the stack. */ addr+= n; /* Process endpoint. */ procp->end= addr; if (verboseboot >= VERBOSEBOOT_BASIC) printf(" %s\n", hdr.name); else { u32_t mem; mem = addr-startaddr; printf("%s ", hdr.name); totalmem += mem; } if (i == 0 && (k_flags & (K_HIGH | K_KHIGH)) == K_HIGH) { /* Load the rest in extended memory. */ addr= mem[1].base; limit= mem[1].base + mem[1].size; } } if (verboseboot < VERBOSEBOOT_BASIC) printf("(%dk)\n", totalmem/1024); if ((n_procs= i) == 0) { printf("There are no programs in %s\n", image); errno= 0; return; } /* Check the kernel magic number. */ raw_copy(mon2abs(&kmagic), process[KERNEL_IDX].data + MAGIC_OFF, sizeof(kmagic)); if (kmagic != KERNEL_D_MAGIC) { printf("Kernel magic number is incorrect (0x%x@0x%lx)\n", kmagic, process[KERNEL_IDX].data + MAGIC_OFF); errno= 0; return; } /* Patch sizes, etc. into kernel data. */ DEBUGEXTRA(("patch_sizes()... ")); patch_sizes(); DEBUGEXTRA(("done\n")); #if !DOS if (!(k_flags & K_MEML)) { /* Copy the a.out headers to the old place. */ raw_copy(HEADERPOS, aout, PROCESS_MAX * A_MINHDR); } #endif /* Run the trailer function just before starting Minix. */ DEBUGEXTRA(("run_trailer()... ")); if (!run_trailer()) { errno= 0; return; } DEBUGEXTRA(("done\n")); /* Translate the boot parameters to what Minix likes best. */ DEBUGEXTRA(("params2params(0x%x, 0x%x)... ", params, sizeof(params))); if (!params2params(params, sizeof(params))) { errno= 0; return; } DEBUGEXTRA(("done\n")); /* Set the video to the required mode. */ if ((console= b_value("console")) == nil || (mode= a2x(console)) == 0) { mode= strcmp(b_value("chrome"), "color") == 0 ? COLOR_MODE : MONO_MODE; } DEBUGEXTRA(("set_mode(%d)... ", mode)); set_mode(mode); DEBUGEXTRA(("done\n")); /* Close the disk. */ DEBUGEXTRA(("dev_close()... ")); (void) dev_close(); DEBUGEXTRA(("done\n")); /* Minix. */ DEBUGEXTRA(("minix(0x%lx, 0x%lx, 0x%lx, 0x%x, 0x%x, 0x%lx)\n", process[KERNEL_IDX].entry, process[KERNEL_IDX].cs, process[KERNEL_IDX].ds, params, sizeof(params), aout)); minix(process[KERNEL_IDX].entry, process[KERNEL_IDX].cs, process[KERNEL_IDX].ds, params, sizeof(params), aout); if (!(k_flags & K_BRET)) { extern u32_t reboot_code; raw_copy(mon2abs(params), reboot_code, sizeof(params)); } parse_code(params); /* Return from Minix. Things may have changed, so assume nothing. */ fsok= -1; errno= 0; /* Read leftover character, if any. */ scan_keyboard(); /* Restore screen contents. */ restore_screen(); }
void copylink(char *source, char *dest, int mode, int owner, int group) { struct stat sst, dst; int sfd, dfd, n; int r, same= 0, change= 0, docopy= 1; char buf[4096]; # define hdr ((struct exec *) buf) pid_t pid; int status; /* Source must exist as a plain file, dest may exist as a plain file. */ if (stat(source, &sst) < 0) { report(source); return; } if (mode == -1) { mode= sst.st_mode & 07777; if (!lflag || cflag) { mode|= 0444; if (mode & 0111) mode|= 0111; } } if (owner == -1) owner= sst.st_uid; if (group == -1) group= sst.st_gid; if (!S_ISREG(sst.st_mode)) { fprintf(stderr, "install: %s is not a regular file\n", source); excode= 1; return; } r= stat(dest, &dst); if (r < 0) { if (errno != ENOENT) { report(dest); return; } } else { if (!S_ISREG(dst.st_mode)) { fprintf(stderr, "install: %s is not a regular file\n", dest); excode= 1; return; } /* Are the files the same? */ if (sst.st_dev == dst.st_dev && sst.st_ino == dst.st_ino) { if (!lflag && cflag) { fprintf(stderr, "install: %s and %s are the same, can't copy\n", source, dest); excode= 1; return; } same= 1; } } if (lflag && !same) { /* Try to link the files. */ if (r >= 0 && unlink(dest) < 0) { report(dest); return; } if (link(source, dest) >= 0) { docopy= 0; } else { if (!cflag || errno != EXDEV) { fprintf(stderr, "install: can't link %s to %s: %s\n", source, dest, strerror(errno)); excode= 1; return; } } } if (docopy && !same) { /* Copy the files, stripping if necessary. */ long count= LONG_MAX; int first= 1; if ((sfd= open(source, O_RDONLY)) < 0) { report(source); return; } /* Open for write is less simple, its mode may be 444. */ dfd= open(dest, O_WRONLY|O_CREAT|O_TRUNC, mode | 0600); if (dfd < 0 && errno == EACCES) { (void) chmod(dest, mode | 0600); dfd= open(dest, O_WRONLY|O_TRUNC); } if (dfd < 0) { report(dest); close(sfd); return; } pid= 0; while (count > 0 && (n= read(sfd, buf, sizeof(buf))) > 0) { if (first && n >= A_MINHDR && !BADMAG(*hdr)) { if (strip) { count= hdr->a_hdrlen + hdr->a_text + hdr->a_data; #ifdef A_NSYM hdr->a_flags &= ~A_NSYM; #endif hdr->a_syms= 0; } if (stack != -1 && setstack(hdr)) change= 1; if (compress != nil) { /* Write first #! line. */ (void) write(dfd, zcat, strlen(zcat)); /* Put a compressor in between. */ if ((pid= filter(dfd, compress)) < 0) { close(sfd); close(dfd); return; } change= 1; } } if (count < n) n= count; if (write(dfd, buf, n) < 0) { report(dest); close(sfd); close(dfd); if (pid != 0) (void) waitpid(pid, nil, 0); return; } count-= n; first= 0; } if (n < 0) report(source); close(sfd); close(dfd); if (pid != 0 && waitpid(pid, &status, 0) < 0 || status != 0) { excode= 1; return; } if (n < 0) return; } else { if (stack != -1) { /* The file has been linked into place. Set the * stack size. */ if ((dfd= open(dest, O_RDWR)) < 0) { report(dest); return; } if ((n= read(dfd, buf, sizeof(*hdr))) < 0) { report(dest); return; } if (n >= A_MINHDR && !BADMAG(*hdr) && setstack(hdr)) { if (lseek(dfd, (off_t) 0, SEEK_SET) == -1 || write(dfd, buf, n) < 0 ) { report(dest); close(dfd); return; } change= 1; } close(dfd); } } if (stat(dest, &dst) < 0) { report(dest); return; } if ((dst.st_mode & 07777) != mode) { if (chmod(dest, mode) < 0) { report(dest); return; } } if (dst.st_uid != owner || dst.st_gid != group) { if (chown(dest, owner, group) < 0 && errno != EPERM) { report(dest); return; } /* Set the mode again, chown may have wrecked it. */ (void) chmod(dest, mode); } if (!change) { struct utimbuf ubuf; ubuf.actime= dst.st_atime; ubuf.modtime= sst.st_mtime; if (utime(dest, &ubuf) < 0 && errno != EPERM) { report(dest); return; } } }