]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/classes.c
2 * "$Id: classes.c 7724 2008-07-14 06:06:06Z mike $"
4 * Printer class routines for the Common UNIX Printing System (CUPS).
6 * Copyright 2007-2010 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 * cupsdFindAvailablePrinter() - Find an available printer in a class.
22 * cupsdFindClass() - Find the named class.
23 * cupsdLoadAllClasses() - Load classes from the classes.conf file.
24 * cupsdSaveAllClasses() - Save classes to the classes.conf file.
25 * cupsdUpdateImplicitClasses() - Update the accepting state of implicit
30 * Include necessary headers...
37 * 'cupsdAddClass()' - Add a class to the system.
40 cupsd_printer_t
* /* O - New class */
41 cupsdAddClass(const char *name
) /* I - Name of class */
43 cupsd_printer_t
*c
; /* New class */
47 * Add the printer and set the type to "class"...
50 if ((c
= cupsdAddPrinter(name
)) != NULL
)
53 * Change from a printer to a class...
56 c
->type
= CUPS_PRINTER_CLASS
;
58 cupsdSetStringf(&c
->uri
, "ipp://%s:%d/classes/%s", ServerName
, RemotePort
,
60 cupsdSetString(&c
->error_policy
, "retry-current-job");
68 * 'cupsdAddPrinterToClass()' - Add a printer to a class...
72 cupsdAddPrinterToClass(
73 cupsd_printer_t
*c
, /* I - Class to add to */
74 cupsd_printer_t
*p
) /* I - Printer to add */
76 int i
; /* Looping var */
77 cupsd_printer_t
**temp
; /* Pointer to printer array */
81 * See if this printer is already a member of the class...
84 for (i
= 0; i
< c
->num_printers
; i
++)
85 if (c
->printers
[i
] == p
)
89 * Allocate memory as needed...
92 if (c
->num_printers
== 0)
93 temp
= malloc(sizeof(cupsd_printer_t
*));
95 temp
= realloc(c
->printers
, sizeof(cupsd_printer_t
*) * (c
->num_printers
+ 1));
99 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to add printer %s to class %s!",
105 * Add the printer to the end of the array and update the number of printers.
109 temp
+= c
->num_printers
;
117 * 'cupsdDeletePrinterFromClass()' - Delete a printer from a class.
120 int /* O - 1 if class changed, 0 otherwise */
121 cupsdDeletePrinterFromClass(
122 cupsd_printer_t
*c
, /* I - Class to delete from */
123 cupsd_printer_t
*p
) /* I - Printer to delete */
125 int i
; /* Looping var */
129 * See if the printer is in the class...
132 for (i
= 0; i
< c
->num_printers
; i
++)
133 if (p
== c
->printers
[i
])
137 * If it is, remove it from the list...
140 if (i
< c
->num_printers
)
143 * Yes, remove the printer...
147 if (i
< c
->num_printers
)
148 memmove(c
->printers
+ i
, c
->printers
+ i
+ 1,
149 (c
->num_printers
- i
) * sizeof(cupsd_printer_t
*));
155 * Update the IPP attributes (have to do this for member-names)...
158 cupsdSetPrinterAttrs(c
);
165 * 'cupsdDeletePrinterFromClasses()' - Delete a printer from all classes.
168 int /* O - 1 if class changed, 0 otherwise */
169 cupsdDeletePrinterFromClasses(
170 cupsd_printer_t
*p
) /* I - Printer to delete */
172 int changed
= 0; /* Any class changed? */
173 cupsd_printer_t
*c
; /* Pointer to current class */
177 * Loop through the printer/class list and remove the printer
178 * from each class listed...
181 for (c
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
183 c
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
184 if (c
->type
& (CUPS_PRINTER_CLASS
| CUPS_PRINTER_IMPLICIT
))
185 changed
|= cupsdDeletePrinterFromClass(c
, p
);
188 * Then clean out any empty implicit classes...
191 for (c
= (cupsd_printer_t
*)cupsArrayFirst(ImplicitPrinters
);
193 c
= (cupsd_printer_t
*)cupsArrayNext(ImplicitPrinters
))
194 if (c
->num_printers
== 0)
196 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Deleting implicit class \"%s\"...",
198 cupsdDeletePrinter(c
, 0);
207 * 'cupsdFindAvailablePrinter()' - Find an available printer in a class.
210 cupsd_printer_t
* /* O - Available printer or NULL */
211 cupsdFindAvailablePrinter(
212 const char *name
) /* I - Class to check */
214 int i
; /* Looping var */
215 cupsd_printer_t
*c
; /* Printer class */
222 if ((c
= cupsdFindClass(name
)) == NULL
)
224 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to find class \"%s\"!", name
);
228 if (c
->num_printers
== 0)
232 * Make sure that the last printer is also a valid index into the printer
233 * array. If not, reset the last printer to 0...
236 if (c
->last_printer
>= c
->num_printers
)
240 * Loop through the printers in the class and return the first idle
241 * printer... We keep track of the last printer that we used so that
242 * a "round robin" type of scheduling is realized (otherwise the first
243 * server might be saturated with print jobs...)
245 * Thanks to Joel Fredrikson for helping us get this right!
248 for (i
= c
->last_printer
+ 1; ; i
++)
250 if (i
>= c
->num_printers
)
253 if (c
->printers
[i
]->accepting
&&
254 (c
->printers
[i
]->state
== IPP_PRINTER_IDLE
||
255 ((c
->printers
[i
]->type
& CUPS_PRINTER_REMOTE
) && !c
->printers
[i
]->job
)))
258 return (c
->printers
[i
]);
261 if (i
== c
->last_printer
)
270 * 'cupsdFindClass()' - Find the named class.
273 cupsd_printer_t
* /* O - Matching class or NULL */
274 cupsdFindClass(const char *name
) /* I - Name of class */
276 cupsd_printer_t
*c
; /* Current class/printer */
279 if ((c
= cupsdFindDest(name
)) != NULL
&&
280 (c
->type
& (CUPS_PRINTER_CLASS
| CUPS_PRINTER_IMPLICIT
)))
288 * 'cupsdLoadAllClasses()' - Load classes from the classes.conf file.
292 cupsdLoadAllClasses(void)
294 int i
; /* Looping var */
295 cups_file_t
*fp
; /* classes.conf file */
296 int linenum
; /* Current line number */
297 char line
[4096], /* Line from file */
298 *value
, /* Pointer to value */
299 *valueptr
; /* Pointer into value */
300 cupsd_printer_t
*p
, /* Current printer class */
301 *temp
; /* Temporary pointer to printer */
305 * Open the classes.conf file...
308 snprintf(line
, sizeof(line
), "%s/classes.conf", ServerRoot
);
309 if ((fp
= cupsFileOpen(line
, "r")) == NULL
)
312 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to open %s - %s", line
,
318 * Read class configurations until we hit EOF...
324 while (cupsFileGetConf(fp
, line
, sizeof(line
), &value
, &linenum
))
327 * Decode the directive...
330 if (!strcasecmp(line
, "<Class") ||
331 !strcasecmp(line
, "<DefaultClass"))
334 * <Class name> or <DefaultClass name>
337 if (p
== NULL
&& value
)
339 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Loading class %s...", value
);
342 * Since prior classes may have implicitly defined this class,
343 * see if it already exists...
346 if ((p
= cupsdFindDest(value
)) != NULL
)
348 p
->type
= CUPS_PRINTER_CLASS
;
349 cupsdSetStringf(&p
->uri
, "ipp://%s:%d/classes/%s", ServerName
,
351 cupsdSetString(&p
->error_policy
, "retry-job");
354 p
= cupsdAddClass(value
);
357 p
->state
= IPP_PRINTER_IDLE
;
359 if (!strcasecmp(line
, "<DefaultClass"))
363 cupsdLogMessage(CUPSD_LOG_ERROR
,
364 "Syntax error on line %d of classes.conf.", linenum
);
366 else if (!strcasecmp(line
, "</Class>"))
370 cupsdSetPrinterAttrs(p
);
374 cupsdLogMessage(CUPSD_LOG_ERROR
,
375 "Syntax error on line %d of classes.conf.", linenum
);
379 cupsdLogMessage(CUPSD_LOG_ERROR
,
380 "Syntax error on line %d of classes.conf.", linenum
);
382 else if (!strcasecmp(line
, "AuthInfoRequired"))
384 if (!cupsdSetAuthInfoRequired(p
, value
, NULL
))
385 cupsdLogMessage(CUPSD_LOG_ERROR
,
386 "Bad AuthInfoRequired on line %d of classes.conf.",
389 else if (!strcasecmp(line
, "Info"))
392 cupsdSetString(&p
->info
, value
);
394 else if (!strcasecmp(line
, "Location"))
397 cupsdSetString(&p
->location
, value
);
399 else if (!strcasecmp(line
, "Option") && value
)
405 for (valueptr
= value
; *valueptr
&& !isspace(*valueptr
& 255); valueptr
++);
408 cupsdLogMessage(CUPSD_LOG_ERROR
,
409 "Syntax error on line %d of classes.conf.", linenum
);
412 for (; *valueptr
&& isspace(*valueptr
& 255); *valueptr
++ = '\0');
414 p
->num_options
= cupsAddOption(value
, valueptr
, p
->num_options
,
418 else if (!strcasecmp(line
, "Printer"))
422 cupsdLogMessage(CUPSD_LOG_ERROR
,
423 "Syntax error on line %d of classes.conf.", linenum
);
426 else if ((temp
= cupsdFindPrinter(value
)) == NULL
)
428 cupsdLogMessage(CUPSD_LOG_WARN
,
429 "Unknown printer %s on line %d of classes.conf.",
433 * Add the missing remote printer...
436 if ((temp
= cupsdAddPrinter(value
)) != NULL
)
438 cupsdSetString(&temp
->make_model
, "Remote Printer on unknown");
440 temp
->state
= IPP_PRINTER_STOPPED
;
441 temp
->type
|= CUPS_PRINTER_REMOTE
;
442 temp
->browse_time
= 2147483647;
444 cupsdSetString(&temp
->location
, "Location Unknown");
445 cupsdSetString(&temp
->info
, "No Information Available");
446 temp
->hostname
[0] = '\0';
448 cupsdSetPrinterAttrs(temp
);
453 cupsdAddPrinterToClass(p
, temp
);
455 else if (!strcasecmp(line
, "State"))
458 * Set the initial queue state...
461 if (!strcasecmp(value
, "idle"))
462 p
->state
= IPP_PRINTER_IDLE
;
463 else if (!strcasecmp(value
, "stopped"))
465 p
->state
= IPP_PRINTER_STOPPED
;
467 for (i
= 0 ; i
< p
->num_reasons
; i
++)
468 if (!strcmp("paused", p
->reasons
[i
]))
471 if (i
>= p
->num_reasons
&&
472 p
->num_reasons
< (int)(sizeof(p
->reasons
) / sizeof(p
->reasons
[0])))
474 p
->reasons
[p
->num_reasons
] = _cupsStrAlloc("paused");
479 cupsdLogMessage(CUPSD_LOG_ERROR
,
480 "Syntax error on line %d of classes.conf.",
483 else if (!strcasecmp(line
, "StateMessage"))
486 * Set the initial queue state message...
490 strlcpy(p
->state_message
, value
, sizeof(p
->state_message
));
492 else if (!strcasecmp(line
, "StateTime"))
495 * Set the state time...
499 p
->state_time
= atoi(value
);
501 else if (!strcasecmp(line
, "Accepting"))
504 * Set the initial accepting state...
508 (!strcasecmp(value
, "yes") ||
509 !strcasecmp(value
, "on") ||
510 !strcasecmp(value
, "true")))
513 (!strcasecmp(value
, "no") ||
514 !strcasecmp(value
, "off") ||
515 !strcasecmp(value
, "false")))
518 cupsdLogMessage(CUPSD_LOG_ERROR
,
519 "Syntax error on line %d of classes.conf.",
522 else if (!strcasecmp(line
, "Shared"))
525 * Set the initial shared state...
529 (!strcasecmp(value
, "yes") ||
530 !strcasecmp(value
, "on") ||
531 !strcasecmp(value
, "true")))
534 (!strcasecmp(value
, "no") ||
535 !strcasecmp(value
, "off") ||
536 !strcasecmp(value
, "false")))
539 cupsdLogMessage(CUPSD_LOG_ERROR
,
540 "Syntax error on line %d of classes.conf.",
543 else if (!strcasecmp(line
, "JobSheets"))
546 * Set the initial job sheets...
551 for (valueptr
= value
;
552 *valueptr
&& !isspace(*valueptr
& 255);
558 cupsdSetString(&p
->job_sheets
[0], value
);
560 while (isspace(*valueptr
& 255))
565 for (value
= valueptr
;
566 *valueptr
&& !isspace(*valueptr
& 255);
572 cupsdSetString(&p
->job_sheets
[1], value
);
576 cupsdLogMessage(CUPSD_LOG_ERROR
,
577 "Syntax error on line %d of classes.conf.", linenum
);
579 else if (!strcasecmp(line
, "AllowUser"))
584 cupsdAddPrinterUser(p
, value
);
587 cupsdLogMessage(CUPSD_LOG_ERROR
,
588 "Syntax error on line %d of classes.conf.", linenum
);
590 else if (!strcasecmp(line
, "DenyUser"))
595 cupsdAddPrinterUser(p
, value
);
598 cupsdLogMessage(CUPSD_LOG_ERROR
,
599 "Syntax error on line %d of classes.conf.", linenum
);
601 else if (!strcasecmp(line
, "QuotaPeriod"))
604 p
->quota_period
= atoi(value
);
606 cupsdLogMessage(CUPSD_LOG_ERROR
,
607 "Syntax error on line %d of classes.conf.", linenum
);
609 else if (!strcasecmp(line
, "PageLimit"))
612 p
->page_limit
= atoi(value
);
614 cupsdLogMessage(CUPSD_LOG_ERROR
,
615 "Syntax error on line %d of classes.conf.", linenum
);
617 else if (!strcasecmp(line
, "KLimit"))
620 p
->k_limit
= atoi(value
);
622 cupsdLogMessage(CUPSD_LOG_ERROR
,
623 "Syntax error on line %d of classes.conf.", linenum
);
625 else if (!strcasecmp(line
, "OpPolicy"))
629 cupsd_policy_t
*pol
; /* Policy */
632 if ((pol
= cupsdFindPolicy(value
)) != NULL
)
634 cupsdSetString(&p
->op_policy
, value
);
635 p
->op_policy_ptr
= pol
;
638 cupsdLogMessage(CUPSD_LOG_ERROR
,
639 "Bad policy \"%s\" on line %d of classes.conf",
643 cupsdLogMessage(CUPSD_LOG_ERROR
,
644 "Syntax error on line %d of classes.conf.", linenum
);
646 else if (!strcasecmp(line
, "ErrorPolicy"))
650 if (strcmp(value
, "retry-current-job") && strcmp(value
, "retry-job"))
651 cupsdLogMessage(CUPSD_LOG_WARN
,
652 "ErrorPolicy %s ignored on line %d of classes.conf",
656 cupsdLogMessage(CUPSD_LOG_ERROR
,
657 "Syntax error on line %d of classes.conf.", linenum
);
662 * Something else we don't understand...
665 cupsdLogMessage(CUPSD_LOG_ERROR
,
666 "Unknown configuration directive %s on line %d of classes.conf.",
676 * 'cupsdSaveAllClasses()' - Save classes to the classes.conf file.
680 cupsdSaveAllClasses(void)
682 cups_file_t
*fp
; /* classes.conf file */
683 char temp
[1024], /* Temporary string */
684 backup
[1024], /* printers.conf.O file */
685 value
[2048]; /* Value string */
686 cupsd_printer_t
*pclass
; /* Current printer class */
687 int i
; /* Looping var */
688 time_t curtime
; /* Current time */
689 struct tm
*curdate
; /* Current date */
690 cups_option_t
*option
; /* Current option */
694 * Create the classes.conf file...
697 snprintf(temp
, sizeof(temp
), "%s/classes.conf", ServerRoot
);
698 snprintf(backup
, sizeof(backup
), "%s/classes.conf.O", ServerRoot
);
700 if (rename(temp
, backup
))
703 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to backup classes.conf - %s",
707 if ((fp
= cupsFileOpen(temp
, "w")) == NULL
)
709 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to save classes.conf - %s",
712 if (rename(backup
, temp
))
713 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to restore classes.conf - %s",
718 cupsdLogMessage(CUPSD_LOG_INFO
, "Saving classes.conf...");
721 * Restrict access to the file...
724 fchown(cupsFileNumber(fp
), RunUser
, Group
);
725 fchmod(cupsFileNumber(fp
), 0600);
728 * Write a small header to the file...
731 curtime
= time(NULL
);
732 curdate
= localtime(&curtime
);
733 strftime(temp
, sizeof(temp
) - 1, "%Y-%m-%d %H:%M", curdate
);
735 cupsFilePuts(fp
, "# Class configuration file for " CUPS_SVERSION
"\n");
736 cupsFilePrintf(fp
, "# Written by cupsd on %s\n", temp
);
737 cupsFilePuts(fp
, "# DO NOT EDIT THIS FILE WHEN CUPSD IS RUNNING\n");
740 * Write each local class known to the system...
743 for (pclass
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
745 pclass
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
748 * Skip remote destinations and regular printers...
751 if ((pclass
->type
& CUPS_PRINTER_REMOTE
) ||
752 (pclass
->type
& CUPS_PRINTER_IMPLICIT
) ||
753 !(pclass
->type
& CUPS_PRINTER_CLASS
))
757 * Write printers as needed...
760 if (pclass
== DefaultPrinter
)
761 cupsFilePrintf(fp
, "<DefaultClass %s>\n", pclass
->name
);
763 cupsFilePrintf(fp
, "<Class %s>\n", pclass
->name
);
765 if (pclass
->num_auth_info_required
> 0)
767 switch (pclass
->num_auth_info_required
)
770 strlcpy(value
, pclass
->auth_info_required
[0], sizeof(value
));
774 snprintf(value
, sizeof(value
), "%s,%s",
775 pclass
->auth_info_required
[0],
776 pclass
->auth_info_required
[1]);
781 snprintf(value
, sizeof(value
), "%s,%s,%s",
782 pclass
->auth_info_required
[0],
783 pclass
->auth_info_required
[1],
784 pclass
->auth_info_required
[2]);
788 cupsFilePutConf(fp
, "AuthInfoRequired", value
);
792 cupsFilePutConf(fp
, "Info", pclass
->info
);
794 if (pclass
->location
)
795 cupsFilePutConf(fp
, "Location", pclass
->location
);
797 if (pclass
->state
== IPP_PRINTER_STOPPED
)
798 cupsFilePuts(fp
, "State Stopped\n");
800 cupsFilePuts(fp
, "State Idle\n");
802 cupsFilePrintf(fp
, "StateTime %d\n", (int)pclass
->state_time
);
804 if (pclass
->accepting
)
805 cupsFilePuts(fp
, "Accepting Yes\n");
807 cupsFilePuts(fp
, "Accepting No\n");
810 cupsFilePuts(fp
, "Shared Yes\n");
812 cupsFilePuts(fp
, "Shared No\n");
814 snprintf(value
, sizeof(value
), "%s %s", pclass
->job_sheets
[0],
815 pclass
->job_sheets
[1]);
816 cupsFilePutConf(fp
, "JobSheets", value
);
818 for (i
= 0; i
< pclass
->num_printers
; i
++)
819 cupsFilePrintf(fp
, "Printer %s\n", pclass
->printers
[i
]->name
);
821 cupsFilePrintf(fp
, "QuotaPeriod %d\n", pclass
->quota_period
);
822 cupsFilePrintf(fp
, "PageLimit %d\n", pclass
->page_limit
);
823 cupsFilePrintf(fp
, "KLimit %d\n", pclass
->k_limit
);
825 for (i
= 0; i
< pclass
->num_users
; i
++)
826 cupsFilePutConf(fp
, pclass
->deny_users
? "DenyUser" : "AllowUser",
829 if (pclass
->op_policy
)
830 cupsFilePutConf(fp
, "OpPolicy", pclass
->op_policy
);
831 if (pclass
->error_policy
)
832 cupsFilePutConf(fp
, "ErrorPolicy", pclass
->error_policy
);
834 for (i
= pclass
->num_options
, option
= pclass
->options
;
838 snprintf(value
, sizeof(value
), "%s %s", option
->name
, option
->value
);
839 cupsFilePutConf(fp
, "Option", value
);
842 cupsFilePuts(fp
, "</Class>\n");
850 * 'cupsdUpdateImplicitClasses()' - Update the accepting state of implicit
855 cupsdUpdateImplicitClasses(void)
857 int i
; /* Looping var */
858 cupsd_printer_t
*pclass
; /* Current class */
859 int accepting
; /* printer-is-accepting-jobs value */
862 for (pclass
= (cupsd_printer_t
*)cupsArrayFirst(ImplicitPrinters
);
864 pclass
= (cupsd_printer_t
*)cupsArrayNext(ImplicitPrinters
))
867 * Loop through the printers to come up with a composite state...
870 for (i
= 0, accepting
= 0; i
< pclass
->num_printers
; i
++)
871 if ((accepting
= pclass
->printers
[i
]->accepting
) != 0)
874 pclass
->accepting
= accepting
;
880 * End of "$Id: classes.c 7724 2008-07-14 06:06:06Z mike $".