]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - berkeley/lpr.c
SIGSEGV in CUPS web ui when adding a printer
[thirdparty/cups.git] / berkeley / lpr.c
index 4b8957ffe1d172f2851c95c255c0a8e4ce7fd9a5..a9aed3ca4007cbfaecfccbe7613e05b993c605c8 100644 (file)
@@ -1,20 +1,11 @@
 /*
- * "$Id$"
+ * "lpr" command for CUPS.
  *
- *   "lpr" command for CUPS.
+ * Copyright © 2007-2018 by Apple Inc.
+ * Copyright © 1997-2007 by Easy Software Products.
  *
- *   Copyright 2007-2013 by Apple Inc.
- *   Copyright 1997-2007 by Easy Software Products.
- *
- *   These coded instructions, statements, and computer programs are the
- *   property of Apple Inc. and are protected by Federal copyright
- *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
- *   which should have been included with this file.  If this file is
- *   file is missing or damaged, see the license at "http://www.cups.org/".
- *
- * Contents:
- *
- *   main() - Parse options and send files for printing.
+ * Licensed under Apache License v2.0.  See the file "LICENSE" for more
+ * information.
  */
 
 /*
 #include <cups/cups-private.h>
 
 
+/*
+ * Local functions...
+ */
+
+static void    usage(void) _CUPS_NORETURN;
+
+
 /*
  * 'main()' - Parse options and send files for printing.
  */
@@ -36,9 +34,9 @@ main(int  argc,                               /* I - Number of command-line arguments */
   int          job_id;                 /* Job ID */
   char         ch;                     /* Option character */
   char         *printer,               /* Destination printer or class */
-               *instance;              /* Instance */
-  const char   *title,                 /* Job title */
-               *val;                   /* Environment variable name */
+               *instance,              /* Instance */
+               *opt;                   /* Option pointer */
+  const char   *title;                 /* Job title */
   int          num_copies;             /* Number of copies per file */
   int          num_files;              /* Number of files to print */
   const char   *files[1000];           /* Files to print */
@@ -60,229 +58,237 @@ main(int  argc,                           /* I - Number of command-line arguments */
   title       = NULL;
 
   for (i = 1; i < argc; i ++)
-    if (argv[i][0] == '-')
+  {
+    if (!strcmp(argv[i], "--help"))
+      usage();
+    else if (argv[i][0] == '-')
     {
-      switch (ch = argv[i][1])
+      for (opt = argv[i] + 1; *opt; opt ++)
       {
-        case 'E' : /* Encrypt */
+       switch (ch = *opt)
+       {
+         case 'E' : /* Encrypt */
 #ifdef HAVE_SSL
-           cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
+             cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
 #else
-            _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."),
-                           argv[0]);
+             _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), argv[0]);
 #endif /* HAVE_SSL */
-           break;
-
-        case 'U' : /* Username */
-           if (argv[i][2] != '\0')
-             cupsSetUser(argv[i] + 2);
-           else
-           {
-             i ++;
-             if (i >= argc)
+             break;
+
+         case 'U' : /* Username */
+             if (opt[1] != '\0')
              {
-               _cupsLangPrintf(stderr,
-                               _("%s: Error - expected username after "
-                                 "\"-U\" option."), argv[0]);
-               return (1);
+               cupsSetUser(opt + 1);
+               opt += strlen(opt) - 1;
              }
+             else
+             {
+               i ++;
+               if (i >= argc)
+               {
+                 _cupsLangPrintf(stderr, _("%s: Error - expected username after \"-U\" option."), argv[0]);
+                 usage();
+               }
+
+               cupsSetUser(argv[i]);
+             }
+             break;
 
-              cupsSetUser(argv[i]);
-           }
-           break;
-
-        case 'H' : /* Connect to host */
-           if (argv[i][2] != '\0')
-              cupsSetServer(argv[i] + 2);
-           else
-           {
-             i ++;
+         case 'H' : /* Connect to host */
+             if (opt[1] != '\0')
+             {
+               cupsSetServer(opt + 1);
+               opt += strlen(opt) - 1;
+             }
+             else
+             {
+               i ++;
+
+               if (i >= argc)
+               {
+                 _cupsLangPrintf(stderr, _("%s: Error - expected hostname after \"-H\" option."), argv[0]);
+                 usage();
+               }
+               else
+                 cupsSetServer(argv[i]);
+             }
+             break;
+
+         case '1' : /* TROFF font set 1 */
+         case '2' : /* TROFF font set 2 */
+         case '3' : /* TROFF font set 3 */
+         case '4' : /* TROFF font set 4 */
+         case 'i' : /* indent */
+         case 'w' : /* width */
+             if (opt[1] != '\0')
+             {
+               opt += strlen(opt) - 1;
+             }
+             else
+             {
+               i ++;
+
+               if (i >= argc)
+               {
+                 _cupsLangPrintf(stderr,
+                                 _("%s: Error - expected value after \"-%c\" "
+                                   "option."), argv[0], ch);
+                 usage();
+               }
+             }
 
-             if (i >= argc)
+         case 'c' : /* CIFPLOT */
+         case 'd' : /* DVI */
+         case 'f' : /* FORTRAN */
+         case 'g' : /* plot */
+         case 'n' : /* Ditroff */
+         case 't' : /* Troff */
+         case 'v' : /* Raster image */
+             _cupsLangPrintf(stderr, _("%s: Warning - \"%c\" format modifier not supported - output may not be correct."), argv[0], ch);
+             break;
+
+         case 'o' : /* Option */
+             if (opt[1] != '\0')
              {
-               _cupsLangPrintf(stderr,
-                               _("%s: Error - expected hostname after "
-                                 "\"-H\" option."), argv[0]);
-               return (1);
-              }
+               num_options = cupsParseOptions(opt + 1, num_options, &options);
+               opt += strlen(opt) - 1;
+             }
              else
-                cupsSetServer(argv[i]);
-           }
-           break;
-
-       case '1' : /* TROFF font set 1 */
-       case '2' : /* TROFF font set 2 */
-       case '3' : /* TROFF font set 3 */
-       case '4' : /* TROFF font set 4 */
-       case 'i' : /* indent */
-       case 'w' : /* width */
-           if (argv[i][2] == '\0')
-           {
-             i ++;
-
-             if (i >= argc)
              {
-               _cupsLangPrintf(stderr,
-                               _("%s: Error - expected value after \"-%c\" "
-                                 "option."), argv[0], ch);
-               return (1);
+               i ++;
+               if (i >= argc)
+               {
+                 _cupsLangPrintf(stderr, _("%s: Error - expected option=value after \"-o\" option."), argv[0]);
+                 usage();
+               }
+
+               num_options = cupsParseOptions(argv[i], num_options, &options);
              }
-           }
-
-        case 'c' : /* CIFPLOT */
-       case 'd' : /* DVI */
-       case 'f' : /* FORTRAN */
-       case 'g' : /* plot */
-       case 'n' : /* Ditroff */
-       case 't' : /* Troff */
-       case 'v' : /* Raster image */
-           _cupsLangPrintf(stderr,
-                           _("%s: Warning - \"%c\" format modifier not "
-                             "supported - output may not be correct."),
-                           argv[0], ch);
-           break;
-
-       case 'o' : /* Option */
-           if (argv[i][2] != '\0')
-             num_options = cupsParseOptions(argv[i] + 2, num_options, &options);
-           else
-           {
-             i ++;
-             if (i >= argc)
+             break;
+
+         case 'l' : /* Literal/raw */
+             num_options = cupsAddOption("raw", "true", num_options, &options);
+             break;
+
+         case 'p' : /* Prettyprint */
+             num_options = cupsAddOption("prettyprint", "true", num_options, &options);
+             break;
+
+         case 'h' : /* Suppress burst page */
+             num_options = cupsAddOption("job-sheets", "none", num_options, &options);
+             break;
+
+         case 's' : /* Don't use symlinks */
+             break;
+
+         case 'm' : /* Mail on completion */
              {
-               _cupsLangPrintf(stderr,
-                               _("%s: Error - expected option=value after "
-                                 "\"-o\" option."), argv[0]);
-               return (1);
+               char    email[1024];    /* EMail address */
+
+               snprintf(email, sizeof(email), "mailto:%s@%s", cupsUser(), httpGetHostname(NULL, buffer, sizeof(buffer)));
+               num_options = cupsAddOption("notify-recipient-uri", email, num_options, &options);
              }
+             break;
 
-             num_options = cupsParseOptions(argv[i], num_options, &options);
-           }
-           break;
-
-       case 'l' : /* Literal/raw */
-            num_options = cupsAddOption("raw", "true", num_options, &options);
-           break;
-
-       case 'p' : /* Prettyprint */
-            num_options = cupsAddOption("prettyprint", "true", num_options,
-                                       &options);
-           break;
-
-       case 'h' : /* Suppress burst page */
-            num_options = cupsAddOption("job-sheets", "none", num_options,
-                                       &options);
-           break;
-
-       case 's' : /* Don't use symlinks */
-           break;
-
-       case 'm' : /* Mail on completion */
-           {
-             char      email[1024];    /* EMail address */
-
-
-             snprintf(email, sizeof(email), "mailto:%s@%s", cupsUser(),
-                      httpGetHostname(NULL, buffer, sizeof(buffer)));
-             num_options = cupsAddOption("notify-recipient-uri", email,
-                                         num_options, &options);
-           }
-           break;
-
-       case 'q' : /* Queue file but don't print */
-            num_options = cupsAddOption("job-hold-until", "indefinite",
-                                       num_options, &options);
-           break;
-
-       case 'r' : /* Remove file after printing */
-           deletefile = 1;
-           break;
-
-        case 'P' : /* Destination printer or class */
-           if (argv[i][2] != '\0')
-             printer = argv[i] + 2;
-           else
-           {
-             i ++;
-             if (i >= argc)
+         case 'q' : /* Queue file but don't print */
+             num_options = cupsAddOption("job-hold-until", "indefinite", num_options, &options);
+             break;
+
+         case 'r' : /* Remove file after printing */
+             deletefile = 1;
+             break;
+
+         case 'P' : /* Destination printer or class */
+             if (opt[1] != '\0')
              {
-               _cupsLangPrintf(stderr,
-                               _("%s: Error - expected destination after "
-                                 "\"-P\" option."), argv[0]);
-               return (1);
+               printer = opt + 1;
+               opt += strlen(opt) - 1;
+             }
+             else
+             {
+               i ++;
+               if (i >= argc)
+               {
+                 _cupsLangPrintf(stderr, _("%s: Error - expected destination after \"-P\" option."), argv[0]);
+                 usage();
+               }
+
+               printer = argv[i];
              }
 
-             printer = argv[i];
-           }
-
-            if ((instance = strrchr(printer, '/')) != NULL)
-             *instance++ = '\0';
-
-            if ((dest = cupsGetNamedDest(NULL, printer, instance)) != NULL)
-           {
-             for (j = 0; j < dest->num_options; j ++)
-               if (cupsGetOption(dest->options[j].name, num_options,
-                                 options) == NULL)
-                 num_options = cupsAddOption(dest->options[j].name,
-                                             dest->options[j].value,
-                                             num_options, &options);
-           }
-           else if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
-                    cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
-           {
-             _cupsLangPrintf(stderr,
-                             _("%s: Error - add '/version=1.1' to server "
-                               "name."), argv[0]);
-             return (1);
-           }
-           break;
-
-       case '#' : /* Number of copies */
-           if (argv[i][2] != '\0')
-             num_copies = atoi(argv[i] + 2);
-           else
-           {
-             i ++;
-             if (i >= argc)
+             if ((instance = strrchr(printer, '/')) != NULL)
+               *instance++ = '\0';
+
+             if ((dest = cupsGetNamedDest(NULL, printer, instance)) != NULL)
+             {
+               for (j = 0; j < dest->num_options; j ++)
+                 if (cupsGetOption(dest->options[j].name, num_options,
+                                   options) == NULL)
+                   num_options = cupsAddOption(dest->options[j].name,
+                                               dest->options[j].value,
+                                               num_options, &options);
+             }
+             else if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
+                      cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
              {
-               _cupsLangPrintf(stderr,
-                               _("%s: Error - expected copies after "
-                                 "\"-#\" option."), argv[0]);
+               _cupsLangPrintf(stderr, _("%s: Error - add '/version=1.1' to server name."), argv[0]);
                return (1);
              }
+             break;
 
-             num_copies = atoi(argv[i]);
-           }
-
-            sprintf(buffer, "%d", num_copies);
-            num_options = cupsAddOption("copies", buffer, num_options, &options);
-           break;
-
-       case 'C' : /* Class */
-       case 'J' : /* Job name */
-       case 'T' : /* Title */
-           if (argv[i][2] != '\0')
-             title = argv[i] + 2;
-           else
-           {
-             i ++;
-             if (i >= argc)
+         case '#' : /* Number of copies */
+             if (opt[1] != '\0')
              {
-               _cupsLangPrintf(stderr,
-                               _("%s: Error - expected name after \"-%c\" "
-                                 "option."), argv[0], ch);
+               num_copies = atoi(opt + 1);
+               opt += strlen(opt) - 1;
+             }
+             else
+             {
+               i ++;
+               if (i >= argc)
+               {
+                 _cupsLangPrintf(stderr, _("%s: Error - expected copies after \"-#\" option."), argv[0]);
+                 usage();
+               }
+
+               num_copies = atoi(argv[i]);
+             }
+
+             if (num_copies < 1)
+             {
+               _cupsLangPrintf(stderr, _("%s: Error - copies must be 1 or more."), argv[0]);
                return (1);
              }
 
-             title = argv[i];
-           }
-           break;
+             sprintf(buffer, "%d", num_copies);
+             num_options = cupsAddOption("copies", buffer, num_options, &options);
+             break;
 
-       default :
-           _cupsLangPrintf(stderr,
-                           _("%s: Error - unknown option \"%c\"."), argv[0],
-                           argv[i][1]);
-           return (1);
+         case 'C' : /* Class */
+         case 'J' : /* Job name */
+         case 'T' : /* Title */
+             if (opt[1] != '\0')
+             {
+               title = opt + 1;
+               opt += strlen(opt) - 1;
+             }
+             else
+             {
+               i ++;
+               if (i >= argc)
+               {
+                 _cupsLangPrintf(stderr, _("%s: Error - expected name after \"-%c\" option."), argv[0], ch);
+                 usage();
+               }
+
+               title = argv[i];
+             }
+             break;
+
+         default :
+             _cupsLangPrintf(stderr, _("%s: Error - unknown option \"%c\"."), argv[0], *opt);
+             return (1);
+       }
       }
     }
     else if (num_files < 1000)
@@ -311,9 +317,11 @@ main(int  argc,                            /* I - Number of command-line arguments */
       }
     }
     else
-      _cupsLangPrintf(stderr,
-                      _("%s: Error - too many files - \"%s\"."), argv[0],
-                     argv[i]);
+    {
+      _cupsLangPrintf(stderr, _("%s: Error - too many files - \"%s\"."), argv[0], argv[i]);
+    }
+  }
+
  /*
   * See if we have any files to print; if not, print from stdin...
   */
@@ -342,33 +350,10 @@ main(int  argc,                           /* I - Number of command-line arguments */
 
   if (printer == NULL)
   {
-    val = NULL;
-
-    if ((printer = getenv("LPDEST")) == NULL)
-    {
-      if ((printer = getenv("PRINTER")) != NULL)
-      {
-        if (!strcmp(printer, "lp"))
-          printer = NULL;
-       else
-         val = "PRINTER";
-      }
-    }
+    if (!cupsGetNamedDest(NULL, NULL, NULL) && cupsLastError() == IPP_STATUS_ERROR_NOT_FOUND)
+      _cupsLangPrintf(stderr, _("%s: Error - %s"), argv[0], cupsLastErrorString());
     else
-      val = "LPDEST";
-
-    if (printer && !cupsGetNamedDest(NULL, printer, NULL))
-      _cupsLangPrintf(stderr,
-                      _("%s: Error - %s environment variable names "
-                       "non-existent destination \"%s\"."), argv[0], val,
-                     printer);
-    else if (cupsLastError() == IPP_NOT_FOUND)
-      _cupsLangPrintf(stderr,
-                      _("%s: Error - no default destination available."),
-                     argv[0]);
-    else
-      _cupsLangPrintf(stderr, _("%s: Error - scheduler not responding."),
-                     argv[0]);
+      _cupsLangPrintf(stderr, _("%s: Error - scheduler not responding."), argv[0]);
 
     return (1);
   }
@@ -406,7 +391,7 @@ main(int  argc,                             /* I - Number of command-line arguments */
 
     while (status == HTTP_CONTINUE &&
            (bytes = read(0, buffer, sizeof(buffer))) > 0)
-      status = cupsWriteRequestData(CUPS_HTTP_DEFAULT, buffer, bytes);
+      status = cupsWriteRequestData(CUPS_HTTP_DEFAULT, buffer, (size_t)bytes);
 
     if (status != HTTP_CONTINUE)
     {
@@ -436,5 +421,35 @@ main(int  argc,                            /* I - Number of command-line arguments */
 
 
 /*
- * End of "$Id$".
+ * 'usage()' - Show program usage and exit.
  */
+
+static void
+usage(void)
+{
+  _cupsLangPuts(stdout, _("Usage: lpr [options] [file(s)]"));
+  _cupsLangPuts(stdout, _("Options:"));
+  _cupsLangPuts(stdout, _("-# num-copies           Specify the number of copies to print"));
+  _cupsLangPuts(stdout, _("-E                      Encrypt the connection to the server"));
+  _cupsLangPuts(stdout, _("-H server[:port]        Connect to the named server and port"));
+  _cupsLangPuts(stdout, _("-m                      Send an email notification when the job completes"));
+  _cupsLangPuts(stdout, _("-o option[=value]       Specify a printer-specific option"));
+  _cupsLangPuts(stdout, _("-o job-sheets=standard  Print a banner page with the job"));
+  _cupsLangPuts(stdout, _("-o media=size           Specify the media size to use"));
+  _cupsLangPuts(stdout, _("-o number-up=N          Specify that input pages should be printed N-up (1, 2, 4, 6, 9, and 16 are supported)"));
+  _cupsLangPuts(stdout, _("-o orientation-requested=N\n"
+                          "                        Specify portrait (3) or landscape (4) orientation"));
+  _cupsLangPuts(stdout, _("-o print-quality=N      Specify the print quality - draft (3), normal (4), or best (5)"));
+  _cupsLangPuts(stdout, _("-o sides=one-sided      Specify 1-sided printing"));
+  _cupsLangPuts(stdout, _("-o sides=two-sided-long-edge\n"
+                          "                        Specify 2-sided portrait printing"));
+  _cupsLangPuts(stdout, _("-o sides=two-sided-short-edge\n"
+                          "                        Specify 2-sided landscape printing"));
+  _cupsLangPuts(stdout, _("-q                      Specify the job should be held for printing"));
+  _cupsLangPuts(stdout, _("-r                      Remove the file(s) after submission"));
+  _cupsLangPuts(stdout, _("-P destination          Specify the destination"));
+  _cupsLangPuts(stdout, _("-T title                Specify the job title"));
+  _cupsLangPuts(stdout, _("-U username             Specify the username to use for authentication"));
+
+  exit(1);
+}