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

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