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