]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/testbackend.c
Merge changes from CUPS 1.4svn-r8681 (tentative CUPS 1.4rc1)
[thirdparty/cups.git] / backend / testbackend.c
CommitLineData
568fa3fa
MS
1/*
2 * "$Id$"
3 *
4 * Backend test program for the Common UNIX Printing System (CUPS).
5 *
b9faaae1 6 * Copyright 2007-2009 by Apple Inc.
568fa3fa
MS
7 * Copyright 1997-2005 by Easy Software Products, all rights reserved.
8 *
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 * "LICENSE" which should have been included with this file. If this
13 * file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * This file is subject to the Apple OS-Developed Software exception.
16 *
17 * Contents:
18 *
b9faaae1
MS
19 * main() - Run the named backend.
20 * usage() - Show usage information.
21 * walk_cb() - Show results of cupsSideChannelSNMPWalk...
568fa3fa
MS
22 */
23
24/*
25 * Include necessary headers.
26 */
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <cups/string.h>
31#include <cups/cups.h>
32#include <cups/sidechannel.h>
33#include <unistd.h>
34#include <fcntl.h>
35#include <errno.h>
36#include <sys/wait.h>
37
38
39/*
40 * Local functions...
41 */
42
43static void usage(void);
b9faaae1
MS
44static void walk_cb(const char *oid, const char *data, int datalen,
45 void *context);
568fa3fa
MS
46
47
48/*
49 * 'main()' - Run the named backend.
50 *
51 * Usage:
52 *
53 * betest [-s] [-t] device-uri job-id user title copies options [file]
54 */
55
56int /* O - Exit status */
57main(int argc, /* I - Number of command-line args */
58 char *argv[]) /* I - Command-line arguments */
59{
60 int first_arg, /* First argument for backend */
e07d4801
MS
61 do_ps = 0, /* Do PostScript query+test? */
62 do_pcl = 0, /* Do PCL query+test? */
568fa3fa 63 do_side_tests = 0, /* Test side-channel ops? */
b9faaae1
MS
64 do_trickle = 0, /* Trickle data to backend */
65 do_walk = 0, /* Do OID lookup (0) or walking (1) */
66 show_log = 0; /* Show log messages from backends? */
67 const char *oid = ".1.3.6.1.2.1.43.10.2.1.4.1.1";
68 /* OID to lookup or walk */
568fa3fa
MS
69 char scheme[255], /* Scheme in URI == backend */
70 backend[1024]; /* Backend path */
71 const char *serverbin; /* CUPS_SERVERBIN environment variable */
72 int back_fds[2], /* Back-channel pipe */
73 side_fds[2], /* Side-channel socket */
74 data_fds[2], /* Data pipe */
75 pid, /* Process ID */
76 status; /* Exit status */
77
78
79 /*
80 * See if we have side-channel tests to do...
81 */
82
83 for (first_arg = 1;
84 argv[first_arg] && argv[first_arg][0] == '-';
85 first_arg ++)
b9faaae1
MS
86 if (!strcmp(argv[first_arg], "-d"))
87 show_log = 1;
e07d4801
MS
88 else if (!strcmp(argv[first_arg], "-pcl"))
89 do_pcl = 1;
b9faaae1 90 else if (!strcmp(argv[first_arg], "-ps"))
e07d4801 91 do_ps = 1;
634763e8 92 else if (!strcmp(argv[first_arg], "-s"))
568fa3fa
MS
93 do_side_tests = 1;
94 else if (!strcmp(argv[first_arg], "-t"))
95 do_trickle = 1;
b9faaae1
MS
96 else if (!strcmp(argv[first_arg], "-get") && (first_arg + 1) < argc)
97 {
98 first_arg ++;
99
100 do_side_tests = 1;
101 oid = argv[first_arg];
102 }
103 else if (!strcmp(argv[first_arg], "-walk") && (first_arg + 1) < argc)
104 {
105 first_arg ++;
106
107 do_side_tests = 1;
108 do_walk = 1;
109 oid = argv[first_arg];
110 }
568fa3fa
MS
111 else
112 usage();
113
114 argc -= first_arg;
115 if (argc < 6 || argc > 7 || (argc == 7 && do_trickle))
116 usage();
117
118 /*
119 * Extract the scheme from the device-uri - that's the program we want to
120 * execute.
121 */
122
123 if (sscanf(argv[first_arg], "%254[^:]", scheme) != 1)
124 {
125 fputs("testbackend: Bad device-uri - no colon!\n", stderr);
126 return (1);
127 }
128
129 if (!access(scheme, X_OK))
130 strlcpy(backend, scheme, sizeof(backend));
131 else
132 {
133 if ((serverbin = getenv("CUPS_SERVERBIN")) == NULL)
134 serverbin = CUPS_SERVERBIN;
135
136 snprintf(backend, sizeof(backend), "%s/backend/%s", serverbin, scheme);
137 if (access(backend, X_OK))
138 {
139 fprintf(stderr, "testbackend: Unknown device scheme \"%s\"!\n", scheme);
140 return (1);
141 }
142 }
143
144 /*
145 * Create the back-channel pipe and side-channel socket...
146 */
147
148 open("/dev/null", O_WRONLY); /* Make sure fd 3 and 4 are used */
149 open("/dev/null", O_WRONLY);
150
151 pipe(back_fds);
152 fcntl(back_fds[0], F_SETFL, fcntl(back_fds[0], F_GETFL) | O_NONBLOCK);
153 fcntl(back_fds[1], F_SETFL, fcntl(back_fds[1], F_GETFL) | O_NONBLOCK);
154
155 socketpair(AF_LOCAL, SOCK_STREAM, 0, side_fds);
156 fcntl(side_fds[0], F_SETFL, fcntl(side_fds[0], F_GETFL) | O_NONBLOCK);
157 fcntl(side_fds[1], F_SETFL, fcntl(side_fds[1], F_GETFL) | O_NONBLOCK);
158
159 /*
160 * Execute the trickle process as needed...
161 */
162
e07d4801 163 if (do_trickle || do_pcl || do_ps)
568fa3fa
MS
164 {
165 pipe(data_fds);
166
167 if ((pid = fork()) == 0)
168 {
169 /*
e07d4801
MS
170 * Trickle/query child comes here. Rearrange file descriptors so that
171 * FD 1, 3, and 4 point to the backend...
568fa3fa
MS
172 */
173
634763e8
MS
174 close(0);
175 open("/dev/null", O_RDONLY);
568fa3fa 176
634763e8
MS
177 close(1);
178 dup(data_fds[1]);
568fa3fa 179 close(data_fds[0]);
634763e8
MS
180 close(data_fds[1]);
181
182 close(3);
183 dup(back_fds[0]);
184 close(back_fds[0]);
185 close(back_fds[1]);
186
187 close(4);
188 dup(side_fds[0]);
189 close(side_fds[0]);
190 close(side_fds[1]);
191
192 if (do_trickle)
193 {
194 /*
195 * Write 10 spaces, 1 per second...
196 */
197
198 int i; /* Looping var */
199
200 for (i = 0; i < 10; i ++)
201 {
202 write(1, " ", 1);
203 sleep(1);
204 }
205 }
206 else
568fa3fa
MS
207 {
208 /*
e07d4801 209 * Do PS or PCL query + test pages.
568fa3fa
MS
210 */
211
e07d4801
MS
212 char buffer[1024]; /* Buffer for response data */
213 ssize_t bytes; /* Number of bytes of response data */
214 double timeout; /* Timeout */
215 const char *data; /* Data to send */
216 static const char *pcl_data = /* PCL data */
217 "\033%-12345X@PJL\r\n"
218 "@PJL JOB NAME = \"Hello, World!\"\r\n"
219 "@PJL INFO USTATUS\r\n"
220 "@PJL ENTER LANGUAGE = PCL\r\n"
221 "\033E"
222 "Hello, World!\n"
223 "\014"
224 "\033%-12345X@PJL\r\n"
225 "@PJL EOJ NAME=\"Hello, World!\"\r\n"
226 "\033%-12345X";
227 static const char *ps_data = /* PostScript data */
634763e8
MS
228 "%!\n"
229 "save\n"
b9faaae1 230 "product = flush\n"
634763e8
MS
231 "currentpagedevice /PageSize get aload pop\n"
232 "2 copy gt {exch} if\n"
233 "(Unknown)\n"
234 "19 dict\n"
235 "dup [612 792] (Letter) put\n"
236 "dup [612 1008] (Legal) put\n"
237 "dup [612 935] (w612h935) put\n"
238 "dup [522 756] (Executive) put\n"
239 "dup [595 842] (A4) put\n"
240 "dup [420 595] (A5) put\n"
241 "dup [499 709] (ISOB5) put\n"
242 "dup [516 728] (B5) put\n"
243 "dup [612 936] (w612h936) put\n"
244 "dup [284 419] (Postcard) put\n"
245 "dup [419.5 567] (DoublePostcard) put\n"
246 "dup [558 774] (w558h774) put\n"
247 "dup [553 765] (w553h765) put\n"
248 "dup [522 737] (w522h737) put\n"
249 "dup [499 709] (EnvISOB5) put\n"
250 "dup [297 684] (Env10) put\n"
251 "dup [459 649] (EnvC5) put\n"
252 "dup [312 624] (EnvDL) put\n"
253 "dup [279 540] (EnvMonarch) put\n"
254 "{ exch aload pop 4 index sub abs 5 le exch\n"
255 " 5 index sub abs 5 le and\n"
256 " {exch pop exit} {pop} ifelse\n"
257 "} bind forall\n"
258 "= flush pop pop\n"
e07d4801
MS
259 "/Courier findfont 12 scalefont setfont\n"
260 "0 setgray 36 720 moveto (Hello, ) show product show (!) show\n"
261 "showpage\n"
634763e8
MS
262 "restore\n"
263 "\004";
264
265
e07d4801
MS
266 if (do_pcl)
267 data = pcl_data;
268 else
269 data = ps_data;
270
271 write(1, data, strlen(data));
634763e8 272 write(2, "DEBUG: START\n", 13);
e07d4801
MS
273 timeout = 60.0;
274 while ((bytes = cupsBackChannelRead(buffer, sizeof(buffer),
275 timeout)) > 0)
276 {
634763e8 277 write(2, buffer, bytes);
e07d4801
MS
278 timeout = 5.0;
279 }
634763e8 280 write(2, "\nDEBUG: END\n", 12);
568fa3fa
MS
281 }
282
283 exit(0);
284 }
285 else if (pid < 0)
286 {
287 perror("testbackend: Unable to fork");
288 return (1);
289 }
290 }
291 else
292 data_fds[0] = data_fds[1] = -1;
293
294 /*
295 * Execute the backend...
296 */
297
298 if ((pid = fork()) == 0)
299 {
300 /*
301 * Child comes here...
302 */
303
e07d4801 304 if (do_trickle || do_ps)
568fa3fa
MS
305 {
306 close(0);
307 dup(data_fds[0]);
308 close(data_fds[0]);
309 close(data_fds[1]);
310 }
311
b9faaae1
MS
312 if (!show_log)
313 {
314 close(2);
315 open("/dev/null", O_WRONLY);
316 }
317
568fa3fa
MS
318 close(3);
319 dup(back_fds[1]);
320 close(back_fds[0]);
321 close(back_fds[1]);
322
323 close(4);
324 dup(side_fds[1]);
325 close(side_fds[0]);
326 close(side_fds[1]);
327
328 execv(backend, argv + first_arg);
1340db2d 329 fprintf(stderr, "testbackend: Unable to execute \"%s\": %s\n", backend,
568fa3fa
MS
330 strerror(errno));
331 return (errno);
332 }
333 else if (pid < 0)
334 {
335 perror("testbackend: Unable to fork");
336 return (1);
337 }
338
339 /*
340 * Parent comes here, setup back and side channel file descriptors...
341 */
342
e07d4801 343 if (do_trickle || do_ps)
568fa3fa
MS
344 {
345 close(data_fds[0]);
346 close(data_fds[1]);
347 }
348
349 close(3);
350 dup(back_fds[0]);
351 close(back_fds[0]);
352 close(back_fds[1]);
353
354 close(4);
355 dup(side_fds[0]);
356 close(side_fds[0]);
357 close(side_fds[1]);
358
359 /*
360 * Do side-channel tests as needed, then wait for the backend...
361 */
362
363 if (do_side_tests)
364 {
365 int length; /* Length of buffer */
366 char buffer[2049]; /* Buffer for reponse */
367 cups_sc_status_t scstatus; /* Status of side-channel command */
368 static const char * const statuses[] =
369 {
370 "CUPS_SC_STATUS_NONE", /* No status */
371 "CUPS_SC_STATUS_OK", /* Operation succeeded */
372 "CUPS_SC_STATUS_IO_ERROR", /* An I/O error occurred */
373 "CUPS_SC_STATUS_TIMEOUT", /* The backend did not respond */
374 "CUPS_SC_STATUS_NO_RESPONSE", /* The device did not respond */
375 "CUPS_SC_STATUS_BAD_MESSAGE", /* The command/response message was invalid */
376 "CUPS_SC_STATUS_TOO_BIG", /* Response too big */
377 "CUPS_SC_STATUS_NOT_IMPLEMENTED" /* Command not implemented */
378 };
379
380
20fbc903
MS
381 sleep(2);
382
568fa3fa
MS
383 length = 0;
384 scstatus = cupsSideChannelDoRequest(CUPS_SC_CMD_DRAIN_OUTPUT, buffer,
1340db2d 385 &length, 60.0);
568fa3fa
MS
386 printf("CUPS_SC_CMD_DRAIN_OUTPUT returned %s\n", statuses[scstatus]);
387
388 length = 1;
389 scstatus = cupsSideChannelDoRequest(CUPS_SC_CMD_GET_BIDI, buffer,
390 &length, 5.0);
391 printf("CUPS_SC_CMD_GET_BIDI returned %s, %d\n", statuses[scstatus], buffer[0]);
392
393 length = sizeof(buffer) - 1;
394 scstatus = cupsSideChannelDoRequest(CUPS_SC_CMD_GET_DEVICE_ID, buffer,
395 &length, 5.0);
396 buffer[length] = '\0';
397 printf("CUPS_SC_CMD_GET_DEVICE_ID returned %s, \"%s\"\n",
398 statuses[scstatus], buffer);
399
400 length = 1;
401 scstatus = cupsSideChannelDoRequest(CUPS_SC_CMD_GET_STATE, buffer,
402 &length, 5.0);
403 printf("CUPS_SC_CMD_GET_STATE returned %s, %02X\n", statuses[scstatus],
404 buffer[0] & 255);
405
b9faaae1
MS
406 if (do_walk)
407 {
408 /*
409 * Walk the OID tree...
410 */
411
412 scstatus = cupsSideChannelSNMPWalk(oid, 5.0, walk_cb, NULL);
413 printf("CUPS_SC_CMD_SNMP_WALK returned %s\n", statuses[scstatus]);
414 }
415 else
416 {
417 /*
418 * Lookup the same OID twice...
419 */
420
421 length = sizeof(buffer);
422 scstatus = cupsSideChannelSNMPGet(oid, buffer, &length, 5.0);
423 printf("CUPS_SC_CMD_SNMP_GET %s returned %s, %s\n", oid,
424 statuses[scstatus], buffer);
425
426 length = sizeof(buffer);
427 scstatus = cupsSideChannelSNMPGet(oid, buffer, &length, 5.0);
428 printf("CUPS_SC_CMD_SNMP_GET %s returned %s, %s\n", oid,
429 statuses[scstatus], buffer);
430 }
20fbc903 431
568fa3fa
MS
432 length = 0;
433 scstatus = cupsSideChannelDoRequest(CUPS_SC_CMD_SOFT_RESET, buffer,
434 &length, 5.0);
435 printf("CUPS_SC_CMD_SOFT_RESET returned %s\n", statuses[scstatus]);
436 }
437
438 while (wait(&status) != pid);
439
440 if (status)
441 {
442 if (WIFEXITED(status))
443 printf("%s exited with status %d!\n", backend, WEXITSTATUS(status));
444 else
445 printf("%s crashed with signal %d!\n", backend, WTERMSIG(status));
446 }
447
448 /*
449 * Exit accordingly...
450 */
451
452 return (status != 0);
453}
454
455
456/*
457 * 'usage()' - Show usage information.
458 */
459
460static void
461usage(void)
462{
b9faaae1
MS
463 puts("Usage: testbackend [-d] [-ps] [-s [-oid OID] [-walk OID]] [-t] "
464 "device-uri job-id user title copies options [file]");
465 puts("");
466 puts("Options:");
467 puts(" -d Show log messages from backend.");
468 puts(" -oid OID Lookup the specified SNMP OID.");
1340db2d 469 puts(" (.1.3.6.1.2.1.43.10.2.1.4.1.1 is a good one for printers)");
e07d4801
MS
470 puts(" -pcl Send PCL+PJL query and test page to backend.");
471 puts(" -ps Send PostScript query and test page to backend.");
1340db2d 472 puts(" -s Do side-channel + SNMP tests.");
b9faaae1
MS
473 puts(" -t Send spaces slowly to backend ('trickle').");
474 puts(" -walk OID Walk the specified SNMP OID.");
1340db2d 475 puts(" (.1.3.6.1.2.1.43 is a good one for printers)");
b9faaae1 476
568fa3fa
MS
477 exit(1);
478}
479
480
b9faaae1
MS
481/*
482 * 'walk_cb()' - Show results of cupsSideChannelSNMPWalk...
483 */
484
485static void
486walk_cb(const char *oid, /* I - OID */
487 const char *data, /* I - Data */
488 int datalen, /* I - Length of data */
489 void *context) /* I - Context (unused) */
490{
491 printf("CUPS_SC_CMD_SNMP_WALK %s=%s (%d bytes)\n", oid, data, datalen);
492}
493
494
568fa3fa
MS
495/*
496 * End of "$Id$".
497 */