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