1996-05-04 11:50:46 +04:00
/*
Unix SMB / Netbios implementation .
2000-04-16 10:20:02 +04:00
Version 3.0
printing backend routines
Copyright ( C ) Andrew Tridgell 1992 - 2000
1996-05-04 11:50:46 +04:00
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 2 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 , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
2000-11-08 02:05:53 +03:00
1996-05-04 11:50:46 +04:00
extern int DEBUGLEVEL ;
2000-04-16 10:20:02 +04:00
/*
the printing backend revolves around a tdb database that stores the
SMB view of the print queue
The key for this database is a jobid - a internally generated number that
uniquely identifies a print job
1996-05-04 11:50:46 +04:00
2000-04-16 10:20:02 +04:00
reading the print queue involves two steps :
- possibly running lpq and updating the internal database from that
- reading entries from the database
jobids are assigned when a job starts spooling .
*/
2001-02-22 04:31:55 +03:00
# define NEXT_JOBID(j) ((j+1) % PRINT_MAX_JOBID > 0 ? (j+1) % PRINT_MAX_JOBID : 1)
2000-04-16 10:20:02 +04:00
struct printjob {
pid_t pid ; /* which process launched the job */
int sysjob ; /* the system (lp) job number */
int fd ; /* file descriptor of open file if open */
time_t starttime ; /* when the job started spooling */
int status ; /* the status of this job */
size_t size ; /* the size of the job so far */
BOOL spooled ; /* has it been sent to the spooler yet? */
BOOL smbjob ; /* set if the job is a SMB job */
fstring filename ; /* the filename used to spool the file */
fstring jobname ; /* the job name given to us by the client */
fstring user ; /* the user who started the job */
fstring qname ; /* name of the print queue the job was sent to */
} ;
/* the open printing.tdb database */
static TDB_CONTEXT * tdb ;
static pid_t local_pid ;
# define PRINT_MAX_JOBID 10000
# define UNIX_JOB_START PRINT_MAX_JOBID
# define PRINT_SPOOL_PREFIX "smbprn."
2000-10-11 06:26:27 +04:00
# define PRINT_DATABASE_VERSION 2
2000-04-16 10:20:02 +04:00
2000-11-21 03:30:15 +03:00
static int get_queue_status ( int , print_status_struct * ) ;
2000-04-16 10:20:02 +04:00
/****************************************************************************
initialise the printing backend . Called once at startup .
Does not survive a fork
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL print_backend_init ( void )
{
2000-10-10 10:45:09 +04:00
char * sversion = " INFO/version " ;
2000-05-02 06:23:41 +04:00
if ( tdb & & local_pid = = sys_getpid ( ) ) return True ;
2000-04-16 10:20:02 +04:00
tdb = tdb_open ( lock_path ( " printing.tdb " ) , 0 , 0 , O_RDWR | O_CREAT , 0600 ) ;
if ( ! tdb ) {
2001-02-15 22:33:57 +03:00
DEBUG ( 0 , ( " print_backend_init: Failed to open printing backend database. Error = [%s] \n " ,
tdb_errorstr ( tdb ) ) ) ;
return False ;
2000-04-16 10:20:02 +04:00
}
2000-05-02 06:23:41 +04:00
local_pid = sys_getpid ( ) ;
2000-04-16 10:20:02 +04:00
/* handle a Samba upgrade */
2000-10-10 10:45:09 +04:00
tdb_lock_bystring ( tdb , sversion ) ;
if ( tdb_fetch_int ( tdb , sversion ) ! = PRINT_DATABASE_VERSION ) {
2000-04-19 00:41:04 +04:00
tdb_traverse ( tdb , ( tdb_traverse_func ) tdb_delete , NULL ) ;
2000-10-10 10:45:09 +04:00
tdb_store_int ( tdb , sversion , PRINT_DATABASE_VERSION ) ;
2000-04-16 10:20:02 +04:00
}
2000-10-10 10:45:09 +04:00
tdb_unlock_bystring ( tdb , sversion ) ;
2000-04-16 10:20:02 +04:00
2000-05-24 10:10:21 +04:00
return nt_printing_init ( ) ;
1996-05-04 11:50:46 +04:00
}
2000-04-16 10:20:02 +04:00
/****************************************************************************
useful function to generate a tdb key
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static TDB_DATA print_key ( int jobid )
1996-05-04 11:50:46 +04:00
{
2000-04-16 10:20:02 +04:00
static int j ;
TDB_DATA ret ;
j = jobid ;
ret . dptr = ( void * ) & j ;
ret . dsize = sizeof ( j ) ;
return ret ;
1996-05-04 11:50:46 +04:00
}
2000-04-16 10:20:02 +04:00
/****************************************************************************
useful function to find a print job in the database
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static struct printjob * print_job_find ( int jobid )
{
static struct printjob pjob ;
TDB_DATA ret ;
ret = tdb_fetch ( tdb , print_key ( jobid ) ) ;
if ( ! ret . dptr | | ret . dsize ! = sizeof ( pjob ) ) return NULL ;
memcpy ( & pjob , ret . dptr , sizeof ( pjob ) ) ;
free ( ret . dptr ) ;
return & pjob ;
}
1996-05-04 11:50:46 +04:00
/****************************************************************************
2000-04-16 10:20:02 +04:00
store a job structure back to the database
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-04-16 10:20:02 +04:00
static BOOL print_job_store ( int jobid , struct printjob * pjob )
1996-05-04 11:50:46 +04:00
{
2000-04-16 10:20:02 +04:00
TDB_DATA d ;
d . dptr = ( void * ) pjob ;
d . dsize = sizeof ( * pjob ) ;
2000-11-04 22:48:53 +03:00
2000-11-11 01:05:08 +03:00
return ( tdb_store ( tdb , print_key ( jobid ) , d , TDB_REPLACE ) = = 0 ) ;
2000-04-16 10:20:02 +04:00
}
1996-05-04 11:50:46 +04:00
2000-04-16 10:20:02 +04:00
/****************************************************************************
run a given print command
2000-06-03 10:18:43 +04:00
a null terminated list of value / substitute pairs is provided
for local substitution strings
2000-04-16 10:20:02 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int print_run_command ( int snum , char * command ,
char * outfile ,
2000-06-03 10:18:43 +04:00
. . . )
2000-04-16 10:20:02 +04:00
{
pstring syscmd ;
2000-06-03 10:18:43 +04:00
char * p , * arg ;
2000-04-16 10:20:02 +04:00
int ret ;
2000-06-03 10:18:43 +04:00
va_list ap ;
2000-04-16 10:20:02 +04:00
2000-04-16 12:03:37 +04:00
if ( ! command | | ! * command ) return - 1 ;
2000-04-23 12:13:12 +04:00
if ( ! VALID_SNUM ( snum ) ) {
DEBUG ( 0 , ( " Invalid snum %d for command %s \n " , snum , command ) ) ;
return - 1 ;
}
2000-04-16 10:20:02 +04:00
pstrcpy ( syscmd , command ) ;
2000-06-03 10:18:43 +04:00
va_start ( ap , outfile ) ;
while ( ( arg = va_arg ( ap , char * ) ) ) {
char * value = va_arg ( ap , char * ) ;
pstring_sub ( syscmd , arg , value ) ;
}
va_end ( ap ) ;
1996-05-04 11:50:46 +04:00
2000-04-16 10:20:02 +04:00
p = PRINTERNAME ( snum ) ;
1999-12-13 16:27:58 +03:00
2000-07-17 06:42:25 +04:00
pstring_sub ( syscmd , " %p " , p ) ;
2000-04-16 10:20:02 +04:00
standard_sub_snum ( snum , syscmd ) ;
2001-01-08 22:58:30 +03:00
/* Convert script args to unix-codepage */
dos_to_unix ( syscmd , True ) ;
2000-04-16 10:20:02 +04:00
ret = smbrun ( syscmd , outfile , False ) ;
DEBUG ( 3 , ( " Running the command `%s' gave %d \n " , syscmd , ret ) ) ;
2000-11-11 01:05:08 +03:00
2000-04-16 10:20:02 +04:00
return ret ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2000-04-16 10:20:02 +04:00
parse a file name from the system spooler to generate a jobid
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-04-16 10:20:02 +04:00
static int print_parse_jobid ( char * fname )
1996-05-04 11:50:46 +04:00
{
2000-04-16 10:20:02 +04:00
int jobid ;
1996-05-04 11:50:46 +04:00
2000-04-16 10:20:02 +04:00
if ( strncmp ( fname , PRINT_SPOOL_PREFIX , strlen ( PRINT_SPOOL_PREFIX ) ) ! = 0 ) return - 1 ;
fname + = strlen ( PRINT_SPOOL_PREFIX ) ;
1996-05-04 11:50:46 +04:00
2000-04-16 10:20:02 +04:00
jobid = atoi ( fname ) ;
if ( jobid < = 0 ) return - 1 ;
1996-05-04 11:50:46 +04:00
2000-04-16 10:20:02 +04:00
return jobid ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2000-04-16 10:20:02 +04:00
list a unix job in the print database
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-04-16 10:20:02 +04:00
static void print_unix_job ( int snum , print_queue_struct * q )
1996-05-04 11:50:46 +04:00
{
2000-04-16 10:20:02 +04:00
int jobid = q - > job + UNIX_JOB_START ;
2000-11-08 02:05:53 +03:00
struct printjob pj , * old_pj ;
2000-04-16 10:20:02 +04:00
2000-11-08 02:05:53 +03:00
/* Preserve the timestamp on an existing unix print job */
2000-11-04 22:48:53 +03:00
2000-11-08 02:05:53 +03:00
old_pj = print_job_find ( jobid ) ;
2000-11-04 22:48:53 +03:00
2000-04-16 10:20:02 +04:00
ZERO_STRUCT ( pj ) ;
pj . pid = ( pid_t ) - 1 ;
pj . sysjob = q - > job ;
pj . fd = - 1 ;
2000-11-08 02:05:53 +03:00
pj . starttime = old_pj ? old_pj - > starttime : q - > time ;
2000-04-16 10:20:02 +04:00
pj . status = q - > status ;
pj . size = q - > size ;
pj . spooled = True ;
pj . smbjob = False ;
fstrcpy ( pj . filename , " " ) ;
fstrcpy ( pj . jobname , q - > file ) ;
fstrcpy ( pj . user , q - > user ) ;
fstrcpy ( pj . qname , lp_servicename ( snum ) ) ;
print_job_store ( jobid , & pj ) ;
}
1996-05-04 11:50:46 +04:00
2000-04-16 10:20:02 +04:00
struct traverse_struct {
print_queue_struct * queue ;
2001-01-23 23:25:25 +03:00
int qcount , snum , maxcount , total_jobs ;
2000-04-16 10:20:02 +04:00
} ;
2000-04-16 12:03:37 +04:00
/* utility fn to delete any jobs that are no longer active */
2000-04-16 10:20:02 +04:00
static int traverse_fn_delete ( TDB_CONTEXT * t , TDB_DATA key , TDB_DATA data , void * state )
{
struct traverse_struct * ts = ( struct traverse_struct * ) state ;
struct printjob pjob ;
int i , jobid ;
if ( data . dsize ! = sizeof ( pjob ) | | key . dsize ! = sizeof ( int ) ) return 0 ;
memcpy ( & jobid , key . dptr , sizeof ( jobid ) ) ;
memcpy ( & pjob , data . dptr , sizeof ( pjob ) ) ;
1996-05-04 11:50:46 +04:00
2000-04-16 10:20:02 +04:00
if ( strcmp ( lp_servicename ( ts - > snum ) , pjob . qname ) ) {
/* this isn't for the queue we are looking at */
2001-01-23 23:25:25 +03:00
ts - > total_jobs + + ;
2000-04-16 10:20:02 +04:00
return 0 ;
1998-08-14 21:38:29 +04:00
}
1996-05-04 11:50:46 +04:00
2000-04-16 10:20:02 +04:00
if ( ! pjob . smbjob ) {
2001-01-23 23:25:25 +03:00
/* remove a unix job if it isn't in the system queue any more */
2000-11-08 02:05:53 +03:00
2000-04-16 10:20:02 +04:00
for ( i = 0 ; i < ts - > qcount ; i + + ) {
if ( jobid = = ts - > queue [ i ] . job + UNIX_JOB_START ) break ;
}
2001-01-23 23:25:25 +03:00
if ( i = = ts - > qcount )
tdb_delete ( tdb , key ) ;
else
ts - > total_jobs + + ;
2000-04-16 10:20:02 +04:00
return 0 ;
}
1996-05-04 11:50:46 +04:00
2000-04-16 10:20:02 +04:00
/* maybe it hasn't been spooled yet */
if ( ! pjob . spooled ) {
/* if a job is not spooled and the process doesn't
exist then kill it . This cleans up after smbd
deaths */
2001-01-23 23:25:25 +03:00
if ( ! process_exists ( pjob . pid ) )
2000-04-16 10:20:02 +04:00
tdb_delete ( tdb , key ) ;
2001-01-23 23:25:25 +03:00
else
ts - > total_jobs + + ;
2000-04-16 10:20:02 +04:00
return 0 ;
1996-05-04 11:50:46 +04:00
}
2000-04-16 10:20:02 +04:00
for ( i = 0 ; i < ts - > qcount ; i + + ) {
int qid = print_parse_jobid ( ts - > queue [ i ] . file ) ;
if ( jobid = = qid ) break ;
1998-08-14 21:38:29 +04:00
}
2000-11-15 04:11:38 +03:00
/* The job isn't in the system queue - we have to assume it has
completed , so delete the database entry . */
2000-04-16 10:20:02 +04:00
if ( i = = ts - > qcount ) {
2000-11-15 04:11:38 +03:00
time_t cur_t = time ( NULL ) ;
/* A race can occur between the time a job is spooled and
when it appears in the lpq output . This happens when
the job is added to printing . tdb when another smbd
running print_queue_update ( ) has completed a lpq and
is currently traversing the printing tdb and deleting jobs .
A workaround is to not delete the job if it has been
submitted less than lp_lpqcachetime ( ) seconds ago . */
2001-01-23 23:25:25 +03:00
if ( ( cur_t - pjob . starttime ) > lp_lpqcachetime ( ) )
2000-11-15 04:11:38 +03:00
tdb_delete ( t , key ) ;
2001-01-23 23:25:25 +03:00
else
ts - > total_jobs + + ;
2000-04-16 10:20:02 +04:00
}
2001-01-23 23:25:25 +03:00
else
ts - > total_jobs + + ;
2000-04-16 10:20:02 +04:00
return 0 ;
}
/****************************************************************************
check if the print queue has been updated recently enough
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void print_cache_flush ( int snum )
{
fstring key ;
slprintf ( key , sizeof ( key ) , " CACHE/%s " , lp_servicename ( snum ) ) ;
2001-01-11 23:41:19 +03:00
dos_to_unix ( key , True ) ; /* Convert key to unix-codepage */
2000-04-16 10:20:02 +04:00
tdb_store_int ( tdb , key , - 1 ) ;
}
2001-02-22 20:39:36 +03:00
/****************************************************************************
Check if someone already thinks they are doing the update .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static pid_t get_updating_pid ( fstring printer_name )
{
fstring keystr ;
TDB_DATA data , key ;
pid_t updating_pid ;
slprintf ( keystr , sizeof ( keystr ) , " UPDATING/%s " , printer_name ) ;
key . dptr = keystr ;
key . dsize = strlen ( keystr ) ;
data = tdb_fetch ( tdb , key ) ;
if ( ! data . dptr | | data . dsize ! = sizeof ( pid_t ) )
return ( pid_t ) - 1 ;
memcpy ( & updating_pid , data . dptr , sizeof ( pid_t ) ) ;
free ( data . dptr ) ;
if ( process_exists ( updating_pid ) )
return updating_pid ;
return ( pid_t ) - 1 ;
}
/****************************************************************************
Set the fact that we ' re doing the update , or have finished doing the update
in th tdb .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void set_updating_pid ( fstring printer_name , BOOL delete )
{
fstring keystr ;
TDB_DATA key ;
TDB_DATA data ;
pid_t updating_pid = getpid ( ) ;
slprintf ( keystr , sizeof ( keystr ) , " UPDATING/%s " , printer_name ) ;
key . dptr = keystr ;
key . dsize = strlen ( keystr ) ;
if ( delete ) {
tdb_delete ( tdb , key ) ;
return ;
}
data . dptr = ( void * ) & updating_pid ;
data . dsize = sizeof ( pid_t ) ;
tdb_store ( tdb , key , data , TDB_REPLACE ) ;
}
2000-04-16 10:20:02 +04:00
/****************************************************************************
update the internal database from the system print queue for a queue
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-02-22 20:39:36 +03:00
2000-04-16 10:20:02 +04:00
static void print_queue_update ( int snum )
{
char * path = lp_pathname ( snum ) ;
char * cmd = lp_lpqcommand ( snum ) ;
char * * qlines ;
2000-04-19 00:41:04 +04:00
pstring tmp_file ;
2000-04-16 10:20:02 +04:00
int numlines , i , qcount ;
print_queue_struct * queue = NULL ;
print_status_struct status ;
2000-11-21 03:30:15 +03:00
print_status_struct old_status ;
2000-04-16 10:20:02 +04:00
struct printjob * pjob ;
struct traverse_struct tstruct ;
2001-02-22 20:39:36 +03:00
fstring keystr , printer_name , cachestr ;
2000-04-16 10:20:02 +04:00
TDB_DATA data , key ;
2001-02-22 20:39:36 +03:00
2001-01-11 23:41:19 +03:00
/* Convert printer name (i.e. share name) to unix-codepage for all of the
* following tdb key generation */
2000-11-15 00:56:32 +03:00
fstrcpy ( printer_name , lp_servicename ( snum ) ) ;
2001-01-11 23:41:19 +03:00
dos_to_unix ( printer_name , True ) ;
2000-11-15 00:56:32 +03:00
2000-10-11 01:52:31 +04:00
/*
2001-02-22 20:39:36 +03:00
* Check to see if someone else is doing this update .
* This is essentially a mutex on the update .
2000-10-11 01:52:31 +04:00
*/
2001-02-23 06:59:37 +03:00
if ( get_updating_pid ( printer_name ) ! = - 1 )
return ;
2001-02-22 20:39:36 +03:00
2001-02-23 06:59:37 +03:00
/* Lock the queue for the database update */
2001-02-22 20:39:36 +03:00
2001-02-23 06:59:37 +03:00
slprintf ( keystr , sizeof ( keystr ) - 1 , " LOCK/%s " , printer_name ) ;
tdb_lock_bystring ( tdb , keystr ) ;
2001-02-22 20:39:36 +03:00
2001-02-23 06:59:37 +03:00
/*
* Ensure that no one else got in here .
* If the updating pid is still - 1 then we are
* the winner .
*/
2001-02-22 20:39:36 +03:00
2001-02-23 06:59:37 +03:00
if ( get_updating_pid ( printer_name ) ! = - 1 ) {
2001-02-22 20:39:36 +03:00
/*
2001-02-23 06:59:37 +03:00
* Someone else is doing the update , exit .
2001-02-22 20:39:36 +03:00
*/
2001-02-23 06:59:37 +03:00
tdb_unlock_bystring ( tdb , keystr ) ;
return ;
}
2001-02-22 20:39:36 +03:00
2001-02-23 06:59:37 +03:00
/*
* We ' re going to do the update ourselves .
*/
2001-02-22 20:39:36 +03:00
2001-02-23 06:59:37 +03:00
/* Tell others we're doing the update. */
set_updating_pid ( printer_name , False ) ;
2001-02-22 20:39:36 +03:00
2001-02-23 06:59:37 +03:00
/*
* Allow others to enter and notice we ' re doing
* the update .
*/
2001-02-22 20:39:36 +03:00
2001-02-23 06:59:37 +03:00
tdb_unlock_bystring ( tdb , keystr ) ;
2001-02-22 20:39:36 +03:00
2001-02-23 06:59:37 +03:00
/*
* Update the cache time FIRST ! Stops others even
* attempting to get the lock and doing this
* if the lpq takes a long time .
*/
2001-02-22 20:39:36 +03:00
2001-02-23 06:59:37 +03:00
slprintf ( cachestr , sizeof ( cachestr ) , " CACHE/%s " , printer_name ) ;
tdb_store_int ( tdb , cachestr , ( int ) time ( NULL ) ) ;
2000-10-11 01:52:31 +04:00
2000-04-19 00:41:04 +04:00
slprintf ( tmp_file , sizeof ( tmp_file ) , " %s/smblpq.%d " , path , local_pid ) ;
2000-04-16 10:20:02 +04:00
2000-04-19 00:41:04 +04:00
unlink ( tmp_file ) ;
2000-11-11 01:05:08 +03:00
print_run_command ( snum , cmd , tmp_file , NULL ) ;
2000-04-16 10:20:02 +04:00
numlines = 0 ;
2000-12-07 22:26:04 +03:00
qlines = file_lines_load ( tmp_file , & numlines , True ) ;
2000-04-19 00:41:04 +04:00
unlink ( tmp_file ) ;
2000-04-16 10:20:02 +04:00
/* turn the lpq output into a series of job structures */
qcount = 0 ;
ZERO_STRUCT ( status ) ;
2000-10-10 22:40:03 +04:00
if ( numlines )
queue = ( print_queue_struct * ) malloc ( sizeof ( print_queue_struct ) * ( numlines + 1 ) ) ;
if ( queue ) {
for ( i = 0 ; i < numlines ; i + + ) {
/* parse the line */
if ( parse_lpq_entry ( snum , qlines [ i ] ,
& queue [ qcount ] , & status , qcount = = 0 ) ) {
qcount + + ;
}
}
}
2000-04-16 10:20:02 +04:00
file_lines_free ( qlines ) ;
2000-11-11 01:05:08 +03:00
DEBUG ( 3 , ( " %d job%s in queue for %s \n " , qcount , ( qcount ! = 1 ) ?
2000-11-15 00:56:32 +03:00
" s " : " " , printer_name ) ) ;
2000-11-11 01:05:08 +03:00
2000-04-16 10:20:02 +04:00
/*
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
is added as a unix job
fill in any system job numbers as we go
*/
for ( i = 0 ; i < qcount ; i + + ) {
int jobid = print_parse_jobid ( queue [ i ] . file ) ;
if ( jobid = = - 1 ) {
/* assume its a unix print job */
print_unix_job ( snum , & queue [ i ] ) ;
continue ;
}
1998-08-14 21:38:29 +04:00
2000-04-16 10:20:02 +04:00
/* we have an active SMB print job - update its status */
pjob = print_job_find ( 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 ] ) ;
1998-08-14 21:38:29 +04:00
continue ;
2000-04-16 10:20:02 +04:00
}
1998-08-14 21:38:29 +04:00
2000-04-16 10:20:02 +04:00
pjob - > sysjob = queue [ i ] . job ;
pjob - > status = queue [ i ] . status ;
print_job_store ( jobid , pjob ) ;
1998-08-14 21:38:29 +04:00
}
2000-04-16 10:20:02 +04:00
/* now delete any queued entries that don't appear in the
system queue */
tstruct . queue = queue ;
tstruct . qcount = qcount ;
tstruct . snum = snum ;
2001-01-23 23:25:25 +03:00
tstruct . total_jobs = 0 ;
2000-04-16 10:20:02 +04:00
tdb_traverse ( tdb , traverse_fn_delete , ( void * ) & tstruct ) ;
safe_free ( tstruct . queue ) ;
2001-01-23 23:25:25 +03:00
tdb_store_int ( tdb , " INFO/total_jobs " , tstruct . total_jobs ) ;
2000-11-21 03:30:15 +03:00
/*
* Get the old print status . We will use this to compare the
* number of jobs . If they have changed we need to send a
* " changed " message to the smbds .
*/
if ( qcount ! = get_queue_status ( snum , & old_status ) ) {
DEBUG ( 10 , ( " print_queue_update: queue status change %d jobs -> %d jobs for printer %s \n " ,
old_status . qcount , qcount , printer_name ) ) ;
2000-12-15 04:02:11 +03:00
message_send_all ( conn_tdb_ctx ( ) , MSG_PRINTER_NOTIFY , printer_name , strlen ( printer_name ) + 1 , False ) ;
2000-11-21 03:30:15 +03:00
}
/* store the new queue status structure */
2000-11-15 00:56:32 +03:00
slprintf ( keystr , sizeof ( keystr ) , " STATUS/%s " , printer_name ) ;
2001-02-22 20:39:36 +03:00
key . dptr = keystr ;
2000-04-16 10:20:02 +04:00
key . dsize = strlen ( keystr ) ;
2000-11-21 03:30:15 +03:00
status . qcount = qcount ;
data . dptr = ( void * ) & status ;
data . dsize = sizeof ( status ) ;
2000-04-16 10:20:02 +04:00
tdb_store ( tdb , key , data , TDB_REPLACE ) ;
2000-10-11 01:52:31 +04:00
/*
* Update the cache time again . We want to do this call
* as little as possible . . .
*/
2000-11-15 00:56:32 +03:00
slprintf ( keystr , sizeof ( keystr ) , " CACHE/%s " , printer_name ) ;
2000-04-16 10:20:02 +04:00
tdb_store_int ( tdb , keystr , ( int ) time ( NULL ) ) ;
2001-02-22 20:39:36 +03:00
/* Delete our pid from the db. */
set_updating_pid ( printer_name , True ) ;
2000-04-16 10:20:02 +04:00
}
/****************************************************************************
check if a jobid is valid . It is valid if it exists in the database
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL print_job_exists ( int jobid )
{
return tdb_exists ( tdb , print_key ( jobid ) ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2000-04-16 10:20:02 +04:00
work out which service a jobid is for
note that we have to look up by queue name to ensure that it works for
other than the process that started the job
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-04-16 10:20:02 +04:00
int print_job_snum ( int jobid )
{
struct printjob * pjob = print_job_find ( jobid ) ;
if ( ! pjob ) return - 1 ;
return lp_servicenumber ( pjob - > qname ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2000-04-16 10:20:02 +04:00
give the fd used for a jobid
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-04-16 10:20:02 +04:00
int print_job_fd ( int jobid )
{
struct printjob * pjob = print_job_find ( jobid ) ;
if ( ! pjob ) return - 1 ;
/* don't allow another process to get this info - it is meaningless */
if ( pjob - > pid ! = local_pid ) return - 1 ;
return pjob - > fd ;
1996-05-04 11:50:46 +04:00
}
2000-04-16 10:20:02 +04:00
/****************************************************************************
give the filename used for a jobid
only valid for the process doing the spooling and when the job
has not been spooled
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char * print_job_fname ( int jobid )
{
struct printjob * pjob = print_job_find ( jobid ) ;
if ( ! pjob | | pjob - > spooled | | pjob - > pid ! = local_pid ) return NULL ;
return pjob - > filename ;
}
1996-05-04 11:50:46 +04:00
1997-08-31 06:18:59 +04:00
/****************************************************************************
2000-04-16 10:20:02 +04:00
set the place in the queue for a job
1997-08-31 06:18:59 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-04-16 10:20:02 +04:00
BOOL print_job_set_place ( int jobid , int place )
1997-08-31 06:18:59 +04:00
{
2000-04-16 10:20:02 +04:00
DEBUG ( 2 , ( " print_job_set_place not implemented yet \n " ) ) ;
return False ;
1997-08-31 06:18:59 +04:00
}
/****************************************************************************
2000-04-16 10:20:02 +04:00
set the name of a job . Only possible for owner
1997-08-31 06:18:59 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-04-16 10:20:02 +04:00
BOOL print_job_set_name ( int jobid , char * name )
1997-08-31 06:18:59 +04:00
{
2000-04-16 10:20:02 +04:00
struct printjob * pjob = print_job_find ( jobid ) ;
if ( ! pjob | | pjob - > pid ! = local_pid ) return False ;
fstrcpy ( pjob - > jobname , name ) ;
return print_job_store ( jobid , pjob ) ;
1997-08-31 06:18:59 +04:00
}
1998-07-16 04:06:29 +04:00
2000-04-16 10:20:02 +04:00
1998-07-16 04:06:29 +04:00
/****************************************************************************
2000-04-16 10:20:02 +04:00
delete a print job - don ' t update queue
1998-07-16 04:06:29 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-04-16 10:20:02 +04:00
static BOOL print_job_delete1 ( int jobid )
1998-07-16 04:06:29 +04:00
{
2000-04-16 10:20:02 +04:00
struct printjob * pjob = print_job_find ( jobid ) ;
2001-01-24 19:46:08 +03:00
int snum , result = 0 ;
1998-07-16 04:06:29 +04:00
2000-04-16 10:20:02 +04:00
if ( ! pjob ) return False ;
1998-07-16 04:06:29 +04:00
2001-02-23 06:59:37 +03:00
/*
* If already deleting just return .
*/
if ( pjob - > status = = LPQ_DELETING )
return True ;
2000-04-16 10:20:02 +04:00
snum = print_job_snum ( jobid ) ;
1998-07-16 04:06:29 +04:00
2001-01-22 19:59:24 +03:00
/* Hrm - we need to be able to cope with deleting a job before it
has reached the spooler . */
if ( pjob - > sysjob = = - 1 ) {
DEBUG ( 5 , ( " attempt to delete job %d not seen by lpr \n " ,
jobid ) ) ;
}
2001-02-23 06:59:37 +03:00
/* Set the tdb entry to be deleting. */
pjob - > status = LPQ_DELETING ;
print_job_store ( jobid , pjob ) ;
2000-04-16 10:20:02 +04:00
if ( pjob - > spooled & & pjob - > sysjob ! = - 1 ) {
fstring jobstr ;
2001-01-24 19:46:08 +03:00
/* need to delete the spooled entry */
2000-04-16 10:20:02 +04:00
slprintf ( jobstr , sizeof ( jobstr ) , " %d " , pjob - > sysjob ) ;
2001-01-24 19:46:08 +03:00
result = print_run_command (
snum ,
lp_lprmcommand ( snum ) , NULL ,
" %j " , jobstr ,
" %T " , http_timestring ( pjob - > starttime ) ,
NULL ) ;
}
return ( result = = 0 ) ;
1998-07-16 04:06:29 +04:00
}
1998-08-14 21:38:29 +04:00
2000-07-17 06:42:25 +04:00
/****************************************************************************
2000-09-13 08:42:06 +04:00
return true if the current user owns the print job
2000-07-17 06:42:25 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-09-13 08:42:06 +04:00
static BOOL is_owner ( struct current_user * user , int jobid )
2000-07-10 09:08:21 +04:00
{
struct printjob * pjob = print_job_find ( jobid ) ;
2000-09-13 08:42:06 +04:00
user_struct * vuser ;
2000-07-10 09:08:21 +04:00
2000-09-13 08:42:06 +04:00
if ( ! pjob | | ! user ) return False ;
2000-07-10 09:08:21 +04:00
2000-09-13 08:42:06 +04:00
if ( ( vuser = get_valid_user_struct ( user - > vuid ) ) ! = NULL ) {
2001-02-22 04:31:55 +03:00
return strequal ( pjob - > user ,
unix_to_dos ( vuser - > user . smb_name , False ) ) ;
2000-09-13 08:42:06 +04:00
} else {
2001-02-22 04:31:55 +03:00
return strequal ( pjob - > user ,
unix_to_dos ( uidtoname ( user - > uid ) , False ) ) ;
2000-09-13 08:42:06 +04:00
}
2000-07-10 09:08:21 +04:00
}
2000-04-16 10:20:02 +04:00
/****************************************************************************
delete a print job
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-11-08 02:05:53 +03:00
BOOL print_job_delete ( struct current_user * user , int jobid , int * errcode )
1998-08-14 21:38:29 +04:00
{
2000-04-16 10:20:02 +04:00
int snum = print_job_snum ( jobid ) ;
2000-11-08 02:05:53 +03:00
char * printer_name ;
2000-07-17 06:42:25 +04:00
BOOL owner ;
2000-09-13 08:42:06 +04:00
owner = is_owner ( user , jobid ) ;
2000-07-17 06:42:25 +04:00
2000-07-10 09:08:21 +04:00
/* Check access against security descriptor or whether the user
owns their job . */
2000-07-17 06:42:25 +04:00
if ( ! owner & &
2001-01-19 19:57:39 +03:00
! print_access_check ( user , snum , JOB_ACCESS_ADMINISTER ) ) {
2000-06-16 12:21:51 +04:00
DEBUG ( 3 , ( " delete denied by security descriptor \n " ) ) ;
2000-11-08 02:05:53 +03:00
* errcode = ERROR_ACCESS_DENIED ;
2000-06-16 12:21:51 +04:00
return False ;
}
2000-04-16 10:20:02 +04:00
if ( ! print_job_delete1 ( jobid ) ) return False ;
1998-08-14 21:38:29 +04:00
2000-04-16 10:20:02 +04:00
/* force update the database and say the delete failed if the
job still exists */
2000-07-17 06:42:25 +04:00
2000-04-16 10:20:02 +04:00
print_queue_update ( snum ) ;
1998-08-14 21:38:29 +04:00
2000-11-08 02:05:53 +03:00
/* Send a printer notify message */
printer_name = PRINTERNAME ( snum ) ;
2000-12-15 04:02:11 +03:00
message_send_all ( conn_tdb_ctx ( ) , MSG_PRINTER_NOTIFY , printer_name , strlen ( printer_name ) + 1 , False ) ;
2000-11-08 02:05:53 +03:00
2000-04-16 10:20:02 +04:00
return ! print_job_exists ( jobid ) ;
1998-08-14 21:38:29 +04:00
}
2000-04-16 10:20:02 +04:00
/****************************************************************************
pause a job
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-11-08 02:05:53 +03:00
BOOL print_job_pause ( struct current_user * user , int jobid , int * errcode )
1998-08-14 21:38:29 +04:00
{
2000-04-16 10:20:02 +04:00
struct printjob * pjob = print_job_find ( jobid ) ;
2000-04-16 12:03:37 +04:00
int snum , ret = - 1 ;
2000-11-08 02:05:53 +03:00
char * printer_name ;
2000-04-16 12:03:37 +04:00
fstring jobstr ;
2000-07-17 06:42:25 +04:00
BOOL owner ;
if ( ! pjob | | ! user ) return False ;
2000-04-16 10:20:02 +04:00
2000-04-16 12:03:37 +04:00
if ( ! pjob - > spooled | | pjob - > sysjob = = - 1 ) return False ;
2000-04-16 10:20:02 +04:00
snum = print_job_snum ( jobid ) ;
2000-09-13 08:42:06 +04:00
owner = is_owner ( user , jobid ) ;
2000-04-16 10:20:02 +04:00
2000-07-17 06:42:25 +04:00
if ( ! owner & &
2001-01-19 19:57:39 +03:00
! print_access_check ( user , snum , JOB_ACCESS_ADMINISTER ) ) {
2000-06-16 12:21:51 +04:00
DEBUG ( 3 , ( " pause denied by security descriptor \n " ) ) ;
2000-11-08 02:05:53 +03:00
* errcode = ERROR_ACCESS_DENIED ;
2000-06-16 12:21:51 +04:00
return False ;
}
2000-04-16 12:03:37 +04:00
/* need to pause the spooled entry */
slprintf ( jobstr , sizeof ( jobstr ) , " %d " , pjob - > sysjob ) ;
ret = print_run_command ( snum ,
lp_lppausecommand ( snum ) , NULL ,
" %j " , jobstr ,
2000-06-03 10:18:43 +04:00
NULL ) ;
1998-08-14 21:38:29 +04:00
2000-11-08 02:05:53 +03:00
if ( ret ! = 0 ) {
* errcode = ERROR_INVALID_PARAMETER ;
return False ;
}
2000-04-16 10:20:02 +04:00
/* force update the database */
print_cache_flush ( snum ) ;
1998-08-14 21:38:29 +04:00
2000-11-08 02:05:53 +03:00
/* Send a printer notify message */
printer_name = PRINTERNAME ( snum ) ;
2000-12-15 04:02:11 +03:00
message_send_all ( conn_tdb_ctx ( ) , MSG_PRINTER_NOTIFY , printer_name , strlen ( printer_name ) + 1 , False ) ;
2000-11-08 02:05:53 +03:00
2000-04-16 10:20:02 +04:00
/* how do we tell if this succeeded? */
2000-11-08 02:05:53 +03:00
return True ;
2000-04-16 10:20:02 +04:00
}
1998-08-14 21:38:29 +04:00
2000-04-16 10:20:02 +04:00
/****************************************************************************
resume a job
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-11-08 02:05:53 +03:00
BOOL print_job_resume ( struct current_user * user , int jobid , int * errcode )
2000-04-16 10:20:02 +04:00
{
struct printjob * pjob = print_job_find ( jobid ) ;
2000-11-08 02:05:53 +03:00
char * printer_name ;
2000-04-16 12:03:37 +04:00
int snum , ret ;
fstring jobstr ;
2000-07-17 06:42:25 +04:00
if ( ! pjob | | ! user ) return False ;
2000-04-16 10:20:02 +04:00
2000-04-16 12:03:37 +04:00
if ( ! pjob - > spooled | | pjob - > sysjob = = - 1 ) return False ;
2000-04-16 10:20:02 +04:00
snum = print_job_snum ( jobid ) ;
2000-09-13 08:42:06 +04:00
if ( ! is_owner ( user , jobid ) & &
2001-01-19 19:57:39 +03:00
! print_access_check ( user , snum , JOB_ACCESS_ADMINISTER ) ) {
2000-06-16 12:21:51 +04:00
DEBUG ( 3 , ( " resume denied by security descriptor \n " ) ) ;
2000-11-08 02:05:53 +03:00
* errcode = ERROR_ACCESS_DENIED ;
2000-06-16 12:21:51 +04:00
return False ;
}
2000-04-16 12:03:37 +04:00
slprintf ( jobstr , sizeof ( jobstr ) , " %d " , pjob - > sysjob ) ;
ret = print_run_command ( snum ,
lp_lpresumecommand ( snum ) , NULL ,
" %j " , jobstr ,
2000-06-03 10:18:43 +04:00
NULL ) ;
2000-04-16 10:20:02 +04:00
2000-11-08 02:05:53 +03:00
if ( ret ! = 0 ) {
* errcode = ERROR_INVALID_PARAMETER ;
return False ;
}
2000-04-16 10:20:02 +04:00
/* force update the database */
print_cache_flush ( snum ) ;
2000-11-08 02:05:53 +03:00
/* Send a printer notify message */
printer_name = PRINTERNAME ( snum ) ;
2000-12-15 04:02:11 +03:00
message_send_all ( conn_tdb_ctx ( ) , MSG_PRINTER_NOTIFY , printer_name , strlen ( printer_name ) + 1 , False ) ;
2000-11-08 02:05:53 +03:00
return True ;
1998-08-14 21:38:29 +04:00
}
2000-04-16 10:20:02 +04:00
/****************************************************************************
write to a print file
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int print_job_write ( int jobid , const char * buf , int size )
1998-08-14 21:38:29 +04:00
{
2000-04-16 10:20:02 +04:00
int fd ;
fd = print_job_fd ( jobid ) ;
if ( fd = = - 1 ) return - 1 ;
return write ( fd , buf , size ) ;
1998-08-14 21:38:29 +04:00
}
2000-04-10 17:00:12 +04:00
2000-10-11 06:26:27 +04:00
/****************************************************************************
Check if the print queue has been updated recently enough .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL print_cache_expired ( int snum )
{
fstring key ;
time_t t2 , t = time ( NULL ) ;
2000-11-11 01:05:08 +03:00
2000-10-11 06:26:27 +04:00
slprintf ( key , sizeof ( key ) , " CACHE/%s " , lp_servicename ( snum ) ) ;
2001-01-11 23:41:19 +03:00
dos_to_unix ( key , True ) ; /* Convert key to unix-codepage */
2000-10-11 06:26:27 +04:00
t2 = tdb_fetch_int ( tdb , key ) ;
if ( t2 = = ( ( time_t ) - 1 ) | | ( t - t2 ) > = lp_lpqcachetime ( ) ) {
2000-11-11 01:05:08 +03:00
DEBUG ( 3 , ( " print cache expired \n " ) ) ;
2000-10-11 06:26:27 +04:00
return True ;
}
return False ;
}
/****************************************************************************
2000-11-21 03:30:15 +03:00
Get the queue status - do not update if db is out of date .
2000-10-11 06:26:27 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-11-21 03:30:15 +03:00
static int get_queue_status ( int snum , print_status_struct * status )
2000-10-11 06:26:27 +04:00
{
fstring keystr ;
TDB_DATA data , key ;
2000-11-21 03:30:15 +03:00
ZERO_STRUCTP ( status ) ;
2000-10-11 06:26:27 +04:00
slprintf ( keystr , sizeof ( keystr ) , " STATUS/%s " , lp_servicename ( snum ) ) ;
2001-01-11 23:41:19 +03:00
dos_to_unix ( keystr , True ) ; /* Convert key to unix-codepage */
2000-10-11 06:26:27 +04:00
key . dptr = keystr ;
key . dsize = strlen ( keystr ) ;
data = tdb_fetch ( tdb , key ) ;
if ( data . dptr ) {
2000-11-21 03:30:15 +03:00
if ( data . dsize = = sizeof ( print_status_struct ) ) {
memcpy ( status , data . dptr , sizeof ( print_status_struct ) ) ;
2000-10-11 06:26:27 +04:00
}
free ( data . dptr ) ;
}
2000-11-21 03:30:15 +03:00
return status - > qcount ;
}
/****************************************************************************
Determine the number of jobs in a queue .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int print_queue_length ( int snum )
{
print_status_struct status ;
/* make sure the database is up to date */
if ( print_cache_expired ( snum ) ) print_queue_update ( snum ) ;
/* also fetch the queue status */
return get_queue_status ( snum , & status ) ;
2000-10-11 06:26:27 +04:00
}
2000-04-10 17:00:12 +04:00
2001-01-23 23:25:25 +03:00
/****************************************************************************
Determine the number of jobs in all queues .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int get_total_jobs ( int snum )
{
int total_jobs ;
/* make sure the database is up to date */
if ( print_cache_expired ( snum ) ) print_queue_update ( snum ) ;
total_jobs = tdb_fetch_int ( tdb , " INFO/total_jobs " ) ;
if ( total_jobs > 0 )
return total_jobs ;
else
return 0 ;
}
2000-04-16 10:20:02 +04:00
/***************************************************************************
start spooling a job - return the jobid
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-07-06 11:06:05 +04:00
int print_job_start ( struct current_user * user , int snum , char * jobname )
2000-04-10 17:00:12 +04:00
{
2000-04-16 10:20:02 +04:00
int jobid ;
char * path ;
struct printjob pjob ;
int next_jobid ;
2000-09-13 08:42:06 +04:00
user_struct * vuser ;
2000-04-10 17:00:12 +04:00
2000-08-24 03:05:49 +04:00
errno = 0 ;
2000-09-01 22:49:26 +04:00
if ( ! print_access_check ( user , snum , PRINTER_ACCESS_USE ) ) {
2000-09-13 06:24:35 +04:00
DEBUG ( 3 , ( " print_job_start: job start denied by security descriptor \n " ) ) ;
return - 1 ;
}
if ( ! print_time_access_check ( snum ) ) {
DEBUG ( 3 , ( " print_job_start: job start denied by time check \n " ) ) ;
2000-09-01 22:49:26 +04:00
return - 1 ;
2000-06-16 12:21:51 +04:00
}
2000-04-16 10:20:02 +04:00
path = lp_pathname ( snum ) ;
2000-04-10 17:00:12 +04:00
/* see if we have sufficient disk space */
2000-04-16 10:20:02 +04:00
if ( lp_minprintspace ( snum ) ) {
2000-04-19 12:44:56 +04:00
SMB_BIG_UINT dspace , dsize ;
if ( sys_fsusage ( path , & dspace , & dsize ) = = 0 & &
dspace < 2 * ( SMB_BIG_UINT ) lp_minprintspace ( snum ) ) {
2000-04-10 17:00:12 +04:00
errno = ENOSPC ;
2000-04-16 10:20:02 +04:00
return - 1 ;
2000-04-10 17:00:12 +04:00
}
}
2000-05-10 15:49:06 +04:00
/* for autoloaded printers, check that the printcap entry still exists */
if ( lp_autoloaded ( snum ) & & ! pcap_printername_ok ( lp_servicename ( snum ) , NULL ) ) {
errno = ENOENT ;
return - 1 ;
}
2001-01-23 23:25:25 +03:00
/* Insure the maximum queue size is not violated */
2001-01-04 22:27:08 +03:00
if ( lp_maxprintjobs ( snum ) & & print_queue_length ( snum ) > lp_maxprintjobs ( snum ) ) {
2000-10-11 06:26:27 +04:00
errno = ENOSPC ;
return - 1 ;
}
2001-01-23 23:25:25 +03:00
/* Insure the maximum print jobs in the system is not violated */
if ( lp_totalprintjobs ( ) & & get_total_jobs ( snum ) > lp_totalprintjobs ( ) ) {
errno = ENOSPC ;
return - 1 ;
}
2000-04-16 10:20:02 +04:00
/* create the database entry */
ZERO_STRUCT ( pjob ) ;
pjob . pid = local_pid ;
pjob . sysjob = - 1 ;
pjob . fd = - 1 ;
pjob . starttime = time ( NULL ) ;
2001-02-23 06:59:37 +03:00
pjob . status = LPQ_SPOOLING ;
2000-04-16 10:20:02 +04:00
pjob . size = 0 ;
pjob . spooled = False ;
pjob . smbjob = True ;
fstrcpy ( pjob . jobname , jobname ) ;
2000-09-13 08:42:06 +04:00
if ( ( vuser = get_valid_user_struct ( user - > vuid ) ) ! = NULL ) {
2001-02-22 04:31:55 +03:00
fstrcpy ( pjob . user , unix_to_dos ( vuser - > user . smb_name , False ) ) ;
2000-09-13 08:42:06 +04:00
} else {
2001-02-22 04:31:55 +03:00
fstrcpy ( pjob . user , unix_to_dos ( uidtoname ( user - > uid ) , False ) ) ;
2000-09-13 08:42:06 +04:00
}
2000-04-16 10:20:02 +04:00
fstrcpy ( pjob . qname , lp_servicename ( snum ) ) ;
/* lock the database */
2000-10-10 10:45:09 +04:00
tdb_lock_bystring ( tdb , " INFO/nextjob " ) ;
2000-04-16 10:20:02 +04:00
2000-09-01 22:49:26 +04:00
next_jobnum :
2000-05-12 10:27:35 +04:00
next_jobid = tdb_fetch_int ( tdb , " INFO/nextjob " ) ;
2000-04-16 10:20:02 +04:00
if ( next_jobid = = - 1 ) next_jobid = 1 ;
2001-02-22 04:31:55 +03:00
for ( jobid = NEXT_JOBID ( next_jobid ) ; jobid ! = next_jobid ; jobid = NEXT_JOBID ( jobid ) ) {
2000-04-16 10:20:02 +04:00
if ( ! print_job_exists ( jobid ) ) break ;
}
if ( jobid = = next_jobid | | ! print_job_store ( jobid , & pjob ) ) {
jobid = - 1 ;
goto fail ;
2000-04-10 17:00:12 +04:00
}
2000-04-16 10:20:02 +04:00
tdb_store_int ( tdb , " INFO/nextjob " , jobid ) ;
2000-04-10 17:00:12 +04:00
2000-04-16 10:20:02 +04:00
/* we have a job entry - now create the spool file
we unlink first to cope with old spool files and also to beat
a symlink security hole - it allows us to use O_EXCL
2000-09-01 22:49:26 +04:00
There may be old spool files owned by other users lying around .
2000-04-16 10:20:02 +04:00
*/
slprintf ( pjob . filename , sizeof ( pjob . filename ) , " %s/%s%d " ,
path , PRINT_SPOOL_PREFIX , jobid ) ;
if ( unlink ( pjob . filename ) = = - 1 & & errno ! = ENOENT ) {
2000-09-01 22:49:26 +04:00
goto next_jobnum ;
2000-04-10 17:00:12 +04:00
}
2000-04-16 10:20:02 +04:00
pjob . fd = sys_open ( pjob . filename , O_WRONLY | O_CREAT | O_EXCL , 0600 ) ;
2001-02-22 04:31:55 +03:00
if ( pjob . fd = = - 1 ) goto fail ;
2000-04-16 10:20:02 +04:00
print_job_store ( jobid , & pjob ) ;
2000-10-10 10:45:09 +04:00
tdb_unlock_bystring ( tdb , " INFO/nextjob " ) ;
2000-09-01 22:49:26 +04:00
2000-04-10 17:00:12 +04:00
/*
* If the printer is marked as postscript output a leading
* file identifier to ensure the file is treated as a raw
* postscript file .
* This has a similar effect as CtrlD = 0 in WIN . INI file .
* tim @ fsg . com 09 / 06 / 94
*/
2000-04-16 10:20:02 +04:00
if ( lp_postscript ( snum ) ) {
print_job_write ( jobid , " %! \n " , 3 ) ;
2000-04-10 17:00:12 +04:00
}
2000-04-16 10:20:02 +04:00
return jobid ;
fail :
if ( jobid ! = - 1 ) {
tdb_delete ( tdb , print_key ( jobid ) ) ;
}
2000-10-10 10:45:09 +04:00
tdb_unlock_bystring ( tdb , " INFO/nextjob " ) ;
2000-08-24 03:05:49 +04:00
return - 1 ;
2000-04-16 10:20:02 +04:00
}
/****************************************************************************
2000-08-01 04:41:19 +04:00
Print a file - called on closing the file . This spools the job .
2001-01-30 00:34:08 +03:00
If normal close is false then we ' re tearing down the jobs - treat as an
error .
2000-04-16 10:20:02 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-08-01 04:41:19 +04:00
2001-01-30 00:34:08 +03:00
BOOL print_job_end ( int jobid , BOOL normal_close )
2000-04-16 10:20:02 +04:00
{
struct printjob * pjob = print_job_find ( jobid ) ;
2001-01-22 19:59:24 +03:00
int snum , ret ;
2000-04-16 10:20:02 +04:00
SMB_STRUCT_STAT sbuf ;
pstring current_directory ;
pstring print_directory ;
2001-01-22 22:46:22 +03:00
char * wd , * p ;
2000-06-03 10:18:43 +04:00
pstring jobname ;
2000-04-16 10:20:02 +04:00
2000-08-01 04:41:19 +04:00
if ( ! pjob )
return False ;
2000-04-16 10:20:02 +04:00
2000-08-01 04:41:19 +04:00
if ( pjob - > spooled | | pjob - > pid ! = local_pid )
return False ;
2000-04-16 10:20:02 +04:00
snum = print_job_snum ( jobid ) ;
2001-01-30 00:34:08 +03:00
if ( normal_close & & ( sys_fstat ( pjob - > fd , & sbuf ) = = 0 ) ) {
2000-08-01 04:41:19 +04:00
pjob - > size = sbuf . st_size ;
2001-01-19 19:57:39 +03:00
close ( pjob - > fd ) ;
pjob - > fd = - 1 ;
} else {
2001-01-30 00:34:08 +03:00
/*
* Not a normal close or we couldn ' t stat the job file ,
* so something has gone wrong . Cleanup .
*/
2001-02-22 04:31:55 +03:00
close ( pjob - > fd ) ;
pjob - > fd = - 1 ;
goto fail ;
2001-01-19 19:57:39 +03:00
}
2001-02-22 04:31:55 +03:00
/* Technically, this is not quit right. If the printer has a separator
* page turned on , the NT spooler prints the separator page even if the
* print job is 0 bytes . 010215 JRR */
2001-02-23 06:59:37 +03:00
if ( pjob - > size = = 0 | | pjob - > status = = LPQ_DELETING ) {
/* don't bother spooling empty files or something being deleted. */
DEBUG ( 5 , ( " print_job_end: canceling spool of %s (%s) \n " ,
pjob - > filename , pjob - > size ? " deleted " : " zero length " ) ) ;
2000-04-16 10:20:02 +04:00
unlink ( pjob - > filename ) ;
tdb_delete ( tdb , print_key ( jobid ) ) ;
return True ;
}
/* we print from the directory path to give the best chance of
parsing the lpq output */
wd = sys_getwd ( current_directory ) ;
2001-02-22 04:31:55 +03:00
if ( ! wd ) goto fail ;
2000-04-16 10:20:02 +04:00
pstrcpy ( print_directory , pjob - > filename ) ;
p = strrchr ( print_directory , ' / ' ) ;
2001-02-22 04:31:55 +03:00
if ( ! p ) goto fail ;
2000-04-16 10:20:02 +04:00
* p + + = 0 ;
2001-02-22 04:31:55 +03:00
if ( chdir ( print_directory ) ! = 0 ) goto fail ;
2000-04-16 10:20:02 +04:00
2000-06-03 10:18:43 +04:00
pstrcpy ( jobname , pjob - > jobname ) ;
pstring_sub ( jobname , " ' " , " _ " ) ;
2000-04-16 10:20:02 +04:00
/* send it to the system spooler */
2001-01-22 19:59:24 +03:00
ret = print_run_command ( snum ,
2000-04-16 10:20:02 +04:00
lp_printcommand ( snum ) , NULL ,
" %s " , p ,
2000-06-03 10:18:43 +04:00
" %J " , jobname ,
" %f " , p ,
NULL ) ;
2000-04-16 10:20:02 +04:00
chdir ( wd ) ;
2001-02-22 04:31:55 +03:00
if ( ret ) goto fail ;
/* The print job has been sucessfully handed over to the back-end */
pjob - > spooled = True ;
2001-02-23 06:59:37 +03:00
pjob - > status = LPQ_QUEUED ;
2001-02-22 04:31:55 +03:00
print_job_store ( jobid , pjob ) ;
/* make sure the database is up to date */
if ( print_cache_expired ( snum ) ) print_queue_update ( snum ) ;
return True ;
fail :
/* The print job was not succesfully started. Cleanup */
/* Still need to add proper error return propagation! 010122:JRR */
unlink ( pjob - > filename ) ;
tdb_delete ( tdb , print_key ( jobid ) ) ;
return False ;
2000-04-16 10:20:02 +04:00
}
2000-04-16 12:03:37 +04:00
/* utility fn to enumerate the print queue */
2000-04-16 10:20:02 +04:00
static int traverse_fn_queue ( TDB_CONTEXT * t , TDB_DATA key , TDB_DATA data , void * state )
{
struct traverse_struct * ts = ( struct traverse_struct * ) state ;
struct printjob pjob ;
int i , jobid ;
if ( data . dsize ! = sizeof ( pjob ) | | key . dsize ! = sizeof ( int ) ) return 0 ;
memcpy ( & jobid , key . dptr , sizeof ( jobid ) ) ;
memcpy ( & pjob , data . dptr , sizeof ( pjob ) ) ;
/* maybe it isn't for this queue */
if ( ts - > snum ! = print_queue_snum ( pjob . qname ) ) return 0 ;
2000-10-10 22:40:03 +04:00
if ( ts - > qcount > = ts - > maxcount ) return 0 ;
2000-04-16 10:20:02 +04:00
i = ts - > qcount ;
ts - > queue [ i ] . job = jobid ;
ts - > queue [ i ] . size = pjob . size ;
ts - > queue [ i ] . status = pjob . status ;
2000-07-07 03:31:46 +04:00
ts - > queue [ i ] . priority = 1 ;
2000-04-16 10:20:02 +04:00
ts - > queue [ i ] . time = pjob . starttime ;
fstrcpy ( ts - > queue [ i ] . user , pjob . user ) ;
fstrcpy ( ts - > queue [ i ] . file , pjob . jobname ) ;
ts - > qcount + + ;
return 0 ;
}
2000-10-10 22:40:03 +04:00
struct traverse_count_struct {
int snum , count ;
} ;
/* utility fn to count the number of entries in the print queue */
static int traverse_count_fn_queue ( TDB_CONTEXT * t , TDB_DATA key , TDB_DATA data , void * state )
{
struct traverse_count_struct * ts = ( struct traverse_count_struct * ) state ;
struct printjob pjob ;
int jobid ;
if ( data . dsize ! = sizeof ( pjob ) | | key . dsize ! = sizeof ( int ) ) return 0 ;
memcpy ( & jobid , key . dptr , sizeof ( jobid ) ) ;
memcpy ( & pjob , data . dptr , sizeof ( pjob ) ) ;
/* maybe it isn't for this queue */
if ( ts - > snum ! = print_queue_snum ( pjob . qname ) ) return 0 ;
ts - > count + + ;
return 0 ;
}
2000-11-04 21:24:15 +03:00
/* Sort print jobs by submittal time */
static int printjob_comp ( print_queue_struct * j1 , print_queue_struct * j2 )
{
/* Silly cases */
if ( ! j1 & & ! j2 ) return 0 ;
if ( ! j1 ) return - 1 ;
if ( ! j2 ) return 1 ;
/* Sort on job start time */
if ( j1 - > time = = j2 - > time ) return 0 ;
return ( j1 - > time > j2 - > time ) ? 1 : - 1 ;
}
2000-04-16 10:20:02 +04:00
/****************************************************************************
get a printer queue listing
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int print_queue_status ( int snum ,
print_queue_struct * * queue ,
print_status_struct * status )
{
struct traverse_struct tstruct ;
2000-10-10 22:40:03 +04:00
struct traverse_count_struct tsc ;
2000-04-16 10:20:02 +04:00
fstring keystr ;
TDB_DATA data , key ;
/* make sure the database is up to date */
if ( print_cache_expired ( snum ) ) print_queue_update ( snum ) ;
2000-11-10 22:36:34 +03:00
* queue = NULL ;
2000-04-16 10:20:02 +04:00
2000-10-10 22:40:03 +04:00
/*
2000-12-14 00:24:06 +03:00
* Fetch the queue status . We must do this first , as there may
* be no jobs in the queue .
*/
ZERO_STRUCTP ( status ) ;
slprintf ( keystr , sizeof ( keystr ) , " STATUS/%s " , lp_servicename ( snum ) ) ;
2001-01-11 23:41:19 +03:00
dos_to_unix ( keystr , True ) ; /* Convert key to unix-codepage */
2000-12-14 00:24:06 +03:00
key . dptr = keystr ;
key . dsize = strlen ( keystr ) ;
data = tdb_fetch ( tdb , key ) ;
if ( data . dptr ) {
if ( data . dsize = = sizeof ( * status ) ) {
memcpy ( status , data . dptr , sizeof ( * status ) ) ;
}
free ( data . dptr ) ;
}
/*
* Now , fetch the print queue information . We first count the number
* of entries , and then only retrieve the queue if necessary .
2000-10-10 22:40:03 +04:00
*/
tsc . count = 0 ;
tsc . snum = snum ;
2000-12-14 00:24:06 +03:00
2000-10-10 22:40:03 +04:00
tdb_traverse ( tdb , traverse_count_fn_queue , ( void * ) & tsc ) ;
2000-11-10 22:36:34 +03:00
if ( tsc . count = = 0 )
return 0 ;
2000-10-10 22:40:03 +04:00
/* Allocate the queue size. */
2000-11-15 00:56:32 +03:00
if ( ( tstruct . queue = ( print_queue_struct * )
malloc ( sizeof ( print_queue_struct ) * tsc . count ) )
2000-10-10 22:40:03 +04:00
= = NULL )
return 0 ;
/*
* Fill in the queue .
* We need maxcount as the queue size may have changed between
* the two calls to tdb_traverse .
*/
2000-04-16 10:20:02 +04:00
tstruct . qcount = 0 ;
2000-10-10 22:40:03 +04:00
tstruct . maxcount = tsc . count ;
2000-04-16 10:20:02 +04:00
tstruct . snum = snum ;
tdb_traverse ( tdb , traverse_fn_queue , ( void * ) & tstruct ) ;
2000-11-04 21:24:15 +03:00
/* Sort the queue by submission time otherwise they are displayed
in hash order . */
qsort ( tstruct . queue , tstruct . qcount , sizeof ( print_queue_struct ) ,
QSORT_CAST ( printjob_comp ) ) ;
2000-04-16 10:20:02 +04:00
* queue = tstruct . queue ;
return tstruct . qcount ;
}
/****************************************************************************
turn a queue name into a snum
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int print_queue_snum ( char * qname )
{
int snum = lp_servicenumber ( qname ) ;
if ( snum = = - 1 | | ! lp_print_ok ( snum ) ) return - 1 ;
return snum ;
}
/****************************************************************************
pause a queue
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-08-30 04:45:59 +04:00
BOOL print_queue_pause ( struct current_user * user , int snum , int * errcode )
2000-04-16 10:20:02 +04:00
{
2000-11-08 02:05:53 +03:00
char * printer_name ;
2000-06-16 12:21:51 +04:00
int ret ;
2000-07-17 06:42:25 +04:00
2000-09-01 22:49:26 +04:00
if ( ! print_access_check ( user , snum , PRINTER_ACCESS_ADMINISTER ) ) {
2000-08-30 04:45:59 +04:00
* errcode = ERROR_ACCESS_DENIED ;
2000-06-16 12:21:51 +04:00
return False ;
}
2000-07-17 06:42:25 +04:00
ret = print_run_command ( snum , lp_queuepausecommand ( snum ) , NULL ,
NULL ) ;
2000-04-16 12:03:37 +04:00
2000-11-08 02:05:53 +03:00
if ( ret ! = 0 ) {
* errcode = ERROR_INVALID_PARAMETER ;
return False ;
}
2000-04-16 12:03:37 +04:00
/* force update the database */
print_cache_flush ( snum ) ;
2000-11-04 21:24:15 +03:00
/* Send a printer notify message */
2000-11-08 02:05:53 +03:00
printer_name = PRINTERNAME ( snum ) ;
2000-11-04 21:24:15 +03:00
2000-12-15 04:02:11 +03:00
message_send_all ( conn_tdb_ctx ( ) , MSG_PRINTER_NOTIFY , printer_name , strlen ( printer_name ) + 1 , False ) ;
2000-11-04 21:24:15 +03:00
2000-11-08 02:05:53 +03:00
return True ;
2000-04-16 10:20:02 +04:00
}
/****************************************************************************
resume a queue
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-08-30 04:45:59 +04:00
BOOL print_queue_resume ( struct current_user * user , int snum , int * errcode )
2000-04-16 10:20:02 +04:00
{
2000-11-08 02:05:53 +03:00
char * printer_name ;
2000-06-16 12:21:51 +04:00
int ret ;
2000-09-01 22:49:26 +04:00
if ( ! print_access_check ( user , snum , PRINTER_ACCESS_ADMINISTER ) ) {
2000-08-30 04:45:59 +04:00
* errcode = ERROR_ACCESS_DENIED ;
2000-06-16 12:21:51 +04:00
return False ;
}
2000-07-17 06:42:25 +04:00
ret = print_run_command ( snum , lp_queueresumecommand ( snum ) , NULL ,
NULL ) ;
2000-04-16 12:03:37 +04:00
2000-11-08 02:05:53 +03:00
if ( ret ! = 0 ) {
* errcode = ERROR_INVALID_PARAMETER ;
return False ;
}
2001-01-19 19:57:39 +03:00
/* make sure the database is up to date */
if ( print_cache_expired ( snum ) ) print_queue_update ( snum ) ;
2000-04-16 12:03:37 +04:00
2000-11-04 21:24:15 +03:00
/* Send a printer notify message */
2000-11-08 02:05:53 +03:00
printer_name = PRINTERNAME ( snum ) ;
2000-11-04 21:24:15 +03:00
2000-12-15 04:02:11 +03:00
message_send_all ( conn_tdb_ctx ( ) , MSG_PRINTER_NOTIFY , printer_name , strlen ( printer_name ) + 1 , False ) ;
2000-11-04 21:24:15 +03:00
2000-11-08 02:05:53 +03:00
return True ;
2000-04-16 10:20:02 +04:00
}
/****************************************************************************
purge a queue - implemented by deleting all jobs that we can delete
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-08-30 04:45:59 +04:00
BOOL print_queue_purge ( struct current_user * user , int snum , int * errcode )
2000-04-16 10:20:02 +04:00
{
print_queue_struct * queue ;
print_status_struct status ;
2000-11-04 21:24:15 +03:00
char * printer_name ;
2000-04-16 10:20:02 +04:00
int njobs , i ;
2001-01-22 19:59:24 +03:00
BOOL can_job_admin ;
2000-04-16 10:20:02 +04:00
2001-01-23 20:39:03 +03:00
/* Force and update so the count is accurate (i.e. not a cached count) */
print_queue_update ( snum ) ;
2001-01-22 19:59:24 +03:00
can_job_admin = print_access_check ( user , snum , JOB_ACCESS_ADMINISTER ) ;
2000-04-16 10:20:02 +04:00
njobs = print_queue_status ( snum , & queue , & status ) ;
2001-01-11 23:41:19 +03:00
2001-01-22 19:59:24 +03:00
for ( i = 0 ; i < njobs ; i + + ) {
BOOL owner = is_owner ( user , queue [ i ] . job ) ;
if ( owner | | can_job_admin ) {
2000-09-01 22:49:26 +04:00
print_job_delete1 ( queue [ i ] . job ) ;
}
2000-04-16 10:20:02 +04:00
}
2000-10-11 01:52:31 +04:00
safe_free ( queue ) ;
2000-04-16 10:20:02 +04:00
2000-11-04 21:24:15 +03:00
/* Send a printer notify message */
printer_name = PRINTERNAME ( snum ) ;
2000-12-15 04:02:11 +03:00
message_send_all ( conn_tdb_ctx ( ) , MSG_PRINTER_NOTIFY , printer_name , strlen ( printer_name ) + 1 , False ) ;
2000-11-04 21:24:15 +03:00
2000-04-16 10:20:02 +04:00
return True ;
}