Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : printing command routines
4 : Copyright (C) Andrew Tridgell 1992-2000
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "lib/util/util_file.h"
22 : #include "printing.h"
23 : #include "smbd/proto.h"
24 : #include "source3/lib/substitute.h"
25 :
26 : extern userdom_struct current_user_info;
27 :
28 : /****************************************************************************
29 : Run a given print command
30 : a null terminated list of value/substitute pairs is provided
31 : for local substitution strings
32 : ****************************************************************************/
33 3155 : static int print_run_command(int snum, const char* printername, bool do_sub,
34 : const char *command, int *outfd, ...)
35 : {
36 0 : const struct loadparm_substitution *lp_sub =
37 3155 : loadparm_s3_global_substitution();
38 0 : char *syscmd;
39 0 : char *arg;
40 0 : int ret;
41 3155 : TALLOC_CTX *ctx = talloc_tos();
42 0 : va_list ap;
43 3155 : va_start(ap, outfd);
44 :
45 : /* check for a valid system printername and valid command to run */
46 :
47 3155 : if ( !printername || !*printername ) {
48 0 : va_end(ap);
49 0 : return -1;
50 : }
51 :
52 3155 : if (!command || !*command) {
53 0 : va_end(ap);
54 0 : return -1;
55 : }
56 :
57 3155 : syscmd = talloc_strdup(ctx, command);
58 3155 : if (!syscmd) {
59 0 : va_end(ap);
60 0 : return -1;
61 : }
62 :
63 3155 : DBG_DEBUG("Incoming command '%s'\n", syscmd);
64 :
65 7207 : while ((arg = va_arg(ap, char *))) {
66 4052 : char *value = va_arg(ap,char *);
67 4052 : syscmd = talloc_string_sub(ctx, syscmd, arg, value);
68 4052 : if (!syscmd) {
69 0 : va_end(ap);
70 0 : return -1;
71 : }
72 : }
73 3155 : va_end(ap);
74 :
75 3155 : syscmd = talloc_string_sub(ctx, syscmd, "%p", printername);
76 3155 : if (!syscmd) {
77 0 : return -1;
78 : }
79 :
80 3155 : syscmd = lpcfg_substituted_string(ctx, lp_sub, syscmd);
81 3155 : if (syscmd == NULL) {
82 0 : return -1;
83 : }
84 :
85 3155 : if (do_sub && snum != -1) {
86 1644 : syscmd = talloc_sub_advanced(ctx,
87 822 : lp_servicename(talloc_tos(), lp_sub, snum),
88 : current_user_info.unix_name,
89 : "",
90 : get_current_gid(NULL),
91 : syscmd);
92 822 : if (!syscmd) {
93 0 : return -1;
94 : }
95 : }
96 :
97 3155 : ret = smbrun_no_sanitize(syscmd, outfd, NULL);
98 :
99 3155 : DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
100 :
101 3155 : return ret;
102 : }
103 :
104 :
105 : /****************************************************************************
106 : delete a print job
107 : ****************************************************************************/
108 329 : static int generic_job_delete( const char *sharename, const char *lprm_command, struct printjob *pjob)
109 : {
110 0 : fstring jobstr;
111 :
112 : /* need to delete the spooled entry */
113 329 : fstr_sprintf(jobstr, "%d", pjob->sysjob);
114 329 : return print_run_command( -1, sharename, False, lprm_command, NULL,
115 : "%j", jobstr,
116 : "%T", http_timestring(talloc_tos(), pjob->starttime),
117 : NULL);
118 : }
119 :
120 : /****************************************************************************
121 : pause a job
122 : ****************************************************************************/
123 32 : static int generic_job_pause(int snum, struct printjob *pjob)
124 : {
125 0 : const struct loadparm_substitution *lp_sub =
126 32 : loadparm_s3_global_substitution();
127 0 : fstring jobstr;
128 :
129 : /* need to pause the spooled entry */
130 32 : fstr_sprintf(jobstr, "%d", pjob->sysjob);
131 32 : return print_run_command(snum, lp_printername(talloc_tos(), lp_sub, snum), True,
132 : lp_lppause_command(snum), NULL,
133 : "%j", jobstr,
134 : NULL);
135 : }
136 :
137 : /****************************************************************************
138 : resume a job
139 : ****************************************************************************/
140 32 : static int generic_job_resume(int snum, struct printjob *pjob)
141 : {
142 0 : const struct loadparm_substitution *lp_sub =
143 32 : loadparm_s3_global_substitution();
144 0 : fstring jobstr;
145 :
146 : /* need to pause the spooled entry */
147 32 : fstr_sprintf(jobstr, "%d", pjob->sysjob);
148 32 : return print_run_command(snum, lp_printername(talloc_tos(), lp_sub, snum), True,
149 : lp_lpresume_command(snum), NULL,
150 : "%j", jobstr,
151 : NULL);
152 : }
153 :
154 : /****************************************************************************
155 : get the current list of queued jobs
156 : ****************************************************************************/
157 2004 : static int generic_queue_get(const char *printer_name,
158 : enum printing_types printing_type,
159 : char *lpq_command,
160 : print_queue_struct **q,
161 : print_status_struct *status)
162 : {
163 0 : char **qlines;
164 0 : int fd;
165 0 : int numlines, i, qcount;
166 2004 : print_queue_struct *queue = NULL;
167 :
168 : /* never do substitution when running the 'lpq command' since we can't
169 : get it right when using the background update daemon. Make the caller
170 : do it before passing off the command string to us here. */
171 :
172 2004 : print_run_command(-1, printer_name, False, lpq_command, &fd, NULL);
173 :
174 2004 : if (fd == -1) {
175 0 : DEBUG(5,("generic_queue_get: Can't read print queue status for printer %s\n",
176 : printer_name ));
177 0 : return 0;
178 : }
179 :
180 2004 : numlines = 0;
181 2004 : qlines = fd_lines_load(fd, &numlines,0,NULL);
182 2004 : close(fd);
183 :
184 : /* turn the lpq output into a series of job structures */
185 2004 : qcount = 0;
186 2004 : ZERO_STRUCTP(status);
187 2004 : if (numlines && qlines) {
188 2004 : queue = SMB_MALLOC_ARRAY(print_queue_struct, numlines+1);
189 2004 : if (!queue) {
190 0 : TALLOC_FREE(qlines);
191 0 : *q = NULL;
192 0 : return 0;
193 : }
194 2004 : memset(queue, '\0', sizeof(print_queue_struct)*(numlines+1));
195 :
196 7870 : for (i=0; i<numlines; i++) {
197 : /* parse the line */
198 5866 : if (parse_lpq_entry(printing_type,qlines[i],
199 5866 : &queue[qcount],status,qcount==0)) {
200 3862 : qcount++;
201 : }
202 : }
203 : }
204 :
205 2004 : TALLOC_FREE(qlines);
206 2004 : *q = queue;
207 2004 : return qcount;
208 : }
209 :
210 : /****************************************************************************
211 : Submit a file for printing - called from print_job_end()
212 : ****************************************************************************/
213 :
214 666 : static int generic_job_submit(int snum, struct printjob *pjob,
215 : enum printing_types printing_type,
216 : char *lpq_cmd)
217 : {
218 666 : int ret = -1;
219 0 : const struct loadparm_substitution *lp_sub =
220 666 : loadparm_s3_global_substitution();
221 666 : char *current_directory = NULL;
222 666 : char *print_directory = NULL;
223 666 : char *wd = NULL;
224 666 : char *p = NULL;
225 666 : char *jobname = NULL;
226 666 : TALLOC_CTX *ctx = talloc_tos();
227 0 : fstring job_page_count, job_size;
228 0 : print_queue_struct *q;
229 0 : print_status_struct status;
230 :
231 : /* we print from the directory path to give the best chance of
232 : parsing the lpq output */
233 666 : wd = sys_getwd();
234 666 : if (!wd) {
235 0 : return -1;
236 : }
237 :
238 666 : current_directory = talloc_strdup(ctx, wd);
239 666 : SAFE_FREE(wd);
240 :
241 666 : if (!current_directory) {
242 0 : return -1;
243 : }
244 666 : print_directory = talloc_strdup(ctx, pjob->filename);
245 666 : if (!print_directory) {
246 0 : return -1;
247 : }
248 666 : p = strrchr_m(print_directory,'/');
249 666 : if (!p) {
250 0 : return -1;
251 : }
252 666 : *p++ = 0;
253 :
254 666 : if (chdir(print_directory) != 0) {
255 0 : return -1;
256 : }
257 :
258 666 : jobname = talloc_strdup(ctx, pjob->jobname);
259 666 : if (!jobname) {
260 0 : ret = -1;
261 0 : goto out;
262 : }
263 666 : jobname = talloc_string_sub(ctx, jobname, "'", "_");
264 666 : if (!jobname) {
265 0 : ret = -1;
266 0 : goto out;
267 : }
268 666 : fstr_sprintf(job_page_count, "%d", pjob->page_count);
269 666 : fstr_sprintf(job_size, "%zu", pjob->size);
270 :
271 : /* send it to the system spooler */
272 666 : ret = print_run_command(snum, lp_printername(talloc_tos(), lp_sub, snum), True,
273 : lp_print_command(snum), NULL,
274 : "%s", p,
275 : "%J", jobname,
276 : "%f", p,
277 : "%z", job_size,
278 : "%c", job_page_count,
279 : NULL);
280 666 : if (ret != 0) {
281 292 : ret = -1;
282 292 : goto out;
283 : }
284 :
285 : /*
286 : * check the queue for the newly submitted job, this allows us to
287 : * determine the backend job identifier (sysjob).
288 : */
289 374 : pjob->sysjob = -1;
290 374 : ret = generic_queue_get(lp_printername(talloc_tos(), lp_sub, snum),
291 : printing_type, lpq_cmd, &q, &status);
292 374 : if (ret > 0) {
293 : int i;
294 1462 : for (i = 0; i < ret; i++) {
295 1462 : if (strcmp(q[i].fs_file, p) == 0) {
296 340 : pjob->sysjob = q[i].sysjob;
297 340 : DEBUG(5, ("new job %u (%s) matches sysjob %d\n",
298 : pjob->jobid, jobname, pjob->sysjob));
299 340 : break;
300 : }
301 : }
302 340 : SAFE_FREE(q);
303 340 : ret = 0;
304 : }
305 374 : if (pjob->sysjob == -1) {
306 34 : DEBUG(2, ("failed to get sysjob for job %u (%s), tracking as "
307 : "Unix job\n", pjob->jobid, jobname));
308 : }
309 :
310 :
311 340 : out:
312 :
313 666 : if (chdir(current_directory) == -1) {
314 0 : smb_panic("chdir failed in generic_job_submit");
315 : }
316 666 : TALLOC_FREE(current_directory);
317 666 : return ret;
318 : }
319 :
320 : /****************************************************************************
321 : pause a queue
322 : ****************************************************************************/
323 52 : static int generic_queue_pause(int snum)
324 : {
325 0 : const struct loadparm_substitution *lp_sub =
326 52 : loadparm_s3_global_substitution();
327 :
328 52 : return print_run_command(snum, lp_printername(talloc_tos(), lp_sub, snum), True,
329 : lp_queuepause_command(snum), NULL, NULL);
330 : }
331 :
332 : /****************************************************************************
333 : resume a queue
334 : ****************************************************************************/
335 40 : static int generic_queue_resume(int snum)
336 : {
337 0 : const struct loadparm_substitution *lp_sub =
338 40 : loadparm_s3_global_substitution();
339 :
340 40 : return print_run_command(snum, lp_printername(talloc_tos(), lp_sub, snum), True,
341 : lp_queueresume_command(snum), NULL, NULL);
342 : }
343 :
344 : /****************************************************************************
345 : * Generic printing interface definitions...
346 : ***************************************************************************/
347 :
348 : struct printif generic_printif =
349 : {
350 : DEFAULT_PRINTING,
351 : generic_queue_get,
352 : generic_queue_pause,
353 : generic_queue_resume,
354 : generic_job_delete,
355 : generic_job_pause,
356 : generic_job_resume,
357 : generic_job_submit,
358 : };
359 :
|