📄 printing.c
字号:
if (new_job || !strequal(old_data->jobname, new_data->jobname)) notify_job_name(sharename, jobid, new_data->jobname); if (new_job || old_data->status != new_data->status) notify_job_status(sharename, jobid, map_to_spoolss_status(new_data->status)); if (new_job || old_data->size != new_data->size) notify_job_total_bytes(sharename, jobid, new_data->size); if (new_job || old_data->page_count != new_data->page_count) notify_job_total_pages(sharename, jobid, new_data->page_count);}/**************************************************************************** Store a job structure back to the database.****************************************************************************/static BOOL pjob_store(const char* sharename, uint32 jobid, struct printjob *pjob){ TDB_DATA old_data, new_data; BOOL ret = False; struct tdb_print_db *pdb = get_print_db_byname(sharename); char *buf = NULL; int len, newlen, buflen; if (!pdb) return False; /* Get old data */ old_data = tdb_fetch(pdb->tdb, print_key(jobid)); /* Doh! Now we have to pack/unpack data since the NT_DEVICEMODE was added */ newlen = 0; do { len = 0; buflen = newlen; len += tdb_pack(buf+len, buflen-len, "dddddddddffff", (uint32)pjob->pid, (uint32)pjob->sysjob, (uint32)pjob->fd, (uint32)pjob->starttime, (uint32)pjob->status, (uint32)pjob->size, (uint32)pjob->page_count, (uint32)pjob->spooled, (uint32)pjob->smbjob, pjob->filename, pjob->jobname, pjob->user, pjob->queuename); len += pack_devicemode(pjob->nt_devmode, buf+len, buflen-len); if (buflen != len) { char *tb; tb = (char *)SMB_REALLOC(buf, len); if (!tb) { DEBUG(0,("pjob_store: failed to enlarge buffer!\n")); goto done; } else buf = tb; newlen = len; } } while ( buflen != len ); /* Store new data */ new_data.dptr = buf; new_data.dsize = len; ret = (tdb_store(pdb->tdb, print_key(jobid), new_data, TDB_REPLACE) == 0); release_print_db(pdb); /* Send notify updates for what has changed */ if ( ret ) { struct printjob old_pjob; if ( old_data.dsize ) { if ( unpack_pjob( old_data.dptr, old_data.dsize, &old_pjob ) != -1 ) { pjob_store_notify( sharename, jobid, &old_pjob , pjob ); free_nt_devicemode( &old_pjob.nt_devmode ); } } else { /* new job */ pjob_store_notify( sharename, jobid, NULL, pjob ); } }done: SAFE_FREE( old_data.dptr ); SAFE_FREE( buf ); return ret;}/**************************************************************************** Remove a job structure from the database.****************************************************************************/void pjob_delete(const char* sharename, uint32 jobid){ struct printjob *pjob; uint32 job_status = 0; struct tdb_print_db *pdb; pdb = get_print_db_byname( sharename ); if (!pdb) return; pjob = print_job_find( sharename, jobid ); if (!pjob) { DEBUG(5, ("pjob_delete: we were asked to delete nonexistent job %u\n", (unsigned int)jobid)); release_print_db(pdb); return; } /* 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)); remove_from_jobs_changed(sharename, jobid); release_print_db( pdb ); 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.****************************************************************************/static void print_unix_job(const char *sharename, print_queue_struct *q, uint32 jobid){ struct printjob pj, *old_pj; if (jobid == (uint32)-1) jobid = q->job + UNIX_JOB_START; /* Preserve the timestamp on an existing unix print job */ old_pj = print_job_find(sharename, jobid); ZERO_STRUCT(pj); pj.pid = (pid_t)-1; pj.sysjob = q->job; pj.fd = -1; pj.starttime = old_pj ? old_pj->starttime : q->time; pj.status = q->status; pj.size = q->size; pj.spooled = True; fstrcpy(pj.filename, old_pj ? old_pj->filename : ""); if (jobid < UNIX_JOB_START) { pj.smbjob = True; fstrcpy(pj.jobname, old_pj ? old_pj->jobname : "Remote Downlevel Document"); } else { pj.smbjob = False; fstrcpy(pj.jobname, old_pj ? old_pj->jobname : q->fs_file); } fstrcpy(pj.user, old_pj ? old_pj->user : q->fs_user); fstrcpy(pj.queuename, old_pj ? old_pj->queuename : sharename ); pjob_store(sharename, jobid, &pj);}struct traverse_struct { print_queue_struct *queue; int qcount, snum, maxcount, total_jobs; const char *sharename; time_t lpq_time; const char *lprm_command; struct printif *print_if;};/**************************************************************************** Utility fn to delete any jobs that are no longer active.****************************************************************************/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; uint32 jobid; int i = 0; 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 ); if (!pjob.smbjob) { /* remove a unix job if it isn't in the system queue any more */ for (i=0;i<ts->qcount;i++) { uint32 u_jobid = (ts->queue[i].job + UNIX_JOB_START); if (jobid == u_jobid) break; } if (i == ts->qcount) { DEBUG(10,("traverse_fn_delete: pjob %u deleted due to !smbjob\n", (unsigned int)jobid )); pjob_delete(ts->sharename, jobid); return 0; } /* need to continue the the bottom of the function to save the correct attributes */ } /* maybe it hasn't been spooled yet */ if (!pjob.spooled) { /* if a job is not spooled and the process doesn't exist then kill it. This cleans up after smbd deaths */ if (!process_exists_by_pid(pjob.pid)) { DEBUG(10,("traverse_fn_delete: pjob %u deleted due to !process_exists (%u)\n", (unsigned int)jobid, (unsigned int)pjob.pid )); pjob_delete(ts->sharename, jobid); } else ts->total_jobs++; return 0; } /* this check only makes sense for jobs submitted from Windows clients */ if ( pjob.smbjob ) { for (i=0;i<ts->qcount;i++) { uint32 curr_jobid; if ( pjob.status == LPQ_DELETED ) continue; curr_jobid = print_parse_jobid(ts->queue[i].fs_file); if (jobid == curr_jobid) { /* try to clean up any jobs that need to be deleted */ if ( pjob.status == LPQ_DELETING ) { int result; result = (*(ts->print_if->job_delete))( ts->sharename, ts->lprm_command, &pjob ); if ( result != 0 ) { /* if we can't delete, then reset the job status */ pjob.status = LPQ_QUEUED; pjob_store(ts->sharename, jobid, &pjob); } else { /* if we deleted the job, the remove the tdb record */ pjob_delete(ts->sharename, jobid); pjob.status = LPQ_DELETED; } } break; } } } /* The job isn't in the system queue - we have to assume it has completed, so delete the database entry. */ if (i == ts->qcount) { /* 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. Don't delete the job if it was submitted after the lpq_time. */ if (pjob.starttime < ts->lpq_time) { DEBUG(10,("traverse_fn_delete: pjob %u deleted due to pjob.starttime (%u) < ts->lpq_time (%u)\n", (unsigned int)jobid, (unsigned int)pjob.starttime, (unsigned int)ts->lpq_time )); pjob_delete(ts->sharename, jobid); } else ts->total_jobs++; return 0; } /* Save the pjob attributes we will store. FIXME!!! This is the only place where queue->job represents the SMB jobid --jerry */ ts->queue[i].job = jobid; ts->queue[i].size = pjob.size; ts->queue[i].page_count = pjob.page_count; ts->queue[i].status = pjob.status; ts->queue[i].priority = 1; ts->queue[i].time = pjob.starttime; fstrcpy(ts->queue[i].fs_user, pjob.user); fstrcpy(ts->queue[i].fs_file, pjob.jobname); ts->total_jobs++; return 0;}/**************************************************************************** Check if the print queue has been updated recently enough.****************************************************************************/static void print_cache_flush(int snum){ fstring key; const char *sharename = lp_const_servicename(snum); struct tdb_print_db *pdb = get_print_db_byname(sharename); if (!pdb) return; slprintf(key, sizeof(key)-1, "CACHE/%s", sharename); tdb_store_int32(pdb->tdb, key, -1); release_print_db(pdb);}/**************************************************************************** Check if someone already thinks they are doing the update.****************************************************************************/static pid_t get_updating_pid(const char *sharename){ fstring keystr; TDB_DATA data, key; pid_t updating_pid; struct tdb_print_db *pdb = get_print_db_byname(sharename); if (!pdb) return (pid_t)-1; slprintf(keystr, sizeof(keystr)-1, "UPDATING/%s", sharename); key.dptr = keystr; key.dsize = strlen(keystr); data = tdb_fetch(pdb->tdb, key); release_print_db(pdb); if (!data.dptr || data.dsize != sizeof(pid_t)) { SAFE_FREE(data.dptr); return (pid_t)-1; } updating_pid = IVAL(data.dptr, 0); SAFE_FREE(data.dptr); if (process_exists_by_pid(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 the tdb.****************************************************************************/static void set_updating_pid(const fstring sharename, BOOL updating){ fstring keystr; TDB_DATA key; TDB_DATA data; pid_t updating_pid = sys_getpid(); uint8 buffer[4]; struct tdb_print_db *pdb = get_print_db_byname(sharename); if (!pdb) return; slprintf(keystr, sizeof(keystr)-1, "UPDATING/%s", sharename); key.dptr = keystr; key.dsize = strlen(keystr); DEBUG(5, ("set_updating_pid: %s updating lpq cache for print share %s\n", updating ? "" : "not ", sharename )); if ( !updating ) { tdb_delete(pdb->tdb, key); release_print_db(pdb); return; } SIVAL( buffer, 0, updating_pid); data.dptr = (void *)buffer; data.dsize = 4; /* we always assume this is a 4 byte value */ tdb_store(pdb->tdb, key, data, TDB_REPLACE); release_print_db(pdb);}/**************************************************************************** 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;}/**************************************************************************** Store the sorted queue representation for later portmon retrieval. Skip deleted jobs****************************************************************************/static void store_queue_struct(struct tdb_print_db *pdb, struct traverse_struct *pts){ TDB_DATA data; int max_reported_jobs = lp_max_reported_jobs(pts->snum); print_queue_struct *queue = pts->queue; size_t len; size_t i; uint qcount; if (max_reported_jobs && (max_reported_jobs < pts->qcount)) pts->qcount = max_reported_jobs; qcount = 0; /* Work out the size. */ data.dsize = 0; data.dsize += tdb_pack(NULL, 0, "d", qcount); for (i = 0; i < pts->qcount; i++) { if ( queue[i].status == LPQ_DELETED ) continue;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -