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

1.31    ! otto        1: /*     $OpenBSD: util.c,v 1.30 2005/05/16 15:22:46 espie 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.31    ! otto       30: static const char rcsid[] = "$OpenBSD: util.c,v 1.30 2005/05/16 15:22:46 espie 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.9       provos    310:
1.13      deraadt   311:        if ((tmpbuf = strdup(filename)) == NULL)
                    312:                fatal("out of memory\n");
1.9       provos    313:
1.13      deraadt   314:        if (striplast) {
                    315:                char    *s = strrchr(tmpbuf, '/');
                    316:                if (s == NULL)
                    317:                        return; /* nothing to be done */
                    318:                *s = '\0';
                    319:        }
1.31    ! otto      320:        if (mkpath(tmpbuf) != 0)
1.30      espie     321:                pfatal("creation of %s failed", tmpbuf);
                    322:        free(tmpbuf);
1.1       deraadt   323: }
                    324:
1.13      deraadt   325: /*
                    326:  * Make filenames more reasonable.
                    327:  */
                    328: char *
1.27      millert   329: fetchname(const char *at, bool *exists, int strip_leading)
1.13      deraadt   330: {
1.27      millert   331:        char            *fullname, *name, *t;
1.29      otto      332:        int             sleading, tab;
1.20      otto      333:        struct stat     filestat;
1.1       deraadt   334:
1.20      otto      335:        if (at == NULL || *at == '\0')
1.16      otto      336:                return NULL;
1.13      deraadt   337:        while (isspace(*at))
                    338:                at++;
1.1       deraadt   339: #ifdef DEBUGGING
1.13      deraadt   340:        if (debug & 128)
1.27      millert   341:                say("fetchname %s %d\n", at, strip_leading);
1.1       deraadt   342: #endif
1.22      millert   343:        /* So files can be created by diffing against /dev/null.  */
                    344:        if (strnEQ(at, _PATH_DEVNULL, sizeof(_PATH_DEVNULL) - 1))
                    345:                return NULL;
1.13      deraadt   346:        name = fullname = t = savestr(at);
                    347:
1.29      otto      348:        tab = strchr(t, '\t') != NULL;
1.21      millert   349:        /* Strip off up to `strip_leading' path components and NUL terminate. */
1.29      otto      350:        for (sleading = strip_leading; *t != '\0' && ((tab && *t != '\t') ||
                    351:            !isspace(*t)); t++) {
1.21      millert   352:                if (t[0] == '/' && t[1] != '/' && t[1] != '\0')
1.24      otto      353:                        if (--sleading >= 0)
1.13      deraadt   354:                                name = t + 1;
1.21      millert   355:        }
1.13      deraadt   356:        *t = '\0';
                    357:
                    358:        /*
                    359:         * If no -p option was given (957 is the default value!), we were
                    360:         * given a relative pathname, and the leading directories that we
                    361:         * just stripped off all exist, put them back on.
                    362:         */
                    363:        if (strip_leading == 957 && name != fullname && *fullname != '/') {
                    364:                name[-1] = '\0';
                    365:                if (stat(fullname, &filestat) == 0 && S_ISDIR(filestat.st_mode)) {
                    366:                        name[-1] = '/';
                    367:                        name = fullname;
                    368:                }
1.1       deraadt   369:        }
1.13      deraadt   370:        name = savestr(name);
                    371:        free(fullname);
1.1       deraadt   372:
1.27      millert   373:        *exists = stat(name, &filestat) == 0;
                    374:        return name;
                    375: }
                    376:
                    377: /*
                    378:  * Takes the name returned by fetchname and looks in RCS/SCCS directories
                    379:  * for a checked in version.
                    380:  */
                    381: char *
                    382: checked_in(char *file)
                    383: {
                    384:        char            *filebase, *filedir, tmpbuf[MAXPATHLEN];
                    385:        struct stat     filestat;
                    386:
                    387:        filebase = basename(file);
                    388:        filedir = dirname(file);
1.13      deraadt   389:
                    390: #define try(f, a1, a2, a3) \
1.27      millert   391: (snprintf(tmpbuf, sizeof tmpbuf, f, a1, a2, a3), stat(tmpbuf, &filestat) == 0)
1.13      deraadt   392:
1.27      millert   393:        if (try("%s/RCS/%s%s", filedir, filebase, RCSSUFFIX) ||
                    394:            try("%s/RCS/%s%s", filedir, filebase, "") ||
                    395:            try("%s/%s%s", filedir, filebase, RCSSUFFIX) ||
                    396:            try("%s/SCCS/%s%s", filedir, SCCSPREFIX, filebase) ||
                    397:            try("%s/%s%s", filedir, SCCSPREFIX, filebase))
                    398:                return file;
                    399:
                    400:        return NULL;
1.12      deraadt   401: }
                    402:
                    403: void
1.13      deraadt   404: version(void)
1.12      deraadt   405: {
1.13      deraadt   406:        fprintf(stderr, "Patch version 2.0-12u8-OpenBSD\n");
1.19      millert   407:        my_exit(EXIT_SUCCESS);
1.16      otto      408: }
                    409:
                    410: /*
                    411:  * Exit with cleanup.
                    412:  */
                    413: void
                    414: my_exit(int status)
                    415: {
                    416:        unlink(TMPINNAME);
                    417:        if (!toutkeep)
                    418:                unlink(TMPOUTNAME);
                    419:        if (!trejkeep)
                    420:                unlink(TMPREJNAME);
                    421:        unlink(TMPPATNAME);
                    422:        exit(status);
1.1       deraadt   423: }