[BACK]Return to util.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / patch

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: }