]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/devices.c
cde82421273114e14eab361a1e3f5539c6f8b471
2 * "$Id: devices.c,v 1.16 2002/01/02 17:59:15 mike Exp $"
4 * Device scanning routines for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2002 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 if (line
[strlen(line
) - 1] == '\n')
188 line
[strlen(line
) - 1] = '\0';
190 LogMessage(L_ERROR
, "LoadDevices: Bad line from \"%s\": %s",
198 * Add the device to the array of available devices...
201 if (num_devs
>= alloc_devs
)
204 * Allocate (more) memory for the devices...
208 dev
= malloc(sizeof(dev_info_t
) * 16);
210 dev
= realloc(devs
, sizeof(dev_info_t
) * (alloc_devs
+ 16));
214 LogMessage(L_ERROR
, "LoadDevices: Ran out of memory for %d devices!",
224 dev
= devs
+ num_devs
;
227 memset(dev
, 0, sizeof(dev_info_t
));
228 strncpy(dev
->device_class
, dclass
, sizeof(dev
->device_class
) - 1);
229 strncpy(dev
->device_info
, info
, sizeof(dev
->device_info
) - 1);
230 strncpy(dev
->device_make_and_model
, make_model
,
231 sizeof(dev
->device_make_and_model
) - 1);
232 strncpy(dev
->device_uri
, uri
, sizeof(dev
->device_uri
) - 1);
234 LogMessage(L_DEBUG
, "LoadDevices: Added device \"%s\"...", uri
);
240 * Turn the alarm clock off and close the pipe to the command...
248 * Hack for backends that don't support the CUPS 1.1 calling convention:
249 * add a network device with the method == backend name.
252 if (count
== 0 && compat
)
254 if (num_devs
>= alloc_devs
)
257 * Allocate (more) memory for the devices...
261 dev
= malloc(sizeof(dev_info_t
) * 16);
263 dev
= realloc(devs
, sizeof(dev_info_t
) * (alloc_devs
+ 16));
267 LogMessage(L_ERROR
, "LoadDevices: Ran out of memory for %d devices!",
277 dev
= devs
+ num_devs
;
280 memset(dev
, 0, sizeof(dev_info_t
));
281 strcpy(dev
->device_class
, "network");
282 snprintf(dev
->device_info
, sizeof(dev
->device_info
),
283 "Unknown Network Device (%s)", dent
->d_name
);
284 strcpy(dev
->device_make_and_model
, "Unknown");
285 strncpy(dev
->device_uri
, dent
->d_name
, sizeof(dev
->device_uri
) - 1);
287 LogMessage(L_DEBUG
, "LoadDevices: Compatibility device \"%s\"...",
292 LogMessage(L_WARN
, "LoadDevices: Unable to execute \"%s\" backend: %s",
293 dent
->d_name
, strerror(errno
));
299 * Catch child signals...
305 * Sort the available devices...
309 qsort(devs
, num_devs
, sizeof(dev_info_t
),
310 (int (*)(const void *, const void *))compare_devs
);
313 * Create the list of devices...
316 for (i
= num_devs
, dev
= devs
; i
> 0; i
--, dev
++)
319 * Add strings to attributes...
323 ippAddSeparator(Devices
);
325 ippAddString(Devices
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
326 "device-class", NULL
, dev
->device_class
);
327 ippAddString(Devices
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
328 "device-info", NULL
, dev
->device_info
);
329 ippAddString(Devices
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
330 "device-make-and-model", NULL
, dev
->device_make_and_model
);
331 ippAddString(Devices
, IPP_TAG_PRINTER
, IPP_TAG_URI
,
332 "device-uri", NULL
, dev
->device_uri
);
336 * Free the devices array...
345 * 'compare_devs()' - Compare PPD file make and model names for sorting.
348 static int /* O - Result of comparison */
349 compare_devs(const dev_info_t
*d0
, /* I - First PPD file */
350 const dev_info_t
*d1
) /* I - Second PPD file */
352 const char *s
, /* First name */
353 *t
; /* Second name */
354 int diff
, /* Difference between digits */
355 digits
; /* Number of digits */
359 * First compare names...
366 * Loop through both nicknames, returning only when a difference is
367 * seen. Also, compare whole numbers rather than just characters, too!
372 if (isdigit(*s
) && isdigit(*t
))
375 * Got a number; start by skipping leading 0's...
384 * Skip equal digits...
387 while (isdigit(*s
) && *s
== *t
)
394 * Bounce out if *s and *t aren't both digits...
397 if (isdigit(*s
) && !isdigit(*t
))
399 else if (!isdigit(*s
) && isdigit(*t
))
401 else if (!isdigit(*s
) || !isdigit(*t
))
410 * Figure out how many more digits there are...
430 * Return if the number or value of the digits is different...
440 else if (tolower(*s
) < tolower(*t
))
442 else if (tolower(*s
) > tolower(*t
))
452 * Return the results of the final comparison...
459 else if ((diff
= strcasecmp(d0
->device_class
, d1
->device_class
)) != 0)
462 return (strcasecmp(d0
->device_uri
, d1
->device_uri
));
467 * 'sigalrm_handler()' - Handle alarm signals for backends that get hung
468 * trying to list the available devices...
472 sigalrm_handler(int sig
) /* I - Signal number */
474 (void)sig
; /* remove compiler warnings... */
476 LogMessage(L_WARN
, "LoadDevices: Backend did not respond within 30 seconds!");
481 * End of "$Id: devices.c,v 1.16 2002/01/02 17:59:15 mike Exp $".