/* mknod -- make special files This is the mknod utility
Copyright (C) 1990-2018 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */ The GNUv3 license
/* Written by David MacKenzie <djm@ai.mit.edu> */
#include <config.h> Provides system specific information
#include <stdio.h> Provides standard I/O capability
#include <getopt.h> ...!includes auto-comment...
#include <sys/types.h> Provides system data types
#include <selinux/selinux.h> ...!includes auto-comment......!includes auto-comment...
#include "system.h" ...!includes auto-comment...
#include "die.h" ...!includes auto-comment...
#include "error.h" ...!includes auto-comment...
#include "modechange.h" ...!includes auto-comment...
#include "quote.h" ...!includes auto-comment...
#include "selinux.h" ...!includes auto-comment...
#include "smack.h" ...!includes auto-comment...
#include "xstrtol.h" ...!includes auto-comment...
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "mknod" Line 35
#define AUTHORS proper_name ("David MacKenzie") Line 37
static struct option const longopts[] = Line 39
{
{GETOPT_SELINUX_CONTEXT_OPTION_DECL}, Line 41
{"mode", required_argument, NULL, 'm'}, Line 42
{GETOPT_HELP_OPTION_DECL}, Line 43
{GETOPT_VERSION_OPTION_DECL}, Line 44
{NULL, 0, NULL, 0} Line 45
}; Block 1
void Line 48
usage (int status) Line 49
{
if (status != EXIT_SUCCESS) Line 51
emit_try_help (); ...!common auto-comment...
else Line 53
{
printf (_("Usage: %s [OPTION]... NAME TYPE [MAJOR MINOR]\n"), Line 55
program_name); Line 56
fputs (_("\ Line 57
Create the special file NAME of the given TYPE.\n\ Line 58
"), stdout); Line 59
emit_mandatory_arg_note (); ...!common auto-comment...
fputs (_("\ Line 63
-m, --mode=MODE set file permission bits to MODE, not a=rw - umask\n\ Line 64
"), stdout); Line 65
fputs (_("\ Line 66
-Z set the SELinux security context to default type\n\ Line 67
--context[=CTX] like -Z, or if CTX is specified then set the SELinux\n\ Line 68
or SMACK security context to CTX\n\ Line 69
"), stdout); Line 70
fputs (HELP_OPTION_DESCRIPTION, stdout); Line 71
fputs (VERSION_OPTION_DESCRIPTION, stdout); Line 72
fputs (_("\ Line 73
\n\
Both MAJOR and MINOR must be specified when TYPE is b, c, or u, and they\n\ Line 75
must be omitted when TYPE is p. If MAJOR or MINOR begins with 0x or 0X,\n\ Line 76
it is interpreted as hexadecimal; otherwise, if it begins with 0, as octal;\n\ Line 77
otherwise, as decimal. TYPE may be:\n\ Line 78
"), stdout); Line 79
fputs (_("\ Line 80
\n\
b create a block (buffered) special file\n\ Line 82
c, u create a character (unbuffered) special file\n\ Line 83
p create a FIFO\n\ Line 84
"), stdout); Line 85
printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME); Line 86
emit_ancillary_info (PROGRAM_NAME); Line 87
}
exit (status); Line 89
} Block 2
int
main (int argc, char **argv) Line 93
{
mode_t newmode; Line 95
char const *specified_mode = NULL; Line 96
int optc; Line 97
size_t expected_operands; Line 98
mode_t node_type; Line 99
char const *scontext = NULL; Line 100
bool set_security_context = false; Line 101
initialize_main (&argc, &argv); VMS-specific entry point handling wildcard expansion
set_program_name (argv[0]); Retains program name and discards path
setlocale (LC_ALL, ""); Sets up internationalization (i18n)
bindtextdomain (PACKAGE, LOCALEDIR); Assigns i18n directorySets text domain for _() [gettext()] function
textdomain (PACKAGE); Sets text domain for _() [gettext()] function
atexit (close_stdout); Close stdout on exit (see gnulib)
while ((optc = getopt_long (argc, argv, "m:Z", longopts, NULL)) != -1) Line 111
{
switch (optc) Line 113
{
case 'm': Line 115
specified_mode = optarg; Line 116
break; Line 117
case 'Z': Line 118
if (is_smack_enabled ()) ...!common auto-comment...
{
/* We don't yet support -Z to restore context with SMACK. */
scontext = optarg; Line 122
}
else if (is_selinux_enabled () > 0) ...!common auto-comment...
{
if (optarg) Line 126
scontext = optarg; Line 127
else Line 128
set_security_context = true; Line 129
}
else if (optarg) Line 131
{
error (0, 0, Line 133
_("warning: ignoring --context; " Line 134
"it requires an SELinux/SMACK-enabled kernel")); Line 135
}
break; Line 137
case_GETOPT_HELP_CHAR; Line 138
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); Line 139
default: Line 140
usage (EXIT_FAILURE); Line 141
}
}
newmode = MODE_RW_UGO; Line 145
if (specified_mode) Line 146
{
mode_t umask_value; Line 148
struct mode_change *change = mode_compile (specified_mode); Line 149
if (!change) Line 150
die (EXIT_FAILURE, 0, _("invalid mode")); Line 151
umask_value = umask (0); Line 152
umask (umask_value); Line 153
newmode = mode_adjust (newmode, false, umask_value, change, NULL); Line 154
free (change); Line 155
if (newmode & ~S_IRWXUGO) Line 156
die (EXIT_FAILURE, 0, Line 157
_("mode must specify only file permission bits")); Line 158
}
/* If the number of arguments is 0 or 1,
or (if it's 2 or more and the second one starts with 'p'), then there
must be exactly two operands. Otherwise, there must be four. */
expected_operands = (argc <= optind Line 164
|| (optind + 1 < argc && argv[optind + 1][0] == 'p') Line 165
? 2 : 4); Line 166
if (argc - optind < expected_operands) Line 168
{
if (argc <= optind) Line 170
error (0, 0, _("missing operand")); Line 171
else Line 172
error (0, 0, _("missing operand after %s"), quote (argv[argc - 1])); Line 173
if (expected_operands == 4 && argc - optind == 2) Line 174
fprintf (stderr, "%s\n", Line 175
_("Special files require major and minor device numbers.")); Line 176
usage (EXIT_FAILURE); Line 177
}
if (expected_operands < argc - optind) Line 180
{
error (0, 0, _("extra operand %s"), Line 182
quote (argv[optind + expected_operands])); Line 183
if (expected_operands == 2 && argc - optind == 4) Line 184
fprintf (stderr, "%s\n", Line 185
_("Fifos do not have major and minor device numbers.")); Line 186
usage (EXIT_FAILURE); Line 187
}
if (scontext) Line 190
{
int ret = 0; Line 192
if (is_smack_enabled ()) ...!common auto-comment...
ret = smack_set_label_for_self (scontext); Line 194
else Line 195
ret = setfscreatecon (se_const (scontext)); Line 196
if (ret < 0) Line 198
die (EXIT_FAILURE, errno, Line 199
_("failed to set default file creation context to %s"), Line 200
quote (scontext)); Line 201
}
/* Only check the first character, to allow mnemonic usage like
'mknod /dev/rst0 character 18 0'. */
switch (argv[optind + 1][0]) Line 207
{
case 'b': /* 'block' or 'buffered' */ Line 209
#ifndef S_IFBLK Line 210
die (EXIT_FAILURE, 0, _("block special files not supported")); Line 211
#else Line 212
node_type = S_IFBLK; Line 213
#endif Line 214
goto block_or_character; Line 215
case 'c': /* 'character' */ Line 217
case 'u': /* 'unbuffered' */ Line 218
#ifndef S_IFCHR Line 219
die (EXIT_FAILURE, 0, _("character special files not supported")); Line 220
#else Line 221
node_type = S_IFCHR; Line 222
#endif Line 223
goto block_or_character; Line 224
block_or_character: Line 226
{
char const *s_major = argv[optind + 2]; Line 228
char const *s_minor = argv[optind + 3]; Line 229
uintmax_t i_major, i_minor; Line 230
dev_t device; Line 231
if (xstrtoumax (s_major, NULL, 0, &i_major, NULL) != LONGINT_OK Line 233
|| i_major != (major_t) i_major) Line 234
die (EXIT_FAILURE, 0, Line 235
_("invalid major device number %s"), quote (s_major)); Line 236
if (xstrtoumax (s_minor, NULL, 0, &i_minor, NULL) != LONGINT_OK Line 238
|| i_minor != (minor_t) i_minor) Line 239
die (EXIT_FAILURE, 0, Line 240
_("invalid minor device number %s"), quote (s_minor)); Line 241
device = makedev (i_major, i_minor); Line 243
#ifdef NODEV Line 244
if (device == NODEV) Line 245
die (EXIT_FAILURE, 0, _("invalid device %s %s"), Line 246
s_major, s_minor); Line 247
#endif Line 248
if (set_security_context) Line 250
defaultcon (argv[optind], node_type); Line 251
if (mknod (argv[optind], newmode | node_type, device) != 0) Line 253...!syscalls auto-comment...
die (EXIT_FAILURE, errno, "%s", quotef (argv[optind])); Line 254
}
break; Line 256
case 'p': /* 'pipe' */ Line 258
if (set_security_context) Line 259
defaultcon (argv[optind], S_IFIFO); Line 260
if (mkfifo (argv[optind], newmode) != 0) Line 261
die (EXIT_FAILURE, errno, "%s", quotef (argv[optind])); Line 262
break; Line 263
default: Line 265
error (0, 0, _("invalid device type %s"), quote (argv[optind + 1])); Line 266
usage (EXIT_FAILURE); Line 267
}
if (specified_mode && lchmod (argv[optind], newmode) != 0) Line 270
die (EXIT_FAILURE, errno, _("cannot set permissions of %s"), Line 271
quoteaf (argv[optind])); Line 272
return EXIT_SUCCESS; Line 274
} Block 3