1 /*
2 * Common run loop APIs for CUPS backends.
3 *
4 * Copyright © 2007-2014 by Apple Inc.
5 * Copyright © 2006-2007 by Easy Software Products, all rights reserved.
6 *
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more
8 * information.
9 */
10
11 /*
12 * Include necessary headers.
13 */
14
15 #include "backend-private.h"
16 #include <limits.h>
17 #include <sys/select.h>
18
19
20 /*
21 * 'backendDrainOutput()' - Drain pending print data to the device.
22 */
23
24 int /* O - 0 on success, -1 on error */
backendDrainOutput(int print_fd,int device_fd)25 backendDrainOutput(int print_fd, /* I - Print file descriptor */
26 int device_fd) /* I - Device file descriptor */
27 {
28 int nfds; /* Maximum file descriptor value + 1 */
29 fd_set input; /* Input set for reading */
30 ssize_t print_bytes, /* Print bytes read */
31 bytes; /* Bytes written */
32 char print_buffer[8192], /* Print data buffer */
33 *print_ptr; /* Pointer into print data buffer */
34 struct timeval timeout; /* Timeout for read... */
35
36
37 fprintf(stderr, "DEBUG: backendDrainOutput(print_fd=%d, device_fd=%d)\n",
38 print_fd, device_fd);
39
40 /*
41 * Figure out the maximum file descriptor value to use with select()...
42 */
43
44 nfds = (print_fd > device_fd ? print_fd : device_fd) + 1;
45
46 /*
47 * Now loop until we are out of data from print_fd...
48 */
49
50 for (;;)
51 {
52 /*
53 * Use select() to determine whether we have data to copy around...
54 */
55
56 FD_ZERO(&input);
57 FD_SET(print_fd, &input);
58
59 timeout.tv_sec = 0;
60 timeout.tv_usec = 0;
61
62 if (select(nfds, &input, NULL, NULL, &timeout) < 0)
63 return (-1);
64
65 if (!FD_ISSET(print_fd, &input))
66 return (0);
67
68 if ((print_bytes = read(print_fd, print_buffer,
69 sizeof(print_buffer))) < 0)
70 {
71 /*
72 * Read error - bail if we don't see EAGAIN or EINTR...
73 */
74
75 if (errno != EAGAIN && errno != EINTR)
76 {
77 fprintf(stderr, "DEBUG: Read failed: %s\n", strerror(errno));
78 _cupsLangPrintFilter(stderr, "ERROR", _("Unable to read print data."));
79 return (-1);
80 }
81
82 print_bytes = 0;
83 }
84 else if (print_bytes == 0)
85 {
86 /*
87 * End of file, return...
88 */
89
90 return (0);
91 }
92
93 fprintf(stderr, "DEBUG: Read %d bytes of print data...\n",
94 (int)print_bytes);
95
96 for (print_ptr = print_buffer; print_bytes > 0;)
97 {
98 if ((bytes = write(device_fd, print_ptr, (size_t)print_bytes)) < 0)
99 {
100 /*
101 * Write error - bail if we don't see an error we can retry...
102 */
103
104 if (errno != ENOSPC && errno != ENXIO && errno != EAGAIN &&
105 errno != EINTR && errno != ENOTTY)
106 {
107 _cupsLangPrintError("ERROR", _("Unable to write print data"));
108 return (-1);
109 }
110 }
111 else
112 {
113 fprintf(stderr, "DEBUG: Wrote %d bytes of print data...\n", (int)bytes);
114
115 print_bytes -= bytes;
116 print_ptr += bytes;
117 }
118 }
119 }
120 }
121
122
123 /*
124 * 'backendRunLoop()' - Read and write print and back-channel data.
125 */
126
127 ssize_t /* O - Total bytes on success, -1 on error */
backendRunLoop(int print_fd,int device_fd,int snmp_fd,http_addr_t * addr,int use_bc,int update_state,_cups_sccb_t side_cb)128 backendRunLoop(
129 int print_fd, /* I - Print file descriptor */
130 int device_fd, /* I - Device file descriptor */
131 int snmp_fd, /* I - SNMP socket or -1 if none */
132 http_addr_t *addr, /* I - Address of device */
133 int use_bc, /* I - Use back-channel? */
134 int update_state, /* I - Update printer-state-reasons? */
135 _cups_sccb_t side_cb) /* I - Side-channel callback */
136 {
137 int nfds; /* Maximum file descriptor value + 1 */
138 fd_set input, /* Input set for reading */
139 output; /* Output set for writing */
140 ssize_t print_bytes, /* Print bytes read */
141 bc_bytes, /* Backchannel bytes read */
142 total_bytes, /* Total bytes written */
143 bytes; /* Bytes written */
144 int paperout; /* "Paper out" status */
145 int offline; /* "Off-line" status */
146 char print_buffer[8192], /* Print data buffer */
147 *print_ptr, /* Pointer into print data buffer */
148 bc_buffer[1024]; /* Back-channel data buffer */
149 struct timeval timeout; /* Timeout for select() */
150 time_t curtime, /* Current time */
151 snmp_update = 0;
152 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
153 struct sigaction action; /* Actions for POSIX signals */
154 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
155
156
157 fprintf(stderr,
158 "DEBUG: backendRunLoop(print_fd=%d, device_fd=%d, snmp_fd=%d, "
159 "addr=%p, use_bc=%d, side_cb=%p)\n",
160 print_fd, device_fd, snmp_fd, addr, use_bc, side_cb);
161
162 /*
163 * If we are printing data from a print driver on stdin, ignore SIGTERM
164 * so that the driver can finish out any page data, e.g. to eject the
165 * current page. We only do this for stdin printing as otherwise there
166 * is no way to cancel a raw print job...
167 */
168
169 if (!print_fd)
170 {
171 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
172 sigset(SIGTERM, SIG_IGN);
173 #elif defined(HAVE_SIGACTION)
174 memset(&action, 0, sizeof(action));
175
176 sigemptyset(&action.sa_mask);
177 action.sa_handler = SIG_IGN;
178 sigaction(SIGTERM, &action, NULL);
179 #else
180 signal(SIGTERM, SIG_IGN);
181 #endif /* HAVE_SIGSET */
182 }
183 else if (print_fd < 0)
184 {
185 /*
186 * Copy print data from stdin, but don't mess with the signal handlers...
187 */
188
189 print_fd = 0;
190 }
191
192 /*
193 * Figure out the maximum file descriptor value to use with select()...
194 */
195
196 nfds = (print_fd > device_fd ? print_fd : device_fd) + 1;
197
198 /*
199 * Now loop until we are out of data from print_fd...
200 */
201
202 for (print_bytes = 0, print_ptr = print_buffer, offline = -1,
203 paperout = -1, total_bytes = 0;;)
204 {
205 /*
206 * Use select() to determine whether we have data to copy around...
207 */
208
209 FD_ZERO(&input);
210 if (!print_bytes)
211 FD_SET(print_fd, &input);
212 if (use_bc)
213 FD_SET(device_fd, &input);
214 if (!print_bytes && side_cb)
215 FD_SET(CUPS_SC_FD, &input);
216
217 FD_ZERO(&output);
218 if (print_bytes || (!use_bc && !side_cb))
219 FD_SET(device_fd, &output);
220
221 if (use_bc || side_cb)
222 {
223 timeout.tv_sec = 5;
224 timeout.tv_usec = 0;
225
226 if (select(nfds, &input, &output, NULL, &timeout) < 0)
227 {
228 /*
229 * Pause printing to clear any pending errors...
230 */
231
232 if (errno == ENXIO && offline != 1 && update_state)
233 {
234 fputs("STATE: +offline-report\n", stderr);
235 _cupsLangPrintFilter(stderr, "INFO",
236 _("The printer is not connected."));
237 offline = 1;
238 }
239 else if (errno == EINTR && total_bytes == 0)
240 {
241 fputs("DEBUG: Received an interrupt before any bytes were "
242 "written, aborting.\n", stderr);
243 return (0);
244 }
245
246 sleep(1);
247 continue;
248 }
249 }
250
251 /*
252 * Check if we have a side-channel request ready...
253 */
254
255 if (side_cb && FD_ISSET(CUPS_SC_FD, &input))
256 {
257 /*
258 * Do the side-channel request, then start back over in the select
259 * loop since it may have read from print_fd...
260 */
261
262 if ((*side_cb)(print_fd, device_fd, snmp_fd, addr, use_bc))
263 side_cb = NULL;
264 continue;
265 }
266
267 /*
268 * Check if we have back-channel data ready...
269 */
270
271 if (FD_ISSET(device_fd, &input))
272 {
273 if ((bc_bytes = read(device_fd, bc_buffer, sizeof(bc_buffer))) > 0)
274 {
275 fprintf(stderr,
276 "DEBUG: Received " CUPS_LLFMT " bytes of back-channel data\n",
277 CUPS_LLCAST bc_bytes);
278 cupsBackChannelWrite(bc_buffer, (size_t)bc_bytes, 1.0);
279 }
280 else if (bc_bytes < 0 && errno != EAGAIN && errno != EINTR)
281 {
282 fprintf(stderr, "DEBUG: Error reading back-channel data: %s\n",
283 strerror(errno));
284 use_bc = 0;
285 }
286 else if (bc_bytes == 0)
287 use_bc = 0;
288 }
289
290 /*
291 * Check if we have print data ready...
292 */
293
294 if (FD_ISSET(print_fd, &input))
295 {
296 if ((print_bytes = read(print_fd, print_buffer,
297 sizeof(print_buffer))) < 0)
298 {
299 /*
300 * Read error - bail if we don't see EAGAIN or EINTR...
301 */
302
303 if (errno != EAGAIN && errno != EINTR)
304 {
305 fprintf(stderr, "DEBUG: Read failed: %s\n", strerror(errno));
306 _cupsLangPrintFilter(stderr, "ERROR",
307 _("Unable to read print data."));
308 return (-1);
309 }
310
311 print_bytes = 0;
312 }
313 else if (print_bytes == 0)
314 {
315 /*
316 * End of file, break out of the loop...
317 */
318
319 break;
320 }
321
322 print_ptr = print_buffer;
323
324 fprintf(stderr, "DEBUG: Read %d bytes of print data...\n",
325 (int)print_bytes);
326 }
327
328 /*
329 * Check if the device is ready to receive data and we have data to
330 * send...
331 */
332
333 if (print_bytes && FD_ISSET(device_fd, &output))
334 {
335 if ((bytes = write(device_fd, print_ptr, (size_t)print_bytes)) < 0)
336 {
337 /*
338 * Write error - bail if we don't see an error we can retry...
339 */
340
341 if (errno == ENOSPC)
342 {
343 if (paperout != 1 && update_state)
344 {
345 fputs("STATE: +media-empty-warning\n", stderr);
346 fputs("DEBUG: Out of paper\n", stderr);
347 paperout = 1;
348 }
349 }
350 else if (errno == ENXIO)
351 {
352 if (offline != 1 && update_state)
353 {
354 fputs("STATE: +offline-report\n", stderr);
355 _cupsLangPrintFilter(stderr, "INFO",
356 _("The printer is not connected."));
357 offline = 1;
358 }
359 }
360 else if (errno != EAGAIN && errno != EINTR && errno != ENOTTY)
361 {
362 _cupsLangPrintError("ERROR", _("Unable to write print data"));
363 return (-1);
364 }
365 }
366 else
367 {
368 if (paperout && update_state)
369 {
370 fputs("STATE: -media-empty-warning\n", stderr);
371 paperout = 0;
372 }
373
374 if (offline && update_state)
375 {
376 fputs("STATE: -offline-report\n", stderr);
377 _cupsLangPrintFilter(stderr, "INFO",
378 _("The printer is now connected."));
379 offline = 0;
380 }
381
382 fprintf(stderr, "DEBUG: Wrote %d bytes of print data...\n", (int)bytes);
383
384 print_bytes -= bytes;
385 print_ptr += bytes;
386 total_bytes += bytes;
387 }
388 }
389
390 /*
391 * Do SNMP updates periodically...
392 */
393
394 if (snmp_fd >= 0 && time(&curtime) >= snmp_update)
395 {
396 if (backendSNMPSupplies(snmp_fd, addr, NULL, NULL))
397 snmp_update = INT_MAX;
398 else
399 snmp_update = curtime + 5;
400 }
401 }
402
403 /*
404 * Return with success...
405 */
406
407 return (total_bytes);
408 }
409
410
411 /*
412 * 'backendWaitLoop()' - Wait for input from stdin while handling side-channel
413 * queries.
414 */
415
416 int /* O - 1 if data is ready, 0 if not */
backendWaitLoop(int snmp_fd,http_addr_t * addr,int use_bc,_cups_sccb_t side_cb)417 backendWaitLoop(
418 int snmp_fd, /* I - SNMP socket or -1 if none */
419 http_addr_t *addr, /* I - Address of device */
420 int use_bc, /* I - Use back-channel? */
421 _cups_sccb_t side_cb) /* I - Side-channel callback */
422 {
423 int nfds; /* Number of file descriptors */
424 fd_set input; /* Input set for reading */
425 time_t curtime = 0, /* Current time */
426 snmp_update = 0;/* Last SNMP status update */
427 struct timeval timeout; /* Timeout for select() */
428
429
430 fprintf(stderr, "DEBUG: backendWaitLoop(snmp_fd=%d, addr=%p, side_cb=%p)\n",
431 snmp_fd, addr, side_cb);
432
433 /*
434 * Now loop until we receive data from stdin...
435 */
436
437 if (snmp_fd >= 0)
438 snmp_update = time(NULL) + 5;
439
440 for (;;)
441 {
442 /*
443 * Use select() to determine whether we have data to copy around...
444 */
445
446 FD_ZERO(&input);
447 FD_SET(0, &input);
448 if (side_cb)
449 FD_SET(CUPS_SC_FD, &input);
450
451 if (snmp_fd >= 0)
452 {
453 curtime = time(NULL);
454 timeout.tv_sec = curtime >= snmp_update ? 0 : snmp_update - curtime;
455 timeout.tv_usec = 0;
456
457 nfds = select(CUPS_SC_FD + 1, &input, NULL, NULL, &timeout);
458 }
459 else
460 nfds = select(CUPS_SC_FD + 1, &input, NULL, NULL, NULL);
461
462 if (nfds < 0)
463 {
464 /*
465 * Pause printing to clear any pending errors...
466 */
467
468 if (errno == EINTR)
469 {
470 fputs("DEBUG: Received an interrupt before any bytes were "
471 "written, aborting.\n", stderr);
472 return (0);
473 }
474
475 sleep(1);
476 continue;
477 }
478
479 /*
480 * Check for input on stdin...
481 */
482
483 if (FD_ISSET(0, &input))
484 break;
485
486 /*
487 * Check if we have a side-channel request ready...
488 */
489
490 if (side_cb && FD_ISSET(CUPS_SC_FD, &input))
491 {
492 /*
493 * Do the side-channel request, then start back over in the select
494 * loop since it may have read from print_fd...
495 */
496
497 if ((*side_cb)(0, -1, snmp_fd, addr, use_bc))
498 side_cb = NULL;
499 continue;
500 }
501
502 /*
503 * Do SNMP updates periodically...
504 */
505
506 if (snmp_fd >= 0 && curtime >= snmp_update)
507 {
508 if (backendSNMPSupplies(snmp_fd, addr, NULL, NULL))
509 snmp_fd = -1;
510 else
511 snmp_update = curtime + 5;
512 }
513 }
514
515 /*
516 * Return with success...
517 */
518
519 return (1);
520 }
521