home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / touch / touch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-09  |  8.1 KB  |  343 lines

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