tc.sched.c revision 145479
11844Swollman/* $Header: /src/pub/tcsh/tc.sched.c,v 3.21 2004/11/23 02:10:50 christos Exp $ */
250476Speter/*
31638Srgrimes * tc.sched.c: Scheduled command execution
494940Sru *
51638Srgrimes * Karl Kleinpaste: Computer Consoles Inc. 1984
6103713Smarkm */
71638Srgrimes/*-
8133653Sru * Copyright (c) 1980, 1991 The Regents of the University of California.
9119607Sru * All rights reserved.
10298503Sngie *
11119607Sru * Redistribution and use in source and binary forms, with or without
12119607Sru * modification, are permitted provided that the following conditions
13119607Sru * are met:
14162210Simp * 1. Redistributions of source code must retain the above copyright
15162210Simp *    notice, this list of conditions and the following disclaimer.
16162293Sobrien * 2. Redistributions in binary form must reproduce the above copyright
17162210Simp *    notice, this list of conditions and the following disclaimer in the
18162210Simp *    documentation and/or other materials provided with the distribution.
19119607Sru * 3. Neither the name of the University nor the names of its contributors
20119607Sru *    may be used to endorse or promote products derived from this software
21204027Smarcel *    without specific prior written permission.
22179184Sjb *
23228158Sfjoe * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24179184Sjb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25119607Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26179184Sjb * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27119607Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28251512Semaste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29251512Semaste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30251512Semaste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31251512Semaste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32271274Semaste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33251512Semaste * SUCH DAMAGE.
34251512Semaste */
35251512Semaste#include "sh.h"
36119607Sru
37117034SgordonRCSID("$Id: tc.sched.c,v 3.21 2004/11/23 02:10:50 christos Exp $")
38251512Semaste
39251512Semaste#include "ed.h"
40251512Semaste#include "tw.h"
41251512Semaste#include "tc.h"
42251512Semaste
43119607Sruextern int just_signaled;
44251512Semaste
451638Srgrimesstruct sched_event {
462827Sjkh    struct sched_event *t_next;
471638Srgrimes    time_t t_when;
482827Sjkh    Char  **t_lex;
491638Srgrimes};
50139112Srustatic struct sched_event *sched_ptr = NULL;
511844Swollman
521844Swollman
531638Srgrimestime_t
54255384Sdessched_next()
55255384Sdes{
56255384Sdes    if (sched_ptr)
57255384Sdes	return (sched_ptr->t_when);
58251512Semaste    return ((time_t) - 1);
59251512Semaste}
60251512Semaste
61251512Semaste/*ARGSUSED*/
62251512Semastevoid
63251512Semastedosched(v, c)
64251512Semaste    Char **v;
65251512Semaste    struct command *c;
66251512Semaste{
67251512Semaste    struct sched_event *tp, *tp1, *tp2;
68251512Semaste    time_t  cur_time;
69251512Semaste    int     count, hours, minutes, dif_hour, dif_min;
70251512Semaste    Char   *cp;
7194424Sru    int    relative;		/* time specified as +hh:mm */
72251512Semaste    struct tm *ltp;
73251512Semaste
74251512Semaste    USE(c);
7594424Sru/* This is a major kludge because of a gcc linker  */
761638Srgrimes/* Problem.  It may or may not be needed for you   */
77248753Semaste#if defined(_MINIX) && !defined(_MINIX_VMD)
78251512Semaste    char kludge[10];
791638Srgrimes    extern char *sprintf();
801638Srgrimes    sprintf(kludge, CGETS(24, 1, "kludge"));
811844Swollman#endif /* _MINIX && !_MINIX_VMD */
821638Srgrimes
83212423Srpaulo    v++;
84244915Smarkj    cp = *v++;
85251512Semaste    if (cp == NULL) {
86244224Semaste	Char   *fmt;
87251512Semaste	if ((fmt = varval(STRsched)) == STRNULL)
8894518Sru	    fmt = str2short("%h\t%T\t%R\n");
8994518Sru	/* print list of scheduled events */
9094518Sru	for (count = 1, tp = sched_ptr; tp; count++, tp = tp->t_next) {
9194518Sru	    Char buf[BUFSIZE], sbuf[BUFSIZE];
9294518Sru	    blkexpand(tp->t_lex, buf);
93228158Sfjoe	    tprintf(FMT_SCHED, sbuf, fmt, sizeof(sbuf),
94228124Sfjoe		    short2str(buf), tp->t_when, (ptr_t) &count);
95228124Sfjoe	    for (cp = sbuf; *cp;)
9694518Sru		xputwchar(*cp++);
97144893Sharti	}
981844Swollman	return;
9994518Sru    }
10094424Sru
10194424Sru    if (*cp == '-') {
10294424Sru	/* remove item from list */
1032351Sbde	if (!sched_ptr)
10494424Sru	    stderror(ERR_NOSCHED);
1051638Srgrimes	if (*v)
1062351Sbde	    stderror(ERR_SCHEDUSAGE);
1072351Sbde	count = atoi(short2str(++cp));
1082351Sbde	if (count <= 0)
1092351Sbde	    stderror(ERR_SCHEDUSAGE);
1102351Sbde	tp = sched_ptr;
111248742Smarkj	tp1 = 0;
11233624Seivind	while (--count) {
113212423Srpaulo	    if (tp->t_next == 0)
114244915Smarkj		break;
115251512Semaste	    else {
116244224Semaste		tp1 = tp;
117251512Semaste		tp = tp->t_next;
11894497Sru	    }
11994497Sru	}
12094497Sru	if (count)
12194410Sru	    stderror(ERR_SCHEDEV);
12233624Seivind	if (tp1 == 0)
123228158Sfjoe	    sched_ptr = tp->t_next;
124228124Sfjoe	else
12594518Sru	    tp1->t_next = tp->t_next;
126251512Semaste	blkfree(tp->t_lex);
1271638Srgrimes	xfree((ptr_t) tp);
128244224Semaste	return;
1291638Srgrimes    }
130251512Semaste
131251512Semaste    /* else, add an item to the list */
132251512Semaste    if (!*v)
133251512Semaste	stderror(ERR_SCHEDCOM);
134251512Semaste    relative = 0;
135251512Semaste    if (!Isdigit(*cp)) {	/* not abs. time */
136251512Semaste	if (*cp != '+')
137251512Semaste	    stderror(ERR_SCHEDUSAGE);
138251512Semaste	cp++, relative++;
139156813Sru    }
14074806Sru    minutes = 0;
1411638Srgrimes    hours = atoi(short2str(cp));
142245515Sbrooks    while (*cp && *cp != ':' && *cp != 'a' && *cp != 'p')
14374941Sru	cp++;
14474941Sru    if (*cp && *cp == ':')
1451638Srgrimes	minutes = atoi(short2str(++cp));
146244224Semaste    if ((hours < 0) || (minutes < 0) ||
1471638Srgrimes	(hours > 23) || (minutes > 59))
148269946Srpaulo	stderror(ERR_SCHEDTIME);
149269946Srpaulo    while (*cp && *cp != 'p' && *cp != 'a')
150156813Sru	cp++;
15196164Sru    if (*cp && relative)
15274806Sru	stderror(ERR_SCHEDREL);
1531638Srgrimes    if (*cp == 'p')
154119607Sru	hours += 12;
155119607Sru    (void) time(&cur_time);
156251512Semaste    ltp = localtime(&cur_time);
157251512Semaste    if (relative) {
158119607Sru	dif_hour = hours;
159251512Semaste	dif_min = minutes;
1601638Srgrimes    }
161119607Sru    else {
162119607Sru	if ((dif_hour = hours - ltp->tm_hour) < 0)
163119607Sru	    dif_hour += 24;
164119607Sru	if ((dif_min = minutes - ltp->tm_min) < 0) {
165125620Sru	    dif_min += 60;
166125620Sru	    if ((--dif_hour) < 0)
16755670Sbde		dif_hour = 23;
16824750Sbde	}
169125620Sru    }
170125620Sru    tp = (struct sched_event *) xcalloc(1, sizeof *tp);
171279958Sjhb#ifdef _SX
172125620Sru    tp->t_when = cur_time - ltp->tm_sec + dif_hour * 3600 + dif_min * 60;
173125620Sru#else	/* _SX */
174279958Sjhb    tp->t_when = cur_time - ltp->tm_sec + dif_hour * 3600L + dif_min * 60L;
17594497Sru#endif /* _SX */
176255431Sdes    /* use of tm_sec: get to beginning of minute. */
177279958Sjhb    if (!sched_ptr || tp->t_when < sched_ptr->t_when) {
178239686Sdim	tp->t_next = sched_ptr;
179279958Sjhb	sched_ptr = tp;
18024750Sbde    }
18128945Speter    else {
182125620Sru	tp1 = sched_ptr->t_next;
183239686Sdim	tp2 = sched_ptr;
18424750Sbde	while (tp1 && tp->t_when >= tp1->t_when) {
1851638Srgrimes	    tp2 = tp1;
1861638Srgrimes	    tp1 = tp1->t_next;
187137614Sru	}
188139111Sru	tp->t_next = tp1;
189137164Sru	tp2->t_next = tp;
190137164Sru    }
191137614Sru    tp->t_lex = saveblk(v);
192137614Sru}
193137164Sru
19449328Shoek/*
19549328Shoek * Execute scheduled events
19649328Shoek */
19749328Shoek/*ARGSUSED*/
19849328Shoekvoid
199125620Srusched_run(n)
20096163Sru    int n;
20199343Sru{
20296163Sru    time_t   cur_time;
2031638Srgrimes    struct sched_event *tp, *tp1;
204100872Sru    struct wordent cmd, *nextword, *lastword;
20575083Sru    struct command *t;
206251512Semaste    Char  **v, *cp;
207251512Semaste#ifdef BSDSIGS
208251512Semaste    sigmask_t omask;
2091638Srgrimes
210251512Semaste    omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
211251512Semaste#else
212251512Semaste    (void) sighold(SIGINT);
213251512Semaste#endif
214144893Sharti
2151638Srgrimes    USE(n);
21675284Sru
21775284Sru    (void) time(&cur_time);
21899343Sru    tp = sched_ptr;
21975284Sru
22075284Sru    /* bugfix by: Justin Bur at Universite de Montreal */
22175284Sru    /*
22275284Sru     * this test wouldn't be necessary if this routine were not called before
22375284Sru     * each prompt (in sh.c).  But it is, to catch missed alarms.  Someone
22475284Sru     * ought to fix it all up.  -jbb
22575284Sru     */
22675284Sru    if (!(tp && tp->t_when < cur_time)) {
22775284Sru#ifdef BSDSIGS
22875284Sru	(void) sigsetmask(omask);
22975284Sru#else
23075284Sru	(void) sigrelse(SIGINT);
23175284Sru#endif
23275284Sru	return;
23375284Sru    }
23475284Sru
23588055Sru    if (GettingInput)
23688055Sru	(void) Cookedmode();
237100872Sru
23875284Sru    while (tp && tp->t_when < cur_time) {
23994954Sru	if (seterr) {
24075284Sru	    xfree((ptr_t) seterr);
24175284Sru	    seterr = NULL;
24275284Sru	}
24375284Sru	cmd.word = STRNULL;
24499257Sru	lastword = &cmd;
24599257Sru	v = tp->t_lex;
24699257Sru	for (cp = *v; cp; cp = *++v) {
24797769Sru	    nextword = (struct wordent *) xcalloc(1, sizeof cmd);
24896668Sru	    nextword->word = Strsave(cp);
24999256Sru	    lastword->next = nextword;
25096462Sru	    nextword->prev = lastword;
251156813Sru	    lastword = nextword;
25296164Sru	}
25399343Sru	lastword->next = &cmd;
25496163Sru	cmd.prev = lastword;
25596163Sru	tp1 = tp;
256289051Sbdrewery	sched_ptr = tp = tp1->t_next;	/* looping termination cond: */
2571638Srgrimes	blkfree(tp1->t_lex);	/* straighten out in case of */
2581638Srgrimes	xfree((ptr_t) tp1);	/* command blow-up. */
259103713Smarkm
2601638Srgrimes	/* expand aliases like process() does. */
261103713Smarkm	alias(&cmd);
2621638Srgrimes	/* build a syntax tree for the command. */
2631638Srgrimes	t = syntax(cmd.next, &cmd, 0);
2641638Srgrimes	if (seterr)
265156813Sru	    stderror(ERR_OLD);
2661638Srgrimes	/* execute the parse tree. */
26774842Sru	execute(t, -1, NULL, NULL, TRUE);
2681844Swollman	/* done. free the lex list and parse tree. */
2691844Swollman	freelex(&cmd), freesyn(t);
27034081Sbde    }
27194113Sru    if (GettingInput && !just_signaled) {	/* PWP */
27234087Sbde	(void) Rawmode();
27334081Sbde	ClearLines();		/* do a real refresh since something may */
27434081Sbde	ClearDisp();		/* have printed to the screen */
27516663Sjkh	Refresh();
27676861Skris    }
27776861Skris    just_signaled = 0;
278139068Spaul
279139068Spaul#ifdef BSDSIGS
280139068Spaul    (void) sigsetmask(omask);
281139068Spaul#else
282    (void) sigrelse(SIGINT);
283#endif
284}
285