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