diff options
author | Jeremy Allison <jra@samba.org> | 2008-10-10 17:25:44 -0700 |
---|---|---|
committer | Karolin Seeger <kseeger@samba.org> | 2008-10-15 18:50:26 +0200 |
commit | f5f7ed4041ef986a5ce208d59bbf39d34373ce71 (patch) | |
tree | ac847dec01f66a41e8355fb30f52acf10c811238 /source | |
parent | 69de2806465742ea6f1ea96d75d2cb3be6b84284 (diff) | |
download | samba-f5f7ed4041ef986a5ce208d59bbf39d34373ce71.tar.gz samba-f5f7ed4041ef986a5ce208d59bbf39d34373ce71.tar.xz samba-f5f7ed4041ef986a5ce208d59bbf39d34373ce71.zip |
Now it's working, back port the aync fix for parsing large cups printer lists.
Jeremy.
(cherry picked from commit 48ee5a66d18b805d03f93c85e98a41374d82cfb9)
Diffstat (limited to 'source')
-rw-r--r-- | source/include/smb.h | 1 | ||||
-rw-r--r-- | source/lib/dummysmbd.c | 10 | ||||
-rw-r--r-- | source/param/loadparm.c | 2 | ||||
-rw-r--r-- | source/printing/load.c | 2 | ||||
-rw-r--r-- | source/printing/pcap.c | 77 | ||||
-rw-r--r-- | source/printing/print_cups.c | 262 |
6 files changed, 322 insertions, 32 deletions
diff --git a/source/include/smb.h b/source/include/smb.h index 3c7058fc29d..bfada1168e2 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -422,6 +422,7 @@ struct idle_event; struct share_mode_entry; struct uuid; struct named_mutex; +struct pcap_cache; struct vfs_fsp_data { struct vfs_fsp_data *next; diff --git a/source/lib/dummysmbd.c b/source/lib/dummysmbd.c index dbe886e3d13..a9ba2f2de7f 100644 --- a/source/lib/dummysmbd.c +++ b/source/lib/dummysmbd.c @@ -51,3 +51,13 @@ NTSTATUS can_delete_directory(struct connection_struct *conn, { return NT_STATUS_OK; } + +struct event_context *smbd_event_context(void) +{ + return NULL; +} + +struct messaging_context *smbd_messaging_context(void) +{ + return NULL; +} diff --git a/source/param/loadparm.c b/source/param/loadparm.c index 8390701879d..0f35f191166 100644 --- a/source/param/loadparm.c +++ b/source/param/loadparm.c @@ -7790,7 +7790,7 @@ static void lp_add_auto_services(char *str) Auto-load one printer. ***************************************************************************/ -void lp_add_one_printer(char *name, char *comment) +void lp_add_one_printer(const char *name, const char *comment, void *pdata) { int printers = lp_servicenumber(PRINTERS_NAME); int i; diff --git a/source/printing/load.c b/source/printing/load.c index 23144d5a955..fc21f271bd9 100644 --- a/source/printing/load.c +++ b/source/printing/load.c @@ -60,5 +60,5 @@ void load_printers(void) /* load all printcap printers */ if (lp_load_printers() && lp_servicenumber(PRINTERS_NAME) >= 0) - pcap_printer_fn(lp_add_one_printer); + pcap_printer_fn(lp_add_one_printer, NULL); } diff --git a/source/printing/pcap.c b/source/printing/pcap.c index 30cb254a29a..10c1a2d608b 100644 --- a/source/printing/pcap.c +++ b/source/printing/pcap.c @@ -63,41 +63,51 @@ #include "includes.h" -typedef struct pcap_cache { +struct pcap_cache { char *name; char *comment; struct pcap_cache *next; -} pcap_cache_t; +}; -static pcap_cache_t *pcap_cache = NULL; +/* The systemwide printcap cache. */ +static struct pcap_cache *pcap_cache = NULL; -bool pcap_cache_add(const char *name, const char *comment) +bool pcap_cache_add_specific(struct pcap_cache **ppcache, const char *name, const char *comment) { - pcap_cache_t *p; + struct pcap_cache *p; - if (name == NULL || ((p = SMB_MALLOC_P(pcap_cache_t)) == NULL)) - return False; + if (name == NULL || ((p = SMB_MALLOC_P(struct pcap_cache)) == NULL)) + return false; p->name = SMB_STRDUP(name); p->comment = (comment && *comment) ? SMB_STRDUP(comment) : NULL; - p->next = pcap_cache; - pcap_cache = p; + DEBUG(11,("pcap_cache_add_specific: Adding name %s info %s\n", + p->name, p->comment ? p->comment : "")); + + p->next = *ppcache; + *ppcache = p; - return True; + return true; } -static void pcap_cache_destroy(pcap_cache_t *cache) +void pcap_cache_destroy_specific(struct pcap_cache **pp_cache) { - pcap_cache_t *p, *next; + struct pcap_cache *p, *next; - for (p = cache; p != NULL; p = next) { + for (p = *pp_cache; p != NULL; p = next) { next = p->next; SAFE_FREE(p->name); SAFE_FREE(p->comment); SAFE_FREE(p); } + *pp_cache = NULL; +} + +bool pcap_cache_add(const char *name, const char *comment) +{ + return pcap_cache_add_specific(&pcap_cache, name, comment); } bool pcap_cache_loaded(void) @@ -105,11 +115,21 @@ bool pcap_cache_loaded(void) return (pcap_cache != NULL); } +void pcap_cache_replace(const struct pcap_cache *pcache) +{ + const struct pcap_cache *p; + + pcap_cache_destroy_specific(&pcap_cache); + for (p = pcache; p; p = p->next) { + pcap_cache_add(p->name, p->comment); + } +} + void pcap_cache_reload(void) { const char *pcap_name = lp_printcapname(); bool pcap_reloaded = False; - pcap_cache_t *tmp_cache = NULL; + struct pcap_cache *tmp_cache = NULL; XFILE *pcap_file; char *pcap_line; @@ -223,9 +243,9 @@ done: DEBUG(3, ("reload status: %s\n", (pcap_reloaded) ? "ok" : "error")); if (pcap_reloaded) - pcap_cache_destroy(tmp_cache); + pcap_cache_destroy_specific(&tmp_cache); else { - pcap_cache_destroy(pcap_cache); + pcap_cache_destroy_specific(&pcap_cache); pcap_cache = tmp_cache; } @@ -235,7 +255,7 @@ done: bool pcap_printername_ok(const char *printername) { - pcap_cache_t *p; + struct pcap_cache *p; for (p = pcap_cache; p != NULL; p = p->next) if (strequal(p->name, printername)) @@ -245,19 +265,22 @@ bool pcap_printername_ok(const char *printername) } /*************************************************************************** -run a function on each printer name in the printcap file. The function is -passed the primary name and the comment (if possible). Note the fn() takes -strings in DOS codepage. This means the xxx_printer_fn() calls must be fixed -to return DOS codepage. FIXME !! JRA. - -XXX: I'm not sure if this comment still applies.. Anyone? -Rob +run a function on each printer name in the printcap file. ***************************************************************************/ -void pcap_printer_fn(void (*fn)(char *, char *)) + +void pcap_printer_fn_specific(const struct pcap_cache *pc, + void (*fn)(const char *, const char *, void *), + void *pdata) { - pcap_cache_t *p; + const struct pcap_cache *p; - for (p = pcap_cache; p != NULL; p = p->next) - fn(p->name, p->comment); + for (p = pc; p != NULL; p = p->next) + fn(p->name, p->comment, pdata); return; } + +void pcap_printer_fn(void (*fn)(const char *, const char *, void *), void *pdata) +{ + return pcap_printer_fn_specific(pcap_cache, fn, pdata); +} diff --git a/source/printing/print_cups.c b/source/printing/print_cups.c index 0be65a58bef..8d32ddbc71e 100644 --- a/source/printing/print_cups.c +++ b/source/printing/print_cups.c @@ -82,9 +82,46 @@ static http_t *cups_connect(TALLOC_CTX *frame) return http; } -bool cups_cache_reload(void) +static void send_pcap_info(const char *name, const char *info, void *pd) +{ + int fd = *(int *)pd; + size_t namelen = name ? strlen(name)+1 : 0; + size_t infolen = info ? strlen(info)+1 : 0; + + DEBUG(11,("send_pcap_info: writing namelen %u\n", (unsigned int)namelen)); + if (sys_write(fd, &namelen, sizeof(namelen)) != sizeof(namelen)) { + DEBUG(10,("send_pcap_info: namelen write failed %s\n", + strerror(errno))); + return; + } + DEBUG(11,("send_pcap_info: writing infolen %u\n", (unsigned int)infolen)); + if (sys_write(fd, &infolen, sizeof(infolen)) != sizeof(infolen)) { + DEBUG(10,("send_pcap_info: infolen write failed %s\n", + strerror(errno))); + return; + } + if (namelen) { + DEBUG(11,("send_pcap_info: writing name %s\n", name)); + if (sys_write(fd, name, namelen) != namelen) { + DEBUG(10,("send_pcap_info: name write failed %s\n", + strerror(errno))); + return; + } + } + if (infolen) { + DEBUG(11,("send_pcap_info: writing info %s\n", info)); + if (sys_write(fd, info, infolen) != infolen) { + DEBUG(10,("send_pcap_info: info write failed %s\n", + strerror(errno))); + return; + } + } +} + +static bool cups_cache_reload_async(int fd) { TALLOC_CTX *frame = talloc_stackframe(); + struct pcap_cache *tmp_pcap_cache = NULL; http_t *http = NULL; /* HTTP connection to server */ ipp_t *request = NULL, /* IPP Request */ *response = NULL; /* IPP Response */ @@ -195,7 +232,7 @@ bool cups_cache_reload(void) if (name == NULL) break; - if (!pcap_cache_add(name, info)) { + if (!pcap_cache_add_specific(&tmp_pcap_cache, name, info)) { goto out; } } @@ -281,7 +318,7 @@ bool cups_cache_reload(void) if (name == NULL) break; - if (!pcap_cache_add(name, info)) { + if (!pcap_cache_add_specific(&tmp_pcap_cache, name, info)) { goto out; } } @@ -298,10 +335,229 @@ bool cups_cache_reload(void) if (http) httpClose(http); + /* Send all the entries up the pipe. */ + if (tmp_pcap_cache) { + pcap_printer_fn_specific(tmp_pcap_cache, + send_pcap_info, + (void *)&fd); + + pcap_cache_destroy_specific(&tmp_pcap_cache); + } TALLOC_FREE(frame); return ret; } +static struct pcap_cache *local_pcap_copy; +struct fd_event *cache_fd_event; + +static bool cups_pcap_load_async(int *pfd) +{ + int fds[2]; + pid_t pid; + + *pfd = -1; + + if (cache_fd_event) { + DEBUG(3,("cups_pcap_load_async: already waiting for " + "a refresh event\n" )); + return false; + } + + DEBUG(5,("cups_pcap_load_async: asynchronously loading cups printers\n")); + + if (pipe(fds) == -1) { + return false; + } + + pid = sys_fork(); + if (pid == (pid_t)-1) { + DEBUG(10,("cups_pcap_load_async: fork failed %s\n", + strerror(errno) )); + close(fds[0]); + close(fds[1]); + return false; + } + + if (pid) { + DEBUG(10,("cups_pcap_load_async: child pid = %u\n", + (unsigned int)pid )); + /* Parent. */ + close(fds[1]); + *pfd = fds[0]; + return true; + } + + /* Child. */ + if (!reinit_after_fork(smbd_messaging_context(), true)) { + DEBUG(0,("cups_pcap_load_async: reinit_after_fork() failed\n")); + smb_panic("cups_pcap_load_async: reinit_after_fork() failed"); + } + + close(fds[0]); + cups_cache_reload_async(fds[1]); + close(fds[1]); + _exit(0); +} + +static void cups_async_callback(struct event_context *event_ctx, + struct fd_event *event, + uint16 flags, + void *p) +{ + TALLOC_CTX *frame = talloc_stackframe(); + int fd = *(int *)p; + struct pcap_cache *tmp_pcap_cache = NULL; + + DEBUG(5,("cups_async_callback: callback received for printer data. " + "fd = %d\n", fd)); + + while (1) { + char *name = NULL, *info = NULL; + size_t namelen = 0, infolen = 0; + ssize_t ret = -1; + + ret = sys_read(fd, &namelen, sizeof(namelen)); + if (ret == 0) { + /* EOF */ + break; + } + if (ret != sizeof(namelen)) { + DEBUG(10,("cups_async_callback: namelen read failed %d %s\n", + errno, strerror(errno))); + break; + } + + DEBUG(11,("cups_async_callback: read namelen %u\n", + (unsigned int)namelen)); + + ret = sys_read(fd, &infolen, sizeof(infolen)); + if (ret == 0) { + /* EOF */ + break; + } + if (ret != sizeof(infolen)) { + DEBUG(10,("cups_async_callback: infolen read failed %s\n", + strerror(errno))); + break; + } + + DEBUG(11,("cups_async_callback: read infolen %u\n", + (unsigned int)infolen)); + + if (namelen) { + name = TALLOC_ARRAY(frame, char, namelen); + if (!name) { + break; + } + ret = sys_read(fd, name, namelen); + if (ret == 0) { + /* EOF */ + break; + } + if (ret != namelen) { + DEBUG(10,("cups_async_callback: name read failed %s\n", + strerror(errno))); + break; + } + DEBUG(11,("cups_async_callback: read name %s\n", + name)); + } else { + name = NULL; + } + if (infolen) { + info = TALLOC_ARRAY(frame, char, infolen); + if (!info) { + break; + } + ret = sys_read(fd, info, infolen); + if (ret == 0) { + /* EOF */ + break; + } + if (ret != infolen) { + DEBUG(10,("cups_async_callback: info read failed %s\n", + strerror(errno))); + break; + } + DEBUG(11,("cups_async_callback: read info %s\n", + info)); + } else { + info = NULL; + } + + /* Add to our local pcap cache. */ + pcap_cache_add_specific(&tmp_pcap_cache, name, info); + TALLOC_FREE(name); + TALLOC_FREE(info); + } + + TALLOC_FREE(frame); + if (tmp_pcap_cache) { + /* We got a namelist, replace our local cache. */ + pcap_cache_destroy_specific(&local_pcap_copy); + local_pcap_copy = tmp_pcap_cache; + + /* And the systemwide pcap cache. */ + pcap_cache_replace(local_pcap_copy); + } else { + DEBUG(2,("cups_async_callback: failed to read a new " + "printer list\n")); + } + close(fd); + TALLOC_FREE(p); + TALLOC_FREE(cache_fd_event); +} + +bool cups_cache_reload(void) +{ + int *p_pipe_fd = TALLOC_P(NULL, int); + + if (!p_pipe_fd) { + return false; + } + + *p_pipe_fd = -1; + + /* Set up an async refresh. */ + if (!cups_pcap_load_async(p_pipe_fd)) { + return false; + } + if (!local_pcap_copy) { + /* We have no local cache, wait directly for + * async refresh to complete. + */ + DEBUG(10,("cups_cache_reload: sync read on fd %d\n", + *p_pipe_fd )); + + cups_async_callback(smbd_event_context(), + NULL, + EVENT_FD_READ, + (void *)p_pipe_fd); + if (!local_pcap_copy) { + return false; + } + } else { + /* Replace the system cache with our + * local copy. */ + pcap_cache_replace(local_pcap_copy); + + DEBUG(10,("cups_cache_reload: async read on fd %d\n", + *p_pipe_fd )); + + /* Trigger an event when the pipe can be read. */ + cache_fd_event = event_add_fd(smbd_event_context(), + NULL, *p_pipe_fd, + EVENT_FD_READ, + cups_async_callback, + (void *)p_pipe_fd); + if (!cache_fd_event) { + close(*p_pipe_fd); + TALLOC_FREE(p_pipe_fd); + return false; + } + } + return true; +} /* * 'cups_job_delete()' - Delete a job. |