1 /*
2  * mknod - build special file
3  *
4  * Gunnar Ritter, Freiburg i. Br., Germany, August 2003.
5  */
6 /*
7  * Copyright (c) 2003 Gunnar Ritter
8  *
9  * This software is provided 'as-is', without any express or implied
10  * warranty. In no event will the authors be held liable for any damages
11  * arising from the use of this software.
12  *
13  * Permission is granted to anyone to use this software for any purpose,
14  * including commercial applications, and to alter it and redistribute
15  * it freely, subject to the following restrictions:
16  *
17  * 1. The origin of this software must not be misrepresented; you must not
18  *    claim that you wrote the original software. If you use this software
19  *    in a product, an acknowledgment in the product documentation would be
20  *    appreciated but is not required.
21  *
22  * 2. Altered source versions must be plainly marked as such, and must not be
23  *    misrepresented as being the original software.
24  *
25  * 3. This notice may not be removed or altered from any source distribution.
26  */
27 
28 #if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
29 #define	USED	__attribute__ ((used))
30 #elif defined __GNUC__
31 #define	USED	__attribute__ ((unused))
32 #else
33 #define	USED
34 #endif
35 static const char sccsid[] USED = "@(#)mknod.sl	1.8 (gritter) 5/29/05";
36 
37 #if defined (__GLIBC__) || defined (_AIX)
38 #include	<sys/sysmacros.h>
39 #endif	/* __GLIBC__ || _AIX */
40 #include	<sys/stat.h>
41 #include	<stdio.h>
42 #include	<stdlib.h>
43 #include	<libgen.h>
44 #include	<errno.h>
45 #include	<string.h>
46 #include	<limits.h>
47 #include	<unistd.h>
48 #ifndef	major
49 #include	<sys/mkdev.h>
50 #endif	/* !major */
51 
52 #ifndef	S_IFNAM
53 #define	S_IFNAM		0x5000
54 #endif
55 #ifndef	S_INSEM
56 #define	S_INSEM		0x1
57 #endif
58 #ifndef	S_INSHD
59 #define	S_INSHD		0x2
60 #endif
61 
62 static char	*progname;
63 static long	max_major;
64 static long	max_minor;
65 
66 static void
usage(void)67 usage(void)
68 {
69 	fprintf(stderr, "usage: %s name [ b/c major minor ] [ p ]\n",
70 			progname);
71 	exit(2);
72 }
73 
74 static int
mnode(const char * name,mode_t type,dev_t dev)75 mnode(const char *name, mode_t type, dev_t dev)
76 {
77 	if (mknod(name, type|0666, dev) == 0)
78 		return 0;
79 	switch (errno) {
80 	case EPERM:
81 		fprintf(stderr, "%s: must be super-user\n", progname);
82 		break;
83 	default:
84 		fprintf(stderr, "%s: %s\n", progname, strerror(errno));
85 	}
86 	return 1;
87 }
88 
89 static dev_t
nu(const char * s,const char * msg,dev_t max)90 nu(const char *s, const char *msg, dev_t max)
91 {
92 	int	n;
93 
94 	n = atoi(s);
95 	if (n < 0 || n > max) {
96 		fprintf(stderr, "%s: invalid %s number '%s' - "
97 				"valid range is 0-%d\n",
98 				progname, msg, s, (int)max);
99 		exit(2);
100 	}
101 	return n;
102 }
103 
104 static int
mspec(int ac,char ** av,mode_t type)105 mspec(int ac, char **av, mode_t type)
106 {
107 	dev_t	major, minor;
108 
109 	if (ac != 5)
110 		usage();
111 	major = nu(av[3], "major", max_major);
112 	minor = nu(av[4], "minor", max_minor);
113 	return mnode(av[1], type, makedev(major, minor));
114 }
115 
116 static int
mfifo(int ac,char ** av)117 mfifo(int ac, char **av)
118 {
119 	if (ac != 3)
120 		usage();
121 	return mnode(av[1], S_IFIFO, 0);
122 }
123 
124 static int
mnam(int ac,char ** av,mode_t type)125 mnam(int ac, char **av, mode_t type)
126 {
127 	if (ac != 3)
128 		usage();
129 	return mnode(av[1], S_IFNAM, type);
130 }
131 
132 static void
getlimits(void)133 getlimits(void)
134 {
135 #ifdef	__linux__
136 #ifndef	WORD_BIT
137 	int	WORD_BIT;
138 	for (WORD_BIT = 2; (1<<WORD_BIT) != 1; WORD_BIT++);
139 #endif	/* !WORD_BIT */
140 	max_major = (1<<(WORD_BIT-20)) - 1;
141 	max_minor = (1<<20) - 1;
142 #else	/* !__linux__ */
143 	max_major = (1<<14) - 1;
144 	max_minor = (1<<18) - 1;
145 #endif	/* !__linux__ */
146 }
147 
148 int
main(int argc,char ** argv)149 main(int argc, char **argv)
150 {
151 	progname = basename(argv[0]);
152 	if (argc < 3)
153 		usage();
154 	if (argv[2][1] != '\0')
155 		usage();
156 	getlimits();
157 	switch (argv[2][0]) {
158 	case 'b':
159 		return mspec(argc, argv, S_IFBLK);
160 	case 'c':
161 		return mspec(argc, argv, S_IFCHR);
162 	case 'p':
163 		return mfifo(argc, argv);
164 	case 'm':
165 		return mnam(argc, argv, S_INSHD);
166 	case 's':
167 		return mnam(argc, argv, S_INSEM);
168 	default:
169 		usage();
170 	}
171 	/*NOTREACHED*/
172 	return 0;
173 }
174