2 Copyright © 2010, The AROS Development Team. All rights reserved.
5 Desc: Execute a command after a given time
9 /******************************************************************************
17 D=DATE/K,T=TIME/K,YR=YEARS/K/N,MN=MONTHS/K/N,DY=DAYS/K/N,H=HOURS/K/N,
18 M=MINS/K/N,S=SECS/K/N,L=LOOP/K/N,A=ALWAYS/S,V=VERBOSE/S,HELP/S,CMDLINE/F
26 WaitX will wait for a given amount of time and then it
27 will execute the given command.
31 D=DATE -- Waits until DATE has been reached
32 T=TIME -- Waits until TIME has been reached
33 YR=YEARS -- How many years to wait
34 MN=MONTHS -- How many months to wait
35 DY=DAYS -- How many days to wait
36 H=HOURS -- How many hours to wait
37 M=MINS -- How many minutes to wait
38 S=SECS -- How many seconds to wait
39 L=LOOP -- How many times to execute CMDLINE
40 A=ALWAYS -- Execute CMDLINE every set interval/time/date
41 V=VERBOSE -- Print extra info on what waitx is doing
45 $ waitx TIME=12:34:12 echo "this is an example"
46 waitx waits until 12:34:12 is reached and will execute echo
48 $ waitx H=5 M=36 echo "this is an example"
49 waitx will wait 5 hours and 36 minutes and execute echo
51 $ waitx HOURS=2 MINS=12 SECS=59
52 waitx will wait 2 hours, 12 minutes and 59 seconds and then
55 $ waitx DY=1 L=5 echo "this is an example"
56 waitx will wait 1 day and execute echo,
57 then repeat this a total of 5 times
59 $ waitx M=15 ALWAYS echo "this is an example"
60 waitx will execute echo every 15 minutes
62 $ waitx D=12/9 T=16 L=0 echo "this is an example"
63 waitx will wait until September 12th 16:00 and execute echo,
66 $ waitx echo "this is an example"
67 waitx will execute echo immediatly
73 Based on Public Domain WaitX:
74 http://aminet.net/package/util/cli/waitx
75 Programming: Sigbjørn Skjæret <cisc@c2i.net>
76 Idea & Docs: Nicholas Stallard <snowy@netphile.de>
82 Will not return to prompt while waiting. This is intended.
88 ******************************************************************************/
92 #include <proto/dos.h>
93 #include <proto/exec.h>
94 #include <exec/memory.h>
95 #include <proto/timer.h>
96 #include <proto/utility.h>
97 #include <utility/date.h>
108 const char Version
[] = "$VER: WaitX 2.1 (16.04.2008)";
110 int strtoi(STRPTR string
);
112 LONG
MainEntry(struct ExecBase
*SysBase
);
114 __startup
static AROS_ENTRY(int, Start
,
115 AROS_UFHA(char *, argstr
, A0
),
116 AROS_UFHA(ULONG
, argsize
, D0
),
117 struct ExecBase
*, sBase
)
120 return MainEntry(sBase
);
125 LONG
MainEntry(struct ExecBase
*SysBase
)
127 struct DosLibrary
*DOSBase
= NULL
;
128 struct UtilityBase
*UtilityBase
= NULL
;
129 struct Library
*TimerBase
;
131 BYTE TimerDevice
= -1;
132 struct ClockData
*clock
= NULL
;
133 struct Interval
*interval
= NULL
;
134 struct MsgPort
*TimerPort
= NULL
;
135 struct timerequest
*TimerReq
= NULL
;
136 ULONG i
, loop
, step
, unit
, seconds
= 0, signal
= 0, timesig
= 0, usersig
= SIGBREAKF_CTRL_C
| SIGBREAKF_CTRL_D
| SIGBREAKF_CTRL_E
;
138 BPTR StdErr
= BNULL
, StdIn
;
140 struct RDArgs
*rdargs
= NULL
;
141 STRPTR Template
= "D=DATE/K,T=TIME/K,YR=YEARS/K/N,MN=MONTHS/K/N,DY=DAYS/K/N,H=HOURS/K/N,M=MINS/K/N,S=SECS/K/N,L=LOOP/K/N,A=ALWAYS/S,V=VERBOSE/S,HELP/S,CMDLINE/F";
161 IPTR ArgArray
[TEM_NUMARGS
], ret
;
165 ret
= 20; /* Fatal error if something fails here */
166 if (!(DOSBase
= (struct DosLibrary
*)OpenLibrary("dos.library", 36)))
168 if (!(UtilityBase
= (struct UtilityBase
*)OpenLibrary("utility.library", 36)))
170 if (!(StdErr
= Open("CONSOLE:", MODE_NEWFILE
)))
172 ret
= 0; /* Clear return */
174 GetProgramName(ProgName
, sizeof(ProgName
));
175 for (i
=0; i
<TEM_NUMARGS
; ArgArray
[i
++]=0)
177 rdargs
= ReadArgs(Template
, ArgArray
, NULL
);
179 if (ArgArray
[TEM_HELP
] || !rdargs
)
181 FPrintf(StdErr
, "%s\n\n", &Version
[6]);
182 FPrintf(StdErr
, "Usage: %s [DATE=<DD/MM/YYYY>] [TIME=<HH:MM:SS>] <commandline>\n", ProgName
);
183 FPrintf(StdErr
, "Usage: %s [HOURS=<hours>] [MINS=<mins>] [SECS=<secs>] <commandline>\n", ProgName
);
188 if (ArgArray
[TEM_LOOP
])
189 loop
= *((ULONG
*)ArgArray
[TEM_LOOP
]);
191 if (ArgArray
[TEM_ALWAYS
] || loop
== 0)
197 if (ArgArray
[TEM_CMDLINE
])
198 cmdline
= (STRPTR
)ArgArray
[TEM_CMDLINE
];
200 cmdline
= ""; /* Prevented from Execute()ing later */
202 if (ArgArray
[TEM_DATE
] || ArgArray
[TEM_TIME
] || ArgArray
[TEM_YEARS
] || ArgArray
[TEM_MONTHS
])
204 unit
= UNIT_WAITUNTIL
;
205 if (!(clock
= AllocMem(sizeof(struct ClockData
), MEMF_PUBLIC
| MEMF_CLEAR
)))
207 FPrintf(StdErr
, "Unable to allocate needed memory!\n");
211 if (!(interval
= AllocMem(sizeof(struct Interval
), MEMF_PUBLIC
| MEMF_CLEAR
)))
213 FPrintf(StdErr
, "Unable to allocate needed memory!\n");
218 if (ArgArray
[TEM_YEARS
])
219 interval
->years
= *((ULONG
*)ArgArray
[TEM_YEARS
]);
220 if (ArgArray
[TEM_MONTHS
])
221 interval
->months
= *((ULONG
*)ArgArray
[TEM_MONTHS
]);
222 if (ArgArray
[TEM_DAYS
])
223 interval
->seconds
+= *((ULONG
*)ArgArray
[TEM_DAYS
]) * 86400;
224 if (ArgArray
[TEM_HOURS
])
225 interval
->seconds
+= *((ULONG
*)ArgArray
[TEM_HOURS
]) * 3600;
226 if (ArgArray
[TEM_MINS
])
227 interval
->seconds
+= *((ULONG
*)ArgArray
[TEM_MINS
]) * 60;
228 if (ArgArray
[TEM_SECS
])
229 interval
->seconds
+= *((ULONG
*)ArgArray
[TEM_SECS
]);
231 if (interval
->years
|| interval
->months
|| interval
->seconds
)
239 if (ArgArray
[TEM_DAYS
])
240 seconds
+= *((ULONG
*)ArgArray
[TEM_DAYS
]) * 86400;
241 if (ArgArray
[TEM_HOURS
])
242 seconds
+= *((ULONG
*)ArgArray
[TEM_HOURS
]) * 3600;
243 if (ArgArray
[TEM_MINS
])
244 seconds
+= *((ULONG
*)ArgArray
[TEM_MINS
]) * 60;
245 if (ArgArray
[TEM_SECS
])
246 seconds
+= *((ULONG
*)ArgArray
[TEM_SECS
]);
249 if (seconds
> 0 || clock
)
251 if (!(TimerPort
= CreateMsgPort()))
253 FPrintf(StdErr
, "Couldn't create Timer-MsgPort!\n");
257 if (!(TimerReq
= (struct timerequest
*)CreateIORequest(TimerPort
, sizeof(struct timerequest
))))
259 FPrintf(StdErr
, "Couldn't create Timer-IORequest!\n");
263 if ((TimerDevice
= OpenDevice(TIMERNAME
, unit
, (struct IORequest
*)TimerReq
, 0)))
265 FPrintf(StdErr
, "Couldn't open %s!\n", TIMERNAME
);
270 TimerBase
= (struct Library
*)TimerReq
->tr_node
.io_Device
;
271 timesig
= 1L << TimerPort
->mp_SigBit
;
275 GetSysTime(&TimerReq
->tr_time
); /* Get current System Time */
276 Amiga2Date(TimerReq
->tr_time
.tv_secs
, clock
); /* Fill in current date/time as default */
278 if (ArgArray
[TEM_DATE
])
280 tmpptr
= (STRPTR
)ArgArray
[TEM_DATE
];
281 clock
->mday
= strtoi(tmpptr
);
282 if ((tmpptr
= strstr(tmpptr
, "/")))
284 clock
->month
= strtoi(++tmpptr
);
285 if ((tmpptr
= strstr(tmpptr
, "/")))
287 clock
->year
= strtoi(++tmpptr
);
295 else if (!interval
->set
)
297 interval
->months
= 1;
301 if (clock
->year
< 100) /* Be nice to digit-challenged ppl. ;) */
303 if (clock
->year
< 78)
304 clock
->year
+= 2000; /* If less than 78, assume 20xx */
309 else if (!interval
->set
)
311 interval
->seconds
= 86400;
315 if (ArgArray
[TEM_TIME
])
317 tmpptr
= (STRPTR
)ArgArray
[TEM_TIME
];
318 clock
->hour
= strtoi(tmpptr
);
319 clock
->min
= clock
->sec
= 0; /* Clear default time */
320 if ((tmpptr
= strstr(tmpptr
, ":")))
322 clock
->min
= strtoi(++tmpptr
);
323 if ((tmpptr
= strstr(tmpptr
, ":")))
324 clock
->sec
= strtoi(++tmpptr
);
328 if (!(seconds
= CheckDate(clock
)))
330 FPrintf(StdErr
, "Invalid date/time!\n");
334 if (seconds
<= TimerReq
->tr_time
.tv_secs
)
338 for (i
=0; i
<count
; i
+=step
)
340 clock
->year
+= interval
->years
;
341 clock
->month
+= interval
->months
;
343 if (clock
->month
> 12) /* We need some annual magic */
346 clock
->year
+= clock
->month
/ 12;
349 if (!(seconds
= CheckDate(clock
)))
351 clock
->mday
-= 1; /* If date doesn't exist, try previous day */
352 if (!(seconds
= CheckDate(clock
)))
355 if (!(seconds
= CheckDate(clock
)))
358 if (!(seconds
= CheckDate(clock
)))
360 FPrintf(StdErr
, "Invalid date/time!\n");
368 clock
->mday
+= 1; /* Restore day for future reference */
371 if (interval
->seconds
)
373 seconds
+= interval
->seconds
;
374 Amiga2Date(seconds
, clock
);
377 if (loop
> 0 && step
> 0)
379 if (seconds
> TimerReq
->tr_time
.tv_secs
)
383 if (seconds
<= TimerReq
->tr_time
.tv_secs
|| loop
== 0)
385 FPrintf(StdErr
, "Date/time has already passed!\n");
389 else if (ArgArray
[TEM_VERBOSE
])
391 FPrintf(StdErr
, "Note: Schedule has been moved to %02lu/%02lu/%lu %02lu:%02lu:%02lu because the assigned date/time has already passed",
392 (ULONG
)clock
->mday
, (ULONG
)clock
->month
, (ULONG
)clock
->year
, (ULONG
)clock
->hour
, (ULONG
)clock
->min
, (ULONG
)clock
->sec
);
395 FPrintf(StdErr
, ".\n");
397 FPrintf(StdErr
, " (%lu loop(s) left).\n", loop
);
403 if (IsInteractive((StdIn
= Input())))
404 StdIn
= BNULL
; /* Don't use StdIn if it isn't redirected */
406 for (i
=0; i
<loop
; i
+=step
)
410 TimerReq
->tr_time
.tv_secs
= seconds
;
411 TimerReq
->tr_time
.tv_micro
= 0;
412 TimerReq
->tr_node
.io_Command
= TR_ADDREQUEST
;
414 SendIO((struct IORequest
*)TimerReq
);
415 signal
= Wait(timesig
| usersig
);
417 if (signal
& usersig
)
419 AbortIO((struct IORequest
*)TimerReq
);
420 WaitIO((struct IORequest
*)TimerReq
);
421 SetSignal(0L, timesig
| usersig
); /* Clear signalbits since WaitIO most likely preserves them */
423 if (signal
& SIGBREAKF_CTRL_C
)
428 if (cmdline
[0] == '\0')
429 break; /* There's no point in going on */
430 if (!(signal
& SIGBREAKF_CTRL_D
))
432 if (!Execute(cmdline
, StdIn
, Output()))
434 FPrintf(StdErr
, "Unable to execute \"%s\".\n", cmdline
);
440 break; /* Don't go into tight unbreakable loop */
444 clock
->year
+= interval
->years
;
445 clock
->month
+= interval
->months
;
447 if (clock
->month
> 12) /* We need some annual magic */
450 clock
->year
+= clock
->month
/ 12;
453 if (!(seconds
= CheckDate(clock
)))
455 clock
->mday
-= 1; /* If date doesn't exist, try previous day */
456 if (!(seconds
= CheckDate(clock
)))
459 if (!(seconds
= CheckDate(clock
)))
462 if (!(seconds
= CheckDate(clock
)))
464 FPrintf(StdErr
, "Invalid date/time!\n");
472 clock
->mday
+= 1; /* Restore day for future reference */
475 if (interval
->seconds
)
477 seconds
+= interval
->seconds
;
478 Amiga2Date(seconds
, clock
);
482 if (ArgArray
[TEM_VERBOSE
] && (i
+1<loop
|| step
== 0))
484 FPrintf(StdErr
, "Next scheduled execution ");
487 FPrintf(StdErr
, "at %02lu/%02lu/%lu %02lu:%02lu:%02lu", (ULONG
)clock
->mday
, (ULONG
)clock
->month
, (ULONG
)clock
->year
,
488 (ULONG
)clock
->hour
, (ULONG
)clock
->min
, (ULONG
)clock
->sec
);
490 FPrintf(StdErr
, "in %lu hours, %lu minutes and %lu seconds", seconds
/ 3600, (seconds
% 3600) / 60, seconds
% 60);
493 FPrintf(StdErr
, ".\n");
495 FPrintf(StdErr
, " (%lu loop(s) left).\n", loop
-i
-1);
501 FreeMem(clock
, sizeof(struct ClockData
));
503 FreeMem(interval
, sizeof(struct Interval
));
506 CloseDevice((struct IORequest
*)TimerReq
);
508 DeleteIORequest((struct IORequest
*)TimerReq
);
510 DeleteMsgPort(TimerPort
);
517 CloseLibrary((struct Library
*)DOSBase
);
523 /* A simple atoi()-alike function because it does what we need, and no more. */
524 int strtoi(STRPTR string
)
528 for (i
=0,num
=0; string
[i
]>='0' && string
[i
]<='9'; ++i
)
529 num
= 10 * num
+ (string
[i
] - '0');