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