[BACK]Return to touch.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / touch

Annotation of src/usr.bin/touch/touch.c, Revision 1.1

1.1     ! deraadt     1: /*     $NetBSD: touch.c,v 1.11 1995/08/31 22:10:06 jtc Exp $   */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 1993
        !             5:  *     The Regents of the University of California.  All rights reserved.
        !             6:  *
        !             7:  * Redistribution and use in source and binary forms, with or without
        !             8:  * modification, are permitted provided that the following conditions
        !             9:  * are met:
        !            10:  * 1. Redistributions of source code must retain the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer.
        !            12:  * 2. Redistributions in binary form must reproduce the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer in the
        !            14:  *    documentation and/or other materials provided with the distribution.
        !            15:  * 3. All advertising materials mentioning features or use of this software
        !            16:  *    must display the following acknowledgement:
        !            17:  *     This product includes software developed by the University of
        !            18:  *     California, Berkeley and its contributors.
        !            19:  * 4. Neither the name of the University nor the names of its contributors
        !            20:  *    may be used to endorse or promote products derived from this software
        !            21:  *    without specific prior written permission.
        !            22:  *
        !            23:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            24:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            25:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            26:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            27:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            28:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            29:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            31:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            32:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            33:  * SUCH DAMAGE.
        !            34:  */
        !            35:
        !            36: #ifndef lint
        !            37: static char copyright[] =
        !            38: "@(#) Copyright (c) 1993\n\
        !            39:        The Regents of the University of California.  All rights reserved.\n";
        !            40: #endif /* not lint */
        !            41:
        !            42: #ifndef lint
        !            43: #if 0
        !            44: static char sccsid[] = "@(#)touch.c    8.2 (Berkeley) 4/28/95";
        !            45: #endif
        !            46: static char rcsid[] = "$NetBSD: touch.c,v 1.11 1995/08/31 22:10:06 jtc Exp $";
        !            47: #endif /* not lint */
        !            48:
        !            49: #include <sys/types.h>
        !            50: #include <sys/stat.h>
        !            51: #include <sys/time.h>
        !            52:
        !            53: #include <err.h>
        !            54: #include <errno.h>
        !            55: #include <fcntl.h>
        !            56: #include <stdio.h>
        !            57: #include <stdlib.h>
        !            58: #include <string.h>
        !            59: #include <locale.h>
        !            60: #include <time.h>
        !            61: #include <unistd.h>
        !            62:
        !            63: int    rw __P((char *, struct stat *, int));
        !            64: void   stime_arg1 __P((char *, struct timeval *));
        !            65: void   stime_arg2 __P((char *, int, struct timeval *));
        !            66: void   stime_file __P((char *, struct timeval *));
        !            67: void   usage __P((void));
        !            68:
        !            69: int
        !            70: main(argc, argv)
        !            71:        int argc;
        !            72:        char *argv[];
        !            73: {
        !            74:        struct stat sb;
        !            75:        struct timeval tv[2];
        !            76:        int aflag, cflag, fflag, mflag, ch, fd, len, rval, timeset;
        !            77:        char *p;
        !            78:
        !            79:        setlocale(LC_ALL, "");
        !            80:
        !            81:        aflag = cflag = fflag = mflag = timeset = 0;
        !            82:        if (gettimeofday(&tv[0], NULL))
        !            83:                err(1, "gettimeofday");
        !            84:
        !            85:        while ((ch = getopt(argc, argv, "acfmr:t:")) != EOF)
        !            86:                switch(ch) {
        !            87:                case 'a':
        !            88:                        aflag = 1;
        !            89:                        break;
        !            90:                case 'c':
        !            91:                        cflag = 1;
        !            92:                        break;
        !            93:                case 'f':
        !            94:                        fflag = 1;
        !            95:                        break;
        !            96:                case 'm':
        !            97:                        mflag = 1;
        !            98:                        break;
        !            99:                case 'r':
        !           100:                        timeset = 1;
        !           101:                        stime_file(optarg, tv);
        !           102:                        break;
        !           103:                case 't':
        !           104:                        timeset = 1;
        !           105:                        stime_arg1(optarg, tv);
        !           106:                        break;
        !           107:                case '?':
        !           108:                default:
        !           109:                        usage();
        !           110:                }
        !           111:        argc -= optind;
        !           112:        argv += optind;
        !           113:
        !           114:        /* Default is both -a and -m. */
        !           115:        if (aflag == 0 && mflag == 0)
        !           116:                aflag = mflag = 1;
        !           117:
        !           118:        /*
        !           119:         * If no -r or -t flag, at least two operands, the first of which
        !           120:         * is an 8 or 10 digit number, use the obsolete time specification.
        !           121:         */
        !           122:        if (!timeset && argc > 1) {
        !           123:                (void)strtol(argv[0], &p, 10);
        !           124:                len = p - argv[0];
        !           125:                if (*p == '\0' && (len == 8 || len == 10)) {
        !           126:                        timeset = 1;
        !           127:                        stime_arg2(*argv++, len == 10, tv);
        !           128:                }
        !           129:        }
        !           130:
        !           131:        /* Otherwise use the current time of day. */
        !           132:        if (!timeset)
        !           133:                tv[1] = tv[0];
        !           134:
        !           135:        if (*argv == NULL)
        !           136:                usage();
        !           137:
        !           138:        for (rval = 0; *argv; ++argv) {
        !           139:                /* See if the file exists. */
        !           140:                if (stat(*argv, &sb))
        !           141:                        if (!cflag) {
        !           142:                                /* Create the file. */
        !           143:                                fd = open(*argv,
        !           144:                                    O_WRONLY | O_CREAT, DEFFILEMODE);
        !           145:                                if (fd == -1 || fstat(fd, &sb) || close(fd)) {
        !           146:                                        rval = 1;
        !           147:                                        warn("%s", *argv);
        !           148:                                        continue;
        !           149:                                }
        !           150:
        !           151:                                /* If using the current time, we're done. */
        !           152:                                if (!timeset)
        !           153:                                        continue;
        !           154:                        } else
        !           155:                                continue;
        !           156:
        !           157:                if (!aflag)
        !           158:                        TIMESPEC_TO_TIMEVAL(&tv[0], &sb.st_atimespec);
        !           159:                if (!mflag)
        !           160:                        TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec);
        !           161:
        !           162:                /* Try utimes(2). */
        !           163:                if (!utimes(*argv, tv))
        !           164:                        continue;
        !           165:
        !           166:                /* If the user specified a time, nothing else we can do. */
        !           167:                if (timeset) {
        !           168:                        rval = 1;
        !           169:                        warn("%s", *argv);
        !           170:                }
        !           171:
        !           172:                /*
        !           173:                 * System V and POSIX 1003.1 require that a NULL argument
        !           174:                 * set the access/modification times to the current time.
        !           175:                 * The permission checks are different, too, in that the
        !           176:                 * ability to write the file is sufficient.  Take a shot.
        !           177:                 */
        !           178:                 if (!utimes(*argv, NULL))
        !           179:                        continue;
        !           180:
        !           181:                /* Try reading/writing. */
        !           182:                if (rw(*argv, &sb, fflag))
        !           183:                        rval = 1;
        !           184:        }
        !           185:        exit(rval);
        !           186: }
        !           187:
        !           188: #define        ATOI2(ar)       ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
        !           189:
        !           190: void
        !           191: stime_arg1(arg, tvp)
        !           192:        char *arg;
        !           193:        struct timeval *tvp;
        !           194: {
        !           195:        struct tm *t;
        !           196:        time_t tmptime;
        !           197:        int yearset;
        !           198:        char *p;
        !           199:                                        /* Start with the current time. */
        !           200:        tmptime = tvp[0].tv_sec;
        !           201:        if ((t = localtime(&tmptime)) == NULL)
        !           202:                err(1, "localtime");
        !           203:                                        /* [[CC]YY]MMDDhhmm[.SS] */
        !           204:        if ((p = strchr(arg, '.')) == NULL)
        !           205:                t->tm_sec = 0;          /* Seconds defaults to 0. */
        !           206:        else {
        !           207:                if (strlen(p + 1) != 2)
        !           208:                        goto terr;
        !           209:                *p++ = '\0';
        !           210:                t->tm_sec = ATOI2(p);
        !           211:        }
        !           212:
        !           213:        yearset = 0;
        !           214:        switch(strlen(arg)) {
        !           215:        case 12:                        /* CCYYMMDDhhmm */
        !           216:                t->tm_year = ATOI2(arg);
        !           217:                t->tm_year *= 100;
        !           218:                yearset = 1;
        !           219:                /* FALLTHOUGH */
        !           220:        case 10:                        /* YYMMDDhhmm */
        !           221:                if (yearset) {
        !           222:                        yearset = ATOI2(arg);
        !           223:                        t->tm_year += yearset;
        !           224:                } else {
        !           225:                        yearset = ATOI2(arg);
        !           226:                        if (yearset < 69)
        !           227:                                t->tm_year = yearset + 2000;
        !           228:                        else
        !           229:                                t->tm_year = yearset + 1900;
        !           230:                }
        !           231:                t->tm_year -= 1900;     /* Convert to UNIX time. */
        !           232:                /* FALLTHROUGH */
        !           233:        case 8:                         /* MMDDhhmm */
        !           234:                t->tm_mon = ATOI2(arg);
        !           235:                --t->tm_mon;            /* Convert from 01-12 to 00-11 */
        !           236:                t->tm_mday = ATOI2(arg);
        !           237:                t->tm_hour = ATOI2(arg);
        !           238:                t->tm_min = ATOI2(arg);
        !           239:                break;
        !           240:        default:
        !           241:                goto terr;
        !           242:        }
        !           243:
        !           244:        t->tm_isdst = -1;               /* Figure out DST. */
        !           245:        tvp[0].tv_sec = tvp[1].tv_sec = mktime(t);
        !           246:        if (tvp[0].tv_sec == -1)
        !           247: terr:          errx(1,
        !           248:        "out of range or illegal time specification: [[CC]YY]MMDDhhmm[.SS]");
        !           249:
        !           250:        tvp[0].tv_usec = tvp[1].tv_usec = 0;
        !           251: }
        !           252:
        !           253: void
        !           254: stime_arg2(arg, year, tvp)
        !           255:        char *arg;
        !           256:        int year;
        !           257:        struct timeval *tvp;
        !           258: {
        !           259:        struct tm *t;
        !           260:        time_t tmptime;
        !           261:                                        /* Start with the current time. */
        !           262:        tmptime = tvp[0].tv_sec;
        !           263:        if ((t = localtime(&tmptime)) == NULL)
        !           264:                err(1, "localtime");
        !           265:
        !           266:        t->tm_mon = ATOI2(arg);         /* MMDDhhmm[yy] */
        !           267:        --t->tm_mon;                    /* Convert from 01-12 to 00-11 */
        !           268:        t->tm_mday = ATOI2(arg);
        !           269:        t->tm_hour = ATOI2(arg);
        !           270:        t->tm_min = ATOI2(arg);
        !           271:        if (year)
        !           272:                t->tm_year = ATOI2(arg);
        !           273:
        !           274:        t->tm_isdst = -1;               /* Figure out DST. */
        !           275:        tvp[0].tv_sec = tvp[1].tv_sec = mktime(t);
        !           276:        if (tvp[0].tv_sec == -1)
        !           277:                errx(1,
        !           278:        "out of range or illegal time specification: MMDDhhmm[yy]");
        !           279:
        !           280:        tvp[0].tv_usec = tvp[1].tv_usec = 0;
        !           281: }
        !           282:
        !           283: void
        !           284: stime_file(fname, tvp)
        !           285:        char *fname;
        !           286:        struct timeval *tvp;
        !           287: {
        !           288:        struct stat sb;
        !           289:
        !           290:        if (stat(fname, &sb))
        !           291:                err(1, "%s", fname);
        !           292:        TIMESPEC_TO_TIMEVAL(tvp, &sb.st_atimespec);
        !           293:        TIMESPEC_TO_TIMEVAL(tvp + 1, &sb.st_mtimespec);
        !           294: }
        !           295:
        !           296: int
        !           297: rw(fname, sbp, force)
        !           298:        char *fname;
        !           299:        struct stat *sbp;
        !           300:        int force;
        !           301: {
        !           302:        int fd, needed_chmod, rval;
        !           303:        u_char byte;
        !           304:
        !           305:        /* Try regular files and directories. */
        !           306:        if (!S_ISREG(sbp->st_mode) && !S_ISDIR(sbp->st_mode)) {
        !           307:                warnx("%s: %s", fname, strerror(EFTYPE));
        !           308:                return (1);
        !           309:        }
        !           310:
        !           311:        needed_chmod = rval = 0;
        !           312:        if ((fd = open(fname, O_RDWR, 0)) == -1) {
        !           313:                if (!force || chmod(fname, DEFFILEMODE))
        !           314:                        goto err;
        !           315:                if ((fd = open(fname, O_RDWR, 0)) == -1)
        !           316:                        goto err;
        !           317:                needed_chmod = 1;
        !           318:        }
        !           319:
        !           320:        if (sbp->st_size != 0) {
        !           321:                if (read(fd, &byte, sizeof(byte)) != sizeof(byte))
        !           322:                        goto err;
        !           323:                if (lseek(fd, (off_t)0, SEEK_SET) == -1)
        !           324:                        goto err;
        !           325:                if (write(fd, &byte, sizeof(byte)) != sizeof(byte))
        !           326:                        goto err;
        !           327:        } else {
        !           328:                if (write(fd, &byte, sizeof(byte)) != sizeof(byte)) {
        !           329: err:                   rval = 1;
        !           330:                        warn("%s", fname);
        !           331:                } else if (ftruncate(fd, (off_t)0)) {
        !           332:                        rval = 1;
        !           333:                        warn("%s: file modified", fname);
        !           334:                }
        !           335:        }
        !           336:
        !           337:        if (close(fd) && rval != 1) {
        !           338:                rval = 1;
        !           339:                warn("%s", fname);
        !           340:        }
        !           341:        if (needed_chmod && chmod(fname, sbp->st_mode) && rval != 1) {
        !           342:                rval = 1;
        !           343:                warn("%s: permissions modified", fname);
        !           344:        }
        !           345:        return (rval);
        !           346: }
        !           347:
        !           348: __dead void
        !           349: usage()
        !           350: {
        !           351:        (void)fprintf(stderr,
        !           352:            "usage: touch [-acfm] [-r file] [-t time] file ...\n");
        !           353:        exit(1);
        !           354: }