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