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

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