xref: /plan9/sys/src/ape/cmd/patch/util.c (revision 0b459c2cb92b7c9d88818e9a2f72e678e5bc4553)
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