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

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