1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-11 05:18:09 +03:00

[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 f1062e79de)
This commit is contained in:
Gerald Carter 2002-11-26 00:46:31 +00:00
parent 3ab6fcc5c6
commit afc5f1aefb
5 changed files with 191 additions and 286 deletions

View File

@ -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 $@

View File

@ -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_ */

View File

@ -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;
}

View File

@ -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; idx<num_services; idx++ ) {
if (lp_snum_ok(idx) && lp_print_ok(idx) )
print_notify_register_pid(idx);
}
return True;
}
else /* register for a specific printer */
{
printername = lp_const_servicename(snum);
pdb = get_print_db_byname(printername);
if (!pdb)
return False;
tdb = pdb->tdb;
} 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; idx<num_services; idx++ ) {
if ( lp_snum_ok(idx) && lp_print_ok(idx) )
print_notify_deregister_pid(idx);
}
return True;
}
else /* deregister a specific printer */
{
printername = lp_const_servicename(snum);
pdb = get_print_db_byname(printername);
if (!pdb)
return False;
tdb = pdb->tdb;
} 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.
****************************************************************************/

View File

@ -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);
}