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