diff options
author | msweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be> | 2008-04-21 23:14:57 +0000 |
---|---|---|
committer | msweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be> | 2008-04-21 23:14:57 +0000 |
commit | 3dfe78b3363fe9e058a98197eda9a856991cbc6f (patch) | |
tree | 4fe49470197216a2d1860e6dd327693f3636b084 /scheduler | |
parent | ae71f5deb42f3d526b5f35d2eed9241abb6405ba (diff) | |
download | cups-3dfe78b3363fe9e058a98197eda9a856991cbc6f.tar.gz |
Merge changes from CUPS 1.4svn-r7485.
git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@718 a1ca3aef-8c08-0410-bb20-df032aa958be
Diffstat (limited to 'scheduler')
-rw-r--r-- | scheduler/auth.c | 15 | ||||
-rw-r--r-- | scheduler/client.c | 67 | ||||
-rw-r--r-- | scheduler/client.h | 4 | ||||
-rw-r--r-- | scheduler/conf.c | 6 | ||||
-rw-r--r-- | scheduler/dirsvc.c | 60 | ||||
-rw-r--r-- | scheduler/ipp.c | 216 | ||||
-rw-r--r-- | scheduler/job.c | 173 | ||||
-rw-r--r-- | scheduler/job.h | 7 | ||||
-rw-r--r-- | scheduler/main.c | 69 | ||||
-rw-r--r-- | scheduler/printers.c | 7 | ||||
-rw-r--r-- | scheduler/server.c | 10 | ||||
-rw-r--r-- | scheduler/subscriptions.c | 6 | ||||
-rw-r--r-- | scheduler/sysman.c | 115 | ||||
-rw-r--r-- | scheduler/sysman.h | 23 |
14 files changed, 589 insertions, 189 deletions
diff --git a/scheduler/auth.c b/scheduler/auth.c index ed49087a8..9516f28ba 100644 --- a/scheduler/auth.c +++ b/scheduler/auth.c @@ -114,7 +114,8 @@ static int compare_locations(cupsd_location_t *a, static char *cups_crypt(const char *pw, const char *salt); #endif /* !HAVE_LIBPAM && !HAVE_USERSEC_H */ #ifdef HAVE_GSSAPI -static gss_cred_id_t get_gss_creds(const char *service_name); +static gss_cred_id_t get_gss_creds(const char *service_name, + const char *con_server_name); #endif /* HAVE_GSSAPI */ static char *get_md5_password(const char *username, const char *group, char passwd[33]); @@ -990,7 +991,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ * Get the server credentials... */ - if ((server_creds = get_gss_creds(GSSServiceName)) == NULL) + if ((server_creds = get_gss_creds(GSSServiceName, con->servername)) == NULL) return; /* @@ -2468,7 +2469,9 @@ cups_crypt(const char *pw, /* I - Password string */ */ static gss_cred_id_t /* O - Server credentials */ -get_gss_creds(const char *service_name) /* I - Service name */ +get_gss_creds( + const char *service_name, /* I - Service name */ + const char *con_server_name) /* I - Hostname of server */ { OM_uint32 major_status, /* Major status code */ minor_status; /* Minor status code */ @@ -2476,12 +2479,10 @@ get_gss_creds(const char *service_name) /* I - Service name */ gss_cred_id_t server_creds; /* Server credentials */ gss_buffer_desc token = GSS_C_EMPTY_BUFFER; /* Service name token */ - char buf[1024], /* Service name buffer */ - fqdn[HTTP_MAX_URI]; /* Hostname of server */ + char buf[1024]; /* Service name buffer */ - snprintf(buf, sizeof(buf), "%s@%s", service_name, - httpGetHostname(NULL, fqdn, sizeof(fqdn))); + snprintf(buf, sizeof(buf), "%s@%s", service_name, con_server_name); token.value = buf; token.length = strlen(buf); diff --git a/scheduler/client.c b/scheduler/client.c index ba016434a..107482773 100644 --- a/scheduler/client.c +++ b/scheduler/client.c @@ -28,6 +28,7 @@ * cupsdUpdateCGI() - Read status messages from CGI scripts and programs. * cupsdWriteClient() - Write data to a client as needed. * check_if_modified() - Decode an "If-Modified-Since" line. + * compare_clients() - Compare two client connections. * encrypt_client() - Enable encryption for the client... * get_cdsa_certificate() - Convert a keychain name into the CFArrayRef * required by SSLSetCertificate. @@ -82,6 +83,8 @@ extern const char *cssmErrorString(int error); static int check_if_modified(cupsd_client_t *con, struct stat *filestats); +static int compare_clients(cupsd_client_t *a, cupsd_client_t *b, + void *data); #ifdef HAVE_SSL static int encrypt_client(cupsd_client_t *con); #endif /* HAVE_SSL */ @@ -145,7 +148,18 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ if (!Clients) { cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate memory for client array!"); + "Unable to allocate memory for clients array!"); + cupsdPauseListening(); + return; + } + + if (!ActiveClients) + ActiveClients = cupsArrayNew((cups_array_func_t)compare_clients, NULL); + + if (!ActiveClients) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to allocate memory for active clients array!"); cupsdPauseListening(); return; } @@ -607,8 +621,11 @@ cupsdCloseClient(cupsd_client_t *con) /* I - Client to close */ * Close the socket and clear the file from the input set for select()... */ - if (con->http.fd > 0) + if (con->http.fd >= 0) { + cupsArrayRemove(ActiveClients, con); + cupsdSetBusyState(); + if (partial) { /* @@ -973,6 +990,9 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ con->http.status = HTTP_OK; + cupsArrayAdd(ActiveClients, con); + cupsdSetBusyState(); + case HTTP_OPTIONS : case HTTP_DELETE : case HTTP_GET : @@ -2144,8 +2164,16 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ break; /* Anti-compiler-warning-code */ } - if (!con->http.keep_alive && con->http.state == HTTP_WAITING) - cupsdCloseClient(con); + if (con->http.state == HTTP_WAITING) + { + if (!con->http.keep_alive) + cupsdCloseClient(con); + else + { + cupsArrayRemove(ActiveClients, con); + cupsdSetBusyState(); + } + } } @@ -2913,6 +2941,26 @@ check_if_modified( } +/* + * 'compare_clients()' - Compare two client connections. + */ + +static int /* O - Result of comparison */ +compare_clients(cupsd_client_t *a, /* I - First client */ + cupsd_client_t *b, /* I - Second client */ + void *data) /* I - User data (not used) */ +{ + (void)data; + + if (a == b) + return (0); + else if (a < b) + return (-1); + else + return (1); +} + + #ifdef HAVE_SSL /* * 'encrypt_client()' - Enable encryption for the client... @@ -3649,12 +3697,7 @@ is_cgi(cupsd_client_t *con, /* I - Client connection */ */ if ((options = strchr(con->uri, '?')) != NULL) - { - options ++; - - if (strchr(options, '=')) - cupsdSetStringf(&(con->query_string), "QUERY_STRING=%s", options); - } + cupsdSetStringf(&(con->query_string), "QUERY_STRING=%s", options + 1); /* * Check for known types... @@ -3677,7 +3720,7 @@ is_cgi(cupsd_client_t *con, /* I - Client connection */ filename = strrchr(filename, '/') + 1; /* Filename always absolute */ - cupsdSetString(&con->options, options); + cupsdSetStringf(&con->options, " %s", options); cupsdLogMessage(CUPSD_LOG_DEBUG2, "is_cgi: Returning 1 with command=\"%s\" and options=\"%s\"", @@ -4678,6 +4721,8 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */ envp[envc ++] = con->query_string; } + else + envp[envc ++] = "QUERY_STRING="; } else { diff --git a/scheduler/client.h b/scheduler/client.h index f185c1e91..e6d946d47 100644 --- a/scheduler/client.h +++ b/scheduler/client.h @@ -93,8 +93,10 @@ VAR cups_array_t *Listeners VALUE(NULL); /* Listening sockets */ VAR time_t ListeningPaused VALUE(0); /* Time when listening was paused */ -VAR cups_array_t *Clients VALUE(NULL); +VAR cups_array_t *Clients VALUE(NULL), /* HTTP clients */ + *ActiveClients VALUE(NULL); + /* Active HTTP clients */ VAR http_addrlist_t *ServerAddrs VALUE(NULL); /* Server address(es) */ VAR char *ServerHeader VALUE(NULL); diff --git a/scheduler/conf.c b/scheduler/conf.c index c8e814886..de4d98adc 100644 --- a/scheduler/conf.c +++ b/scheduler/conf.c @@ -103,6 +103,7 @@ static const cupsd_var_t variables[] = { "DefaultLeaseDuration", &DefaultLeaseDuration, CUPSD_VARTYPE_INTEGER }, { "DefaultPolicy", &DefaultPolicy, CUPSD_VARTYPE_STRING }, { "DefaultShared", &DefaultShared, CUPSD_VARTYPE_BOOLEAN }, + { "DirtyCleanInterval", &DirtyCleanInterval, CUPSD_VARTYPE_INTEGER }, { "DocumentRoot", &DocumentRoot, CUPSD_VARTYPE_STRING }, { "ErrorLog", &ErrorLog, CUPSD_VARTYPE_STRING }, { "ErrorPolicy", &ErrorPolicy, CUPSD_VARTYPE_STRING }, @@ -516,6 +517,7 @@ cupsdReadConfiguration(void) #ifdef HAVE_SSL DefaultEncryption = HTTP_ENCRYPT_REQUIRED; #endif /* HAVE_SSL */ + DirtyCleanInterval = 60; JobRetryLimit = 5; JobRetryInterval = 300; FileDevice = FALSE; @@ -1188,7 +1190,7 @@ cupsdReadConfiguration(void) cupsdLoadAllPrinters(); cupsdLoadAllClasses(); cupsdLoadRemoteCache(); - cupsdWritePrintcap(); + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); cupsdCreateCommonData(); @@ -1219,7 +1221,7 @@ cupsdReadConfiguration(void) */ cupsdUpdatePrinters(); - cupsdWritePrintcap(); + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); cupsdLogMessage(CUPSD_LOG_INFO, "Partial reload complete."); } diff --git a/scheduler/dirsvc.c b/scheduler/dirsvc.c index f9ee02320..5bc61f680 100644 --- a/scheduler/dirsvc.c +++ b/scheduler/dirsvc.c @@ -98,7 +98,7 @@ static void process_browse_data(const char *uri, const char *host, ipp_pstate_t state, const char *location, const char *info, const char *make_model, int num_attrs, cups_option_t *attrs); -static void process_implicit_classes(int *write_printcap); +static void process_implicit_classes(void); static void send_cups_browse(cupsd_printer_t *p); #ifdef HAVE_LDAP static void send_ldap_browse(cupsd_printer_t *p); @@ -616,7 +616,7 @@ cupsdLoadRemoteCache(void) * Do auto-classing if needed... */ - process_implicit_classes(NULL); + process_implicit_classes(); } @@ -801,7 +801,6 @@ cupsdSendBrowseList(void) cupsd_printer_t *p; /* Current printer */ time_t ut, /* Minimum update time */ to; /* Timeout time */ - int write_printcap; /* Write the printcap file? */ if (!Browsing || !BrowseLocalProtocols || !Printers) @@ -899,7 +898,7 @@ cupsdSendBrowseList(void) * Loop through all of the printers and send local updates as needed... */ - for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), write_printcap = 0; + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers)) { @@ -924,13 +923,10 @@ cupsdSendBrowseList(void) cupsArraySave(Printers); cupsdDeletePrinter(p, 1); cupsArrayRestore(Printers); - write_printcap = 1; + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); } } } - - if (write_printcap) - cupsdWritePrintcap(); } @@ -1749,8 +1745,7 @@ process_browse_data( cups_option_t *attrs) /* I - Attributes */ { int i; /* Looping var */ - int update, /* Update printer attributes? */ - write_printcap; /* Write the printcap file? */ + int update; /* Update printer attributes? */ char finaluri[HTTP_MAX_URI], /* Final URI for printer */ name[IPP_MAX_NAME], /* Name of printer */ newname[IPP_MAX_NAME], /* New name of printer */ @@ -1837,12 +1832,11 @@ process_browse_data( * See if we already have it listed in the Printers list, and add it if not... */ - type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED; - type &= ~CUPS_PRINTER_IMPLICIT; - update = 0; - write_printcap = 0; - hptr = strchr(host, '.'); - sptr = strchr(ServerName, '.'); + type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED; + type &= ~CUPS_PRINTER_IMPLICIT; + update = 0; + hptr = strchr(host, '.'); + sptr = strchr(ServerName, '.'); if (!ServerNameIsIP && sptr != NULL && hptr != NULL) { @@ -1965,8 +1959,9 @@ process_browse_data( cupsdSetString(&p->device_uri, uri); cupsdSetString(&p->hostname, host); - update = 1; - write_printcap = 1; + update = 1; + + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); } } else @@ -2072,8 +2067,9 @@ process_browse_data( cupsdSetString(&p->uri, uri); cupsdSetString(&p->device_uri, uri); - write_printcap = 1; - update = 1; + update = 1; + + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); } } @@ -2132,8 +2128,9 @@ process_browse_data( if (info && (!p->info || strcmp(p->info, info))) { cupsdSetString(&p->info, info); - update = 1; - write_printcap = 1; + update = 1; + + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); } if (!make_model || !make_model[0]) @@ -2198,7 +2195,7 @@ process_browse_data( cupsdDeletePrinter(p, 1); cupsdUpdateImplicitClasses(); - write_printcap = 1; + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); } else if (update) { @@ -2223,7 +2220,7 @@ process_browse_data( if (p->type & CUPS_PRINTER_DEFAULT) { DefaultPrinter = p; - write_printcap = 1; + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); break; } } @@ -2232,14 +2229,7 @@ process_browse_data( * Do auto-classing if needed... */ - process_implicit_classes(&write_printcap); - - /* - * Update the printcap file... - */ - - if (write_printcap) - cupsdWritePrintcap(); + process_implicit_classes(); } @@ -2766,8 +2756,7 @@ dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */ */ static void -process_implicit_classes( - int *write_printcap) /* O - Write printcap file? */ +process_implicit_classes(void) { int i; /* Looping var */ int update; /* Update printer attributes? */ @@ -2848,8 +2837,7 @@ process_implicit_classes( update = 1; - if (write_printcap) - *write_printcap = 1; + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); cupsdLogMessage(CUPSD_LOG_DEBUG, "Added implicit class \"%s\"...", name); diff --git a/scheduler/ipp.c b/scheduler/ipp.c index f29006b86..dc08f621b 100644 --- a/scheduler/ipp.c +++ b/scheduler/ipp.c @@ -42,6 +42,8 @@ * cancel_job() - Cancel a print job. * cancel_subscription() - Cancel a subscription. * check_quotas() - Check quotas for a printer and user. + * check_rss_recipient() - Check that we do not have a duplicate RSS + * feed URI. * copy_attribute() - Copy a single attribute. * copy_attrs() - Copy attributes from one request to another. * copy_banner() - Copy a banner file to the requests directory @@ -157,6 +159,7 @@ static void authenticate_job(cupsd_client_t *con, ipp_attribute_t *uri); static void cancel_all_jobs(cupsd_client_t *con, ipp_attribute_t *uri); static void cancel_job(cupsd_client_t *con, ipp_attribute_t *uri); static void cancel_subscription(cupsd_client_t *con, int id); +static int check_rss_recipient(const char *recipient); static int check_quotas(cupsd_client_t *con, cupsd_printer_t *p); static ipp_attribute_t *copy_attribute(ipp_t *to, ipp_attribute_t *attr, int quickcopy); @@ -858,14 +861,14 @@ accept_jobs(cupsd_client_t *con, /* I - Client connection */ if (dtype & CUPS_PRINTER_CLASS) { - cupsdSaveAllClasses(); + cupsdMarkDirty(CUPSD_DIRTY_CLASSES); cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" now accepting jobs (\"%s\").", printer->name, get_username(con)); } else { - cupsdSaveAllPrinters(); + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" now accepting jobs (\"%s\").", @@ -1162,7 +1165,7 @@ add_class(cupsd_client_t *con, /* I - Client connection */ */ cupsdSetPrinterAttrs(pclass); - cupsdSaveAllClasses(); + cupsdMarkDirty(CUPSD_DIRTY_CLASSES); if (need_restart_job && pclass->job) { @@ -1183,7 +1186,7 @@ add_class(cupsd_client_t *con, /* I - Client connection */ if (need_restart_job) cupsdCheckJobs(); - cupsdWritePrintcap(); + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); if (modify) { @@ -1265,6 +1268,9 @@ add_file(cupsd_client_t *con, /* I - Connection to client */ job->num_files ++; + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); + return (0); } @@ -1320,7 +1326,8 @@ add_job(cupsd_client_t *con, /* I - Client connection */ send_http_error(con, status, printer); return (NULL); } - else if ((printer->type & CUPS_PRINTER_AUTHENTICATED) && + else if (printer->num_auth_info_required > 0 && + strcmp(printer->auth_info_required[0], "none") && !con->username[0] && !auth_info) { send_http_error(con, HTTP_UNAUTHORIZED, printer); @@ -1388,6 +1395,34 @@ add_job(cupsd_client_t *con, /* I - Client connection */ } } + if ((attr = ippFindAttribute(con->request, "job-sheets", + IPP_TAG_ZERO)) != NULL) + { + if (attr->value_tag != IPP_TAG_KEYWORD && + attr->value_tag != IPP_TAG_NAME) + { + send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-sheets value type!")); + return (NULL); + } + + if (attr->num_values > 2) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("Too many job-sheets values (%d > 2)!"), + attr->num_values); + return (NULL); + } + + for (i = 0; i < attr->num_values; i ++) + if (strcmp(attr->values[i].string.text, "none") && + !cupsdFindBanner(attr->values[i].string.text)) + { + send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-sheets value \"%s\"!"), + attr->values[i].string.text); + return (NULL); + } + } + if ((attr = ippFindAttribute(con->request, "number-up", IPP_TAG_INTEGER)) != NULL) { @@ -1487,8 +1522,11 @@ add_job(cupsd_client_t *con, /* I - Client connection */ job->dtype = printer->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_REMOTE); job->attrs = con->request; + job->dirty = 1; con->request = ippNewRequest(job->attrs->request.op.operation_id); + cupsdMarkDirty(CUPSD_DIRTY_JOBS); + add_job_uuid(con, job); apply_printer_defaults(printer, job); @@ -1812,7 +1850,10 @@ add_job(cupsd_client_t *con, /* I - Client connection */ job->id, attr->values[0].string.text); if ((kbytes = copy_banner(con, job, attr->values[0].string.text)) < 0) + { + cupsdDeleteJob(job); return (NULL); + } cupsdUpdateQuota(printer, job->username, 0, kbytes); } @@ -1986,10 +2027,70 @@ add_job_subscriptions( { if (!strcmp(attr->name, "notify-recipient-uri") && attr->value_tag == IPP_TAG_URI) + { + /* + * Validate the recipient scheme against the ServerBin/notifier + * directory... + */ + + char notifier[1024], /* Notifier filename */ + scheme[HTTP_MAX_URI], /* Scheme portion of URI */ + userpass[HTTP_MAX_URI], /* Username portion of URI */ + host[HTTP_MAX_URI], /* Host portion of URI */ + resource[HTTP_MAX_URI]; /* Resource portion of URI */ + int port; /* Port portion of URI */ + + recipient = attr->values[0].string.text; + + if (httpSeparateURI(HTTP_URI_CODING_ALL, recipient, + scheme, sizeof(scheme), userpass, sizeof(userpass), + host, sizeof(host), &port, + resource, sizeof(resource)) < HTTP_URI_OK) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("Bad notify-recipient-uri URI \"%s\"!"), recipient); + ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, + "notify-status-code", IPP_URI_SCHEME); + return; + } + + snprintf(notifier, sizeof(notifier), "%s/notifier/%s", ServerBin, + scheme); + if (access(notifier, X_OK)) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("notify-recipient-uri URI \"%s\" uses unknown " + "scheme!"), recipient); + ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, + "notify-status-code", IPP_URI_SCHEME); + return; + } + + if (!strcmp(scheme, "rss") && !check_rss_recipient(recipient)) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("notify-recipient-uri URI \"%s\" is already used!"), + recipient); + ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, + "notify-status-code", IPP_ATTRIBUTES); + return; + } + } else if (!strcmp(attr->name, "notify-pull-method") && attr->value_tag == IPP_TAG_KEYWORD) + { pullmethod = attr->values[0].string.text; + + if (strcmp(pullmethod, "ippget")) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("Bad notify-pull-method \"%s\"!"), pullmethod); + ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, + "notify-status-code", IPP_ATTRIBUTES); + return; + } + } else if (!strcmp(attr->name, "notify-charset") && attr->value_tag == IPP_TAG_CHARSET && strcmp(attr->values[0].string.text, "us-ascii") && @@ -2071,7 +2172,7 @@ add_job_subscriptions( attr = attr->next; } - cupsdSaveAllSubscriptions(); + cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS); /* * Remove all of the subscription attributes from the job request... @@ -2720,7 +2821,7 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ */ cupsdSetPrinterAttrs(printer); - cupsdSaveAllPrinters(); + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); if (need_restart_job && printer->job) { @@ -2741,7 +2842,7 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ if (need_restart_job) cupsdCheckJobs(); - cupsdWritePrintcap(); + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); if (modify) { @@ -3914,6 +4015,40 @@ cancel_subscription( /* + * 'check_rss_recipient()' - Check that we do not have a duplicate RSS feed URI. + */ + +static int /* O - 1 if OK, 0 if not */ +check_rss_recipient( + const char *recipient) /* I - Recipient URI */ +{ + cupsd_subscription_t *sub; /* Current subscription */ + + + for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions); + sub; + sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions)) + if (sub->recipient) + { + /* + * Compare the URIs up to the first ?... + */ + + const char *r1, *r2; + + for (r1 = recipient, r2 = sub->recipient; + *r1 == *r2 && *r1 && *r1 != '?' && *r2 && *r2 != '?'; + r1 ++, r2 ++); + + if (*r1 == *r2) + return (0); + } + + return (1); +} + + +/* * 'check_quotas()' - Check quotas for a printer and user. */ @@ -4436,7 +4571,8 @@ copy_banner(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *attr; /* Attribute */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_banner(%p[%d], %p[%d], %s)", + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "copy_banner(con=%p[%d], job=%p[%d], name=\"%s\")", con, con ? con->http.fd : -1, job, job->id, name ? name : "(null)"); @@ -4460,7 +4596,7 @@ copy_banner(cupsd_client_t *con, /* I - Client connection */ if ((out = cupsFileOpen(filename, "w")) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, - "copy_banner: Unable to create banner job file %s - %s", + "Unable to create banner job file %s - %s", filename, strerror(errno)); job->num_files --; return (0); @@ -4516,7 +4652,7 @@ copy_banner(cupsd_client_t *con, /* I - Client connection */ cupsFileClose(out); unlink(filename); cupsdLogMessage(CUPSD_LOG_ERROR, - "copy_banner: Unable to open banner template file %s - %s", + "Unable to open banner template file %s - %s", filename, strerror(errno)); job->num_files --; return (0); @@ -5453,8 +5589,6 @@ create_job(cupsd_client_t *con, /* I - Client connection */ * Save and log the job... */ - cupsdSaveJob(job); - cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Queued on \"%s\" by \"%s\".", job->id, job->dest, job->username); } @@ -5694,10 +5828,10 @@ create_subscription( for (attr = con->request->attrs; attr; attr = attr->next) { if (attr->group_tag != IPP_TAG_ZERO) - cupsdLogMessage(CUPSD_LOG_DEBUG, "g%04x v%04x %s", attr->group_tag, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "g%04x v%04x %s", attr->group_tag, attr->value_tag, attr->name); else - cupsdLogMessage(CUPSD_LOG_DEBUG, "----SEP----"); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "----SEP----"); } #endif /* DEBUG */ @@ -5851,6 +5985,16 @@ create_subscription( "notify-status-code", IPP_URI_SCHEME); return; } + + if (!strcmp(scheme, "rss") && !check_rss_recipient(recipient)) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("notify-recipient-uri URI \"%s\" is already used!"), + recipient); + ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, + "notify-status-code", IPP_ATTRIBUTES); + return; + } } else if (!strcmp(attr->name, "notify-pull-method") && attr->value_tag == IPP_TAG_KEYWORD) @@ -6001,8 +6145,7 @@ create_subscription( attr = attr->next; } - cupsdSaveAllSubscriptions(); - + cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS); } @@ -6091,7 +6234,7 @@ delete_printer(cupsd_client_t *con, /* I - Client connection */ printer->name, get_username(con)); cupsdDeletePrinter(printer, 0); - cupsdSaveAllClasses(); + cupsdMarkDirty(CUPSD_DIRTY_CLASSES); } else { @@ -6099,10 +6242,10 @@ delete_printer(cupsd_client_t *con, /* I - Client connection */ printer->name, get_username(con)); cupsdDeletePrinter(printer, 0); - cupsdSaveAllPrinters(); + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); } - cupsdWritePrintcap(); + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); /* * Return with no errors... @@ -6597,6 +6740,11 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ completed = 0; list = Jobs; } + else if (attr && !strcmp(attr->values[0].string.text, "printing")) + { + completed = 0; + list = PrintingJobs; + } else { completed = 0; @@ -6611,7 +6759,7 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ IPP_TAG_INTEGER)) != NULL) limit = attr->values[0].integer; else - limit = 1000000; + limit = 0; if ((attr = ippFindAttribute(con->request, "first-job-id", IPP_TAG_INTEGER)) != NULL) @@ -6637,7 +6785,7 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ */ for (count = 0, job = (cupsd_job_t *)cupsArrayFirst(list); - count < limit && job; + (limit <= 0 || count < limit) && job; job = (cupsd_job_t *)cupsArrayNext(list)) { /* @@ -8271,8 +8419,6 @@ print_job(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job %d] hold_until = %d", job->id, (int)job->hold_until); - cupsdSaveJob(job); - /* * Start the job if possible... */ @@ -8525,14 +8671,14 @@ reject_jobs(cupsd_client_t *con, /* I - Client connection */ if (dtype & CUPS_PRINTER_CLASS) { - cupsdSaveAllClasses(); + cupsdMarkDirty(CUPSD_DIRTY_CLASSES); cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" rejecting jobs (\"%s\").", printer->name, get_username(con)); } else { - cupsdSaveAllPrinters(); + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" rejecting jobs (\"%s\").", printer->name, get_username(con)); @@ -8761,7 +8907,7 @@ renew_subscription( sub->expire = sub->lease ? time(NULL) + sub->lease : 0; - cupsdSaveAllSubscriptions(); + cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS); con->response->request.status.status_code = IPP_OK; @@ -9485,7 +9631,8 @@ send_document(cupsd_client_t *con, /* I - Client connection */ } } - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); /* * Start the job if possible... Since cupsdCheckJobs() can cancel a @@ -9509,7 +9656,9 @@ send_document(cupsd_client_t *con, /* I - Client connection */ job->state->values[0].integer = IPP_JOB_HELD; job->state_value = IPP_JOB_HELD; job->hold_until = time(NULL) + 60; - cupsdSaveJob(job); + job->dirty = 1; + + cupsdMarkDirty(CUPSD_DIRTY_JOBS); } } @@ -9676,10 +9825,8 @@ set_default(cupsd_client_t *con, /* I - Client connection */ DefaultPrinter = printer; - cupsdSaveAllPrinters(); - cupsdSaveAllClasses(); - - cupsdWritePrintcap(); + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS | CUPSD_DIRTY_CLASSES | + CUPSD_DIRTY_REMOTE | CUPSD_DIRTY_PRINTCAP); cupsdLogMessage(CUPSD_LOG_INFO, "Default destination set to \"%s\" by \"%s\".", @@ -10025,7 +10172,8 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ * Save the job... */ - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); /* * Send events as needed... diff --git a/scheduler/job.c b/scheduler/job.c index 11cc5fe1d..0e4e94af9 100644 --- a/scheduler/job.c +++ b/scheduler/job.c @@ -21,6 +21,7 @@ * cupsdCheckJobs() - Check the pending jobs and start any if * the destination is available. * cupsdCleanJobs() - Clean out old jobs. + * cupsdDeleteJob() - Free all memory used by a job. * cupsdFinishJob() - Finish a job. * cupsdFreeAllJobs() - Free all jobs from memory. * cupsdFindJob() - Find the specified job. @@ -44,7 +45,6 @@ * compare_active_jobs() - Compare the job IDs and priorities of two * jobs. * compare_jobs() - Compare the job IDs of two jobs. - * free_job() - Free all memory used by a job. * ipp_length() - Compute the size of the buffer needed to * hold the textual IPP attributes. * load_job_cache() - Load jobs from the job.cache file. @@ -89,7 +89,6 @@ static mime_filter_t gziptoany_filter = static int compare_active_jobs(void *first, void *second, void *data); static int compare_jobs(void *first, void *second, void *data); -static void free_job(cupsd_job_t *job); static int ipp_length(ipp_t *ipp); static void load_job_cache(const char *filename); static void load_next_job_id(const char *filename); @@ -211,10 +210,11 @@ cupsdCancelJob(cupsd_job_t *job, /* I - Job to cancel */ cupsdExpireSubscriptions(NULL, job); /* - * Remove the job from the active list... + * Remove the job from the active and printing lists... */ cupsArrayRemove(ActiveJobs, job); + cupsArrayRemove(PrintingJobs, job); /* * Remove any authentication data... @@ -277,7 +277,8 @@ cupsdCancelJob(cupsd_job_t *job, /* I - Job to cancel */ * Save job state info... */ - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); } else { @@ -299,8 +300,10 @@ cupsdCancelJob(cupsd_job_t *job, /* I - Job to cancel */ * Free all memory used... */ - free_job(job); + cupsdDeleteJob(job); } + + cupsdSetBusyState(); } @@ -395,7 +398,8 @@ cupsdCheckJobs(void) { attr->value_tag = IPP_TAG_KEYWORD; cupsdSetString(&(attr->values[0].string.text), "no-hold"); - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); } } @@ -462,6 +466,9 @@ cupsdCheckJobs(void) else ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-actual-printer-uri", NULL, printer->uri); + + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); } if ((!(printer->type & CUPS_PRINTER_DISCOVERED) && /* Printer is local */ @@ -511,6 +518,45 @@ cupsdCleanJobs(void) /* + * 'cupsdDeleteJob()' - Free all memory used by a job. + */ + +void +cupsdDeleteJob(cupsd_job_t *job) /* I - Job */ +{ + cupsdClearString(&job->username); + cupsdClearString(&job->dest); + cupsdClearString(&job->auth_username); + cupsdClearString(&job->auth_domain); + cupsdClearString(&job->auth_password); + +#ifdef HAVE_GSSAPI + /* + * Destroy the credential cache and clear the KRB5CCNAME env var string. + */ + + if (job->ccache) + { + krb5_cc_destroy(KerberosContext, job->ccache); + job->ccache = NULL; + } + + cupsdClearString(&job->ccname); +#endif /* HAVE_GSSAPI */ + + if (job->num_files > 0) + { + free(job->compressions); + free(job->filetypes); + } + + ippDelete(job->attrs); + + free(job); +} + + +/* * 'cupsdFinishJob()' - Finish a job. */ @@ -608,7 +654,8 @@ cupsdFinishJob(cupsd_job_t *job) /* I - Job */ job->state_value = IPP_JOB_PENDING; } - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); /* * If the job was queued to a class, try requeuing it... For @@ -686,7 +733,8 @@ cupsdFinishJob(cupsd_job_t *job) /* I - Job */ job->state->values[0].integer = IPP_JOB_HELD; job->state_value = IPP_JOB_HELD; - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, printer, job, "Job held due to backend errors; please consult " @@ -703,7 +751,9 @@ cupsdFinishJob(cupsd_job_t *job) /* I - Job */ job->state->values[0].integer = IPP_JOB_PENDING; job->state_value = IPP_JOB_PENDING; - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); + cupsdSetPrinterState(printer, IPP_PRINTER_STOPPED, 1); cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, printer, job, @@ -730,7 +780,8 @@ cupsdFinishJob(cupsd_job_t *job) /* I - Job */ job->state->values[0].integer = IPP_JOB_HELD; job->state_value = IPP_JOB_HELD; - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, printer, job, "Authentication is required for job %d.", job->id); @@ -752,7 +803,8 @@ cupsdFinishJob(cupsd_job_t *job) /* I - Job */ cupsdLogMessage(CUPSD_LOG_ERROR, "[Job %d] Job stopped due to filter errors.", job->id); cupsdStopJob(job, 1); - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, printer, job, "Job stopped due to filter errors; please consult the " "error_log file for details."); @@ -812,8 +864,9 @@ cupsdFreeAllJobs(void) { cupsArrayRemove(Jobs, job); cupsArrayRemove(ActiveJobs, job); + cupsArrayRemove(PrintingJobs, job); - free_job(job); + cupsdDeleteJob(job); } cupsdReleaseSignals(); @@ -902,7 +955,8 @@ cupsdHoldJob(cupsd_job_t *job) /* I - Job data */ job->state_value = IPP_JOB_HELD; job->current_file = 0; - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); cupsdCheckJobs(); } @@ -931,6 +985,9 @@ cupsdLoadAllJobs(void) if (!ActiveJobs) ActiveJobs = cupsArrayNew(compare_active_jobs, NULL); + if (!PrintingJobs) + PrintingJobs = cupsArrayNew(compare_jobs, NULL); + /* * See whether the job.cache file is older than the RequestRoot directory... */ @@ -1317,7 +1374,8 @@ cupsdMoveJob(cupsd_job_t *job, /* I - Job */ "Job #%d moved from %s to %s.", job->id, olddest, p->name); - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); } @@ -1336,7 +1394,8 @@ cupsdReleaseJob(cupsd_job_t *job) /* I - Job */ job->state->values[0].integer = IPP_JOB_PENDING; job->state_value = IPP_JOB_PENDING; - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); cupsdCheckJobs(); } } @@ -1364,7 +1423,8 @@ cupsdRestartJob(cupsd_job_t *job) /* I - Job */ job->state->values[0].integer = IPP_JOB_PENDING; job->state_value = IPP_JOB_PENDING; - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); if (old_state > IPP_JOB_STOPPED) cupsArrayAdd(ActiveJobs, job); @@ -1479,6 +1539,8 @@ cupsdSaveJob(cupsd_job_t *job) /* I - Job */ "[Job %d] Unable to write job control file!", job->id); cupsFileClose(fp); + + job->dirty = 0; } @@ -1654,7 +1716,8 @@ cupsdSetJobPriority( cupsArrayAdd(ActiveJobs, job); - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); } @@ -1780,7 +1843,12 @@ cupsdUnloadCompletedJobs(void) job = (cupsd_job_t *)cupsArrayNext(Jobs)) if (job->attrs && job->state_value >= IPP_JOB_STOPPED && job->access_time < expire) + { + if (job->dirty) + cupsdSaveJob(job); + unload_job(job); + } } @@ -1818,45 +1886,6 @@ compare_jobs(void *first, /* I - First job */ /* - * 'free_job()' - Free all memory used by a job. - */ - -static void -free_job(cupsd_job_t *job) /* I - Job */ -{ - cupsdClearString(&job->username); - cupsdClearString(&job->dest); - cupsdClearString(&job->auth_username); - cupsdClearString(&job->auth_domain); - cupsdClearString(&job->auth_password); - -#ifdef HAVE_GSSAPI - /* - * Destroy the credential cache and clear the KRB5CCNAME env var string. - */ - - if (job->ccache) - { - krb5_cc_destroy(KerberosContext, job->ccache); - job->ccache = NULL; - } - - cupsdClearString(&job->ccname); -#endif /* HAVE_GSSAPI */ - - if (job->num_files > 0) - { - free(job->compressions); - free(job->filetypes); - } - - ippDelete(job->attrs); - - free(job); -} - - -/* * 'ipp_length()' - Compute the size of the buffer needed to hold * the textual IPP attributes. */ @@ -2426,7 +2455,8 @@ set_hold_until(cupsd_job_t *job, /* I - Job to update */ else cupsdSetString(&attr->values[0].string.text, holdstr); - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); } @@ -2697,6 +2727,22 @@ start_job(cupsd_job_t *job, /* I - Job ID */ } /* + * Make sure we don't go over the "MAX_FILTERS" limit... + */ + + if (cupsArrayCount(filters) > MAX_FILTERS) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "[Job %d] Too many filters (%d > %d), unable to print!", + job->id, cupsArrayCount(filters), MAX_FILTERS); + + cupsArrayDelete(filters); + cupsdCancelJob(job, 0, IPP_JOB_STOPPED); + + return; + } + + /* * Update the printer and job state to "processing"... */ @@ -2712,6 +2758,13 @@ start_job(cupsd_job_t *job, /* I - Job ID */ if (job->current_file == 0) { /* + * Add to the printing list... + */ + + cupsArrayAdd(PrintingJobs, job); + cupsdSetBusyState(); + + /* * Set the processing time... */ @@ -3676,7 +3729,11 @@ update_job(cupsd_job_t *job) /* I - Job to check */ { cupsdSetAuthInfoRequired(job->printer, attr, NULL); cupsdSetPrinterAttrs(job->printer); - cupsdSaveAllPrinters(); + + if (job->printer->type & CUPS_PRINTER_DISCOVERED) + cupsdMarkDirty(CUPSD_DIRTY_REMOTE); + else + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); } if ((attr = cupsGetOption("printer-alert", num_attrs, attrs)) != NULL) diff --git a/scheduler/job.h b/scheduler/job.h index 78c836b75..09bf75ce0 100644 --- a/scheduler/job.h +++ b/scheduler/job.h @@ -20,7 +20,8 @@ typedef struct cupsd_job_s { int id, /* Job ID */ - priority; /* Job priority */ + priority, /* Job priority */ + dirty; /* Do we need to write the "c" file? */ ipp_jstate_t state_value; /* Cached job-state */ int pending_timeout;/* Non-zero if the job was created and waiting on files */ char *username; /* Printing user */ @@ -84,8 +85,10 @@ VAR int JobAutoPurge VALUE(0); /* Automatically purge jobs */ VAR cups_array_t *Jobs VALUE(NULL), /* List of current jobs */ - *ActiveJobs VALUE(NULL); + *ActiveJobs VALUE(NULL), /* List of active jobs */ + *PrintingJobs VALUE(NULL); + /* List of jobs that are printing */ VAR int NextJobId VALUE(1); /* Next job ID to use */ VAR int JobRetryLimit VALUE(5), diff --git a/scheduler/main.c b/scheduler/main.c index e831920a0..4c7c697e9 100644 --- a/scheduler/main.c +++ b/scheduler/main.c @@ -862,6 +862,16 @@ main(int argc, /* I - Number of command-line args */ current_time = time(NULL); + /* + * Write dirty config/state files... + */ + + if (DirtyCleanTime && current_time >= DirtyCleanTime) + { + cupsdCleanDirty(); + cupsdSetBusyState(); + } + #ifndef __APPLE__ /* * Update the network interfaces once a minute... @@ -1622,27 +1632,6 @@ process_children(void) cupsdFinishProcess(pid, name, sizeof(name)); - if (status == SIGTERM) - status = 0; - - if (status) - { - if (WIFEXITED(status)) - cupsdLogMessage(CUPSD_LOG_ERROR, "PID %d (%s) stopped with status %d!", - pid, name, WEXITSTATUS(status)); - else - cupsdLogMessage(CUPSD_LOG_ERROR, "PID %d (%s) crashed on signal %d!", - pid, name, WTERMSIG(status)); - - if (LogLevel < CUPSD_LOG_DEBUG) - cupsdLogMessage(CUPSD_LOG_INFO, - "Hint: Try setting the LogLevel to \"debug\" to find " - "out more."); - } - else - cupsdLogMessage(CUPSD_LOG_DEBUG, "PID %d (%s) exited with no errors.", - pid, name); - /* * Delete certificates for CGI processes... */ @@ -1674,6 +1663,9 @@ process_children(void) else job->backend = -pid; + if (job->state_value == IPP_JOB_CANCELED) + status = 0; /* Ignore errors when canceling jobs */ + if (status && job->status >= 0) { /* @@ -1721,6 +1713,31 @@ process_children(void) break; } } + + /* + * Show the exit status as needed... + */ + + if (status == SIGTERM) + status = 0; + + if (status) + { + if (WIFEXITED(status)) + cupsdLogMessage(CUPSD_LOG_ERROR, "PID %d (%s) stopped with status %d!", + pid, name, WEXITSTATUS(status)); + else + cupsdLogMessage(CUPSD_LOG_ERROR, "PID %d (%s) crashed on signal %d!", + pid, name, WTERMSIG(status)); + + if (LogLevel < CUPSD_LOG_DEBUG) + cupsdLogMessage(CUPSD_LOG_INFO, + "Hint: Try setting the LogLevel to \"debug\" to find " + "out more."); + } + else + cupsdLogMessage(CUPSD_LOG_DEBUG, "PID %d (%s) exited with no errors.", + pid, name); } } @@ -1910,6 +1927,16 @@ select_timeout(int fds) /* I - Number of descriptors returned */ * Check for any active jobs... */ + if (DirtyCleanTime && timeout > DirtyCleanTime) + { + timeout = DirtyCleanTime; + why = "write dirty config/state files"; + } + + /* + * Check for any active jobs... + */ + if (timeout > (now + 10) && ActiveJobs) { for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); diff --git a/scheduler/printers.c b/scheduler/printers.c index 6dc8bd971..11abd6b8d 100644 --- a/scheduler/printers.c +++ b/scheduler/printers.c @@ -2793,9 +2793,9 @@ cupsdSetPrinterState( update) { if (p->type & CUPS_PRINTER_CLASS) - cupsdSaveAllClasses(); + cupsdMarkDirty(CUPSD_DIRTY_CLASSES); else - cupsdSaveAllPrinters(); + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); } } @@ -2841,8 +2841,9 @@ cupsdStopPrinter(cupsd_printer_t *p, /* I - Printer to stop */ job->state->values[0].integer = IPP_JOB_PENDING; job->state_value = IPP_JOB_PENDING; + job->dirty = 1; - cupsdSaveJob(job); + cupsdMarkDirty(CUPSD_DIRTY_JOBS); cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, p, job, "Job stopped due to printer being paused"); diff --git a/scheduler/server.c b/scheduler/server.c index dcff28baa..9483ae658 100644 --- a/scheduler/server.c +++ b/scheduler/server.c @@ -3,7 +3,7 @@ * * Server start/stop routines for the Common UNIX Printing System (CUPS). * - * Copyright 2007 by Apple Inc. + * Copyright 2007-2008 by Apple Inc. * Copyright 1997-2006 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -137,7 +137,6 @@ cupsdStopServer(void) cupsdStopPolling(); cupsdStopBrowsing(); cupsdStopAllNotifiers(); - cupsdSaveRemoteCache(); cupsdDeleteAllCerts(); if (Clients) @@ -203,6 +202,13 @@ cupsdStopServer(void) cupsdDestroyProfile(DefaultProfile); DefaultProfile = NULL; + /* + * Write out any dirty files... + */ + + if (DirtyFiles) + cupsdCleanDirty(); + started = 0; } diff --git a/scheduler/subscriptions.c b/scheduler/subscriptions.c index 5bbb38c28..cea357fd3 100644 --- a/scheduler/subscriptions.c +++ b/scheduler/subscriptions.c @@ -297,7 +297,7 @@ cupsdAddEvent( } if (temp) - cupsdSaveAllSubscriptions(); + cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS); else cupsdLogMessage(CUPSD_LOG_DEBUG, "Discarding unused %s event...", cupsdEventName(event)); @@ -463,7 +463,7 @@ cupsdDeleteSubscription( */ if (update) - cupsdSaveAllSubscriptions(); + cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS); } @@ -646,7 +646,7 @@ cupsdExpireSubscriptions( } if (update) - cupsdSaveAllSubscriptions(); + cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS); } diff --git a/scheduler/sysman.c b/scheduler/sysman.c index 03aa8d035..636cc9475 100644 --- a/scheduler/sysman.c +++ b/scheduler/sysman.c @@ -3,7 +3,7 @@ * * System management definitions for the Common UNIX Printing System (CUPS). * - * Copyright 2007 by Apple Inc. + * Copyright 2007-2008 by Apple Inc. * Copyright 2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -14,6 +14,11 @@ * * Contents: * + * cupsdCleanDirty() - Write dirty config and state files. + * cupsdMarkDirty() - Mark config or state files as needing a + * write. + * cupsdSetBusyState() - Let the system know when we are busy + * doing something. * cupsdStartSystemMonitor() - Start monitoring for system change. * cupsdStopSystemMonitor() - Stop monitoring for system change. * cupsdUpdateSystemMonitor() - Update the current system state. @@ -34,15 +39,108 @@ /* - * Power management is a new addition to CUPS. Right now it is only - * implemented on MacOS X, but essentially we use these three functions - * to let the OS know when it is OK to put the system to sleep, typically - * when we are not in the middle of printing a job. + * The system management functions cover disk and power management which + * are primarily used on portable computers. * - * Once put to sleep, we invalidate all remote printers since it is - * common to wake up in a new location. + * Disk management involves delaying the write of certain configuration + * and state files to minimize the number of times the disk has to spin + * up. + * + * Power management support is currently only implemented on MacOS X, but + * essentially we use four functions to let the OS know when it is OK to + * put the system to idle sleep, typically when we are not in the middle of + * printing a job. + * + * Once put to sleep, we invalidate all remote printers since it is common + * to wake up in a new location/on a new wireless network. + */ + + +/* + * 'cupsdCleanDirty()' - Write dirty config and state files. + */ + +void +cupsdCleanDirty(void) +{ + if (DirtyFiles & CUPSD_DIRTY_PRINTERS) + cupsdSaveAllPrinters(); + + if (DirtyFiles & CUPSD_DIRTY_CLASSES) + cupsdSaveAllClasses(); + + if (DirtyFiles & CUPSD_DIRTY_REMOTE) + cupsdSaveRemoteCache(); + + if (DirtyFiles & CUPSD_DIRTY_PRINTCAP) + cupsdWritePrintcap(); + + if (DirtyFiles & CUPSD_DIRTY_JOBS) + { + cupsd_job_t *job; /* Current job */ + + cupsdSaveAllJobs(); + + for (job = (cupsd_job_t *)cupsArrayFirst(Jobs); + job; + job = (cupsd_job_t *)cupsArrayNext(Jobs)) + if (job->dirty) + cupsdSaveJob(job); + } + + if (DirtyFiles & CUPSD_DIRTY_SUBSCRIPTIONS) + cupsdSaveAllSubscriptions(); + + DirtyFiles = CUPSD_DIRTY_NONE; + DirtyCleanTime = 0; +} + + +/* + * 'cupsdMarkDirty()' - Mark config or state files as needing a write. */ +void +cupsdMarkDirty(int what) /* I - What file(s) are dirty? */ +{ + DirtyFiles |= what; + + if (!DirtyCleanTime) + DirtyCleanTime = time(NULL) + DirtyCleanInterval; + + cupsdSetBusyState(); +} + + +/* + * 'cupsdSetBusyState()' - Let the system know when we are busy doing something. + */ + +void +cupsdSetBusyState(void) +{ + int newbusy; /* New busy state */ + static int busy = 0; /* Current busy state */ + + + newbusy = DirtyCleanTime || + cupsArrayCount(PrintingJobs) || + cupsArrayCount(ActiveClients); + + if (newbusy != busy) + { + busy = newbusy; + + if (busy) + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdSetBusyState: Server no longer busy..."); + else + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdSetBusyState: Server is now busy..."); + } +} + + #ifdef __APPLE__ /* * This is the Apple-specific system event code. It works by creating @@ -280,7 +378,6 @@ cupsdUpdateSystemMonitor(void) Sleeping = 1; cupsdStopAllJobs(0); - cupsdSaveAllJobs(); for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; @@ -302,6 +399,8 @@ cupsdUpdateSystemMonitor(void) } } + cupsdCleanDirty(); + IOAllowPowerChange(sysevent.powerKernelPort, sysevent.powerNotificationID); } diff --git a/scheduler/sysman.h b/scheduler/sysman.h index e30be84bf..50ef17f96 100644 --- a/scheduler/sysman.h +++ b/scheduler/sysman.h @@ -3,7 +3,7 @@ * * System management definitions for the Common UNIX Printing System (CUPS). * - * Copyright 2007 by Apple Inc. + * Copyright 2007-2008 by Apple Inc. * Copyright 2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -14,9 +14,27 @@ */ /* + * Constants... + */ + +#define CUPSD_DIRTY_NONE 0 /* Nothing is dirty */ +#define CUPSD_DIRTY_PRINTERS 1 /* printers.conf is dirty */ +#define CUPSD_DIRTY_CLASSES 2 /* classes.conf is dirty */ +#define CUPSD_DIRTY_REMOTE 4 /* remote.cache is dirty */ +#define CUPSD_DIRTY_PRINTCAP 8 /* printcap is dirty */ +#define CUPSD_DIRTY_JOBS 16 /* jobs.cache or "c" file(s) are dirty */ +#define CUPSD_DIRTY_SUBSCRIPTIONS 32 /* subscriptions.conf is dirty */ + +/* * Globals... */ +VAR int DirtyFiles VALUE(CUPSD_DIRTY_NONE), + /* What files are dirty? */ + DirtyCleanInterval VALUE(60); + /* How often do we write dirty files? */ +VAR time_t DirtyCleanTime VALUE(0); + /* When to clean dirty files next */ VAR int Sleeping VALUE(0); /* Non-zero if machine is entering or * * in a sleep state... */ @@ -30,6 +48,9 @@ VAR int SysEventPipes[2] VALUE2(-1,-1); * Prototypes... */ +extern void cupsdCleanDirty(void); +extern void cupsdMarkDirty(int what); +extern void cupsdSetBusyState(void); extern void cupsdStartSystemMonitor(void); extern void cupsdStopSystemMonitor(void); extern void cupsdUpdateSystemMonitor(void); |