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

1.38    ! tobias      1: /*     $OpenBSD: util.c,v 1.37 2014/11/22 15:49:28 tobias Exp $        */
1.26      otto        2:
                      3: /*
                      4:  * patch - a program to apply diffs to original files
                      5:  *
                      6:  * Copyright 1986, Larry Wall
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following condition is met:
                     10:  * 1. Redistributions of source code must retain the above copyright notice,
                     11:  * this condition and the following disclaimer.
                     12:  *
                     13:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
                     14:  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     15:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     16:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
                     17:  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     18:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     19:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
                     20:  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     21:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     22:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     23:  * SUCH DAMAGE.
                     24:  *
                     25:  * -C option added in 1998, original code by Marc Espie, based on FreeBSD
                     26:  * behaviour
                     27:  */
1.1       deraadt    28:
1.16      otto       29: #include <sys/param.h>
                     30: #include <sys/stat.h>
                     31:
                     32: #include <ctype.h>
                     33: #include <errno.h>
                     34: #include <fcntl.h>
                     35: #include <libgen.h>
                     36: #include <paths.h>
1.32      otto       37: #include <signal.h>
1.16      otto       38: #include <stdarg.h>
                     39: #include <stdlib.h>
1.20      otto       40: #include <stdio.h>
1.16      otto       41: #include <string.h>
                     42: #include <unistd.h>
                     43:
1.1       deraadt    44: #include "common.h"
                     45: #include "util.h"
                     46: #include "backupfile.h"
1.22      millert    47: #include "pathnames.h"
1.1       deraadt    48:
                     49: /* Rename a file, copying it if necessary. */
                     50:
                     51: int
1.20      otto       52: move_file(const char *from, const char *to)
1.1       deraadt    53: {
1.20      otto       54:        int     fromfd;
                     55:        ssize_t i;
1.1       deraadt    56:
1.13      deraadt    57:        /* to stdout? */
1.1       deraadt    58:
1.13      deraadt    59:        if (strEQ(to, "-")) {
1.1       deraadt    60: #ifdef DEBUGGING
1.13      deraadt    61:                if (debug & 4)
                     62:                        say("Moving %s to stdout.\n", from);
1.1       deraadt    63: #endif
1.13      deraadt    64:                fromfd = open(from, O_RDONLY);
                     65:                if (fromfd < 0)
                     66:                        pfatal("internal error, can't reopen %s", from);
                     67:                while ((i = read(fromfd, buf, sizeof buf)) > 0)
1.16      otto       68:                        if (write(STDOUT_FILENO, buf, i) != i)
1.13      deraadt    69:                                pfatal("write failed");
                     70:                close(fromfd);
                     71:                return 0;
1.1       deraadt    72:        }
1.18      millert    73:        if (backup_file(to) < 0) {
                     74:                say("Can't backup %s, output is in %s: %s\n", to, from,
                     75:                    strerror(errno));
                     76:                return -1;
                     77:        }
                     78: #ifdef DEBUGGING
                     79:        if (debug & 4)
                     80:                say("Moving %s to %s.\n", from, to);
                     81: #endif
                     82:        if (rename(from, to) < 0) {
                     83:                if (errno != EXDEV || copy_file(from, to) < 0) {
                     84:                        say("Can't create %s, output is in %s: %s\n",
                     85:                            to, from, strerror(errno));
                     86:                        return -1;
                     87:                }
                     88:        }
                     89:        return 0;
                     90: }
                     91:
                     92: /* Backup the original file.  */
                     93:
                     94: int
1.20      otto       95: backup_file(const char *orig)
1.18      millert    96: {
1.20      otto       97:        struct stat     filestat;
                     98:        char            bakname[MAXPATHLEN], *s, *simplename;
                     99:        dev_t           orig_device;
                    100:        ino_t           orig_inode;
1.18      millert   101:
                    102:        if (backup_type == none || stat(orig, &filestat) != 0)
                    103:                return 0;                       /* nothing to do */
                    104:        orig_device = filestat.st_dev;
                    105:        orig_inode = filestat.st_ino;
                    106:
1.13      deraadt   107:        if (origprae) {
                    108:                if (strlcpy(bakname, origprae, sizeof(bakname)) >= sizeof(bakname) ||
1.18      millert   109:                    strlcat(bakname, orig, sizeof(bakname)) >= sizeof(bakname))
1.13      deraadt   110:                        fatal("filename %s too long for buffer\n", origprae);
                    111:        } else {
1.18      millert   112:                if ((s = find_backup_file_name(orig)) == NULL)
1.13      deraadt   113:                        fatal("out of memory\n");
1.18      millert   114:                if (strlcpy(bakname, s, sizeof(bakname)) >= sizeof(bakname))
                    115:                        fatal("filename %s too long for buffer\n", s);
                    116:                free(s);
1.1       deraadt   117:        }
1.13      deraadt   118:
1.18      millert   119:        if ((simplename = strrchr(bakname, '/')) != NULL)
                    120:                simplename = simplename + 1;
                    121:        else
                    122:                simplename = bakname;
                    123:
                    124:        /*
                    125:         * Find a backup name that is not the same file. Change the
                    126:         * first lowercase char into uppercase; if that isn't
                    127:         * sufficient, chop off the first char and try again.
                    128:         */
                    129:        while (stat(bakname, &filestat) == 0 &&
                    130:            orig_device == filestat.st_dev && orig_inode == filestat.st_ino) {
                    131:                /* Skip initial non-lowercase chars.  */
1.36      deraadt   132:                for (s = simplename; *s && !islower((unsigned char)*s); s++)
1.18      millert   133:                        ;
                    134:                if (*s)
1.36      deraadt   135:                        *s = toupper((unsigned char)*s);
1.18      millert   136:                else
                    137:                        memmove(simplename, simplename + 1,
                    138:                            strlen(simplename + 1) + 1);
1.1       deraadt   139:        }
                    140: #ifdef DEBUGGING
1.13      deraadt   141:        if (debug & 4)
1.18      millert   142:                say("Moving %s to %s.\n", orig, bakname);
1.1       deraadt   143: #endif
1.18      millert   144:        if (rename(orig, bakname) < 0) {
                    145:                if (errno != EXDEV || copy_file(orig, bakname) < 0)
1.13      deraadt   146:                        return -1;
                    147:        }
                    148:        return 0;
                    149: }
                    150:
                    151: /*
                    152:  * Copy a file.
                    153:  */
1.18      millert   154: int
1.20      otto      155: copy_file(const char *from, const char *to)
1.13      deraadt   156: {
1.20      otto      157:        int     tofd, fromfd;
                    158:        ssize_t i;
1.12      deraadt   159:
1.18      millert   160:        tofd = open(to, O_CREAT|O_TRUNC|O_WRONLY, 0666);
1.13      deraadt   161:        if (tofd < 0)
1.18      millert   162:                return -1;
                    163:        fromfd = open(from, O_RDONLY, 0);
1.1       deraadt   164:        if (fromfd < 0)
1.13      deraadt   165:                pfatal("internal error, can't reopen %s", from);
                    166:        while ((i = read(fromfd, buf, sizeof buf)) > 0)
                    167:                if (write(tofd, buf, i) != i)
                    168:                        pfatal("write to %s failed", to);
1.12      deraadt   169:        close(fromfd);
                    170:        close(tofd);
1.18      millert   171:        return 0;
1.1       deraadt   172: }
                    173:
1.13      deraadt   174: /*
                    175:  * Allocate a unique area for a string.
                    176:  */
1.1       deraadt   177: char *
1.20      otto      178: savestr(const char *s)
1.1       deraadt   179: {
1.20      otto      180:        char    *rv;
1.1       deraadt   181:
1.13      deraadt   182:        if (!s)
                    183:                s = "Oops";
1.20      otto      184:        rv = strdup(s);
1.16      otto      185:        if (rv == NULL) {
1.13      deraadt   186:                if (using_plan_a)
1.25      otto      187:                        out_of_mem = true;
1.13      deraadt   188:                else
                    189:                        fatal("out of memory\n");
                    190:        }
1.38    ! tobias    191:        return rv;
        !           192: }
        !           193:
        !           194: /*
        !           195:  * Allocate a unique area for a string.  Call fatal if out of memory.
        !           196:  */
        !           197: char *
        !           198: xstrdup(const char *s)
        !           199: {
        !           200:        char    *rv;
        !           201:
        !           202:        if (!s)
        !           203:                s = "Oops";
        !           204:        rv = strdup(s);
        !           205:        if (rv == NULL)
        !           206:                fatal("out of memory\n");
1.13      deraadt   207:        return rv;
1.1       deraadt   208: }
                    209:
1.13      deraadt   210: /*
                    211:  * Vanilla terminal output (buffered).
                    212:  */
1.1       deraadt   213: void
1.20      otto      214: say(const char *fmt, ...)
1.1       deraadt   215: {
1.13      deraadt   216:        va_list ap;
1.12      deraadt   217:
1.13      deraadt   218:        va_start(ap, fmt);
1.35      ray       219:        vfprintf(stdout, fmt, ap);
1.13      deraadt   220:        va_end(ap);
1.35      ray       221:        fflush(stdout);
1.1       deraadt   222: }
                    223:
1.13      deraadt   224: /*
                    225:  * Terminal output, pun intended.
                    226:  */
1.12      deraadt   227: void
1.20      otto      228: fatal(const char *fmt, ...)
1.1       deraadt   229: {
1.13      deraadt   230:        va_list ap;
1.12      deraadt   231:
1.13      deraadt   232:        va_start(ap, fmt);
                    233:        fprintf(stderr, "patch: **** ");
                    234:        vfprintf(stderr, fmt, ap);
                    235:        va_end(ap);
1.19      millert   236:        my_exit(2);
1.1       deraadt   237: }
                    238:
1.13      deraadt   239: /*
                    240:  * Say something from patch, something from the system, then silence . . .
                    241:  */
1.12      deraadt   242: void
1.20      otto      243: pfatal(const char *fmt, ...)
1.1       deraadt   244: {
1.13      deraadt   245:        va_list ap;
                    246:        int     errnum = errno;
1.1       deraadt   247:
1.13      deraadt   248:        fprintf(stderr, "patch: **** ");
                    249:        va_start(ap, fmt);
                    250:        vfprintf(stderr, fmt, ap);
                    251:        va_end(ap);
                    252:        fprintf(stderr, ": %s\n", strerror(errnum));
1.19      millert   253:        my_exit(2);
1.1       deraadt   254: }
                    255:
1.13      deraadt   256: /*
1.23      millert   257:  * Get a response from the user via /dev/tty
1.13      deraadt   258:  */
1.1       deraadt   259: void
1.20      otto      260: ask(const char *fmt, ...)
1.1       deraadt   261: {
1.13      deraadt   262:        va_list ap;
1.23      millert   263:        ssize_t nr;
                    264:        static  int ttyfd = -1;
1.13      deraadt   265:
                    266:        va_start(ap, fmt);
1.23      millert   267:        vfprintf(stdout, fmt, ap);
1.13      deraadt   268:        va_end(ap);
1.23      millert   269:        fflush(stdout);
                    270:        if (ttyfd < 0)
                    271:                ttyfd = open(_PATH_TTY, O_RDONLY);
                    272:        if (ttyfd >= 0) {
                    273:                if ((nr = read(ttyfd, buf, sizeof(buf))) > 0 &&
                    274:                    buf[nr - 1] == '\n')
                    275:                        buf[nr - 1] = '\0';
                    276:        }
                    277:        if (ttyfd < 0 || nr <= 0) {
                    278:                /* no tty or error reading, pretend user entered 'return' */
                    279:                putchar('\n');
                    280:                buf[0] = '\0';
1.13      deraadt   281:        }
1.1       deraadt   282: }
                    283:
1.13      deraadt   284: /*
                    285:  * How to handle certain events when not in a critical region.
                    286:  */
1.1       deraadt   287: void
1.13      deraadt   288: set_signals(int reset)
1.1       deraadt   289: {
1.13      deraadt   290:        static sig_t    hupval, intval;
1.1       deraadt   291:
1.13      deraadt   292:        if (!reset) {
                    293:                hupval = signal(SIGHUP, SIG_IGN);
                    294:                if (hupval != SIG_IGN)
                    295:                        hupval = (sig_t) my_exit;
                    296:                intval = signal(SIGINT, SIG_IGN);
                    297:                if (intval != SIG_IGN)
                    298:                        intval = (sig_t) my_exit;
                    299:        }
                    300:        signal(SIGHUP, hupval);
                    301:        signal(SIGINT, intval);
1.1       deraadt   302: }
                    303:
1.13      deraadt   304: /*
                    305:  * How to handle certain events when in a critical region.
                    306:  */
1.1       deraadt   307: void
1.13      deraadt   308: ignore_signals(void)
1.1       deraadt   309: {
1.13      deraadt   310:        signal(SIGHUP, SIG_IGN);
                    311:        signal(SIGINT, SIG_IGN);
1.1       deraadt   312: }
                    313:
1.13      deraadt   314: /*
                    315:  * Make sure we'll have the directories to create a file. If `striplast' is
1.25      otto      316:  * true, ignore the last element of `filename'.
1.13      deraadt   317:  */
1.1       deraadt   318:
                    319: void
1.20      otto      320: makedirs(const char *filename, bool striplast)
1.1       deraadt   321: {
1.13      deraadt   322:        char    *tmpbuf;
1.9       provos    323:
1.13      deraadt   324:        if ((tmpbuf = strdup(filename)) == NULL)
                    325:                fatal("out of memory\n");
1.9       provos    326:
1.13      deraadt   327:        if (striplast) {
                    328:                char    *s = strrchr(tmpbuf, '/');
1.34      oga       329:                if (s == NULL) {
                    330:                        free(tmpbuf);
1.13      deraadt   331:                        return; /* nothing to be done */
1.34      oga       332:                }
1.13      deraadt   333:                *s = '\0';
                    334:        }
1.31      otto      335:        if (mkpath(tmpbuf) != 0)
1.30      espie     336:                pfatal("creation of %s failed", tmpbuf);
                    337:        free(tmpbuf);
1.1       deraadt   338: }
                    339:
1.13      deraadt   340: /*
                    341:  * Make filenames more reasonable.
                    342:  */
                    343: char *
1.27      millert   344: fetchname(const char *at, bool *exists, int strip_leading)
1.13      deraadt   345: {
1.27      millert   346:        char            *fullname, *name, *t;
1.29      otto      347:        int             sleading, tab;
1.20      otto      348:        struct stat     filestat;
1.1       deraadt   349:
1.20      otto      350:        if (at == NULL || *at == '\0')
1.16      otto      351:                return NULL;
1.36      deraadt   352:        while (isspace((unsigned char)*at))
1.13      deraadt   353:                at++;
1.1       deraadt   354: #ifdef DEBUGGING
1.13      deraadt   355:        if (debug & 128)
1.27      millert   356:                say("fetchname %s %d\n", at, strip_leading);
1.1       deraadt   357: #endif
1.22      millert   358:        /* So files can be created by diffing against /dev/null.  */
                    359:        if (strnEQ(at, _PATH_DEVNULL, sizeof(_PATH_DEVNULL) - 1))
                    360:                return NULL;
1.13      deraadt   361:        name = fullname = t = savestr(at);
                    362:
1.29      otto      363:        tab = strchr(t, '\t') != NULL;
1.21      millert   364:        /* Strip off up to `strip_leading' path components and NUL terminate. */
1.29      otto      365:        for (sleading = strip_leading; *t != '\0' && ((tab && *t != '\t') ||
1.36      deraadt   366:            !isspace((unsigned char)*t)); t++) {
1.21      millert   367:                if (t[0] == '/' && t[1] != '/' && t[1] != '\0')
1.24      otto      368:                        if (--sleading >= 0)
1.13      deraadt   369:                                name = t + 1;
1.21      millert   370:        }
1.13      deraadt   371:        *t = '\0';
                    372:
                    373:        /*
                    374:         * If no -p option was given (957 is the default value!), we were
                    375:         * given a relative pathname, and the leading directories that we
                    376:         * just stripped off all exist, put them back on.
                    377:         */
                    378:        if (strip_leading == 957 && name != fullname && *fullname != '/') {
                    379:                name[-1] = '\0';
                    380:                if (stat(fullname, &filestat) == 0 && S_ISDIR(filestat.st_mode)) {
                    381:                        name[-1] = '/';
                    382:                        name = fullname;
                    383:                }
1.1       deraadt   384:        }
1.13      deraadt   385:        name = savestr(name);
                    386:        free(fullname);
1.1       deraadt   387:
1.27      millert   388:        *exists = stat(name, &filestat) == 0;
                    389:        return name;
                    390: }
                    391:
                    392: /*
1.37      tobias    393:  * Takes the name returned by fetchname and looks in RCS directory
1.27      millert   394:  * for a checked in version.
                    395:  */
                    396: char *
                    397: checked_in(char *file)
                    398: {
                    399:        char            *filebase, *filedir, tmpbuf[MAXPATHLEN];
                    400:        struct stat     filestat;
                    401:
                    402:        filebase = basename(file);
                    403:        filedir = dirname(file);
1.13      deraadt   404:
                    405: #define try(f, a1, a2, a3) \
1.27      millert   406: (snprintf(tmpbuf, sizeof tmpbuf, f, a1, a2, a3), stat(tmpbuf, &filestat) == 0)
1.13      deraadt   407:
1.27      millert   408:        if (try("%s/RCS/%s%s", filedir, filebase, RCSSUFFIX) ||
                    409:            try("%s/RCS/%s%s", filedir, filebase, "") ||
1.37      tobias    410:            try("%s/%s%s", filedir, filebase, RCSSUFFIX))
1.27      millert   411:                return file;
                    412:
                    413:        return NULL;
1.12      deraadt   414: }
                    415:
                    416: void
1.13      deraadt   417: version(void)
1.12      deraadt   418: {
1.13      deraadt   419:        fprintf(stderr, "Patch version 2.0-12u8-OpenBSD\n");
1.19      millert   420:        my_exit(EXIT_SUCCESS);
1.16      otto      421: }
                    422:
                    423: /*
                    424:  * Exit with cleanup.
                    425:  */
                    426: void
                    427: my_exit(int status)
                    428: {
                    429:        unlink(TMPINNAME);
                    430:        if (!toutkeep)
                    431:                unlink(TMPOUTNAME);
                    432:        if (!trejkeep)
                    433:                unlink(TMPREJNAME);
                    434:        unlink(TMPPATNAME);
                    435:        exit(status);
1.1       deraadt   436: }