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