Ejemplo n.º 1
0
int cut_main(int argc, char **argv)
{
	char *sopt, *ltok;

	opt_complementary = "b--bcf:c--bcf:f--bcf";
	getopt32(argc, argv, optstring, &sopt, &sopt, &sopt, &ltok);
//	argc -= optind;
	argv += optind;
	if (!(option_mask32 & (CUT_OPT_BYTE_FLGS | CUT_OPT_CHAR_FLGS | CUT_OPT_FIELDS_FLGS)))
		bb_error_msg_and_die("expected a list of bytes, characters, or fields");
	if (option_mask32 & BB_GETOPT_ERROR)
		bb_error_msg_and_die("only one type of list may be specified");

	if (option_mask32 & CUT_OPT_DELIM_FLGS) {
		if (strlen(ltok) > 1) {
			bb_error_msg_and_die("the delimiter must be a single character");
		}
		delim = ltok[0];
	}

	/*  non-field (char or byte) cutting has some special handling */
	if (!(option_mask32 & CUT_OPT_FIELDS_FLGS)) {
		if (option_mask32 & CUT_OPT_SUPPRESS_FLGS) {
			bb_error_msg_and_die
				("suppressing non-delimited lines makes sense%s",
				 _op_on_field);
		}
		if (delim != '\t') {
			bb_error_msg_and_die
				("a delimiter may be specified%s", _op_on_field);
		}
	}

	/*
	 * parse list and put values into startpos and endpos.
	 * valid list formats: N, N-, N-M, -M
	 * more than one list can be separated by commas
	 */
	{
		char *ntok;
		int s = 0, e = 0;

		/* take apart the lists, one by one (they are separated with commas */
		while ((ltok = strsep(&sopt, ",")) != NULL) {

			/* it's actually legal to pass an empty list */
			if (strlen(ltok) == 0)
				continue;

			/* get the start pos */
			ntok = strsep(&ltok, "-");
			if (ntok == NULL) {
				bb_error_msg
					("internal error: ntok is null for start pos!?\n");
			} else if (strlen(ntok) == 0) {
				s = BOL;
			} else {
				s = xatoi_u(ntok);
				/* account for the fact that arrays are zero based, while
				 * the user expects the first char on the line to be char #1 */
				if (s != 0)
					s--;
			}

			/* get the end pos */
			ntok = strsep(&ltok, "-");
			if (ntok == NULL) {
				e = NON_RANGE;
			} else if (strlen(ntok) == 0) {
				e = EOL;
			} else {
				e = xatoi_u(ntok);
				/* if the user specified and end position of 0, that means "til the
				 * end of the line */
				if (e == 0)
					e = EOL;
				e--;	/* again, arrays are zero based, lines are 1 based */
				if (e == s)
					e = NON_RANGE;
			}

			/* if there's something left to tokenize, the user passed
			 * an invalid list */
			if (ltok)
				bb_error_msg_and_die("invalid byte or field list");

			/* add the new list */
			cut_lists = xrealloc(cut_lists, sizeof(struct cut_list) * (++nlists));
			cut_lists[nlists-1].startpos = s;
			cut_lists[nlists-1].endpos = e;
		}

		/* make sure we got some cut positions out of all that */
		if (nlists == 0)
			bb_error_msg_and_die("missing list of positions");

		/* now that the lists are parsed, we need to sort them to make life
		 * easier on us when it comes time to print the chars / fields / lines
		 */
		qsort(cut_lists, nlists, sizeof(struct cut_list), cmpfunc);
	}

	/* argv[0..argc-1] should be names of file to process. If no
	 * files were specified or '-' was specified, take input from stdin.
	 * Otherwise, we process all the files specified. */
	if (argv[0] == NULL || LONE_DASH(argv[0])) {
		cut_file(stdin);
	} else {
		FILE *file;

		do {
			file = fopen_or_warn(argv[0], "r");
			if (file) {
				cut_file(file);
				fclose(file);
			}
		} while (*++argv);
	}
	if (ENABLE_FEATURE_CLEAN_UP)
		free(cut_lists);
	return EXIT_SUCCESS;
}
Ejemplo n.º 2
0
int brctl_main(int argc UNUSED_PARAM, 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;

	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, *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);
			printf("bridge name\tbridge id\t\tSTP enabled\tinterfaces\n");
			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(ifr.ifr_name, brname, IFNAMSIZ);

				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("%.2x", 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 'addif/delif' need at least two arguments */
			bb_show_usage();

		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_next_argv;
		}
#if ENABLE_FEATURE_BRCTL_FANCY
		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_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, *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_u(*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;
}
Ejemplo n.º 3
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""qlen\0""multicast\0"
		"arp\0""address\0""dev\0";
	enum { ARG_up = 0, ARG_down, ARG_name, ARG_mtu, ARG_qlen, 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;
		} else if (key == ARG_down) {
			mask |= IFF_UP;
			flags &= ~IFF_UP;
		} else if (key == ARG_name) {
			NEXT_ARG();
			newname = *argv;
		} else if (key == ARG_mtu) {
			NEXT_ARG();
			if (mtu != -1)
				duparg("mtu", *argv);
			mtu = get_unsigned(*argv, "mtu");
		} else if (key == ARG_qlen) {
			NEXT_ARG();
			if (qlen != -1)
				duparg("qlen", *argv);
			qlen = get_unsigned(*argv, "qlen");
		} else if (key == ARG_addr) {
			NEXT_ARG();
			newaddr = *argv;
		} else if (key >= ARG_dev) {
			if (key == ARG_dev) {
				NEXT_ARG();
			}
			if (dev)
				duparg2("dev", *argv);
			dev = *argv;
		} else {
			int param;
			NEXT_ARG();
			param = index_in_strings(str_on_off, *argv);
			if (key == ARG_multicast) {
				if (param < 0)
					die_must_be_on_off("multicast");
				mask |= IFF_MULTICAST;
				if (param == PARM_on)
					flags |= IFF_MULTICAST;
				else
					flags &= ~IFF_MULTICAST;
			} else if (key == ARG_arp) {
				if (param < 0)
					die_must_be_on_off("arp");
				mask |= IFF_NOARP;
				if (param == PARM_on)
					flags &= ~IFF_NOARP;
				else
					flags |= IFF_NOARP;
			}
		}
		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);
			set_address(&ifr0, 0);
		}
		if (newbrd) {
			parse_address(dev, htype, halen, newbrd, &ifr1);
			set_address(&ifr1, 1);
		}
	}

	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 (mask)
		do_chflags(dev, flags, mask);
	return 0;
}
static void INET6_setroute(int action, char **args)
{
	struct sockaddr_in6 sa6;
	struct in6_rtmsg rt;
	int prefix_len, skfd;
	const char *devname;

	assert((action == RTACTION_ADD) || (action == RTACTION_DEL));

	{
		/* We know args isn't NULL from the check in route_main. */
		const char *target = *args++;

		if (strcmp(target, "default") == 0) {
			prefix_len = 0;
			memset(&sa6, 0, sizeof(sa6));
		} else {
			char *cp;
			if ((cp = strchr(target, '/'))) { /* Yes... const to non is ok. */
				*cp = 0;
				prefix_len = bb_xgetularg10_bnd(cp+1, 0, 128);
			} else {
				prefix_len = 128;
			}
			if (INET6_resolve(target, (struct sockaddr_in6 *) &sa6) < 0) {
				bb_error_msg_and_die("resolving %s", target);
			}
		}
	}

	/* Clean out the RTREQ structure. */
	memset((char *) &rt, 0, sizeof(struct in6_rtmsg));

	memcpy(&rt.rtmsg_dst, sa6.sin6_addr.s6_addr, sizeof(struct in6_addr));

	/* Fill in the other fields. */
	rt.rtmsg_dst_len = prefix_len;
	rt.rtmsg_flags = ((prefix_len == 128) ? (RTF_UP|RTF_HOST) : RTF_UP);
	rt.rtmsg_metric = 1;

	devname = NULL;

	while (*args) {
		int k = kw_lookup(tbl_ipvx, &args);
		const char *args_m1 = args[-1];

		if ((k == KW_IPVx_MOD) || (k == KW_IPVx_DYN)) {
			rt.rtmsg_flags |= flags_ipvx[k & 3];
			continue;
		}

		if (k == KW_IPVx_METRIC) {
			rt.rtmsg_metric = bb_xgetularg10(args_m1);
			continue;
		}

		if (k == KW_IPVx_GATEWAY) {
			if (rt.rtmsg_flags & RTF_GATEWAY) {
				bb_show_usage();
			}

			if (INET6_resolve(args_m1, (struct sockaddr_in6 *) &sa6) < 0) {
				bb_error_msg_and_die("resolving %s", args_m1);
			}
			memcpy(&rt.rtmsg_gateway, sa6.sin6_addr.s6_addr,
				   sizeof(struct in6_addr));
			rt.rtmsg_flags |= RTF_GATEWAY;
			continue;
		}

		/* Device is special in that it can be the last arg specified
		 * and doesn't requre the dev/device keyword in that case. */
		if (!devname && ((k == KW_IPVx_DEVICE) || (!k && !*++args))) {
			/* Don't use args_m1 here since args may have changed! */
			devname = args[-1];
			continue;
		}

		/* Nothing matched. */
		bb_show_usage();
	}

	/* Create a socket to the INET6 kernel. */
	if ((skfd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
		bb_perror_msg_and_die("socket");
	}

	rt.rtmsg_ifindex = 0;

	if (devname) {
		struct ifreq ifr;
		memset(&ifr, 0, sizeof(ifr));
		strcpy(ifr.ifr_name, devname);

		if (ioctl(skfd, SIOGIFINDEX, &ifr) < 0) {
			bb_perror_msg_and_die("SIOGIFINDEX");
		}
		rt.rtmsg_ifindex = ifr.ifr_ifindex;
	}

	/* Tell the kernel to accept this route. */
	if (ioctl(skfd, ((action==RTACTION_ADD) ? SIOCADDRT : SIOCDELRT), &rt)<0) {
		bb_perror_msg_and_die("SIOC[ADD|DEL]RT");
	}

	/* Don't bother closing, as we're exiting after we return anyway. */
	/* close(skfd); */
}
static void INET6_displayroutes(int noresolve)
{
	char addr6[128], naddr6[128];
	/* In addr6x, we store both 40-byte ':'-delimited ipv6 addresses.
	 * We read the non-delimited strings into the tail of the buffer
	 * using fscanf and then modify the buffer by shifting forward
	 * while inserting ':'s and the nul terminator for the first string.
	 * Hence the strings are at addr6x and addr6x+40.  This generates
	 * _much_ less code than the previous (upstream) approach. */
	char addr6x[80];
	char iface[16], flags[16];
	int iflags, metric, refcnt, use, prefix_len, slen;
	struct sockaddr_in6 snaddr6;

	FILE *fp = bb_xfopen("/proc/net/ipv6_route", "r");

	bb_printf("Kernel IPv6 routing table\n%-44s%-40s"
			  "Flags Metric Ref    Use Iface\n",
			  "Destination", "Next Hop");

	while (1) {
		int r;
		r = fscanf(fp, "%32s%x%*s%x%32s%x%x%x%x%s\n",
				   addr6x+14, &prefix_len, &slen, addr6x+40+7,
				   &metric, &use, &refcnt, &iflags, iface);
		if (r != 9) {
			if ((r < 0) && feof(fp)) { /* EOF with no (nonspace) chars read. */
				break;
			}
		ERROR:
			bb_error_msg_and_die("fscanf");
		}

		/* Do the addr6x shift-and-insert changes to ':'-delimit addresses.
		 * For now, always do this to validate the proc route format, even
		 * if the interface is down. */
		{
			int i = 0;
			char *p = addr6x+14;

			do {
				if (!*p) {
					if (i==40) { /* nul terminator for 1st address? */
						addr6x[39] = 0;	/* Fixup... need 0 instead of ':'. */
						++p;	/* Skip and continue. */
						continue;
					}
					goto ERROR;
				}
				addr6x[i++] = *p++;
				if (!((i+1)%5)) {
					addr6x[i++] = ':';
				}
			} while (i < 40+28+7);
		}

		if (!(iflags & RTF_UP)) { /* Skip interfaces that are down. */
			continue;
		}

		set_flags(flags, (iflags & IPV6_MASK));

		r = 0;
		do {
			inet_pton(AF_INET6, addr6x + r,
					  (struct sockaddr *) &snaddr6.sin6_addr);
			snaddr6.sin6_family = AF_INET6;
			INET6_rresolve(naddr6, sizeof(naddr6),
						   (struct sockaddr_in6 *) &snaddr6,
#if 0
						   (noresolve | 0x8000) /* Default instead of *. */
#else
						   0x0fff /* Apparently, upstream never resolves. */
#endif
						   );

			if (!r) {			/* 1st pass */
				snprintf(addr6, sizeof(addr6), "%s/%d", naddr6, prefix_len);
				r += 40;
			} else {			/* 2nd pass */
				/* Print the info. */
				bb_printf("%-43s %-39s %-5s %-6d %-2d %7d %-8s\n",
						  addr6, naddr6, flags, metric, refcnt, use, iface);
				break;
			}
		} while (1);
	}
}
Ejemplo n.º 6
0
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 */
		else {
			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) {
//TODO: URL-decode "user:password" string before base64-encoding:
//wget http://test:my%[email protected] should send
// Authorization: Basic dGVzdDpteSBwYXNz
//which decodes to "test:my pass", instead of what we send now:
// Authorization: Basic dGVzdDpteSUyMHBhc3M=
//Can reuse decodeString() from httpd.c
			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)
			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:
			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(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 {
Ejemplo n.º 7
0
int patch_main(int argc UNUSED_PARAM, char **argv)
{
	int opts;
	int reverse, state = 0;
	char *oldname = NULL, *newname = NULL;
	char *opt_p, *opt_i;
	long oldlen = oldlen; /* for compiler */
	long newlen = newlen; /* for compiler */

	INIT_TT();

	opts = getopt32(argv, FLAG_STR, &opt_p, &opt_i);
	argv += optind;
	reverse = opts & FLAG_REVERSE;
	TT.prefix = (opts & FLAG_PATHLEN) ? xatoi(opt_p) : 0; // can be negative!
	TT.filein = TT.fileout = -1;
	if (opts & FLAG_INPUT) {
		xmove_fd(xopen_stdin(opt_i), STDIN_FILENO);
	} else {
		if (argv[0] && argv[1]) {
			xmove_fd(xopen_stdin(argv[1]), STDIN_FILENO);
		}
	}
	if (argv[0]) {
		oldname = xstrdup(argv[0]);
		newname = xstrdup(argv[0]);
	}

	// Loop through the lines in the patch
	for(;;) {
		char *patchline;

		patchline = xmalloc_fgetline(stdin);
		if (!patchline) break;

		// Other versions of patch accept damaged patches,
		// so we need to also.
		if (!*patchline) {
			free(patchline);
			patchline = xstrdup(" ");
		}

		// Are we assembling a hunk?
		if (state >= 2) {
			if (*patchline==' ' || *patchline=='+' || *patchline=='-') {
				dlist_add(&TT.current_hunk, patchline);

				if (*patchline != '+') oldlen--;
				if (*patchline != '-') newlen--;

				// Context line?
				if (*patchline==' ' && state==2) TT.context++;
				else state=3;

				// If we've consumed all expected hunk lines, apply the hunk.

				if (!oldlen && !newlen) state = apply_one_hunk();
				continue;
			}
			fail_hunk();
			state = 0;
			continue;
		}

		// Open a new file?
		if (!strncmp("--- ", patchline, 4) || !strncmp("+++ ", patchline, 4)) {
			char *s, **name = reverse ? &newname : &oldname;
			int i;

			if (*patchline == '+') {
				name = reverse ? &oldname : &newname;
				state = 1;
			}

			finish_oldfile();

			if (!argv[0]) {
				free(*name);
				// Trim date from end of filename (if any).  We don't care.
				for (s = patchline+4; *s && *s!='\t'; s++)
					if (*s=='\\' && s[1]) s++;
				i = atoi(s);
				if (i>1900 && i<=1970)
					*name = xstrdup("/dev/null");
				else {
					*s = 0;
					*name = xstrdup(patchline+4);
				}
			}

			// We defer actually opening the file because svn produces broken
			// patches that don't signal they want to create a new file the
			// way the patch man page says, so you have to read the first hunk
			// and _guess_.

		// Start a new hunk?  Usually @@ -oldline,oldlen +newline,newlen @@
		// but a missing ,value means the value is 1.
		} else if (state == 1 && !strncmp("@@ -", patchline, 4)) {
			int i;
			char *s = patchline+4;

			// Read oldline[,oldlen] +newline[,newlen]

			TT.oldlen = oldlen = TT.newlen = newlen = 1;
			TT.oldline = strtol(s, &s, 10);
			if (*s == ',') TT.oldlen = oldlen = strtol(s+1, &s, 10);
			TT.newline = strtol(s+2, &s, 10);
			if (*s == ',') TT.newlen = newlen = strtol(s+1, &s, 10);

			if (oldlen < 1 && newlen < 1)
				bb_error_msg_and_die("Really? %s", patchline);

			TT.context = 0;
			state = 2;

			// If this is the first hunk, open the file.
			if (TT.filein == -1) {
				int oldsum, newsum, empty = 0;
				char *name;

				oldsum = TT.oldline + oldlen;
				newsum = TT.newline + newlen;

				name = reverse ? oldname : newname;

				// We're deleting oldname if new file is /dev/null (before -p)
				// or if new hunk is empty (zero context) after patching
				if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum))
				{
					name = reverse ? newname : oldname;
					empty++;
				}

				// handle -p path truncation.
				for (i=0, s = name; *s;) {
					if ((option_mask32 & FLAG_PATHLEN) && TT.prefix == i) break;
					if (*(s++)=='/') {
						name = s;
						i++;
					}
				}

				if (empty) {
					// File is empty after the patches have been applied
					state = 0;
					if (option_mask32 & FLAG_RMEMPTY) {
						// If flag -E or --remove-empty-files is set
						printf("removing %s\n", name);
						xunlink(name);
					} else {
						printf("patching file %s\n", name);
						xclose(xopen(name, O_WRONLY | O_TRUNC));
					}
				// If we've got a file to open, do so.
				} else if (!(option_mask32 & FLAG_PATHLEN) || i <= TT.prefix) {
					struct stat statbuf;

					// If the old file was null, we're creating a new one.
					if (!strcmp(oldname, "/dev/null") || !oldsum) {
						printf("creating %s\n", name);
						s = strrchr(name, '/');
						if (s) {
							*s = 0;
							bb_make_directory(name, -1, FILEUTILS_RECUR);
							*s = '/';
						}
						TT.filein = xopen(name, O_CREAT|O_EXCL|O_RDWR);
					} else {
						printf("patching file %s\n", name);
						TT.filein = xopen(name, O_RDONLY);
					}

					TT.tempname = xasprintf("%sXXXXXX", name);
					TT.fileout = xmkstemp(TT.tempname);
					// Set permissions of output file
					fstat(TT.filein, &statbuf);
					fchmod(TT.fileout, statbuf.st_mode);

					TT.linenum = 0;
					TT.hunknum = 0;
				}
			}

			TT.hunknum++;

			continue;
		}

		// If we didn't continue above, discard this line.
		free(patchline);
	}

	finish_oldfile();

	if (ENABLE_FEATURE_CLEAN_UP) {
		free(oldname);
		free(newname);
	}

	return TT.exitval;
}
Ejemplo n.º 8
0
int split_main(int argc, char **argv)
{
	unsigned suffix_len = 2;
	char *pfx;
	char *count_p;
	const char *sfx;
	off_t cnt = 1000;
	off_t remaining = 0;
	unsigned opt;
	ssize_t bytes_read, to_write;
	char *src;

	opt_complementary = "?2";
	opt = getopt32(argc, argv, "l:b:a:", &count_p, &count_p, &sfx);

	if (opt & SPLIT_OPT_l)
		cnt = xatoul(count_p);
	if (opt & SPLIT_OPT_b)
		cnt = xatoul_sfx(count_p, split_suffices);
	if (opt & SPLIT_OPT_a)
		suffix_len = xatou(sfx);
	sfx = "x";

	argv += optind;
	if (argv[0]) {
		if (argv[1])
			sfx = argv[1];
		xmove_fd(xopen(argv[0], O_RDONLY), 0);
	} else {
		argv[0] = (char *) bb_msg_standard_input;
	}

	if (NAME_MAX < strlen(sfx) + suffix_len)
		bb_error_msg_and_die("suffix too long");

	{
		char *char_p = xzalloc(suffix_len + 1);
		memset(char_p, 'a', suffix_len);
		pfx = xasprintf("%s%s", sfx, char_p);
		if (ENABLE_FEATURE_CLEAN_UP)
			free(char_p);
	}

	while (1) {
		bytes_read = safe_read(0, read_buffer, READ_BUFFER_SIZE);
		if (!bytes_read)
			break;
		if (bytes_read < 0)
			bb_perror_msg_and_die("%s", argv[0]);
		src = read_buffer;
		do {
			if (!remaining) {
				if (!pfx)
					bb_error_msg_and_die("suffixes exhausted");
				xmove_fd(xopen(pfx, O_WRONLY | O_CREAT | O_TRUNC), 1);
				pfx = next_file(pfx, suffix_len);
				remaining = cnt;
			}

			if (opt & SPLIT_OPT_b) {
				/* split by bytes */
				to_write = (bytes_read < remaining) ? bytes_read : remaining;
				remaining -= to_write;
			} else {
				/* split by lines */
				/* can be sped up by using _memrchr_
				 * and writing many lines at once... */
				char *end = memchr(src, '\n', bytes_read);
				if (end) {
					--remaining;
					to_write = end - src + 1;
				} else {
					to_write = bytes_read;
				}
			}

			xwrite(1, src, to_write);
			bytes_read -= to_write;
			src += to_write;
		} while (bytes_read);
	}
	return 0;
}
Ejemplo n.º 9
0
static void process_files(void)
{
	char *pattern_space, *next_line;
	int linenum = 0;
	char last_puts_char = '\n';
	char last_gets_char, next_gets_char;
	sed_cmd_t *sed_cmd;
	int substituted;

	/* Prime the pump */
	next_line = get_next_line(&next_gets_char, &last_puts_char);

	/* Go through every line in each file */
 again:
	substituted = 0;

	/* Advance to next line.  Stop if out of lines. */
	pattern_space = next_line;
	if (!pattern_space)
		return;
	last_gets_char = next_gets_char;

	/* Read one line in advance so we can act on the last line,
	 * the '$' address */
	next_line = get_next_line(&next_gets_char, &last_puts_char);
	linenum++;

	/* For every line, go through all the commands */
 restart:
	for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) {
		int old_matched, matched;

		old_matched = sed_cmd->in_match;

		/* Determine if this command matches this line: */

		dbg("match1:%d", sed_cmd->in_match);
		dbg("match2:%d", (!sed_cmd->beg_line && !sed_cmd->end_line
				&& !sed_cmd->beg_match && !sed_cmd->end_match));
		dbg("match3:%d", (sed_cmd->beg_line > 0
			&& (sed_cmd->end_line || sed_cmd->end_match
			    ? (sed_cmd->beg_line <= linenum)
			    : (sed_cmd->beg_line == linenum)
			    )
			));
		dbg("match4:%d", (beg_match(sed_cmd, pattern_space)));
		dbg("match5:%d", (sed_cmd->beg_line == -1 && next_line == NULL));

		/* Are we continuing a previous multi-line match? */
		sed_cmd->in_match = sed_cmd->in_match
			/* Or is no range necessary? */
			|| (!sed_cmd->beg_line && !sed_cmd->end_line
				&& !sed_cmd->beg_match && !sed_cmd->end_match)
			/* Or did we match the start of a numerical range? */
			|| (sed_cmd->beg_line > 0
			    && (sed_cmd->end_line || sed_cmd->end_match
				  /* note: even if end is numeric and is < linenum too,
				   * GNU sed matches! We match too, therefore we don't
				   * check here that linenum <= end.
				   * Example:
				   * printf '1\n2\n3\n4\n' | sed -n '1{N;N;d};1p;2,3p;3p;4p'
				   * first three input lines are deleted;
				   * 4th line is matched and printed
				   * by "2,3" (!) and by "4" ranges
				   */
				? (sed_cmd->beg_line <= linenum)    /* N,end */
				: (sed_cmd->beg_line == linenum)    /* N */
				)
			    )
			/* Or does this line match our begin address regex? */
			|| (beg_match(sed_cmd, pattern_space))
			/* Or did we match last line of input? */
			|| (sed_cmd->beg_line == -1 && next_line == NULL);

		/* Snapshot the value */
		matched = sed_cmd->in_match;

		dbg("cmd:'%c' matched:%d beg_line:%d end_line:%d linenum:%d",
			sed_cmd->cmd, matched, sed_cmd->beg_line, sed_cmd->end_line, linenum);

		/* Is this line the end of the current match? */

		if (matched) {
			if (sed_cmd->end_line <= -2) {
				/* address2 is +N, i.e. N lines from beg_line */
				sed_cmd->end_line = linenum + (-sed_cmd->end_line - 2);
			}
			/* once matched, "n,xxx" range is dead, disabling it */
			if (sed_cmd->beg_line > 0) {
				sed_cmd->beg_line = -2;
			}
			dbg("end1:%d", sed_cmd->end_line ? sed_cmd->end_line == -1
						? !next_line : (sed_cmd->end_line <= linenum)
					: !sed_cmd->end_match);
			dbg("end2:%d", sed_cmd->end_match && old_matched
					&& !regexec(sed_cmd->end_match,pattern_space, 0, NULL, 0));
			sed_cmd->in_match = !(
				/* has the ending line come, or is this a single address command? */
				(sed_cmd->end_line
					? sed_cmd->end_line == -1
						? !next_line
						: (sed_cmd->end_line <= linenum)
					: !sed_cmd->end_match
				)
				/* or does this line matches our last address regex */
				|| (sed_cmd->end_match && old_matched
				     && (regexec(sed_cmd->end_match,
						pattern_space, 0, NULL, 0) == 0)
				)
			);
		}

		/* Skip blocks of commands we didn't match */
		if (sed_cmd->cmd == '{') {
			if (sed_cmd->invert ? matched : !matched) {
				unsigned nest_cnt = 0;
				while (1) {
					if (sed_cmd->cmd == '{')
						nest_cnt++;
					if (sed_cmd->cmd == '}') {
						nest_cnt--;
						if (nest_cnt == 0)
							break;
					}
					sed_cmd = sed_cmd->next;
					if (!sed_cmd)
						bb_error_msg_and_die("unterminated {");
				}
			}
			continue;
		}

		/* Okay, so did this line match? */
		if (sed_cmd->invert ? matched : !matched)
			continue; /* no */

		/* Update last used regex in case a blank substitute BRE is found */
		if (sed_cmd->beg_match) {
			G.previous_regex_ptr = sed_cmd->beg_match;
		}

		/* actual sedding */
		dbg("pattern_space:'%s' next_line:'%s' cmd:%c",
				pattern_space, next_line, sed_cmd->cmd);
		switch (sed_cmd->cmd) {

		/* Print line number */
		case '=':
			fprintf(G.nonstdout, "%d\n", linenum);
			break;

		/* Write the current pattern space up to the first newline */
		case 'P':
		{
			char *tmp = strchr(pattern_space, '\n');
			if (tmp) {
				*tmp = '\0';
				/* TODO: explain why '\n' below */
				sed_puts(pattern_space, '\n');
				*tmp = '\n';
				break;
			}
			/* Fall Through */
		}

		/* Write the current pattern space to output */
		case 'p':
			/* NB: we print this _before_ the last line
			 * (of current file) is printed. Even if
			 * that line is nonterminated, we print
			 * '\n' here (gnu sed does the same) */
			sed_puts(pattern_space, '\n');
			break;
		/* Delete up through first newline */
		case 'D':
		{
			char *tmp = strchr(pattern_space, '\n');
			if (tmp) {
				overlapping_strcpy(pattern_space, tmp + 1);
				goto restart;
			}
		}
		/* discard this line. */
		case 'd':
			goto discard_line;

		/* Substitute with regex */
		case 's':
			if (!do_subst_command(sed_cmd, &pattern_space))
				break;
			dbg("do_subst_command succeeded:'%s'", pattern_space);
			substituted |= 1;

			/* handle p option */
			if (sed_cmd->sub_p)
				sed_puts(pattern_space, last_gets_char);
			/* handle w option */
			if (sed_cmd->sw_file)
				puts_maybe_newline(
					pattern_space, sed_cmd->sw_file,
					&sed_cmd->sw_last_char, last_gets_char);
			break;

		/* Append line to linked list to be printed later */
		case 'a':
			append(xstrdup(sed_cmd->string));
			break;

		/* Insert text before this line */
		case 'i':
			sed_puts(sed_cmd->string, '\n');
			break;

		/* Cut and paste text (replace) */
		case 'c':
			/* Only triggers on last line of a matching range. */
			if (!sed_cmd->in_match)
				sed_puts(sed_cmd->string, '\n');
			goto discard_line;

		/* Read file, append contents to output */
		case 'r':
		{
			FILE *rfile;
			rfile = fopen_for_read(sed_cmd->string);
			if (rfile) {
				char *line;
				while ((line = xmalloc_fgetline(rfile))
						!= NULL)
					append(line);
				fclose(rfile);
			}

			break;
		}

		/* Write pattern space to file. */
		case 'w':
			puts_maybe_newline(
				pattern_space, sed_cmd->sw_file,
				&sed_cmd->sw_last_char, last_gets_char);
			break;

		/* Read next line from input */
		case 'n':
			if (!G.be_quiet)
				sed_puts(pattern_space, last_gets_char);
			if (next_line == NULL) {
				/* If no next line, jump to end of script and exit. */
				goto discard_line;
			}
			free(pattern_space);
			pattern_space = next_line;
			last_gets_char = next_gets_char;
			next_line = get_next_line(&next_gets_char, &last_puts_char);
			substituted = 0;
			linenum++;
			break;

		/* Quit.  End of script, end of input. */
		case 'q':
			/* Exit the outer while loop */
			free(next_line);
			next_line = NULL;
			goto discard_commands;

		/* Append the next line to the current line */
		case 'N':
		{
			int len;
			/* If no next line, jump to end of script and exit. */
			/* http://www.gnu.org/software/sed/manual/sed.html:
			 * "Most versions of sed exit without printing anything
			 * when the N command is issued on the last line of
			 * a file. GNU sed prints pattern space before exiting
			 * unless of course the -n command switch has been
			 * specified. This choice is by design."
			 */
			if (next_line == NULL) {
				//goto discard_line;
				goto discard_commands; /* GNU behavior */
			}
			/* Append next_line, read new next_line. */
			len = strlen(pattern_space);
			pattern_space = xrealloc(pattern_space, len + strlen(next_line) + 2);
			pattern_space[len] = '\n';
			strcpy(pattern_space + len+1, next_line);
			last_gets_char = next_gets_char;
			next_line = get_next_line(&next_gets_char, &last_puts_char);
			linenum++;
			break;
		}

		/* Test/branch if substitution occurred */
		case 't':
			if (!substituted) break;
			substituted = 0;
			/* Fall through */
		/* Test/branch if substitution didn't occur */
		case 'T':
			if (substituted) break;
			/* Fall through */
		/* Branch to label */
		case 'b':
			if (!sed_cmd->string) goto discard_commands;
			else sed_cmd = branch_to(sed_cmd->string);
			break;
		/* Transliterate characters */
		case 'y':
		{
			int i, j;
			for (i = 0; pattern_space[i]; i++) {
				for (j = 0; sed_cmd->string[j]; j += 2) {
					if (pattern_space[i] == sed_cmd->string[j]) {
						pattern_space[i] = sed_cmd->string[j + 1];
						break;
					}
				}
			}

			break;
		}
		case 'g':	/* Replace pattern space with hold space */
			free(pattern_space);
			pattern_space = xstrdup(G.hold_space ? G.hold_space : "");
			break;
		case 'G':	/* Append newline and hold space to pattern space */
		{
			int pattern_space_size = 2;
			int hold_space_size = 0;

			if (pattern_space)
				pattern_space_size += strlen(pattern_space);
			if (G.hold_space)
				hold_space_size = strlen(G.hold_space);
			pattern_space = xrealloc(pattern_space,
					pattern_space_size + hold_space_size);
			if (pattern_space_size == 2)
				pattern_space[0] = 0;
			strcat(pattern_space, "\n");
			if (G.hold_space)
				strcat(pattern_space, G.hold_space);
			last_gets_char = '\n';

			break;
		}
		case 'h':	/* Replace hold space with pattern space */
			free(G.hold_space);
			G.hold_space = xstrdup(pattern_space);
			break;
		case 'H':	/* Append newline and pattern space to hold space */
		{
			int hold_space_size = 2;
			int pattern_space_size = 0;

			if (G.hold_space)
				hold_space_size += strlen(G.hold_space);
			if (pattern_space)
				pattern_space_size = strlen(pattern_space);
			G.hold_space = xrealloc(G.hold_space,
					hold_space_size + pattern_space_size);

			if (hold_space_size == 2)
				*G.hold_space = 0;
			strcat(G.hold_space, "\n");
			if (pattern_space)
				strcat(G.hold_space, pattern_space);

			break;
		}
		case 'x': /* Exchange hold and pattern space */
		{
			char *tmp = pattern_space;
			pattern_space = G.hold_space ? G.hold_space : xzalloc(1);
			last_gets_char = '\n';
			G.hold_space = tmp;
			break;
		}
		} /* switch */
	} /* for each cmd */

	/*
	 * Exit point from sedding...
	 */
 discard_commands:
	/* we will print the line unless we were told to be quiet ('-n')
	   or if the line was suppressed (ala 'd'elete) */
	if (!G.be_quiet)
		sed_puts(pattern_space, last_gets_char);

	/* Delete and such jump here. */
 discard_line:
	flush_append(&last_puts_char /*,last_gets_char*/);
	free(pattern_space);

	goto again;
}
Ejemplo n.º 10
0
static void ping(const char *host)
{
	char packet[datalen + MAXIPLEN + MAXICMPLEN];
	char buf[INET6_ADDRSTRLEN];
	int sockopt;
	struct msghdr msg;
	struct sockaddr_in6 from;
	struct iovec iov;
	char control_buf[CMSG_SPACE(36)];

	pingsock = create_icmp6_socket();

	memset(&pingaddr, 0, sizeof(struct sockaddr_in));

	pingaddr.sin6_family = AF_INET6;
	hostent = xgethostbyname2(host, AF_INET6);
	if (hostent->h_addrtype != AF_INET6)
		bb_error_msg_and_die("unknown address type; only AF_INET6 is currently supported.");

	memcpy(&pingaddr.sin6_addr, hostent->h_addr, sizeof(pingaddr.sin6_addr));

#ifdef ICMP6_FILTER
	{
		struct icmp6_filter filt;
		if (!(options & O_VERBOSE)) {
			ICMP6_FILTER_SETBLOCKALL(&filt);
#if 0
			if ((options & F_FQDN) || (options & F_FQDNOLD) ||
				(options & F_NODEADDR) || (options & F_SUPTYPES))
				ICMP6_FILTER_SETPASS(ICMP6_NI_REPLY, &filt);
			else
#endif
				ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt);
		} else {
			ICMP6_FILTER_SETPASSALL(&filt);
		}
		if (setsockopt(pingsock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
					   sizeof(filt)) < 0)
			bb_error_msg_and_die("setsockopt(ICMP6_FILTER)");
	}
#endif /*ICMP6_FILTER*/

	/* enable broadcast pings */
	sockopt = 1;
	setsockopt(pingsock, SOL_SOCKET, SO_BROADCAST, (char *) &sockopt,
			   sizeof(sockopt));

	/* set recv buf for broadcast pings */
	sockopt = 48 * 1024;
	setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, (char *) &sockopt,
			   sizeof(sockopt));

	sockopt = offsetof(struct icmp6_hdr, icmp6_cksum);
	setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, (char *) &sockopt,
			   sizeof(sockopt));

	sockopt = 1;
	setsockopt(pingsock, SOL_IPV6, IPV6_HOPLIMIT, (char *) &sockopt,
			   sizeof(sockopt));

	if (ifname) {
		if ((pingaddr.sin6_scope_id = if_nametoindex(ifname)) == 0)
			bb_error_msg_and_die("%s: invalid interface name", ifname);
	}

	printf("PING %s (%s): %d data bytes\n",
	           hostent->h_name,
			   inet_ntop(AF_INET6, (struct in_addr6 *) &pingaddr.sin6_addr,
						 buf, sizeof(buf)),
		   datalen);

	signal(SIGINT, pingstats);

	/* start the ping's going ... */
	sendping(0);

	/* listen for replies */
	msg.msg_name=&from;
	msg.msg_namelen=sizeof(from);
	msg.msg_iov=&iov;
	msg.msg_iovlen=1;
	msg.msg_control=control_buf;
	iov.iov_base=packet;
	iov.iov_len=sizeof(packet);
	while (1) {
		int c;
		struct cmsghdr *cmsgptr = NULL;
		int hoplimit=-1;
		msg.msg_controllen=sizeof(control_buf);

		if ((c = recvmsg(pingsock, &msg, 0)) < 0) {
			if (errno == EINTR)
				continue;
			bb_perror_msg("recvfrom");
			continue;
		}
		for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
			 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
			if (cmsgptr->cmsg_level == SOL_IPV6 &&
				cmsgptr->cmsg_type == IPV6_HOPLIMIT ) {
				hoplimit=*(int*)CMSG_DATA(cmsgptr);
			}
		}
		unpack(packet, c, &from, hoplimit);
		if (pingcount > 0 && nreceived >= pingcount)
			break;
	}
	pingstats(0);
}
Ejemplo n.º 11
0
int sulogin_main(int argc, char **argv)
{
	char *cp;
	int timeout = 0;
	char *timeout_arg;
	const char *const *p;
	struct passwd *pwd;
	const char *shell;
#if ENABLE_FEATURE_SHADOWPASSWDS
	/* Using _r function to avoid pulling in static buffers */
	char buffer[256];
	struct spwd spw;
	struct spwd *result;
#endif

	logmode = LOGMODE_BOTH;
	openlog(applet_name, 0, LOG_AUTH);

	if (getopt32(argv, "t:", &timeout_arg)) {
		timeout = xatoi_u(timeout_arg);
	}

	if (argv[optind]) {
		close(0);
		close(1);
		dup(xopen(argv[optind], O_RDWR));
		close(2);
		dup(0);
	}

	if (!isatty(0) || !isatty(1) || !isatty(2)) {
		logmode = LOGMODE_SYSLOG;
		bb_error_msg_and_die("not a tty");
	}

	/* Clear out anything dangerous from the environment */
	for (p = forbid; *p; p++)
		unsetenv(*p);

	signal(SIGALRM, catchalarm);

	pwd = getpwuid(0);
	if (!pwd) {
		goto auth_error;
	}

#if ENABLE_FEATURE_SHADOWPASSWDS
	if (getspnam_r(pwd->pw_name, &spw, buffer, sizeof(buffer), &result)) {
		goto auth_error;
	}
	pwd->pw_passwd = spw.sp_pwdp;
#endif

	while (1) {
		/* cp points to a static buffer that is zeroed every time */
		cp = bb_askpass(timeout,
				"Give root password for system maintenance\n"
				"(or type Control-D for normal startup):");

		if (!cp || !*cp) {
			bb_info_msg("Normal startup");
			return 0;
		}
		if (strcmp(pw_encrypt(cp, pwd->pw_passwd), pwd->pw_passwd) == 0) {
			break;
		}
		bb_do_delay(FAIL_DELAY);
		bb_error_msg("login incorrect");
	}
	memset(cp, 0, strlen(cp));
	signal(SIGALRM, SIG_DFL);

	bb_info_msg("System Maintenance Mode");

	USE_SELINUX(renew_current_security_context());

	shell = getenv("SUSHELL");
	if (!shell) shell = getenv("sushell");
	if (!shell) {
		shell = "/bin/sh";
		if (pwd->pw_shell[0])
			shell = pwd->pw_shell;
	}
	run_shell(shell, 1, 0, 0);
	/* never returns */

auth_error:
	bb_error_msg_and_die("no password entry for 'root'");
}
Ejemplo n.º 12
0
static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd)
{
	char buf[512];
#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
# if ENABLE_FEATURE_WGET_TIMEOUT
	unsigned second_cnt;
# endif
	struct pollfd polldata;

	polldata.fd = fileno(dfp);
	polldata.events = POLLIN | POLLPRI;
	ndelay_on(polldata.fd);
#endif
	progress_meter(PROGRESS_START);

	if (G.chunked)
		goto get_clen;

	/* Loops only if chunked */
	while (1) {
		while (1) {
			int n;
			unsigned rdsz;

			rdsz = sizeof(buf);
			if (G.got_clen) {
				if (G.content_len < (off_t)sizeof(buf)) {
					if ((int)G.content_len <= 0)
						break;
					rdsz = (unsigned)G.content_len;
				}
			}
#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
# if ENABLE_FEATURE_WGET_TIMEOUT
			second_cnt = G.timeout_seconds;
# endif
			while (1) {
				if (safe_poll(&polldata, 1, 1000) != 0)
					break; /* error, EOF, or data is available */
# if ENABLE_FEATURE_WGET_TIMEOUT
				if (second_cnt != 0 && --second_cnt == 0) {
					progress_meter(PROGRESS_END);
					bb_perror_msg_and_die("download timed out");
				}
# endif
				/* Needed for "stalled" indicator */
				progress_meter(PROGRESS_BUMP);
			}
#endif
			n = safe_fread(buf, rdsz, dfp);
			if (n <= 0) {
				if (ferror(dfp)) {
					/* perror will not work: ferror doesn't set errno */
					bb_error_msg_and_die(bb_msg_read_error);
				}
				break;
			}
			xwrite(output_fd, buf, n);
#if ENABLE_FEATURE_WGET_STATUSBAR
			G.transferred += n;
			progress_meter(PROGRESS_BUMP);
#endif
			if (G.got_clen)
				G.content_len -= n;
		}

		if (!G.chunked)
			break;

		safe_fgets(buf, sizeof(buf), dfp); /* This is a newline */
 get_clen:
		safe_fgets(buf, sizeof(buf), dfp);
		G.content_len = STRTOOFF(buf, NULL, 16);
		/* FIXME: error check? */
		if (G.content_len == 0)
			break; /* all done! */
		G.got_clen = 1;
	}

	progress_meter(PROGRESS_END);
}
Ejemplo n.º 13
0
int chpasswd_main(int argc UNUSED_PARAM, char **argv)
{
	char *name;
	const char *algo = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO;
	int opt;

	if (getuid() != 0)
		bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);

	opt = getopt32long(argv, "^" "emc:" "\0" "m--ec:e--mc:c--em",
			chpasswd_longopts,
			&algo
	);

	while ((name = xmalloc_fgetline(stdin)) != NULL) {
		char *free_me;
		char *pass;
		int rc;

		pass = strchr(name, ':');
		if (!pass)
			bb_error_msg_and_die("missing new password");
		*pass++ = '\0';

		xuname2uid(name); /* dies if there is no such user */

		free_me = NULL;
		if (!(opt & OPT_ENC)) {
			char salt[MAX_PW_SALT_LEN];

			if (opt & OPT_MD5) {
				/* Force MD5 if the -m flag is set */
				algo = "md5";
			}

			crypt_make_pw_salt(salt, algo);
			free_me = pass = pw_encrypt(pass, salt, 0);
		}

		/* This is rather complex: if user is not found in /etc/shadow,
		 * we try to find & change his passwd in /etc/passwd */
#if ENABLE_FEATURE_SHADOWPASSWDS
		rc = update_passwd(bb_path_shadow_file, name, pass, NULL);
		if (rc > 0) /* password in /etc/shadow was updated */
			pass = (char*)"x";
		if (rc >= 0)
			/* 0 = /etc/shadow missing (not an error), >0 = passwd changed in /etc/shadow */
#endif
			rc = update_passwd(bb_path_passwd_file, name, pass, NULL);
		/* LOGMODE_BOTH logs to syslog also */
		logmode = LOGMODE_BOTH;
		if (rc < 0)
			bb_error_msg_and_die("an error occurred updating password for %s", name);
		if (rc)
			bb_error_msg("password for '%s' changed", name);
		logmode = LOGMODE_STDIO;
		free(name);
		free(free_me);
	}
	return EXIT_SUCCESS;
}
Ejemplo n.º 14
0
int ifconfig_main(int argc, char **argv)
{
	struct ifreq ifr;
	struct sockaddr_in sai;
#ifdef CONFIG_FEATURE_IPV6
	struct sockaddr_in6 sai6;
#endif
#ifdef CONFIG_FEATURE_IFCONFIG_HW
	struct sockaddr sa;
#endif
	const struct arg1opt *a1op;
	const struct options *op;
	int sockfd;			/* socket fd we use to manipulate stuff with */
	int goterr;
	int selector;
#ifdef CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS
	unsigned int mask;
	unsigned int did_flags;
	unsigned int sai_hostname, sai_netmask;
#else
	unsigned char mask;
	unsigned char did_flags;
#endif
	char *p;
	char host[128];

	goterr = 0;
	did_flags = 0;
#ifdef CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS
	sai_hostname = 0;
	sai_netmask = 0;
#endif

	/* skip argv[0] */
	++argv;
	--argc;

#ifdef CONFIG_FEATURE_IFCONFIG_STATUS
	if ((argc > 0) && (((*argv)[0] == '-') && ((*argv)[1] == 'a') && !(*argv)[2])) {
		interface_opt_a = 1;
		--argc;
		++argv;
	}
#endif

	if (argc <= 1) {
#ifdef CONFIG_FEATURE_IFCONFIG_STATUS
		return display_interfaces(argc ? *argv : NULL);
#else
		bb_error_msg_and_die
			("ifconfig was not compiled with interface status display support.");
#endif
	}

	/* Create a channel to the NET kernel. */
	if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		bb_perror_msg_and_die("socket");
	}

	/* get interface name */
	safe_strncpy(ifr.ifr_name, *argv, IFNAMSIZ);

	/* Process the remaining arguments. */
	while (*++argv != (char *) NULL) {
		p = *argv;
		mask = N_MASK;
		if (*p == '-') {	/* If the arg starts with '-'... */
			++p;		/*    advance past it and */
			mask = M_MASK;	/*    set the appropriate mask. */
		}
		for (op = OptArray; op->name; op++) {	/* Find table entry. */
			if (strcmp(p, op->name) == 0) {	/* If name matches... */
				if ((mask &= op->flags)) {	/* set the mask and go. */
					goto FOUND_ARG;;
				}
				/* If we get here, there was a valid arg with an */
				/* invalid '-' prefix. */
				++goterr;
				goto LOOP;
			}
		}

		/* We fell through, so treat as possible hostname. */
		a1op = Arg1Opt + (sizeof(Arg1Opt) / sizeof(Arg1Opt[0])) - 1;
		mask = op->arg_flags;
		goto HOSTNAME;

	  FOUND_ARG:
		if (mask & ARG_MASK) {
			mask = op->arg_flags;
			a1op = Arg1Opt + (op - OptArray);
			if (mask & A_NETMASK & did_flags) {
				bb_show_usage();
			}
			if (*++argv == NULL) {
				if (mask & A_ARG_REQ) {
					bb_show_usage();
				} else {
					--argv;
					mask &= A_SET_AFTER;	/* just for broadcast */
				}
			} else {	/* got an arg so process it */
			  HOSTNAME:
				did_flags |= (mask & (A_NETMASK|A_HOSTNAME));
				if (mask & A_CAST_HOST_COPY) {
#ifdef CONFIG_FEATURE_IFCONFIG_HW
					if (mask & A_CAST_RESOLVE) {
#endif
#ifdef CONFIG_FEATURE_IPV6
						char *prefix;
						int prefix_len = 0;
#endif

						safe_strncpy(host, *argv, (sizeof host));
#ifdef CONFIG_FEATURE_IPV6
						if ((prefix = strchr(host, '/'))) {
							if (safe_strtoi(prefix + 1, &prefix_len) ||
								(prefix_len < 0) || (prefix_len > 128))
							{
								++goterr;
								goto LOOP;
							}
							*prefix = 0;
						}
#endif

						sai.sin_family = AF_INET;
						sai.sin_port = 0;
						if (!strcmp(host, bb_INET_default)) {
							/* Default is special, meaning 0.0.0.0. */
							sai.sin_addr.s_addr = INADDR_ANY;
#ifdef CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS
						} else if (((host[0] == '+') && !host[1]) && (mask & A_BROADCAST) &&
								   (did_flags & (A_NETMASK|A_HOSTNAME)) == (A_NETMASK|A_HOSTNAME)) {
							/* + is special, meaning broadcast is derived. */
							sai.sin_addr.s_addr = (~sai_netmask) | (sai_hostname & sai_netmask);
#endif
#ifdef CONFIG_FEATURE_IPV6
						} else if (inet_pton(AF_INET6, host, &sai6.sin6_addr) > 0) {
							int sockfd6;
							struct in6_ifreq ifr6;

							memcpy((char *) &ifr6.ifr6_addr,
								   (char *) &sai6.sin6_addr,
								   sizeof(struct in6_addr));

							/* Create a channel to the NET kernel. */
							if ((sockfd6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
								bb_perror_msg_and_die("socket6");
							}
							if (ioctl(sockfd6, SIOGIFINDEX, &ifr) < 0) {
								perror("SIOGIFINDEX");
								++goterr;
								continue;
							}
							ifr6.ifr6_ifindex = ifr.ifr_ifindex;
							ifr6.ifr6_prefixlen = prefix_len;
							if (ioctl(sockfd6, a1op->selector, &ifr6) < 0) {
								perror(a1op->name);
								++goterr;
							}
							continue;
#endif
						} else if (inet_aton(host, &sai.sin_addr) == 0) {
							/* It's not a dotted quad. */
							struct hostent *hp;
							if ((hp = gethostbyname(host)) == (struct hostent *)NULL) {
								++goterr;
								continue;
							}
							memcpy((char *) &sai.sin_addr, (char *) hp->h_addr_list[0],
							sizeof(struct in_addr));
						}
#ifdef CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS
						if (mask & A_HOSTNAME) {
							sai_hostname = sai.sin_addr.s_addr;
						}
						if (mask & A_NETMASK) {
							sai_netmask = sai.sin_addr.s_addr;
						}
#endif
						p = (char *) &sai;
#ifdef CONFIG_FEATURE_IFCONFIG_HW
					} else {	/* A_CAST_HOST_COPY_IN_ETHER */
						/* This is the "hw" arg case. */
						if (strcmp("ether", *argv) || (*++argv == NULL)) {
							bb_show_usage();
						}
						safe_strncpy(host, *argv, (sizeof host));
						if (in_ether(host, &sa)) {
							bb_error_msg("invalid hw-addr %s", host);
							++goterr;
							continue;
						}
						p = (char *) &sa;
					}
#endif
					memcpy((((char *) (&ifr)) + a1op->ifr_offset),
						   p, sizeof(struct sockaddr));
				} else {
					unsigned int i = strtoul(*argv, NULL, 0);

					p = ((char *) (&ifr)) + a1op->ifr_offset;
#ifdef CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
					if (mask & A_MAP_TYPE) {
						if (ioctl(sockfd, SIOCGIFMAP, &ifr) < 0) {
							++goterr;
							continue;
						}
						if ((mask & A_MAP_UCHAR) == A_MAP_UCHAR) {
							*((unsigned char *) p) = i;
						} else if (mask & A_MAP_USHORT) {
							*((unsigned short *) p) = i;
						} else {
							*((unsigned long *) p) = i;
						}
					} else
#endif
					if (mask & A_CAST_CHAR_PTR) {
						*((caddr_t *) p) = (caddr_t) i;
					} else {	/* A_CAST_INT */
						*((int *) p) = i;
					}
				}

				if (ioctl(sockfd, a1op->selector, &ifr) < 0) {
					perror(a1op->name);
					++goterr;
					continue;
				}
#ifdef QUESTIONABLE_ALIAS_CASE
				if (mask & A_COLON_CHK) {
					/*
					 * Don't do the set_flag() if the address is an alias with
					 * a - at the end, since it's deleted already! - Roman
					 *
					 * Should really use regex.h here, not sure though how well
					 * it'll go with the cross-platform support etc.
					 */
					char *ptr;
					short int found_colon = 0;

					for (ptr = ifr.ifr_name; *ptr; ptr++) {
						if (*ptr == ':') {
							found_colon++;
						}
					}

					if (found_colon && *(ptr - 1) == '-') {
						continue;
					}
				}
#endif
			}
			if (!(mask & A_SET_AFTER)) {
				continue;
			}
			mask = N_SET;
		}

		if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
			perror("SIOCGIFFLAGS");
			++goterr;
		} else {
			selector = op->selector;
			if (mask & SET_MASK) {
				ifr.ifr_flags |= selector;
			} else {
				ifr.ifr_flags &= ~selector;
			}
			if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
				perror("SIOCSIFFLAGS");
				++goterr;
			}
		}
	  LOOP:
		continue;
	}					/* end of while-loop */

	return goterr;
}
Ejemplo n.º 15
0
static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_sockaddr *lsa)
{
	FILE *sfp;
	char *str;
	int port;

	if (!target->user)
		target->user = xstrdup("anonymous:busybox@");

	sfp = open_socket(lsa);
	if (ftpcmd(NULL, NULL, sfp) != 220)
		bb_error_msg_and_die("%s", sanitize_string(G.wget_buf + 4));

	/*
	 * Splitting username:password pair,
	 * trying to log in
	 */
	str = strchr(target->user, ':');
	if (str)
		*str++ = '\0';
	switch (ftpcmd("USER ", target->user, sfp)) {
	case 230:
		break;
	case 331:
		if (ftpcmd("PASS ", str, sfp) == 230)
			break;
		/* fall through (failed login) */
	default:
		bb_error_msg_and_die("ftp login: %s", sanitize_string(G.wget_buf + 4));
	}

	ftpcmd("TYPE I", NULL, sfp);

	/*
	 * Querying file size
	 */
	if (ftpcmd("SIZE ", target->path, sfp) == 213) {
		G.content_len = BB_STRTOOFF(G.wget_buf + 4, NULL, 10);
		if (G.content_len < 0 || errno) {
			bb_error_msg_and_die("SIZE value is garbage");
		}
		G.got_clen = 1;
	}

	/*
	 * Entering passive mode
	 */
	if (ftpcmd("PASV", NULL, sfp) != 227) {
 pasv_error:
		bb_error_msg_and_die("bad response to %s: %s", "PASV", sanitize_string(G.wget_buf));
	}
	// Response is "227 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
	str = strrchr(G.wget_buf, ')');
	if (str) str[0] = '\0';
	str = strrchr(G.wget_buf, ',');
	if (!str) goto pasv_error;
	port = xatou_range(str+1, 0, 255);
	*str = '\0';
	str = strrchr(G.wget_buf, ',');
	if (!str) goto pasv_error;
	port += xatou_range(str+1, 0, 255) * 256;
	set_nport(&lsa->u.sa, htons(port));

	*dfpp = open_socket(lsa);

	if (G.beg_range) {
		sprintf(G.wget_buf, "REST %"OFF_FMT"u", G.beg_range);
		if (ftpcmd(G.wget_buf, NULL, sfp) == 350)
			G.content_len -= G.beg_range;
	}

	if (ftpcmd("RETR ", target->path, sfp) > 150)
		bb_error_msg_and_die("bad response to %s: %s", "RETR", sanitize_string(G.wget_buf));

	return sfp;
}
Ejemplo n.º 16
0
int sed_main(int argc UNUSED_PARAM, char **argv)
{
	unsigned opt;
	llist_t *opt_e, *opt_f;
	char *opt_i;

#if ENABLE_LONG_OPTS
	static const char sed_longopts[] ALIGN1 =
		/* name             has_arg             short */
		"in-place\0"        Optional_argument   "i"
		"regexp-extended\0" No_argument         "r"
		"quiet\0"           No_argument         "n"
		"silent\0"          No_argument         "n"
		"expression\0"      Required_argument   "e"
		"file\0"            Required_argument   "f";
#endif

	INIT_G();

	/* destroy command strings on exit */
	if (ENABLE_FEATURE_CLEAN_UP) atexit(sed_free_and_close_stuff);

	/* Lie to autoconf when it starts asking stupid questions. */
	if (argv[1] && strcmp(argv[1], "--version") == 0) {
		puts("This is not GNU sed version 4.0");
		return 0;
	}

	/* do normal option parsing */
	opt_e = opt_f = NULL;
	opt_i = NULL;
	opt_complementary = "nn"; /* count -n */

	IF_LONG_OPTS(applet_long_options = sed_longopts);

	/* -i must be first, to match OPT_in_place definition */
	/* -E is a synonym of -r:
	 * GNU sed 4.2.1 mentions it in neither --help
	 * nor manpage, but does recognize it.
	 */
	opt = getopt32(argv, "i::rEne:*f:*", &opt_i, &opt_e, &opt_f,
			    &G.be_quiet); /* counter for -n */
	//argc -= optind;
	argv += optind;
	if (opt & OPT_in_place) { // -i
		atexit(cleanup_outname);
	}
	if (opt & (2|4))
		G.regex_type |= REG_EXTENDED; // -r or -E
	//if (opt & 8)
	//	G.be_quiet++; // -n (implemented with a counter instead)
	while (opt_e) { // -e
		add_cmd_block(llist_pop(&opt_e));
	}
	while (opt_f) { // -f
		char *line;
		FILE *cmdfile;
		cmdfile = xfopen_stdin(llist_pop(&opt_f));
		while ((line = xmalloc_fgetline(cmdfile)) != NULL) {
			add_cmd(line);
			free(line);
		}
		fclose_if_not_stdin(cmdfile);
	}
	/* if we didn't get a pattern from -e or -f, use argv[0] */
	if (!(opt & 0x30)) {
		if (!*argv)
			bb_show_usage();
		add_cmd_block(*argv++);
	}
	/* Flush any unfinished commands. */
	add_cmd("");

	/* By default, we write to stdout */
	G.nonstdout = stdout;

	/* argv[0..(argc-1)] should be names of file to process. If no
	 * files were specified or '-' was specified, take input from stdin.
	 * Otherwise, we process all the files specified. */
	G.input_file_list = argv;
	if (!argv[0]) {
		if (opt & OPT_in_place)
			bb_error_msg_and_die(bb_msg_requires_arg, "-i");
		argv[0] = (char*)bb_msg_standard_input;
		/* G.last_input_file = 0; - already is */
	} else {
		goto start;

		for (; *argv; argv++) {
			struct stat statbuf;
			int nonstdoutfd;
			sed_cmd_t *sed_cmd;

			G.last_input_file++;
 start:
			if (!(opt & OPT_in_place)) {
				if (LONE_DASH(*argv)) {
					*argv = (char*)bb_msg_standard_input;
					process_files();
				}
				continue;
			}

			/* -i: process each FILE separately: */

			if (stat(*argv, &statbuf) != 0) {
				bb_simple_perror_msg(*argv);
				G.exitcode = EXIT_FAILURE;
				G.current_input_file++;
				continue;
			}
			G.outname = xasprintf("%sXXXXXX", *argv);
			nonstdoutfd = xmkstemp(G.outname);
			G.nonstdout = xfdopen_for_write(nonstdoutfd);
			/* Set permissions/owner of output file */
			/* chmod'ing AFTER chown would preserve suid/sgid bits,
			 * but GNU sed 4.2.1 does not preserve them either */
			fchmod(nonstdoutfd, statbuf.st_mode);
			fchown(nonstdoutfd, statbuf.st_uid, statbuf.st_gid);

			process_files();
			fclose(G.nonstdout);
			G.nonstdout = stdout;

			if (opt_i) {
				char *backupname = xasprintf("%s%s", *argv, opt_i);
				xrename(*argv, backupname);
				free(backupname);
			}
			/* else unlink(*argv); - rename below does this */
			xrename(G.outname, *argv); //TODO: rollback backup on error?
			free(G.outname);
			G.outname = NULL;

			/* Fix disabled range matches and mangled ",+N" ranges */
			for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) {
				sed_cmd->beg_line = sed_cmd->beg_line_orig;
				sed_cmd->end_line = sed_cmd->end_line_orig;
			}
		}
		/* Here, to handle "sed 'cmds' nonexistent_file" case we did:
		 * if (G.current_input_file[G.current_input_file] == NULL)
		 *	return G.exitcode;
		 * but it's not needed since process_files() works correctly
		 * in this case too. */
	}

	process_files();

	return G.exitcode;
}
Ejemplo n.º 17
0
static void NOINLINE retrieve_file_data(FILE *dfp)
{
#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
# if ENABLE_FEATURE_WGET_TIMEOUT
	unsigned second_cnt;
# endif
	struct pollfd polldata;

	polldata.fd = fileno(dfp);
	polldata.events = POLLIN | POLLPRI;
#endif
	progress_meter(PROGRESS_START);

	if (G.chunked)
		goto get_clen;

	/* Loops only if chunked */
	while (1) {

#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
		/* Must use nonblocking I/O, otherwise fread will loop
		 * and *block* until it reads full buffer,
		 * which messes up progress bar and/or timeout logic.
		 * Because of nonblocking I/O, we need to dance
		 * very carefully around EAGAIN. See explanation at
		 * clearerr() call.
		 */
		ndelay_on(polldata.fd);
#endif
		while (1) {
			int n;
			unsigned rdsz;

			rdsz = sizeof(G.wget_buf);
			if (G.got_clen) {
				if (G.content_len < (off_t)sizeof(G.wget_buf)) {
					if ((int)G.content_len <= 0)
						break;
					rdsz = (unsigned)G.content_len;
				}
			}

#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
# if ENABLE_FEATURE_WGET_TIMEOUT
			second_cnt = G.timeout_seconds;
# endif
			while (1) {
				if (safe_poll(&polldata, 1, 1000) != 0)
					break; /* error, EOF, or data is available */
# if ENABLE_FEATURE_WGET_TIMEOUT
				if (second_cnt != 0 && --second_cnt == 0) {
					progress_meter(PROGRESS_END);
					bb_error_msg_and_die("download timed out");
				}
# endif
				/* Needed for "stalled" indicator */
				progress_meter(PROGRESS_BUMP);
			}

			/* fread internally uses read loop, which in our case
			 * is usually exited when we get EAGAIN.
			 * In this case, libc sets error marker on the stream.
			 * Need to clear it before next fread to avoid possible
			 * rare false positive ferror below. Rare because usually
			 * fread gets more than zero bytes, and we don't fall
			 * into if (n <= 0) ...
			 */
			clearerr(dfp);
			errno = 0;
#endif
			n = fread(G.wget_buf, 1, rdsz, dfp);
			/* man fread:
			 * If error occurs, or EOF is reached, the return value
			 * is a short item count (or zero).
			 * fread does not distinguish between EOF and error.
			 */
			if (n <= 0) {
#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
				if (errno == EAGAIN) /* poll lied, there is no data? */
					continue; /* yes */
#endif
				if (ferror(dfp))
					bb_perror_msg_and_die(bb_msg_read_error);
				break; /* EOF, not error */
			}

			xwrite(G.output_fd, G.wget_buf, n);

#if ENABLE_FEATURE_WGET_STATUSBAR
			G.transferred += n;
			progress_meter(PROGRESS_BUMP);
#endif
			if (G.got_clen) {
				G.content_len -= n;
				if (G.content_len == 0)
					break;
			}
		}
#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
		clearerr(dfp);
		ndelay_off(polldata.fd); /* else fgets can get very unhappy */
#endif
		if (!G.chunked)
			break;

		fgets_and_trim(dfp); /* Eat empty line */
 get_clen:
		fgets_and_trim(dfp);
		G.content_len = STRTOOFF(G.wget_buf, NULL, 16);
		/* FIXME: error check? */
		if (G.content_len == 0)
			break; /* all done! */
		G.got_clen = 1;
	}

	/* Draw full bar and free its resources */
	G.chunked = 0;  /* makes it show 100% even for chunked download */
	G.got_clen = 1; /* makes it show 100% even for download of (formerly) unknown size */
	progress_meter(PROGRESS_END);
}
Ejemplo n.º 18
0
static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr)
{
	int cflags = G.regex_type;
	char *match;
	int idx;

	/*
	 * A substitution command should look something like this:
	 *    s/match/replace/ #giIpw
	 *    ||     |        |||
	 *    mandatory       optional
	 */
	idx = parse_regex_delim(substr, &match, &sed_cmd->string);

	/* determine the number of back references in the match string */
	/* Note: we compute this here rather than in the do_subst_command()
	 * function to save processor time, at the expense of a little more memory
	 * (4 bits) per sed_cmd */

	/* process the flags */

	sed_cmd->which_match = 1;
	dbg("s flags:'%s'", substr + idx + 1);
	while (substr[++idx]) {
		dbg("s flag:'%c'", substr[idx]);
		/* Parse match number */
		if (isdigit(substr[idx])) {
			if (match[0] != '^') {
				/* Match 0 treated as all, multiple matches we take the last one. */
				const char *pos = substr + idx;
/* FIXME: error check? */
				sed_cmd->which_match = (unsigned)strtol(substr+idx, (char**) &pos, 10);
				idx = pos - substr - 1;
			}
			continue;
		}
		/* Skip spaces */
		if (isspace(substr[idx]))
			continue;

		switch (substr[idx]) {
		/* Replace all occurrences */
		case 'g':
			if (match[0] != '^')
				sed_cmd->which_match = 0;
			break;
		/* Print pattern space */
		case 'p':
			sed_cmd->sub_p = 1;
			break;
		/* Write to file */
		case 'w':
		{
			char *fname;
			idx += parse_file_cmd(/*sed_cmd,*/ substr+idx+1, &fname);
			sed_cmd->sw_file = xfopen_for_write(fname);
			sed_cmd->sw_last_char = '\n';
			free(fname);
			break;
		}
		/* Ignore case (gnu extension) */
		case 'i':
		case 'I':
			cflags |= REG_ICASE;
			break;
		/* Comment */
		case '#':
			// while (substr[++idx]) continue;
			idx += strlen(substr + idx); // same
			/* Fall through */
		/* End of command */
		case ';':
		case '}':
			goto out;
		default:
			dbg("s bad flags:'%s'", substr + idx);
			bb_error_msg_and_die("bad option in substitution expression");
		}
	}
 out:
	/* compile the match string into a regex */
	if (*match != '\0') {
		/* If match is empty, we use last regex used at runtime */
		sed_cmd->sub_match = xzalloc(sizeof(regex_t));
		dbg("xregcomp('%s',%x)", match, cflags);
		xregcomp(sed_cmd->sub_match, match, cflags);
		dbg("regcomp ok");
	}
	free(match);

	return idx;
}
Ejemplo n.º 19
0
int fbset_main(int argc, char **argv)
#endif
{
	struct fb_var_screeninfo var, varset;
	int fh, i;
	const char *fbdev = DEFAULTFBDEV;
	const char *modefile = DEFAULTFBMODE;
	char *thisarg, *mode = NULL;

	memset(&varset, 0xFF, sizeof(varset));

	/* parse cmd args.... why do they have to make things so difficult? */
	argv++;
	argc--;
	for (; argc > 0 && (thisarg = *argv); argc--, argv++) {
		for (i = 0; g_cmdoptions[i].name[0]; i++) {
			if (strcmp(thisarg, g_cmdoptions[i].name))
				continue;
			if (argc-1 < g_cmdoptions[i].param_count)
				bb_show_usage();

			switch (g_cmdoptions[i].code) {
			case CMD_FB:
				fbdev = argv[1];
				break;
			case CMD_DB:
				modefile = argv[1];
				break;
			case CMD_GEOMETRY:
				varset.xres = xatou32(argv[1]);
				varset.yres = xatou32(argv[2]);
				varset.xres_virtual = xatou32(argv[3]);
				varset.yres_virtual = xatou32(argv[4]);
				varset.bits_per_pixel = xatou32(argv[5]);
				break;
			case CMD_TIMING:
				varset.pixclock = xatou32(argv[1]);
				varset.left_margin = xatou32(argv[2]);
				varset.right_margin = xatou32(argv[3]);
				varset.upper_margin = xatou32(argv[4]);
				varset.lower_margin = xatou32(argv[5]);
				varset.hsync_len = xatou32(argv[6]);
				varset.vsync_len = xatou32(argv[7]);
				break;
			case CMD_ALL:
				g_options |= OPT_ALL;
				break;
			case CMD_CHANGE:
				g_options |= OPT_CHANGE;
				break;
#ifdef CONFIG_FEATURE_FBSET_FANCY
			case CMD_XRES:
				varset.xres = xatou32(argv[1]);
				break;
			case CMD_YRES:
				varset.yres = xatou32(argv[1]);
				break;
			case CMD_DEPTH:
				varset.bits_per_pixel = xatou32(argv[1]);
				break;
#endif
			}
			argc -= g_cmdoptions[i].param_count;
			argv += g_cmdoptions[i].param_count;
			break;
		}
		if (!g_cmdoptions[i].name[0]) {
			if (argc != 1)
				bb_show_usage();
			mode = *argv;
			g_options |= OPT_READMODE;
		}
	}

	fh = xopen(fbdev, O_RDONLY);
	if (ioctl(fh, FBIOGET_VSCREENINFO, &var))
		bb_perror_msg_and_die("ioctl(%sT_VSCREENINFO)", "GE");
	if (g_options & OPT_READMODE) {
		if (!readmode(&var, modefile, mode)) {
			bb_error_msg_and_die("unknown video mode '%s'", mode);
		}
	}

	setmode(&var, &varset);
	if (g_options & OPT_CHANGE) {
		if (g_options & OPT_ALL)
			var.activate = FB_ACTIVATE_ALL;
		if (ioctl(fh, FBIOPUT_VSCREENINFO, &var))
			bb_perror_msg_and_die("ioctl(%sT_VSCREENINFO)", "PU");
	}
	showmode(&var);
	/* Don't close the file, as exiting will take care of that */
	/* close(fh); */

	return EXIT_SUCCESS;
}
Ejemplo n.º 20
0
/*
 *  Process the commands arguments
 */
static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr)
{
	static const char cmd_letters[] ALIGN1 = "saicrw:btTydDgGhHlnNpPqx={}";
	enum {
		IDX_s = 0,
		IDX_a,
		IDX_i,
		IDX_c,
		IDX_r,
		IDX_w,
		IDX_colon,
		IDX_b,
		IDX_t,
		IDX_T,
		IDX_y,
		IDX_d,
		IDX_D,
		IDX_g,
		IDX_G,
		IDX_h,
		IDX_H,
		IDX_l,
		IDX_n,
		IDX_N,
		IDX_p,
		IDX_P,
		IDX_q,
		IDX_x,
		IDX_equal,
		IDX_lbrace,
		IDX_rbrace,
		IDX_nul
	};
	unsigned idx;

	BUILD_BUG_ON(sizeof(cmd_letters)-1 != IDX_nul);

	idx = strchrnul(cmd_letters, sed_cmd->cmd) - cmd_letters;

	/* handle (s)ubstitution command */
	if (idx == IDX_s) {
		cmdstr += parse_subst_cmd(sed_cmd, cmdstr);
	}
	/* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */
	else if (idx <= IDX_c) { /* a,i,c */
		unsigned len;

		if (idx < IDX_c) { /* a,i */
			if (sed_cmd->end_line || sed_cmd->end_match)
				bb_error_msg_and_die("command '%c' uses only one address", sed_cmd->cmd);
		}
		for (;;) {
			if (*cmdstr == '\n' || *cmdstr == '\\') {
				cmdstr++;
				break;
			}
			if (!isspace(*cmdstr))
				break;
			cmdstr++;
		}
		len = strlen(cmdstr);
		sed_cmd->string = copy_parsing_escapes(cmdstr, len);
		cmdstr += len;
		/* "\anychar" -> "anychar" */
		parse_escapes(sed_cmd->string, sed_cmd->string, -1, '\0', '\0');
	}
	/* handle file cmds: (r)ead */
	else if (idx <= IDX_w) { /* r,w */
		if (idx < IDX_w) { /* r */
			if (sed_cmd->end_line || sed_cmd->end_match)
				bb_error_msg_and_die("command '%c' uses only one address", sed_cmd->cmd);
		}
		cmdstr += parse_file_cmd(/*sed_cmd,*/ cmdstr, &sed_cmd->string);
		if (sed_cmd->cmd == 'w') {
			sed_cmd->sw_file = xfopen_for_write(sed_cmd->string);
			sed_cmd->sw_last_char = '\n';
		}
	}
	/* handle branch commands */
	else if (idx <= IDX_T) { /* :,b,t,T */
		int length;

		cmdstr = skip_whitespace(cmdstr);
		length = strcspn(cmdstr, semicolon_whitespace);
		if (length) {
			sed_cmd->string = xstrndup(cmdstr, length);
			cmdstr += length;
		}
	}
	/* translation command */
	else if (idx == IDX_y) {
		char *match, *replace;
		int i = cmdstr[0];

		cmdstr += parse_regex_delim(cmdstr, &match, &replace)+1;
		/* \n already parsed, but \delimiter needs unescaping. */
		parse_escapes(match,   match,   -1, i, i);
		parse_escapes(replace, replace, -1, i, i);

		sed_cmd->string = xzalloc((strlen(match) + 1) * 2);
		for (i = 0; match[i] && replace[i]; i++) {
			sed_cmd->string[i*2] = match[i];
			sed_cmd->string[i*2+1] = replace[i];
		}
		free(match);
		free(replace);
	}
	/* if it wasn't a single-letter command that takes no arguments
	 * then it must be an invalid command.
	 */
	else if (idx >= IDX_nul) { /* not d,D,g,G,h,H,l,n,N,p,P,q,x,=,{,} */
		bb_error_msg_and_die("unsupported command %c", sed_cmd->cmd);
	}

	/* give back whatever's left over */
	return cmdstr;
}
static void INET_setroute(int action, char **args)
{
	struct rtentry rt;
	const char *netmask;
	int skfd, isnet, xflag;

	assert((action == RTACTION_ADD) || (action == RTACTION_DEL));

	/* 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((char *) &rt, 0, sizeof(struct rtentry));

	{
		const char *target = *args++;

		/* 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 (xflag) {		/* Reinit isnet if -net or -host was specified. */
		isnet = (xflag & NET_FLAG);
	}

	/* Fill in the other fields. */
	rt.rt_flags = ((isnet) ? RTF_UP : (RTF_UP | RTF_HOST));

	netmask = bb_INET_default;

	while (*args) {
		int k = kw_lookup(tbl_ipvx, &args);
		const char *args_m1 = args[-1];

		if (k & KW_IPVx_FLAG_ONLY) {
			rt.rt_flags |= flags_ipvx[k & 3];
			continue;
		}

#if HAVE_NEW_ADDRT
		if (k == KW_IPVx_METRIC) {
			rt.rt_metric = bb_xgetularg10(args_m1) + 1;
			continue;
		}
#endif

		if (k == KW_IPVx_NETMASK) {
			struct sockaddr mask;

			if (mask_in_addr(rt)) {
				bb_show_usage();
			}

			netmask = args_m1;
			isnet = INET_resolve(netmask, (struct sockaddr_in *) &mask, 0);
			if (isnet < 0) {
				bb_error_msg_and_die("resolving %s", netmask);
			}
			rt.rt_genmask = full_mask(mask);
			continue;
		}

		if (k == KW_IPVx_GATEWAY) {
			if (rt.rt_flags & RTF_GATEWAY) {
				bb_show_usage();
			}

			isnet = INET_resolve(args_m1,
								 (struct sockaddr_in *) &rt.rt_gateway, 1);
			rt.rt_flags |= RTF_GATEWAY;

			if (isnet) {
				if (isnet < 0) {
					bb_error_msg_and_die("resolving %s", args_m1);
				}
				bb_error_msg_and_die("gateway %s is a NETWORK", args_m1);
			}
			continue;
		}

		if (k == KW_IPVx_MSS) {	/* Check valid MSS bounds. */
			rt.rt_flags |= RTF_MSS;
			rt.rt_mss = bb_xgetularg10_bnd(args_m1, 64, 32768);
			continue;
		}

		if (k == KW_IPVx_WINDOW) {	/* Check valid window bounds. */
			rt.rt_flags |= RTF_WINDOW;
			rt.rt_window = bb_xgetularg10_bnd(args_m1, 128, INT_MAX);
			continue;
		}

#ifdef RTF_IRTT
		if (k == KW_IPVx_IRTT) {
			rt.rt_flags |= RTF_IRTT;
			rt.rt_irtt = bb_xgetularg10(args_m1);
			rt.rt_irtt *= (sysconf(_SC_CLK_TCK) / 100);	/* FIXME */
#if 0					/* FIXME: do we need to check anything of this? */
			if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) {
				bb_error_msg_and_die("bad irtt");
			}
#endif
			continue;
		}
#endif

		/* Device is special in that it can be the last arg specified
		 * and doesn't requre the dev/device keyword in that case. */
		if (!rt.rt_dev && ((k == KW_IPVx_DEVICE) || (!k && !*++args))) {
			/* Don't use args_m1 here since args may have changed! */
			rt.rt_dev = args[-1];
			continue;
		}

		/* Nothing matched. */
		bb_show_usage();
	}

#ifdef RTF_REJECT
	if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev) {
		rt.rt_dev = "lo";
	}
#endif

	/* sanity checks.. */
	if (mask_in_addr(rt)) {
		unsigned long mask = mask_in_addr(rt);

		mask = ~ntohl(mask);
		if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) {
			bb_error_msg_and_die("netmask %.8x and host route conflict",
								 (unsigned int) mask);
		}
		if (mask & (mask + 1)) {
			bb_error_msg_and_die("bogus netmask %s", netmask);
		}
		mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr;
		if (mask & ~mask_in_addr(rt)) {
			bb_error_msg_and_die("netmask and route address conflict");
		}
	}

	/* Fill out netmask if still unset */
	if ((action == RTACTION_ADD) && (rt.rt_flags & RTF_HOST)) {
		mask_in_addr(rt) = 0xffffffff;
	}

	/* Create a socket to the INET kernel. */
	if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		bb_perror_msg_and_die("socket");
	}

	if (ioctl(skfd, ((action==RTACTION_ADD) ? SIOCADDRT : SIOCDELRT), &rt)<0) {
		bb_perror_msg_and_die("SIOC[ADD|DEL]RT");
	}

	/* Don't bother closing, as we're exiting after we return anyway. */
	/* close(skfd); */
}
Ejemplo n.º 22
0
static void add_cmd(const char *cmdstr)
{
	sed_cmd_t *sed_cmd;
	unsigned len, n;

	/* Append this line to any unfinished line from last time. */
	if (G.add_cmd_line) {
		char *tp = xasprintf("%s\n%s", G.add_cmd_line, cmdstr);
		free(G.add_cmd_line);
		cmdstr = G.add_cmd_line = tp;
	}

	/* If this line ends with unescaped backslash, request next line. */
	n = len = strlen(cmdstr);
	while (n && cmdstr[n-1] == '\\')
		n--;
	if ((len - n) & 1) { /* if odd number of trailing backslashes */
		if (!G.add_cmd_line)
			G.add_cmd_line = xstrdup(cmdstr);
		G.add_cmd_line[len-1] = '\0';
		return;
	}

	/* Loop parsing all commands in this line. */
	while (*cmdstr) {
		/* Skip leading whitespace and semicolons */
		cmdstr += strspn(cmdstr, semicolon_whitespace);

		/* If no more commands, exit. */
		if (!*cmdstr) break;

		/* if this is a comment, jump past it and keep going */
		if (*cmdstr == '#') {
			/* "#n" is the same as using -n on the command line */
			if (cmdstr[1] == 'n')
				G.be_quiet++;
			cmdstr = strpbrk(cmdstr, "\n\r");
			if (!cmdstr) break;
			continue;
		}

		/* parse the command
		 * format is: [addr][,addr][!]cmd
		 *            |----||-----||-|
		 *            part1 part2  part3
		 */

		sed_cmd = xzalloc(sizeof(sed_cmd_t));

		/* first part (if present) is an address: either a '$', a number or a /regex/ */
		cmdstr += get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match);
		sed_cmd->beg_line_orig = sed_cmd->beg_line;

		/* second part (if present) will begin with a comma */
		if (*cmdstr == ',') {
			int idx;

			cmdstr++;
			if (*cmdstr == '+' && isdigit(cmdstr[1])) {
				/* http://sed.sourceforge.net/sedfaq3.html#s3.3
				 * Under GNU sed 3.02+, ssed, and sed15+, <address2>
				 * may also be a notation of the form +num,
				 * indicating the next num lines after <address1> is
				 * matched.
				 * GNU sed 4.2.1 accepts even "+" (meaning "+0").
				 * We don't (we check for isdigit, see above), think
				 * about the "+-3" case.
				 */
				char *end;
				/* code is smaller compared to using &cmdstr here: */
				idx = strtol(cmdstr+1, &end, 10);
				sed_cmd->end_line = -2 - idx;
				cmdstr = end;
			} else {
				idx = get_address(cmdstr, &sed_cmd->end_line, &sed_cmd->end_match);
				cmdstr += idx;
				idx--; /* if 0, trigger error check below */
			}
			if (idx < 0)
				bb_error_msg_and_die("no address after comma");
			sed_cmd->end_line_orig = sed_cmd->end_line;
		}

		/* skip whitespace before the command */
		cmdstr = skip_whitespace(cmdstr);

		/* Check for inversion flag */
		if (*cmdstr == '!') {
			sed_cmd->invert = 1;
			cmdstr++;

			/* skip whitespace before the command */
			cmdstr = skip_whitespace(cmdstr);
		}

		/* last part (mandatory) will be a command */
		if (!*cmdstr)
			bb_error_msg_and_die("missing command");
		sed_cmd->cmd = *cmdstr++;
		cmdstr = parse_cmd_args(sed_cmd, cmdstr);

		/* cmdstr now points past args.
		 * GNU sed requires a separator, if there are more commands,
		 * else it complains "char N: extra characters after command".
		 * Example: "sed 'p;d'". We also allow "sed 'pd'".
		 */

		/* Add the command to the command array */
		*G.sed_cmd_tail = sed_cmd;
		G.sed_cmd_tail = &sed_cmd->next;
	}

	/* If we glued multiple lines together, free the memory. */
	free(G.add_cmd_line);
	G.add_cmd_line = NULL;
}
void displayroutes(int noresolve, int netstatfmt)
{
	char devname[64], flags[16], sdest[16], sgw[16];
	unsigned long int d, g, m;
	int flgs, ref, use, metric, mtu, win, ir;
	struct sockaddr_in s_addr;
	struct in_addr mask;

	FILE *fp = bb_xfopen("/proc/net/route", "r");

	bb_printf("Kernel IP routing table\n"
			  "Destination     Gateway         Genmask"
			  "         Flags %s Iface\n",
			  netstatfmt ? "  MSS Window  irtt" : "Metric Ref    Use");

	if (fscanf(fp, "%*[^\n]\n") < 0) { /* Skip the first line. */
		goto ERROR;		   /* Empty or missing line, or read error. */
	}
	while (1) {
		int r;
		r = fscanf(fp, "%63s%lx%lx%X%d%d%d%lx%d%d%d\n",
				   devname, &d, &g, &flgs, &ref, &use, &metric, &m,
				   &mtu, &win, &ir);
		if (r != 11) {
			if ((r < 0) && feof(fp)) { /* EOF with no (nonspace) chars read. */
				break;
			}
		ERROR:
			bb_error_msg_and_die("fscanf");
		}

		if (!(flgs & RTF_UP)) { /* Skip interfaces that are down. */
			continue;
		}

		set_flags(flags, (flgs & IPV4_MASK));
#ifdef RTF_REJECT
		if (flgs & RTF_REJECT) {
			flags[0] = '!';
		}
#endif

		memset(&s_addr, 0, sizeof(struct sockaddr_in));
		s_addr.sin_family = AF_INET;
		s_addr.sin_addr.s_addr = d;
		INET_rresolve(sdest, sizeof(sdest), &s_addr,
					  (noresolve | 0x8000), m);	/* Default instead of *. */

		s_addr.sin_addr.s_addr = g;
		INET_rresolve(sgw, sizeof(sgw), &s_addr,
					  (noresolve | 0x4000), m);	/* Host instead of net. */

		mask.s_addr = m;
		bb_printf("%-16s%-16s%-16s%-6s", sdest, sgw, inet_ntoa(mask), flags);
		if (netstatfmt) {
			bb_printf("%5d %-5d %6d %s\n", mtu, win, ir, devname);
		} else {
			bb_printf("%-6d %-2d %7d %s\n", metric, ref, use, devname);
		}
	}
}
Ejemplo n.º 24
0
static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p)
{
	char *line = *line_p;
	unsigned match_count = 0;
	bool altered = 0;
	bool prev_match_empty = 1;
	bool tried_at_eol = 0;
	regex_t *current_regex;

	current_regex = sed_cmd->sub_match;
	/* Handle empty regex. */
	if (!current_regex) {
		current_regex = G.previous_regex_ptr;
		if (!current_regex)
			bb_error_msg_and_die("no previous regexp");
	}
	G.previous_regex_ptr = current_regex;

	/* Find the first match */
	dbg("matching '%s'", line);
	if (REG_NOMATCH == regexec(current_regex, line, 10, G.regmatch, 0)) {
		dbg("no match");
		return 0;
	}
	dbg("match");

	/* Initialize temporary output buffer. */
	G.pipeline.buf = xmalloc(PIPE_GROW);
	G.pipeline.len = PIPE_GROW;
	G.pipeline.idx = 0;

	/* Now loop through, substituting for matches */
	do {
		int start = G.regmatch[0].rm_so;
		int end = G.regmatch[0].rm_eo;
		int i;

		match_count++;

		/* If we aren't interested in this match, output old line to
		 * end of match and continue */
		if (sed_cmd->which_match
		 && (sed_cmd->which_match != match_count)
		) {
			for (i = 0; i < end; i++)
				pipe_putc(*line++);
			/* Null match? Print one more char */
			if (start == end && *line)
				pipe_putc(*line++);
			goto next;
		}

		/* Print everything before the match */
		for (i = 0; i < start; i++)
			pipe_putc(line[i]);

		/* Then print the substitution string,
		 * unless we just matched empty string after non-empty one.
		 * Example: string "cccd", pattern "c*", repl "R":
		 * result is "RdR", not "RRdR": first match "ccc",
		 * second is "" before "d", third is "" after "d".
		 * Second match is NOT replaced!
		 */
		if (prev_match_empty || start != 0 || start != end) {
			//dbg("%d %d %d", prev_match_empty, start, end);
			dbg("inserting replacement at %d in '%s'", start, line);
			do_subst_w_backrefs(line, sed_cmd->string);
			/* Flag that something has changed */
			altered = 1;
		} else {
			dbg("NOT inserting replacement at %d in '%s'", start, line);
		}

		/* If matched string is empty (f.e. "c*" pattern),
		 * copy verbatim one char after it before attempting more matches
		 */
		prev_match_empty = (start == end);
		if (prev_match_empty) {
			if (!line[end]) {
				tried_at_eol = 1;
			} else {
				pipe_putc(line[end]);
				end++;
			}
		}

		/* Advance past the match */
		dbg("line += %d", end);
		line += end;

		/* if we're not doing this globally, get out now */
		if (sed_cmd->which_match != 0)
			break;
 next:
		/* Exit if we are at EOL and already tried matching at it */
		if (*line == '\0') {
			if (tried_at_eol)
				break;
			tried_at_eol = 1;
		}

//maybe (end ? REG_NOTBOL : 0) instead of unconditional REG_NOTBOL?
	} while (regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH);

	/* Copy rest of string into output pipeline */
	while (1) {
		char c = *line++;
		pipe_putc(c);
		if (c == '\0')
			break;
	}

	free(*line_p);
	*line_p = G.pipeline.buf;
	return altered;
}
Ejemplo n.º 25
0
static char* FAST_FUNC process_stdin(int n_max_chars, int n_max_arg, char *buf)
{
#define NORM      0
#define QUOTE     1
#define BACKSLASH 2
#define SPACE     4
	char q = '\0';             /* quote char */
	char state = NORM;
	char *s = buf;             /* start of the word */
	char *p = s + strlen(buf); /* end of the word */

	buf += n_max_chars;        /* past buffer's end */

	/* "goto ret" is used instead of "break" to make control flow
	 * more obvious: */

	while (1) {
		int c = getchar();
		if (c == EOF) {
			if (p != s)
				goto close_word;
			goto ret;
		}
		if (state == BACKSLASH) {
			state = NORM;
			goto set;
		}
		if (state == QUOTE) {
			if (c != q)
				goto set;
			q = '\0';
			state = NORM;
		} else { /* if (state == NORM) */
			if (ISSPACE(c)) {
				if (p != s) {
 close_word:
					state = SPACE;
					c = '\0';
					goto set;
				}
			} else {
				if (c == '\\') {
					state = BACKSLASH;
				} else if (c == '\'' || c == '"') {
					q = c;
					state = QUOTE;
				} else {
 set:
					*p++ = c;
				}
			}
		}
		if (state == SPACE) {   /* word's delimiter or EOF detected */
			if (q) {
				bb_error_msg_and_die("unmatched %s quote",
					q == '\'' ? "single" : "double");
			}
			/* A full word is loaded */
			if (G.eof_str) {
				if (strcmp(s, G.eof_str) == 0) {
					while (getchar() != EOF)
						continue;
					p = s;
					goto ret;
				}
			}
			store_param(s);
			dbg_msg("args[]:'%s'", s);
			s = p;
			n_max_arg--;
			if (n_max_arg == 0) {
				goto ret;
			}
			state = NORM;
		}
		if (p == buf) {
			goto ret;
		}
	}
 ret:
	*p = '\0';
	/* store_param(NULL) - caller will do it */
	dbg_msg("return:'%s'", s);
	return s;
}
Ejemplo n.º 26
0
static int writeTarHeader(struct TarBallInfo *tbInfo,
		const char *header_name, const char *fileName, struct stat *statbuf)
{
	struct TarHeader header;

	if (sizeof(header) != 512)
		BUG_tar_header_size();

	memset(&header, 0, sizeof(struct TarHeader));

	strncpy(header.name, header_name, sizeof(header.name));

	/* POSIX says to mask mode with 07777. */
	PUT_OCTAL(header.mode, statbuf->st_mode & 07777);
	PUT_OCTAL(header.uid, statbuf->st_uid);
	PUT_OCTAL(header.gid, statbuf->st_gid);
	memset(header.size, '0', sizeof(header.size)-1); /* Regular file size is handled later */
	PUT_OCTAL(header.mtime, statbuf->st_mtime);

	/* Enter the user and group names */
	safe_strncpy(header.uname, get_cached_username(statbuf->st_uid), sizeof(header.uname));
	safe_strncpy(header.gname, get_cached_groupname(statbuf->st_gid), sizeof(header.gname));

	if (tbInfo->hlInfo) {
		/* This is a hard link */
		header.typeflag = LNKTYPE;
		strncpy(header.linkname, tbInfo->hlInfo->name,
				sizeof(header.linkname));
#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
		/* Write out long linkname if needed */
		if (header.linkname[sizeof(header.linkname)-1])
			writeLongname(tbInfo->tarFd, GNULONGLINK,
					tbInfo->hlInfo->name, 0);
#endif
	} else if (S_ISLNK(statbuf->st_mode)) {
		char *lpath = xmalloc_readlink_or_warn(fileName);
		if (!lpath)
			return FALSE;
		header.typeflag = SYMTYPE;
		strncpy(header.linkname, lpath, sizeof(header.linkname));
#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
		/* Write out long linkname if needed */
		if (header.linkname[sizeof(header.linkname)-1])
			writeLongname(tbInfo->tarFd, GNULONGLINK, lpath, 0);
#else
		/* If it is larger than 100 bytes, bail out */
		if (header.linkname[sizeof(header.linkname)-1]) {
			free(lpath);
			bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
			return FALSE;
		}
#endif
		free(lpath);
	} else if (S_ISDIR(statbuf->st_mode)) {
		header.typeflag = DIRTYPE;
		/* Append '/' only if there is a space for it */
		if (!header.name[sizeof(header.name)-1])
			header.name[strlen(header.name)] = '/';
	} else if (S_ISCHR(statbuf->st_mode)) {
		header.typeflag = CHRTYPE;
		PUT_OCTAL(header.devmajor, major(statbuf->st_rdev));
		PUT_OCTAL(header.devminor, minor(statbuf->st_rdev));
	} else if (S_ISBLK(statbuf->st_mode)) {
		header.typeflag = BLKTYPE;
		PUT_OCTAL(header.devmajor, major(statbuf->st_rdev));
		PUT_OCTAL(header.devminor, minor(statbuf->st_rdev));
	} else if (S_ISFIFO(statbuf->st_mode)) {
		header.typeflag = FIFOTYPE;
	} else if (S_ISREG(statbuf->st_mode)) {
		if (sizeof(statbuf->st_size) > 4
		 && statbuf->st_size > (off_t)0777777777777LL
		) {
			bb_error_msg_and_die("cannot store file '%s' "
				"of size %"OFF_FMT"d, aborting",
				fileName, statbuf->st_size);
		}
		header.typeflag = REGTYPE;
		PUT_OCTAL(header.size, statbuf->st_size);
	} else {
		bb_error_msg("%s: unknown file type", fileName);
		return FALSE;
	}

#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
	/* Write out long name if needed */
	/* (we, like GNU tar, output long linkname *before* long name) */
	if (header.name[sizeof(header.name)-1])
		writeLongname(tbInfo->tarFd, GNULONGNAME,
				header_name, S_ISDIR(statbuf->st_mode));
#endif

	/* Now write the header out to disk */
	chksum_and_xwrite(tbInfo->tarFd, &header);

	/* Now do the verbose thing (or not) */
	if (tbInfo->verboseFlag) {
		FILE *vbFd = stdout;

		if (tbInfo->tarFd == STDOUT_FILENO)	/* If the archive goes to stdout, verbose to stderr */
			vbFd = stderr;
		/* GNU "tar cvvf" prints "extended" listing a-la "ls -l" */
		/* We don't have such excesses here: for us "v" == "vv" */
		/* '/' is probably a GNUism */
		fprintf(vbFd, "%s%s\n", header_name,
				S_ISDIR(statbuf->st_mode) ? "/" : "");
	}

	return TRUE;
}
Ejemplo n.º 27
0
static void die_must_be_on_off(const char *msg)
{
	bb_error_msg_and_die("argument of \"%s\" must be \"on\" or \"off\"", msg);
}
Ejemplo n.º 28
0
int tar_main(int argc UNUSED_PARAM, char **argv)
{
	char FAST_FUNC (*get_header_ptr)(archive_handle_t *) = get_header_tar;
	archive_handle_t *tar_handle;
	char *base_dir = NULL;
	const char *tar_filename = "-";
	unsigned opt;
	int verboseFlag = 0;
#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
	llist_t *excludes = NULL;
#endif

	/* Initialise default values */
	tar_handle = init_handle();
	tar_handle->ah_flags = ARCHIVE_CREATE_LEADING_DIRS
	                     | ARCHIVE_PRESERVE_DATE
	                     | ARCHIVE_EXTRACT_UNCONDITIONAL;

	/* Apparently only root's tar preserves perms (see bug 3844) */
	if (getuid() != 0)
		tar_handle->ah_flags |= ARCHIVE_NOPRESERVE_PERM;

	/* Prepend '-' to the first argument if required */
	opt_complementary = "--:" // first arg is options
		"tt:vv:" // count -t,-v
		"?:" // bail out with usage instead of error return
		"X::T::" // cumulative lists
#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
		"\xff::" // cumulative lists for --exclude
#endif
		USE_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd
		USE_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive
		SKIP_FEATURE_TAR_CREATE("t--x:x--t"); // mutually exclusive
#if ENABLE_FEATURE_TAR_LONG_OPTIONS
	applet_long_options = tar_longopts;
#endif
	opt = getopt32(argv,
		"txC:f:Opvk"
		USE_FEATURE_TAR_CREATE(   "ch"  )
		USE_FEATURE_SEAMLESS_BZ2( "j"   )
		USE_FEATURE_SEAMLESS_LZMA("a"   )
		USE_FEATURE_TAR_FROM(     "T:X:")
		USE_FEATURE_SEAMLESS_GZ(  "z"   )
		USE_FEATURE_SEAMLESS_Z(   "Z"   )
		, &base_dir // -C dir
		, &tar_filename // -f filename
		USE_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T
		USE_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X
#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
		, &excludes // --exclude
#endif
		, &verboseFlag // combined count for -t and -v
		, &verboseFlag // combined count for -t and -v
		);
	argv += optind;

	if (verboseFlag) tar_handle->action_header = header_verbose_list;
	if (verboseFlag == 1) tar_handle->action_header = header_list;

	if (opt & OPT_EXTRACT)
		tar_handle->action_data = data_extract_all;

	if (opt & OPT_2STDOUT)
		tar_handle->action_data = data_extract_to_stdout;

	if (opt & OPT_KEEP_OLD)
		tar_handle->ah_flags &= ~ARCHIVE_EXTRACT_UNCONDITIONAL;

	if (opt & OPT_NOPRESERVE_OWN)
		tar_handle->ah_flags |= ARCHIVE_NOPRESERVE_OWN;

	if (opt & OPT_NOPRESERVE_PERM)
		tar_handle->ah_flags |= ARCHIVE_NOPRESERVE_PERM;

	if (opt & OPT_GZIP)
		get_header_ptr = get_header_tar_gz;

	if (opt & OPT_BZIP2)
		get_header_ptr = get_header_tar_bz2;

	if (opt & OPT_LZMA)
		get_header_ptr = get_header_tar_lzma;

	if (opt & OPT_COMPRESS)
		get_header_ptr = get_header_tar_Z;

#if ENABLE_FEATURE_TAR_FROM
	tar_handle->reject = append_file_list_to_list(tar_handle->reject);
#if ENABLE_FEATURE_TAR_LONG_OPTIONS
	/* Append excludes to reject */
	while (excludes) {
		llist_t *next = excludes->link;
		excludes->link = tar_handle->reject;
		tar_handle->reject = excludes;
		excludes = next;
	}
#endif
	tar_handle->accept = append_file_list_to_list(tar_handle->accept);
#endif

	/* Setup an array of filenames to work with */
	/* TODO: This is the same as in ar, separate function ? */
	while (*argv) {
		/* kill trailing '/' unless the string is just "/" */
		char *cp = last_char_is(*argv, '/');
		if (cp > *argv)
			*cp = '\0';
		llist_add_to_end(&tar_handle->accept, *argv);
		argv++;
	}

	if (tar_handle->accept || tar_handle->reject)
		tar_handle->filter = filter_accept_reject_list;

	/* Open the tar file */
	{
		FILE *tar_stream;
		int flags;

		if (opt & OPT_CREATE) {
			/* Make sure there is at least one file to tar up.  */
			if (tar_handle->accept == NULL)
				bb_error_msg_and_die("empty archive");

			tar_stream = stdout;
			/* Mimicking GNU tar 1.15.1: */
			flags = O_WRONLY | O_CREAT | O_TRUNC;
		} else {
			tar_stream = stdin;
			flags = O_RDONLY;
		}

		if (LONE_DASH(tar_filename)) {
			tar_handle->src_fd = fileno(tar_stream);
			tar_handle->seek = seek_by_read;
		} else {
			if (ENABLE_FEATURE_TAR_AUTODETECT && flags == O_RDONLY) {
				get_header_ptr = get_header_tar;
				tar_handle->src_fd = open_zipped(tar_filename);
				if (tar_handle->src_fd < 0)
					bb_perror_msg_and_die("can't open '%s'", tar_filename);
			} else {
				tar_handle->src_fd = xopen(tar_filename, flags);
			}
		}
	}

	if (base_dir)
		xchdir(base_dir);

#ifdef CHECK_FOR_CHILD_EXITCODE
	/* We need to know whether child (gzip/bzip/etc) exits abnormally */
	signal(SIGCHLD, handle_SIGCHLD);
#endif

	/* create an archive */
	if (opt & OPT_CREATE) {
#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
		int zipMode = 0;
		if (ENABLE_FEATURE_SEAMLESS_GZ && (opt & OPT_GZIP))
			zipMode = 1;
		if (ENABLE_FEATURE_SEAMLESS_BZ2 && (opt & OPT_BZIP2))
			zipMode = 2;
#endif
		/* NB: writeTarFile() closes tar_handle->src_fd */
		return writeTarFile(tar_handle->src_fd, verboseFlag, opt & OPT_DEREFERENCE,
				tar_handle->accept,
				tar_handle->reject, zipMode);
	}

	while (get_header_ptr(tar_handle) == EXIT_SUCCESS)
		continue;

	/* Check that every file that should have been extracted was */
	while (tar_handle->accept) {
		if (!find_list_entry(tar_handle->reject, tar_handle->accept->data)
		 && !find_list_entry(tar_handle->passed, tar_handle->accept->data)
		) {
			bb_error_msg_and_die("%s: not found in archive",
				tar_handle->accept->data);
		}
		tar_handle->accept = tar_handle->accept->link;
	}
	if (ENABLE_FEATURE_CLEAN_UP /* && tar_handle->src_fd != STDIN_FILENO */)
		close(tar_handle->src_fd);

	return EXIT_SUCCESS;
}
Ejemplo n.º 29
0
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_1_to_2(*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));
}
Ejemplo n.º 30
0
int fbset_main(int argc, char **argv)
{
	enum {
		OPT_CHANGE   = (1 << 0),
		OPT_SHOW     = (1 << 1),
		OPT_READMODE = (1 << 2),
		OPT_ALL      = (1 << 9),
	};
	struct fb_var_screeninfo var, varset;
	int fh, i;
	unsigned options = 0;

	const char *fbdev = DEFAULTFBDEV;
	const char *modefile = DEFAULTFBMODE;
	char *thisarg, *mode = NULL;

	memset(&varset, 0xff, sizeof(varset));

	/* parse cmd args.... why do they have to make things so difficult? */
	argv++;
	argc--;
	for (; argc > 0 && (thisarg = *argv) != NULL; argc--, argv++) {
		if (thisarg[0] == '-') for (i = 0; i < ARRAY_SIZE(g_cmdoptions); i++) {
			if (strcmp(thisarg + 1, g_cmdoptions[i].name) != 0)
				continue;
			if (argc <= g_cmdoptions[i].param_count)
				bb_show_usage();

			switch (g_cmdoptions[i].code) {
			case CMD_FB:
				fbdev = argv[1];
				break;
			case CMD_DB:
				modefile = argv[1];
				break;
			case CMD_ALL:
				options |= OPT_ALL;
				break;
			case CMD_SHOW:
				options |= OPT_SHOW;
				break;
			case CMD_GEOMETRY:
				varset.xres = xatou32(argv[1]);
				varset.yres = xatou32(argv[2]);
				varset.xres_virtual = xatou32(argv[3]);
				varset.yres_virtual = xatou32(argv[4]);
				varset.bits_per_pixel = xatou32(argv[5]);
				break;
			case CMD_TIMING:
				varset.pixclock = xatou32(argv[1]);
				varset.left_margin = xatou32(argv[2]);
				varset.right_margin = xatou32(argv[3]);
				varset.upper_margin = xatou32(argv[4]);
				varset.lower_margin = xatou32(argv[5]);
				varset.hsync_len = xatou32(argv[6]);
				varset.vsync_len = xatou32(argv[7]);
				break;
#if ENABLE_FEATURE_FBSET_FANCY
			case CMD_XRES:
				varset.xres = xatou32(argv[1]);
				break;
			case CMD_YRES:
				varset.yres = xatou32(argv[1]);
				break;
			case CMD_DEPTH:
				varset.bits_per_pixel = xatou32(argv[1]);
				break;
#endif
			}
			switch (g_cmdoptions[i].code) {
			case CMD_FB:
			case CMD_DB:
			case CMD_ALL:
			case CMD_SHOW:
				break;
			default:
				options |= OPT_CHANGE; /* the other commands imply changes */
			}
			argc -= g_cmdoptions[i].param_count;
			argv += g_cmdoptions[i].param_count;
			goto contin;
		}
		if (argc != 1)
			bb_show_usage();
		mode = *argv;
		options |= OPT_READMODE;
 contin: ;
	}

	fh = xopen(fbdev, O_RDONLY);
	xioctl(fh, FBIOGET_VSCREENINFO, &var);
	if (options & OPT_READMODE) {
#if !ENABLE_FEATURE_FBSET_READMODE
		bb_show_usage();
#else
		if (!read_mode_db(&var, modefile, mode)) {
			bb_error_msg_and_die("unknown video mode '%s'", mode);
		}
#endif
	}

	if (options & OPT_CHANGE) {
		setmode(&var, &varset);
		if (options & OPT_ALL)
			var.activate = FB_ACTIVATE_ALL;
		xioctl(fh, FBIOPUT_VSCREENINFO, &var);
	}
	if (options == 0 || options & OPT_SHOW)
		showmode(&var);
	/* Don't close the file, as exiting will take care of that */
	/* close(fh); */

	return EXIT_SUCCESS;
}