LCOV - code coverage report
Current view: top level - src - mknod.c (source / functions) Hit Total Coverage
Test: coreutils.info Lines: 63 90 70.0 %
Date: 2018-01-30 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /* mknod -- make special files
       2             :    Copyright (C) 90, 91, 1995-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             : /* Written by David MacKenzie <djm@ai.mit.edu>  */
      18             : 
      19             : #include <config.h>
      20             : #include <stdio.h>
      21             : #include <getopt.h>
      22             : #include <sys/types.h>
      23             : #include <selinux/selinux.h>
      24             : 
      25             : #include "system.h"
      26             : #include "error.h"
      27             : #include "modechange.h"
      28             : #include "quote.h"
      29             : #include "xstrtol.h"
      30             : 
      31             : /* The official name of this program (e.g., no `g' prefix).  */
      32             : #define PROGRAM_NAME "mknod"
      33             : 
      34             : #define AUTHORS "David MacKenzie"
      35             : 
      36             : /* The name this program was run with. */
      37             : char *program_name;
      38             : 
      39             : static struct option const longopts[] =
      40             : {
      41             :   {GETOPT_SELINUX_CONTEXT_OPTION_DECL},
      42             :   {"mode", required_argument, NULL, 'm'},
      43             :   {GETOPT_HELP_OPTION_DECL},
      44             :   {GETOPT_VERSION_OPTION_DECL},
      45             :   {NULL, 0, NULL, 0}
      46             : };
      47             : 
      48             : void
      49          53 : usage (int status)
      50             : {
      51          53 :   if (status != EXIT_SUCCESS)
      52          52 :     fprintf (stderr, _("Try `%s --help' for more information.\n"),
      53             :              program_name);
      54             :   else
      55             :     {
      56           1 :       printf (_("Usage: %s [OPTION]... NAME TYPE [MAJOR MINOR]\n"),
      57             :               program_name);
      58           1 :       fputs (_("\
      59             : Create the special file NAME of the given TYPE.\n\
      60             : \n\
      61             : "), stdout);
      62           1 :       fputs(_("\
      63             :   -Z, --context=CTX  set the SELinux security context of NAME to CTX\n\
      64             : "), stdout);
      65           1 :       fputs (_("\
      66             : Mandatory arguments to long options are mandatory for short options too.\n\
      67             : "), stdout);
      68           1 :       fputs (_("\
      69             :   -m, --mode=MODE   set file permission bits to MODE, not a=rw - umask\n\
      70             : "), stdout);
      71           1 :       fputs (HELP_OPTION_DESCRIPTION, stdout);
      72           1 :       fputs (VERSION_OPTION_DESCRIPTION, stdout);
      73           1 :       fputs (_("\
      74             : \n\
      75             : Both MAJOR and MINOR must be specified when TYPE is b, c, or u, and they\n\
      76             : must be omitted when TYPE is p.  If MAJOR or MINOR begins with 0x or 0X,\n\
      77             : it is interpreted as hexadecimal; otherwise, if it begins with 0, as octal;\n\
      78             : otherwise, as decimal.  TYPE may be:\n\
      79             : "), stdout);
      80           1 :       fputs (_("\
      81             : \n\
      82             :   b      create a block (buffered) special file\n\
      83             :   c, u   create a character (unbuffered) special file\n\
      84             :   p      create a FIFO\n\
      85             : "), stdout);
      86           1 :       printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);
      87           1 :       emit_bug_reporting_address ();
      88             :     }
      89          53 :   exit (status);
      90             : }
      91             : 
      92             : int
      93          71 : main (int argc, char **argv)
      94             : {
      95             :   mode_t newmode;
      96          71 :   char const *specified_mode = NULL;
      97             :   int optc;
      98             :   int expected_operands;
      99             :   mode_t node_type;
     100          71 :   security_context_t scontext = NULL;
     101             : 
     102             :   initialize_main (&argc, &argv);
     103          71 :   program_name = argv[0];
     104          71 :   setlocale (LC_ALL, "");
     105             :   bindtextdomain (PACKAGE, LOCALEDIR);
     106             :   textdomain (PACKAGE);
     107             : 
     108          71 :   atexit (close_stdout);
     109             : 
     110         178 :   while ((optc = getopt_long (argc, argv, "m:Z:", longopts, NULL)) != -1)
     111             :     {
     112          46 :       switch (optc)
     113             :         {
     114          32 :         case 'm':
     115          32 :           specified_mode = optarg;
     116          32 :           break;
     117           4 :         case 'Z':
     118           4 :           scontext = optarg;
     119           4 :           break;
     120           1 :         case_GETOPT_HELP_CHAR;
     121           1 :         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
     122           8 :         default:
     123           8 :           usage (EXIT_FAILURE);
     124             :         }
     125             :     }
     126             : 
     127          61 :   newmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
     128          61 :   if (specified_mode)
     129             :     {
     130          32 :       struct mode_change *change = mode_compile (specified_mode);
     131          32 :       if (!change)
     132          11 :         error (EXIT_FAILURE, 0, _("invalid mode"));
     133          21 :       newmode = mode_adjust (newmode, false, umask (0), change, NULL);
     134          21 :       free (change);
     135          21 :       if (newmode & ~S_IRWXUGO)
     136           3 :         error (EXIT_FAILURE, 0,
     137             :                _("mode must specify only file permission bits"));
     138             :     }
     139             : 
     140             :   /* If the number of arguments is 0 or 1,
     141             :      or (if it's 2 or more and the second one starts with `p'), then there
     142             :      must be exactly two operands.  Otherwise, there must be four.  */
     143          94 :   expected_operands = (argc <= optind
     144          36 :                        || (optind + 1 < argc && argv[optind + 1][0] == 'p')
     145          62 :                        ? 2 : 4);
     146             : 
     147          47 :   if (argc - optind < expected_operands)
     148             :     {
     149          43 :       if (argc <= optind)
     150          11 :         error (0, 0, _("missing operand"));
     151             :       else
     152          32 :         error (0, 0, _("missing operand after %s"), quote (argv[argc - 1]));
     153          43 :       if (expected_operands == 4 && argc - optind == 2)
     154          13 :         fprintf (stderr, "%s\n",
     155             :                  _("Special files require major and minor device numbers."));
     156          43 :       usage (EXIT_FAILURE);
     157             :     }
     158             : 
     159           4 :   if (expected_operands < argc - optind)
     160             :     {
     161           1 :       error (0, 0, _("extra operand %s"),
     162           1 :              quote (argv[optind + expected_operands]));
     163           1 :       if (expected_operands == 2 && argc - optind == 4)
     164           0 :         fprintf (stderr, "%s\n",
     165             :                  _("Fifos do not have major and minor device numbers."));
     166           1 :       usage (EXIT_FAILURE);
     167             :     }
     168             : 
     169           3 :   if (scontext && setfscreatecon (scontext) < 0)
     170           1 :     error (EXIT_FAILURE, errno,
     171             :            _("failed to set default file creation context to %s"),
     172             :            quote (scontext));
     173             : 
     174             :   /* Only check the first character, to allow mnemonic usage like
     175             :      `mknod /dev/rst0 character 18 0'. */
     176             : 
     177           2 :   switch (argv[optind + 1][0])
     178             :     {
     179           0 :     case 'b':                   /* `block' or `buffered' */
     180             : #ifndef S_IFBLK
     181             :       error (EXIT_FAILURE, 0, _("block special files not supported"));
     182             : #else
     183           0 :       node_type = S_IFBLK;
     184             : #endif
     185           0 :       goto block_or_character;
     186             : 
     187           0 :     case 'c':                   /* `character' */
     188             :     case 'u':                   /* `unbuffered' */
     189             : #ifndef S_IFCHR
     190             :       error (EXIT_FAILURE, 0, _("character special files not supported"));
     191             : #else
     192           0 :       node_type = S_IFCHR;
     193             : #endif
     194           0 :       goto block_or_character;
     195             : 
     196           0 :     block_or_character:
     197             :       {
     198           0 :         char const *s_major = argv[optind + 2];
     199           0 :         char const *s_minor = argv[optind + 3];
     200             :         uintmax_t i_major, i_minor;
     201             :         dev_t device;
     202             : 
     203           0 :         if (xstrtoumax (s_major, NULL, 0, &i_major, NULL) != LONGINT_OK
     204           0 :             || i_major != (major_t) i_major)
     205           0 :           error (EXIT_FAILURE, 0,
     206             :                  _("invalid major device number %s"), quote (s_major));
     207             : 
     208           0 :         if (xstrtoumax (s_minor, NULL, 0, &i_minor, NULL) != LONGINT_OK
     209           0 :             || i_minor != (minor_t) i_minor)
     210           0 :           error (EXIT_FAILURE, 0,
     211             :                  _("invalid minor device number %s"), quote (s_minor));
     212             : 
     213           0 :         device = makedev (i_major, i_minor);
     214             : #ifdef NODEV
     215           0 :         if (device == NODEV)
     216           0 :           error (EXIT_FAILURE, 0, _("invalid device %s %s"), s_major, s_minor);
     217             : #endif
     218             : 
     219           0 :         if (mknod (argv[optind], newmode | node_type, device) != 0)
     220           0 :           error (EXIT_FAILURE, errno, "%s", quote (argv[optind]));
     221             :       }
     222           0 :       break;
     223             : 
     224           2 :     case 'p':                   /* `pipe' */
     225           2 :       if (mkfifo (argv[optind], newmode) != 0)
     226           2 :         error (EXIT_FAILURE, errno, "%s", quote (argv[optind]));
     227           0 :       break;
     228             : 
     229           0 :     default:
     230           0 :       error (0, 0, _("invalid device type %s"), quote (argv[optind + 1]));
     231           0 :       usage (EXIT_FAILURE);
     232             :     }
     233             : 
     234           0 :   exit (EXIT_SUCCESS);
     235             : }

Generated by: LCOV version 1.10