]>
Commit | Line | Data |
---|---|---|
d09495fa | 1 | /* |
7e86f2f6 | 2 | * cups-lpd test program for CUPS. |
d09495fa | 3 | * |
3bb59731 | 4 | * Copyright 2007-2015 by Apple Inc. |
7e86f2f6 | 5 | * Copyright 2006 by Easy Software Products, all rights reserved. |
d09495fa | 6 | * |
7e86f2f6 MS |
7 | * These coded instructions, statements, and computer programs are the |
8 | * property of Apple Inc. and are protected by Federal copyright | |
9 | * law. Distribution and use rights are outlined in the file "LICENSE.txt" | |
10 | * which should have been included with this file. If this file is | |
57b7b66b | 11 | * missing or damaged, see the license at "http://www.cups.org/". |
d09495fa | 12 | */ |
13 | ||
14 | /* | |
15 | * Include necessary headers... | |
16 | */ | |
17 | ||
18 | #include <cups/cups.h> | |
71e16022 | 19 | #include <cups/string-private.h> |
d09495fa | 20 | #include <sys/stat.h> |
76cd9e37 | 21 | #include <sys/wait.h> |
d09495fa | 22 | #include <signal.h> |
23 | #include <unistd.h> | |
24 | #include <fcntl.h> | |
25 | ||
26 | ||
27 | /* | |
28 | * Local functions... | |
29 | */ | |
30 | ||
31 | static int do_command(int outfd, int infd, const char *command); | |
cb7f98ee | 32 | static int print_job(int outfd, int infd, char *dest, char **args) __attribute__((nonnull(4))); |
d09495fa | 33 | static int print_waiting(int outfd, int infd, char *dest); |
cb7f98ee MS |
34 | static int remove_job(int outfd, int infd, char *dest, char **args) __attribute__((nonnull(4))); |
35 | static int status_long(int outfd, int infd, char *dest, char **args) __attribute__((nonnull(4))); | |
36 | static int status_short(int outfd, int infd, char *dest, char **args) __attribute__((nonnull(4))); | |
85dda01c | 37 | static void usage(void) __attribute__((noreturn)); |
d09495fa | 38 | |
39 | ||
40 | /* | |
41 | * 'main()' - Simulate an LPD client. | |
42 | */ | |
43 | ||
44 | int /* O - Exit status */ | |
45 | main(int argc, /* I - Number of command-line arguments */ | |
46 | char *argv[]) /* I - Command-line arguments */ | |
47 | { | |
48 | int i; /* Looping var */ | |
49 | int status; /* Test status */ | |
50 | char *op, /* Operation to test */ | |
51 | **opargs, /* Remaining arguments */ | |
52 | *dest; /* Destination */ | |
53 | int cupslpd_argc; /* Argument count for cups-lpd */ | |
54 | char *cupslpd_argv[1000]; /* Arguments for cups-lpd */ | |
55 | int cupslpd_stdin[2], /* Standard input for cups-lpd */ | |
56 | cupslpd_stdout[2], /* Standard output for cups-lpd */ | |
355e94dc MS |
57 | cupslpd_pid, /* Process ID for cups-lpd */ |
58 | cupslpd_status; /* Status of cups-lpd process */ | |
d09495fa | 59 | |
60 | ||
61 | /* | |
62 | * Collect command-line arguments... | |
63 | */ | |
64 | ||
65 | op = NULL; | |
cb7f98ee | 66 | opargs = argv + argc; |
d09495fa | 67 | dest = NULL; |
68 | cupslpd_argc = 1; | |
69 | cupslpd_argv[0] = (char *)"cups-lpd"; | |
70 | ||
71 | for (i = 1; i < argc; i ++) | |
72 | if (!strncmp(argv[i], "-o", 2)) | |
73 | { | |
74 | cupslpd_argv[cupslpd_argc++] = argv[i]; | |
75 | ||
355e94dc | 76 | if (!argv[i][2]) |
d09495fa | 77 | { |
78 | i ++; | |
79 | ||
80 | if (i >= argc) | |
81 | usage(); | |
82 | ||
83 | cupslpd_argv[cupslpd_argc++] = argv[i]; | |
84 | } | |
85 | } | |
86 | else if (argv[i][0] == '-') | |
87 | usage(); | |
88 | else if (!op) | |
89 | op = argv[i]; | |
90 | else if (!dest) | |
91 | dest = argv[i]; | |
92 | else | |
93 | { | |
94 | opargs = argv + i; | |
95 | break; | |
96 | } | |
97 | ||
98 | if (!op || | |
99 | (!strcmp(op, "print-job") && (!dest || !opargs)) || | |
100 | (!strcmp(op, "remove-job") && (!dest || !opargs)) || | |
101 | (strcmp(op, "print-job") && strcmp(op, "print-waiting") && | |
102 | strcmp(op, "remove-job") && strcmp(op, "status-long") && | |
103 | strcmp(op, "status-short"))) | |
355e94dc MS |
104 | { |
105 | printf("op=\"%s\", dest=\"%s\", opargs=%p\n", op, dest, opargs); | |
d09495fa | 106 | usage(); |
355e94dc | 107 | } |
d09495fa | 108 | |
109 | /* | |
110 | * Run the cups-lpd program using pipes... | |
111 | */ | |
112 | ||
113 | cupslpd_argv[cupslpd_argc] = NULL; | |
114 | ||
115 | pipe(cupslpd_stdin); | |
116 | pipe(cupslpd_stdout); | |
117 | ||
118 | if ((cupslpd_pid = fork()) < 0) | |
119 | { | |
120 | /* | |
121 | * Error! | |
122 | */ | |
123 | ||
124 | perror("testlpd: Unable to fork"); | |
125 | return (1); | |
126 | } | |
127 | else if (cupslpd_pid == 0) | |
128 | { | |
129 | /* | |
130 | * Child goes here... | |
131 | */ | |
132 | ||
97c9a8d7 | 133 | dup2(cupslpd_stdin[0], 0); |
d09495fa | 134 | close(cupslpd_stdin[0]); |
135 | close(cupslpd_stdin[1]); | |
136 | ||
97c9a8d7 | 137 | dup2(cupslpd_stdout[1], 1); |
d09495fa | 138 | close(cupslpd_stdout[0]); |
139 | close(cupslpd_stdout[1]); | |
140 | ||
141 | execv("./cups-lpd", cupslpd_argv); | |
142 | ||
143 | perror("testlpd: Unable to exec ./cups-lpd"); | |
144 | exit(errno); | |
145 | } | |
146 | else | |
147 | { | |
148 | close(cupslpd_stdin[0]); | |
149 | close(cupslpd_stdout[1]); | |
150 | } | |
151 | ||
152 | /* | |
153 | * Do the operation test... | |
154 | */ | |
155 | ||
156 | if (!strcmp(op, "print-job")) | |
157 | status = print_job(cupslpd_stdin[1], cupslpd_stdout[0], dest, opargs); | |
158 | else if (!strcmp(op, "print-waiting")) | |
159 | status = print_waiting(cupslpd_stdin[1], cupslpd_stdout[0], dest); | |
160 | else if (!strcmp(op, "remove-job")) | |
161 | status = remove_job(cupslpd_stdin[1], cupslpd_stdout[0], dest, opargs); | |
162 | else if (!strcmp(op, "status-long")) | |
163 | status = status_long(cupslpd_stdin[1], cupslpd_stdout[0], dest, opargs); | |
164 | else if (!strcmp(op, "status-short")) | |
165 | status = status_short(cupslpd_stdin[1], cupslpd_stdout[0], dest, opargs); | |
f7deaa1a | 166 | else |
167 | { | |
168 | printf("Unknown operation \"%s\"!\n", op); | |
169 | status = 1; | |
170 | } | |
d09495fa | 171 | |
172 | /* | |
173 | * Kill the test program... | |
174 | */ | |
175 | ||
176 | close(cupslpd_stdin[1]); | |
177 | close(cupslpd_stdout[0]); | |
355e94dc MS |
178 | |
179 | while (wait(&cupslpd_status) != cupslpd_pid); | |
180 | ||
181 | printf("cups-lpd exit status was %d...\n", cupslpd_status); | |
d09495fa | 182 | |
183 | /* | |
184 | * Return the test status... | |
185 | */ | |
186 | ||
187 | return (status); | |
188 | } | |
189 | ||
190 | ||
191 | /* | |
192 | * 'do_command()' - Send the LPD command and wait for a response. | |
193 | */ | |
194 | ||
195 | static int /* O - Status from cups-lpd */ | |
196 | do_command(int outfd, /* I - Command file descriptor */ | |
197 | int infd, /* I - Response file descriptor */ | |
198 | const char *command) /* I - Command line to send */ | |
199 | { | |
7e86f2f6 MS |
200 | size_t len; /* Length of command line */ |
201 | char status; /* Status byte */ | |
d09495fa | 202 | |
203 | ||
204 | printf("COMMAND: %02X %s", command[0], command + 1); | |
205 | ||
206 | len = strlen(command); | |
207 | ||
7e86f2f6 | 208 | if ((size_t)write(outfd, command, len) < len) |
d09495fa | 209 | { |
210 | puts(" Write failed!"); | |
211 | return (-1); | |
212 | } | |
213 | ||
214 | if (read(infd, &status, 1) < 1) | |
355e94dc | 215 | puts("STATUS: ERROR"); |
d09495fa | 216 | else |
355e94dc | 217 | printf("STATUS: %d\n", status); |
d09495fa | 218 | |
219 | return (status); | |
220 | } | |
221 | ||
222 | ||
223 | /* | |
224 | * 'print_job()' - Submit a file for printing. | |
225 | */ | |
226 | ||
227 | static int /* O - Status from cups-lpd */ | |
228 | print_job(int outfd, /* I - Command file descriptor */ | |
229 | int infd, /* I - Response file descriptor */ | |
230 | char *dest, /* I - Destination */ | |
231 | char **args) /* I - Arguments */ | |
232 | { | |
233 | int fd; /* Print file descriptor */ | |
234 | char command[1024], /* Command buffer */ | |
235 | control[1024], /* Control file */ | |
236 | buffer[8192]; /* Print buffer */ | |
237 | int status; /* Status of command */ | |
238 | struct stat fileinfo; /* File information */ | |
239 | char *jobname; /* Job name */ | |
240 | int sequence; /* Sequence number */ | |
7e86f2f6 | 241 | ssize_t bytes; /* Bytes read/written */ |
d09495fa | 242 | |
243 | ||
244 | /* | |
245 | * Check the print file... | |
246 | */ | |
247 | ||
248 | if (stat(args[0], &fileinfo)) | |
249 | { | |
250 | perror(args[0]); | |
251 | return (-1); | |
252 | } | |
253 | ||
254 | if ((fd = open(args[0], O_RDONLY)) < 0) | |
255 | { | |
256 | perror(args[0]); | |
257 | return (-1); | |
258 | } | |
259 | ||
260 | /* | |
261 | * Send the "receive print job" command... | |
262 | */ | |
263 | ||
264 | snprintf(command, sizeof(command), "\002%s\n", dest); | |
265 | if ((status = do_command(outfd, infd, command)) != 0) | |
266 | { | |
267 | close(fd); | |
268 | return (status); | |
269 | } | |
270 | ||
271 | /* | |
272 | * Format a control file string that will be used to submit the job... | |
273 | */ | |
274 | ||
275 | if ((jobname = strrchr(args[0], '/')) != NULL) | |
276 | jobname ++; | |
277 | else | |
278 | jobname = args[0]; | |
279 | ||
280 | sequence = (int)getpid() % 1000; | |
281 | ||
282 | snprintf(control, sizeof(control), | |
283 | "Hlocalhost\n" | |
284 | "P%s\n" | |
285 | "J%s\n" | |
f7deaa1a | 286 | "ldfA%03dlocalhost\n" |
287 | "UdfA%03dlocalhost\n" | |
d09495fa | 288 | "N%s\n", |
289 | cupsUser(), jobname, sequence, sequence, jobname); | |
290 | ||
291 | /* | |
292 | * Send the control file... | |
293 | */ | |
294 | ||
7e86f2f6 | 295 | bytes = (ssize_t)strlen(control); |
d09495fa | 296 | |
f7deaa1a | 297 | snprintf(command, sizeof(command), "\002%d cfA%03dlocalhost\n", |
7e86f2f6 | 298 | (int)bytes, sequence); |
d09495fa | 299 | |
300 | if ((status = do_command(outfd, infd, command)) != 0) | |
301 | { | |
302 | close(fd); | |
303 | return (status); | |
304 | } | |
305 | ||
306 | bytes ++; | |
307 | ||
7e86f2f6 | 308 | if (write(outfd, control, (size_t)bytes) < bytes) |
d09495fa | 309 | { |
7e86f2f6 | 310 | printf("CONTROL: Unable to write %d bytes!\n", (int)bytes); |
d09495fa | 311 | close(fd); |
312 | return (-1); | |
313 | } | |
314 | ||
7e86f2f6 | 315 | printf("CONTROL: Wrote %d bytes.\n", (int)bytes); |
d09495fa | 316 | |
317 | if (read(infd, command, 1) < 1) | |
318 | { | |
355e94dc | 319 | puts("STATUS: ERROR"); |
d09495fa | 320 | close(fd); |
321 | return (-1); | |
322 | } | |
323 | else | |
324 | { | |
325 | status = command[0]; | |
326 | ||
355e94dc | 327 | printf("STATUS: %d\n", status); |
d09495fa | 328 | } |
329 | ||
330 | /* | |
331 | * Send the data file... | |
332 | */ | |
333 | ||
f7deaa1a | 334 | snprintf(command, sizeof(command), "\003%d dfA%03dlocalhost\n", |
d09495fa | 335 | (int)fileinfo.st_size, sequence); |
336 | ||
337 | if ((status = do_command(outfd, infd, command)) != 0) | |
338 | { | |
339 | close(fd); | |
340 | return (status); | |
341 | } | |
342 | ||
343 | while ((bytes = read(fd, buffer, sizeof(buffer))) > 0) | |
344 | { | |
7e86f2f6 | 345 | if (write(outfd, buffer, (size_t)bytes) < bytes) |
d09495fa | 346 | { |
7e86f2f6 | 347 | printf("DATA: Unable to write %d bytes!\n", (int)bytes); |
d09495fa | 348 | close(fd); |
349 | return (-1); | |
350 | } | |
351 | } | |
352 | ||
353 | write(outfd, "", 1); | |
354 | ||
355 | close(fd); | |
356 | ||
357 | printf("DATA: Wrote %d bytes.\n", (int)fileinfo.st_size); | |
358 | ||
359 | if (read(infd, command, 1) < 1) | |
360 | { | |
355e94dc | 361 | puts("STATUS: ERROR"); |
d09495fa | 362 | close(fd); |
363 | return (-1); | |
364 | } | |
365 | else | |
366 | { | |
367 | status = command[0]; | |
368 | ||
355e94dc | 369 | printf("STATUS: %d\n", status); |
d09495fa | 370 | } |
371 | ||
372 | return (status); | |
373 | } | |
374 | ||
375 | ||
376 | /* | |
377 | * 'print_waiting()' - Print waiting jobs. | |
378 | */ | |
379 | ||
380 | static int /* O - Status from cups-lpd */ | |
381 | print_waiting(int outfd, /* I - Command file descriptor */ | |
382 | int infd, /* I - Response file descriptor */ | |
383 | char *dest) /* I - Destination */ | |
384 | { | |
385 | char command[1024]; /* Command buffer */ | |
386 | ||
387 | ||
388 | /* | |
389 | * Send the "print waiting jobs" command... | |
390 | */ | |
391 | ||
392 | snprintf(command, sizeof(command), "\001%s\n", dest); | |
393 | ||
394 | return (do_command(outfd, infd, command)); | |
395 | } | |
396 | ||
397 | ||
398 | /* | |
399 | * 'remove_job()' - Cancel a print job. | |
400 | */ | |
401 | ||
402 | static int /* O - Status from cups-lpd */ | |
403 | remove_job(int outfd, /* I - Command file descriptor */ | |
404 | int infd, /* I - Response file descriptor */ | |
405 | char *dest, /* I - Destination */ | |
406 | char **args) /* I - Arguments */ | |
407 | { | |
408 | int i; /* Looping var */ | |
409 | char command[1024]; /* Command buffer */ | |
410 | ||
411 | /* | |
412 | * Send the "remove jobs" command... | |
413 | */ | |
414 | ||
415 | snprintf(command, sizeof(command), "\005%s", dest); | |
416 | ||
417 | for (i = 0; args[i]; i ++) | |
418 | { | |
419 | strlcat(command, " ", sizeof(command)); | |
420 | strlcat(command, args[i], sizeof(command)); | |
421 | } | |
422 | ||
423 | strlcat(command, "\n", sizeof(command)); | |
424 | ||
425 | return (do_command(outfd, infd, command)); | |
426 | } | |
427 | ||
428 | ||
429 | /* | |
430 | * 'status_long()' - Show the long printer status. | |
431 | */ | |
432 | ||
433 | static int /* O - Status from cups-lpd */ | |
434 | status_long(int outfd, /* I - Command file descriptor */ | |
435 | int infd, /* I - Response file descriptor */ | |
436 | char *dest, /* I - Destination */ | |
437 | char **args) /* I - Arguments */ | |
438 | { | |
439 | char command[1024], /* Command buffer */ | |
440 | buffer[8192]; /* Status buffer */ | |
7e86f2f6 | 441 | ssize_t bytes; /* Bytes read/written */ |
d09495fa | 442 | |
443 | ||
444 | /* | |
445 | * Send the "send short status" command... | |
446 | */ | |
447 | ||
3bb59731 | 448 | if (args[0]) |
d09495fa | 449 | snprintf(command, sizeof(command), "\004%s %s\n", dest, args[0]); |
450 | else | |
451 | snprintf(command, sizeof(command), "\004%s\n", dest); | |
452 | ||
7e86f2f6 | 453 | bytes = (ssize_t)strlen(command); |
d09495fa | 454 | |
7e86f2f6 | 455 | if (write(outfd, command, (size_t)bytes) < bytes) |
d09495fa | 456 | return (-1); |
457 | ||
458 | /* | |
459 | * Read the status back... | |
460 | */ | |
461 | ||
462 | while ((bytes = read(infd, buffer, sizeof(buffer))) > 0) | |
463 | { | |
7e86f2f6 | 464 | fwrite(buffer, 1, (size_t)bytes, stdout); |
d09495fa | 465 | fflush(stdout); |
466 | } | |
467 | ||
468 | return (0); | |
469 | } | |
470 | ||
471 | ||
472 | /* | |
473 | * 'status_short()' - Show the short printer status. | |
474 | */ | |
475 | ||
476 | static int /* O - Status from cups-lpd */ | |
477 | status_short(int outfd, /* I - Command file descriptor */ | |
478 | int infd, /* I - Response file descriptor */ | |
479 | char *dest, /* I - Destination */ | |
480 | char **args) /* I - Arguments */ | |
481 | { | |
482 | char command[1024], /* Command buffer */ | |
483 | buffer[8192]; /* Status buffer */ | |
7e86f2f6 | 484 | ssize_t bytes; /* Bytes read/written */ |
d09495fa | 485 | |
486 | ||
487 | /* | |
488 | * Send the "send short status" command... | |
489 | */ | |
490 | ||
3bb59731 | 491 | if (args[0]) |
d09495fa | 492 | snprintf(command, sizeof(command), "\003%s %s\n", dest, args[0]); |
493 | else | |
494 | snprintf(command, sizeof(command), "\003%s\n", dest); | |
495 | ||
7e86f2f6 | 496 | bytes = (ssize_t)strlen(command); |
d09495fa | 497 | |
7e86f2f6 | 498 | if (write(outfd, command, (size_t)bytes) < bytes) |
d09495fa | 499 | return (-1); |
500 | ||
501 | /* | |
502 | * Read the status back... | |
503 | */ | |
504 | ||
505 | while ((bytes = read(infd, buffer, sizeof(buffer))) > 0) | |
506 | { | |
7e86f2f6 | 507 | fwrite(buffer, 1, (size_t)bytes, stdout); |
d09495fa | 508 | fflush(stdout); |
509 | } | |
510 | ||
511 | return (0); | |
512 | } | |
513 | ||
514 | ||
515 | /* | |
516 | * 'usage()' - Show program usage... | |
517 | */ | |
518 | ||
519 | static void | |
520 | usage(void) | |
521 | { | |
355e94dc | 522 | puts("Usage: testlpd [options] print-job printer filename [... filename]"); |
d09495fa | 523 | puts(" testlpd [options] print-waiting [printer or user]"); |
524 | puts(" testlpd [options] remove-job printer [user [job-id]]"); | |
525 | puts(" testlpd [options] status-long [printer or user]"); | |
526 | puts(" testlpd [options] status-short [printer or user]"); | |
527 | puts(""); | |
528 | puts("Options:"); | |
529 | puts(" -o name=value"); | |
530 | ||
531 | exit(0); | |
532 | } |