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