tc.sched.c revision 59243
1189251Ssam/* $Header: /src/pub/tcsh/tc.sched.c,v 3.16 1998/10/25 15:10:40 christos Exp $ */ 2214734Srpaulo/* 3214734Srpaulo * 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 15189251Ssam * notice, this list of conditions and the following disclaimer. 16189251Ssam * 2. Redistributions in binary form must reproduce the above copyright 17189251Ssam * notice, this list of conditions and the following disclaimer in the 18189251Ssam * 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.16 1998/10/25 15:10:40 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#ifdef _MINIX 81189251Ssam char kludge[10]; 82189251Ssam extern char *sprintf(); 83189251Ssam sprintf(kludge, CGETS(24, 1, "kludge")); 84189251Ssam#endif /* _MINIX */ 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 212214734Srpaulo sigmask_t omask; 213214734Srpaulo 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 224189251Ssam /* bugfix by: Justin Bur at Universite de Montreal */ 225189251Ssam /* 226189251Ssam * 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; 255189251Ssam lastword = nextword; 256214734Srpaulo } 257189251Ssam lastword->next = &cmd; 258189251Ssam cmd.prev = lastword; 259189251Ssam tp1 = tp; 260214734Srpaulo sched_ptr = tp = tp1->t_next; /* looping termination cond: */ 261214734Srpaulo 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. */ 273189251Ssam 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