[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.7

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