Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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 *
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
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 *
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 *
432
savestr(s)
433
     char const *s;
434
{
435
  return savebuf (s, strlen (s) + 1);
436
}
437
 
438
void
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
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
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
494
memory_fatal ()
495
{
496
  fatal ("out of memory");
497
}
498
 
499
void
500
read_fatal ()
501
{
502
  pfatal ("read error");
503
}
504
 
505
void
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
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
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
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
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
735
fatal_exit_handler (sig)
736
     int sig;
737
{
738
  signal (sig, SIG_IGN);
739
  fatal_exit (sig);
740
}
741
#endif
742
 
743
void
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
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
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
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
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
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
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 *
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
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
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
988
init_time ()
989
{
990
  time (&initial_time);
991
}
992
 
993
/* Make filenames more reasonable. */
994
 
995
char *
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 *
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
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
}