int mknod_main(int argc, char **argv) { mode_t mode; dev_t dev; const char *name; mode = getopt_mk_fifo_nod(argc, argv); argv += optind; argc -= optind; if ((argc >= 2) && ((name = strchr(modes_chars, argv[1][0])) != NULL)) { mode |= modes_cubp[(int)(name[4])]; dev = 0; if ((*name != 'p') && ((argc -= 2) == 2)) { /* Autodetect what the system supports; these macros should * optimize out to two constants. */ dev = makedev(xatoul_range(argv[2], 0, major(UINT_MAX)), xatoul_range(argv[3], 0, minor(UINT_MAX))); } if (argc == 2) { name = *argv; if (mknod(name, mode, dev) == 0) { return EXIT_SUCCESS; } bb_perror_msg_and_die("%s", name); } } bb_show_usage(); }
int vconfig_main(int argc, char **argv) { struct vlan_ioctl_args ifr; const char *p; int fd; if (argc < 3) { bb_show_usage(); } /* Don't bother closing the filedes. It will be closed on cleanup. */ /* Will die if 802.1q is not present */ xopen(conf_file_name, O_RDONLY); memset(&ifr, 0, sizeof(struct vlan_ioctl_args)); ++argv; p = xfind_str(cmds+2, *argv); ifr.cmd = *p; if (argc != p[-1]) { bb_show_usage(); } if (ifr.cmd == SET_VLAN_NAME_TYPE_CMD) { /* set_name_type */ ifr.u.name_type = *xfind_str(name_types+1, argv[1]); } else { if (strlen(argv[1]) >= IF_NAMESIZE) { bb_error_msg_and_die("if_name >= %d chars", IF_NAMESIZE); } strcpy(ifr.device1, argv[1]); p = argv[2]; /* I suppose one could try to combine some of the function calls below, * since ifr.u.flag, ifr.u.VID, and ifr.u.skb_priority are all same-sized * (unsigned) int members of a unions. But because of the range checking, * doing so wouldn't save that much space and would also make maintainence * more of a pain. */ if (ifr.cmd == SET_VLAN_FLAG_CMD) { /* set_flag */ ifr.u.flag = xatoul_range(p, 0, 1); /* DM: in order to set reorder header, qos must be set */ ifr.vlan_qos = xatoul_range(argv[3], 0, 7); } else if (ifr.cmd == ADD_VLAN_CMD) { /* add */ ifr.u.VID = xatoul_range(p, 0, VLAN_GROUP_ARRAY_LEN-1); } else if (ifr.cmd != DEL_VLAN_CMD) { /* set_{egress|ingress}_map */ ifr.u.skb_priority = xatou(p); ifr.vlan_qos = xatoul_range(argv[3], 0, 7); } } fd = xsocket(AF_INET, SOCK_STREAM, 0); if (ioctl(fd, SIOCSIFVLAN, &ifr) < 0) { bb_perror_msg_and_die("ioctl error for %s", *argv); } return 0; }
int dmesg_main(int argc ATTRIBUTE_UNUSED, char **argv) { int len; char *buf; char *size, *level; unsigned flags = getopt32(argv, "cs:n:", &size, &level); enum { OPT_c = 1<<0, OPT_s = 1<<1, OPT_n = 1<<2 }; if (flags & OPT_n) { if (klogctl(8, NULL, xatoul_range(level, 0, 10))) bb_perror_msg_and_die("klogctl"); return EXIT_SUCCESS; } len = (flags & OPT_s) ? xatoul_range(size, 2, INT_MAX) : 16384; buf = xmalloc(len); len = klogctl(3 + (flags & OPT_c), buf, len); if (len < 0) bb_perror_msg_and_die("klogctl"); if (len == 0) return EXIT_SUCCESS; /* Skip <#> at the start of lines, and make sure we end with a newline. */ if (ENABLE_FEATURE_DMESG_PRETTY) { int last = '\n'; int in = 0; do { if (last == '\n' && buf[in] == '<') in += 3; else { last = buf[in++]; bb_putchar(last); } } while (in < len); if (last != '\n') bb_putchar('\n'); } else { full_write(STDOUT_FILENO, buf, len); if (buf[len-1] != '\n') bb_putchar('\n'); } if (ENABLE_FEATURE_CLEAN_UP) free(buf); return EXIT_SUCCESS; }
int openvt_main(int argc, char **argv) { int fd; char vtname[sizeof(VC_FORMAT) + 2]; if (argc < 3) { bb_show_usage(); } /* check for illegal vt number: < 1 or > 63 */ sprintf(vtname, VC_FORMAT, (int)xatoul_range(argv[1], 1, 63)); if (fork() == 0) { /* child */ /* leave current vt (controlling tty) */ setsid(); /* and grab new one */ fd = xopen(vtname, O_RDWR); /* Reassign stdin, stdout and sterr */ dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); while (fd > 2) close(fd--); BB_EXECVP(argv[2], &argv[2]); _exit(1); } return EXIT_SUCCESS; }
int ipcalc_main(int argc UNUSED_PARAM, char **argv) { unsigned opt; bool have_netmask = 0; struct in_addr s_netmask, s_broadcast, s_network, s_ipaddr; /* struct in_addr { in_addr_t s_addr; } and in_addr_t * (which in turn is just a typedef to uint32_t) * are essentially the same type. A few macros for less verbosity: */ #define netmask (s_netmask.s_addr) #define broadcast (s_broadcast.s_addr) #define network (s_network.s_addr) #define ipaddr (s_ipaddr.s_addr) char *ipstr; #if ENABLE_FEATURE_IPCALC_LONG_OPTIONS applet_long_options = ipcalc_longopts; #endif opt_complementary = "-1:?2"; /* minimum 1 arg, maximum 2 args */ opt = getopt32(argv, "mbn" IF_FEATURE_IPCALC_FANCY("phs")); argv += optind; if (opt & SILENT) logmode = LOGMODE_NONE; /* suppress error_msg() output */ opt &= ~SILENT; if (!(opt & (BROADCAST | NETWORK | NETPREFIX))) { /* if no options at all or * (no broadcast,network,prefix) and (two args)... */ if (!opt || argv[1]) bb_show_usage(); } ipstr = argv[0]; if (ENABLE_FEATURE_IPCALC_FANCY) { unsigned long netprefix = 0; char *prefixstr; prefixstr = ipstr; while (*prefixstr) { if (*prefixstr == '/') { *prefixstr++ = '\0'; if (*prefixstr) { unsigned msk; netprefix = xatoul_range(prefixstr, 0, 32); netmask = 0; msk = 0x80000000; while (netprefix > 0) { netmask |= msk; msk >>= 1; netprefix--; } netmask = htonl(netmask); /* Even if it was 0, we will signify that we have a netmask. This allows */ /* for specification of default routes, etc which have a 0 netmask/prefix */ have_netmask = 1; } break; } prefixstr++; } }
int ipcalc_main(int argc, char **argv) { unsigned opt; int have_netmask = 0; in_addr_t netmask, broadcast, network, ipaddr; struct in_addr a; char *ipstr; #if ENABLE_FEATURE_IPCALC_LONG_OPTIONS applet_long_options = ipcalc_longopts; #endif opt = getopt32(argv, "mbn" USE_FEATURE_IPCALC_FANCY("phs")); argc -= optind; argv += optind; if (opt & (BROADCAST | NETWORK | NETPREFIX)) { if (argc > 2 || argc <= 0) bb_show_usage(); } else { if (argc != 1) bb_show_usage(); } if (opt & SILENT) logmode = LOGMODE_NONE; /* Suppress error_msg() output */ ipstr = argv[0]; if (ENABLE_FEATURE_IPCALC_FANCY) { unsigned long netprefix = 0; char *prefixstr; prefixstr = ipstr; while (*prefixstr) { if (*prefixstr == '/') { *prefixstr = (char)0; prefixstr++; if (*prefixstr) { unsigned msk; netprefix = xatoul_range(prefixstr, 0, 32); netmask = 0; msk = 0x80000000; while (netprefix > 0) { netmask |= msk; msk >>= 1; netprefix--; } netmask = htonl(netmask); /* Even if it was 0, we will signify that we have a netmask. This allows */ /* for specification of default routes, etc which have a 0 netmask/prefix */ have_netmask = 1; } break; } prefixstr++; } }
int taskset_main(int argc, char** argv) { cpu_set_t mask, new_mask; pid_t pid = 0; unsigned opt; const char *state = "current\0new"; char *p_opt = NULL, *aff = NULL; opt = getopt32(argc, argv, "+p:", &p_opt); if (opt & OPT_p) { if (argc == optind+1) { /* -p <aff> <pid> */ aff = p_opt; p_opt = argv[optind]; } argv += optind; /* me -p <arg> */ pid = xatoul_range(p_opt, 1, ULONG_MAX); /* -p <pid> */ } else aff = *++argv; /* <aff> <cmd...> */ if (aff) { unsigned i = 0; unsigned long l = xstrtol_range(aff, 0, 1, LONG_MAX); CPU_ZERO(&new_mask); while (i < CPU_SETSIZE && l >= (1<<i)) { if ((1<<i) & l) CPU_SET(i, &new_mask); ++i; } } if (opt & OPT_p) { print_aff: if (sched_getaffinity(pid, sizeof(mask), &mask) < 0) bb_perror_msg_and_die("failed to %cet pid %d's affinity", 'g', pid); printf("pid %d's %s affinity mask: "TASKSET_PRINTF_MASK"\n", pid, state, from_cpuset(mask)); if (!*argv) /* no new affinity given or we did print already, done. */ return EXIT_SUCCESS; } if (sched_setaffinity(pid, sizeof(new_mask), &new_mask)) bb_perror_msg_and_die("failed to %cet pid %d's affinity", 's', pid); if (opt & OPT_p) { state += 8; ++argv; goto print_aff; } ++argv; BB_EXECVP(*argv, argv); bb_perror_msg_and_die("%s", *argv); }
int dmesg_main(int argc, char **argv) { char *size, *level; int flags = getopt32(argv, "cs:n:", &size, &level); if (flags & 4) { if (klogctl(8, NULL, xatoul_range(level, 0, 10))) bb_perror_msg_and_die("klogctl"); } else { int len; char *buf; len = (flags & 2) ? xatoul_range(size, 2, INT_MAX) : 16384; buf = xmalloc(len); if (0 > (len = klogctl(3 + (flags & 1), buf, len))) bb_perror_msg_and_die("klogctl"); // Skip <#> at the start of lines, and make sure we end with a newline. if (ENABLE_FEATURE_DMESG_PRETTY) { int last = '\n'; int in; for (in = 0; in<len;) { if (last == '\n' && buf[in] == '<') in += 3; else bb_putchar(last = buf[in++]); } if (last != '\n') bb_putchar('\n'); } else { write(1,buf,len); if (len && buf[len-1]!='\n') bb_putchar('\n'); } if (ENABLE_FEATURE_CLEAN_UP) free(buf); } return 0; }
static NOINLINE void INET_setroute(int action, char **args) { /* char buffer instead of bona-fide struct avoids aliasing warning */ char rt_buf[sizeof(struct rtentry)]; struct rtentry *const rt = (void *)rt_buf; const char *netmask = NULL; int skfd, isnet, xflag; /* Grab the -net or -host options. Remember they were transformed. */ xflag = kw_lookup(tbl_hash_net_host, &args); /* If we did grab -net or -host, make sure we still have an arg left. */ if (*args == NULL) { bb_show_usage(); } /* Clean out the RTREQ structure. */ memset(rt, 0, sizeof(*rt)); { const char *target = *args++; char *prefix; /* recognize x.x.x.x/mask format. */ prefix = strchr(target, '/'); if (prefix) { int prefix_len; prefix_len = xatoul_range(prefix+1, 0, 32); mask_in_addr(*rt) = htonl( ~(0xffffffffUL >> prefix_len)); *prefix = '\0'; #if HAVE_NEW_ADDRT rt->rt_genmask.sa_family = AF_INET; #endif } else { /* Default netmask. */ netmask = "default"; } /* Prefer hostname lookup is -host flag (xflag==1) was given. */ isnet = INET_resolve(target, (struct sockaddr_in *) &rt->rt_dst, (xflag & HOST_FLAG)); if (isnet < 0) { bb_error_msg_and_die("resolving %s", target); } if (prefix) { /* do not destroy prefix for process args */ *prefix = '/'; } }
static int xconnect_ftpdata(ftp_host_info_t *server, char *buf) { printf("xconnect_ftpdata++++++++++++++++++++++\n"); char *buf_ptr; unsigned short port_num; /* Response is "NNN garbageN1,N2,N3,N4,P1,P2[)garbage] * Server's IP is N1.N2.N3.N4 (we ignore it) * Server's port for data connection is P1*256+P2 */ buf_ptr = strrchr(buf, ')'); if (buf_ptr) *buf_ptr = '\0'; buf_ptr = strrchr(buf, ','); *buf_ptr = '\0'; port_num = xatoul_range(buf_ptr + 1, 0, 255); buf_ptr = strrchr(buf, ','); *buf_ptr = '\0'; port_num += xatoul_range(buf_ptr + 1, 0, 255) * 256; set_nport(server->lsa, htons(port_num)); printf("xconnect_ftpdata============\n"); return xconnect_stream(server->lsa); }
int chvt_main(int argc, char **argv) { int fd, num; if (argc != 2) { bb_show_usage(); } fd = get_console_fd(); num = xatoul_range(argv[1], 1, 63); if ((-1 == ioctl(fd, VT_ACTIVATE, num)) || (-1 == ioctl(fd, VT_WAITACTIVE, num))) { bb_perror_msg_and_die("ioctl"); } return EXIT_SUCCESS; }
int chrt_main(int argc, char **argv) { pid_t pid = 0; unsigned opt; struct sched_param sp; char *p_opt = NULL, *priority = NULL; const char *state = "current\0new"; int prio = 0, policy = SCHED_RR; opt_complementary = "r--fo:f--ro:r--fo"; /* only one policy accepted */ opt = getopt32(argv, "+mp:rfo", &p_opt); if (opt & OPT_r) policy = SCHED_RR; if (opt & OPT_f) policy = SCHED_FIFO; if (opt & OPT_o) policy = SCHED_OTHER; if (opt & OPT_m) { /* print min/max */ show_min_max(SCHED_FIFO); show_min_max(SCHED_RR); show_min_max(SCHED_OTHER); fflush_stdout_and_exit(EXIT_SUCCESS); } if (opt & OPT_p) { if (argc == optind+1) { /* -p <priority> <pid> */ priority = p_opt; p_opt = argv[optind]; } argv += optind; /* me -p <arg> */ pid = xatoul_range(p_opt, 1, ULONG_MAX); /* -p <pid> */ } else { argv += optind; /* me -p <arg> */ priority = *argv; } if (priority) { /* from the manpage of sched_getscheduler: [...] sched_priority can have a value in the range 0 to 99. [...] SCHED_OTHER or SCHED_BATCH must be assigned the static priority 0. [...] SCHED_FIFO or SCHED_RR can have a static priority in the range 1 to 99. */ prio = xstrtol_range(priority, 0, policy == SCHED_OTHER ? 0 : 1, 99); } if (opt & OPT_p) { int pol = 0; print_rt_info: pol = sched_getscheduler(pid); if (pol < 0) bb_perror_msg_and_die("failed to %cet pid %d's policy", 'g', pid); printf("pid %d's %s scheduling policy: %s\n", pid, state, policies[pol].name); if (sched_getparam(pid, &sp)) bb_perror_msg_and_die("failed to get pid %d's attributes", pid); printf("pid %d's %s scheduling priority: %d\n", pid, state, sp.sched_priority); if (!*argv) /* no new prio given or we did print already, done. */ return EXIT_SUCCESS; } sp.sched_priority = prio; if (sched_setscheduler(pid, policy, &sp) < 0) bb_perror_msg_and_die("failed to %cet pid %d's policy", 's', pid); if (opt & OPT_p) { state += 8; ++argv; goto print_rt_info; } ++argv; BB_EXECVP(*argv, argv); bb_simple_perror_msg_and_die(*argv); }
int arping_main(int argc, char **argv) { const char *device = "eth0"; int ifindex; char *source = NULL; char *target; s = xsocket(PF_PACKET, SOCK_DGRAM, 0); // Drop suid root privileges xsetuid(getuid()); { unsigned opt; char *_count, *_timeout; /* Dad also sets quit_on_reply. * Advert also sets unsolicited. */ opt_complementary = "Df:AU"; opt = getopt32(argc, argv, "DUAqfbc:w:i:s:", &_count, &_timeout, &device, &source); cfg |= opt & 0x3f; /* set respective flags */ if (opt & 0x40) /* -c: count */ count = xatou(_count); if (opt & 0x80) /* -w: timeout */ timeout = xatoul_range(_timeout, 0, INT_MAX/2000); //if (opt & 0x100) /* -i: interface */ if (strlen(device) > IF_NAMESIZE) { bb_error_msg_and_die("interface name '%s' is too long", device); } //if (opt & 0x200) /* -s: source */ } argc -= optind; argv += optind; if (argc != 1) bb_show_usage(); target = *argv; xfunc_error_retval = 2; { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, device, IFNAMSIZ - 1); if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { bb_error_msg_and_die("interface %s not found", device); } ifindex = ifr.ifr_ifindex; if (ioctl(s, SIOCGIFFLAGS, (char *) &ifr)) { bb_error_msg_and_die("SIOCGIFFLAGS"); } if (!(ifr.ifr_flags & IFF_UP)) { bb_error_msg_and_die("interface %s is down", device); } if (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) { bb_error_msg("interface %s is not ARPable", device); return (cfg & dad ? 0 : 2); } } if (!inet_aton(target, &dst)) { len_and_sockaddr *lsa; lsa = xhost_and_af2sockaddr(target, 0, AF_INET); memcpy(&dst, &lsa->sin.sin_addr.s_addr, 4); if (ENABLE_FEATURE_CLEAN_UP) free(lsa); } if (source && !inet_aton(source, &src)) { bb_error_msg_and_die("invalid source address %s", source); } if (!(cfg & dad) && (cfg & unsolicited) && src.s_addr == 0) src = dst; if (!(cfg & dad) || src.s_addr) { struct sockaddr_in saddr; int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0); if (device) { if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device) + 1) == -1) bb_error_msg("warning: interface %s is ignored", device); } memset(&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; if (src.s_addr) { saddr.sin_addr = src; xbind(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); } else if (!(cfg & dad)) { socklen_t alen = sizeof(saddr); saddr.sin_port = htons(1025); saddr.sin_addr = dst; if (setsockopt(probe_fd, SOL_SOCKET, SO_DONTROUTE, &const_int_1, sizeof(const_int_1)) == -1) bb_perror_msg("warning: setsockopt(SO_DONTROUTE)"); xconnect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == -1) { bb_error_msg_and_die("getsockname"); } src = saddr.sin_addr; } close(probe_fd); } me.sll_family = AF_PACKET; me.sll_ifindex = ifindex; me.sll_protocol = htons(ETH_P_ARP); xbind(s, (struct sockaddr *) &me, sizeof(me)); { socklen_t alen = sizeof(me); if (getsockname(s, (struct sockaddr *) &me, &alen) == -1) { bb_error_msg_and_die("getsockname"); } } if (me.sll_halen == 0) { bb_error_msg("interface \"%s\" is not ARPable (no ll address)", device); return (cfg & dad ? 0 : 2); } he = me; memset(he.sll_addr, -1, he.sll_halen); if (!(cfg & quiet)) { printf("ARPING to %s from %s via %s\n", inet_ntoa(dst), inet_ntoa(src), device ? device : "unknown"); } if (!src.s_addr && !(cfg & dad)) { bb_error_msg_and_die("no src address in the non-DAD mode"); } { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_RESTART; sa.sa_handler = (void (*)(int)) finish; sigaction(SIGINT, &sa, NULL); sa.sa_handler = (void (*)(int)) catcher; sigaction(SIGALRM, &sa, NULL); } catcher(); while (1) { sigset_t sset, osset; RESERVE_CONFIG_UBUFFER(packet, 4096); struct sockaddr_ll from; socklen_t alen = sizeof(from); int cc; cc = recvfrom(s, packet, 4096, 0, (struct sockaddr *) &from, &alen); if (cc < 0) { bb_perror_msg("recvfrom"); continue; } sigemptyset(&sset); sigaddset(&sset, SIGALRM); sigaddset(&sset, SIGINT); sigprocmask(SIG_BLOCK, &sset, &osset); recv_pack(packet, cc, &from); sigprocmask(SIG_SETMASK, &osset, NULL); RELEASE_CONFIG_BUFFER(packet); } }
int klogd_main(int argc, char **argv) { int i = i; /* silence gcc */ char *start; /* do normal option parsing */ getopt32(argv, "c:n", &start); if (option_mask32 & OPT_LEVEL) { /* Valid levels are between 1 and 8 */ i = xatoul_range(start, 1, 8); } if (!(option_mask32 & OPT_FOREGROUND)) { bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); } openlog("kernel", 0, LOG_KERN); /* Set up sig handlers */ signal(SIGINT, klogd_signal); signal(SIGKILL, klogd_signal); signal(SIGTERM, klogd_signal); signal(SIGHUP, SIG_IGN); /* "Open the log. Currently a NOP." */ klogctl(1, NULL, 0); /* Set level of kernel console messaging. */ if (option_mask32 & OPT_LEVEL) klogctl(8, NULL, i); syslog(LOG_NOTICE, "klogd started: %s", bb_banner); /* Note: this code does not detect incomplete messages * (messages not ending with '\n' or just when kernel * generates too many messages for us to keep up) * and will split them in two separate lines */ while (1) { int n; int priority; n = klogctl(2, log_buffer, KLOGD_LOGBUF_SIZE - 1); if (n < 0) { if (errno == EINTR) continue; syslog(LOG_ERR, "klogd: error from klogctl(2): %d - %m", errno); break; } log_buffer[n] = '\n'; i = 0; while (i < n) { priority = LOG_INFO; start = &log_buffer[i]; if (log_buffer[i] == '<') { i++; // kernel never ganerates multi-digit prios //priority = 0; //while (log_buffer[i] >= '0' && log_buffer[i] <= '9') { // priority = priority * 10 + (log_buffer[i] - '0'); // i++; //} if (isdigit(log_buffer[i])) { priority = (log_buffer[i] - '0'); i++; } if (log_buffer[i] == '>') i++; start = &log_buffer[i]; } while (log_buffer[i] != '\n') i++; log_buffer[i] = '\0'; syslog(priority, "%s", start); i++; } } return EXIT_FAILURE; }
static uint16_t xatou16(const char *numstr) { return (uint16_t)xatoul_range((char *)numstr, 0, 0xffff); }