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

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