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