hpux-1122-initial-support-20030213
[openafs.git] / src / pinstall / install.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11                       All Rights Reserved
12
13 Permission to use, copy, modify, and distribute this software and its 
14 documentation for any purpose and without fee is hereby granted, 
15 provided that the above copyright notice appear in all copies and that
16 both that copyright notice and this permission notice appear in 
17 supporting documentation, and that the name of IBM not be
18 used in advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.  
20
21 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
22 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
23 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
24 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
25 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
26 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
27 SOFTWARE.
28 ******************************************************************/
29 /* $ACIS: $ */
30
31 /* ALSO utimes and strip the file
32
33 Generic install command.  Options are:
34         -s              strip the file  (default for executable files with no extension)
35         -ns             do not strip the file   (default for other files)
36         -c              ignored for compatability
37         -m <mode>       chmod to this value
38         -o <user>       chown to this user
39         -g <group>      chgrp to this group
40         -f              target path is a file
41         -q              be very, very quick and quiet
42         -l <envcwd>     attempt symbolic link back from destination to source
43                         with the current directory in the specified environment
44                         variable
45 */
46
47 #define MAXFILES 200
48 #define BUFSIZE 32768
49 #include <afsconfig.h>
50 #include <afs/param.h>
51
52 RCSID("$Header$");
53
54 #include <stdio.h>
55 #include <pwd.h>
56 #include <grp.h>
57 #include <errno.h>
58 #ifdef  AFS_AIX32_ENV
59 #include <signal.h>
60 #endif
61 #include <sys/types.h>
62 #include <sys/stat.h>
63 #include <sys/file.h>
64 #include <sys/time.h>
65 #ifdef  AFS_SUN5_ENV
66 #include <fcntl.h>
67 #include <string.h>
68 #include <elf.h>
69 #else
70 #ifdef AFS_DARWIN_ENV
71 #include <fcntl.h>
72 #include <string.h>
73 #else
74 #include <strings.h>
75 #include <a.out.h>
76 #endif
77 #endif
78 #ifdef  AFS_HPUX_ENV
79 #include <utime.h>
80 #endif
81 #include <unistd.h>
82 #include <string.h>
83 #include <sys/wait.h>
84 #include <stdlib.h>
85 #ifdef HAVE_PWD_H
86 #include <pwd.h>
87 #endif
88 #include <stdio.h>
89
90 static struct stat istat, ostat;
91 static int stripcalled = 0;
92
93 #if !defined(AFS_DARWIN60_ENV) && !defined(AFS_FBSD50_ENV)
94 extern int sys_nerr;
95 #endif
96 #if !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
97 extern char *sys_errlist[];
98 #endif
99
100 /* static prototypes */
101 char *ErrorString(int aerrno);
102 int stripName(char *aname);
103 int atoo(register char *astr);
104
105
106 #if defined(AFS_HPUX_ENV) && !defined(AFS_HPUX102_ENV)
107 int utimes(char *file, struct timeval tvp[2])
108 {
109         struct utimbuf times;
110         
111         times.actime = tvp[0].tv_sec;
112         times.modtime = tvp[1].tv_sec;
113         return (utime(file,&times));
114 }
115 #endif
116
117 static char *strrpbrk (char *s, char *set)
118 {
119     char sets[256];
120     int  i;
121
122     memset(sets, 0, sizeof(sets));
123     while (*set) sets[(int) *set++] = 1;
124     i = strlen (s);
125     while (i > 0) if (sets[(int)s[--i]]) return &s[i];
126     return 0;
127 }
128
129 char *ErrorString(int aerrno)
130 {
131     static char tbuffer[100];
132     if (aerrno < 0 || aerrno >= sys_nerr) {
133         sprintf(tbuffer, "undefined error code %d", aerrno);
134     } else {
135         strcpy(tbuffer, sys_errlist[aerrno]);
136     }
137     return tbuffer;
138 }
139
140 int stripName(char *aname)
141 {
142     if (strrchr(aname, '.') == 0) return 1;
143     else return 0;
144 }
145
146 int atoo(register char *astr)
147 {
148     register afs_int32 value;
149     register char tc;
150     value = 0;
151     while ((tc = *astr++))
152         {value <<= 3;
153         value += tc-'0';
154         }
155     return value;
156 }
157
158 #if     defined(AFS_HPUX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_DECOSF_ENV) || defined(AFS_SGI_ENV) || defined(AFS_LINUX20_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_OBSD_ENV) || defined(AFS_NBSD_ENV)
159 /*
160  * Implementation lifted from that for AIX 3.1, since there didn't seem to be any
161  * reason why it wouldn't work.
162  */
163 static int quickStrip (char *iname, char *oname, int ignored, int copy_only)
164 {
165         int pid;
166         pid_t status;
167         static char *strip[] = {
168                 "strip", 0, 0,
169         };
170         static char *copy[] = {
171                 "cp", 0, 0, 0,
172         };
173         
174         /*
175          * first, copy the `iname' to the `oname'
176          */
177         switch (pid = fork()) {
178             case -1:                    /* error        */
179                 perror("fork");
180                 return -1;
181
182             case 0:                     /* child        */
183                 copy[1] = iname;
184                 copy[2] = oname;
185                 execve("/bin/cp", copy, NULL);
186                 perror("/bin/cp");
187                 exit(1);
188
189             default:                    /* parent       */
190                 if (waitpid(pid, &status, 0) != pid && errno != ECHILD) {
191                         perror("waitpid");
192                         return -1;
193                 }
194         }
195
196         if (status != 0) {
197                 fprintf(stderr, "Bad exit code from /bin/cp: %d\n", status);
198                 return -1;
199         }
200
201         /*
202          * need to do a chmod to guarantee that the perms will permit
203          * the strip.  Perms are fixed up later.
204          */
205         if (chmod(oname, 0700)) {
206                 perror("chmod");
207                 return -1;
208         }
209
210 #if !defined(AFS_OBSD_ENV) && !defined(AFS_NBSD_ENV)
211         /*
212          * done the copy, now strip if desired.
213          */
214         if (copy_only)
215                 return 0;
216
217         switch (pid = fork()) {
218             case -1:                    /* error        */
219                 perror("fork");
220                 return -1;
221
222             case 0:                     /* child        */
223                 strip[1] = oname;
224 #ifdef  AFS_SUN5_ENV
225 #define STRIP_BIN       "/usr/ccs/bin/strip"
226 #elif defined(AFS_LINUX20_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
227 #define STRIP_BIN       "/usr/bin/strip"
228 #else
229 #define STRIP_BIN       "/bin/strip"
230 #endif
231                 execve(STRIP_BIN, strip, NULL);
232                 perror(STRIP_BIN);
233                 exit(1);
234
235             default:                    /* parent       */
236                 if (waitpid(pid, &status, 0) != pid && errno != ECHILD) {
237                         perror("waitpid");
238                         return -1;
239                 }
240         }
241 #endif
242
243         return status;
244 }
245
246 #else
247 #ifdef AFS_AIX_ENV
248 #ifdef AFS_AIX32_ENV
249 /*
250  * whoa! back up and be a little more rational (every little bit helps in
251  * aix_31).
252  */
253 static int quickStrip (char *iname, char *oname, int ignored, int copy_only)
254 {
255         int pid, status;
256         static char *strip[] = {
257                 "strip", 0, 0,
258         };
259         static char *copy[] = {
260                 "cp", 0, 0, 0,
261         };
262
263         /*
264          * first, copy the `iname' to the `oname'
265          */
266         switch (pid = fork()) {
267             case -1:                    /* error        */
268                 perror("fork");
269                 return -1;
270
271             case 0:                     /* child        */
272                 copy[1] = iname;
273                 copy[2] = oname;
274                 execve("/bin/cp", copy, 0);
275                 perror("/bin/cp");
276                 exit(1);
277
278             default:                    /* parent       */
279                 if (waitpid(pid, &status, 0) != pid && errno != ECHILD) {
280                         perror("waitpid");
281                         return -1;
282                 }
283         }
284
285         if (status != 0) {
286                 fprintf(stderr, "Bad exit code from /bin/cp: %d\n", status);
287                 return -1;
288         }
289
290         /*
291          * need to do a chmod to guarantee that the perms will permit
292          * the strip.  Perms are fixed up later.
293          */
294         if (chmod(oname, 0700)) {
295                 perror("chmod");
296                 return -1;
297         }
298
299         /*
300          * done the copy, now strip if desired.
301          */
302         if (copy_only)
303                 return 0;
304
305         switch (pid = fork()) {
306             case -1:                    /* error        */
307                 perror("fork");
308                 return -1;
309
310             case 0:                     /* child        */
311                 strip[1] = oname;
312                 execve("/bin/strip", strip, 0);
313                 perror("/bin/strip");
314                 exit(1);
315
316             default:                    /* parent       */
317                 if (waitpid(pid, &status, 0) != pid && errno != ECHILD) {
318                         perror("waitpid");
319                         return -1;
320                 }
321         }
322
323         return status;
324 }
325
326 #endif  /* AFS_AIX32_ENV        */
327 #else   /* !AFS_AIX_ENV         */
328
329 #ifdef  mips
330 #include "sex.h"
331 int quickStrip(int fd, afs_int32 asize)
332 {
333     FILHDR fheader;
334     int dum, newlen;
335     int mysex, swapheader;
336     
337     /* Read the file header, if it is one. */
338     if (lseek(fd, 0, L_SET) == -1) {
339         printf("Initial lseek failed while stripping file: %s\n", ErrorString(errno));
340         return -1;
341     }
342     dum = read(fd, (char *) &fheader, sizeof(fheader));
343     /* Fail on I/O error */
344     if (dum < 0) {
345         printf("Initial read failed while stripping: %s\n", ErrorString(errno)); 
346         return -1;
347     }
348     /* If the file is smaller than a file header, forget it. */
349     if (dum != sizeof(fheader)) return 0;
350 #ifdef AFS_DECOSF_ENV
351     mysex = LITTLEENDIAN;
352 #else
353     mysex = gethostsex();
354     if (mysex != BIGENDIAN && mysex != LITTLEENDIAN) return 0;
355 #endif /* DEC OSF */
356     swapheader = 0;
357     if (fheader.f_magic == MIPSELMAGIC) {
358         if (mysex == BIGENDIAN) swapheader = 1;
359     } else if (fheader.f_magic == MIPSEBMAGIC) {
360         if (mysex == LITTLEENDIAN) swapheader = 1;
361     } else return 0;    /* not executable */
362 #ifdef AFS_DECOSF_ENV
363     if (swapheader) return 0;
364 #else
365     if (swapheader) swap_filehdr(&fheader, gethostsex());
366 #endif /* DEC OSF */
367     /* Already stripped? */
368     if (fheader.f_symptr == 0 || fheader.f_nsyms == 0) return 0;
369     /* Strip it.  Zero out the symbol pointers. */
370     newlen = fheader.f_symptr;
371     fheader.f_symptr = 0;
372     fheader.f_nsyms = 0;
373 #ifndef AFS_DECOSF_ENV
374     if (swapheader) swap_filehdr(&fheader, gethostsex());
375 #endif /* DEC OSF */
376     if (lseek(fd, 0, L_SET) == -1) return -1;
377     if (write(fd, (char *) &fheader, sizeof(fheader)) != sizeof(fheader)) return -1;
378 /* Now truncate the file itself. */
379     if (ftruncate(fd, newlen) != 0) return -1;
380     return 0;
381 }
382 #else /* !mips */
383 static int quickStrip (int afd, afs_int32 asize)
384 {
385     int n, bytesLeft;
386     struct exec buf;
387     struct exec *head;
388     n = lseek(afd, 0, 0);
389     if (n < 0) {printf("Initial lseek failed while stripping file: %s\n", ErrorString(errno)); return -1;}
390     n = read(afd, &buf, sizeof(buf));
391     if (n < 0) {printf("Initial read failed while stripping: %s\n", ErrorString(errno)); return -1;}
392     head = &buf;
393     if (n >= sizeof(*head) && !N_BADMAG(*head))
394         {/* This code lifted from strip.c. */
395         bytesLeft = (afs_int32) head->a_text + head->a_data;
396         head->a_syms = head->a_trsize = head->a_drsize = 0;
397         if (head->a_magic == ZMAGIC)
398             bytesLeft += N_TXTOFF(*head) - sizeof(*head);
399         /* also include size of header */
400         bytesLeft += sizeof(*head);
401         n = lseek(afd, 0, 0);
402         if (n < 0) {printf("lseek failed while stripping file: %s\n", ErrorString(errno)); return -1;}
403         n = write(afd, &buf, sizeof(buf));
404         if (n < 0) {printf("write failed while stripping file: %s\n", ErrorString(errno)); return -1;}
405         }
406     else
407         bytesLeft = 0;
408
409      /* check if size of stripped file is same as existing file */
410      if (bytesLeft != 0 && bytesLeft != asize)
411         {if (ftruncate(afd, bytesLeft) < 0)
412             {printf("ftruncate failed after stripping file: %s\n", ErrorString(errno)); return -1;}
413         }
414     return 0;
415     }
416 #endif /* mips */
417 #endif
418 #endif /* AFS_HPUX_ENV */
419
420 #include "AFS_component_version_number.c"
421
422 int main (int argc, char *argv[])
423 {
424     int setOwner, setMode, setGroup, ifd, ofd;
425     afs_int32 mode=0, owner, group;
426     struct passwd *tpw;
427     struct group *tgp;
428     char *fnames[MAXFILES], *newNames[MAXFILES];
429     afs_int32 rcode, code;
430     char *dname;
431     char pname[1024];
432 #if defined (AFS_HPUX_ENV)
433     char pnameBusy[1024];
434 #endif /* AFS_HPUX_ENV */
435     char pnametmp[1024];
436     int pnamelen;
437     afs_int32 newcode;
438     static char diskBuffer[BUFSIZE];    /* must be static to avoid compiler bugs for large stuff */
439     char myHostName[100];
440     struct timeval tvp[2];
441     int isDir;
442     int strip;
443     int fptr;
444     register char *tp;
445     register afs_int32 i;
446
447 #ifdef  AFS_AIX32_ENV
448     /*
449      * The following signal action for AIX is necessary so that in case of a 
450      * crash (i.e. core is generated) we can include the user's data section 
451      * in the core dump. Unfortunately, by default, only a partial core is
452      * generated which, in many cases, isn't too useful.
453      */
454     struct sigaction nsa;
455     
456     sigemptyset(&nsa.sa_mask);
457     nsa.sa_handler = SIG_DFL;
458     nsa.sa_flags = SA_FULLDUMP;
459     sigaction(SIGSEGV, &nsa, NULL);
460 #endif
461     fptr = 0;
462     rcode = 0;
463     strip = -1; /* don't know yet */
464     owner = 0;
465     setOwner = 0;
466     setMode = 0;
467     group = 0;
468     setGroup = 0;
469     isDir = -1;                         /* don't know yet */
470
471     for(i=1; i<argc; i++)
472         {tp = argv[i];
473         if (tp[0] == '-')
474             {/* a switch */
475             if (!strcmp(tp, "-m")) mode = atoo(argv[++i]), setMode=1;
476             else if (!strcmp(tp, "-s")) strip = 1;
477             else if (!strcmp(tp, "-ns")) strip = 0;
478             else if (!strcmp(tp, "-c")) /* nothing */;
479             else if (!strcmp(tp, "-f")) isDir = 0; /* => dest is file */
480             else if (!strcmp(tp, "-o"))
481                 {/* look up the dude */
482                 tpw = getpwnam(argv[++i]);
483                 if (!tpw)
484                     {printf("User %s not found in passwd database, ignored\n", argv[i]);
485                     }
486                 else
487                     {owner = tpw->pw_uid;
488                     setOwner =1;
489                     }
490                 }
491             else if (!strcmp(tp, "-g"))
492                 {/* look up the dude */
493                 tgp = getgrnam(argv[++i]);
494                 if (!tgp)
495                     {printf("Group %s not found in passwd database; ignored\n", argv[i]);
496                     }
497                 else
498                     {group = tgp->gr_gid;
499                     setGroup =1;
500                     }
501                 }
502                 else {
503                     printf("Bad switch %s\n", argv[i]);
504                     exit (1);
505                 }
506             }
507         else
508             {/* a file name */
509             if (fptr >= MAXFILES)
510                 {printf("Too many files on command line, max is %d\n", MAXFILES);
511                 exit(1);
512                 }
513             fnames[fptr++] = argv[i];
514             }
515         }
516
517     /* we've parse the commands, now *do* them */
518
519     /* otherwise we are doing a local install, so we do the work for each file
520        here the last name in the fname array is the dir in which to put all
521        this stuff */
522
523     if (fptr < 2)
524         {printf("Not enough file names\n");
525         exit(1);
526         }
527
528     /* N file usage requires last argument to be a directory.  If -f was
529        specified it is an error.  In the 2 file usage when -f is not specified
530        use a heuristic.  If the ends of the two pathnames are equal then assume
531        the target is a file, otherwise assume it is a directory. */
532
533     if ((fptr > 2) && (isDir == 0)) {
534         printf ("target must be a directory, don't use multiple source files with -f switch\n");
535         exit (1);
536     }
537     else if (fptr > 2) isDir = 1;
538     else if (isDir != 0) {
539         char *targetSuffix;
540         char *sourceSuffix;
541
542         targetSuffix = strrpbrk (fnames[1], "./");
543         sourceSuffix = strrpbrk (fnames[0], "./");
544         if (sourceSuffix == 0) {
545             sourceSuffix = fnames[0];
546             if (targetSuffix == 0) targetSuffix = fnames[1];
547             else targetSuffix++;
548         }
549         else if (targetSuffix == 0) targetSuffix = fnames[1];
550         if (strcmp(targetSuffix, sourceSuffix) == 0) isDir = 0;
551     }
552
553     dname = fnames[--fptr];
554     if (stat(dname, &istat) < 0) {
555         if ((errno == ENOENT) || (errno == ENOTDIR)) {
556             /* create path */
557             char protopath[BUFSIZ];
558             int  i = 0;
559             char c;
560             while (dname[i]) {
561                 do {
562                     protopath[i] = dname[i];
563                     c = dname[++i];     /* next char */
564                 } while (!((c == 0) || (c == '/')));
565                 protopath[i] = 0;
566
567                 /* don't mkdir last component if target is a file */
568                 if ((c == 0) && (isDir == 0)) break;
569
570                 /* else create dir component if it doesn't exist */
571                 code = stat(protopath, &istat);
572                 if (code && (errno == ENOENT)) {
573                     code = mkdir (protopath, 0755);
574                     if (code) {
575                         printf ("Can't create destination path at %s\n",
576                                 protopath);
577                         exit (1);
578                     }
579                 }
580             } /* while dname not exhausted */
581             if (isDir == -1) isDir = 1;
582         }
583         else {
584             printf("Can't stat destination ``%s'': %s\n", dname, ErrorString(errno));
585             exit(1);
586         }
587     } else {
588         if ((istat.st_mode & S_IFMT) == S_IFDIR)  isDir = 1;
589         else isDir = 0;
590     }
591
592     /* either can be n files and one dir, or one file and one target */
593     if (!isDir && fptr != 1) {
594         printf("target for multiple files must be a dir\n");
595         exit (1);
596     }
597
598     for (i=0;i<fptr;i++)
599         {/* figure out name to put as entry name for file */
600         tp = strrchr(fnames[i], '/');
601         if (tp) newNames[i] = tp+1;
602         else newNames[i] = fnames[i];
603         }
604     for (i=0;i<fptr;i++)
605         {/* copy newName[i] into directory dname */
606
607         /* pname is target file in either case */
608         if (isDir)
609             {strcpy(pname, dname);
610             strcat(pname, "/");
611             strcat(pname, newNames[i]);
612             }
613         else strcpy(pname, dname);
614         strcpy(pnametmp, pname);
615         /* Make up a temporary name for a destination */
616         pnamelen = strlen(pnametmp);
617         gethostname(myHostName, sizeof(myHostName)-1);  /* lv room for null */
618         if (pnamelen > 1020 - strlen(myHostName)) pnamelen = 1020 - strlen(myHostName);
619         pnametmp[pnamelen] = '.';
620         strcpy(&pnametmp[pnamelen+1], myHostName);
621         if (strcmp(fnames[i], pnametmp) == 0) strcpy(&pnametmp[pnamelen], ".NeW");
622
623         ifd = open(fnames[i], O_RDONLY, 0);
624         if (ifd < 0)
625             {printf("Can't open source file ``%s'': %s\n", fnames[i], ErrorString(errno));
626             rcode = 1;
627             continue;
628             }
629         if (fstat (ifd, &istat) < 0) {
630             printf("Cound not fstat input file ``%s'': %s; skipping it\n", fnames[i], ErrorString(errno));
631             close(ifd);
632             rcode = 1;
633             continue;
634         }
635         if (lstat(pname, &ostat) == 0) {
636             if ((ostat.st_size == istat.st_size) &&
637                 (ostat.st_mtime == istat.st_mtime) &&
638                 ((!setMode) || ((ostat.st_mode & S_IFMT) == mode)) &&
639                 ((!setOwner) || (ostat.st_uid == owner)) &&
640                 ((!setGroup) || (ostat.st_gid == group))) {
641                 close(ifd);
642                 printf("No changes to %s since %s installed\n", fnames[i], pname);
643                 continue;
644             }
645         }
646 #if     defined(AFS_AIX_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_DECOSF_ENV) || defined(AFS_SGI_ENV) || defined(AFS_LINUX20_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_OBSD_ENV) || defined(AFS_NBSD_ENV)
647         stripcalled = 0;
648         if (strip == 1 ||
649             ((strip == -1 && ((istat.st_mode & 0111) == 0111) && stripName(newNames[i]))))
650             stripcalled = 1;
651         if (!stripcalled) {
652             /* Simply copy target to dest */
653             quickStrip(fnames[i], pnametmp, istat.st_size, 1);
654         } else {
655             if (quickStrip(fnames[i],pnametmp,istat.st_size, 0) < 0) {
656                 printf("...strip failed for output temp file ``%s''; skipping it\n", pnametmp);
657                 close(ifd); unlink(pnametmp);
658                 rcode = 1;
659                 continue;
660             }
661         }
662         close(ifd);
663
664         ofd = open(pnametmp, O_RDWR, 0);
665         if (ofd < 0) {
666             printf("Could not open output temp file ``%s'': %s\n", pnametmp, ErrorString(errno));
667             close(ifd);
668             rcode = 1;
669             continue;
670         }
671         if (!setMode) mode = istat.st_mode;     /* Was 0755:> this is the default for our rcs to work */
672 #else /* AFS_AIX_ENV */
673         /* check to see if this file is hard to duplicate */
674         ofd = open(pnametmp, O_RDWR | O_TRUNC | O_CREAT, 0666);
675         if (ofd < 0)
676             {printf("Could not create output temp file ``%s'': %s\n", pnametmp, ErrorString(errno));
677             close(ifd);
678             rcode = 1;
679             continue;
680             }
681         if (!setMode) mode = istat.st_mode;     /* Was 0755:> this is the default for our rcs to work */
682         /* here both files are open and ready to go */
683         while (1)
684             {code = read(ifd, diskBuffer, BUFSIZE);
685             if (code == 0) break;
686             if (code < 0)
687                 {printf("READ ERROR %d: %s\n", errno, ErrorString(errno));
688                 break;
689                 }
690             errno = 0;
691             newcode = write(ofd, diskBuffer, code);
692             if (newcode != code)
693                 {printf("WRITE ERROR %d: %s\n", errno, ErrorString(errno));
694                 break;
695                 }
696             }
697         if (code != 0)
698             {rcode = 1; /* an error occurred copying the file */
699              printf("Warning: Error occurred writing output temp file %s; skipping it\n",
700                          pnametmp);
701             close(ifd); unlink(pnametmp); close(ofd);
702             continue;   /* to the next file */
703             }
704         /* strip the file? */
705         if (strip == 1 ||
706             (strip == -1 && ((istat.st_mode & 0111) == 0111) && stripName(newNames[i])))
707                 if (quickStrip(ofd,istat.st_size) < 0) {
708                     printf("...strip failed for output temp file ``%s''; skipping it\n", pnametmp);
709                     close(ifd); unlink(pnametmp);
710                     rcode = 1;
711                     continue;
712                 }
713
714         /* do the chmod, etc calls before closing the file for max parallelism on store behind */
715         close(ifd);
716
717 #endif /* AFS_AIX_ENV */
718         if (fchmod(ofd, mode) < 0)
719             {printf("Couldn't chmod output temp file ``%s'': %s\n",
720                         pnametmp, ErrorString(errno));
721             unlink(pnametmp); close(ofd);
722             rcode = 1;
723             continue;
724             }
725
726         tvp[0].tv_sec = istat.st_atime;
727         tvp[0].tv_usec = 0;
728         tvp[1].tv_sec = istat.st_mtime;
729         tvp[1].tv_usec = 0;
730         if (utimes(pnametmp, tvp) < 0)
731             {printf("Couldn't utimes output temp file ``%s'': %s\n",
732                         pnametmp, ErrorString(errno));
733             unlink(pnametmp); close(ofd);
734             rcode = 1;
735             continue;
736             }
737         code = close(ofd);
738         if (code != 0)
739             {printf("Warning: Could not close output temp file %s (%s)\n",
740                         pnametmp, ErrorString(errno));
741             unlink(pnametmp);
742             rcode = 1;  /* an error occurred closing the output file */
743             continue;   /* to the next file */
744             }
745
746         /* do this later so vice doesn't see chown of unstored file */
747         if (setOwner || setGroup)
748             if (chown(pnametmp, (setOwner? owner : -1), (setGroup? group : -1)) < 0) {
749                 printf("Couldn't set %s for output temp file %s: %s\n",
750                         (setOwner? (setGroup? "owner and group" : "owner") : "group"),
751                         pnametmp, ErrorString(errno));
752                 unlink(pnametmp);
753                 rcode = 1;
754                 continue;
755             }
756
757         if (rename(pnametmp, pname) < 0) {
758 #if defined(AFS_HPUX_ENV)
759           if (errno == ETXTBSY) {
760             (void)strcpy(pnameBusy, pname);
761             (void)strcat(pnameBusy, ".BUSY");
762             if (rename(pname, pnameBusy) == 0) {
763               fprintf(stdout, "Had to leave old file: %s.\n", pnameBusy);
764               fprintf(stdout,
765                     "Please delete this file when the program using it is finished.\n");
766               if (rename(pnametmp, pname) < 0) {
767 #endif /* AFS_HPUX_ENV */
768
769               printf("Couldn't rename temp file %s to be output file %s: %s\n",
770                      pnametmp, pname, ErrorString(errno));
771               unlink(pnametmp);
772               rcode = 1;
773               continue;
774
775 #if defined(AFS_HPUX_ENV)
776               }
777             }
778             else {
779               fprintf(stderr,
780                 "Couldn't move busy target file %s to make room for new version %s: %s\n",
781                       pname, pnametmp, ErrorString(errno));
782               if (errno == ETXTBSY) {
783                 fprintf(stderr,
784                     "Try terminating any programs using the file %s and then re-run %s.\n",
785                         pnameBusy, argv[0]);
786               }
787               unlink(pnametmp);
788               rcode = 1;
789               continue;
790             }
791           }
792 #endif /* AFS_HPUX_ENV */
793         }
794       }
795     /* all done now */
796     exit(rcode);
797 }