1 /* @(#)util.c 1.42 21/07/22 2011-2020 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)util.c 1.42 21/07/22 2011-2020 J. Schilling";
6 #endif
7 /*
8 * Copyright (c) 1986 Larry Wall
9 * Copyright (c) 2011-2020 J. Schilling
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following condition is met:
13 *
14 * 1. Redistributions of source code must retain the above copyright notice,
15 * this condition and the following disclaimer.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #define EXT extern
31 #include "common.h"
32 #undef EXT
33 #define EXT
34 #include "util.h"
35 #include <schily/varargs.h>
36 #include <schily/errno.h>
37 #include <schily/wait.h>
38 #define VMS_VFORK_OK
39 #include <schily/vfork.h>
40
41 #ifndef HAVE_STRERROR
42 #define strerror errmsgstr
43 #endif
44
45 static int fetchtime __PR((char *t, dtime_t *));
46 static void sig_exit __PR((int signo));
47 static int wday __PR((char *d));
48 static int month __PR((char *m));
49 static int fetchtz __PR((char *t));
50 static int fetchctime __PR((char *t, dtime_t *));
51
52 /* Rename a file, copying it if necessary. */
53
54 int
move_file(from,to)55 move_file(from, to)
56 char *from;
57 char *to;
58 {
59 char bakname[512];
60 char *s;
61 int i;
62 int fromfd;
63
64 /* to stdout? */
65
66 if (from && strEQ(to, "-")) {
67 #ifdef DEBUGGING
68 if (debug & 4)
69 say(_("Moving %s to stdout.\n"), from);
70 #endif
71 fromfd = open(from, O_RDONLY);
72 if (fromfd < 0) {
73 pfatal(_("internal error, can't reopen %s\n"),
74 from);
75 }
76 /*
77 * For file copy operations, we use the minimal buf size that
78 * is better aligned.
79 */
80 while ((i = read(fromfd, buf, BUFFERSIZE)) > 0)
81 if (write(STDOUT_FILENO, buf, i) != i)
82 pfatal(_("write failed\n"));
83 Close(fromfd);
84 return (0);
85 }
86
87 if (origprae) {
88 Strcpy(bakname, origprae);
89 Strcat(bakname, to);
90 } else {
91 Strcpy(bakname, to);
92 Strcat(bakname, origext?origext:ORIGEXT);
93 }
94 if (do_backup &&
95 stat(to, &file_stat) >= 0) { /* output file exists */
96 dev_t to_device = file_stat.st_dev;
97 ino_t to_inode = file_stat.st_ino;
98 char *simplename = bakname;
99
100 for (s = bakname; *s; s++) {
101 if (*s == '/')
102 simplename = s+1;
103 }
104 /* find a backup name that is not the same file */
105 file_stat.st_ctime = (time_t)0;
106 while (stat(bakname, &file_stat) >= 0 &&
107 to_device == file_stat.st_dev &&
108 to_inode == file_stat.st_ino) {
109 if (file_stat.st_ctime >= starttime) /* mult patches */
110 goto backup_done;
111 for (s = simplename; *s && !islower(UCH *s); s++) {
112 ;
113 /* LINTED */
114 }
115 if (*s)
116 *s = toupper(*s);
117 else
118 Strcpy(simplename, simplename+1);
119 }
120 if (file_stat.st_ctime >= starttime) /* mult patches */
121 goto backup_done;
122 while (unlink(bakname) >= 0) { /* while() is for Eunice */
123 ;
124 /* LINTED */
125 }
126 #ifdef DEBUGGING
127 if (debug & 4)
128 say(_("Moving %s to %s.\n"), to, bakname);
129 #endif
130 if (rename(to, bakname) < 0) {
131 say(_("patch: can't backup %s, output is in %s\n"),
132 to, from);
133 return (-1);
134 }
135 }
136 backup_done:
137 if (from == NULL) {
138 if (!do_backup) {
139 if (debug & 4)
140 say(_("Removing file %s\n"), to);
141 if (unlink(to) != 0 && errno != ENOENT)
142 pfatal(_("Can't remove file %s\n"), to);
143 }
144 return (0);
145 }
146 #ifdef DEBUGGING
147 if (debug & 4)
148 say(_("Moving %s to %s.\n"), from, to);
149 #endif
150 if (rename(from, to) < 0) { /* different file system? */
151 int tofd;
152
153 unlink(to); /* to may be a readonly file */
154 tofd = creat(to, 0666);
155 if (tofd < 0) {
156 say(_("patch: can't create %s, output is in %s.\n"),
157 to, from);
158 return (-1);
159 }
160 fromfd = open(from, O_RDONLY);
161 if (fromfd < 0) {
162 pfatal(_("internal error, can't reopen %s\n"),
163 from);
164 }
165 /*
166 * For file copy operations, we use the minimal buf size that
167 * is better aligned.
168 */
169 while ((i = read(fromfd, buf, BUFFERSIZE)) > 0)
170 if (write(tofd, buf, i) != i)
171 pfatal(_("write failed\n"));
172 Close(fromfd);
173 Close(tofd);
174 }
175 Unlink(from);
176 return (0);
177 }
178
179 void
removedirs(path)180 removedirs(path)
181 char *path;
182 {
183 char *p = strrchr(path, '/');
184
185 if (p == NULL)
186 return;
187 while (p > path) {
188 *p = '\0';
189 if (rmdir(path) == 0 && verbose)
190 say(_("Removed empty directory %s\n"),
191 path);
192 *p = '/';
193 while (--p > path) {
194 if (*p == '/')
195 break;
196 }
197 }
198 }
199
200 /* Copy a file. */
201
202 void
copy_file(from,to)203 copy_file(from, to)
204 char *from;
205 char *to;
206 {
207 int tofd;
208 int fromfd;
209 int i;
210
211 tofd = creat(to, 0666);
212 if (tofd < 0)
213 pfatal(_("can't create %s.\n"), to);
214 fromfd = open(from, O_RDONLY);
215 if (fromfd < 0)
216 pfatal(_("internal error, can't reopen %s\n"), from);
217 /*
218 * For file copy operations, we use the minimal buf size that
219 * is better aligned.
220 */
221 while ((i = read(fromfd, buf, BUFFERSIZE)) > 0)
222 if (write(tofd, buf, i) != i)
223 pfatal(_("write (%s) failed\n"), to);
224 Close(fromfd);
225 Close(tofd);
226 }
227
228 /* Allocate a unique area for a string. */
229
230 char *
savestr(s)231 savestr(s)
232 char *s;
233 {
234 char *rv;
235
236 if (!s)
237 s = "Oops";
238 rv = strdup(s);
239 if (rv == Nullch) {
240 if (using_plan_a) {
241 out_of_mem = TRUE;
242 } else {
243 pfatal(_("out of memory (savestr)\n"));
244 /* NOTREACHED */
245 }
246 }
247 return (rv);
248 }
249
250 /* Vanilla terminal output (buffered). */
251
252 /* VARARGS1 */
253 #ifdef PROTOTYPES
254 EXPORT void
say(const char * fmt,...)255 say(const char *fmt, ...)
256 #else
257 EXPORT void
258 say(fmt, va_alist)
259 char *fmt;
260 va_dcl
261 #endif
262 {
263 va_list args;
264
265 #ifdef PROTOTYPES
266 va_start(args, fmt);
267 #else
268 va_start(args);
269 #endif
270 #ifdef USE_VPRINTF
271 (void) vfprintf(stderr, fmt, args);
272 #else
273 (void) js_fprintf(stderr, "%r", fmt, args);
274 #endif
275 va_end(args);
276 Fflush(stderr);
277 }
278
279 /* Terminal output, pun intended. */
280
281 /* VARARGS1 */
282 #ifdef PROTOTYPES
283 EXPORT void
fatal(const char * fmt,...)284 fatal(const char *fmt, ...)
285 #else
286 EXPORT void
287 fatal(fmt, va_alist)
288 char *fmt;
289 va_dcl
290 #endif
291 {
292 va_list args;
293
294 #ifdef PROTOTYPES
295 va_start(args, fmt);
296 #else
297 va_start(args);
298 #endif
299 #ifdef USE_VPRINTF
300 (void) vfprintf(stderr, fmt, args);
301 #else
302 (void) js_fprintf(stderr, "%r", fmt, args);
303 #endif
304 va_end(args);
305 my_exit(EXIT_FAIL);
306 }
307
308
309 /* VARARGS1 */
310 #ifdef PROTOTYPES
311 EXPORT void
pfatal(const char * fmt,...)312 pfatal(const char *fmt, ...)
313 #else
314 EXPORT void
315 pfatal(fmt, va_alist)
316 char *fmt;
317 va_dcl
318 #endif
319 {
320 va_list args;
321 int errsav = errno;
322 char *err;
323 char errbuf[32];
324
325 err = strerror(errsav);
326 if (err == NULL) {
327 sprintf(errbuf, "Error %d", errsav);
328 err = errbuf;
329 }
330 #ifdef PROTOTYPES
331 va_start(args, fmt);
332 #else
333 va_start(args);
334 #endif
335 #ifdef USE_VPRINTF
336 (void) fprintf(stderr, "patch: %s. ", err);
337 (void) vfprintf(stderr, fmt, args);
338 #else
339 (void) js_fprintf(stderr, "patch: %s. %r", err, fmt, args);
340 #endif
341 va_end(args);
342 my_exit(EXIT_FAIL);
343 }
344
345
346 /* Get a response from the user, somehow or other. */
347
348 /* VARARGS1 */
349 #ifdef PROTOTYPES
350 EXPORT void
ask(const char * fmt,...)351 ask(const char *fmt, ...)
352 #else
353 EXPORT void
354 ask(fmt, va_alist)
355 char *fmt;
356 va_dcl
357 #endif
358 {
359 va_list args;
360 int ttyfd;
361 int r;
362 bool tty2 = isatty(STDERR_FILENO);
363
364 #ifdef PROTOTYPES
365 va_start(args, fmt);
366 #else
367 va_start(args);
368 #endif
369 #ifdef USE_VPRINTF
370 (void) vsprintf(buf, fmt, args);
371 #else
372 (void) js_sprintf(buf, "%r", fmt, args);
373 #endif
374 va_end(args);
375 Fflush(stderr);
376 write(STDERR_FILENO, buf, strlen(buf));
377 if (tty2) { /* might be redirected to a file */
378 r = read(STDERR_FILENO, buf, bufsize);
379 } else if (isatty(STDOUT_FILENO)) {
380 /* this may be new file output */
381 Fflush(stdout);
382 write(STDOUT_FILENO, buf, strlen(buf));
383 r = read(STDOUT_FILENO, buf, bufsize);
384 } else if ((ttyfd = open("/dev/tty", O_RDWR)) >= 0 && isatty(ttyfd)) {
385 /* might be deleted or unwriteable */
386 write(ttyfd, buf, strlen(buf));
387 r = read(ttyfd, buf, bufsize);
388 Close(ttyfd);
389 } else if (isatty(STDIN_FILENO)) {
390 /* this is probably patch input */
391 Fflush(stdin);
392 write(STDIN_FILENO, buf, strlen(buf));
393 r = read(STDIN_FILENO, buf, bufsize);
394 } else { /* no terminal at all--default it */
395 buf[0] = '\n';
396 r = 1;
397 }
398 if (r <= 0)
399 buf[0] = 0;
400 else
401 buf[r] = '\0';
402 if (!tty2)
403 say("%s", buf);
404 }
405
406 /* How to handle certain events when not in a critical region. */
407
408 void
set_signals(reset)409 set_signals(reset)
410 int reset;
411 {
412 static RETSIGTYPE (*hupval) __PR((int)), (*intval) __PR((int));
413
414 if (!reset) {
415 #ifdef SIGHUP
416 hupval = signal(SIGHUP, SIG_IGN);
417 if (hupval != SIG_IGN)
418 hupval = (RETSIGTYPE(*) __PR((int)))sig_exit;
419 #endif
420 intval = signal(SIGINT, SIG_IGN);
421 if (intval != SIG_IGN)
422 intval = (RETSIGTYPE(*) __PR((int)))sig_exit;
423 }
424 #ifdef SIGHUP
425 Signal(SIGHUP, hupval);
426 #endif
427 Signal(SIGINT, intval);
428 }
429
430 static void
sig_exit(signo)431 sig_exit(signo)
432 int signo;
433 {
434 my_exit(EXIT_SIGNAL);
435 }
436
437 /* How to handle certain events when in a critical region. */
438
439 void
ignore_signals()440 ignore_signals()
441 {
442 #ifdef SIGHUP
443 Signal(SIGHUP, SIG_IGN);
444 #endif
445 Signal(SIGINT, SIG_IGN);
446 }
447
448 /* Make sure we'll have the directories to create a file. */
449
450 #ifndef _SCHILY_SCHILY_H
451 #ifdef PROTOTYPES
452 int
makedirs(char * filename,mode_t mode,bool striplast)453 makedirs(char *filename, mode_t mode, bool striplast)
454 #else
455 int
456 makedirs(filename, mode, striplast)
457 char *filename;
458 mode_t mode;
459 bool striplast;
460 #endif
461 {
462 char tmpbuf[256];
463 char *s = tmpbuf;
464 char *dirv[20];
465 int i;
466 int dirvp = 0;
467
468 while (*filename) {
469 if (*filename == '/') {
470 filename++;
471 dirv[dirvp++] = s;
472 *s++ = '\0';
473 } else {
474 *s++ = *filename++;
475 }
476 }
477 *s = '\0';
478 dirv[dirvp] = s;
479 if (striplast)
480 dirvp--;
481 if (dirvp < 0)
482 return (0);
483 #if 1
484 for (i = 0; i <= dirvp; i++) {
485 mkdir(tmpbuf, mode);
486 #if 0
487 S_IRUSR|S_IWUSR|S_IXUSR
488 |S_IRGRP|S_IWGRP|S_IXGRP
489 |S_IROTH|S_IWOTH|S_IXOTH);
490 #endif
491 *dirv[i] = '/';
492 }
493 #else
494 strcpy(buf, "mkdir");
495 s = buf;
496 for (i = 0; i <= dirvp; i++) {
497 while (*s) s++;
498 *s++ = ' ';
499 strcpy(s, tmpbuf);
500 *dirv[i] = '/';
501 }
502 system(buf);
503 #endif
504 return (0);
505 }
506 #endif /* _SCHILY_SCHILY_H */
507
508 /* Make filenames more reasonable. */
509
510 char *
fetchname(at,strip_leading,assume_exists,dtp)511 fetchname(at, strip_leading, assume_exists, dtp)
512 char *at;
513 int strip_leading;
514 int assume_exists;
515 dtime_t *dtp;
516 {
517 char *s;
518 char *sn;
519 char *name;
520 char *t;
521 char tmpbuf[512];
522 dtime_t dt;
523
524 if (dtp == NULL)
525 dtp = &dt;
526 dtp->dt_sec = -1; /* Mark as illegal time */
527 dtp->dt_nsec = 0; /* Default to no nsecs */
528 dtp->dt_zone = DT_NO_ZONE; /* No timezone seen yet */
529
530 if (!at)
531 return (Nullch);
532 s = savestr(at);
533 for (t = s; isspace(UCH *t); t++) {
534 ;
535 /* LINTED */
536 }
537 sn = name = t;
538 #ifdef DEBUGGING
539 if (debug & 128)
540 say(_("fetchname %s %d %d\n"),
541 name, strip_leading, assume_exists);
542 #endif
543 for (; *t && !isspace(UCH *t); t++)
544 if (*t == '/')
545 if (--strip_leading >= 0)
546 name = t+1;
547 *t = '\0';
548 if (strEQ(sn, "/dev/null")) { /* files can be created by diffing */
549 dtp->dt_sec = 0; /* against /dev/null. */
550 free(s);
551 return (Nullch);
552 }
553 fetchtime(t, dtp);
554
555 /*
556 * If we could not strip the full number of directories and
557 * if we stripped off existing leading directories from a relative path
558 * use the unstipped full name.
559 */
560 if (strip_leading > 0 && name != s && *s != '/') {
561 name[-1] = '\0';
562 if (stat(s, &file_stat) == 0 && S_ISDIR(file_stat.st_mode)) {
563 name[-1] = '/';
564 name = s;
565 }
566 }
567 name = savestr(name);
568 Snprintf(tmpbuf, sizeof (tmpbuf), "RCS/%s", name);
569 free(s);
570 if (stat(name, &file_stat) < 0 && !assume_exists) {
571 Strcat(tmpbuf, RCSSUFFIX);
572 if (stat(tmpbuf, &file_stat) < 0 &&
573 stat(tmpbuf+4, &file_stat) < 0) {
574 Snprintf(tmpbuf, sizeof (tmpbuf), "SCCS/%s%s",
575 SCCSPREFIX, name);
576 if (stat(tmpbuf, &file_stat) < 0 &&
577 stat(tmpbuf+5, &file_stat) < 0) {
578 free(name);
579 name = Nullch;
580 }
581 }
582 }
583 return (name);
584 }
585
586 static int
wday(d)587 wday(d)
588 char *d;
589 {
590 char *days = "SunMonTueWedThuFriSat";
591 char day[4];
592 char *p;
593
594 strlcpy(day, d, 4);
595 p = strstr(days, day);
596 if (p == NULL)
597 return (-1);
598 return ((p - days) / 3);
599 }
600
601 static int
month(m)602 month(m)
603 char *m;
604 {
605 char *months = "JanFebMarAprMayJunJulAugSepOctNovDec";
606 char mon[4];
607 char *p;
608
609 strlcpy(mon, m, 4);
610 p = strstr(months, mon);
611 if (p == NULL)
612 return (-1);
613 return ((p - months) / 3);
614 }
615
616 static int
fetchtz(t)617 fetchtz(t)
618 char *t;
619 {
620 int n;
621 int h;
622 int m;
623
624 /*
625 * Skip until until the timezone offset field
626 */
627 for (; *t != '\0' && isspace(UCH *t); t++)
628 ;
629 /*
630 * Scan timezone hours and minutes
631 */
632 n = sscanf(t, "%3d%2d", &h, &m);
633 if (n != 2)
634 return (-1);
635 if (h < -24 || h > 25)
636 return (-1);
637 if (m < 0 || m > 59)
638 return (-1);
639 m += 60 * h;
640 m *= 60;
641 return (m);
642 }
643
644 /*
645 * Fetch a time that is in ctime() syntax.
646 * This is a format like: LC_ALL=C date "+%a %b %e %T %Y"
647 */
648 static int
fetchctime(t,dtp)649 fetchctime(t, dtp)
650 char *t;
651 dtime_t *dtp;
652 {
653 char y[10];
654 Llong d = -1;
655 struct tm tm;
656 int n;
657 char *ep = t + strlen(t);
658
659 for (; *t != '\0' && isspace(UCH *t); t++)
660 ;
661 n = wday(t);
662 if (n < 0)
663 return (-1);
664 tm.tm_wday = n;
665 t += 3;
666 if (t >= ep)
667 return (-1);
668 for (; *t != '\0' && isspace(UCH *t); t++)
669 ;
670 n = month(t);
671 if (n < 0)
672 return (-1);
673 tm.tm_mon = n;
674 t += 3;
675 if (t >= ep)
676 return (-1);
677 for (; *t != '\0' && isspace(UCH *t); t++)
678 ;
679 if (!isdigit(UCH *t))
680 return (-1);
681 n = atoi(t);
682 if (n < 1 || n > 31)
683 return (-1);
684 tm.tm_mday = n;
685 for (; *t != '\0' && isdigit(UCH *t); t++)
686 ;
687 for (; *t != '\0' && isspace(UCH *t); t++)
688 ;
689 n = sscanf(t, "%2d:%2d:%2d %4d",
690 &tm.tm_hour, &tm.tm_min, &tm.tm_sec,
691 &tm.tm_year);
692 if (n != 4)
693 return (-1);
694
695 /*
696 * Now check whether there is a timezone field.
697 * This may be present in case the diff has been created by
698 * a "hg export" call.
699 */
700 sprintf(y, " %d", tm.tm_year);
701 ep = strstr(t, y);
702 if (ep) {
703 ep += strlen(y);
704 n = fetchtz(ep);
705 } else {
706 n = -1;
707 }
708 tm.tm_year -= 1900;
709
710 tm.tm_isdst = -1;
711 if (n != -1) { /* Timezone string seen */
712 d = mklgmtime(&tm);
713 d -= n; /* Add timezone offset */
714 dtp->dt_zone = n;
715 } else if (touch_gmt) {
716 d = mklgmtime(&tm);
717 } else {
718 d = mktime(&tm);
719 }
720 dtp->dt_sec = d;
721 return (0);
722 }
723
724
725 static int mul[10] = { 0, 100000000, 10000000,
726 1000000, 100000, 10000,
727 1000, 100, 10,
728 1
729 };
730
731 static int
fetchtime(t,dtp)732 fetchtime(t, dtp)
733 char *t;
734 dtime_t *dtp;
735 {
736 Llong d = -1;
737 struct tm tm;
738 int n;
739 int m;
740
741 for (++t; *t != '\0' && isspace(UCH *t); t++)
742 ;
743 /*
744 * Check format from: LC_ALL=C date "+%a %b %e %T %Y"
745 */
746 if (wday(t) >= 0) {
747 return (fetchctime(t, dtp));
748 }
749 /*
750 * Parse format from: date '+%Y-%m-%d %H:%M:%S'
751 */
752 n = sscanf(t, "%4d-%2d-%2d %2d:%2d:%2d",
753 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
754 &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
755 tm.tm_year -= 1900;
756 tm.tm_mon -= 1;
757
758 if (n != 6)
759 return (-1);
760
761 if (strlen(t) <= 19) /* Assume time >= y1000 */
762 return (-1);
763
764 t += 19; /* Skip minimum length */
765
766 if (*t == '.') {
767 Llong frac = 0;
768 int dig = -1;
769
770 /*
771 * Convert fractions of a second.
772 */
773 for (++t; ++dig < 9 && *t != '\0' && isdigit(UCH *t); t++) {
774 frac *= 10;
775 frac += *t - '0';
776 }
777 frac *= mul[dig];
778 if (frac < 0 || frac > 999999999)
779 frac = 0;
780 dtp->dt_nsec = frac;
781 }
782 /*
783 * Skip rest of fractions of a second
784 */
785 for (; *t != '\0' && !isspace(UCH *t); t++)
786 ;
787
788 m = fetchtz(t);
789 if (m == -1) /* The diff -u time format requires a TZ */
790 return (m); /* Without, the whole format is invalid */
791 d = mklgmtime(&tm);
792 d -= m; /* Add timezone offset */
793 dtp->dt_sec = d;
794 dtp->dt_zone = m;
795 return (0);
796 }
797
798 int
settime(name,idx,failed)799 settime(name, idx, failed)
800 char *name;
801 int idx;
802 int failed;
803 {
804 int ret;
805 time_t t;
806 struct timespec tp[2];
807
808 /*
809 * Silently return if we have no "new" time.
810 */
811 if (file_times[idx].dt_sec == -1)
812 return (0);
813
814 /*
815 * If there is no old time stamp in the patch file, we do not verify
816 * the old time stamp.
817 */
818 t = file_times[!idx].dt_sec;
819 if (!force && t != -1 && filetime.tv_sec != t) {
820 say("Not setting time of file %s (time mismatch)\n", name);
821 return (-1);
822 }
823
824 /*
825 * We always verify the content.
826 */
827 if (!force && failed) {
828 say("Not setting time of file %s (contents mismatch)\n", name);
829 return (-1);
830 }
831
832 tp[0].tv_sec = file_times[idx].dt_sec;
833 tp[0].tv_nsec = file_times[idx].dt_nsec;
834 tp[1].tv_sec = file_times[idx].dt_sec;
835 tp[1].tv_nsec = file_times[idx].dt_nsec;
836
837 ret = utimensat(AT_FDCWD, name, tp, AT_SYMLINK_NOFOLLOW);
838 if (ret)
839 pfatal("Can't set timestamp on file %s", name);
840 return (ret);
841 }
842
843 typedef RETSIGTYPE (*sigtype) __PR((int));
844
845 int
pspawn(av)846 pspawn(av)
847 char *av[];
848 {
849 pid_t pid;
850 pid_t p;
851 int status;
852 sigtype sint;
853 sigtype squit;
854 #ifdef SIGCHLD
855 sigtype schld;
856 #endif
857
858 if ((pid = vfork()) == 0) {
859 execvp(av[0], av);
860 _exit(127);
861 }
862
863 sint = signal(SIGINT, SIG_IGN);
864 squit = signal(SIGQUIT, SIG_IGN);
865 #ifdef SIGCHLD
866 schld = signal(SIGCHLD, SIG_DFL);
867 #endif
868 while ((p = wait(&status)) != pid && p != (pid_t)-1)
869 ;
870 (void) signal(SIGINT, sint);
871 (void) signal(SIGQUIT, squit);
872 #ifdef SIGCHLD
873 (void) signal(SIGCHLD, schld);
874 #endif
875
876 if (p == (pid_t)-1)
877 return (-1);
878 return (status);
879 }
880