]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/classes.c
2 * "$Id: classes.c 7608 2008-05-21 01:37:21Z mike $"
4 * Printer class routines for the Common UNIX Printing System (CUPS).
6 * Copyright 2007 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
17 * cupsdAddClass() - Add a class to the system.
18 * cupsdAddPrinterToClass() - Add a printer to a class...
19 * cupsdDeletePrinterFromClass() - Delete a printer from a class.
20 * cupsdDeletePrinterFromClasses() - Delete a printer from all classes.
21 * cupsdDeleteAllClasses() - Remove all classes from the system.
22 * cupsdFindAvailablePrinter() - Find an available printer in a class.
23 * cupsdFindClass() - Find the named class.
24 * cupsdLoadAllClasses() - Load classes from the classes.conf file.
25 * cupsdSaveAllClasses() - Save classes to the classes.conf file.
26 * cupsdUpdateImplicitClasses() - Update the accepting state of implicit
31 * Include necessary headers...
38 * 'cupsdAddClass()' - Add a class to the system.
41 cupsd_printer_t
* /* O - New class */
42 cupsdAddClass(const char *name
) /* I - Name of class */
44 cupsd_printer_t
*c
; /* New class */
48 * Add the printer and set the type to "class"...
51 if ((c
= cupsdAddPrinter(name
)) != NULL
)
54 * Change from a printer to a class...
57 c
->type
= CUPS_PRINTER_CLASS
;
59 cupsdSetStringf(&c
->uri
, "ipp://%s:%d/classes/%s", ServerName
, LocalPort
,
61 cupsdSetString(&c
->error_policy
, "retry-job");
69 * 'cupsdAddPrinterToClass()' - Add a printer to a class...
73 cupsdAddPrinterToClass(
74 cupsd_printer_t
*c
, /* I - Class to add to */
75 cupsd_printer_t
*p
) /* I - Printer to add */
77 int i
; /* Looping var */
78 cupsd_printer_t
**temp
; /* Pointer to printer array */
82 * See if this printer is already a member of the class...
85 for (i
= 0; i
< c
->num_printers
; i
++)
86 if (c
->printers
[i
] == p
)
90 * Allocate memory as needed...
93 if (c
->num_printers
== 0)
94 temp
= malloc(sizeof(cupsd_printer_t
*));
96 temp
= realloc(c
->printers
, sizeof(cupsd_printer_t
*) * (c
->num_printers
+ 1));
100 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to add printer %s to class %s!",
106 * Add the printer to the end of the array and update the number of printers.
110 temp
+= c
->num_printers
;
118 * 'cupsdDeletePrinterFromClass()' - Delete a printer from a class.
122 cupsdDeletePrinterFromClass(
123 cupsd_printer_t
*c
, /* I - Class to delete from */
124 cupsd_printer_t
*p
) /* I - Printer to delete */
126 int i
; /* Looping var */
127 cups_ptype_t type
, /* Class type */
128 oldtype
; /* Old class type */
132 * See if the printer is in the class...
135 for (i
= 0; i
< c
->num_printers
; i
++)
136 if (p
== c
->printers
[i
])
140 * If it is, remove it from the list...
143 if (i
< c
->num_printers
)
146 * Yes, remove the printer...
150 if (i
< c
->num_printers
)
151 memmove(c
->printers
+ i
, c
->printers
+ i
+ 1,
152 (c
->num_printers
- i
) * sizeof(cupsd_printer_t
*));
158 * Recompute the printer type mask as needed...
161 if (c
->num_printers
> 0)
164 type
= c
->type
& (CUPS_PRINTER_CLASS
| CUPS_PRINTER_IMPLICIT
);
165 c
->type
= ~CUPS_PRINTER_REMOTE
;
167 for (i
= 0; i
< c
->num_printers
; i
++)
168 c
->type
&= c
->printers
[i
]->type
;
173 * Update the IPP attributes...
176 if (c
->type
!= oldtype
)
177 cupsdSetPrinterAttrs(c
);
183 * 'cupsdDeletePrinterFromClasses()' - Delete a printer from all classes.
187 cupsdDeletePrinterFromClasses(
188 cupsd_printer_t
*p
) /* I - Printer to delete */
190 cupsd_printer_t
*c
; /* Pointer to current class */
194 * Loop through the printer/class list and remove the printer
195 * from each class listed...
198 for (c
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
200 c
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
201 if (c
->type
& (CUPS_PRINTER_CLASS
| CUPS_PRINTER_IMPLICIT
))
202 cupsdDeletePrinterFromClass(c
, p
);
205 * Then clean out any empty implicit classes...
208 for (c
= (cupsd_printer_t
*)cupsArrayFirst(ImplicitPrinters
);
210 c
= (cupsd_printer_t
*)cupsArrayNext(ImplicitPrinters
))
211 if (c
->num_printers
== 0)
213 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Deleting implicit class \"%s\"...",
215 cupsdDeletePrinter(c
, 0);
221 * 'cupsdDeleteAllClasses()' - Remove all classes from the system.
225 cupsdDeleteAllClasses(void)
227 cupsd_printer_t
*c
; /* Pointer to current printer/class */
230 for (c
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
232 c
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
233 if (c
->type
& CUPS_PRINTER_CLASS
)
234 cupsdDeletePrinter(c
, 0);
239 * 'cupsdFindAvailablePrinter()' - Find an available printer in a class.
242 cupsd_printer_t
* /* O - Available printer or NULL */
243 cupsdFindAvailablePrinter(
244 const char *name
) /* I - Class to check */
246 int i
; /* Looping var */
247 cupsd_printer_t
*c
; /* Printer class */
254 if ((c
= cupsdFindClass(name
)) == NULL
)
256 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to find class \"%s\"!", name
);
260 if (c
->num_printers
== 0)
264 * Make sure that the last printer is also a valid index into the printer
265 * array. If not, reset the last printer to 0...
268 if (c
->last_printer
>= c
->num_printers
)
272 * Loop through the printers in the class and return the first idle
273 * printer... We keep track of the last printer that we used so that
274 * a "round robin" type of scheduling is realized (otherwise the first
275 * server might be saturated with print jobs...)
277 * Thanks to Joel Fredrikson for helping us get this right!
280 for (i
= c
->last_printer
+ 1; ; i
++)
282 if (i
>= c
->num_printers
)
285 if (c
->printers
[i
]->accepting
&&
286 (c
->printers
[i
]->state
== IPP_PRINTER_IDLE
||
287 ((c
->printers
[i
]->type
& CUPS_PRINTER_REMOTE
) && !c
->printers
[i
]->job
)))
290 return (c
->printers
[i
]);
293 if (i
== c
->last_printer
)
302 * 'cupsdFindClass()' - Find the named class.
305 cupsd_printer_t
* /* O - Matching class or NULL */
306 cupsdFindClass(const char *name
) /* I - Name of class */
308 cupsd_printer_t
*c
; /* Current class/printer */
311 if ((c
= cupsdFindDest(name
)) != NULL
&&
312 (c
->type
& (CUPS_PRINTER_CLASS
| CUPS_PRINTER_IMPLICIT
)))
320 * 'cupsdLoadAllClasses()' - Load classes from the classes.conf file.
324 cupsdLoadAllClasses(void)
326 cups_file_t
*fp
; /* classes.conf file */
327 int linenum
; /* Current line number */
328 char line
[1024], /* Line from file */
329 *value
, /* Pointer to value */
330 *valueptr
; /* Pointer into value */
331 cupsd_printer_t
*p
, /* Current printer class */
332 *temp
; /* Temporary pointer to printer */
336 * Open the classes.conf file...
339 snprintf(line
, sizeof(line
), "%s/classes.conf", ServerRoot
);
340 if ((fp
= cupsFileOpen(line
, "r")) == NULL
)
343 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to open %s - %s", line
,
349 * Read class configurations until we hit EOF...
355 while (cupsFileGetConf(fp
, line
, sizeof(line
), &value
, &linenum
))
358 * Decode the directive...
361 if (!strcasecmp(line
, "<Class") ||
362 !strcasecmp(line
, "<DefaultClass"))
365 * <Class name> or <DefaultClass name>
368 if (p
== NULL
&& value
)
370 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Loading class %s...", value
);
373 * Since prior classes may have implicitly defined this class,
374 * see if it already exists...
377 if ((p
= cupsdFindDest(value
)) != NULL
)
379 p
->type
= CUPS_PRINTER_CLASS
;
380 cupsdSetStringf(&p
->uri
, "ipp://%s:%d/classes/%s", ServerName
,
382 cupsdSetString(&p
->error_policy
, "retry-job");
385 p
= cupsdAddClass(value
);
388 p
->state
= IPP_PRINTER_IDLE
;
390 if (!strcasecmp(line
, "<DefaultClass"))
395 cupsdLogMessage(CUPSD_LOG_ERROR
,
396 "Syntax error on line %d of classes.conf.", linenum
);
400 else if (!strcasecmp(line
, "</Class>"))
404 cupsdSetPrinterAttrs(p
);
409 cupsdLogMessage(CUPSD_LOG_ERROR
,
410 "Syntax error on line %d of classes.conf.", linenum
);
416 cupsdLogMessage(CUPSD_LOG_ERROR
,
417 "Syntax error on line %d of classes.conf.", linenum
);
420 else if (!strcasecmp(line
, "AuthInfoRequired"))
422 if (!cupsdSetAuthInfoRequired(p
, value
, NULL
))
423 cupsdLogMessage(CUPSD_LOG_ERROR
,
424 "Bad AuthInfoRequired on line %d of classes.conf.",
427 else if (!strcasecmp(line
, "Info"))
430 cupsdSetString(&p
->info
, value
);
432 else if (!strcasecmp(line
, "Location"))
435 cupsdSetString(&p
->location
, value
);
437 else if (!strcasecmp(line
, "Option") && value
)
443 for (valueptr
= value
; *valueptr
&& !isspace(*valueptr
& 255); valueptr
++);
446 cupsdLogMessage(CUPSD_LOG_ERROR
,
447 "Syntax error on line %d of classes.conf.", linenum
);
450 for (; *valueptr
&& isspace(*valueptr
& 255); *valueptr
++ = '\0');
452 p
->num_options
= cupsAddOption(value
, valueptr
, p
->num_options
,
456 else if (!strcasecmp(line
, "Printer"))
460 cupsdLogMessage(CUPSD_LOG_ERROR
,
461 "Syntax error on line %d of classes.conf.", linenum
);
464 else if ((temp
= cupsdFindPrinter(value
)) == NULL
)
466 cupsdLogMessage(CUPSD_LOG_WARN
,
467 "Unknown printer %s on line %d of classes.conf.",
471 * Add the missing remote printer...
474 if ((temp
= cupsdAddPrinter(value
)) != NULL
)
476 cupsdSetString(&temp
->make_model
, "Remote Printer on unknown");
478 temp
->state
= IPP_PRINTER_STOPPED
;
479 temp
->type
|= CUPS_PRINTER_REMOTE
;
480 temp
->browse_time
= 2147483647;
482 cupsdSetString(&temp
->location
, "Location Unknown");
483 cupsdSetString(&temp
->info
, "No Information Available");
484 temp
->hostname
[0] = '\0';
486 cupsdSetPrinterAttrs(temp
);
491 cupsdAddPrinterToClass(p
, temp
);
493 else if (!strcasecmp(line
, "State"))
496 * Set the initial queue state...
499 if (!strcasecmp(value
, "idle"))
500 p
->state
= IPP_PRINTER_IDLE
;
501 else if (!strcasecmp(value
, "stopped"))
502 p
->state
= IPP_PRINTER_STOPPED
;
505 cupsdLogMessage(CUPSD_LOG_ERROR
,
506 "Syntax error on line %d of classes.conf.",
511 else if (!strcasecmp(line
, "StateMessage"))
514 * Set the initial queue state message...
518 strlcpy(p
->state_message
, value
, sizeof(p
->state_message
));
520 else if (!strcasecmp(line
, "StateTime"))
523 * Set the state time...
527 p
->state_time
= atoi(value
);
529 else if (!strcasecmp(line
, "Accepting"))
532 * Set the initial accepting state...
536 (!strcasecmp(value
, "yes") ||
537 !strcasecmp(value
, "on") ||
538 !strcasecmp(value
, "true")))
541 (!strcasecmp(value
, "no") ||
542 !strcasecmp(value
, "off") ||
543 !strcasecmp(value
, "false")))
547 cupsdLogMessage(CUPSD_LOG_ERROR
,
548 "Syntax error on line %d of classes.conf.",
553 else if (!strcasecmp(line
, "Shared"))
556 * Set the initial shared state...
560 (!strcasecmp(value
, "yes") ||
561 !strcasecmp(value
, "on") ||
562 !strcasecmp(value
, "true")))
565 (!strcasecmp(value
, "no") ||
566 !strcasecmp(value
, "off") ||
567 !strcasecmp(value
, "false")))
571 cupsdLogMessage(CUPSD_LOG_ERROR
,
572 "Syntax error on line %d of classes.conf.",
577 else if (!strcasecmp(line
, "JobSheets"))
580 * Set the initial job sheets...
585 for (valueptr
= value
;
586 *valueptr
&& !isspace(*valueptr
& 255);
592 cupsdSetString(&p
->job_sheets
[0], value
);
594 while (isspace(*valueptr
& 255))
599 for (value
= valueptr
;
600 *valueptr
&& !isspace(*valueptr
& 255);
606 cupsdSetString(&p
->job_sheets
[1], value
);
611 cupsdLogMessage(CUPSD_LOG_ERROR
,
612 "Syntax error on line %d of classes.conf.", linenum
);
616 else if (!strcasecmp(line
, "AllowUser"))
621 cupsdAddPrinterUser(p
, value
);
625 cupsdLogMessage(CUPSD_LOG_ERROR
,
626 "Syntax error on line %d of classes.conf.", linenum
);
630 else if (!strcasecmp(line
, "DenyUser"))
635 cupsdAddPrinterUser(p
, value
);
639 cupsdLogMessage(CUPSD_LOG_ERROR
,
640 "Syntax error on line %d of classes.conf.", linenum
);
644 else if (!strcasecmp(line
, "QuotaPeriod"))
647 p
->quota_period
= atoi(value
);
650 cupsdLogMessage(CUPSD_LOG_ERROR
,
651 "Syntax error on line %d of classes.conf.", linenum
);
655 else if (!strcasecmp(line
, "PageLimit"))
658 p
->page_limit
= atoi(value
);
661 cupsdLogMessage(CUPSD_LOG_ERROR
,
662 "Syntax error on line %d of classes.conf.", linenum
);
666 else if (!strcasecmp(line
, "KLimit"))
669 p
->k_limit
= atoi(value
);
672 cupsdLogMessage(CUPSD_LOG_ERROR
,
673 "Syntax error on line %d of classes.conf.", linenum
);
677 else if (!strcasecmp(line
, "OpPolicy"))
681 cupsd_policy_t
*pol
; /* Policy */
684 if ((pol
= cupsdFindPolicy(value
)) != NULL
)
686 cupsdSetString(&p
->op_policy
, value
);
687 p
->op_policy_ptr
= pol
;
690 cupsdLogMessage(CUPSD_LOG_ERROR
,
691 "Bad policy \"%s\" on line %d of classes.conf",
696 cupsdLogMessage(CUPSD_LOG_ERROR
,
697 "Syntax error on line %d of classes.conf.", linenum
);
701 else if (!strcasecmp(line
, "ErrorPolicy"))
704 cupsdSetString(&p
->error_policy
, value
);
707 cupsdLogMessage(CUPSD_LOG_ERROR
,
708 "Syntax error on line %d of classes.conf.", linenum
);
715 * Something else we don't understand...
718 cupsdLogMessage(CUPSD_LOG_ERROR
,
719 "Unknown configuration directive %s on line %d of classes.conf.",
729 * 'cupsdSaveAllClasses()' - Save classes to the classes.conf file.
733 cupsdSaveAllClasses(void)
735 cups_file_t
*fp
; /* classes.conf file */
736 char temp
[1024]; /* Temporary string */
737 char backup
[1024]; /* classes.conf.O file */
738 cupsd_printer_t
*pclass
; /* Current printer class */
739 int i
; /* Looping var */
740 time_t curtime
; /* Current time */
741 struct tm
*curdate
; /* Current date */
742 cups_option_t
*option
; /* Current option */
743 const char *ptr
; /* Pointer into info/location */
747 * Create the classes.conf file...
750 snprintf(temp
, sizeof(temp
), "%s/classes.conf", ServerRoot
);
751 snprintf(backup
, sizeof(backup
), "%s/classes.conf.O", ServerRoot
);
753 if (rename(temp
, backup
))
756 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to backup classes.conf - %s",
760 if ((fp
= cupsFileOpen(temp
, "w")) == NULL
)
762 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to save classes.conf - %s",
765 if (rename(backup
, temp
))
766 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to restore classes.conf - %s",
771 cupsdLogMessage(CUPSD_LOG_INFO
, "Saving classes.conf...");
774 * Restrict access to the file...
777 fchown(cupsFileNumber(fp
), RunUser
, Group
);
778 fchmod(cupsFileNumber(fp
), 0600);
781 * Write a small header to the file...
784 curtime
= time(NULL
);
785 curdate
= localtime(&curtime
);
786 strftime(temp
, sizeof(temp
) - 1, "%Y-%m-%d %H:%M", curdate
);
788 cupsFilePuts(fp
, "# Class configuration file for " CUPS_SVERSION
"\n");
789 cupsFilePrintf(fp
, "# Written by cupsd on %s\n", temp
);
792 * Write each local class known to the system...
795 for (pclass
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
797 pclass
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
800 * Skip remote destinations and regular printers...
803 if ((pclass
->type
& CUPS_PRINTER_REMOTE
) ||
804 (pclass
->type
& CUPS_PRINTER_IMPLICIT
) ||
805 !(pclass
->type
& CUPS_PRINTER_CLASS
))
809 * Write printers as needed...
812 if (pclass
== DefaultPrinter
)
813 cupsFilePrintf(fp
, "<DefaultClass %s>\n", pclass
->name
);
815 cupsFilePrintf(fp
, "<Class %s>\n", pclass
->name
);
817 if (pclass
->num_auth_info_required
> 0)
819 cupsFilePrintf(fp
, "AuthInfoRequired %s", pclass
->auth_info_required
[0]);
820 for (i
= 1; i
< pclass
->num_auth_info_required
; i
++)
821 cupsFilePrintf(fp
, ",%s", pclass
->auth_info_required
[i
]);
822 cupsFilePutChar(fp
, '\n');
827 if ((ptr
= strchr(pclass
->info
, '#')) != NULL
)
830 * Need to quote the first # in the info string...
833 cupsFilePuts(fp
, "Info ");
834 cupsFileWrite(fp
, pclass
->info
, ptr
- pclass
->info
);
835 cupsFilePutChar(fp
, '\\');
836 cupsFilePuts(fp
, ptr
);
837 cupsFilePutChar(fp
, '\n');
840 cupsFilePrintf(fp
, "Info %s\n", pclass
->info
);
843 if (pclass
->location
)
845 if ((ptr
= strchr(pclass
->info
, '#')) != NULL
)
848 * Need to quote the first # in the location string...
851 cupsFilePuts(fp
, "Location ");
852 cupsFileWrite(fp
, pclass
->location
, ptr
- pclass
->location
);
853 cupsFilePutChar(fp
, '\\');
854 cupsFilePuts(fp
, ptr
);
855 cupsFilePutChar(fp
, '\n');
858 cupsFilePrintf(fp
, "Location %s\n", pclass
->location
);
861 if (pclass
->state
== IPP_PRINTER_STOPPED
)
863 cupsFilePuts(fp
, "State Stopped\n");
864 cupsFilePrintf(fp
, "StateMessage %s\n", pclass
->state_message
);
867 cupsFilePuts(fp
, "State Idle\n");
869 cupsFilePrintf(fp
, "StateTime %d\n", (int)pclass
->state_time
);
871 if (pclass
->accepting
)
872 cupsFilePuts(fp
, "Accepting Yes\n");
874 cupsFilePuts(fp
, "Accepting No\n");
877 cupsFilePuts(fp
, "Shared Yes\n");
879 cupsFilePuts(fp
, "Shared No\n");
881 cupsFilePrintf(fp
, "JobSheets %s %s\n", pclass
->job_sheets
[0],
882 pclass
->job_sheets
[1]);
884 for (i
= 0; i
< pclass
->num_users
; i
++)
886 if ((ptr
= strchr(pclass
->users
[i
], '#')) != NULL
)
889 * Need to quote the first # in the user string...
892 cupsFilePrintf(fp
, "%sUser ", pclass
->deny_users
? "Deny" : "Allow");
893 cupsFileWrite(fp
, pclass
->users
[i
], ptr
- pclass
->users
[i
]);
894 cupsFilePutChar(fp
, '\\');
895 cupsFilePuts(fp
, ptr
);
896 cupsFilePutChar(fp
, '\n');
899 cupsFilePrintf(fp
, "%sUser %s\n",
900 pclass
->deny_users
? "Deny" : "Allow",
904 cupsFilePrintf(fp
, "QuotaPeriod %d\n", pclass
->quota_period
);
905 cupsFilePrintf(fp
, "PageLimit %d\n", pclass
->page_limit
);
906 cupsFilePrintf(fp
, "KLimit %d\n", pclass
->k_limit
);
908 for (i
= 0; i
< pclass
->num_users
; i
++)
909 cupsFilePrintf(fp
, "%sUser %s\n", pclass
->deny_users
? "Deny" : "Allow",
912 if (pclass
->op_policy
)
913 cupsFilePrintf(fp
, "OpPolicy %s\n", pclass
->op_policy
);
914 if (pclass
->error_policy
)
915 cupsFilePrintf(fp
, "ErrorPolicy %s\n", pclass
->error_policy
);
917 for (i
= pclass
->num_options
, option
= pclass
->options
;
920 cupsFilePrintf(fp
, "Option %s %s\n", option
->name
, option
->value
);
922 cupsFilePuts(fp
, "</Class>\n");
930 * 'cupsdUpdateImplicitClasses()' - Update the accepting state of implicit
935 cupsdUpdateImplicitClasses(void)
937 int i
; /* Looping var */
938 cupsd_printer_t
*pclass
; /* Current class */
939 int accepting
; /* printer-is-accepting-jobs value */
942 for (pclass
= (cupsd_printer_t
*)cupsArrayFirst(ImplicitPrinters
);
944 pclass
= (cupsd_printer_t
*)cupsArrayNext(ImplicitPrinters
))
947 * Loop through the printers to come up with a composite state...
950 for (i
= 0, accepting
= 0; i
< pclass
->num_printers
; i
++)
951 if ((accepting
= pclass
->printers
[i
]->accepting
) != 0)
954 pclass
->accepting
= accepting
;
960 * End of "$Id: classes.c 7608 2008-05-21 01:37:21Z mike $".