(add_tabstop): Give correct size when reallocating tab_list buffer.
[platform/upstream/coreutils.git] / src / mknod.c
1 /* mknod -- make special files
2    Copyright (C) 1990, 1991, 1995 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
16    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
17
18 /* Usage: mknod [-m mode] [--mode=mode] path {bcu} major minor
19                 make a block or character device node
20           mknod [-m mode] [--mode=mode] path p
21                 make a FIFO (named pipe)
22
23    Options:
24    -m, --mode=mode      Set the mode of created nodes to MODE, which is
25                         symbolic as in chmod and uses the umask as a point of
26                         departure.
27
28    David MacKenzie <djm@ai.mit.edu>  */
29
30 #include <config.h>
31 #include <stdio.h>
32 #include <getopt.h>
33 #include <sys/types.h>
34
35 #include "system.h"
36 #include "modechange.h"
37 #include "version.h"
38 #include "error.h"
39
40 static void usage ();
41
42 /* The name this program was run with. */
43 char *program_name;
44
45 /* If non-zero, display usage information and exit.  */
46 static int show_help;
47
48 /* If non-zero, print the version on standard output and exit.  */
49 static int show_version;
50
51 static struct option const longopts[] =
52 {
53   {"mode", required_argument, NULL, 'm'},
54   {"help", no_argument, &show_help, 1},
55   {"version", no_argument, &show_version, 1},
56   {NULL, 0, NULL, 0}
57 };
58
59 static int
60 my_strtol (str, ptr, base, result)
61      const char *str;
62      const char **ptr;
63      int base;
64      long int *result;
65 {
66   long int val;
67   char *terminator;
68   int return_code;
69
70   return_code = 0;
71
72   errno = 0;
73   val = strtol (str, &terminator, base);
74
75   if (terminator == str
76       || (ptr == NULL && *terminator != '\0')
77       || errno == ERANGE)
78     return_code = 1;
79
80   if (ptr != NULL)
81     *ptr = terminator;
82
83   *result = val;
84   return return_code;
85 }
86
87 void
88 main (argc, argv)
89      int argc;
90      char **argv;
91 {
92   unsigned short newmode;
93   struct mode_change *change;
94   char *symbolic_mode;
95   int optc;
96   int i_major, i_minor;
97   long int tmp_major, tmp_minor;
98   char *s;
99
100   program_name = argv[0];
101   symbolic_mode = NULL;
102
103   while ((optc = getopt_long (argc, argv, "m:", longopts, (int *) 0)) != EOF)
104     {
105       switch (optc)
106         {
107         case 0:
108           break;
109         case 'm':
110           symbolic_mode = optarg;
111           break;
112         default:
113           usage (1);
114         }
115     }
116
117   if (show_version)
118     {
119       printf ("%s\n", version_string);
120       exit (0);
121     }
122
123   if (show_help)
124     usage (0);
125
126   newmode = 0666 & ~umask (0);
127   if (symbolic_mode)
128     {
129       change = mode_compile (symbolic_mode, 0);
130       if (change == MODE_INVALID)
131         error (1, 0, "invalid mode");
132       else if (change == MODE_MEMORY_EXHAUSTED)
133         error (1, 0, "virtual memory exhausted");
134       newmode = mode_adjust (newmode, change);
135     }
136
137   if (argc - optind != 2 && argc - optind != 4)
138     {
139       const char *msg;
140       if (argc - optind < 2)
141         msg = "too few arguments";
142       else if (argc - optind > 4)
143         msg = "too many arguments";
144       else
145         msg = "wrong number of arguments";
146       error (0, 0, msg);
147       usage (1);
148     }
149
150   /* Only check the first character, to allow mnemonic usage like
151      `mknod /dev/rst0 character 18 0'. */
152
153   switch (argv[optind + 1][0])
154     {
155     case 'b':                   /* `block' or `buffered' */
156 #ifndef S_IFBLK
157       error (4, 0, "block special files not supported");
158 #else
159       if (argc - optind != 4)
160         {
161           error (0, 0, "\
162 when creating block special files, major and minor device\n\
163 numbers must be specified");
164           usage (1);
165         }
166
167       s = argv[optind + 2];
168       if (my_strtol (s, NULL, 0, &tmp_major))
169         error (1, 0, "invalid major device number `%s'", s);
170
171       s = argv[optind + 3];
172       if (my_strtol (s, NULL, 0, &tmp_minor))
173         error (1, 0, "invalid minor device number `%s'", s);
174       
175       i_major = (int) tmp_major;
176       i_minor = (int) tmp_minor;
177
178       if (mknod (argv[optind], newmode | S_IFBLK, makedev (i_major, i_minor)))
179         error (1, errno, "%s", argv[optind]);
180 #endif
181       break;
182
183     case 'c':                   /* `character' */
184     case 'u':                   /* `unbuffered' */
185 #ifndef S_IFCHR
186       error (4, 0, "character special files not supported");
187 #else
188       if (argc - optind != 4)
189         {
190           error (0, 0, "\
191 when creating character special files, major and minor device\n\
192 numbers must be specified");
193           usage (1);
194         }
195
196       s = argv[optind + 2];
197       if (my_strtol (s, NULL, 0, &tmp_major))
198         error (1, 0, "invalid major device number `%s'", s);
199
200       s = argv[optind + 3];
201       if (my_strtol (s, NULL, 0, &tmp_minor))
202         error (1, 0, "invalid minor device number `%s'", s);
203       
204       i_major = (int) tmp_major;
205       i_minor = (int) tmp_minor;
206
207       if (mknod (argv[optind], newmode | S_IFCHR, makedev (i_major, i_minor)))
208         error (1, errno, "%s", argv[optind]);
209 #endif
210       break;
211
212     case 'p':                   /* `pipe' */
213 #ifndef S_ISFIFO
214       error (4, 0, "fifo files not supported");
215 #else
216       if (argc - optind != 2)
217         {
218           error (0, 0, "\
219 major and minor device numbers may not be specified for fifo files");
220           usage (1);
221         }
222       if (mkfifo (argv[optind], newmode))
223         error (1, errno, "%s", argv[optind]);
224 #endif
225       break;
226
227     default:
228       usage (1);
229     }
230
231   exit (0);
232 }
233
234 static void
235 usage (status)
236      int status;
237 {
238   if (status != 0)
239     fprintf (stderr, "Try `%s --help' for more information.\n",
240              program_name);
241   else
242     {
243       printf ("Usage: %s [OPTION]... PATH TYPE [MAJOR MINOR]\n", program_name);
244       printf ("\
245 \n\
246   -m, --mode=MODE   set permission mode (as in chmod), not 0666 - umask\n\
247       --help        display this help and exit\n\
248       --version     output version information and exit\n\
249 \n\
250 MAJOR MINOR are forbidden for TYPE p, mandatory otherwise.  TYPE may be:\n\
251 \n\
252   b      create a block (buffered) special file\n\
253   c, u   create a character (unbuffered) special file   \n\
254   p      create a FIFO\n");
255     }
256   exit (status);
257 }