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

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