Example #1
0
int makedevs_main(int argc, char **argv)
{
	mode_t mode;
	char *basedev, *type, *nodname, *buf;
	int Smajor, Sminor, S, E;

	if (argc < 7 || argv[1][0] == '-')
		bb_show_usage();

	basedev = argv[1];
	buf = xasprintf("%s%u", argv[1], (unsigned)-1);
	type = argv[2];
	Smajor = xatoi_positive(argv[3]);
	Sminor = xatoi_positive(argv[4]);
	S = xatoi_positive(argv[5]);
	E = xatoi_positive(argv[6]);
	nodname = argv[7] ? basedev : buf;

	mode = 0660;
	switch (type[0]) {
	case 'c':
		mode |= S_IFCHR;
		break;
	case 'b':
		mode |= S_IFBLK;
		break;
	case 'f':
		mode |= S_IFIFO;
		break;
	default:
		bb_show_usage();
	}

	while (S <= E) {
		sprintf(buf, "%s%u", basedev, S);

		/* if mode != S_IFCHR and != S_IFBLK,
		 * third param in mknod() ignored */
		if (mknod(nodname, mode, makedev(Smajor, Sminor)) != 0
		 && errno != EEXIST
		) {
			bb_perror_msg("can't create '%s'", nodname);
		}

		/*if (nodname == basedev)*/ /* ex. /dev/hda - to /dev/hda1 ... */
			nodname = buf;
		S++;
		Sminor++;
	}

	return 0;
}
Example #2
0
static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf)
{
	int result;
	if (s1) {
		if (!s2) s2 = "";
		fprintf(fp, "%s%s\r\n", s1, s2);
		fflush(fp);
	}

	do {
		char *buf_ptr;

		if (fgets(buf, 510, fp) == NULL) {
			bb_perror_msg_and_die("error getting response");
		}
		buf_ptr = strstr(buf, "\r\n");
		if (buf_ptr) {
			*buf_ptr = '\0';
		}
	} while (!isdigit(buf[0]) || buf[3] != ' ');

	buf[3] = '\0';
	result = xatoi_positive(buf);
	buf[3] = ' ';
	return result;
}
Example #3
0
static int is_hpet_irq(const char *name)
{
	char *p;
# if BLOATY_HPET_IRQ_NUM_DETECTION
	long hpet_chan;

	/* Learn the range of existing hpet timers. This is done once */
	if (!G.scanned_timer_list) {
		FILE *fp;
		char buf[80];

		G.scanned_timer_list = true;
		fp = fopen_for_read("/proc/timer_list");
		if (!fp)
			return 0;

		while (fgets(buf, sizeof(buf), fp)) {
			p = strstr(buf, "Clock Event Device: hpet");
			if (!p)
				continue;
			p += sizeof("Clock Event Device: hpet")-1;
			if (!isdigit(*p))
				continue;
			hpet_chan = xatoi_positive(p);
			if (hpet_chan < G.percpu_hpet_start)
				G.percpu_hpet_start = hpet_chan;
			if (hpet_chan > G.percpu_hpet_end)
				G.percpu_hpet_end = hpet_chan;
		}
		fclose(fp);
	}
# endif
//TODO: optimize
	p = strstr(name, "hpet");
	if (!p)
		return 0;
	p += 4;
	if (!isdigit(*p))
		return 0;
# if BLOATY_HPET_IRQ_NUM_DETECTION
	hpet_chan = xatoi_positive(p);
	if (hpet_chan < G.percpu_hpet_start || hpet_chan > G.percpu_hpet_end)
		return 0;
# endif
	return 1;
}
Example #4
0
int mt_main(int argc UNUSED_PARAM, char **argv)
{
	const char *file = "/dev/tape";
	struct mtop op;
	struct mtpos position;
	int fd, mode, idx;

	if (!argv[1]) {
		bb_show_usage();
	}

	if (strcmp(argv[1], "-f") == 0) {
		if (!argv[2] || !argv[3])
			bb_show_usage();
		file = argv[2];
		argv += 2;
	}

	idx = index_in_strings(opcode_name, argv[1]);

	if (idx < 0)
		bb_error_msg_and_die("unrecognized opcode %s", argv[1]);

	op.mt_op = opcode_value[idx];
	if (argv[2])
		op.mt_count = xatoi_positive(argv[2]);
	else
		op.mt_count = 1;  /* One, not zero, right? */

	switch (opcode_value[idx]) {
		case MTWEOF:
		case MTERASE:
		case MTWSM:
		case MTSETDRVBUFFER:
			mode = O_WRONLY;
			break;

		default:
			mode = O_RDONLY;
			break;
	}

	fd = xopen(file, mode);

	switch (opcode_value[idx]) {
		case MTTELL:
			ioctl_or_perror_and_die(fd, MTIOCPOS, &position, "%s", file);
			printf("At block %d\n", (int) position.mt_blkno);
			break;

		default:
			ioctl_or_perror_and_die(fd, MTIOCTOP, &op, "%s", file);
			break;
	}

	return EXIT_SUCCESS;
}
Example #5
0
File: xatonum.c Project: rplnt/abrt
int xatoi(const char *numstr)
{
    unsigned r;

    if (*numstr != '-')
        return xatoi_positive(numstr);

    r = xatou(numstr + 1);
    if (r > (unsigned)INT_MAX + 1)
        error_msg_and_die("invalid number '%s'", numstr);
    return - (int)r;
}
Example #6
0
int pmap_main(int argc UNUSED_PARAM, char **argv)
{
	unsigned opts;
	int ret;

	opts = getopt32(argv, "xq");
	argv += optind;

	ret = 0;
	while (*argv) {
		pid_t pid = xatoi_positive(*argv++);
		/* GNU pmap returns 42 if any of the pids failed */
		if (procps_get_maps(pid, opts) != 0)
			ret = 42;
	}

	return ret;
}
Example #7
0
static void nameif_parse_selector(ethtable_t *ch, char *selector)
{
	struct ether_addr *lmac;
#if ENABLE_FEATURE_NAMEIF_EXTENDED
	int found_selector = 0;

	while (*selector) {
		char *next;
#endif
		selector = skip_whitespace(selector);
#if ENABLE_FEATURE_NAMEIF_EXTENDED
		ch->phy_address = -1;
		if (*selector == '\0')
			break;
		/* Search for the end .... */
		next = skip_non_whitespace(selector);
		if (*next)
			*next++ = '\0';
		/* Check for selectors, mac= is assumed */
		if (strncmp(selector, "bus=", 4) == 0) {
			ch->bus_info = xstrdup(selector + 4);
			found_selector++;
		} else if (strncmp(selector, "driver=", 7) == 0) {
			ch->driver = xstrdup(selector + 7);
			found_selector++;
		} else if (strncmp(selector, "phyaddr=", 8) == 0) {
			ch->phy_address = xatoi_positive(selector + 8);
			found_selector++;
		} else {
#endif
			lmac = xmalloc(ETH_ALEN);
			ch->mac = ether_aton_r(selector + (strncmp(selector, "mac=", 4) != 0 ? 0 : 4), lmac);
			if (ch->mac == NULL)
				bb_error_msg_and_die("can't parse %s", selector);
#if  ENABLE_FEATURE_NAMEIF_EXTENDED
			found_selector++;
		};
		selector = next;
	}
	if (found_selector == 0)
		bb_error_msg_and_die("no selectors found for %s", ch->ifname);
#endif
}
Example #8
0
static int ftpcmd(const char *s1, const char *s2, FILE *fp)
{
	int result;
	if (s1) {
		if (!s2)
			s2 = "";
		fprintf(fp, "%s%s\r\n", s1, s2);
		fflush(fp);
		log_io("> %s%s", s1, s2);
	}

	do {
		fgets_and_trim(fp);
	} while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' ');

	G.wget_buf[3] = '\0';
	result = xatoi_positive(G.wget_buf);
	G.wget_buf[3] = ' ';
	return result;
}
Example #9
0
static void parse_map_file(const char *filename)
{
	parser_t *parser;
	char *tokens[6];

	parser = config_open2(filename, fopen_for_read);

	if (parser) {
		while (config_read(parser, tokens, 6, 6, "# \t", PARSE_NORMAL)) {
			evt_tab = xrealloc_vector(evt_tab, 1, n_evt);
			evt_tab[n_evt].s_type = xstrdup(tokens[0]);
			evt_tab[n_evt].n_type = xstrtou(tokens[1], 16);
			evt_tab[n_evt].s_code = xstrdup(tokens[2]);
			evt_tab[n_evt].n_code = xatou16(tokens[3]);
			evt_tab[n_evt].value = xatoi_positive(tokens[4]);
			evt_tab[n_evt].desc = xstrdup(tokens[5]);
			n_evt++;
		}
		config_close(parser);
	} else {
		evt_tab = (void*)f_evt_tab;
		n_evt = ARRAY_SIZE(f_evt_tab);
	}
}
Example #10
0
int brctl_main(int argc UNUSED_PARAM, char **argv)
{
	static const char keywords[] ALIGN1 =
		"addbr\0" "delbr\0" "addif\0" "delif\0"
	IF_FEATURE_BRCTL_FANCY(
		"stp\0"
		"setageing\0" "setfd\0" "sethello\0" "setmaxage\0"
		"setpathcost\0" "setportprio\0" "setbridgeprio\0"
	)
	IF_FEATURE_BRCTL_SHOW("show\0");

	enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif
		IF_FEATURE_BRCTL_FANCY(,
			ARG_stp,
			ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage,
			ARG_setpathcost, ARG_setportprio, ARG_setbridgeprio
		)
		IF_FEATURE_BRCTL_SHOW(, ARG_show)
	};

	int fd;
	smallint key;
	struct ifreq ifr;
	char *br, *brif;

	argv++;
	while (*argv) {
#if ENABLE_FEATURE_BRCTL_FANCY
		int ifidx[MAX_PORTS];
		unsigned long args[4];
		ifr.ifr_data = (char *) &args;
#endif

		key = index_in_strings(keywords, *argv);
		if (key == -1) /* no match found in keywords array, bail out. */
			bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name);
		argv++;
		fd = xsocket(AF_INET, SOCK_STREAM, 0);

#if ENABLE_FEATURE_BRCTL_SHOW
		if (key == ARG_show) { /* show */
			char brname[IFNAMSIZ];
			int bridx[MAX_PORTS];
			int i, num;
			arm_ioctl(args, BRCTL_GET_BRIDGES,
						(unsigned long) bridx, MAX_PORTS);
			num = xioctl(fd, SIOCGIFBR, args);
			puts("bridge name\tbridge id\t\tSTP enabled\tinterfaces");
			for (i = 0; i < num; i++) {
				char ifname[IFNAMSIZ];
				int j, tabs;
				struct __bridge_info bi;
				unsigned char *x;

				if (!if_indextoname(bridx[i], brname))
					bb_perror_msg_and_die("can't get bridge name for index %d", i);
				strncpy_IFNAMSIZ(ifr.ifr_name, brname);

				arm_ioctl(args, BRCTL_GET_BRIDGE_INFO,
							(unsigned long) &bi, 0);
				xioctl(fd, SIOCDEVPRIVATE, &ifr);
				printf("%s\t\t", brname);

				/* print bridge id */
				x = (unsigned char *) &bi.bridge_id;
				for (j = 0; j < 8; j++) {
					printf("%02x", x[j]);
					if (j == 1)
						bb_putchar('.');
				}
				printf(bi.stp_enabled ? "\tyes" : "\tno");

				/* print interface list */
				arm_ioctl(args, BRCTL_GET_PORT_LIST,
							(unsigned long) ifidx, MAX_PORTS);
				xioctl(fd, SIOCDEVPRIVATE, &ifr);
				tabs = 0;
				for (j = 0; j < MAX_PORTS; j++) {
					if (!ifidx[j])
						continue;
					if (!if_indextoname(ifidx[j], ifname))
						bb_perror_msg_and_die("can't get interface name for index %d", j);
					if (tabs)
						printf("\t\t\t\t\t");
					else
						tabs = 1;
					printf("\t\t%s\n", ifname);
				}
				if (!tabs)  /* bridge has no interfaces */
					bb_putchar('\n');
			}
			goto done;
		}
#endif

		if (!*argv) /* all but 'show' need at least one argument */
			bb_show_usage();

		br = *argv++;

		if (key == ARG_addbr || key == ARG_delbr) { /* addbr or delbr */
			ioctl_or_perror_and_die(fd,
					key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR,
					br, "bridge %s", br);
			goto done;
		}

		if (!*argv) /* all but 'addbr/delbr' need at least two arguments */
			bb_show_usage();

		strncpy_IFNAMSIZ(ifr.ifr_name, br);
		if (key == ARG_addif || key == ARG_delif) { /* addif or delif */
			brif = *argv;
			ifr.ifr_ifindex = if_nametoindex(brif);
			if (!ifr.ifr_ifindex) {
				bb_perror_msg_and_die("iface %s", brif);
			}
			ioctl_or_perror_and_die(fd,
					key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF,
					&ifr, "bridge %s", br);
			goto done_next_argv;
		}
#if ENABLE_FEATURE_BRCTL_FANCY
		if (key == ARG_stp) { /* stp */
			static const char no_yes[] ALIGN1 =
				"0\0" "off\0" "n\0" "no\0"   /* 0 .. 3 */
				"1\0" "on\0"  "y\0" "yes\0"; /* 4 .. 7 */
			int onoff = index_in_strings(no_yes, *argv);
			if (onoff < 0)
				bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name);
			onoff = (unsigned)onoff / 4;
			arm_ioctl(args, BRCTL_SET_BRIDGE_STP_STATE, onoff, 0);
			goto fire;
		}
		if ((unsigned)(key - ARG_setageing) < 4) { /* time related ops */
			static const uint8_t ops[] ALIGN1 = {
				BRCTL_SET_AGEING_TIME,          /* ARG_setageing */
				BRCTL_SET_BRIDGE_FORWARD_DELAY, /* ARG_setfd     */
				BRCTL_SET_BRIDGE_HELLO_TIME,    /* ARG_sethello  */
				BRCTL_SET_BRIDGE_MAX_AGE        /* ARG_setmaxage */
			};
			arm_ioctl(args, ops[key - ARG_setageing], str_to_jiffies(*argv), 0);
			goto fire;
		}
		if (key == ARG_setpathcost
		 || key == ARG_setportprio
		 || key == ARG_setbridgeprio
		) {
			static const uint8_t ops[] ALIGN1 = {
				BRCTL_SET_PATH_COST,      /* ARG_setpathcost   */
				BRCTL_SET_PORT_PRIORITY,  /* ARG_setportprio   */
				BRCTL_SET_BRIDGE_PRIORITY /* ARG_setbridgeprio */
			};
			int port = -1;
			unsigned arg1, arg2;

			if (key != ARG_setbridgeprio) {
				/* get portnum */
				unsigned i;

				port = if_nametoindex(*argv++);
				if (!port)
					bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, "port");
				memset(ifidx, 0, sizeof ifidx);
				arm_ioctl(args, BRCTL_GET_PORT_LIST, (unsigned long)ifidx,
						MAX_PORTS);
				xioctl(fd, SIOCDEVPRIVATE, &ifr);
				for (i = 0; i < MAX_PORTS; i++) {
					if (ifidx[i] == port) {
						port = i;
						break;
					}
				}
			}
			arg1 = port;
			arg2 = xatoi_positive(*argv);
			if (key == ARG_setbridgeprio) {
				arg1 = arg2;
				arg2 = 0;
			}
			arm_ioctl(args, ops[key - ARG_setpathcost], arg1, arg2);
		}
 fire:
		/* Execute the previously set command */
		xioctl(fd, SIOCDEVPRIVATE, &ifr);
#endif
 done_next_argv:
		argv++;
 done:
		close(fd);
	}

	return EXIT_SUCCESS;
}
Example #11
0
int rfkill_main(int argc UNUSED_PARAM, char **argv)
{
	struct rfkill_event event;
	const char *rf_name;
	int rf_fd;
	int mode;
	int rf_type;
	int rf_idx;
	unsigned rf_opt = 0;

	argv++;
	/* Must have one or two params */
	if (!argv[0] || (argv[1] && argv[2]))
		bb_show_usage();

	mode = O_RDWR | O_NONBLOCK;
	rf_name = argv[1];
	if (strcmp(argv[0], "list") == 0) {
		rf_opt |= OPT_l;
		mode = O_RDONLY | O_NONBLOCK;
	} else if (strcmp(argv[0], "block") == 0 && rf_name) {
		rf_opt |= OPT_b;
	} else if (strcmp(argv[0], "unblock") == 0 && rf_name) {
		rf_opt |= OPT_u;
	} else
		bb_show_usage();

	rf_type = RFKILL_TYPE_ALL;
	rf_idx = -1;
	if (rf_name) {
		static const char rfkill_types[] ALIGN1 = "all\0wlan\0bluetooth\0uwb\0wimax\0wwan\0gps\0fm\0";
		if (strcmp(rf_name, "wifi") == 0)
			rf_name = "wlan";
		if (strcmp(rf_name, "ultrawideband") == 0)
			rf_name = "uwb";
		rf_type = index_in_strings(rfkill_types, rf_name);
		if (rf_type < 0) {
			rf_idx = xatoi_positive(rf_name);
		}
	}

	rf_fd = device_open("/dev/rfkill", mode);
	if (rf_fd < 0)
		bb_perror_msg_and_die("/dev/rfkill");

	if (rf_opt & OPT_l) {
		while (full_read(rf_fd, &event, sizeof(event)) == RFKILL_EVENT_SIZE_V1) {
			parser_t *parser;
			char *tokens[2];
			char rf_sysfs[sizeof("/sys/class/rfkill/rfkill%u/uevent") + sizeof(int)*3];
			char *name, *type;

			if (rf_type && rf_type != event.type && rf_idx < 0) {
				continue;
			}

			if (rf_idx >= 0 && event.idx != rf_idx) {
				continue;
			}

			name = NULL;
			type = NULL;
			sprintf(rf_sysfs, "/sys/class/rfkill/rfkill%u/uevent", event.idx);
			parser = config_open2(rf_sysfs, fopen_for_read);
			while (config_read(parser, tokens, 2, 2, "\n=", PARSE_NORMAL)) {
				if (strcmp(tokens[0], "RFKILL_NAME") == 0) {
					name = xstrdup(tokens[1]);
					continue;
				}
				if (strcmp(tokens[0], "RFKILL_TYPE") == 0) {
					type = xstrdup(tokens[1]);
					continue;
				}
			}
			config_close(parser);

			printf("%u: %s: %s\n", event.idx, name, type);
			printf("\tSoft blocked: %s\n", event.soft ? "yes" : "no");
			printf("\tHard blocked: %s\n", event.hard ? "yes" : "no");
			free(name);
			free(type);
		}
	} else {
		memset(&event, 0, sizeof(event));
		if (rf_type >= 0) {
			event.type = rf_type;
			event.op = RFKILL_OP_CHANGE_ALL;
		}

		if (rf_idx >= 0) {
			event.idx = rf_idx;
			event.op = RFKILL_OP_CHANGE;
		}

		/* Note: OPT_b == 1 */
		event.soft = (rf_opt & OPT_b);

		xwrite(rf_fd, &event, sizeof(event));
	}

	return EXIT_SUCCESS;
}
Example #12
0
int main(int argc, char **argv)
{
    abrt_init(argv);

    /* I18n */
    setlocale(LC_ALL, "");
#if ENABLE_NLS
    bindtextdomain(PACKAGE, LOCALEDIR);
    textdomain(PACKAGE);
#endif

    /* Can't keep these strings/structs static: _() doesn't support that */
    const char *program_usage_string = _(
        "\n& [-vbf] [-g GROUP-NAME]... [-c CONFFILE]... [-F FMTFILE] [-A FMTFILE2] -d DIR"
        "\nor:"
        "\n& [-v] [-c CONFFILE]... [-d DIR] -t[ID] FILE..."
        "\nor:"
        "\n& [-v] [-c CONFFILE]... [-d DIR] -t[ID] -w"
        "\nor:"
        "\n& [-v] [-c CONFFILE]... -h DUPHASH"
        "\n"
        "\nReports problem to Bugzilla."
        "\n"
        "\nThe tool reads DIR. Then it logs in to Bugzilla and tries to find a bug"
        "\nwith the same abrt_hash:HEXSTRING in 'Whiteboard'."
        "\n"
        "\nIf such bug is not found, then a new bug is created. Elements of DIR"
        "\nare stored in the bug as part of bug description or as attachments,"
        "\ndepending on their type and size."
        "\n"
        "\nOtherwise, if such bug is found and it is marked as CLOSED DUPLICATE,"
        "\nthe tool follows the chain of duplicates until it finds a non-DUPLICATE bug."
        "\nThe tool adds a new comment to found bug."
        "\n"
        "\nThe URL to new or modified bug is printed to stdout and recorded in"
        "\n'reported_to' element."
        "\n"
        "\nOption -t uploads FILEs to the already created bug on Bugzilla site."
        "\nThe bug ID is retrieved from directory specified by -d DIR."
        "\nIf problem data in DIR was never reported to Bugzilla, upload will fail."
        "\n"
        "\nOption -tID uploads FILEs to the bug with specified ID on Bugzilla site."
        "\n-d DIR is ignored."
        "\n"
        "\nOption -w adds bugzilla user to bug's CC list."
        "\n"
        "\nIf not specified, CONFFILE defaults to "CONF_DIR"/plugins/bugzilla.conf"
        "\nIts lines should have 'PARAM = VALUE' format."
        "\nRecognized string parameters: BugzillaURL, Login, Password, OSRelease."
        "\nRecognized boolean parameter (VALUE should be 1/0, yes/no): SSLVerify."
        "\nParameters can be overridden via $Bugzilla_PARAM environment variables."
        "\n"
        "\nFMTFILE and FMTFILE2 default to "CONF_DIR"/plugins/bugzilla_format.conf"
    );
    enum {
        OPT_v = 1 << 0,
        OPT_d = 1 << 1,
        OPT_c = 1 << 2,
        OPT_F = 1 << 3,
        OPT_A = 1 << 4,
        OPT_t = 1 << 5,
        OPT_b = 1 << 6,
        OPT_f = 1 << 7,
        OPT_w = 1 << 8,
        OPT_h = 1 << 9,
        OPT_g = 1 << 10,
        OPT_D = 1 << 11,
    };
    const char *dump_dir_name = ".";
    GList *conf_file = NULL;
    const char *fmt_file = CONF_DIR"/plugins/bugzilla_format.conf";
    const char *fmt_file2 = fmt_file;
    char *abrt_hash = NULL;
    char *ticket_no = NULL;
    char *debug_str = NULL;
    GList *group = NULL;
    /* Keep enum above and order of options below in sync! */
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT_STRING(   'd', NULL, &dump_dir_name , "DIR"    , _("Problem directory")),
        OPT_LIST(     'c', NULL, &conf_file     , "FILE"   , _("Configuration file (may be given many times)")),
        OPT_STRING(   'F', NULL, &fmt_file      , "FILE"   , _("Formatting file for initial comment")),
        OPT_STRING(   'A', NULL, &fmt_file2     , "FILE"   , _("Formatting file for duplicates")),
        OPT_OPTSTRING('t', "ticket", &ticket_no , "ID"     , _("Attach FILEs [to bug with this ID]")),
        OPT_BOOL(     'b', NULL, NULL,                       _("When creating bug, attach binary files too")),
        OPT_BOOL(     'f', NULL, NULL,                       _("Force reporting even if this problem is already reported")),
        OPT_BOOL(     'w', NULL, NULL,                       _("Add bugzilla user to CC list [of bug with this ID]")),
        OPT_STRING(   'h', "duphash", &abrt_hash, "DUPHASH", _("Print BUG_ID which has given DUPHASH")),
        OPT_LIST(     'g', "group", &group      , "GROUP"  , _("Restrict access to this group only")),
        OPT_OPTSTRING('D', "debug", &debug_str  , "STR"    , _("Debug")),
        OPT_END()
    };
    unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
    argv += optind;

    export_abrt_envvars(0);

    map_string_t *settings = new_map_string();
    struct bugzilla_struct rhbz = { 0 };
    {
        if (!conf_file)
            conf_file = g_list_append(conf_file, (char*) CONF_DIR"/plugins/bugzilla.conf");
        while (conf_file)
        {
            char *fn = (char *)conf_file->data;
            VERB1 log("Loading settings from '%s'", fn);
            load_conf_file(fn, settings, /*skip key w/o values:*/ false);
            VERB3 log("Loaded '%s'", fn);
            conf_file = g_list_delete_link(conf_file, conf_file);
        }
        set_settings(&rhbz, settings);
        /* WRONG! set_settings() does not copy the strings, it merely sets up pointers
         * to settings[] dictionary:
         */
        /*free_map_string(settings);*/
    }

    VERB1 log("Initializing XML-RPC library");
    xmlrpc_env env;
    xmlrpc_env_init(&env);
    xmlrpc_client_setup_global_const(&env);
    if (env.fault_occurred)
        abrt_xmlrpc_die(&env);
    xmlrpc_env_clean(&env);

    struct abrt_xmlrpc *client;
    client = abrt_xmlrpc_new_client(rhbz.b_bugzilla_xmlrpc, rhbz.b_ssl_verify);
    unsigned rhbz_ver = rhbz_version(client);

    if (abrt_hash)
    {
        log(_("Looking for similar problems in bugzilla"));
        char *hash;
        if (prefixcmp(abrt_hash, "abrt_hash:"))
            hash = xasprintf("abrt_hash:%s", abrt_hash);
        else
            hash = xstrdup(abrt_hash);

        /* it's Fedora specific */
        xmlrpc_value *all_bugs = rhbz_search_duphash(client,
                                /*product:*/ "Fedora",
                                /*version:*/ NULL,
                                /*component:*/ NULL,
                                hash);
        free(hash);
        unsigned all_bugs_size = rhbz_array_size(all_bugs);
        if (all_bugs_size > 0)
        {
            int bug_id = rhbz_get_bug_id_from_array0(all_bugs, rhbz_ver);
            printf("%i\n", bug_id);
        }

        return EXIT_SUCCESS;
    }

    if (rhbz.b_login[0] == '\0')
    {
        free(rhbz.b_login);
        rhbz.b_login = ask_bz_login(_("Login is not provided by configuration. Please enter your BZ login:"******"Password is not provided by configuration. Please enter the password for '%s':"), rhbz.b_login);
        rhbz.b_password = ask_bz_password(question);
        free(question);
    }

    if (opts & OPT_t)
    {
        if ((!argv[0] && !(opts & OPT_w)) || (argv[0] && (opts & OPT_w)))
            show_usage_and_die(program_usage_string, program_options);

        if (!ticket_no)
        {
            struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
            if (!dd)
                xfunc_die();
            report_result_t *reported_to = find_in_reported_to(dd, "Bugzilla:");
            dd_close(dd);

            if (!reported_to || !reported_to->url)
                error_msg_and_die(_("Can't get Bugzilla ID because this problem has not yet been reported to Bugzilla."));

            char *url = reported_to->url;
            reported_to->url = NULL;
            free_report_result(reported_to);

            if (prefixcmp(url, rhbz.b_bugzilla_url) != 0)
                error_msg_and_die(_("This problem has been reported to Bugzilla '%s' which differs from the configured Bugzilla '%s'."), url, rhbz.b_bugzilla_url);

            ticket_no = strrchr(url, '=');
            if (!ticket_no)
                error_msg_and_die(_("Malformed url to Bugzilla '%s'."), url);

            /* won't ever call free on it - it simplifies the code a lot */
            ticket_no = xstrdup(ticket_no + 1);
            log(_("Using Bugzilla ID '%s'"), ticket_no);
        }

        login(client, &rhbz);

        if (opts & OPT_w)
            rhbz_mail_to_cc(client, xatoi_positive(ticket_no), rhbz.b_login, /* require mail notify */ 0);
        else
        {   /* Attach files to existing BZ */
            while (*argv)
            {
                const char *filename = *argv++;
                VERB1 log("Attaching file '%s' to bug %s", filename, ticket_no);

                int fd = open(filename, O_RDONLY);
                if (fd < 0)
                {
                    perror_msg("Can't open '%s'", filename);
                    continue;
                }

                struct stat st;
                if (fstat(fd, &st) != 0 || !S_ISREG(st.st_mode))
                {
                    error_msg("'%s': not a regular file", filename);
                    close(fd);
                    continue;
                }

                rhbz_attach_fd(client, ticket_no, filename, fd, /*flags*/ 0);
                close(fd);
            }
        }

        log(_("Logging out"));
        rhbz_logout(client);

#if 0  /* enable if you search for leaks (valgrind etc) */
        abrt_xmlrpc_free_client(client);
#endif
        return 0;
    }

    /* Create new bug in Bugzilla */

    if (!(opts & OPT_f))
    {
        struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
        if (!dd)
            xfunc_die();
        report_result_t *reported_to = find_in_reported_to(dd, "Bugzilla:");
        dd_close(dd);

        if (reported_to && reported_to->url)
        {
            char *msg = xasprintf("This problem was already reported to Bugzilla (see '%s')."
                            " Do you still want to create a new bug?",
                            reported_to->url);
            int yes = ask_yes_no(msg);
            free(msg);
            if (!yes)
                return 0;
        }
        free_report_result(reported_to);
    }

    problem_data_t *problem_data = create_problem_data_for_reporting(dump_dir_name);
    if (!problem_data)
        xfunc_die(); /* create_problem_data_for_reporting already emitted error msg */

    const char *component = problem_data_get_content_or_die(problem_data, FILENAME_COMPONENT);
    const char *duphash   = problem_data_get_content_or_NULL(problem_data, FILENAME_DUPHASH);
//COMPAT, remove after 2.1 release
    if (!duphash) duphash = problem_data_get_content_or_die(problem_data, "global_uuid");

    if (!rhbz.b_product || !*rhbz.b_product) /* if not overridden or empty... */
    {
        free(rhbz.b_product);
        free(rhbz.b_product_version);
        map_string_t *osinfo = new_map_string();
        problem_data_get_osinfo(problem_data, osinfo);
        parse_osinfo_for_bz(osinfo, &rhbz.b_product, &rhbz.b_product_version);
        free_map_string(osinfo);

        if (!rhbz.b_product)
            error_msg_and_die(_("Can't determine Bugzilla Product from problem data."));
    }

    if (opts & OPT_D)
    {
        GList *comment_fmt_spec = load_bzrep_conf_file(fmt_file);
        struct strbuf *bzcomment_buf = strbuf_new();
        generate_bz_comment(bzcomment_buf, problem_data, comment_fmt_spec);
        char *bzcomment = strbuf_free_nobuf(bzcomment_buf);
        char *summary = create_summary_string(problem_data, comment_fmt_spec);
        printf("summary: %s\n"
                "\n"
                "%s"
                , summary, bzcomment
        );
        free(bzcomment);
        free(summary);
        exit(0);
    }

    login(client, &rhbz);


    int bug_id = 0;

    /* If REMOTE_RESULT contains "DUPLICATE 12345", we consider it a dup of 12345
     * and won't search on bz server.
     */
    char *remote_result;
    remote_result = problem_data_get_content_or_NULL(problem_data, FILENAME_REMOTE_RESULT);
    if (remote_result)
    {
        char *cmd = strtok(remote_result, " \n");
        char *id = strtok(NULL, " \n");

        if (!prefixcmp(cmd, "DUPLICATE"))
        {
            errno = 0;
            char *e;
            bug_id = strtoul(id, &e, 10);
            if (errno || id == e || *e != '\0' || bug_id > INT_MAX)
            {
                /* error / no digits / illegal trailing chars / too big a number */
                bug_id = 0;
            }
        }
    }

    struct bug_info *bz = NULL;
    if (!bug_id)
    {
        log(_("Checking for duplicates"));

        int existing_id = -1;
        int crossver_id = -1;
        {
            /* Figure out whether we want to match component
             * when doing dup search.
             */
            const char *component_substitute = is_in_comma_separated_list(component, rhbz.b_DontMatchComponents) ? NULL : component;

            /* We don't do dup detection across versions (see below why),
             * but we do add a note if cross-version potential dup exists.
             * For that, we search for cross version dups first:
             */
            xmlrpc_value *crossver_bugs = rhbz_search_duphash(client, rhbz.b_product, /*version:*/ NULL,
                            component_substitute, duphash);
            unsigned crossver_bugs_count = rhbz_array_size(crossver_bugs);
            VERB3 log("Bugzilla has %i reports with duphash '%s' including cross-version ones",
                    crossver_bugs_count, duphash);
            if (crossver_bugs_count > 0)
                crossver_id = rhbz_get_bug_id_from_array0(crossver_bugs, rhbz_ver);
            xmlrpc_DECREF(crossver_bugs);

            if (crossver_bugs_count > 0)
            {
                /* In dup detection we require match in product *and version*.
                 * Otherwise we sometimes have bugs in e.g. Fedora 17
                 * considered to be dups of Fedora 16 bugs.
                 * Imagine that F16 is "end-of-lifed" - allowing cross-version
                 * match will make all newly detected crashes DUPed
                 * to a bug in a dead release.
                 */
                xmlrpc_value *dup_bugs = rhbz_search_duphash(client, rhbz.b_product,
                                rhbz.b_product_version, component_substitute, duphash);
                unsigned dup_bugs_count = rhbz_array_size(dup_bugs);
                VERB3 log("Bugzilla has %i reports with duphash '%s'",
                        dup_bugs_count, duphash);
                if (dup_bugs_count > 0)
                    existing_id = rhbz_get_bug_id_from_array0(dup_bugs, rhbz_ver);
                xmlrpc_DECREF(dup_bugs);
            }
        }

        if (existing_id < 0)
        {
            /* Create new bug */
            log(_("Creating a new bug"));

            GList *comment_fmt_spec = load_bzrep_conf_file(fmt_file);

            struct strbuf *bzcomment_buf = strbuf_new();
            generate_bz_comment(bzcomment_buf, problem_data, comment_fmt_spec);
            if (crossver_id >= 0)
                strbuf_append_strf(bzcomment_buf, "\nPotential duplicate: bug %u\n", crossver_id);
            char *bzcomment = strbuf_free_nobuf(bzcomment_buf);
            char *summary = create_summary_string(problem_data, comment_fmt_spec);
            int new_id = rhbz_new_bug(client, problem_data, rhbz.b_product, rhbz.b_product_version,
                    summary, bzcomment,
                    group
            );
            free(bzcomment);
            free(summary);

            if (new_id == -1)
            {
                error_msg_and_die(_("Failed to create a new bug."));
            }

            log(_("Adding attachments to bug %i"), new_id);
            char new_id_str[sizeof(int)*3 + 2];
            sprintf(new_id_str, "%i", new_id);

            attach_files(client, new_id_str, problem_data, comment_fmt_spec);

//TODO: free_comment_fmt_spec(comment_fmt_spec);

            bz = new_bug_info();
            bz->bi_status = xstrdup("NEW");
            bz->bi_id = new_id;
            goto log_out;
        }

        bug_id = existing_id;
    }

    bz = rhbz_bug_info(client, bug_id);

    log(_("Bug is already reported: %i"), bz->bi_id);

    /* Follow duplicates */
    if ((strcmp(bz->bi_status, "CLOSED") == 0)
     && (strcmp(bz->bi_resolution, "DUPLICATE") == 0)
    ) {
        struct bug_info *origin;
        origin = rhbz_find_origin_bug_closed_duplicate(client, bz);
        if (origin)
        {
            free_bug_info(bz);
            bz = origin;
        }
    }

    if (strcmp(bz->bi_status, "CLOSED") != 0)
    {
        /* Add user's login to CC if not there already */
        if (strcmp(bz->bi_reporter, rhbz.b_login) != 0
         && !g_list_find_custom(bz->bi_cc_list, rhbz.b_login, (GCompareFunc)g_strcmp0)
        ) {
            log(_("Adding %s to CC list"), rhbz.b_login);
            rhbz_mail_to_cc(client, bz->bi_id, rhbz.b_login, RHBZ_NOMAIL_NOTIFY);
        }

        /* Add comment and bt */
        const char *comment = problem_data_get_content_or_NULL(problem_data, FILENAME_COMMENT);
        if (comment && comment[0])
        {
            GList *comment_fmt_spec = load_bzrep_conf_file(fmt_file2);
            struct strbuf *bzcomment_buf = strbuf_new();
            generate_bz_comment(bzcomment_buf, problem_data, comment_fmt_spec);
            char *bzcomment = strbuf_free_nobuf(bzcomment_buf);
//TODO: free_comment_fmt_spec(comment_fmt_spec);

            int dup_comment = is_comment_dup(bz->bi_comments, bzcomment);
            if (!dup_comment)
            {
                log(_("Adding new comment to bug %d"), bz->bi_id);
                rhbz_add_comment(client, bz->bi_id, bzcomment, 0);
                free(bzcomment);

                const char *bt = problem_data_get_content_or_NULL(problem_data, FILENAME_BACKTRACE);
                unsigned rating = 0;
                const char *rating_str = problem_data_get_content_or_NULL(problem_data, FILENAME_RATING);
                /* python doesn't have rating file */
                if (rating_str)
                    rating = xatou(rating_str);
                if (bt && rating > bz->bi_best_bt_rating)
                {
                    char bug_id_str[sizeof(int)*3 + 2];
                    sprintf(bug_id_str, "%i", bz->bi_id);
                    log(_("Attaching better backtrace"));
                    rhbz_attach_blob(client, bug_id_str, FILENAME_BACKTRACE, bt, strlen(bt),
                                     RHBZ_NOMAIL_NOTIFY);
                }
            }
            else
            {
                free(bzcomment);
                log(_("Found the same comment in the bug history, not adding a new one"));
            }
        }
    }

 log_out:
    log(_("Logging out"));
    rhbz_logout(client);

    log(_("Status: %s%s%s %s/show_bug.cgi?id=%u"),
                bz->bi_status,
                bz->bi_resolution ? " " : "",
                bz->bi_resolution ? bz->bi_resolution : "",
                rhbz.b_bugzilla_url,
                bz->bi_id);

    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
    if (dd)
    {
        char *msg = xasprintf("Bugzilla: URL=%s/show_bug.cgi?id=%u", rhbz.b_bugzilla_url, bz->bi_id);
        add_reported_to(dd, msg);
        free(msg);
        dd_close(dd);
    }

#if 0  /* enable if you search for leaks (valgrind etc) */
    free(rhbz.b_product);
    free(rhbz.b_product_version);
    problem_data_free(problem_data);
    free_bug_info(bz);
    abrt_xmlrpc_free_client(client);
#endif
    return 0;
}
Example #13
0
int hexdump_main(int argc, char **argv)
{
	dumper_t *dumper = alloc_dumper();
	const char *p;
	int ch;
#if ENABLE_FEATURE_HEXDUMP_REVERSE
	FILE *fp;
	smallint rdump = 0;
#endif

	if (ENABLE_HD && !applet_name[2]) { /* we are "hd" */
		ch = 'C';
		goto hd_applet;
	}

	/* We cannot use getopt32: in hexdump options are cumulative.
	 * E.g. "hexdump -C -C file" should dump each line twice */
	while ((ch = getopt(argc, argv, hexdump_opts)) > 0) {
		p = strchr(hexdump_opts, ch);
		if (!p)
			bb_show_usage();
		if ((p - hexdump_opts) < 5) {
			bb_dump_add(dumper, add_first);
			bb_dump_add(dumper, add_strings[(int)(p - hexdump_opts)]);
		}
		/* Save a little bit of space below by omitting the 'else's. */
		if (ch == 'C') {
 hd_applet:
			bb_dump_add(dumper, "\"%08.8_Ax\n\"");
			bb_dump_add(dumper, "\"%08.8_ax  \" 8/1 \"%02x \" \"  \" 8/1 \"%02x \" ");
			bb_dump_add(dumper, "\"  |\" 16/1 \"%_p\" \"|\\n\"");
		}
		if (ch == 'e') {
			bb_dump_add(dumper, optarg);
		} /* else */
		if (ch == 'f') {
			bb_dump_addfile(dumper, optarg);
		} /* else */
		if (ch == 'n') {
			dumper->dump_length = xatoi_positive(optarg);
		} /* else */
		if (ch == 's') { /* compat: -s accepts hex numbers too */
			dumper->dump_skip = xstrtoull_range_sfx(
				optarg,
				/*base:*/ 0,
				/*lo:*/ 0, /*hi:*/ OFF_T_MAX,
				bkm_suffixes
			);
		} /* else */
		if (ch == 'v') {
			dumper->dump_vflag = ALL;
		}
#if ENABLE_FEATURE_HEXDUMP_REVERSE
		if (ch == 'R') {
			rdump = 1;
		}
#endif
	}

	if (!dumper->fshead) {
		bb_dump_add(dumper, add_first);
		bb_dump_add(dumper, "\"%07.7_ax \" 8/2 \"%04x \" \"\\n\"");
	}

	argv += optind;

#if !ENABLE_FEATURE_HEXDUMP_REVERSE
	return bb_dump_dump(dumper, argv);
#else
	if (!rdump) {
		return bb_dump_dump(dumper, argv);
	}

	/* -R: reverse of 'hexdump -Cv' */
	fp = stdin;
	if (!*argv) {
		argv--;
		goto jump_in;
	}

	do {
		char *buf;
		fp = xfopen_for_read(*argv);
 jump_in:
		while ((buf = xmalloc_fgetline(fp)) != NULL) {
			p = buf;
			while (1) {
				/* skip address or previous byte */
				while (isxdigit(*p)) p++;
				while (*p == ' ') p++;
				/* '|' char will break the line */
				if (!isxdigit(*p) || sscanf(p, "%x ", &ch) != 1)
					break;
				putchar(ch);
			}
			free(buf);
		}
		fclose(fp);
	} while (*++argv);

	fflush_stdout_and_exit(EXIT_SUCCESS);
#endif
}
Example #14
0
static char *run_unstrip_n(const char *dump_dir_name, unsigned timeout_sec)
{
    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
    if (!dd)
        return NULL;

    char *uid_str = dd_load_text_ext(dd, FILENAME_UID, DD_FAIL_QUIETLY_ENOENT | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE);
    dd_close(dd);
    uid_t uid = -1L;
    if (uid_str)
    {
        uid = xatoi_positive(uid_str);
        free(uid_str);
        if (uid == geteuid())
        {
            uid = -1L; /* no need to setuid/gid if we are already under right uid */
        }
    }

    int flags = EXECFLG_INPUT_NUL | EXECFLG_OUTPUT | EXECFLG_SETSID | EXECFLG_QUIET;
    if (uid != (uid_t)-1L)
        flags |= EXECFLG_SETGUID;
    VERB1 flags &= ~EXECFLG_QUIET;
    int pipeout[2];
    char* args[4];
    args[0] = (char*)"eu-unstrip";
    args[1] = xasprintf("--core=%s/"FILENAME_COREDUMP, dump_dir_name);
    args[2] = (char*)"-n";
    args[3] = NULL;
    pid_t child = fork_execv_on_steroids(flags, args, pipeout, /*env_vec:*/ NULL, /*dir:*/ NULL, uid);
    free(args[1]);

    /* Bugs in unstrip or corrupted coredumps can cause it to enter infinite loop.
     * Therefore we have a (largish) timeout, after which we kill the child.
     */
    int t = time(NULL); /* int is enough, no need to use time_t */
    int endtime = t + timeout_sec;
    struct strbuf *buf_out = strbuf_new();
    while (1)
    {
        int timeout = endtime - t;
        if (timeout < 0)
        {
            kill(child, SIGKILL);
            strbuf_append_strf(buf_out, "\nTimeout exceeded: %u seconds, killing %s\n", timeout_sec, args[0]);
            break;
        }

        /* We don't check poll result - checking read result is enough */
        struct pollfd pfd;
        pfd.fd = pipeout[0];
        pfd.events = POLLIN;
        poll(&pfd, 1, timeout * 1000);

        char buff[1024];
        int r = read(pipeout[0], buff, sizeof(buff) - 1);
        if (r <= 0)
            break;
        buff[r] = '\0';
        strbuf_append_str(buf_out, buff);
        t = time(NULL);
    }
    close(pipeout[0]);

    /* Prevent having zombie child process */
    int status;
    waitpid(child, &status, 0);

    if (status != 0)
    {
        /* unstrip didnt exit with exit code 0 */
        strbuf_free(buf_out);
        return NULL;
    }

    return strbuf_free_nobuf(buf_out);
}
Example #15
0
int cut_main(int argc UNUSED_PARAM, char **argv)
{
	/* growable array holding a series of lists */
	struct cut_list *cut_lists = NULL;
	unsigned nlists = 0;	/* number of elements in above list */
	char delim = '\t';	/* delimiter, default is tab */
	char *sopt, *ltok;
	unsigned opt;

	opt_complementary = "b--bcf:c--bcf:f--bcf";
	opt = getopt32(argv, optstring, &sopt, &sopt, &sopt, &ltok);
//	argc -= optind;
	argv += optind;
	if (!(opt & (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 (opt & CUT_OPT_DELIM_FLGS) {
		if (ltok[0] && ltok[1]) { /* more than 1 char? */
			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 (!(opt & CUT_OPT_FIELDS_FLGS)) {
		static const char _op_on_field[] ALIGN1 = " only when operating on fields";

		if (opt & 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 (!ltok[0])
				continue;

			/* get the start pos */
			ntok = strsep(&ltok, "-");
			if (!ntok[0]) {
				s = BOL;
			} else {
				s = xatoi_positive(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 */
			if (ltok == NULL) {
				e = NON_RANGE;
			} else if (!ltok[0]) {
				e = EOL;
			} else {
				e = xatoi_positive(ltok);
				/* 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;
			}

			/* add the new list */
			cut_lists = xrealloc_vector(cut_lists, 4, nlists);
			/* NB: startpos is always >= 0,
			 * while endpos may be = NON_RANGE (-1) */
			cut_lists[nlists].startpos = s;
			cut_lists[nlists].endpos = e;
			nlists++;
		}

		/* 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(cut_lists[0]), cmpfunc);
	}

	{
		int retval = EXIT_SUCCESS;

		if (!*argv)
			*--argv = (char *)"-";

		do {
			FILE *file = fopen_or_warn_stdin(*argv);
			if (!file) {
				retval = EXIT_FAILURE;
				continue;
			}
			cut_file(file, delim, cut_lists, nlists);
			fclose_if_not_stdin(file);
		} while (*++argv);

		if (ENABLE_FEATURE_CLEAN_UP)
			free(cut_lists);
		fflush_stdout_and_exit(retval);
	}
}
Example #16
0
int flock_main(int argc UNUSED_PARAM, char **argv)
{
	int mode, opt, fd;
	enum {
		OPT_s = (1 << 0),
		OPT_x = (1 << 1),
		OPT_n = (1 << 2),
		OPT_u = (1 << 3),
		OPT_c = (1 << 4),
	};

#if ENABLE_LONG_OPTS
	static const char getopt_longopts[] ALIGN1 =
		"shared\0"      No_argument       "s"
		"exclusive\0"   No_argument       "x"
		"unlock\0"      No_argument       "u"
		"nonblock\0"    No_argument       "n"
		;
	applet_long_options = getopt_longopts;
#endif
	opt_complementary = "-1";

	opt = getopt32(argv, "+sxnu");
	argv += optind;

	if (argv[1]) {
		fd = open(argv[0], O_RDONLY|O_NOCTTY|O_CREAT, 0666);
		if (fd < 0 && errno == EISDIR)
			fd = open(argv[0], O_RDONLY|O_NOCTTY);
		if (fd < 0)
			bb_perror_msg_and_die("can't open '%s'", argv[0]);
		//TODO? close_on_exec_on(fd);
	} else {
		fd = xatoi_positive(argv[0]);
	}
	argv++;

	/* If it is "flock FILE -c PROG", then -c isn't caught by getopt32:
	 * we use "+" in order to support "flock -opt FILE PROG -with-opts",
	 * we need to remove -c by hand.
	 */
	if (argv[0]
	 && argv[0][0] == '-'
	 && (  (argv[0][1] == 'c' && !argv[0][2])
	    || (ENABLE_LONG_OPTS && strcmp(argv[0] + 1, "-command") == 0)
	    )
	) {
		argv++;
		if (argv[1])
			bb_error_msg_and_die("-c takes only one argument");
		opt |= OPT_c;
	}

	if (OPT_s == LOCK_SH && OPT_x == LOCK_EX && OPT_n == LOCK_NB && OPT_u == LOCK_UN) {
		/* With suitably matched constants, mode setting is much simpler */
		mode = opt & (LOCK_SH + LOCK_EX + LOCK_NB + LOCK_UN);
		if (!(mode & ~LOCK_NB))
			mode |= LOCK_EX;
	} else {
		if (opt & OPT_u)
			mode = LOCK_UN;
		else if (opt & OPT_s)
			mode = LOCK_SH;
		else
			mode = LOCK_EX;
		if (opt & OPT_n)
			mode |= LOCK_NB;
	}

	if (flock(fd, mode) != 0) {
		if (errno == EWOULDBLOCK)
			return EXIT_FAILURE;
		bb_perror_nomsg_and_die();
	}

	if (argv[0]) {
		int rc;
		if (opt & OPT_c) {
			/* -c 'PROG ARGS' means "run sh -c 'PROG ARGS'" */
			argv -= 2;
			argv[0] = (char*)get_shell_name();
			argv[1] = (char*)"-c";
			/* argv[2] = "PROG ARGS"; */
			/* argv[3] = NULL; */
		}
		rc = spawn_and_wait(argv);
		if (rc < 0)
			bb_simple_perror_msg(argv[0]);
		return rc;
	}

	return EXIT_SUCCESS;
}