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

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