Home | History | Annotate | Download | only in lpsched
      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