]>
Commit | Line | Data |
---|---|---|
568fa3fa MS |
1 | /* |
2 | * "$Id$" | |
3 | * | |
4 | * Backend test program for the Common UNIX Printing System (CUPS). | |
5 | * | |
6 | * Copyright 2007-2008 by Apple Inc. | |
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 | * | |
19 | * main() - Run the named backend. | |
20 | * usage() - Show usage information. | |
21 | */ | |
22 | ||
23 | /* | |
24 | * Include necessary headers. | |
25 | */ | |
26 | ||
27 | #include <stdio.h> | |
28 | #include <stdlib.h> | |
29 | #include <cups/string.h> | |
30 | #include <cups/cups.h> | |
31 | #include <cups/sidechannel.h> | |
32 | #include <unistd.h> | |
33 | #include <fcntl.h> | |
34 | #include <errno.h> | |
35 | #include <sys/wait.h> | |
36 | ||
37 | ||
38 | /* | |
39 | * Local functions... | |
40 | */ | |
41 | ||
42 | static void usage(void); | |
43 | ||
44 | ||
45 | /* | |
46 | * 'main()' - Run the named backend. | |
47 | * | |
48 | * Usage: | |
49 | * | |
50 | * betest [-s] [-t] device-uri job-id user title copies options [file] | |
51 | */ | |
52 | ||
53 | int /* O - Exit status */ | |
54 | main(int argc, /* I - Number of command-line args */ | |
55 | char *argv[]) /* I - Command-line arguments */ | |
56 | { | |
57 | int first_arg, /* First argument for backend */ | |
634763e8 | 58 | do_query = 0, /* Do PostScript query? */ |
568fa3fa MS |
59 | do_side_tests = 0, /* Test side-channel ops? */ |
60 | do_trickle = 0; /* Trickle data to backend */ | |
61 | char scheme[255], /* Scheme in URI == backend */ | |
62 | backend[1024]; /* Backend path */ | |
63 | const char *serverbin; /* CUPS_SERVERBIN environment variable */ | |
64 | int back_fds[2], /* Back-channel pipe */ | |
65 | side_fds[2], /* Side-channel socket */ | |
66 | data_fds[2], /* Data pipe */ | |
67 | pid, /* Process ID */ | |
68 | status; /* Exit status */ | |
69 | ||
70 | ||
71 | /* | |
72 | * See if we have side-channel tests to do... | |
73 | */ | |
74 | ||
75 | for (first_arg = 1; | |
76 | argv[first_arg] && argv[first_arg][0] == '-'; | |
77 | first_arg ++) | |
634763e8 MS |
78 | if (!strcmp(argv[first_arg], "-ps")) |
79 | do_query = 1; | |
80 | else if (!strcmp(argv[first_arg], "-s")) | |
568fa3fa MS |
81 | do_side_tests = 1; |
82 | else if (!strcmp(argv[first_arg], "-t")) | |
83 | do_trickle = 1; | |
84 | else | |
85 | usage(); | |
86 | ||
87 | argc -= first_arg; | |
88 | if (argc < 6 || argc > 7 || (argc == 7 && do_trickle)) | |
89 | usage(); | |
90 | ||
91 | /* | |
92 | * Extract the scheme from the device-uri - that's the program we want to | |
93 | * execute. | |
94 | */ | |
95 | ||
96 | if (sscanf(argv[first_arg], "%254[^:]", scheme) != 1) | |
97 | { | |
98 | fputs("testbackend: Bad device-uri - no colon!\n", stderr); | |
99 | return (1); | |
100 | } | |
101 | ||
102 | if (!access(scheme, X_OK)) | |
103 | strlcpy(backend, scheme, sizeof(backend)); | |
104 | else | |
105 | { | |
106 | if ((serverbin = getenv("CUPS_SERVERBIN")) == NULL) | |
107 | serverbin = CUPS_SERVERBIN; | |
108 | ||
109 | snprintf(backend, sizeof(backend), "%s/backend/%s", serverbin, scheme); | |
110 | if (access(backend, X_OK)) | |
111 | { | |
112 | fprintf(stderr, "testbackend: Unknown device scheme \"%s\"!\n", scheme); | |
113 | return (1); | |
114 | } | |
115 | } | |
116 | ||
117 | /* | |
118 | * Create the back-channel pipe and side-channel socket... | |
119 | */ | |
120 | ||
121 | open("/dev/null", O_WRONLY); /* Make sure fd 3 and 4 are used */ | |
122 | open("/dev/null", O_WRONLY); | |
123 | ||
124 | pipe(back_fds); | |
125 | fcntl(back_fds[0], F_SETFL, fcntl(back_fds[0], F_GETFL) | O_NONBLOCK); | |
126 | fcntl(back_fds[1], F_SETFL, fcntl(back_fds[1], F_GETFL) | O_NONBLOCK); | |
127 | ||
128 | socketpair(AF_LOCAL, SOCK_STREAM, 0, side_fds); | |
129 | fcntl(side_fds[0], F_SETFL, fcntl(side_fds[0], F_GETFL) | O_NONBLOCK); | |
130 | fcntl(side_fds[1], F_SETFL, fcntl(side_fds[1], F_GETFL) | O_NONBLOCK); | |
131 | ||
132 | /* | |
133 | * Execute the trickle process as needed... | |
134 | */ | |
135 | ||
634763e8 | 136 | if (do_trickle || do_query) |
568fa3fa MS |
137 | { |
138 | pipe(data_fds); | |
139 | ||
140 | if ((pid = fork()) == 0) | |
141 | { | |
142 | /* | |
634763e8 MS |
143 | * Trickle/query child comes here... Rearrange file descriptors so that |
144 | * FD | |
568fa3fa MS |
145 | */ |
146 | ||
634763e8 MS |
147 | close(0); |
148 | open("/dev/null", O_RDONLY); | |
568fa3fa | 149 | |
634763e8 MS |
150 | close(1); |
151 | dup(data_fds[1]); | |
568fa3fa | 152 | close(data_fds[0]); |
634763e8 MS |
153 | close(data_fds[1]); |
154 | ||
155 | close(3); | |
156 | dup(back_fds[0]); | |
157 | close(back_fds[0]); | |
158 | close(back_fds[1]); | |
159 | ||
160 | close(4); | |
161 | dup(side_fds[0]); | |
162 | close(side_fds[0]); | |
163 | close(side_fds[1]); | |
164 | ||
165 | if (do_trickle) | |
166 | { | |
167 | /* | |
168 | * Write 10 spaces, 1 per second... | |
169 | */ | |
170 | ||
171 | int i; /* Looping var */ | |
172 | ||
173 | for (i = 0; i < 10; i ++) | |
174 | { | |
175 | write(1, " ", 1); | |
176 | sleep(1); | |
177 | } | |
178 | } | |
179 | else | |
568fa3fa MS |
180 | { |
181 | /* | |
634763e8 | 182 | * Do a simple PostScript query job to get the default page size. |
568fa3fa MS |
183 | */ |
184 | ||
634763e8 MS |
185 | char buffer[1024]; /* Buffer for response data */ |
186 | ssize_t bytes; /* Number of bytes of response data */ | |
187 | static const char *ps_query = /* PostScript query file */ | |
188 | "%!\n" | |
189 | "save\n" | |
190 | "currentpagedevice /PageSize get aload pop\n" | |
191 | "2 copy gt {exch} if\n" | |
192 | "(Unknown)\n" | |
193 | "19 dict\n" | |
194 | "dup [612 792] (Letter) put\n" | |
195 | "dup [612 1008] (Legal) put\n" | |
196 | "dup [612 935] (w612h935) put\n" | |
197 | "dup [522 756] (Executive) put\n" | |
198 | "dup [595 842] (A4) put\n" | |
199 | "dup [420 595] (A5) put\n" | |
200 | "dup [499 709] (ISOB5) put\n" | |
201 | "dup [516 728] (B5) put\n" | |
202 | "dup [612 936] (w612h936) put\n" | |
203 | "dup [284 419] (Postcard) put\n" | |
204 | "dup [419.5 567] (DoublePostcard) put\n" | |
205 | "dup [558 774] (w558h774) put\n" | |
206 | "dup [553 765] (w553h765) put\n" | |
207 | "dup [522 737] (w522h737) put\n" | |
208 | "dup [499 709] (EnvISOB5) put\n" | |
209 | "dup [297 684] (Env10) put\n" | |
210 | "dup [459 649] (EnvC5) put\n" | |
211 | "dup [312 624] (EnvDL) put\n" | |
212 | "dup [279 540] (EnvMonarch) put\n" | |
213 | "{ exch aload pop 4 index sub abs 5 le exch\n" | |
214 | " 5 index sub abs 5 le and\n" | |
215 | " {exch pop exit} {pop} ifelse\n" | |
216 | "} bind forall\n" | |
217 | "= flush pop pop\n" | |
218 | "restore\n" | |
219 | "\004"; | |
220 | ||
221 | ||
222 | write(1, ps_query, strlen(ps_query)); | |
223 | write(2, "DEBUG: START\n", 13); | |
224 | while ((bytes = cupsBackChannelRead(buffer, sizeof(buffer), 30.0)) > 0) | |
225 | write(2, buffer, bytes); | |
226 | write(2, "\nDEBUG: END\n", 12); | |
568fa3fa MS |
227 | } |
228 | ||
229 | exit(0); | |
230 | } | |
231 | else if (pid < 0) | |
232 | { | |
233 | perror("testbackend: Unable to fork"); | |
234 | return (1); | |
235 | } | |
236 | } | |
237 | else | |
238 | data_fds[0] = data_fds[1] = -1; | |
239 | ||
240 | /* | |
241 | * Execute the backend... | |
242 | */ | |
243 | ||
244 | if ((pid = fork()) == 0) | |
245 | { | |
246 | /* | |
247 | * Child comes here... | |
248 | */ | |
249 | ||
634763e8 | 250 | if (do_trickle || do_query) |
568fa3fa MS |
251 | { |
252 | close(0); | |
253 | dup(data_fds[0]); | |
254 | close(data_fds[0]); | |
255 | close(data_fds[1]); | |
256 | } | |
257 | ||
258 | close(3); | |
259 | dup(back_fds[1]); | |
260 | close(back_fds[0]); | |
261 | close(back_fds[1]); | |
262 | ||
263 | close(4); | |
264 | dup(side_fds[1]); | |
265 | close(side_fds[0]); | |
266 | close(side_fds[1]); | |
267 | ||
268 | execv(backend, argv + first_arg); | |
269 | fprintf(stderr, "textbackend: Unable to execute \"%s\": %s\n", backend, | |
270 | strerror(errno)); | |
271 | return (errno); | |
272 | } | |
273 | else if (pid < 0) | |
274 | { | |
275 | perror("testbackend: Unable to fork"); | |
276 | return (1); | |
277 | } | |
278 | ||
279 | /* | |
280 | * Parent comes here, setup back and side channel file descriptors... | |
281 | */ | |
282 | ||
634763e8 | 283 | if (do_trickle || do_query) |
568fa3fa MS |
284 | { |
285 | close(data_fds[0]); | |
286 | close(data_fds[1]); | |
287 | } | |
288 | ||
289 | close(3); | |
290 | dup(back_fds[0]); | |
291 | close(back_fds[0]); | |
292 | close(back_fds[1]); | |
293 | ||
294 | close(4); | |
295 | dup(side_fds[0]); | |
296 | close(side_fds[0]); | |
297 | close(side_fds[1]); | |
298 | ||
299 | /* | |
300 | * Do side-channel tests as needed, then wait for the backend... | |
301 | */ | |
302 | ||
303 | if (do_side_tests) | |
304 | { | |
305 | int length; /* Length of buffer */ | |
306 | char buffer[2049]; /* Buffer for reponse */ | |
307 | cups_sc_status_t scstatus; /* Status of side-channel command */ | |
308 | static const char * const statuses[] = | |
309 | { | |
310 | "CUPS_SC_STATUS_NONE", /* No status */ | |
311 | "CUPS_SC_STATUS_OK", /* Operation succeeded */ | |
312 | "CUPS_SC_STATUS_IO_ERROR", /* An I/O error occurred */ | |
313 | "CUPS_SC_STATUS_TIMEOUT", /* The backend did not respond */ | |
314 | "CUPS_SC_STATUS_NO_RESPONSE", /* The device did not respond */ | |
315 | "CUPS_SC_STATUS_BAD_MESSAGE", /* The command/response message was invalid */ | |
316 | "CUPS_SC_STATUS_TOO_BIG", /* Response too big */ | |
317 | "CUPS_SC_STATUS_NOT_IMPLEMENTED" /* Command not implemented */ | |
318 | }; | |
319 | ||
320 | ||
20fbc903 MS |
321 | sleep(2); |
322 | ||
568fa3fa MS |
323 | length = 0; |
324 | scstatus = cupsSideChannelDoRequest(CUPS_SC_CMD_DRAIN_OUTPUT, buffer, | |
325 | &length, 5.0); | |
326 | printf("CUPS_SC_CMD_DRAIN_OUTPUT returned %s\n", statuses[scstatus]); | |
327 | ||
328 | length = 1; | |
329 | scstatus = cupsSideChannelDoRequest(CUPS_SC_CMD_GET_BIDI, buffer, | |
330 | &length, 5.0); | |
331 | printf("CUPS_SC_CMD_GET_BIDI returned %s, %d\n", statuses[scstatus], buffer[0]); | |
332 | ||
333 | length = sizeof(buffer) - 1; | |
334 | scstatus = cupsSideChannelDoRequest(CUPS_SC_CMD_GET_DEVICE_ID, buffer, | |
335 | &length, 5.0); | |
336 | buffer[length] = '\0'; | |
337 | printf("CUPS_SC_CMD_GET_DEVICE_ID returned %s, \"%s\"\n", | |
338 | statuses[scstatus], buffer); | |
339 | ||
340 | length = 1; | |
341 | scstatus = cupsSideChannelDoRequest(CUPS_SC_CMD_GET_STATE, buffer, | |
342 | &length, 5.0); | |
343 | printf("CUPS_SC_CMD_GET_STATE returned %s, %02X\n", statuses[scstatus], | |
344 | buffer[0] & 255); | |
345 | ||
20fbc903 MS |
346 | length = sizeof(buffer); |
347 | scstatus = cupsSideChannelSNMPGet(".1.3.6.1.2.1.43.10.2.1.4.1.1", buffer, | |
348 | &length, 5.0); | |
349 | printf("CUPS_SC_CMD_SNMP_GET returned %s, %s\n", statuses[scstatus], | |
350 | buffer); | |
351 | ||
568fa3fa MS |
352 | length = 0; |
353 | scstatus = cupsSideChannelDoRequest(CUPS_SC_CMD_SOFT_RESET, buffer, | |
354 | &length, 5.0); | |
355 | printf("CUPS_SC_CMD_SOFT_RESET returned %s\n", statuses[scstatus]); | |
356 | } | |
357 | ||
358 | while (wait(&status) != pid); | |
359 | ||
360 | if (status) | |
361 | { | |
362 | if (WIFEXITED(status)) | |
363 | printf("%s exited with status %d!\n", backend, WEXITSTATUS(status)); | |
364 | else | |
365 | printf("%s crashed with signal %d!\n", backend, WTERMSIG(status)); | |
366 | } | |
367 | ||
368 | /* | |
369 | * Exit accordingly... | |
370 | */ | |
371 | ||
372 | return (status != 0); | |
373 | } | |
374 | ||
375 | ||
376 | /* | |
377 | * 'usage()' - Show usage information. | |
378 | */ | |
379 | ||
380 | static void | |
381 | usage(void) | |
382 | { | |
20fbc903 | 383 | fputs("Usage: testbackend [-ps] [-s] [-t] device-uri job-id user title copies " |
634763e8 | 384 | "options [file]\n", stderr); |
568fa3fa MS |
385 | exit(1); |
386 | } | |
387 | ||
388 | ||
389 | /* | |
390 | * End of "$Id$". | |
391 | */ |