Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include "includes.h"
#include "printing.h"
+extern SIG_ATOMIC_T got_sig_term;
+extern SIG_ATOMIC_T reload_after_sighup;
+extern struct current_user current_user;
+extern userdom_struct current_user_info;
+
/* Current printer interface */
-static struct printif *current_printif = &generic_printif;
-static BOOL remove_from_jobs_changed(int snum, uint32 jobid);
+static BOOL remove_from_jobs_changed(const char* sharename, uint32 jobid);
/*
the printing backend revolves around a tdb database that stores the
jobids are assigned when a job starts spooling.
*/
+static TDB_CONTEXT *rap_tdb;
+static uint16 next_rap_jobid;
+struct rap_jobid_key {
+ fstring sharename;
+ uint32 jobid;
+};
+
/***************************************************************************
Nightmare. LANMAN jobid's are 16 bit numbers..... We must map them to 32
bit RPC jobids.... JRA.
***************************************************************************/
-static TDB_CONTEXT *rap_tdb;
-static uint16 next_rap_jobid;
-
-uint16 pjobid_to_rap(int snum, uint32 jobid)
+uint16 pjobid_to_rap(const char* sharename, uint32 jobid)
{
uint16 rap_jobid;
TDB_DATA data, key;
- char jinfo[8];
+ struct rap_jobid_key jinfo;
+ uint8 buf[2];
DEBUG(10,("pjobid_to_rap: called.\n"));
return 0;
}
- SIVAL(&jinfo,0,(int32)snum);
- SIVAL(&jinfo,4,jobid);
-
- key.dptr = (char *)&jinfo;
+ ZERO_STRUCT( jinfo );
+ fstrcpy( jinfo.sharename, sharename );
+ jinfo.jobid = jobid;
+ key.dptr = (uint8 *)&jinfo;
key.dsize = sizeof(jinfo);
+
data = tdb_fetch(rap_tdb, key);
if (data.dptr && data.dsize == sizeof(uint16)) {
- memcpy(&rap_jobid, data.dptr, sizeof(uint16));
+ rap_jobid = SVAL(data.dptr, 0);
SAFE_FREE(data.dptr);
DEBUG(10,("pjobid_to_rap: jobid %u maps to RAP jobid %u\n",
- (unsigned int)jobid,
- (unsigned int)rap_jobid));
+ (unsigned int)jobid, (unsigned int)rap_jobid));
return rap_jobid;
}
SAFE_FREE(data.dptr);
rap_jobid = ++next_rap_jobid;
if (rap_jobid == 0)
rap_jobid = ++next_rap_jobid;
- data.dptr = (char *)&rap_jobid;
+ SSVAL(buf,0,rap_jobid);
+ data.dptr = buf;
data.dsize = sizeof(rap_jobid);
tdb_store(rap_tdb, key, data, TDB_REPLACE);
tdb_store(rap_tdb, data, key, TDB_REPLACE);
DEBUG(10,("pjobid_to_rap: created jobid %u maps to RAP jobid %u\n",
- (unsigned int)jobid,
- (unsigned int)rap_jobid));
+ (unsigned int)jobid, (unsigned int)rap_jobid));
return rap_jobid;
}
-BOOL rap_to_pjobid(uint16 rap_jobid, int *psnum, uint32 *pjobid)
+BOOL rap_to_pjobid(uint16 rap_jobid, fstring sharename, uint32 *pjobid)
{
TDB_DATA data, key;
+ uint8 buf[2];
DEBUG(10,("rap_to_pjobid called.\n"));
if (!rap_tdb)
return False;
- key.dptr = (char *)&rap_jobid;
+ SSVAL(buf,0,rap_jobid);
+ key.dptr = buf;
key.dsize = sizeof(rap_jobid);
data = tdb_fetch(rap_tdb, key);
- if (data.dptr && data.dsize == 8) {
- *psnum = IVAL(data.dptr,0);
- *pjobid = IVAL(data.dptr,4);
+ if ( data.dptr && data.dsize == sizeof(struct rap_jobid_key) )
+ {
+ struct rap_jobid_key *jinfo = (struct rap_jobid_key*)data.dptr;
+ fstrcpy( sharename, jinfo->sharename );
+ *pjobid = jinfo->jobid;
DEBUG(10,("rap_to_pjobid: jobid %u maps to RAP jobid %u\n",
- (unsigned int)*pjobid,
- (unsigned int)rap_jobid));
+ (unsigned int)*pjobid, (unsigned int)rap_jobid));
SAFE_FREE(data.dptr);
return True;
}
DEBUG(10,("rap_to_pjobid: Failed to lookup RAP jobid %u\n",
- (unsigned int)rap_jobid));
+ (unsigned int)rap_jobid));
SAFE_FREE(data.dptr);
return False;
}
-static void rap_jobid_delete(int snum, uint32 jobid)
+static void rap_jobid_delete(const char* sharename, uint32 jobid)
{
TDB_DATA key, data;
uint16 rap_jobid;
- char jinfo[8];
+ struct rap_jobid_key jinfo;
+ uint8 buf[2];
DEBUG(10,("rap_jobid_delete: called.\n"));
if (!rap_tdb)
return;
- SIVAL(&jinfo,0,(int32)snum);
- SIVAL(&jinfo,4,jobid);
-
- key.dptr = (char *)&jinfo;
+ ZERO_STRUCT( jinfo );
+ fstrcpy( jinfo.sharename, sharename );
+ jinfo.jobid = jobid;
+ key.dptr = (uint8 *)&jinfo;
key.dsize = sizeof(jinfo);
+
data = tdb_fetch(rap_tdb, key);
if (!data.dptr || (data.dsize != sizeof(uint16))) {
DEBUG(10,("rap_jobid_delete: cannot find jobid %u\n",
- (unsigned int)jobid ));
+ (unsigned int)jobid ));
SAFE_FREE(data.dptr);
return;
}
DEBUG(10,("rap_jobid_delete: deleting jobid %u\n",
- (unsigned int)jobid ));
+ (unsigned int)jobid ));
- memcpy(&rap_jobid, data.dptr, sizeof(uint16));
+ rap_jobid = SVAL(data.dptr, 0);
SAFE_FREE(data.dptr);
- data.dptr = (char *)&rap_jobid;
+ SSVAL(buf,0,rap_jobid);
+ data.dptr = buf;
data.dsize = sizeof(rap_jobid);
tdb_delete(rap_tdb, key);
tdb_delete(rap_tdb, data);
}
-static pid_t local_pid;
-
-static int get_queue_status(int, print_status_struct *);
+static int get_queue_status(const char* sharename, print_status_struct *);
/****************************************************************************
Initialise the printing backend. Called once at startup before the fork().
****************************************************************************/
-BOOL print_backend_init(void)
+BOOL print_backend_init(struct messaging_context *msg_ctx)
{
const char *sversion = "INFO/version";
pstring printing_path;
int services = lp_numservices();
int snum;
- if (local_pid == sys_getpid())
- return True;
-
unlink(lock_path("printing.tdb"));
pstrcpy(printing_path,lock_path("printing"));
mkdir(printing_path,0755);
- local_pid = sys_getpid();
-
/* handle a Samba upgrade */
for (snum = 0; snum < services; snum++) {
pdb = get_print_db_byname(lp_const_servicename(snum));
if (!pdb)
continue;
- if (tdb_lock_bystring(pdb->tdb, sversion, 0) == -1) {
+ if (tdb_lock_bystring(pdb->tdb, sversion) == -1) {
DEBUG(0,("print_backend_init: Failed to open printer %s database\n", lp_const_servicename(snum) ));
release_print_db(pdb);
return False;
close_all_print_db(); /* Don't leave any open. */
- /* select the appropriate printing interface... */
-#ifdef HAVE_CUPS
- if (strcmp(lp_printcapname(), "cups") == 0)
- current_printif = &cups_printif;
-#endif /* HAVE_CUPS */
-
/* do NT print initialization... */
- return nt_printing_init();
+ return nt_printing_init(msg_ctx);
}
/****************************************************************************
close_all_print_db(); /* Don't leave any open. */
}
+/****************************************************************************
+ Retrieve the set of printing functions for a given service. This allows
+ us to set the printer function table based on the value of the 'printing'
+ service parameter.
+
+ Use the generic interface as the default and only use cups interface only
+ when asked for (and only when supported)
+****************************************************************************/
+
+static struct printif *get_printer_fns_from_type( enum printing_types type )
+{
+ struct printif *printer_fns = &generic_printif;
+
+#ifdef HAVE_CUPS
+ if ( type == PRINT_CUPS ) {
+ printer_fns = &cups_printif;
+ }
+#endif /* HAVE_CUPS */
+
+#ifdef HAVE_IPRINT
+ if ( type == PRINT_IPRINT ) {
+ printer_fns = &iprint_printif;
+ }
+#endif /* HAVE_IPRINT */
+
+ printer_fns->type = type;
+
+ return printer_fns;
+}
+
+static struct printif *get_printer_fns( int snum )
+{
+ return get_printer_fns_from_type( (enum printing_types)lp_printing(snum) );
+}
+
+
/****************************************************************************
Useful function to generate a tdb key.
****************************************************************************/
static uint32 j;
TDB_DATA ret;
- j = jobid;
- ret.dptr = (void *)&j;
+ SIVAL(&j, 0, jobid);
+ ret.dptr = (uint8 *)&j;
ret.dsize = sizeof(j);
return ret;
}
unpack a pjob from a tdb buffer
***********************************************************************/
-int unpack_pjob( char* buf, int buflen, struct printjob *pjob )
+int unpack_pjob( uint8 *buf, int buflen, struct printjob *pjob )
{
int len = 0;
int used;
Useful function to find a print job in the database.
****************************************************************************/
-static struct printjob *print_job_find(int snum, uint32 jobid)
+static struct printjob *print_job_find(const char *sharename, uint32 jobid)
{
static struct printjob pjob;
TDB_DATA ret;
- struct tdb_print_db *pdb = get_print_db_byname(lp_const_servicename(snum));
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
+ DEBUG(10,("print_job_find: looking up job %u for share %s\n",
+ (unsigned int)jobid, sharename ));
- if (!pdb)
+ if (!pdb) {
return NULL;
+ }
ret = tdb_fetch(pdb->tdb, print_key(jobid));
release_print_db(pdb);
- if (!ret.dptr)
+ if (!ret.dptr) {
+ DEBUG(10,("print_job_find: failed to find jobid %u.\n", (unsigned int)jobid ));
return NULL;
+ }
- if ( pjob.nt_devmode )
+ if ( pjob.nt_devmode ) {
free_nt_devicemode( &pjob.nt_devmode );
+ }
ZERO_STRUCT( pjob );
if ( unpack_pjob( ret.dptr, ret.dsize, &pjob ) == -1 ) {
+ DEBUG(10,("print_job_find: failed to unpack jobid %u.\n", (unsigned int)jobid ));
SAFE_FREE(ret.dptr);
return NULL;
}
- SAFE_FREE(ret.dptr);
+ SAFE_FREE(ret.dptr);
+
+ DEBUG(10,("print_job_find: returning system job %d for jobid %u.\n",
+ (int)pjob.sysjob, (unsigned int)jobid ));
+
return &pjob;
}
return 0;
if (*sysjob == pjob->sysjob) {
- uint32 *jobid = (uint32 *)key.dptr;
+ uint32 jobid = IVAL(key.dptr,0);
- sysjob_to_jobid_value = *jobid;
+ sysjob_to_jobid_value = jobid;
return 1;
}
if (!lp_print_ok(snum))
continue;
pdb = get_print_db_byname(lp_const_servicename(snum));
- if (pdb)
- tdb_traverse(pdb->tdb, unixjob_traverse_fn, &unix_jobid);
+ if (!pdb) {
+ continue;
+ }
+ tdb_traverse(pdb->tdb, unixjob_traverse_fn, &unix_jobid);
release_print_db(pdb);
if (sysjob_to_jobid_value != (uint32)-1)
return sysjob_to_jobid_value;
return 0;
}
-static void pjob_store_notify(int snum, uint32 jobid, struct printjob *old_data,
+static void pjob_store_notify(const char* sharename, uint32 jobid, struct printjob *old_data,
struct printjob *new_data)
{
BOOL new_job = False;
if (!old_data)
new_job = True;
- /* Notify the job name first */
-
- if (new_job || !strequal(old_data->jobname, new_data->jobname))
- notify_job_name(snum, jobid, new_data->jobname);
-
/* Job attributes that can't be changed. We only send
notification for these on a new job. */
+ /* ACHTUNG! Due to a bug in Samba's spoolss parsing of the
+ NOTIFY_INFO_DATA buffer, we *have* to send the job submission
+ time first or else we'll end up with potential alignment
+ errors. I don't think the systemtime should be spooled as
+ a string, but this gets us around that error.
+ --jerry (i'll feel dirty for this) */
+
if (new_job) {
- notify_job_submitted(snum, jobid, new_data->starttime);
- notify_job_username(snum, jobid, new_data->user);
+ notify_job_submitted(sharename, jobid, new_data->starttime);
+ notify_job_username(sharename, jobid, new_data->user);
}
+ if (new_job || !strequal(old_data->jobname, new_data->jobname))
+ notify_job_name(sharename, jobid, new_data->jobname);
+
/* Job attributes of a new job or attributes that can be
modified. */
+ if (new_job || !strequal(old_data->jobname, new_data->jobname))
+ notify_job_name(sharename, jobid, new_data->jobname);
+
if (new_job || old_data->status != new_data->status)
- notify_job_status(snum, jobid, map_to_spoolss_status(new_data->status));
+ notify_job_status(sharename, jobid, map_to_spoolss_status(new_data->status));
if (new_job || old_data->size != new_data->size)
- notify_job_total_bytes(snum, jobid, new_data->size);
+ notify_job_total_bytes(sharename, jobid, new_data->size);
if (new_job || old_data->page_count != new_data->page_count)
- notify_job_total_pages(snum, jobid, new_data->page_count);
+ notify_job_total_pages(sharename, jobid, new_data->page_count);
}
/****************************************************************************
Store a job structure back to the database.
****************************************************************************/
-static BOOL pjob_store(int snum, uint32 jobid, struct printjob *pjob)
+static BOOL pjob_store(const char* sharename, uint32 jobid, struct printjob *pjob)
{
TDB_DATA old_data, new_data;
BOOL ret = False;
- struct tdb_print_db *pdb = get_print_db_byname(lp_const_servicename(snum));
- char *buf = NULL;
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
+ uint8 *buf = NULL;
int len, newlen, buflen;
len += pack_devicemode(pjob->nt_devmode, buf+len, buflen-len);
if (buflen != len) {
- char *tb;
-
- tb = (char *)Realloc(buf, len);
- if (!tb) {
+ buf = (uint8 *)SMB_REALLOC(buf, len);
+ if (!buf) {
DEBUG(0,("pjob_store: failed to enlarge buffer!\n"));
goto done;
}
- else
- buf = tb;
newlen = len;
}
} while ( buflen != len );
/* Send notify updates for what has changed */
- if ( ret && (old_data.dsize == 0 || old_data.dsize == sizeof(*pjob)) )
- pjob_store_notify( snum, jobid, (struct printjob *)old_data.dptr, pjob );
+ if ( ret ) {
+ struct printjob old_pjob;
+
+ if ( old_data.dsize )
+ {
+ if ( unpack_pjob( old_data.dptr, old_data.dsize, &old_pjob ) != -1 )
+ {
+ pjob_store_notify( sharename, jobid, &old_pjob , pjob );
+ free_nt_devicemode( &old_pjob.nt_devmode );
+ }
+ }
+ else {
+ /* new job */
+ pjob_store_notify( sharename, jobid, NULL, pjob );
+ }
+ }
done:
SAFE_FREE( old_data.dptr );
Remove a job structure from the database.
****************************************************************************/
-void pjob_delete(int snum, uint32 jobid)
+void pjob_delete(const char* sharename, uint32 jobid)
{
- struct printjob *pjob = print_job_find(snum, jobid);
+ struct printjob *pjob;
uint32 job_status = 0;
- struct tdb_print_db *pdb = get_print_db_byname(lp_const_servicename(snum));
+ struct tdb_print_db *pdb;
+
+ pdb = get_print_db_byname( sharename );
if (!pdb)
return;
+ pjob = print_job_find( sharename, jobid );
+
if (!pjob) {
- DEBUG(5, ("pjob_delete(): we were asked to delete nonexistent job %u\n",
+ DEBUG(5, ("pjob_delete: we were asked to delete nonexistent job %u\n",
(unsigned int)jobid));
release_print_db(pdb);
return;
}
- /* Send a notification that a job has been deleted */
-
- job_status = map_to_spoolss_status(pjob->status);
-
/* We must cycle through JOB_STATUS_DELETING and
JOB_STATUS_DELETED for the port monitor to delete the job
properly. */
- job_status |= JOB_STATUS_DELETING;
- notify_job_status(snum, jobid, job_status);
+ job_status = JOB_STATUS_DELETING|JOB_STATUS_DELETED;
+ notify_job_status(sharename, jobid, job_status);
- job_status |= JOB_STATUS_DELETED;
- notify_job_status(snum, jobid, job_status);
-
/* Remove from printing.tdb */
tdb_delete(pdb->tdb, print_key(jobid));
- release_print_db(pdb);
- rap_jobid_delete(snum, jobid);
+ remove_from_jobs_changed(sharename, jobid);
+ release_print_db( pdb );
+ rap_jobid_delete(sharename, jobid);
}
/****************************************************************************
List a unix job in the print database.
****************************************************************************/
-static void print_unix_job(int snum, print_queue_struct *q, uint32 jobid)
+static void print_unix_job(const char *sharename, print_queue_struct *q, uint32 jobid)
{
struct printjob pj, *old_pj;
- if (jobid == (uint32)-1)
+ if (jobid == (uint32)-1)
jobid = q->job + UNIX_JOB_START;
/* Preserve the timestamp on an existing unix print job */
- old_pj = print_job_find(snum, jobid);
+ old_pj = print_job_find(sharename, jobid);
ZERO_STRUCT(pj);
pj.status = q->status;
pj.size = q->size;
pj.spooled = True;
- pj.smbjob = (old_pj != NULL ? True : False);
fstrcpy(pj.filename, old_pj ? old_pj->filename : "");
- if (jobid < UNIX_JOB_START)
+ if (jobid < UNIX_JOB_START) {
+ pj.smbjob = True;
fstrcpy(pj.jobname, old_pj ? old_pj->jobname : "Remote Downlevel Document");
- else
+ } else {
+ pj.smbjob = False;
fstrcpy(pj.jobname, old_pj ? old_pj->jobname : q->fs_file);
+ }
fstrcpy(pj.user, old_pj ? old_pj->user : q->fs_user);
- fstrcpy(pj.queuename, old_pj ? old_pj->queuename : lp_const_servicename(snum));
+ fstrcpy(pj.queuename, old_pj ? old_pj->queuename : sharename );
- pjob_store(snum, jobid, &pj);
+ pjob_store(sharename, jobid, &pj);
}
struct traverse_struct {
print_queue_struct *queue;
int qcount, snum, maxcount, total_jobs;
+ const char *sharename;
time_t lpq_time;
+ const char *lprm_command;
+ struct printif *print_if;
};
/****************************************************************************
struct traverse_struct *ts = (struct traverse_struct *)state;
struct printjob pjob;
uint32 jobid;
- int i;
+ int i = 0;
if ( key.dsize != sizeof(jobid) )
return 0;
- memcpy(&jobid, key.dptr, sizeof(jobid));
+ jobid = IVAL(key.dptr, 0);
if ( unpack_pjob( data.dptr, data.dsize, &pjob ) == -1 )
return 0;
free_nt_devicemode( &pjob.nt_devmode );
- if (ts->snum != lp_servicenumber(pjob.queuename)) {
- /* this isn't for the queue we are looking at - this cannot happen with the split tdb's. JRA */
- return 0;
- }
-
if (!pjob.smbjob) {
/* remove a unix job if it isn't in the system queue any more */
if (i == ts->qcount) {
DEBUG(10,("traverse_fn_delete: pjob %u deleted due to !smbjob\n",
(unsigned int)jobid ));
- pjob_delete(ts->snum, jobid);
- } else
- ts->total_jobs++;
- return 0;
+ pjob_delete(ts->sharename, jobid);
+ return 0;
+ }
+
+ /* need to continue the the bottom of the function to
+ save the correct attributes */
}
/* maybe it hasn't been spooled yet */
/* if a job is not spooled and the process doesn't
exist then kill it. This cleans up after smbd
deaths */
- if (!process_exists(pjob.pid)) {
+ if (!process_exists_by_pid(pjob.pid)) {
DEBUG(10,("traverse_fn_delete: pjob %u deleted due to !process_exists (%u)\n",
(unsigned int)jobid, (unsigned int)pjob.pid ));
- pjob_delete(ts->snum, jobid);
+ pjob_delete(ts->sharename, jobid);
} else
ts->total_jobs++;
return 0;
}
- for (i=0;i<ts->qcount;i++) {
- uint32 curr_jobid = print_parse_jobid(ts->queue[i].fs_file);
- if (jobid == curr_jobid)
- break;
+ /* this check only makes sense for jobs submitted from Windows clients */
+
+ if ( pjob.smbjob ) {
+ for (i=0;i<ts->qcount;i++) {
+ uint32 curr_jobid;
+
+ if ( pjob.status == LPQ_DELETED )
+ continue;
+
+ curr_jobid = print_parse_jobid(ts->queue[i].fs_file);
+
+ if (jobid == curr_jobid) {
+
+ /* try to clean up any jobs that need to be deleted */
+
+ if ( pjob.status == LPQ_DELETING ) {
+ int result;
+
+ result = (*(ts->print_if->job_delete))(
+ ts->sharename, ts->lprm_command, &pjob );
+
+ if ( result != 0 ) {
+ /* if we can't delete, then reset the job status */
+ pjob.status = LPQ_QUEUED;
+ pjob_store(ts->sharename, jobid, &pjob);
+ }
+ else {
+ /* if we deleted the job, the remove the tdb record */
+ pjob_delete(ts->sharename, jobid);
+ pjob.status = LPQ_DELETED;
+ }
+
+ }
+
+ break;
+ }
+ }
}
/* The job isn't in the system queue - we have to assume it has
(unsigned int)jobid,
(unsigned int)pjob.starttime,
(unsigned int)ts->lpq_time ));
- pjob_delete(ts->snum, jobid);
+ pjob_delete(ts->sharename, jobid);
} else
ts->total_jobs++;
return 0;
}
- /* Save the pjob attributes we will store. */
- ts->queue[i].job = jobid;
+ /* Save the pjob attributes we will store.
+ FIXME!!! This is the only place where queue->job
+ represents the SMB jobid --jerry */
+
+ ts->queue[i].job = jobid;
ts->queue[i].size = pjob.size;
ts->queue[i].page_count = pjob.page_count;
ts->queue[i].status = pjob.status;
Check if the print queue has been updated recently enough.
****************************************************************************/
-static void print_cache_flush(int snum)
+static void print_cache_flush(const char *sharename)
{
fstring key;
- const char *printername = lp_const_servicename(snum);
- struct tdb_print_db *pdb = get_print_db_byname(printername);
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
if (!pdb)
return;
- slprintf(key, sizeof(key)-1, "CACHE/%s", printername);
+ slprintf(key, sizeof(key)-1, "CACHE/%s", sharename);
tdb_store_int32(pdb->tdb, key, -1);
release_print_db(pdb);
}
Check if someone already thinks they are doing the update.
****************************************************************************/
-static pid_t get_updating_pid(fstring printer_name)
+static pid_t get_updating_pid(const char *sharename)
{
fstring keystr;
TDB_DATA data, key;
pid_t updating_pid;
- struct tdb_print_db *pdb = get_print_db_byname(printer_name);
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
if (!pdb)
return (pid_t)-1;
- slprintf(keystr, sizeof(keystr)-1, "UPDATING/%s", printer_name);
- key.dptr = keystr;
- key.dsize = strlen(keystr);
+ slprintf(keystr, sizeof(keystr)-1, "UPDATING/%s", sharename);
+ key = string_tdb_data(keystr);
data = tdb_fetch(pdb->tdb, key);
release_print_db(pdb);
return (pid_t)-1;
}
- memcpy(&updating_pid, data.dptr, sizeof(pid_t));
+ updating_pid = IVAL(data.dptr, 0);
SAFE_FREE(data.dptr);
- if (process_exists(updating_pid))
+ if (process_exists_by_pid(updating_pid))
return updating_pid;
return (pid_t)-1;
in the tdb.
****************************************************************************/
-static void set_updating_pid(const fstring printer_name, BOOL delete)
+static void set_updating_pid(const fstring sharename, BOOL updating)
{
fstring keystr;
TDB_DATA key;
TDB_DATA data;
pid_t updating_pid = sys_getpid();
- struct tdb_print_db *pdb = get_print_db_byname(printer_name);
+ uint8 buffer[4];
+
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
if (!pdb)
return;
- slprintf(keystr, sizeof(keystr)-1, "UPDATING/%s", printer_name);
- key.dptr = keystr;
- key.dsize = strlen(keystr);
+ slprintf(keystr, sizeof(keystr)-1, "UPDATING/%s", sharename);
+ key = string_tdb_data(keystr);
+
+ DEBUG(5, ("set_updating_pid: %s updating lpq cache for print share %s\n",
+ updating ? "" : "not ",
+ sharename ));
- if (delete) {
+ if ( !updating ) {
tdb_delete(pdb->tdb, key);
release_print_db(pdb);
return;
}
- data.dptr = (void *)&updating_pid;
- data.dsize = sizeof(pid_t);
+ SIVAL( buffer, 0, updating_pid);
+ data.dptr = buffer;
+ data.dsize = 4; /* we always assume this is a 4 byte value */
tdb_store(pdb->tdb, key, data, TDB_REPLACE);
release_print_db(pdb);
/****************************************************************************
Store the sorted queue representation for later portmon retrieval.
+ Skip deleted jobs
****************************************************************************/
static void store_queue_struct(struct tdb_print_db *pdb, struct traverse_struct *pts)
{
- TDB_DATA data, key;
+ TDB_DATA data;
int max_reported_jobs = lp_max_reported_jobs(pts->snum);
print_queue_struct *queue = pts->queue;
size_t len;
size_t i;
uint qcount;
- if (max_reported_jobs < pts->qcount)
+ if (max_reported_jobs && (max_reported_jobs < pts->qcount))
pts->qcount = max_reported_jobs;
- qcount = pts->qcount;
+ qcount = 0;
/* Work out the size. */
data.dsize = 0;
data.dsize += tdb_pack(NULL, 0, "d", qcount);
for (i = 0; i < pts->qcount; i++) {
+ if ( queue[i].status == LPQ_DELETED )
+ continue;
+
+ qcount++;
data.dsize += tdb_pack(NULL, 0, "ddddddff",
(uint32)queue[i].job,
(uint32)queue[i].size,
queue[i].fs_file);
}
- if ((data.dptr = malloc(data.dsize)) == NULL)
+ if ((data.dptr = (uint8 *)SMB_MALLOC(data.dsize)) == NULL)
return;
len = 0;
len += tdb_pack(data.dptr + len, data.dsize - len, "d", qcount);
for (i = 0; i < pts->qcount; i++) {
+ if ( queue[i].status == LPQ_DELETED )
+ continue;
+
len += tdb_pack(data.dptr + len, data.dsize - len, "ddddddff",
(uint32)queue[i].job,
(uint32)queue[i].size,
queue[i].fs_file);
}
- key.dptr = "INFO/linear_queue_array";
- key.dsize = strlen(key.dptr);
- tdb_store(pdb->tdb, key, data, TDB_REPLACE);
+ tdb_store(pdb->tdb, string_tdb_data("INFO/linear_queue_array"), data,
+ TDB_REPLACE);
SAFE_FREE(data.dptr);
return;
}
static TDB_DATA get_jobs_changed_data(struct tdb_print_db *pdb)
{
- TDB_DATA data, key;
+ TDB_DATA data;
- key.dptr = "INFO/jobs_changed";
- key.dsize = strlen(key.dptr);
ZERO_STRUCT(data);
- data = tdb_fetch(pdb->tdb, key);
+ data = tdb_fetch(pdb->tdb, string_tdb_data("INFO/jobs_changed"));
if (data.dptr == NULL || data.dsize == 0 || (data.dsize % 4 != 0)) {
SAFE_FREE(data.dptr);
ZERO_STRUCT(data);
return data;
}
-static void check_job_changed(int snum, TDB_DATA data, uint32 jobid)
+static void check_job_changed(const char *sharename, TDB_DATA data, uint32 jobid)
{
unsigned int i;
unsigned int job_count = data.dsize / 4;
for (i = 0; i < job_count; i++) {
uint32 ch_jobid;
- memcpy(&ch_jobid, data.dptr + (i*4), 4);
+ ch_jobid = IVAL(data.dptr, i*4);
if (ch_jobid == jobid)
- remove_from_jobs_changed(snum, jobid);
+ remove_from_jobs_changed(sharename, jobid);
}
}
/****************************************************************************
- Update the internal database from the system print queue for a queue.
+ Check if the print queue has been updated recently enough.
****************************************************************************/
-static void print_queue_update(int snum)
+static BOOL print_cache_expired(const char *sharename, BOOL check_pending)
{
- int i, qcount;
- print_queue_struct *queue = NULL;
- print_status_struct status;
- print_status_struct old_status;
- struct printjob *pjob;
- struct traverse_struct tstruct;
- fstring keystr, printer_name, cachestr;
- TDB_DATA data, key;
- TDB_DATA jcdata;
- struct tdb_print_db *pdb;
+ fstring key;
+ time_t last_qscan_time, time_now = time(NULL);
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
+ BOOL result = False;
- fstrcpy(printer_name, lp_const_servicename(snum));
- pdb = get_print_db_byname(printer_name);
if (!pdb)
- return;
+ return False;
+
+ snprintf(key, sizeof(key), "CACHE/%s", sharename);
+ last_qscan_time = (time_t)tdb_fetch_int32(pdb->tdb, key);
/*
- * Check to see if someone else is doing this update.
- * This is essentially a mutex on the update.
+ * Invalidate the queue for 3 reasons.
+ * (1). last queue scan time == -1.
+ * (2). Current time - last queue scan time > allowed cache time.
+ * (3). last queue scan time > current time + MAX_CACHE_VALID_TIME (1 hour by default).
+ * This last test picks up machines for which the clock has been moved
+ * forward, an lpq scan done and then the clock moved back. Otherwise
+ * that last lpq scan would stay around for a loooong loooong time... :-). JRA.
*/
- if (get_updating_pid(printer_name) != -1) {
- release_print_db(pdb);
- return;
+ if (last_qscan_time == ((time_t)-1)
+ || (time_now - last_qscan_time) >= lp_lpqcachetime()
+ || last_qscan_time > (time_now + MAX_CACHE_VALID_TIME))
+ {
+ uint32 u;
+ time_t msg_pending_time;
+
+ DEBUG(4, ("print_cache_expired: cache expired for queue %s "
+ "(last_qscan_time = %d, time now = %d, qcachetime = %d)\n",
+ sharename, (int)last_qscan_time, (int)time_now,
+ (int)lp_lpqcachetime() ));
+
+ /* check if another smbd has already sent a message to update the
+ queue. Give the pending message one minute to clear and
+ then send another message anyways. Make sure to check for
+ clocks that have been run forward and then back again. */
+
+ snprintf(key, sizeof(key), "MSG_PENDING/%s", sharename);
+
+ if ( check_pending
+ && tdb_fetch_uint32( pdb->tdb, key, &u )
+ && (msg_pending_time=u) > 0
+ && msg_pending_time <= time_now
+ && (time_now - msg_pending_time) < 60 )
+ {
+ DEBUG(4,("print_cache_expired: message already pending for %s. Accepting cache\n",
+ sharename));
+ goto done;
+ }
+
+ result = True;
}
- /* Lock the queue for the database update */
+done:
+ release_print_db(pdb);
+ return result;
+}
- slprintf(keystr, sizeof(keystr) - 1, "LOCK/%s", printer_name);
- /* Only wait 10 seconds for this. */
- if (tdb_lock_bystring(pdb->tdb, keystr, 10) == -1) {
- DEBUG(0,("print_queue_update: Failed to lock printer %s database\n", printer_name));
- release_print_db(pdb);
- return;
- }
+/****************************************************************************
+ main work for updating the lpq cahe for a printer queue
+****************************************************************************/
- /*
- * Ensure that no one else got in here.
- * If the updating pid is still -1 then we are
- * the winner.
- */
+static void print_queue_update_internal( const char *sharename,
+ struct printif *current_printif,
+ char *lpq_command, char *lprm_command )
+{
+ int i, qcount;
+ print_queue_struct *queue = NULL;
+ print_status_struct status;
+ print_status_struct old_status;
+ struct printjob *pjob;
+ struct traverse_struct tstruct;
+ TDB_DATA data, key;
+ TDB_DATA jcdata;
+ fstring keystr, cachestr;
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
- if (get_updating_pid(printer_name) != -1) {
- /*
- * Someone else is doing the update, exit.
- */
- tdb_unlock_bystring(pdb->tdb, keystr);
- release_print_db(pdb);
+ if (!pdb) {
return;
}
-
- /*
- * We're going to do the update ourselves.
- */
-
- /* Tell others we're doing the update. */
- set_updating_pid(printer_name, False);
-
- /*
- * Allow others to enter and notice we're doing
- * the update.
- */
-
- tdb_unlock_bystring(pdb->tdb, keystr);
+
+ DEBUG(5,("print_queue_update_internal: printer = %s, type = %d, lpq command = [%s]\n",
+ sharename, current_printif->type, lpq_command));
/*
* Update the cache time FIRST ! Stops others even
* attempting to get the lock and doing this
* if the lpq takes a long time.
*/
-
- slprintf(cachestr, sizeof(cachestr)-1, "CACHE/%s", printer_name);
+
+ slprintf(cachestr, sizeof(cachestr)-1, "CACHE/%s", sharename);
tdb_store_int32(pdb->tdb, cachestr, (int)time(NULL));
/* get the current queue using the appropriate interface */
ZERO_STRUCT(status);
- qcount = (*(current_printif->queue_get))(snum, &queue, &status);
+ qcount = (*(current_printif->queue_get))(sharename,
+ current_printif->type,
+ lpq_command, &queue, &status);
- DEBUG(3, ("%d job%s in queue for %s\n", qcount, (qcount != 1) ?
- "s" : "", printer_name));
+ DEBUG(3, ("print_queue_update_internal: %d job%s in queue for %s\n",
+ qcount, (qcount != 1) ? "s" : "", sharename));
/* Sort the queue by submission time otherwise they are displayed
in hash order. */
qsort(queue, qcount, sizeof(print_queue_struct),
- QSORT_CAST(printjob_comp));
+ QSORT_CAST(printjob_comp));
/*
any job in the internal database that is marked as spooled
if (jobid == (uint32)-1) {
/* assume its a unix print job */
- print_unix_job(snum, &queue[i], jobid);
+ print_unix_job(sharename, &queue[i], jobid);
continue;
}
/* we have an active SMB print job - update its status */
- pjob = print_job_find(snum, jobid);
+ pjob = print_job_find(sharename, jobid);
if (!pjob) {
/* err, somethings wrong. Probably smbd was restarted
with jobs in the queue. All we can do is treat them
like unix jobs. Pity. */
- print_unix_job(snum, &queue[i], jobid);
+ print_unix_job(sharename, &queue[i], jobid);
continue;
}
pjob->sysjob = queue[i].job;
- pjob->status = queue[i].status;
- pjob_store(snum, jobid, pjob);
- check_job_changed(snum, jcdata, jobid);
+
+ /* don't reset the status on jobs to be deleted */
+
+ if ( pjob->status != LPQ_DELETING )
+ pjob->status = queue[i].status;
+
+ pjob_store(sharename, jobid, pjob);
+
+ check_job_changed(sharename, jcdata, jobid);
}
SAFE_FREE(jcdata.dptr);
system queue */
tstruct.queue = queue;
tstruct.qcount = qcount;
- tstruct.snum = snum;
+ tstruct.snum = -1;
tstruct.total_jobs = 0;
tstruct.lpq_time = time(NULL);
+ tstruct.sharename = sharename;
+ tstruct.lprm_command = lprm_command;
+ tstruct.print_if = current_printif;
tdb_traverse(pdb->tdb, traverse_fn_delete, (void *)&tstruct);
SAFE_FREE(tstruct.queue);
- DEBUG(10,("print_queue_update: printer %s INFO/total_jobs = %d\n",
- printer_name, tstruct.total_jobs ));
+ DEBUG(10,("print_queue_update_internal: printer %s INFO/total_jobs = %d\n",
+ sharename, tstruct.total_jobs ));
tdb_store_int32(pdb->tdb, "INFO/total_jobs", tstruct.total_jobs);
- get_queue_status(snum, &old_status);
+ get_queue_status(sharename, &old_status);
if (old_status.qcount != qcount)
- DEBUG(10,("print_queue_update: queue status change %d jobs -> %d jobs for printer %s\n",
- old_status.qcount, qcount, printer_name ));
+ DEBUG(10,("print_queue_update_internal: queue status change %d jobs -> %d jobs for printer %s\n",
+ old_status.qcount, qcount, sharename));
/* store the new queue status structure */
- slprintf(keystr, sizeof(keystr)-1, "STATUS/%s", printer_name);
- key.dptr = keystr;
- key.dsize = strlen(keystr);
+ slprintf(keystr, sizeof(keystr)-1, "STATUS/%s", sharename);
+ key = string_tdb_data(keystr);
status.qcount = qcount;
- data.dptr = (void *)&status;
+ data.dptr = (uint8 *)&status;
data.dsize = sizeof(status);
tdb_store(pdb->tdb, key, data, TDB_REPLACE);
* as little as possible...
*/
- slprintf(keystr, sizeof(keystr)-1, "CACHE/%s", printer_name);
+ slprintf(keystr, sizeof(keystr)-1, "CACHE/%s", sharename);
tdb_store_int32(pdb->tdb, keystr, (int32)time(NULL));
+ /* clear the msg pending record for this queue */
+
+ snprintf(keystr, sizeof(keystr), "MSG_PENDING/%s", sharename);
+
+ if ( !tdb_store_uint32( pdb->tdb, keystr, 0 ) ) {
+ /* log a message but continue on */
+
+ DEBUG(0,("print_queue_update: failed to store MSG_PENDING flag for [%s]!\n",
+ sharename));
+ }
+
+ release_print_db( pdb );
+
+ return;
+}
+
+/****************************************************************************
+ Update the internal database from the system print queue for a queue.
+ obtain a lock on the print queue before proceeding (needed when mutiple
+ smbd processes maytry to update the lpq cache concurrently).
+****************************************************************************/
+
+static void print_queue_update_with_lock( const char *sharename,
+ struct printif *current_printif,
+ char *lpq_command, char *lprm_command )
+{
+ fstring keystr;
+ struct tdb_print_db *pdb;
+
+ DEBUG(5,("print_queue_update_with_lock: printer share = %s\n", sharename));
+ pdb = get_print_db_byname(sharename);
+ if (!pdb)
+ return;
+
+ if ( !print_cache_expired(sharename, False) ) {
+ DEBUG(5,("print_queue_update_with_lock: print cache for %s is still ok\n", sharename));
+ release_print_db(pdb);
+ return;
+ }
+
+ /*
+ * Check to see if someone else is doing this update.
+ * This is essentially a mutex on the update.
+ */
+
+ if (get_updating_pid(sharename) != -1) {
+ release_print_db(pdb);
+ return;
+ }
+
+ /* Lock the queue for the database update */
+
+ slprintf(keystr, sizeof(keystr) - 1, "LOCK/%s", sharename);
+ /* Only wait 10 seconds for this. */
+ if (tdb_lock_bystring_with_timeout(pdb->tdb, keystr, 10) == -1) {
+ DEBUG(0,("print_queue_update_with_lock: Failed to lock printer %s database\n", sharename));
+ release_print_db(pdb);
+ return;
+ }
+
+ /*
+ * Ensure that no one else got in here.
+ * If the updating pid is still -1 then we are
+ * the winner.
+ */
+
+ if (get_updating_pid(sharename) != -1) {
+ /*
+ * Someone else is doing the update, exit.
+ */
+ tdb_unlock_bystring(pdb->tdb, keystr);
+ release_print_db(pdb);
+ return;
+ }
+
+ /*
+ * We're going to do the update ourselves.
+ */
+
+ /* Tell others we're doing the update. */
+ set_updating_pid(sharename, True);
+
+ /*
+ * Allow others to enter and notice we're doing
+ * the update.
+ */
+
+ tdb_unlock_bystring(pdb->tdb, keystr);
+
+ /* do the main work now */
+
+ print_queue_update_internal( sharename, current_printif,
+ lpq_command, lprm_command );
+
/* Delete our pid from the db. */
- set_updating_pid(printer_name, True);
+ set_updating_pid(sharename, False);
release_print_db(pdb);
}
+/****************************************************************************
+this is the receive function of the background lpq updater
+****************************************************************************/
+static void print_queue_receive(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ fstring sharename;
+ pstring lpqcommand, lprmcommand;
+ int printing_type;
+ size_t len;
+
+ len = tdb_unpack( (uint8 *)data->data, data->length, "fdPP",
+ sharename,
+ &printing_type,
+ lpqcommand,
+ lprmcommand );
+
+ if ( len == -1 ) {
+ DEBUG(0,("print_queue_receive: Got invalid print queue update message\n"));
+ return;
+ }
+
+ print_queue_update_with_lock(sharename,
+ get_printer_fns_from_type((enum printing_types)printing_type),
+ lpqcommand, lprmcommand );
+
+ return;
+}
+
+static pid_t background_lpq_updater_pid = -1;
+
+/****************************************************************************
+main thread of the background lpq updater
+****************************************************************************/
+void start_background_queue(void)
+{
+ DEBUG(3,("start_background_queue: Starting background LPQ thread\n"));
+ background_lpq_updater_pid = sys_fork();
+
+ if (background_lpq_updater_pid == -1) {
+ DEBUG(5,("start_background_queue: background LPQ thread failed to start. %s\n", strerror(errno) ));
+ exit(1);
+ }
+
+ if(background_lpq_updater_pid == 0) {
+ /* Child. */
+ DEBUG(5,("start_background_queue: background LPQ thread started\n"));
+
+ claim_connection( NULL, "smbd lpq backend", 0, False,
+ FLAG_MSG_GENERAL|FLAG_MSG_SMBD|FLAG_MSG_PRINT_GENERAL);
+
+ if (!locking_init(0)) {
+ exit(1);
+ }
+
+ messaging_register(smbd_messaging_context(), NULL,
+ MSG_PRINTER_UPDATE, print_queue_receive);
+
+ DEBUG(5,("start_background_queue: background LPQ thread waiting for messages\n"));
+ while (1) {
+ pause();
+
+ /* check for some essential signals first */
+
+ if (got_sig_term) {
+ exit_server_cleanly(NULL);
+ }
+
+ if (reload_after_sighup) {
+ change_to_root_user();
+ DEBUG(1,("Reloading services after SIGHUP\n"));
+ reload_services(False);
+ reload_after_sighup = 0;
+ }
+
+ /* now check for messages */
+
+ DEBUG(10,("start_background_queue: background LPQ thread got a message\n"));
+ message_dispatch();
+
+ /* process any pending print change notify messages */
+
+ print_notify_send_messages(smbd_messaging_context(),
+ 0);
+ }
+ }
+}
+
+/****************************************************************************
+update the internal database from the system print queue for a queue
+****************************************************************************/
+
+static void print_queue_update(int snum, BOOL force)
+{
+ fstring key;
+ fstring sharename;
+ pstring lpqcommand, lprmcommand;
+ uint8 *buffer = NULL;
+ size_t len = 0;
+ size_t newlen;
+ struct tdb_print_db *pdb;
+ int type;
+ struct printif *current_printif;
+
+ fstrcpy( sharename, lp_const_servicename(snum));
+
+ /* don't strip out characters like '$' from the printername */
+
+ pstrcpy( lpqcommand, lp_lpqcommand(snum));
+ string_sub2( lpqcommand, "%p", PRINTERNAME(snum), sizeof(lpqcommand),
+ False, False, False );
+ standard_sub_advanced(lp_servicename(snum),
+ current_user_info.unix_name, "",
+ current_user.ut.gid,
+ get_current_username(),
+ current_user_info.domain,
+ lpqcommand, sizeof(lpqcommand) );
+
+ pstrcpy( lprmcommand, lp_lprmcommand(snum));
+ string_sub2( lprmcommand, "%p", PRINTERNAME(snum), sizeof(lprmcommand),
+ False, False, False );
+ standard_sub_advanced(lp_servicename(snum),
+ current_user_info.unix_name, "",
+ current_user.ut.gid,
+ get_current_username(),
+ current_user_info.domain,
+ lprmcommand, sizeof(lprmcommand) );
+
+ /*
+ * Make sure that the background queue process exists.
+ * Otherwise just do the update ourselves
+ */
+
+ if ( force || background_lpq_updater_pid == -1 ) {
+ DEBUG(4,("print_queue_update: updating queue [%s] myself\n", sharename));
+ current_printif = get_printer_fns( snum );
+ print_queue_update_with_lock( sharename, current_printif, lpqcommand, lprmcommand );
+
+ return;
+ }
+
+ type = lp_printing(snum);
+
+ /* get the length */
+
+ len = tdb_pack( NULL, 0, "fdPP",
+ sharename,
+ type,
+ lpqcommand,
+ lprmcommand );
+
+ buffer = SMB_XMALLOC_ARRAY( uint8, len );
+
+ /* now pack the buffer */
+ newlen = tdb_pack( buffer, len, "fdPP",
+ sharename,
+ type,
+ lpqcommand,
+ lprmcommand );
+
+ SMB_ASSERT( newlen == len );
+
+ DEBUG(10,("print_queue_update: Sending message -> printer = %s, "
+ "type = %d, lpq command = [%s] lprm command = [%s]\n",
+ sharename, type, lpqcommand, lprmcommand ));
+
+ /* here we set a msg pending record for other smbd processes
+ to throttle the number of duplicate print_queue_update msgs
+ sent. */
+
+ pdb = get_print_db_byname(sharename);
+ if (!pdb) {
+ SAFE_FREE(buffer);
+ return;
+ }
+
+ snprintf(key, sizeof(key), "MSG_PENDING/%s", sharename);
+
+ if ( !tdb_store_uint32( pdb->tdb, key, time(NULL) ) ) {
+ /* log a message but continue on */
+
+ DEBUG(0,("print_queue_update: failed to store MSG_PENDING flag for [%s]!\n",
+ sharename));
+ }
+
+ release_print_db( pdb );
+
+ /* finally send the message */
+
+ messaging_send_buf(smbd_messaging_context(),
+ pid_to_procid(background_lpq_updater_pid),
+ MSG_PRINTER_UPDATE, (uint8 *)buffer, len);
+
+ SAFE_FREE( buffer );
+
+ return;
+}
+
/****************************************************************************
Create/Update an entry in the print tdb that will allow us to send notify
updates only to interested smbd's.
tdb = pdb->tdb;
}
- if (tdb_lock_bystring(tdb, NOTIFY_PID_LIST_KEY, 10) == -1) {
+ if (tdb_lock_bystring_with_timeout(tdb, NOTIFY_PID_LIST_KEY, 10) == -1) {
DEBUG(0,("print_notify_register_pid: Failed to lock printer %s\n",
printername));
if (pdb)
if (i == data.dsize) {
/* We weren't in the list. Realloc. */
- data.dptr = Realloc(data.dptr, data.dsize + 8);
+ data.dptr = (uint8 *)SMB_REALLOC(data.dptr, data.dsize + 8);
if (!data.dptr) {
DEBUG(0,("print_notify_register_pid: Relloc fail for printer %s\n",
printername));
tdb = pdb->tdb;
}
- if (tdb_lock_bystring(tdb, NOTIFY_PID_LIST_KEY, 10) == -1) {
+ if (tdb_lock_bystring_with_timeout(tdb, NOTIFY_PID_LIST_KEY, 10) == -1) {
DEBUG(0,("print_notify_register_pid: Failed to lock \
printer %s database\n", printername));
if (pdb)
Check if a jobid is valid. It is valid if it exists in the database.
****************************************************************************/
-BOOL print_job_exists(int snum, uint32 jobid)
+BOOL print_job_exists(const char* sharename, uint32 jobid)
{
- struct tdb_print_db *pdb = get_print_db_byname(lp_const_servicename(snum));
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
BOOL ret;
if (!pdb)
Give the fd used for a jobid.
****************************************************************************/
-int print_job_fd(int snum, uint32 jobid)
+int print_job_fd(const char* sharename, uint32 jobid)
{
- struct printjob *pjob = print_job_find(snum, jobid);
+ struct printjob *pjob = print_job_find(sharename, jobid);
if (!pjob)
return -1;
/* don't allow another process to get this info - it is meaningless */
- if (pjob->pid != local_pid)
+ if (pjob->pid != sys_getpid())
return -1;
return pjob->fd;
}
has not been spooled.
****************************************************************************/
-char *print_job_fname(int snum, uint32 jobid)
+char *print_job_fname(const char* sharename, uint32 jobid)
{
- struct printjob *pjob = print_job_find(snum, jobid);
- if (!pjob || pjob->spooled || pjob->pid != local_pid)
+ struct printjob *pjob = print_job_find(sharename, jobid);
+ if (!pjob || pjob->spooled || pjob->pid != sys_getpid())
return NULL;
return pjob->filename;
}
has not been spooled.
****************************************************************************/
-NT_DEVICEMODE *print_job_devmode(int snum, uint32 jobid)
+NT_DEVICEMODE *print_job_devmode(const char* sharename, uint32 jobid)
{
- struct printjob *pjob = print_job_find(snum, jobid);
+ struct printjob *pjob = print_job_find(sharename, jobid);
if ( !pjob )
return NULL;
Set the place in the queue for a job.
****************************************************************************/
-BOOL print_job_set_place(int snum, uint32 jobid, int place)
+BOOL print_job_set_place(const char *sharename, uint32 jobid, int place)
{
DEBUG(2,("print_job_set_place not implemented yet\n"));
return False;
Set the name of a job. Only possible for owner.
****************************************************************************/
-BOOL print_job_set_name(int snum, uint32 jobid, char *name)
+BOOL print_job_set_name(const char *sharename, uint32 jobid, char *name)
{
- struct printjob *pjob = print_job_find(snum, jobid);
- if (!pjob || pjob->pid != local_pid)
+ struct printjob *pjob;
+
+ pjob = print_job_find(sharename, jobid);
+ if (!pjob || pjob->pid != sys_getpid())
return False;
fstrcpy(pjob->jobname, name);
- return pjob_store(snum, jobid, pjob);
+ return pjob_store(sharename, jobid, pjob);
}
/***************************************************************************
Remove a jobid from the 'jobs changed' list.
***************************************************************************/
-static BOOL remove_from_jobs_changed(int snum, uint32 jobid)
+static BOOL remove_from_jobs_changed(const char* sharename, uint32 jobid)
{
- const char *printername = lp_const_servicename(snum);
- struct tdb_print_db *pdb = get_print_db_byname(printername);
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
TDB_DATA data, key;
size_t job_count, i;
BOOL ret = False;
BOOL gotlock = False;
- key.dptr = "INFO/jobs_changed";
- key.dsize = strlen(key.dptr);
+ if (!pdb) {
+ return False;
+ }
+
ZERO_STRUCT(data);
+ key = string_tdb_data("INFO/jobs_changed");
+
if (tdb_chainlock_with_timeout(pdb->tdb, key, 5) == -1)
goto out;
for (i = 0; i < job_count; i++) {
uint32 ch_jobid;
- memcpy(&ch_jobid, data.dptr + (i*4), 4);
+ ch_jobid = IVAL(data.dptr, i*4);
if (ch_jobid == jobid) {
if (i < job_count -1 )
memmove(data.dptr + (i*4), data.dptr + (i*4) + 4, (job_count - i - 1)*4 );
static BOOL print_job_delete1(int snum, uint32 jobid)
{
- struct printjob *pjob = print_job_find(snum, jobid);
+ const char* sharename = lp_const_servicename(snum);
+ struct printjob *pjob = print_job_find(sharename, jobid);
int result = 0;
+ struct printif *current_printif = get_printer_fns( snum );
if (!pjob)
return False;
return True;
/* Hrm - we need to be able to cope with deleting a job before it
- has reached the spooler. */
+ has reached the spooler. Just mark it as LPQ_DELETING and
+ let the print_queue_update() code rmeove the record */
+
if (pjob->sysjob == -1) {
DEBUG(5, ("attempt to delete job %u not seen by lpr\n", (unsigned int)jobid));
/* Set the tdb entry to be deleting. */
pjob->status = LPQ_DELETING;
- pjob_store(snum, jobid, pjob);
+ pjob_store(sharename, jobid, pjob);
- if (pjob->spooled && pjob->sysjob != -1)
- result = (*(current_printif->job_delete))(snum, pjob);
- else
- remove_from_jobs_changed(snum, jobid);
+ if (pjob->spooled && pjob->sysjob != -1)
+ {
+ result = (*(current_printif->job_delete))(
+ PRINTERNAME(snum),
+ lp_lprmcommand(snum),
+ pjob);
- /* Delete the tdb entry if the delete succeeded or the job hasn't
- been spooled. */
+ /* Delete the tdb entry if the delete succeeded or the job hasn't
+ been spooled. */
- if (result == 0) {
- const char *printername = lp_const_servicename(snum);
- struct tdb_print_db *pdb = get_print_db_byname(printername);
- int njobs = 1;
+ if (result == 0) {
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
+ int njobs = 1;
- if (!pdb)
- return False;
- pjob_delete(snum, jobid);
- /* Ensure we keep a rough count of the number of total jobs... */
- tdb_change_int32_atomic(pdb->tdb, "INFO/total_jobs", &njobs, -1);
- release_print_db(pdb);
+ if (!pdb)
+ return False;
+ pjob_delete(sharename, jobid);
+ /* Ensure we keep a rough count of the number of total jobs... */
+ tdb_change_int32_atomic(pdb->tdb, "INFO/total_jobs", &njobs, -1);
+ release_print_db(pdb);
+ }
}
+ remove_from_jobs_changed( sharename, jobid );
+
return (result == 0);
}
Return true if the current user owns the print job.
****************************************************************************/
-static BOOL is_owner(struct current_user *user, int snum, uint32 jobid)
+static BOOL is_owner(struct current_user *user, const char *servicename,
+ uint32 jobid)
{
- struct printjob *pjob = print_job_find(snum, jobid);
+ struct printjob *pjob = print_job_find(servicename, jobid);
user_struct *vuser;
if (!pjob || !user)
if ((vuser = get_valid_user_struct(user->vuid)) != NULL) {
return strequal(pjob->user, vuser->user.smb_name);
} else {
- return strequal(pjob->user, uidtoname(user->uid));
+ return strequal(pjob->user, uidtoname(user->ut.uid));
}
}
BOOL print_job_delete(struct current_user *user, int snum, uint32 jobid, WERROR *errcode)
{
- BOOL owner, deleted;
+ const char* sharename = lp_const_servicename( snum );
+ struct printjob *pjob;
+ BOOL owner;
char *fname;
*errcode = WERR_OK;
- owner = is_owner(user, snum, jobid);
+ owner = is_owner(user, lp_const_servicename(snum), jobid);
/* Check access against security descriptor or whether the user
owns their job. */
sys_adminlog( LOG_ERR,
"Permission denied-- user not allowed to delete, \
pause, or resume print job. User name: %s. Printer name: %s.",
- uidtoname(user->uid), PRINTERNAME(snum) );
+ uidtoname(user->ut.uid), PRINTERNAME(snum) );
/* END_ADMIN_LOG */
return False;
* spool file & return.
*/
- if ( (fname = print_job_fname( snum, jobid )) != NULL )
+ if ( (fname = print_job_fname( sharename, jobid )) != NULL )
{
/* remove the spool file */
DEBUG(10,("print_job_delete: Removing spool file [%s]\n", fname ));
*errcode = map_werror_from_unix(errno);
return False;
}
-
- return True;
}
if (!print_job_delete1(snum, jobid)) {
/* force update the database and say the delete failed if the
job still exists */
- print_queue_update(snum);
+ print_queue_update(snum, True);
- deleted = !print_job_exists(snum, jobid);
- if ( !deleted )
+ pjob = print_job_find(sharename, jobid);
+ if ( pjob && (pjob->status != LPQ_DELETING) )
*errcode = WERR_ACCESS_DENIED;
- return deleted;
+ return (pjob == NULL );
}
/****************************************************************************
BOOL print_job_pause(struct current_user *user, int snum, uint32 jobid, WERROR *errcode)
{
- struct printjob *pjob = print_job_find(snum, jobid);
+ const char* sharename = lp_const_servicename(snum);
+ struct printjob *pjob;
int ret = -1;
+ struct printif *current_printif = get_printer_fns( snum );
+
+ pjob = print_job_find(sharename, jobid);
- if (!pjob || !user)
+ if (!pjob || !user) {
+ DEBUG(10, ("print_job_pause: no pjob or user for jobid %u\n",
+ (unsigned int)jobid ));
return False;
+ }
- if (!pjob->spooled || pjob->sysjob == -1)
+ if (!pjob->spooled || pjob->sysjob == -1) {
+ DEBUG(10, ("print_job_pause: not spooled or bad sysjob = %d for jobid %u\n",
+ (int)pjob->sysjob, (unsigned int)jobid ));
return False;
+ }
- if (!is_owner(user, snum, jobid) &&
+ if (!is_owner(user, lp_const_servicename(snum), jobid) &&
!print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) {
DEBUG(3, ("pause denied by security descriptor\n"));
sys_adminlog( LOG_ERR,
"Permission denied-- user not allowed to delete, \
pause, or resume print job. User name: %s. Printer name: %s.",
- uidtoname(user->uid), PRINTERNAME(snum) );
+ uidtoname(user->ut.uid), PRINTERNAME(snum) );
/* END_ADMIN_LOG */
*errcode = WERR_ACCESS_DENIED;
}
/* force update the database */
- print_cache_flush(snum);
+ print_cache_flush(lp_const_servicename(snum));
/* Send a printer notify message */
- notify_job_status(snum, jobid, JOB_STATUS_PAUSED);
+ notify_job_status(sharename, jobid, JOB_STATUS_PAUSED);
/* how do we tell if this succeeded? */
BOOL print_job_resume(struct current_user *user, int snum, uint32 jobid, WERROR *errcode)
{
- struct printjob *pjob = print_job_find(snum, jobid);
+ const char *sharename = lp_const_servicename(snum);
+ struct printjob *pjob;
int ret;
+ struct printif *current_printif = get_printer_fns( snum );
+
+ pjob = print_job_find(sharename, jobid);
- if (!pjob || !user)
+ if (!pjob || !user) {
+ DEBUG(10, ("print_job_resume: no pjob or user for jobid %u\n",
+ (unsigned int)jobid ));
return False;
+ }
- if (!pjob->spooled || pjob->sysjob == -1)
+ if (!pjob->spooled || pjob->sysjob == -1) {
+ DEBUG(10, ("print_job_resume: not spooled or bad sysjob = %d for jobid %u\n",
+ (int)pjob->sysjob, (unsigned int)jobid ));
return False;
+ }
- if (!is_owner(user, snum, jobid) &&
+ if (!is_owner(user, lp_const_servicename(snum), jobid) &&
!print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) {
DEBUG(3, ("resume denied by security descriptor\n"));
*errcode = WERR_ACCESS_DENIED;
sys_adminlog( LOG_ERR,
"Permission denied-- user not allowed to delete, \
pause, or resume print job. User name: %s. Printer name: %s.",
- uidtoname(user->uid), PRINTERNAME(snum) );
+ uidtoname(user->ut.uid), PRINTERNAME(snum) );
/* END_ADMIN_LOG */
return False;
}
}
/* force update the database */
- print_cache_flush(snum);
+ print_cache_flush(lp_const_servicename(snum));
/* Send a printer notify message */
- notify_job_status(snum, jobid, JOB_STATUS_QUEUED);
+ notify_job_status(sharename, jobid, JOB_STATUS_QUEUED);
return True;
}
Write to a print file.
****************************************************************************/
-int print_job_write(int snum, uint32 jobid, const char *buf, int size)
+ssize_t print_job_write(int snum, uint32 jobid, const char *buf, SMB_OFF_T pos, size_t size)
{
+ const char* sharename = lp_const_servicename(snum);
int return_code;
- struct printjob *pjob = print_job_find(snum, jobid);
+ struct printjob *pjob;
+
+ pjob = print_job_find(sharename, jobid);
if (!pjob)
return -1;
/* don't allow another process to get this info - it is meaningless */
- if (pjob->pid != local_pid)
+ if (pjob->pid != sys_getpid())
return -1;
- return_code = write(pjob->fd, buf, size);
+ return_code = write_data_at_offset(pjob->fd, buf, size, pos);
+
if (return_code>0) {
pjob->size += size;
- pjob_store(snum, jobid, pjob);
+ pjob_store(sharename, jobid, pjob);
}
return return_code;
}
-/****************************************************************************
- Check if the print queue has been updated recently enough.
-****************************************************************************/
-
-static BOOL print_cache_expired(int snum)
-{
- fstring key;
- time_t last_qscan_time, time_now = time(NULL);
- const char *printername = lp_const_servicename(snum);
- struct tdb_print_db *pdb = get_print_db_byname(printername);
-
- if (!pdb)
- return False;
-
- slprintf(key, sizeof(key), "CACHE/%s", printername);
- last_qscan_time = (time_t)tdb_fetch_int32(pdb->tdb, key);
-
- /*
- * Invalidate the queue for 3 reasons.
- * (1). last queue scan time == -1.
- * (2). Current time - last queue scan time > allowed cache time.
- * (3). last queue scan time > current time + MAX_CACHE_VALID_TIME (1 hour by default).
- * This last test picks up machines for which the clock has been moved
- * forward, an lpq scan done and then the clock moved back. Otherwise
- * that last lpq scan would stay around for a loooong loooong time... :-). JRA.
- */
-
- if (last_qscan_time == ((time_t)-1) || (time_now - last_qscan_time) >= lp_lpqcachetime() ||
- last_qscan_time > (time_now + MAX_CACHE_VALID_TIME)) {
- DEBUG(3, ("print cache expired for queue %s \
-(last_qscan_time = %d, time now = %d, qcachetime = %d)\n", printername,
- (int)last_qscan_time, (int)time_now, (int)lp_lpqcachetime() ));
- release_print_db(pdb);
- return True;
- }
- release_print_db(pdb);
- return False;
-}
-
/****************************************************************************
Get the queue status - do not update if db is out of date.
****************************************************************************/
-static int get_queue_status(int snum, print_status_struct *status)
+static int get_queue_status(const char* sharename, print_status_struct *status)
{
fstring keystr;
- TDB_DATA data, key;
- const char *printername = lp_const_servicename(snum);
- struct tdb_print_db *pdb = get_print_db_byname(printername);
+ TDB_DATA data;
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
int len;
+ if (status) {
+ ZERO_STRUCTP(status);
+ }
+
if (!pdb)
return 0;
if (status) {
- ZERO_STRUCTP(status);
- slprintf(keystr, sizeof(keystr)-1, "STATUS/%s", printername);
- key.dptr = keystr;
- key.dsize = strlen(keystr);
- data = tdb_fetch(pdb->tdb, key);
+ fstr_sprintf(keystr, "STATUS/%s", sharename);
+ data = tdb_fetch(pdb->tdb, string_tdb_data(keystr));
if (data.dptr) {
if (data.dsize == sizeof(print_status_struct))
+ /* this memcpy is ok since the status struct was
+ not packed before storing it in the tdb */
memcpy(status, data.dptr, sizeof(print_status_struct));
SAFE_FREE(data.dptr);
}
int print_queue_length(int snum, print_status_struct *pstatus)
{
+ const char* sharename = lp_const_servicename( snum );
print_status_struct status;
int len;
+
+ ZERO_STRUCT( status );
/* make sure the database is up to date */
- if (print_cache_expired(snum))
- print_queue_update(snum);
+ if (print_cache_expired(lp_const_servicename(snum), True))
+ print_queue_update(snum, False);
/* also fetch the queue status */
memset(&status, 0, sizeof(status));
- len = get_queue_status(snum, &status);
+ len = get_queue_status(sharename, &status);
if (pstatus)
*pstatus = status;
Allocate a jobid. Hold the lock for as short a time as possible.
***************************************************************************/
-static BOOL allocate_print_jobid(struct tdb_print_db *pdb, int snum, const char *printername, uint32 *pjobid)
+static BOOL allocate_print_jobid(struct tdb_print_db *pdb, int snum, const char *sharename, uint32 *pjobid)
{
int i;
uint32 jobid;
for (i = 0; i < 3; i++) {
/* Lock the database - only wait 20 seconds. */
- if (tdb_lock_bystring(pdb->tdb, "INFO/nextjob", 20) == -1) {
- DEBUG(0,("allocate_print_jobid: failed to lock printing database %s\n", printername ));
+ if (tdb_lock_bystring_with_timeout(pdb->tdb, "INFO/nextjob", 20) == -1) {
+ DEBUG(0,("allocate_print_jobid: failed to lock printing database %s\n", sharename));
return False;
}
if (!tdb_fetch_uint32(pdb->tdb, "INFO/nextjob", &jobid)) {
if (tdb_error(pdb->tdb) != TDB_ERR_NOEXIST) {
DEBUG(0, ("allocate_print_jobid: failed to fetch INFO/nextjob for print queue %s\n",
- printername ));
+ sharename));
return False;
}
jobid = 0;
/* We've finished with the INFO/nextjob lock. */
tdb_unlock_bystring(pdb->tdb, "INFO/nextjob");
- if (!print_job_exists(snum, jobid))
+ if (!print_job_exists(sharename, jobid))
break;
}
if (i > 2) {
DEBUG(0, ("allocate_print_jobid: failed to allocate a print job for queue %s\n",
- printername ));
+ sharename));
/* Probably full... */
errno = ENOSPC;
return False;
static BOOL add_to_jobs_changed(struct tdb_print_db *pdb, uint32 jobid)
{
- TDB_DATA data, key;
+ TDB_DATA data;
+ uint32 store_jobid;
- key.dptr = "INFO/jobs_changed";
- key.dsize = strlen(key.dptr);
- data.dptr = (char *)&jobid;
+ SIVAL(&store_jobid, 0, jobid);
+ data.dptr = (uint8 *)&store_jobid;
data.dsize = 4;
DEBUG(10,("add_to_jobs_changed: Added jobid %u\n", (unsigned int)jobid ));
- return (tdb_append(pdb->tdb, key, data) == 0);
+ return (tdb_append(pdb->tdb, string_tdb_data("INFO/jobs_changed"),
+ data) == 0);
}
/***************************************************************************
char *path;
struct printjob pjob;
user_struct *vuser;
- const char *printername = lp_const_servicename(snum);
- struct tdb_print_db *pdb = get_print_db_byname(printername);
+ const char *sharename = lp_const_servicename(snum);
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
int njobs;
errno = 0;
return (uint32)-1;
}
- if (!print_time_access_check(snum)) {
+ if (!print_time_access_check(lp_servicename(snum))) {
DEBUG(3, ("print_job_start: job start denied by time check\n"));
release_print_db(pdb);
return (uint32)-1;
}
/* for autoloaded printers, check that the printcap entry still exists */
- if (lp_autoloaded(snum) && !pcap_printername_ok(lp_const_servicename(snum), NULL)) {
+ if (lp_autoloaded(snum) && !pcap_printername_ok(lp_const_servicename(snum))) {
DEBUG(3, ("print_job_start: printer name %s check failed.\n", lp_const_servicename(snum) ));
release_print_db(pdb);
errno = ENOENT;
/* Insure the maximum queue size is not violated */
if ((njobs = print_queue_length(snum,NULL)) > lp_maxprintjobs(snum)) {
DEBUG(3, ("print_job_start: Queue %s number of jobs (%d) larger than max printjobs per queue (%d).\n",
- printername, njobs, lp_maxprintjobs(snum) ));
+ sharename, njobs, lp_maxprintjobs(snum) ));
release_print_db(pdb);
errno = ENOSPC;
return (uint32)-1;
}
DEBUG(10,("print_job_start: Queue %s number of jobs (%d), max printjobs = %d\n",
- printername, njobs, lp_maxprintjobs(snum) ));
+ sharename, njobs, lp_maxprintjobs(snum) ));
- if (!allocate_print_jobid(pdb, snum, printername, &jobid))
+ if (!allocate_print_jobid(pdb, snum, sharename, &jobid))
goto fail;
/* create the database entry */
ZERO_STRUCT(pjob);
- pjob.pid = local_pid;
+ pjob.pid = sys_getpid();
pjob.sysjob = -1;
pjob.fd = -1;
pjob.starttime = time(NULL);
fstrcpy(pjob.jobname, jobname);
if ((vuser = get_valid_user_struct(user->vuid)) != NULL) {
- fstrcpy(pjob.user, vuser->user.smb_name);
+ fstrcpy(pjob.user, lp_printjob_username(snum));
+ standard_sub_basic(vuser->user.smb_name, vuser->user.domain,
+ pjob.user, sizeof(pjob.user)-1);
+ /* ensure NULL termination */
+ pjob.user[sizeof(pjob.user)-1] = '\0';
} else {
- fstrcpy(pjob.user, uidtoname(user->uid));
+ fstrcpy(pjob.user, uidtoname(user->ut.uid));
}
fstrcpy(pjob.queuename, lp_const_servicename(snum));
goto fail;
}
- pjob_store(snum, jobid, &pjob);
+ pjob_store(sharename, jobid, &pjob);
/* Update the 'jobs changed' entry used by print_queue_status. */
add_to_jobs_changed(pdb, jobid);
fail:
if (jobid != -1)
- pjob_delete(snum, jobid);
+ pjob_delete(sharename, jobid);
release_print_db(pdb);
void print_job_endpage(int snum, uint32 jobid)
{
- struct printjob *pjob = print_job_find(snum, jobid);
+ const char* sharename = lp_const_servicename(snum);
+ struct printjob *pjob;
+
+ pjob = print_job_find(sharename, jobid);
if (!pjob)
return;
/* don't allow another process to get this info - it is meaningless */
- if (pjob->pid != local_pid)
+ if (pjob->pid != sys_getpid())
return;
pjob->page_count++;
- pjob_store(snum, jobid, pjob);
+ pjob_store(sharename, jobid, pjob);
}
/****************************************************************************
error.
****************************************************************************/
-BOOL print_job_end(int snum, uint32 jobid, BOOL normal_close)
+BOOL print_job_end(int snum, uint32 jobid, enum file_close_type close_type)
{
- struct printjob *pjob = print_job_find(snum, jobid);
+ const char* sharename = lp_const_servicename(snum);
+ struct printjob *pjob;
int ret;
SMB_STRUCT_STAT sbuf;
+ struct printif *current_printif = get_printer_fns( snum );
+
+ pjob = print_job_find(sharename, jobid);
if (!pjob)
return False;
- if (pjob->spooled || pjob->pid != local_pid)
+ if (pjob->spooled || pjob->pid != sys_getpid())
return False;
- if (normal_close && (sys_fstat(pjob->fd, &sbuf) == 0)) {
+ if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) &&
+ (sys_fstat(pjob->fd, &sbuf) == 0)) {
pjob->size = sbuf.st_size;
close(pjob->fd);
pjob->fd = -1;
DEBUG(5,("print_job_end: canceling spool of %s (%s)\n",
pjob->filename, pjob->size ? "deleted" : "zero length" ));
unlink(pjob->filename);
- pjob_delete(snum, jobid);
+ pjob_delete(sharename, jobid);
return True;
}
+ pjob->smbjob = jobid;
+
ret = (*(current_printif->job_submit))(snum, pjob);
if (ret)
pjob->spooled = True;
pjob->status = LPQ_QUEUED;
- pjob_store(snum, jobid, pjob);
+ pjob_store(sharename, jobid, pjob);
/* make sure the database is up to date */
- if (print_cache_expired(snum))
- print_queue_update(snum);
+ if (print_cache_expired(lp_const_servicename(snum), True))
+ print_queue_update(snum, False);
return True;
/* The print job was not succesfully started. Cleanup */
/* Still need to add proper error return propagation! 010122:JRR */
unlink(pjob->filename);
- pjob_delete(snum, jobid);
- remove_from_jobs_changed(snum, jobid);
+ pjob_delete(sharename, jobid);
return False;
}
static BOOL get_stored_queue_info(struct tdb_print_db *pdb, int snum, int *pcount, print_queue_struct **ppqueue)
{
- TDB_DATA data, key, cgdata;
+ TDB_DATA data, cgdata;
print_queue_struct *queue = NULL;
uint32 qcount = 0;
uint32 extra_count = 0;
uint32 i;
int max_reported_jobs = lp_max_reported_jobs(snum);
BOOL ret = False;
+ const char* sharename = lp_servicename(snum);
/* make sure the database is up to date */
- if (print_cache_expired(snum))
- print_queue_update(snum);
+ if (print_cache_expired(lp_const_servicename(snum), True))
+ print_queue_update(snum, False);
*pcount = 0;
*ppqueue = NULL;
ZERO_STRUCT(data);
ZERO_STRUCT(cgdata);
- key.dptr = "INFO/linear_queue_array";
- key.dsize = strlen(key.dptr);
/* Get the stored queue data. */
- data = tdb_fetch(pdb->tdb, key);
-
- if (data.dptr == NULL || data.dsize < 4)
- qcount = 0;
- else
- memcpy(&qcount, data.dptr, 4);
-
+ data = tdb_fetch(pdb->tdb, string_tdb_data("INFO/linear_queue_array"));
+
+ if (data.dptr && data.dsize >= sizeof(qcount))
+ len += tdb_unpack(data.dptr + len, data.dsize - len, "d", &qcount);
+
/* Get the changed jobs list. */
- key.dptr = "INFO/jobs_changed";
- key.dsize = strlen(key.dptr);
-
- cgdata = tdb_fetch(pdb->tdb, key);
+ cgdata = tdb_fetch(pdb->tdb, string_tdb_data("INFO/jobs_changed"));
if (cgdata.dptr != NULL && (cgdata.dsize % 4 == 0))
extra_count = cgdata.dsize/4;
if (qcount == 0 && extra_count == 0)
goto out;
- if ((queue = (print_queue_struct *)malloc(sizeof(print_queue_struct)*(qcount + extra_count))) == NULL)
+ if ((queue = SMB_MALLOC_ARRAY(print_queue_struct, qcount + extra_count)) == NULL)
goto out;
/* Retrieve the linearised queue data. */
- len = 0;
+
for( i = 0; i < qcount; i++) {
uint32 qjob, qsize, qpage_count, qstatus, qpriority, qtime;
- len += tdb_unpack(data.dptr + 4 + len, data.dsize - len, NULL, "ddddddff",
+ len += tdb_unpack(data.dptr + len, data.dsize - len, "ddddddff",
&qjob,
&qsize,
&qpage_count,
uint32 jobid;
struct printjob *pjob;
- memcpy(&jobid, &cgdata.dptr[i*4], 4);
+ jobid = IVAL(cgdata.dptr, i*4);
DEBUG(5,("get_stored_queue_info: changed job = %u\n", (unsigned int)jobid));
- pjob = print_job_find(snum, jobid);
+ pjob = print_job_find(lp_const_servicename(snum), jobid);
if (!pjob) {
DEBUG(5,("get_stored_queue_info: failed to find changed job = %u\n", (unsigned int)jobid));
- remove_from_jobs_changed(snum, jobid);
+ remove_from_jobs_changed(sharename, jobid);
continue;
}
{
fstring keystr;
TDB_DATA data, key;
- const char *printername;
+ const char *sharename;
struct tdb_print_db *pdb;
int count = 0;
/* make sure the database is up to date */
- if (print_cache_expired(snum))
- print_queue_update(snum);
+ if (print_cache_expired(lp_const_servicename(snum), True))
+ print_queue_update(snum, False);
/* return if we are done */
if ( !ppqueue || !status )
return 0;
*ppqueue = NULL;
- printername = lp_const_servicename(snum);
- pdb = get_print_db_byname(printername);
+ sharename = lp_const_servicename(snum);
+ pdb = get_print_db_byname(sharename);
if (!pdb)
return 0;
*/
ZERO_STRUCTP(status);
- slprintf(keystr, sizeof(keystr)-1, "STATUS/%s", printername);
- key.dptr = keystr;
- key.dsize = strlen(keystr);
+ slprintf(keystr, sizeof(keystr)-1, "STATUS/%s", sharename);
+ key = string_tdb_data(keystr);
+
data = tdb_fetch(pdb->tdb, key);
if (data.dptr) {
if (data.dsize == sizeof(*status)) {
+ /* this memcpy is ok since the status struct was
+ not packed before storing it in the tdb */
memcpy(status, data.dptr, sizeof(*status));
}
SAFE_FREE(data.dptr);
BOOL print_queue_pause(struct current_user *user, int snum, WERROR *errcode)
{
int ret;
+ struct printif *current_printif = get_printer_fns( snum );
if (!print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) {
*errcode = WERR_ACCESS_DENIED;
return False;
}
+
+ become_root();
+
ret = (*(current_printif->queue_pause))(snum);
+ unbecome_root();
+
if (ret != 0) {
*errcode = WERR_INVALID_PARAM;
return False;
}
/* force update the database */
- print_cache_flush(snum);
+ print_cache_flush(lp_const_servicename(snum));
/* Send a printer notify message */
BOOL print_queue_resume(struct current_user *user, int snum, WERROR *errcode)
{
int ret;
+ struct printif *current_printif = get_printer_fns( snum );
if (!print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) {
*errcode = WERR_ACCESS_DENIED;
return False;
}
-
+
+ become_root();
+
ret = (*(current_printif->queue_resume))(snum);
+ unbecome_root();
+
if (ret != 0) {
*errcode = WERR_INVALID_PARAM;
return False;
}
/* make sure the database is up to date */
- if (print_cache_expired(snum))
- print_queue_update(snum);
+ if (print_cache_expired(lp_const_servicename(snum), True))
+ print_queue_update(snum, True);
/* Send a printer notify message */
BOOL can_job_admin;
/* Force and update so the count is accurate (i.e. not a cached count) */
- print_queue_update(snum);
+ print_queue_update(snum, True);
can_job_admin = print_access_check(user, snum, JOB_ACCESS_ADMINISTER);
njobs = print_queue_status(snum, &queue, &status);
+
+ if ( can_job_admin )
+ become_root();
for (i=0;i<njobs;i++) {
- BOOL owner = is_owner(user, snum, queue[i].job);
+ BOOL owner = is_owner(user, lp_const_servicename(snum), queue[i].job);
if (owner || can_job_admin) {
print_job_delete1(snum, queue[i].job);
}
}
+
+ if ( can_job_admin )
+ unbecome_root();
+
+ /* update the cache */
+ print_queue_update( snum, True );
SAFE_FREE(queue);