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