source: rtems/cpukit/libmisc/shell/main_mknod.c @ 0a695c2d

4.104.115
Last change on this file since 0a695c2d was 9a77af8, checked in by Ralf Corsepius <ralf.corsepius@…>, on 03/26/10 at 17:18:43

Add HAVE_CONFIG_H support to let files receive configure defines.

  • Property mode set to 100644
File size: 10.5 KB
Line 
1/*      $NetBSD: mknod.c,v 1.39 2009/02/13 01:37:23 lukem Exp $ */
2
3/*-
4 * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#ifdef HAVE_CONFIG_H
33#include "config.h"
34#endif
35
36#if HAVE_NBTOOL_CONFIG_H
37#include "nbtool_config.h"
38#endif
39
40#if 0
41#ifndef lint
42__COPYRIGHT("@(#) Copyright (c) 1998\
43 The NetBSD Foundation, Inc.  All rights reserved.");
44__RCSID("$NetBSD: mknod.c,v 1.39 2009/02/13 01:37:23 lukem Exp $");
45#endif /* not lint */
46#endif
47
48#include <rtems.h>
49#include <rtems/shell.h>
50#include <rtems/shellconfig.h>
51#define __need_getopt_newlib
52#include <getopt.h>
53
54#include <sys/cdefs.h>
55
56#include <sys/types.h>
57#include <sys/stat.h>
58#include <sys/param.h>
59#if !HAVE_NBTOOL_CONFIG_H && defined(KERN_DRIVERS)
60#include <sys/sysctl.h>
61#endif
62
63#include <err.h>
64#include <errno.h>
65#include <limits.h>
66#include <stdio.h>
67#include <stdlib.h>
68#include <unistd.h>
69#include <pwd.h>
70#include <grp.h>
71#include <string.h>
72#include <ctype.h>
73
74#include "mknod-pack_dev.h"
75
76#include <setjmp.h>
77
78typedef struct {
79  int exit_code;
80  jmp_buf exit_jmp;
81} rtems_shell_mknod_globals;
82
83#define exit_jump &(globals->exit_jmp)
84
85#define exit(ec) rtems_shell_mknod_exit(globals, ec)
86
87static int gid_name(const char *, gid_t *);
88static portdev_t callPack(rtems_shell_mknod_globals* globals,
89                          pack_t *, int, u_long *);
90
91static int      main_mknod(rtems_shell_mknod_globals*, int, char *[]);
92static  void    usage(rtems_shell_mknod_globals* );
93
94static void
95rtems_shell_mknod_exit (rtems_shell_mknod_globals* globals, int code)
96{
97  globals->exit_code = code;
98  longjmp (globals->exit_jmp, 1);
99}
100
101#include "mknod-pack_dev.c"
102
103int
104rtems_shell_main_mknod(int argc, char *argv[])
105{
106  rtems_shell_mknod_globals  mknod_globals;
107  rtems_shell_mknod_globals* globals = &mknod_globals;
108  memset (globals, 0, sizeof (mknod_globals));
109  mknod_globals.exit_code = 1;
110  if (setjmp (mknod_globals.exit_jmp) == 0)
111    return main_mknod (globals, argc, argv);
112  return mknod_globals.exit_code;
113}
114
115#define getprogname() "mknod"
116
117#ifdef KERN_DRIVERS
118#error invalid for RTEMS
119static struct kinfo_drivers *kern_drivers;
120static int num_drivers;
121
122static void get_device_info(void);
123static void print_device_info(char **);
124static int major_from_name(const char *, mode_t);
125#endif
126
127#define MAXARGS 3               /* 3 for bsdos, 2 for rest */
128
129int
130main_mknod(rtems_shell_mknod_globals* globals, int argc, char **argv)
131{
132        char    *name, *p;
133        mode_t   mode;
134        portdev_t        dev;
135        pack_t  *pack;
136        u_long   numbers[MAXARGS];
137        int      n, ch, fifo, hasformat;
138        int      r_flag = 0;            /* force: delete existing entry */
139#ifdef KERN_DRIVERS
140        int      l_flag = 0;            /* list device names and numbers */
141        int      major;
142#endif
143#if RTEMS_REMOVED
144        void    *modes = 0;
145#endif
146        uid_t    uid = -1;
147        gid_t    gid = -1;
148        int      rval;
149
150        struct getopt_data getopt_reent;
151        memset(&getopt_reent, 0, sizeof(getopt_data));
152
153        dev = 0;
154        fifo = hasformat = 0;
155        pack = pack_native;
156
157#ifdef KERN_DRIVERS
158        while ((ch = getopt(argc, argv, "lrRF:g:m:u:")) != -1) {
159#else
160        while ((ch = getopt_r(argc, argv, "rRF:g:m:u:", &getopt_reent)) != -1) {
161#endif
162                switch (ch) {
163
164#ifdef KERN_DRIVERS
165                case 'l':
166                        l_flag = 1;
167                        break;
168#endif
169
170                case 'r':
171                        r_flag = 1;
172                        break;
173
174                case 'R':
175                        r_flag = 2;
176                        break;
177
178                case 'F':
179                        pack = pack_find(getopt_reent.optarg);
180                        if (pack == NULL)
181                                errx(exit_jump, 1, "invalid format: %s", getopt_reent.optarg);
182                        hasformat++;
183                        break;
184
185                case 'g':
186                        if (getopt_reent.optarg[0] == '#') {
187                                gid = strtol(getopt_reent.optarg + 1, &p, 10);
188                                if (*p == 0)
189                                        break;
190                        }
191                        if (gid_name(getopt_reent.optarg, &gid) == 0)
192                                break;
193                        gid = strtol(getopt_reent.optarg, &p, 10);
194                        if (*p == 0)
195                                break;
196                        errx(exit_jump, 1, "%s: invalid group name", getopt_reent.optarg);
197
198                case 'm':
199#if RTEMS_REMOVED
200                        modes = setmode(getopt_reent.optarg);
201                        if (modes == NULL)
202#endif
203                                err(exit_jump, 1, "Cannot set file mode `%s'", getopt_reent.optarg);
204                        break;
205
206                case 'u':
207                        if (getopt_reent.optarg[0] == '#') {
208                                uid = strtol(getopt_reent.optarg + 1, &p, 10);
209                                if (*p == 0)
210                                        break;
211                        }
212#if RTEMS_REMOVED
213                        if (uid_from_user(getopt_reent.optarg, &uid) == 0)
214                                break;
215#endif
216                        uid = strtol(getopt_reent.optarg, &p, 10);
217                        if (*p == 0)
218                                break;
219                        errx(exit_jump, 1, "%s: invalid user name", getopt_reent.optarg);
220
221                default:
222                case '?':
223                        usage(globals);
224                }
225        }
226        argc -= getopt_reent.optind;
227        argv += getopt_reent.optind;
228
229#ifdef KERN_DRIVERS
230        if (l_flag) {
231                print_device_info(argv);
232                return 0;
233        }
234#endif
235
236        if (argc < 2 || argc > 10)
237                usage(globals);
238
239        name = *argv;
240        argc--;
241        argv++;
242
243        umask(mode = umask(0));
244        mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) & ~mode;
245
246        if (argv[0][1] != '\0')
247                goto badtype;
248        switch (*argv[0]) {
249        case 'c':
250                mode |= S_IFCHR;
251                break;
252
253        case 'b':
254                mode |= S_IFBLK;
255                break;
256
257        case 'p':
258                if (hasformat)
259                        errx(exit_jump, 1, "format is meaningless for fifos");
260                mode |= S_IFIFO;
261                fifo = 1;
262                break;
263
264        default:
265 badtype:
266                errx(exit_jump, 1, "node type must be 'b', 'c' or 'p'.");
267        }
268        argc--;
269        argv++;
270
271        if (fifo) {
272                if (argc != 0)
273                        usage(globals);
274        } else {
275                if (argc < 1 || argc > MAXARGS)
276                        usage(globals);
277        }
278
279        for (n = 0; n < argc; n++) {
280                errno = 0;
281                numbers[n] = strtoul(argv[n], &p, 0);
282                if (*p == 0 && errno == 0)
283                        continue;
284#ifdef KERN_DRIVERS
285                if (n == 0) {
286                        major = major_from_name(argv[0], mode);
287                        if (major != -1) {
288                                numbers[0] = major;
289                                continue;
290                        }
291                        if (!isdigit(*(unsigned char *)argv[0]))
292                                errx(1, "unknown driver: %s", argv[0]);
293                }
294#endif
295                errx(exit_jump, 1, "invalid number: %s", argv[n]);
296        }
297
298        switch (argc) {
299        case 0:
300                dev = 0;
301                break;
302
303        case 1:
304                dev = numbers[0];
305                break;
306
307        default:
308                dev = callPack(globals, pack, argc, numbers);
309                break;
310        }
311
312#if RTEMS_REMOVED
313        if (modes != NULL)
314                mode = getmode(modes, mode);
315#endif
316        umask(0);
317        rval = fifo ? mkfifo(name, mode) : mknod(name, mode, dev);
318        if (rval < 0 && errno == EEXIST && r_flag) {
319                struct stat sb;
320                if (lstat(name, &sb) != 0 || (!fifo && sb.st_rdev != dev))
321                        sb.st_mode = 0;
322
323                if ((sb.st_mode & S_IFMT) == (mode & S_IFMT)) {
324                        if (r_flag == 1)
325                                /* Ignore permissions and user/group */
326                                return 0;
327                        if (sb.st_mode != mode)
328                                rval = chmod(name, mode);
329                        else
330                                rval = 0;
331                } else {
332                        unlink(name);
333                        rval = fifo ? mkfifo(name, mode)
334                                    : mknod(name, mode, dev);
335                }
336        }
337        if (rval < 0)
338                err(exit_jump, 1, "%s", name);
339        if ((uid != (uid_t)-1 || gid != (uid_t)-1) && chown(name, uid, gid) == -1)
340                /* XXX Should we unlink the files here? */
341                warn("%s: uid/gid not changed", name);
342
343        return 0;
344}
345
346static void
347usage(rtems_shell_mknod_globals* globals)
348{
349        const char *progname = getprogname();
350
351        (void)fprintf(stderr,
352            "usage: %s [-rR] [-F format] [-m mode] [-u user] [-g group]\n",
353            progname);
354        (void)fprintf(stderr,
355#ifdef KERN_DRIVERS
356            "                   [ name [b | c] [major | driver] minor\n"
357#else
358            "                   [ name [b | c] major minor\n"
359#endif
360            "                   | name [b | c] major unit subunit\n"
361            "                   | name [b | c] number\n"
362            "                   | name p ]\n");
363#ifdef KERN_DRIVERS
364        (void)fprintf(stderr, "       %s -l [driver] ...\n", progname);
365#endif
366        exit(1);
367}
368
369static int
370gid_name(const char *name, gid_t *gid)
371{
372        struct group *g;
373
374        g = getgrnam(name);
375        if (!g)
376                return -1;
377        *gid = g->gr_gid;
378        return 0;
379}
380
381static portdev_t
382callPack(rtems_shell_mknod_globals* globals, pack_t *f, int n, u_long *numbers)
383{
384        portdev_t d;
385        const char *error = NULL;
386
387        d = (*f)(n, numbers, &error);
388        if (error != NULL)
389                errx(exit_jump, 1, "%s", error);
390        return d;
391}
392
393#ifdef KERN_DRIVERS
394static void
395get_device_info(void)
396{
397        static int mib[2] = {CTL_KERN, KERN_DRIVERS};
398        size_t len;
399
400        if (sysctl(mib, 2, NULL, &len, NULL, 0) != 0)
401                err(1, "kern.drivers" );
402        kern_drivers = malloc(len);
403        if (kern_drivers == NULL)
404                err(1, "malloc");
405        if (sysctl(mib, 2, kern_drivers, &len, NULL, 0) != 0)
406                err(1, "kern.drivers" );
407
408        num_drivers = len / sizeof *kern_drivers;
409}
410
411static void
412print_device_info(char **names)
413{
414        int i;
415        struct kinfo_drivers *kd;
416
417        if (kern_drivers == NULL)
418                get_device_info();
419
420        do {
421                kd = kern_drivers;
422                for (i = 0; i < num_drivers; kd++, i++) {
423                        if (*names && strcmp(*names, kd->d_name))
424                                continue;
425                        printf("%s", kd->d_name);
426                        if (kd->d_cmajor != -1)
427                                printf(" character major %d", kd->d_cmajor);
428                        if (kd->d_bmajor != -1)
429                                printf(" block major %d", kd->d_bmajor);
430                        printf("\n");
431                }
432        } while (*names && *++names);
433}
434
435static int
436major_from_name(const char *name, mode_t mode)
437{
438        int i;
439        struct kinfo_drivers *kd;
440
441        if (kern_drivers == NULL)
442                get_device_info();
443
444        kd = kern_drivers;
445        for (i = 0; i < num_drivers; kd++, i++) {
446                if (strcmp(name, kd->d_name))
447                        continue;
448                if (S_ISCHR(mode))
449                        return kd->d_cmajor;
450                return kd->d_bmajor;
451        }
452        return -1;
453}
454#endif
455
456rtems_shell_cmd_t rtems_shell_MKNOD_Command = {
457  "mknod",                                                   /* name */
458  "mknod mknod [-rR] [-F fmt] [-m mode] name [c | b] minor", /* usage */
459  "files",                                                   /* topic */
460  rtems_shell_main_mknod,                                    /* command */
461  NULL,                                                      /* alias */
462  NULL                                                       /* next */
463};
Note: See TracBrowser for help on using the repository browser.