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
main(int argc,char * argv[])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
startup()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
lpshut(int immediate)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
process()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
ticktock(int sig)344 ticktock(int sig)
345 {
346 Sig_Alrm = 1;
347 (void)signal (SIGALRM, ticktock);
348 return;
349 }
350
351 static void
background()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
usage()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
Exit(n)402 Exit(n)
403 int n;
404 {
405 fail ("Received unexpected signal %d; terminating.\n", n);
406 }
407
408 static void
disable_signals()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