-/*
+/*
Unix SMB/Netbios implementation.
Version 3.0
printing backend routines
Copyright (C) Andrew Tridgell 1992-2000
Copyright (C) Jeremy Allison 2002
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "printing.h"
+#include "librpc/gen_ndr/messaging.h"
+#include "../librpc/gen_ndr/ndr_spoolss.h"
+#include "nt_printing.h"
+#include "../librpc/gen_ndr/netlogon.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 bool remove_from_jobs_changed(const char* sharename, uint32 jobid);
-/*
+/*
the printing backend revolves around a tdb database that stores the
- SMB view of the print queue
-
+ SMB view of the print queue
+
The key for this database is a jobid - a internally generated number that
uniquely identifies a print job
- possibly running lpq and updating the internal database from that
- reading entries from the database
- jobids are assigned when a job starts spooling.
+ jobids are assigned when a job starts spooling.
*/
static TDB_CONTEXT *rap_tdb;
key.dptr = buf;
key.dsize = sizeof(rap_jobid);
data = tdb_fetch(rap_tdb, key);
- if ( data.dptr && data.dsize == sizeof(struct rap_jobid_key) )
+ 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 );
+ if (sharename != NULL) {
+ 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));
return False;
}
-static void rap_jobid_delete(const char* sharename, uint32 jobid)
+void rap_jobid_delete(const char* sharename, uint32 jobid)
{
TDB_DATA key, data;
uint16 rap_jobid;
int services = lp_numservices();
int snum;
- unlink(lock_path("printing.tdb"));
- mkdir(lock_path("printing"),0755);
+ unlink(cache_path("printing.tdb"));
+ mkdir(cache_path("printing"),0755);
/* handle a Samba upgrade */
}
/****************************************************************************
- Retrieve the set of printing functions for a given service. This allows
+ 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)
****************************************************************************/
#endif /* HAVE_IPRINT */
printer_fns->type = type;
-
+
return printer_fns;
}
return ret;
}
+/****************************************************************************
+ Pack the devicemode to store it in a tdb.
+****************************************************************************/
+static int pack_devicemode(struct spoolss_DeviceMode *devmode, uint8 *buf, int buflen)
+{
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ int len = 0;
+
+ if (devmode) {
+ ndr_err = ndr_push_struct_blob(&blob, talloc_tos(),
+ devmode,
+ (ndr_push_flags_fn_t)
+ ndr_push_spoolss_DeviceMode);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(10, ("pack_devicemode: "
+ "error encoding spoolss_DeviceMode\n"));
+ goto done;
+ }
+ } else {
+ ZERO_STRUCT(blob);
+ }
+
+ len = tdb_pack(buf, buflen, "B", blob.length, blob.data);
+
+ if (devmode) {
+ DEBUG(8, ("Packed devicemode [%s]\n", devmode->formname));
+ }
+
+done:
+ return len;
+}
+
+/****************************************************************************
+ Unpack the devicemode to store it in a tdb.
+****************************************************************************/
+static int unpack_devicemode(TALLOC_CTX *mem_ctx,
+ const uint8 *buf, int buflen,
+ struct spoolss_DeviceMode **devmode)
+{
+ struct spoolss_DeviceMode *dm;
+ enum ndr_err_code ndr_err;
+ char *data = NULL;
+ int data_len = 0;
+ DATA_BLOB blob;
+ int len = 0;
+
+ *devmode = NULL;
+
+ len = tdb_unpack(buf, buflen, "B", &data_len, &data);
+ if (!data) {
+ return len;
+ }
+
+ dm = talloc_zero(mem_ctx, struct spoolss_DeviceMode);
+ if (!dm) {
+ goto done;
+ }
+
+ blob = data_blob_const(data, data_len);
+
+ ndr_err = ndr_pull_struct_blob(&blob, dm, dm,
+ (ndr_pull_flags_fn_t)ndr_pull_spoolss_DeviceMode);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(10, ("unpack_devicemode: "
+ "error parsing spoolss_DeviceMode\n"));
+ goto done;
+ }
+
+ DEBUG(8, ("Unpacked devicemode [%s](%s)\n",
+ dm->devicename, dm->formname));
+ if (dm->driverextra_data.data) {
+ DEBUG(8, ("with a private section of %d bytes\n",
+ dm->__driverextra_length));
+ }
+
+ *devmode = dm;
+
+done:
+ SAFE_FREE(data);
+ return len;
+}
+
/***********************************************************************
- unpack a pjob from a tdb buffer
+ unpack a pjob from a tdb buffer
***********************************************************************/
-
+
int unpack_pjob( uint8 *buf, int buflen, struct printjob *pjob )
{
int len = 0;
if ( !buf || !pjob )
return -1;
-
+
len += tdb_unpack(buf+len, buflen-len, "dddddddddffff",
&pjpid,
&pjsysjob,
pjob->jobname,
pjob->user,
pjob->queuename);
-
+
if ( len == -1 )
return -1;
-
- if ( (used = unpack_devicemode(&pjob->nt_devmode, buf+len, buflen-len)) == -1 )
+
+ used = unpack_devicemode(NULL, buf+len, buflen-len, &pjob->devmode);
+ if (used == -1) {
return -1;
-
+ }
+
len += used;
pjob->pid = pjpid;
pjob->page_count = pjpage_count;
pjob->spooled = pjspooled;
pjob->smbjob = pjsmbjob;
-
+
return len;
}
return NULL;
}
- if ( pjob.nt_devmode ) {
- free_nt_devicemode( &pjob.nt_devmode );
- }
+ talloc_free(pjob.devmode);
ZERO_STRUCT( pjob );
{ LPQ_PAPEROUT, JOB_STATUS_PAPEROUT },
{ LPQ_PRINTED, JOB_STATUS_PRINTED },
{ LPQ_DELETED, JOB_STATUS_DELETED },
- { LPQ_BLOCKED, JOB_STATUS_BLOCKED },
+ { LPQ_BLOCKED, JOB_STATUS_BLOCKED_DEVQ },
{ LPQ_USER_INTERVENTION, JOB_STATUS_USER_INTERVENTION },
{ -1, 0 }
};
/* 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) */
-
+ /* 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(sharename, jobid, new_data->starttime);
notify_job_username(sharename, jobid, new_data->user);
struct tdb_print_db *pdb = get_print_db_byname(sharename);
uint8 *buf = NULL;
int len, newlen, buflen;
-
+
if (!pdb)
return False;
/* Doh! Now we have to pack/unpack data since the NT_DEVICEMODE was added */
newlen = 0;
-
+
do {
len = 0;
buflen = newlen;
pjob->user,
pjob->queuename);
- len += pack_devicemode(pjob->nt_devmode, buf+len, buflen-len);
-
+ len += pack_devicemode(pjob->devmode, buf+len, buflen-len);
+
if (buflen != len) {
buf = (uint8 *)SMB_REALLOC(buf, len);
if (!buf) {
newlen = len;
}
} while ( buflen != len );
-
-
+
+
/* Store new data */
new_data.dptr = buf;
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 );
+ talloc_free(old_pjob.devmode);
}
}
else {
/* 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|JOB_STATUS_DELETED;
notify_job_status(sharename, jobid, job_status);
-
+
/* Remove from printing.tdb */
tdb_delete(pdb->tdb, print_key(jobid, &tmp));
rap_jobid_delete(sharename, jobid);
}
-/****************************************************************************
- Parse a file name from the system spooler to generate a jobid.
-****************************************************************************/
-
-static uint32 print_parse_jobid(char *fname)
-{
- int jobid;
-
- if (strncmp(fname,PRINT_SPOOL_PREFIX,strlen(PRINT_SPOOL_PREFIX)) != 0)
- return (uint32)-1;
- fname += strlen(PRINT_SPOOL_PREFIX);
-
- jobid = atoi(fname);
- if (jobid <= 0)
- return (uint32)-1;
-
- return (uint32)jobid;
-}
-
/****************************************************************************
List a unix job in the print database.
****************************************************************************/
{
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 */
if ( key.dsize != sizeof(jobid) )
return 0;
-
+
jobid = IVAL(key.dptr, 0);
if ( unpack_pjob( data.dptr, data.dsize, &pjob ) == -1 )
return 0;
- free_nt_devicemode( &pjob.nt_devmode );
+ talloc_free(pjob.devmode);
if (!pjob.smbjob) {
(unsigned int)jobid ));
pjob_delete(ts->sharename, jobid);
return 0;
- }
+ }
/* need to continue the the bottom of the function to
save the correct attributes */
}
/* 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_DELETING ) {
int result;
- result = (*(ts->print_if->job_delete))(
+ result = (*(ts->print_if->job_delete))(
ts->sharename, ts->lprm_command, &pjob );
if ( result != 0 ) {
pjob_delete(ts->sharename, jobid);
pjob.status = LPQ_DELETED;
}
-
+
}
break;
}
}
}
-
+
/* The job isn't in the system queue - we have to assume it has
completed, so delete the database entry. */
return 0;
}
- /* Save the pjob attributes we will store.
- FIXME!!! This is the only place where queue->job
+ /* 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].job = jobid;
ts->queue[i].size = pjob.size;
ts->queue[i].page_count = pjob.page_count;
ts->queue[i].status = pjob.status;
TDB_DATA data;
pid_t updating_pid = sys_getpid();
uint8 buffer[4];
-
+
struct tdb_print_db *pdb = get_print_db_byname(sharename);
if (!pdb)
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",
+
+ DEBUG(5, ("set_updating_pid: %s updating lpq cache for print share %s\n",
updating ? "" : "not ",
sharename ));
release_print_db(pdb);
return;
}
-
+
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);
+ tdb_store(pdb->tdb, key, data, TDB_REPLACE);
release_print_db(pdb);
}
* 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))
+ 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,
+ 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
+ /* 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 )
+ 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 )
+ && 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;
}
main work for updating the lpq cahe for a printer queue
****************************************************************************/
-static void print_queue_update_internal( const char *sharename,
+static void print_queue_update_internal( const char *sharename,
struct printif *current_printif,
char *lpq_command, char *lprm_command )
{
if (!pdb) {
return;
}
-
+
DEBUG(5,("print_queue_update_internal: printer = %s, type = %d, lpq command = [%s]\n",
sharename, current_printif->type, lpq_command));
* attempting to get the lock and doing this
* if the lpq takes a long time.
*/
-
+
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))(sharename,
- current_printif->type,
+ qcount = (*(current_printif->queue_get))(sharename,
+ current_printif->type,
lpq_command, &queue, &status);
- DEBUG(3, ("print_queue_update_internal: %d job%s in queue for %s\n",
+ 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));
+ TYPESAFE_QSORT(queue, qcount, printjob_comp);
/*
any job in the internal database that is marked as spooled
and doesn't exist in the system queue is considered finished
and removed from the database
- any job in the system database but not in the internal database
+ any job in the system database but not in the internal database
is added as a unix job
fill in any system job numbers as we go
status.qcount = qcount;
data.dptr = (uint8 *)&status;
data.dsize = sizeof(status);
- tdb_store(pdb->tdb, key, data, TDB_REPLACE);
+ tdb_store(pdb->tdb, key, data, TDB_REPLACE);
/*
* Update the cache time again. We want to do this call
smbd processes maytry to update the lpq cache concurrently).
****************************************************************************/
-static void print_queue_update_with_lock( const char *sharename,
+static void print_queue_update_with_lock( const char *sharename,
struct printif *current_printif,
char *lpq_command, char *lprm_command )
{
release_print_db(pdb);
return;
}
-
+
/*
* Check to see if someone else is doing this update.
* This is essentially a mutex on the update.
tdb_unlock_bystring(pdb->tdb, keystr);
/* do the main work now */
-
- print_queue_update_internal( sharename, current_printif,
+
+ print_queue_update_internal( sharename, current_printif,
lpq_command, lprm_command );
-
+
/* Delete our pid from the db. */
set_updating_pid(sharename, False);
release_print_db(pdb);
return;
}
- print_queue_update_with_lock(sharename,
+ print_queue_update_with_lock(sharename,
get_printer_fns_from_type((enum printing_types)printing_type),
lpqcommand, lprmcommand );
return;
}
+static void printing_pause_fd_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ /*
+ * If pause_pipe[1] is closed it means the parent smbd
+ * and children exited or aborted.
+ */
+ exit_server_cleanly(NULL);
+}
+
+extern struct child_pid *children;
+extern int num_children;
+
+static void add_child_pid(pid_t pid)
+{
+ struct child_pid *child;
+
+ child = SMB_MALLOC_P(struct child_pid);
+ if (child == NULL) {
+ DEBUG(0, ("Could not add child struct -- malloc failed\n"));
+ return;
+ }
+ child->pid = pid;
+ DLIST_ADD(children, child);
+ num_children += 1;
+}
+
static pid_t background_lpq_updater_pid = -1;
/****************************************************************************
main thread of the background lpq updater
****************************************************************************/
-void start_background_queue(void)
+void start_background_queue(struct tevent_context *ev,
+ struct messaging_context *msg_ctx)
{
+ /* Use local variables for this as we don't
+ * need to save the parent side of this, just
+ * ensure it closes when the process exits.
+ */
+ int pause_pipe[2];
+
DEBUG(3,("start_background_queue: Starting background LPQ thread\n"));
+
+ if (pipe(pause_pipe) == -1) {
+ DEBUG(5,("start_background_queue: cannot create pipe. %s\n", strerror(errno) ));
+ exit(1);
+ }
+
background_lpq_updater_pid = sys_fork();
if (background_lpq_updater_pid == -1) {
exit(1);
}
+ /* Track the printing pid along with other smbd children */
+ add_child_pid(background_lpq_updater_pid);
+
if(background_lpq_updater_pid == 0) {
+ struct tevent_fd *fde;
+ int ret;
+ NTSTATUS status;
+
/* Child. */
DEBUG(5,("start_background_queue: background LPQ thread started\n"));
- if (!reinit_after_fork(smbd_messaging_context(), true)) {
+ close(pause_pipe[0]);
+ pause_pipe[0] = -1;
+
+ status = reinit_after_fork(msg_ctx, ev, procid_self(), true);
+
+ if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("reinit_after_fork() failed\n"));
smb_panic("reinit_after_fork() failed");
}
- claim_connection( NULL, "smbd lpq backend",
- FLAG_MSG_GENERAL|FLAG_MSG_SMBD|FLAG_MSG_PRINT_GENERAL);
+ smbd_setup_sig_term_handler();
+ smbd_setup_sig_hup_handler(ev, msg_ctx);
+
+ if (!serverid_register(procid_self(),
+ FLAG_MSG_GENERAL|FLAG_MSG_SMBD
+ |FLAG_MSG_PRINT_GENERAL)) {
+ exit(1);
+ }
if (!locking_init()) {
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(smbd_messaging_context());
-
- /* process any pending print change notify messages */
-
- print_notify_send_messages(smbd_messaging_context(),
- 0);
+ messaging_register(msg_ctx, NULL, MSG_PRINTER_UPDATE,
+ print_queue_receive);
+
+ fde = tevent_add_fd(ev, ev, pause_pipe[1], TEVENT_FD_READ,
+ printing_pause_fd_handler,
+ NULL);
+ if (!fde) {
+ DEBUG(0,("tevent_add_fd() failed for pause_pipe\n"));
+ smb_panic("tevent_add_fd() failed for pause_pipe");
}
+
+ DEBUG(5,("start_background_queue: background LPQ thread waiting for messages\n"));
+ ret = tevent_loop_wait(ev);
+ /* should not be reached */
+ DEBUG(0,("background_queue: tevent_loop_wait() exited with %d - %s\n",
+ ret, (ret == 0) ? "out of events" : strerror(errno)));
+ exit(1);
}
+
+ close(pause_pipe[1]);
}
/****************************************************************************
update the internal database from the system print queue for a queue
****************************************************************************/
-static void print_queue_update(int snum, bool force)
+static void print_queue_update(struct messaging_context *msg_ctx,
+ int snum, bool force)
{
fstring key;
fstring sharename;
lpqcommand = talloc_string_sub2(ctx,
lp_lpqcommand(snum),
"%p",
- PRINTERNAME(snum),
+ lp_printername(snum),
false, false, false);
if (!lpqcommand) {
return;
lprmcommand = talloc_string_sub2(ctx,
lp_lprmcommand(snum),
"%p",
- PRINTERNAME(snum),
+ lp_printername(snum),
false, false, false);
if (!lprmcommand) {
return;
SMB_ASSERT( newlen == len );
DEBUG(10,("print_queue_update: Sending message -> printer = %s, "
- "type = %d, lpq command = [%s] lprm command = [%s]\n",
+ "type = %d, lpq command = [%s] lprm command = [%s]\n",
sharename, type, lpqcommand, lprmcommand ));
- /* here we set a msg pending record for other smbd processes
+ /* here we set a msg pending record for other smbd processes
to throttle the number of duplicate print_queue_update msgs
sent. */
release_print_db( pdb );
/* finally send the message */
-
- messaging_send_buf(smbd_messaging_context(),
- pid_to_procid(background_lpq_updater_pid),
+
+ messaging_send_buf(msg_ctx, pid_to_procid(background_lpq_updater_pid),
MSG_PRINTER_UPDATE, (uint8 *)buffer, len);
SAFE_FREE( buffer );
/****************************************************************************
Create/Update an entry in the print tdb that will allow us to send notify
- updates only to interested smbd's.
+ updates only to interested smbd's.
****************************************************************************/
bool print_notify_register_pid(int snum)
/* 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)
+
+ 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 */
/****************************************************************************
Update an entry in the print tdb that will allow us to send notify
- updates only to interested smbd's.
+ updates only to interested smbd's.
****************************************************************************/
bool print_notify_deregister_pid(int snum)
/* if ( snum == -1 ), we are deregister a print server handle
which means to deregister on all print queues */
-
- if (snum == -1)
+
+ 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 */
return ret;
}
-/****************************************************************************
- Give the fd used for a jobid.
-****************************************************************************/
-
-int print_job_fd(const char* sharename, uint32 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 != sys_getpid())
- return -1;
- return pjob->fd;
-}
-
/****************************************************************************
Give the filename used for a jobid.
Only valid for the process doing the spooling and when the job
has not been spooled.
****************************************************************************/
-NT_DEVICEMODE *print_job_devmode(const char* sharename, uint32 jobid)
+struct spoolss_DeviceMode *print_job_devmode(const char* sharename, uint32 jobid)
{
struct printjob *pjob = print_job_find(sharename, jobid);
-
+
if ( !pjob )
return NULL;
-
- return pjob->nt_devmode;
-}
-/****************************************************************************
- Set the place in the queue for a job.
-****************************************************************************/
-
-bool print_job_set_place(const char *sharename, uint32 jobid, int place)
-{
- DEBUG(2,("print_job_set_place not implemented yet\n"));
- return False;
+ return pjob->devmode;
}
/****************************************************************************
Set the name of a job. Only possible for owner.
****************************************************************************/
-bool print_job_set_name(const char *sharename, uint32 jobid, char *name)
+bool print_job_set_name(const char *sharename, uint32 jobid, const char *name)
{
struct printjob *pjob;
return pjob_store(sharename, jobid, pjob);
}
+/****************************************************************************
+ Get the name of a job. Only possible for owner.
+****************************************************************************/
+
+bool print_job_get_name(TALLOC_CTX *mem_ctx, const char *sharename, uint32_t jobid, char **name)
+{
+ struct printjob *pjob;
+
+ pjob = print_job_find(sharename, jobid);
+ if (!pjob || pjob->pid != sys_getpid()) {
+ return false;
+ }
+
+ *name = talloc_strdup(mem_ctx, pjob->jobname);
+ if (!*name) {
+ return false;
+ }
+
+ return true;
+}
+
+
/***************************************************************************
Remove a jobid from the 'jobs changed' list.
***************************************************************************/
return True;
/* Hrm - we need to be able to cope with deleting a job before it
- has reached the spooler. Just mark it as LPQ_DELETING and
+ 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));
pjob->status = LPQ_DELETING;
pjob_store(sharename, jobid, pjob);
- if (pjob->spooled && pjob->sysjob != -1)
+ if (pjob->spooled && pjob->sysjob != -1)
{
result = (*(current_printif->job_delete))(
- PRINTERNAME(snum),
- lp_lprmcommand(snum),
+ lp_printername(snum),
+ lp_lprmcommand(snum),
pjob);
/* Delete the tdb entry if the delete succeeded or the job hasn't
Delete a print job.
****************************************************************************/
-bool print_job_delete(struct auth_serversupplied_info *server_info, int snum,
- uint32 jobid, WERROR *errcode)
+WERROR print_job_delete(struct auth_serversupplied_info *server_info,
+ struct messaging_context *msg_ctx,
+ int snum, uint32_t jobid)
{
- const char* sharename = lp_const_servicename( snum );
+ const char* sharename = lp_const_servicename(snum);
struct printjob *pjob;
bool owner;
char *fname;
- *errcode = WERR_OK;
-
owner = is_owner(server_info, lp_const_servicename(snum), jobid);
-
+
/* Check access against security descriptor or whether the user
owns their job. */
- if (!owner &&
- !print_access_check(server_info, snum, JOB_ACCESS_ADMINISTER)) {
+ if (!owner &&
+ !print_access_check(server_info, msg_ctx, snum,
+ JOB_ACCESS_ADMINISTER)) {
DEBUG(3, ("delete denied by security descriptor\n"));
- *errcode = WERR_ACCESS_DENIED;
/* BEGIN_ADMIN_LOG */
- sys_adminlog( LOG_ERR,
+ sys_adminlog( LOG_ERR,
"Permission denied-- user not allowed to delete, \
pause, or resume print job. User name: %s. Printer name: %s.",
uidtoname(server_info->utok.uid),
- PRINTERNAME(snum) );
+ lp_printername(snum) );
/* END_ADMIN_LOG */
- return False;
+ return WERR_ACCESS_DENIED;
}
- /*
+ /*
* get the spooled filename of the print job
* if this works, then the file has not been spooled
- * to the underlying print system. Just delete the
+ * to the underlying print system. Just delete the
* spool file & return.
*/
-
- if ( (fname = print_job_fname( sharename, jobid )) != NULL )
- {
+
+ fname = print_job_fname(sharename, jobid);
+ if (fname != NULL) {
/* remove the spool file */
- DEBUG(10,("print_job_delete: Removing spool file [%s]\n", fname ));
- if ( unlink( fname ) == -1 ) {
- *errcode = map_werror_from_unix(errno);
- return False;
+ DEBUG(10, ("print_job_delete: "
+ "Removing spool file [%s]\n", fname));
+ if (unlink(fname) == -1) {
+ return map_werror_from_unix(errno);
}
}
-
+
if (!print_job_delete1(snum, jobid)) {
- *errcode = WERR_ACCESS_DENIED;
- return False;
+ return WERR_ACCESS_DENIED;
}
/* force update the database and say the delete failed if the
job still exists */
- print_queue_update(snum, True);
-
+ print_queue_update(msg_ctx, snum, True);
+
pjob = print_job_find(sharename, jobid);
- if ( pjob && (pjob->status != LPQ_DELETING) )
- *errcode = WERR_ACCESS_DENIED;
+ if (pjob && (pjob->status != LPQ_DELETING)) {
+ return WERR_ACCESS_DENIED;
+ }
- return (pjob == NULL );
+ return WERR_PRINTER_HAS_JOBS_QUEUED;
}
/****************************************************************************
Pause a job.
****************************************************************************/
-bool print_job_pause(struct auth_serversupplied_info *server_info, int snum,
- uint32 jobid, WERROR *errcode)
+bool print_job_pause(struct auth_serversupplied_info *server_info,
+ struct messaging_context *msg_ctx,
+ int snum, uint32 jobid, WERROR *errcode)
{
const char* sharename = lp_const_servicename(snum);
struct printjob *pjob;
struct printif *current_printif = get_printer_fns( snum );
pjob = print_job_find(sharename, jobid);
-
+
if (!pjob || !server_info) {
DEBUG(10, ("print_job_pause: no pjob or user for jobid %u\n",
(unsigned int)jobid ));
}
if (!is_owner(server_info, lp_const_servicename(snum), jobid) &&
- !print_access_check(server_info, snum, JOB_ACCESS_ADMINISTER)) {
+ !print_access_check(server_info, msg_ctx, snum,
+ JOB_ACCESS_ADMINISTER)) {
DEBUG(3, ("pause denied by security descriptor\n"));
/* BEGIN_ADMIN_LOG */
- sys_adminlog( LOG_ERR,
+ sys_adminlog( LOG_ERR,
"Permission denied-- user not allowed to delete, \
pause, or resume print job. User name: %s. Printer name: %s.",
uidtoname(server_info->utok.uid),
- PRINTERNAME(snum) );
+ lp_printername(snum) );
/* END_ADMIN_LOG */
*errcode = WERR_ACCESS_DENIED;
Resume a job.
****************************************************************************/
-bool print_job_resume(struct auth_serversupplied_info *server_info, int snum,
- uint32 jobid, WERROR *errcode)
+bool print_job_resume(struct auth_serversupplied_info *server_info,
+ struct messaging_context *msg_ctx,
+ int snum, uint32 jobid, WERROR *errcode)
{
const char *sharename = lp_const_servicename(snum);
struct printjob *pjob;
}
if (!is_owner(server_info, lp_const_servicename(snum), jobid) &&
- !print_access_check(server_info, snum, JOB_ACCESS_ADMINISTER)) {
+ !print_access_check(server_info, msg_ctx, snum,
+ JOB_ACCESS_ADMINISTER)) {
DEBUG(3, ("resume denied by security descriptor\n"));
*errcode = WERR_ACCESS_DENIED;
/* BEGIN_ADMIN_LOG */
- sys_adminlog( LOG_ERR,
+ sys_adminlog( LOG_ERR,
"Permission denied-- user not allowed to delete, \
pause, or resume print job. User name: %s. Printer name: %s.",
uidtoname(server_info->utok.uid),
- PRINTERNAME(snum) );
+ lp_printername(snum) );
/* END_ADMIN_LOG */
return False;
}
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;
+ ssize_t return_code;
struct printjob *pjob;
pjob = print_job_find(sharename, jobid);
if (pjob->pid != sys_getpid())
return -1;
+ /* if SMBD is spooling this can't be allowed */
+ if (pjob->status == PJOB_SMBD_SPOOLING) {
+ return -1;
+ }
+
return_code = write_data_at_offset(pjob->fd, buf, size, pos);
if (return_code>0) {
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
+ /* 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);
Determine the number of jobs in a queue.
****************************************************************************/
-int print_queue_length(int snum, print_status_struct *pstatus)
+int print_queue_length(struct messaging_context *msg_ctx, 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(lp_const_servicename(snum), True))
- print_queue_update(snum, False);
-
+ print_queue_update(msg_ctx, snum, False);
+
/* also fetch the queue status */
memset(&status, 0, sizeof(status));
len = get_queue_status(sharename, &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 *sharename, uint32 *pjobid)
+static WERROR allocate_print_jobid(struct tdb_print_db *pdb, int snum,
+ const char *sharename, uint32 *pjobid)
{
int i;
uint32 jobid;
+ enum TDB_ERROR terr;
+ int ret;
*pjobid = (uint32)-1;
for (i = 0; i < 3; i++) {
/* Lock the database - only wait 20 seconds. */
- 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;
+ ret = tdb_lock_bystring_with_timeout(pdb->tdb,
+ "INFO/nextjob", 20);
+ if (ret == -1) {
+ DEBUG(0, ("allocate_print_jobid: "
+ "Failed to lock printing database %s\n",
+ sharename));
+ terr = tdb_error(pdb->tdb);
+ return ntstatus_to_werror(map_nt_error_from_tdb(terr));
}
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",
- sharename));
- return False;
+ terr = tdb_error(pdb->tdb);
+ if (terr != TDB_ERR_NOEXIST) {
+ DEBUG(0, ("allocate_print_jobid: "
+ "Failed to fetch INFO/nextjob "
+ "for print queue %s\n", sharename));
+ tdb_unlock_bystring(pdb->tdb, "INFO/nextjob");
+ return ntstatus_to_werror(map_nt_error_from_tdb(terr));
}
+ DEBUG(10, ("allocate_print_jobid: "
+ "No existing jobid in %s\n", sharename));
jobid = 0;
}
+ DEBUG(10, ("allocate_print_jobid: "
+ "Read jobid %u from %s\n", jobid, sharename));
+
jobid = NEXT_JOBID(jobid);
- if (tdb_store_int32(pdb->tdb, "INFO/nextjob", jobid)==-1) {
- DEBUG(3, ("allocate_print_jobid: failed to store INFO/nextjob.\n"));
+ ret = tdb_store_int32(pdb->tdb, "INFO/nextjob", jobid);
+ if (ret == -1) {
+ terr = tdb_error(pdb->tdb);
+ DEBUG(3, ("allocate_print_jobid: "
+ "Failed to store INFO/nextjob.\n"));
tdb_unlock_bystring(pdb->tdb, "INFO/nextjob");
- return False;
+ return ntstatus_to_werror(map_nt_error_from_tdb(terr));
}
/* We've finished with the INFO/nextjob lock. */
tdb_unlock_bystring(pdb->tdb, "INFO/nextjob");
-
- if (!print_job_exists(sharename, jobid))
+
+ if (!print_job_exists(sharename, jobid)) {
break;
+ }
+ DEBUG(10, ("allocate_print_jobid: "
+ "Found jobid %u in %s\n", jobid, sharename));
}
if (i > 2) {
- DEBUG(0, ("allocate_print_jobid: failed to allocate a print job for queue %s\n",
- sharename));
+ DEBUG(0, ("allocate_print_jobid: "
+ "Failed to allocate a print job for queue %s\n",
+ sharename));
/* Probably full... */
- errno = ENOSPC;
- return False;
+ return WERR_NO_SPOOL_SPACE;
}
/* Store a dummy placeholder. */
dum.dsize = 0;
if (tdb_store(pdb->tdb, print_key(jobid, &tmp), dum,
TDB_INSERT) == -1) {
- DEBUG(3, ("allocate_print_jobid: jobid (%d) failed to store placeholder.\n",
- jobid ));
- return False;
+ DEBUG(3, ("allocate_print_jobid: "
+ "jobid (%d) failed to store placeholder.\n",
+ jobid ));
+ terr = tdb_error(pdb->tdb);
+ return ntstatus_to_werror(map_nt_error_from_tdb(terr));
}
}
*pjobid = jobid;
- return True;
+ return WERR_OK;
}
/***************************************************************************
data) == 0);
}
+
/***************************************************************************
- Start spooling a job - return the jobid.
+ Do all checks needed to determine if we can start a job.
***************************************************************************/
-uint32 print_job_start(struct auth_serversupplied_info *server_info, int snum,
- char *jobname, NT_DEVICEMODE *nt_devmode )
+static WERROR print_job_checks(struct auth_serversupplied_info *server_info,
+ struct messaging_context *msg_ctx,
+ int snum, int *njobs)
{
- uint32 jobid;
- char *path;
- struct printjob pjob;
const char *sharename = lp_const_servicename(snum);
- struct tdb_print_db *pdb = get_print_db_byname(sharename);
- int njobs;
-
- errno = 0;
-
- if (!pdb)
- return (uint32)-1;
+ uint64_t dspace, dsize;
+ uint64_t minspace;
+ int ret;
- if (!print_access_check(server_info, snum, PRINTER_ACCESS_USE)) {
- DEBUG(3, ("print_job_start: job start denied by security descriptor\n"));
- release_print_db(pdb);
- return (uint32)-1;
+ if (!print_access_check(server_info, msg_ctx, snum,
+ PRINTER_ACCESS_USE)) {
+ DEBUG(3, ("print_job_checks: "
+ "job start denied by security descriptor\n"));
+ return WERR_ACCESS_DENIED;
}
- 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;
+ if (!print_time_access_check(server_info, msg_ctx, sharename)) {
+ DEBUG(3, ("print_job_checks: "
+ "job start denied by time check\n"));
+ return WERR_ACCESS_DENIED;
}
- path = lp_pathname(snum);
-
/* see if we have sufficient disk space */
if (lp_minprintspace(snum)) {
- uint64_t dspace, dsize;
- if (sys_fsusage(path, &dspace, &dsize) == 0 &&
- dspace < 2*(uint64_t)lp_minprintspace(snum)) {
- DEBUG(3, ("print_job_start: disk space check failed.\n"));
- release_print_db(pdb);
- errno = ENOSPC;
- return (uint32)-1;
+ minspace = lp_minprintspace(snum);
+ ret = sys_fsusage(lp_pathname(snum), &dspace, &dsize);
+ if (ret == 0 && dspace < 2*minspace) {
+ DEBUG(3, ("print_job_checks: "
+ "disk space check failed.\n"));
+ return WERR_NO_SPOOL_SPACE;
}
}
/* for autoloaded printers, check that the printcap entry still exists */
- 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;
- return (uint32)-1;
+ if (lp_autoloaded(snum) && !pcap_printername_ok(sharename)) {
+ DEBUG(3, ("print_job_checks: printer name %s check failed.\n",
+ sharename));
+ return WERR_ACCESS_DENIED;
}
/* 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",
- sharename, njobs, lp_maxprintjobs(snum) ));
+ *njobs = print_queue_length(msg_ctx, snum, NULL);
+ if (*njobs > lp_maxprintjobs(snum)) {
+ DEBUG(3, ("print_job_checks: Queue %s number of jobs (%d) "
+ "larger than max printjobs per queue (%d).\n",
+ sharename, *njobs, lp_maxprintjobs(snum)));
+ return WERR_NO_SPOOL_SPACE;
+ }
+
+ return WERR_OK;
+}
+
+/***************************************************************************
+ Create a job file.
+***************************************************************************/
+
+static WERROR print_job_spool_file(int snum, uint32_t jobid,
+ const char *output_file,
+ struct printjob *pjob)
+{
+ WERROR werr;
+ SMB_STRUCT_STAT st;
+ const char *path;
+ int len;
+
+ /* if this file is within the printer path, it means that smbd
+ * is spooling it and will pass us control when it is finished.
+ * Verify that the file name is ok, within path, and it is
+ * already already there */
+ if (output_file) {
+ path = lp_pathname(snum);
+ len = strlen(path);
+ if (strncmp(output_file, path, len) == 0 &&
+ (output_file[len - 1] == '/' || output_file[len] == '/')) {
+
+ /* verify path is not too long */
+ if (strlen(output_file) >= sizeof(pjob->filename)) {
+ return WERR_INVALID_NAME;
+ }
+
+ /* verify that the file exists */
+ if (sys_stat(output_file, &st, false) != 0) {
+ return WERR_INVALID_NAME;
+ }
+
+ fstrcpy(pjob->filename, output_file);
+
+ DEBUG(3, ("print_job_spool_file:"
+ "External spooling activated"));
+
+ /* we do not open the file until spooling is done */
+ pjob->fd = -1;
+ pjob->status = PJOB_SMBD_SPOOLING;
+
+ return WERR_OK;
+ }
+ }
+
+ slprintf(pjob->filename, sizeof(pjob->filename)-1,
+ "%s/%s%.8u.XXXXXX", lp_pathname(snum),
+ PRINT_SPOOL_PREFIX, (unsigned int)jobid);
+ pjob->fd = mkstemp(pjob->filename);
+
+ if (pjob->fd == -1) {
+ werr = map_werror_from_unix(errno);
+ if (W_ERROR_EQUAL(werr, WERR_ACCESS_DENIED)) {
+ /* Common setup error, force a report. */
+ DEBUG(0, ("print_job_spool_file: "
+ "insufficient permissions to open spool "
+ "file %s.\n", pjob->filename));
+ } else {
+ /* Normal case, report at level 3 and above. */
+ DEBUG(3, ("print_job_spool_file: "
+ "can't open spool file %s\n",
+ pjob->filename));
+ }
+ return werr;
+ }
+
+ return WERR_OK;
+}
+
+/***************************************************************************
+ Start spooling a job - return the jobid.
+***************************************************************************/
+
+WERROR print_job_start(struct auth_serversupplied_info *server_info,
+ struct messaging_context *msg_ctx,
+ int snum, const char *docname, const char *filename,
+ struct spoolss_DeviceMode *devmode, uint32_t *_jobid)
+{
+ uint32_t jobid;
+ char *path;
+ struct printjob pjob;
+ const char *sharename = lp_const_servicename(snum);
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
+ int njobs;
+ WERROR werr;
+
+ if (!pdb) {
+ return WERR_INTERNAL_DB_CORRUPTION;
+ }
+
+ path = lp_pathname(snum);
+
+ werr = print_job_checks(server_info, msg_ctx, snum, &njobs);
+ if (!W_ERROR_IS_OK(werr)) {
release_print_db(pdb);
- errno = ENOSPC;
- return (uint32)-1;
+ return werr;
}
- DEBUG(10,("print_job_start: Queue %s number of jobs (%d), max printjobs = %d\n",
- sharename, njobs, lp_maxprintjobs(snum) ));
+ DEBUG(10, ("print_job_start: "
+ "Queue %s number of jobs (%d), max printjobs = %d\n",
+ sharename, njobs, lp_maxprintjobs(snum)));
- if (!allocate_print_jobid(pdb, snum, sharename, &jobid))
+ werr = allocate_print_jobid(pdb, snum, sharename, &jobid);
+ if (!W_ERROR_IS_OK(werr)) {
goto fail;
+ }
/* create the database entry */
-
+
ZERO_STRUCT(pjob);
-
+
pjob.pid = sys_getpid();
pjob.sysjob = -1;
pjob.fd = -1;
pjob.size = 0;
pjob.spooled = False;
pjob.smbjob = True;
- pjob.nt_devmode = nt_devmode;
-
- fstrcpy(pjob.jobname, jobname);
+ pjob.devmode = devmode;
+
+ fstrcpy(pjob.jobname, docname);
fstrcpy(pjob.user, lp_printjob_username(snum));
standard_sub_advanced(sharename, server_info->sanitized_username,
- path, server_info->utok.gid,
+ path, server_info->utok.gid,
server_info->sanitized_username,
- pdb_get_domain(server_info->sam_account),
+ server_info->info3->base.domain.string,
pjob.user, sizeof(pjob.user)-1);
/* ensure NULL termination */
pjob.user[sizeof(pjob.user)-1] = '\0';
fstrcpy(pjob.queuename, lp_const_servicename(snum));
/* we have a job entry - now create the spool file */
- slprintf(pjob.filename, sizeof(pjob.filename)-1, "%s/%s%.8u.XXXXXX",
- path, PRINT_SPOOL_PREFIX, (unsigned int)jobid);
- pjob.fd = smb_mkstemp(pjob.filename);
-
- if (pjob.fd == -1) {
- if (errno == EACCES) {
- /* Common setup error, force a report. */
- DEBUG(0, ("print_job_start: insufficient permissions \
-to open spool file %s.\n", pjob.filename));
- } else {
- /* Normal case, report at level 3 and above. */
- DEBUG(3, ("print_job_start: can't open spool file %s,\n", pjob.filename));
- DEBUGADD(3, ("errno = %d (%s).\n", errno, strerror(errno)));
- }
+ werr = print_job_spool_file(snum, jobid, filename, &pjob);
+ if (!W_ERROR_IS_OK(werr)) {
goto fail;
}
release_print_db(pdb);
- return jobid;
+ *_jobid = jobid;
+ return WERR_OK;
- fail:
- if (jobid != -1)
+fail:
+ if (jobid != -1) {
pjob_delete(sharename, jobid);
+ }
release_print_db(pdb);
- DEBUG(3, ("print_job_start: returning fail. Error = %s\n", strerror(errno) ));
- return (uint32)-1;
+ DEBUG(3, ("print_job_start: returning fail. "
+ "Error = %s\n", win_errstr(werr)));
+ return werr;
}
/****************************************************************************
error.
****************************************************************************/
-bool print_job_end(int snum, uint32 jobid, enum file_close_type close_type)
+NTSTATUS print_job_end(struct messaging_context *msg_ctx, int snum,
+ uint32 jobid, enum file_close_type close_type)
{
const char* sharename = lp_const_servicename(snum);
struct printjob *pjob;
int ret;
SMB_STRUCT_STAT sbuf;
struct printif *current_printif = get_printer_fns( snum );
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
pjob = print_job_find(sharename, jobid);
- if (!pjob)
- return False;
+ if (!pjob) {
+ return NT_STATUS_PRINT_CANCELLED;
+ }
- if (pjob->spooled || pjob->pid != sys_getpid())
- return False;
+ if (pjob->spooled || pjob->pid != sys_getpid()) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) {
+ if (pjob->status == PJOB_SMBD_SPOOLING) {
+ /* take over the file now, smbd is done */
+ if (sys_stat(pjob->filename, &sbuf, false) != 0) {
+ status = map_nt_error_from_unix(errno);
+ DEBUG(3, ("print_job_end: "
+ "stat file failed for jobid %d\n",
+ jobid));
+ goto fail;
+ }
+
+ pjob->status = LPQ_SPOOLING;
+
+ } else {
+
+ if ((sys_fstat(pjob->fd, &sbuf, false) != 0)) {
+ status = map_nt_error_from_unix(errno);
+ close(pjob->fd);
+ DEBUG(3, ("print_job_end: "
+ "stat file failed for jobid %d\n",
+ jobid));
+ goto fail;
+ }
+
+ close(pjob->fd);
+ }
- 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;
+ pjob->size = sbuf.st_ex_size;
} else {
- /*
- * Not a normal close or we couldn't stat the job file,
- * so something has gone wrong. Cleanup.
+ /*
+ * Not a normal close, something has gone wrong. Cleanup.
*/
- close(pjob->fd);
- pjob->fd = -1;
- DEBUG(3,("print_job_end: failed to stat file for jobid %d\n", jobid ));
+ if (pjob->fd != -1) {
+ close(pjob->fd);
+ }
goto fail;
}
pjob->filename, pjob->size ? "deleted" : "zero length" ));
unlink(pjob->filename);
pjob_delete(sharename, jobid);
- return True;
+ return NT_STATUS_OK;
}
- pjob->smbjob = jobid;
-
ret = (*(current_printif->job_submit))(snum, pjob);
- if (ret)
+ if (ret) {
+ status = NT_STATUS_PRINT_CANCELLED;
goto fail;
+ }
/* The print job has been successfully handed over to the back-end */
-
+
pjob->spooled = True;
pjob->status = LPQ_QUEUED;
pjob_store(sharename, jobid, pjob);
-
+
/* make sure the database is up to date */
if (print_cache_expired(lp_const_servicename(snum), True))
- print_queue_update(snum, False);
-
- return True;
+ print_queue_update(msg_ctx, snum, False);
+
+ return NT_STATUS_OK;
fail:
/* The print job was not successfully started. Cleanup */
/* Still need to add proper error return propagation! 010122:JRR */
+ pjob->fd = -1;
unlink(pjob->filename);
pjob_delete(sharename, jobid);
- return False;
+ return status;
}
/****************************************************************************
Get a snapshot of jobs in the system without traversing.
****************************************************************************/
-static bool get_stored_queue_info(struct tdb_print_db *pdb, int snum, int *pcount, print_queue_struct **ppqueue)
+static bool get_stored_queue_info(struct messaging_context *msg_ctx,
+ struct tdb_print_db *pdb, int snum,
+ int *pcount, print_queue_struct **ppqueue)
{
TDB_DATA data, cgdata;
print_queue_struct *queue = NULL;
/* make sure the database is up to date */
if (print_cache_expired(lp_const_servicename(snum), True))
- print_queue_update(snum, False);
-
+ print_queue_update(msg_ctx, snum, False);
+
*pcount = 0;
*ppqueue = NULL;
/* Get the stored queue data. */
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. */
cgdata = tdb_fetch(pdb->tdb, string_tdb_data("INFO/jobs_changed"));
if (cgdata.dptr != NULL && (cgdata.dsize % 4 == 0))
/* Sort the queue by submission time otherwise they are displayed
in hash order. */
- qsort(queue, total_count, sizeof(print_queue_struct), QSORT_CAST(printjob_comp));
+ TYPESAFE_QSORT(queue, total_count, printjob_comp);
DEBUG(5,("get_stored_queue_info: total_count = %u\n", (unsigned int)total_count));
set queue = NULL and status = NULL if you just want to update the cache
****************************************************************************/
-int print_queue_status(int snum,
+int print_queue_status(int snum,
print_queue_struct **ppqueue,
print_status_struct *status)
{
/* make sure the database is up to date */
if (print_cache_expired(lp_const_servicename(snum), True))
- print_queue_update(snum, False);
+ print_queue_update(server_messaging_context(), snum, False);
/* return if we are done */
if ( !ppqueue || !status )
data = tdb_fetch(pdb->tdb, key);
if (data.dptr) {
if (data.dsize == sizeof(*status)) {
- /* this memcpy is ok since the status struct was
+ /* this memcpy is ok since the status struct was
not packed before storing it in the tdb */
memcpy(status, data.dptr, sizeof(*status));
}
* of entries, and then only retrieve the queue if necessary.
*/
- if (!get_stored_queue_info(pdb, snum, &count, ppqueue)) {
+ if (!get_stored_queue_info(server_messaging_context(), pdb, snum,
+ &count, ppqueue)) {
release_print_db(pdb);
return 0;
}
Pause a queue.
****************************************************************************/
-bool print_queue_pause(struct auth_serversupplied_info *server_info, int snum,
- WERROR *errcode)
+WERROR print_queue_pause(struct auth_serversupplied_info *server_info,
+ struct messaging_context *msg_ctx, int snum)
{
int ret;
struct printif *current_printif = get_printer_fns( snum );
-
- if (!print_access_check(server_info, snum,
+
+ if (!print_access_check(server_info, msg_ctx, snum,
PRINTER_ACCESS_ADMINISTER)) {
- *errcode = WERR_ACCESS_DENIED;
- return False;
+ return WERR_ACCESS_DENIED;
}
-
+
become_root();
-
+
ret = (*(current_printif->queue_pause))(snum);
unbecome_root();
-
+
if (ret != 0) {
- *errcode = WERR_INVALID_PARAM;
- return False;
+ return WERR_INVALID_PARAM;
}
/* force update the database */
notify_printer_status(snum, PRINTER_STATUS_PAUSED);
- return True;
+ return WERR_OK;
}
/****************************************************************************
Resume a queue.
****************************************************************************/
-bool print_queue_resume(struct auth_serversupplied_info *server_info, int snum,
- WERROR *errcode)
+WERROR print_queue_resume(struct auth_serversupplied_info *server_info,
+ struct messaging_context *msg_ctx, int snum)
{
int ret;
struct printif *current_printif = get_printer_fns( snum );
- if (!print_access_check(server_info, snum,
+ if (!print_access_check(server_info, msg_ctx, snum,
PRINTER_ACCESS_ADMINISTER)) {
- *errcode = WERR_ACCESS_DENIED;
- return False;
+ return WERR_ACCESS_DENIED;
}
-
+
become_root();
-
+
ret = (*(current_printif->queue_resume))(snum);
unbecome_root();
-
+
if (ret != 0) {
- *errcode = WERR_INVALID_PARAM;
- return False;
+ return WERR_INVALID_PARAM;
}
/* make sure the database is up to date */
if (print_cache_expired(lp_const_servicename(snum), True))
- print_queue_update(snum, True);
+ print_queue_update(msg_ctx, snum, True);
/* Send a printer notify message */
notify_printer_status(snum, PRINTER_STATUS_OK);
- return True;
+ return WERR_OK;
}
/****************************************************************************
Purge a queue - implemented by deleting all jobs that we can delete.
****************************************************************************/
-bool print_queue_purge(struct auth_serversupplied_info *server_info, int snum,
- WERROR *errcode)
+WERROR print_queue_purge(struct auth_serversupplied_info *server_info,
+ struct messaging_context *msg_ctx, int snum)
{
print_queue_struct *queue;
print_status_struct status;
bool can_job_admin;
/* Force and update so the count is accurate (i.e. not a cached count) */
- print_queue_update(snum, True);
-
- can_job_admin = print_access_check(server_info, snum,
+ print_queue_update(msg_ctx, snum, True);
+
+ can_job_admin = print_access_check(server_info,
+ msg_ctx,
+ snum,
JOB_ACCESS_ADMINISTER);
njobs = print_queue_status(snum, &queue, &status);
-
+
if ( can_job_admin )
become_root();
print_job_delete1(snum, queue[i].job);
}
}
-
+
if ( can_job_admin )
unbecome_root();
/* update the cache */
- print_queue_update( snum, True );
+ print_queue_update(msg_ctx, snum, True);
SAFE_FREE(queue);
- return True;
+ return WERR_OK;
}