]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - gnu/usr.bin/patch/util.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / gnu / usr.bin / patch / util.c
1 /* $FreeBSD$ */
2
3 #include <paths.h>
4
5 #include "EXTERN.h"
6 #include "common.h"
7 #include "INTERN.h"
8 #include "util.h"
9 #include "backupfile.h"
10
11 void    my_exit(int _status);           /* in patch.c */
12
13 #ifndef HAVE_STRERROR
14 static char *
15 private_strerror (errnum)
16      int errnum;
17 {
18   extern char *sys_errlist[];
19   extern int sys_nerr;
20
21   if (errnum > 0 && errnum <= sys_nerr)
22     return sys_errlist[errnum];
23   return "Unknown system error";
24 }
25 #define strerror private_strerror
26 #endif /* !HAVE_STRERROR */
27
28 /*
29  * Rename a file, copying it if necessary.
30  */
31 int
32 move_file(char *from, char *to)
33 {
34         char bakname[512];
35         Reg1 char *s;
36         Reg2 int i;
37         Reg3 int fromfd;
38
39         /* to stdout? */
40
41         if (strEQ(to, "-")) {
42 #ifdef DEBUGGING
43                 if (debug & 4)
44                         say2("Moving %s to stdout.\n", from);
45 #endif
46                 fromfd = open(from, 0);
47                 if (fromfd < 0)
48                         pfatal2("internal error, can't reopen %s", from);
49                 while ((i = read(fromfd, buf, buf_size)) > 0)
50                         if (write(1, buf, i) != 1)
51                                 pfatal1("write failed");
52                 Close(fromfd);
53                 return 0;
54         }
55
56         if (origprae) {
57                 Strcpy(bakname, origprae);
58                 Strcat(bakname, to);
59         } else {
60 #ifndef NODIR
61                 char *backupname = find_backup_file_name(to);
62                 if (backupname == (char *) 0)
63                     fatal1("out of memory\n");
64                 Strcpy(bakname, backupname);
65                 free(backupname);
66 #else /* NODIR */
67                 Strcpy(bakname, to);
68                 Strcat(bakname, simple_backup_suffix);
69 #endif /* NODIR */
70         }
71
72         if (stat(to, &filestat) == 0) { /* output file exists */
73                 dev_t to_device = filestat.st_dev;
74                 ino_t to_inode  = filestat.st_ino;
75                 char *simplename = bakname;
76
77                 for (s = bakname; *s; s++) {
78                         if (*s == '/')
79                                 simplename = s + 1;
80                 }
81                 /*
82                  * Find a backup name that is not the same file.
83                  * Change the first lowercase char into uppercase;
84                  * if that isn't sufficient, chop off the first char
85                  * and try again.
86                  */
87                 while (stat(bakname, &filestat) == 0 &&
88                     to_device == filestat.st_dev &&
89                     to_inode == filestat.st_ino) {
90                         /* Skip initial non-lowercase chars.  */
91                         for (s=simplename; *s && !islower((unsigned char)*s);
92                             s++)
93                                 ;
94                         if (*s)
95                                 *s = toupper((unsigned char)*s);
96                         else
97                                 Strcpy(simplename, simplename + 1);
98                 }
99                 while (unlink(bakname) >= 0)
100                         ;       /* while() is for benefit of Eunice */
101 #ifdef DEBUGGING
102                 if (debug & 4)
103                         say3("Moving %s to %s.\n", to, bakname);
104 #endif
105                 if (rename(to, bakname) < 0) {
106                         say4("Can't backup %s, output is in %s: %s\n", to, from,
107                             strerror(errno));
108                         return -1;
109                 }
110                 while (unlink(to) >= 0)
111                         ;
112         }
113 #ifdef DEBUGGING
114         if (debug & 4)
115                 say3("Moving %s to %s.\n", from, to);
116 #endif
117         if (rename(from, to) < 0) {     /* different file system? */
118                 Reg4 int tofd;
119
120                 tofd = creat(to, 0666);
121                 if (tofd < 0) {
122                         say4("Can't create %s, output is in %s: %s\n",
123                             to, from, strerror(errno));
124                         return -1;
125                 }
126                 fromfd = open(from, 0);
127                 if (fromfd < 0)
128                         pfatal2("internal error, can't reopen %s", from);
129                 while ((i = read(fromfd, buf, buf_size)) > 0)
130                         if (write(tofd, buf, i) != i)
131                                 pfatal1("write failed");
132                 Close(fromfd);
133                 Close(tofd);
134         }
135         Unlink(from);
136         return 0;
137 }
138
139 /*
140  * Copy a file.
141  */
142 void
143 copy_file(char *from, char *to)
144 {
145         Reg3 int tofd;
146         Reg2 int fromfd;
147         Reg1 int i;
148
149         tofd = creat(to, 0666);
150         if (tofd < 0)
151                 pfatal2("can't create %s", to);
152         fromfd = open(from, 0);
153         if (fromfd < 0)
154                 pfatal2("internal error, can't reopen %s", from);
155         while ((i = read(fromfd, buf, buf_size)) > 0)
156                 if (write(tofd, buf, i) != i)
157                         pfatal2("write to %s failed", to);
158         Close(fromfd);
159         Close(tofd);
160 }
161
162 /*
163  * Allocate a unique area for a string.
164  */
165 char *
166 savestr(char *s)
167 {
168         Reg3 char *rv;
169         Reg2 char *t;
170
171         if (!s)
172                 s = "Oops";
173         t = s;
174         while (*t++)
175                 ;
176         rv = malloc((MEM) (t - s));
177         if (rv == Nullch) {
178                 if (using_plan_a)
179                         out_of_mem = TRUE;
180                 else
181                         fatal1("out of memory\n");
182         } else {
183                 t = rv;
184                 while ((*t++ = *s++));
185         }
186         return rv;
187 }
188
189 #if defined(lint) && defined(CANVARARG)
190
191 /*VARARGS ARGSUSED*/
192 say(pat) char *pat; { ; }
193 /*VARARGS ARGSUSED*/
194 fatal(pat) char *pat; { ; }
195 /*VARARGS ARGSUSED*/
196 pfatal(pat) char *pat; { ; }
197 /*VARARGS ARGSUSED*/
198 ask(pat) char *pat; { ; }
199
200 #else
201
202 /*
203  * Vanilla terminal output (buffered).
204  */
205 void
206 say(pat,arg1,arg2,arg3)
207 char *pat;
208 long arg1,arg2,arg3;
209 {
210         fprintf(stderr, pat, arg1, arg2, arg3);
211         Fflush(stderr);
212 }
213
214 /*
215  * Terminal output, pun intended.
216  */
217 void                            /* very void */
218 fatal(pat,arg1,arg2,arg3)
219 char *pat;
220 long arg1,arg2,arg3;
221 {
222         fprintf(stderr, "patch: **** ");
223         fprintf(stderr, pat, arg1, arg2, arg3);
224         my_exit(1);
225 }
226
227 /*
228  * Say something from patch, something from the system, then silence...
229  */
230 void                            /* very void */
231 pfatal(pat,arg1,arg2,arg3)
232 char *pat;
233 long arg1,arg2,arg3;
234 {
235         int errnum = errno;
236
237         fprintf(stderr, "patch: **** ");
238         fprintf(stderr, pat, arg1, arg2, arg3);
239         fprintf(stderr, ": %s\n", strerror(errnum));
240         my_exit(1);
241 }
242
243 /*
244  * Get a response from the user, somehow or other.
245  */
246 int
247 ask(pat,arg1,arg2,arg3)
248 char *pat;
249 long arg1,arg2,arg3;
250 {
251         int ttyfd;
252         int r;
253         bool tty2 = isatty(2);
254
255         Sprintf(buf, pat, arg1, arg2, arg3);
256         Fflush(stderr);
257         write(2, buf, strlen(buf));
258         if (tty2) {                     /* might be redirected to a file */
259                 r = read(2, buf, buf_size);
260         } else if (isatty(1)) {         /* this may be new file output */
261                 Fflush(stdout);
262                 write(1, buf, strlen(buf));
263                 r = read(1, buf, buf_size);
264         } else if ((ttyfd = open(_PATH_TTY, 2)) >= 0 && isatty(ttyfd)) {
265                                         /* might be deleted or unwriteable */
266                 write(ttyfd, buf, strlen(buf));
267                 r = read(ttyfd, buf, buf_size);
268                 Close(ttyfd);
269         } else if (isatty(0)) {         /* this is probably patch input */
270                 Fflush(stdin);
271                 write(0, buf, strlen(buf));
272                 r = read(0, buf, buf_size);
273         } else {                        /* no terminal at all--default it */
274                 buf[0] = '\n';
275                 buf[1] = 0;
276                 say1(buf);
277                 return 0;               /* signal possible error */
278         }
279         if (r <= 0)
280                 buf[0] = 0;
281         else
282                 buf[r] = '\0';
283         if (!tty2)
284                 say1(buf);
285
286         if (r <= 0)
287                 return 0;               /* if there was an error, return it */
288         else
289                 return 1;
290 }
291 #endif /* lint */
292
293 /*
294  * How to handle certain events when not in a critical region.
295  */
296 void
297 set_signals(int reset)
298 {
299 #ifndef lint
300         static RETSIGTYPE (*hupval)(),(*intval)();
301
302         if (!reset) {
303                 hupval = signal(SIGHUP, SIG_IGN);
304                 if (hupval != SIG_IGN)
305                         hupval = (RETSIGTYPE(*)())my_exit;
306                 intval = signal(SIGINT, SIG_IGN);
307                 if (intval != SIG_IGN)
308                         intval = (RETSIGTYPE(*)())my_exit;
309         }
310         Signal(SIGHUP, hupval);
311         Signal(SIGINT, intval);
312 #endif
313 }
314
315 /*
316  * How to handle certain events when in a critical region.
317  */
318 void
319 ignore_signals(void)
320 {
321 #ifndef lint
322         Signal(SIGHUP, SIG_IGN);
323         Signal(SIGINT, SIG_IGN);
324 #endif
325 }
326
327 /*
328  * Make sure we'll have the directories to create a file.
329  * If `striplast' is TRUE, ignore the last element of `filename'.
330  */
331 void
332 makedirs(filename,striplast)
333 Reg1 char *filename;
334 bool striplast;
335 {
336         char tmpbuf[256];
337         Reg2 char *s = tmpbuf;
338         char *dirv[20];         /* Point to the NULs between elements.  */
339         Reg3 int i;
340         Reg4 int dirvp = 0;     /* Number of finished entries in dirv. */
341
342         /*
343          * Copy `filename' into `tmpbuf' with a NUL instead of a slash
344          * between the directories.
345          */
346         while (*filename) {
347                 if (*filename == '/') {
348                         filename++;
349                         dirv[dirvp++] = s;
350                         *s++ = '\0';
351                 } else {
352                         *s++ = *filename++;
353                 }
354         }
355         *s = '\0';
356         dirv[dirvp] = s;
357         if (striplast)
358                 dirvp--;
359         if (dirvp < 0)
360                 return;
361
362         strcpy(buf, "mkdir");
363         s = buf;
364         for (i = 0; i <= dirvp; i++) {
365                 struct stat sbuf;
366
367                 if (stat(tmpbuf, &sbuf) && errno == ENOENT) {
368                         while (*s)
369                                 s++;
370                         *s++ = ' ';
371                         strcpy(s, tmpbuf);
372                 }
373                 *dirv[i] = '/';
374         }
375         if (s != buf)
376                 system(buf);
377 }
378
379 /*
380  * Make filenames more reasonable.
381  */
382 char *
383 fetchname(char *at, int strip_leading, int assume_exists)
384 {
385         char *fullname;
386         char *name;
387         Reg1 char *t;
388         char tmpbuf[200];
389         int sleading = strip_leading;
390
391         if (!at)
392                 return Nullch;
393         while (isspace((unsigned char)*at))
394                 at++;
395 #ifdef DEBUGGING
396         if (debug & 128)
397                 say4("fetchname %s %d %d\n",at,strip_leading,assume_exists);
398 #endif
399         if (strnEQ(at, _PATH_DEVNULL, sizeof _PATH_DEVNULL - 1))
400                 /* So files can be created by diffing against /dev/null. */
401                 return Nullch;
402         name = fullname = t = savestr(at);
403
404         /* Strip off up to `sleading' leading slashes and null terminate. */
405         for (; *t && !isspace((unsigned char)*t); t++)
406                 if (*t == '/')
407                         if (--sleading >= 0)
408                                 name = t + 1;
409         *t = '\0';
410
411         /*
412          * If no -p option was given (957 is the default value!),
413          * we were given a relative pathname,
414          * and the leading directories that we just stripped off all exist,
415          * put them back on. 
416          */
417         if (strip_leading == 957 && name != fullname && *fullname != '/') {
418                 name[-1] = '\0';
419                 if (stat(fullname, &filestat) == 0 &&
420                     S_ISDIR(filestat.st_mode)) {
421                         name[-1] = '/';
422                         name = fullname;
423                 }
424         }
425
426         name = savestr(name);
427         free(fullname);
428
429         if (stat(name, &filestat) && !assume_exists) {
430                 char *filebase = basename(name);
431                 int pathlen = filebase - name;
432
433                 /* Put any leading path into `tmpbuf'. */
434                 strncpy(tmpbuf, name, pathlen);
435
436 #define try(f, a1, a2) \
437     (Sprintf(tmpbuf + pathlen, f, a1, a2), stat(tmpbuf, &filestat) == 0)
438                 if (try("RCS/%s%s", filebase, RCSSUFFIX) ||
439                     try("RCS/%s%s", filebase,        "") ||
440                     try(    "%s%s", filebase, RCSSUFFIX) ||
441                     try("SCCS/%s%s", SCCSPREFIX, filebase) ||
442                     try(     "%s%s", SCCSPREFIX, filebase))
443                         return name;
444                 free(name);
445                 name = Nullch;
446         }
447
448         return name;
449 }
450
451 char *
452 xmalloc(unsigned int size)
453 {
454         register char *p = (char *) malloc (size);
455         if (!p)
456                 fatal("out of memory");
457         return p;
458 }