1 /* mknod -- make special files
2 Copyright (C) 90, 91, 1995-2008 Free Software Foundation, Inc.
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.
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.
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/>. */
17 /* Written by David MacKenzie <djm@ai.mit.edu> */
22 #include <sys/types.h>
23 #include <selinux/selinux.h>
27 #include "modechange.h"
31 /* The official name of this program (e.g., no `g' prefix). */
32 #define PROGRAM_NAME "mknod"
34 #define AUTHORS proper_name ("David MacKenzie")
36 /* The name this program was run with. */
37 char const *program_name;
39 static struct option const longopts[] =
41 {GETOPT_SELINUX_CONTEXT_OPTION_DECL},
42 {"mode", required_argument, NULL, 'm'},
43 {GETOPT_HELP_OPTION_DECL},
44 {GETOPT_VERSION_OPTION_DECL},
51 if (status != EXIT_SUCCESS)
52 fprintf (stderr, _("Try `%s --help' for more information.\n"),
56 printf (_("Usage: %s [OPTION]... NAME TYPE [MAJOR MINOR]\n"),
59 Create the special file NAME of the given TYPE.\n\
63 -Z, --context=CTX set the SELinux security context of NAME to CTX\n\
66 Mandatory arguments to long options are mandatory for short options too.\n\
69 -m, --mode=MODE set file permission bits to MODE, not a=rw - umask\n\
71 fputs (HELP_OPTION_DESCRIPTION, stdout);
72 fputs (VERSION_OPTION_DESCRIPTION, stdout);
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\
82 b create a block (buffered) special file\n\
83 c, u create a character (unbuffered) special file\n\
86 printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);
87 emit_bug_reporting_address ();
93 main (int argc, char **argv)
96 char const *specified_mode = NULL;
98 int expected_operands;
100 security_context_t scontext = NULL;
102 initialize_main (&argc, &argv);
103 program_name = argv[0];
104 setlocale (LC_ALL, "");
105 bindtextdomain (PACKAGE, LOCALEDIR);
106 textdomain (PACKAGE);
108 atexit (close_stdout);
110 while ((optc = getopt_long (argc, argv, "m:Z:", longopts, NULL)) != -1)
115 specified_mode = optarg;
120 case_GETOPT_HELP_CHAR;
121 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
123 usage (EXIT_FAILURE);
127 newmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
130 struct mode_change *change = mode_compile (specified_mode);
132 error (EXIT_FAILURE, 0, _("invalid mode"));
133 newmode = mode_adjust (newmode, false, umask (0), change, NULL);
135 if (newmode & ~S_IRWXUGO)
136 error (EXIT_FAILURE, 0,
137 _("mode must specify only file permission bits"));
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 expected_operands = (argc <= optind
144 || (optind + 1 < argc && argv[optind + 1][0] == 'p')
147 if (argc - optind < expected_operands)
150 error (0, 0, _("missing operand"));
152 error (0, 0, _("missing operand after %s"), quote (argv[argc - 1]));
153 if (expected_operands == 4 && argc - optind == 2)
154 fprintf (stderr, "%s\n",
155 _("Special files require major and minor device numbers."));
156 usage (EXIT_FAILURE);
159 if (expected_operands < argc - optind)
161 error (0, 0, _("extra operand %s"),
162 quote (argv[optind + expected_operands]));
163 if (expected_operands == 2 && argc - optind == 4)
164 fprintf (stderr, "%s\n",
165 _("Fifos do not have major and minor device numbers."));
166 usage (EXIT_FAILURE);
169 if (scontext && setfscreatecon (scontext) < 0)
170 error (EXIT_FAILURE, errno,
171 _("failed to set default file creation context to %s"),
174 /* Only check the first character, to allow mnemonic usage like
175 `mknod /dev/rst0 character 18 0'. */
177 switch (argv[optind + 1][0])
179 case 'b': /* `block' or `buffered' */
181 error (EXIT_FAILURE, 0, _("block special files not supported"));
185 goto block_or_character;
187 case 'c': /* `character' */
188 case 'u': /* `unbuffered' */
190 error (EXIT_FAILURE, 0, _("character special files not supported"));
194 goto block_or_character;
198 char const *s_major = argv[optind + 2];
199 char const *s_minor = argv[optind + 3];
200 uintmax_t i_major, i_minor;
203 if (xstrtoumax (s_major, NULL, 0, &i_major, NULL) != LONGINT_OK
204 || i_major != (major_t) i_major)
205 error (EXIT_FAILURE, 0,
206 _("invalid major device number %s"), quote (s_major));
208 if (xstrtoumax (s_minor, NULL, 0, &i_minor, NULL) != LONGINT_OK
209 || i_minor != (minor_t) i_minor)
210 error (EXIT_FAILURE, 0,
211 _("invalid minor device number %s"), quote (s_minor));
213 device = makedev (i_major, i_minor);
216 error (EXIT_FAILURE, 0, _("invalid device %s %s"), s_major, s_minor);
219 if (mknod (argv[optind], newmode | node_type, device) != 0)
220 error (EXIT_FAILURE, errno, "%s", quote (argv[optind]));
224 case 'p': /* `pipe' */
225 if (mkfifo (argv[optind], newmode) != 0)
226 error (EXIT_FAILURE, errno, "%s", quote (argv[optind]));
230 error (0, 0, _("invalid device type %s"), quote (argv[optind + 1]));
231 usage (EXIT_FAILURE);