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