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