1 /* at - run a command at a specified time Author: Jan Looyen */ 2 3 #include <sys/types.h> 4 #include <time.h> 5 #include <fcntl.h> 6 #include <unistd.h> 7 #include <stdlib.h> 8 #include <string.h> 9 #include <sys/stat.h> 10 #include <stdio.h> 11 #include <limits.h> 12 #include <signal.h> 13 #include <errno.h> 14 15 #define STARTDAY 0 /* see ctime(3) */ 16 #define LEAPDAY (STARTDAY+59) 17 #define MAXDAYNR (STARTDAY+365) 18 #define NODAY (-2) 19 char CRONPID[] = "/usr/run/cron.pid"; 20 21 int main(int argc, char **argv, char **envp); 22 int getltim(char *t); 23 int getlday(char *m, char *d); 24 int digitstring(char *s); 25 26 int main(int argc, char **argv, char **envp) 27 { 28 int i, c, mask, ltim, year, lday = NODAY; 29 char buf[64], job[30], pastjob[35], *dp, *sp; 30 struct tm *p; 31 long clk; 32 FILE *fp; 33 char pwd[PATH_MAX+1]; 34 35 /*-------------------------------------------------------------------------* 36 * check arguments & pipe to "pwd" * 37 *-------------------------------------------------------------------------*/ 38 if (argc < 2 || argc > 5) { 39 fprintf(stderr, "Usage: %s time [month day] [file]\n", argv[0]); 40 exit(1); 41 } 42 if ((ltim = getltim(argv[1])) == -1) { 43 fprintf(stderr, "%s: wrong time specification\n", argv[0]); 44 exit(1); 45 } 46 if ((argc == 4 || argc == 5) && (lday = getlday(argv[2], argv[3])) == -1) { 47 fprintf(stderr, "%s: wrong date specification\n", argv[0]); 48 exit(1); 49 } 50 if ((argc == 3 || argc == 5) && open(argv[argc - 1], O_RDONLY) == -1) { 51 fprintf(stderr, "%s: cannot find: %s\n", argv[0], argv[argc - 1]); 52 exit(1); 53 } 54 if (getcwd(pwd, sizeof(pwd)) == NULL) { 55 fprintf(stderr, "%s: cannot determine current directory: %s\n", 56 argv[0], strerror(errno)); 57 exit(1); 58 } 59 60 /*-------------------------------------------------------------------------* 61 * determine execution time and create 'at' job file * 62 *-------------------------------------------------------------------------*/ 63 time(&clk); 64 p = localtime(&clk); 65 year = p->tm_year; 66 if (lday == NODAY) { /* no [month day] given */ 67 lday = p->tm_yday; 68 if (ltim <= (p->tm_hour * 100 + p->tm_min)) { 69 lday++; 70 if ((lday == MAXDAYNR && (year % 4)) || lday == MAXDAYNR + 1) { 71 lday = STARTDAY; 72 year++; 73 } 74 } 75 } else 76 switch (year % 4) { 77 case 0: 78 if (lday < p->tm_yday || 79 (lday == p->tm_yday && 80 ltim <= (p->tm_hour * 100 + p->tm_min))) { 81 year++; 82 if (lday > LEAPDAY) lday--; 83 } 84 break; 85 case 1: 86 case 2: 87 if (lday > LEAPDAY) lday--; 88 if (lday < p->tm_yday || 89 (lday == p->tm_yday && 90 ltim <= (p->tm_hour * 100 + p->tm_min))) 91 year++; 92 break; 93 case 3: 94 if (lday < ((lday > LEAPDAY) ? p->tm_yday + 1 : p->tm_yday) || 95 (lday ==((lday > LEAPDAY) ? p->tm_yday + 1 : p->tm_yday) && 96 ltim <= (p->tm_hour * 100 + p->tm_min))) 97 year++; 98 else if (lday > LEAPDAY) 99 lday--; 100 break; 101 } 102 sprintf(job, "/usr/spool/at/%02d.%03d.%04d.%02d", 103 year % 100, lday, ltim, getpid() % 100); 104 sprintf(pastjob, "/usr/spool/at/past/%02d.%03d.%04d.%02d", 105 year % 100, lday, ltim, getpid() % 100); 106 mask= umask(0077); 107 if ((fp = fopen(pastjob, "w")) == NULL) { 108 fprintf(stderr, "%s: cannot create %s: %s\n", 109 argv[0], pastjob, strerror(errno)); 110 exit(1); 111 } 112 113 /*-------------------------------------------------------------------------* 114 * write environment and command(s) to 'at'job file * 115 *-------------------------------------------------------------------------*/ 116 i = 0; 117 while ((sp= envp[i++]) != NULL) { 118 dp = buf; 119 while ((c= *sp++) != '\0' && c != '=' && dp < buf+sizeof(buf)-1) 120 *dp++ = c; 121 if (c != '=') continue; 122 *dp = '\0'; 123 fprintf(fp, "%s='", buf); 124 while (*sp != 0) { 125 if (*sp == '\'') 126 fprintf(fp, "'\\''"); 127 else 128 fputc(*sp, fp); 129 sp++; 130 } 131 fprintf(fp, "'; export %s\n", buf); 132 } 133 fprintf(fp, "cd '%s'\n", pwd); 134 fprintf(fp, "umask %o\n", mask); 135 if (argc == 3 || argc == 5) 136 fprintf(fp, "%s\n", argv[argc - 1]); 137 else /* read from stdinput */ 138 while ((c = getchar()) != EOF) putc(c, fp); 139 fclose(fp); 140 141 if (chown(pastjob, getuid(), getgid()) == -1) { 142 fprintf(stderr, "%s: cannot set ownership of %s: %s\n", 143 argv[0], pastjob, strerror(errno)); 144 unlink(pastjob); 145 exit(1); 146 } 147 /* "Arm" the job. */ 148 if (rename(pastjob, job) == -1) { 149 fprintf(stderr, "%s: cannot move %s to %s: %s\n", 150 argv[0], pastjob, job, strerror(errno)); 151 unlink(pastjob); 152 exit(1); 153 } 154 printf("%s: %s created\n", argv[0], job); 155 156 /* Alert cron to the new situation. */ 157 if ((fp= fopen(CRONPID, "r")) != NULL) { 158 unsigned long pid; 159 160 pid= 0; 161 while ((c= fgetc(fp)) != EOF && c != '\n') { 162 if ((unsigned) (c - '0') >= 10) { pid= 0; break; } 163 pid= 10*pid + (c - '0'); 164 if (pid >= 30000) { pid= 0; break; } 165 } 166 if (pid > 1) kill((pid_t) pid, SIGHUP); 167 } 168 return(0); 169 } 170 171 /*-------------------------------------------------------------------------* 172 * getltim() return((time OK) ? daytime : -1) * 173 *-------------------------------------------------------------------------*/ 174 int getltim(char *t) 175 { 176 if (t[4] == '\0' && t[3] >= '0' && t[3] <= '9' && 177 t[2] >= '0' && t[2] <= '5' && t[1] >= '0' && t[1] <= '9' && 178 (t[0] == '0' || t[0] == '1' || (t[1] <= '3' && t[0] == '2'))) 179 return(atoi(t)); 180 else 181 return(-1); 182 } 183 184 /*-------------------------------------------------------------------------* 185 * getlday() return ((date OK) ? yearday : -1) * 186 *-------------------------------------------------------------------------*/ 187 int getlday(char *m, char *d) 188 { 189 int i, day, im; 190 static int cumday[] = {0, 0, 31, 60, 91, 121, 152, 191 182, 213, 244, 274, 305, 335}; 192 static struct date { 193 char *mon; 194 int dcnt; 195 } *pc, kal[] = { 196 { "Jan", 31 }, { "Feb", 29 }, { "Mar", 31 }, { "Apr", 30 }, 197 { "May", 31 }, { "Jun", 30 }, { "Jul", 31 }, { "Aug", 31 }, 198 { "Sep", 30 }, { "Oct", 31 }, { "Nov", 30 }, { "Dec", 31 }, 199 }; 200 201 pc = kal; 202 im = (digitstring(m)) ? atoi(m) : 0; 203 m[0] &= 0337; 204 for (i = 1; i < 13 && strcmp(m, pc->mon) && im != i; i++, pc++); 205 if (i < 13 && (day = (digitstring(d)) ? atoi(d) : 0) && day <= pc->dcnt) { 206 if (!STARTDAY) day--; 207 return(day + cumday[i]); 208 } else 209 return(-1); 210 } 211 212 213 214 int digitstring(char *s) 215 { 216 while (*s >= '0' && *s <= '9') s++; 217 return((*s == '\0') ? 1 : 0); 218 } 219