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

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