]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/cups-driverd.c
2 * "$Id: cups-driverd.c 4812 2005-10-25 18:23:10Z mike $"
4 * PPD/driver support for the Common UNIX Printing System (CUPS).
6 * This program handles listing and installing both static PPD files
7 * in CUPS_DATADIR/model and dynamically generated PPD files using
8 * the driver helper programs in CUPS_SERVERBIN/driver.
10 * Copyright 1997-2005 by Easy Software Products.
12 * These coded instructions, statements, and computer programs are the
13 * property of Easy Software Products and are protected by Federal
14 * copyright law. Distribution and use rights are outlined in the file
15 * "LICENSE.txt" which should have been included with this file. If this
16 * file is missing or damaged please contact Easy Software Products
19 * Attn: CUPS Licensing Information
20 * Easy Software Products
21 * 44141 Airport View Drive, Suite 204
22 * Hollywood, Maryland 20636 USA
24 * Voice: (301) 373-9600
25 * EMail: cups-info@cups.org
26 * WWW: http://www.cups.org
30 * main() - Scan for drivers and return an IPP response.
31 * add_ppd() - Add a PPD file.
32 * cat_ppd() - Copy a PPD file to stdout.
33 * compare_names() - Compare PPD filenames for sorting.
34 * compare_ppds() - Compare PPD file make and model names for sorting.
35 * list_ppds() - List PPD files.
36 * load_ppds() - Load PPD files recursively.
37 * load_drivers() - Load driver-generated PPD files.
41 * Include necessary headers...
49 * PPD information structures...
52 typedef struct /**** PPD record ****/
54 time_t mtime
; /* Modification time */
55 size_t size
; /* Size in bytes */
56 char name
[512 - sizeof(time_t) - sizeof(size_t)],
58 natural_language
[128], /* Natural language(s) */
59 make
[128], /* Manufacturer */
60 make_and_model
[256]; /* Make and model */
63 typedef struct /**** In-memory record ****/
65 int found
; /* 1 if PPD is found */
66 ppd_rec_t record
; /* PPDs.dat record */
74 int NumPPDs
, /* Number of PPD files */
75 SortedPPDs
, /* Number of sorted PPD files */
76 AllocPPDs
; /* Number of allocated entries */
77 ppd_info_t
*PPDs
; /* PPD file info */
78 int ChangedPPD
; /* Did we change the PPD database? */
85 ppd_info_t
*add_ppd(const char *name
, const char *natural_language
,
86 const char *make
, const char *make_and_model
,
87 time_t mtime
, size_t size
);
88 int cat_ppd(const char *name
);
89 int compare_names(const ppd_info_t
*p0
, const ppd_info_t
*p1
);
90 int compare_ppds(const ppd_info_t
*p0
, const ppd_info_t
*p1
);
91 int list_ppds(int request_id
, int limit
, const char *opt
);
92 int load_drivers(void);
93 int load_ppds(const char *d
, const char *p
);
97 * 'main()' - Scan for drivers and return an IPP response.
101 * cups-driverd request_id limit options
104 int /* O - Exit code */
105 main(int argc
, /* I - Number of command-line args */
106 char *argv
[]) /* I - Command-line arguments */
109 * Install or list PPDs...
112 if (argc
== 3 && !strcmp(argv
[1], "cat"))
113 return (cat_ppd(argv
[2]));
114 else if (argc
== 5 && !strcmp(argv
[1], "list"))
115 return (list_ppds(atoi(argv
[2]), atoi(argv
[3]), argv
[4]));
118 fputs("Usage: cups-driverd cat ppd-name\n", stderr
);
119 fputs("Usage: cups-driverd list request_id limit options\n", stderr
);
126 * 'add_ppd()' - Add a PPD file.
129 ppd_info_t
* /* O - PPD */
130 add_ppd(const char *name
, /* I - PPD name */
131 const char *natural_language
, /* I - Language(s) */
132 const char *make
, /* I - Manufacturer */
133 const char *make_and_model
, /* I - NickName */
134 time_t mtime
, /* I - Modification time */
135 size_t size
) /* I - File size */
137 ppd_info_t
*ppd
; /* PPD */
141 * Add a new PPD file...
144 if (NumPPDs
>= AllocPPDs
)
147 * Allocate (more) memory for the PPD files...
153 ppd
= malloc(sizeof(ppd_info_t
) * AllocPPDs
);
155 ppd
= realloc(PPDs
, sizeof(ppd_info_t
) * AllocPPDs
);
159 fprintf(stderr
, "ERROR: [cups-driverd] Ran out of memory for %d PPD files!\n",
167 ppd
= PPDs
+ NumPPDs
;
171 * Zero-out the PPD data and copy the values over...
174 memset(ppd
, 0, sizeof(ppd_info_t
));
177 ppd
->record
.mtime
= mtime
;
178 ppd
->record
.size
= size
;
180 strlcpy(ppd
->record
.name
, name
, sizeof(ppd
->record
.name
));
181 strlcpy(ppd
->record
.natural_language
, natural_language
,
182 sizeof(ppd
->record
.natural_language
));
183 strlcpy(ppd
->record
.make
, make
, sizeof(ppd
->record
.make
));
184 strlcpy(ppd
->record
.make_and_model
, make_and_model
,
185 sizeof(ppd
->record
.make_and_model
));
188 * Return the new PPD pointer...
196 * 'cat_ppd()' - Copy a PPD file to stdout.
199 int /* O - Exit code */
200 cat_ppd(const char *name
) /* I - PPD name */
202 char scheme
[256], /* Scheme from PPD name */
203 *sptr
; /* Pointer into scheme */
204 char line
[1024]; /* Line/filename */
208 * Figure out if this is a static or dynamic PPD file...
211 strlcpy(scheme
, name
, sizeof(scheme
));
212 if ((sptr
= strchr(scheme
, ':')) != NULL
)
216 if (!strcmp(scheme
, "file"))
219 * "file:name" == "name"...
232 * Dynamic PPD, see if we have a driver program to support it...
235 const char *serverbin
; /* CUPS_SERVERBIN env var */
238 if ((serverbin
= getenv("CUPS_SERVERBIN")) == NULL
)
239 serverbin
= CUPS_SERVERBIN
;
241 snprintf(line
, sizeof(line
), "%s/driver/%s", serverbin
, scheme
);
242 if (access(line
, X_OK
))
245 * File does not exist or is not executable...
248 fprintf(stderr
, "ERROR: [cups-driverd] Unable to access \"%s\" - %s\n",
249 line
, strerror(errno
));
254 * Yes, let it cat the PPD file...
257 if (execl(line
, scheme
, "cat", name
, (char *)NULL
))
260 * Unable to execute driver...
263 fprintf(stderr
, "ERROR: [cups-driverd] Unable to execute \"%s\" - %s\n",
264 line
, strerror(errno
));
271 * Static PPD, see if we have a valid path and it exists...
274 cups_file_t
*fp
; /* PPD file */
275 const char *datadir
; /* CUPS_DATADIR env var */
278 if (name
[0] == '/' || strstr(name
, "../") || strstr(name
, "/.."))
284 fprintf(stderr
, "ERROR: [cups-driverd] Bad PPD name \"%s\"!\n", name
);
289 * Try opening the file...
292 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
293 datadir
= CUPS_DATADIR
;
295 snprintf(line
, sizeof(line
), "%s/model/%s", datadir
, name
);
296 if ((fp
= cupsFileOpen(line
, "r")) == NULL
)
298 fprintf(stderr
, "ERROR: [cups-driverd] Unable to open \"%s\" - %s\n",
299 line
, strerror(errno
));
304 * Now copy the file to stdout...
307 while (cupsFileGets(fp
, line
, sizeof(line
)))
314 * Return with no errors...
322 * 'compare_names()' - Compare PPD filenames for sorting.
325 int /* O - Result of comparison */
326 compare_names(const ppd_info_t
*p0
, /* I - First PPD file */
327 const ppd_info_t
*p1
) /* I - Second PPD file */
329 return (strcasecmp(p0
->record
.name
, p1
->record
.name
));
334 * 'compare_ppds()' - Compare PPD file make and model names for sorting.
337 int /* O - Result of comparison */
338 compare_ppds(const ppd_info_t
*p0
, /* I - First PPD file */
339 const ppd_info_t
*p1
) /* I - Second PPD file */
341 int diff
; /* Difference between strings */
344 * First compare manufacturers...
347 if ((diff
= strcasecmp(p0
->record
.make
, p1
->record
.make
)) != 0)
349 else if ((diff
= cupsdCompareNames(p0
->record
.make_and_model
,
350 p1
->record
.make_and_model
)) != 0)
353 return (strcasecmp(p0
->record
.natural_language
,
354 p1
->record
.natural_language
));
359 * 'list_ppds()' - List PPD files.
362 int /* O - Exit code */
363 list_ppds(int request_id
, /* I - Request ID */
364 int limit
, /* I - Limit */
365 const char *opt
) /* I - Option argument */
367 int i
; /* Looping var */
368 int count
; /* Number of PPDs to send */
369 ppd_info_t
*ppd
; /* Current PPD file */
370 cups_file_t
*fp
; /* ppds.dat file */
371 struct stat fileinfo
; /* ppds.dat information */
372 char filename
[1024], /* ppds.dat filename */
373 model
[1024]; /* Model directory */
374 const char *cups_cachedir
; /* CUPS_CACHEDIR environment variable */
375 const char *cups_datadir
; /* CUPS_DATADIR environment variable */
376 int num_options
; /* Number of options */
377 cups_option_t
*options
; /* Options */
378 const char *requested
, /* requested-attributes option */
379 *make
; /* ppd-make option */
380 int send_natural_language
, /* Send ppd-natural-language attribute? */
381 send_make
, /* Send ppd-make attribute? */
382 send_make_and_model
, /* Send ppd-make-and-model attribute? */
383 send_name
; /* Send ppd-name attribute? */
386 fprintf(stderr
, "DEBUG2: [cups-driverd] list_ppds(request_id=%d, limit=%d, opt=\"%s\"\n",
387 request_id
, limit
, opt
);
390 * See if we a PPD database file...
395 PPDs
= (ppd_info_t
*)NULL
;
398 if ((cups_cachedir
= getenv("CUPS_CACHEDIR")) == NULL
)
399 cups_cachedir
= CUPS_CACHEDIR
;
401 snprintf(filename
, sizeof(filename
), "%s/ppds.dat", cups_cachedir
);
402 if (!stat(filename
, &fileinfo
) &&
403 (fileinfo
.st_size
% sizeof(ppd_rec_t
)) == 0 &&
404 (NumPPDs
= fileinfo
.st_size
/ sizeof(ppd_rec_t
)) > 0)
407 * We have a ppds.dat file, so read it!
412 if ((PPDs
= malloc(sizeof(ppd_info_t
) * NumPPDs
)) == NULL
)
414 fprintf(stderr
, "ERROR: [cups-driverd] Unable to allocate memory for %d PPD files!\n",
419 else if ((fp
= cupsFileOpen(filename
, "r")) != NULL
)
421 for (i
= NumPPDs
, ppd
= PPDs
; i
> 0; i
--, ppd
++)
423 cupsFileRead(fp
, (char *)&(ppd
->record
), sizeof(ppd_rec_t
));
429 fprintf(stderr
, "INFO: [cups-driverd] Read \"%s\", %d PPDs...\n",
434 fprintf(stderr
, "ERROR: [cups-driverd] Unable to read \"%s\" - %s\n", filename
,
441 * Load all PPDs in the specified directory and below...
444 SortedPPDs
= NumPPDs
;
446 if ((cups_datadir
= getenv("CUPS_DATADIR")) == NULL
)
447 cups_datadir
= CUPS_DATADIR
;
449 snprintf(model
, sizeof(model
), "%s/model", cups_datadir
);
450 load_ppds(model
, "");
453 * Cull PPD files that are no longer present...
456 for (i
= NumPPDs
, ppd
= PPDs
; i
> 0; i
--, ppd
++)
460 * Remove this PPD file from the list...
464 memmove(ppd
, ppd
+ 1, (i
- 1) * sizeof(ppd_info_t
));
471 * Sort the PPDs by name...
475 qsort(PPDs
, NumPPDs
, sizeof(ppd_info_t
),
476 (int (*)(const void *, const void *))compare_names
);
479 * Write the new ppds.dat file...
484 if ((fp
= cupsFileOpen(filename
, "w")) != NULL
)
486 for (i
= NumPPDs
, ppd
= PPDs
; i
> 0; i
--, ppd
++)
487 cupsFileWrite(fp
, (char *)&(ppd
->record
), sizeof(ppd_rec_t
));
491 fprintf(stderr
, "INFO: [cups-driverd] Wrote \"%s\", %d PPDs...\n",
495 fprintf(stderr
, "ERROR: [cups-driverd] Unable to write \"%s\" - %s\n",
496 filename
, strerror(errno
));
499 fputs("INFO: [cups-driverd] No new or changed PPDs...\n", stderr
);
502 * Scan for dynamic PPD files...
508 * Add the raw driver...
511 add_ppd("raw", "en", "Raw", "Raw Queue", 0, 0);
514 * Sort the PPDs by make and model...
518 qsort(PPDs
, NumPPDs
, sizeof(ppd_info_t
),
519 (int (*)(const void *, const void *))compare_ppds
);
522 * Send IPP attributes...
525 num_options
= cupsParseOptions(opt
, 0, &options
);
526 requested
= cupsGetOption("requested-attributes", num_options
, options
);
527 make
= cupsGetOption("ppd-make", num_options
, options
);
529 fprintf(stderr
, "DEBUG: [cups-driverd] requested=\"%s\"\n",
530 requested
? requested
: "(nil)");
532 if (!requested
|| strstr(requested
, "all"))
536 send_make_and_model
= 1;
537 send_natural_language
= 1;
541 send_name
= strstr(requested
, "ppd-name") != NULL
;
542 send_make
= strstr(requested
, "ppd-make,") != NULL
||
543 strstr(requested
, ",ppd-make") != NULL
||
544 !strcmp(requested
, "ppd-make");
545 send_make_and_model
= strstr(requested
, "ppd-make-and-model") != NULL
;
546 send_natural_language
= strstr(requested
, "ppd-natural-language") != NULL
;
549 puts("Content-Type: application/ipp\n");
551 cupsdSendIPPHeader(IPP_OK
, request_id
);
552 cupsdSendIPPGroup(IPP_TAG_OPERATION
);
553 cupsdSendIPPString(IPP_TAG_CHARSET
, "attributes-charset", "utf-8");
554 cupsdSendIPPString(IPP_TAG_LANGUAGE
, "attributes-natural-language", "en-US");
556 if (limit
<= 0 || limit
> NumPPDs
)
561 for (i
= NumPPDs
, ppd
= PPDs
; count
> 0 && i
> 0; i
--, ppd
++)
562 if (!make
|| !strcasecmp(ppd
->record
.make
, make
))
568 fprintf(stderr
, "DEBUG: [cups-driverd] Sending %s (%s)...\n",
569 ppd
->record
.name
, ppd
->record
.make_and_model
);
573 cupsdSendIPPGroup(IPP_TAG_PRINTER
);
576 cupsdSendIPPString(IPP_TAG_NAME
, "ppd-name", ppd
->record
.name
);
578 if (send_natural_language
)
579 cupsdSendIPPString(IPP_TAG_LANGUAGE
, "ppd-natural-language",
580 ppd
->record
.natural_language
);
583 cupsdSendIPPString(IPP_TAG_TEXT
, "ppd-make", ppd
->record
.make
);
585 if (send_make_and_model
)
586 cupsdSendIPPString(IPP_TAG_TEXT
, "ppd-make-and-model",
587 ppd
->record
.make_and_model
);
590 * If we have only requested the ppd-make attribute, then skip
591 * the remaining PPDs with this make...
594 if (requested
&& !strcmp(requested
, "ppd-make"))
596 const char *this_make
; /* This ppd-make */
599 for (this_make
= ppd
->record
.make
, i
--, ppd
++; i
> 0; i
--, ppd
++)
600 if (strcasecmp(this_make
, ppd
->record
.make
))
608 cupsdSendIPPTrailer();
615 * 'load_ppds()' - Load PPD files recursively.
618 int /* O - 1 on success, 0 on failure */
619 load_ppds(const char *d
, /* I - Actual directory */
620 const char *p
) /* I - Virtual path in name */
622 int i
; /* Looping var */
623 cups_file_t
*fp
; /* Pointer to file */
624 cups_dir_t
*dir
; /* Directory pointer */
625 cups_dentry_t
*dent
; /* Directory entry */
626 char filename
[1024], /* Name of PPD or directory */
627 line
[256], /* Line from backend */
628 *ptr
, /* Pointer into name */
629 name
[128], /* Name of PPD file */
630 language
[64], /* PPD language version */
631 country
[64], /* Country code */
632 manufacturer
[256], /* Manufacturer */
633 make_model
[256], /* Make and Model */
634 model_name
[256], /* ModelName */
635 nick_name
[256]; /* NickName */
636 ppd_info_t
*ppd
, /* New PPD file */
637 key
; /* Search key */
638 int new_ppd
; /* Is this a new PPD? */
639 struct /* LanguageVersion translation table */
641 const char *version
, /* LanguageVersion string */
642 *language
; /* Language code */
654 { "japanese", "jp" },
655 { "norwegian", "no" },
657 { "portuguese", "pt" },
666 if ((dir
= cupsDirOpen(d
)) == NULL
)
668 fprintf(stderr
, "ERROR: [cups-driverd] Unable to open PPD directory \"%s\": %s\n",
673 while ((dent
= cupsDirRead(dir
)) != NULL
)
676 * See if this is a file...
679 snprintf(filename
, sizeof(filename
), "%s/%s", d
, dent
->filename
);
682 snprintf(name
, sizeof(name
), "%s/%s", p
, dent
->filename
);
684 strlcpy(name
, dent
->filename
, sizeof(name
));
686 if (S_ISDIR(dent
->fileinfo
.st_mode
))
692 if (!load_ppds(filename
, name
))
702 * See if this file has been scanned before...
707 strcpy(key
.record
.name
, name
);
709 ppd
= bsearch(&key
, PPDs
, SortedPPDs
, sizeof(ppd_info_t
),
710 (int (*)(const void *, const void *))compare_names
);
713 ppd
->record
.size
== dent
->fileinfo
.st_size
&&
714 ppd
->record
.mtime
== dent
->fileinfo
.st_mtime
)
724 * No, file is new/changed, so re-scan it...
727 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
731 * Now see if this is a PPD file...
735 cupsFileGets(fp
, line
, sizeof(line
));
737 if (strncmp(line
, "*PPD-Adobe:", 11))
740 * Nope, close the file and continue...
749 * Now read until we get the NickName field...
752 model_name
[0] = '\0';
754 manufacturer
[0] = '\0';
755 strcpy(language
, "en");
757 while (cupsFileGets(fp
, line
, sizeof(line
)) != NULL
)
759 if (!strncmp(line
, "*Manufacturer:", 14))
760 sscanf(line
, "%*[^\"]\"%255[^\"]", manufacturer
);
761 else if (!strncmp(line
, "*ModelName:", 11))
762 sscanf(line
, "%*[^\"]\"%127[^\"]", model_name
);
763 else if (!strncmp(line
, "*LanguageVersion:", 17))
764 sscanf(line
, "%*[^:]:%63s", language
);
765 else if (!strncmp(line
, "*NickName:", 10))
766 sscanf(line
, "%*[^\"]\"%255[^\"]", nick_name
);
767 else if (!strncmp(line
, "*OpenUI", 7))
770 * Stop early if we have a NickName or ModelName attributes
771 * before the first OpenUI...
774 if (model_name
[0] || nick_name
[0])
779 * Stop early if we have both the Manufacturer and NickName
783 if (manufacturer
[0] && nick_name
[0])
794 * See if we got all of the required info...
798 strcpy(make_model
, nick_name
);
800 strcpy(make_model
, model_name
);
802 while (isspace(make_model
[0] & 255))
803 _cups_strcpy(make_model
, make_model
+ 1);
806 continue; /* Nope... */
809 * See if we got a manufacturer...
812 while (isspace(manufacturer
[0] & 255))
813 _cups_strcpy(manufacturer
, manufacturer
+ 1);
815 if (!manufacturer
[0] || !strcmp(manufacturer
, "ESP"))
818 * Nope, copy the first part of the make and model then...
821 strlcpy(manufacturer
, make_model
, sizeof(manufacturer
));
824 * Truncate at the first space, dash, or slash, or make the
825 * manufacturer "Other"...
828 for (ptr
= manufacturer
; *ptr
; ptr
++)
829 if (*ptr
== ' ' || *ptr
== '-' || *ptr
== '/')
832 if (*ptr
&& ptr
> manufacturer
)
834 else if (!strncasecmp(manufacturer
, "agfa", 4))
835 strcpy(manufacturer
, "AGFA");
836 else if (!strncasecmp(manufacturer
, "herk", 4) ||
837 !strncasecmp(manufacturer
, "linotype", 8))
838 strcpy(manufacturer
, "LHAG");
840 strcpy(manufacturer
, "Other");
843 * Hack for various vendors...
846 if (!strcasecmp(manufacturer
, "XPrint"))
847 strcpy(manufacturer
, "Xerox");
848 else if (!strcasecmp(manufacturer
, "Eastman"))
849 strcpy(manufacturer
, "Kodak");
850 else if (!strcasecmp(manufacturer
, "laserwriter"))
851 strcpy(manufacturer
, "Apple");
852 else if (!strcasecmp(manufacturer
, "colorpoint"))
853 strcpy(manufacturer
, "Seiko");
854 else if (!strcasecmp(manufacturer
, "fiery"))
855 strcpy(manufacturer
, "EFI");
856 else if (!strcasecmp(manufacturer
, "ps") ||
857 !strcasecmp(manufacturer
, "colorpass"))
858 strcpy(manufacturer
, "Canon");
859 else if (!strncasecmp(manufacturer
, "primera", 7))
860 strcpy(manufacturer
, "Fargo");
861 else if (!strcasecmp(manufacturer
, "designjet"))
862 strcpy(manufacturer
, "HP");
864 else if (!strncasecmp(manufacturer
, "LHAG", 4) ||
865 !strncasecmp(manufacturer
, "linotype", 8))
866 strcpy(manufacturer
, "LHAG");
869 * Fix the language as needed...
872 if ((ptr
= strchr(language
, '-')) != NULL
)
874 else if ((ptr
= strchr(language
, '_')) != NULL
)
880 * Setup the country suffix...
884 _cups_strcpy(country
+ 1, ptr
);
889 * No country suffix...
895 for (i
= 0; i
< (int)(sizeof(languages
) / sizeof(languages
[0])); i
++)
896 if (!strcasecmp(languages
[i
].version
, language
))
899 if (i
< (int)(sizeof(languages
) / sizeof(languages
[0])))
902 * Found a known language...
905 snprintf(language
, sizeof(language
), "%s%s", languages
[i
].language
,
911 * Unknown language; use "xx"...
914 strcpy(language
, "xx");
918 * Add the PPD file...
926 * Add new PPD file...
929 fprintf(stderr
, "DEBUG: [cups-driverd] Adding ppd \"%s\"...\n", name
);
931 if (!add_ppd(name
, language
, manufacturer
, make_model
,
932 dent
->fileinfo
.st_mtime
, dent
->fileinfo
.st_size
))
941 * Update existing record...
944 fprintf(stderr
, "DEBUG: [cups-driverd] Updating ppd \"%s\"...\n", name
);
946 memset(ppd
, 0, sizeof(ppd_info_t
));
949 ppd
->record
.mtime
= dent
->fileinfo
.st_mtime
;
950 ppd
->record
.size
= dent
->fileinfo
.st_size
;
952 strlcpy(ppd
->record
.name
, name
, sizeof(ppd
->record
.name
));
953 strlcpy(ppd
->record
.make
, manufacturer
, sizeof(ppd
->record
.make
));
954 strlcpy(ppd
->record
.make_and_model
, make_model
,
955 sizeof(ppd
->record
.make_and_model
));
956 strlcpy(ppd
->record
.natural_language
, language
,
957 sizeof(ppd
->record
.natural_language
));
970 * 'load_drivers()' - Load driver-generated PPD files.
973 int /* O - 1 on success, 0 on failure */
976 const char *server_bin
; /* CUPS_SERVERBIN environment variable */
977 char drivers
[1024]; /* Location of driver programs */
978 FILE *fp
; /* Pipe to driver program */
979 cups_dir_t
*dir
; /* Directory pointer */
980 cups_dentry_t
*dent
; /* Directory entry */
981 char filename
[1024], /* Name of driver */
982 line
[2048], /* Line from driver */
983 name
[512], /* ppd-name */
984 natural_language
[128], /* ppd-natural-language */
985 make
[128], /* ppd-make */
986 make_and_model
[256]; /* ppd-make-and-model */
990 * Try opening the driver directory...
993 if ((server_bin
= getenv("CUPS_SERVERBIN")) == NULL
)
994 server_bin
= CUPS_SERVERBIN
;
996 snprintf(drivers
, sizeof(drivers
), "%s/driver", server_bin
);
998 if ((dir
= cupsDirOpen(drivers
)) == NULL
)
1000 fprintf(stderr
, "ERROR: [cups-driverd] Unable to open driver directory "
1002 drivers
, strerror(errno
));
1007 * Loop through all of the device drivers...
1010 while ((dent
= cupsDirRead(dir
)) != NULL
)
1013 * Only look at executable files...
1016 if (!(dent
->fileinfo
.st_mode
& 0111) || !S_ISREG(dent
->fileinfo
.st_mode
))
1020 * Run the driver with no arguments and collect the output...
1023 snprintf(filename
, sizeof(filename
), "%s/%s", drivers
, dent
->filename
);
1024 if ((fp
= popen(filename
, "r")) != NULL
)
1026 while (fgets(line
, sizeof(line
), fp
) != NULL
)
1029 * Each line is of the form:
1031 * \"ppd-name\" ppd-natural-language "ppd-make" "ppd-make-and-model"
1034 if (sscanf(line
, "\"%511[^\"]\"%127s%*[ \t]\"%127[^\"]\"%*[ \t]\"%256[^\"]\"",
1035 name
, natural_language
, make
, make_and_model
) != 4)
1038 * Bad format; strip trailing newline and write an error message.
1041 if (line
[strlen(line
) - 1] == '\n')
1042 line
[strlen(line
) - 1] = '\0';
1044 fprintf(stderr
, "ERROR: [cups-driverd] Bad line from \"%s\": %s\n",
1045 dent
->filename
, line
);
1051 * Add the device to the array of available devices...
1054 if (!add_ppd(name
, natural_language
, make
, make_and_model
, 0, 0))
1060 fprintf(stderr
, "DEBUG: [cups-driverd] Added dynamic PPD \"%s\"...\n",
1068 fprintf(stderr
, "WARNING: [cups-driverd] Unable to execute \"%s\": %s\n",
1069 filename
, strerror(errno
));
1079 * End of "$Id: cups-driverd.c 4812 2005-10-25 18:23:10Z mike $".