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