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