1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 #include "limits.h" 33 #include "ulimit.h" 34 #include "sys/utsname.h" 35 36 #include "lpsched.h" 37 38 #include <sys/stat.h> 39 #include <sys/time.h> /* to up the max # of fds */ 40 #include <sys/resource.h> 41 #include <syslog.h> 42 #include <locale.h> 43 #include <stdio_ext.h> 44 45 46 int lock_fd = -1; 47 int isStartingForms = 0; 48 int Starting = 0; 49 int Shutdown = 0; 50 int DoneChildren = 0; 51 int Sig_Alrm = 0; 52 int OpenMax = OPEN_MAX; 53 int Reserve_Fds = 0; 54 55 char *Local_System = 0; 56 char *SHELL = 0; 57 58 gid_t Lp_Gid; 59 uid_t Lp_Uid; 60 61 #if defined(DEBUG) 62 unsigned long debug = 0; 63 static int signals = 0; 64 #endif 65 66 extern int errno; 67 extern void shutdown_messages(); 68 69 int am_in_background = 0; 70 71 static void disable_signals(); 72 static void startup(); 73 static void process(); 74 static void ticktock(int); 75 static void background(); 76 static void usage(); 77 static void Exit(); 78 static void disable_signals(); 79 80 /** 81 ** main() 82 **/ 83 84 int 85 main(int argc, char *argv[]) 86 { 87 int c; 88 extern char *optarg; 89 extern int optopt; 90 extern int opterr; 91 char * cp; 92 struct rlimit rlim; 93 int fd_limit = 4096; 94 95 (void) setlocale(LC_ALL, ""); 96 if ((cp = strrchr(argv[0], '/')) == NULL) 97 cp = argv[0]; 98 else 99 cp++; 100 101 /* open the syslog() */ 102 openlog(cp, LOG_PID|LOG_NDELAY|LOG_NOWAIT, LOG_LPR); 103 104 SHELL = DEFAULT_SHELL; 105 106 opterr = 0; 107 while((c = getopt(argc, (char * const *)argv, "dsf:n:r:M:p:")) != EOF) 108 switch(c) 109 { 110 # if defined (DEBUG) 111 case 'd': 112 debug = DB_ALL; 113 syslog(LOG_DEBUG, "debug = DB_ALL"); 114 break; 115 116 case 's': 117 signals++; 118 break; 119 # endif /* DEBUG */ 120 121 case 'f': 122 if ((ET_SlowSize = atoi(optarg)) < 1) 123 ET_SlowSize = 1; 124 syslog(LOG_DEBUG, "-f option is %d", ET_SlowSize); 125 break; 126 127 case 'n': 128 if ((ET_NotifySize = atoi(optarg)) < 1) 129 ET_NotifySize = 1; 130 syslog(LOG_DEBUG, "-n option is %d", ET_NotifySize); 131 break; 132 133 case 'r': 134 if ((Reserve_Fds = atoi(optarg)) < 0) 135 Reserve_Fds = 0; 136 syslog(LOG_DEBUG, "-r option is %d", Reserve_Fds); 137 break; 138 139 case 'p': 140 if ((fd_limit = atoi(optarg)) < 16) 141 fd_limit = 4096; 142 syslog(LOG_DEBUG, "-p option is %d", fd_limit); 143 break; 144 145 case '?': 146 if (optopt == '?') { 147 usage (); 148 exit (0); 149 } else 150 fail ("%s: illegal option -- %c\n", argv[0], optopt); 151 } 152 153 /* reset the fd resource limit */ 154 rlim.rlim_max = rlim.rlim_cur = fd_limit; 155 setrlimit(RLIMIT_NOFILE, &rlim); 156 getrlimit(RLIMIT_NOFILE, &rlim); 157 (void) enable_extended_FILE_stdio(-1, -1); 158 syslog(LOG_DEBUG, "file descriptor resource limit is %d (~%d printers)", 159 rlim.rlim_cur, (rlim.rlim_cur - 12)/ 2); 160 161 lp_alloc_fail_handler = mallocfail; 162 163 startup(); 164 165 process(); 166 167 lpshut(1); /* one last time to clean up */ 168 /*NOTREACHED*/ 169 return (0); 170 } 171 172 static void 173 startup() 174 { 175 struct passwd *p; 176 177 178 Starting = 1; 179 getpaths(); 180 181 /* 182 * There must be a user named "lp". 183 */ 184 if ((p = getpwnam(LPUSER)) == NULL) 185 fail ("Can't find the user \"lp\" on this system!\n"); 186 187 Lp_Uid = p->pw_uid; 188 Lp_Gid = p->pw_gid; 189 190 /* 191 * Only "root" is allowed to run us. 192 */ 193 if ((getuid() != 0) && (geteuid() != 0)) 194 fail ("You must be \"root\" to run this program.\n"); 195 196 setuid (0); 197 198 Local_System = Strdup("localhost"); 199 200 /* 201 * Make sure that all critical directories are present and that 202 * symbolic links are correct. 203 */ 204 lpfsck(); 205 206 /* 207 * Try setting the lock file to see if another Spooler is running. 208 * We'll release it immediately; this allows us to fork the child 209 * that will run in the background. The child will relock the file. 210 */ 211 if ((lock_fd = open_locked(Lp_Schedlock, "a", 0664)) < 0) 212 if (errno == EAGAIN) 213 fail ("Print services already active.\n"); 214 else 215 fail ("Can't open file \"%s\" (%s).\n", NB(Lp_Schedlock), PERROR); 216 close(lock_fd); 217 218 background(); 219 /* 220 * We are the child process now. 221 */ 222 223 if ((lock_fd = open_locked(Lp_Schedlock, "w", 0664)) < 0) 224 fail ("Failed to lock the file \"%s\" (%s).\n", NB(Lp_Schedlock), PERROR); 225 226 Close (0); 227 Close (2); 228 if (am_in_background) 229 Close (1); 230 231 if ((OpenMax = ulimit(4, 0L)) == -1) 232 OpenMax = OPEN_MAX; 233 234 disable_signals(); 235 236 init_messages(); 237 238 init_memory(); 239 240 note ("Print services started.\n"); 241 Starting = 0; 242 } 243 244 void 245 lpshut(int immediate) 246 { 247 int i; 248 extern MESG * Net_md; 249 250 251 /* 252 * If this is the first time here, stop all running 253 * child processes, and shut off the alarm clock so 254 * it doesn't bug us. 255 */ 256 if (!Shutdown) { 257 mputm (Net_md, S_SHUTDOWN, 1); 258 for (i = 0; Exec_Table != NULL && Exec_Table[i] != NULL; i++) 259 terminate (Exec_Table[i]); 260 alarm (0); 261 Shutdown = (immediate? 2 : 1); 262 } 263 264 /* 265 * If this is an express shutdown, or if all the 266 * child processes have been cleaned up, clean up 267 * and get out. 268 */ 269 if (Shutdown == 2) { 270 271 /* 272 * We don't shut down the message queues until 273 * now, to give the children a chance to answer. 274 * This means an LP command may have been snuck 275 * in while we were waiting for the children to 276 * finish, but that's OK because we'll have 277 * stored the jobs on disk (that's part of the 278 * normal operation, not just during shutdown phase). 279 */ 280 shutdown_messages(); 281 282 (void) close(lock_fd); 283 (void) Unlink(Lp_Schedlock); 284 285 note ("Print services stopped.\n"); 286 exit (0); 287 /*NOTREACHED*/ 288 } 289 } 290 291 static void 292 process() 293 { 294 FSTATUS *pfs; 295 PWSTATUS *ppws; 296 int i; 297 298 299 /* 300 * Call the "check_..._alert()" routines for each form/print-wheel; 301 * we need to do this at this point because these routines 302 * short-circuit themselves while we are in startup mode. 303 * Calling them now will kick off any necessary alerts. 304 */ 305 isStartingForms = 1; 306 for (i = 0; FStatus != NULL && FStatus[i] != NULL; i++) 307 check_form_alert (FStatus[i], (_FORM *)0); 308 isStartingForms = 0; 309 310 for (i = 0; PWStatus != NULL && PWStatus[i] != NULL; i++) 311 check_pwheel_alert (PWStatus[i], (PWHEEL *)0); 312 313 /* 314 * Clear the alarm, then schedule an EV_ALARM. This will clear 315 * all events that had been scheduled for later without waiting 316 * for the next tick. 317 */ 318 alarm (0); 319 schedule (EV_ALARM); 320 321 /* 322 * Start the ball rolling. 323 */ 324 schedule (EV_INTERF, (PSTATUS *)0); 325 schedule (EV_NOTIFY, (RSTATUS *)0); 326 schedule (EV_SLOWF, (RSTATUS *)0); 327 328 for (EVER) { 329 take_message (); 330 331 if (Sig_Alrm) 332 schedule (EV_ALARM); 333 334 if (DoneChildren) 335 dowait (); 336 337 if (Shutdown) 338 check_children(); 339 if (Shutdown == 2) 340 break; 341 } 342 } 343 344 /*ARGSUSED*/ 345 static void 346 ticktock(int sig) 347 { 348 Sig_Alrm = 1; 349 (void)signal (SIGALRM, ticktock); 350 return; 351 } 352 353 static void 354 background() 355 { 356 #if defined(DEBUG) 357 if (debug & DB_SDB) 358 return; 359 #endif 360 361 switch(fork()) 362 { 363 case -1: 364 fail ("Failed to fork child process (%s).\n", PERROR); 365 /*NOTREACHED*/ 366 367 case 0: 368 (void) setpgrp(); 369 am_in_background = 1; 370 return; 371 372 default: 373 note ("Print services started.\n"); 374 exit(0); 375 /* NOTREACHED */ 376 } 377 } 378 379 static void 380 usage() 381 { 382 note ("\ 383 usage: lpsched [ options ]\n\ 384 [ -f #filter-slots ] (increase no. concurrent slow filters)\n\ 385 [ -n #notify-slots ] (increase no. concurrent notifications)\n\ 386 [ -r #reserved-fds ] (increase margin of file descriptors)\n" 387 ); 388 389 #if defined(DEBUG) 390 note ("\ 391 [ -d ] (same as -D ALL)\n\ 392 [ -s ] (don't trap most signals)\n" 393 ); 394 #endif 395 396 note ("\ 397 WARNING: all these options are currently unsupported\n" 398 ); 399 400 return; 401 } 402 403 static void 404 Exit(n) 405 int n; 406 { 407 fail ("Received unexpected signal %d; terminating.\n", n); 408 } 409 410 static void 411 disable_signals() 412 { 413 int i; 414 415 # if defined(DEBUG) 416 if (!signals) 417 # endif 418 for (i = 0; i < NSIG; i++) 419 if (signal(i, SIG_IGN) != SIG_IGN) 420 signal (i, Exit); 421 422 (void) signal(SIGHUP, SIG_IGN); 423 (void) signal(SIGINT, SIG_IGN); 424 (void) signal(SIGQUIT, SIG_IGN); 425 (void) signal(SIGALRM, ticktock); 426 (void) signal(SIGTERM, lpshut); /* needs arg, but sig# OK */ 427 (void) signal(SIGCLD, SIG_IGN); 428 (void) signal(SIGTSTP, SIG_IGN); 429 (void) signal(SIGCONT, SIG_DFL); 430 (void) signal(SIGTTIN, SIG_IGN); 431 (void) signal(SIGTTOU, SIG_IGN); 432 (void) signal(SIGXFSZ, SIG_IGN); /* could be a problem */ 433 (void) signal(SIGWINCH, SIG_IGN); /* if started in a window */ 434 (void) signal(SIGTHAW, SIG_IGN); /* used by CPR - energystar */ 435 436 #if defined(DEBUG) 437 if (debug & DB_ABORT) 438 (void) signal(SIGABRT, SIG_DFL); 439 #endif 440 441 } 442