]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/testlpd.c
Fix source file header text duplication text duplication.
[thirdparty/cups.git] / scheduler / testlpd.c
1 /*
2 * cups-lpd test program for CUPS.
3 *
4 * Copyright 2007-2015 by Apple Inc.
5 * Copyright 2006 by Easy Software Products, all rights reserved.
6 *
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
11 * missing or damaged, see the license at "http://www.cups.org/".
12 */
13
14 /*
15 * Include necessary headers...
16 */
17
18 #include <cups/cups.h>
19 #include <cups/string-private.h>
20 #include <sys/stat.h>
21 #include <sys/wait.h>
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);
32 static int print_job(int outfd, int infd, char *dest, char **args) __attribute__((nonnull(4)));
33 static int print_waiting(int outfd, int infd, char *dest);
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)));
37 static void usage(void) __attribute__((noreturn));
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 */
57 cupslpd_pid, /* Process ID for cups-lpd */
58 cupslpd_status; /* Status of cups-lpd process */
59
60
61 /*
62 * Collect command-line arguments...
63 */
64
65 op = NULL;
66 opargs = argv + argc;
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
76 if (!argv[i][2])
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")))
104 {
105 printf("op=\"%s\", dest=\"%s\", opargs=%p\n", op, dest, opargs);
106 usage();
107 }
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
133 dup2(cupslpd_stdin[0], 0);
134 close(cupslpd_stdin[0]);
135 close(cupslpd_stdin[1]);
136
137 dup2(cupslpd_stdout[1], 1);
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);
166 else
167 {
168 printf("Unknown operation \"%s\"!\n", op);
169 status = 1;
170 }
171
172 /*
173 * Kill the test program...
174 */
175
176 close(cupslpd_stdin[1]);
177 close(cupslpd_stdout[0]);
178
179 while (wait(&cupslpd_status) != cupslpd_pid);
180
181 printf("cups-lpd exit status was %d...\n", cupslpd_status);
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 {
200 size_t len; /* Length of command line */
201 char status; /* Status byte */
202
203
204 printf("COMMAND: %02X %s", command[0], command + 1);
205
206 len = strlen(command);
207
208 if ((size_t)write(outfd, command, len) < len)
209 {
210 puts(" Write failed!");
211 return (-1);
212 }
213
214 if (read(infd, &status, 1) < 1)
215 puts("STATUS: ERROR");
216 else
217 printf("STATUS: %d\n", status);
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 */
241 ssize_t bytes; /* Bytes read/written */
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"
286 "ldfA%03dlocalhost\n"
287 "UdfA%03dlocalhost\n"
288 "N%s\n",
289 cupsUser(), jobname, sequence, sequence, jobname);
290
291 /*
292 * Send the control file...
293 */
294
295 bytes = (ssize_t)strlen(control);
296
297 snprintf(command, sizeof(command), "\002%d cfA%03dlocalhost\n",
298 (int)bytes, sequence);
299
300 if ((status = do_command(outfd, infd, command)) != 0)
301 {
302 close(fd);
303 return (status);
304 }
305
306 bytes ++;
307
308 if (write(outfd, control, (size_t)bytes) < bytes)
309 {
310 printf("CONTROL: Unable to write %d bytes!\n", (int)bytes);
311 close(fd);
312 return (-1);
313 }
314
315 printf("CONTROL: Wrote %d bytes.\n", (int)bytes);
316
317 if (read(infd, command, 1) < 1)
318 {
319 puts("STATUS: ERROR");
320 close(fd);
321 return (-1);
322 }
323 else
324 {
325 status = command[0];
326
327 printf("STATUS: %d\n", status);
328 }
329
330 /*
331 * Send the data file...
332 */
333
334 snprintf(command, sizeof(command), "\003%d dfA%03dlocalhost\n",
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 {
345 if (write(outfd, buffer, (size_t)bytes) < bytes)
346 {
347 printf("DATA: Unable to write %d bytes!\n", (int)bytes);
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 {
361 puts("STATUS: ERROR");
362 close(fd);
363 return (-1);
364 }
365 else
366 {
367 status = command[0];
368
369 printf("STATUS: %d\n", status);
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 */
441 ssize_t bytes; /* Bytes read/written */
442
443
444 /*
445 * Send the "send short status" command...
446 */
447
448 if (args[0])
449 snprintf(command, sizeof(command), "\004%s %s\n", dest, args[0]);
450 else
451 snprintf(command, sizeof(command), "\004%s\n", dest);
452
453 bytes = (ssize_t)strlen(command);
454
455 if (write(outfd, command, (size_t)bytes) < bytes)
456 return (-1);
457
458 /*
459 * Read the status back...
460 */
461
462 while ((bytes = read(infd, buffer, sizeof(buffer))) > 0)
463 {
464 fwrite(buffer, 1, (size_t)bytes, stdout);
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 */
484 ssize_t bytes; /* Bytes read/written */
485
486
487 /*
488 * Send the "send short status" command...
489 */
490
491 if (args[0])
492 snprintf(command, sizeof(command), "\003%s %s\n", dest, args[0]);
493 else
494 snprintf(command, sizeof(command), "\003%s\n", dest);
495
496 bytes = (ssize_t)strlen(command);
497
498 if (write(outfd, command, (size_t)bytes) < bytes)
499 return (-1);
500
501 /*
502 * Read the status back...
503 */
504
505 while ((bytes = read(infd, buffer, sizeof(buffer))) > 0)
506 {
507 fwrite(buffer, 1, (size_t)bytes, stdout);
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 {
522 puts("Usage: testlpd [options] print-job printer filename [... filename]");
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 }