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