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