source: vendor/patch/2.5.9/util.c@ 3754

Last change on this file since 3754 was 3444, checked in by bird, 18 years ago

patch 2.5.9

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