• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2005-2016 Apple Inc. All rights reserved.
3  *
4  * IMPORTANT:  This Apple software is supplied to you by Apple Computer,
5  * Inc. ("Apple") in consideration of your agreement to the following
6  * terms, and your use, installation, modification or redistribution of
7  * this Apple software constitutes acceptance of these terms.  If you do
8  * not agree with these terms, please do not use, install, modify or
9  * redistribute this Apple software.
10  *
11  * In consideration of your agreement to abide by the following terms, and
12  * subject to these terms, Apple grants you a personal, non-exclusive
13  * license, under Apple's copyrights in this original Apple software (the
14  * "Apple Software"), to use, reproduce, modify and redistribute the Apple
15  * Software, with or without modifications, in source and/or binary forms;
16  * provided that if you redistribute the Apple Software in its entirety and
17  * without modifications, you must retain this notice and the following
18  * text and disclaimers in all such redistributions of the Apple Software.
19  * Neither the name, trademarks, service marks or logos of Apple Computer,
20  * Inc. may be used to endorse or promote products derived from the Apple
21  * Software without specific prior written permission from Apple.  Except
22  * as expressly stated in this notice, no other rights or licenses, express
23  * or implied, are granted by Apple herein, including but not limited to
24  * any patent rights that may be infringed by your derivative works or by
25  * other works in which the Apple Software may be incorporated.
26  *
27  * The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
28  * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
29  * THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
30  * FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
31  * OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
32  *
33  * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
34  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36  * INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
37  * MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
38  * AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
39  * STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
40  * POSSIBILITY OF SUCH DAMAGE.
41  */
42 
43 /*
44  * Include necessary headers.
45  */
46 
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <errno.h>
50 #include <signal.h>
51 #include <fcntl.h>
52 #include <termios.h>
53 #include <unistd.h>
54 #include <sys/stat.h>
55 #include <sys/sysctl.h>
56 #include <libgen.h>
57 #include <mach/mach.h>
58 #include <mach/mach_error.h>
59 #include <mach/mach_time.h>
60 #include <cups/debug-private.h>
61 #include <cups/file-private.h>
62 #include <cups/sidechannel.h>
63 #include <cups/language-private.h>
64 #include <cups/ppd-private.h>
65 #include "backend-private.h"
66 #include <CoreFoundation/CoreFoundation.h>
67 #include <IOKit/usb/IOUSBLib.h>
68 #include <IOKit/IOCFPlugIn.h>
69 #include <libproc.h>
70 #include <asl.h>
71 #include <spawn.h>
72 #include <pthread.h>
73 
74 /*
75  * Include necessary headers.
76  */
77 
78 extern char **environ;
79 
80 
81 /*
82  * DEBUG_WRITES, if defined, causes the backend to write data to the printer in
83  * 512 byte increments, up to 8192 bytes, to make debugging with a USB bus
84  * analyzer easier.
85  */
86 
87 #define DEBUG_WRITES 0
88 
89 /*
90  * WAIT_EOF_DELAY is number of seconds we'll wait for responses from
91  * the printer after we've finished sending all the data
92  */
93 #define WAIT_EOF_DELAY			7
94 #define WAIT_SIDE_DELAY			3
95 #define DEFAULT_TIMEOUT			5000L
96 
97 #define	USB_INTERFACE_KIND		CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID245)
98 #define kUSBLanguageEnglish		0x409
99 
100 #define PRINTER_POLLING_INTERVAL	5			/* seconds */
101 #define INITIAL_LOG_INTERVAL		PRINTER_POLLING_INTERVAL
102 #define SUBSEQUENT_LOG_INTERVAL		3 * INITIAL_LOG_INTERVAL
103 
104 #define kUSBPrinterClassTypeID		CFUUIDGetConstantUUIDWithBytes(NULL, 0x06, 0x04, 0x7D, 0x16, 0x53, 0xA2, 0x11, 0xD6, 0x92, 0x06, 0x00, 0x30, 0x65, 0x52, 0x45, 0x92)
105 #define	kUSBPrinterClassInterfaceID	CFUUIDGetConstantUUIDWithBytes(NULL, 0x03, 0x34, 0x6D, 0x74, 0x53, 0xA3, 0x11, 0xD6, 0x9E, 0xA1, 0x76, 0x30, 0x65, 0x52, 0x45, 0x92)
106 
107 #define kUSBClassDriverProperty		CFSTR("USB Printing Class")
108 
109 #define kUSBGenericTOPrinterClassDriver	CFSTR("/System/Library/Printers/Libraries/USBGenericPrintingClass.plugin")
110 #define kUSBPrinterClassDeviceNotOpen	-9664	/*kPMInvalidIOMContext*/
111 
112 #define CRSetCrashLogMessage(m) _crc_make_setter(message, m)
113 #define _crc_make_setter(attr, arg) (gCRAnnotations.attr = (uint64_t)(unsigned long)(arg))
114 #define CRASH_REPORTER_CLIENT_HIDDEN __attribute__((visibility("hidden")))
115 #define CRASHREPORTER_ANNOTATIONS_VERSION 4
116 #define CRASHREPORTER_ANNOTATIONS_SECTION "__crash_info"
117 
118 struct crashreporter_annotations_t {
119 	uint64_t version;		// unsigned long
120 	uint64_t message;		// char *
121 	uint64_t signature_string;	// char *
122 	uint64_t backtrace;		// char *
123 	uint64_t message2;		// char *
124 	uint64_t thread;		// uint64_t
125 	uint64_t dialog_mode;		// unsigned int
126 };
127 
128 CRASH_REPORTER_CLIENT_HIDDEN
129 struct crashreporter_annotations_t gCRAnnotations
130 	__attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION)))
131 	= { CRASHREPORTER_ANNOTATIONS_VERSION, 0, 0, 0, 0, 0, 0 };
132 
133 /*
134  * Section 5.3 USB Printing Class spec
135  */
136 #define kUSBPrintingSubclass			1
137 #define kUSBPrintingProtocolNoOpen		0
138 #define kUSBPrintingProtocolUnidirectional	1
139 #define kUSBPrintingProtocolBidirectional	2
140 #define kUSBPrintingProtocolIPP			4
141 
142 typedef IOUSBInterfaceInterface245	**printer_interface_t;
143 
144 typedef struct iodevice_request_s	/**** Device request ****/
145 {
146   UInt8		requestType;
147   UInt8		request;
148   UInt16	value;
149   UInt16	index;
150   UInt16	length;
151   void		*buffer;
152 } iodevice_request_t;
153 
154 typedef union				/**** Centronics status byte ****/
155 {
156   char		b;
157   struct
158   {
159     unsigned	reserved0:2;
160     unsigned	paperError:1;
161     unsigned	select:1;
162     unsigned	notError:1;
163     unsigned	reserved1:3;
164   } status;
165 } centronics_status_t;
166 
167 typedef struct classdriver_s		/**** g.classdriver context ****/
168 {
169   IUNKNOWN_C_GUTS;
170   CFPlugInRef		plugin;			/* release plugin */
171   IUnknownVTbl		**factory;		/* Factory */
172   void			*vendorReference;	/* vendor class specific usage */
173   UInt32		location;		/* unique location in bus topology */
174   UInt8			interfaceNumber;	/* Interface number */
175   UInt16		vendorID;		/* Vendor id */
176   UInt16		productID;		/* Product id */
177   printer_interface_t	interface;		/* identify the device to IOKit */
178   UInt8			outpipe;		/* mandatory bulkOut pipe */
179   UInt8			inpipe;			/* optional bulkIn pipe */
180 
181   /* general class requests */
182   kern_return_t (*DeviceRequest)(struct classdriver_s **printer, iodevice_request_t *iorequest, UInt16 timeout);
183   kern_return_t	(*GetString)(struct classdriver_s **printer, UInt8 whichString, UInt16 language, UInt16 timeout, CFStringRef *result);
184 
185   /* standard printer class requests */
186   kern_return_t	(*SoftReset)(struct classdriver_s **printer, UInt16 timeout);
187   kern_return_t	(*GetCentronicsStatus)(struct classdriver_s **printer, centronics_status_t *result, UInt16 timeout);
188   kern_return_t	(*GetDeviceID)(struct classdriver_s **printer, CFStringRef *devid, UInt16 timeout);
189 
190   /* standard bulk device requests */
191   kern_return_t (*ReadPipe)(struct classdriver_s **printer, UInt8 *buffer, UInt32 *count);
192   kern_return_t (*WritePipe)(struct classdriver_s **printer, UInt8 *buffer, UInt32 *count, Boolean eoj);
193 
194   /* interface requests */
195   kern_return_t (*Open)(struct classdriver_s **printer, UInt32 location, UInt8 protocol);
196   kern_return_t (*Abort)(struct classdriver_s **printer);
197   kern_return_t (*Close)(struct classdriver_s **printer);
198 
199   /* initialize and terminate */
200   kern_return_t (*Initialize)(struct classdriver_s **printer, struct classdriver_s **baseclass);
201   kern_return_t (*Terminate)(struct classdriver_s **printer);
202 
203 } classdriver_t;
204 
205 typedef Boolean (*iterator_callback_t)(io_service_t obj, printer_interface_t printerIntf, void *refcon);
206 
207 typedef struct iterator_reference_s	/**** Iterator reference data */
208 {
209   iterator_callback_t callback;
210   void		*userdata;
211   Boolean	keepRunning;
212 } iterator_reference_t;
213 
214 typedef struct globals_s
215 {
216   io_service_t		printer_obj;
217   classdriver_t		**classdriver;
218 
219   pthread_mutex_t	read_thread_mutex;
220   pthread_cond_t	read_thread_cond;
221   int			read_thread_stop;
222   int			read_thread_done;
223 
224   pthread_mutex_t	readwrite_lock_mutex;
225   pthread_cond_t	readwrite_lock_cond;
226   int			readwrite_lock;
227 
228   CFStringRef		make;
229   CFStringRef		model;
230   CFStringRef		serial;
231   UInt32		location;
232   UInt8			interfaceNum;
233   UInt8			alternateSetting;
234   UInt8                 interfaceProtocol;
235 
236   CFRunLoopTimerRef 	status_timer;
237 
238   int			print_fd;	/* File descriptor to print */
239   ssize_t		print_bytes;	/* Print bytes read */
240 #if DEBUG_WRITES
241   ssize_t		debug_bytes;	/* Current bytes to read */
242 #endif /* DEBUG_WRITES */
243 
244   Boolean		use_generic_class_driver;
245   Boolean		wait_eof;
246   int			drain_output;	/* Drain all pending output */
247   int			bidi_flag;	/* 0=unidirectional, 1=bidirectional */
248 
249   pthread_mutex_t	sidechannel_thread_mutex;
250   pthread_cond_t	sidechannel_thread_cond;
251   int			sidechannel_thread_stop;
252   int			sidechannel_thread_done;
253 } globals_t;
254 
255 
256 /*
257  * Globals...
258  */
259 
260 globals_t g = { 0 };			/* Globals */
261 int Iterating = 0;			/* Are we iterating the bus? */
262 
263 
264 /*
265  * Local functions...
266  */
267 
268 static Boolean list_device_cb(io_service_t obj, printer_interface_t printerIntf, void *refcon);
269 static Boolean find_device_cb(io_service_t obj, printer_interface_t printerIntf, void *refcon);
270 
271 static CFStringRef cfstr_create_trim(const char *cstr);
272 static CFStringRef copy_value_for_key(CFStringRef deviceID, CFStringRef *keys);
273 static kern_return_t load_classdriver(CFStringRef driverPath, printer_interface_t interface, classdriver_t ***printerDriver);
274 static kern_return_t load_printerdriver(CFStringRef *driverBundlePath);
275 static kern_return_t registry_close(void);
276 static kern_return_t registry_open(CFStringRef *driverBundlePath);
277 static kern_return_t unload_classdriver(classdriver_t ***classdriver);
278 
279 static void *read_thread(void *reference);
280 static void *sidechannel_thread(void *reference);
281 static void device_added(void *userdata, io_iterator_t iterator);
282 static void get_device_id(cups_sc_status_t *status, char *data, int *datalen);
283 static void iterate_printers(iterator_callback_t callBack, void *userdata);
284 static void parse_options(char *options, char *serial, int serial_size, UInt32 *location, Boolean *wait_eof);
285 static void setup_cfLanguage(void);
286 static void soft_reset(void);
287 static void status_timer_cb(CFRunLoopTimerRef timer, void *info);
288 #define IS_64BIT 1
289 #define IS_NOT_64BIT 0
290 
291 #if defined(__i386__) || defined(__x86_64__)
292 static pid_t	child_pid;		/* Child PID */
293 static void run_legacy_backend(int argc, char *argv[], int fd) _CUPS_NORETURN;	/* Starts child backend process running as a ppc executable */
294 #endif /* __i386__ || __x86_64__ */
295 static void sigterm_handler(int sig);	/* SIGTERM handler */
296 static void sigquit_handler(int sig, siginfo_t *si, void *unused) _CUPS_NORETURN;
297 
298 #ifdef PARSE_PS_ERRORS
299 static const char *next_line (const char *buffer);
300 static void parse_pserror (char *sockBuffer, int len);
301 #endif /* PARSE_PS_ERRORS */
302 
303 static printer_interface_t usb_printer_interface_interface(io_service_t usbClass);
304 
305 static CFStringRef copy_printer_interface_deviceid(printer_interface_t printer, UInt8 alternateSetting);
306 static CFStringRef copy_printer_interface_indexed_description(printer_interface_t  printer, UInt8 index, UInt16 language);
307 static CFStringRef deviceIDCopyManufacturer(CFStringRef deviceID);
308 static CFStringRef deviceIDCopyModel(CFStringRef deviceID);
309 static CFStringRef deviceIDCopySerialNumber(CFStringRef deviceID);
310 
311 #pragma mark -
312 
313 /*
314  * 'list_devices()' - List all USB devices.
315  */
316 
list_devices()317 void list_devices()
318 {
319   iterate_printers(list_device_cb, NULL);
320 }
321 
322 
323 /*
324  * 'print_device()' - Print a file to a USB device.
325  */
326 
327 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[])328 print_device(const char *uri,		/* I - Device URI */
329              const char *hostname,	/* I - Hostname/manufacturer */
330              const char *resource,	/* I - Resource/modelname */
331 	     char       *options,	/* I - Device options/serial number */
332 	     int        print_fd,	/* I - File descriptor to print */
333 	     int        copies,		/* I - Copies to print */
334 	     int	argc,		/* I - Number of command-line arguments (6 or 7) */
335 	     char	*argv[])	/* I - Command-line arguments */
336 {
337   char		  serial[1024];		/* Serial number buffer */
338   OSStatus	  status;		/* Function results */
339   IOReturn	  iostatus;		/* Current IO status */
340   pthread_t	  read_thread_id,	/* Read thread */
341 		  sidechannel_thread_id;/* Side-channel thread */
342   int		  have_sidechannel = 0;	/* Was the side-channel thread started? */
343   struct stat     sidechannel_info;	/* Side-channel file descriptor info */
344   char		  print_buffer[8192],	/* Print data buffer */
345 		  *print_ptr;		/* Pointer into print data buffer */
346   UInt32	  location;		/* Unique location in bus topology */
347   fd_set	  input_set;		/* Input set for select() */
348   CFStringRef	  driverBundlePath;	/* Class driver path */
349   int		  countdown,		/* Logging interval */
350 		  nfds;			/* Number of file descriptors */
351   ssize_t	  total_bytes;		/* Total bytes written */
352   UInt32	  bytes;		/* Bytes written */
353   struct timeval  *timeout,		/* Timeout pointer */
354 		  tv;			/* Time value */
355   struct timespec cond_timeout;		/* pthread condition timeout */
356   struct sigaction action;		/* Actions for POSIX signals */
357 
358 
359   (void)uri;
360 
361  /*
362   * Catch SIGQUIT to determine who is sending it...
363   */
364 
365   memset(&action, 0, sizeof(action));
366   action.sa_sigaction = sigquit_handler;
367   action.sa_flags = SA_SIGINFO;
368   sigaction(SIGQUIT, &action, NULL);
369 
370  /*
371   * See if the side-channel descriptor is valid...
372   */
373 
374   have_sidechannel = !fstat(CUPS_SC_FD, &sidechannel_info) &&
375                      S_ISSOCK(sidechannel_info.st_mode);
376 
377  /*
378   * Localize using CoreFoundation...
379   */
380 
381   setup_cfLanguage();
382 
383   parse_options(options, serial, sizeof(serial), &location, &g.wait_eof);
384 
385   if (resource[0] == '/')
386     resource++;
387 
388   g.print_fd	= print_fd;
389   g.make	= cfstr_create_trim(hostname);
390   g.model	= cfstr_create_trim(resource);
391   g.serial	= cfstr_create_trim(serial);
392   g.location	= location;
393 
394   if (!g.make || !g.model)
395   {
396     fprintf(stderr, "DEBUG: Fatal USB error.\n");
397     _cupsLangPrintFilter(stderr, "ERROR",
398                          _("There was an unrecoverable USB error."));
399 
400     if (!g.make)
401       fputs("DEBUG: USB make string is NULL\n", stderr);
402     if (!g.model)
403       fputs("DEBUG: USB model string is NULL\n", stderr);
404 
405     return (CUPS_BACKEND_STOP);
406   }
407 
408   fputs("STATE: +connecting-to-device\n", stderr);
409 
410   countdown = INITIAL_LOG_INTERVAL;
411 
412   do
413   {
414     if (g.printer_obj)
415     {
416       IOObjectRelease(g.printer_obj);
417       unload_classdriver(&g.classdriver);
418       g.printer_obj = 0x0;
419       g.classdriver = 0x0;
420     }
421     fprintf(stderr, "DEBUG: Looking for '%s %s'\n", hostname, resource);
422 
423     do
424     {
425       iterate_printers(find_device_cb, NULL);
426       if (g.printer_obj != 0x0)
427         break;
428 
429       _cupsLangPrintFilter(stderr, "INFO", _("Waiting for printer to become available."));
430       sleep(5);
431     } while (true);
432 
433     fputs("DEBUG: Opening connection\n", stderr);
434 
435     driverBundlePath = NULL;
436 
437     status = registry_open(&driverBundlePath);
438 
439 #if defined(__i386__) || defined(__x86_64__)
440     /*
441      * If we were unable to load the class drivers for this printer it's
442      * probably because they're ppc or i386. In this case try to run this
443      * backend as i386 or ppc executables so we can use them...
444      */
445     if (status == -2)
446     {
447       run_legacy_backend(argc, argv, print_fd);
448       /* Never returns here */
449     }
450 #endif /* __i386__ || __x86_64__ */
451 
452     if (status ==  -2)
453     {
454      /*
455       * If we still were unable to load the class drivers for this printer log
456       * the error and stop the queue...
457       */
458 
459       if (driverBundlePath == NULL || !CFStringGetCString(driverBundlePath, print_buffer, sizeof(print_buffer), kCFStringEncodingUTF8))
460         strlcpy(print_buffer, "USB class driver", sizeof(print_buffer));
461 
462       fputs("STATE: +apple-missing-usbclassdriver-error\n", stderr);
463       _cupsLangPrintFilter(stderr, "ERROR",
464 			   _("There was an unrecoverable USB error."));
465       fprintf(stderr, "DEBUG: Could not load %s\n", print_buffer);
466 
467       if (driverBundlePath)
468 	CFRelease(driverBundlePath);
469 
470       return (CUPS_BACKEND_STOP);
471     }
472 
473     if (driverBundlePath)
474       CFRelease(driverBundlePath);
475 
476     if (status != noErr)
477     {
478       sleep(PRINTER_POLLING_INTERVAL);
479       countdown -= PRINTER_POLLING_INTERVAL;
480       if (countdown <= 0)
481       {
482 	_cupsLangPrintFilter(stderr, "INFO",
483 		             _("Waiting for printer to become available."));
484 	fprintf(stderr, "DEBUG: USB printer status: 0x%08x\n", (int)status);
485 	countdown = SUBSEQUENT_LOG_INTERVAL;	/* subsequent log entries, every 15 seconds */
486       }
487     }
488   } while (status != noErr);
489 
490   fputs("STATE: -connecting-to-device\n", stderr);
491 
492   /*
493    * Now that we are "connected" to the port, ignore SIGTERM so that we
494    * can finish out any page data the driver sends (e.g. to eject the
495    * current page...  Only ignore SIGTERM if we are printing data from
496    * stdin (otherwise you can't cancel raw jobs...)
497    */
498 
499   if (!print_fd)
500   {
501     memset(&action, 0, sizeof(action));
502 
503     sigemptyset(&action.sa_mask);
504     action.sa_handler = SIG_IGN;
505     sigaction(SIGTERM, &action, NULL);
506   }
507 
508  /*
509   * Start the side channel thread if the descriptor is valid...
510   */
511 
512   pthread_mutex_init(&g.readwrite_lock_mutex, NULL);
513   pthread_cond_init(&g.readwrite_lock_cond, NULL);
514   g.readwrite_lock = 1;
515 
516   if (have_sidechannel)
517   {
518     g.sidechannel_thread_stop = 0;
519     g.sidechannel_thread_done = 0;
520 
521     pthread_cond_init(&g.sidechannel_thread_cond, NULL);
522     pthread_mutex_init(&g.sidechannel_thread_mutex, NULL);
523 
524     if (pthread_create(&sidechannel_thread_id, NULL, sidechannel_thread, NULL))
525     {
526       fprintf(stderr, "DEBUG: Fatal USB error.\n");
527       _cupsLangPrintFilter(stderr, "ERROR",
528 			   _("There was an unrecoverable USB error."));
529       fputs("DEBUG: Couldn't create side-channel thread\n", stderr);
530       registry_close();
531       return (CUPS_BACKEND_STOP);
532     }
533   }
534 
535  /*
536   * Get the read thread going...
537   */
538 
539   g.read_thread_stop = 0;
540   g.read_thread_done = 0;
541 
542   pthread_cond_init(&g.read_thread_cond, NULL);
543   pthread_mutex_init(&g.read_thread_mutex, NULL);
544 
545   if (pthread_create(&read_thread_id, NULL, read_thread, NULL))
546   {
547     fprintf(stderr, "DEBUG: Fatal USB error.\n");
548     _cupsLangPrintFilter(stderr, "ERROR",
549                          _("There was an unrecoverable USB error."));
550     fputs("DEBUG: Couldn't create read thread\n", stderr);
551     registry_close();
552     return (CUPS_BACKEND_STOP);
553   }
554 
555  /*
556   * The main thread sends the print file...
557   */
558 
559   g.drain_output = 0;
560   g.print_bytes	 = 0;
561   total_bytes	 = 0;
562   print_ptr	 = print_buffer;
563 
564   while (status == noErr && copies-- > 0)
565   {
566     _cupsLangPrintFilter(stderr, "INFO", _("Sending data to printer."));
567 
568     if (print_fd != STDIN_FILENO)
569     {
570       fputs("PAGE: 1 1\n", stderr);
571       lseek(print_fd, 0, SEEK_SET);
572     }
573 
574     while (status == noErr)
575     {
576       FD_ZERO(&input_set);
577 
578       if (!g.print_bytes)
579 	FD_SET(print_fd, &input_set);
580 
581      /*
582       * Calculate select timeout...
583       *   If we have data waiting to send timeout is 100ms.
584       *   else if we're draining print_fd timeout is 0.
585       *   else we're waiting forever...
586       */
587 
588       if (g.print_bytes)
589       {
590 	tv.tv_sec  = 0;
591 	tv.tv_usec = 100000;		/* 100ms */
592 	timeout = &tv;
593       }
594       else if (g.drain_output)
595       {
596 	tv.tv_sec  = 0;
597 	tv.tv_usec = 0;
598 	timeout = &tv;
599       }
600       else
601 	timeout = NULL;
602 
603      /*
604       * I/O is unlocked around select...
605       */
606 
607       pthread_mutex_lock(&g.readwrite_lock_mutex);
608       g.readwrite_lock = 0;
609       pthread_cond_signal(&g.readwrite_lock_cond);
610       pthread_mutex_unlock(&g.readwrite_lock_mutex);
611 
612       nfds = select(print_fd + 1, &input_set, NULL, NULL, timeout);
613 
614      /*
615       * Reacquire the lock...
616       */
617 
618       pthread_mutex_lock(&g.readwrite_lock_mutex);
619       while (g.readwrite_lock)
620 	pthread_cond_wait(&g.readwrite_lock_cond, &g.readwrite_lock_mutex);
621       g.readwrite_lock = 1;
622       pthread_mutex_unlock(&g.readwrite_lock_mutex);
623 
624       if (nfds < 0)
625       {
626 	if (errno == EINTR && total_bytes == 0)
627 	{
628 	  fputs("DEBUG: Received an interrupt before any bytes were "
629 	        "written, aborting\n", stderr);
630           registry_close();
631           return (CUPS_BACKEND_OK);
632 	}
633 	else if (errno != EAGAIN && errno != EINTR)
634 	{
635 	  _cupsLangPrintFilter(stderr, "ERROR",
636 	                       _("Unable to read print data."));
637 	  perror("DEBUG: select");
638 	  registry_close();
639           return (CUPS_BACKEND_FAILED);
640 	}
641       }
642 
643      /*
644       * If drain output has finished send a response...
645       */
646 
647       if (g.drain_output && !nfds && !g.print_bytes)
648       {
649 	/* Send a response... */
650 	cupsSideChannelWrite(CUPS_SC_CMD_DRAIN_OUTPUT, CUPS_SC_STATUS_OK, NULL, 0, 1.0);
651 	g.drain_output = 0;
652       }
653 
654      /*
655       * Check if we have print data ready...
656       */
657 
658       if (FD_ISSET(print_fd, &input_set))
659       {
660 #if DEBUG_WRITES
661 	g.debug_bytes += 512;
662         if (g.debug_bytes > sizeof(print_buffer))
663 	  g.debug_bytes = 512;
664 
665 	g.print_bytes = read(print_fd, print_buffer, g.debug_bytes);
666 
667 #else
668 	g.print_bytes = read(print_fd, print_buffer, sizeof(print_buffer));
669 #endif /* DEBUG_WRITES */
670 
671 	if (g.print_bytes < 0)
672 	{
673 	 /*
674 	  * Read error - bail if we don't see EAGAIN or EINTR...
675 	  */
676 
677 	  if (errno != EAGAIN && errno != EINTR)
678 	  {
679 	    _cupsLangPrintFilter(stderr, "ERROR",
680 				 _("Unable to read print data."));
681 	    perror("DEBUG: read");
682 	    registry_close();
683 	    return (CUPS_BACKEND_FAILED);
684 	  }
685 
686 	  g.print_bytes = 0;
687 	}
688 	else if (g.print_bytes == 0)
689 	{
690 	 /*
691 	  * End of file, break out of the loop...
692 	  */
693 
694 	  break;
695 	}
696 
697 	print_ptr = print_buffer;
698 
699 	fprintf(stderr, "DEBUG: Read %d bytes of print data...\n",
700 		(int)g.print_bytes);
701       }
702 
703       if (g.print_bytes)
704       {
705 	bytes    = (UInt32)g.print_bytes;
706 	iostatus = (*g.classdriver)->WritePipe(g.classdriver, (UInt8*)print_ptr, &bytes, 0);
707 
708        /*
709 	* Ignore timeout errors, but retain the number of bytes written to
710 	* avoid sending duplicate data...
711 	*/
712 
713 	if (iostatus == kIOUSBTransactionTimeout)
714 	{
715 	  fputs("DEBUG: Got USB transaction timeout during write\n", stderr);
716 	  iostatus = 0;
717 	}
718 
719        /*
720         * If we've stalled, retry the write...
721 	*/
722 
723 	else if (iostatus == kIOUSBPipeStalled)
724 	{
725 	  fputs("DEBUG: Got USB pipe stalled during write\n", stderr);
726 
727 	  bytes    = (UInt32)g.print_bytes;
728 	  iostatus = (*g.classdriver)->WritePipe(g.classdriver, (UInt8*)print_ptr, &bytes, 0);
729 	}
730 
731        /*
732 	* Retry a write after an aborted write since we probably just got
733 	* SIGTERM...
734 	*/
735 
736 	else if (iostatus == kIOReturnAborted)
737 	{
738 	  fputs("DEBUG: Got USB return aborted during write\n", stderr);
739 
740 	  IOReturn err = (*g.classdriver)->Abort(g.classdriver);
741 	  fprintf(stderr, "DEBUG: USB class driver Abort returned %x\n", err);
742 
743 #if DEBUG_WRITES
744           sleep(5);
745 #endif /* DEBUG_WRITES */
746 
747 	  bytes    = (UInt32)g.print_bytes;
748 	  iostatus = (*g.classdriver)->WritePipe(g.classdriver, (UInt8*)print_ptr, &bytes, 0);
749         }
750 
751 	if (iostatus)
752 	{
753 	 /*
754 	  * Write error - bail if we don't see an error we can retry...
755 	  */
756 
757 	  _cupsLangPrintFilter(stderr, "ERROR",
758 	                       _("Unable to send data to printer."));
759 	  fprintf(stderr, "DEBUG: USB class driver WritePipe returned %x\n",
760 	          iostatus);
761 
762 	  IOReturn err = (*g.classdriver)->Abort(g.classdriver);
763 	  fprintf(stderr, "DEBUG: USB class driver Abort returned %x\n",
764 	          err);
765 
766 	  status = CUPS_BACKEND_FAILED;
767 	  break;
768 	}
769 	else if (bytes > 0)
770 	{
771 	  fprintf(stderr, "DEBUG: Wrote %d bytes of print data...\n", (int)bytes);
772 
773 	  g.print_bytes -= bytes;
774 	  print_ptr   += bytes;
775 	  total_bytes += bytes;
776 	}
777       }
778 
779       if (print_fd != 0 && status == noErr)
780 	fprintf(stderr, "DEBUG: Sending print file, %lld bytes...\n",
781 		(off_t)total_bytes);
782     }
783   }
784 
785   fprintf(stderr, "DEBUG: Sent %lld bytes...\n", (off_t)total_bytes);
786   fputs("STATE: +cups-waiting-for-job-completed\n", stderr);
787 
788  /*
789   * Signal the side channel thread to exit...
790   */
791 
792   if (have_sidechannel)
793   {
794     close(CUPS_SC_FD);
795     pthread_mutex_lock(&g.readwrite_lock_mutex);
796     g.readwrite_lock = 0;
797     pthread_cond_signal(&g.readwrite_lock_cond);
798     pthread_mutex_unlock(&g.readwrite_lock_mutex);
799 
800     g.sidechannel_thread_stop = 1;
801     pthread_mutex_lock(&g.sidechannel_thread_mutex);
802 
803     if (!g.sidechannel_thread_done)
804     {
805       gettimeofday(&tv, NULL);
806       cond_timeout.tv_sec  = tv.tv_sec + WAIT_SIDE_DELAY;
807       cond_timeout.tv_nsec = tv.tv_usec * 1000;
808 
809       while (!g.sidechannel_thread_done)
810       {
811 	if (pthread_cond_timedwait(&g.sidechannel_thread_cond,
812 				   &g.sidechannel_thread_mutex,
813 				   &cond_timeout) != 0)
814 	  break;
815       }
816     }
817 
818     pthread_mutex_unlock(&g.sidechannel_thread_mutex);
819   }
820 
821  /*
822   * Signal the read thread to exit then wait 7 seconds for it to complete...
823   */
824 
825   g.read_thread_stop = 1;
826 
827   pthread_mutex_lock(&g.read_thread_mutex);
828 
829   if (!g.read_thread_done)
830   {
831     fputs("DEBUG: Waiting for read thread to exit...\n", stderr);
832 
833     gettimeofday(&tv, NULL);
834     cond_timeout.tv_sec  = tv.tv_sec + WAIT_EOF_DELAY;
835     cond_timeout.tv_nsec = tv.tv_usec * 1000;
836 
837     while (!g.read_thread_done)
838     {
839       if (pthread_cond_timedwait(&g.read_thread_cond, &g.read_thread_mutex,
840 				 &cond_timeout) != 0)
841 	break;
842     }
843 
844    /*
845     * If it didn't exit abort the pending read and wait an additional second...
846     */
847 
848     if (!g.read_thread_done)
849     {
850       fputs("DEBUG: Read thread still active, aborting the pending read...\n",
851 	    stderr);
852 
853       g.wait_eof = 0;
854 
855       (*g.classdriver)->Abort(g.classdriver);
856 
857       gettimeofday(&tv, NULL);
858       cond_timeout.tv_sec  = tv.tv_sec + 1;
859       cond_timeout.tv_nsec = tv.tv_usec * 1000;
860 
861       while (!g.read_thread_done)
862       {
863 	if (pthread_cond_timedwait(&g.read_thread_cond, &g.read_thread_mutex,
864 				   &cond_timeout) != 0)
865 	  break;
866       }
867     }
868   }
869 
870   pthread_mutex_unlock(&g.read_thread_mutex);
871 
872  /*
873   * Close the connection and input file and general clean up...
874   */
875 
876   registry_close();
877 
878   if (print_fd != STDIN_FILENO)
879     close(print_fd);
880 
881   if (g.make != NULL)
882     CFRelease(g.make);
883 
884   if (g.model != NULL)
885     CFRelease(g.model);
886 
887   if (g.serial != NULL)
888     CFRelease(g.serial);
889 
890   if (g.printer_obj != 0x0)
891     IOObjectRelease(g.printer_obj);
892 
893   return status;
894 }
895 
896 
897 /*
898  * 'read_thread()' - Thread to read the backchannel data on.
899  */
900 
read_thread(void * reference)901 static void *read_thread(void *reference)
902 {
903   UInt8				readbuffer[512];
904   UInt32			rbytes;
905   kern_return_t			readstatus;
906   struct mach_timebase_info	timeBaseInfo;
907   uint64_t			start,
908 				delay;
909 
910 
911   (void)reference;
912 
913   /* Calculate what 250 milliSeconds are in mach absolute time...
914    */
915   mach_timebase_info(&timeBaseInfo);
916   delay = ((uint64_t)250000000 * (uint64_t)timeBaseInfo.denom) / (uint64_t)timeBaseInfo.numer;
917 
918   do
919   {
920    /*
921     * Remember when we started so we can throttle the loop after the read call...
922     */
923 
924     start = mach_absolute_time();
925 
926     rbytes = sizeof(readbuffer);
927     readstatus = (*g.classdriver)->ReadPipe(g.classdriver, readbuffer, &rbytes);
928     if (readstatus == kIOReturnSuccess && rbytes > 0)
929     {
930       fprintf(stderr, "DEBUG: Read %d bytes of back-channel data...\n",
931               (int)rbytes);
932       cupsBackChannelWrite((char*)readbuffer, rbytes, 1.0);
933 
934       /* cntrl-d is echoed by the printer.
935        * NOTES:
936        *   Xerox Phaser 6250D doesn't echo the cntrl-d.
937        *   Xerox Phaser 6250D doesn't always send the product query.
938        */
939       if (g.wait_eof && readbuffer[rbytes-1] == 0x4)
940 	break;
941 
942 #ifdef PARSE_PS_ERRORS
943       parse_pserror(readbuffer, rbytes);
944 #endif
945     }
946     else if (readstatus == kIOUSBTransactionTimeout)
947       fputs("DEBUG: Got USB transaction timeout during read\n", stderr);
948     else if (readstatus == kIOUSBPipeStalled)
949       fputs("DEBUG: Got USB pipe stalled during read\n", stderr);
950     else if (readstatus == kIOReturnAborted)
951       fputs("DEBUG: Got USB return aborted during read\n", stderr);
952 
953    /*
954     * Make sure this loop executes no more than once every 250 miliseconds...
955     */
956 
957     if ((readstatus != kIOReturnSuccess || rbytes == 0) && (g.wait_eof || !g.read_thread_stop))
958       mach_wait_until(start + delay);
959 
960   } while (g.wait_eof || !g.read_thread_stop);	/* Abort from main thread tests error here */
961 
962   /* Workaround for usb race condition. <rdar://problem/21882551> */
963   if (!g.wait_eof && g.use_generic_class_driver)
964   {
965      const char *pdl = getenv("FINAL_CONTENT_TYPE");
966      if (pdl && strcmp(pdl, "application/vnd.cups-postscript") == 0)
967      {
968        while (readstatus == kIOReturnSuccess && ((rbytes > 0 && readbuffer[rbytes-1] != 0x4) || rbytes == 0))
969        {
970          start = mach_absolute_time();
971 
972          rbytes = sizeof(readbuffer);
973          readstatus = (*g.classdriver)->ReadPipe(g.classdriver, readbuffer, &rbytes);
974          if (readstatus == kIOReturnSuccess && rbytes > 0 && readbuffer[rbytes-1] == 0x4)
975            break;
976 
977          /* Make sure this loop executes no more than once every 250 miliseconds... */
978          mach_wait_until(start + delay);
979        }
980      }
981   }
982 
983  /*
984   * Let the main thread know that we have completed the read thread...
985   */
986 
987   pthread_mutex_lock(&g.read_thread_mutex);
988   g.read_thread_done = 1;
989   pthread_cond_signal(&g.read_thread_cond);
990   pthread_mutex_unlock(&g.read_thread_mutex);
991 
992   return NULL;
993 }
994 
995 
996 /*
997  * 'sidechannel_thread()' - Handle side-channel requests.
998  */
999 
1000 static void*
sidechannel_thread(void * reference)1001 sidechannel_thread(void *reference)
1002 {
1003   cups_sc_command_t	command;	/* Request command */
1004   cups_sc_status_t	status;		/* Request/response status */
1005   char			data[2048];	/* Request/response data */
1006   int			datalen;	/* Request/response data size */
1007 
1008 
1009   (void)reference;
1010 
1011   do
1012   {
1013     datalen = sizeof(data);
1014 
1015     if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
1016     {
1017       if (status == CUPS_SC_STATUS_TIMEOUT)
1018 	continue;
1019       else
1020 	break;
1021     }
1022 
1023     switch (command)
1024     {
1025       case CUPS_SC_CMD_SOFT_RESET:	/* Do a soft reset */
1026 	  fputs("DEBUG: CUPS_SC_CMD_SOFT_RESET received from driver...\n",
1027 		stderr);
1028 
1029           if ((*g.classdriver)->SoftReset != NULL)
1030 	  {
1031 	    soft_reset();
1032 	    cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, NULL, 0, 1.0);
1033 	    fputs("DEBUG: Returning status CUPS_STATUS_OK with no bytes...\n",
1034 	          stderr);
1035 	  }
1036 	  else
1037 	  {
1038 	    cupsSideChannelWrite(command, CUPS_SC_STATUS_NOT_IMPLEMENTED,
1039 	                         NULL, 0, 1.0);
1040 	    fputs("DEBUG: Returning status CUPS_STATUS_NOT_IMPLEMENTED with "
1041 	          "no bytes...\n", stderr);
1042 	  }
1043 	  break;
1044 
1045       case CUPS_SC_CMD_DRAIN_OUTPUT:	/* Drain all pending output */
1046 	  fputs("DEBUG: CUPS_SC_CMD_DRAIN_OUTPUT received from driver...\n",
1047 		stderr);
1048 
1049 	  g.drain_output = 1;
1050 	  break;
1051 
1052       case CUPS_SC_CMD_GET_BIDI:		/* Is the connection bidirectional? */
1053 	  fputs("DEBUG: CUPS_SC_CMD_GET_BIDI received from driver...\n",
1054 		stderr);
1055 
1056 	  data[0] = (char)g.bidi_flag;
1057 	  cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0);
1058 
1059 	  fprintf(stderr,
1060 	          "DEBUG: Returned CUPS_SC_STATUS_OK with 1 byte (%02X)...\n",
1061 		  data[0]);
1062 	  break;
1063 
1064       case CUPS_SC_CMD_GET_DEVICE_ID:	/* Return IEEE-1284 device ID */
1065 	  fputs("DEBUG: CUPS_SC_CMD_GET_DEVICE_ID received from driver...\n",
1066 		stderr);
1067 
1068 	  datalen = sizeof(data);
1069 	  get_device_id(&status, data, &datalen);
1070 	  cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, datalen, 1.0);
1071 
1072           if ((size_t)datalen < sizeof(data))
1073 	    data[datalen] = '\0';
1074 	  else
1075 	    data[sizeof(data) - 1] = '\0';
1076 
1077 	  fprintf(stderr,
1078 	          "DEBUG: Returning CUPS_SC_STATUS_OK with %d bytes (%s)...\n",
1079 		  datalen, data);
1080 	  break;
1081 
1082       case CUPS_SC_CMD_GET_STATE:		/* Return device state */
1083 	  fputs("DEBUG: CUPS_SC_CMD_GET_STATE received from driver...\n",
1084 		stderr);
1085 
1086 	  data[0] = CUPS_SC_STATE_ONLINE;
1087 	  cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0);
1088 
1089 	  fprintf(stderr,
1090 	          "DEBUG: Returned CUPS_SC_STATUS_OK with 1 byte (%02X)...\n",
1091 		  data[0]);
1092 	  break;
1093 
1094       default:
1095 	  fprintf(stderr, "DEBUG: Unknown side-channel command (%d) received "
1096 			  "from driver...\n", command);
1097 
1098 	  cupsSideChannelWrite(command, CUPS_SC_STATUS_NOT_IMPLEMENTED,
1099 			       NULL, 0, 1.0);
1100 
1101 	  fputs("DEBUG: Returned CUPS_SC_STATUS_NOT_IMPLEMENTED with no bytes...\n",
1102 		stderr);
1103 	  break;
1104     }
1105   }
1106   while (!g.sidechannel_thread_stop);
1107 
1108   pthread_mutex_lock(&g.sidechannel_thread_mutex);
1109   g.sidechannel_thread_done = 1;
1110   pthread_cond_signal(&g.sidechannel_thread_cond);
1111   pthread_mutex_unlock(&g.sidechannel_thread_mutex);
1112 
1113   return NULL;
1114 }
1115 
1116 
1117 #pragma mark -
1118 /*
1119  * 'iterate_printers()' - Iterate over all the printers.
1120  */
iterate_printers(iterator_callback_t callBack,void * userdata)1121 static void iterate_printers(iterator_callback_t callBack, void *userdata)
1122 {
1123   Iterating = 1;
1124 
1125   iterator_reference_t reference = { callBack, userdata, true };
1126 
1127   IONotificationPortRef addNotification = IONotificationPortCreate(kIOMasterPortDefault);
1128 
1129   int printingClass = kUSBPrintingClass;
1130   int printingSubclass = kUSBPrintingSubclass;
1131 
1132   CFNumberRef interfaceClass = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &printingClass);
1133   CFNumberRef interfaceSubClass = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &printingSubclass);
1134 
1135   CFMutableDictionaryRef usbPrinterMatchDictionary = IOServiceMatching(kIOUSBInterfaceClassName);
1136   CFDictionaryAddValue(usbPrinterMatchDictionary, CFSTR("bInterfaceClass"), interfaceClass);
1137   CFDictionaryAddValue(usbPrinterMatchDictionary, CFSTR("bInterfaceSubClass"), interfaceSubClass);
1138 
1139   CFRelease(interfaceClass);
1140   CFRelease(interfaceSubClass);
1141 
1142   io_iterator_t add_iterator = IO_OBJECT_NULL;
1143   IOServiceAddMatchingNotification(addNotification, kIOMatchedNotification,
1144                 usbPrinterMatchDictionary, &device_added, &reference, &add_iterator);
1145   if (add_iterator != IO_OBJECT_NULL)
1146   {
1147     device_added (&reference, add_iterator);
1148     if (reference.keepRunning)
1149     {
1150       CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(addNotification), kCFRunLoopDefaultMode);
1151       CFRunLoopRun();
1152     }
1153     IOObjectRelease(add_iterator);
1154   }
1155   Iterating = 0;
1156 }
1157 
1158 
1159 /*
1160  * 'device_added()' - Device added notifier.
1161  */
device_added(void * userdata,io_iterator_t iterator)1162 static void device_added(void *userdata, io_iterator_t iterator)
1163 {
1164   iterator_reference_t *reference = userdata;
1165   io_service_t intf;
1166 
1167   while (reference->keepRunning && (intf = IOIteratorNext(iterator)) != 0x0)
1168   {
1169     printer_interface_t printerIntf = usb_printer_interface_interface(intf);
1170     if (printerIntf != NULL)
1171     {
1172       UInt8 intfClass = 0, intfSubClass = 0;
1173 
1174       (*printerIntf)->GetInterfaceClass(printerIntf, &intfClass);
1175       (*printerIntf)->GetInterfaceSubClass(printerIntf, &intfSubClass);
1176       if (intfClass == kUSBPrintingInterfaceClass && intfSubClass == kUSBPrintingSubclass)
1177         reference->keepRunning = reference->callback(intf, printerIntf, userdata);
1178         (*printerIntf)->Release(printerIntf);
1179       }
1180       IOObjectRelease(intf);
1181     }
1182 
1183     if (reference->keepRunning && reference->callback)
1184       reference->keepRunning = reference->callback(IO_OBJECT_NULL, NULL, reference->userdata);
1185 
1186     if (!reference->keepRunning)
1187       CFRunLoopStop(CFRunLoopGetCurrent());
1188 }
1189 
1190 /*
1191  * 'list_device_cb()' - list_device iterator callback.
1192  */
list_device_cb(io_service_t obj,printer_interface_t printerIntf,void * refcon)1193 static Boolean list_device_cb(io_service_t obj, printer_interface_t printerIntf, void *refcon)
1194 {
1195   (void)refcon;
1196 
1197   if (obj != IO_OBJECT_NULL)
1198   {
1199     CFStringRef deviceIDString = NULL;
1200     CFStringRef make = NULL;
1201     CFStringRef model = NULL;
1202     CFStringRef serial = NULL;
1203     UInt32 intfLocation;
1204 
1205     deviceIDString = copy_printer_interface_deviceid(printerIntf, 0);
1206     if (deviceIDString == NULL)
1207       goto list_device_done;
1208 
1209     make = deviceIDCopyManufacturer(deviceIDString);
1210     model = deviceIDCopyModel(deviceIDString);
1211     serial = deviceIDCopySerialNumber(deviceIDString);
1212 
1213     char uristr[1024], makestr[1024], modelstr[1024], serialstr[1024];
1214     char optionsstr[1024], idstr[1024], make_modelstr[1024];
1215 
1216     CFStringGetCString(deviceIDString, idstr, sizeof(idstr), kCFStringEncodingUTF8);
1217     backendGetMakeModel(idstr, make_modelstr, sizeof(make_modelstr));
1218 
1219     modelstr[0] = '/';
1220 
1221     if (make  == NULL || !CFStringGetCString(make, makestr, sizeof(makestr), kCFStringEncodingUTF8))
1222       strlcpy(makestr, "Unknown", sizeof(makestr));
1223 
1224     if (model == NULL || !CFStringGetCString(model, &modelstr[1], sizeof(modelstr)-1, kCFStringEncodingUTF8))
1225       strlcpy(modelstr + 1, "Printer", sizeof(modelstr) - 1);
1226 
1227     optionsstr[0] = '\0';
1228     if (serial != NULL && CFStringGetCString(serial, serialstr, sizeof(serialstr), kCFStringEncodingUTF8))
1229       snprintf(optionsstr, sizeof(optionsstr), "?serial=%s", serialstr);
1230     else if ((*printerIntf)->GetLocationID(printerIntf, &intfLocation) == kIOReturnSuccess)
1231       snprintf(optionsstr, sizeof(optionsstr), "?location=%x", (unsigned)intfLocation);
1232 
1233     httpAssembleURI(HTTP_URI_CODING_ALL, uristr, sizeof(uristr), "usb", NULL, makestr, 0, modelstr);
1234     strlcat(uristr, optionsstr, sizeof(uristr));
1235 
1236     cupsBackendReport("direct", uristr, make_modelstr, make_modelstr, idstr,
1237                           NULL);
1238   list_device_done:
1239 
1240     if (make != NULL) CFRelease(make);
1241     if (model != NULL) CFRelease(model);
1242     if (serial != NULL) CFRelease(serial);
1243   }
1244   return obj != IO_OBJECT_NULL;
1245 }
1246 
1247 /*
1248  * 'find_device_cb()' - print_device iterator callback.
1249  */
find_device_cb(io_service_t obj,printer_interface_t printerIntf,void * refcon)1250 static Boolean find_device_cb(io_service_t obj, printer_interface_t printerIntf, void *refcon)
1251 {
1252   (void)refcon;
1253 
1254   Boolean keepLooking = true;
1255 
1256   if (obj != IO_OBJECT_NULL)
1257   {
1258     CFStringRef deviceIDString = NULL;
1259     CFStringRef make = NULL;
1260     CFStringRef model = NULL;
1261     CFStringRef serial = NULL;
1262 
1263     deviceIDString = copy_printer_interface_deviceid(printerIntf, 0);
1264     if (deviceIDString == NULL)
1265       goto find_device_done;
1266 
1267     make = deviceIDCopyManufacturer(deviceIDString);
1268     model = deviceIDCopyModel(deviceIDString);
1269     serial = deviceIDCopySerialNumber(deviceIDString);
1270 
1271     if (make && CFStringCompare(make, g.make, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
1272     {
1273       if (model && CFStringCompare(model, g.model, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
1274       {
1275         UInt8 intfAltSetting = 0, intfNumber = 0, intfProtocol = 0;
1276         UInt32 intfLocation = 0;
1277 
1278         (*printerIntf)->GetInterfaceProtocol(printerIntf, &intfProtocol);
1279         (*printerIntf)->GetAlternateSetting(printerIntf, &intfAltSetting);
1280         (*printerIntf)->GetInterfaceNumber(printerIntf, &intfNumber);
1281         (*printerIntf)->GetLocationID(printerIntf, &intfLocation);
1282 
1283         if (intfProtocol == kUSBPrintingProtocolIPP)
1284             return keepLooking;
1285 
1286         if (g.serial != NULL && CFStringGetLength(g.serial) > 0)
1287         {
1288           if (serial != NULL && CFStringCompare(serial, g.serial, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
1289           {
1290             g.interfaceProtocol = intfProtocol;
1291             g.location = intfLocation;
1292             g.alternateSetting = intfAltSetting;
1293             g.printer_obj = obj;
1294             IOObjectRetain(obj);
1295             keepLooking = false;
1296           }
1297         }
1298         else
1299         {
1300           if (g.printer_obj != 0)
1301             IOObjectRelease(g.printer_obj);
1302 
1303             if (g.location == 0 || g.location == intfLocation)
1304                 keepLooking = false;
1305 
1306             g.location = intfLocation;
1307             g.alternateSetting = intfAltSetting;
1308             g.interfaceProtocol = intfProtocol;
1309             g.printer_obj = obj;
1310             IOObjectRetain(obj);
1311         }
1312 
1313         if (!keepLooking)
1314           g.interfaceNum = intfNumber;
1315       }
1316     }
1317 
1318   find_device_done:
1319     if (deviceIDString != NULL) CFRelease(deviceIDString);
1320     if (make != NULL) CFRelease(make);
1321     if (model != NULL) CFRelease(model);
1322     if (serial != NULL) CFRelease(serial);
1323   }
1324   else
1325   {
1326     keepLooking = (g.printer_obj == 0 && g.interfaceProtocol != kUSBPrintingProtocolIPP);
1327     if (obj == IO_OBJECT_NULL && keepLooking)
1328     {
1329       CFRunLoopTimerContext context = { 0, refcon, NULL, NULL, NULL };
1330       CFRunLoopTimerRef timer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent() + 1.0, 10, 0x0, 0x0, status_timer_cb, &context);
1331       if (timer != NULL)
1332       {
1333         CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
1334         g.status_timer = timer;
1335       }
1336     }
1337   }
1338 
1339   if (!keepLooking && g.status_timer != NULL)
1340   {
1341     fputs("STATE: -offline-report\n", stderr);
1342     _cupsLangPrintFilter(stderr, "INFO", _("The printer is now online."));
1343     CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), g.status_timer, kCFRunLoopDefaultMode);
1344     CFRelease(g.status_timer);
1345     g.status_timer = NULL;
1346   }
1347 
1348   return keepLooking;
1349 }
1350 
deviceIDCopySerialNumber(CFStringRef deviceID)1351 static CFStringRef deviceIDCopySerialNumber(CFStringRef deviceID)
1352 {
1353     CFStringRef serialKeys[] = { CFSTR("SN:"),  CFSTR("SERN:"), NULL };
1354 
1355     return copy_value_for_key(deviceID, serialKeys);
1356 }
1357 
deviceIDCopyModel(CFStringRef deviceID)1358 static CFStringRef deviceIDCopyModel(CFStringRef deviceID)
1359 {
1360     CFStringRef modelKeys[] = { CFSTR("MDL:"), CFSTR("MODEL:"), NULL };
1361     return copy_value_for_key(deviceID, modelKeys);
1362 }
1363 
deviceIDCopyManufacturer(CFStringRef deviceID)1364 static CFStringRef deviceIDCopyManufacturer(CFStringRef deviceID)
1365 {
1366     CFStringRef makeKeys[]   = { CFSTR("MFG:"), CFSTR("MANUFACTURER:"), NULL };
1367     return copy_value_for_key(deviceID, makeKeys);
1368 }
1369 
1370 /*
1371  * 'status_timer_cb()' - Status timer callback.
1372  */
1373 
status_timer_cb(CFRunLoopTimerRef timer,void * info)1374 static void status_timer_cb(CFRunLoopTimerRef timer,
1375 			    void *info)
1376 {
1377   (void)timer;
1378   (void)info;
1379 
1380   fputs("STATE: +offline-report\n", stderr);
1381   _cupsLangPrintFilter(stderr, "INFO", _("The printer is offline."));
1382 
1383   if (getenv("CLASS") != NULL)
1384   {
1385    /*
1386     * If the CLASS environment variable is set, the job was submitted
1387     * to a class and not to a specific queue.  In this case, we want
1388     * to abort immediately so that the job can be requeued on the next
1389     * available printer in the class.
1390     *
1391     * Sleep 5 seconds to keep the job from requeuing too rapidly...
1392     */
1393 
1394     sleep(5);
1395 
1396     exit(CUPS_BACKEND_FAILED);
1397   }
1398 }
1399 
1400 
1401 #pragma mark -
1402 /*
1403  * 'load_classdriver()' - Load a classdriver.
1404  */
1405 
load_classdriver(CFStringRef driverPath,printer_interface_t interface,classdriver_t *** printerDriver)1406 static kern_return_t load_classdriver(CFStringRef	    driverPath,
1407 				      printer_interface_t   interface,
1408 				      classdriver_t	    ***printerDriver)
1409 {
1410   kern_return_t	kr = kUSBPrinterClassDeviceNotOpen;
1411   classdriver_t	**driver = NULL;
1412   CFStringRef	bundle = driverPath ? driverPath : kUSBGenericTOPrinterClassDriver;
1413   char 		bundlestr[1024];	/* Bundle path */
1414   CFURLRef	url;			/* URL for driver */
1415   CFPlugInRef	plugin = NULL;		/* Plug-in address */
1416 
1417 
1418   CFStringGetCString(bundle, bundlestr, sizeof(bundlestr), kCFStringEncodingUTF8);
1419 
1420  /*
1421   * Validate permissions for the class driver...
1422   */
1423 
1424   _cups_fc_result_t result = _cupsFileCheck(bundlestr,
1425                                             _CUPS_FILE_CHECK_DIRECTORY, 1,
1426                                             Iterating ? NULL : _cupsFileCheckFilter, NULL);
1427 
1428   if (result && driverPath)
1429     return (load_classdriver(NULL, interface, printerDriver));
1430   else if (result)
1431     return (kr);
1432 
1433  /*
1434   * Try loading the class driver...
1435   */
1436 
1437   url = CFURLCreateWithFileSystemPath(NULL, bundle, kCFURLPOSIXPathStyle, true);
1438 
1439   if (url)
1440   {
1441     plugin = CFPlugInCreate(NULL, url);
1442     CFRelease(url);
1443   }
1444   else
1445     plugin = NULL;
1446 
1447   if (plugin)
1448   {
1449     CFArrayRef factories = CFPlugInFindFactoriesForPlugInTypeInPlugIn(kUSBPrinterClassTypeID, plugin);
1450     if (factories != NULL && CFArrayGetCount(factories) > 0)
1451     {
1452       CFUUIDRef factoryID = CFArrayGetValueAtIndex(factories, 0);
1453       IUnknownVTbl **iunknown = CFPlugInInstanceCreate(NULL, factoryID, kUSBPrinterClassTypeID);
1454       if (iunknown != NULL)
1455       {
1456 	kr = (*iunknown)->QueryInterface(iunknown, CFUUIDGetUUIDBytes(kUSBPrinterClassInterfaceID), (LPVOID *)&driver);
1457 	if (kr == kIOReturnSuccess && driver != NULL)
1458 	{
1459 	  classdriver_t **genericDriver = NULL;
1460 	  if (driverPath != NULL && CFStringCompare(driverPath, kUSBGenericTOPrinterClassDriver, 0) != kCFCompareEqualTo)
1461 	    kr = load_classdriver(NULL, interface, &genericDriver);
1462 
1463 	  if (kr == kIOReturnSuccess)
1464 	  {
1465 	    (*driver)->interface = interface;
1466 	    (*driver)->Initialize(driver, genericDriver);
1467 
1468 	    (*driver)->plugin = plugin;
1469 	    (*driver)->interface = interface;
1470 	    *printerDriver = driver;
1471 	  }
1472 	}
1473 	(*iunknown)->Release(iunknown);
1474       }
1475       CFRelease(factories);
1476     }
1477   }
1478 
1479   fprintf(stderr, "DEBUG: load_classdriver(%s) (kr:0x%08x)\n", bundlestr, (int)kr);
1480 
1481   return (kr);
1482 }
1483 
1484 
1485 /*
1486  * 'unload_classdriver()' - Unload a classdriver.
1487  */
1488 
unload_classdriver(classdriver_t *** classdriver)1489 static kern_return_t unload_classdriver(classdriver_t ***classdriver)
1490 {
1491   if (*classdriver != NULL)
1492   {
1493     (**classdriver)->Release(*classdriver);
1494     *classdriver = NULL;
1495   }
1496 
1497   return kIOReturnSuccess;
1498 }
1499 
1500 
1501 /*
1502  * 'load_printerdriver()' - Load vendor's classdriver.
1503  *
1504  * If driverBundlePath is not NULL on return it is the callers responsbility to release it!
1505  */
1506 
load_printerdriver(CFStringRef * driverBundlePath)1507 static kern_return_t load_printerdriver(CFStringRef *driverBundlePath)
1508 {
1509   IOCFPlugInInterface	**iodev = NULL;
1510   SInt32		score;
1511   kern_return_t		kr;
1512   printer_interface_t	interface;
1513   HRESULT		res;
1514 
1515   kr = IOCreatePlugInInterfaceForService(g.printer_obj, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
1516   if (kr == kIOReturnSuccess)
1517   {
1518     if ((res = (*iodev)->QueryInterface(iodev, USB_INTERFACE_KIND, (LPVOID *) &interface)) == noErr)
1519     {
1520       *driverBundlePath = IORegistryEntryCreateCFProperty(g.printer_obj, kUSBClassDriverProperty, NULL, kNilOptions);
1521 
1522       g.use_generic_class_driver = (*driverBundlePath == NULL || (CFStringCompare(*driverBundlePath, kUSBGenericTOPrinterClassDriver, 0x0) == kCFCompareEqualTo));
1523       kr = load_classdriver(*driverBundlePath, interface, &g.classdriver);
1524 
1525       if (kr != kIOReturnSuccess)
1526 	(*interface)->Release(interface);
1527     }
1528     IODestroyPlugInInterface(iodev);
1529   }
1530   return kr;
1531 }
1532 
usb_printer_interface_interface(io_service_t usbClass)1533 static printer_interface_t usb_printer_interface_interface(io_service_t usbClass)
1534 {
1535 	printer_interface_t  intf = NULL;
1536 	IOCFPlugInInterface **plugin = NULL;
1537 	SInt32	score;
1538 	int kr = IOCreatePlugInInterfaceForService(usbClass, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, &score);
1539 	if (kr == kIOReturnSuccess)
1540 	{
1541 		(*plugin)->QueryInterface(plugin, USB_INTERFACE_KIND, (LPVOID *)&intf);
1542 		IODestroyPlugInInterface(plugin);
1543 	}
1544 
1545 	return intf;
1546 }
1547 
copy_printer_interface_deviceid(printer_interface_t printer,UInt8 alternateSetting)1548 static CFStringRef copy_printer_interface_deviceid(printer_interface_t printer, UInt8 alternateSetting)
1549 {
1550 	// I have tried to make this function as neat as I can, but the possibility of needing to resend
1551 	// a request to get the entire string makes it hideous...
1552 	//
1553 	// We package the job of sending a request up into the block (^sendRequest), which takes the size
1554 	// it should allocate for the message buffer. It frees the current buffer if one is set and
1555 	// allocates one of the specified size, then performs the request. We can then easily retry by
1556 	// calling the block again if we fail to get the whole string the first time around.
1557 
1558 	#define kUSBPrintClassGetDeviceID           0
1559 	#define kDefaultNoDataTimeout               5000L
1560 	#define pack_device_id_wIndex(intf, alt)  ((UInt16)((((UInt16)(intf)) << 8) | ((UInt8)(alt))))
1561 
1562 	if (printer == NULL)
1563 			return NULL;
1564 
1565 
1566 	IOReturn err        = kIOReturnError;
1567 	UInt8    configurationIndex	= 0;
1568 	UInt8    interfaceNumber	= 0;
1569 	size_t   bufferLength		= 256;
1570 	CFStringRef ret             = NULL;
1571 
1572 	if ((*printer)->GetConfigurationValue( printer, &configurationIndex) == kIOReturnSuccess &&
1573 			(*printer)->GetInterfaceNumber( printer, &interfaceNumber) == kIOReturnSuccess)
1574 	{
1575 		__block IOUSBDevRequestTO	request;
1576 		IOReturn (^sendRequest)(size_t) = ^ (size_t size)
1577 		{
1578 			if (request.pData)
1579 			{
1580 				free(request.pData);
1581 				request.wLength = 0;
1582 				request.pData = NULL;
1583 			}
1584 
1585 			IOReturn berr = kIOReturnError;
1586 			char *buffer = malloc(size);
1587 			if (buffer == NULL)
1588 				return kIOReturnNoMemory;
1589 
1590 			request.wLength = HostToUSBWord(size);
1591 			request.pData = buffer;
1592 			berr = (*printer)->ControlRequestTO(printer, (UInt8)0, &request);
1593 			return berr;
1594 		};
1595 
1596 		/* This request takes the 0 based configuration index. IOKit returns a 1 based configuration index */
1597 		configurationIndex -= 1;
1598 
1599 		bzero(&request, sizeof(request));
1600 
1601 		request.bmRequestType		= USBmakebmRequestType(kUSBIn, kUSBClass, kUSBInterface);
1602 		request.bRequest			= kUSBPrintClassGetDeviceID;
1603 		request.wValue				= HostToUSBWord(configurationIndex);
1604 		request.wIndex				= HostToUSBWord(pack_device_id_wIndex(interfaceNumber, alternateSetting));
1605 		request.noDataTimeout		= kDefaultNoDataTimeout;
1606 		request.completionTimeout	= 0; // Copying behavior from Generic Class Driver
1607 
1608 		err = sendRequest(bufferLength);
1609 
1610 		if (err == kIOReturnSuccess && request.wLenDone > 1)
1611 		{
1612 			UInt16 actualLength = OSSwapBigToHostInt16(*((UInt16 *)request.pData));
1613 
1614 			if (actualLength > 2 && actualLength <= bufferLength - 2)
1615 			{
1616 				ret = CFStringCreateWithBytes(NULL, (const UInt8 *) &request.pData[2], actualLength - 2, kCFStringEncodingUTF8, false);
1617 			}
1618 			else if (actualLength > 2) {
1619 				err = sendRequest(actualLength);
1620 				if (err == kIOReturnSuccess && request.wLenDone > 0)
1621 				{
1622 					actualLength = OSSwapBigToHostInt16(*((UInt16 *)request.pData));
1623 					ret = CFStringCreateWithBytes(NULL, (const UInt8 *) &request.pData[2], actualLength - 2, kCFStringEncodingUTF8, false);
1624 				}
1625 			}
1626 		}
1627 
1628 		if (request.pData)
1629 			free(request.pData);
1630 	}
1631 
1632 	CFStringRef manufacturer = deviceIDCopyManufacturer(ret);
1633 	CFStringRef model = deviceIDCopyModel(ret);
1634 	CFStringRef serial = deviceIDCopySerialNumber(ret);
1635 
1636 	if (manufacturer == NULL || serial == NULL || model == NULL)
1637 	{
1638 		IOUSBDevRequestTO		request;
1639 		IOUSBDeviceDescriptor	desc;
1640 
1641 		bzero(&request, sizeof(request));
1642 
1643 		request.bmRequestType = USBmakebmRequestType( kUSBIn,  kUSBStandard, kUSBDevice );
1644 		request.bRequest = kUSBRqGetDescriptor;
1645 		request.wValue = kUSBDeviceDesc << 8;
1646 		request.wIndex = 0;
1647 		request.wLength = sizeof(desc);
1648 		request.pData = &desc;
1649 		request.completionTimeout = 0;
1650 		request.noDataTimeout = 60L;
1651 
1652 		err = (*printer)->ControlRequestTO(printer, 0, &request);
1653 		if (err == kIOReturnSuccess)
1654 		{
1655 			CFMutableStringRef extras = CFStringCreateMutable(NULL, 0);
1656 			if (manufacturer == NULL)
1657 			{
1658 				manufacturer = copy_printer_interface_indexed_description(printer, desc.iManufacturer, kUSBLanguageEnglish);
1659 				if (manufacturer && CFStringGetLength(manufacturer) > 0)
1660 					CFStringAppendFormat(extras, NULL, CFSTR("MFG:%@;"), manufacturer);
1661 			}
1662 
1663 			if (model == NULL)
1664 			{
1665 				model = copy_printer_interface_indexed_description(printer, desc.iProduct, kUSBLanguageEnglish);
1666 				if (model && CFStringGetLength(model) > 0)
1667 					CFStringAppendFormat(extras, NULL, CFSTR("MDL:%@;"), model);
1668 			}
1669 
1670 			if (serial == NULL && desc.iSerialNumber != 0)
1671 			{
1672 				serial = copy_printer_interface_indexed_description(printer, desc.iSerialNumber, kUSBLanguageEnglish);
1673 				if (serial && CFStringGetLength(serial) > 0)
1674 					CFStringAppendFormat(extras, NULL, CFSTR("SERN:%@;"), serial);
1675 			}
1676 
1677 			if (ret != NULL)
1678 			{
1679 				CFStringAppend(extras, ret);
1680 				CFRelease(ret);
1681 
1682 				ret = extras;
1683 			}
1684 			else
1685 			{
1686 				ret = extras;
1687 			}
1688 		}
1689 	}
1690 
1691 	if (ret != NULL)
1692 	{
1693 	/* Remove special characters from the serial number */
1694 	CFRange range = (serial != NULL ? CFStringFind(serial, CFSTR("+"), 0) : CFRangeMake(0, 0));
1695 	if (range.length == 1)
1696 	{
1697 		range = CFStringFind(ret, serial, 0);
1698 
1699 		CFMutableStringRef deviceIDString = CFStringCreateMutableCopy(NULL, 0, ret);
1700 		CFRelease(ret);
1701 
1702 		ret = deviceIDString;
1703 		CFStringFindAndReplace(deviceIDString, CFSTR("+"), CFSTR(""), range, 0);
1704 	}
1705 	}
1706 
1707 	if (manufacturer != NULL)
1708 		CFRelease(manufacturer);
1709 
1710 	if (model != NULL)
1711 		CFRelease(model);
1712 
1713 	if (serial != NULL)
1714 		CFRelease(serial);
1715 
1716 	if (ret != NULL && CFStringGetLength(ret) == 0)
1717 	{
1718 		CFRelease(ret);
1719 		return NULL;
1720 	}
1721 
1722 	return ret;
1723 }
1724 
copy_printer_interface_indexed_description(printer_interface_t printer,UInt8 index,UInt16 language)1725 static CFStringRef copy_printer_interface_indexed_description(printer_interface_t  printer, UInt8 index, UInt16 language)
1726 {
1727 	IOReturn err;
1728 	UInt8 description[256]; // Max possible descriptor length
1729 	IOUSBDevRequestTO	request;
1730 
1731 	bzero(description, 2);
1732 
1733 	request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
1734 	request.bRequest = kUSBRqGetDescriptor;
1735 	request.wValue = (kUSBStringDesc << 8) | index;
1736 	request.wIndex = language;
1737 	request.wLength = 2;
1738 	request.pData = &description;
1739 	request.completionTimeout = 0;
1740 	request.noDataTimeout = 60L;
1741 
1742 	err = (*printer)->ControlRequestTO(printer, 0, &request);
1743 	if (err != kIOReturnSuccess && err != kIOReturnOverrun)
1744 	{
1745 		bzero(description, request.wLength);
1746 
1747 		// Let's try again full length. Here's why:
1748 		//      On USB 2.0 controllers, we will not get an overrun error.  We just get a "babble" error
1749 		//      and no valid data.  So, if we ask for the max size, we will either get it, or we'll get an underrun.
1750 		//      It looks like we get it w/out an underrun
1751 
1752 		request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
1753 		request.bRequest = kUSBRqGetDescriptor;
1754 		request.wValue = (kUSBStringDesc << 8) | index;
1755 		request.wIndex = language;
1756 		request.wLength = sizeof description;
1757 		request.pData = &description;
1758 		request.completionTimeout = 0;
1759 		request.noDataTimeout = 60L;
1760 
1761 		err = (*printer)->ControlRequestTO(printer, 0, &request);
1762 		if (err != kIOReturnSuccess && err != kIOReturnUnderrun)
1763 			return NULL;
1764 	}
1765 
1766 	unsigned int length = description[0];
1767 	if (length == 0)
1768 		return CFStringCreateWithCString(NULL, "", kCFStringEncodingUTF8);
1769 
1770 	if (description[1] != kUSBStringDesc)
1771 		return NULL;
1772 
1773 	request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
1774 	request.bRequest = kUSBRqGetDescriptor;
1775 	request.wValue = (kUSBStringDesc << 8) | index;
1776 	request.wIndex = language;
1777 
1778 	bzero(description, length);
1779 	request.wLength = (UInt16)length;
1780 	request.pData = &description;
1781 	request.completionTimeout = 0;
1782 	request.noDataTimeout = 60L;
1783 
1784 	err = (*printer)->ControlRequestTO(printer, 0, &request);
1785 	if (err != kIOReturnSuccess)
1786 		return NULL;
1787 
1788 	if (description[1] != kUSBStringDesc)
1789 		return NULL;
1790 
1791 	if ((description[0] & 1) != 0)
1792 		description[0] &= 0xfe;
1793 
1794 	char buffer[258] = {};
1795 	unsigned int maxLength = sizeof buffer;
1796 	if (description[0] > 1)
1797 	{
1798 		length = (description[0]-2)/2;
1799 
1800 		if (length > maxLength - 1)
1801 			length = maxLength -1;
1802 
1803 		for (unsigned i = 0; i < length; i++)
1804 			buffer[i] = (char) description[2*i+2];
1805 
1806 		buffer[length] = 0;
1807 	}
1808 
1809 	return CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
1810 }
1811 
1812 /*
1813  * 'registry_open()' - Open a connection to the printer.
1814  */
1815 
registry_open(CFStringRef * driverBundlePath)1816 static kern_return_t registry_open(CFStringRef *driverBundlePath)
1817 {
1818   g.bidi_flag = 0;	/* 0=unidirectional */
1819 
1820   kern_return_t kr = load_printerdriver(driverBundlePath);
1821   if (kr != kIOReturnSuccess)
1822     kr = -2;
1823 
1824   if (g.classdriver != NULL)
1825   {
1826   	(*g.classdriver)->interfaceNumber = g.interfaceNum;
1827     kr = (*g.classdriver)->Open(g.classdriver, g.location, kUSBPrintingProtocolBidirectional);
1828     if (kr != kIOReturnSuccess || (*g.classdriver)->interface == NULL)
1829     {
1830       kr = (*g.classdriver)->Open(g.classdriver, g.location, kUSBPrintingProtocolUnidirectional);
1831       if (kr == kIOReturnSuccess)
1832       {
1833 	if ((*g.classdriver)->interface == NULL)
1834 	{
1835 	  (*g.classdriver)->Close(g.classdriver);
1836 	  kr = -1;
1837 	}
1838       }
1839     }
1840     else
1841       g.bidi_flag = 1;	/* 1=bidirectional */
1842   }
1843 
1844   if (kr != kIOReturnSuccess)
1845     unload_classdriver(&g.classdriver);
1846 
1847   return kr;
1848 }
1849 
1850 
1851 /*
1852  * 'registry_close()' - Close the connection to the printer.
1853  */
1854 
registry_close(void)1855 static kern_return_t registry_close(void)
1856 {
1857   if (g.classdriver != NULL)
1858     (*g.classdriver)->Close(g.classdriver);
1859 
1860   unload_classdriver(&g.classdriver);
1861   return kIOReturnSuccess;
1862 }
1863 
1864 #pragma mark -
1865 /*
1866  * 'copy_value_for_key()' - Copy value string associated with a key.
1867  */
1868 
copy_value_for_key(CFStringRef deviceID,CFStringRef * keys)1869 static CFStringRef copy_value_for_key(CFStringRef deviceID,
1870 				      CFStringRef *keys)
1871 {
1872   CFStringRef	value = NULL;
1873   CFArrayRef	kvPairs = deviceID != NULL ? CFStringCreateArrayBySeparatingStrings(NULL, deviceID, CFSTR(";")) : NULL;
1874   CFIndex	max = kvPairs != NULL ? CFArrayGetCount(kvPairs) : 0;
1875   CFIndex	idx = 0;
1876 
1877   while (idx < max && value == NULL)
1878   {
1879     CFStringRef kvpair = CFArrayGetValueAtIndex(kvPairs, idx);
1880     CFIndex idxx = 0;
1881     while (keys[idxx] != NULL && value == NULL)
1882     {
1883       CFRange range = CFStringFind(kvpair, keys[idxx], kCFCompareCaseInsensitive);
1884       if (range.length != -1)
1885       {
1886 	if (range.location != 0)
1887 	{
1888 	  CFMutableStringRef theString = CFStringCreateMutableCopy(NULL, 0, kvpair);
1889 	  CFStringTrimWhitespace(theString);
1890 	  range = CFStringFind(theString, keys[idxx], kCFCompareCaseInsensitive);
1891 	  if (range.location == 0)
1892 	    value = CFStringCreateWithSubstring(NULL, theString, CFRangeMake(range.length, CFStringGetLength(theString) - range.length));
1893 
1894 	  CFRelease(theString);
1895 	}
1896 	else
1897 	{
1898 	  CFStringRef theString = CFStringCreateWithSubstring(NULL, kvpair, CFRangeMake(range.length, CFStringGetLength(kvpair) - range.length));
1899 	  CFMutableStringRef theString2 = CFStringCreateMutableCopy(NULL, 0, theString);
1900 	  CFRelease(theString);
1901 
1902 	  CFStringTrimWhitespace(theString2);
1903 	  value = theString2;
1904 	}
1905       }
1906       idxx++;
1907     }
1908     idx++;
1909   }
1910 
1911   if (kvPairs != NULL)
1912     CFRelease(kvPairs);
1913   return value;
1914 }
1915 
1916 
1917 /*
1918  * 'cfstr_create_trim()' - Create CFString and trim whitespace characters.
1919  */
1920 
cfstr_create_trim(const char * cstr)1921 CFStringRef cfstr_create_trim(const char *cstr)
1922 {
1923   CFStringRef		cfstr;
1924   CFMutableStringRef	cfmutablestr = NULL;
1925 
1926   if ((cfstr = CFStringCreateWithCString(NULL, cstr, kCFStringEncodingUTF8)) != NULL)
1927   {
1928     if ((cfmutablestr = CFStringCreateMutableCopy(NULL, 1024, cfstr)) != NULL)
1929       CFStringTrimWhitespace(cfmutablestr);
1930 
1931     CFRelease(cfstr);
1932   }
1933   return (CFStringRef) cfmutablestr;
1934 }
1935 
1936 
1937 #pragma mark -
1938 /*
1939  * 'parse_options()' - Parse URI options.
1940  */
1941 
parse_options(char * options,char * serial,int serial_size,UInt32 * location,Boolean * wait_eof)1942 static void parse_options(char *options,
1943 			  char *serial,
1944 			  int serial_size,
1945 			  UInt32 *location,
1946 			  Boolean *wait_eof)
1947 {
1948   char	sep,				/* Separator character */
1949 	*name,				/* Name of option */
1950 	*value;				/* Value of option */
1951 
1952 
1953   if (serial)
1954     *serial = '\0';
1955   if (location)
1956     *location = 0;
1957 
1958   if (!options)
1959     return;
1960 
1961   while (*options)
1962   {
1963    /*
1964     * Get the name...
1965     */
1966 
1967     name = options;
1968 
1969     while (*options && *options != '=' && *options != '+' && *options != '&')
1970       options ++;
1971 
1972     if ((sep = *options) != '\0')
1973       *options++ = '\0';
1974 
1975     if (sep == '=')
1976     {
1977      /*
1978       * Get the value...
1979       */
1980 
1981       value = options;
1982 
1983       while (*options && *options != '+' && *options != '&')
1984 	options ++;
1985 
1986       if (*options)
1987 	*options++ = '\0';
1988     }
1989     else
1990       value = (char *)"";
1991 
1992    /*
1993     * Process the option...
1994     */
1995 
1996     if (!_cups_strcasecmp(name, "waiteof"))
1997     {
1998       if (!_cups_strcasecmp(value, "on") ||
1999 	  !_cups_strcasecmp(value, "yes") ||
2000 	  !_cups_strcasecmp(value, "true"))
2001 	*wait_eof = true;
2002       else if (!_cups_strcasecmp(value, "off") ||
2003 	       !_cups_strcasecmp(value, "no") ||
2004 	       !_cups_strcasecmp(value, "false"))
2005 	*wait_eof = false;
2006       else
2007 	_cupsLangPrintFilter(stderr, "WARNING",
2008 			     _("Boolean expected for waiteof option \"%s\"."),
2009 			     value);
2010     }
2011     else if (!_cups_strcasecmp(name, "serial"))
2012       strlcpy(serial, value, (size_t)serial_size);
2013     else if (!_cups_strcasecmp(name, "location") && location)
2014       *location = (UInt32)strtoul(value, NULL, 16);
2015   }
2016 }
2017 
2018 
2019 /*!
2020  * @function	setup_cfLanguage
2021  * @abstract	Convert the contents of the CUPS 'APPLE_LANGUAGE' environment
2022  *		variable into a one element CF array of languages.
2023  *
2024  * @discussion	Each submitted job comes with a natural language. CUPS passes
2025  * 		that language in an environment variable. We take that language
2026  * 		and jam it into the AppleLanguages array so that CF will use
2027  * 		it when reading localized resources. We need to do this before
2028  * 		any CF code reads and caches the languages array, so this function
2029  *		should be called early in main()
2030  */
setup_cfLanguage(void)2031 static void setup_cfLanguage(void)
2032 {
2033   CFStringRef	lang[1] = {NULL};
2034   CFArrayRef	langArray = NULL;
2035   const char	*requestedLang = NULL;
2036 
2037   if ((requestedLang = getenv("APPLE_LANGUAGE")) == NULL)
2038     requestedLang = getenv("LANG");
2039 
2040   if (requestedLang != NULL)
2041   {
2042     lang[0] = CFStringCreateWithCString(kCFAllocatorDefault, requestedLang, kCFStringEncodingUTF8);
2043     langArray = CFArrayCreate(kCFAllocatorDefault, (const void **)lang, sizeof(lang) / sizeof(lang[0]), &kCFTypeArrayCallBacks);
2044 
2045     CFPreferencesSetValue(CFSTR("AppleLanguages"), langArray, kCFPreferencesCurrentApplication, kCFPreferencesAnyUser, kCFPreferencesAnyHost);
2046     fprintf(stderr, "DEBUG: usb: AppleLanguages=\"%s\"\n", requestedLang);
2047 
2048     CFRelease(lang[0]);
2049     CFRelease(langArray);
2050   }
2051   else
2052     fputs("DEBUG: usb: LANG and APPLE_LANGUAGE environment variables missing.\n", stderr);
2053 }
2054 
2055 #pragma mark -
2056 #if defined(__i386__) || defined(__x86_64__)
2057 /*!
2058  * @function	run_legacy_backend
2059  *
2060  * @abstract	Starts child backend process running as a ppc or i386 executable.
2061  *
2062  * @result	Never returns; always calls exit().
2063  *
2064  * @discussion
2065  */
run_legacy_backend(int argc,char * argv[],int fd)2066 static void run_legacy_backend(int argc,
2067 			       char *argv[],
2068 			       int fd)
2069 {
2070   int	i;
2071   int	exitstatus = 0;
2072   int	childstatus;
2073   pid_t	waitpid_status;
2074   char	*my_argv[32];
2075   char	*usb_legacy_status;
2076 
2077 
2078  /*
2079   * If we're running as x86_64 or i386 and couldn't load the class driver
2080   * (because it's ppc or i386), then try to re-exec ourselves in ppc or i386
2081   * mode to try again. If we don't have a ppc or i386 architecture we may be
2082   * running with the same architecture again so guard against this by setting
2083   * and testing an environment variable...
2084   */
2085 
2086 #  ifdef __x86_64__
2087   usb_legacy_status = getenv("USB_I386_STATUS");
2088 #  else
2089   usb_legacy_status = getenv("USB_PPC_STATUS");
2090 #  endif /* __x86_64__ */
2091 
2092   if (!usb_legacy_status)
2093   {
2094    /*
2095     * Setup a SIGTERM handler then block it before forking...
2096     */
2097 
2098     int			err;		/* posix_spawn result */
2099     struct sigaction	action;		/* POSIX signal action */
2100     sigset_t		newmask,	/* New signal mask */
2101 			oldmask;	/* Old signal mask */
2102     char		usbpath[1024];	/* Path to USB backend */
2103     const char		*cups_serverbin;/* Path to CUPS binaries */
2104 
2105 
2106     memset(&action, 0, sizeof(action));
2107     sigaddset(&action.sa_mask, SIGTERM);
2108     action.sa_handler = sigterm_handler;
2109     sigaction(SIGTERM, &action, NULL);
2110 
2111     sigemptyset(&newmask);
2112     sigaddset(&newmask, SIGTERM);
2113     sigprocmask(SIG_BLOCK, &newmask, &oldmask);
2114 
2115    /*
2116     * Set the environment variable...
2117     */
2118 
2119 #  ifdef __x86_64__
2120     setenv("USB_I386_STATUS", "1", false);
2121 #  else
2122     setenv("USB_PPC_STATUS", "1", false);
2123 #  endif /* __x86_64__ */
2124 
2125    /*
2126     * Tell the kernel to use the specified CPU architecture...
2127     */
2128 
2129 #  ifdef __x86_64__
2130     cpu_type_t cpu = CPU_TYPE_I386;
2131 #  else
2132     cpu_type_t cpu = CPU_TYPE_POWERPC;
2133 #  endif /* __x86_64__ */
2134     size_t ocount = 1;
2135     posix_spawnattr_t attrs;
2136 
2137     if (!posix_spawnattr_init(&attrs))
2138     {
2139       posix_spawnattr_setsigdefault(&attrs, &oldmask);
2140       if (posix_spawnattr_setbinpref_np(&attrs, 1, &cpu, &ocount) || ocount != 1)
2141       {
2142 #  ifdef __x86_64__
2143 	perror("DEBUG: Unable to set binary preference to i386");
2144 #  else
2145 	perror("DEBUG: Unable to set binary preference to ppc");
2146 #  endif /* __x86_64__ */
2147 	_cupsLangPrintFilter(stderr, "ERROR",
2148 	                     _("Unable to use legacy USB class driver."));
2149 	exit(CUPS_BACKEND_STOP);
2150       }
2151     }
2152 
2153    /*
2154     * Set up the arguments and call posix_spawn...
2155     */
2156 
2157     if ((cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL)
2158       cups_serverbin = CUPS_SERVERBIN;
2159     snprintf(usbpath, sizeof(usbpath), "%s/backend/usb", cups_serverbin);
2160 
2161     for (i = 0; i < argc && i < (int)(sizeof(my_argv) / sizeof(my_argv[0])) - 1; i ++)
2162       my_argv[i] = argv[i];
2163 
2164     my_argv[i] = NULL;
2165 
2166     if ((err = posix_spawn(&child_pid, usbpath, NULL, &attrs, my_argv,
2167                            environ)) != 0)
2168     {
2169       fprintf(stderr, "DEBUG: Unable to exec %s: %s\n", usbpath,
2170               strerror(err));
2171       _cupsLangPrintFilter(stderr, "ERROR",
2172                            _("Unable to use legacy USB class driver."));
2173       exit(CUPS_BACKEND_STOP);
2174     }
2175 
2176    /*
2177     * Unblock signals...
2178     */
2179 
2180     sigprocmask(SIG_SETMASK, &oldmask, NULL);
2181 
2182    /*
2183     * Close the fds we won't be using then wait for the child backend to exit.
2184     */
2185 
2186     close(fd);
2187     close(1);
2188 
2189     fprintf(stderr, "DEBUG: Started usb(legacy) backend (PID %d)\n",
2190             (int)child_pid);
2191 
2192     while ((waitpid_status = waitpid(child_pid, &childstatus, 0)) == (pid_t)-1 && errno == EINTR)
2193       usleep(1000);
2194 
2195     if (WIFSIGNALED(childstatus))
2196     {
2197       exitstatus = CUPS_BACKEND_STOP;
2198       fprintf(stderr, "DEBUG: usb(legacy) backend %d crashed on signal %d\n",
2199               child_pid, WTERMSIG(childstatus));
2200     }
2201     else
2202     {
2203       if ((exitstatus = WEXITSTATUS(childstatus)) != 0)
2204 	fprintf(stderr,
2205 	        "DEBUG: usb(legacy) backend %d stopped with status %d\n",
2206 		child_pid, exitstatus);
2207       else
2208 	fprintf(stderr, "DEBUG: usb(legacy) backend %d exited with no errors\n",
2209 	        child_pid);
2210     }
2211   }
2212   else
2213   {
2214     fputs("DEBUG: usb(legacy) backend running native again\n", stderr);
2215     exitstatus = CUPS_BACKEND_STOP;
2216   }
2217 
2218   exit(exitstatus);
2219 }
2220 #endif /* __i386__ || __x86_64__ */
2221 
2222 
2223 /*
2224  * 'sigterm_handler()' - SIGTERM handler.
2225  */
2226 
2227 static void
sigterm_handler(int sig)2228 sigterm_handler(int sig)		/* I - Signal */
2229 {
2230 #if defined(__i386__) || defined(__x86_64__)
2231  /*
2232   * If we started a child process pass the signal on to it...
2233   */
2234 
2235   if (child_pid)
2236   {
2237    /*
2238     * If we started a child process pass the signal on to it...
2239     */
2240 
2241     int	status;
2242 
2243     kill(child_pid, sig);
2244     while (waitpid(child_pid, &status, 0) < 0 && errno == EINTR);
2245 
2246     if (WIFEXITED(status))
2247       _exit(WEXITSTATUS(status));
2248     else if (status == SIGTERM || status == SIGKILL)
2249       _exit(0);
2250     else
2251     {
2252       write(2, "DEBUG: Child crashed.\n", 22);
2253       _exit(CUPS_BACKEND_STOP);
2254     }
2255   }
2256 #endif /* __i386__ || __x86_64__ */
2257 }
2258 
2259 
2260 /*
2261  * 'sigquit_handler()' - SIGQUIT handler.
2262  */
2263 
sigquit_handler(int sig,siginfo_t * si,void * unused)2264 static void sigquit_handler(int sig, siginfo_t *si, void *unused)
2265 {
2266   char  *path;
2267   char	pathbuf[PROC_PIDPATHINFO_MAXSIZE];
2268   static char msgbuf[256] = "";
2269 
2270 
2271   (void)sig;
2272   (void)unused;
2273 
2274   if (proc_pidpath(si->si_pid, pathbuf, sizeof(pathbuf)) > 0 &&
2275       (path = basename(pathbuf)) != NULL)
2276     snprintf(msgbuf, sizeof(msgbuf), "SIGQUIT sent by %s(%d)", path, (int)si->si_pid);
2277   else
2278     snprintf(msgbuf, sizeof(msgbuf), "SIGQUIT sent by PID %d", (int)si->si_pid);
2279 
2280   CRSetCrashLogMessage(msgbuf);
2281 
2282   abort();
2283 }
2284 
2285 
2286 #ifdef PARSE_PS_ERRORS
2287 /*
2288  * 'next_line()' - Find the next line in a buffer.
2289  */
2290 
next_line(const char * buffer)2291 static const char *next_line (const char *buffer)
2292 {
2293   const char *cptr, *lptr = NULL;
2294 
2295   for (cptr = buffer; *cptr && lptr == NULL; cptr++)
2296     if (*cptr == '\n' || *cptr == '\r')
2297       lptr = cptr;
2298   return lptr;
2299 }
2300 
2301 
2302 /*
2303  * 'parse_pserror()' - Scan the backchannel data for postscript errors.
2304  */
2305 
parse_pserror(char * sockBuffer,int len)2306 static void parse_pserror(char *sockBuffer,
2307 			  int len)
2308 {
2309   static char  gErrorBuffer[1024] = "";
2310   static char *gErrorBufferPtr = gErrorBuffer;
2311   static char *gErrorBufferEndPtr = gErrorBuffer + sizeof(gErrorBuffer);
2312 
2313   char *pCommentBegin, *pCommentEnd, *pLineEnd;
2314   char *logLevel;
2315   char logstr[1024];
2316   int  logstrlen;
2317 
2318   if (gErrorBufferPtr + len > gErrorBufferEndPtr - 1)
2319     gErrorBufferPtr = gErrorBuffer;
2320   if (len > sizeof(gErrorBuffer) - 1)
2321     len = sizeof(gErrorBuffer) - 1;
2322 
2323   memcpy(gErrorBufferPtr, (const void *)sockBuffer, len);
2324   gErrorBufferPtr += len;
2325   *(gErrorBufferPtr + 1) = '\0';
2326 
2327   pLineEnd = (char *)next_line((const char *)gErrorBuffer);
2328   while (pLineEnd != NULL)
2329   {
2330     *pLineEnd++ = '\0';
2331 
2332     pCommentBegin = strstr(gErrorBuffer,"%%[");
2333     pCommentEnd = strstr(gErrorBuffer, "]%%");
2334     if (pCommentBegin != gErrorBuffer && pCommentEnd != NULL)
2335     {
2336       pCommentEnd += 3;            /* Skip past "]%%" */
2337       *pCommentEnd = '\0';         /* There's always room for the nul */
2338 
2339       if (_cups_strncasecmp(pCommentBegin, "%%[ Error:", 10) == 0)
2340 	logLevel = "DEBUG";
2341       else if (_cups_strncasecmp(pCommentBegin, "%%[ Flushing", 12) == 0)
2342 	logLevel = "DEBUG";
2343       else
2344 	logLevel = "INFO";
2345 
2346       if ((logstrlen = snprintf(logstr, sizeof(logstr), "%s: %s\n", logLevel, pCommentBegin)) >= sizeof(logstr))
2347       {
2348 	/* If the string was trucnated make sure it has a linefeed before the nul */
2349 	logstrlen = sizeof(logstr) - 1;
2350 	logstr[logstrlen - 1] = '\n';
2351       }
2352       write(STDERR_FILENO, logstr, logstrlen);
2353     }
2354 
2355     /* move everything over... */
2356     strlcpy(gErrorBuffer, pLineEnd, sizeof(gErrorBuffer));
2357     gErrorBufferPtr = gErrorBuffer;
2358     pLineEnd = (char *)next_line((const char *)gErrorBuffer);
2359   }
2360 }
2361 #endif /* PARSE_PS_ERRORS */
2362 
2363 
2364 /*
2365  * 'soft_reset()' - Send a soft reset to the device.
2366  */
2367 
soft_reset(void)2368 static void soft_reset(void)
2369 {
2370   fd_set	  input_set;		/* Input set for select() */
2371   struct timeval  tv;			/* Time value */
2372   char		  buffer[2048];		/* Buffer */
2373   struct timespec cond_timeout;		/* pthread condition timeout */
2374 
2375  /*
2376   * Send an abort once a second until the I/O lock is released by the main thread...
2377   */
2378 
2379   pthread_mutex_lock(&g.readwrite_lock_mutex);
2380   while (g.readwrite_lock)
2381   {
2382     (*g.classdriver)->Abort(g.classdriver);
2383 
2384     gettimeofday(&tv, NULL);
2385     cond_timeout.tv_sec  = tv.tv_sec + 1;
2386     cond_timeout.tv_nsec = tv.tv_usec * 1000;
2387 
2388     while (g.readwrite_lock)
2389     {
2390       if (pthread_cond_timedwait(&g.readwrite_lock_cond,
2391 				 &g.readwrite_lock_mutex,
2392 				 &cond_timeout) != 0)
2393 	break;
2394     }
2395   }
2396 
2397   g.readwrite_lock = 1;
2398   pthread_mutex_unlock(&g.readwrite_lock_mutex);
2399 
2400  /*
2401   * Flush bytes waiting on print_fd...
2402   */
2403 
2404   g.print_bytes = 0;
2405 
2406   FD_ZERO(&input_set);
2407   FD_SET(g.print_fd, &input_set);
2408 
2409   tv.tv_sec  = 0;
2410   tv.tv_usec = 0;
2411 
2412   while (select(g.print_fd+1, &input_set, NULL, NULL, &tv) > 0)
2413     if (read(g.print_fd, buffer, sizeof(buffer)) <= 0)
2414       break;
2415 
2416  /*
2417   * Send the reset...
2418   */
2419 
2420   (*g.classdriver)->SoftReset(g.classdriver, DEFAULT_TIMEOUT);
2421 
2422  /*
2423   * Release the I/O lock...
2424   */
2425 
2426   pthread_mutex_lock(&g.readwrite_lock_mutex);
2427   g.readwrite_lock = 0;
2428   pthread_cond_signal(&g.readwrite_lock_cond);
2429   pthread_mutex_unlock(&g.readwrite_lock_mutex);
2430 }
2431 
2432 
2433 /*
2434  * 'get_device_id()' - Return IEEE-1284 device ID.
2435  */
2436 
get_device_id(cups_sc_status_t * status,char * data,int * datalen)2437 static void get_device_id(cups_sc_status_t *status,
2438 			  char *data,
2439 			  int *datalen)
2440 {
2441   CFStringRef deviceIDString = NULL;
2442 
2443   if (g.printer_obj != IO_OBJECT_NULL)
2444   {
2445     printer_interface_t printerIntf = usb_printer_interface_interface(g.printer_obj);
2446     if (printerIntf)
2447     {
2448       deviceIDString = copy_printer_interface_deviceid(printerIntf, g.alternateSetting);
2449       (*printerIntf)->Release(printerIntf);
2450     }
2451   }
2452 
2453 
2454   if (deviceIDString)
2455   {
2456     if (CFStringGetCString(deviceIDString, data, *datalen, kCFStringEncodingUTF8))
2457       *datalen = (int)strlen(data);
2458     else
2459       *datalen = 0;
2460 
2461     CFRelease(deviceIDString);
2462   }
2463   else
2464   {
2465     *datalen = 0;
2466   }
2467 
2468   *status  = CUPS_SC_STATUS_OK;
2469 }
2470