LCOV - code coverage report
Current view: top level - src - mktemp.c (source / functions) Hit Total Coverage
Test: coreutils.info Lines: 105 107 98.1 %
Date: 2018-01-30 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /* Create a temporary file or directory, safely.
       2             :    Copyright (C) 2007-2008 Free Software Foundation, Inc.
       3             : 
       4             :    This program is free software: you can redistribute it and/or modify
       5             :    it under the terms of the GNU General Public License as published by
       6             :    the Free Software Foundation, either version 3 of the License, or
       7             :    (at your option) any later version.
       8             : 
       9             :    This program is distributed in the hope that it will be useful,
      10             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :    GNU General Public License for more details.
      13             : 
      14             :    You should have received a copy of the GNU General Public License
      15             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
      16             : 
      17             : /* Jim Meyering */
      18             : 
      19             : #include <config.h>
      20             : #include <stdio.h>
      21             : #include <sys/types.h>
      22             : #include <getopt.h>
      23             : 
      24             : #include "system.h"
      25             : 
      26             : #include "error.h"
      27             : #include "filenamecat.h"
      28             : #include "quote.h"
      29             : #include "tempname.h"
      30             : 
      31             : /* The official name of this program (e.g., no `g' prefix).  */
      32             : #define PROGRAM_NAME "mktemp"
      33             : 
      34             : #define AUTHORS "Jim Meyering"
      35             : 
      36             : static const char *default_template = "tmp.XXXXXXXXXX";
      37             : 
      38             : /* The name this program was run with. */
      39             : char *program_name;
      40             : 
      41             : /* For long options that have no equivalent short option, use a
      42             :    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
      43             : enum
      44             : {
      45             :   TMPDIR_OPTION = CHAR_MAX + 1
      46             : };
      47             : 
      48             : static struct option const longopts[] =
      49             : {
      50             :   {"directory", no_argument, NULL, 'd'},
      51             :   {"quiet", no_argument, NULL, 'q'},
      52             :   {"dry-run", no_argument, NULL, 'u'},
      53             :   {"tmpdir", optional_argument, NULL, TMPDIR_OPTION},
      54             :   {GETOPT_HELP_OPTION_DECL},
      55             :   {GETOPT_VERSION_OPTION_DECL},
      56             :   {NULL, 0, NULL, 0}
      57             : };
      58             : 
      59             : void
      60          17 : usage (int status)
      61             : {
      62          17 :   if (status != EXIT_SUCCESS)
      63          16 :     fprintf (stderr, _("Try `%s --help' for more information.\n"),
      64             :              program_name);
      65             :   else
      66             :     {
      67           1 :       printf (_("Usage: %s [OPTION]... [TEMPLATE]\n"), program_name);
      68           1 :       fputs (_("\
      69             : Create a temporary file or directory, safely, and print its name.\n\
      70             : If TEMPLATE is not specified, use tmp.XXXXXXXXXX.\n\
      71             : "), stdout);
      72           1 :       fputs ("\n", stdout);
      73           1 :       fputs (_("\
      74             :   -d, --directory  create a directory, not a file\n\
      75             : "), stdout);
      76           1 :       fputs (_("\
      77             :   -q, --quiet      suppress diagnostics about file/dir-creation failure\n\
      78             : "), stdout);
      79           1 :       fputs (_("\
      80             :   -u, --dry-run    do not create anything; merely print a name (unsafe)\n\
      81             : "), stdout);
      82           1 :       fputs (_("\
      83             :   --tmpdir[=DIR]   interpret TEMPLATE relative to DIR.  If DIR is\n\
      84             :                      not specified, use $TMPDIR if set, else /tmp.\n\
      85             :                      With this option, TEMPLATE must not be an absolute name.\n\
      86             :                      Unlike with -t, TEMPLATE may contain slashes, but even\n\
      87             :                      here, mktemp still creates only the final component.\n\
      88             : "), stdout);
      89           1 :       fputs ("\n", stdout);
      90           1 :       fputs (_("\
      91             :   -p DIR           use DIR as a prefix; implies -t [deprecated]\n\
      92             : "), stdout);
      93           1 :       fputs (_("\
      94             :   -t               interpret TEMPLATE as a single file name component,\n\
      95             :                      relative to a directory: $TMPDIR, if set; else the\n\
      96             :                      directory specified via -p; else /tmp [deprecated]\n\
      97             : "), stdout);
      98           1 :       fputs ("\n", stdout);
      99           1 :       fputs (HELP_OPTION_DESCRIPTION, stdout);
     100           1 :       fputs (VERSION_OPTION_DESCRIPTION, stdout);
     101           1 :       emit_bug_reporting_address ();
     102             :     }
     103             : 
     104          17 :   exit (status);
     105             : }
     106             : 
     107             : static size_t
     108          41 : count_trailing_X_s (const char *s)
     109             : {
     110          41 :   size_t len = strlen (s);
     111          41 :   size_t n = 0;
     112         217 :   for ( ; len && s[len-1] == 'X'; len--)
     113         176 :     ++n;
     114          41 :   return n;
     115             : }
     116             : 
     117             : static int
     118          16 : mkstemp_len (char *tmpl, size_t suff_len, bool dry_run)
     119             : {
     120          16 :   return gen_tempname_len (tmpl, dry_run ? GT_NOCREATE : GT_FILE, suff_len);
     121             : }
     122             : 
     123             : static int
     124           2 : mkdtemp_len (char *tmpl, size_t suff_len, bool dry_run)
     125             : {
     126           2 :   return gen_tempname_len (tmpl, dry_run ? GT_NOCREATE : GT_DIR, suff_len);
     127             : }
     128             : 
     129             : int
     130          59 : main (int argc, char **argv)
     131             : {
     132             :   char *dest_dir;
     133          59 :   char *dest_dir_arg = NULL;
     134          59 :   bool suppress_stderr = false;
     135             :   int c;
     136             :   unsigned int n_args;
     137             :   char *template;
     138          59 :   bool use_dest_dir = false;
     139          59 :   bool deprecated_t_option = false;
     140          59 :   bool create_directory = false;
     141          59 :   bool dry_run = false;
     142          59 :   int status = EXIT_SUCCESS;
     143             :   size_t x_count;
     144             :   char *dest_name;
     145             : 
     146             :   initialize_main (&argc, &argv);
     147          59 :   program_name = argv[0];
     148          59 :   setlocale (LC_ALL, "");
     149             :   bindtextdomain (PACKAGE, LOCALEDIR);
     150             :   textdomain (PACKAGE);
     151             : 
     152          59 :   atexit (close_stdout);
     153             : 
     154         148 :   while ((c = getopt_long (argc, argv, "dp:qtuV", longopts, NULL)) != -1)
     155             :     {
     156          41 :       switch (c)
     157             :         {
     158           7 :         case 'd':
     159           7 :           create_directory = true;
     160           7 :           break;
     161          10 :         case 'p':
     162          10 :           dest_dir_arg = optarg;
     163          10 :           use_dest_dir = true;
     164          10 :           break;
     165           4 :         case 'q':
     166           4 :           suppress_stderr = true;
     167           4 :           break;
     168           3 :         case 't':
     169           3 :           use_dest_dir = true;
     170           3 :           deprecated_t_option = true;
     171           3 :           break;
     172           4 :         case 'u':
     173           4 :           dry_run = true;
     174           4 :           break;
     175             : 
     176           2 :         case TMPDIR_OPTION:
     177           2 :           use_dest_dir = true;
     178           2 :           dest_dir_arg = optarg;
     179           2 :           break;
     180             : 
     181           1 :         case_GETOPT_HELP_CHAR;
     182             : 
     183           1 :         case 'V':
     184           1 :         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
     185           9 :         default:
     186           9 :           usage (EXIT_FAILURE);
     187             :         }
     188             :     }
     189             : 
     190          48 :   if (suppress_stderr)
     191             :     {
     192             :       /* From here on, redirect stderr to /dev/null.
     193             :          A diagnostic from getopt_long, above, would still go to stderr.  */
     194           4 :       freopen ("/dev/null", "wb", stderr);
     195             :     }
     196             : 
     197          48 :   n_args = argc - optind;
     198          48 :   if (2 <= n_args)
     199             :     {
     200           7 :       error (0, 0, _("too many templates"));
     201           7 :       usage (EXIT_FAILURE);
     202             :     }
     203             : 
     204          41 :   if (n_args == 0)
     205             :     {
     206          16 :       use_dest_dir = true;
     207          16 :       template = (char *) default_template;
     208             :     }
     209             :   else
     210             :     {
     211          25 :       template = argv[optind];
     212             :     }
     213             : 
     214          41 :   x_count = count_trailing_X_s (template);
     215          41 :   if (x_count < 3)
     216          21 :     error (EXIT_FAILURE, 0, _("too few X's in template %s"), quote (template));
     217             : 
     218          20 :   if (use_dest_dir)
     219             :     {
     220          18 :       if (deprecated_t_option)
     221             :         {
     222           3 :           char *env = getenv ("TMPDIR");
     223           3 :           dest_dir = (env && *env
     224             :                       ? env
     225           6 :                       : (dest_dir_arg ? dest_dir_arg : "/tmp"));
     226             : 
     227           3 :           if (last_component (template) != template)
     228           1 :             error (EXIT_FAILURE, 0,
     229             :                    _("invalid template, %s, contains directory separator"),
     230             :                    quote (template));
     231             :         }
     232             :       else
     233             :         {
     234          15 :           if (dest_dir_arg && *dest_dir_arg)
     235           6 :             dest_dir = dest_dir_arg;
     236             :           else
     237             :             {
     238           9 :               char *env = getenv ("TMPDIR");
     239           9 :               dest_dir = (env && *env ? env : "/tmp");
     240             :             }
     241          15 :           if (IS_ABSOLUTE_FILE_NAME (template))
     242           1 :             error (EXIT_FAILURE, 0,
     243             :                    _("invalid template, %s; with --tmpdir,"
     244             :                      " it may not be absolute"),
     245             :                    quote (template));
     246             :         }
     247             : 
     248          16 :       dest_name = file_name_concat (dest_dir, template, NULL);
     249             :     }
     250             :   else
     251             :     {
     252           2 :       dest_name = xstrdup (template);
     253             :     }
     254             : 
     255          18 :   if (create_directory)
     256             :     {
     257           2 :       int err = mkdtemp_len (dest_name, x_count, dry_run);
     258           2 :       if (err != 0)
     259             :         {
     260           0 :           error (0, errno, _("failed to create directory via template %s"),
     261             :                  quote (dest_name));
     262           0 :           status = EXIT_FAILURE;
     263             :         }
     264             :     }
     265             :   else
     266             :     {
     267          16 :       int fd = mkstemp_len (dest_name, x_count, dry_run);
     268          16 :       if (fd < 0 || (!dry_run && close (fd) != 0))
     269             :         {
     270           6 :           error (0, errno, _("failed to create file via template %s"),
     271             :                  quote (dest_name));
     272           6 :           status = EXIT_FAILURE;
     273             :         }
     274             :     }
     275             : 
     276          18 :   if (status == EXIT_SUCCESS)
     277          12 :     puts (dest_name);
     278             : 
     279             : #ifdef lint
     280             :   free (dest_name);
     281             : #endif
     282             : 
     283          18 :   exit (status);
     284             : }
     285             : 
     286             : /*
     287             :  * Local variables:
     288             :  *  indent-tabs-mode: nil
     289             :  * End:
     290             :  */

Generated by: LCOV version 1.10