1/*	$OpenBSD: leave.c,v 1.20 2020/01/27 01:05:28 tedu Exp $	*/
2/*	$NetBSD: leave.c,v 1.4 1995/07/03 16:50:13 phil Exp $	*/
3
4/*
5 * Copyright (c) 1980, 1988, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/time.h>
34#include <ctype.h>
35#include <err.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
40
41static __dead void	usage(void);
42static void		doalarm(u_int secs);
43
44#define SECOND  1
45#define MINUTE  (SECOND * 60)
46#define	FIVEMIN	(5 * MINUTE)
47#define HOUR    (MINUTE * 60)
48
49/*
50 * leave [[+]hhmm]
51 *
52 * Reminds you when you have to leave.
53 * Leave prompts for input and goes away if you hit return.
54 * It nags you like a mother hen.
55 */
56int
57main(int argc, char *argv[])
58{
59	u_int secs;
60	int hours, minutes;
61	char c, *cp;
62	struct tm *t;
63	time_t now;
64	int plusnow = 0, twentyfour;
65	char buf[50];
66
67	if (pledge("stdio proc", NULL) == -1)
68		err(1, "pledge");
69
70	if (setvbuf(stdout, NULL, _IOLBF, 0) != 0)
71		errx(1, "Cannot set stdout to line buffered.");
72
73	if (argc < 2) {
74		(void)fputs("When do you have to leave? ", stdout);
75		cp = fgets(buf, sizeof(buf), stdin);
76		if (cp == NULL || *cp == '\n')
77			return 0;
78	} else if (argc > 2)
79		usage();
80	else
81		cp = argv[1];
82
83	if (*cp == '+') {
84		plusnow = 1;
85		++cp;
86	}
87
88	if (!plusnow && strlen(cp) != 4)
89		usage();
90
91	for (hours = 0; (c = *cp) && c != '\n'; ++cp) {
92		if (!isdigit((unsigned char)c))
93			usage();
94		hours = hours * 10 + (c - '0');
95	}
96	minutes = hours % 100;
97	hours /= 100;
98	/* determine 24 hours mode */
99	twentyfour = hours > 12;
100
101	if (minutes < 0 || minutes > 59)
102		usage();
103	if (plusnow)
104		secs = (hours * HOUR) + (minutes * MINUTE);
105	else {
106		if (hours > 23)
107			usage();
108		(void)time(&now);
109		t = localtime(&now);
110		while (t->tm_hour > hours ||
111		    (t->tm_hour == hours && t->tm_min >= minutes)) {
112			if (twentyfour)
113				hours += 24;
114			else
115				hours += 12;
116		}
117
118		secs = (hours - t->tm_hour) * HOUR;
119		secs += (minutes - t->tm_min) * MINUTE;
120		secs -= t->tm_sec;	/* aim for beginning of minute */
121	}
122	doalarm(secs);
123	return 0;
124}
125
126static void
127doalarm(u_int secs)
128{
129	int bother;
130	time_t daytime;
131	pid_t pid;
132
133	switch (pid = fork()) {
134	case 0:
135		break;
136	case -1:
137		err(1, "Fork failed");
138		/* NOTREACHED */
139	default:
140		(void)time(&daytime);
141		daytime += secs;
142		printf("Alarm set for %.16s. (pid %ld)\n",
143		    ctime(&daytime), (long)pid);
144		exit(0);
145	}
146	sleep(2);			/* let parent print set message */
147
148	/*
149	 * if write fails, we've lost the terminal through someone else
150	 * causing a vhangup by logging in.
151	 */
152	if (secs >= FIVEMIN) {
153		sleep(secs - FIVEMIN);
154		if (puts("\a\aYou have to leave in 5 minutes.") == EOF)
155			exit(0);
156		secs = FIVEMIN;
157	}
158
159	if (secs >= MINUTE) {
160		sleep(secs - MINUTE);
161		if (puts("\a\aJust one more minute!") == EOF)
162			exit(0);
163		secs = MINUTE;
164	}
165
166	sleep(secs);
167
168	for (bother = 10; bother--;) {
169		if (puts("\a\aTime to leave!") == EOF)
170			exit(0);
171		if (bother)
172			sleep(MINUTE);
173	}
174
175	puts("\a\aThat was the last time I'll tell you.  Bye.");
176	exit(0);
177}
178
179static __dead void
180usage(void)
181{
182	fprintf(stderr, "usage: leave [[+]hhmm]\n");
183	exit(1);
184}
185