tc.sched.c revision 69408
1189251Ssam/* $Header: /src/pub/tcsh/tc.sched.c,v 3.17 2000/07/04 19:46:23 christos Exp $ */
2189251Ssam/*
3189251Ssam * tc.sched.c: Scheduled command execution
4189251Ssam *
5252726Srpaulo * Karl Kleinpaste: Computer Consoles Inc. 1984
6252726Srpaulo */
7189251Ssam/*-
8189251Ssam * Copyright (c) 1980, 1991 The Regents of the University of California.
9189251Ssam * All rights reserved.
10189251Ssam *
11189251Ssam * Redistribution and use in source and binary forms, with or without
12189251Ssam * modification, are permitted provided that the following conditions
13189251Ssam * are met:
14189251Ssam * 1. Redistributions of source code must retain the above copyright
15214734Srpaulo *    notice, this list of conditions and the following disclaimer.
16214734Srpaulo * 2. Redistributions in binary form must reproduce the above copyright
17252726Srpaulo *    notice, this list of conditions and the following disclaimer in the
18214734Srpaulo *    documentation and/or other materials provided with the distribution.
19189251Ssam * 3. All advertising materials mentioning features or use of this software
20189251Ssam *    must display the following acknowledgement:
21189251Ssam *	This product includes software developed by the University of
22189251Ssam *	California, Berkeley and its contributors.
23189251Ssam * 4. Neither the name of the University nor the names of its contributors
24189251Ssam *    may be used to endorse or promote products derived from this software
25189251Ssam *    without specific prior written permission.
26189251Ssam *
27189251Ssam * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28189251Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29189251Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30189251Ssam * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31189251Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32189251Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33189251Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34189251Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35189251Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36189251Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37189251Ssam * SUCH DAMAGE.
38189251Ssam */
39189251Ssam#include "sh.h"
40189251Ssam
41189251SsamRCSID("$Id: tc.sched.c,v 3.17 2000/07/04 19:46:23 christos Exp $")
42189251Ssam
43189251Ssam#include "ed.h"
44189251Ssam#include "tc.h"
45189251Ssam
46189251Ssamextern int just_signaled;
47189251Ssam
48189251Ssamstruct sched_event {
49189251Ssam    struct sched_event *t_next;
50189251Ssam    time_t t_when;
51189251Ssam    Char  **t_lex;
52189251Ssam};
53189251Ssamstatic struct sched_event *sched_ptr = NULL;
54189251Ssam
55189251Ssam
56189251Ssamtime_t
57189251Ssamsched_next()
58189251Ssam{
59189251Ssam    if (sched_ptr)
60189251Ssam	return (sched_ptr->t_when);
61189251Ssam    return ((time_t) - 1);
62189251Ssam}
63189251Ssam
64189251Ssam/*ARGSUSED*/
65189251Ssamvoid
66189251Ssamdosched(v, c)
67189251Ssam    register Char **v;
68189251Ssam    struct command *c;
69189251Ssam{
70189251Ssam    register struct sched_event *tp, *tp1, *tp2;
71189251Ssam    time_t  cur_time;
72189251Ssam    int     count, hours, minutes, dif_hour, dif_min;
73189251Ssam    Char   *cp;
74189251Ssam    bool    relative;		/* time specified as +hh:mm */
75189251Ssam    struct tm *ltp;
76189251Ssam
77189251Ssam    USE(c);
78189251Ssam/* This is a major kludge because of a gcc linker  */
79189251Ssam/* Problem.  It may or may not be needed for you   */
80189251Ssam#if defined(_MINIX) && !defined(_MINIX_VMD)
81189251Ssam    char kludge[10];
82189251Ssam    extern char *sprintf();
83189251Ssam    sprintf(kludge, CGETS(24, 1, "kludge"));
84189251Ssam#endif /* _MINIX && !_MINIX_VMD */
85189251Ssam
86189251Ssam    v++;
87189251Ssam    cp = *v++;
88189251Ssam    if (cp == NULL) {
89189251Ssam	Char   *fmt;
90189251Ssam	if ((fmt = varval(STRsched)) == STRNULL)
91189251Ssam	    fmt = str2short("%h\t%T\t%R\n");
92189251Ssam	/* print list of scheduled events */
93189251Ssam	for (count = 1, tp = sched_ptr; tp; count++, tp = tp->t_next) {
94189251Ssam	    Char buf[BUFSIZE], sbuf[BUFSIZE];
95189251Ssam	    blkexpand(tp->t_lex, buf);
96189251Ssam	    tprintf(FMT_SCHED, sbuf, fmt, sizeof(sbuf),
97189251Ssam		    short2str(buf), tp->t_when, (ptr_t) &count);
98189251Ssam	    for (cp = sbuf; *cp;)
99189251Ssam		xputchar(*cp++);
100189251Ssam	}
101189251Ssam	return;
102189251Ssam    }
103189251Ssam
104189251Ssam    if (*cp == '-') {
105189251Ssam	/* remove item from list */
106189251Ssam	if (!sched_ptr)
107189251Ssam	    stderror(ERR_NOSCHED);
108189251Ssam	if (*v)
109189251Ssam	    stderror(ERR_SCHEDUSAGE);
110189251Ssam	count = atoi(short2str(++cp));
111189251Ssam	if (count <= 0)
112189251Ssam	    stderror(ERR_SCHEDUSAGE);
113189251Ssam	tp = sched_ptr;
114189251Ssam	tp1 = 0;
115189251Ssam	while (--count) {
116189251Ssam	    if (tp->t_next == 0)
117189251Ssam		break;
118189251Ssam	    else {
119189251Ssam		tp1 = tp;
120189251Ssam		tp = tp->t_next;
121189251Ssam	    }
122189251Ssam	}
123189251Ssam	if (count)
124189251Ssam	    stderror(ERR_SCHEDEV);
125189251Ssam	if (tp1 == 0)
126189251Ssam	    sched_ptr = tp->t_next;
127189251Ssam	else
128189251Ssam	    tp1->t_next = tp->t_next;
129189251Ssam	blkfree(tp->t_lex);
130189251Ssam	xfree((ptr_t) tp);
131189251Ssam	return;
132189251Ssam    }
133189251Ssam
134189251Ssam    /* else, add an item to the list */
135189251Ssam    if (!*v)
136189251Ssam	stderror(ERR_SCHEDCOM);
137189251Ssam    relative = 0;
138189251Ssam    if (!Isdigit(*cp)) {	/* not abs. time */
139189251Ssam	if (*cp != '+')
140189251Ssam	    stderror(ERR_SCHEDUSAGE);
141189251Ssam	cp++, relative++;
142189251Ssam    }
143189251Ssam    minutes = 0;
144189251Ssam    hours = atoi(short2str(cp));
145189251Ssam    while (*cp && *cp != ':' && *cp != 'a' && *cp != 'p')
146189251Ssam	cp++;
147189251Ssam    if (*cp && *cp == ':')
148189251Ssam	minutes = atoi(short2str(++cp));
149189251Ssam    if ((hours < 0) || (minutes < 0) ||
150189251Ssam	(hours > 23) || (minutes > 59))
151189251Ssam	stderror(ERR_SCHEDTIME);
152189251Ssam    while (*cp && *cp != 'p' && *cp != 'a')
153189251Ssam	cp++;
154189251Ssam    if (*cp && relative)
155189251Ssam	stderror(ERR_SCHEDREL);
156189251Ssam    if (*cp == 'p')
157189251Ssam	hours += 12;
158189251Ssam    (void) time(&cur_time);
159189251Ssam    ltp = localtime(&cur_time);
160189251Ssam    if (relative) {
161189251Ssam	dif_hour = hours;
162189251Ssam	dif_min = minutes;
163189251Ssam    }
164189251Ssam    else {
165189251Ssam	if ((dif_hour = hours - ltp->tm_hour) < 0)
166189251Ssam	    dif_hour += 24;
167189251Ssam	if ((dif_min = minutes - ltp->tm_min) < 0) {
168189251Ssam	    dif_min += 60;
169189251Ssam	    if ((--dif_hour) < 0)
170189251Ssam		dif_hour = 23;
171189251Ssam	}
172189251Ssam    }
173189251Ssam    tp = (struct sched_event *) xcalloc(1, sizeof *tp);
174189251Ssam#ifdef _SX
175189251Ssam    tp->t_when = cur_time - ltp->tm_sec + dif_hour * 3600 + dif_min * 60;
176189251Ssam#else	/* _SX */
177189251Ssam    tp->t_when = cur_time - ltp->tm_sec + dif_hour * 3600L + dif_min * 60L;
178189251Ssam#endif /* _SX */
179189251Ssam    /* use of tm_sec: get to beginning of minute. */
180189251Ssam    if (!sched_ptr || tp->t_when < sched_ptr->t_when) {
181189251Ssam	tp->t_next = sched_ptr;
182189251Ssam	sched_ptr = tp;
183189251Ssam    }
184189251Ssam    else {
185189251Ssam	tp1 = sched_ptr->t_next;
186189251Ssam	tp2 = sched_ptr;
187189251Ssam	while (tp1 && tp->t_when >= tp1->t_when) {
188189251Ssam	    tp2 = tp1;
189189251Ssam	    tp1 = tp1->t_next;
190189251Ssam	}
191189251Ssam	tp->t_next = tp1;
192189251Ssam	tp2->t_next = tp;
193189251Ssam    }
194189251Ssam    tp->t_lex = saveblk(v);
195189251Ssam}
196189251Ssam
197189251Ssam/*
198189251Ssam * Execute scheduled events
199189251Ssam */
200189251Ssam/*ARGSUSED*/
201189251Ssamvoid
202189251Ssamsched_run(n)
203189251Ssam    int n;
204189251Ssam{
205189251Ssam    time_t   cur_time;
206189251Ssam    register struct sched_event *tp, *tp1;
207189251Ssam    struct wordent cmd, *nextword, *lastword;
208189251Ssam    struct command *t;
209189251Ssam    Char  **v, *cp;
210189251Ssam    extern Char GettingInput;
211189251Ssam#ifdef BSDSIGS
212189251Ssam    sigmask_t omask;
213189251Ssam
214189251Ssam    omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
215189251Ssam#else
216189251Ssam    (void) sighold(SIGINT);
217189251Ssam#endif
218189251Ssam
219189251Ssam    USE(n);
220189251Ssam
221189251Ssam    (void) time(&cur_time);
222189251Ssam    tp = sched_ptr;
223189251Ssam
224252726Srpaulo    /* bugfix by: Justin Bur at Universite de Montreal */
225252726Srpaulo    /*
226252726Srpaulo     * this test wouldn't be necessary if this routine were not called before
227189251Ssam     * each prompt (in sh.c).  But it is, to catch missed alarms.  Someone
228189251Ssam     * ought to fix it all up.  -jbb
229189251Ssam     */
230189251Ssam    if (!(tp && tp->t_when < cur_time)) {
231189251Ssam#ifdef BSDSIGS
232189251Ssam	(void) sigsetmask(omask);
233189251Ssam#else
234189251Ssam	(void) sigrelse(SIGINT);
235189251Ssam#endif
236189251Ssam	return;
237189251Ssam    }
238189251Ssam
239189251Ssam    if (GettingInput)
240189251Ssam	(void) Cookedmode();
241189251Ssam
242189251Ssam    while (tp && tp->t_when < cur_time) {
243189251Ssam	if (seterr) {
244189251Ssam	    xfree((ptr_t) seterr);
245189251Ssam	    seterr = NULL;
246189251Ssam	}
247189251Ssam	cmd.word = STRNULL;
248189251Ssam	lastword = &cmd;
249189251Ssam	v = tp->t_lex;
250189251Ssam	for (cp = *v; cp; cp = *++v) {
251189251Ssam	    nextword = (struct wordent *) xcalloc(1, sizeof cmd);
252189251Ssam	    nextword->word = Strsave(cp);
253189251Ssam	    lastword->next = nextword;
254189251Ssam	    nextword->prev = lastword;
255252726Srpaulo	    lastword = nextword;
256214734Srpaulo	}
257189251Ssam	lastword->next = &cmd;
258189251Ssam	cmd.prev = lastword;
259189251Ssam	tp1 = tp;
260189251Ssam	sched_ptr = tp = tp1->t_next;	/* looping termination cond: */
261189251Ssam	blkfree(tp1->t_lex);	/* straighten out in case of */
262189251Ssam	xfree((ptr_t) tp1);	/* command blow-up. */
263189251Ssam
264189251Ssam	/* expand aliases like process() does. */
265189251Ssam	alias(&cmd);
266189251Ssam	/* build a syntax tree for the command. */
267189251Ssam	t = syntax(cmd.next, &cmd, 0);
268189251Ssam	if (seterr)
269189251Ssam	    stderror(ERR_OLD);
270189251Ssam	/* execute the parse tree. */
271189251Ssam	execute(t, -1, NULL, NULL);
272189251Ssam	/* done. free the lex list and parse tree. */
273252726Srpaulo	freelex(&cmd), freesyn(t);
274189251Ssam    }
275189251Ssam    if (GettingInput && !just_signaled) {	/* PWP */
276189251Ssam	(void) Rawmode();
277189251Ssam	ClearLines();		/* do a real refresh since something may */
278189251Ssam	ClearDisp();		/* have printed to the screen */
279189251Ssam	Refresh();
280189251Ssam    }
281189251Ssam    just_signaled = 0;
282189251Ssam
283189251Ssam#ifdef BSDSIGS
284189251Ssam    (void) sigsetmask(omask);
285189251Ssam#else
286189251Ssam    (void) sigrelse(SIGINT);
287189251Ssam#endif
288189251Ssam}
289189251Ssam