]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - backend/usb-darwin.c
Merge changes from CUPS 1.5svn-r9631.
[thirdparty/cups.git] / backend / usb-darwin.c
index 7bc37f75cb18f2aefafe4cfd4f96f036ae2e5c7f..4b7bb5c38856c75bbf308db5634866523761fde5 100644 (file)
@@ -1,7 +1,7 @@
 /*
 * "$Id: usb-darwin.c 7953 2008-09-17 01:43:19Z mike $"
 *
-* Copyright 2005-2009 Apple Inc. All rights reserved.
+* Copyright 2005-2010 Apple Inc. All rights reserved.
 *
 * IMPORTANT:  This Apple software is supplied to you by Apple Computer,
 * Inc. ("Apple") in consideration of your agreement to the following
 *
 * Contents:
 *
-*  list_devices()      - List all USB devices.
-*  print_device()      - Print a file to a USB device.
-*  sidechannel_thread() - Thread to handle side-channel requests.
-*  read_thread()       - Thread to read the backchannel data on.
-*  list_device_cb()    - list_device iterator callback.
-*  find_device_cb()    - print_device iterator callback.
-*  status_timer_cb()   - Status timer callback.
-*  iterate_printers()  - Iterate over all the printers.
-*  device_added()      - Device added notifier.
-*  copy_deviceinfo()   - Copy strings from the 1284 device ID.
-*  release_deviceinfo()        - Release deviceinfo strings.
-*  load_classdriver()  - Load a classdriver.
-*  unload_classdriver()        - Unload a classdriver.
-*  load_printerdriver()        - Load vendor's classdriver.
-*  registry_open()     - Open a connection to the printer.
-*  registry_close()    - Close the connection to the printer.
-*  copy_deviceid()     - Copy the 1284 device id string.
-*  copy_devicestring() - Copy the 1284 device id string.
-*  copy_value_for_key()        - Copy value string associated with a key.
-*  cfstr_create_trim() - Create CFString and trim whitespace characters.
-*  parse_options()     - Parse uri options.
-*  setup_cfLanguage()  - Create AppleLanguages array from LANG environment var.
-*  run_legacy_backend()        - Re-exec backend as ppc or i386.
-*  sigterm_handler()   - SIGTERM handler.
-*  next_line()         - Find the next line in a buffer.
-*  parse_pserror()     - Scan the backchannel data for postscript errors.
-*  get_device_id()     - Return IEEE-1284 device ID.
+ *   list_devices()       - List all USB devices.
+ *   print_device()       - Print a file to a USB device.
+ *   read_thread()        - Thread to read the backchannel data on.
+ *   sidechannel_thread() - Handle side-channel requests.
+ *   iterate_printers()   - Iterate over all the printers.
+ *   device_added()       - Device added notifier.
+ *   list_device_cb()     - list_device iterator callback.
+ *   find_device_cb()     - print_device iterator callback.
+ *   status_timer_cb()    - Status timer callback.
+ *   copy_deviceinfo()    - Copy strings from the 1284 device ID.
+ *   release_deviceinfo() - Release deviceinfo strings.
+ *   load_classdriver()   - Load a classdriver.
+ *   unload_classdriver() - Unload a classdriver.
+ *   load_printerdriver() - Load vendor's classdriver.
+ *   registry_open()      - Open a connection to the printer.
+ *   registry_close()     - Close the connection to the printer.
+ *   copy_deviceid()      - Copy the 1284 device id string.
+ *   copy_devicestring()  - Copy the 1284 device id string.
+ *   copy_value_for_key() - Copy value string associated with a key.
+ *   cfstr_create_trim()  - Create CFString and trim whitespace characters.
+ *   parse_options()      - Parse URI options.
+ *   sigterm_handler()    - SIGTERM handler.
+ *   next_line()          - Find the next line in a buffer.
+ *   parse_pserror()      - Scan the backchannel data for postscript errors.
+ *   soft_reset()         - Send a soft reset to the device.
+ *   get_device_id()      - Return IEEE-1284 device ID.
 */
 
 /*
@@ -89,9 +88,9 @@
 #include <mach/mach.h>
 #include <mach/mach_error.h>
 #include <mach/mach_time.h>
-#include <cups/debug.h>
+#include <cups/debug-private.h>
 #include <cups/sidechannel.h>
-#include <cups/i18n.h>
+#include <cups/language-private.h>
 #include "backend-private.h"
 
 #include <CoreFoundation/CoreFoundation.h>
@@ -293,7 +292,6 @@ static void status_timer_cb(CFRunLoopTimerRef timer, void *info);
 static pid_t   child_pid;              /* Child PID */
 static void run_legacy_backend(int argc, char *argv[], int fd);        /* Starts child backend process running as a ppc executable */
 #endif /* __i386__ || __x86_64__ */
-static int     job_canceled = 0;       /* Was the job canceled? */
 static void sigterm_handler(int sig);  /* SIGTERM handler */
 
 #ifdef PARSE_PS_ERRORS
@@ -374,12 +372,14 @@ print_device(const char *uri,             /* I - Device URI */
 
   if (!g.make || !g.model)
   {
-    _cupsLangPuts(stderr, _("ERROR: Fatal USB error!\n"));
+    fprintf(stderr, "DEBUG: Fatal USB error.\n");
+    _cupsLangPrintFilter(stderr, "ERROR",
+                         _("There was an unrecoverable USB error."));
 
     if (!g.make)
-      fputs("DEBUG: USB make string is NULL!\n", stderr);
+      fputs("DEBUG: USB make string is NULL\n", stderr);
     if (!g.model)
-      fputs("DEBUG: USB model string is NULL!\n", stderr);
+      fputs("DEBUG: USB model string is NULL\n", stderr);
 
     return (CUPS_BACKEND_STOP);
   }
@@ -432,7 +432,8 @@ print_device(const char *uri,               /* I - Device URI */
         strlcpy(print_buffer, "USB class driver", sizeof(print_buffer));
 
       fputs("STATE: +apple-missing-usbclassdriver-error\n", stderr);
-      _cupsLangPuts(stderr, _("ERROR: Fatal USB error!\n"));
+      _cupsLangPrintFilter(stderr, "ERROR",
+                          _("There was an unrecoverable USB error."));
       fprintf(stderr, "DEBUG: Could not load %s\n", print_buffer);
 
       if (driverBundlePath)
@@ -450,8 +451,8 @@ print_device(const char *uri,               /* I - Device URI */
       countdown -= PRINTER_POLLING_INTERVAL;
       if (countdown <= 0)
       {
-       _cupsLangPuts(stderr,
-                     _("INFO: Waiting for printer to become available...\n"));
+       _cupsLangPrintFilter(stderr, "INFO",
+                            _("Waiting for printer to become available."));
        fprintf(stderr, "DEBUG: USB printer status: 0x%08x\n", (int)status);
        countdown = SUBSEQUENT_LOG_INTERVAL;    /* subsequent log entries, every 15 seconds */
       }
@@ -461,9 +462,9 @@ print_device(const char *uri,               /* I - Device URI */
   fputs("STATE: -connecting-to-device\n", stderr);
 
   /*
-   * Now that we are "connected" to the port, catch SIGTERM so that we
+   * Now that we are "connected" to the port, ignore SIGTERM so that we
    * can finish out any page data the driver sends (e.g. to eject the
-   * current page...  Only catch SIGTERM if we are printing data from
+   * current page...  Only ignore SIGTERM if we are printing data from
    * stdin (otherwise you can't cancel raw jobs...)
    */
 
@@ -475,7 +476,7 @@ print_device(const char *uri,               /* I - Device URI */
     memset(&action, 0, sizeof(action));
 
     sigemptyset(&action.sa_mask);
-    action.sa_handler = sigterm_handler;
+    action.sa_handler = SIG_IGN;
     sigaction(SIGTERM, &action, NULL);
   }
 
@@ -497,8 +498,11 @@ print_device(const char *uri,              /* I - Device URI */
 
     if (pthread_create(&sidechannel_thread_id, NULL, sidechannel_thread, NULL))
     {
-      _cupsLangPuts(stderr, _("ERROR: Fatal USB error!\n"));
-      fputs("DEBUG: Couldn't create side-channel thread!\n", stderr);
+      fprintf(stderr, "DEBUG: Fatal USB error.\n");
+      _cupsLangPrintFilter(stderr, "ERROR",
+                          _("There was an unrecoverable USB error."));
+      fputs("DEBUG: Couldn't create side-channel thread\n", stderr);
+      registry_close();
       return (CUPS_BACKEND_STOP);
     }
   }
@@ -515,8 +519,11 @@ print_device(const char *uri,              /* I - Device URI */
 
   if (pthread_create(&read_thread_id, NULL, read_thread, NULL))
   {
-    _cupsLangPuts(stderr, _("ERROR: Fatal USB error!\n"));
-    fputs("DEBUG: Couldn't create read thread!\n", stderr);
+    fprintf(stderr, "DEBUG: Fatal USB error.\n");
+    _cupsLangPrintFilter(stderr, "ERROR",
+                         _("There was an unrecoverable USB error."));
+    fputs("DEBUG: Couldn't create read thread\n", stderr);
+    registry_close();
     return (CUPS_BACKEND_STOP);
   }
 
@@ -531,7 +538,7 @@ print_device(const char *uri,               /* I - Device URI */
 
   while (status == noErr && copies-- > 0)
   {
-    _cupsLangPuts(stderr, _("INFO: Sending print data...\n"));
+    _cupsLangPrintFilter(stderr, "INFO", _("Sending data to printer."));
 
     if (print_fd != STDIN_FILENO)
     {
@@ -594,14 +601,17 @@ print_device(const char *uri,             /* I - Device URI */
        if (errno == EINTR && total_bytes == 0)
        {
          fputs("DEBUG: Received an interrupt before any bytes were "
-               "written, aborting!\n", stderr);
+               "written, aborting\n", stderr);
+          registry_close();
           return (CUPS_BACKEND_OK);
        }
        else if (errno != EAGAIN && errno != EINTR)
        {
-         _cupsLangPuts(stderr, _("ERROR: Unable to read print data!\n"));
+         _cupsLangPrintFilter(stderr, "ERROR",
+                              _("Unable to read print data."));
          perror("DEBUG: select");
-         return (CUPS_BACKEND_FAILED);
+         registry_close();
+          return (CUPS_BACKEND_FAILED);
        }
       }
 
@@ -641,8 +651,10 @@ print_device(const char *uri,              /* I - Device URI */
 
          if (errno != EAGAIN && errno != EINTR)
          {
-           _cupsLangPuts(stderr, _("ERROR: Unable to read print data!\n"));
+           _cupsLangPrintFilter(stderr, "ERROR",
+                                _("Unable to read print data."));
            perror("DEBUG: read");
+           registry_close();
            return (CUPS_BACKEND_FAILED);
          }
 
@@ -675,7 +687,7 @@ print_device(const char *uri,               /* I - Device URI */
 
        if (iostatus == kIOUSBTransactionTimeout)
        {
-         fputs("DEBUG: Got USB transaction timeout during write!\n", stderr);
+         fputs("DEBUG: Got USB transaction timeout during write\n", stderr);
          iostatus = 0;
        }
 
@@ -685,7 +697,7 @@ print_device(const char *uri,               /* I - Device URI */
 
        else if (iostatus == kIOUSBPipeStalled)
        {
-         fputs("DEBUG: Got USB pipe stalled during write!\n", stderr);
+         fputs("DEBUG: Got USB pipe stalled during write\n", stderr);
 
          bytes    = g.print_bytes;
          iostatus = (*g.classdriver)->WritePipe(g.classdriver, (UInt8*)print_ptr, &bytes, 0);
@@ -698,7 +710,7 @@ print_device(const char *uri,               /* I - Device URI */
 
        else if (iostatus == kIOReturnAborted)
        {
-         fputs("DEBUG: Got return aborted during write!\n", stderr);
+         fputs("DEBUG: Got USB return aborted during write\n", stderr);
 
          IOReturn err = (*g.classdriver)->Abort(g.classdriver);
          fprintf(stderr, "DEBUG: USB class driver Abort returned %x\n", err);
@@ -711,13 +723,13 @@ print_device(const char *uri,             /* I - Device URI */
          iostatus = (*g.classdriver)->WritePipe(g.classdriver, (UInt8*)print_ptr, &bytes, 0);
         }
 
-       if (iostatus || bytes < 0)
+       if (iostatus)
        {
         /*
          * Write error - bail if we don't see an error we can retry...
          */
-
-         _cupsLangPuts(stderr, _("ERROR: Unable to send print data!\n"));
+         _cupsLangPrintFilter(stderr, "ERROR",
+                              _("Unable to send data to printer."));
          fprintf(stderr, "DEBUG: USB class driver WritePipe returned %x\n",
                  iostatus);
 
@@ -725,7 +737,7 @@ print_device(const char *uri,               /* I - Device URI */
          fprintf(stderr, "DEBUG: USB class driver Abort returned %x\n",
                  err);
 
-         status = job_canceled ? CUPS_BACKEND_FAILED : CUPS_BACKEND_STOP;
+         status = CUPS_BACKEND_FAILED;
          break;
        }
        else if (bytes > 0)
@@ -746,6 +758,22 @@ print_device(const char *uri,              /* I - Device URI */
 
   fprintf(stderr, "DEBUG: Sent %lld bytes...\n", (off_t)total_bytes);
 
+  if (!print_fd)
+  {
+   /*
+    * Re-enable the SIGTERM handler so pthread_kill() will work...
+    */
+  
+    struct sigaction   action;         /* POSIX signal action */
+
+    memset(&action, 0, sizeof(action));
+
+    sigemptyset(&action.sa_mask);
+    sigaddset(&action.sa_mask, SIGTERM);
+    action.sa_handler = sigterm_handler;
+    sigaction(SIGTERM, &action, NULL);
+  }
+
  /*
   * Wait for the side channel thread to exit...
   */
@@ -776,6 +804,7 @@ print_device(const char *uri,               /* I - Device URI */
        * Force the side-channel thread to exit...
        */
 
+        fputs("DEBUG: Force the side-channel thread to exit...\n", stderr);
        pthread_kill(sidechannel_thread_id, SIGTERM);
       }
     }
@@ -816,6 +845,7 @@ print_device(const char *uri,               /* I - Device URI */
       */
 
       g.wait_eof = 0;
+      fputs("DEBUG: Force the read thread to exit...\n", stderr);
       pthread_kill(read_thread_id, SIGTERM);
     }
   }
@@ -898,11 +928,11 @@ static void *read_thread(void *reference)
 #endif
     }
     else if (readstatus == kIOUSBTransactionTimeout)
-      fputs("DEBUG: Got USB transaction timeout during write!\n", stderr);
+      fputs("DEBUG: Got USB transaction timeout during read\n", stderr);
     else if (readstatus == kIOUSBPipeStalled)
-      fputs("DEBUG: Got USB pipe stalled during read!\n", stderr);
+      fputs("DEBUG: Got USB pipe stalled during read\n", stderr);
     else if (readstatus == kIOReturnAborted)
-      fputs("DEBUG: Got return aborted during read!\n", stderr);
+      fputs("DEBUG: Got USB return aborted during read\n", stderr);
 
    /*
     * Make sure this loop executes no more than once every 250 miliseconds...
@@ -944,7 +974,12 @@ sidechannel_thread(void *reference)
     datalen = sizeof(data);
 
     if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
-      continue;
+    {
+      if (status == CUPS_SC_STATUS_TIMEOUT)
+       continue;
+      else
+       break;
+    }
 
     switch (command)
     {
@@ -1165,7 +1200,7 @@ static Boolean list_device_cb(void *refcon,
        snprintf(optionsstr, sizeof(optionsstr), "?location=%x", (unsigned)deviceLocation);
 
       httpAssembleURI(HTTP_URI_CODING_ALL, uristr, sizeof(uristr), "usb", NULL, makestr, 0, modelstr);
-      strncat(uristr, optionsstr, sizeof(uristr));
+      strlcat(uristr, optionsstr, sizeof(uristr));
 
       cupsBackendReport("direct", uristr, make_modelstr, make_modelstr, idstr,
                         NULL);
@@ -1251,7 +1286,7 @@ static Boolean find_device_cb(void *refcon,
   if (!keepLooking && g.status_timer != NULL)
   {
     fputs("STATE: -offline-report\n", stderr);
-    _cupsLangPuts(stderr, _("INFO: Printer is now online.\n"));
+    _cupsLangPrintFilter(stderr, "INFO", _("Printer is now online."));
     CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), g.status_timer, kCFRunLoopDefaultMode);
     CFRelease(g.status_timer);
     g.status_timer = NULL;
@@ -1269,7 +1304,7 @@ static void status_timer_cb(CFRunLoopTimerRef timer,
                            void *info)
 {
   fputs("STATE: +offline-report\n", stderr);
-  _cupsLangPuts(stderr, _("INFO: Printer is offline.\n"));
+  _cupsLangPrintFilter(stderr, "INFO", _("Printer is offline."));
 
   if (getenv("CLASS") != NULL)
   {
@@ -1368,15 +1403,32 @@ static kern_return_t load_classdriver(CFStringRef           driverPath,
 
   if (stat(bundlestr, &bundleinfo))
   {
-    fprintf(stderr, "DEBUG: Unable to load class driver \"%s\": %s\n",
+    fprintf(stderr, "DEBUG: Class driver \"%s\" not available: %s\n",
            bundlestr, strerror(errno));
-    return (kr);
+    fputs("STATE: +cups-missing-filter-warning\n", stderr);
+
+    if (errno == ENOENT && driverPath)
+      return (load_classdriver(NULL, intf, printerDriver));
+    else
+      return (kr);
   }
-  else if (bundleinfo.st_mode & S_IWOTH)
+  else if (bundleinfo.st_uid ||
+           (bundleinfo.st_gid && (bundleinfo.st_mode & S_IWGRP)) ||
+          (bundleinfo.st_mode & S_IWOTH))
   {
-    fprintf(stderr, "DEBUG: Unable to load class driver \"%s\": insecure file "
-                   "permissions (0%o)\n", bundlestr, bundleinfo.st_mode);
-    return (kr);
+    fprintf(stderr, "DEBUG: Class driver \"%s\" has insecure file "
+                   "permissions (0%o/uid=%d/gid=%d).\n", bundlestr,
+                   bundleinfo.st_mode, (int)bundleinfo.st_uid,
+                   (int)bundleinfo.st_gid);
+    fputs("STATE: +cups-insecure-filter-warning\n", stderr);
+
+    if (bundleinfo.st_uid || (bundleinfo.st_mode & S_IWOTH))
+    {
+      if (driverPath)
+        return (load_classdriver(NULL, intf, printerDriver));
+      else
+        return (kr);
+    }
   }
 
  /*
@@ -1812,9 +1864,9 @@ static void parse_options(char *options,
               !strcasecmp(value, "false"))
        *wait_eof = false;
       else
-       _cupsLangPrintf(stderr,
-                       _("WARNING: Boolean expected for waiteof option "
-                         "\"%s\"\n"), value);
+       _cupsLangPrintFilter(stderr, "WARNING",
+                            _("Boolean expected for waiteof option \"%s\"."),
+                            value);
     }
     else if (!strcasecmp(name, "serial"))
       strlcpy(serial, value, serial_size);
@@ -1902,6 +1954,7 @@ static void run_legacy_backend(int argc,
     * Setup a SIGTERM handler then block it before forking...
     */
 
+    int                        err;            /* posix_spawn result */
     struct sigaction   action;         /* POSIX signal action */
     sigset_t           newmask,        /* New signal mask */
                        oldmask;        /* Old signal mask */
@@ -1950,7 +2003,8 @@ static void run_legacy_backend(int argc,
 #  else
        perror("DEBUG: Unable to set binary preference to ppc");
 #  endif /* __x86_64__ */
-       _cupsLangPrintf(stderr, _("Unable to use legacy USB class driver!\n"));
+       _cupsLangPrintFilter(stderr, "ERROR",
+                            _("Unable to use legacy USB class driver."));
        exit(CUPS_BACKEND_STOP);
       }
     }
@@ -1968,11 +2022,13 @@ static void run_legacy_backend(int argc,
 
     my_argv[i] = NULL;
 
-    if (posix_spawn(&child_pid, usbpath, NULL, &attrs, my_argv, environ))
+    if ((err = posix_spawn(&child_pid, usbpath, NULL, &attrs, my_argv,
+                           environ)) != 0)
     {
       fprintf(stderr, "DEBUG: Unable to exec %s: %s\n", usbpath,
-              strerror(errno));
-      _cupsLangPrintf(stderr, _("Unable to use legacy USB class driver!\n"));
+              strerror(err));
+      _cupsLangPrintFilter(stderr, "ERROR",
+                           _("Unable to use legacy USB class driver."));
       exit(CUPS_BACKEND_STOP);
     }
 
@@ -1998,14 +2054,14 @@ static void run_legacy_backend(int argc,
     if (WIFSIGNALED(childstatus))
     {
       exitstatus = CUPS_BACKEND_STOP;
-      fprintf(stderr, "DEBUG: usb(legacy) backend %d crashed on signal %d!\n",
+      fprintf(stderr, "DEBUG: usb(legacy) backend %d crashed on signal %d\n",
               child_pid, WTERMSIG(childstatus));
     }
     else
     {
       if ((exitstatus = WEXITSTATUS(childstatus)) != 0)
        fprintf(stderr,
-               "DEBUG: usb(legacy) backend %d stopped with status %d!\n",
+               "DEBUG: usb(legacy) backend %d stopped with status %d\n",
                child_pid, exitstatus);
       else
        fprintf(stderr, "DEBUG: usb(legacy) backend %d exited with no errors\n",
@@ -2031,6 +2087,10 @@ static void
 sigterm_handler(int sig)               /* I - Signal */
 {
 #if defined(__i386__) || defined(__x86_64__)
+ /*
+  * If we started a child process pass the signal on to it...
+  */
+
   if (child_pid)
   {
    /*
@@ -2048,17 +2108,11 @@ sigterm_handler(int sig)                /* I - Signal */
       exit(0);
     else
     {
-      fprintf(stderr, "DEBUG: Child crashed on signal %d!\n", status);
+      fprintf(stderr, "DEBUG: Child crashed on signal %d\n", status);
       exit(CUPS_BACKEND_STOP);
     }
   }
 #endif /* __i386__ || __x86_64__ */
-
- /*
-  * Otherwise just flag that the job has been canceled...
-  */
-
-  job_canceled = 1;
 }
 
 
@@ -2210,12 +2264,11 @@ static void get_device_id(cups_sc_status_t *status,
                          char *data,
                          int *datalen)
 {
-  UInt32 deviceLocation = 0;
-  UInt8        interfaceNum = 0;
   CFStringRef deviceIDString = NULL;
 
   /* GetDeviceID */
-  copy_devicestring(g.printer_obj, &deviceIDString, &deviceLocation, &interfaceNum);
+  copy_deviceid(g.classdriver, &deviceIDString);
+
   if (deviceIDString)
   {
     CFStringGetCString(deviceIDString, data, *datalen, kCFStringEncodingUTF8);