1fd1efedcSConrad Meyer /*-
2fd1efedcSConrad Meyer * SPDX-License-Identifier: BSD-3-Clause
3fd1efedcSConrad Meyer *
4fd1efedcSConrad Meyer * Copyright (c) 1989, 1993, 1994
5fd1efedcSConrad Meyer * The Regents of the University of California. All rights reserved.
6fd1efedcSConrad Meyer *
7fd1efedcSConrad Meyer * Redistribution and use in source and binary forms, with or without
8fd1efedcSConrad Meyer * modification, are permitted provided that the following conditions
9fd1efedcSConrad Meyer * are met:
10fd1efedcSConrad Meyer * 1. Redistributions of source code must retain the above copyright
11fd1efedcSConrad Meyer * notice, this list of conditions and the following disclaimer.
12fd1efedcSConrad Meyer * 2. Redistributions in binary form must reproduce the above copyright
13fd1efedcSConrad Meyer * notice, this list of conditions and the following disclaimer in the
14fd1efedcSConrad Meyer * documentation and/or other materials provided with the distribution.
15fd1efedcSConrad Meyer * 3. Neither the name of the University nor the names of its contributors
16fd1efedcSConrad Meyer * may be used to endorse or promote products derived from this software
17fd1efedcSConrad Meyer * without specific prior written permission.
18fd1efedcSConrad Meyer *
19fd1efedcSConrad Meyer * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20fd1efedcSConrad Meyer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21fd1efedcSConrad Meyer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22fd1efedcSConrad Meyer * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23fd1efedcSConrad Meyer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24fd1efedcSConrad Meyer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25fd1efedcSConrad Meyer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26fd1efedcSConrad Meyer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27fd1efedcSConrad Meyer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28fd1efedcSConrad Meyer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29fd1efedcSConrad Meyer * SUCH DAMAGE.
30fd1efedcSConrad Meyer */
31fd1efedcSConrad Meyer
32fd1efedcSConrad Meyer #include <sys/types.h>
33fd1efedcSConrad Meyer #include <err.h>
34fd1efedcSConrad Meyer #include <errno.h>
35fd1efedcSConrad Meyer #include <locale.h>
36fd1efedcSConrad Meyer #include <login_cap.h>
37fd1efedcSConrad Meyer #include <langinfo.h>
38fd1efedcSConrad Meyer #include <pwd.h>
39fd1efedcSConrad Meyer #include <stdio.h>
40fd1efedcSConrad Meyer #include <stdlib.h>
41fd1efedcSConrad Meyer #include <string.h>
42fd1efedcSConrad Meyer #include <time.h>
43fd1efedcSConrad Meyer #include <unistd.h>
44fd1efedcSConrad Meyer
45fd1efedcSConrad Meyer #include "calendar.h"
46fd1efedcSConrad Meyer
47fd1efedcSConrad Meyer #define UTCOFFSET_NOTSET 100 /* Expected between -24 and +24 */
48fd1efedcSConrad Meyer #define LONGITUDE_NOTSET 1000 /* Expected between -360 and +360 */
49fd1efedcSConrad Meyer
50fd1efedcSConrad Meyer struct passwd *pw;
51fd1efedcSConrad Meyer int doall = 0;
52fd1efedcSConrad Meyer int debug = 0;
53fd1efedcSConrad Meyer static char *DEBUG = NULL;
54fd1efedcSConrad Meyer static time_t f_time = 0;
55fd1efedcSConrad Meyer double UTCOffset = UTCOFFSET_NOTSET;
56fd1efedcSConrad Meyer int EastLongitude = LONGITUDE_NOTSET;
57fd1efedcSConrad Meyer #ifdef WITH_ICONV
58fd1efedcSConrad Meyer const char *outputEncoding = NULL;
59fd1efedcSConrad Meyer #endif
60fd1efedcSConrad Meyer
61fd1efedcSConrad Meyer static void usage(void) __dead2;
62fd1efedcSConrad Meyer
63fd1efedcSConrad Meyer int
main(int argc,char * argv[])64fd1efedcSConrad Meyer main(int argc, char *argv[])
65fd1efedcSConrad Meyer {
66fd1efedcSConrad Meyer int f_dayAfter = 0; /* days after current date */
67fd1efedcSConrad Meyer int f_dayBefore = 0; /* days before current date */
68fd1efedcSConrad Meyer int Friday = 5; /* day before weekend */
69fd1efedcSConrad Meyer
70fd1efedcSConrad Meyer int ch;
71fd1efedcSConrad Meyer struct tm tp1, tp2;
72fd1efedcSConrad Meyer
73fd1efedcSConrad Meyer (void)setlocale(LC_ALL, "");
74fd1efedcSConrad Meyer
75fd1efedcSConrad Meyer while ((ch = getopt(argc, argv, "-A:aB:D:dF:f:l:t:U:W:?")) != -1)
76fd1efedcSConrad Meyer switch (ch) {
77fd1efedcSConrad Meyer case '-': /* backward contemptible */
78fd1efedcSConrad Meyer case 'a':
79fd1efedcSConrad Meyer if (getuid()) {
80fd1efedcSConrad Meyer errno = EPERM;
81fd1efedcSConrad Meyer err(1, NULL);
82fd1efedcSConrad Meyer }
83fd1efedcSConrad Meyer doall = 1;
84fd1efedcSConrad Meyer break;
85fd1efedcSConrad Meyer
86fd1efedcSConrad Meyer case 'W': /* we don't need no steenking Fridays */
87fd1efedcSConrad Meyer Friday = -1;
88fd1efedcSConrad Meyer /* FALLTHROUGH */
89fd1efedcSConrad Meyer
90fd1efedcSConrad Meyer case 'A': /* days after current date */
91fd1efedcSConrad Meyer f_dayAfter = atoi(optarg);
92fd1efedcSConrad Meyer if (f_dayAfter < 0)
93fd1efedcSConrad Meyer errx(1, "number of days must be positive");
94fd1efedcSConrad Meyer break;
95fd1efedcSConrad Meyer
96fd1efedcSConrad Meyer case 'B': /* days before current date */
97fd1efedcSConrad Meyer f_dayBefore = atoi(optarg);
98fd1efedcSConrad Meyer if (f_dayBefore < 0)
99fd1efedcSConrad Meyer errx(1, "number of days must be positive");
100fd1efedcSConrad Meyer break;
101fd1efedcSConrad Meyer
102fd1efedcSConrad Meyer case 'D': /* debug output of sun and moon info */
103fd1efedcSConrad Meyer DEBUG = optarg;
104fd1efedcSConrad Meyer break;
105fd1efedcSConrad Meyer
106fd1efedcSConrad Meyer case 'd': /* debug output of current date */
107fd1efedcSConrad Meyer debug = 1;
108fd1efedcSConrad Meyer break;
109fd1efedcSConrad Meyer
110fd1efedcSConrad Meyer case 'F': /* Change the time: When does weekend start? */
111fd1efedcSConrad Meyer Friday = atoi(optarg);
112fd1efedcSConrad Meyer break;
113fd1efedcSConrad Meyer
114fd1efedcSConrad Meyer case 'f': /* other calendar file */
115fd1efedcSConrad Meyer calendarFile = optarg;
116fd1efedcSConrad Meyer break;
117fd1efedcSConrad Meyer
118fd1efedcSConrad Meyer case 'l': /* Change longitudal position */
119fd1efedcSConrad Meyer EastLongitude = strtol(optarg, NULL, 10);
120fd1efedcSConrad Meyer break;
121fd1efedcSConrad Meyer
122fd1efedcSConrad Meyer case 't': /* other date, for tests */
123fd1efedcSConrad Meyer f_time = Mktime(optarg);
124fd1efedcSConrad Meyer break;
125fd1efedcSConrad Meyer
126fd1efedcSConrad Meyer case 'U': /* Change UTC offset */
127fd1efedcSConrad Meyer UTCOffset = strtod(optarg, NULL);
128fd1efedcSConrad Meyer break;
129fd1efedcSConrad Meyer
130fd1efedcSConrad Meyer case '?':
131fd1efedcSConrad Meyer default:
132fd1efedcSConrad Meyer usage();
133fd1efedcSConrad Meyer }
134fd1efedcSConrad Meyer
135fd1efedcSConrad Meyer argc -= optind;
136fd1efedcSConrad Meyer argv += optind;
137fd1efedcSConrad Meyer
138fd1efedcSConrad Meyer if (argc)
139fd1efedcSConrad Meyer usage();
140fd1efedcSConrad Meyer
141fd1efedcSConrad Meyer /* use current time */
142fd1efedcSConrad Meyer if (f_time <= 0)
143fd1efedcSConrad Meyer (void)time(&f_time);
144fd1efedcSConrad Meyer
145fd1efedcSConrad Meyer /* if not set, determine where I could be */
146fd1efedcSConrad Meyer {
147fd1efedcSConrad Meyer if (UTCOffset == UTCOFFSET_NOTSET &&
148fd1efedcSConrad Meyer EastLongitude == LONGITUDE_NOTSET) {
149fd1efedcSConrad Meyer /* Calculate on difference between here and UTC */
150fd1efedcSConrad Meyer time_t t;
151fd1efedcSConrad Meyer struct tm tm;
152fd1efedcSConrad Meyer long utcoffset, hh, mm, ss;
153fd1efedcSConrad Meyer double uo;
154fd1efedcSConrad Meyer
155fd1efedcSConrad Meyer time(&t);
156fd1efedcSConrad Meyer localtime_r(&t, &tm);
157fd1efedcSConrad Meyer utcoffset = tm.tm_gmtoff;
158fd1efedcSConrad Meyer /* seconds -> hh:mm:ss */
159fd1efedcSConrad Meyer hh = utcoffset / SECSPERHOUR;
160fd1efedcSConrad Meyer utcoffset %= SECSPERHOUR;
161fd1efedcSConrad Meyer mm = utcoffset / SECSPERMINUTE;
162fd1efedcSConrad Meyer utcoffset %= SECSPERMINUTE;
163fd1efedcSConrad Meyer ss = utcoffset;
164fd1efedcSConrad Meyer
165fd1efedcSConrad Meyer /* hh:mm:ss -> hh.mmss */
166fd1efedcSConrad Meyer uo = mm + (100.0 * (ss / 60.0));
167fd1efedcSConrad Meyer uo /= 60.0 / 100.0;
168fd1efedcSConrad Meyer uo = hh + uo / 100;
169fd1efedcSConrad Meyer
170fd1efedcSConrad Meyer UTCOffset = uo;
171fd1efedcSConrad Meyer EastLongitude = UTCOffset * 15;
172fd1efedcSConrad Meyer } else if (UTCOffset == UTCOFFSET_NOTSET) {
173fd1efedcSConrad Meyer /* Base on information given */
174fd1efedcSConrad Meyer UTCOffset = EastLongitude / 15;
175fd1efedcSConrad Meyer } else if (EastLongitude == LONGITUDE_NOTSET) {
176fd1efedcSConrad Meyer /* Base on information given */
177fd1efedcSConrad Meyer EastLongitude = UTCOffset * 15;
178fd1efedcSConrad Meyer }
179fd1efedcSConrad Meyer }
180fd1efedcSConrad Meyer
181fd1efedcSConrad Meyer settimes(f_time, f_dayBefore, f_dayAfter, Friday, &tp1, &tp2);
182fd1efedcSConrad Meyer generatedates(&tp1, &tp2);
183fd1efedcSConrad Meyer
184fd1efedcSConrad Meyer /*
185fd1efedcSConrad Meyer * FROM now on, we are working in UTC.
186fd1efedcSConrad Meyer * This will only affect moon and sun related events anyway.
187fd1efedcSConrad Meyer */
188fd1efedcSConrad Meyer if (setenv("TZ", "UTC", 1) != 0)
189fd1efedcSConrad Meyer errx(1, "setenv: %s", strerror(errno));
190fd1efedcSConrad Meyer tzset();
191fd1efedcSConrad Meyer
192fd1efedcSConrad Meyer if (debug)
193fd1efedcSConrad Meyer dumpdates();
194fd1efedcSConrad Meyer
195fd1efedcSConrad Meyer if (DEBUG != NULL) {
196fd1efedcSConrad Meyer dodebug(DEBUG);
197fd1efedcSConrad Meyer exit(0);
198fd1efedcSConrad Meyer }
199fd1efedcSConrad Meyer
200fd1efedcSConrad Meyer if (doall)
201fd1efedcSConrad Meyer while ((pw = getpwent()) != NULL) {
202fd1efedcSConrad Meyer pid_t pid;
203fd1efedcSConrad Meyer
204fd1efedcSConrad Meyer if (chdir(pw->pw_dir) == -1)
205fd1efedcSConrad Meyer continue;
206fd1efedcSConrad Meyer pid = fork();
207fd1efedcSConrad Meyer if (pid < 0)
208fd1efedcSConrad Meyer err(1, "fork");
209fd1efedcSConrad Meyer if (pid == 0) {
210fd1efedcSConrad Meyer login_cap_t *lc;
211fd1efedcSConrad Meyer
212fd1efedcSConrad Meyer lc = login_getpwclass(pw);
213fd1efedcSConrad Meyer if (setusercontext(lc, pw, pw->pw_uid,
214*6cb8b61eSKyle Evans LOGIN_SETALL & ~LOGIN_SETLOGIN) != 0)
215fd1efedcSConrad Meyer errx(1, "setusercontext");
2163fa2a149SStefan Eßer setenv("HOME", pw->pw_dir, 1);
217fd1efedcSConrad Meyer cal();
218fd1efedcSConrad Meyer exit(0);
219fd1efedcSConrad Meyer }
220fd1efedcSConrad Meyer }
221fd1efedcSConrad Meyer else {
222fd1efedcSConrad Meyer #ifdef WITH_ICONV
223fd1efedcSConrad Meyer /* Save the information about the encoding used in the terminal. */
224fd1efedcSConrad Meyer outputEncoding = strdup(nl_langinfo(CODESET));
225fd1efedcSConrad Meyer if (outputEncoding == NULL)
226fd1efedcSConrad Meyer errx(1, "cannot allocate memory");
227fd1efedcSConrad Meyer #endif
228fd1efedcSConrad Meyer cal();
229fd1efedcSConrad Meyer }
230fd1efedcSConrad Meyer exit(0);
231fd1efedcSConrad Meyer }
232fd1efedcSConrad Meyer
233fd1efedcSConrad Meyer
234fd1efedcSConrad Meyer static void __dead2
usage(void)235fd1efedcSConrad Meyer usage(void)
236fd1efedcSConrad Meyer {
237fd1efedcSConrad Meyer
238fd1efedcSConrad Meyer fprintf(stderr, "%s\n%s\n%s\n",
239fd1efedcSConrad Meyer "usage: calendar [-A days] [-a] [-B days] [-D sun|moon] [-d]",
240fd1efedcSConrad Meyer " [-F friday] [-f calendarfile] [-l longitude]",
241fd1efedcSConrad Meyer " [-t dd[.mm[.year]]] [-U utcoffset] [-W days]"
242fd1efedcSConrad Meyer );
243fd1efedcSConrad Meyer exit(1);
244fd1efedcSConrad Meyer }
245