[BACK]Return to util.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / usr.bin / patch

Annotation of src/usr.bin/patch/util.c, Revision 1.21

1.21    ! skd         1: /*     $NetBSD: util.c,v 1.20 2004/10/30 21:52:09 dsl Exp $    */
1.16      itojun      2:
                      3: /*
                      4:  * Copyright (c) 1988, Larry Wall
                      5:  *
                      6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following condition
                      8:  * is met:
                      9:  *  1. Redistributions of source code must retain the above copyright
                     10:  *     notice, this condition and the following disclaimer.
                     11:  *
                     12:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     13:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     14:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     15:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     16:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     17:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     18:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     19:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     20:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     21:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     22:  * SUCH DAMAGE.
                     23:  */
                     24:
1.5       christos   25: #include <sys/cdefs.h>
1.2       mycroft    26: #ifndef lint
1.21    ! skd        27: __RCSID("$NetBSD: util.c,v 1.20 2004/10/30 21:52:09 dsl Exp $");
1.2       mycroft    28: #endif /* not lint */
                     29:
1.12      kristerw   30: #include <sys/param.h>
                     31:
1.1       cgd        32: #include "EXTERN.h"
                     33: #include "common.h"
                     34: #include "INTERN.h"
                     35: #include "util.h"
                     36: #include "backupfile.h"
1.10      kristerw   37:
1.5       christos   38: #include <stdarg.h>
                     39: #include <stdlib.h>
                     40: #include <unistd.h>
                     41: #include <fcntl.h>
1.1       cgd        42:
1.11      kristerw   43: /*
                     44:  * Rename a file, copying it if necessary.
                     45:  */
1.1       cgd        46: int
1.9       kristerw   47: move_file(char *from, char *to)
1.1       cgd        48: {
1.12      kristerw   49:        char bakname[MAXPATHLEN];
1.11      kristerw   50:        char *s;
1.14      kristerw   51:        size_t i;
1.11      kristerw   52:        int fromfd;
1.1       cgd        53:
1.21    ! skd        54:        if ( check_only == TRUE )
        !            55:                return(0);
        !            56:
1.11      kristerw   57:        /* to stdout? */
1.1       cgd        58:
1.11      kristerw   59:        if (strEQ(to, "-")) {
1.1       cgd        60: #ifdef DEBUGGING
1.11      kristerw   61:                if (debug & 4)
                     62:                        say("Moving %s to stdout.\n", from);
1.1       cgd        63: #endif
1.11      kristerw   64:                fromfd = open(from, 0);
                     65:                if (fromfd < 0)
                     66:                        pfatal("internal error, can't reopen %s", from);
                     67:                while ((i = read(fromfd, buf, sizeof buf)) > 0)
                     68:                        if (write(1, buf, i) != 1)
                     69:                                pfatal("write failed");
                     70:                Close(fromfd);
                     71:                return 0;
                     72:        }
1.1       cgd        73:
1.11      kristerw   74:        if (origprae) {
1.18      itojun     75:                strlcpy(bakname, origprae, sizeof(bakname));
                     76:                strlcat(bakname, to, sizeof(bakname));
1.11      kristerw   77:        } else {
1.1       cgd        78: #ifndef NODIR
1.11      kristerw   79:                char *backupname = find_backup_file_name(to);
1.18      itojun     80:                strlcpy(bakname, backupname, sizeof(bakname));
1.11      kristerw   81:                free(backupname);
1.1       cgd        82: #else /* NODIR */
1.18      itojun     83:                strlcpy(bakname, to, sizeof(bakname));
                     84:                strlcat(bakname, simple_backup_suffix, sizeof(bakname));
1.1       cgd        85: #endif /* NODIR */
1.11      kristerw   86:        }
1.1       cgd        87:
1.11      kristerw   88:        if (stat(to, &filestat) == 0) { /* output file exists */
                     89:                dev_t to_device = filestat.st_dev;
                     90:                ino_t to_inode  = filestat.st_ino;
                     91:                char *simplename = bakname;
1.1       cgd        92:
1.11      kristerw   93:                for (s = bakname; *s; s++) {
                     94:                        if (*s == '/')
                     95:                                simplename = s + 1;
                     96:                }
                     97:                /*
                     98:                 * Find a backup name that is not the same file.
                     99:                 * Change the first lowercase char into uppercase;
                    100:                 * if that isn't sufficient, chop off the first char
                    101:                 * and try again.
                    102:                 */
                    103:                while (stat(bakname, &filestat) == 0 &&
                    104:                       to_device == filestat.st_dev &&
                    105:                       to_inode == filestat.st_ino) {
                    106:                        /* Skip initial non-lowercase chars. */
                    107:                        for (s = simplename;
1.20      dsl       108:                             *s && *s == toupper((unsigned char)*s);
1.11      kristerw  109:                             s++)
                    110:                                ;
                    111:                        if (*s)
1.20      dsl       112:                                *s = toupper((unsigned char)*s);
1.11      kristerw  113:                        else
1.19      itojun    114:                                strcpy(simplename, simplename + 1);
1.11      kristerw  115:                }
                    116:                while (unlink(bakname) >= 0)
                    117:                        ;       /* while() is for benefit of Eunice */
                    118: #ifdef DEBUGGING
                    119:                if (debug & 4)
                    120:                        say("Moving %s to %s.\n", to, bakname);
                    121: #endif
                    122:                if (link(to, bakname) < 0) {
                    123:                        /*
                    124:                         * Maybe `to' is a symlink into a different file
                    125:                         * system. Copying replaces the symlink with a file;
                    126:                         * using rename would be better.
                    127:                         */
                    128:                        int tofd;
                    129:                        int bakfd;
                    130:
                    131:                        bakfd = creat(bakname, 0666);
                    132:                        if (bakfd < 0) {
                    133:                                say("Can't backup %s, output is in %s: %s\n",
                    134:                                    to, from, strerror(errno));
                    135:                                return -1;
                    136:                        }
                    137:                        tofd = open(to, 0);
                    138:                        if (tofd < 0)
                    139:                                pfatal("internal error, can't open %s", to);
                    140:                        while ((i = read(tofd, buf, sizeof buf)) > 0)
                    141:                                if (write(bakfd, buf, i) != i)
                    142:                                        pfatal("write failed");
                    143:                        Close(tofd);
                    144:                        Close(bakfd);
                    145:                }
                    146:                while (unlink(to) >= 0) ;
1.1       cgd       147:        }
                    148: #ifdef DEBUGGING
                    149:        if (debug & 4)
1.11      kristerw  150:                say("Moving %s to %s.\n", from, to);
1.1       cgd       151: #endif
1.11      kristerw  152:        if (link(from, to) < 0) {               /* different file system? */
                    153:                int tofd;
                    154:
                    155:                tofd = creat(to, 0666);
                    156:                if (tofd < 0) {
                    157:                        say("Can't create %s, output is in %s: %s\n",
                    158:                            to, from, strerror(errno));
                    159:                        return -1;
                    160:                }
                    161:                fromfd = open(from, 0);
                    162:                if (fromfd < 0)
                    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 failed");
                    167:                Close(fromfd);
                    168:                Close(tofd);
1.1       cgd       169:        }
1.11      kristerw  170:        Unlink(from);
                    171:        return 0;
                    172: }
                    173:
                    174: /*
                    175:  * Copy a file.
                    176:  */
                    177: void
                    178: copy_file(char *from, char *to)
                    179: {
1.9       kristerw  180:        int tofd;
1.11      kristerw  181:        int fromfd;
1.14      kristerw  182:        size_t i;
1.11      kristerw  183:
1.1       cgd       184:        tofd = creat(to, 0666);
1.11      kristerw  185:        if (tofd < 0)
                    186:                pfatal("can't create %s", to);
1.1       cgd       187:        fromfd = open(from, 0);
                    188:        if (fromfd < 0)
1.11      kristerw  189:                pfatal("internal error, can't reopen %s", from);
                    190:        while ((i = read(fromfd, buf, sizeof buf)) > 0)
                    191:                if (write(tofd, buf, i) != i)
                    192:                        pfatal("write to %s failed", to);
1.1       cgd       193:        Close(fromfd);
                    194:        Close(tofd);
                    195: }
                    196:
1.11      kristerw  197: /*
1.12      kristerw  198:  * malloc with result test.
                    199:  */
                    200: void *
                    201: xmalloc(size_t size)
                    202: {
                    203:        void *p;
                    204:
                    205:        if ((p = malloc(size)) == NULL)
                    206:                fatal("out of memory\n");
                    207:        return p;
                    208: }
                    209:
                    210: /*
1.15      kristerw  211:  * realloc with result test.
1.12      kristerw  212:  */
1.15      kristerw  213: void *
                    214: xrealloc(void *ptr, size_t size)
1.12      kristerw  215: {
1.15      kristerw  216:        void *p;
1.12      kristerw  217:
1.15      kristerw  218:        if ((p = realloc(ptr, size)) == NULL)
1.12      kristerw  219:                fatal("out of memory\n");
                    220:        return p;
                    221: }
                    222:
                    223: /*
1.15      kristerw  224:  * strdup with result test.
1.11      kristerw  225:  */
1.1       cgd       226: char *
1.15      kristerw  227: xstrdup(const char *s)
1.1       cgd       228: {
1.15      kristerw  229:        char *p;
1.1       cgd       230:
1.15      kristerw  231:        if ((p = strdup(s)) == NULL)
                    232:                fatal("out of memory\n");
                    233:        return p;
1.1       cgd       234: }
                    235:
1.11      kristerw  236: /*
1.12      kristerw  237:  * Vanilla terminal output.
1.11      kristerw  238:  */
1.1       cgd       239: void
1.5       christos  240: say(const char *pat, ...)
1.1       cgd       241: {
1.11      kristerw  242:        va_list ap;
                    243:        va_start(ap, pat);
1.5       christos  244:
1.11      kristerw  245:        vfprintf(stderr, pat, ap);
                    246:        va_end(ap);
                    247:        Fflush(stderr);
1.1       cgd       248: }
                    249:
1.11      kristerw  250: /*
                    251:  * Terminal output, pun intended.
                    252:  */
1.1       cgd       253: void                           /* very void */
1.5       christos  254: fatal(const char *pat, ...)
1.1       cgd       255: {
1.11      kristerw  256:        va_list ap;
                    257:        va_start(ap, pat);
1.5       christos  258:
1.11      kristerw  259:        fprintf(stderr, "patch: **** ");
                    260:        vfprintf(stderr, pat, ap);
                    261:        va_end(ap);
                    262:        my_exit(1);
1.1       cgd       263: }
                    264:
1.11      kristerw  265: /*
                    266:  * Say something from patch, something from the system, then silence...
                    267:  */
1.1       cgd       268: void                           /* very void */
1.5       christos  269: pfatal(const char *pat, ...)
1.1       cgd       270: {
1.11      kristerw  271:        va_list ap;
                    272:        int errnum = errno;
                    273:        va_start(ap, pat);
1.5       christos  274:
1.11      kristerw  275:        fprintf(stderr, "patch: **** ");
                    276:        vfprintf(stderr, pat, ap);
                    277:        fprintf(stderr, ": %s\n", strerror(errnum));
                    278:        va_end(ap);
                    279:        my_exit(1);
1.1       cgd       280: }
                    281:
1.11      kristerw  282: /*
                    283:  * Get a response from the user, somehow or other.
                    284:  */
1.1       cgd       285: void
1.5       christos  286: ask(const char *pat, ...)
1.1       cgd       287: {
1.11      kristerw  288:        int ttyfd;
                    289:        int r;
                    290:        bool tty2 = isatty(2);
                    291:        va_list ap;
                    292:        va_start(ap, pat);
                    293:
                    294:        (void)vsprintf(buf, pat, ap);
                    295:        va_end(ap);
                    296:        Fflush(stderr);
                    297:        write(2, buf, strlen(buf));
                    298:        if (tty2) {                     /* might be redirected to a file */
                    299:                r = read(2, buf, sizeof buf);
                    300:        } else if (isatty(1)) {         /* this may be new file output */
                    301:                Fflush(stdout);
                    302:                write(1, buf, strlen(buf));
                    303:                r = read(1, buf, sizeof buf);
                    304:        } else if ((ttyfd = open("/dev/tty", 2)) >= 0 && isatty(ttyfd)) {
1.13      wiz       305:                                        /* might be deleted or unwritable */
1.11      kristerw  306:                write(ttyfd, buf, strlen(buf));
                    307:                r = read(ttyfd, buf, sizeof buf);
                    308:                Close(ttyfd);
                    309:        } else if (isatty(0)) {         /* this is probably patch input */
                    310:                Fflush(stdin);
                    311:                write(0, buf, strlen(buf));
                    312:                r = read(0, buf, sizeof buf);
                    313:        } else {                        /* no terminal at all--default it */
                    314:                buf[0] = '\n';
                    315:                r = 1;
                    316:        }
                    317:        if (r <= 0)
                    318:                buf[0] = 0;
                    319:        else
                    320:                buf[r] = '\0';
                    321:        if (!tty2)
                    322:                say("%s", buf);
1.1       cgd       323: }
                    324:
1.11      kristerw  325: /*
                    326:  * How to handle certain events when not in a critical region.
                    327:  */
1.1       cgd       328: void
1.9       kristerw  329: set_signals(int reset)
1.1       cgd       330: {
1.11      kristerw  331:        static void (*hupval)(int);
                    332:        static void (*intval)(int);
1.1       cgd       333:
1.11      kristerw  334:        if (!reset) {
                    335:                hupval = signal(SIGHUP, SIG_IGN);
                    336:                if (hupval != SIG_IGN)
                    337:                        hupval = my_exit;
                    338:                intval = signal(SIGINT, SIG_IGN);
                    339:                if (intval != SIG_IGN)
                    340:                        intval = my_exit;
                    341:        }
                    342:        Signal(SIGHUP, hupval);
                    343:        Signal(SIGINT, intval);
1.1       cgd       344: }
                    345:
1.11      kristerw  346: /*
                    347:  * How to handle certain events when in a critical region.
                    348:  */
1.1       cgd       349: void
                    350: ignore_signals()
                    351: {
1.11      kristerw  352:        Signal(SIGHUP, SIG_IGN);
                    353:        Signal(SIGINT, SIG_IGN);
1.1       cgd       354: }
                    355:
1.11      kristerw  356: /*
                    357:  * Make sure we'll have the directories to create a file.
                    358:  * If `striplast' is TRUE, ignore the last element of `filename'.
                    359:  */
1.1       cgd       360: void
1.9       kristerw  361: makedirs(char *filename, bool striplast)
1.1       cgd       362: {
1.12      kristerw  363:        char tmpbuf[MAXPATHLEN];
1.11      kristerw  364:        char *s = tmpbuf;
1.12      kristerw  365:        char *dirv[MAXPATHLEN]; /* Point to the NULs between elements.  */
1.11      kristerw  366:        int i;
                    367:        int dirvp = 0;          /* Number of finished entries in dirv. */
                    368:
                    369:        /*
                    370:         * Copy `filename' into `tmpbuf' with a NUL instead of a slash
                    371:         * between the directories.
                    372:         */
                    373:        while (*filename) {
                    374:                if (*filename == '/') {
                    375:                        filename++;
                    376:                        dirv[dirvp++] = s;
                    377:                        *s++ = '\0';
                    378:                } else {
                    379:                        *s++ = *filename++;
                    380:                }
                    381:        }
                    382:        *s = '\0';
                    383:        dirv[dirvp] = s;
                    384:        if (striplast)
                    385:                dirvp--;
                    386:        if (dirvp < 0)
                    387:                return;
                    388:
1.18      itojun    389:        strlcpy(buf, "mkdir", sizeof(buf));
1.11      kristerw  390:        s = buf;
                    391:        for (i = 0; i <= dirvp; i++) {
                    392:                struct stat sbuf;
                    393:
                    394:                if (stat(tmpbuf, &sbuf) && errno == ENOENT) {
                    395:                        while (*s)
                    396:                                s++;
                    397:                        *s++ = ' ';
1.18      itojun    398:                        strlcpy(s, tmpbuf, sizeof(buf) - (s - buf));
1.11      kristerw  399:                }
                    400:                *dirv[i] = '/';
                    401:        }
                    402:        if (s != buf)
                    403:                system(buf);
1.1       cgd       404: }
                    405:
1.11      kristerw  406: /*
                    407:  * Make filenames more reasonable.
                    408:  */
1.1       cgd       409: char *
1.9       kristerw  410: fetchname(char *at, int strip_leading, int assume_exists)
1.1       cgd       411: {
1.11      kristerw  412:        char *fullname;
                    413:        char *name;
                    414:        char *t;
1.12      kristerw  415:        char tmpbuf[MAXPATHLEN];
1.11      kristerw  416:        int sleading = strip_leading;
                    417:
                    418:        if (!at)
                    419:                return NULL;
                    420:        while (isspace((unsigned char)*at))
                    421:                at++;
1.1       cgd       422: #ifdef DEBUGGING
1.11      kristerw  423:        if (debug & 128)
                    424:                say("fetchname %s %d %d\n", at, strip_leading, assume_exists);
1.1       cgd       425: #endif
1.11      kristerw  426:        filename_is_dev_null = FALSE;
                    427:        if (strnEQ(at, "/dev/null", 9)) {
                    428:                /* So files can be created by diffing against /dev/null. */
                    429:                filename_is_dev_null = TRUE;
                    430:                return NULL;
                    431:        }
1.12      kristerw  432:        name = fullname = t = xstrdup(at);
1.11      kristerw  433:
                    434:        /* Strip off up to `sleading' leading slashes and null terminate. */
                    435:        for (; *t && !isspace((unsigned char)*t); t++)
                    436:                if (*t == '/')
                    437:                        if (--sleading >= 0)
                    438:                                name = t + 1;
                    439:        *t = '\0';
                    440:
                    441:        /*
                    442:         * If no -p option was given (957 is the default value!),
                    443:         * we were given a relative pathname,
                    444:         * and the leading directories that we just stripped off all exist,
                    445:         * put them back on.
                    446:         */
                    447:        if (strip_leading == 957 && name != fullname && *fullname != '/') {
                    448:                name[-1] = '\0';
                    449:                if (stat(fullname, &filestat) == 0 &&
                    450:                    S_ISDIR(filestat.st_mode)) {
                    451:                        name[-1] = '/';
                    452:                        name = fullname;
                    453:                }
                    454:        }
                    455:
1.12      kristerw  456:        name = xstrdup(name);
1.11      kristerw  457:        free(fullname);
                    458:
                    459:        if (stat(name, &filestat) && !assume_exists) {
                    460:                char *filebase = basename(name);
1.14      kristerw  461:                size_t pathlen = filebase - name;
1.11      kristerw  462:
                    463:                /* Put any leading path into `tmpbuf'. */
1.17      itojun    464:                if (pathlen >= sizeof(tmpbuf))
                    465:                        return NULL;
1.11      kristerw  466:                strncpy(tmpbuf, name, pathlen);
1.17      itojun    467:                tmpbuf[pathlen] = '\0';
1.11      kristerw  468:
                    469: #define try(f, a1, a2) \
1.18      itojun    470:     (snprintf(tmpbuf + pathlen, sizeof(tmpbuf) - pathlen, f, a1, a2), \
                    471:      stat(tmpbuf, &filestat) == 0)
1.11      kristerw  472: #define try1(f, a1) \
1.18      itojun    473:     (snprintf(tmpbuf + pathlen, sizeof(tmpbuf) - pathlen, f, a1), \
                    474:      stat(tmpbuf, &filestat) == 0)
1.11      kristerw  475:                if (try("RCS/%s%s", filebase, RCSSUFFIX) ||
                    476:                    try1("RCS/%s"  , filebase) ||
                    477:                    try(    "%s%s", filebase, RCSSUFFIX) ||
                    478:                    try("SCCS/%s%s", SCCSPREFIX, filebase) ||
                    479:                    try(     "%s%s", SCCSPREFIX, filebase))
                    480:                        return name;
                    481:                free(name);
                    482:                name = NULL;
                    483:        }
1.1       cgd       484:
1.11      kristerw  485:        return name;
1.1       cgd       486: }

CVSweb <webmaster@jp.NetBSD.org>