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

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