]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/main.c
Added implicit/auto class code.
[thirdparty/cups.git] / scheduler / main.c
1 /*
2 * "$Id: main.c,v 1.19 1999/06/09 20:07:04 mike Exp $"
3 *
4 * Scheduler main loop for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-1999 by Easy Software Products, all rights reserved.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44145 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
19 *
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * main() - Main entry for the CUPS scheduler.
27 * sigchld_handler() - Handle 'child' signals from old processes.
28 * sighup_handler() - Handle 'hangup' signals to reconfigure the scheduler.
29 * usage() - Show scheduler usage.
30 */
31
32 /*
33 * Include necessary headers...
34 */
35
36 #define _MAIN_C_
37 #include "cupsd.h"
38 #include <sys/resource.h>
39
40
41 /*
42 * Local functions...
43 */
44
45 static void sigchld_handler(int sig);
46 static void sighup_handler(int sig);
47 static void usage(void);
48
49
50 /*
51 * 'main()' - Main entry for the CUPS scheduler.
52 */
53
54 int /* O - Exit status */
55 main(int argc, /* I - Number of command-line arguments */
56 char *argv[]) /* I - Command-line arguments */
57 {
58 int i; /* Looping var */
59 char *opt; /* Option character */
60 fd_set input, /* Input set for select() */
61 output; /* Output set for select() */
62 client_t *con; /* Current client */
63 job_t *job, /* Current job */
64 *next; /* Next job */
65 listener_t *lis; /* Current listener */
66 time_t activity; /* Activity timer */
67 struct timeval timeout; /* select() timeout */
68 struct rlimit limit; /* Runtime limit */
69 #ifdef HAVE_SIGACTION
70 struct sigaction action; /* Actions for POSIX signals */
71 #endif /* HAVE_SIGACTION */
72
73
74 /*
75 * Check for command-line arguments...
76 */
77
78 for (i = 1; i < argc; i ++)
79 if (argv[i][0] == '-')
80 for (opt = argv[i] + 1; *opt != '\0'; opt ++)
81 switch (*opt)
82 {
83 case 'c' : /* Configuration file */
84 i ++;
85 if (i >= argc)
86 usage();
87
88 strncpy(ConfigurationFile, argv[i], sizeof(ConfigurationFile) - 1);
89 ConfigurationFile[sizeof(ConfigurationFile) - 1] = '\0';
90 break;
91
92 default : /* Unknown option */
93 fprintf(stderr, "cupsd: Unknown option \'%c\' - aborting!\n", *opt);
94 usage();
95 break;
96 }
97 else
98 {
99 fprintf(stderr, "cupsd: Unknown argument \'%s\' - aborting!\n", argv[i]);
100 usage();
101 }
102
103 /*
104 * Set the timezone to GMT...
105 */
106
107 putenv("TZ=GMT");
108 tzset();
109
110 #ifndef DEBUG
111 /*
112 * Disable core dumps...
113 */
114
115 getrlimit(RLIMIT_CORE, &limit);
116 limit.rlim_cur = 0;
117 setrlimit(RLIMIT_CORE, &limit);
118 #endif /* DEBUG */
119
120 /*
121 * Set the maximum number of files...
122 */
123
124 getrlimit(RLIMIT_NOFILE, &limit);
125 limit.rlim_cur = limit.rlim_max;
126 setrlimit(RLIMIT_NOFILE, &limit);
127
128 /*
129 * Catch hangup and child signals and ignore broken pipes...
130 */
131
132 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
133 sigset(SIGHUP, sighup_handler);
134 sigset(SIGCHLD, sigchld_handler);
135 sigset(SIGPIPE, SIG_IGN);
136 #elif defined(HAVE_SIGACTION)
137 memset(&action, 0, sizeof(action));
138
139 sigemptyset(&action.sa_mask);
140 sigaddset(&action.sa_mask, SIGHUP);
141 action.sa_handler = sighup_handler;
142 sigaction(SIGHUP, &action, NULL);
143
144 sigemptyset(&action.sa_mask);
145 sigaddset(&action.sa_mask, SIGCHLD);
146 action.sa_handler = sigchld_handler;
147 sigaction(SIGCHLD, &action, NULL);
148
149 sigemptyset(&action.sa_mask);
150 action.sa_handler = SIG_IGN;
151 sigaction(SIGPIPE, &action, NULL);
152 #else
153 signal(SIGHUP, sighup_handler);
154 signal(SIGCLD, sigchld_handler); /* No, SIGCLD isn't a typo... */
155 signal(SIGPIPE, SIG_IGN);
156 #endif /* HAVE_SIGSET */
157
158 /*
159 * Loop forever...
160 */
161
162 for (;;)
163 {
164 /*
165 * Check if we need to load the server configuration file...
166 */
167
168 if (NeedReload)
169 {
170 if (NumClients > 0)
171 {
172 for (i = NumClients, con = Clients; i > 0; i --, con ++)
173 if (con->http.state == HTTP_WAITING)
174 {
175 CloseClient(con);
176 con --;
177 }
178 else
179 con->http.keep_alive = HTTP_KEEPALIVE_OFF;
180
181 for (i = 0; i < NumListeners; i ++)
182 FD_CLR(Listeners[i].fd, &InputSet);
183 }
184 else if (!ReadConfiguration())
185 {
186 fprintf(stderr, "cupsd: Unable to read configuration file \'%s\' - exiting!\n",
187 ConfigurationFile);
188 exit(1);
189 }
190 }
191
192 /*
193 * Check for available input or ready output. If select() returns
194 * 0 or -1, something bad happened and we should exit immediately.
195 *
196 * Note that we at least have one listening socket open at all
197 * times.
198 */
199
200 input = InputSet;
201 output = OutputSet;
202
203 timeout.tv_sec = 1;
204 timeout.tv_usec = 0;
205
206 for (i = NumClients, con = Clients; i > 0; i --, con ++)
207 if (con->http.used > 0)
208 {
209 timeout.tv_sec = 0;
210 break;
211 }
212
213 if ((i = select(100, &input, &output, NULL, &timeout)) < 0)
214 {
215 if (errno == EINTR)
216 continue;
217
218 perror("cupsd: select() failed");
219
220 #ifdef DEBUG
221 printf("cupsd: InputSet =");
222 for (i = 0; i < 100; i ++)
223 if (FD_ISSET(i, &input))
224 printf(" %d", i);
225 puts("");
226
227 printf("cupsd: OutputSet =");
228 for (i = 0; i < 100; i ++)
229 if (FD_ISSET(i, &output))
230 printf(" %d", i);
231 puts("");
232 #endif /* 0 */
233
234 break;
235 }
236
237 for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
238 if (FD_ISSET(lis->fd, &input))
239 AcceptClient(lis);
240
241 for (i = NumClients, con = Clients; i > 0; i --, con ++)
242 {
243 /*
244 * Process the input buffer...
245 */
246
247 if (FD_ISSET(con->http.fd, &input) || con->http.used)
248 if (!ReadClient(con))
249 {
250 con --;
251 continue;
252 }
253
254 /*
255 * Write data as needed...
256 */
257
258 if (FD_ISSET(con->http.fd, &output) &&
259 (!con->pipe_pid || FD_ISSET(con->file, &input)))
260 if (!WriteClient(con))
261 {
262 con --;
263 continue;
264 }
265
266 /*
267 * Check the activity and close old clients...
268 */
269
270 activity = time(NULL) - 30;
271 if (con->http.activity < activity)
272 {
273 CloseClient(con);
274 con --;
275 continue;
276 }
277 }
278
279 /*
280 * Check for status info from job filters...
281 */
282
283 for (job = Jobs; job != NULL; job = next)
284 {
285 next = job->next;
286
287 if (job->pipe && FD_ISSET(job->pipe, &input))
288 UpdateJob(job);
289 }
290
291 /*
292 * Update the browse list as needed...
293 */
294
295 if (BrowseSocket >= 0)
296 {
297 if (FD_ISSET(BrowseSocket, &input))
298 UpdateBrowseList();
299
300 SendBrowseList();
301 }
302 }
303
304 /*
305 * If we get here something very bad happened and we need to exit
306 * immediately.
307 */
308
309 CloseAllClients();
310 StopListening();
311
312 return (1);
313 }
314
315
316 /*
317 * 'sigchld_handler()' - Handle 'child' signals from old processes.
318 */
319
320 static void
321 sigchld_handler(int sig) /* I - Signal number */
322 {
323 int status; /* Exit status of child */
324 int pid; /* Process ID of child */
325 job_t *job; /* Current job */
326 int i; /* Looping var */
327
328
329 (void)sig;
330
331 #ifdef HAVE_WAITPID
332 while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
333 #elif defined(HAVE_WAIT3)
334 while ((pid = wait3(&status, WNOHANG, NULL)) > 0)
335 #else
336 if ((pid = wait(&status)) > 0)
337 #endif /* HAVE_WAITPID */
338 {
339 DEBUG_printf(("sigcld_handler: pid = %d, status = %d\n", pid, status));
340
341 for (job = Jobs; job != NULL; job = job->next)
342 if (job->state == IPP_JOB_PROCESSING)
343 {
344 for (i = 0; job->procs[i]; i ++)
345 if (job->procs[i] == pid)
346 break;
347
348 if (job->procs[i])
349 {
350 /*
351 * OK, this process has gone away; what's left?
352 */
353
354 job->procs[i] = -pid;
355
356 if (status)
357 {
358 /*
359 * A fatal error occurred; save the exit status so we know to stop
360 * the printer when all of the filters finish...
361 */
362
363 job->status = status;
364 }
365 break;
366 }
367 }
368 }
369
370 #ifdef HAVE_SIGSET
371 sigset(SIGCHLD, sigchld_handler);
372 #elif !defined(HAVE_SIGACTION)
373 signal(SIGCLD, sigchld_handler);
374 #endif /* HAVE_SIGSET */
375 }
376
377
378 /*
379 * 'sighup_handler()' - Handle 'hangup' signals to reconfigure the scheduler.
380 */
381
382 static void
383 sighup_handler(int sig) /* I - Signal number */
384 {
385 (void)sig;
386
387 NeedReload = TRUE;
388 }
389
390
391 /*
392 * 'usage()' - Show scheduler usage.
393 */
394
395 static void
396 usage(void)
397 {
398 fputs("Usage: cupsd [-c config-file]\n", stderr);
399 exit(1);
400 }
401
402
403 /*
404 * End of "$Id: main.c,v 1.19 1999/06/09 20:07:04 mike Exp $".
405 */