]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/cups-driverd.c
2 * "$Id: cups-driverd.c 5130 2006-02-17 20:25:33Z 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-2006 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
[128], /* Make and model */
61 device_id
[128]; /* IEEE 1284 Device ID */
64 typedef struct /**** In-memory record ****/
66 int found
; /* 1 if PPD is found */
67 ppd_rec_t record
; /* PPDs.dat record */
75 int NumPPDs
, /* Number of PPD files */
76 SortedPPDs
, /* Number of sorted PPD files */
77 AllocPPDs
; /* Number of allocated entries */
78 ppd_info_t
*PPDs
; /* PPD file info */
79 int ChangedPPD
; /* Did we change the PPD database? */
86 static ppd_info_t
*add_ppd(const char *name
, const char *natural_language
,
87 const char *make
, const char *make_and_model
,
88 const char *device_id
, time_t mtime
, size_t size
);
89 static int cat_ppd(const char *name
);
90 static int compare_names(const ppd_info_t
*p0
,
91 const ppd_info_t
*p1
);
92 static int compare_ppds(const ppd_info_t
*p0
,
93 const ppd_info_t
*p1
);
94 static int list_ppds(int request_id
, int limit
, const char *opt
);
95 static int load_drivers(void);
96 static int load_ppds(const char *d
, const char *p
);
100 * 'main()' - Scan for drivers and return an IPP response.
104 * cups-driverd request_id limit options
107 int /* O - Exit code */
108 main(int argc
, /* I - Number of command-line args */
109 char *argv
[]) /* I - Command-line arguments */
112 * Install or list PPDs...
115 if (argc
== 3 && !strcmp(argv
[1], "cat"))
116 return (cat_ppd(argv
[2]));
117 else if (argc
== 5 && !strcmp(argv
[1], "list"))
118 return (list_ppds(atoi(argv
[2]), atoi(argv
[3]), argv
[4]));
121 fputs("Usage: cups-driverd cat ppd-name\n", stderr
);
122 fputs("Usage: cups-driverd list request_id limit options\n", stderr
);
129 * 'add_ppd()' - Add a PPD file.
132 static ppd_info_t
* /* O - PPD */
133 add_ppd(const char *name
, /* I - PPD name */
134 const char *natural_language
, /* I - Language(s) */
135 const char *make
, /* I - Manufacturer */
136 const char *make_and_model
, /* I - NickName */
137 const char *device_id
, /* I - 1284DeviceId */
138 time_t mtime
, /* I - Modification time */
139 size_t size
) /* I - File size */
141 ppd_info_t
*ppd
; /* PPD */
145 * Add a new PPD file...
148 if (NumPPDs
>= AllocPPDs
)
151 * Allocate (more) memory for the PPD files...
157 ppd
= malloc(sizeof(ppd_info_t
) * AllocPPDs
);
159 ppd
= realloc(PPDs
, sizeof(ppd_info_t
) * AllocPPDs
);
163 fprintf(stderr
, "ERROR: [cups-driverd] Ran out of memory for %d PPD files!\n",
171 ppd
= PPDs
+ NumPPDs
;
175 * Zero-out the PPD data and copy the values over...
178 memset(ppd
, 0, sizeof(ppd_info_t
));
181 ppd
->record
.mtime
= mtime
;
182 ppd
->record
.size
= size
;
184 strlcpy(ppd
->record
.name
, name
, sizeof(ppd
->record
.name
));
185 strlcpy(ppd
->record
.natural_language
, natural_language
,
186 sizeof(ppd
->record
.natural_language
));
187 strlcpy(ppd
->record
.make
, make
, sizeof(ppd
->record
.make
));
188 strlcpy(ppd
->record
.make_and_model
, make_and_model
,
189 sizeof(ppd
->record
.make_and_model
));
190 strlcpy(ppd
->record
.device_id
, device_id
, sizeof(ppd
->record
.device_id
));
193 * Return the new PPD pointer...
201 * 'cat_ppd()' - Copy a PPD file to stdout.
204 static int /* O - Exit code */
205 cat_ppd(const char *name
) /* I - PPD name */
207 char scheme
[256], /* Scheme from PPD name */
208 *sptr
; /* Pointer into scheme */
209 char line
[1024]; /* Line/filename */
213 * Figure out if this is a static or dynamic PPD file...
216 strlcpy(scheme
, name
, sizeof(scheme
));
217 if ((sptr
= strchr(scheme
, ':')) != NULL
)
221 if (!strcmp(scheme
, "file"))
224 * "file:name" == "name"...
237 * Dynamic PPD, see if we have a driver program to support it...
240 const char *serverbin
; /* CUPS_SERVERBIN env var */
243 if ((serverbin
= getenv("CUPS_SERVERBIN")) == NULL
)
244 serverbin
= CUPS_SERVERBIN
;
246 snprintf(line
, sizeof(line
), "%s/driver/%s", serverbin
, scheme
);
247 if (access(line
, X_OK
))
250 * File does not exist or is not executable...
253 fprintf(stderr
, "ERROR: [cups-driverd] Unable to access \"%s\" - %s\n",
254 line
, strerror(errno
));
259 * Yes, let it cat the PPD file...
262 if (execl(line
, scheme
, "cat", name
, (char *)NULL
))
265 * Unable to execute driver...
268 fprintf(stderr
, "ERROR: [cups-driverd] Unable to execute \"%s\" - %s\n",
269 line
, strerror(errno
));
276 * Static PPD, see if we have a valid path and it exists...
279 cups_file_t
*fp
; /* PPD file */
280 const char *datadir
; /* CUPS_DATADIR env var */
283 if (name
[0] == '/' || strstr(name
, "../") || strstr(name
, "/.."))
289 fprintf(stderr
, "ERROR: [cups-driverd] Bad PPD name \"%s\"!\n", name
);
294 * Try opening the file...
297 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
298 datadir
= CUPS_DATADIR
;
300 snprintf(line
, sizeof(line
), "%s/model/%s", datadir
, name
);
301 if ((fp
= cupsFileOpen(line
, "r")) == NULL
)
303 fprintf(stderr
, "ERROR: [cups-driverd] Unable to open \"%s\" - %s\n",
304 line
, strerror(errno
));
309 * Now copy the file to stdout...
312 while (cupsFileGets(fp
, line
, sizeof(line
)))
319 * Return with no errors...
327 * 'compare_names()' - Compare PPD filenames for sorting.
330 static int /* O - Result of comparison */
331 compare_names(const ppd_info_t
*p0
, /* I - First PPD file */
332 const ppd_info_t
*p1
) /* I - Second PPD file */
334 return (strcasecmp(p0
->record
.name
, p1
->record
.name
));
339 * 'compare_ppds()' - Compare PPD file make and model names for sorting.
342 static int /* O - Result of comparison */
343 compare_ppds(const ppd_info_t
*p0
, /* I - First PPD file */
344 const ppd_info_t
*p1
) /* I - Second PPD file */
346 int diff
; /* Difference between strings */
350 * First compare manufacturers...
353 if ((diff
= strcasecmp(p0
->record
.make
, p1
->record
.make
)) != 0)
355 else if ((diff
= cupsdCompareNames(p0
->record
.make_and_model
,
356 p1
->record
.make_and_model
)) != 0)
359 return (strcasecmp(p0
->record
.natural_language
,
360 p1
->record
.natural_language
));
365 * 'list_ppds()' - List PPD files.
368 static int /* O - Exit code */
369 list_ppds(int request_id
, /* I - Request ID */
370 int limit
, /* I - Limit */
371 const char *opt
) /* I - Option argument */
373 int i
; /* Looping var */
374 int count
; /* Number of PPDs to send */
375 ppd_info_t
*ppd
; /* Current PPD file */
376 cups_file_t
*fp
; /* ppds.dat file */
377 struct stat fileinfo
; /* ppds.dat information */
378 char filename
[1024], /* ppds.dat filename */
379 model
[1024]; /* Model directory */
380 const char *cups_cachedir
; /* CUPS_CACHEDIR environment variable */
381 const char *cups_datadir
; /* CUPS_DATADIR environment variable */
382 int num_options
; /* Number of options */
383 cups_option_t
*options
; /* Options */
384 const char *requested
, /* requested-attributes option */
385 *make
; /* ppd-make option */
386 int send_natural_language
, /* Send ppd-natural-language attribute? */
387 send_make
, /* Send ppd-make attribute? */
388 send_make_and_model
, /* Send ppd-make-and-model attribute? */
389 send_name
, /* Send ppd-name attribute? */
390 send_device_id
; /* Send ppd-device-id attribute? */
393 fprintf(stderr
, "DEBUG2: [cups-driverd] list_ppds(request_id=%d, limit=%d, opt=\"%s\"\n",
394 request_id
, limit
, opt
);
397 * See if we a PPD database file...
402 PPDs
= (ppd_info_t
*)NULL
;
405 if ((cups_cachedir
= getenv("CUPS_CACHEDIR")) == NULL
)
406 cups_cachedir
= CUPS_CACHEDIR
;
408 snprintf(filename
, sizeof(filename
), "%s/ppds.dat", cups_cachedir
);
409 if (!stat(filename
, &fileinfo
) &&
410 (fileinfo
.st_size
% sizeof(ppd_rec_t
)) == 0 &&
411 (NumPPDs
= fileinfo
.st_size
/ sizeof(ppd_rec_t
)) > 0)
414 * We have a ppds.dat file, so read it!
419 if ((PPDs
= malloc(sizeof(ppd_info_t
) * NumPPDs
)) == NULL
)
422 "ERROR: [cups-driverd] Unable to allocate memory for %d "
423 "PPD files!\n", NumPPDs
);
427 else if ((fp
= cupsFileOpen(filename
, "r")) != NULL
)
429 for (i
= NumPPDs
, ppd
= PPDs
; i
> 0; i
--, ppd
++)
431 cupsFileRead(fp
, (char *)&(ppd
->record
), sizeof(ppd_rec_t
));
437 fprintf(stderr
, "INFO: [cups-driverd] Read \"%s\", %d PPDs...\n",
442 fprintf(stderr
, "ERROR: [cups-driverd] Unable to read \"%s\" - %s\n", filename
,
449 * Load all PPDs in the specified directory and below...
452 SortedPPDs
= NumPPDs
;
454 if ((cups_datadir
= getenv("CUPS_DATADIR")) == NULL
)
455 cups_datadir
= CUPS_DATADIR
;
457 snprintf(model
, sizeof(model
), "%s/model", cups_datadir
);
458 load_ppds(model
, "");
461 * Cull PPD files that are no longer present...
464 for (i
= NumPPDs
, ppd
= PPDs
; i
> 0; i
--, ppd
++)
468 * Remove this PPD file from the list...
472 memmove(ppd
, ppd
+ 1, (i
- 1) * sizeof(ppd_info_t
));
479 * Sort the PPDs by name...
483 qsort(PPDs
, NumPPDs
, sizeof(ppd_info_t
),
484 (int (*)(const void *, const void *))compare_names
);
487 * Write the new ppds.dat file...
492 if ((fp
= cupsFileOpen(filename
, "w")) != NULL
)
494 for (i
= NumPPDs
, ppd
= PPDs
; i
> 0; i
--, ppd
++)
495 cupsFileWrite(fp
, (char *)&(ppd
->record
), sizeof(ppd_rec_t
));
499 fprintf(stderr
, "INFO: [cups-driverd] Wrote \"%s\", %d PPDs...\n",
503 fprintf(stderr
, "ERROR: [cups-driverd] Unable to write \"%s\" - %s\n",
504 filename
, strerror(errno
));
507 fputs("INFO: [cups-driverd] No new or changed PPDs...\n", stderr
);
510 * Scan for dynamic PPD files...
516 * Add the raw driver...
519 add_ppd("raw", "en", "Raw", "Raw Queue", "", 0, 0);
522 * Sort the PPDs by make and model...
526 qsort(PPDs
, NumPPDs
, sizeof(ppd_info_t
),
527 (int (*)(const void *, const void *))compare_ppds
);
530 * Send IPP attributes...
533 num_options
= cupsParseOptions(opt
, 0, &options
);
534 requested
= cupsGetOption("requested-attributes", num_options
, options
);
535 make
= cupsGetOption("ppd-make", num_options
, options
);
537 fprintf(stderr
, "DEBUG: [cups-driverd] requested=\"%s\"\n",
538 requested
? requested
: "(nil)");
540 if (!requested
|| strstr(requested
, "all"))
544 send_make_and_model
= 1;
545 send_natural_language
= 1;
550 send_name
= strstr(requested
, "ppd-name") != NULL
;
551 send_make
= strstr(requested
, "ppd-make,") != NULL
||
552 strstr(requested
, ",ppd-make") != NULL
||
553 !strcmp(requested
, "ppd-make");
554 send_make_and_model
= strstr(requested
, "ppd-make-and-model") != NULL
;
555 send_natural_language
= strstr(requested
, "ppd-natural-language") != NULL
;
556 send_device_id
= strstr(requested
, "ppd-device-id") != NULL
;
559 puts("Content-Type: application/ipp\n");
561 cupsdSendIPPHeader(IPP_OK
, request_id
);
562 cupsdSendIPPGroup(IPP_TAG_OPERATION
);
563 cupsdSendIPPString(IPP_TAG_CHARSET
, "attributes-charset", "utf-8");
564 cupsdSendIPPString(IPP_TAG_LANGUAGE
, "attributes-natural-language", "en-US");
566 if (limit
<= 0 || limit
> NumPPDs
)
571 for (i
= NumPPDs
, ppd
= PPDs
; count
> 0 && i
> 0; i
--, ppd
++)
572 if (!make
|| !strcasecmp(ppd
->record
.make
, make
))
578 fprintf(stderr
, "DEBUG: [cups-driverd] Sending %s (%s)...\n",
579 ppd
->record
.name
, ppd
->record
.make_and_model
);
583 cupsdSendIPPGroup(IPP_TAG_PRINTER
);
586 cupsdSendIPPString(IPP_TAG_NAME
, "ppd-name", ppd
->record
.name
);
588 if (send_natural_language
)
589 cupsdSendIPPString(IPP_TAG_LANGUAGE
, "ppd-natural-language",
590 ppd
->record
.natural_language
);
593 cupsdSendIPPString(IPP_TAG_TEXT
, "ppd-make", ppd
->record
.make
);
595 if (send_make_and_model
)
596 cupsdSendIPPString(IPP_TAG_TEXT
, "ppd-make-and-model",
597 ppd
->record
.make_and_model
);
600 cupsdSendIPPString(IPP_TAG_TEXT
, "ppd-device-id",
601 ppd
->record
.device_id
);
604 * If we have only requested the ppd-make attribute, then skip
605 * the remaining PPDs with this make...
608 if (requested
&& !strcmp(requested
, "ppd-make"))
610 const char *this_make
; /* This ppd-make */
613 for (this_make
= ppd
->record
.make
, i
--, ppd
++; i
> 0; i
--, ppd
++)
614 if (strcasecmp(this_make
, ppd
->record
.make
))
622 cupsdSendIPPTrailer();
629 * 'load_ppds()' - Load PPD files recursively.
632 static int /* O - 1 on success, 0 on failure */
633 load_ppds(const char *d
, /* I - Actual directory */
634 const char *p
) /* I - Virtual path in name */
636 int i
; /* Looping var */
637 cups_file_t
*fp
; /* Pointer to file */
638 cups_dir_t
*dir
; /* Directory pointer */
639 cups_dentry_t
*dent
; /* Directory entry */
640 char filename
[1024], /* Name of PPD or directory */
641 line
[256], /* Line from backend */
642 *ptr
, /* Pointer into name */
643 name
[128], /* Name of PPD file */
644 language
[64], /* PPD language version */
645 country
[64], /* Country code */
646 manufacturer
[256], /* Manufacturer */
647 make_model
[256], /* Make and Model */
648 model_name
[256], /* ModelName */
649 nick_name
[256], /* NickName */
650 device_id
[256]; /* 1284DeviceId */
651 ppd_info_t
*ppd
, /* New PPD file */
652 key
; /* Search key */
653 int new_ppd
; /* Is this a new PPD? */
654 struct /* LanguageVersion translation table */
656 const char *version
, /* LanguageVersion string */
657 *language
; /* Language code */
669 { "japanese", "jp" },
670 { "norwegian", "no" },
672 { "portuguese", "pt" },
681 if ((dir
= cupsDirOpen(d
)) == NULL
)
683 fprintf(stderr
, "ERROR: [cups-driverd] Unable to open PPD directory \"%s\": %s\n",
688 while ((dent
= cupsDirRead(dir
)) != NULL
)
691 * Skip files/directories starting with "."...
694 if (dent
->filename
[0] == '.')
698 * See if this is a file...
701 snprintf(filename
, sizeof(filename
), "%s/%s", d
, dent
->filename
);
704 snprintf(name
, sizeof(name
), "%s/%s", p
, dent
->filename
);
706 strlcpy(name
, dent
->filename
, sizeof(name
));
708 if (S_ISDIR(dent
->fileinfo
.st_mode
))
714 if (!load_ppds(filename
, name
))
724 * See if this file has been scanned before...
729 strcpy(key
.record
.name
, name
);
731 ppd
= bsearch(&key
, PPDs
, SortedPPDs
, sizeof(ppd_info_t
),
732 (int (*)(const void *, const void *))compare_names
);
735 ppd
->record
.size
== dent
->fileinfo
.st_size
&&
736 ppd
->record
.mtime
== dent
->fileinfo
.st_mtime
)
746 * No, file is new/changed, so re-scan it...
749 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
753 * Now see if this is a PPD file...
757 cupsFileGets(fp
, line
, sizeof(line
));
759 if (strncmp(line
, "*PPD-Adobe:", 11))
762 * Nope, close the file and continue...
771 * Now read until we get the NickName field...
774 model_name
[0] = '\0';
776 manufacturer
[0] = '\0';
778 strcpy(language
, "en");
780 while (cupsFileGets(fp
, line
, sizeof(line
)) != NULL
)
782 if (!strncmp(line
, "*Manufacturer:", 14))
783 sscanf(line
, "%*[^\"]\"%255[^\"]", manufacturer
);
784 else if (!strncmp(line
, "*ModelName:", 11))
785 sscanf(line
, "%*[^\"]\"%127[^\"]", model_name
);
786 else if (!strncmp(line
, "*LanguageVersion:", 17))
787 sscanf(line
, "%*[^:]:%63s", language
);
788 else if (!strncmp(line
, "*NickName:", 10))
789 sscanf(line
, "%*[^\"]\"%255[^\"]", nick_name
);
790 else if (!strncmp(line
, "*1284DeviceId:", 14))
791 sscanf(line
, "%*[^\"]\"%255[^\"]", device_id
);
792 else if (!strncmp(line
, "*OpenUI", 7))
795 * Stop early if we have a NickName or ModelName attributes
796 * before the first OpenUI...
799 if (model_name
[0] || nick_name
[0])
811 * See if we got all of the required info...
815 strcpy(make_model
, nick_name
);
817 strcpy(make_model
, model_name
);
819 while (isspace(make_model
[0] & 255))
820 _cups_strcpy(make_model
, make_model
+ 1);
823 continue; /* Nope... */
826 * See if we got a manufacturer...
829 while (isspace(manufacturer
[0] & 255))
830 _cups_strcpy(manufacturer
, manufacturer
+ 1);
832 if (!manufacturer
[0] || !strcmp(manufacturer
, "ESP"))
835 * Nope, copy the first part of the make and model then...
838 strlcpy(manufacturer
, make_model
, sizeof(manufacturer
));
841 * Truncate at the first space, dash, or slash, or make the
842 * manufacturer "Other"...
845 for (ptr
= manufacturer
; *ptr
; ptr
++)
846 if (*ptr
== ' ' || *ptr
== '-' || *ptr
== '/')
849 if (*ptr
&& ptr
> manufacturer
)
851 else if (!strncasecmp(manufacturer
, "agfa", 4))
852 strcpy(manufacturer
, "AGFA");
853 else if (!strncasecmp(manufacturer
, "herk", 4) ||
854 !strncasecmp(manufacturer
, "linotype", 8))
855 strcpy(manufacturer
, "LHAG");
857 strcpy(manufacturer
, "Other");
860 * Hack for various vendors...
863 if (!strcasecmp(manufacturer
, "XPrint"))
864 strcpy(manufacturer
, "Xerox");
865 else if (!strcasecmp(manufacturer
, "Eastman"))
866 strcpy(manufacturer
, "Kodak");
867 else if (!strcasecmp(manufacturer
, "laserwriter"))
868 strcpy(manufacturer
, "Apple");
869 else if (!strcasecmp(manufacturer
, "colorpoint"))
870 strcpy(manufacturer
, "Seiko");
871 else if (!strcasecmp(manufacturer
, "fiery"))
872 strcpy(manufacturer
, "EFI");
873 else if (!strcasecmp(manufacturer
, "ps") ||
874 !strcasecmp(manufacturer
, "colorpass"))
875 strcpy(manufacturer
, "Canon");
876 else if (!strncasecmp(manufacturer
, "primera", 7))
877 strcpy(manufacturer
, "Fargo");
878 else if (!strcasecmp(manufacturer
, "designjet"))
879 strcpy(manufacturer
, "HP");
881 else if (!strncasecmp(manufacturer
, "LHAG", 4) ||
882 !strncasecmp(manufacturer
, "linotype", 8))
883 strcpy(manufacturer
, "LHAG");
886 * Fix the language as needed...
889 if ((ptr
= strchr(language
, '-')) != NULL
)
891 else if ((ptr
= strchr(language
, '_')) != NULL
)
897 * Setup the country suffix...
901 _cups_strcpy(country
+ 1, ptr
);
906 * No country suffix...
912 for (i
= 0; i
< (int)(sizeof(languages
) / sizeof(languages
[0])); i
++)
913 if (!strcasecmp(languages
[i
].version
, language
))
916 if (i
< (int)(sizeof(languages
) / sizeof(languages
[0])))
919 * Found a known language...
922 snprintf(language
, sizeof(language
), "%s%s", languages
[i
].language
,
928 * Unknown language; use "xx"...
931 strcpy(language
, "xx");
935 * Add the PPD file...
943 * Add new PPD file...
946 fprintf(stderr
, "DEBUG: [cups-driverd] Adding ppd \"%s\"...\n", name
);
948 if (!add_ppd(name
, language
, manufacturer
, make_model
, device_id
,
949 dent
->fileinfo
.st_mtime
, dent
->fileinfo
.st_size
))
958 * Update existing record...
961 fprintf(stderr
, "DEBUG: [cups-driverd] Updating ppd \"%s\"...\n", name
);
963 memset(ppd
, 0, sizeof(ppd_info_t
));
966 ppd
->record
.mtime
= dent
->fileinfo
.st_mtime
;
967 ppd
->record
.size
= dent
->fileinfo
.st_size
;
969 strlcpy(ppd
->record
.name
, name
, sizeof(ppd
->record
.name
));
970 strlcpy(ppd
->record
.make
, manufacturer
, sizeof(ppd
->record
.make
));
971 strlcpy(ppd
->record
.make_and_model
, make_model
,
972 sizeof(ppd
->record
.make_and_model
));
973 strlcpy(ppd
->record
.natural_language
, language
,
974 sizeof(ppd
->record
.natural_language
));
975 strlcpy(ppd
->record
.device_id
, device_id
, sizeof(ppd
->record
.device_id
));
988 * 'load_drivers()' - Load driver-generated PPD files.
991 static int /* O - 1 on success, 0 on failure */
994 const char *server_bin
; /* CUPS_SERVERBIN environment variable */
995 char drivers
[1024]; /* Location of driver programs */
996 FILE *fp
; /* Pipe to driver program */
997 cups_dir_t
*dir
; /* Directory pointer */
998 cups_dentry_t
*dent
; /* Directory entry */
999 char filename
[1024], /* Name of driver */
1000 line
[2048], /* Line from driver */
1001 name
[512], /* ppd-name */
1002 natural_language
[128], /* ppd-natural-language */
1003 make
[128], /* ppd-make */
1004 make_and_model
[256], /* ppd-make-and-model */
1005 device_id
[256]; /* ppd-device-id */
1009 * Try opening the driver directory...
1012 if ((server_bin
= getenv("CUPS_SERVERBIN")) == NULL
)
1013 server_bin
= CUPS_SERVERBIN
;
1015 snprintf(drivers
, sizeof(drivers
), "%s/driver", server_bin
);
1017 if ((dir
= cupsDirOpen(drivers
)) == NULL
)
1019 fprintf(stderr
, "ERROR: [cups-driverd] Unable to open driver directory "
1021 drivers
, strerror(errno
));
1026 * Loop through all of the device drivers...
1029 while ((dent
= cupsDirRead(dir
)) != NULL
)
1032 * Only look at executable files...
1035 if (!(dent
->fileinfo
.st_mode
& 0111) || !S_ISREG(dent
->fileinfo
.st_mode
))
1039 * Run the driver with no arguments and collect the output...
1042 snprintf(filename
, sizeof(filename
), "%s/%s list", drivers
, dent
->filename
);
1043 if ((fp
= popen(filename
, "r")) != NULL
)
1045 while (fgets(line
, sizeof(line
), fp
) != NULL
)
1048 * Each line is of the form:
1050 * \"ppd-name\" ppd-natural-language "ppd-make" "ppd-make-and-model"
1053 device_id
[0] = '\0';
1055 if (sscanf(line
, "\"%511[^\"]\"%127s%*[ \t]\"%127[^\"]\""
1056 "%*[ \t]\"%256[^\"]\"%*[ \t]\"%256[^\"]\"",
1057 name
, natural_language
, make
, make_and_model
,
1061 * Bad format; strip trailing newline and write an error message.
1064 if (line
[strlen(line
) - 1] == '\n')
1065 line
[strlen(line
) - 1] = '\0';
1067 fprintf(stderr
, "ERROR: [cups-driverd] Bad line from \"%s\": %s\n",
1068 dent
->filename
, line
);
1074 * Add the device to the array of available devices...
1077 if (!add_ppd(name
, natural_language
, make
, make_and_model
, device_id
,
1084 fprintf(stderr
, "DEBUG: [cups-driverd] Added dynamic PPD \"%s\"...\n",
1092 fprintf(stderr
, "WARNING: [cups-driverd] Unable to execute \"%s\": %s\n",
1093 filename
, strerror(errno
));
1103 * End of "$Id: cups-driverd.c 5130 2006-02-17 20:25:33Z mike $".