]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - systemv/cupstestppd.c
Merge changes from CUPS 1.5svn-r8849.
[thirdparty/cups.git] / systemv / cupstestppd.c
index dda0f0e75e7a9b03bb8a6392858f83cb08315eec..0a7ae4b3b6ca8eec34113d30f3434601d5db1636 100644 (file)
@@ -100,6 +100,17 @@ enum
 };
 
 
+/*
+ * File permissions...
+ */
+
+#define MODE_WRITE     0022            /* Group/other write */
+#define MODE_MASK      0555            /* Owner/group/other read+exec/search */
+#define MODE_DATAFILE  0444            /* Owner/group/other read */
+#define MODE_DIRECTORY 0555            /* Owner/group/other read+search */
+#define MODE_PROGRAM   0555            /* Owner/group/other read+exec */
+
+
 /*
  * Standard Adobe media keywords (must remain sorted)...
  */
@@ -304,6 +315,7 @@ main(int  argc,                             /* I - Number of command-line args */
   int          files;                  /* Number of files */
   int          verbose;                /* Want verbose output? */
   int          warn;                   /* Which errors to just warn about */
+  int          ignore;                 /* Which errors to ignore */
   int          status;                 /* Exit status */
   int          errors;                 /* Number of conformance errors */
   int          ppdversion;             /* PPD spec version in PPD file */
@@ -341,6 +353,7 @@ main(int  argc,                             /* I - Number of command-line args */
   status  = ERROR_NONE;
   root    = "";
   warn    = WARN_NONE;
+  ignore  = WARN_NONE;
 
   for (i = 1; i < argc; i ++)
     if (argv[i][0] == '-' && argv[i][1])
@@ -348,6 +361,24 @@ main(int  argc,                            /* I - Number of command-line args */
       for (opt = argv[i] + 1; *opt; opt ++)
         switch (*opt)
        {
+         case 'I' :                    /* Ignore errors */
+             i ++;
+
+             if (i >= argc)
+               usage();
+
+              if (!strcmp(argv[i], "none"))
+               ignore = WARN_NONE;
+             else if (!strcmp(argv[i], "filters"))
+               ignore |= WARN_FILTERS;
+             else if (!strcmp(argv[i], "profiles"))
+               ignore |= WARN_PROFILES;
+             else if (!strcmp(argv[i], "all"))
+               ignore = WARN_FILTERS | WARN_PROFILES;
+             else
+               usage();
+             break;
+
          case 'R' :                    /* Alternate root directory */
              i ++;
 
@@ -357,7 +388,7 @@ main(int  argc,                             /* I - Number of command-line args */
               root = argv[i];
              break;
 
-         case 'W' :                    /* Turn errors into warnings  */
+         case 'W' :                    /* Turn errors into warnings */
              i ++;
 
              if (i >= argc)
@@ -595,7 +626,7 @@ main(int  argc,                             /* I - Number of command-line args */
            _cupsLangPuts(stdout, _(" FAIL\n"));
 
          _cupsLangPrintf(stdout,
-                         _("      **FAIL**  BAD DefaultImageableArea %s!\n"
+                         _("      **FAIL**  BAD DefaultImageableArea %s\n"
                            "                REF: Page 102, section 5.15.\n"),
                          attr->value);
        }
@@ -631,7 +662,7 @@ main(int  argc,                             /* I - Number of command-line args */
            _cupsLangPuts(stdout, _(" FAIL\n"));
 
          _cupsLangPrintf(stdout,
-                         _("      **FAIL**  BAD DefaultPaperDimension %s!\n"
+                         _("      **FAIL**  BAD DefaultPaperDimension %s\n"
                            "                REF: Page 103, section 5.15.\n"),
                          attr->value);
        }
@@ -1224,7 +1255,7 @@ main(int  argc,                           /* I - Number of command-line args */
                _cupsLangPuts(stdout, _(" FAIL\n"));
 
              _cupsLangPrintf(stdout,
-                             _("      **FAIL**  Bad %s choice %s!\n"
+                             _("      **FAIL**  Bad %s choice %s\n"
                                "                REF: Page 84, section 5.9\n"),
                              option->keyword, choice->choice);
             }
@@ -1243,7 +1274,7 @@ main(int  argc,                           /* I - Number of command-line args */
            _cupsLangPuts(stdout, _(" FAIL\n"));
 
          _cupsLangPrintf(stdout,
-                         _("      **FAIL**  %s must be 1284DeviceID!\n"
+                         _("      **FAIL**  %s must be 1284DeviceID\n"
                            "                REF: Page 72, section 5.5\n"),
                          attr->name);
         }
@@ -1256,10 +1287,10 @@ main(int  argc,                         /* I - Number of command-line args */
       if (!(warn & WARN_CONSTRAINTS))
         errors = check_constraints(ppd, errors, verbose, 0);
 
-      if (!(warn & WARN_FILTERS))
+      if (!(warn & WARN_FILTERS) && !(ignore & WARN_FILTERS))
         errors = check_filters(ppd, root, errors, verbose, 0);
 
-      if (!(warn & WARN_PROFILES))
+      if (!(warn & WARN_PROFILES) && !(ignore & WARN_PROFILES))
         errors = check_profiles(ppd, root, errors, verbose, 0);
 
       if (!(warn & WARN_SIZES))
@@ -1289,7 +1320,7 @@ main(int  argc,                           /* I - Number of command-line args */
             if (verbose >= 0)
              _cupsLangPrintf(stdout,
                              _("      **FAIL**  Bad LanguageEncoding %s - "
-                               "must be ISOLatin1!\n"),
+                               "must be ISOLatin1\n"),
                              attr->value ? attr->value : "(null)");
 
             errors ++;
@@ -1303,7 +1334,7 @@ main(int  argc,                           /* I - Number of command-line args */
             if (verbose >= 0)
              _cupsLangPrintf(stdout,
                              _("      **FAIL**  Bad LanguageVersion %s - "
-                               "must be English!\n"),
+                               "must be English\n"),
                              ppd->lang_version ? ppd->lang_version : "(null)");
 
             errors ++;
@@ -1336,7 +1367,7 @@ main(int  argc,                           /* I - Number of command-line args */
                _cupsLangPrintf(stdout,
                                _("      **FAIL**  Default translation "
                                  "string for option %s contains 8-bit "
-                                 "characters!\n"),
+                                 "characters\n"),
                                option->keyword);
 
              errors ++;
@@ -1363,7 +1394,7 @@ main(int  argc,                           /* I - Number of command-line args */
                  _cupsLangPrintf(stdout,
                                  _("      **FAIL**  Default translation "
                                    "string for option %s choice %s contains "
-                                   "8-bit characters!\n"),
+                                   "8-bit characters\n"),
                                  option->keyword,
                                  option->choices[j].choice);
 
@@ -1387,18 +1418,18 @@ main(int  argc,                         /* I - Number of command-line args */
       {
         check_basics(argv[i]);
 
-       if (warn & WARN_CONSTRAINTS)
-         errors = check_constraints(ppd, errors, verbose, 1);
-
        if (warn & WARN_DEFAULTS)
          errors = check_defaults(ppd, errors, verbose, 1);
 
-       if (warn & WARN_PROFILES)
-         errors = check_profiles(ppd, root, errors, verbose, 1);
+       if (warn & WARN_CONSTRAINTS)
+         errors = check_constraints(ppd, errors, verbose, 1);
 
-       if (warn & WARN_FILTERS)
+       if ((warn & WARN_FILTERS) && !(ignore & WARN_FILTERS))
          errors = check_filters(ppd, root, errors, verbose, 1);
 
+       if ((warn & WARN_PROFILES) && !(ignore & WARN_PROFILES))
+         errors = check_profiles(ppd, root, errors, verbose, 1);
+
         if (warn & WARN_SIZES)
          errors = check_sizes(ppd, errors, verbose, 1);
         else
@@ -1421,7 +1452,7 @@ main(int  argc,                           /* I - Number of command-line args */
        if (option)
          _cupsLangPrintf(stdout,
                          _("        WARN    Duplex option keyword %s may not "
-                           "work as expected and should be named Duplex!\n"
+                           "work as expected and should be named Duplex\n"
                            "                REF: Page 122, section 5.17\n"),
                          option->keyword);
 
@@ -1450,7 +1481,7 @@ main(int  argc,                           /* I - Number of command-line args */
              !ppdFindOption(ppd, attr->name + 7))
             _cupsLangPrintf(stdout,
                            _("        WARN    %s has no corresponding "
-                             "options!\n"),
+                             "options\n"),
                            attr->name);
        }
 
@@ -1458,7 +1489,7 @@ main(int  argc,                           /* I - Number of command-line args */
        if (ppdConflicts(ppd))
        {
          _cupsLangPuts(stdout,
-                       _("        WARN    Default choices conflicting!\n"));
+                       _("        WARN    Default choices conflicting\n"));
 
           show_conflicts(ppd);
         }
@@ -1466,7 +1497,7 @@ main(int  argc,                           /* I - Number of command-line args */
         if (ppdversion < 43)
        {
           _cupsLangPrintf(stdout,
-                         _("        WARN    Obsolete PPD version %.1f!\n"
+                         _("        WARN    Obsolete PPD version %.1f\n"
                            "                REF: Page 42, section 5.2.\n"),
                          0.1f * ppdversion);
        }
@@ -1801,7 +1832,7 @@ check_basics(const char *filename)        /* I - PPD file to check */
       
       if (col > 0 && whitespace)
        _cupsLangPrintf(stdout,
-                       _("        WARN    Line %d only contains whitespace!\n"),
+                       _("        WARN    Line %d only contains whitespace\n"),
                        linenum);
 
       linenum ++;
@@ -1820,12 +1851,12 @@ check_basics(const char *filename)      /* I - PPD file to check */
   if (mixed)
     _cupsLangPuts(stdout,
                  _("        WARN    File contains a mix of CR, LF, and "
-                   "CR LF line endings!\n"));
+                   "CR LF line endings\n"));
 
   if (eol == EOL_CRLF)
     _cupsLangPuts(stdout,
                  _("        WARN    Non-Windows PPD files should use lines "
-                   "ending with only LF, not CR LF!\n"));
+                   "ending with only LF, not CR LF\n"));
 
   cupsFileClose(fp);
 }
@@ -1878,7 +1909,7 @@ check_constraints(ppd_file_t *ppd,        /* I - PPD file */
          _cupsLangPuts(stdout, _(" FAIL\n"));
 
        _cupsLangPrintf(stdout,
-                       _("      %s  Empty cupsUIConstraints %s!\n"),
+                       _("      %s  Empty cupsUIConstraints %s\n"),
                        prefix, constattr->spec);
 
        if (!warn)
@@ -1897,7 +1928,7 @@ check_constraints(ppd_file_t *ppd,        /* I - PPD file */
          _cupsLangPuts(stdout, _(" FAIL\n"));
 
        _cupsLangPrintf(stdout,
-                       _("      %s  Bad cupsUIConstraints %s: \"%s\"!\n"),
+                       _("      %s  Bad cupsUIConstraints %s: \"%s\"\n"),
                        prefix, constattr->spec, constattr->value);
 
        if (!warn)
@@ -1915,7 +1946,7 @@ check_constraints(ppd_file_t *ppd,        /* I - PPD file */
          _cupsLangPuts(stdout, _(" FAIL\n"));
 
        _cupsLangPrintf(stdout,
-                       _("      %s  Missing cupsUIResolver %s!\n"),
+                       _("      %s  Missing cupsUIResolver %s\n"),
                        prefix, constattr->spec);
 
        if (!warn)
@@ -1968,7 +1999,7 @@ check_constraints(ppd_file_t *ppd,        /* I - PPD file */
 
          _cupsLangPrintf(stdout,
                          _("      %s  Missing option %s in "
-                           "cupsUIConstraints %s: \"%s\"!\n"),
+                           "cupsUIConstraints %s: \"%s\"\n"),
                          prefix, option, constattr->spec, constattr->value);
          
          if (!warn)
@@ -1984,7 +2015,7 @@ check_constraints(ppd_file_t *ppd,        /* I - PPD file */
 
          _cupsLangPrintf(stdout,
                          _("      %s  Missing choice *%s %s in "
-                           "cupsUIConstraints %s: \"%s\"!\n"),
+                           "cupsUIConstraints %s: \"%s\"\n"),
                          prefix, option, choice, constattr->spec,
                          constattr->value);
 
@@ -2021,7 +2052,7 @@ check_constraints(ppd_file_t *ppd,        /* I - PPD file */
 
        _cupsLangPrintf(stdout,
                        _("      %s  cupsUIResolver %s does not list at least "
-                         "two different options!\n"),
+                         "two different options\n"),
                        prefix, constattr->spec);
 
        if (!warn)
@@ -2038,7 +2069,7 @@ check_constraints(ppd_file_t *ppd,        /* I - PPD file */
          _cupsLangPuts(stdout, _(" FAIL\n"));
 
        _cupsLangPrintf(stdout,
-                       _("      %s  cupsUIResolver %s causes a loop!\n"),
+                       _("      %s  cupsUIResolver %s causes a loop\n"),
                        prefix, constattr->spec);
 
        if (!warn)
@@ -2075,7 +2106,7 @@ check_constraints(ppd_file_t *ppd,        /* I - PPD file */
 
        _cupsLangPrintf(stdout,
                        _("      %s  Missing option %s in "
-                         "UIConstraints \"*%s %s *%s %s\"!\n"),
+                         "UIConstraints \"*%s %s *%s %s\"\n"),
                        prefix, c->option1,
                        c->option1, c->choice1, c->option2, c->choice2);
 
@@ -2089,7 +2120,7 @@ check_constraints(ppd_file_t *ppd,        /* I - PPD file */
 
        _cupsLangPrintf(stdout,
                        _("      %s  Missing choice *%s %s in "
-                         "UIConstraints \"*%s %s *%s %s\"!\n"),
+                         "UIConstraints \"*%s %s *%s %s\"\n"),
                        prefix, c->option1, c->choice1,
                        c->option1, c->choice1, c->option2, c->choice2);
 
@@ -2116,7 +2147,7 @@ check_constraints(ppd_file_t *ppd,        /* I - PPD file */
 
        _cupsLangPrintf(stdout,
                        _("      %s  Missing option %s in "
-                         "UIConstraints \"*%s %s *%s %s\"!\n"),
+                         "UIConstraints \"*%s %s *%s %s\"\n"),
                        prefix, c->option2,
                        c->option1, c->choice1, c->option2, c->choice2);
 
@@ -2130,7 +2161,7 @@ check_constraints(ppd_file_t *ppd,        /* I - PPD file */
 
        _cupsLangPrintf(stdout,
                        _("      %s  Missing choice *%s %s in "
-                         "UIConstraints \"*%s %s *%s %s\"!\n"),
+                         "UIConstraints \"*%s %s *%s %s\"\n"),
                        prefix, c->option2, c->choice2,
                        c->option1, c->choice1, c->option2, c->choice2);
 
@@ -2177,7 +2208,7 @@ check_case(ppd_file_t *ppd,               /* I - PPD file */
        if (verbose >= 0)
          _cupsLangPrintf(stdout,
                          _("      **FAIL**  Group names %s and %s differ only "
-                           "by case!\n"),
+                           "by case\n"),
                          groupa->name, groupb->name);
 
        errors ++;
@@ -2199,7 +2230,7 @@ check_case(ppd_file_t *ppd,               /* I - PPD file */
        if (verbose >= 0)
          _cupsLangPrintf(stdout,
                          _("      **FAIL**  Option names %s and %s differ only "
-                           "by case!\n"),
+                           "by case\n"),
                          optiona->keyword, optionb->keyword);
 
        errors ++;
@@ -2222,7 +2253,7 @@ check_case(ppd_file_t *ppd,               /* I - PPD file */
          if (verbose >= 0)
            _cupsLangPrintf(stdout,
                            _("      **FAIL**  Multiple occurrences of %s "
-                             "choice name %s!\n"),
+                             "choice name %s\n"),
                            optiona->keyword, choicea->choice);
 
          errors ++;
@@ -2239,7 +2270,7 @@ check_case(ppd_file_t *ppd,               /* I - PPD file */
          if (verbose >= 0)
            _cupsLangPrintf(stdout,
                            _("      **FAIL**  %s choice names %s and %s "
-                             "differ only by case!\n"),
+                             "differ only by case\n"),
                            optiona->keyword, choicea->choice, choiceb->choice);
 
          errors ++;
@@ -2307,7 +2338,7 @@ check_defaults(ppd_file_t *ppd,           /* I - PPD file */
 
          if (verbose >= 0)
            _cupsLangPrintf(stdout,
-                           _("      %s  %s %s does not exist!\n"),
+                           _("      %s  %s %s does not exist\n"),
                            prefix, attr->name, attr->value);
 
           if (!warn)
@@ -2354,7 +2385,7 @@ check_duplex(ppd_file_t *ppd,             /* I - PPD file */
 
        _cupsLangPrintf(stdout,
                        _("      %s  REQUIRED %s does not define "
-                         "choice None!\n"
+                         "choice None\n"
                          "                REF: Page 122, section 5.17\n"),
                        prefix, option->keyword);
       }
@@ -2377,7 +2408,7 @@ check_duplex(ppd_file_t *ppd,             /* I - PPD file */
            _cupsLangPuts(stdout, _(" FAIL\n"));
 
          _cupsLangPrintf(stdout,
-                         _("      %s  Bad %s choice %s!\n"
+                         _("      %s  Bad %s choice %s\n"
                            "                REF: Page 122, section 5.17\n"),
                          prefix, option->keyword, choice->choice);
        }
@@ -2411,6 +2442,7 @@ check_filters(ppd_file_t *ppd,            /* I - PPD file */
                pathprog[1024];         /* Complete path to program/filter */
   int          cost;                   /* Cost of filter */
   const char   *prefix;                /* WARN/FAIL prefix */
+  struct stat  fileinfo;               /* File information */
 
 
   prefix = warn ? "  WARN  " : "**FAIL**";
@@ -2429,7 +2461,7 @@ check_filters(ppd_file_t *ppd,            /* I - PPD file */
 
       if (verbose >= 0)
        _cupsLangPrintf(stdout,
-                       _("      %s  Bad cupsFilter value \"%s\"!\n"),
+                       _("      %s  Bad cupsFilter value \"%s\"\n"),
                        prefix, ppd->filters[i]);
 
       if (!warn)
@@ -2452,14 +2484,28 @@ check_filters(ppd_file_t *ppd,          /* I - PPD file */
                   program);
       }
 
-      if (access(pathprog, X_OK))
+      if (stat(pathprog, &fileinfo))
       {
        if (!warn && !errors && !verbose)
          _cupsLangPuts(stdout, _(" FAIL\n"));
 
        if (verbose >= 0)
          _cupsLangPrintf(stdout, _("      %s  Missing cupsFilter "
-                                   "file \"%s\"\n"), prefix, program);
+                                   "file \"%s\"\n"), prefix, pathprog);
+
+       if (!warn)
+         errors ++;
+      }
+      else if (fileinfo.st_uid != 0 ||
+               (fileinfo.st_mode & MODE_WRITE) ||
+              (fileinfo.st_mode & MODE_MASK) != MODE_PROGRAM)
+      {
+       if (!warn && !errors && !verbose)
+         _cupsLangPuts(stdout, _(" FAIL\n"));
+
+       if (verbose >= 0)
+         _cupsLangPrintf(stdout, _("      %s  Bad permissions on cupsFilter "
+                                   "file \"%s\"\n"), prefix, pathprog);
 
        if (!warn)
          errors ++;
@@ -2484,7 +2530,7 @@ check_filters(ppd_file_t *ppd,            /* I - PPD file */
 
       if (verbose >= 0)
        _cupsLangPrintf(stdout,
-                       _("      %s  Bad spelling of %s - should be %s!\n"),
+                       _("      %s  Bad spelling of %s - should be %s\n"),
                        prefix, attr->name, "cupsPreFilter");
 
       if (!warn)
@@ -2500,7 +2546,7 @@ check_filters(ppd_file_t *ppd,            /* I - PPD file */
 
       if (verbose >= 0)
        _cupsLangPrintf(stdout,
-                       _("      %s  Bad cupsPreFilter value \"%s\"!\n"),
+                       _("      %s  Bad cupsPreFilter value \"%s\"\n"),
                        prefix, attr->value ? attr->value : "");
 
       if (!warn)
@@ -2523,18 +2569,33 @@ check_filters(ppd_file_t *ppd,          /* I - PPD file */
                   program);
       }
 
-      if (access(pathprog, X_OK))
+      if (stat(pathprog, &fileinfo))
       {
        if (!warn && !errors && !verbose)
          _cupsLangPuts(stdout, _(" FAIL\n"));
 
        if (verbose >= 0)
          _cupsLangPrintf(stdout, _("      %s  Missing cupsPreFilter "
-                                   "file \"%s\"\n"), prefix, program);
+                                   "file \"%s\"\n"), prefix, pathprog);
 
         if (!warn)
          errors ++;
       }
+      else if (fileinfo.st_uid != 0 ||
+               (fileinfo.st_mode & MODE_WRITE) ||
+              (fileinfo.st_mode & MODE_MASK) != MODE_PROGRAM)
+      {
+       if (!warn && !errors && !verbose)
+         _cupsLangPuts(stdout, _(" FAIL\n"));
+
+       if (verbose >= 0)
+         _cupsLangPrintf(stdout, _("      %s  Bad permissions on "
+                                   "cupsPreFilter file \"%s\"\n"), prefix,
+                         pathprog);
+
+       if (!warn)
+         errors ++;
+      }
       else
         errors = valid_path("cupsPreFilter", pathprog, errors, verbose, warn);
     }
@@ -2556,14 +2617,17 @@ check_filters(ppd_file_t *ppd,          /* I - PPD file */
 
       if (verbose >= 0)
        _cupsLangPrintf(stdout,
-                       _("      %s  Bad spelling of %s - should be %s!\n"),
+                       _("      %s  Bad spelling of %s - should be %s\n"),
                        prefix, attr->name, "APDialogExtension");
 
       if (!warn)
         errors ++;
     }
+    
+    snprintf(pathprog, sizeof(pathprog), "%s%s", root,
+             attr->value ? attr->value : "(null)");
 
-    if (!attr->value || access(attr->value, 0))
+    if (!attr->value || stat(pathprog, &fileinfo))
     {
       if (!warn && !errors && !verbose)
        _cupsLangPuts(stdout, _(" FAIL\n"));
@@ -2571,13 +2635,28 @@ check_filters(ppd_file_t *ppd,          /* I - PPD file */
       if (verbose >= 0)
        _cupsLangPrintf(stdout, _("      %s  Missing "
                                  "APDialogExtension file \"%s\"\n"),
-                       prefix, attr->value ? attr->value : "<NULL>");
+                       prefix, pathprog);
+
+      if (!warn)
+       errors ++;
+    }
+    else if (fileinfo.st_uid != 0 ||
+            (fileinfo.st_mode & MODE_WRITE) ||
+            (fileinfo.st_mode & MODE_MASK) != MODE_DIRECTORY)
+    {
+      if (!warn && !errors && !verbose)
+       _cupsLangPuts(stdout, _(" FAIL\n"));
+
+      if (verbose >= 0)
+       _cupsLangPrintf(stdout, _("      %s  Bad permissions on "
+                                 "APDialogExtension file \"%s\"\n"), prefix,
+                       pathprog);
 
       if (!warn)
        errors ++;
     }
     else
-      errors = valid_path("APDialogExtension", attr->value, errors, verbose,
+      errors = valid_path("APDialogExtension", pathprog, errors, verbose,
                           warn);
   }
 
@@ -2594,14 +2673,17 @@ check_filters(ppd_file_t *ppd,          /* I - PPD file */
 
       if (verbose >= 0)
        _cupsLangPrintf(stdout,
-                       _("      %s  Bad spelling of %s - should be %s!\n"),
+                       _("      %s  Bad spelling of %s - should be %s\n"),
                        prefix, attr->name, "APPrinterIconPath");
 
       if (!warn)
         errors ++;
     }
 
-    if (!attr->value || access(attr->value, 0))
+    snprintf(pathprog, sizeof(pathprog), "%s%s", root,
+             attr->value ? attr->value : "(null)");
+
+    if (!attr->value || stat(pathprog, &fileinfo))
     {
       if (!warn && !errors && !verbose)
        _cupsLangPuts(stdout, _(" FAIL\n"));
@@ -2609,13 +2691,28 @@ check_filters(ppd_file_t *ppd,          /* I - PPD file */
       if (verbose >= 0)
        _cupsLangPrintf(stdout, _("      %s  Missing "
                                  "APPrinterIconPath file \"%s\"\n"),
-                       prefix, attr->value ? attr->value : "<NULL>");
+                       prefix, pathprog);
+
+      if (!warn)
+       errors ++;
+    }
+    else if (fileinfo.st_uid != 0 ||
+            (fileinfo.st_mode & MODE_WRITE) ||
+            (fileinfo.st_mode & MODE_MASK) != MODE_DATAFILE)
+    {
+      if (!warn && !errors && !verbose)
+       _cupsLangPuts(stdout, _(" FAIL\n"));
+
+      if (verbose >= 0)
+       _cupsLangPrintf(stdout, _("      %s  Bad permissions on "
+                                 "APPrinterIconPath file \"%s\"\n"), prefix,
+                       pathprog);
 
       if (!warn)
        errors ++;
     }
     else
-      errors = valid_path("APPrinterIconPath", attr->value, errors, verbose,
+      errors = valid_path("APPrinterIconPath", pathprog, errors, verbose,
                           warn);
   }
 
@@ -2632,14 +2729,17 @@ check_filters(ppd_file_t *ppd,          /* I - PPD file */
 
       if (verbose >= 0)
        _cupsLangPrintf(stdout,
-                       _("      %s  Bad spelling of %s - should be %s!\n"),
+                       _("      %s  Bad spelling of %s - should be %s\n"),
                        prefix, attr->name, "APPrinterLowInkTool");
 
       if (!warn)
         errors ++;
     }
 
-    if (!attr->value || access(attr->value, 0))
+    snprintf(pathprog, sizeof(pathprog), "%s%s", root,
+             attr->value ? attr->value : "(null)");
+
+    if (!attr->value || stat(pathprog, &fileinfo))
     {
       if (!warn && !errors && !verbose)
        _cupsLangPuts(stdout, _(" FAIL\n"));
@@ -2647,13 +2747,28 @@ check_filters(ppd_file_t *ppd,          /* I - PPD file */
       if (verbose >= 0)
        _cupsLangPrintf(stdout, _("      %s  Missing "
                                  "APPrinterLowInkTool file \"%s\"\n"),
-                       prefix, attr->value ? attr->value : "<NULL>");
+                       prefix, pathprog);
+
+      if (!warn)
+       errors ++;
+    }
+    else if (fileinfo.st_uid != 0 ||
+            (fileinfo.st_mode & MODE_WRITE) ||
+            (fileinfo.st_mode & MODE_MASK) != MODE_DIRECTORY)
+    {
+      if (!warn && !errors && !verbose)
+       _cupsLangPuts(stdout, _(" FAIL\n"));
+
+      if (verbose >= 0)
+       _cupsLangPrintf(stdout, _("      %s  Bad permissions on "
+                                 "APPrinterLowInkTool file \"%s\"\n"), prefix,
+                       pathprog);
 
       if (!warn)
        errors ++;
     }
     else
-      errors = valid_path("APPrinterLowInkTool", attr->value, errors, verbose,
+      errors = valid_path("APPrinterLowInkTool", pathprog, errors, verbose,
                           warn);
   }
 
@@ -2670,14 +2785,17 @@ check_filters(ppd_file_t *ppd,          /* I - PPD file */
 
       if (verbose >= 0)
        _cupsLangPrintf(stdout,
-                       _("      %s  Bad spelling of %s - should be %s!\n"),
+                       _("      %s  Bad spelling of %s - should be %s\n"),
                        prefix, attr->name, "APPrinterUtilityPath");
 
       if (!warn)
         errors ++;
     }
 
-    if (!attr->value || access(attr->value, 0))
+    snprintf(pathprog, sizeof(pathprog), "%s%s", root,
+             attr->value ? attr->value : "(null)");
+
+    if (!attr->value || stat(pathprog, &fileinfo))
     {
       if (!warn && !errors && !verbose)
        _cupsLangPuts(stdout, _(" FAIL\n"));
@@ -2685,13 +2803,28 @@ check_filters(ppd_file_t *ppd,          /* I - PPD file */
       if (verbose >= 0)
        _cupsLangPrintf(stdout, _("      %s  Missing "
                                  "APPrinterUtilityPath file \"%s\"\n"),
-                       prefix, attr->value ? attr->value : "<NULL>");
+                       prefix, pathprog);
+
+      if (!warn)
+       errors ++;
+    }
+    else if (fileinfo.st_uid != 0 ||
+            (fileinfo.st_mode & MODE_WRITE) ||
+            (fileinfo.st_mode & MODE_MASK) != MODE_DIRECTORY)
+    {
+      if (!warn && !errors && !verbose)
+       _cupsLangPuts(stdout, _(" FAIL\n"));
+
+      if (verbose >= 0)
+       _cupsLangPrintf(stdout, _("      %s  Bad permissions on "
+                                 "APPrinterUtilityPath file \"%s\"\n"), prefix,
+                       pathprog);
 
       if (!warn)
        errors ++;
     }
     else
-      errors = valid_path("APPrinterUtilityPath", attr->value, errors, verbose,
+      errors = valid_path("APPrinterUtilityPath", pathprog, errors, verbose,
                           warn);
   }
 
@@ -2708,14 +2841,14 @@ check_filters(ppd_file_t *ppd,          /* I - PPD file */
 
       if (verbose >= 0)
        _cupsLangPrintf(stdout,
-                       _("      %s  Bad spelling of %s - should be %s!\n"),
+                       _("      %s  Bad spelling of %s - should be %s\n"),
                        prefix, attr->name, "APScanAppPath");
 
       if (!warn)
         errors ++;
     }
 
-    if (!attr->value || access(attr->value, 0))
+    if (!attr->value || stat(attr->value, &fileinfo))
     {
       if (!warn && !errors && !verbose)
        _cupsLangPuts(stdout, _(" FAIL\n"));
@@ -2728,6 +2861,21 @@ check_filters(ppd_file_t *ppd,           /* I - PPD file */
       if (!warn)
        errors ++;
     }
+    else if (fileinfo.st_uid != 0 ||
+            (fileinfo.st_mode & MODE_WRITE) ||
+            (fileinfo.st_mode & MODE_MASK) != MODE_DIRECTORY)
+    {
+      if (!warn && !errors && !verbose)
+       _cupsLangPuts(stdout, _(" FAIL\n"));
+
+      if (verbose >= 0)
+       _cupsLangPrintf(stdout, _("      %s  Bad permissions on "
+                                 "APScanAppPath file \"%s\"\n"), prefix,
+                       attr->value);
+
+      if (!warn)
+       errors ++;
+    }
     else
       errors = valid_path("APScanAppPath", attr->value, errors, verbose,
                           warn);
@@ -2739,7 +2887,7 @@ check_filters(ppd_file_t *ppd,            /* I - PPD file */
 
       if (verbose >= 0)
        _cupsLangPrintf(stdout, _("      %s  Cannot provide both "
-                                 "APScanAppPath and APScanAppBundleID!\n"),
+                                 "APScanAppPath and APScanAppBundleID\n"),
                        prefix);
 
       if (!warn)
@@ -2768,6 +2916,7 @@ check_profiles(ppd_file_t *ppd,           /* I - PPD file */
   const char   *ptr;                   /* Pointer into string */
   const char   *prefix;                /* WARN/FAIL prefix */
   char         filename[1024];         /* Profile filename */
+  struct stat  fileinfo;               /* File information */
   int          num_profiles = 0;       /* Number of profiles */
   unsigned     hash,                   /* Current hash value */
                hashes[1000];           /* Hash values of profile names */
@@ -2794,7 +2943,7 @@ check_profiles(ppd_file_t *ppd,           /* I - PPD file */
 
       if (verbose >= 0)
        _cupsLangPrintf(stdout,
-                       _("      %s  Bad cupsICCProfile %s!\n"),
+                       _("      %s  Bad cupsICCProfile %s\n"),
                        prefix, attr->spec);
 
       if (!warn)
@@ -2822,14 +2971,29 @@ check_profiles(ppd_file_t *ppd,         /* I - PPD file */
                 attr->value);
     }
 
-    if (access(filename, 0))
+    if (stat(filename, &fileinfo))
     {
       if (!warn && !errors && !verbose)
        _cupsLangPuts(stdout, _(" FAIL\n"));
 
       if (verbose >= 0)
        _cupsLangPrintf(stdout, _("      %s  Missing cupsICCProfile "
-                                 "file \"%s\"!\n"), prefix, attr->value);
+                                 "file \"%s\"\n"), prefix, filename);
+
+      if (!warn)
+       errors ++;
+    }
+    else if (fileinfo.st_uid != 0 ||
+            (fileinfo.st_mode & MODE_WRITE) ||
+            (fileinfo.st_mode & MODE_MASK) != MODE_DATAFILE)
+    {
+      if (!warn && !errors && !verbose)
+       _cupsLangPuts(stdout, _(" FAIL\n"));
+
+      if (verbose >= 0)
+       _cupsLangPrintf(stdout, _("      %s  Bad permissions on "
+                                 "cupsICCProfile file \"%s\"\n"), prefix,
+                       filename);
 
       if (!warn)
        errors ++;
@@ -2857,7 +3021,7 @@ check_profiles(ppd_file_t *ppd,           /* I - PPD file */
        if (verbose >= 0)
          _cupsLangPrintf(stdout,
                          _("      %s  cupsICCProfile %s hash value "
-                           "collides with %s!\n"), prefix, attr->spec,
+                           "collides with %s\n"), prefix, attr->spec,
                          specs[i]);
 
        if (!warn)
@@ -2911,7 +3075,7 @@ check_sizes(ppd_file_t *ppd,              /* I - PPD file */
 
     if (verbose >= 0)
       _cupsLangPrintf(stdout,
-                     _("      %s  Missing REQUIRED PageSize option!\n"
+                     _("      %s  Missing REQUIRED PageSize option\n"
                        "                REF: Page 99, section 5.14.\n"),
                      prefix);
 
@@ -2926,7 +3090,7 @@ check_sizes(ppd_file_t *ppd,              /* I - PPD file */
 
     if (verbose >= 0)
       _cupsLangPrintf(stdout,
-                     _("      %s  Missing REQUIRED PageRegion option!\n"
+                     _("      %s  Missing REQUIRED PageRegion option\n"
                        "                REF: Page 100, section 5.14.\n"),
                      prefix);
 
@@ -2965,7 +3129,7 @@ check_sizes(ppd_file_t *ppd,              /* I - PPD file */
        if (verbose >= 0)
          _cupsLangPrintf(stdout,
                          _("      %s  Size \"%s\" has unexpected dimensions "
-                           "(%gx%g)!\n"),
+                           "(%gx%g)\n"),
                          prefix, size->name, size->width, size->length);
 
        if (!warn)
@@ -2989,7 +3153,7 @@ check_sizes(ppd_file_t *ppd,              /* I - PPD file */
                   (int (*)(const void *, const void *))strcmp))
       {
        _cupsLangPrintf(stdout,
-                       _("      %s  Non-standard size name \"%s\"!\n"
+                       _("      %s  Non-standard size name \"%s\"\n"
                          "                REF: Page 187, section B.2.\n"),
                        prefix, size->name);
       }
@@ -3007,7 +3171,7 @@ check_sizes(ppd_file_t *ppd,              /* I - PPD file */
       if (verbose >= 0)
        _cupsLangPrintf(stdout,
                        _("      %s  Size \"%s\" defined for %s but not for "
-                         "%s!\n"),
+                         "%s\n"),
                        prefix, size->name, "PageRegion", "PageSize");
 
       if (!warn)
@@ -3021,7 +3185,7 @@ check_sizes(ppd_file_t *ppd,              /* I - PPD file */
       if (verbose >= 0)
        _cupsLangPrintf(stdout,
                        _("      %s  Size \"%s\" defined for %s but not for "
-                         "%s!\n"),
+                         "%s\n"),
                        prefix, size->name, "PageSize", "PageRegion");
 
       if (!warn)
@@ -3081,7 +3245,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
 
        if (verbose >= 0)
          _cupsLangPrintf(stdout,
-                         _("      %s  Bad language \"%s\"!\n"),
+                         _("      %s  Bad language \"%s\"\n"),
                          prefix, language);
 
        if (!warn)
@@ -3118,7 +3282,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
          if (verbose >= 0)
            _cupsLangPrintf(stdout,
                            _("      %s  Missing \"%s\" translation "
-                             "string for option %s!\n"),
+                             "string for option %s\n"),
                            prefix, language, option->keyword);
 
           if (!warn)
@@ -3132,7 +3296,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
          if (verbose >= 0)
            _cupsLangPrintf(stdout,
                            _("      %s  Bad UTF-8 \"%s\" translation "
-                             "string for option %s!\n"),
+                             "string for option %s\n"),
                            prefix, language, option->keyword);
 
          if (!warn)
@@ -3179,7 +3343,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
                _cupsLangPrintf(stdout,
                                _("      %s  Bad UTF-8 \"%s\" "
                                  "translation string for option %s, "
-                                 "choice %s!\n"),
+                                 "choice %s\n"),
                                prefix, language,
                                ckeyword + 1 + strlen(language),
                                "True");
@@ -3211,7 +3375,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
                    _cupsLangPrintf(stdout,
                                    _("      %s  Missing \"%s\" "
                                      "translation string for option %s, "
-                                     "choice %s!\n"),
+                                     "choice %s\n"),
                                    prefix, language,
                                    ckeyword + 1 + strlen(language),
                                    cparam->name);
@@ -3228,7 +3392,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
                    _cupsLangPrintf(stdout,
                                    _("      %s  Bad UTF-8 \"%s\" "
                                      "translation string for option %s, "
-                                     "choice %s!\n"),
+                                     "choice %s\n"),
                                    prefix, language,
                                    ckeyword + 1 + strlen(language),
                                    cparam->name);
@@ -3251,7 +3415,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
              _cupsLangPrintf(stdout,
                              _("      %s  Missing \"%s\" "
                                "translation string for option %s, "
-                               "choice %s!\n"),
+                               "choice %s\n"),
                              prefix, language, option->keyword,
                              option->choices[j].choice);
 
@@ -3267,7 +3431,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
              _cupsLangPrintf(stdout,
                              _("      %s  Bad UTF-8 \"%s\" "
                                "translation string for option %s, "
-                               "choice %s!\n"),
+                               "choice %s\n"),
                              prefix, language, option->keyword,
                              option->choices[j].choice);
 
@@ -3304,7 +3468,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
          if (verbose >= 0)
            _cupsLangPrintf(stdout,
                            _("      %s  No base translation \"%s\" "
-                             "is included in file!\n"), prefix, ll);
+                             "is included in file\n"), prefix, ll);
 
          if (!warn)
            errors ++;
@@ -3489,6 +3653,8 @@ usage(void)
                  "\n"
                  "Options:\n"
                  "\n"
+                 "    -I {filters,profiles}\n"
+                 "                         Ignore missing files\n"
                  "    -R root-directory    Set alternate root\n"
                  "    -W {all,none,constraints,defaults,duplex,filters,"
                  "profiles,sizes,translations}\n"
@@ -3572,7 +3738,7 @@ valid_path(const char *keyword,           /* I - Keyword using path */
       if (verbose >= 0)
        _cupsLangPrintf(stdout,
                        _("      %s  %s file \"%s\" has the wrong "
-                         "capitalization!\n"), prefix, keyword, path);
+                         "capitalization\n"), prefix, keyword, path);
 
       if (!warn)
        errors ++;