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