]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/testbackend.c
Import CUPS 1.4svn-r7356.
[thirdparty/cups.git] / backend / testbackend.c
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 */
58 do_side_tests = 0, /* Test side-channel ops? */
59 do_trickle = 0; /* Trickle data to backend */
60 char scheme[255], /* Scheme in URI == backend */
61 backend[1024]; /* Backend path */
62 const char *serverbin; /* CUPS_SERVERBIN environment variable */
63 int back_fds[2], /* Back-channel pipe */
64 side_fds[2], /* Side-channel socket */
65 data_fds[2], /* Data pipe */
66 pid, /* Process ID */
67 status; /* Exit status */
68
69
70 /*
71 * See if we have side-channel tests to do...
72 */
73
74 for (first_arg = 1;
75 argv[first_arg] && argv[first_arg][0] == '-';
76 first_arg ++)
77 if (!strcmp(argv[first_arg], "-s"))
78 do_side_tests = 1;
79 else if (!strcmp(argv[first_arg], "-t"))
80 do_trickle = 1;
81 else
82 usage();
83
84 argc -= first_arg;
85 if (argc < 6 || argc > 7 || (argc == 7 && do_trickle))
86 usage();
87
88 /*
89 * Extract the scheme from the device-uri - that's the program we want to
90 * execute.
91 */
92
93 if (sscanf(argv[first_arg], "%254[^:]", scheme) != 1)
94 {
95 fputs("testbackend: Bad device-uri - no colon!\n", stderr);
96 return (1);
97 }
98
99 if (!access(scheme, X_OK))
100 strlcpy(backend, scheme, sizeof(backend));
101 else
102 {
103 if ((serverbin = getenv("CUPS_SERVERBIN")) == NULL)
104 serverbin = CUPS_SERVERBIN;
105
106 snprintf(backend, sizeof(backend), "%s/backend/%s", serverbin, scheme);
107 if (access(backend, X_OK))
108 {
109 fprintf(stderr, "testbackend: Unknown device scheme \"%s\"!\n", scheme);
110 return (1);
111 }
112 }
113
114 /*
115 * Create the back-channel pipe and side-channel socket...
116 */
117
118 open("/dev/null", O_WRONLY); /* Make sure fd 3 and 4 are used */
119 open("/dev/null", O_WRONLY);
120
121 pipe(back_fds);
122 fcntl(back_fds[0], F_SETFL, fcntl(back_fds[0], F_GETFL) | O_NONBLOCK);
123 fcntl(back_fds[1], F_SETFL, fcntl(back_fds[1], F_GETFL) | O_NONBLOCK);
124
125 socketpair(AF_LOCAL, SOCK_STREAM, 0, side_fds);
126 fcntl(side_fds[0], F_SETFL, fcntl(side_fds[0], F_GETFL) | O_NONBLOCK);
127 fcntl(side_fds[1], F_SETFL, fcntl(side_fds[1], F_GETFL) | O_NONBLOCK);
128
129 /*
130 * Execute the trickle process as needed...
131 */
132
133 if (do_trickle)
134 {
135 pipe(data_fds);
136
137 if ((pid = fork()) == 0)
138 {
139 /*
140 * Trickle child comes here...
141 */
142
143 int i; /* Looping var */
144
145 close(data_fds[0]);
146 for (i = 0; i < 10; i ++)
147 {
148 /*
149 * Write 10 spaces, 1 per second...
150 */
151
152 write(data_fds[1], " ", 1);
153 sleep(1);
154 }
155
156 exit(0);
157 }
158 else if (pid < 0)
159 {
160 perror("testbackend: Unable to fork");
161 return (1);
162 }
163 }
164 else
165 data_fds[0] = data_fds[1] = -1;
166
167 /*
168 * Execute the backend...
169 */
170
171 if ((pid = fork()) == 0)
172 {
173 /*
174 * Child comes here...
175 */
176
177 if (do_trickle)
178 {
179 close(0);
180 dup(data_fds[0]);
181 close(data_fds[0]);
182 close(data_fds[1]);
183 }
184
185 close(3);
186 dup(back_fds[1]);
187 close(back_fds[0]);
188 close(back_fds[1]);
189
190 close(4);
191 dup(side_fds[1]);
192 close(side_fds[0]);
193 close(side_fds[1]);
194
195 execv(backend, argv + first_arg);
196 fprintf(stderr, "textbackend: Unable to execute \"%s\": %s\n", backend,
197 strerror(errno));
198 return (errno);
199 }
200 else if (pid < 0)
201 {
202 perror("testbackend: Unable to fork");
203 return (1);
204 }
205
206 /*
207 * Parent comes here, setup back and side channel file descriptors...
208 */
209
210 if (do_trickle)
211 {
212 close(data_fds[0]);
213 close(data_fds[1]);
214 }
215
216 close(3);
217 dup(back_fds[0]);
218 close(back_fds[0]);
219 close(back_fds[1]);
220
221 close(4);
222 dup(side_fds[0]);
223 close(side_fds[0]);
224 close(side_fds[1]);
225
226 /*
227 * Do side-channel tests as needed, then wait for the backend...
228 */
229
230 if (do_side_tests)
231 {
232 int length; /* Length of buffer */
233 char buffer[2049]; /* Buffer for reponse */
234 cups_sc_status_t scstatus; /* Status of side-channel command */
235 static const char * const statuses[] =
236 {
237 "CUPS_SC_STATUS_NONE", /* No status */
238 "CUPS_SC_STATUS_OK", /* Operation succeeded */
239 "CUPS_SC_STATUS_IO_ERROR", /* An I/O error occurred */
240 "CUPS_SC_STATUS_TIMEOUT", /* The backend did not respond */
241 "CUPS_SC_STATUS_NO_RESPONSE", /* The device did not respond */
242 "CUPS_SC_STATUS_BAD_MESSAGE", /* The command/response message was invalid */
243 "CUPS_SC_STATUS_TOO_BIG", /* Response too big */
244 "CUPS_SC_STATUS_NOT_IMPLEMENTED" /* Command not implemented */
245 };
246
247
248 length = 0;
249 scstatus = cupsSideChannelDoRequest(CUPS_SC_CMD_DRAIN_OUTPUT, buffer,
250 &length, 5.0);
251 printf("CUPS_SC_CMD_DRAIN_OUTPUT returned %s\n", statuses[scstatus]);
252
253 length = 1;
254 scstatus = cupsSideChannelDoRequest(CUPS_SC_CMD_GET_BIDI, buffer,
255 &length, 5.0);
256 printf("CUPS_SC_CMD_GET_BIDI returned %s, %d\n", statuses[scstatus], buffer[0]);
257
258 length = sizeof(buffer) - 1;
259 scstatus = cupsSideChannelDoRequest(CUPS_SC_CMD_GET_DEVICE_ID, buffer,
260 &length, 5.0);
261 buffer[length] = '\0';
262 printf("CUPS_SC_CMD_GET_DEVICE_ID returned %s, \"%s\"\n",
263 statuses[scstatus], buffer);
264
265 length = 1;
266 scstatus = cupsSideChannelDoRequest(CUPS_SC_CMD_GET_STATE, buffer,
267 &length, 5.0);
268 printf("CUPS_SC_CMD_GET_STATE returned %s, %02X\n", statuses[scstatus],
269 buffer[0] & 255);
270
271 length = 0;
272 scstatus = cupsSideChannelDoRequest(CUPS_SC_CMD_SOFT_RESET, buffer,
273 &length, 5.0);
274 printf("CUPS_SC_CMD_SOFT_RESET returned %s\n", statuses[scstatus]);
275 }
276
277 while (wait(&status) != pid);
278
279 if (status)
280 {
281 if (WIFEXITED(status))
282 printf("%s exited with status %d!\n", backend, WEXITSTATUS(status));
283 else
284 printf("%s crashed with signal %d!\n", backend, WTERMSIG(status));
285 }
286
287 /*
288 * Exit accordingly...
289 */
290
291 return (status != 0);
292 }
293
294
295 /*
296 * 'usage()' - Show usage information.
297 */
298
299 static void
300 usage(void)
301 {
302 fputs("Usage: betest [-s] [-t] device-uri job-id user title copies options "
303 "[file]\n", stderr);
304 exit(1);
305 }
306
307
308 /*
309 * End of "$Id$".
310 */