int date_main(int argc ATTRIBUTE_UNUSED, char **argv) { struct tm tm_time; time_t tm; unsigned opt; int ifmt = -1; char *date_str; char *fmt_dt2str; char *fmt_str2dt; char *filename; char *isofmt_arg = NULL; opt_complementary = "d--s:s--d" USE_FEATURE_DATE_ISOFMT(":R--I:I--R"); opt = getopt32(argv, "Rs:ud:r:" USE_FEATURE_DATE_ISOFMT("I::D:"), &date_str, &date_str, &filename USE_FEATURE_DATE_ISOFMT(, &isofmt_arg, &fmt_str2dt)); argv += optind; maybe_set_utc(opt); if (ENABLE_FEATURE_DATE_ISOFMT && (opt & DATE_OPT_TIMESPEC)) { ifmt = 0; /* default is date */ if (isofmt_arg) { static const char isoformats[] ALIGN1 = "date\0""hours\0""minutes\0""seconds\0"; ifmt = index_in_strings(isoformats, isofmt_arg); if (ifmt < 0) bb_show_usage(); } }
int mt_main(int argc, char **argv) { const char *file = "/dev/tape"; struct mtop op; struct mtpos position; int fd, mode, idx; if (argc < 2) { bb_show_usage(); } if (strcmp(argv[1], "-f") == 0) { if (argc < 4) { bb_show_usage(); } file = argv[2]; argv += 2; argc -= 2; } idx = index_in_strings(opcode_name, argv[1]); if (idx < 0) bb_error_msg_and_die("unrecognized opcode %s", argv[1]); op.mt_op = opcode_value[idx]; if (argc >= 3) op.mt_count = xatoi_u(argv[2]); else op.mt_count = 1; /* One, not zero, right? */ switch (opcode_value[idx]) { case MTWEOF: case MTERASE: case MTWSM: case MTSETDRVBUFFER: mode = O_WRONLY; break; default: mode = O_RDONLY; break; } fd = xopen(file, mode); switch (opcode_value[idx]) { case MTTELL: ioctl_or_perror_and_die(fd, MTIOCPOS, &position, "%s", file); printf("At block %d\n", (int) position.mt_blkno); break; default: ioctl_or_perror_and_die(fd, MTIOCTOP, &op, "%s", file); break; } return EXIT_SUCCESS; }
static int find_param(const char *name) { static const char params[] ALIGN1 = "line\0" /* 1 */ "rows\0" /* 2 */ "cols\0" /* 3 */ "columns\0" /* 4 */ "size\0" /* 5 */ "speed\0" /* 6 */ "ispeed\0" "ospeed\0"; int i = index_in_strings(params, name) + 1; if (i == 0) return 0; if (i != 5 && i != 6) i |= 0x80; return i; }
unsigned FAST_FUNC udhcp_option_idx(const char *name, const char *option_strings) { int n = index_in_strings(option_strings, name); if (n >= 0) return n; { char *buf, *d; const char *s; s = option_strings; while (*s) s += strlen(s) + 1; d = buf = xzalloc(s - option_strings); s = option_strings; while (!(*s == '\0' && s[1] == '\0')) { *d++ = (*s == '\0' ? ' ' : *s); s++; } bb_error_msg_and_die("unknown option '%s', known options: %s", name, buf); } }
static const struct control_info *find_control(const char *name) { int i = index_in_strings(control_name, name); return i >= 0 ? &control_info[i] : NULL; }
FILE *start_wget(char *url, int *total) { char buf[512]; struct host_info server, target; len_and_sockaddr *lsa; int redir_limit; #if ENABLE_FEATURE_WGET_LONG_OPTIONS char *post_data; char *extra_headers = NULL; llist_t *headers_llist = NULL; #endif FILE *sfp; /* socket to web/ftp server */ int use_proxy = 0; /* Use proxies if env vars are set */ const char *user_agent = "Wget";/* "User-Agent" header field */ struct globals state; char *str; int status; bzero(&state, sizeof(state)); static const char keywords[] = "content-length\0""transfer-encoding\0""chunked\0""location\0"; enum { KEY_content_length = 1, KEY_transfer_encoding, KEY_chunked, KEY_location }; target.user = NULL; parse_url(url, &target); state.timeout_seconds = 900; server.port = target.port; server.host = target.host; #if 0 if (opt & WGET_OPT_CONTINUE) { output_fd = open(fname_out, O_WRONLY); if (output_fd >= 0) { state.beg_range = xlseek(output_fd, 0, SEEK_END); } /* File doesn't exist. We do not create file here yet. * We are not sure it exists on remove side */ } #endif redir_limit = 5; resolve_lsa: lsa = xhost2sockaddr(server.host, server.port); establish_session: /* * HTTP session */ /* Open socket to http server */ sfp = open_socket(lsa); if (!sfp) { ERROR("Couldn't connect to %s:%d", server.host, server.port); return NULL; } /* Send HTTP request */ fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path); fprintf(sfp, "Host: %s\r\nUser-Agent: %s\r\n", target.host, user_agent); /* Ask server to close the connection as soon as we are done * (IOW: we do not intend to send more requests) */ fprintf(sfp, "Connection: close\r\n"); if (state.beg_range) fprintf(sfp, "Range: bytes=%lu-\r\n", state.beg_range); fprintf(sfp, "\r\n"); fflush(sfp); /* * Retrieve HTTP response line and check for "200" status code. */ read_response: if (fgets(buf, sizeof(buf), sfp) == NULL) ERROR("no response from server"); str = buf; str = skip_non_whitespace(str); str = skip_whitespace(str); // FIXME: no error check // xatou wouldn't work: "200 OK" status = atoi(str); switch (status) { case 0: case 100: while (gethdr(buf, sizeof(buf), sfp /*, &n*/) != NULL) /* eat all remaining headers */; goto read_response; case 200: /* Response 204 doesn't say "null file", it says "metadata has changed but data didn't": "10.2.5 204 No Content The server has fulfilled the request but does not need to return an entity-body, and might want to return updated metainformation. The response MAY include new or updated metainformation in the form of entity-headers, which if present SHOULD be associated with the requested variant. If the client is a user agent, it SHOULD NOT change its document view from that which caused the request to be sent. This response is primarily intended to allow input for actions to take place without causing a change to the user agent's active document view, although any new or updated metainformation SHOULD be applied to the document currently in the user agent's active view. The 204 response MUST NOT include a message-body, and thus is always terminated by the first empty line after the header fields." However, in real world it was observed that some web servers (e.g. Boa/0.94.14rc21) simply use code 204 when file size is zero. */ case 204: break; case 300: /* redirection */ case 301: case 302: case 303: break; case 206: if (state.beg_range) break; /* fall through */ default: ERROR("server returned error: %s", sanitize_string(buf)); } /* * Retrieve HTTP headers. */ while ((str = gethdr(buf, sizeof(buf), sfp /*, &n*/)) != NULL) { /* gethdr converted "FOO:" string to lowercase */ smalluint key; /* strip trailing whitespace */ char *s = strchrnul(str, '\0') - 1; while (s >= str && (*s == ' ' || *s == '\t')) { *s = '\0'; s--; } key = index_in_strings(keywords, buf) + 1; if (key == KEY_content_length) { state.content_len = strtoul(str, NULL, 10); state.total_len = strtoul(str, NULL, 10); if (state.content_len < 0 || errno) { ERROR("content-length %s is garbage", sanitize_string(str)); } state.got_clen = 1; continue; } if (key == KEY_transfer_encoding) { if (index_in_strings(keywords, str_tolower(str)) + 1 != KEY_chunked) ERROR("transfer encoding '%s' is not supported", sanitize_string(str)); state.chunked = state.got_clen = 1; } if (key == KEY_location && status >= 300) { if (--redir_limit == 0) ERROR("too many redirections"); fclose(sfp); state.got_clen = 0; state.chunked = 0; if (str[0] == '/') /* free(target.allocated); */ target.path = /* target.allocated = */ strdup(str+1); /* lsa stays the same: it's on the same server */ else { parse_url(str, &target); if (!use_proxy) { server.host = target.host; server.port = target.port; free(lsa); goto resolve_lsa; } /* else: lsa stays the same: we use proxy */ } goto establish_session; } } // if (status >= 300) // ERROR("bad redirection (no Location: header from server)"); if (total) *total = state.content_len; ndelay_off(fileno(sfp)); clearerr(sfp); return sfp; #if 0 if (retrieve_file_data(&state, sfp, progress, handle, data)) return -1; handle(data, NULL, 0); return EXIT_SUCCESS; #endif }
/* Called only from main, once */ static int arp_del(char **args) { char *host; struct arpreq req; struct sockaddr sa; int flags = 0; int err; memset(&req, 0, sizeof(req)); /* Resolve the host name. */ host = *args; if (ap->input(host, &sa) < 0) { bb_herror_msg_and_die("%s", host); } /* If a host has more than one address, use the correct one! */ memcpy(&req.arp_pa, &sa, sizeof(struct sockaddr)); if (hw_set) req.arp_ha.sa_family = hw->type; req.arp_flags = ATF_PERM; args++; while (*args != NULL) { switch (index_in_strings(options, *args)) { case 0: /* "pub" */ flags |= 1; args++; break; case 1: /* "priv" */ flags |= 2; args++; break; case 2: /* "temp" */ req.arp_flags &= ~ATF_PERM; args++; break; case 3: /* "trail" */ req.arp_flags |= ATF_USETRAILERS; args++; break; case 4: /* "dontpub" */ #ifdef HAVE_ATF_DONTPUB req.arp_flags |= ATF_DONTPUB; #else bb_error_msg("feature ATF_DONTPUB is not supported"); #endif args++; break; case 5: /* "auto" */ #ifdef HAVE_ATF_MAGIC req.arp_flags |= ATF_MAGIC; #else bb_error_msg("feature ATF_MAGIC is not supported"); #endif args++; break; case 6: /* "dev" */ if (*++args == NULL) bb_show_usage(); device = *args; args++; break; case 7: /* "netmask" */ if (*++args == NULL) bb_show_usage(); if (strcmp(*args, "255.255.255.255") != 0) { host = *args; if (ap->input(host, &sa) < 0) { bb_herror_msg_and_die("%s", host); } memcpy(&req.arp_netmask, &sa, sizeof(struct sockaddr)); req.arp_flags |= ATF_NETMASK; } args++; break; default: bb_show_usage(); break; } } if (flags == 0) flags = 3; strncpy(req.arp_dev, device, sizeof(req.arp_dev)); err = -1; /* Call the kernel. */ if (flags & 2) { if (option_mask32 & ARP_OPT_v) bb_error_msg("SIOCDARP(nopub)"); err = ioctl(sockfd, SIOCDARP, &req); if (err < 0) { if (errno == ENXIO) { if (flags & 1) goto nopub; printf("No ARP entry for %s\n", host); return -1; } bb_perror_msg_and_die("SIOCDARP(priv)"); } } if ((flags & 1) && err) { nopub: req.arp_flags |= ATF_PUBL; if (option_mask32 & ARP_OPT_v) bb_error_msg("SIOCDARP(pub)"); if (ioctl(sockfd, SIOCDARP, &req) < 0) { if (errno == ENXIO) { printf("No ARP entry for %s\n", host); return -1; } bb_perror_msg_and_die("SIOCDARP(pub)"); } } return 0; }
static NOINLINE int process_timer_stats(void) { char buf[128]; char line[15 + 3 + 128]; int n; FILE *fp; buf[0] = '\0'; n = 0; fp = NULL; if (!G.cant_enable_timer_stats) fp = fopen_for_read("/proc/timer_stats"); if (fp) { // Example file contents: // Timer Stats Version: v0.2 // Sample period: 1.329 s // 76, 0 swapper hrtimer_start_range_ns (tick_sched_timer) // 88, 0 swapper hrtimer_start_range_ns (tick_sched_timer) // 24, 3787 firefox hrtimer_start_range_ns (hrtimer_wakeup) // 46D, 1136 kondemand/1 do_dbs_timer (delayed_work_timer_fn) // ... // 1, 1656 Xorg hrtimer_start_range_ns (hrtimer_wakeup) // 1, 2159 udisks-daemon hrtimer_start_range_ns (hrtimer_wakeup) // 331 total events, 249.059 events/sec while (fgets(buf, sizeof(buf), fp)) { const char *count, *process, *func; char *p; int idx; unsigned cnt; count = skip_whitespace(buf); p = strchr(count, ','); if (!p) continue; *p++ = '\0'; cnt = bb_strtou(count, NULL, 10); if (strcmp(skip_non_whitespace(count), " total events") == 0) { #if ENABLE_FEATURE_POWERTOP_PROCIRQ n = cnt / G.total_cpus; if (n > 0 && n < G.interrupt_0) { sprintf(line, " <interrupt> : %s", "extra timer interrupt"); save_line(line, G.interrupt_0 - n); } #endif break; } if (strchr(count, 'D')) continue; /* deferred */ p = skip_whitespace(p); /* points to pid now */ process = NULL; get_func_name: p = strchr(p, ' '); if (!p) continue; *p++ = '\0'; p = skip_whitespace(p); if (process == NULL) { process = p; goto get_func_name; } func = p; //if (strcmp(process, "swapper") == 0 // && strcmp(func, "hrtimer_start_range_ns (tick_sched_timer)\n") == 0 //) { // process = "[kernel scheduler]"; // func = "Load balancing tick"; //} if (strncmp(func, "tick_nohz_", 10) == 0) continue; if (strncmp(func, "tick_setup_sched_timer", 20) == 0) continue; //if (strcmp(process, "powertop") == 0) // continue; idx = index_in_strings("insmod\0modprobe\0swapper\0", process); if (idx != -1) { process = idx < 2 ? "[kernel module]" : "<kernel core>"; } strchrnul(p, '\n')[0] = '\0'; // 46D\01136\0kondemand/1\0do_dbs_timer (delayed_work_timer_fn) // ^ ^ ^ // count process func //if (strchr(process, '[')) sprintf(line, "%15.15s : %s", process, func); //else // sprintf(line, "%s", process); save_line(line, cnt); } fclose(fp); } return n; }
/* Return value becomes exitcode. It's okay to not return at all */ static int ipaddr_modify(int cmd, int argc, char **argv) { static const char option[] ALIGN1 = "peer\0""remote\0""broadcast\0""brd\0" "anycast\0""scope\0""dev\0""label\0""local\0"; struct rtnl_handle rth; struct { struct nlmsghdr n; struct ifaddrmsg ifa; char buf[256]; } req; char *d = NULL; char *l = NULL; inet_prefix lcl; inet_prefix peer; int local_len = 0; int peer_len = 0; int brd_len = 0; int any_len = 0; bool scoped = 0; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = cmd; req.ifa.ifa_family = preferred_family; while (argc > 0) { const int option_num = index_in_strings(option, *argv); switch (option_num) { case 0: /* peer */ case 1: /* remote */ NEXT_ARG(); if (peer_len) { duparg("peer", *argv); } get_prefix(&peer, *argv, req.ifa.ifa_family); peer_len = peer.bytelen; if (req.ifa.ifa_family == AF_UNSPEC) { req.ifa.ifa_family = peer.family; } addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &peer.data, peer.bytelen); req.ifa.ifa_prefixlen = peer.bitlen; break; case 2: /* broadcast */ case 3: /* brd */ { inet_prefix addr; NEXT_ARG(); if (brd_len) { duparg("broadcast", *argv); } if (LONE_CHAR(*argv, '+')) { brd_len = -1; } else if (LONE_DASH(*argv)) { brd_len = -2; } else { get_addr(&addr, *argv, req.ifa.ifa_family); if (req.ifa.ifa_family == AF_UNSPEC) req.ifa.ifa_family = addr.family; addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &addr.data, addr.bytelen); brd_len = addr.bytelen; } break; } case 4: /* anycast */ { inet_prefix addr; NEXT_ARG(); if (any_len) { duparg("anycast", *argv); } get_addr(&addr, *argv, req.ifa.ifa_family); if (req.ifa.ifa_family == AF_UNSPEC) { req.ifa.ifa_family = addr.family; } addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen); any_len = addr.bytelen; break; } case 5: /* scope */ { uint32_t scope = 0; NEXT_ARG(); if (rtnl_rtscope_a2n(&scope, *argv)) { invarg(*argv, "scope"); } req.ifa.ifa_scope = scope; scoped = 1; break; } case 6: /* dev */ NEXT_ARG(); d = *argv; break; case 7: /* label */ NEXT_ARG(); l = *argv; addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1); break; case 8: /* local */ NEXT_ARG(); default: if (local_len) { duparg2("local", *argv); } get_prefix(&lcl, *argv, req.ifa.ifa_family); if (req.ifa.ifa_family == AF_UNSPEC) { req.ifa.ifa_family = lcl.family; } addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen); local_len = lcl.bytelen; } argc--; argv++; } if (d == NULL) { bb_error_msg(bb_msg_requires_arg,"\"dev\""); return -1; } if (l && strncmp(d, l, strlen(d)) != 0) { bb_error_msg_and_die("\"dev\" (%s) must match \"label\" (%s)", d, l); } if (peer_len == 0 && local_len && cmd != RTM_DELADDR) { peer = lcl; addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &lcl.data, lcl.bytelen); } if (req.ifa.ifa_prefixlen == 0) req.ifa.ifa_prefixlen = lcl.bitlen; if (brd_len < 0 && cmd != RTM_DELADDR) { inet_prefix brd; int i; if (req.ifa.ifa_family != AF_INET) { bb_error_msg_and_die("broadcast can be set only for IPv4 addresses"); } brd = peer; if (brd.bitlen <= 30) { for (i=31; i>=brd.bitlen; i--) { if (brd_len == -1) brd.data[0] |= htonl(1<<(31-i)); else brd.data[0] &= ~htonl(1<<(31-i)); } addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &brd.data, brd.bytelen); brd_len = brd.bytelen; } } if (!scoped && cmd != RTM_DELADDR) req.ifa.ifa_scope = default_scope(&lcl); xrtnl_open(&rth); ll_init_map(&rth); req.ifa.ifa_index = xll_name_to_index(d); if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) return 2; return 0; }
/* Return value becomes exitcode. It's okay to not return at all */ static int do_set(char **argv) { char *dev = NULL; uint32_t mask = 0; uint32_t flags = 0; int qlen = -1; int mtu = -1; char *newaddr = NULL; char *newbrd = NULL; struct ifreq ifr0, ifr1; char *newname = NULL; int htype, halen; static const char keywords[] ALIGN1 = "up\0""down\0""name\0""mtu\0""multicast\0" "arp\0""address\0""dev\0"; enum { ARG_up = 0, ARG_down, ARG_name, ARG_mtu, ARG_multicast, ARG_arp, ARG_addr, ARG_dev }; static const char str_on_off[] ALIGN1 = "on\0""off\0"; enum { PARM_on = 0, PARM_off }; smalluint key; while (*argv) { /* substring search ensures that e.g. "addr" and "address" * are both accepted */ key = index_in_substrings(keywords, *argv); if (key == ARG_up) { mask |= IFF_UP; flags |= IFF_UP; } if (key == ARG_down) { mask |= IFF_UP; flags &= ~IFF_UP; } if (key == ARG_name) { NEXT_ARG(); newname = *argv; } if (key == ARG_mtu) { NEXT_ARG(); if (mtu != -1) duparg("mtu", *argv); mtu = get_unsigned(*argv, "mtu"); } if (key == ARG_multicast) { int param; NEXT_ARG(); mask |= IFF_MULTICAST; param = index_in_strings(str_on_off, *argv); if (param < 0) die_must_be_on_off("multicast"); if (param == PARM_on) flags |= IFF_MULTICAST; else flags &= ~IFF_MULTICAST; } if (key == ARG_arp) { int param; NEXT_ARG(); mask |= IFF_NOARP; param = index_in_strings(str_on_off, *argv); if (param < 0) die_must_be_on_off("arp"); if (param == PARM_on) flags &= ~IFF_NOARP; else flags |= IFF_NOARP; } if (key == ARG_addr) { NEXT_ARG(); newaddr = *argv; } if (key >= ARG_dev) { if (key == ARG_dev) { NEXT_ARG(); } if (dev) duparg2("dev", *argv); dev = *argv; } argv++; } if (!dev) { bb_error_msg_and_die(bb_msg_requires_arg, "\"dev\""); } if (newaddr || newbrd) { halen = get_address(dev, &htype); if (newaddr) { parse_address(dev, htype, halen, newaddr, &ifr0); } if (newbrd) { parse_address(dev, htype, halen, newbrd, &ifr1); } } if (newname && strcmp(dev, newname)) { do_changename(dev, newname); dev = newname; } if (qlen != -1) { set_qlen(dev, qlen); } if (mtu != -1) { set_mtu(dev, mtu); } if (newaddr || newbrd) { if (newbrd) { set_address(&ifr1, 1); } if (newaddr) { set_address(&ifr0, 0); } } if (mask) do_chflags(dev, flags, mask); return 0; }
int slattach_main(int argc ATTRIBUTE_UNUSED, char **argv) { /* Line discipline code table */ static const char proto_names[] ALIGN1 = "slip\0" /* 0 */ "cslip\0" /* 1 */ "slip6\0" /* 2 */ "cslip6\0" /* 3 */ "adaptive\0" /* 8 */ ; int i, encap, opt; struct termios state; const char *proto = "cslip"; const char *extcmd; /* Command to execute after hangup */ const char *baud_str; int baud_code = -1; /* Line baud rate (system code) */ enum { OPT_p_proto = 1 << 0, OPT_s_baud = 1 << 1, OPT_c_extcmd = 1 << 2, OPT_e_quit = 1 << 3, OPT_h_watch = 1 << 4, OPT_m_nonraw = 1 << 5, OPT_L_local = 1 << 6, OPT_F_noflow = 1 << 7 }; INIT_G(); /* Parse command line options */ opt = getopt32(argv, "p:s:c:ehmLF", &proto, &baud_str, &extcmd); /*argc -= optind;*/ argv += optind; if (!*argv) bb_show_usage(); encap = index_in_strings(proto_names, proto); if (encap < 0) invarg(proto, "protocol"); if (encap > 3) encap = 8; /* We want to know if the baud rate is valid before we start touching the ttys */ if (opt & OPT_s_baud) { baud_code = tty_value_to_baud(xatoi(baud_str)); if (baud_code < 0) invarg(baud_str, "baud rate"); } /* Trap signals in order to restore tty states upon exit */ if (!(opt & OPT_e_quit)) { bb_signals(0 + (1 << SIGHUP) + (1 << SIGINT) + (1 << SIGQUIT) + (1 << SIGTERM) , sig_handler); } /* Open tty */ handle = open(*argv, O_RDWR | O_NDELAY); if (handle < 0) { char *buf = concat_path_file("/dev", *argv); handle = xopen(buf, O_RDWR | O_NDELAY); /* maybe if (ENABLE_FEATURE_CLEAN_UP) ?? */ free(buf); } /* Save current tty state */ save_state(); /* Configure tty */ memcpy(&state, &saved_state, sizeof(state)); if (!(opt & OPT_m_nonraw)) { /* raw not suppressed */ memset(&state.c_cc, 0, sizeof(state.c_cc)); state.c_cc[VMIN] = 1; state.c_iflag = IGNBRK | IGNPAR; state.c_oflag = 0; state.c_lflag = 0; state.c_cflag = CS8 | HUPCL | CREAD | ((opt & OPT_L_local) ? CLOCAL : 0) | ((opt & OPT_F_noflow) ? 0 : CRTSCTS); } if (opt & OPT_s_baud) { cfsetispeed(&state, baud_code); cfsetospeed(&state, baud_code); } set_state(&state, encap); /* Exit now if option -e was passed */ if (opt & OPT_e_quit) return 0; /* If we're not requested to watch, just keep descriptor open * until we are killed */ if (!(opt & OPT_h_watch)) while (1) sleep(24*60*60); /* Watch line for hangup */ while (1) { if (ioctl(handle, TIOCMGET, &i) < 0 || !(i & TIOCM_CAR)) goto no_carrier; sleep(15); } no_carrier: /* Execute command on hangup */ if (opt & OPT_c_extcmd) system(extcmd); /* Restore states and exit */ restore_state_and_exit(EXIT_SUCCESS); }
static int read_mode_db(struct fb_var_screeninfo *base, const char *fn, const char *mode) { char *token[2], *p, *s; parser_t *parser = config_open(fn); while (config_read(parser, token, 2, 1, "# \t\r", PARSE_NORMAL)) { if (strcmp(token[0], "mode") != 0 || !token[1]) continue; p = strstr(token[1], mode); if (!p) continue; s = p + strlen(mode); //bb_info_msg("CHECK[%s][%s][%d]", mode, p-1, *s); /* exact match? */ if (((!*s || isspace(*s)) && '"' != s[-1]) /* end-of-token */ || ('"' == *s && '"' == p[-1]) /* ends with " but starts with " too! */ ) { //bb_info_msg("FOUND[%s][%s][%s][%d]", token[1], p, mode, isspace(*s)); break; } } if (!token[0]) return 0; while (config_read(parser, token, 2, 1, "# \t", PARSE_NORMAL)) { int i; //bb_info_msg("???[%s][%s]", token[0], token[1]); if (strcmp(token[0], "endmode") == 0) { //bb_info_msg("OK[%s]", mode); return 1; } p = token[1]; i = index_in_strings( "geometry\0timings\0interlaced\0double\0vsync\0hsync\0csync\0extsync\0", token[0]); switch (i) { case 0: /* FIXME: catastrophic on arches with 64bit ints */ sscanf(p, "%d %d %d %d %d", &(base->xres), &(base->yres), &(base->xres_virtual), &(base->yres_virtual), &(base->bits_per_pixel)); //bb_info_msg("GEO[%s]", p); break; case 1: sscanf(p, "%d %d %d %d %d %d %d", &(base->pixclock), &(base->left_margin), &(base->right_margin), &(base->upper_margin), &(base->lower_margin), &(base->hsync_len), &(base->vsync_len)); //bb_info_msg("TIM[%s]", p); break; case 2: case 3: { static const uint32_t syncs[] = {FB_VMODE_INTERLACED, FB_VMODE_DOUBLE}; ss(&base->vmode, syncs[i-2], p, "false"); //bb_info_msg("VMODE[%s]", p); break; } case 4: case 5: case 6: { static const uint32_t syncs[] = {FB_SYNC_VERT_HIGH_ACT, FB_SYNC_HOR_HIGH_ACT, FB_SYNC_COMP_HIGH_ACT}; ss(&base->sync, syncs[i-4], p, "low"); //bb_info_msg("SYNC[%s]", p); break; } case 7: ss(&base->sync, FB_SYNC_EXT, p, "false"); //bb_info_msg("EXTSYNC[%s]", p); break; } } return 0; }
static VALUE *eval6(void) { static const char keywords[] ALIGN1 = "quote\0""length\0""match\0""index\0""substr\0"; VALUE *r, *i1, *i2; static VALUE *l = NULL; static VALUE *v = NULL; int key = *G.args ? index_in_strings(keywords, *G.args) + 1 : 0; if (key == 0) /* not a keyword */ return eval7(); G.args++; /* We have a valid token, so get the next argument. */ if (key == 1) { /* quote */ if (!*G.args) bb_error_msg_and_die("syntax error"); return str_value(*G.args++); } if (key == 2) { /* length */ r = eval6(); tostring(r); v = int_value(strlen(r->u.s)); freev(r); } else l = eval6(); if (key == 3) { /* match */ r = eval6(); v = docolon(l, r); freev(l); freev(r); } if (key == 4) { /* index */ r = eval6(); tostring(l); tostring(r); v = int_value(strcspn(l->u.s, r->u.s) + 1); if (v->u.i == (arith_t) strlen(l->u.s) + 1) v->u.i = 0; freev(l); freev(r); } if (key == 5) { /* substr */ i1 = eval6(); i2 = eval6(); tostring(l); if (!toarith(i1) || !toarith(i2) || i1->u.i > (arith_t) strlen(l->u.s) || i1->u.i <= 0 || i2->u.i <= 0) v = str_value(""); else { v = xmalloc(sizeof(VALUE)); v->type = STRING; v->u.s = xstrndup(l->u.s + i1->u.i - 1, i2->u.i); } freev(l); freev(i1); freev(i2); } return v; }
int dd_main(int argc UNUSED_PARAM, char **argv) { enum { /* Must be in the same order as OP_conv_XXX! */ /* (see "flags |= (1 << what)" below) */ FLAG_NOTRUNC = 1 << 0, FLAG_SYNC = 1 << 1, FLAG_NOERROR = 1 << 2, FLAG_FSYNC = 1 << 3, /* end of conv flags */ FLAG_TWOBUFS = 1 << 4, FLAG_COUNT = 1 << 5, }; static const char keywords[] ALIGN1 = "bs\0""count\0""seek\0""skip\0""if\0""of\0" #if ENABLE_FEATURE_DD_IBS_OBS "ibs\0""obs\0""conv\0" #endif ; #if ENABLE_FEATURE_DD_IBS_OBS static const char conv_words[] ALIGN1 = "notrunc\0""sync\0""noerror\0""fsync\0"; #endif enum { OP_bs = 0, OP_count, OP_seek, OP_skip, OP_if, OP_of, #if ENABLE_FEATURE_DD_IBS_OBS OP_ibs, OP_obs, OP_conv, /* Must be in the same order as FLAG_XXX! */ OP_conv_notrunc = 0, OP_conv_sync, OP_conv_noerror, OP_conv_fsync, /* Unimplemented conv=XXX: */ //nocreat do not create the output file //excl fail if the output file already exists //fdatasync physically write output file data before finishing //swab swap every pair of input bytes //lcase change upper case to lower case //ucase change lower case to upper case //block pad newline-terminated records with spaces to cbs-size //unblock replace trailing spaces in cbs-size records with newline //ascii from EBCDIC to ASCII //ebcdic from ASCII to EBCDIC //ibm from ASCII to alternate EBCDIC #endif }; int exitcode = EXIT_FAILURE; size_t ibs = 512, obs = 512; ssize_t n, w; char *ibuf, *obuf; /* And these are all zeroed at once! */ struct { int flags; size_t oc; off_t count; off_t seek, skip; const char *infile, *outfile; } Z; #define flags (Z.flags ) #define oc (Z.oc ) #define count (Z.count ) #define seek (Z.seek ) #define skip (Z.skip ) #define infile (Z.infile ) #define outfile (Z.outfile) memset(&Z, 0, sizeof(Z)); INIT_G(); //fflush(NULL); - is this needed because of NOEXEC? #if ENABLE_FEATURE_DD_SIGNAL_HANDLING signal_SA_RESTART_empty_mask(SIGUSR1, dd_output_status); #endif for (n = 1; argv[n]; n++) { int what; char *val; char *arg = argv[n]; #if ENABLE_DESKTOP /* "dd --". NB: coreutils 6.9 will complain if they see * more than one of them. We wouldn't. */ if (arg[0] == '-' && arg[1] == '-' && arg[2] == '\0') continue; #endif val = strchr(arg, '='); if (val == NULL) bb_show_usage(); *val = '\0'; what = index_in_strings(keywords, arg); if (what < 0) bb_show_usage(); /* *val = '='; - to preserve ps listing? */ val++; #if ENABLE_FEATURE_DD_IBS_OBS if (what == OP_ibs) { /* Must fit into positive ssize_t */ ibs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, dd_suffixes); /*continue;*/ } if (what == OP_obs) { obs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, dd_suffixes); /*continue;*/ } if (what == OP_conv) { while (1) { /* find ',', replace them with NUL so we can use val for * index_in_strings() without copying. * We rely on val being non-null, else strchr would fault. */ arg = strchr(val, ','); if (arg) *arg = '\0'; what = index_in_strings(conv_words, val); if (what < 0) bb_error_msg_and_die(bb_msg_invalid_arg, val, "conv"); flags |= (1 << what); if (!arg) /* no ',' left, so this was the last specifier */ break; /* *arg = ','; - to preserve ps listing? */ val = arg + 1; /* skip this keyword and ',' */ } continue; /* we trashed 'what', can't fall through */ } #endif if (what == OP_bs) { ibs = obs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, dd_suffixes); /*continue;*/ } /* These can be large: */ if (what == OP_count) { flags |= FLAG_COUNT; count = XATOU_SFX(val, dd_suffixes); /*continue;*/ } if (what == OP_seek) { seek = XATOU_SFX(val, dd_suffixes); /*continue;*/ } if (what == OP_skip) { skip = XATOU_SFX(val, dd_suffixes); /*continue;*/ } if (what == OP_if) { infile = val; /*continue;*/ } if (what == OP_of) { outfile = val; /*continue;*/ } } /* end of "for (argv[n])" */ //XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever ibuf = obuf = xmalloc(ibs); if (ibs != obs) { flags |= FLAG_TWOBUFS; obuf = xmalloc(obs); } if (infile != NULL) xmove_fd(xopen(infile, O_RDONLY), ifd); else { infile = bb_msg_standard_input; } if (outfile != NULL) { int oflag = O_WRONLY | O_CREAT; if (!seek && !(flags & FLAG_NOTRUNC)) oflag |= O_TRUNC; xmove_fd(xopen(outfile, oflag), ofd); if (seek && !(flags & FLAG_NOTRUNC)) { if (ftruncate(ofd, seek * obs) < 0) { struct stat st; if (fstat(ofd, &st) < 0 || S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) goto die_outfile; } } } else { outfile = bb_msg_standard_output; } if (skip) { if (lseek(ifd, skip * ibs, SEEK_CUR) < 0) { while (skip-- > 0) { n = safe_read(ifd, ibuf, ibs); if (n < 0) goto die_infile; if (n == 0) break; } } } if (seek) { if (lseek(ofd, seek * obs, SEEK_CUR) < 0) goto die_outfile; } while (!(flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { if (flags & FLAG_NOERROR) /* Pre-zero the buffer if conv=noerror */ memset(ibuf, 0, ibs); n = safe_read(ifd, ibuf, ibs); if (n == 0) break; if (n < 0) { if (!(flags & FLAG_NOERROR)) goto die_infile; n = ibs; bb_simple_perror_msg(infile); } if ((size_t)n == ibs) G.in_full++; else { G.in_part++; if (flags & FLAG_SYNC) { memset(ibuf + n, '\0', ibs - n); n = ibs; } } if (flags & FLAG_TWOBUFS) { char *tmp = ibuf; while (n) { size_t d = obs - oc; if (d > (size_t)n) d = n; memcpy(obuf + oc, tmp, d); n -= d; tmp += d; oc += d; if (oc == obs) { if (write_and_stats(obuf, obs, obs, outfile)) goto out_status; oc = 0; } } } else if (write_and_stats(ibuf, n, obs, outfile)) goto out_status; if (flags & FLAG_FSYNC) { if (fsync(ofd) < 0) goto die_outfile; } } if (ENABLE_FEATURE_DD_IBS_OBS && oc) { w = full_write_or_warn(obuf, oc, outfile); if (w < 0) goto out_status; if (w > 0) G.out_part++; } if (close(ifd) < 0) { die_infile: bb_simple_perror_msg_and_die(infile); } if (close(ofd) < 0) { die_outfile: bb_simple_perror_msg_and_die(outfile); } exitcode = EXIT_SUCCESS; out_status: dd_output_status(0); return exitcode; }
int wget_main(int argc UNUSED_PARAM, char **argv) { char buf[512]; struct host_info server, target; len_and_sockaddr *lsa; unsigned opt; int redir_limit; char *proxy = NULL; char *dir_prefix = NULL; #if ENABLE_FEATURE_WGET_LONG_OPTIONS char *post_data; char *extra_headers = NULL; llist_t *headers_llist = NULL; #endif FILE *sfp; /* socket to web/ftp server */ FILE *dfp; /* socket to ftp server (data) */ char *fname_out; /* where to direct output (-O) */ int output_fd = -1; bool use_proxy; /* Use proxies if env vars are set */ const char *proxy_flag = "on"; /* Use proxies if env vars are set */ const char *user_agent = "Wget";/* "User-Agent" header field */ static const char keywords[] ALIGN1 = "content-length\0""transfer-encoding\0""chunked\0""location\0"; enum { KEY_content_length = 1, KEY_transfer_encoding, KEY_chunked, KEY_location }; #if ENABLE_FEATURE_WGET_LONG_OPTIONS static const char wget_longopts[] ALIGN1 = /* name, has_arg, val */ "continue\0" No_argument "c" "spider\0" No_argument "s" "quiet\0" No_argument "q" "output-document\0" Required_argument "O" "directory-prefix\0" Required_argument "P" "proxy\0" Required_argument "Y" "user-agent\0" Required_argument "U" /* Ignored: */ // "tries\0" Required_argument "t" // "timeout\0" Required_argument "T" /* Ignored (we always use PASV): */ "passive-ftp\0" No_argument "\xff" "header\0" Required_argument "\xfe" "post-data\0" Required_argument "\xfd" /* Ignored (we don't do ssl) */ "no-check-certificate\0" No_argument "\xfc" ; #endif INIT_G(); #if ENABLE_FEATURE_WGET_LONG_OPTIONS applet_long_options = wget_longopts; #endif /* server.allocated = target.allocated = NULL; */ opt_complementary = "-1" IF_FEATURE_WGET_LONG_OPTIONS(":\xfe::"); opt = getopt32(argv, "csqO:P:Y:U:" /*ignored:*/ "t:T:", &fname_out, &dir_prefix, &proxy_flag, &user_agent, NULL, /* -t RETRIES */ NULL /* -T NETWORK_READ_TIMEOUT */ IF_FEATURE_WGET_LONG_OPTIONS(, &headers_llist) IF_FEATURE_WGET_LONG_OPTIONS(, &post_data) ); #if ENABLE_FEATURE_WGET_LONG_OPTIONS if (headers_llist) { int size = 1; char *cp; llist_t *ll = headers_llist; while (ll) { size += strlen(ll->data) + 2; ll = ll->link; } extra_headers = cp = xmalloc(size); while (headers_llist) { cp += sprintf(cp, "%s\r\n", (char*)llist_pop(&headers_llist)); } } #endif /* TODO: compat issue: should handle "wget URL1 URL2..." */ target.user = NULL; parse_url(argv[optind], &target); /* Use the proxy if necessary */ use_proxy = (strcmp(proxy_flag, "off") != 0); if (use_proxy) { proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy"); if (proxy && proxy[0]) { server.user = NULL; parse_url(proxy, &server); } else { use_proxy = 0; } } if (!use_proxy) { server.port = target.port; if (ENABLE_FEATURE_IPV6) { server.host = xstrdup(target.host); } else { server.host = target.host; } } if (ENABLE_FEATURE_IPV6) strip_ipv6_scope_id(target.host); /* Guess an output filename, if there was no -O FILE */ if (!(opt & WGET_OPT_OUTNAME)) { fname_out = bb_get_last_path_component_nostrip(target.path); /* handle "wget http://kernel.org//" */ if (fname_out[0] == '/' || !fname_out[0]) fname_out = (char*)"index.html"; /* -P DIR is considered only if there was no -O FILE */ if (dir_prefix) fname_out = concat_path_file(dir_prefix, fname_out); } else { if (LONE_DASH(fname_out)) { /* -O - */ output_fd = 1; opt &= ~WGET_OPT_CONTINUE; } } #if ENABLE_FEATURE_WGET_STATUSBAR G.curfile = bb_get_last_path_component_nostrip(fname_out); #endif /* Impossible? if ((opt & WGET_OPT_CONTINUE) && !fname_out) bb_error_msg_and_die("can't specify continue (-c) without a filename (-O)"); */ /* Determine where to start transfer */ if (opt & WGET_OPT_CONTINUE) { output_fd = open(fname_out, O_WRONLY); if (output_fd >= 0) { G.beg_range = xlseek(output_fd, 0, SEEK_END); } /* File doesn't exist. We do not create file here yet. * We are not sure it exists on remove side */ } redir_limit = 5; resolve_lsa: lsa = xhost2sockaddr(server.host, server.port); if (!(opt & WGET_OPT_QUIET)) { char *s = xmalloc_sockaddr2dotted(&lsa->u.sa); fprintf(stderr, "Connecting to %s (%s)\n", server.host, s); free(s); } establish_session: if (use_proxy || !target.is_ftp) { /* * HTTP session */ char *str; int status; /* Open socket to http server */ sfp = open_socket(lsa); /* Send HTTP request */ if (use_proxy) { fprintf(sfp, "GET %stp://%s/%s HTTP/1.1\r\n", target.is_ftp ? "f" : "ht", target.host, target.path); } else { if (opt & WGET_OPT_POST_DATA) fprintf(sfp, "POST /%s HTTP/1.1\r\n", target.path); else fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path); } fprintf(sfp, "Host: %s\r\nUser-Agent: %s\r\n", target.host, user_agent); #if ENABLE_FEATURE_WGET_AUTHENTICATION if (target.user) { fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6, base64enc_512(buf, target.user)); } if (use_proxy && server.user) { fprintf(sfp, "Proxy-Authorization: Basic %s\r\n", base64enc_512(buf, server.user)); } #endif if (G.beg_range) fprintf(sfp, "Range: bytes=%"OFF_FMT"u-\r\n", G.beg_range); #if ENABLE_FEATURE_WGET_LONG_OPTIONS if (extra_headers) fputs(extra_headers, sfp); if (opt & WGET_OPT_POST_DATA) { char *estr = URL_escape(post_data); fprintf(sfp, "Content-Type: application/x-www-form-urlencoded\r\n"); fprintf(sfp, "Content-Length: %u\r\n" "\r\n" "%s", (int) strlen(estr), estr); /*fprintf(sfp, "Connection: Keep-Alive\r\n\r\n");*/ /*fprintf(sfp, "%s\r\n", estr);*/ free(estr); } else #endif { /* If "Connection:" is needed, document why */ fprintf(sfp, /* "Connection: close\r\n" */ "\r\n"); } /* * Retrieve HTTP response line and check for "200" status code. */ read_response: if (fgets(buf, sizeof(buf), sfp) == NULL) bb_error_msg_and_die("no response from server"); str = buf; str = skip_non_whitespace(str); str = skip_whitespace(str); // FIXME: no error check // xatou wouldn't work: "200 OK" status = atoi(str); switch (status) { case 0: case 100: while (gethdr(buf, sizeof(buf), sfp /*, &n*/) != NULL) /* eat all remaining headers */; goto read_response; case 200: /* Response 204 doesn't say "null file", it says "metadata has changed but data didn't": "10.2.5 204 No Content The server has fulfilled the request but does not need to return an entity-body, and might want to return updated metainformation. The response MAY include new or updated metainformation in the form of entity-headers, which if present SHOULD be associated with the requested variant. If the client is a user agent, it SHOULD NOT change its document view from that which caused the request to be sent. This response is primarily intended to allow input for actions to take place without causing a change to the user agent's active document view, although any new or updated metainformation SHOULD be applied to the document currently in the user agent's active view. The 204 response MUST NOT include a message-body, and thus is always terminated by the first empty line after the header fields." However, in real world it was observed that some web servers (e.g. Boa/0.94.14rc21) simply use code 204 when file size is zero. */ case 204: break; case 300: /* redirection */ case 301: case 302: case 303: break; case 206: if (G.beg_range) break; /* fall through */ default: bb_error_msg_and_die("server returned error: %s", sanitize_string(buf)); } /* * Retrieve HTTP headers. */ while ((str = gethdr(buf, sizeof(buf), sfp /*, &n*/)) != NULL) { /* gethdr converted "FOO:" string to lowercase */ smalluint key; /* strip trailing whitespace */ char *s = strchrnul(str, '\0') - 1; while (s >= str && (*s == ' ' || *s == '\t')) { *s = '\0'; s--; } key = index_in_strings(keywords, buf) + 1; if (key == KEY_content_length) { G.content_len = BB_STRTOOFF(str, NULL, 10); if (G.content_len < 0 || errno) { bb_error_msg_and_die("content-length %s is garbage", sanitize_string(str)); } G.got_clen = 1; continue; } if (key == KEY_transfer_encoding) { if (index_in_strings(keywords, str_tolower(str)) + 1 != KEY_chunked) bb_error_msg_and_die("transfer encoding '%s' is not supported", sanitize_string(str)); G.chunked = G.got_clen = 1; } if (key == KEY_location && status >= 300) { if (--redir_limit == 0) bb_error_msg_and_die("too many redirections"); fclose(sfp); G.got_clen = 0; G.chunked = 0; if (str[0] == '/') /* free(target.allocated); */ target.path = /* target.allocated = */ xstrdup(str+1); /* lsa stays the same: it's on the same server */ else { parse_url(str, &target); if (!use_proxy) { server.host = target.host; /* strip_ipv6_scope_id(target.host); - no! */ /* we assume remote never gives us IPv6 addr with scope id */ server.port = target.port; free(lsa); goto resolve_lsa; } /* else: lsa stays the same: we use proxy */ } goto establish_session; } } // if (status >= 300) // bb_error_msg_and_die("bad redirection (no Location: header from server)"); /* For HTTP, data is pumped over the same connection */ dfp = sfp; } else { /* * FTP session */ sfp = prepare_ftp_session(&dfp, &target, lsa); } if (opt & WGET_OPT_SPIDER) { if (ENABLE_FEATURE_CLEAN_UP) fclose(sfp); return EXIT_SUCCESS; } if (output_fd < 0) { int o_flags = O_WRONLY | O_CREAT | O_TRUNC | O_EXCL; /* compat with wget: -O FILE can overwrite */ if (opt & WGET_OPT_OUTNAME) o_flags = O_WRONLY | O_CREAT | O_TRUNC; output_fd = xopen(fname_out, o_flags); } retrieve_file_data(dfp, output_fd); xclose(output_fd); if (dfp != sfp) { /* It's ftp. Close it properly */ fclose(dfp); if (ftpcmd(NULL, NULL, sfp, buf) != 226) bb_error_msg_and_die("ftp error: %s", sanitize_string(buf+4)); /* ftpcmd("QUIT", NULL, sfp, buf); - why bother? */ } return EXIT_SUCCESS; }
int chat_main(int argc UNUSED_PARAM, char **argv) { int record_fd = -1; bool echo = 0; // collection of device replies which cause unconditional termination llist_t *aborts = NULL; // inactivity period int timeout = DEFAULT_CHAT_TIMEOUT; // maximum length of abort string #if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN size_t max_abort_len = 0; #else #define max_abort_len MAX_ABORT_LEN #endif #if ENABLE_FEATURE_CHAT_TTY_HIFI struct termios tio0, tio; #endif // directive names enum { DIR_HANGUP = 0, DIR_ABORT, #if ENABLE_FEATURE_CHAT_CLR_ABORT DIR_CLR_ABORT, #endif DIR_TIMEOUT, DIR_ECHO, DIR_SAY, DIR_RECORD, }; // make x* functions fail with correct exitcode xfunc_error_retval = ERR_IO; // trap vanilla signals to prevent process from being killed suddenly bb_signals(0 + (1 << SIGHUP) + (1 << SIGINT) + (1 << SIGTERM) + (1 << SIGPIPE) , signal_handler); #if ENABLE_FEATURE_CHAT_TTY_HIFI tcgetattr(STDIN_FILENO, &tio); tio0 = tio; cfmakeraw(&tio); tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio); #endif #if ENABLE_FEATURE_CHAT_SWALLOW_OPTS getopt32(argv, "vVsSE"); argv += optind; #else argv++; // goto first arg #endif // handle chat expect-send pairs while (*argv) { // directive given? process it int key = index_in_strings( "HANGUP\0" "ABORT\0" #if ENABLE_FEATURE_CHAT_CLR_ABORT "CLR_ABORT\0" #endif "TIMEOUT\0" "ECHO\0" "SAY\0" "RECORD\0" , *argv ); if (key >= 0) { // cache directive value char *arg = *++argv; // OFF -> 0, anything else -> 1 bool onoff = (0 != strcmp("OFF", arg)); // process directive if (DIR_HANGUP == key) { // turn SIGHUP on/off signal(SIGHUP, onoff ? signal_handler : SIG_IGN); } else if (DIR_ABORT == key) { // append the string to abort conditions #if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN size_t len = strlen(arg); if (len > max_abort_len) max_abort_len = len; #endif llist_add_to_end(&aborts, arg); #if ENABLE_FEATURE_CHAT_CLR_ABORT } else if (DIR_CLR_ABORT == key) { // remove the string from abort conditions // N.B. gotta refresh maximum length too... #if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN max_abort_len = 0; #endif for (llist_t *l = aborts; l; l = l->link) { #if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN size_t len = strlen(l->data); #endif if (!strcmp(arg, l->data)) { llist_unlink(&aborts, l); continue; } #if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN if (len > max_abort_len) max_abort_len = len; #endif } #endif } else if (DIR_TIMEOUT == key) { // set new timeout // -1 means OFF timeout = atoi(arg) * 1000; // 0 means default // >0 means value in msecs if (!timeout) timeout = DEFAULT_CHAT_TIMEOUT; } else if (DIR_ECHO == key) { // turn echo on/off // N.B. echo means dumping device input/output to stderr echo = onoff; } else if (DIR_RECORD == key) { // turn record on/off // N.B. record means dumping device input to a file // close previous record_fd if (record_fd > 0) close(record_fd); // N.B. do we have to die here on open error? record_fd = (onoff) ? xopen(arg, O_WRONLY|O_CREAT|O_TRUNC) : -1; } else if (DIR_SAY == key) { // just print argument verbatim // TODO: should we use full_write() to avoid unistd/stdio conflict? bb_error_msg("%s", arg); } // next, please! argv++; // ordinary expect-send pair! } else { //----------------------- // do expect //----------------------- int expect_len; size_t buf_len = 0; size_t max_len = max_abort_len; struct pollfd pfd; #if ENABLE_FEATURE_CHAT_NOFAIL int nofail = 0; #endif char *expect = *argv++; // sanity check: shall we really expect something? if (!expect) goto expect_done; #if ENABLE_FEATURE_CHAT_NOFAIL // if expect starts with - if ('-' == *expect) { // swallow - expect++; // and enter nofail mode nofail++; } #endif #ifdef ___TEST___BUF___ // test behaviour with a small buffer # undef COMMON_BUFSIZE # define COMMON_BUFSIZE 6 #endif // expand escape sequences in expect expect_len = unescape(expect, &expect_len /*dummy*/); if (expect_len > max_len) max_len = expect_len; // sanity check: // we should expect more than nothing but not more than input buffer // TODO: later we'll get rid of fixed-size buffer if (!expect_len) goto expect_done; if (max_len >= COMMON_BUFSIZE) { exitcode = ERR_MEM; goto expect_done; } // get reply pfd.fd = STDIN_FILENO; pfd.events = POLLIN; while (!exitcode && poll(&pfd, 1, timeout) > 0 && (pfd.revents & POLLIN) ) { #define buf bb_common_bufsiz1 llist_t *l; ssize_t delta; // read next char from device if (safe_read(STDIN_FILENO, buf+buf_len, 1) > 0) { // dump device input if RECORD fname if (record_fd > 0) { full_write(record_fd, buf+buf_len, 1); } // dump device input if ECHO ON if (echo > 0) { // if (buf[buf_len] < ' ') { // full_write(STDERR_FILENO, "^", 1); // buf[buf_len] += '@'; // } full_write(STDERR_FILENO, buf+buf_len, 1); } buf_len++; // move input frame if we've reached higher bound if (buf_len > COMMON_BUFSIZE) { memmove(buf, buf+buf_len-max_len, max_len); buf_len = max_len; } } // N.B. rule of thumb: values being looked for can // be found only at the end of input buffer // this allows to get rid of strstr() and memmem() // TODO: make expect and abort strings processed uniformly // abort condition is met? -> bail out for (l = aborts, exitcode = ERR_ABORT; l; l = l->link, ++exitcode) { size_t len = strlen(l->data); delta = buf_len-len; if (delta >= 0 && !memcmp(buf+delta, l->data, len)) goto expect_done; } exitcode = ERR_OK; // expected reply received? -> goto next command delta = buf_len - expect_len; if (delta >= 0 && !memcmp(buf+delta, expect, expect_len)) goto expect_done; #undef buf } /* while (have data) */ // device timed out or unexpected reply received exitcode = ERR_TIMEOUT; expect_done: #if ENABLE_FEATURE_CHAT_NOFAIL // on success and when in nofail mode // we should skip following subsend-subexpect pairs if (nofail) { if (!exitcode) { // find last send before non-dashed expect while (*argv && argv[1] && '-' == argv[1][0]) argv += 2; // skip the pair // N.B. do we really need this?! if (!*argv++ || !*argv++) break; } // nofail mode also clears all but IO errors (or signals) if (ERR_IO != exitcode) exitcode = ERR_OK; } #endif // bail out unless we expected successfully if (exitcode) break; //----------------------- // do send //----------------------- if (*argv) { #if ENABLE_FEATURE_CHAT_IMPLICIT_CR int nocr = 0; // inhibit terminating command with \r #endif char *loaded = NULL; // loaded command size_t len; char *buf = *argv++; // if command starts with @ // load "real" command from file named after @ if ('@' == *buf) { // skip the @ and any following white-space trim(++buf); buf = loaded = xmalloc_xopen_read_close(buf, NULL); } // expand escape sequences in command len = unescape(buf, &nocr); // send command alarm(timeout); pfd.fd = STDOUT_FILENO; pfd.events = POLLOUT; while (len && !exitcode && poll(&pfd, 1, -1) > 0 && (pfd.revents & POLLOUT) ) { #if ENABLE_FEATURE_CHAT_SEND_ESCAPES // "\\d" means 1 sec delay, "\\p" means 0.01 sec delay // "\\K" means send BREAK char c = *buf; if ('\\' == c) { c = *++buf; if ('d' == c) { sleep(1); len--; continue; } if ('p' == c) { usleep(10000); len--; continue; } if ('K' == c) { tcsendbreak(STDOUT_FILENO, 0); len--; continue; } buf--; } if (safe_write(STDOUT_FILENO, buf, 1) != 1) break; len--; buf++; #else len -= full_write(STDOUT_FILENO, buf, len); #endif } /* while (can write) */ alarm(0); // report I/O error if there still exists at least one non-sent char if (len) exitcode = ERR_IO; // free loaded command (if any) if (loaded) free(loaded); #if ENABLE_FEATURE_CHAT_IMPLICIT_CR // or terminate command with \r (if not inhibited) else if (!nocr) xwrite(STDOUT_FILENO, "\r", 1); #endif // bail out unless we sent command successfully if (exitcode) break; } /* if (*argv) */ } } /* while (*argv) */ #if ENABLE_FEATURE_CHAT_TTY_HIFI tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio0); #endif return exitcode; }
static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size) { static const char keywords[] ALIGN1 = "id\0" "protocol\0" "reorder_hdr\0" "gvrp\0" "mvrp\0" "loose_binding\0" ; static const char protocols[] ALIGN1 = "802.1q\0" "802.1ad\0" ; static const char str_on_off[] ALIGN1 = "on\0" "off\0" ; enum { ARG_id = 0, ARG_reorder_hdr, ARG_gvrp, ARG_mvrp, ARG_loose_binding, ARG_protocol, }; enum { PROTO_8021Q = 0, PROTO_8021AD, }; enum { PARM_on = 0, PARM_off }; int arg; uint16_t id, proto; struct ifla_vlan_flags flags = {}; while (*argv) { arg = index_in_substrings(keywords, *argv); if (arg < 0) invarg(*argv, "type vlan"); NEXT_ARG(); if (arg == ARG_id) { id = get_u16(*argv, "id"); addattr_l(n, size, IFLA_VLAN_ID, &id, sizeof(id)); } else if (arg == ARG_protocol) { arg = index_in_substrings(protocols, *argv); if (arg == PROTO_8021Q) proto = ETH_P_8021Q; else if (arg == PROTO_8021AD) proto = ETH_P_8021AD; else bb_error_msg_and_die("unknown VLAN encapsulation protocol '%s'", *argv); addattr_l(n, size, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto)); } else { int param = index_in_strings(str_on_off, *argv); if (param < 0) die_must_be_on_off(nth_string(keywords, arg)); if (arg == ARG_reorder_hdr) { flags.mask |= VLAN_FLAG_REORDER_HDR; flags.flags &= ~VLAN_FLAG_REORDER_HDR; if (param == PARM_on) flags.flags |= VLAN_FLAG_REORDER_HDR; } else if (arg == ARG_gvrp) { flags.mask |= VLAN_FLAG_GVRP; flags.flags &= ~VLAN_FLAG_GVRP; if (param == PARM_on) flags.flags |= VLAN_FLAG_GVRP; } else if (arg == ARG_mvrp) { flags.mask |= VLAN_FLAG_MVRP; flags.flags &= ~VLAN_FLAG_MVRP; if (param == PARM_on) flags.flags |= VLAN_FLAG_MVRP; } else { /*if (arg == ARG_loose_binding) */ flags.mask |= VLAN_FLAG_LOOSE_BINDING; flags.flags &= ~VLAN_FLAG_LOOSE_BINDING; if (param == PARM_on) flags.flags |= VLAN_FLAG_LOOSE_BINDING; } } argv++; } if (flags.mask) addattr_l(n, size, IFLA_VLAN_FLAGS, &flags, sizeof(flags)); }
/* Dies on error */ static void parse_args(char **argv, int cmd, struct ip_tunnel_parm *p) { static const char keywords[] ALIGN1 = "mode\0""ipip\0""ip/ip\0""gre\0""gre/ip\0""sit\0""ipv6/ip\0" "key\0""ikey\0""okey\0""seq\0""iseq\0""oseq\0" "csum\0""icsum\0""ocsum\0""nopmtudisc\0""pmtudisc\0" "remote\0""any\0""local\0""dev\0" "ttl\0""inherit\0""tos\0""dsfield\0" "name\0"; enum { ARG_mode, ARG_ipip, ARG_ip_ip, ARG_gre, ARG_gre_ip, ARG_sit, ARG_ip6_ip, ARG_key, ARG_ikey, ARG_okey, ARG_seq, ARG_iseq, ARG_oseq, ARG_csum, ARG_icsum, ARG_ocsum, ARG_nopmtudisc, ARG_pmtudisc, ARG_remote, ARG_any, ARG_local, ARG_dev, ARG_ttl, ARG_inherit, ARG_tos, ARG_dsfield, ARG_name }; int count = 0; char medium[IFNAMSIZ]; int key; memset(p, 0, sizeof(*p)); medium[0] = '\0'; p->iph.version = 4; p->iph.ihl = 5; #ifndef IP_DF #define IP_DF 0x4000 /* Flag: "Don't Fragment" */ #endif p->iph.frag_off = htons(IP_DF); while (*argv) { key = index_in_strings(keywords, *argv); if (key == ARG_mode) { NEXT_ARG(); key = index_in_strings(keywords, *argv); if (key == ARG_ipip || key == ARG_ip_ip ) { if (p->iph.protocol && p->iph.protocol != IPPROTO_IPIP) { bb_error_msg_and_die("%s tunnel mode", "you managed to ask for more than one"); } p->iph.protocol = IPPROTO_IPIP; } else if (key == ARG_gre || key == ARG_gre_ip ) { if (p->iph.protocol && p->iph.protocol != IPPROTO_GRE) { bb_error_msg_and_die("%s tunnel mode", "you managed to ask for more than one"); } p->iph.protocol = IPPROTO_GRE; } else if (key == ARG_sit || key == ARG_ip6_ip ) { if (p->iph.protocol && p->iph.protocol != IPPROTO_IPV6) { bb_error_msg_and_die("%s tunnel mode", "you managed to ask for more than one"); } p->iph.protocol = IPPROTO_IPV6; } else { bb_error_msg_and_die("%s tunnel mode", "can't guess"); } } else if (key == ARG_key) { unsigned uval; NEXT_ARG(); p->i_flags |= GRE_KEY; p->o_flags |= GRE_KEY; if (strchr(*argv, '.')) p->i_key = p->o_key = get_addr32(*argv); else { uval = get_unsigned(*argv, "key"); p->i_key = p->o_key = htonl(uval); } } else if (key == ARG_ikey) { unsigned uval; NEXT_ARG(); p->i_flags |= GRE_KEY; if (strchr(*argv, '.')) p->o_key = get_addr32(*argv); else { uval = get_unsigned(*argv, "ikey"); p->i_key = htonl(uval); } } else if (key == ARG_okey) { unsigned uval; NEXT_ARG(); p->o_flags |= GRE_KEY; if (strchr(*argv, '.')) p->o_key = get_addr32(*argv); else { uval = get_unsigned(*argv, "okey"); p->o_key = htonl(uval); } } else if (key == ARG_seq) { p->i_flags |= GRE_SEQ; p->o_flags |= GRE_SEQ; } else if (key == ARG_iseq) { p->i_flags |= GRE_SEQ; } else if (key == ARG_oseq) { p->o_flags |= GRE_SEQ; } else if (key == ARG_csum) { p->i_flags |= GRE_CSUM; p->o_flags |= GRE_CSUM; } else if (key == ARG_icsum) { p->i_flags |= GRE_CSUM; } else if (key == ARG_ocsum) { p->o_flags |= GRE_CSUM; } else if (key == ARG_nopmtudisc) { p->iph.frag_off = 0; } else if (key == ARG_pmtudisc) { p->iph.frag_off = htons(IP_DF); } else if (key == ARG_remote) { NEXT_ARG(); key = index_in_strings(keywords, *argv); if (key != ARG_any) p->iph.daddr = get_addr32(*argv); } else if (key == ARG_local) { NEXT_ARG(); key = index_in_strings(keywords, *argv); if (key != ARG_any) p->iph.saddr = get_addr32(*argv); } else if (key == ARG_dev) { NEXT_ARG(); strncpy_IFNAMSIZ(medium, *argv); } else if (key == ARG_ttl) { unsigned uval; NEXT_ARG(); key = index_in_strings(keywords, *argv); if (key != ARG_inherit) { uval = get_unsigned(*argv, "TTL"); if (uval > 255) invarg(*argv, "TTL must be <=255"); p->iph.ttl = uval; } } else if (key == ARG_tos || key == ARG_dsfield ) { uint32_t uval; NEXT_ARG(); key = index_in_strings(keywords, *argv); if (key != ARG_inherit) { if (rtnl_dsfield_a2n(&uval, *argv)) invarg(*argv, "TOS"); p->iph.tos = uval; } else p->iph.tos = 1; } else { if (key == ARG_name) { NEXT_ARG(); } if (p->name[0]) duparg2("name", *argv); strncpy_IFNAMSIZ(p->name, *argv); if (cmd == SIOCCHGTUNNEL && count == 0) { struct ip_tunnel_parm old_p; memset(&old_p, 0, sizeof(old_p)); if (do_get_ioctl(*argv, &old_p)) exit(EXIT_FAILURE); *p = old_p; } } count++; argv++; } if (p->iph.protocol == 0) { if (memcmp(p->name, "gre", 3) == 0) p->iph.protocol = IPPROTO_GRE; else if (memcmp(p->name, "ipip", 4) == 0) p->iph.protocol = IPPROTO_IPIP; else if (memcmp(p->name, "sit", 3) == 0) p->iph.protocol = IPPROTO_IPV6; } if (p->iph.protocol == IPPROTO_IPIP || p->iph.protocol == IPPROTO_IPV6) { if ((p->i_flags & GRE_KEY) || (p->o_flags & GRE_KEY)) { bb_error_msg_and_die("keys are not allowed with ipip and sit"); } } if (medium[0]) { p->link = do_ioctl_get_ifindex(medium); } if (p->i_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) { p->i_key = p->iph.daddr; p->i_flags |= GRE_KEY; } if (p->o_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) { p->o_key = p->iph.daddr; p->o_flags |= GRE_KEY; } if (IN_MULTICAST(ntohl(p->iph.daddr)) && !p->iph.saddr) { bb_error_msg_and_die("broadcast tunnel requires a source address"); } }
/* Return value becomes exitcode. It's okay to not return at all */ int ipaddr_list_or_flush(int argc, char **argv, int flush) { static const char option[] ALIGN1 = "to\0""scope\0""up\0""label\0""dev\0"; struct nlmsg_list *linfo = NULL; struct nlmsg_list *ainfo = NULL; struct nlmsg_list *l; struct rtnl_handle rth; char *filter_dev = NULL; int no_link = 0; ipaddr_reset_filter(oneline); filter.showqueue = 1; if (filter.family == AF_UNSPEC) filter.family = preferred_family; if (flush) { if (argc <= 0) { bb_error_msg_and_die(bb_msg_requires_arg, "flush"); } if (filter.family == AF_PACKET) { bb_error_msg_and_die("cannot flush link addresses"); } } while (argc > 0) { const int option_num = index_in_strings(option, *argv); switch (option_num) { case 0: /* to */ NEXT_ARG(); get_prefix(&filter.pfx, *argv, filter.family); if (filter.family == AF_UNSPEC) { filter.family = filter.pfx.family; } break; case 1: /* scope */ { uint32_t scope = 0; NEXT_ARG(); filter.scopemask = -1; if (rtnl_rtscope_a2n(&scope, *argv)) { if (strcmp(*argv, "all") != 0) { invarg(*argv, "scope"); } scope = RT_SCOPE_NOWHERE; filter.scopemask = 0; } filter.scope = scope; break; } case 2: /* up */ filter.up = 1; break; case 3: /* label */ NEXT_ARG(); filter.label = *argv; break; case 4: /* dev */ NEXT_ARG(); default: if (filter_dev) { duparg2("dev", *argv); } filter_dev = *argv; } argv++; argc--; } xrtnl_open(&rth); xrtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK); xrtnl_dump_filter(&rth, store_nlmsg, &linfo); if (filter_dev) { filter.ifindex = xll_name_to_index(filter_dev); } if (flush) { char flushb[4096-512]; filter.flushb = flushb; filter.flushp = 0; filter.flushe = sizeof(flushb); filter.rth = &rth; for (;;) { xrtnl_wilddump_request(&rth, filter.family, RTM_GETADDR); filter.flushed = 0; xrtnl_dump_filter(&rth, print_addrinfo, stdout); if (filter.flushed == 0) { return 0; } if (flush_update() < 0) return 1; } } if (filter.family != AF_PACKET) { xrtnl_wilddump_request(&rth, filter.family, RTM_GETADDR); xrtnl_dump_filter(&rth, store_nlmsg, &ainfo); } if (filter.family && filter.family != AF_PACKET) { struct nlmsg_list **lp; lp=&linfo; if (filter.oneline) no_link = 1; while ((l=*lp)!=NULL) { int ok = 0; struct ifinfomsg *ifi = NLMSG_DATA(&l->h); struct nlmsg_list *a; for (a=ainfo; a; a=a->next) { struct nlmsghdr *n = &a->h; struct ifaddrmsg *ifa = NLMSG_DATA(n); if (ifa->ifa_index != ifi->ifi_index || (filter.family && filter.family != ifa->ifa_family)) continue; if ((filter.scope^ifa->ifa_scope)&filter.scopemask) continue; if ((filter.flags^ifa->ifa_flags)&filter.flagmask) continue; if (filter.pfx.family || filter.label) { struct rtattr *tb[IFA_MAX+1]; memset(tb, 0, sizeof(tb)); parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n)); if (!tb[IFA_LOCAL]) tb[IFA_LOCAL] = tb[IFA_ADDRESS]; if (filter.pfx.family && tb[IFA_LOCAL]) { inet_prefix dst; memset(&dst, 0, sizeof(dst)); dst.family = ifa->ifa_family; memcpy(&dst.data, RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_LOCAL])); if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen)) continue; } if (filter.label) { SPRINT_BUF(b1); const char *label; if (tb[IFA_LABEL]) label = RTA_DATA(tb[IFA_LABEL]); else label = ll_idx_n2a(ifa->ifa_index, b1); if (fnmatch(filter.label, label, 0) != 0) continue; } } ok = 1; break; } if (!ok) *lp = l->next; else lp = &l->next; } } for (l = linfo; l; l = l->next) { if (no_link || print_linkinfo(NULL, &l->h, stdout) == 0) { struct ifinfomsg *ifi = NLMSG_DATA(&l->h); if (filter.family != AF_PACKET) print_selected_addrinfo(ifi->ifi_index, ainfo, stdout); } fflush(stdout); /* why? */ } return 0; }
int rfkill_main(int argc UNUSED_PARAM, char **argv) { struct rfkill_event event; const char *rf_name; int rf_fd; int mode; int rf_type; int rf_idx; unsigned rf_opt = 0; argv++; /* Must have one or two params */ if (!argv[0] || (argv[1] && argv[2])) bb_show_usage(); mode = O_RDWR | O_NONBLOCK; rf_name = argv[1]; if (strcmp(argv[0], "list") == 0) { rf_opt |= OPT_l; mode = O_RDONLY | O_NONBLOCK; } else if (strcmp(argv[0], "block") == 0 && rf_name) { rf_opt |= OPT_b; } else if (strcmp(argv[0], "unblock") == 0 && rf_name) { rf_opt |= OPT_u; } else bb_show_usage(); rf_type = RFKILL_TYPE_ALL; rf_idx = -1; if (rf_name) { static const char rfkill_types[] ALIGN1 = "all\0wlan\0bluetooth\0uwb\0wimax\0wwan\0gps\0fm\0"; if (strcmp(rf_name, "wifi") == 0) rf_name = "wlan"; if (strcmp(rf_name, "ultrawideband") == 0) rf_name = "uwb"; rf_type = index_in_strings(rfkill_types, rf_name); if (rf_type < 0) { rf_idx = xatoi_positive(rf_name); } } rf_fd = device_open("/dev/rfkill", mode); if (rf_fd < 0) bb_perror_msg_and_die("/dev/rfkill"); if (rf_opt & OPT_l) { while (full_read(rf_fd, &event, sizeof(event)) == RFKILL_EVENT_SIZE_V1) { parser_t *parser; char *tokens[2]; char rf_sysfs[sizeof("/sys/class/rfkill/rfkill%u/uevent") + sizeof(int)*3]; char *name, *type; if (rf_type && rf_type != event.type && rf_idx < 0) { continue; } if (rf_idx >= 0 && event.idx != rf_idx) { continue; } name = NULL; type = NULL; sprintf(rf_sysfs, "/sys/class/rfkill/rfkill%u/uevent", event.idx); parser = config_open2(rf_sysfs, fopen_for_read); while (config_read(parser, tokens, 2, 2, "\n=", PARSE_NORMAL)) { if (strcmp(tokens[0], "RFKILL_NAME") == 0) { name = xstrdup(tokens[1]); continue; } if (strcmp(tokens[0], "RFKILL_TYPE") == 0) { type = xstrdup(tokens[1]); continue; } } config_close(parser); printf("%u: %s: %s\n", event.idx, name, type); printf("\tSoft blocked: %s\n", event.soft ? "yes" : "no"); printf("\tHard blocked: %s\n", event.hard ? "yes" : "no"); free(name); free(type); } } else { memset(&event, 0, sizeof(event)); if (rf_type >= 0) { event.type = rf_type; event.op = RFKILL_OP_CHANGE_ALL; } if (rf_idx >= 0) { event.idx = rf_idx; event.op = RFKILL_OP_CHANGE; } /* Note: OPT_b == 1 */ event.soft = (rf_opt & OPT_b); xwrite(rf_fd, &event, sizeof(event)); } return EXIT_SUCCESS; }
/* Read /proc/interrupts, save IRQ counts and IRQ description */ static void process_irq_counts(void) { FILE *fp; char buf[128]; /* Reset values */ G.interrupt_0 = 0; G.total_interrupt = 0; fp = xfopen_for_read("/proc/interrupts"); while (fgets(buf, sizeof(buf), fp)) { char irq_desc[sizeof(" <kernel IPI> : ") + sizeof(buf)]; char *p; const char *name; int nr; ullong count; ullong delta; p = strchr(buf, ':'); if (!p) continue; /* 0: 143646045 153901007 IO-APIC-edge timer * ^ */ *p = '\0'; /* Deal with non-maskable interrupts -- make up fake numbers */ nr = index_in_strings("NMI\0RES\0CAL\0TLB\0TRM\0THR\0SPU\0", buf); if (nr >= 0) { nr += 20000; } else { /* bb_strtou doesn't eat leading spaces, using strtoul */ errno = 0; nr = strtoul(buf, NULL, 10); if (errno) continue; } p++; /* 0: 143646045 153901007 IO-APIC-edge timer * ^ */ /* Sum counts for this IRQ */ count = 0; while (1) { char *tmp; p = skip_whitespace(p); if (!isdigit(*p)) break; count += bb_strtoull(p, &tmp, 10); p = tmp; } /* 0: 143646045 153901007 IO-APIC-edge timer * NMI: 1 2 Non-maskable interrupts * ^ */ if (nr < 20000) { /* Skip to the interrupt name, e.g. 'timer' */ p = strchr(p, ' '); if (!p) continue; p = skip_whitespace(p); } name = p; strchrnul(name, '\n')[0] = '\0'; /* Save description of the interrupt */ if (nr >= 20000) sprintf(irq_desc, " <kernel IPI> : %s", name); else sprintf(irq_desc, " <interrupt> : %s", name); delta = save_irq_count(nr, count); /* Skip per CPU timer interrupts */ if (is_hpet_irq(name)) continue; if (nr != 0 && delta != 0) save_line(irq_desc, delta); if (nr == 0) G.interrupt_0 = delta; else G.total_interrupt += delta; } fclose(fp); }
static void download_one_url(const char *url) { bool use_proxy; /* Use proxies if env vars are set */ int redir_limit; len_and_sockaddr *lsa; FILE *sfp; /* socket to web/ftp server */ FILE *dfp; /* socket to ftp server (data) */ char *proxy = NULL; char *fname_out_alloc; char *redirected_path = NULL; struct host_info server; struct host_info target; server.allocated = NULL; target.allocated = NULL; server.user = NULL; target.user = NULL; parse_url(url, &target); /* Use the proxy if necessary */ use_proxy = (strcmp(G.proxy_flag, "off") != 0); if (use_proxy) { proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy"); use_proxy = (proxy && proxy[0]); if (use_proxy) parse_url(proxy, &server); } if (!use_proxy) { server.port = target.port; if (ENABLE_FEATURE_IPV6) { //free(server.allocated); - can't be non-NULL server.host = server.allocated = xstrdup(target.host); } else { server.host = target.host; } } if (ENABLE_FEATURE_IPV6) strip_ipv6_scope_id(target.host); /* If there was no -O FILE, guess output filename */ fname_out_alloc = NULL; if (!(option_mask32 & WGET_OPT_OUTNAME)) { G.fname_out = bb_get_last_path_component_nostrip(target.path); /* handle "wget http://kernel.org//" */ if (G.fname_out[0] == '/' || !G.fname_out[0]) G.fname_out = (char*)"index.html"; /* -P DIR is considered only if there was no -O FILE */ if (G.dir_prefix) G.fname_out = fname_out_alloc = concat_path_file(G.dir_prefix, G.fname_out); else { /* redirects may free target.path later, need to make a copy */ G.fname_out = fname_out_alloc = xstrdup(G.fname_out); } } #if ENABLE_FEATURE_WGET_STATUSBAR G.curfile = bb_get_last_path_component_nostrip(G.fname_out); #endif /* Determine where to start transfer */ G.beg_range = 0; if (option_mask32 & WGET_OPT_CONTINUE) { G.output_fd = open(G.fname_out, O_WRONLY); if (G.output_fd >= 0) { G.beg_range = xlseek(G.output_fd, 0, SEEK_END); } /* File doesn't exist. We do not create file here yet. * We are not sure it exists on remote side */ } redir_limit = 5; resolve_lsa: lsa = xhost2sockaddr(server.host, server.port); if (!(option_mask32 & WGET_OPT_QUIET)) { char *s = xmalloc_sockaddr2dotted(&lsa->u.sa); fprintf(stderr, "Connecting to %s (%s)\n", server.host, s); free(s); } establish_session: /*G.content_len = 0; - redundant, got_clen = 0 is enough */ G.got_clen = 0; G.chunked = 0; if (use_proxy || !target.is_ftp) { /* * HTTP session */ char *str; int status; /* Open socket to http server */ sfp = open_socket(lsa); /* Send HTTP request */ if (use_proxy) { fprintf(sfp, "GET %stp://%s/%s HTTP/1.1\r\n", target.is_ftp ? "f" : "ht", target.host, target.path); } else { if (option_mask32 & WGET_OPT_POST_DATA) fprintf(sfp, "POST /%s HTTP/1.1\r\n", target.path); else fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path); } fprintf(sfp, "Host: %s\r\nUser-Agent: %s\r\n", target.host, G.user_agent); /* Ask server to close the connection as soon as we are done * (IOW: we do not intend to send more requests) */ fprintf(sfp, "Connection: close\r\n"); #if ENABLE_FEATURE_WGET_AUTHENTICATION if (target.user) { fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6, base64enc(target.user)); } if (use_proxy && server.user) { fprintf(sfp, "Proxy-Authorization: Basic %s\r\n", base64enc(server.user)); } #endif if (G.beg_range != 0) fprintf(sfp, "Range: bytes=%"OFF_FMT"u-\r\n", G.beg_range); #if ENABLE_FEATURE_WGET_LONG_OPTIONS if (G.extra_headers) fputs(G.extra_headers, sfp); if (option_mask32 & WGET_OPT_POST_DATA) { fprintf(sfp, "Content-Type: application/x-www-form-urlencoded\r\n" "Content-Length: %u\r\n" "\r\n" "%s", (int) strlen(G.post_data), G.post_data ); } else #endif { fprintf(sfp, "\r\n"); } fflush(sfp); /* * Retrieve HTTP response line and check for "200" status code. */ read_response: fgets_and_trim(sfp); str = G.wget_buf; str = skip_non_whitespace(str); str = skip_whitespace(str); // FIXME: no error check // xatou wouldn't work: "200 OK" status = atoi(str); switch (status) { case 0: case 100: while (gethdr(sfp) != NULL) /* eat all remaining headers */; goto read_response; case 200: /* Response 204 doesn't say "null file", it says "metadata has changed but data didn't": "10.2.5 204 No Content The server has fulfilled the request but does not need to return an entity-body, and might want to return updated metainformation. The response MAY include new or updated metainformation in the form of entity-headers, which if present SHOULD be associated with the requested variant. If the client is a user agent, it SHOULD NOT change its document view from that which caused the request to be sent. This response is primarily intended to allow input for actions to take place without causing a change to the user agent's active document view, although any new or updated metainformation SHOULD be applied to the document currently in the user agent's active view. The 204 response MUST NOT include a message-body, and thus is always terminated by the first empty line after the header fields." However, in real world it was observed that some web servers (e.g. Boa/0.94.14rc21) simply use code 204 when file size is zero. */ case 204: if (G.beg_range != 0) { /* "Range:..." was not honored by the server. * Restart download from the beginning. */ reset_beg_range_to_zero(); } break; case 300: /* redirection */ case 301: case 302: case 303: break; case 206: /* Partial Content */ if (G.beg_range != 0) /* "Range:..." worked. Good. */ break; /* Partial Content even though we did not ask for it??? */ /* fall through */ default: bb_error_msg_and_die("server returned error: %s", sanitize_string(G.wget_buf)); } /* * Retrieve HTTP headers. */ while ((str = gethdr(sfp)) != NULL) { static const char keywords[] ALIGN1 = "content-length\0""transfer-encoding\0""location\0"; enum { KEY_content_length = 1, KEY_transfer_encoding, KEY_location }; smalluint key; /* gethdr converted "FOO:" string to lowercase */ /* strip trailing whitespace */ char *s = strchrnul(str, '\0') - 1; while (s >= str && (*s == ' ' || *s == '\t')) { *s = '\0'; s--; } key = index_in_strings(keywords, G.wget_buf) + 1; if (key == KEY_content_length) { G.content_len = BB_STRTOOFF(str, NULL, 10); if (G.content_len < 0 || errno) { bb_error_msg_and_die("content-length %s is garbage", sanitize_string(str)); } G.got_clen = 1; continue; } if (key == KEY_transfer_encoding) { if (strcmp(str_tolower(str), "chunked") != 0) bb_error_msg_and_die("transfer encoding '%s' is not supported", sanitize_string(str)); G.chunked = 1; } if (key == KEY_location && status >= 300) { if (--redir_limit == 0) bb_error_msg_and_die("too many redirections"); fclose(sfp); if (str[0] == '/') { free(redirected_path); target.path = redirected_path = xstrdup(str+1); /* lsa stays the same: it's on the same server */ } else { parse_url(str, &target); if (!use_proxy) { free(server.allocated); server.allocated = NULL; server.host = target.host; /* strip_ipv6_scope_id(target.host); - no! */ /* we assume remote never gives us IPv6 addr with scope id */ server.port = target.port; free(lsa); goto resolve_lsa; } /* else: lsa stays the same: we use proxy */ } goto establish_session; } } // if (status >= 300) // bb_error_msg_and_die("bad redirection (no Location: header from server)"); /* For HTTP, data is pumped over the same connection */ dfp = sfp; } else {
/* Called only from main, once */ static int arp_set(char **args) { char *host; struct arpreq req; struct sockaddr sa; int flags; memset(&req, 0, sizeof(req)); host = *args++; if (ap->input(host, &sa) < 0) { bb_herror_msg_and_die("%s", host); } /* If a host has more than one address, use the correct one! */ memcpy(&req.arp_pa, &sa, sizeof(struct sockaddr)); /* Fetch the hardware address. */ if (*args == NULL) { bb_error_msg_and_die("need hardware address"); } if (option_mask32 & ARP_OPT_D) { arp_getdevhw(*args++, &req.arp_ha, hw_set ? hw : NULL); } else { if (hw->input(*args++, &req.arp_ha) < 0) { bb_error_msg_and_die("invalid hardware address"); } } /* Check out any modifiers. */ flags = ATF_PERM | ATF_COM; while (*args != NULL) { switch (index_in_strings(options, *args)) { case 0: /* "pub" */ flags |= ATF_PUBL; args++; break; case 1: /* "priv" */ flags &= ~ATF_PUBL; args++; break; case 2: /* "temp" */ flags &= ~ATF_PERM; args++; break; case 3: /* "trail" */ flags |= ATF_USETRAILERS; args++; break; case 4: /* "dontpub" */ #ifdef HAVE_ATF_DONTPUB flags |= ATF_DONTPUB; #else bb_error_msg("feature ATF_DONTPUB is not supported"); #endif args++; break; case 5: /* "auto" */ #ifdef HAVE_ATF_MAGIC flags |= ATF_MAGIC; #else bb_error_msg("feature ATF_MAGIC is not supported"); #endif args++; break; case 6: /* "dev" */ if (*++args == NULL) bb_show_usage(); device = *args; args++; break; case 7: /* "netmask" */ if (*++args == NULL) bb_show_usage(); if (strcmp(*args, "255.255.255.255") != 0) { host = *args; if (ap->input(host, &sa) < 0) { bb_herror_msg_and_die("%s", host); } memcpy(&req.arp_netmask, &sa, sizeof(struct sockaddr)); flags |= ATF_NETMASK; } args++; break; default: bb_show_usage(); break; } } /* Fill in the remainder of the request. */ req.arp_flags = flags; strncpy(req.arp_dev, device, sizeof(req.arp_dev)); /* Call the kernel. */ if (option_mask32 & ARP_OPT_v) bb_error_msg("SIOCSARP()"); xioctl(sockfd, SIOCSARP, &req); return 0; }
static const struct mode_info *find_mode(const char *name) { int i = index_in_strings(mode_name, name); return i >= 0 ? &mode_info[i] : NULL; }
int brctl_main(int argc UNUSED_PARAM, char **argv) { static const char keywords[] ALIGN1 = "addbr\0" "delbr\0" "addif\0" "delif\0" IF_FEATURE_BRCTL_FANCY( "stp\0" "setageing\0" "setfd\0" "sethello\0" "setmaxage\0" "setpathcost\0" "setportprio\0" "setbridgeprio\0" ) IF_FEATURE_BRCTL_SHOW("show\0"); enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif IF_FEATURE_BRCTL_FANCY(, ARG_stp, ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage, ARG_setpathcost, ARG_setportprio, ARG_setbridgeprio ) IF_FEATURE_BRCTL_SHOW(, ARG_show) }; int fd; smallint key; struct ifreq ifr; char *br, *brif; argv++; while (*argv) { #if ENABLE_FEATURE_BRCTL_FANCY int ifidx[MAX_PORTS]; unsigned long args[4]; ifr.ifr_data = (char *) &args; #endif key = index_in_strings(keywords, *argv); if (key == -1) /* no match found in keywords array, bail out. */ bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name); argv++; fd = xsocket(AF_INET, SOCK_STREAM, 0); #if ENABLE_FEATURE_BRCTL_SHOW if (key == ARG_show) { /* show */ char brname[IFNAMSIZ]; int bridx[MAX_PORTS]; int i, num; arm_ioctl(args, BRCTL_GET_BRIDGES, (unsigned long) bridx, MAX_PORTS); num = xioctl(fd, SIOCGIFBR, args); puts("bridge name\tbridge id\t\tSTP enabled\tinterfaces"); for (i = 0; i < num; i++) { char ifname[IFNAMSIZ]; int j, tabs; struct __bridge_info bi; unsigned char *x; if (!if_indextoname(bridx[i], brname)) bb_perror_msg_and_die("can't get bridge name for index %d", i); strncpy_IFNAMSIZ(ifr.ifr_name, brname); arm_ioctl(args, BRCTL_GET_BRIDGE_INFO, (unsigned long) &bi, 0); xioctl(fd, SIOCDEVPRIVATE, &ifr); printf("%s\t\t", brname); /* print bridge id */ x = (unsigned char *) &bi.bridge_id; for (j = 0; j < 8; j++) { printf("%02x", x[j]); if (j == 1) bb_putchar('.'); } printf(bi.stp_enabled ? "\tyes" : "\tno"); /* print interface list */ arm_ioctl(args, BRCTL_GET_PORT_LIST, (unsigned long) ifidx, MAX_PORTS); xioctl(fd, SIOCDEVPRIVATE, &ifr); tabs = 0; for (j = 0; j < MAX_PORTS; j++) { if (!ifidx[j]) continue; if (!if_indextoname(ifidx[j], ifname)) bb_perror_msg_and_die("can't get interface name for index %d", j); if (tabs) printf("\t\t\t\t\t"); else tabs = 1; printf("\t\t%s\n", ifname); } if (!tabs) /* bridge has no interfaces */ bb_putchar('\n'); } goto done; } #endif if (!*argv) /* all but 'show' need at least one argument */ bb_show_usage(); br = *argv++; if (key == ARG_addbr || key == ARG_delbr) { /* addbr or delbr */ ioctl_or_perror_and_die(fd, key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR, br, "bridge %s", br); goto done; } if (!*argv) /* all but 'addbr/delbr' need at least two arguments */ bb_show_usage(); strncpy_IFNAMSIZ(ifr.ifr_name, br); if (key == ARG_addif || key == ARG_delif) { /* addif or delif */ brif = *argv; ifr.ifr_ifindex = if_nametoindex(brif); if (!ifr.ifr_ifindex) { bb_perror_msg_and_die("iface %s", brif); } ioctl_or_perror_and_die(fd, key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF, &ifr, "bridge %s", br); goto done_next_argv; } #if ENABLE_FEATURE_BRCTL_FANCY if (key == ARG_stp) { /* stp */ static const char no_yes[] ALIGN1 = "0\0" "off\0" "n\0" "no\0" /* 0 .. 3 */ "1\0" "on\0" "y\0" "yes\0"; /* 4 .. 7 */ int onoff = index_in_strings(no_yes, *argv); if (onoff < 0) bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name); onoff = (unsigned)onoff / 4; arm_ioctl(args, BRCTL_SET_BRIDGE_STP_STATE, onoff, 0); goto fire; } if ((unsigned)(key - ARG_setageing) < 4) { /* time related ops */ static const uint8_t ops[] ALIGN1 = { BRCTL_SET_AGEING_TIME, /* ARG_setageing */ BRCTL_SET_BRIDGE_FORWARD_DELAY, /* ARG_setfd */ BRCTL_SET_BRIDGE_HELLO_TIME, /* ARG_sethello */ BRCTL_SET_BRIDGE_MAX_AGE /* ARG_setmaxage */ }; arm_ioctl(args, ops[key - ARG_setageing], str_to_jiffies(*argv), 0); goto fire; } if (key == ARG_setpathcost || key == ARG_setportprio || key == ARG_setbridgeprio ) { static const uint8_t ops[] ALIGN1 = { BRCTL_SET_PATH_COST, /* ARG_setpathcost */ BRCTL_SET_PORT_PRIORITY, /* ARG_setportprio */ BRCTL_SET_BRIDGE_PRIORITY /* ARG_setbridgeprio */ }; int port = -1; unsigned arg1, arg2; if (key != ARG_setbridgeprio) { /* get portnum */ unsigned i; port = if_nametoindex(*argv++); if (!port) bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, "port"); memset(ifidx, 0, sizeof ifidx); arm_ioctl(args, BRCTL_GET_PORT_LIST, (unsigned long)ifidx, MAX_PORTS); xioctl(fd, SIOCDEVPRIVATE, &ifr); for (i = 0; i < MAX_PORTS; i++) { if (ifidx[i] == port) { port = i; break; } } } arg1 = port; arg2 = xatoi_positive(*argv); if (key == ARG_setbridgeprio) { arg1 = arg2; arg2 = 0; } arm_ioctl(args, ops[key - ARG_setpathcost], arg1, arg2); } fire: /* Execute the previously set command */ xioctl(fd, SIOCDEVPRIVATE, &ifr); #endif done_next_argv: argv++; done: close(fd); } return EXIT_SUCCESS; }
int brctl_main(int argc ATTRIBUTE_UNUSED, char **argv) { static const char keywords[] ALIGN1 = "addbr\0" "delbr\0" "addif\0" "delif\0" USE_FEATURE_BRCTL_FANCY( "stp\0" "setageing\0" "setfd\0" "sethello\0" "setmaxage\0" "setpathcost\0" "setportprio\0" "setbridgeprio\0" ) USE_FEATURE_BRCTL_SHOW("showmacs\0" "show\0"); enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif USE_FEATURE_BRCTL_FANCY(, ARG_stp, ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage, ARG_setpathcost, ARG_setportprio, ARG_setbridgeprio ) USE_FEATURE_BRCTL_SHOW(, ARG_showmacs, ARG_show) }; int fd; smallint key; struct ifreq ifr; char *br, *brif; #if ENABLE_FEATURE_BRCTL_FANCY unsigned long args[4] = {0, 0, 0, 0}; int port; int tmp; #endif argv++; while (*argv) { key = index_in_strings(keywords, *argv); if (key == -1) /* no match found in keywords array, bail out. */ bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); argv++; #if ENABLE_FEATURE_BRCTL_SHOW if (key == ARG_show) { /* show */ goto out; /* FIXME: implement me! :) */ } #endif fd = xsocket(AF_INET, SOCK_STREAM, 0); br = *argv++; if (key == ARG_addbr || key == ARG_delbr) { /* addbr or delbr */ ioctl_or_perror_and_die(fd, key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR, br, "bridge %s", br); goto done; } if (!*argv) /* all but 'show' need at least one argument */ bb_show_usage(); safe_strncpy(ifr.ifr_name, br, IFNAMSIZ); if (key == ARG_addif || key == ARG_delif) { /* addif or delif */ brif = *argv++; ifr.ifr_ifindex = if_nametoindex(brif); if (!ifr.ifr_ifindex) { bb_perror_msg_and_die("iface %s", brif); } ioctl_or_perror_and_die(fd, key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF, &ifr, "bridge %s", br); goto done; } #if ENABLE_FEATURE_BRCTL_FANCY ifr.ifr_data = (char *) &args; if (key == ARG_stp) { /* stp */ /* FIXME: parsing yes/y/on/1 versus no/n/off/0 is too involved */ arm_ioctl(args, BRCTL_SET_BRIDGE_STP_STATE, (unsigned)(**argv - '0'), 0); goto fire; } if ((unsigned)(key - ARG_stp) < 5) { /* time related ops */ unsigned long op = (key == ARG_setageing) ? BRCTL_SET_AGEING_TIME : (key == ARG_setfd) ? BRCTL_SET_BRIDGE_FORWARD_DELAY : (key == ARG_sethello) ? BRCTL_SET_BRIDGE_HELLO_TIME : /*key == ARG_setmaxage*/ BRCTL_SET_BRIDGE_MAX_AGE; arm_ioctl(args, op, str_to_jiffies(*argv), 0); goto fire; } port = -1; if (key == ARG_setpathcost || key == ARG_setportprio) {/* get portnum */ int ifidx[MAX_PORTS]; unsigned i; port = if_nametoindex(*argv); if (!port) bb_error_msg_and_die(bb_msg_invalid_arg, *argv, "port"); argv++; memset(ifidx, 0, sizeof ifidx); arm_ioctl(args, BRCTL_GET_PORT_LIST, (unsigned long)ifidx, MAX_PORTS); xioctl(fd, SIOCDEVPRIVATE, &ifr); for (i = 0; i < MAX_PORTS; i++) { if (ifidx[i] == port) { port = i; break; } } } if (key == ARG_setpathcost || key == ARG_setportprio || key == ARG_setbridgeprio ) { unsigned long op = (key == ARG_setpathcost) ? BRCTL_SET_PATH_COST : (key == ARG_setportprio) ? BRCTL_SET_PORT_PRIORITY : /*key == ARG_setbridgeprio*/ BRCTL_SET_BRIDGE_PRIORITY; unsigned long arg1 = port; unsigned long arg2; # if BRCTL_USE_INTERNAL tmp = xatoi(*argv); # else if (sscanf(*argv, "%i", &tmp) != 1) bb_error_msg_and_die(bb_msg_invalid_arg, *argv, key == ARG_setpathcost ? "cost" : "prio"); # endif if (key == ARG_setbridgeprio) { arg1 = tmp; arg2 = 0; } else arg2 = tmp; arm_ioctl(args, op, arg1, arg2); } fire: /* Execute the previously set command. */ xioctl(fd, SIOCDEVPRIVATE, &ifr); argv++; #endif done: if (ENABLE_FEATURE_CLEAN_UP) close(fd); } USE_FEATURE_BRCTL_SHOW(out:) return EXIT_SUCCESS; }