/*
-* "$Id: usb-darwin.c 6591 2007-06-21 20:35:28Z mike $"
+* "$Id: usb-darwin.c 7460 2008-04-16 02:19:54Z mike $"
*
-* Copyright © 2005-2007 Apple Inc. All rights reserved.
+* Copyright 2005-2008 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
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
+#include <sys/stat.h>
#include <sys/sysctl.h>
#include <libgen.h>
#include <mach/mach.h>
#include <cups/debug.h>
#include <cups/sidechannel.h>
#include <cups/i18n.h>
+#include "backend-private.h"
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/usb/IOUSBLib.h>
* the printer after we've finished sending all the data
*/
#define WAIT_EOF_DELAY 7
-#define DEFAULT_TIMEOUT 60L
+#define WAIT_SIDE_DELAY 3
+#define DEFAULT_TIMEOUT 5000L
#define USB_INTERFACE_KIND CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID190)
#define kUSBLanguageEnglish 0x409
CFStringRef model;
CFStringRef serial;
UInt32 location;
+ UInt8 interfaceNum;
CFRunLoopTimerRef status_timer;
Boolean wait_eof;
int drain_output; /* Drain all pending output */
int bidi_flag; /* 0=unidirectional, 1=bidirectional */
+
+ pthread_mutex_t sidechannel_thread_mutex;
+ pthread_cond_t sidechannel_thread_cond;
+ int sidechannel_thread_stop;
+ int sidechannel_thread_done;
} globals_t;
static void *read_thread(void *reference);
static void *sidechannel_thread(void *reference);
static void copy_deviceinfo(CFStringRef deviceIDString, CFStringRef *make, CFStringRef *model, CFStringRef *serial);
-static void copy_devicestring(io_service_t usbInterface, CFStringRef *deviceID, UInt32 *deviceLocation);
+static void copy_devicestring(io_service_t usbInterface, CFStringRef *deviceID, UInt32 *deviceLocation, UInt8 *interfaceNum);
static void device_added(void *userdata, io_iterator_t iterator);
static void get_device_id(cups_sc_status_t *status, char *data, int *datalen);
static void iterate_printers(iterator_callback_t callBack, void *userdata);
-static void parse_options(const char *options, char *serial, UInt32 *location, Boolean *wait_eof);
+static void parse_options(char *options, char *serial, int serial_size, UInt32 *location, Boolean *wait_eof);
static void release_deviceinfo(CFStringRef *make, CFStringRef *model, CFStringRef *serial);
static void setup_cfLanguage(void);
static void soft_reset();
print_device(const char *uri, /* I - Device URI */
const char *hostname, /* I - Hostname/manufacturer */
const char *resource, /* I - Resource/modelname */
- const char *options, /* I - Device options/serial number */
+ char *options, /* I - Device options/serial number */
int print_fd, /* I - File descriptor to print */
int copies, /* I - Copies to print */
int argc, /* I - Number of command-line arguments (6 or 7) */
char serial[1024]; /* Serial number buffer */
OSStatus status; /* Function results */
pthread_t read_thread_id, /* Read thread */
- sidechannel_thread_id;/* Side channel thread */
+ sidechannel_thread_id;/* Side-channel thread */
+ int have_sidechannel = 0; /* Was the side-channel thread started? */
+ struct stat sidechannel_info; /* Side-channel file descriptor info */
char print_buffer[8192], /* Print data buffer */
*print_ptr; /* Pointer into print data buffer */
UInt32 location; /* Unique location in bus topology */
stimeout; /* Timeout for select() */
struct timespec cond_timeout; /* pthread condition timeout */
+
+ /*
+ * See if the side-channel descriptor is valid...
+ */
+
+ have_sidechannel = !fstat(CUPS_SC_FD, &sidechannel_info) &&
+ S_ISSOCK(sidechannel_info.st_mode);
+
+ /*
+ * Localize using CoreFoundation...
+ */
+
setup_cfLanguage();
- parse_options(options, serial, &location, &g.wait_eof);
+ parse_options(options, serial, sizeof(serial), &location, &g.wait_eof);
if (resource[0] == '/')
resource++;
g.serial = cfstr_create_trim(serial);
g.location = location;
+ if (!g.make || !g.model)
+ {
+ _cupsLangPrintf(stderr,
+ _("ERROR: Unable to create make and model strings\n"));
+ return CUPS_BACKEND_STOP;
+ }
+
fputs("STATE: +connecting-to-device\n", stderr);
countdown = INITIAL_LOG_INTERVAL;
strlcpy(print_buffer, "USB class driver", sizeof(print_buffer));
fputs("STATE: +apple-missing-usbclassdriver-error\n", stderr);
- fprintf(stderr, _("FATAL: Could not load %s\n"), print_buffer);
+ _cupsLangPrintf(stderr, _("FATAL: Could not load %s\n"), print_buffer);
if (driverBundlePath)
CFRelease(driverBundlePath);
countdown -= PRINTER_POLLING_INTERVAL;
if (countdown <= 0)
{
- fprintf(stderr, _("INFO: Printer busy (status:0x%08x)\n"), (int)status);
+ _cupsLangPrintf(stderr, _("INFO: Printer busy (status:0x%08x)\n"),
+ (int)status);
countdown = SUBSEQUENT_LOG_INTERVAL; /* subsequent log entries, every 15 seconds */
}
}
if (!print_fd)
{
-#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
- sigset(SIGTERM, SIG_IGN);
-#elif defined(HAVE_SIGACTION)
+ struct sigaction action; /* POSIX signal action */
+
+
memset(&action, 0, sizeof(action));
sigemptyset(&action.sa_mask);
action.sa_handler = SIG_IGN;
sigaction(SIGTERM, &action, NULL);
-#else
- signal(SIGTERM, SIG_IGN);
-#endif /* HAVE_SIGSET */
}
/*
- * Start the side channel thread only if the descriptor is valid
- * (i.e. it's not when the backend is used for auto-setup)...
+ * Start the side channel thread if the descriptor is valid...
*/
pthread_mutex_init(&g.readwrite_lock_mutex, NULL);
pthread_cond_init(&g.readwrite_lock_cond, NULL);
g.readwrite_lock = 1;
- FD_ZERO(&input_set);
- FD_SET(CUPS_SC_FD, &input_set);
+ if (have_sidechannel)
+ {
+ g.sidechannel_thread_stop = 0;
+ g.sidechannel_thread_done = 0;
- stimeout.tv_sec = 0;
- stimeout.tv_usec = 0;
+ pthread_cond_init(&g.sidechannel_thread_cond, NULL);
+ pthread_mutex_init(&g.sidechannel_thread_mutex, NULL);
- if ((select(CUPS_SC_FD+1, &input_set, NULL, NULL, &stimeout)) >= 0)
- {
if (pthread_create(&sidechannel_thread_id, NULL, sidechannel_thread, NULL))
{
- fputs(_("WARNING: Couldn't create side channel\n"), stderr);
+ _cupsLangPuts(stderr, _("WARNING: Couldn't create side channel\n"));
return CUPS_BACKEND_STOP;
}
}
if (pthread_create(&read_thread_id, NULL, read_thread, NULL))
{
- fputs(_("WARNING: Couldn't create read channel\n"), stderr);
+ _cupsLangPuts(stderr, _("WARNING: Couldn't create read channel\n"));
return CUPS_BACKEND_STOP;
}
while (status == noErr && copies-- > 0)
{
- fputs(_("INFO: Sending data\n"), stderr);
+ _cupsLangPuts(stderr, _("INFO: Sending data\n"));
if (print_fd != STDIN_FILENO)
{
}
else if (errno != EAGAIN)
{
- fprintf(stderr, _("ERROR: select() returned %d\n"), (int)errno);
+ _cupsLangPrintf(stderr, _("ERROR: select() returned %d\n"), (int)errno);
return CUPS_BACKEND_STOP;
}
}
if (errno != EAGAIN || errno != EINTR)
{
- perror("ERROR: Unable to read print data");
+ _cupsLangPrintError(_("ERROR: Unable to read print data"));
return CUPS_BACKEND_STOP;
}
*/
OSStatus err = (*g.classdriver)->Abort(g.classdriver);
- fprintf(stderr, _("ERROR: %ld: (canceled:%ld)\n"), (long)status, (long)err);
- return CUPS_BACKEND_STOP;
+ _cupsLangPrintf(stderr, _("ERROR: %ld: (canceled:%ld)\n"),
+ (long)status, (long)err);
+ status = CUPS_BACKEND_STOP;
+ break;
}
fprintf(stderr, "DEBUG: Wrote %d bytes of print data...\n", (int)bytes);
* Wait for the side channel thread to exit...
*/
- close(CUPS_SC_FD);
- pthread_mutex_lock(&g.readwrite_lock_mutex);
- g.readwrite_lock = 0;
- pthread_cond_signal(&g.readwrite_lock_cond);
- pthread_mutex_unlock(&g.readwrite_lock_mutex);
+ if (have_sidechannel)
+ {
+ close(CUPS_SC_FD);
+ pthread_mutex_lock(&g.readwrite_lock_mutex);
+ g.readwrite_lock = 0;
+ pthread_cond_signal(&g.readwrite_lock_cond);
+ pthread_mutex_unlock(&g.readwrite_lock_mutex);
+
+ g.sidechannel_thread_stop = 1;
+ pthread_mutex_lock(&g.sidechannel_thread_mutex);
+ if (!g.sidechannel_thread_done)
+ {
+ /*
+ * Wait for the side-channel thread to exit...
+ */
+
+ cond_timeout.tv_sec = time(NULL) + WAIT_SIDE_DELAY;
+ cond_timeout.tv_nsec = 0;
+ if (pthread_cond_timedwait(&g.sidechannel_thread_cond,
+ &g.sidechannel_thread_mutex,
+ &cond_timeout) != 0)
+ {
+ /*
+ * Force the side-channel thread to exit...
+ */
+
+ pthread_kill(sidechannel_thread_id, SIGTERM);
+ }
+ }
+ pthread_mutex_unlock(&g.sidechannel_thread_mutex);
+
+ pthread_join(sidechannel_thread_id, NULL);
- pthread_join(sidechannel_thread_id, NULL);
+ pthread_cond_destroy(&g.sidechannel_thread_cond);
+ pthread_mutex_destroy(&g.sidechannel_thread_mutex);
+ }
pthread_cond_destroy(&g.readwrite_lock_cond);
pthread_mutex_destroy(&g.readwrite_lock_mutex);
/*
* Give the read thread WAIT_EOF_DELAY seconds to complete all the data. If
- * we are not signaled in that time then force the thread to exit by setting
- * the waiteof to be false. Plese note that this relies on us using the timeout
- * class driver.
+ * we are not signaled in that time then force the thread to exit.
*/
pthread_mutex_lock(&g.read_thread_mutex);
cond_timeout.tv_sec = time(NULL) + WAIT_EOF_DELAY;
cond_timeout.tv_nsec = 0;
- if (pthread_cond_timedwait(&g.read_thread_cond, &g.read_thread_mutex, &cond_timeout) != 0)
- g.wait_eof = false;
+ if (pthread_cond_timedwait(&g.read_thread_cond, &g.read_thread_mutex,
+ &cond_timeout) != 0)
+ {
+ /*
+ * Force the read thread to exit...
+ */
+
+ pthread_kill(read_thread_id, SIGTERM);
+ }
}
pthread_mutex_unlock(&g.read_thread_mutex);
char data[2048]; /* Request/response data */
int datalen; /* Request/response data size */
- for (;;)
+
+ do
{
datalen = sizeof(data);
if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
- break;
+ continue;
switch (command)
{
case CUPS_SC_CMD_SOFT_RESET: /* Do a soft reset */
- soft_reset();
- cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, NULL, 0, 1.0);
+ if ((*g.classdriver)->SoftReset != NULL)
+ {
+ soft_reset();
+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, NULL, 0, 1.0);
+ }
+ else
+ {
+ cupsSideChannelWrite(command, CUPS_SC_STATUS_NOT_IMPLEMENTED,
+ NULL, 0, 1.0);
+ }
break;
case CUPS_SC_CMD_DRAIN_OUTPUT: /* Drain all pending output */
break;
}
}
+ while (!g.sidechannel_thread_stop);
+
+ pthread_mutex_lock(&g.sidechannel_thread_mutex);
+ g.sidechannel_thread_done = 1;
+ pthread_cond_signal(&g.sidechannel_thread_cond);
+ pthread_mutex_unlock(&g.sidechannel_thread_mutex);
+
return NULL;
}
{
CFStringRef deviceIDString = NULL;
UInt32 deviceLocation = 0;
+ UInt8 interfaceNum = 0;
- copy_devicestring(obj, &deviceIDString, &deviceLocation);
+ copy_devicestring(obj, &deviceIDString, &deviceLocation, &interfaceNum);
if (deviceIDString != NULL)
{
CFStringRef make = NULL, model = NULL, serial = NULL;
char uristr[1024], makestr[1024], modelstr[1024], serialstr[1024];
- char optionsstr[1024], idstr[1024];
+ char optionsstr[1024], idstr[1024], make_modelstr[1024];
copy_deviceinfo(deviceIDString, &make, &model, &serial);
-
- modelstr[0] = '/';
-
CFStringGetCString(deviceIDString, idstr, sizeof(idstr),
kCFStringEncodingUTF8);
+ backendGetMakeModel(idstr, make_modelstr, sizeof(make_modelstr));
- if (make)
- CFStringGetCString(make, makestr, sizeof(makestr),
- kCFStringEncodingUTF8);
- else
+ modelstr[0] = '/';
+
+ if (!CFStringGetCString(make, makestr, sizeof(makestr),
+ kCFStringEncodingUTF8))
strcpy(makestr, "Unknown");
- if (model)
- CFStringGetCString(model, &modelstr[1], sizeof(modelstr)-1,
- kCFStringEncodingUTF8);
- else
+ if (!CFStringGetCString(model, &modelstr[1], sizeof(modelstr)-1,
+ kCFStringEncodingUTF8))
strcpy(modelstr + 1, "Printer");
optionsstr[0] = '\0';
httpAssembleURI(HTTP_URI_CODING_ALL, uristr, sizeof(uristr), "usb", NULL, makestr, 0, modelstr);
strncat(uristr, optionsstr, sizeof(uristr));
- /*
- * Fix common HP 1284 bug...
- */
-
- if (!strcasecmp(makestr, "Hewlett-Packard"))
- strcpy(makestr, "HP");
-
- if (!strncasecmp(modelstr + 1, "hp ", 3))
- _cups_strcpy(modelstr + 1, modelstr + 4);
-
- printf("direct %s \"%s %s\" \"%s %s USB\" \"%s\"\n", uristr, makestr,
- &modelstr[1], makestr, &modelstr[1], idstr);
+ printf("direct %s \"%s\" \"%s USB\" \"%s\"\n", uristr, make_modelstr,
+ make_modelstr, idstr);
release_deviceinfo(&make, &model, &serial);
CFRelease(deviceIDString);
{
CFStringRef idString = NULL;
UInt32 location = -1;
+ UInt8 interfaceNum = 0;
- copy_devicestring(obj, &idString, &location);
+ copy_devicestring(obj, &idString, &location, &interfaceNum);
if (idString != NULL)
{
CFStringRef make = NULL, model = NULL, serial = NULL;
copy_deviceinfo(idString, &make, &model, &serial);
- if (CFStringCompare(make, g.make, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
+ if (make && CFStringCompare(make, g.make, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
{
- if (CFStringCompare(model, g.model, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
+ if (model && CFStringCompare(model, g.model, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
{
if (g.serial != NULL && CFStringGetLength(g.serial) > 0)
{
if (g.location == 0 || g.location == location)
keepLooking = false;
}
+ if ( !keepLooking )
+ g.interfaceNum = interfaceNum;
}
}
if (!keepLooking && g.status_timer != NULL)
{
fputs("STATE: -offline-error\n", stderr);
- fputs(_("INFO: Printer is now on-line.\n"), stderr);
+ _cupsLangPuts(stderr, _("INFO: Printer is now online.\n"));
CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), g.status_timer, kCFRunLoopDefaultMode);
CFRelease(g.status_timer);
g.status_timer = NULL;
void *info)
{
fputs("STATE: +offline-error\n", stderr);
- fputs(_("INFO: Printer is currently off-line.\n"), stderr);
+ _cupsLangPuts(stderr, _("INFO: Printer is currently offline.\n"));
+
+ if (getenv("CLASS") != NULL)
+ {
+ /*
+ * If the CLASS environment variable is set, the job was submitted
+ * to a class and not to a specific queue. In this case, we want
+ * to abort immediately so that the job can be requeued on the next
+ * available printer in the class.
+ *
+ * Sleep 5 seconds to keep the job from requeuing too rapidly...
+ */
+
+ sleep(5);
+
+ exit(CUPS_BACKEND_FAILED);
+ }
}
CFStringRef serialKeys[] = { CFSTR("SN:"), CFSTR("SERN:"), NULL };
if (make != NULL)
- *make = copy_value_for_key(deviceIDString, makeKeys);
+ {
+ if ((*make = copy_value_for_key(deviceIDString, makeKeys)) == NULL)
+ *make = CFStringCreateWithCString(kCFAllocatorDefault, "Unknown",
+ kCFStringEncodingUTF8);
+ }
+
if (model != NULL)
- *model = copy_value_for_key(deviceIDString, modelKeys);
+ {
+ if ((*model = copy_value_for_key(deviceIDString, modelKeys)) == NULL)
+ *model = CFStringCreateWithCString(kCFAllocatorDefault, "Printer",
+ kCFStringEncodingUTF8);
+ }
+
if (serial != NULL)
*serial = copy_value_for_key(deviceIDString, serialKeys);
}
if (g.classdriver != NULL)
{
+ (*g.classdriver)->interfaceNumber = g.interfaceNum;
kr = (*g.classdriver)->Open(g.classdriver, g.location, kUSBPrintingProtocolBidirectional);
if (kr != kIOReturnSuccess || (*g.classdriver)->interface == NULL)
{
static void copy_devicestring(io_service_t usbInterface,
CFStringRef *deviceID,
- UInt32 *deviceLocation)
+ UInt32 *deviceLocation,
+ UInt8 *interfaceNumber )
{
IOCFPlugInInterface **iodev = NULL;
SInt32 score;
&intf)) == noErr)
{
(*intf)->GetLocationID(intf, deviceLocation);
+ (*intf)->GetInterfaceNumber(intf, interfaceNumber);
driverBundlePath = IORegistryEntryCreateCFProperty(usbInterface,
kUSBClassDriverProperty,
#pragma mark -
/*
- * 'parse_options()' - Parse uri options.
+ * 'parse_options()' - Parse URI options.
*/
-static void parse_options(const char *options,
+static void parse_options(char *options,
char *serial,
+ int serial_size,
UInt32 *location,
Boolean *wait_eof)
{
- char *serialnumber; /* ?serial=<serial> or ?location=<location> */
- char optionName[255], /* Name of option */
- value[255], /* Value of option */
- *ptr; /* Pointer into name or value */
+ char sep, /* Separator character */
+ *name, /* Name of option */
+ *value; /* Value of option */
+
if (serial)
*serial = '\0';
if (!options)
return;
- serialnumber = NULL;
-
- while (*options != '\0')
+ while (*options)
{
- /* Get the name... */
- for (ptr = optionName; *options && *options != '=' && *options != '+';)
- *ptr++ = *options++;
+ /*
+ * Get the name...
+ */
- *ptr = '\0';
- value[0] = '\0';
+ name = options;
- if (*options == '=')
- {
- /* Get the value... */
+ while (*options && *options != '=' && *options != '+' && *options != '&')
options ++;
- for (ptr = value; *options && *options != '+';)
- *ptr++ = *options++;
+ if ((sep = *options) != '\0')
+ *options++ = '\0';
- *ptr = '\0';
+ if (sep == '=')
+ {
+ /*
+ * Get the value...
+ */
+
+ value = options;
- if (*options == '+')
+ while (*options && *options != '+' && *options != '&')
options ++;
+
+ if (*options)
+ *options++ = '\0';
}
- else if (*options == '+')
- options ++;
+ else
+ value = (char *)"";
- /*
- * Process the option...
- */
- if (strcasecmp(optionName, "waiteof") == 0)
+ /*
+ * Process the option...
+ */
+
+ if (!strcasecmp(name, "waiteof"))
{
- if (strcasecmp(value, "on") == 0 ||
- strcasecmp(value, "yes") == 0 ||
- strcasecmp(value, "true") == 0)
+ if (!strcasecmp(value, "on") ||
+ !strcasecmp(value, "yes") ||
+ !strcasecmp(value, "true"))
*wait_eof = true;
- else if (strcasecmp(value, "off") == 0 ||
- strcasecmp(value, "no") == 0 ||
- strcasecmp(value, "false") == 0)
+ else if (!strcasecmp(value, "off") ||
+ !strcasecmp(value, "no") ||
+ !strcasecmp(value, "false"))
*wait_eof = false;
else
- fprintf(stderr, _("WARNING: Boolean expected for waiteof option \"%s\"\n"), value);
+ _cupsLangPrintf(stderr,
+ _("WARNING: Boolean expected for waiteof option "
+ "\"%s\"\n"), value);
}
- else if (strcasecmp(optionName, "serial") == 0)
- {
- strcpy(serial, value);
- serialnumber = serial;
- }
- else if (strcasecmp(optionName, "location") == 0 && location)
+ else if (!strcasecmp(name, "serial"))
+ strlcpy(serial, value, serial_size);
+ else if (!strcasecmp(name, "location") && location)
*location = strtol(value, NULL, 16);
}
-
- return;
}
/*!
* @function setup_cfLanguage
- * @abstract Convert the contents of the CUPS 'LANG' environment
+ * @abstract Convert the contents of the CUPS 'APPLE_LANGUAGE' environment
* variable into a one element CF array of languages.
*
* @discussion Each submitted job comes with a natural language. CUPS passes
CFArrayRef langArray = NULL;
const char *requestedLang = NULL;
- requestedLang = getenv("LANG");
+ if ((requestedLang = getenv("APPLE_LANGUAGE")) == NULL)
+ requestedLang = getenv("LANG");
+
if (requestedLang != NULL)
{
lang[0] = CFStringCreateWithCString(kCFAllocatorDefault, requestedLang, kCFStringEncodingUTF8);
langArray = CFArrayCreate(kCFAllocatorDefault, (const void **)lang, sizeof(lang) / sizeof(lang[0]), &kCFTypeArrayCallBacks);
CFPreferencesSetAppValue(CFSTR("AppleLanguages"), langArray, kCFPreferencesCurrentApplication);
- DEBUG_printf((stderr, "DEBUG: usb: AppleLanguages = \"%s\"\n", requestedLang));
+ fprintf(stderr, "DEBUG: usb: AppleLanguages = \"%s\"\n", requestedLang);
CFRelease(lang[0]);
CFRelease(langArray);
}
else
- fputs("DEBUG: usb: LANG environment variable missing.\n", stderr);
+ fputs("DEBUG: usb: LANG and APPLE_LANGUAGE environment variables missing.\n", stderr);
}
#pragma mark -
if (usb_ppc_status == NULL)
{
- /* Catch SIGTERM if we are _not_ printing data from
- * stdin (otherwise you can't cancel raw jobs...)
- */
+ /*
+ * Setup a SIGTERM handler then block it before forking...
+ */
- if (fd != 0)
- {
-#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
- sigset(SIGTERM, sigterm_handler);
-#elif defined(HAVE_SIGACTION)
- struct sigaction action; /* Actions for POSIX signals */
- memset(&action, 0, sizeof(action));
- sigaddset(&action.sa_mask, SIGTERM);
- action.sa_handler = sigterm_handler;
- sigaction(SIGTERM, &action, NULL);
-#else
- signal(SIGTERM, sigterm_handler);
-#endif /* HAVE_SIGSET */
- }
+ struct sigaction action; /* POSIX signal action */
+ sigset_t newmask, /* New signal mask */
+ oldmask; /* Old signal mask */
+
+ memset(&action, 0, sizeof(action));
+ sigaddset(&action.sa_mask, SIGTERM);
+ action.sa_handler = sigterm_handler;
+ sigaction(SIGTERM, &action, NULL);
+
+ sigemptyset(&newmask);
+ sigaddset(&newmask, SIGTERM);
+ sigprocmask(SIG_BLOCK, &newmask, &oldmask);
if ((child_pid = fork()) == 0)
{
- /* Child comes here. */
+ /*
+ * Child comes here...
+ */
+
setenv("USB_PPC_STATUS", "1", false);
- /* Tell the kernel we want the next exec call to favor the ppc architecture... */
+ /*
+ * Unblock signals before doing the exec...
+ */
+
+ memset(&action, 0, sizeof(action));
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = SIG_DFL;
+ sigaction(SIGTERM, &action, NULL);
+
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+
+ /*
+ * Tell the kernel the next exec call should favor the ppc architecture...
+ */
+
int mib[] = { CTL_KERN, KERN_AFFINITY, 1, 1 };
int namelen = 4;
sysctl(mib, namelen, NULL, NULL, NULL, 0);
- /* Set up the arguments and call exec... */
+ /*
+ * Set up the arguments and call exec...
+ */
+
for (i = 0; i < argc && i < (sizeof(my_argv)/sizeof(my_argv[0])) - 1; i++)
my_argv[i] = argv[i];
execv("/usr/libexec/cups/backend/usb", my_argv);
- fprintf(stderr, "DEBUG: execv: %s\n", strerror(errno));
- exitstatus = errno;
+ _cupsLangPrintError(_("ERROR: Unable to exec /usr/libexec/cups/backend/usb"));
+ exit(errno);
}
- else if (child_pid > 0)
+ else if (child_pid < 0)
{
- /* Parent comes here.
- *
- * Close the fds we won't be using then wait for the child backend to exit.
- */
- close(fd);
- close(1);
+ /*
+ * Error - couldn't fork a new process!
+ */
- fprintf(stderr, "DEBUG: Started usb(ppc) backend (PID %d)\n", (int)child_pid);
+ _cupsLangPrintError(_("ERROR: Unable to fork"));
+ exit(errno);
+ }
- while ((waitpid_status = waitpid(child_pid, &childstatus, 0)) == (pid_t)-1 && errno == EINTR)
- usleep(1000);
+ /*
+ * Unblock signals...
+ */
- if (WIFSIGNALED(childstatus))
- {
- exitstatus = WTERMSIG(childstatus);
- fprintf(stderr, "DEBUG: usb(ppc) backend %d crashed on signal %d!\n", child_pid, exitstatus);
- }
- else
- {
- if ((exitstatus = WEXITSTATUS(childstatus)) != 0)
- fprintf(stderr, "DEBUG: usb(ppc) backend %d stopped with status %d!\n", child_pid, exitstatus);
- else
- fprintf(stderr, "DEBUG: PID %d exited with no errors\n", child_pid);
- }
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+
+ /*
+ * Close the fds we won't be using then wait for the child backend to exit.
+ */
+
+ close(fd);
+ close(1);
+
+ fprintf(stderr, "DEBUG: Started usb(ppc) backend (PID %d)\n", (int)child_pid);
+
+ while ((waitpid_status = waitpid(child_pid, &childstatus, 0)) == (pid_t)-1 && errno == EINTR)
+ usleep(1000);
+
+ if (WIFSIGNALED(childstatus))
+ {
+ exitstatus = WTERMSIG(childstatus);
+ fprintf(stderr, "DEBUG: usb(ppc) backend %d crashed on signal %d!\n", child_pid, exitstatus);
}
else
{
- /* fork() error */
- fprintf(stderr, "DEBUG: fork: %s\n", strerror(errno));
- exitstatus = errno;
+ if ((exitstatus = WEXITSTATUS(childstatus)) != 0)
+ fprintf(stderr, "DEBUG: usb(ppc) backend %d stopped with status %d!\n", child_pid, exitstatus);
+ else
+ fprintf(stderr, "DEBUG: PID %d exited with no errors\n", child_pid);
}
}
else
/*
- * 'soft_reset'
+ * 'soft_reset()' - Send a soft reset to the device.
*/
static void soft_reset()
* Send the reset...
*/
- (*g.classdriver)->SoftReset(g.classdriver, 0);
+ (*g.classdriver)->SoftReset(g.classdriver, DEFAULT_TIMEOUT);
/*
* Release the I/O lock...
int *datalen)
{
UInt32 deviceLocation = 0;
+ UInt8 interfaceNum = 0;
CFStringRef deviceIDString = NULL;
/* GetDeviceID */
- copy_devicestring(g.printer_obj, &deviceIDString, &deviceLocation);
+ copy_devicestring(g.printer_obj, &deviceIDString, &deviceLocation, &interfaceNum);
if (deviceIDString)
{
CFStringGetCString(deviceIDString, data, *datalen, kCFStringEncodingUTF8);
/*
- * End of "$Id: usb-darwin.c 6591 2007-06-21 20:35:28Z mike $".
+ * End of "$Id: usb-darwin.c 7460 2008-04-16 02:19:54Z mike $".
*/