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