xref: /aosp_15_r20/external/libcups/backend/usb-unix.c (revision 5e7646d21f1134fb0638875d812ef646c12ab91e)
1*5e7646d2SAndroid Build Coastguard Worker /*
2*5e7646d2SAndroid Build Coastguard Worker  * USB port backend for CUPS.
3*5e7646d2SAndroid Build Coastguard Worker  *
4*5e7646d2SAndroid Build Coastguard Worker  * This file is included from "usb.c" when compiled on UNIX/Linux.
5*5e7646d2SAndroid Build Coastguard Worker  *
6*5e7646d2SAndroid Build Coastguard Worker  * Copyright © 2007-2013 by Apple Inc.
7*5e7646d2SAndroid Build Coastguard Worker  * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
8*5e7646d2SAndroid Build Coastguard Worker  *
9*5e7646d2SAndroid Build Coastguard Worker  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
10*5e7646d2SAndroid Build Coastguard Worker  * information.
11*5e7646d2SAndroid Build Coastguard Worker  */
12*5e7646d2SAndroid Build Coastguard Worker 
13*5e7646d2SAndroid Build Coastguard Worker /*
14*5e7646d2SAndroid Build Coastguard Worker  * Include necessary headers.
15*5e7646d2SAndroid Build Coastguard Worker  */
16*5e7646d2SAndroid Build Coastguard Worker 
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  * Local functions...
22*5e7646d2SAndroid Build Coastguard Worker  */
23*5e7646d2SAndroid Build Coastguard Worker 
24*5e7646d2SAndroid Build Coastguard Worker static int	open_device(const char *uri, int *use_bc);
25*5e7646d2SAndroid Build Coastguard Worker static int	side_cb(int print_fd, int device_fd, int snmp_fd,
26*5e7646d2SAndroid Build Coastguard Worker 		        http_addr_t *addr, int use_bc);
27*5e7646d2SAndroid Build Coastguard Worker 
28*5e7646d2SAndroid Build Coastguard Worker 
29*5e7646d2SAndroid Build Coastguard Worker /*
30*5e7646d2SAndroid Build Coastguard Worker  * 'print_device()' - Print a file to a USB device.
31*5e7646d2SAndroid Build Coastguard Worker  */
32*5e7646d2SAndroid Build Coastguard Worker 
33*5e7646d2SAndroid Build Coastguard Worker int					/* O - Exit status */
print_device(const char * uri,const char * hostname,const char * resource,char * options,int print_fd,int copies,int argc,char * argv[])34*5e7646d2SAndroid Build Coastguard Worker print_device(const char *uri,		/* I - Device URI */
35*5e7646d2SAndroid Build Coastguard Worker              const char *hostname,	/* I - Hostname/manufacturer */
36*5e7646d2SAndroid Build Coastguard Worker              const char *resource,	/* I - Resource/modelname */
37*5e7646d2SAndroid Build Coastguard Worker 	     char       *options,	/* I - Device options/serial number */
38*5e7646d2SAndroid Build Coastguard Worker 	     int        print_fd,	/* I - File descriptor to print */
39*5e7646d2SAndroid Build Coastguard Worker 	     int        copies,		/* I - Copies to print */
40*5e7646d2SAndroid Build Coastguard Worker 	     int	argc,		/* I - Number of command-line arguments (6 or 7) */
41*5e7646d2SAndroid Build Coastguard Worker 	     char	*argv[])	/* I - Command-line arguments */
42*5e7646d2SAndroid Build Coastguard Worker {
43*5e7646d2SAndroid Build Coastguard Worker   int		use_bc;			/* Use backchannel path? */
44*5e7646d2SAndroid Build Coastguard Worker   int		device_fd;		/* USB device */
45*5e7646d2SAndroid Build Coastguard Worker   ssize_t	tbytes;			/* Total number of bytes written */
46*5e7646d2SAndroid Build Coastguard Worker   struct termios opts;			/* Parallel port options */
47*5e7646d2SAndroid Build Coastguard Worker 
48*5e7646d2SAndroid Build Coastguard Worker 
49*5e7646d2SAndroid Build Coastguard Worker   (void)argc;
50*5e7646d2SAndroid Build Coastguard Worker   (void)argv;
51*5e7646d2SAndroid Build Coastguard Worker 
52*5e7646d2SAndroid Build Coastguard Worker  /*
53*5e7646d2SAndroid Build Coastguard Worker   * Open the USB port device...
54*5e7646d2SAndroid Build Coastguard Worker   */
55*5e7646d2SAndroid Build Coastguard Worker 
56*5e7646d2SAndroid Build Coastguard Worker   fputs("STATE: +connecting-to-device\n", stderr);
57*5e7646d2SAndroid Build Coastguard Worker 
58*5e7646d2SAndroid Build Coastguard Worker   do
59*5e7646d2SAndroid Build Coastguard Worker   {
60*5e7646d2SAndroid Build Coastguard Worker #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
61*5e7646d2SAndroid Build Coastguard Worker    /*
62*5e7646d2SAndroid Build Coastguard Worker     * *BSD's ulpt driver currently does not support the
63*5e7646d2SAndroid Build Coastguard Worker     * back-channel, incorrectly returns data ready on a select(),
64*5e7646d2SAndroid Build Coastguard Worker     * and locks up on read()...
65*5e7646d2SAndroid Build Coastguard Worker     */
66*5e7646d2SAndroid Build Coastguard Worker 
67*5e7646d2SAndroid Build Coastguard Worker     use_bc = 0;
68*5e7646d2SAndroid Build Coastguard Worker 
69*5e7646d2SAndroid Build Coastguard Worker #elif defined(__sun)
70*5e7646d2SAndroid Build Coastguard Worker    /*
71*5e7646d2SAndroid Build Coastguard Worker     * CUPS STR #3028: Solaris' usbprn driver apparently does not support
72*5e7646d2SAndroid Build Coastguard Worker     * select() or poll(), so we can't support backchannel...
73*5e7646d2SAndroid Build Coastguard Worker     */
74*5e7646d2SAndroid Build Coastguard Worker 
75*5e7646d2SAndroid Build Coastguard Worker     use_bc = 0;
76*5e7646d2SAndroid Build Coastguard Worker 
77*5e7646d2SAndroid Build Coastguard Worker #else
78*5e7646d2SAndroid Build Coastguard Worker    /*
79*5e7646d2SAndroid Build Coastguard Worker     * Disable backchannel data when printing to Brother, Canon, or
80*5e7646d2SAndroid Build Coastguard Worker     * Minolta USB printers - apparently these printers will return
81*5e7646d2SAndroid Build Coastguard Worker     * the IEEE-1284 device ID over and over and over when they get
82*5e7646d2SAndroid Build Coastguard Worker     * a read request...
83*5e7646d2SAndroid Build Coastguard Worker     */
84*5e7646d2SAndroid Build Coastguard Worker 
85*5e7646d2SAndroid Build Coastguard Worker     use_bc = _cups_strcasecmp(hostname, "Brother") &&
86*5e7646d2SAndroid Build Coastguard Worker              _cups_strcasecmp(hostname, "Canon") &&
87*5e7646d2SAndroid Build Coastguard Worker              _cups_strncasecmp(hostname, "Konica", 6) &&
88*5e7646d2SAndroid Build Coastguard Worker              _cups_strncasecmp(hostname, "Minolta", 7);
89*5e7646d2SAndroid Build Coastguard Worker #endif /* __FreeBSD__ || __NetBSD__ || __OpenBSD__ || __DragonFly__ */
90*5e7646d2SAndroid Build Coastguard Worker 
91*5e7646d2SAndroid Build Coastguard Worker     if ((device_fd = open_device(uri, &use_bc)) == -1)
92*5e7646d2SAndroid Build Coastguard Worker     {
93*5e7646d2SAndroid Build Coastguard Worker       if (getenv("CLASS") != NULL)
94*5e7646d2SAndroid Build Coastguard Worker       {
95*5e7646d2SAndroid Build Coastguard Worker        /*
96*5e7646d2SAndroid Build Coastguard Worker         * If the CLASS environment variable is set, the job was submitted
97*5e7646d2SAndroid Build Coastguard Worker 	* to a class and not to a specific queue.  In this case, we want
98*5e7646d2SAndroid Build Coastguard Worker 	* to abort immediately so that the job can be requeued on the next
99*5e7646d2SAndroid Build Coastguard Worker 	* available printer in the class.
100*5e7646d2SAndroid Build Coastguard Worker 	*/
101*5e7646d2SAndroid Build Coastguard Worker 
102*5e7646d2SAndroid Build Coastguard Worker         _cupsLangPrintFilter(stderr, "INFO",
103*5e7646d2SAndroid Build Coastguard Worker 			     _("Unable to contact printer, queuing on next "
104*5e7646d2SAndroid Build Coastguard Worker 			       "printer in class."));
105*5e7646d2SAndroid Build Coastguard Worker 
106*5e7646d2SAndroid Build Coastguard Worker        /*
107*5e7646d2SAndroid Build Coastguard Worker         * Sleep 5 seconds to keep the job from requeuing too rapidly...
108*5e7646d2SAndroid Build Coastguard Worker 	*/
109*5e7646d2SAndroid Build Coastguard Worker 
110*5e7646d2SAndroid Build Coastguard Worker 	sleep(5);
111*5e7646d2SAndroid Build Coastguard Worker 
112*5e7646d2SAndroid Build Coastguard Worker         return (CUPS_BACKEND_FAILED);
113*5e7646d2SAndroid Build Coastguard Worker       }
114*5e7646d2SAndroid Build Coastguard Worker 
115*5e7646d2SAndroid Build Coastguard Worker       if (errno == EBUSY)
116*5e7646d2SAndroid Build Coastguard Worker       {
117*5e7646d2SAndroid Build Coastguard Worker         _cupsLangPrintFilter(stderr, "INFO", _("The printer is in use."));
118*5e7646d2SAndroid Build Coastguard Worker 	sleep(10);
119*5e7646d2SAndroid Build Coastguard Worker       }
120*5e7646d2SAndroid Build Coastguard Worker       else if (errno == ENXIO || errno == EIO || errno == ENOENT ||
121*5e7646d2SAndroid Build Coastguard Worker                errno == ENODEV)
122*5e7646d2SAndroid Build Coastguard Worker       {
123*5e7646d2SAndroid Build Coastguard Worker 	sleep(30);
124*5e7646d2SAndroid Build Coastguard Worker       }
125*5e7646d2SAndroid Build Coastguard Worker       else
126*5e7646d2SAndroid Build Coastguard Worker       {
127*5e7646d2SAndroid Build Coastguard Worker 	_cupsLangPrintError("ERROR", _("Unable to open device file"));
128*5e7646d2SAndroid Build Coastguard Worker 	return (CUPS_BACKEND_FAILED);
129*5e7646d2SAndroid Build Coastguard Worker       }
130*5e7646d2SAndroid Build Coastguard Worker     }
131*5e7646d2SAndroid Build Coastguard Worker   }
132*5e7646d2SAndroid Build Coastguard Worker   while (device_fd < 0);
133*5e7646d2SAndroid Build Coastguard Worker 
134*5e7646d2SAndroid Build Coastguard Worker   fputs("STATE: -connecting-to-device\n", stderr);
135*5e7646d2SAndroid Build Coastguard Worker 
136*5e7646d2SAndroid Build Coastguard Worker  /*
137*5e7646d2SAndroid Build Coastguard Worker   * Set any options provided...
138*5e7646d2SAndroid Build Coastguard Worker   */
139*5e7646d2SAndroid Build Coastguard Worker 
140*5e7646d2SAndroid Build Coastguard Worker   tcgetattr(device_fd, &opts);
141*5e7646d2SAndroid Build Coastguard Worker 
142*5e7646d2SAndroid Build Coastguard Worker   opts.c_lflag &= ~(unsigned)(ICANON | ECHO | ISIG);	/* Raw mode */
143*5e7646d2SAndroid Build Coastguard Worker 
144*5e7646d2SAndroid Build Coastguard Worker   /**** No options supported yet ****/
145*5e7646d2SAndroid Build Coastguard Worker 
146*5e7646d2SAndroid Build Coastguard Worker   tcsetattr(device_fd, TCSANOW, &opts);
147*5e7646d2SAndroid Build Coastguard Worker 
148*5e7646d2SAndroid Build Coastguard Worker  /*
149*5e7646d2SAndroid Build Coastguard Worker   * Finally, send the print file...
150*5e7646d2SAndroid Build Coastguard Worker   */
151*5e7646d2SAndroid Build Coastguard Worker 
152*5e7646d2SAndroid Build Coastguard Worker   tbytes = 0;
153*5e7646d2SAndroid Build Coastguard Worker 
154*5e7646d2SAndroid Build Coastguard Worker   while (copies > 0 && tbytes >= 0)
155*5e7646d2SAndroid Build Coastguard Worker   {
156*5e7646d2SAndroid Build Coastguard Worker     copies --;
157*5e7646d2SAndroid Build Coastguard Worker 
158*5e7646d2SAndroid Build Coastguard Worker     if (print_fd != 0)
159*5e7646d2SAndroid Build Coastguard Worker     {
160*5e7646d2SAndroid Build Coastguard Worker       fputs("PAGE: 1 1\n", stderr);
161*5e7646d2SAndroid Build Coastguard Worker       lseek(print_fd, 0, SEEK_SET);
162*5e7646d2SAndroid Build Coastguard Worker     }
163*5e7646d2SAndroid Build Coastguard Worker 
164*5e7646d2SAndroid Build Coastguard Worker #ifdef __sun
165*5e7646d2SAndroid Build Coastguard Worker    /*
166*5e7646d2SAndroid Build Coastguard Worker     * CUPS STR #3028: Solaris' usbprn driver apparently does not support
167*5e7646d2SAndroid Build Coastguard Worker     * select() or poll(), so we can't support the sidechannel either...
168*5e7646d2SAndroid Build Coastguard Worker     */
169*5e7646d2SAndroid Build Coastguard Worker 
170*5e7646d2SAndroid Build Coastguard Worker     tbytes = backendRunLoop(print_fd, device_fd, -1, NULL, use_bc, 1, NULL);
171*5e7646d2SAndroid Build Coastguard Worker 
172*5e7646d2SAndroid Build Coastguard Worker #else
173*5e7646d2SAndroid Build Coastguard Worker     tbytes = backendRunLoop(print_fd, device_fd, -1, NULL, use_bc, 1, side_cb);
174*5e7646d2SAndroid Build Coastguard Worker #endif /* __sun */
175*5e7646d2SAndroid Build Coastguard Worker 
176*5e7646d2SAndroid Build Coastguard Worker     if (print_fd != 0 && tbytes >= 0)
177*5e7646d2SAndroid Build Coastguard Worker       _cupsLangPrintFilter(stderr, "INFO", _("Print file sent."));
178*5e7646d2SAndroid Build Coastguard Worker   }
179*5e7646d2SAndroid Build Coastguard Worker 
180*5e7646d2SAndroid Build Coastguard Worker  /*
181*5e7646d2SAndroid Build Coastguard Worker   * Close the USB port and return...
182*5e7646d2SAndroid Build Coastguard Worker   */
183*5e7646d2SAndroid Build Coastguard Worker 
184*5e7646d2SAndroid Build Coastguard Worker   close(device_fd);
185*5e7646d2SAndroid Build Coastguard Worker 
186*5e7646d2SAndroid Build Coastguard Worker   return (CUPS_BACKEND_OK);
187*5e7646d2SAndroid Build Coastguard Worker }
188*5e7646d2SAndroid Build Coastguard Worker 
189*5e7646d2SAndroid Build Coastguard Worker 
190*5e7646d2SAndroid Build Coastguard Worker /*
191*5e7646d2SAndroid Build Coastguard Worker  * 'list_devices()' - List all USB devices.
192*5e7646d2SAndroid Build Coastguard Worker  */
193*5e7646d2SAndroid Build Coastguard Worker 
194*5e7646d2SAndroid Build Coastguard Worker void
list_devices(void)195*5e7646d2SAndroid Build Coastguard Worker list_devices(void)
196*5e7646d2SAndroid Build Coastguard Worker {
197*5e7646d2SAndroid Build Coastguard Worker #ifdef __linux
198*5e7646d2SAndroid Build Coastguard Worker   int	i;				/* Looping var */
199*5e7646d2SAndroid Build Coastguard Worker   int	fd;				/* File descriptor */
200*5e7646d2SAndroid Build Coastguard Worker   char	device[255],			/* Device filename */
201*5e7646d2SAndroid Build Coastguard Worker 	device_id[1024],		/* Device ID string */
202*5e7646d2SAndroid Build Coastguard Worker 	device_uri[1024],		/* Device URI string */
203*5e7646d2SAndroid Build Coastguard Worker 	make_model[1024];		/* Make and model */
204*5e7646d2SAndroid Build Coastguard Worker 
205*5e7646d2SAndroid Build Coastguard Worker 
206*5e7646d2SAndroid Build Coastguard Worker  /*
207*5e7646d2SAndroid Build Coastguard Worker   * Try to open each USB device...
208*5e7646d2SAndroid Build Coastguard Worker   */
209*5e7646d2SAndroid Build Coastguard Worker 
210*5e7646d2SAndroid Build Coastguard Worker   for (i = 0; i < 16; i ++)
211*5e7646d2SAndroid Build Coastguard Worker   {
212*5e7646d2SAndroid Build Coastguard Worker    /*
213*5e7646d2SAndroid Build Coastguard Worker     * Linux has a long history of changing the standard filenames used
214*5e7646d2SAndroid Build Coastguard Worker     * for USB printer devices.  We get the honor of trying them all...
215*5e7646d2SAndroid Build Coastguard Worker     */
216*5e7646d2SAndroid Build Coastguard Worker 
217*5e7646d2SAndroid Build Coastguard Worker     snprintf(device, sizeof(device), "/dev/usblp%d", i);
218*5e7646d2SAndroid Build Coastguard Worker 
219*5e7646d2SAndroid Build Coastguard Worker     if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
220*5e7646d2SAndroid Build Coastguard Worker     {
221*5e7646d2SAndroid Build Coastguard Worker       if (errno != ENOENT)
222*5e7646d2SAndroid Build Coastguard Worker 	continue;
223*5e7646d2SAndroid Build Coastguard Worker 
224*5e7646d2SAndroid Build Coastguard Worker       snprintf(device, sizeof(device), "/dev/usb/lp%d", i);
225*5e7646d2SAndroid Build Coastguard Worker 
226*5e7646d2SAndroid Build Coastguard Worker       if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
227*5e7646d2SAndroid Build Coastguard Worker       {
228*5e7646d2SAndroid Build Coastguard Worker 	if (errno != ENOENT)
229*5e7646d2SAndroid Build Coastguard Worker 	  continue;
230*5e7646d2SAndroid Build Coastguard Worker 
231*5e7646d2SAndroid Build Coastguard Worker 	snprintf(device, sizeof(device), "/dev/usb/usblp%d", i);
232*5e7646d2SAndroid Build Coastguard Worker 
233*5e7646d2SAndroid Build Coastguard Worker     	if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
234*5e7646d2SAndroid Build Coastguard Worker 	  continue;
235*5e7646d2SAndroid Build Coastguard Worker       }
236*5e7646d2SAndroid Build Coastguard Worker     }
237*5e7646d2SAndroid Build Coastguard Worker 
238*5e7646d2SAndroid Build Coastguard Worker     if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
239*5e7646d2SAndroid Build Coastguard Worker                             make_model, sizeof(make_model),
240*5e7646d2SAndroid Build Coastguard Worker 			    "usb", device_uri, sizeof(device_uri)))
241*5e7646d2SAndroid Build Coastguard Worker       cupsBackendReport("direct", device_uri, make_model, make_model,
242*5e7646d2SAndroid Build Coastguard Worker                         device_id, NULL);
243*5e7646d2SAndroid Build Coastguard Worker 
244*5e7646d2SAndroid Build Coastguard Worker     close(fd);
245*5e7646d2SAndroid Build Coastguard Worker   }
246*5e7646d2SAndroid Build Coastguard Worker #elif defined(__sun) && defined(ECPPIOC_GETDEVID)
247*5e7646d2SAndroid Build Coastguard Worker   int	i;			/* Looping var */
248*5e7646d2SAndroid Build Coastguard Worker   int	fd;			/* File descriptor */
249*5e7646d2SAndroid Build Coastguard Worker   char	device[255],		/* Device filename */
250*5e7646d2SAndroid Build Coastguard Worker 	device_id[1024],	/* Device ID string */
251*5e7646d2SAndroid Build Coastguard Worker 	device_uri[1024],	/* Device URI string */
252*5e7646d2SAndroid Build Coastguard Worker 	make_model[1024];	/* Make and model */
253*5e7646d2SAndroid Build Coastguard Worker 
254*5e7646d2SAndroid Build Coastguard Worker 
255*5e7646d2SAndroid Build Coastguard Worker  /*
256*5e7646d2SAndroid Build Coastguard Worker   * Open each USB device...
257*5e7646d2SAndroid Build Coastguard Worker   */
258*5e7646d2SAndroid Build Coastguard Worker 
259*5e7646d2SAndroid Build Coastguard Worker   for (i = 0; i < 8; i ++)
260*5e7646d2SAndroid Build Coastguard Worker   {
261*5e7646d2SAndroid Build Coastguard Worker     snprintf(device, sizeof(device), "/dev/usb/printer%d", i);
262*5e7646d2SAndroid Build Coastguard Worker 
263*5e7646d2SAndroid Build Coastguard Worker     if ((fd = open(device, O_WRONLY | O_EXCL)) >= 0)
264*5e7646d2SAndroid Build Coastguard Worker     {
265*5e7646d2SAndroid Build Coastguard Worker       if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
266*5e7646d2SAndroid Build Coastguard Worker                               make_model, sizeof(make_model),
267*5e7646d2SAndroid Build Coastguard Worker 			      "usb", device_uri, sizeof(device_uri)))
268*5e7646d2SAndroid Build Coastguard Worker 	cupsBackendReport("direct", device_uri, make_model, make_model,
269*5e7646d2SAndroid Build Coastguard Worker 			  device_id, NULL);
270*5e7646d2SAndroid Build Coastguard Worker 
271*5e7646d2SAndroid Build Coastguard Worker       close(fd);
272*5e7646d2SAndroid Build Coastguard Worker     }
273*5e7646d2SAndroid Build Coastguard Worker   }
274*5e7646d2SAndroid Build Coastguard Worker #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
275*5e7646d2SAndroid Build Coastguard Worker   int   i;                      /* Looping var */
276*5e7646d2SAndroid Build Coastguard Worker   char  device[255];            /* Device filename */
277*5e7646d2SAndroid Build Coastguard Worker 
278*5e7646d2SAndroid Build Coastguard Worker 
279*5e7646d2SAndroid Build Coastguard Worker   for (i = 0; i < 8; i ++)
280*5e7646d2SAndroid Build Coastguard Worker   {
281*5e7646d2SAndroid Build Coastguard Worker     snprintf(device, sizeof(device), "/dev/ulpt%d", i);
282*5e7646d2SAndroid Build Coastguard Worker     if (!access(device, 0))
283*5e7646d2SAndroid Build Coastguard Worker       printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
284*5e7646d2SAndroid Build Coastguard Worker 
285*5e7646d2SAndroid Build Coastguard Worker     snprintf(device, sizeof(device), "/dev/unlpt%d", i);
286*5e7646d2SAndroid Build Coastguard Worker     if (!access(device, 0))
287*5e7646d2SAndroid Build Coastguard Worker       printf("direct usb:%s \"Unknown\" \"USB Printer #%d (no reset)\"\n", device, i + 1);
288*5e7646d2SAndroid Build Coastguard Worker   }
289*5e7646d2SAndroid Build Coastguard Worker #endif
290*5e7646d2SAndroid Build Coastguard Worker }
291*5e7646d2SAndroid Build Coastguard Worker 
292*5e7646d2SAndroid Build Coastguard Worker 
293*5e7646d2SAndroid Build Coastguard Worker /*
294*5e7646d2SAndroid Build Coastguard Worker  * 'open_device()' - Open a USB device...
295*5e7646d2SAndroid Build Coastguard Worker  */
296*5e7646d2SAndroid Build Coastguard Worker 
297*5e7646d2SAndroid Build Coastguard Worker static int				/* O - File descriptor or -1 on error */
open_device(const char * uri,int * use_bc)298*5e7646d2SAndroid Build Coastguard Worker open_device(const char *uri,		/* I - Device URI */
299*5e7646d2SAndroid Build Coastguard Worker             int        *use_bc)		/* O - Set to 0 for unidirectional */
300*5e7646d2SAndroid Build Coastguard Worker {
301*5e7646d2SAndroid Build Coastguard Worker   int	fd;				/* File descriptor */
302*5e7646d2SAndroid Build Coastguard Worker 
303*5e7646d2SAndroid Build Coastguard Worker 
304*5e7646d2SAndroid Build Coastguard Worker  /*
305*5e7646d2SAndroid Build Coastguard Worker   * The generic implementation just treats the URI as a device filename...
306*5e7646d2SAndroid Build Coastguard Worker   * Specific operating systems may also support using the device serial
307*5e7646d2SAndroid Build Coastguard Worker   * number and/or make/model.
308*5e7646d2SAndroid Build Coastguard Worker   */
309*5e7646d2SAndroid Build Coastguard Worker 
310*5e7646d2SAndroid Build Coastguard Worker   if (!strncmp(uri, "usb:/dev/", 9))
311*5e7646d2SAndroid Build Coastguard Worker #ifdef __linux
312*5e7646d2SAndroid Build Coastguard Worker   {
313*5e7646d2SAndroid Build Coastguard Worker    /*
314*5e7646d2SAndroid Build Coastguard Worker     * Do not allow direct devices anymore...
315*5e7646d2SAndroid Build Coastguard Worker     */
316*5e7646d2SAndroid Build Coastguard Worker 
317*5e7646d2SAndroid Build Coastguard Worker     errno = ENODEV;
318*5e7646d2SAndroid Build Coastguard Worker     return (-1);
319*5e7646d2SAndroid Build Coastguard Worker   }
320*5e7646d2SAndroid Build Coastguard Worker   else if (!strncmp(uri, "usb://", 6))
321*5e7646d2SAndroid Build Coastguard Worker   {
322*5e7646d2SAndroid Build Coastguard Worker    /*
323*5e7646d2SAndroid Build Coastguard Worker     * For Linux, try looking up the device serial number or model...
324*5e7646d2SAndroid Build Coastguard Worker     */
325*5e7646d2SAndroid Build Coastguard Worker 
326*5e7646d2SAndroid Build Coastguard Worker     int		i;			/* Looping var */
327*5e7646d2SAndroid Build Coastguard Worker     int		busy;			/* Are any ports busy? */
328*5e7646d2SAndroid Build Coastguard Worker     char	device[255],		/* Device filename */
329*5e7646d2SAndroid Build Coastguard Worker 		device_id[1024],	/* Device ID string */
330*5e7646d2SAndroid Build Coastguard Worker 		make_model[1024],	/* Make and model */
331*5e7646d2SAndroid Build Coastguard Worker 		device_uri[1024];	/* Device URI string */
332*5e7646d2SAndroid Build Coastguard Worker 
333*5e7646d2SAndroid Build Coastguard Worker 
334*5e7646d2SAndroid Build Coastguard Worker    /*
335*5e7646d2SAndroid Build Coastguard Worker     * Find the correct USB device...
336*5e7646d2SAndroid Build Coastguard Worker     */
337*5e7646d2SAndroid Build Coastguard Worker 
338*5e7646d2SAndroid Build Coastguard Worker     for (;;)
339*5e7646d2SAndroid Build Coastguard Worker     {
340*5e7646d2SAndroid Build Coastguard Worker       for (busy = 0, i = 0; i < 16; i ++)
341*5e7646d2SAndroid Build Coastguard Worker       {
342*5e7646d2SAndroid Build Coastguard Worker        /*
343*5e7646d2SAndroid Build Coastguard Worker 	* Linux has a long history of changing the standard filenames used
344*5e7646d2SAndroid Build Coastguard Worker 	* for USB printer devices.  We get the honor of trying them all...
345*5e7646d2SAndroid Build Coastguard Worker 	*/
346*5e7646d2SAndroid Build Coastguard Worker 
347*5e7646d2SAndroid Build Coastguard Worker 	snprintf(device, sizeof(device), "/dev/usblp%d", i);
348*5e7646d2SAndroid Build Coastguard Worker 
349*5e7646d2SAndroid Build Coastguard Worker 	if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT)
350*5e7646d2SAndroid Build Coastguard Worker 	{
351*5e7646d2SAndroid Build Coastguard Worker 	  snprintf(device, sizeof(device), "/dev/usb/lp%d", i);
352*5e7646d2SAndroid Build Coastguard Worker 
353*5e7646d2SAndroid Build Coastguard Worker 	  if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT)
354*5e7646d2SAndroid Build Coastguard Worker 	  {
355*5e7646d2SAndroid Build Coastguard Worker 	    snprintf(device, sizeof(device), "/dev/usb/usblp%d", i);
356*5e7646d2SAndroid Build Coastguard Worker 
357*5e7646d2SAndroid Build Coastguard Worker     	    if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT)
358*5e7646d2SAndroid Build Coastguard Worker 	      continue;
359*5e7646d2SAndroid Build Coastguard Worker 	  }
360*5e7646d2SAndroid Build Coastguard Worker 	}
361*5e7646d2SAndroid Build Coastguard Worker 
362*5e7646d2SAndroid Build Coastguard Worker 	if (fd >= 0)
363*5e7646d2SAndroid Build Coastguard Worker 	{
364*5e7646d2SAndroid Build Coastguard Worker 	  backendGetDeviceID(fd, device_id, sizeof(device_id),
365*5e7646d2SAndroid Build Coastguard Worker                              make_model, sizeof(make_model),
366*5e7646d2SAndroid Build Coastguard Worker 			     "usb", device_uri, sizeof(device_uri));
367*5e7646d2SAndroid Build Coastguard Worker 	}
368*5e7646d2SAndroid Build Coastguard Worker 	else
369*5e7646d2SAndroid Build Coastguard Worker 	{
370*5e7646d2SAndroid Build Coastguard Worker 	 /*
371*5e7646d2SAndroid Build Coastguard Worker 	  * If the open failed because it was busy, flag it so we retry
372*5e7646d2SAndroid Build Coastguard Worker 	  * as needed...
373*5e7646d2SAndroid Build Coastguard Worker 	  */
374*5e7646d2SAndroid Build Coastguard Worker 
375*5e7646d2SAndroid Build Coastguard Worker 	  if (errno == EBUSY)
376*5e7646d2SAndroid Build Coastguard Worker 	    busy = 1;
377*5e7646d2SAndroid Build Coastguard Worker 
378*5e7646d2SAndroid Build Coastguard Worker 	  device_uri[0] = '\0';
379*5e7646d2SAndroid Build Coastguard Worker         }
380*5e7646d2SAndroid Build Coastguard Worker 
381*5e7646d2SAndroid Build Coastguard Worker         if (!strcmp(uri, device_uri))
382*5e7646d2SAndroid Build Coastguard Worker 	{
383*5e7646d2SAndroid Build Coastguard Worker 	 /*
384*5e7646d2SAndroid Build Coastguard Worker 	  * Yes, return this file descriptor...
385*5e7646d2SAndroid Build Coastguard Worker 	  */
386*5e7646d2SAndroid Build Coastguard Worker 
387*5e7646d2SAndroid Build Coastguard Worker 	  fprintf(stderr, "DEBUG: Printer using device file \"%s\"...\n",
388*5e7646d2SAndroid Build Coastguard Worker 		  device);
389*5e7646d2SAndroid Build Coastguard Worker 
390*5e7646d2SAndroid Build Coastguard Worker 	  return (fd);
391*5e7646d2SAndroid Build Coastguard Worker 	}
392*5e7646d2SAndroid Build Coastguard Worker 
393*5e7646d2SAndroid Build Coastguard Worker        /*
394*5e7646d2SAndroid Build Coastguard Worker 	* This wasn't the one...
395*5e7646d2SAndroid Build Coastguard Worker 	*/
396*5e7646d2SAndroid Build Coastguard Worker 
397*5e7646d2SAndroid Build Coastguard Worker         if (fd >= 0)
398*5e7646d2SAndroid Build Coastguard Worker 	  close(fd);
399*5e7646d2SAndroid Build Coastguard Worker       }
400*5e7646d2SAndroid Build Coastguard Worker 
401*5e7646d2SAndroid Build Coastguard Worker      /*
402*5e7646d2SAndroid Build Coastguard Worker       * If we get here and at least one of the printer ports showed up
403*5e7646d2SAndroid Build Coastguard Worker       * as "busy", then sleep for a bit and retry...
404*5e7646d2SAndroid Build Coastguard Worker       */
405*5e7646d2SAndroid Build Coastguard Worker 
406*5e7646d2SAndroid Build Coastguard Worker       if (busy)
407*5e7646d2SAndroid Build Coastguard Worker 	_cupsLangPrintFilter(stderr, "INFO", _("The printer is in use."));
408*5e7646d2SAndroid Build Coastguard Worker 
409*5e7646d2SAndroid Build Coastguard Worker       sleep(5);
410*5e7646d2SAndroid Build Coastguard Worker     }
411*5e7646d2SAndroid Build Coastguard Worker   }
412*5e7646d2SAndroid Build Coastguard Worker #elif defined(__sun) && defined(ECPPIOC_GETDEVID)
413*5e7646d2SAndroid Build Coastguard Worker   {
414*5e7646d2SAndroid Build Coastguard Worker    /*
415*5e7646d2SAndroid Build Coastguard Worker     * Do not allow direct devices anymore...
416*5e7646d2SAndroid Build Coastguard Worker     */
417*5e7646d2SAndroid Build Coastguard Worker 
418*5e7646d2SAndroid Build Coastguard Worker     errno = ENODEV;
419*5e7646d2SAndroid Build Coastguard Worker     return (-1);
420*5e7646d2SAndroid Build Coastguard Worker   }
421*5e7646d2SAndroid Build Coastguard Worker   else if (!strncmp(uri, "usb://", 6))
422*5e7646d2SAndroid Build Coastguard Worker   {
423*5e7646d2SAndroid Build Coastguard Worker    /*
424*5e7646d2SAndroid Build Coastguard Worker     * For Solaris, try looking up the device serial number or model...
425*5e7646d2SAndroid Build Coastguard Worker     */
426*5e7646d2SAndroid Build Coastguard Worker 
427*5e7646d2SAndroid Build Coastguard Worker     int		i;			/* Looping var */
428*5e7646d2SAndroid Build Coastguard Worker     int		busy;			/* Are any ports busy? */
429*5e7646d2SAndroid Build Coastguard Worker     char	device[255],		/* Device filename */
430*5e7646d2SAndroid Build Coastguard Worker 		device_id[1024],	/* Device ID string */
431*5e7646d2SAndroid Build Coastguard Worker 		make_model[1024],	/* Make and model */
432*5e7646d2SAndroid Build Coastguard Worker 		device_uri[1024];	/* Device URI string */
433*5e7646d2SAndroid Build Coastguard Worker 
434*5e7646d2SAndroid Build Coastguard Worker 
435*5e7646d2SAndroid Build Coastguard Worker    /*
436*5e7646d2SAndroid Build Coastguard Worker     * Find the correct USB device...
437*5e7646d2SAndroid Build Coastguard Worker     */
438*5e7646d2SAndroid Build Coastguard Worker 
439*5e7646d2SAndroid Build Coastguard Worker     do
440*5e7646d2SAndroid Build Coastguard Worker     {
441*5e7646d2SAndroid Build Coastguard Worker       for (i = 0, busy = 0; i < 8; i ++)
442*5e7646d2SAndroid Build Coastguard Worker       {
443*5e7646d2SAndroid Build Coastguard Worker 	snprintf(device, sizeof(device), "/dev/usb/printer%d", i);
444*5e7646d2SAndroid Build Coastguard Worker 
445*5e7646d2SAndroid Build Coastguard Worker 	if ((fd = open(device, O_WRONLY | O_EXCL)) >= 0)
446*5e7646d2SAndroid Build Coastguard Worker 	  backendGetDeviceID(fd, device_id, sizeof(device_id),
447*5e7646d2SAndroid Build Coastguard Worker                              make_model, sizeof(make_model),
448*5e7646d2SAndroid Build Coastguard Worker 			     "usb", device_uri, sizeof(device_uri));
449*5e7646d2SAndroid Build Coastguard Worker 	else
450*5e7646d2SAndroid Build Coastguard Worker 	{
451*5e7646d2SAndroid Build Coastguard Worker 	 /*
452*5e7646d2SAndroid Build Coastguard Worker 	  * If the open failed because it was busy, flag it so we retry
453*5e7646d2SAndroid Build Coastguard Worker 	  * as needed...
454*5e7646d2SAndroid Build Coastguard Worker 	  */
455*5e7646d2SAndroid Build Coastguard Worker 
456*5e7646d2SAndroid Build Coastguard Worker 	  if (errno == EBUSY)
457*5e7646d2SAndroid Build Coastguard Worker 	    busy = 1;
458*5e7646d2SAndroid Build Coastguard Worker 
459*5e7646d2SAndroid Build Coastguard Worker 	  device_uri[0] = '\0';
460*5e7646d2SAndroid Build Coastguard Worker         }
461*5e7646d2SAndroid Build Coastguard Worker 
462*5e7646d2SAndroid Build Coastguard Worker         if (!strcmp(uri, device_uri))
463*5e7646d2SAndroid Build Coastguard Worker 	{
464*5e7646d2SAndroid Build Coastguard Worker 	 /*
465*5e7646d2SAndroid Build Coastguard Worker 	  * Yes, return this file descriptor...
466*5e7646d2SAndroid Build Coastguard Worker 	  */
467*5e7646d2SAndroid Build Coastguard Worker 
468*5e7646d2SAndroid Build Coastguard Worker           fputs("DEBUG: Setting use_bc to 0!\n", stderr);
469*5e7646d2SAndroid Build Coastguard Worker 
470*5e7646d2SAndroid Build Coastguard Worker           *use_bc = 0;
471*5e7646d2SAndroid Build Coastguard Worker 
472*5e7646d2SAndroid Build Coastguard Worker 	  return (fd);
473*5e7646d2SAndroid Build Coastguard Worker 	}
474*5e7646d2SAndroid Build Coastguard Worker 
475*5e7646d2SAndroid Build Coastguard Worker        /*
476*5e7646d2SAndroid Build Coastguard Worker 	* This wasn't the one...
477*5e7646d2SAndroid Build Coastguard Worker 	*/
478*5e7646d2SAndroid Build Coastguard Worker 
479*5e7646d2SAndroid Build Coastguard Worker         if (fd >= 0)
480*5e7646d2SAndroid Build Coastguard Worker 	  close(fd);
481*5e7646d2SAndroid Build Coastguard Worker       }
482*5e7646d2SAndroid Build Coastguard Worker 
483*5e7646d2SAndroid Build Coastguard Worker      /*
484*5e7646d2SAndroid Build Coastguard Worker       * If we get here and at least one of the printer ports showed up
485*5e7646d2SAndroid Build Coastguard Worker       * as "busy", then sleep for a bit and retry...
486*5e7646d2SAndroid Build Coastguard Worker       */
487*5e7646d2SAndroid Build Coastguard Worker 
488*5e7646d2SAndroid Build Coastguard Worker       if (busy)
489*5e7646d2SAndroid Build Coastguard Worker       {
490*5e7646d2SAndroid Build Coastguard Worker 	_cupsLangPrintFilter(stderr, "INFO", _("The printer is in use."));
491*5e7646d2SAndroid Build Coastguard Worker 	sleep(5);
492*5e7646d2SAndroid Build Coastguard Worker       }
493*5e7646d2SAndroid Build Coastguard Worker     }
494*5e7646d2SAndroid Build Coastguard Worker     while (busy);
495*5e7646d2SAndroid Build Coastguard Worker 
496*5e7646d2SAndroid Build Coastguard Worker    /*
497*5e7646d2SAndroid Build Coastguard Worker     * Couldn't find the printer, return "no such device or address"...
498*5e7646d2SAndroid Build Coastguard Worker     */
499*5e7646d2SAndroid Build Coastguard Worker 
500*5e7646d2SAndroid Build Coastguard Worker     errno = ENODEV;
501*5e7646d2SAndroid Build Coastguard Worker 
502*5e7646d2SAndroid Build Coastguard Worker     return (-1);
503*5e7646d2SAndroid Build Coastguard Worker   }
504*5e7646d2SAndroid Build Coastguard Worker #else
505*5e7646d2SAndroid Build Coastguard Worker   {
506*5e7646d2SAndroid Build Coastguard Worker     if (*use_bc)
507*5e7646d2SAndroid Build Coastguard Worker       fd = open(uri + 4, O_RDWR | O_EXCL);
508*5e7646d2SAndroid Build Coastguard Worker     else
509*5e7646d2SAndroid Build Coastguard Worker       fd = -1;
510*5e7646d2SAndroid Build Coastguard Worker 
511*5e7646d2SAndroid Build Coastguard Worker     if (fd < 0)
512*5e7646d2SAndroid Build Coastguard Worker     {
513*5e7646d2SAndroid Build Coastguard Worker       fd      = open(uri + 4, O_WRONLY | O_EXCL);
514*5e7646d2SAndroid Build Coastguard Worker       *use_bc = 0;
515*5e7646d2SAndroid Build Coastguard Worker     }
516*5e7646d2SAndroid Build Coastguard Worker 
517*5e7646d2SAndroid Build Coastguard Worker     return (fd);
518*5e7646d2SAndroid Build Coastguard Worker   }
519*5e7646d2SAndroid Build Coastguard Worker #endif /* __linux */
520*5e7646d2SAndroid Build Coastguard Worker   else
521*5e7646d2SAndroid Build Coastguard Worker   {
522*5e7646d2SAndroid Build Coastguard Worker     errno = ENODEV;
523*5e7646d2SAndroid Build Coastguard Worker     return (-1);
524*5e7646d2SAndroid Build Coastguard Worker   }
525*5e7646d2SAndroid Build Coastguard Worker }
526*5e7646d2SAndroid Build Coastguard Worker 
527*5e7646d2SAndroid Build Coastguard Worker 
528*5e7646d2SAndroid Build Coastguard Worker /*
529*5e7646d2SAndroid Build Coastguard Worker  * 'side_cb()' - Handle side-channel requests...
530*5e7646d2SAndroid Build Coastguard Worker  */
531*5e7646d2SAndroid Build Coastguard Worker 
532*5e7646d2SAndroid Build Coastguard Worker static int				/* O - 0 on success, -1 on error */
side_cb(int print_fd,int device_fd,int snmp_fd,http_addr_t * addr,int use_bc)533*5e7646d2SAndroid Build Coastguard Worker side_cb(int         print_fd,		/* I - Print file */
534*5e7646d2SAndroid Build Coastguard Worker         int         device_fd,		/* I - Device file */
535*5e7646d2SAndroid Build Coastguard Worker         int         snmp_fd,		/* I - SNMP socket (unused) */
536*5e7646d2SAndroid Build Coastguard Worker 	http_addr_t *addr,		/* I - Device address (unused) */
537*5e7646d2SAndroid Build Coastguard Worker 	int         use_bc)		/* I - Using back-channel? */
538*5e7646d2SAndroid Build Coastguard Worker {
539*5e7646d2SAndroid Build Coastguard Worker   cups_sc_command_t	command;	/* Request command */
540*5e7646d2SAndroid Build Coastguard Worker   cups_sc_status_t	status;		/* Request/response status */
541*5e7646d2SAndroid Build Coastguard Worker   char			data[2048];	/* Request/response data */
542*5e7646d2SAndroid Build Coastguard Worker   int			datalen;	/* Request/response data size */
543*5e7646d2SAndroid Build Coastguard Worker 
544*5e7646d2SAndroid Build Coastguard Worker 
545*5e7646d2SAndroid Build Coastguard Worker   (void)snmp_fd;
546*5e7646d2SAndroid Build Coastguard Worker   (void)addr;
547*5e7646d2SAndroid Build Coastguard Worker 
548*5e7646d2SAndroid Build Coastguard Worker   datalen = sizeof(data);
549*5e7646d2SAndroid Build Coastguard Worker 
550*5e7646d2SAndroid Build Coastguard Worker   if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
551*5e7646d2SAndroid Build Coastguard Worker     return (-1);
552*5e7646d2SAndroid Build Coastguard Worker 
553*5e7646d2SAndroid Build Coastguard Worker   switch (command)
554*5e7646d2SAndroid Build Coastguard Worker   {
555*5e7646d2SAndroid Build Coastguard Worker     case CUPS_SC_CMD_DRAIN_OUTPUT :
556*5e7646d2SAndroid Build Coastguard Worker         if (backendDrainOutput(print_fd, device_fd))
557*5e7646d2SAndroid Build Coastguard Worker 	  status = CUPS_SC_STATUS_IO_ERROR;
558*5e7646d2SAndroid Build Coastguard Worker 	else if (tcdrain(device_fd))
559*5e7646d2SAndroid Build Coastguard Worker 	  status = CUPS_SC_STATUS_IO_ERROR;
560*5e7646d2SAndroid Build Coastguard Worker 	else
561*5e7646d2SAndroid Build Coastguard Worker 	  status = CUPS_SC_STATUS_OK;
562*5e7646d2SAndroid Build Coastguard Worker 
563*5e7646d2SAndroid Build Coastguard Worker 	datalen = 0;
564*5e7646d2SAndroid Build Coastguard Worker         break;
565*5e7646d2SAndroid Build Coastguard Worker 
566*5e7646d2SAndroid Build Coastguard Worker     case CUPS_SC_CMD_GET_BIDI :
567*5e7646d2SAndroid Build Coastguard Worker 	status  = CUPS_SC_STATUS_OK;
568*5e7646d2SAndroid Build Coastguard Worker         data[0] = use_bc;
569*5e7646d2SAndroid Build Coastguard Worker         datalen = 1;
570*5e7646d2SAndroid Build Coastguard Worker         break;
571*5e7646d2SAndroid Build Coastguard Worker 
572*5e7646d2SAndroid Build Coastguard Worker     case CUPS_SC_CMD_GET_DEVICE_ID :
573*5e7646d2SAndroid Build Coastguard Worker         memset(data, 0, sizeof(data));
574*5e7646d2SAndroid Build Coastguard Worker 
575*5e7646d2SAndroid Build Coastguard Worker         if (backendGetDeviceID(device_fd, data, sizeof(data) - 1,
576*5e7646d2SAndroid Build Coastguard Worker 	                       NULL, 0, NULL, NULL, 0))
577*5e7646d2SAndroid Build Coastguard Worker         {
578*5e7646d2SAndroid Build Coastguard Worker 	  status  = CUPS_SC_STATUS_NOT_IMPLEMENTED;
579*5e7646d2SAndroid Build Coastguard Worker 	  datalen = 0;
580*5e7646d2SAndroid Build Coastguard Worker 	}
581*5e7646d2SAndroid Build Coastguard Worker 	else
582*5e7646d2SAndroid Build Coastguard Worker         {
583*5e7646d2SAndroid Build Coastguard Worker 	  status  = CUPS_SC_STATUS_OK;
584*5e7646d2SAndroid Build Coastguard Worker 	  datalen = strlen(data);
585*5e7646d2SAndroid Build Coastguard Worker 	}
586*5e7646d2SAndroid Build Coastguard Worker         break;
587*5e7646d2SAndroid Build Coastguard Worker 
588*5e7646d2SAndroid Build Coastguard Worker     default :
589*5e7646d2SAndroid Build Coastguard Worker         status  = CUPS_SC_STATUS_NOT_IMPLEMENTED;
590*5e7646d2SAndroid Build Coastguard Worker 	datalen = 0;
591*5e7646d2SAndroid Build Coastguard Worker 	break;
592*5e7646d2SAndroid Build Coastguard Worker   }
593*5e7646d2SAndroid Build Coastguard Worker 
594*5e7646d2SAndroid Build Coastguard Worker   return (cupsSideChannelWrite(command, status, data, datalen, 1.0));
595*5e7646d2SAndroid Build Coastguard Worker }
596