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

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