]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/devices.c
f6ac4556179e951d24f84ab39d67be8d1d8e5b77
2 * "$Id: devices.c,v 1.14 2001/03/23 13:58:17 mike Exp $"
4 * Device scanning routines for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2001 by Easy Software Products.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
26 * LoadDevices() - Load all available devices.
30 * Include necessary headers...
37 * Device information structure...
42 char device_class
[128], /* Device class */
43 device_make_and_model
[128], /* Make and model, if known */
44 device_info
[128], /* Device info/description */
45 device_uri
[1024]; /* Device URI */
53 static int num_devs
, /* Number of devices */
54 alloc_devs
; /* Number of allocated entries */
55 static dev_info_t
*devs
; /* Device info */
62 static int compare_devs(const dev_info_t
*p0
, const dev_info_t
*p1
);
63 static void sigalrm_handler(int sig
);
67 * 'LoadDevices()' - Load all available devices.
71 LoadDevices(const char *d
) /* I - Directory to scan */
73 int i
; /* Looping var */
74 int count
; /* Number of devices from backend */
75 int compat
; /* Compatibility device? */
76 FILE *fp
; /* Pipe to device backend */
77 DIR *dir
; /* Directory pointer */
78 DIRENT
*dent
; /* Directory entry */
79 char filename
[1024], /* Name of backend */
80 line
[2048], /* Line from backend */
81 dclass
[64], /* Device class */
82 uri
[1024], /* Device URI */
83 info
[128], /* Device info */
84 make_model
[256];/* Make and model */
85 dev_info_t
*dev
; /* Current device */
86 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
87 struct sigaction action
; /* Actions for POSIX signals */
88 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
92 * Initialize the device list.
98 * Try opening the backend directory...
101 if ((dir
= opendir(d
)) == NULL
)
103 LogMessage(L_ERROR
, "LoadDevices: Unable to open backend directory \"%s\": %s",
109 * Setup the devices array...
114 devs
= (dev_info_t
*)0;
117 * Ignore child signals...
120 IgnoreChildSignals();
123 * Loop through all of the device backends...
126 while ((dent
= readdir(dir
)) != NULL
)
129 * Skip "." and ".."...
132 if (dent
->d_name
[0] == '.')
136 * Run the backend with no arguments and collect the output...
139 snprintf(filename
, sizeof(filename
), "%s/%s", d
, dent
->d_name
);
140 if ((fp
= popen(filename
, "r")) != NULL
)
143 * Set an alarm for the first read from the backend; this avoids
144 * problems when a backend is hung getting device information.
147 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
148 sigset(SIGALRM
, sigalrm_handler
);
149 #elif defined(HAVE_SIGACTION)
150 memset(&action
, 0, sizeof(action
));
152 sigemptyset(&action
.sa_mask
);
153 sigaddset(&action
.sa_mask
, SIGALRM
);
154 action
.sa_handler
= sigalrm_handler
;
155 sigaction(SIGALRM
, &action
, NULL
);
157 signal(SIGALRM
, sigalrm_handler
);
158 #endif /* HAVE_SIGSET */
162 compat
= strcmp(dent
->d_name
, "smb") == 0;
164 while (fgets(line
, sizeof(line
), fp
) != NULL
)
167 * Reset the alarm clock...
173 * Each line is of the form:
175 * class URI "make model" "name"
178 if (strncasecmp(line
, "Usage", 5) == 0)
180 else if (sscanf(line
, "%63s%1023s%*[ \t]\"%127[^\"]\"%*[ \t]\"%255[^\"]",
181 dclass
, uri
, make_model
, info
) != 4)
184 * Bad format; strip trailing newline and write an error message.
187 line
[strlen(line
) - 1] = '\0';
188 LogMessage(L_ERROR
, "LoadDevices: Bad line from \"%s\": %s",
195 * Add the device to the array of available devices...
198 if (num_devs
>= alloc_devs
)
201 * Allocate (more) memory for the devices...
205 dev
= malloc(sizeof(dev_info_t
) * 16);
207 dev
= realloc(devs
, sizeof(dev_info_t
) * (alloc_devs
+ 16));
211 LogMessage(L_ERROR
, "LoadDevices: Ran out of memory for %d devices!",
221 dev
= devs
+ num_devs
;
224 memset(dev
, 0, sizeof(dev_info_t
));
225 strncpy(dev
->device_class
, dclass
, sizeof(dev
->device_class
) - 1);
226 strncpy(dev
->device_info
, info
, sizeof(dev
->device_info
) - 1);
227 strncpy(dev
->device_make_and_model
, make_model
,
228 sizeof(dev
->device_make_and_model
) - 1);
229 strncpy(dev
->device_uri
, uri
, sizeof(dev
->device_uri
) - 1);
231 LogMessage(L_DEBUG
, "LoadDevices: Added device \"%s\"...", uri
);
237 * Turn the alarm clock off and close the pipe to the command...
245 * Hack for backends that don't support the CUPS 1.1 calling convention:
246 * add a network device with the method == backend name.
249 if (count
== 0 && compat
)
251 if (num_devs
>= alloc_devs
)
254 * Allocate (more) memory for the devices...
258 dev
= malloc(sizeof(dev_info_t
) * 16);
260 dev
= realloc(devs
, sizeof(dev_info_t
) * (alloc_devs
+ 16));
264 LogMessage(L_ERROR
, "LoadDevices: Ran out of memory for %d devices!",
274 dev
= devs
+ num_devs
;
277 memset(dev
, 0, sizeof(dev_info_t
));
278 strcpy(dev
->device_class
, "network");
279 snprintf(dev
->device_info
, sizeof(dev
->device_info
),
280 "Unknown Network Device (%s)", dent
->d_name
);
281 strcpy(dev
->device_make_and_model
, "Unknown");
282 strncpy(dev
->device_uri
, dent
->d_name
, sizeof(dev
->device_uri
) - 1);
284 LogMessage(L_DEBUG
, "LoadDevices: Compatibility device \"%s\"...",
289 LogMessage(L_WARN
, "LoadDevices: Unable to execute \"%s\" backend: %s",
290 dent
->d_name
, strerror(errno
));
296 * Catch child signals...
302 * Sort the available devices...
306 qsort(devs
, num_devs
, sizeof(dev_info_t
),
307 (int (*)(const void *, const void *))compare_devs
);
310 * Create the list of devices...
313 for (i
= num_devs
, dev
= devs
; i
> 0; i
--, dev
++)
316 * Add strings to attributes...
320 ippAddSeparator(Devices
);
322 ippAddString(Devices
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
323 "device-class", NULL
, dev
->device_class
);
324 ippAddString(Devices
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
325 "device-info", NULL
, dev
->device_info
);
326 ippAddString(Devices
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
327 "device-make-and-model", NULL
, dev
->device_make_and_model
);
328 ippAddString(Devices
, IPP_TAG_PRINTER
, IPP_TAG_URI
,
329 "device-uri", NULL
, dev
->device_uri
);
333 * Free the devices array...
342 * 'compare_devs()' - Compare PPD file make and model names for sorting.
345 static int /* O - Result of comparison */
346 compare_devs(const dev_info_t
*d0
, /* I - First PPD file */
347 const dev_info_t
*d1
) /* I - Second PPD file */
349 const char *s
, /* First name */
350 *t
; /* Second name */
351 int diff
, /* Difference between digits */
352 digits
; /* Number of digits */
356 * First compare names...
363 * Loop through both nicknames, returning only when a difference is
364 * seen. Also, compare whole numbers rather than just characters, too!
369 if (isdigit(*s
) && isdigit(*t
))
372 * Got a number; start by skipping leading 0's...
381 * Skip equal digits...
384 while (isdigit(*s
) && *s
== *t
)
391 * Bounce out if *s and *t aren't both digits...
394 if (isdigit(*s
) && !isdigit(*t
))
396 else if (!isdigit(*s
) && isdigit(*t
))
398 else if (!isdigit(*s
) || !isdigit(*t
))
407 * Figure out how many more digits there are...
427 * Return if the number or value of the digits is different...
437 else if (tolower(*s
) < tolower(*t
))
439 else if (tolower(*s
) > tolower(*t
))
449 * Return the results of the final comparison...
456 else if ((diff
= strcasecmp(d0
->device_class
, d1
->device_class
)) != 0)
459 return (strcasecmp(d0
->device_uri
, d1
->device_uri
));
464 * 'sigalrm_handler()' - Handle alarm signals for backends that get hung
465 * trying to list the available devices...
469 sigalrm_handler(int sig
) /* I - Signal number */
471 (void)sig
; /* remove compiler warnings... */
473 LogMessage(L_WARN
, "LoadDevices: Backend did not respond within 30 seconds!");
478 * End of "$Id: devices.c,v 1.14 2001/03/23 13:58:17 mike Exp $".