Since commit
eada8f8a, updates to the cups pcap cache are performed
asynchronously - cups_cache_reload() forks a child process to request
cups printer information and notify the parent smbd on completion.
Currently printer shares are reloaded immediately following the call to
cups_cache_reload(), this occurs prior to smbd receiving new cups pcap
information from the child process. Such behaviour can result in stale
print shares as outlined in bug 7836.
This fix ensures print shares are only reloaded after new pcap data has
been received.
Pair-Programmed-With: Lars Müller <lars@samba.org>
bool pcap_cache_add(const char *name, const char *comment);
bool pcap_cache_loaded(void);
void pcap_cache_replace(const struct pcap_cache *cache);
-void pcap_cache_reload(void);
+void pcap_cache_reload(void (*post_cache_fill_fn)(void));
bool pcap_printername_ok(const char *printername);
void pcap_printer_fn_specific(const struct pcap_cache *, void (*fn)(const char *, const char *, void *), void *);
void pcap_printer_fn(void (*fn)(const char *, const char *, void *), void *);
/* The following definitions come from printing/print_cups.c */
-bool cups_cache_reload(void);
+bool cups_cache_reload(void (*post_cache_fill_fn)(void));
bool cups_pull_comment_location(NT_PRINTER_INFO_LEVEL_2 *printer);
/* The following definitions come from printing/print_generic.c */
}
/***************************************************************************
-load automatic printer services
+load automatic printer services from pre-populated pcap cache
***************************************************************************/
void load_printers(void)
{
- if (!pcap_cache_loaded())
- pcap_cache_reload();
+ SMB_ASSERT(pcap_cache_loaded());
add_auto_printers();
}
}
-void pcap_cache_reload(void)
+void pcap_cache_reload(void (*post_cache_fill_fn)(void))
{
const char *pcap_name = lp_printcapname();
bool pcap_reloaded = False;
struct pcap_cache *tmp_cache = NULL;
XFILE *pcap_file;
char *pcap_line;
+ bool post_cache_fill_fn_handled = false;
DEBUG(3, ("reloading printcap cache\n"));
#ifdef HAVE_CUPS
if (strequal(pcap_name, "cups")) {
- pcap_reloaded = cups_cache_reload();
+ pcap_reloaded = cups_cache_reload(post_cache_fill_fn);
+ /*
+ * cups_cache_reload() is async and calls post_cache_fill_fn()
+ * on successful completion
+ */
+ post_cache_fill_fn_handled = true;
goto done;
}
#endif
done:
DEBUG(3, ("reload status: %s\n", (pcap_reloaded) ? "ok" : "error"));
- if (pcap_reloaded)
+ if (pcap_reloaded) {
pcap_cache_destroy_specific(&tmp_cache);
- else {
+ if ((post_cache_fill_fn_handled == false)
+ && (post_cache_fill_fn != NULL)) {
+ post_cache_fill_fn();
+ }
+ } else {
pcap_cache_destroy_specific(&pcap_cache);
pcap_cache = tmp_cache;
}
_exit(0);
}
+struct cups_async_cb_args {
+ int pipe_fd;
+ void (*post_cache_fill_fn)(void);
+};
+
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 cups_async_cb_args *cb_args = (struct cups_async_cb_args *)p;
+ int fd = cb_args->pipe_fd;
struct pcap_cache *tmp_pcap_cache = NULL;
DEBUG(5,("cups_async_callback: callback received for printer data. "
/* And the systemwide pcap cache. */
pcap_cache_replace(local_pcap_copy);
+
+ /* Caller may have requested post cache fill callback */
+ if (cb_args->post_cache_fill_fn) {
+ cb_args->post_cache_fill_fn();
+ }
} else {
DEBUG(2,("cups_async_callback: failed to read a new "
"printer list\n"));
}
close(fd);
- TALLOC_FREE(p);
+ TALLOC_FREE(cb_args);
TALLOC_FREE(cache_fd_event);
}
-bool cups_cache_reload(void)
+bool cups_cache_reload(void (*post_cache_fill_fn)(void))
{
- int *p_pipe_fd = TALLOC_P(NULL, int);
+ struct cups_async_cb_args *cb_args;
+ int *p_pipe_fd;
- if (!p_pipe_fd) {
+ cb_args = TALLOC_P(NULL, struct cups_async_cb_args);
+ if (!cb_args) {
return false;
}
-
+ cb_args->post_cache_fill_fn = post_cache_fill_fn;
+ p_pipe_fd = &cb_args->pipe_fd;
*p_pipe_fd = -1;
/* Set up an async refresh. */
if (!cups_pcap_load_async(p_pipe_fd)) {
+ talloc_free(cb_args);
return false;
}
if (!local_pcap_copy) {
cups_async_callback(smbd_event_context(),
NULL,
EVENT_FD_READ,
- (void *)p_pipe_fd);
+ (void *)cb_args);
if (!local_pcap_copy) {
return false;
}
NULL, *p_pipe_fd,
EVENT_FD_READ,
cups_async_callback,
- (void *)p_pipe_fd);
+ (void *)cb_args);
if (!cache_fd_event) {
close(*p_pipe_fd);
- TALLOC_FREE(p_pipe_fd);
+ talloc_free(cb_args);
return false;
}
}
/* NOTREACHED return True; */
}
-/****************************************************************************
- Reload printers
-**************************************************************************/
+/***************************************************************************
+ purge stale printers and reload from pre-populated pcap cache
+***************************************************************************/
void reload_printers(void)
{
int snum;
int pnum = lp_servicenumber(PRINTERS_NAME);
const char *pname;
- pcap_cache_reload();
+ SMB_ASSERT(pcap_cache_loaded());
- /* remove stale printers */
+ DEBUG(10, ("reloading printer services from pcap cache\n"));
for (snum = 0; snum < n_services; snum++) {
/* avoid removing PRINTERS_NAME or non-autoloaded printers */
if (snum == pnum || !(lp_snum_ok(snum) && lp_print_ok(snum) &&
ret = lp_load(get_dyn_CONFIGFILE(), False, False, True, True);
- reload_printers();
+ pcap_cache_reload(&reload_printers);
/* perhaps the config filename is now set */
if (!test)
return 0;
}
iNumNonAutoPrintServices = lp_numservices();
- load_printers();
+ pcap_cache_reload(&load_printers);
return 1;
}
load_config(True);
load_interfaces();
iNumNonAutoPrintServices = lp_numservices();
- load_printers();
+ pcap_cache_reload(&load_printers);
cgi_setup(get_dyn_SWATDIR(), !demo_mode);