]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/main.c
Merge changes from 1.1 tree.
[thirdparty/cups.git] / scheduler / main.c
CommitLineData
3840d6ba 1/*
b5cb0608 2 * "$Id: main.c,v 1.57.2.1 2001/05/13 18:38:37 mike Exp $"
3840d6ba 3 *
e5cf24b2 4 * Scheduler main loop for the Common UNIX Printing System (CUPS).
3840d6ba 5 *
d2935a0f 6 * Copyright 1997-2001 by Easy Software Products, all rights reserved.
3840d6ba 7 *
fd8b1cf8 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:
3840d6ba 14 *
fd8b1cf8 15 * Attn: CUPS Licensing Information
16 * Easy Software Products
8784b6a6 17 * 44141 Airport View Drive, Suite 204
fd8b1cf8 18 * Hollywood, Maryland 20636-3111 USA
3840d6ba 19 *
fd8b1cf8 20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
992cf15a 23 *
fd8b1cf8 24 * Contents:
3840d6ba 25 *
d7845573 26 * main() - Main entry for the CUPS scheduler.
27 * CatchChildSignals() - Catch SIGCHLD signals...
28 * IgnoreChildSignals() - Ignore SIGCHLD signals...
29 * sigchld_handler() - Handle 'child' signals from old processes.
30 * sighup_handler() - Handle 'hangup' signals to reconfigure the scheduler.
31 * sigterm_handler() - Handle 'terminate' signals that stop the scheduler.
32 * usage() - Show scheduler usage.
3840d6ba 33 */
34
35/*
36 * Include necessary headers...
37 */
38
39#define _MAIN_C_
40#include "cupsd.h"
8b43895a 41#include <sys/resource.h>
a3e17a89 42#include <syslog.h>
3840d6ba 43
2bdd1992 44#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
8c57ced1 45# include <malloc.h>
2bdd1992 46#endif /* HAVE_MALLOC_H && HAVE_MALLINFO */
8c57ced1 47
5ec612d5 48#ifndef FD_SETSIZE
49# define FD_SETSIZE 1024
50#endif /* !FD_SETSIZE */
51
3840d6ba 52
53/*
fd8b1cf8 54 * Local functions...
55 */
56
e5cf24b2 57static void sigchld_handler(int sig);
fd8b1cf8 58static void sighup_handler(int sig);
a3e17a89 59static void sigterm_handler(int sig);
fd8b1cf8 60static void usage(void);
61
62
63/*
64 * 'main()' - Main entry for the CUPS scheduler.
3840d6ba 65 */
66
67int /* O - Exit status */
68main(int argc, /* I - Number of command-line arguments */
69 char *argv[]) /* I - Command-line arguments */
70{
71 int i; /* Looping var */
fd8b1cf8 72 char *opt; /* Option character */
a3e17a89 73 int fg; /* Run in the foreground */
3840d6ba 74 fd_set input, /* Input set for select() */
75 output; /* Output set for select() */
fd8b1cf8 76 client_t *con; /* Current client */
6abc7437 77 job_t *job, /* Current job */
78 *next; /* Next job */
fd8b1cf8 79 listener_t *lis; /* Current listener */
992cf15a 80 time_t activity; /* Activity timer */
05ca02bc 81 time_t senddoc_time; /* Send-Document time */
2bdd1992 82#ifdef HAVE_MALLINFO
83 time_t mallinfo_time; /* Malloc information time */
84#endif /* HAVE_MALLINFO */
3840d6ba 85 struct timeval timeout; /* select() timeout */
8b43895a 86 struct rlimit limit; /* Runtime limit */
8a2c2126 87#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
e5cf24b2 88 struct sigaction action; /* Actions for POSIX signals */
8a2c2126 89#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
3840d6ba 90
91
fd8b1cf8 92 /*
93 * Check for command-line arguments...
94 */
95
a3e17a89 96 fg = 0;
97
fd8b1cf8 98 for (i = 1; i < argc; i ++)
99 if (argv[i][0] == '-')
100 for (opt = argv[i] + 1; *opt != '\0'; opt ++)
101 switch (*opt)
102 {
103 case 'c' : /* Configuration file */
104 i ++;
105 if (i >= argc)
106 usage();
107
a3e17a89 108 if (argv[i][0] == '/')
109 {
110 /*
111 * Absolute directory...
112 */
113
114 strncpy(ConfigurationFile, argv[i], sizeof(ConfigurationFile) - 1);
115 ConfigurationFile[sizeof(ConfigurationFile) - 1] = '\0';
116 }
117 else
118 {
119 /*
120 * Relative directory...
121 */
122
123 getcwd(ConfigurationFile, sizeof(ConfigurationFile));
124 strncat(ConfigurationFile, "/", sizeof(ConfigurationFile) - 1);
125 strncat(ConfigurationFile, argv[i], sizeof(ConfigurationFile) - 1);
126 ConfigurationFile[sizeof(ConfigurationFile) - 1] = '\0';
127 }
128 break;
129
130 case 'f' : /* Run in foreground... */
131 fg = 1;
fd8b1cf8 132 break;
133
134 default : /* Unknown option */
135 fprintf(stderr, "cupsd: Unknown option \'%c\' - aborting!\n", *opt);
136 usage();
137 break;
138 }
139 else
140 {
141 fprintf(stderr, "cupsd: Unknown argument \'%s\' - aborting!\n", argv[i]);
142 usage();
143 }
144
992cf15a 145 /*
a3e17a89 146 * If the user hasn't specified "-f", run in the background...
992cf15a 147 */
148
a3e17a89 149 if (!fg)
150 {
151 if (fork() > 0)
152 return (0);
05e63c18 153
a3e17a89 154 /*
155 * Make sure we aren't tying up any filesystems...
156 */
157
158 chdir("/");
992cf15a 159
8b43895a 160#ifndef DEBUG
a3e17a89 161 /*
162 * Disable core dumps...
163 */
164
165 getrlimit(RLIMIT_CORE, &limit);
166 limit.rlim_cur = 0;
167 setrlimit(RLIMIT_CORE, &limit);
168
169 /*
170 * Disconnect from the controlling terminal...
171 */
172
173 close(0);
174 close(1);
175 close(2);
8b43895a 176
a3e17a89 177 setsid();
178#endif /* DEBUG */
179 }
147ddbb6 180
181 /*
a3e17a89 182 * Set the timezone info...
147ddbb6 183 */
184
a3e17a89 185 if (getenv("TZ") != NULL)
a6988fb1 186 snprintf(TZ, sizeof(TZ), "TZ=%s", getenv("TZ"));
a3e17a89 187
188 tzset();
8b43895a 189
190 /*
191 * Set the maximum number of files...
192 */
193
194 getrlimit(RLIMIT_NOFILE, &limit);
5ec612d5 195 if (limit.rlim_max > FD_SETSIZE) /* Can't exceed size of FD set! */
196 MaxFDs = FD_SETSIZE;
197 else
198 MaxFDs = limit.rlim_max;
199
200 limit.rlim_cur = MaxFDs;
8b43895a 201 setrlimit(RLIMIT_NOFILE, &limit);
202
3840d6ba 203 /*
2bffb563 204 * Catch hangup and child signals and ignore broken pipes...
3840d6ba 205 */
206
e5cf24b2 207#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
f3890b95 208 if (RunAsUser)
209 sigset(SIGHUP, sigterm_handler);
210 else
0b50ddbc 211 sigset(SIGHUP, sighup_handler);
e5cf24b2 212 sigset(SIGPIPE, SIG_IGN);
a3e17a89 213 sigset(SIGTERM, sigterm_handler);
e5cf24b2 214#elif defined(HAVE_SIGACTION)
2bffb563 215 memset(&action, 0, sizeof(action));
216
f3890b95 217 sigemptyset(&action.sa_mask);
218 sigaddset(&action.sa_mask, SIGHUP);
219
220 if (RunAsUser)
221 action.sa_handler = sigterm_handler;
222 else
0b50ddbc 223 action.sa_handler = sighup_handler;
f3890b95 224
225 sigaction(SIGHUP, &action, NULL);
2bffb563 226
e5cf24b2 227 sigemptyset(&action.sa_mask);
2bffb563 228 action.sa_handler = SIG_IGN;
229 sigaction(SIGPIPE, &action, NULL);
a3e17a89 230
231 sigemptyset(&action.sa_mask);
232 sigaddset(&action.sa_mask, SIGTERM);
233 action.sa_handler = sigterm_handler;
234 sigaction(SIGTERM, &action, NULL);
e5cf24b2 235#else
f3890b95 236 if (RunAsUser)
237 signal(SIGHUP, sigterm_handler);
238 else
0b50ddbc 239 signal(SIGHUP, sighup_handler);
f3890b95 240
e5cf24b2 241 signal(SIGPIPE, SIG_IGN);
a3e17a89 242 signal(SIGTERM, sigterm_handler);
e5cf24b2 243#endif /* HAVE_SIGSET */
3840d6ba 244
1049abbe 245 /*
246 * Read configuration...
247 */
248
249 if (!ReadConfiguration())
250 {
a3e17a89 251 syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!",
252 ConfigurationFile);
253 return (1);
1049abbe 254 }
255
23bba0c3 256 InitCerts();
257
1049abbe 258 LoadAllJobs();
259
3840d6ba 260 /*
261 * Loop forever...
262 */
263
05ca02bc 264 senddoc_time = time(NULL);
265
b6ea8f29 266#ifdef HAVE_MALLINFO
267 mallinfo_time = 0;
268#endif /* HAVE_MALLINFO */
269
a74b005d 270 for (;;)
3840d6ba 271 {
fd8b1cf8 272 /*
273 * Check if we need to load the server configuration file...
274 */
275
276 if (NeedReload)
277 {
278 if (NumClients > 0)
279 {
280 for (i = NumClients, con = Clients; i > 0; i --, con ++)
a74b005d 281 if (con->http.state == HTTP_WAITING)
fd8b1cf8 282 {
283 CloseClient(con);
284 con --;
285 }
286 else
93894a43 287 con->http.keep_alive = HTTP_KEEPALIVE_OFF;
fd8b1cf8 288
d236cb49 289 PauseListening();
fd8b1cf8 290 }
291 else if (!ReadConfiguration())
292 {
a3e17a89 293 syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!",
294 ConfigurationFile);
d2122fde 295 break;
fd8b1cf8 296 }
297 }
298
3840d6ba 299 /*
300 * Check for available input or ready output. If select() returns
301 * 0 or -1, something bad happened and we should exit immediately.
302 *
42d48bd2 303 * Note that we at least have one listening socket open at all
3840d6ba 304 * times.
305 */
306
307 input = InputSet;
308 output = OutputSet;
309
f736c0e3 310 timeout.tv_sec = 1;
311 timeout.tv_usec = 0;
312
fd8b1cf8 313 for (i = NumClients, con = Clients; i > 0; i --, con ++)
a74b005d 314 if (con->http.used > 0)
f736c0e3 315 {
316 timeout.tv_sec = 0;
3840d6ba 317 break;
f736c0e3 318 }
3840d6ba 319
93336dbc 320 if ((i = select(MaxFDs, &input, &output, NULL, &timeout)) < 0)
fd8b1cf8 321 {
d236cb49 322 char s[16384], /* String buffer */
323 *sptr; /* Pointer into buffer */
324 int slen; /* Length of string buffer */
325
326
886c59e2 327 /*
328 * Got an error from select!
329 */
330
331 if (errno == EINTR) /* Just interrupted by a signal */
fd8b1cf8 332 continue;
333
886c59e2 334 /*
d236cb49 335 * Log all sorts of debug info to help track down the problem.
886c59e2 336 */
337
b5cb0608 338 LogMessage(L_EMERG, "select() failed - %s!", strerror(errno));
d236cb49 339
340 strcpy(s, "InputSet =");
341 slen = 9;
342 sptr = s + 9;
343
93336dbc 344 for (i = 0; i < MaxFDs; i ++)
d236cb49 345 if (FD_ISSET(i, &InputSet))
04de52f8 346 snprintf(sptr, sizeof(s) - slen, " %d", i);
bfa1abf0 347
b5cb0608 348 LogMessage(L_EMERG, s);
bfa1abf0 349
d236cb49 350 strcpy(s, "OutputSet =");
351 slen = 10;
352 sptr = s + 10;
353
93336dbc 354 for (i = 0; i < MaxFDs; i ++)
d236cb49 355 if (FD_ISSET(i, &OutputSet))
04de52f8 356 snprintf(sptr, sizeof(s) - slen, " %d", i);
d236cb49 357
b5cb0608 358 LogMessage(L_EMERG, s);
886c59e2 359
882031b3 360 for (i = 0, con = Clients; i < NumClients; i ++, con ++)
b5cb0608 361 LogMessage(L_EMERG, "Clients[%d] = %d, file = %d, state = %d",
df47c6ae 362 i, con->http.fd, con->file, con->http.state);
886c59e2 363
364 for (i = 0, lis = Listeners; i < NumListeners; i ++, lis ++)
b5cb0608 365 LogMessage(L_EMERG, "Listeners[%d] = %d", i, lis->fd);
886c59e2 366
b5cb0608 367 LogMessage(L_EMERG, "BrowseSocket = %d", BrowseSocket);
886c59e2 368
369 for (job = Jobs; job != NULL; job = job->next)
b5cb0608 370 LogMessage(L_EMERG, "Jobs[%d] = %d", job->id, job->pipe);
bfa1abf0 371
3840d6ba 372 break;
fd8b1cf8 373 }
3840d6ba 374
fd8b1cf8 375 for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
376 if (FD_ISSET(lis->fd, &input))
377 AcceptClient(lis);
3840d6ba 378
fd8b1cf8 379 for (i = NumClients, con = Clients; i > 0; i --, con ++)
3840d6ba 380 {
3840d6ba 381 /*
382 * Process the input buffer...
383 */
384
a74b005d 385 if (FD_ISSET(con->http.fd, &input) || con->http.used)
fd8b1cf8 386 if (!ReadClient(con))
3840d6ba 387 {
388 con --;
3840d6ba 389 continue;
390 }
391
392 /*
393 * Write data as needed...
394 */
395
96df88bb 396 if (FD_ISSET(con->http.fd, &output) &&
397 (!con->pipe_pid || FD_ISSET(con->file, &input)))
fd8b1cf8 398 if (!WriteClient(con))
3840d6ba 399 {
400 con --;
992cf15a 401 continue;
3840d6ba 402 }
992cf15a 403
404 /*
fd8b1cf8 405 * Check the activity and close old clients...
992cf15a 406 */
407
df47c6ae 408 activity = time(NULL) - Timeout;
409 if (con->http.activity < activity && !con->pipe_pid)
992cf15a 410 {
fd8b1cf8 411 CloseClient(con);
992cf15a 412 con --;
992cf15a 413 continue;
414 }
3840d6ba 415 }
6abc7437 416
417 /*
418 * Check for status info from job filters...
419 */
420
421 for (job = Jobs; job != NULL; job = next)
422 {
423 next = job->next;
424
425 if (job->pipe && FD_ISSET(job->pipe, &input))
b5cb0608 426 {
427 /*
428 * Clear the input bit to avoid updating the next job
429 * using the same status pipe file descriptor...
430 */
431
432 FD_CLR(job->pipe, &input);
433
434 /*
435 * Read any status messages from the filters...
436 */
437
6abc7437 438 UpdateJob(job);
b5cb0608 439 }
6abc7437 440 }
d6de4648 441
442 /*
443 * Update the browse list as needed...
444 */
445
f63a2256 446 if (Browsing)
a40c1c6f 447 {
448 if (FD_ISSET(BrowseSocket, &input))
449 UpdateBrowseList();
d6de4648 450
a40c1c6f 451 SendBrowseList();
452 }
d2122fde 453
05ca02bc 454 /*
455 * Update any pending multi-file documents...
456 */
457
f3c3b479 458 if ((time(NULL) - senddoc_time) >= 10)
05ca02bc 459 {
460 CheckJobs();
461 senddoc_time = time(NULL);
462 }
463
2bdd1992 464#ifdef HAVE_MALLINFO
d2122fde 465 /*
2bdd1992 466 * Log memory usage every minute...
d2122fde 467 */
468
2bdd1992 469 if ((time(NULL) - mallinfo_time) >= 60 && LogLevel >= L_DEBUG)
d2122fde 470 {
8c57ced1 471 struct mallinfo mem; /* Malloc information */
472
473
8c57ced1 474 mem = mallinfo();
475 LogMessage(L_DEBUG, "mallinfo: arena = %d, used = %d, free = %d\n",
476 mem.arena, mem.usmblks + mem.uordblks,
477 mem.fsmblks + mem.fordblks);
2bdd1992 478 mallinfo_time = time(NULL);
479 }
480#endif /* HAVE_MALLINFO */
8c57ced1 481
2bdd1992 482 /*
483 * Update the root certificate once every 5 minutes...
484 */
485
486 if ((time(NULL) - RootCertTime) >= 300)
487 {
8c57ced1 488 /*
489 * Update the root certificate...
490 */
491
d2122fde 492 DeleteCert(0);
493 AddCert(0, "root");
494 }
3840d6ba 495 }
496
497 /*
498 * If we get here something very bad happened and we need to exit
499 * immediately.
500 */
501
d2122fde 502 DeleteAllCerts();
fd8b1cf8 503 CloseAllClients();
504 StopListening();
505
506 return (1);
507}
3840d6ba 508
3840d6ba 509
d7845573 510/*
511 * 'CatchChildSignals()' - Catch SIGCHLD signals...
512 */
513
514void
515CatchChildSignals(void)
516{
517#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
518 struct sigaction action; /* Actions for POSIX signals */
519#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
520
521
522#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
523 sigset(SIGCHLD, sigchld_handler);
524#elif defined(HAVE_SIGACTION)
525 memset(&action, 0, sizeof(action));
526
527 sigemptyset(&action.sa_mask);
528 sigaddset(&action.sa_mask, SIGCHLD);
529 action.sa_handler = sigchld_handler;
530 sigaction(SIGCHLD, &action, NULL);
531#else
532 signal(SIGCLD, sigchld_handler); /* No, SIGCLD isn't a typo... */
533#endif /* HAVE_SIGSET */
534}
535
536
537/*
538 * 'IgnoreChildSignals()' - Ignore SIGCHLD signals...
539 */
540
541void
542IgnoreChildSignals(void)
543{
544#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
545 struct sigaction action; /* Actions for POSIX signals */
546#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
547
548#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
549 sigset(SIGCHLD, SIG_IGN);
550#elif defined(HAVE_SIGACTION)
551 memset(&action, 0, sizeof(action));
552
553 sigemptyset(&action.sa_mask);
554 sigaddset(&action.sa_mask, SIGCHLD);
555 action.sa_handler = SIG_IGN;
556 sigaction(SIGCHLD, &action, NULL);
557#else
558 signal(SIGCLD, SIG_IGN); /* No, SIGCLD isn't a typo... */
559#endif /* HAVE_SIGSET */
560}
561
562
6abc7437 563/*
e5cf24b2 564 * 'sigchld_handler()' - Handle 'child' signals from old processes.
6abc7437 565 */
566
567static void
e5cf24b2 568sigchld_handler(int sig) /* I - Signal number */
6abc7437 569{
e5cf24b2 570 int status; /* Exit status of child */
571 int pid; /* Process ID of child */
572 job_t *job; /* Current job */
573 int i; /* Looping var */
6abc7437 574
575
576 (void)sig;
577
e5cf24b2 578#ifdef HAVE_WAITPID
579 while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
580#elif defined(HAVE_WAIT3)
581 while ((pid = wait3(&status, WNOHANG, NULL)) > 0)
582#else
583 if ((pid = wait(&status)) > 0)
584#endif /* HAVE_WAITPID */
585 {
586 DEBUG_printf(("sigcld_handler: pid = %d, status = %d\n", pid, status));
6abc7437 587
d2122fde 588 /*
589 * Delete certificates for CGI processes...
590 */
591
592 if (pid)
593 DeleteCert(pid);
594
595 /*
596 * Ignore SIGTERM errors - that comes when a job is cancelled...
597 */
598
6bc08d08 599 if (status == SIGTERM)
600 status = 0;
601
602 if (status)
603 {
604 if (status < 256)
5ea8888e 605 LogMessage(L_ERROR, "PID %d crashed on signal %d!", pid, status);
6bc08d08 606 else
6d8b6788 607 LogMessage(L_ERROR, "PID %d stopped with status %d!", pid,
6bc08d08 608 status / 256);
609 }
e5b7bd9c 610
e5cf24b2 611 for (job = Jobs; job != NULL; job = job->next)
1049abbe 612 if (job->state->values[0].integer == IPP_JOB_PROCESSING)
6abc7437 613 {
e5cf24b2 614 for (i = 0; job->procs[i]; i ++)
615 if (job->procs[i] == pid)
616 break;
6abc7437 617
e5cf24b2 618 if (job->procs[i])
bfa1abf0 619 {
620 /*
e5cf24b2 621 * OK, this process has gone away; what's left?
bfa1abf0 622 */
6abc7437 623
e5cf24b2 624 job->procs[i] = -pid;
6abc7437 625
bd84e0d1 626 if (status && job->status >= 0)
e5cf24b2 627 {
628 /*
bd84e0d1 629 * An error occurred; save the exit status so we know to stop
630 * the printer or cancel the job when all of the filters finish...
631 *
632 * A negative status indicates that the backend failed and the
633 * printer needs to be stopped.
e5cf24b2 634 */
635
bd84e0d1 636 if (!job->procs[i + 1])
637 job->status = -status; /* Backend failed */
638 else
639 job->status = status; /* Filter failed */
e5cf24b2 640 }
e5cf24b2 641 break;
642 }
6abc7437 643 }
e5cf24b2 644 }
645
646#ifdef HAVE_SIGSET
647 sigset(SIGCHLD, sigchld_handler);
648#elif !defined(HAVE_SIGACTION)
649 signal(SIGCLD, sigchld_handler);
650#endif /* HAVE_SIGSET */
6abc7437 651}
652
653
fd8b1cf8 654/*
655 * 'sighup_handler()' - Handle 'hangup' signals to reconfigure the scheduler.
656 */
657
658static void
659sighup_handler(int sig) /* I - Signal number */
660{
93894a43 661 (void)sig;
662
fd8b1cf8 663 NeedReload = TRUE;
a3e17a89 664
665#ifdef HAVE_SIGSET
666 sigset(SIGHUP, sighup_handler);
667#elif !defined(HAVE_SIGACTION)
668 signal(SIGHUP, sighup_handler);
669#endif /* HAVE_SIGSET */
670}
671
672
673/*
674 * 'sigterm_handler()' - Handle 'terminate' signals that stop the scheduler.
675 */
676
677static void
678sigterm_handler(int sig)
679{
d74efa25 680 (void)sig; /* remove compiler warnings... */
681
a3e17a89 682 /*
683 * Log an error...
684 */
685
686 LogMessage(L_ERROR, "Scheduler shutting down due to SIGTERM.");
687
688 /*
689 * Close all network clients and stop all jobs...
690 */
691
692 CloseAllClients();
693 StopListening();
694 StopPolling();
695 StopBrowsing();
696
697 if (Clients != NULL)
698 free(Clients);
699
700 StopAllJobs();
701
702 if (AccessFile != NULL)
703 fclose(AccessFile);
704
705 if (ErrorFile != NULL)
706 fclose(ErrorFile);
707
708 if (PageFile != NULL)
709 fclose(PageFile);
710
711 DeleteAllLocations();
712
713 DeleteAllClasses();
714
715 if (Devices)
716 ippDelete(Devices);
717
718 if (PPDs)
719 ippDelete(PPDs);
720
721 DeleteAllPrinters();
722
723 if (MimeDatabase != NULL)
724 mimeDelete(MimeDatabase);
725
726 exit(1);
3840d6ba 727}
728
fd8b1cf8 729
730/*
731 * 'usage()' - Show scheduler usage.
732 */
733
734static void
735usage(void)
736{
a3e17a89 737 fputs("Usage: cupsd [-c config-file] [-f]\n", stderr);
fd8b1cf8 738 exit(1);
739}
740
741
3840d6ba 742/*
b5cb0608 743 * End of "$Id: main.c,v 1.57.2.1 2001/05/13 18:38:37 mike Exp $".
3840d6ba 744 */