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