From afc5f1aefbddf68252f4b9a0a2cee2d5601d8057 Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Tue, 26 Nov 2002 00:46:31 +0000 Subject: [PATCH] [print notify fixes from APP_HEAD] * fixing change notify on print server handle * adding change notify support into smbcontrol for sending comment changes, etc... All part of CR 1159/1160 (This used to be commit f1062e79de8a3046c6e3f22b3d1a4819afe6809b) --- source3/Makefile.in | 8 +- source3/include/printing.h | 16 ++ source3/printing/notify.c | 87 ++++++++++ source3/printing/printing.c | 314 ++++-------------------------------- source3/utils/smbcontrol.c | 52 +++++- 5 files changed, 191 insertions(+), 286 deletions(-) diff --git a/source3/Makefile.in b/source3/Makefile.in index f9b4b48346b..5973faa3302 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -283,7 +283,8 @@ PRINTING_OBJ = printing/pcap.o printing/print_svid.o \ printing/print_cups.o printing/print_generic.o \ printing/lpq_parse.o printing/load.o -PRINTBACKEND_OBJ = printing/printing.o printing/nt_printing.o printing/notify.o +PRINTBACKEND_OBJ = printing/printing.o printing/nt_printing.o printing/notify.o \ + printing/printing_db.o MSDFS_OBJ = msdfs/msdfs.o @@ -325,7 +326,8 @@ STATUS_OBJ = utils/status.o $(LOCKING_OBJ) $(PARAM_OBJ) \ $(UBIQX_OBJ) $(PROFILE_OBJ) $(LIB_OBJ) $(POPT_LIB_OBJ) SMBCONTROL_OBJ = utils/smbcontrol.o $(LOCKING_OBJ) $(PARAM_OBJ) \ - $(UBIQX_OBJ) $(PROFILE_OBJ) $(LIB_OBJ) + $(UBIQX_OBJ) $(PROFILE_OBJ) $(LIB_OBJ) printing/notify.o \ + printing/printing_db.o SMBTREE_OBJ = utils/smbtree.o $(LOCKING_OBJ) $(PARAM_OBJ) \ $(UBIQX_OBJ) $(PROFILE_OBJ) $(LIB_OBJ) $(LIBSMB_OBJ) @@ -682,7 +684,7 @@ bin/smbstatus: $(STATUS_OBJ) @BUILD_POPT@ bin/.dummy bin/smbcontrol: $(SMBCONTROL_OBJ) bin/.dummy @echo Linking $@ - @$(CC) $(FLAGS) -o $@ $(SMBCONTROL_OBJ) $(LDFLAGS) $(LIBS) + @$(CC) -DUSING_SMBCONTROL $(FLAGS) -o $@ $(SMBCONTROL_OBJ) $(LDFLAGS) $(LIBS) bin/smbtree: $(SMBTREE_OBJ) bin/.dummy @echo Linking $@ diff --git a/source3/include/printing.h b/source3/include/printing.h index 38ff7eac366..1d658a07681 100644 --- a/source3/include/printing.h +++ b/source3/include/printing.h @@ -74,4 +74,20 @@ extern struct printif cups_printif; #define PRINT_SPOOL_PREFIX "smbprn." #define PRINT_DATABASE_VERSION 5 +/* There can be this many printing tdb's open, plus any locked ones. */ +#define MAX_PRINT_DBS_OPEN 1 + +struct tdb_print_db { + struct tdb_print_db *next, *prev; + TDB_CONTEXT *tdb; + int ref_count; + fstring printer_name; +}; + +/* + * Used for print notify + */ + +#define NOTIFY_PID_LIST_KEY "NOTIFY_PID_LIST" + #endif /* PRINTING_H_ */ diff --git a/source3/printing/notify.c b/source3/printing/notify.c index a4111831d9c..f55dbff47e8 100644 --- a/source3/printing/notify.c +++ b/source3/printing/notify.c @@ -31,6 +31,18 @@ static struct notify_queue { size_t buflen; } *notify_queue_head = NULL; +/**************************************************************************** + Turn a queue name into a snum. +****************************************************************************/ + +int print_queue_snum(const char *qname) +{ + int snum = lp_servicenumber(qname); + if (snum == -1 || !lp_print_ok(snum)) + return -1; + return snum; +} + /******************************************************************* Used to decide if we need a short select timeout. *******************************************************************/ @@ -362,3 +374,78 @@ void notify_printer_location(int snum, char *location) printer_name, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_LOCATION, snum, strlen(location) + 1, location); } + +void notify_printer_byname( char *printername, uint32 change, char *value ) +{ + int snum = print_queue_snum(printername); + int type = PRINTER_NOTIFY_TYPE; + + if ( snum == -1 ) + return; + + send_notify_field_buffer( printername, type, change, snum, strlen(value), value ); +} + + +/**************************************************************************** + Return a malloced list of pid_t's that are interested in getting update + messages on this print queue. Used in printing/notify to send the messages. +****************************************************************************/ + +BOOL print_notify_pid_list(const char *printername, TALLOC_CTX *mem_ctx, size_t *p_num_pids, pid_t **pp_pid_list) +{ + struct tdb_print_db *pdb = NULL; + TDB_CONTEXT *tdb = NULL; + TDB_DATA data; + BOOL ret = True; + size_t i, num_pids, offset; + pid_t *pid_list; + + *p_num_pids = 0; + *pp_pid_list = NULL; + + pdb = get_print_db_byname(printername); + if (!pdb) + return False; + tdb = pdb->tdb; + + if (tdb_read_lock_bystring(tdb, NOTIFY_PID_LIST_KEY, 10) == -1) { + DEBUG(0,("print_notify_pid_list: Failed to lock printer %s database\n", + printername)); + if (pdb) + release_print_db(pdb); + return False; + } + + data = get_printer_notify_pid_list( tdb, printername, True ); + + if (!data.dptr) { + ret = True; + goto done; + } + + num_pids = data.dsize / 8; + + if ((pid_list = (pid_t *)talloc(mem_ctx, sizeof(pid_t) * num_pids)) == NULL) { + ret = False; + goto done; + } + + for( i = 0, offset = 0; offset < data.dsize; offset += 8, i++) + pid_list[i] = (pid_t)IVAL(data.dptr, offset); + + *pp_pid_list = pid_list; + *p_num_pids = num_pids; + + ret = True; + + done: + + tdb_read_unlock_bystring(tdb, NOTIFY_PID_LIST_KEY); + if (pdb) + release_print_db(pdb); + SAFE_FREE(data.dptr); + return ret; +} + + diff --git a/source3/printing/printing.c b/source3/printing/printing.c index a8f90972557..a6b5e5cb834 100644 --- a/source3/printing/printing.c +++ b/source3/printing/printing.c @@ -136,135 +136,6 @@ static pid_t local_pid; static int get_queue_status(int, print_status_struct *); -/* There can be this many printing tdb's open, plus any locked ones. */ -#define MAX_PRINT_DBS_OPEN 1 - -struct tdb_print_db { - struct tdb_print_db *next, *prev; - TDB_CONTEXT *tdb; - int ref_count; - fstring printer_name; -}; - -static struct tdb_print_db *print_db_head; - -/**************************************************************************** - Function to find or create the printer specific job tdb given a printername. - Limits the number of tdb's open to MAX_PRINT_DBS_OPEN. -****************************************************************************/ - -static struct tdb_print_db *get_print_db_byname(const char *printername) -{ - struct tdb_print_db *p = NULL, *last_entry = NULL; - int num_open = 0; - pstring printdb_path; - BOOL done_become_root = False; - - for (p = print_db_head, last_entry = print_db_head; p; p = p->next) { - /* Ensure the list terminates... JRA. */ - SMB_ASSERT(p->next != print_db_head); - - if (p->tdb && strequal(p->printer_name, printername)) { - DLIST_PROMOTE(print_db_head, p); - p->ref_count++; - return p; - } - num_open++; - last_entry = p; - } - - /* Not found. */ - if (num_open >= MAX_PRINT_DBS_OPEN) { - /* Try and recycle the last entry. */ - DLIST_PROMOTE(print_db_head, last_entry); - - for (p = print_db_head; p; p = p->next) { - if (p->ref_count) - continue; - if (p->tdb) { - if (tdb_close(print_db_head->tdb)) { - DEBUG(0,("get_print_db: Failed to close tdb for printer %s\n", - print_db_head->printer_name )); - return NULL; - } - } - p->tdb = NULL; - p->ref_count = 0; - memset(p->printer_name, '\0', sizeof(p->printer_name)); - break; - } - if (p) { - DLIST_PROMOTE(print_db_head, p); - p = print_db_head; - } - } - - if (!p) { - /* Create one. */ - p = (struct tdb_print_db *)malloc(sizeof(struct tdb_print_db)); - if (!p) { - DEBUG(0,("get_print_db: malloc fail !\n")); - return NULL; - } - ZERO_STRUCTP(p); - DLIST_ADD(print_db_head, p); - } - - pstrcpy(printdb_path, lock_path("printing/")); - pstrcat(printdb_path, printername); - pstrcat(printdb_path, ".tdb"); - - if (geteuid() != 0) { - become_root(); - done_become_root = True; - } - - p->tdb = tdb_open_log(printdb_path, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600); - - if (done_become_root) - unbecome_root(); - - if (!p->tdb) { - DEBUG(0,("get_print_db: Failed to open printer backend database %s.\n", - printdb_path )); - DLIST_REMOVE(print_db_head, p); - SAFE_FREE(p); - return NULL; - } - fstrcpy(p->printer_name, printername); - p->ref_count++; - return p; -} - -/*************************************************************************** - Remove a reference count. -****************************************************************************/ - -static void release_print_db( struct tdb_print_db *pdb) -{ - pdb->ref_count--; - SMB_ASSERT(pdb->ref_count >= 0); -} - -/*************************************************************************** - Close all open print db entries. -****************************************************************************/ - -static void close_all_print_db(void) -{ - struct tdb_print_db *p = NULL, *next_p = NULL; - - for (p = print_db_head; p; p = next_p) { - next_p = p->next; - - if (p->tdb) - tdb_close(p->tdb); - DLIST_REMOVE(print_db_head, p); - ZERO_STRUCTP(p); - SAFE_FREE(p); - } -} - /**************************************************************************** Initialise the printing backend. Called once at startup before the fork(). ****************************************************************************/ @@ -1046,134 +917,6 @@ static void print_queue_update(int snum) release_print_db(pdb); } -/**************************************************************************** - Fetch and clean the pid_t record list for all pids interested in notify - messages. data needs freeing on exit. -****************************************************************************/ - -#define NOTIFY_PID_LIST_KEY "NOTIFY_PID_LIST" -#define PRINT_SERVER_ENTRY_NAME "___PRINT_SERVER_ENTRY___" - -static TDB_DATA get_printer_notify_pid_list(TDB_CONTEXT *tdb, const char *printer_name, BOOL cleanlist) -{ - TDB_DATA data; - size_t i; - - ZERO_STRUCT(data); - - data = tdb_fetch_by_string( tdb, NOTIFY_PID_LIST_KEY ); - - if (!data.dptr) { - ZERO_STRUCT(data); - return data; - } - - if (data.dsize % 8) { - DEBUG(0,("get_printer_notify_pid_list: Size of record for printer %s not a multiple of 8 !\n", printer_name )); - tdb_delete_by_string(tdb, NOTIFY_PID_LIST_KEY ); - SAFE_FREE(data.dptr); - ZERO_STRUCT(data); - return data; - } - - if (!cleanlist) - return data; - - /* - * Weed out all dead entries. - */ - - for( i = 0; i < data.dsize; i += 8) { - pid_t pid = (pid_t)IVAL(data.dptr, i); - - if (pid == sys_getpid()) - continue; - - /* Entry is dead if process doesn't exist or refcount is zero. */ - - while ((i < data.dsize) && ((IVAL(data.dptr, i + 4) == 0) || !process_exists(pid))) { - - /* Refcount == zero is a logic error and should never happen. */ - if (IVAL(data.dptr, i + 4) == 0) { - DEBUG(0,("get_printer_notify_pid_list: Refcount == 0 for pid = %u printer %s !\n", - (unsigned int)pid, printer_name )); - } - - if (data.dsize - i > 8) - memmove( &data.dptr[i], &data.dptr[i+8], data.dsize - i - 8); - data.dsize -= 8; - } - } - - return data; -} - -/**************************************************************************** - Return a malloced list of pid_t's that are interested in getting update - messages on this print queue. Used in printing/notify to send the messages. -****************************************************************************/ - -BOOL print_notify_pid_list(const char *printername, TALLOC_CTX *mem_ctx, size_t *p_num_pids, pid_t **pp_pid_list) -{ - struct tdb_print_db *pdb = NULL; - TDB_CONTEXT *tdb = NULL; - TDB_DATA data; - BOOL ret = True; - size_t i, num_pids, offset; - pid_t *pid_list; - - *p_num_pids = 0; - *pp_pid_list = NULL; - - if (strequal(printername, PRINT_SERVER_ENTRY_NAME)) { - pdb = NULL; - tdb = conn_tdb_ctx(); - } else { - pdb = get_print_db_byname(printername); - if (!pdb) - return False; - tdb = pdb->tdb; - } - - if (tdb_read_lock_bystring(tdb, NOTIFY_PID_LIST_KEY, 10) == -1) { - DEBUG(0,("print_notify_pid_list: Failed to lock printer %s database\n", - printername)); - if (pdb) - release_print_db(pdb); - return False; - } - - data = get_printer_notify_pid_list( tdb, printername, True ); - - if (!data.dptr) { - ret = True; - goto done; - } - - num_pids = data.dsize / 8; - - if ((pid_list = (pid_t *)talloc(mem_ctx, sizeof(pid_t) * num_pids)) == NULL) { - ret = False; - goto done; - } - - for( i = 0, offset = 0; offset < data.dsize; offset += 8, i++) - pid_list[i] = (pid_t)IVAL(data.dptr, offset); - - *pp_pid_list = pid_list; - *p_num_pids = num_pids; - - ret = True; - - done: - - tdb_read_unlock_bystring(tdb, NOTIFY_PID_LIST_KEY); - if (pdb) - release_print_db(pdb); - SAFE_FREE(data.dptr); - return ret; -} - /**************************************************************************** Create/Update an entry in the print tdb that will allow us to send notify updates only to interested smbd's. @@ -1189,16 +932,29 @@ BOOL print_notify_register_pid(int snum) BOOL ret = False; size_t i; - if (snum != -1) { + /* if (snum == -1), then the change notify request was + on a print server handle and we need to register on + all print queus */ + + if (snum == -1) + { + int num_services = lp_numservices(); + int idx; + + for ( idx=0; idxtdb; - } else { - printername = PRINT_SERVER_ENTRY_NAME; - pdb = NULL; - tdb = conn_tdb_ctx(); } if (tdb_lock_bystring(tdb, NOTIFY_PID_LIST_KEY, 10) == -1) { @@ -1267,16 +1023,28 @@ BOOL print_notify_deregister_pid(int snum) size_t i; BOOL ret = False; - if (snum != -1) { + /* if ( snum == -1 ), we are deregister a print server handle + which means to deregister on all print queues */ + + if (snum == -1) + { + int num_services = lp_numservices(); + int idx; + + for ( idx=0; idxtdb; - } else { - printername = PRINT_SERVER_ENTRY_NAME; - pdb = NULL; - tdb = conn_tdb_ctx(); } if (tdb_lock_bystring(tdb, NOTIFY_PID_LIST_KEY, 10) == -1) { @@ -2197,18 +1965,6 @@ int print_queue_status(int snum, return tstruct.qcount; } -/**************************************************************************** - Turn a queue name into a snum. -****************************************************************************/ - -int print_queue_snum(const char *qname) -{ - int snum = lp_servicenumber(qname); - if (snum == -1 || !lp_print_ok(snum)) - return -1; - return snum; -} - /**************************************************************************** Pause a queue. ****************************************************************************/ diff --git a/source3/utils/smbcontrol.c b/source3/utils/smbcontrol.c index 034de91ce01..2f3bb2e0da1 100644 --- a/source3/utils/smbcontrol.c +++ b/source3/utils/smbcontrol.c @@ -42,7 +42,7 @@ static struct { {"dmalloc-mark", MSG_REQ_DMALLOC_MARK }, {"dmalloc-log-changed", MSG_REQ_DMALLOC_LOG_CHANGED }, {"shutdown", MSG_SHUTDOWN }, - {"change_id", MSG_PRINTER_DRVUPGRADE}, + {"drvupgrade", MSG_PRINTER_DRVUPGRADE}, {NULL, -1} }; @@ -50,6 +50,12 @@ time_t timeout_start; #define MAX_WAIT 10 +/* we need these because we link to printing*.o */ + +void become_root(void) {} +void unbecome_root(void) {} + + static void usage(BOOL doexit) { int i; @@ -250,6 +256,7 @@ static BOOL do_command(char *dest, char *msg_name, int iparams, char **params) int i, n, v; int mtype; BOOL retval=False; + BOOL check_notify_msgs = False; mtype = parse_type(msg_name); if (mtype == -1) { @@ -360,9 +367,7 @@ static BOOL do_command(char *dest, char *msg_name, int iparams, char **params) break; /* Send a notification message to a printer */ - /* NB. None of these currently work due to changes in the printing notify mechanisms. */ -#if 0 case MSG_PRINTER_NOTIFY2: { char *cmd; @@ -380,6 +385,8 @@ static BOOL do_command(char *dest, char *msg_name, int iparams, char **params) cmd = params[0]; + check_notify_msgs = True; + /* Pause a print queue */ if (strequal(cmd, "queuepause")) { @@ -421,6 +428,7 @@ static BOOL do_command(char *dest, char *msg_name, int iparams, char **params) notify_job_status_byname( params[1], jobid, JOB_STATUS_PAUSED, SPOOLSS_NOTIFY_MSG_UNIX_JOBID); + break; } /* Resume a print job */ @@ -438,6 +446,7 @@ static BOOL do_command(char *dest, char *msg_name, int iparams, char **params) notify_job_status_byname( params[1], jobid, JOB_STATUS_QUEUED, SPOOLSS_NOTIFY_MSG_UNIX_JOBID); + break; } /* Delete a print job */ @@ -462,9 +471,39 @@ static BOOL do_command(char *dest, char *msg_name, int iparams, char **params) SPOOLSS_NOTIFY_MSG_UNIX_JOBID); } + /* printer change notify */ + + if (strequal(cmd, "printer")) { + int attribute = -1; + + if (!params[1] || !params[2] || !params[3]) { + fprintf(stderr, "printer command requires an and attribute name and value!\n"); + fprintf(stderr, "supported attributes:\n"); + fprintf(stderr, "\tcomment:\n"); + fprintf(stderr, "\tport:\n"); + fprintf(stderr, "\tdriver:\n"); + return False; + } + if ( strequal(params[2], "comment") ) + attribute = PRINTER_NOTIFY_COMMENT; + else if ( strequal(params[2], "port") ) + attribute = PRINTER_NOTIFY_PORT_NAME; + else if ( strequal(params[2], "driver") ) + attribute = PRINTER_NOTIFY_DRIVER_NAME; + + if ( attribute == -1 ) { + fprintf(stderr, "bad attribute!\n"); + return False; + } + + notify_printer_byname( params[1], attribute, params[3]); + + break; + } + break; } -#endif + case MSG_SMB_FORCE_TDIS: if (!strequal(dest, "smbd")) { @@ -563,6 +602,11 @@ static BOOL do_command(char *dest, char *msg_name, int iparams, char **params) break; } + /* check if we have any pending print notify messages */ + + if ( check_notify_msgs ) + print_notify_send_messages(); + return (True); } -- 2.34.1