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