Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:19

0001 /*  $NetBSD: mknod.c,v 1.39 2009/02/13 01:37:23 lukem Exp $ */
0002 
0003 /*-
0004  * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
0005  * All rights reserved.
0006  *
0007  * This code is derived from software contributed to The NetBSD Foundation
0008  * by Charles M. Hannum.
0009  *
0010  * Redistribution and use in source and binary forms, with or without
0011  * modification, are permitted provided that the following conditions
0012  * are met:
0013  * 1. Redistributions of source code must retain the above copyright
0014  *    notice, this list of conditions and the following disclaimer.
0015  * 2. Redistributions in binary form must reproduce the above copyright
0016  *    notice, this list of conditions and the following disclaimer in the
0017  *    documentation and/or other materials provided with the distribution.
0018  *
0019  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
0020  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
0021  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
0022  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
0023  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0024  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0025  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0026  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0027  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0028  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0029  * POSSIBILITY OF SUCH DAMAGE.
0030  */
0031 
0032 #ifdef HAVE_CONFIG_H
0033 #include "config.h"
0034 #endif
0035 
0036 #if HAVE_NBTOOL_CONFIG_H
0037 #include "nbtool_config.h"
0038 #endif
0039 
0040 #if 0
0041 #ifndef lint
0042 __COPYRIGHT("@(#) Copyright (c) 1998\
0043  The NetBSD Foundation, Inc.  All rights reserved.");
0044 __RCSID("$NetBSD: mknod.c,v 1.39 2009/02/13 01:37:23 lukem Exp $");
0045 #endif /* not lint */
0046 #endif
0047 
0048 #include <rtems.h>
0049 #include <rtems/shell.h>
0050 #include <rtems/shellconfig.h>
0051 #define __need_getopt_newlib
0052 #include <getopt.h>
0053 
0054 #include <sys/cdefs.h>
0055 
0056 #include <sys/types.h>
0057 #include <sys/stat.h>
0058 #include <sys/param.h>
0059 #if !HAVE_NBTOOL_CONFIG_H && defined(KERN_DRIVERS)
0060 #include <sys/sysctl.h>
0061 #endif
0062 
0063 #include "err.h"
0064 #include <errno.h>
0065 #include <limits.h>
0066 #include <stdio.h>
0067 #include <stdlib.h>
0068 #include <unistd.h>
0069 #include <pwd.h>
0070 #include <grp.h>
0071 #include <string.h>
0072 #include <ctype.h>
0073 
0074 #include "mknod-pack_dev.h"
0075 
0076 #include <setjmp.h>
0077 
0078 typedef struct {
0079   int exit_code;
0080   jmp_buf exit_jmp;
0081 } rtems_shell_mknod_globals;
0082 
0083 #define exit_jump &(globals->exit_jmp)
0084 
0085 #define exit(ec) rtems_shell_mknod_exit(globals, ec)
0086 
0087 static int gid_name(const char *, gid_t *);
0088 static portdev_t callPack(rtems_shell_mknod_globals* globals,
0089                           pack_t *, int, u_long *);
0090 
0091 static int  main_mknod(rtems_shell_mknod_globals*, int, char *[]);
0092 static  void    usage(rtems_shell_mknod_globals* );
0093 
0094 static void
0095 rtems_shell_mknod_exit (rtems_shell_mknod_globals* globals, int code)
0096 {
0097   globals->exit_code = code;
0098   longjmp (globals->exit_jmp, 1);
0099 }
0100 
0101 #include "mknod-pack_dev.c"
0102 
0103 static int
0104 rtems_shell_main_mknod(int argc, char *argv[])
0105 {
0106   rtems_shell_mknod_globals  mknod_globals;
0107   rtems_shell_mknod_globals* globals = &mknod_globals;
0108   memset (globals, 0, sizeof (mknod_globals));
0109   mknod_globals.exit_code = 1;
0110   if (setjmp (mknod_globals.exit_jmp) == 0)
0111     return main_mknod (globals, argc, argv);
0112   return mknod_globals.exit_code;
0113 }
0114 
0115 #define getprogname() "mknod"
0116 
0117 #ifdef KERN_DRIVERS
0118 #error invalid for RTEMS
0119 static struct kinfo_drivers *kern_drivers;
0120 static int num_drivers;
0121 
0122 static void get_device_info(void);
0123 static void print_device_info(char **);
0124 static int major_from_name(const char *, mode_t);
0125 #endif
0126 
0127 #define MAXARGS 3       /* 3 for bsdos, 2 for rest */
0128 
0129 int
0130 main_mknod(rtems_shell_mknod_globals* globals, int argc, char **argv)
0131 {
0132     char    *name, *p;
0133     mode_t   mode;
0134     portdev_t    dev;
0135     pack_t  *pack;
0136     u_long   numbers[MAXARGS];
0137     int  n, ch, fifo, hasformat;
0138     int  r_flag = 0;        /* force: delete existing entry */
0139 #ifdef KERN_DRIVERS
0140     int  l_flag = 0;        /* list device names and numbers */
0141     int  major;
0142 #endif
0143 #if RTEMS_REMOVED
0144     void    *modes = 0;
0145 #endif
0146     uid_t    uid = -1;
0147     gid_t    gid = -1;
0148     int  rval;
0149 
0150     struct getopt_data getopt_reent;
0151     memset(&getopt_reent, 0, sizeof(getopt_data));
0152 
0153     dev = 0;
0154     fifo = hasformat = 0;
0155     pack = pack_native;
0156 
0157 #ifdef KERN_DRIVERS
0158     while ((ch = getopt(argc, argv, "lrRF:g:m:u:")) != -1) {
0159 #else
0160     while ((ch = getopt_r(argc, argv, "rRF:g:m:u:", &getopt_reent)) != -1) {
0161 #endif
0162         switch (ch) {
0163 
0164 #ifdef KERN_DRIVERS
0165         case 'l':
0166             l_flag = 1;
0167             break;
0168 #endif
0169 
0170         case 'r':
0171             r_flag = 1;
0172             break;
0173 
0174         case 'R':
0175             r_flag = 2;
0176             break;
0177 
0178         case 'F':
0179             pack = pack_find(getopt_reent.optarg);
0180             if (pack == NULL)
0181                 errx(exit_jump, 1, "invalid format: %s", getopt_reent.optarg);
0182             hasformat++;
0183             break;
0184 
0185         case 'g':
0186             if (getopt_reent.optarg[0] == '#') {
0187                 gid = strtol(getopt_reent.optarg + 1, &p, 10);
0188                 if (*p == 0)
0189                     break;
0190             }
0191             if (gid_name(getopt_reent.optarg, &gid) == 0)
0192                 break;
0193             gid = strtol(getopt_reent.optarg, &p, 10);
0194             if (*p == 0)
0195                 break;
0196             errx(exit_jump, 1, "%s: invalid group name", getopt_reent.optarg);
0197 
0198         case 'm':
0199 #if RTEMS_REMOVED
0200             modes = setmode(getopt_reent.optarg);
0201             if (modes == NULL)
0202 #endif
0203                 err(exit_jump, 1, "Cannot set file mode `%s'", getopt_reent.optarg);
0204             break;
0205 
0206         case 'u':
0207             if (getopt_reent.optarg[0] == '#') {
0208                 uid = strtol(getopt_reent.optarg + 1, &p, 10);
0209                 if (*p == 0)
0210                     break;
0211             }
0212 #if RTEMS_REMOVED
0213             if (uid_from_user(getopt_reent.optarg, &uid) == 0)
0214                 break;
0215 #endif
0216             uid = strtol(getopt_reent.optarg, &p, 10);
0217             if (*p == 0)
0218                 break;
0219             errx(exit_jump, 1, "%s: invalid user name", getopt_reent.optarg);
0220 
0221         default:
0222         case '?':
0223             usage(globals);
0224         }
0225     }
0226     argc -= getopt_reent.optind;
0227     argv += getopt_reent.optind;
0228 
0229 #ifdef KERN_DRIVERS
0230     if (l_flag) {
0231         print_device_info(argv);
0232         return 0;
0233     }
0234 #endif
0235 
0236     if (argc < 2 || argc > 10)
0237         usage(globals);
0238 
0239     name = *argv;
0240     argc--;
0241     argv++;
0242 
0243     umask(mode = umask(0));
0244     mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) & ~mode;
0245 
0246     if (argv[0][1] != '\0')
0247         goto badtype;
0248     switch (*argv[0]) {
0249     case 'c':
0250         mode |= S_IFCHR;
0251         break;
0252 
0253     case 'b':
0254         mode |= S_IFBLK;
0255         break;
0256 
0257     case 'p':
0258         if (hasformat)
0259             errx(exit_jump, 1, "format is meaningless for fifos");
0260         mode |= S_IFIFO;
0261         fifo = 1;
0262         break;
0263 
0264     default:
0265  badtype:
0266         errx(exit_jump, 1, "node type must be 'b', 'c' or 'p'.");
0267     }
0268     argc--;
0269     argv++;
0270 
0271     if (fifo) {
0272         if (argc != 0)
0273             usage(globals);
0274     } else {
0275         if (argc < 1 || argc > MAXARGS)
0276             usage(globals);
0277     }
0278 
0279     for (n = 0; n < argc; n++) {
0280         errno = 0;
0281         numbers[n] = strtoul(argv[n], &p, 0);
0282         if (*p == 0 && errno == 0)
0283             continue;
0284 #ifdef KERN_DRIVERS
0285         if (n == 0) {
0286             major = major_from_name(argv[0], mode);
0287             if (major != -1) {
0288                 numbers[0] = major;
0289                 continue;
0290             }
0291             if (!isdigit(*(unsigned char *)argv[0]))
0292                 errx(1, "unknown driver: %s", argv[0]);
0293         }
0294 #endif
0295         errx(exit_jump, 1, "invalid number: %s", argv[n]);
0296     }
0297 
0298     switch (argc) {
0299     case 0:
0300         dev = 0;
0301         break;
0302 
0303     case 1:
0304         dev = numbers[0];
0305         break;
0306 
0307     default:
0308         dev = callPack(globals, pack, argc, numbers);
0309         break;
0310     }
0311 
0312 #if RTEMS_REMOVED
0313     if (modes != NULL)
0314         mode = getmode(modes, mode);
0315 #endif
0316     umask(0);
0317     rval = fifo ? mkfifo(name, mode) : mknod(name, mode, dev);
0318     if (rval < 0 && errno == EEXIST && r_flag) {
0319         struct stat sb;
0320         if (lstat(name, &sb) != 0 || (!fifo && sb.st_rdev != dev))
0321             sb.st_mode = 0;
0322 
0323         if ((sb.st_mode & S_IFMT) == (mode & S_IFMT)) {
0324             if (r_flag == 1)
0325                 /* Ignore permissions and user/group */
0326                 return 0;
0327             if (sb.st_mode != mode)
0328                 rval = chmod(name, mode);
0329             else
0330                 rval = 0;
0331         } else {
0332             unlink(name);
0333             rval = fifo ? mkfifo(name, mode)
0334                     : mknod(name, mode, dev);
0335         }
0336     }
0337     if (rval < 0)
0338         err(exit_jump, 1, "%s", name);
0339     if ((uid != (uid_t)-1 || gid != (uid_t)-1) && chown(name, uid, gid) == -1)
0340         /* XXX Should we unlink the files here? */
0341         warn("%s: uid/gid not changed", name);
0342 
0343     return 0;
0344 }
0345 
0346 static void
0347 usage(rtems_shell_mknod_globals* globals)
0348 {
0349     const char *progname = getprogname();
0350 
0351     (void)fprintf(stderr,
0352         "usage: %s [-rR] [-F format] [-m mode] [-u user] [-g group]\n",
0353         progname);
0354     (void)fprintf(stderr,
0355 #ifdef KERN_DRIVERS
0356         "                   [ name [b | c] [major | driver] minor\n"
0357 #else
0358         "                   [ name [b | c] major minor\n"
0359 #endif
0360         "                   | name [b | c] major unit subunit\n"
0361         "                   | name [b | c] number\n"
0362         "                   | name p ]\n");
0363 #ifdef KERN_DRIVERS
0364     (void)fprintf(stderr, "       %s -l [driver] ...\n", progname);
0365 #endif
0366     exit(1);
0367 }
0368 
0369 static int
0370 gid_name(const char *name, gid_t *gid)
0371 {
0372     struct group *g;
0373 
0374     g = getgrnam(name);
0375     if (!g)
0376         return -1;
0377     *gid = g->gr_gid;
0378     return 0;
0379 }
0380 
0381 static portdev_t
0382 callPack(rtems_shell_mknod_globals* globals, pack_t *f, int n, u_long *numbers)
0383 {
0384     portdev_t d;
0385     const char *error = NULL;
0386 
0387     d = (*f)(n, numbers, &error);
0388     if (error != NULL)
0389         errx(exit_jump, 1, "%s", error);
0390     return d;
0391 }
0392 
0393 #ifdef KERN_DRIVERS
0394 static void
0395 get_device_info(void)
0396 {
0397     static int mib[2] = {CTL_KERN, KERN_DRIVERS};
0398     size_t len;
0399 
0400     if (sysctl(mib, 2, NULL, &len, NULL, 0) != 0)
0401         err(1, "kern.drivers" );
0402     kern_drivers = malloc(len);
0403     if (kern_drivers == NULL)
0404         err(1, "malloc");
0405     if (sysctl(mib, 2, kern_drivers, &len, NULL, 0) != 0)
0406         err(1, "kern.drivers" );
0407 
0408     num_drivers = len / sizeof *kern_drivers;
0409 }
0410 
0411 static void
0412 print_device_info(char **names)
0413 {
0414     int i;
0415     struct kinfo_drivers *kd;
0416 
0417     if (kern_drivers == NULL)
0418         get_device_info();
0419 
0420     do {
0421         kd = kern_drivers;
0422         for (i = 0; i < num_drivers; kd++, i++) {
0423             if (*names && strcmp(*names, kd->d_name))
0424                 continue;
0425             printf("%s", kd->d_name);
0426             if (kd->d_cmajor != -1)
0427                 printf(" character major %d", kd->d_cmajor);
0428             if (kd->d_bmajor != -1)
0429                 printf(" block major %d", kd->d_bmajor);
0430             printf("\n");
0431         }
0432     } while (*names && *++names);
0433 }
0434 
0435 static int
0436 major_from_name(const char *name, mode_t mode)
0437 {
0438     int i;
0439     struct kinfo_drivers *kd;
0440 
0441     if (kern_drivers == NULL)
0442         get_device_info();
0443 
0444     kd = kern_drivers;
0445     for (i = 0; i < num_drivers; kd++, i++) {
0446         if (strcmp(name, kd->d_name))
0447             continue;
0448         if (S_ISCHR(mode))
0449             return kd->d_cmajor;
0450         return kd->d_bmajor;
0451     }
0452     return -1;
0453 }
0454 #endif
0455 
0456 rtems_shell_cmd_t rtems_shell_MKNOD_Command = {
0457   "mknod",                                                   /* name */
0458   "mknod mknod [-rR] [-F fmt] [-m mode] name [c | b] minor", /* usage */
0459   "files",                                                   /* topic */
0460   rtems_shell_main_mknod,                                    /* command */
0461   NULL,                                                      /* alias */
0462   NULL                                                       /* next */
0463 };