xref: /aosp_15_r20/external/libcups/backend/runloop.c (revision 5e7646d21f1134fb0638875d812ef646c12ab91e)
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