1 /* mknod -- make special files
2 Copyright (C) 90, 91, 1995-2009 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 static struct option
const longopts
[] =
38 {GETOPT_SELINUX_CONTEXT_OPTION_DECL
},
39 {"mode", required_argument
, NULL
, 'm'},
40 {GETOPT_HELP_OPTION_DECL
},
41 {GETOPT_VERSION_OPTION_DECL
},
48 if (status
!= EXIT_SUCCESS
)
49 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
53 printf (_("Usage: %s [OPTION]... NAME TYPE [MAJOR MINOR]\n"),
56 Create the special file NAME of the given TYPE.\n\
60 Mandatory arguments to long options are mandatory for short options too.\n\
63 -m, --mode=MODE set file permission bits to MODE, not a=rw - umask\n\
66 -Z, --context=CTX set the SELinux security context of NAME to CTX\n\
68 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
69 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
72 Both MAJOR and MINOR must be specified when TYPE is b, c, or u, and they\n\
73 must be omitted when TYPE is p. If MAJOR or MINOR begins with 0x or 0X,\n\
74 it is interpreted as hexadecimal; otherwise, if it begins with 0, as octal;\n\
75 otherwise, as decimal. TYPE may be:\n\
79 b create a block (buffered) special file\n\
80 c, u create a character (unbuffered) special file\n\
83 printf (USAGE_BUILTIN_WARNING
, PROGRAM_NAME
);
84 emit_bug_reporting_address ();
90 main (int argc
, char **argv
)
93 char const *specified_mode
= NULL
;
95 int expected_operands
;
97 security_context_t scontext
= NULL
;
99 initialize_main (&argc
, &argv
);
100 set_program_name (argv
[0]);
101 setlocale (LC_ALL
, "");
102 bindtextdomain (PACKAGE
, LOCALEDIR
);
103 textdomain (PACKAGE
);
105 atexit (close_stdout
);
107 while ((optc
= getopt_long (argc
, argv
, "m:Z:", longopts
, NULL
)) != -1)
112 specified_mode
= optarg
;
117 case_GETOPT_HELP_CHAR
;
118 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
120 usage (EXIT_FAILURE
);
124 newmode
= (S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IWGRP
| S_IROTH
| S_IWOTH
);
127 struct mode_change
*change
= mode_compile (specified_mode
);
129 error (EXIT_FAILURE
, 0, _("invalid mode"));
130 newmode
= mode_adjust (newmode
, false, umask (0), change
, NULL
);
132 if (newmode
& ~S_IRWXUGO
)
133 error (EXIT_FAILURE
, 0,
134 _("mode must specify only file permission bits"));
137 /* If the number of arguments is 0 or 1,
138 or (if it's 2 or more and the second one starts with `p'), then there
139 must be exactly two operands. Otherwise, there must be four. */
140 expected_operands
= (argc
<= optind
141 || (optind
+ 1 < argc
&& argv
[optind
+ 1][0] == 'p')
144 if (argc
- optind
< expected_operands
)
147 error (0, 0, _("missing operand"));
149 error (0, 0, _("missing operand after %s"), quote (argv
[argc
- 1]));
150 if (expected_operands
== 4 && argc
- optind
== 2)
151 fprintf (stderr
, "%s\n",
152 _("Special files require major and minor device numbers."));
153 usage (EXIT_FAILURE
);
156 if (expected_operands
< argc
- optind
)
158 error (0, 0, _("extra operand %s"),
159 quote (argv
[optind
+ expected_operands
]));
160 if (expected_operands
== 2 && argc
- optind
== 4)
161 fprintf (stderr
, "%s\n",
162 _("Fifos do not have major and minor device numbers."));
163 usage (EXIT_FAILURE
);
166 if (scontext
&& setfscreatecon (scontext
) < 0)
167 error (EXIT_FAILURE
, errno
,
168 _("failed to set default file creation context to %s"),
171 /* Only check the first character, to allow mnemonic usage like
172 `mknod /dev/rst0 character 18 0'. */
174 switch (argv
[optind
+ 1][0])
176 case 'b': /* `block' or `buffered' */
178 error (EXIT_FAILURE
, 0, _("block special files not supported"));
182 goto block_or_character
;
184 case 'c': /* `character' */
185 case 'u': /* `unbuffered' */
187 error (EXIT_FAILURE
, 0, _("character special files not supported"));
191 goto block_or_character
;
195 char const *s_major
= argv
[optind
+ 2];
196 char const *s_minor
= argv
[optind
+ 3];
197 uintmax_t i_major
, i_minor
;
200 if (xstrtoumax (s_major
, NULL
, 0, &i_major
, NULL
) != LONGINT_OK
201 || i_major
!= (major_t
) i_major
)
202 error (EXIT_FAILURE
, 0,
203 _("invalid major device number %s"), quote (s_major
));
205 if (xstrtoumax (s_minor
, NULL
, 0, &i_minor
, NULL
) != LONGINT_OK
206 || i_minor
!= (minor_t
) i_minor
)
207 error (EXIT_FAILURE
, 0,
208 _("invalid minor device number %s"), quote (s_minor
));
210 device
= makedev (i_major
, i_minor
);
213 error (EXIT_FAILURE
, 0, _("invalid device %s %s"), s_major
, s_minor
);
216 if (mknod (argv
[optind
], newmode
| node_type
, device
) != 0)
217 error (EXIT_FAILURE
, errno
, "%s", quote (argv
[optind
]));
221 case 'p': /* `pipe' */
222 if (mkfifo (argv
[optind
], newmode
) != 0)
223 error (EXIT_FAILURE
, errno
, "%s", quote (argv
[optind
]));
227 error (0, 0, _("invalid device type %s"), quote (argv
[optind
+ 1]));
228 usage (EXIT_FAILURE
);