Пример #1
0
const char* FAST_FUNC strip_unsafe_prefix(const char *str)
{
	const char *cp = str;
	while (1) {
		char *cp2;
		if (*cp == '/') {
			cp++;
			continue;
		}
		if (is_prefixed_with(cp, "/../"+1)) {
			cp += 3;
			continue;
		}
		cp2 = strstr(cp, "/../");
		if (!cp2)
			break;
		cp = cp2 + 4;
	}
	if (cp != str) {
		static smallint warned = 0;
		if (!warned) {
			warned = 1;
			bb_error_msg("removing leading '%.*s' from member names",
				(int)(cp - str), str);
		}
	}
	return cp;
}
Пример #2
0
static const char *if_redefined(const char *var, const char *key, const char *line)
{
	if (!is_prefixed_with(line, key))
		return var;
	line += strlen(key);
	if (!isspace(line[0]))
		return var;
	return xstrdup(skip_whitespace(line));
}
Пример #3
0
int FAST_FUNC index_in_substr_array(const char *const string_array[], const char *key)
{
	int i;
	if (key[0]) {
		for (i = 0; string_array[i] != 0; i++) {
			if (is_prefixed_with(string_array[i], key)) {
				return i;
			}
		}
	}
	return -1;
}
Пример #4
0
static NOINLINE bool may_wakeup(const char *rtcname)
{
	ssize_t ret;
	char buf[128];

	/* strip "/dev/" from the rtcname here */
	rtcname = skip_dev_pfx(rtcname);

	snprintf(buf, sizeof(buf), SYS_RTC_PATH, rtcname);
	ret = open_read_close(buf, buf, sizeof(buf));
	if (ret < 0)
		return false;

	/* wakeup events could be disabled or not supported */
	return is_prefixed_with(buf, "enabled\n") != NULL;
}
Пример #5
0
static void
sgi_write_table(void)
{
	sgilabel->csum = 0;
	sgilabel->csum = SGI_SSWAP32(two_s_complement_32bit_sum(
			(unsigned int*)sgilabel, sizeof(*sgilabel)));
	assert(two_s_complement_32bit_sum(
		(unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);

	write_sector(0, sgilabel);
	if (is_prefixed_with((char*)sgilabel->directory[0].vol_file_name, "sgilabel")) {
		/*
		 * keep this habit of first writing the "sgilabel".
		 * I never tested whether it works without (AN 981002).
		 */
		sgiinfo *info = fill_sgiinfo();
		int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
		write_sector(infostartblock, info);
		free(info);
	}
}
Пример #6
0
static char* find_keyword(char *ptr, size_t len, const char *word)
{
	if (!ptr) /* happens if xmalloc_open_zipped_read_close cannot read it */
		return NULL;

	len -= strlen(word) - 1;
	while ((ssize_t)len > 0) {
		char *old = ptr;
		char *after_word;

		/* search for the first char in word */
		ptr = memchr(ptr, word[0], len);
		if (ptr == NULL) /* no occurance left, done */
			break;
		after_word = is_prefixed_with(ptr, word);
		if (after_word)
			return after_word; /* found, return ptr past it */
		++ptr;
		len -= (ptr - old);
	}
	return NULL;
}
Пример #7
0
int setarch_main(int argc UNUSED_PARAM, char **argv)
{
	unsigned opts;
	unsigned long pers;

	/* Figure out what personality we are supposed to switch to ...
	 * we can be invoked as either:
	 * argv[0],argv[1] == "setarch","personality"
	 * argv[0]         == "personality"
	 */
	if (ENABLE_SETARCH && applet_name[0] == 's'
	 && argv[1] && is_prefixed_with(argv[1], "linux")
	) {
		applet_name = argv[1];
		argv++;
	}
	if (applet_name[5] == '6') /* linux64 */
		pers = PER_LINUX;
	else if (applet_name[5] == '3') /* linux32 */
		pers = PER_LINUX32;
	else
		bb_show_usage();

	opts = getopt32(argv, "+R"); /* '+': stop at first non-option */
	if (opts)
		pers |= ADDR_NO_RANDOMIZE;

	/* Try to set personality */
	if (personality(pers) < 0)
		bb_perror_msg_and_die("personality(0x%lx)", pers);

	argv += optind;
	if (!argv[0])
		(--argv)[0] = (char*)"/bin/sh";

	/* Try to execute the program */
	BB_EXECVP_or_die(argv);
}
Пример #8
0
static void add_probe(const char *name)
{
	struct module_entry *m;

	m = get_or_add_modentry(name);
	if (!(option_mask32 & (OPT_REMOVE | OPT_SHOW_DEPS))
	 && (m->flags & (MODULE_FLAG_LOADED | MODULE_FLAG_BUILTIN))
	) {
		DBG("skipping %s, it is already loaded", name);
		return;
	}

	DBG("queuing %s", name);
	m->probed_name = name;
	m->flags |= MODULE_FLAG_NEED_DEPS;
	llist_add_to_end(&G.probes, m);
	G.num_unresolved_deps++;
	if (ENABLE_FEATURE_MODUTILS_SYMBOLS
	 && is_prefixed_with(m->modname, "symbol:")
	) {
		G.need_symbols = 1;
	}
}
Пример #9
0
char* FAST_FUNC skip_dev_pfx(const char *tty_name)
{
	if (is_prefixed_with(tty_name, "/dev/"))
		tty_name += 5;
	return (char*)tty_name;
}
Пример #10
0
static void load_crontab(const char *fileName)
{
	struct parser_t *parser;
	struct stat sbuf;
	int maxLines;
	char *tokens[6];
#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
	char *mailTo = NULL;
#endif
	char *shell = NULL;

	delete_cronfile(fileName);

	if (!getpwnam(fileName)) {
		log7("ignoring file '%s' (no such user)", fileName);
		return;
	}

	parser = config_open(fileName);
	if (!parser)
		return;

	maxLines = (strcmp(fileName, "root") == 0) ? 65535 : MAXLINES;

	if (fstat(fileno(parser->fp), &sbuf) == 0 && sbuf.st_uid == DAEMON_UID) {
		CronFile *file = xzalloc(sizeof(CronFile));
		CronLine **pline;
		int n;

		file->cf_username = xstrdup(fileName);
		pline = &file->cf_lines;

		while (1) {
			CronLine *line;

			if (!--maxLines) {
				bb_error_msg("user %s: too many lines", fileName);
				break;
			}

			n = config_read(parser, tokens, 6, 1, "# \t", PARSE_NORMAL | PARSE_KEEP_COPY);
			if (!n)
				break;

			log5("user:%s entry:%s", fileName, parser->data);

			/* check if line is setting MAILTO= */
			if (is_prefixed_with(tokens[0], "MAILTO=")) {
#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
				free(mailTo);
				mailTo = (tokens[0][7]) ? xstrdup(&tokens[0][7]) : NULL;
#endif /* otherwise just ignore such lines */
				continue;
			}
			if (is_prefixed_with(tokens[0], "SHELL=")) {
				free(shell);
				shell = xstrdup(&tokens[0][6]);
				continue;
			}
//TODO: handle HOME= too? "man crontab" says:
//name = value
//
//where the spaces around the equal-sign (=) are optional, and any subsequent
//non-leading spaces in value will be part of the value assigned to name.
//The value string may be placed in quotes (single or double, but matching)
//to preserve leading or trailing blanks.
//
//Several environment variables are set up automatically by the cron(8) daemon.
//SHELL is set to /bin/sh, and LOGNAME and HOME are set from the /etc/passwd
//line of the crontab's owner. HOME and SHELL may be overridden by settings
//in the crontab; LOGNAME may not.

			/* check if a minimum of tokens is specified */
			if (n < 6)
				continue;
			*pline = line = xzalloc(sizeof(*line));
			/* parse date ranges */
			ParseField(file->cf_username, line->cl_Mins, 60, 0, NULL, tokens[0]);
			ParseField(file->cf_username, line->cl_Hrs, 24, 0, NULL, tokens[1]);
			ParseField(file->cf_username, line->cl_Days, 32, 0, NULL, tokens[2]);
			ParseField(file->cf_username, line->cl_Mons, 12, -1, MonAry, tokens[3]);
			ParseField(file->cf_username, line->cl_Dow, 7, 0, DowAry, tokens[4]);
			/*
			 * fix days and dow - if one is not "*" and the other
			 * is "*", the other is set to 0, and vise-versa
			 */
			FixDayDow(line);
#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
			/* copy mailto (can be NULL) */
			line->cl_mailto = xstrdup(mailTo);
#endif
			line->cl_shell = xstrdup(shell);
			/* copy command */
			line->cl_cmd = xstrdup(tokens[5]);
			pline = &line->cl_next;
//bb_error_msg("M[%s]F[%s][%s][%s][%s][%s][%s]", mailTo, tokens[0], tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]);
		}
		*pline = NULL;

		file->cf_next = G.cron_files;
		G.cron_files = file;
	}
	config_close(parser);
#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
	free(mailTo);
#endif
	free(shell);
}
Пример #11
0
static void load_crontab(const char *fileName)
{
	struct parser_t *parser;
	struct stat sbuf;
	int maxLines;
	char *tokens[6];
#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
	char *mailTo = NULL;
#endif
	char *shell = NULL;

	delete_cronfile(fileName);

	if (!getpwnam(fileName)) {
		log7("ignoring file '%s' (no such user)", fileName);
		return;
	}

	parser = config_open(fileName);
	if (!parser)
		return;

	maxLines = (strcmp(fileName, "root") == 0) ? 65535 : MAXLINES;

	if (fstat(fileno(parser->fp), &sbuf) == 0 && sbuf.st_uid == DAEMON_UID) {
		CronFile *file = xzalloc(sizeof(CronFile));
		CronLine **pline;
		int n;

		file->cf_username = xstrdup(fileName);
		pline = &file->cf_lines;

		while (1) {
			CronLine *line;

			if (!--maxLines) {
				bb_error_msg("user %s: too many lines", fileName);
				break;
			}

			n = config_read(parser, tokens, 6, 1, "# \t", PARSE_NORMAL | PARSE_KEEP_COPY);
			if (!n)
				break;

			log5("user:%s entry:%s", fileName, parser->data);

			/* check if line is setting MAILTO= */
			if (is_prefixed_with(tokens[0], "MAILTO=")) {
#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
				free(mailTo);
				mailTo = (tokens[0][7]) ? xstrdup(&tokens[0][7]) : NULL;
#endif /* otherwise just ignore such lines */
				continue;
			}
			if (is_prefixed_with(tokens[0], "SHELL=")) {
				free(shell);
				shell = xstrdup(&tokens[0][6]);
				continue;
			}
//TODO: handle HOME= too? "man crontab" says:
//name = value
//
//where the spaces around the equal-sign (=) are optional, and any subsequent
//non-leading spaces in value will be part of the value assigned to name.
//The value string may be placed in quotes (single or double, but matching)
//to preserve leading or trailing blanks.
//
//Several environment variables are set up automatically by the cron(8) daemon.
//SHELL is set to /bin/sh, and LOGNAME and HOME are set from the /etc/passwd
//line of the crontab's owner. HOME and SHELL may be overridden by settings
//in the crontab; LOGNAME may not.

#if ENABLE_FEATURE_CROND_SPECIAL_TIMES
			if (tokens[0][0] == '@') {
				/*
				 * "@daily /a/script/to/run PARAM1 PARAM2..."
				 */
				typedef struct SpecialEntry {
					const char *name;
					const char tokens[8];
				} SpecialEntry;
				static const SpecialEntry SpecAry[] = {
					/*              hour  day   month weekday */
					{ "yearly",     "0\0" "1\0" "1\0" "*" },
					{ "annually",   "0\0" "1\0" "1\0" "*" },
					{ "monthly",    "0\0" "1\0" "*\0" "*" },
					{ "weekly",     "0\0" "*\0" "*\0" "0" },
					{ "daily",      "0\0" "*\0" "*\0" "*" },
					{ "midnight",   "0\0" "*\0" "*\0" "*" },
					{ "hourly",     "*\0" "*\0" "*\0" "*" },
					{ "reboot",     ""                    },
				};
				const SpecialEntry *e = SpecAry;

				if (n < 2)
					continue;
				for (;;) {
					if (strcmp(e->name, tokens[0] + 1) == 0) {
						/*
						 * tokens[1] is only the first word of command,
						 * can'r use it.
						 * find the entire command in unmodified string:
						 */
						tokens[5] = skip_whitespace(
							skip_non_whitespace(
							skip_whitespace(parser->data)));
						if (e->tokens[0]) {
							char *et = (char*)e->tokens;
							/* minute is "0" for all specials */
							tokens[0] = (char*)"0";
							tokens[1] = et;
							tokens[2] = et + 2;
							tokens[3] = et + 4;
							tokens[4] = et + 6;
						}
						goto got_it;
					}
					if (!e->tokens[0])
						break;
					e++;
				}
				continue; /* bad line (unrecognized '@foo') */
			}
#endif
			/* check if a minimum of tokens is specified */
			if (n < 6)
				continue;
 IF_FEATURE_CROND_SPECIAL_TIMES(
  got_it:
 )
			*pline = line = xzalloc(sizeof(*line));
#if ENABLE_FEATURE_CROND_SPECIAL_TIMES
			if (tokens[0][0] == '@') { /* "@reboot" line */
				file->cf_wants_starting = 1;
				line->cl_pid = START_ME_REBOOT; /* wants to start */
				/* line->cl_Mins/Hrs/etc stay zero: never match any time */
			} else
#endif
			{
				/* parse date ranges */
				ParseField(file->cf_username, line->cl_Mins, 60, 0, NULL, tokens[0]);
				ParseField(file->cf_username, line->cl_Hrs, 24, 0, NULL, tokens[1]);
				ParseField(file->cf_username, line->cl_Days, 32, 0, NULL, tokens[2]);
				ParseField(file->cf_username, line->cl_Mons, 12, -1, MonAry, tokens[3]);
				ParseField(file->cf_username, line->cl_Dow, 7, 0, DowAry, tokens[4]);
				/*
				 * fix days and dow - if one is not "*" and the other
				 * is "*", the other is set to 0, and vise-versa
				 */
				FixDayDow(line);
			}
#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
			/* copy mailto (can be NULL) */
			line->cl_mailto = xstrdup(mailTo);
#endif
			line->cl_shell = xstrdup(shell);
			/* copy command */
			line->cl_cmd = xstrdup(tokens[5]);
			pline = &line->cl_next;
//bb_error_msg("M[%s]F[%s][%s][%s][%s][%s][%s]", mailTo, tokens[0], tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]);
		}
		*pline = NULL;

		file->cf_next = G.cron_files;
		G.cron_files = file;
	}
Пример #12
0
static int
xbsd_initlabel(struct partition *p)
{
    struct xbsd_disklabel *d = &xbsd_dlabel;
    struct xbsd_partition *pp;

    get_geometry();
    memset(d, 0, sizeof(struct xbsd_disklabel));

    d->d_magic = BSD_DISKMAGIC;

    if (is_prefixed_with(disk_device, "/dev/sd"))
        d->d_type = BSD_DTYPE_SCSI;
    else
        d->d_type = BSD_DTYPE_ST506;

#if !defined(__alpha__)
    d->d_flags = BSD_D_DOSPART;
#else
    d->d_flags = 0;
#endif
    d->d_secsize = SECTOR_SIZE;           /* bytes/sector  */
    d->d_nsectors = g_sectors;            /* sectors/track */
    d->d_ntracks = g_heads;               /* tracks/cylinder (heads) */
    d->d_ncylinders = g_cylinders;
    d->d_secpercyl  = g_sectors * g_heads;/* sectors/cylinder */
    if (d->d_secpercyl == 0)
        d->d_secpercyl = 1;           /* avoid segfaults */
    d->d_secperunit = d->d_secpercyl * d->d_ncylinders;

    d->d_rpm = 3600;
    d->d_interleave = 1;
    d->d_trackskew = 0;
    d->d_cylskew = 0;
    d->d_headswitch = 0;
    d->d_trkseek = 0;

    d->d_magic2 = BSD_DISKMAGIC;
    d->d_bbsize = BSD_BBSIZE;
    d->d_sbsize = BSD_SBSIZE;

#if !defined(__alpha__)
    d->d_npartitions = 4;
    pp = &d->d_partitions[2]; /* Partition C should be NetBSD partition */

    pp->p_offset = get_start_sect(p);
    pp->p_size   = get_nr_sects(p);
    pp->p_fstype = BSD_FS_UNUSED;
    pp = &d->d_partitions[3]; /* Partition D should be whole disk */

    pp->p_offset = 0;
    pp->p_size   = d->d_secperunit;
    pp->p_fstype = BSD_FS_UNUSED;
#else
    d->d_npartitions = 3;
    pp = &d->d_partitions[2]; /* Partition C should be the whole disk */
    pp->p_offset = 0;
    pp->p_size   = d->d_secperunit;
    pp->p_fstype = BSD_FS_UNUSED;
#endif

    return 1;
}
Пример #13
0
static void modinfo(const char *path, const char *version,
			const struct modinfo_env *env)
{
	static const char *const shortcuts[] = {
		"filename",
		"license",
		"author",
		"description",
		"version",
		"alias",
		"srcversion",
		"depends",
		"uts_release",
		"vermagic",
		"parm",
		"firmware",
	};
	size_t len;
	int j;
	char *ptr, *fullpath, *the_module;
	const char *field = env->field;
	int tags = env->tags;

	if (tags & 1) { /* filename */
		display(path, shortcuts[0], 1 != tags);
	}

	len = MAXINT(ssize_t);
	the_module = xmalloc_open_zipped_read_close(path, &len);
	if (!the_module) {
		if (path[0] == '/')
			return;
		/* Newer depmod puts relative paths in modules.dep */
		fullpath = xasprintf("%s/%s/%s", CONFIG_DEFAULT_MODULES_DIR, version, path);
		the_module = xmalloc_open_zipped_read_close(fullpath, &len);
#ifdef DONT_USE_UTS_REL_FOLDER
		if (!the_module) {
			free((char*)fullpath);
			fullpath = xasprintf("%s/%s", CONFIG_DEFAULT_MODULES_DIR, path);
			the_module = xmalloc_open_zipped_read_close(fullpath, &len);
		}
#endif
		free((char*)fullpath);
		if (!the_module) {
			// outputs system error msg
			bb_perror_msg("");
			return;
		}
	}

	if (field)
		tags |= OPT_F;
	for (j = 1; (1<<j) & (OPT_TAGS + OPT_F); j++) {
		const char *pattern;

		if (!((1<<j) & tags))
			continue;
		pattern = field;
		if ((1<<j) & OPT_TAGS)
			pattern = shortcuts[j];
		ptr = the_module;
		while (1) {
			char *after_pattern;

			ptr = memchr(ptr, *pattern, len - (ptr - (char*)the_module));
			if (ptr == NULL) /* no occurance left, done */
				break;
			after_pattern = is_prefixed_with(ptr, pattern);
			if (after_pattern && *after_pattern == '=') {
				/* field prefixes are 0x80 or 0x00 */
				if ((ptr[-1] & 0x7F) == 0x00) {
					ptr = after_pattern + 1;
					display(ptr, pattern, (1<<j) != tags);
					ptr += strlen(ptr);
				}
			}
			++ptr;
		}
	}
	free(the_module);
}
Пример #14
0
static int run_pipe(char *man_filename, int man, int level)
{
	char *cmd;

	/* Prevent man page link loops */
	if (level > 10)
		return 0;

	if (access(man_filename, R_OK) != 0)
		return 0;

	if (option_mask32 & OPT_w) {
		puts(man_filename);
		return 1;
	}

	if (man) { /* man page, not cat page */
		/* Is this a link to another manpage? */
		/* The link has the following on the first line: */
		/* ".so another_man_page" */

		struct stat sb;
		char *line;
		char *linkname, *p;

		/* On my system:
		 * man1/genhostid.1.gz: 203 bytes - smallest real manpage
		 * man2/path_resolution.2.gz: 114 bytes - largest link
		 */
		xstat(man_filename, &sb);
		if (sb.st_size > 300) /* err on the safe side */
			goto ordinary_manpage;

		line = xmalloc_open_zipped_read_close(man_filename, NULL);
		if (!line || !is_prefixed_with(line, ".so ")) {
			free(line);
			goto ordinary_manpage;
		}
		/* Example: man2/path_resolution.2.gz contains
		 * ".so man7/path_resolution.7\n<junk>"
		 */
		*strchrnul(line, '\n') = '\0';
		linkname = skip_whitespace(&line[4]);

		/* If link has no slashes, we just replace man page name.
		 * If link has slashes (however many), we go back *once*.
		 * ".so zzz/ggg/page.3" does NOT go back two levels. */
		p = strrchr(man_filename, '/');
		if (!p)
			goto ordinary_manpage;
		*p = '\0';
		if (strchr(linkname, '/')) {
			p = strrchr(man_filename, '/');
			if (!p)
				goto ordinary_manpage;
			*p = '\0';
		}

		/* Links do not have .gz extensions, even if manpage
		 * is compressed */
		man_filename = xasprintf("%s/%s", man_filename, linkname);
		free(line);
		/* Note: we leak "new" man_filename string as well... */
		if (show_manpage(man_filename, man, level + 1))
			return 1;
		/* else: show the link, it's better than nothing */
	}

 ordinary_manpage:
	close(STDIN_FILENO);
	open_zipped(man_filename, /*fail_if_not_compressed:*/ 0); /* guaranteed to use fd 0 (STDIN_FILENO) */
	if (man) {
		int w = get_terminal_width(-1);
		if (w > 10)
			w -= 2;
		/* "2>&1" is added so that nroff errors are shown in pager too.
		 * Otherwise it may show just empty screen.
		 */
		cmd = xasprintf("%s | %s -rLL=%un -rLT=%un 2>&1 | %s",
				G.tbl, G.nroff, w, w,
				G.pager);
	} else {
		cmd = xstrdup(G.pager);
	}
	system(cmd);
	free(cmd);
	return 1;
}
Пример #15
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);
		}
	}

	// 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 (is_prefixed_with(patchline, "--- ") || is_prefixed_with(patchline, "+++ ")) {
			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 && is_prefixed_with(patchline, "@@ -")) {
			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 the --- line is missing or malformed, either oldname
			// or (for -R) newname could be NULL -- but not both.  Like
			// GNU patch, proceed based on the +++ line, and avoid SEGVs.
			if (!oldname)
				oldname = xstrdup("MISSING_FILENAME");
			if (!newname)
				newname = xstrdup("MISSING_FILENAME");

			// 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 = 1;
				}

				// Handle -p path truncation.
				for (i = 0, s = name; *s;) {
					if ((option_mask32 & FLAG_PATHLEN) && TT.prefix == i)
						break;
					if (*s++ != '/')
						continue;
					while (*s == '/')
						s++;
					i++;
					name = s;
				}
				// If "patch FILE_TO_PATCH", completely ignore name from patch
				if (argv[0])
					name = argv[0];

				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;
}
Пример #16
0
int man_main(int argc UNUSED_PARAM, char **argv)
{
	parser_t *parser;
	const char *pager = ENABLE_LESS ? "less" : "more";
	char *sec_list;
	char *cur_path, *cur_sect;
	char **man_path_list;
	int count_mp;
	int cur_mp;
	int opt, not_found;
	char *token[2];

	opt_complementary = "-1"; /* at least one argument */
	opt = getopt32(argv, "+aw");
	argv += optind;

	sec_list = xstrdup("0p:1:1p:2:3:3p:4:5:6:7:8:9");

	count_mp = 0;
	man_path_list = add_MANPATH(NULL, &count_mp,
			getenv("MANDATORY_MANPATH"+10) /* "MANPATH" */
	);
	if (!man_path_list) {
		/* default, may be overridden by /etc/man.conf */
		man_path_list = xzalloc(2 * sizeof(man_path_list[0]));
		man_path_list[0] = (char*)"/usr/man";
		/* count_mp stays 0.
		 * Thus, man.conf will overwrite man_path_list[0]
		 * if a path is defined there.
		 */
	}

	/* Parse man.conf[ig] or man_db.conf */
	/* man version 1.6f uses man.config */
	/* man-db implementation of man uses man_db.conf */
	parser = config_open2("/etc/man.config", fopen_for_read);
	if (!parser)
		parser = config_open2("/etc/man.conf", fopen_for_read);
	if (!parser)
		parser = config_open2("/etc/man_db.conf", fopen_for_read);

	while (config_read(parser, token, 2, 0, "# \t", PARSE_NORMAL)) {
		if (!token[1])
			continue;
		if (strcmp("DEFINE", token[0]) == 0) {
			if (is_prefixed_with("pager", token[1])) {
				pager = xstrdup(skip_whitespace(token[1]) + 5);
			}
		} else
		if (strcmp("MANDATORY_MANPATH"+10, token[0]) == 0 /* "MANPATH"? */
		 || strcmp("MANDATORY_MANPATH", token[0]) == 0
		) {
			man_path_list = add_MANPATH(man_path_list, &count_mp, token[1]);
		}
		if (strcmp("MANSECT", token[0]) == 0) {
			free(sec_list);
			sec_list = xstrdup(token[1]);
		}
	}
	config_close(parser);

	{
		/* environment overrides setting from man.config */
		char *env_pager = getenv("MANPAGER");
		if (!env_pager)
			env_pager = getenv("PAGER");
		if (env_pager)
			pager = env_pager;
	}

	not_found = 0;
	do { /* for each argv[] */
		int found = 0;
		cur_mp = 0;

		if (strchr(*argv, '/')) {
			found = show_manpage(pager, *argv, /*man:*/ 1, 0);
			goto check_found;
		}
		while ((cur_path = man_path_list[cur_mp++]) != NULL) {
			/* for each MANPATH */
			cur_sect = sec_list;
			do { /* for each section */
				char *next_sect = strchrnul(cur_sect, ':');
				int sect_len = next_sect - cur_sect;
				char *man_filename;
				int cat0man1 = 0;

				/* Search for cat, then man page */
				while (cat0man1 < 2) {
					int found_here;
					man_filename = xasprintf("%s/%s%.*s/%s.%.*s",
							cur_path,
							"cat\0man" + (cat0man1 * 4),
							sect_len, cur_sect,
							*argv,
							sect_len, cur_sect);
					found_here = show_manpage(pager, man_filename, cat0man1, 0);
					found |= found_here;
					cat0man1 += found_here + 1;
					free(man_filename);
				}

				if (found && !(opt & OPT_a))
					goto next_arg;
				cur_sect = next_sect;
				while (*cur_sect == ':')
					cur_sect++;
			} while (*cur_sect);
		}
 check_found:
		if (!found) {
			bb_error_msg("no manual entry for '%s'", *argv);
			not_found = 1;
		}
 next_arg:
		argv++;
	} while (*argv);

	return not_found;
}
Пример #17
0
/*
 1) add a user: update_passwd(FILE, USER, REMAINING_PWLINE, NULL)
    only if CONFIG_ADDUSER=y and applet_name[0] == 'a' like in adduser

 2) add a group: update_passwd(FILE, GROUP, REMAINING_GRLINE, NULL)
    only if CONFIG_ADDGROUP=y and applet_name[0] == 'a' like in addgroup

 3) add a user to a group: update_passwd(FILE, GROUP, NULL, MEMBER)
    only if CONFIG_FEATURE_ADDUSER_TO_GROUP=y, applet_name[0] == 'a'
    like in addgroup and member != NULL

 4) delete a user: update_passwd(FILE, USER, NULL, NULL)

 5) delete a group: update_passwd(FILE, GROUP, NULL, NULL)

 6) delete a user from a group: update_passwd(FILE, GROUP, NULL, MEMBER)
    only if CONFIG_FEATURE_DEL_USER_FROM_GROUP=y and member != NULL

 7) change user's password: update_passwd(FILE, USER, NEW_PASSWD, NULL)
    only if CONFIG_PASSWD=y and applet_name[0] == 'p' like in passwd
    or if CONFIG_CHPASSWD=y and applet_name[0] == 'c' like in chpasswd

 8) delete a user from all groups: update_passwd(FILE, NULL, NULL, MEMBER)

 This function does not validate the arguments fed to it
 so the calling program should take care of that.

 Returns number of lines changed, or -1 on error.
*/
int FAST_FUNC update_passwd(const char *filename,
		const char *name,
		const char *new_passwd,
		const char *member)
{
#if !(ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP)
#define member NULL
#endif
	struct stat sb;
	struct flock lock;
	FILE *old_fp;
	FILE *new_fp;
	char *fnamesfx;
	char *sfx_char;
	char *name_colon;
	int old_fd;
	int new_fd;
	int i;
	int changed_lines;
	int ret = -1; /* failure */
	/* used as a bool: "are we modifying /etc/shadow?" */
#if ENABLE_FEATURE_SHADOWPASSWDS
	const char *shadow = strstr(filename, "shadow");
#else
# define shadow NULL
#endif

	filename = xmalloc_follow_symlinks(filename);
	if (filename == NULL)
		return ret;

	if (name)
		check_selinux_update_passwd(name);

	/* New passwd file, "/etc/passwd+" for now */
	fnamesfx = xasprintf("%s+", filename);
	sfx_char = &fnamesfx[strlen(fnamesfx)-1];
	name_colon = xasprintf("%s:", name ? name : "");

	if (shadow)
		old_fp = fopen(filename, "r+");
	else
		old_fp = fopen_or_warn(filename, "r+");
	if (!old_fp) {
		if (shadow)
			ret = 0; /* missing shadow is not an error */
		goto free_mem;
	}
	old_fd = fileno(old_fp);

	selinux_preserve_fcontext(old_fd);

	/* Try to create "/etc/passwd+". Wait if it exists. */
	i = 30;
	do {
		// FIXME: on last iteration try w/o O_EXCL but with O_TRUNC?
		new_fd = open(fnamesfx, O_WRONLY|O_CREAT|O_EXCL, 0600);
		if (new_fd >= 0) goto created;
		if (errno != EEXIST) break;
		usleep(100000); /* 0.1 sec */
	} while (--i);
	bb_perror_msg("can't create '%s'", fnamesfx);
	goto close_old_fp;

 created:
	if (fstat(old_fd, &sb) == 0) {
		fchmod(new_fd, sb.st_mode & 0777); /* ignore errors */
		fchown(new_fd, sb.st_uid, sb.st_gid);
	}
	errno = 0;
	new_fp = xfdopen_for_write(new_fd);

	/* Backup file is "/etc/passwd-" */
	*sfx_char = '-';
	/* Delete old backup */
	i = (unlink(fnamesfx) && errno != ENOENT);
	/* Create backup as a hardlink to current */
	if (i || link(filename, fnamesfx))
		bb_perror_msg("warning: can't create backup copy '%s'",
				fnamesfx);
	*sfx_char = '+';

	/* Lock the password file before updating */
	lock.l_type = F_WRLCK;
	lock.l_whence = SEEK_SET;
	lock.l_start = 0;
	lock.l_len = 0;
	if (fcntl(old_fd, F_SETLK, &lock) < 0)
		bb_perror_msg("warning: can't lock '%s'", filename);
	lock.l_type = F_UNLCK;

	/* Read current password file, write updated /etc/passwd+ */
	changed_lines = 0;
	while (1) {
		char *cp, *line;

		line = xmalloc_fgetline(old_fp);
		if (!line) /* EOF/error */
			break;

		if (!name && member) {
			/* Delete member from all groups */
			/* line is "GROUP:PASSWD:[member1[,member2]...]" */
			unsigned member_len = strlen(member);
			char *list = strrchr(line, ':');
			while (list) {
				list++;
 next_list_element:
				if (is_prefixed_with(list, member)) {
					char c;
					changed_lines++;
					c = list[member_len];
					if (c == '\0') {
						if (list[-1] == ',')
							list--;
						*list = '\0';
						break;
					}
					if (c == ',') {
						overlapping_strcpy(list, list + member_len + 1);
						goto next_list_element;
					}
					changed_lines--;
				}
				list = strchr(list, ',');
			}
			fprintf(new_fp, "%s\n", line);
			goto next;
		}

		cp = is_prefixed_with(line, name_colon);
		if (!cp) {
			fprintf(new_fp, "%s\n", line);
			goto next;
		}

		/* We have a match with "name:"... */
		/* cp points past "name:" */

#if ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP
		if (member) {
			/* It's actually /etc/group+, not /etc/passwd+ */
			if (ENABLE_FEATURE_ADDUSER_TO_GROUP
			 && applet_name[0] == 'a'
			) {
				/* Add user to group */
				fprintf(new_fp, "%s%s%s\n", line,
					last_char_is(line, ':') ? "" : ",",
					member);
				changed_lines++;
			} else if (ENABLE_FEATURE_DEL_USER_FROM_GROUP
			/* && applet_name[0] == 'd' */
			) {
				/* Delete user from group */
				char *tmp;
				const char *fmt = "%s";

				/* find the start of the member list: last ':' */
				cp = strrchr(line, ':');
				/* cut it */
				*cp++ = '\0';
				/* write the cut line name:passwd:gid:
				 * or name:!:: */
				fprintf(new_fp, "%s:", line);
				/* parse the tokens of the member list */
				tmp = cp;
				while ((cp = strsep(&tmp, ",")) != NULL) {
					if (strcmp(member, cp) != 0) {
						fprintf(new_fp, fmt, cp);
						fmt = ",%s";
					} else {
						/* found member, skip it */
						changed_lines++;
					}
				}
				fprintf(new_fp, "\n");
			}
		} else
#endif
		if ((ENABLE_PASSWD && applet_name[0] == 'p')
		 || (ENABLE_CHPASSWD && applet_name[0] == 'c')
		) {
			/* Change passwd */
			cp = strchrnul(cp, ':'); /* move past old passwd */

			if (shadow && *cp == ':') {
				/* /etc/shadow's field 3 (passwd change date) needs updating */
				/* move past old change date */
				cp = strchrnul(cp + 1, ':');
				/* "name:" + "new_passwd" + ":" + "change date" + ":rest of line" */
				fprintf(new_fp, "%s%s:%u%s\n", name_colon, new_passwd,
					(unsigned)(time(NULL)) / (24*60*60), cp);
			} else {
				/* "name:" + "new_passwd" + ":rest of line" */
				fprintf(new_fp, "%s%s%s\n", name_colon, new_passwd, cp);
			}
			changed_lines++;
		} /* else delete user or group: skip the line */
 next:
		free(line);
	}

	if (changed_lines == 0) {
#if ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP
		if (member) {
			if (ENABLE_ADDGROUP && applet_name[0] == 'a')
				bb_error_msg("can't find %s in %s", name, filename);
			if (ENABLE_DELGROUP && applet_name[0] == 'd')
				bb_error_msg("can't find %s in %s", member, filename);
		}
#endif
		if ((ENABLE_ADDUSER || ENABLE_ADDGROUP)
		 && applet_name[0] == 'a' && !member
		) {
			/* add user or group */
			fprintf(new_fp, "%s%s\n", name_colon, new_passwd);
			changed_lines++;
		}
	}

	fcntl(old_fd, F_SETLK, &lock);

	/* We do want all of them to execute, thus | instead of || */
	errno = 0;
	if ((ferror(old_fp) | fflush(new_fp) | fsync(new_fd) | fclose(new_fp))
	 || rename(fnamesfx, filename)
	) {
		/* At least one of those failed */
		bb_perror_nomsg();
		goto unlink_new;
	}
	/* Success: ret >= 0 */
	ret = changed_lines;

 unlink_new:
	if (ret < 0)
		unlink(fnamesfx);

 close_old_fp:
	fclose(old_fp);

 free_mem:
	free(fnamesfx);
	free((char *)filename);
	free(name_colon);
	return ret;
}