1 /* utility functions for `patch' */
2
3 /* $Id: util.c,v 1.24 1997/07/10 08:16:12 eggert Exp $ */
4
5 /*
6 Copyright 1986 Larry Wall
7 Copyright 1992, 1993, 1997 Free Software Foundation, Inc.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; see the file COPYING.
21 If not, write to the Free Software Foundation,
22 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 */
24
25 #define XTERN extern
26 #include <common.h>
27 #include <backupfile.h>
28 #include <quotearg.h>
29 #include <version.h>
30 #undef XTERN
31 #define XTERN
32 #include <util.h>
33
34 #include <maketime.h>
35 #include <partime.h>
36
37 #include <signal.h>
38 #if !defined SIGCHLD && defined SIGCLD
39 #define SIGCHLD SIGCLD
40 #endif
41 #if ! HAVE_RAISE
42 # define raise(sig) kill (getpid (), sig)
43 #endif
44
45 #ifdef __STDC__
46 # include <stdarg.h>
47 # define vararg_start va_start
48 #else
49 # define vararg_start(ap,p) va_start (ap)
50 # if HAVE_VARARGS_H
51 # include <varargs.h>
52 # else
53 typedef char *va_list;
54 # define va_dcl int va_alist;
55 # define va_start(ap) ((ap) = (va_list) &va_alist)
56 # define va_arg(ap, t) (((t *) ((ap) += sizeof (t))) [-1])
57 # define va_end(ap)
58 # endif
59 #endif
60
61 static void makedirs PARAMS ((char *));
62
63 /* Move a file FROM to TO, renaming it if possible and copying it if necessary.
64 If we must create TO, use MODE to create it.
65 If FROM is null, remove TO (ignoring FROMSTAT).
66 Back up TO if BACKUP is nonzero. */
67
68 #ifdef __STDC__
69 /* If mode_t doesn't promote to itself, we can't use old-style definition. */
70 void
move_file(char const * from,char * to,mode_t mode,int backup)71 move_file (char const *from, char *to, mode_t mode, int backup)
72 #else
73 void
74 move_file (from, to, mode, backup)
75 char const *from;
76 char *to;
77 mode_t mode;
78 int backup;
79 #endif
80 {
81 struct stat to_st;
82 int to_errno = ! backup ? -1 : stat (to, &to_st) == 0 ? 0 : errno;
83
84 if (backup)
85 {
86 int try_makedirs_errno = 0;
87 char *bakname;
88
89 if (origprae || origbase)
90 {
91 char const *p = origprae ? origprae : "";
92 char const *b = origbase ? origbase : "";
93 char const *o = base_name (to);
94 size_t plen = strlen (p);
95 size_t tlen = o - to;
96 size_t blen = strlen (b);
97 size_t osize = strlen (o) + 1;
98 bakname = xmalloc (plen + tlen + blen + osize);
99 memcpy (bakname, p, plen);
100 memcpy (bakname + plen, to, tlen);
101 memcpy (bakname + plen + tlen, b, blen);
102 memcpy (bakname + plen + tlen + blen, o, osize);
103 for (p += FILESYSTEM_PREFIX_LEN (p); *p; p++)
104 if (ISSLASH (*p))
105 {
106 try_makedirs_errno = ENOENT;
107 break;
108 }
109 }
110 else
111 {
112 bakname = find_backup_file_name (to);
113 if (!bakname)
114 memory_fatal ();
115 }
116
117 if (to_errno)
118 {
119 int fd;
120 if (debug & 4)
121 say ("creating empty unreadable file `%s'\n", bakname);
122 try_makedirs_errno = ENOENT;
123 unlink (bakname);
124 while ((fd = creat (bakname, 0)) < 0)
125 {
126 if (errno != try_makedirs_errno)
127 pfatal ("can't create file `%s'", bakname);
128 makedirs (bakname);
129 try_makedirs_errno = 0;
130 }
131 if (close (fd) != 0)
132 pfatal ("can't close `%s'", bakname);
133 }
134 else
135 {
136 if (debug & 4)
137 say ("renaming `%s' to `%s'\n", to, bakname);
138 while (rename (to, bakname) != 0)
139 {
140 if (errno != try_makedirs_errno)
141 pfatal ("can't rename `%s' to `%s'", to, bakname);
142 makedirs (bakname);
143 try_makedirs_errno = 0;
144 }
145 }
146
147 free (bakname);
148 }
149
150 if (from)
151 {
152 if (debug & 4)
153 say ("renaming `%s' to `%s'\n", from, to);
154
155 if (rename (from, to) != 0)
156 {
157 int to_dir_known_to_exist = 0;
158
159 if (errno == ENOENT
160 && (to_errno == -1 || to_errno == ENOENT))
161 {
162 makedirs (to);
163 to_dir_known_to_exist = 1;
164 if (rename (from, to) == 0)
165 return;
166 }
167
168 if (errno == EXDEV)
169 {
170 if (! backup)
171 {
172 if (unlink (to) == 0)
173 to_dir_known_to_exist = 1;
174 else if (errno != ENOENT)
175 pfatal ("can't remove `%s'", to);
176 }
177 if (! to_dir_known_to_exist)
178 makedirs (to);
179 copy_file (from, to, mode);
180 return;
181 }
182
183 pfatal ("can't rename `%s' to `%s'", from, to);
184 }
185 }
186 else if (! backup)
187 {
188 if (debug & 4)
189 say ("removing `%s'\n", to);
190 if (unlink (to) != 0)
191 pfatal ("can't remove `%s'", to);
192 }
193 }
194
195 /* Create FILE with OPEN_FLAGS, and with MODE adjusted so that
196 we can read and write the file and that the file is not executable.
197 Return the file descriptor. */
198 #ifdef __STDC__
199 /* If mode_t doesn't promote to itself, we can't use old-style definition. */
200 int
create_file(char const * file,int open_flags,mode_t mode)201 create_file (char const *file, int open_flags, mode_t mode)
202 #else
203 int
204 create_file (file, open_flags, mode)
205 char const *file;
206 int open_flags;
207 mode_t mode;
208 #endif
209 {
210 int fd;
211 mode |= S_IRUSR | S_IWUSR;
212 mode &= ~ (S_IXUSR | S_IXGRP | S_IXOTH);
213 if (! (O_CREAT && O_TRUNC))
214 close (creat (file, mode));
215 fd = open (file, O_CREAT | O_TRUNC | open_flags, mode);
216 if (fd < 0)
217 pfatal ("can't create `%s'", file);
218 return fd;
219 }
220
221 /* Copy a file. */
222
223 #ifdef __STDC__
224 /* If mode_t doesn't promote to itself, we can't use old-style definition. */
225 void
copy_file(char const * from,char const * to,mode_t mode)226 copy_file (char const *from, char const *to, mode_t mode)
227 #else
228 void
229 copy_file (from, to, mode)
230 char const *from;
231 char const *to;
232 mode_t mode;
233 #endif
234 {
235 int tofd;
236 int fromfd;
237 size_t i;
238
239 if ((fromfd = open (from, O_RDONLY | O_BINARY)) < 0)
240 pfatal ("can't reopen `%s'", from);
241 tofd = create_file (to, O_WRONLY | O_BINARY, mode);
242 while ((i = read (fromfd, buf, bufsize)) != 0)
243 {
244 if (i == -1)
245 read_fatal ();
246 if (write (tofd, buf, i) != i)
247 write_fatal ();
248 }
249 if (close (fromfd) != 0)
250 read_fatal ();
251 if (close (tofd) != 0)
252 write_fatal ();
253 }
254
255 static char const DEV_NULL[] = NULL_DEVICE;
256
257 static char const SCCSPREFIX[] = "s.";
258 static char const GET[] = "get ";
259 static char const GET_LOCKED[] = "get -e ";
260 static char const SCCSDIFF1[] = "get -p ";
261 static char const SCCSDIFF2[] = "|diff - %s";
262
263 static char const RCSSUFFIX[] = ",v";
264 static char const CHECKOUT[] = "co %s";
265 static char const CHECKOUT_LOCKED[] = "co -l %s";
266 static char const RCSDIFF1[] = "rcsdiff %s";
267
268 /* Return "RCS" if FILENAME is controlled by RCS,
269 "SCCS" if it is controlled by SCCS, and 0 otherwise.
270 READONLY is nonzero if we desire only readonly access to FILENAME.
271 FILESTAT describes FILENAME's status or is 0 if FILENAME does not exist.
272 If successful and if GETBUF is nonzero, set *GETBUF to a command
273 that gets the file; similarly for DIFFBUF and a command to diff the file.
274 *GETBUF and *DIFFBUF must be freed by the caller. */
275 char const *
version_controller(filename,readonly,filestat,getbuf,diffbuf)276 version_controller (filename, readonly, filestat, getbuf, diffbuf)
277 char const *filename;
278 int readonly;
279 struct stat const *filestat;
280 char **getbuf;
281 char **diffbuf;
282 {
283 struct stat cstat;
284 char const *filebase = base_name (filename);
285 char const *dotslash = *filename == '-' ? "./" : "";
286 size_t dir_len = filebase - filename;
287 size_t filenamelen = strlen (filename);
288 size_t maxfixlen = sizeof "SCCS/" - 1 + sizeof SCCSPREFIX - 1;
289 size_t maxtrysize = filenamelen + maxfixlen + 1;
290 size_t quotelen = quote_system_arg (0, filename);
291 size_t maxgetsize = sizeof GET_LOCKED + quotelen + maxfixlen;
292 size_t maxdiffsize =
293 (sizeof SCCSDIFF1 + sizeof SCCSDIFF2 + sizeof DEV_NULL - 1
294 + 2 * quotelen + maxfixlen);
295 char *trybuf = xmalloc (maxtrysize);
296 char const *r = 0;
297
298 strcpy (trybuf, filename);
299
300 #define try1(f,a1) (sprintf (trybuf + dir_len, f, a1), stat (trybuf, &cstat) == 0)
301 #define try2(f,a1,a2) (sprintf (trybuf + dir_len, f, a1,a2), stat (trybuf, &cstat) == 0)
302
303 /* Check that RCS file is not working file.
304 Some hosts don't report file name length errors. */
305
306 if ((try2 ("RCS/%s%s", filebase, RCSSUFFIX)
307 || try1 ("RCS/%s", filebase)
308 || try2 ("%s%s", filebase, RCSSUFFIX))
309 && ! (filestat
310 && filestat->st_dev == cstat.st_dev
311 && filestat->st_ino == cstat.st_ino))
312 {
313 if (getbuf)
314 {
315 char *p = *getbuf = xmalloc (maxgetsize);
316 sprintf (p, readonly ? CHECKOUT : CHECKOUT_LOCKED, dotslash);
317 p += strlen (p);
318 p += quote_system_arg (p, filename);
319 *p = '\0';
320 }
321
322 if (diffbuf)
323 {
324 char *p = *diffbuf = xmalloc (maxdiffsize);
325 sprintf (p, RCSDIFF1, dotslash);
326 p += strlen (p);
327 p += quote_system_arg (p, filename);
328 *p++ = '>';
329 strcpy (p, DEV_NULL);
330 }
331
332 r = "RCS";
333 }
334 else if (try2 ("SCCS/%s%s", SCCSPREFIX, filebase)
335 || try2 ("%s%s", SCCSPREFIX, filebase))
336 {
337 if (getbuf)
338 {
339 char *p = *getbuf = xmalloc (maxgetsize);
340 sprintf (p, readonly ? GET : GET_LOCKED);
341 p += strlen (p);
342 p += quote_system_arg (p, trybuf);
343 *p = '\0';
344 }
345
346 if (diffbuf)
347 {
348 char *p = *diffbuf = xmalloc (maxdiffsize);
349 strcpy (p, SCCSDIFF1);
350 p += sizeof SCCSDIFF1 - 1;
351 p += quote_system_arg (p, trybuf);
352 sprintf (p, SCCSDIFF2, dotslash);
353 p += strlen (p);
354 p += quote_system_arg (p, filename);
355 *p++ = '>';
356 strcpy (p, DEV_NULL);
357 }
358
359 r = "SCCS";
360 }
361
362 free (trybuf);
363 return r;
364 }
365
366 /* Get FILENAME from version control system CS. The file already exists if
367 EXISTS is nonzero. Only readonly access is needed if READONLY is nonzero.
368 Use the command GETBUF to actually get the named file.
369 Store the resulting file status into *FILESTAT.
370 Return nonzero if successful. */
371 int
version_get(filename,cs,exists,readonly,getbuf,filestat)372 version_get (filename, cs, exists, readonly, getbuf, filestat)
373 char const *filename;
374 char const *cs;
375 int exists;
376 int readonly;
377 char const *getbuf;
378 struct stat *filestat;
379 {
380 if (patch_get < 0)
381 {
382 ask ("Get file `%s' from %s%s? [y] ", filename,
383 cs, readonly ? "" : " with lock");
384 if (*buf == 'n')
385 return 0;
386 }
387
388 if (dry_run)
389 {
390 if (! exists)
391 fatal ("can't do dry run on nonexistent version-controlled file `%s'; invoke `%s' and try again",
392 filename, getbuf);
393 }
394 else
395 {
396 if (verbosity == VERBOSE)
397 say ("Getting file `%s' from %s%s...\n", filename,
398 cs, readonly ? "" : " with lock");
399 if (systemic (getbuf) != 0)
400 fatal ("can't get file `%s' from %s", filename, cs);
401 if (stat (filename, filestat) != 0)
402 pfatal ("%s", filename);
403 }
404
405 return 1;
406 }
407
408 /* Allocate a unique area for a string. */
409
410 char *
savebuf(s,size)411 savebuf (s, size)
412 register char const *s;
413 register size_t size;
414 {
415 register char *rv;
416
417 assert (s && size);
418 rv = malloc (size);
419
420 if (! rv)
421 {
422 if (! using_plan_a)
423 memory_fatal ();
424 }
425 else
426 memcpy (rv, s, size);
427
428 return rv;
429 }
430
431 char *
savestr(s)432 savestr(s)
433 char const *s;
434 {
435 return savebuf (s, strlen (s) + 1);
436 }
437
438 void
remove_prefix(p,prefixlen)439 remove_prefix (p, prefixlen)
440 char *p;
441 size_t prefixlen;
442 {
443 char const *s = p + prefixlen;
444 while ((*p++ = *s++))
445 continue;
446 }
447
448 #if !HAVE_VPRINTF
449 #define vfprintf my_vfprintf
450 static int vfprintf PARAMS ((FILE *, char const *, va_list));
451 static int
vfprintf(stream,format,args)452 vfprintf (stream, format, args)
453 FILE *stream;
454 char const *format;
455 va_list args;
456 {
457 #if !HAVE_DOPRNT && HAVE__DOPRINTF
458 # define _doprnt _doprintf
459 #endif
460 #if HAVE_DOPRNT || HAVE__DOPRINTF
461 _doprnt (format, args, stream);
462 return ferror (stream) ? -1 : 0;
463 #else
464 int *a = (int *) args;
465 return fprintf (stream, format,
466 a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]);
467 #endif
468 }
469 #endif /* !HAVE_VPRINTF */
470
471 /* Terminal output, pun intended. */
472
473 #ifdef __STDC__
474 void
fatal(char const * format,...)475 fatal (char const *format, ...)
476 #else
477 /*VARARGS1*/ void
478 fatal (format, va_alist)
479 char const *format;
480 va_dcl
481 #endif
482 {
483 va_list args;
484 fprintf (stderr, "%s: **** ", program_name);
485 vararg_start (args, format);
486 vfprintf (stderr, format, args);
487 va_end (args);
488 putc ('\n', stderr);
489 fflush (stderr);
490 fatal_exit (0);
491 }
492
493 void
memory_fatal()494 memory_fatal ()
495 {
496 fatal ("out of memory");
497 }
498
499 void
read_fatal()500 read_fatal ()
501 {
502 pfatal ("read error");
503 }
504
505 void
write_fatal()506 write_fatal ()
507 {
508 pfatal ("write error");
509 }
510
511 /* Say something from patch, something from the system, then silence . . . */
512
513 #ifdef __STDC__
514 void
pfatal(char const * format,...)515 pfatal (char const *format, ...)
516 #else
517 /*VARARGS1*/ void
518 pfatal (format, va_alist)
519 char const *format;
520 va_dcl
521 #endif
522 {
523 int errnum = errno;
524 va_list args;
525 fprintf (stderr, "%s: **** ", program_name);
526 vararg_start (args, format);
527 vfprintf (stderr, format, args);
528 va_end (args);
529 fflush (stderr); /* perror bypasses stdio on some hosts. */
530 errno = errnum;
531 perror (" ");
532 fflush (stderr);
533 fatal_exit (0);
534 }
535
536 /* Tell the user something. */
537
538 #ifdef __STDC__
539 void
say(char const * format,...)540 say (char const *format, ...)
541 #else
542 /*VARARGS1*/ void
543 say (format, va_alist)
544 char const *format;
545 va_dcl
546 #endif
547 {
548 va_list args;
549 vararg_start (args, format);
550 vfprintf (stdout, format, args);
551 va_end (args);
552 fflush (stdout);
553 }
554
555 /* Get a response from the user, somehow or other. */
556
557 #ifdef __STDC__
558 void
ask(char const * format,...)559 ask (char const *format, ...)
560 #else
561 /*VARARGS1*/ void
562 ask (format, va_alist)
563 char const *format;
564 va_dcl
565 #endif
566 {
567 static int ttyfd = -2;
568 int r;
569 va_list args;
570
571 vararg_start (args, format);
572 vfprintf (stdout, format, args);
573 va_end (args);
574 fflush (stdout);
575
576 if (ttyfd == -2)
577 {
578 /* If standard output is not a tty, don't bother opening /dev/tty,
579 since it's unlikely that stdout will be seen by the tty user.
580 The isatty test also works around a bug in GNU Emacs 19.34 under Linux
581 which makes a call-process `patch' hang when it reads from /dev/tty.
582 POSIX.2 requires that we read /dev/tty, though. */
583 ttyfd = (posixly_correct || isatty (STDOUT_FILENO)
584 ? open (TTY_DEVICE, O_RDONLY)
585 : -1);
586 }
587
588 if (ttyfd < 0)
589 {
590 /* No terminal at all -- default it. */
591 printf ("\n");
592 buf[0] = '\n';
593 buf[1] = '\0';
594 }
595 else
596 {
597 size_t s = 0;
598 while ((r = read (ttyfd, buf + s, bufsize - 1 - s)) == bufsize - 1 - s
599 && buf[bufsize - 2] != '\n')
600 {
601 s = bufsize - 1;
602 bufsize *= 2;
603 buf = realloc (buf, bufsize);
604 if (!buf)
605 memory_fatal ();
606 }
607 if (r == 0)
608 printf ("EOF\n");
609 else if (r < 0)
610 {
611 perror ("tty read");
612 fflush (stderr);
613 close (ttyfd);
614 ttyfd = -1;
615 r = 0;
616 }
617 buf[s + r] = '\0';
618 }
619 }
620
621 /* Return nonzero if it OK to reverse a patch. */
622
623 #ifdef __STDC__
624 int
ok_to_reverse(char const * format,...)625 ok_to_reverse (char const *format, ...)
626 #else
627 ok_to_reverse (format, va_alist)
628 char const *format;
629 va_dcl
630 #endif
631 {
632 int r = 0;
633
634 if (noreverse || ! (force && verbosity == SILENT))
635 {
636 va_list args;
637 vararg_start (args, format);
638 vfprintf (stdout, format, args);
639 va_end (args);
640 }
641
642 if (noreverse)
643 {
644 printf (" Skipping patch.\n");
645 skip_rest_of_patch = TRUE;
646 r = 0;
647 }
648 else if (force)
649 {
650 if (verbosity != SILENT)
651 printf (" Applying it anyway.\n");
652 r = 0;
653 }
654 else if (batch)
655 {
656 say (reverse ? " Ignoring -R.\n" : " Assuming -R.\n");
657 r = 1;
658 }
659 else
660 {
661 ask (reverse ? " Ignore -R? [n] " : " Assume -R? [n] ");
662 r = *buf == 'y';
663 if (! r)
664 {
665 ask ("Apply anyway? [n] ");
666 if (*buf != 'y')
667 {
668 if (verbosity != SILENT)
669 say ("Skipping patch.\n");
670 skip_rest_of_patch = TRUE;
671 }
672 }
673 }
674
675 return r;
676 }
677
678 /* How to handle certain events when not in a critical region. */
679
680 #define NUM_SIGS (sizeof (sigs) / sizeof (*sigs))
681 static int const sigs[] = {
682 #ifdef SIGHUP
683 SIGHUP,
684 #endif
685 #ifdef SIGPIPE
686 SIGPIPE,
687 #endif
688 #ifdef SIGTERM
689 SIGTERM,
690 #endif
691 #ifdef SIGXCPU
692 SIGXCPU,
693 #endif
694 #ifdef SIGXFSZ
695 SIGXFSZ,
696 #endif
697 SIGINT
698 };
699
700 #if !HAVE_SIGPROCMASK
701 #define sigset_t int
702 #define sigemptyset(s) (*(s) = 0)
703 #ifndef sigmask
704 #define sigmask(sig) (1 << ((sig) - 1))
705 #endif
706 #define sigaddset(s, sig) (*(s) |= sigmask (sig))
707 #define sigismember(s, sig) ((*(s) & sigmask (sig)) != 0)
708 #ifndef SIG_BLOCK
709 #define SIG_BLOCK 0
710 #endif
711 #ifndef SIG_UNBLOCK
712 #define SIG_UNBLOCK (SIG_BLOCK + 1)
713 #endif
714 #ifndef SIG_SETMASK
715 #define SIG_SETMASK (SIG_BLOCK + 2)
716 #endif
717 #define sigprocmask(how, n, o) \
718 ((how) == SIG_BLOCK \
719 ? ((o) ? *(o) = sigblock (*(n)) : sigblock (*(n))) \
720 : (how) == SIG_UNBLOCK \
721 ? sigsetmask (((o) ? *(o) = sigblock (0) : sigblock (0)) & ~*(n)) \
722 : (o ? *(o) = sigsetmask (*(n)) : sigsetmask (*(n))))
723 #if !HAVE_SIGSETMASK
724 #define sigblock(mask) 0
725 #define sigsetmask(mask) 0
726 #endif
727 #endif
728
729 static sigset_t initial_signal_mask;
730 static sigset_t signals_to_block;
731
732 #if ! HAVE_SIGACTION
733 static RETSIGTYPE fatal_exit_handler PARAMS ((int)) __attribute__ ((noreturn));
734 static RETSIGTYPE
fatal_exit_handler(sig)735 fatal_exit_handler (sig)
736 int sig;
737 {
738 signal (sig, SIG_IGN);
739 fatal_exit (sig);
740 }
741 #endif
742
743 void
set_signals(reset)744 set_signals(reset)
745 int reset;
746 {
747 int i;
748 #if HAVE_SIGACTION
749 struct sigaction initial_act, fatal_act;
750 fatal_act.sa_handler = fatal_exit;
751 sigemptyset (&fatal_act.sa_mask);
752 fatal_act.sa_flags = 0;
753 #define setup_handler(sig) sigaction (sig, &fatal_act, (struct sigaction *) 0)
754 #else
755 #define setup_handler(sig) signal (sig, fatal_exit_handler)
756 #endif
757
758 if (!reset)
759 {
760 #ifdef SIGCHLD
761 /* System V fork+wait does not work if SIGCHLD is ignored. */
762 signal (SIGCHLD, SIG_DFL);
763 #endif
764 sigemptyset (&signals_to_block);
765 for (i = 0; i < NUM_SIGS; i++)
766 {
767 int ignoring_signal;
768 #if HAVE_SIGACTION
769 if (sigaction (sigs[i], (struct sigaction *) 0, &initial_act) != 0)
770 continue;
771 ignoring_signal = initial_act.sa_handler == SIG_IGN;
772 #else
773 ignoring_signal = signal (sigs[i], SIG_IGN) == SIG_IGN;
774 #endif
775 if (! ignoring_signal)
776 {
777 sigaddset (&signals_to_block, sigs[i]);
778 setup_handler (sigs[i]);
779 }
780 }
781 }
782 else
783 {
784 /* Undo the effect of ignore_signals. */
785 #if HAVE_SIGPROCMASK || HAVE_SIGSETMASK
786 sigprocmask (SIG_SETMASK, &initial_signal_mask, (sigset_t *) 0);
787 #else
788 for (i = 0; i < NUM_SIGS; i++)
789 if (sigismember (&signals_to_block, sigs[i]))
790 setup_handler (sigs[i]);
791 #endif
792 }
793 }
794
795 /* How to handle certain events when in a critical region. */
796
797 void
ignore_signals()798 ignore_signals()
799 {
800 #if HAVE_SIGPROCMASK || HAVE_SIGSETMASK
801 sigprocmask (SIG_BLOCK, &signals_to_block, &initial_signal_mask);
802 #else
803 int i;
804 for (i = 0; i < NUM_SIGS; i++)
805 if (sigismember (&signals_to_block, sigs[i]))
806 signal (sigs[i], SIG_IGN);
807 #endif
808 }
809
810 void
exit_with_signal(sig)811 exit_with_signal (sig)
812 int sig;
813 {
814 sigset_t s;
815 signal (sig, SIG_DFL);
816 sigemptyset (&s);
817 sigaddset (&s, sig);
818 sigprocmask (SIG_UNBLOCK, &s, (sigset_t *) 0);
819 raise (sig);
820 exit (2);
821 }
822
823 int
systemic(command)824 systemic (command)
825 char const *command;
826 {
827 if (debug & 8)
828 say ("+ %s\n", command);
829 fflush (stdout);
830 return system (command);
831 }
832
833 #if !HAVE_MKDIR
834 /* These mkdir and rmdir substitutes are good enough for `patch';
835 they are not general emulators. */
836
837 static int doprogram PARAMS ((char const *, char const *));
838 static int mkdir PARAMS ((char const *, mode_t));
839 static int rmdir PARAMS ((char const *));
840
841 static int
doprogram(program,arg)842 doprogram (program, arg)
843 char const *program;
844 char const *arg;
845 {
846 int result;
847 static char const DISCARD_OUTPUT[] = " 2>/dev/null";
848 size_t program_len = strlen (program);
849 char *cmd = xmalloc (program_len + 1 + quote_system_arg (0, arg)
850 + sizeof DISCARD_OUTPUT);
851 char *p = cmd;
852 strcpy (p, program);
853 p += program_len;
854 *p++ = ' ';
855 p += quote_system_arg (p, arg);
856 strcpy (p, DISCARD_OUTPUT);
857 result = systemic (cmd);
858 free (cmd);
859 return result;
860 }
861
862 #ifdef __STDC__
863 /* If mode_t doesn't promote to itself, we can't use old-style definition. */
864 static int
mkdir(char const * path,mode_t mode)865 mkdir (char const *path, mode_t mode)
866 #else
867 static int
868 mkdir (path, mode)
869 char const *path;
870 mode_t mode; /* ignored */
871 #endif
872 {
873 return doprogram ("mkdir", path);
874 }
875
876 static int
rmdir(path)877 rmdir (path)
878 char const *path;
879 {
880 int result = doprogram ("rmdir", path);
881 errno = EEXIST;
882 return result;
883 }
884 #endif
885
886 /* Replace '/' with '\0' in FILENAME if it marks a place that
887 needs testing for the existence of directory. Return the address
888 of the last location replaced, or 0 if none were replaced. */
889 static char *replace_slashes PARAMS ((char *));
890 static char *
replace_slashes(filename)891 replace_slashes (filename)
892 char *filename;
893 {
894 char *f;
895 char *last_location_replaced = 0;
896 char const *component_start;
897
898 for (f = filename + FILESYSTEM_PREFIX_LEN (filename); ISSLASH (*f); f++)
899 continue;
900
901 component_start = f;
902
903 for (; *f; f++)
904 if (ISSLASH (*f))
905 {
906 char *slash = f;
907
908 /* Treat multiple slashes as if they were one slash. */
909 while (ISSLASH (f[1]))
910 f++;
911
912 /* Ignore slashes at the end of the path. */
913 if (! f[1])
914 break;
915
916 /* "." and ".." need not be tested. */
917 if (! (slash - component_start <= 2
918 && component_start[0] == '.' && slash[-1] == '.'))
919 {
920 *slash = '\0';
921 last_location_replaced = slash;
922 }
923
924 component_start = f + 1;
925 }
926
927 return last_location_replaced;
928 }
929
930 /* Make sure we'll have the directories to create a file.
931 Ignore the last element of `filename'. */
932
933 static void
makedirs(filename)934 makedirs (filename)
935 register char *filename;
936 {
937 register char *f;
938 register char *flim = replace_slashes (filename);
939
940 if (flim)
941 {
942 /* Create any missing directories, replacing NULs by '/'s.
943 Ignore errors. We may have to keep going even after an EEXIST,
944 since the path may contain ".."s; and when there is an EEXIST
945 failure the system may return some other error number.
946 Any problems will eventually be reported when we create the file. */
947 for (f = filename; f <= flim; f++)
948 if (!*f)
949 {
950 mkdir (filename,
951 S_IRUSR|S_IWUSR|S_IXUSR
952 |S_IRGRP|S_IWGRP|S_IXGRP
953 |S_IROTH|S_IWOTH|S_IXOTH);
954 *f = '/';
955 }
956 }
957 }
958
959 /* Remove empty ancestor directories of FILENAME.
960 Ignore errors, since the path may contain ".."s, and when there
961 is an EEXIST failure the system may return some other error number. */
962 void
removedirs(filename)963 removedirs (filename)
964 char *filename;
965 {
966 size_t i;
967
968 for (i = strlen (filename); i != 0; i--)
969 if (ISSLASH (filename[i])
970 && ! (ISSLASH (filename[i - 1])
971 || (filename[i - 1] == '.'
972 && (i == 1
973 || ISSLASH (filename[i - 2])
974 || (filename[i - 2] == '.'
975 && (i == 2
976 || ISSLASH (filename[i - 3])))))))
977 {
978 filename[i] = '\0';
979 if (rmdir (filename) == 0 && verbosity == VERBOSE)
980 say ("Removed empty directory `%s'.\n", filename);
981 filename[i] = '/';
982 }
983 }
984
985 static time_t initial_time;
986
987 void
init_time()988 init_time ()
989 {
990 time (&initial_time);
991 }
992
993 /* Make filenames more reasonable. */
994
995 char *
fetchname(at,strip_leading,pstamp)996 fetchname (at, strip_leading, pstamp)
997 char *at;
998 int strip_leading;
999 time_t *pstamp;
1000 {
1001 char *name;
1002 register char *t;
1003 int sleading = strip_leading;
1004 time_t stamp = (time_t) -1;
1005
1006 while (ISSPACE ((unsigned char) *at))
1007 at++;
1008 if (debug & 128)
1009 say ("fetchname %s %d\n", at, strip_leading);
1010
1011 name = at;
1012 /* Strip off up to `sleading' leading slashes and null terminate. */
1013 for (t = at; *t; t++)
1014 {
1015 if (ISSLASH (*t))
1016 {
1017 while (ISSLASH (t[1]))
1018 t++;
1019 if (--sleading >= 0)
1020 name = t+1;
1021 }
1022 else if (ISSPACE ((unsigned char) *t))
1023 {
1024 if (set_time | set_utc)
1025 stamp = str2time (t, initial_time, set_utc ? 0L : TM_LOCAL_ZONE);
1026 else
1027 {
1028 /* The head says the file is nonexistent if the timestamp
1029 is the epoch; but the listed time is local time, not UTC,
1030 and POSIX.1 allows local time to be 24 hours away from UTC.
1031 So match any time within 24 hours of the epoch.
1032 Use a default time zone 24 hours behind UTC so that any
1033 non-zoned time within 24 hours of the epoch is valid. */
1034 stamp = str2time (t, initial_time, -24L * 60 * 60);
1035 if (0 <= stamp && stamp <= 2 * 24L * 60 * 60)
1036 stamp = 0;
1037 }
1038
1039 *t = '\0';
1040 break;
1041 }
1042 }
1043
1044 if (!*name)
1045 return 0;
1046
1047 /* Allow files to be created by diffing against /dev/null. */
1048 if (strcmp (at, "/dev/null") == 0)
1049 {
1050 if (pstamp)
1051 *pstamp = 0;
1052 return 0;
1053 }
1054
1055 if (pstamp)
1056 *pstamp = stamp;
1057
1058 return savestr (name);
1059 }
1060
1061 GENERIC_OBJECT *
xmalloc(size)1062 xmalloc (size)
1063 size_t size;
1064 {
1065 register GENERIC_OBJECT *p = malloc (size);
1066 if (!p)
1067 memory_fatal ();
1068 return p;
1069 }
1070
1071 void
Fseek(stream,offset,ptrname)1072 Fseek (stream, offset, ptrname)
1073 FILE *stream;
1074 file_offset offset;
1075 int ptrname;
1076 {
1077 if (file_seek (stream, offset, ptrname) != 0)
1078 pfatal ("fseek");
1079 }
1080