Exemplo n.º 1
0
static int write_ar_header(archive_handle_t *handle)
{
    char *fn;
    char fn_h[17]; /* 15 + "/" + NUL */
    struct stat st;
    int fd;

    fn = llist_pop(&handle->accept);
    if (!fn)
        return -1;

    xstat(fn, &st);

    handle->file_header->mtime = st.st_mtime;
    handle->file_header->uid = st.st_uid;
    handle->file_header->gid = st.st_gid;
    handle->file_header->mode = st.st_mode;
    handle->file_header->size = st.st_size;
    handle->file_header->name = fn_h;
//TODO: if ENABLE_FEATURE_AR_LONG_FILENAMES...
    sprintf(fn_h, "%.15s/", bb_basename(fn));

    output_ar_header(handle);

    fd = xopen(fn, O_RDONLY);
    bb_copyfd_exact_size(fd, handle->src_fd, st.st_size);
    close(fd);
    handle->offset += st.st_size;

    return 0;
}
Exemplo n.º 2
0
/* find_pid_by_name()
 *
 *  Modified by Vladimir Oleynik for use with libbb/procps.c
 *  This finds the pid of the specified process.
 *  Currently, it's implemented by rummaging through
 *  the proc filesystem.
 *
 *  Returns a list of all matching PIDs
 *  It is the caller's duty to free the returned pidlist.
 */
pid_t* find_pid_by_name(const char* procName)
{
	pid_t* pidList;
	int i = 0;
	procps_status_t* p = NULL;

	pidList = xmalloc(sizeof(*pidList));
	while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_COMM|PSSCAN_ARGV0))) {
		if (
		/* we require comm to match and to not be truncated */
		/* in Linux, if comm is 15 chars, it may be a truncated
		 * name, so we don't allow that to match */
		    (!p->comm[sizeof(p->comm)-2] && strcmp(p->comm, procName) == 0)
		/* or we require argv0 to match (essential for matching reexeced /proc/self/exe)*/
		 || (p->argv0 && strcmp(bb_basename(p->argv0), procName) == 0)
		/* TOOD: we can also try /proc/NUM/exe link, do we want that? */
		) {
			pidList = xrealloc(pidList, sizeof(*pidList) * (i+2));
			pidList[i++] = p->pid;
		}
	}

	pidList[i] = 0;
	return pidList;
}
static int comm_match(procps_status_t *p, const char *procName)
{
	int argv1idx;
	const char *argv1;

	if (strncmp(p->comm, procName, 15) != 0)
		return 0; /* comm does not match */

	/* In Linux, if comm is 15 chars, it is truncated.
	 * (or maybe the name was exactly 15 chars, but there is
	 * no way to know that) */
	if (p->comm[14] == '\0')
		return 1; /* comm is not truncated - matches */

	/* comm is truncated, but first 15 chars match.
	 * This can be crazily_long_script_name.sh!
	 * The telltale sign is basename(argv[1]) == procName */

	if (!p->argv0)
		return 0;

	argv1idx = strlen(p->argv0) + 1;
	if (argv1idx >= p->argv_len)
		return 0;
	argv1 = p->argv0 + argv1idx;

	if (strcmp(bb_basename(argv1), procName) != 0)
		return 0;

	return 1;
}
int sestatus_main(int argc, char **argv)
{
	unsigned opts;
	const char *pol_path;
	int rc;

	opt_complementary = "?0";	/* no arguments are required. */
	opts = getopt32(argv, "vb");

	/* SELinux status: line */
	rc = is_selinux_enabled();
	if (rc < 0)
		goto error;
	printf(COL_FMT "%s\n", "SELinux status:",
	       rc == 1 ? "enabled" : "disabled");

	/* SELinuxfs mount: line */
	if (!selinux_mnt)
		goto error;
	printf(COL_FMT "%s\n", "SELinuxfs mount:",
	       selinux_mnt);

	/* Current mode: line */
	rc = security_getenforce();
	if (rc < 0)
		goto error;
	printf(COL_FMT "%s\n", "Current mode:",
	       rc == 0 ? "permissive" : "enforcing");

	/* Mode from config file: line */
	if (selinux_getenforcemode(&rc) != 0)
		goto error;
	printf(COL_FMT "%s\n", "Mode from config file:",
	       rc < 0 ? "disabled" : (rc == 0 ? "permissive" : "enforcing"));

	/* Policy version: line */
	rc = security_policyvers();
	if (rc < 0)
		goto error;
	printf(COL_FMT "%u\n", "Policy version:", rc);

	/* Policy from config file: line */
	pol_path = selinux_policy_root();
	if (!pol_path)
		goto error;
	printf(COL_FMT "%s\n", "Policy from config file:",
	       bb_basename(pol_path));

	if (opts & OPT_BOOLEAN)
		display_boolean();
	if (opts & OPT_VERBOSE)
		display_verbose();

	return 0;

  error:
	bb_perror_msg_and_die("libselinux returns unknown state");
}
Exemplo n.º 5
0
/* Is this a valid filename (upper/lower alpha, digits,
 * underscores, and hyphens only?)
 */
static bool invalid_name(const char *c)
{
	c = bb_basename(c);

	while (*c && (isalnum(*c) || *c == '_' || *c == '-'))
		c++;

	return *c; /* TRUE (!0) if terminating NUL is not reached */
}
Exemplo n.º 6
0
int mktemp_main(int argc UNUSED_PARAM, char **argv)
{
	const char *path;
	char *chp;
	unsigned opts;
	enum {
		OPT_d = 1 << 0,
		OPT_q = 1 << 1,
		OPT_t = 1 << 2,
		OPT_p = 1 << 3,
		OPT_u = 1 << 4,
	};

	path = getenv("TMPDIR");
	if (!path || path[0] == '\0')
		path = "/tmp";

	opt_complementary = "?1"; /* 1 argument max */
	opts = getopt32(argv, "dqtp:u", &path);

	chp = argv[optind];
	if (!chp) {
		/* GNU coreutils 8.4:
		 * bare "mktemp" -> "mktemp -t tmp.XXXXXX"
		 */
		chp = xstrdup("tmp.XXXXXX");
		opts |= OPT_t;
	}
#if 0
	/* Don't allow directory separator in template */
	if ((opts & OPT_t) && bb_basename(chp) != chp) {
		errno = EINVAL;
		goto error;
	}
#endif
	if (opts & (OPT_t|OPT_p))
		chp = concat_path_file(path, chp);

	if (opts & OPT_u) {
		chp = mktemp(chp);
		if (chp[0] == '\0')
			goto error;
	} else if (opts & OPT_d) {
		if (mkdtemp(chp) == NULL)
			goto error;
	} else {
		if (mkstemp(chp) < 0)
			goto error;
	}
	puts(chp);
	return EXIT_SUCCESS;
 error:
	if (opts & OPT_q)
		return EXIT_FAILURE;
	/* don't use chp as it gets mangled in case of error */
	bb_perror_nomsg_and_die();
}
/* This finds the pid of the specified process.
 * Currently, it's implemented by rummaging through
 * the proc filesystem.
 *
 * Returns a list of all matching PIDs
 * It is the caller's duty to free the returned pidlist.
 *
 * Modified by Vladimir Oleynik for use with libbb/procps.c
 */
pid_t* FAST_FUNC find_pid_by_name(const char *procName)
{
    pid_t* pidList;
    int i = 0;
    procps_status_t* p = NULL;

    pidList = xzalloc(sizeof(*pidList));
    while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_COMM|PSSCAN_ARGVN|PSSCAN_EXE))) {
        if (comm_match(p, procName)
                /* or we require argv0 to match (essential for matching reexeced /proc/self/exe)*/
                || (p->argv0 && strcmp(bb_basename(p->argv0), procName) == 0)
                /* or we require /proc/PID/exe link to match */
                || (p->exe && strcmp(bb_basename(p->exe), procName) == 0)
           ) {
            pidList = xrealloc_vector(pidList, 2, i);
            pidList[i++] = p->pid;
        }
    }

    pidList[i] = 0;
    return pidList;
}
Exemplo n.º 8
0
int modinfo_main(int argc UNUSED_PARAM, char **argv)
{
	struct modinfo_env env;
	char name[MODULE_NAME_LEN];
	struct utsname uts;
	parser_t *parser;
	char *colon, *tokens[2];
	unsigned opts;
	unsigned i;

	env.field = NULL;
	opt_complementary = "-1"; /* minimum one param */
	opts = getopt32(argv, "nladvAsDumpF:0", &env.field);
	env.tags = opts & OPT_TAGS ? opts & OPT_TAGS : OPT_TAGS;
	argv += optind;

	uname(&uts);
	parser = config_open2(
		xasprintf("%s/%s/%s", CONFIG_DEFAULT_MODULES_DIR, uts.release, CONFIG_DEFAULT_DEPMOD_FILE),
		xfopen_for_read
	);

	while (config_read(parser, tokens, 2, 1, "# \t", PARSE_NORMAL)) {
		colon = last_char_is(tokens[0], ':');
		if (colon == NULL)
			continue;
		*colon = '\0';
		filename2modname(bb_basename(tokens[0]), name);
		for (i = 0; argv[i]; i++) {
			if (fnmatch(argv[i], name, 0) == 0) {
				modinfo(tokens[0], uts.release, &env);
				argv[i] = (char *) "";
			}
		}
	}
	if (ENABLE_FEATURE_CLEAN_UP)
		config_close(parser);

	for (i = 0; argv[i]; i++) {
		if (argv[i][0]) {
			modinfo(argv[i], uts.release, &env);
		}
	}

	return 0;
}
Exemplo n.º 9
0
int rmmod_main(int argc UNUSED_PARAM, char **argv)
{
	int n, err;
	unsigned flags = O_NONBLOCK | O_EXCL;

	/* Parse command line. */
	n = getopt32(argv, "wfas"); // -s ignored
	argv += optind;
	if (n & 1)  // --wait
		flags &= ~O_NONBLOCK;
	if (n & 2)  // --force
		flags |= O_TRUNC;
	if (n & 4) {
		/* Unload _all_ unused modules via NULL delete_module() call */
		err = bb_delete_module(NULL, flags);
		if (err && err != EFAULT)
			bb_perror_msg_and_die("rmmod");
		return EXIT_SUCCESS;
	}

	if (!*argv)
		bb_show_usage();

	n = ENABLE_FEATURE_2_4_MODULES && get_linux_version_code() < KERNEL_VERSION(2,6,0);
	while (*argv) {
		char modname[MODULE_NAME_LEN];
		const char *bname;

		bname = bb_basename(*argv++);
		if (n)
			safe_strncpy(modname, bname, MODULE_NAME_LEN);
		else
			filename2modname(bname, modname);
		err = bb_delete_module(modname, flags);
		if (err)
			bb_perror_msg_and_die("can't unload module '%s'",
					modname);
	}

	return EXIT_SUCCESS;
}
static void display_verbose(void)
{
	security_context_t con, _con;
	char *fc[50], *pc[50], *cterm;
	pid_t *pidList;
	int i;

	read_config(pc, ARRAY_SIZE(pc), fc, ARRAY_SIZE(fc));

	/* process contexts */
	puts("\nProcess contexts:");

	/* current context */
	if (getcon(&con) == 0) {
		printf(COL_FMT "%s\n", "Current context:", con);
		if (ENABLE_FEATURE_CLEAN_UP)
			freecon(con);
	}
	/* /sbin/init context */
	if (getpidcon(1, &con) == 0) {
		printf(COL_FMT "%s\n", "Init context:", con);
		if (ENABLE_FEATURE_CLEAN_UP)
			freecon(con);
	}

	/* [process] context */
	for (i = 0; pc[i] != NULL; i++) {
		pidList = find_pid_by_name(bb_basename(pc[i]));
		if (pidList[0] > 0 && getpidcon(pidList[0], &con) == 0) {
			printf(COL_FMT "%s\n", pc[i], con);
			if (ENABLE_FEATURE_CLEAN_UP)
				freecon(con);
		}
		if (ENABLE_FEATURE_CLEAN_UP)
			free(pidList);
	}

	/* files contexts */
	puts("\nFile contexts:");

	cterm = ttyname(0);
	puts(cterm);
	if (cterm && lgetfilecon(cterm, &con) >= 0) {
		printf(COL_FMT "%s\n", "Controlling term:", con);
		if (ENABLE_FEATURE_CLEAN_UP)
			freecon(con);
	}

	for (i=0; fc[i] != NULL; i++) {
		struct stat stbuf;

		if (lgetfilecon(fc[i], &con) < 0)
			continue;
		if (lstat(fc[i], &stbuf) == 0) {
			if (S_ISLNK(stbuf.st_mode)) {
				if (getfilecon(fc[i], &_con) >= 0) {
					printf(COL_FMT "%s -> %s\n", fc[i], _con, con);
					if (ENABLE_FEATURE_CLEAN_UP)
						freecon(_con);
				}
			} else {
				printf(COL_FMT "%s\n", fc[i], con);
			}
		}
		if (ENABLE_FEATURE_CLEAN_UP)
			freecon(con);
	}
}
Exemplo n.º 11
0
int install_main(int argc, char **argv)
{
	struct stat statbuf;
	mode_t mode;
	uid_t uid;
	gid_t gid;
	char *arg, *last;
	const char *gid_str;
	const char *uid_str;
	const char *mode_str;
	int copy_flags = FILEUTILS_DEREFERENCE | FILEUTILS_FORCE;
	int opts;
	int min_args = 1;
	int ret = EXIT_SUCCESS;
	int isdir = 0;
#if ENABLE_SELINUX
	security_context_t scontext;
	bool use_default_selinux_context = 1;
#endif
	enum {
		OPT_c             = 1 << 0,
		OPT_v             = 1 << 1,
		OPT_b             = 1 << 2,
		OPT_MKDIR_LEADING = 1 << 3,
		OPT_DIRECTORY     = 1 << 4,
		OPT_PRESERVE_TIME = 1 << 5,
		OPT_STRIP         = 1 << 6,
		OPT_GROUP         = 1 << 7,
		OPT_MODE          = 1 << 8,
		OPT_OWNER         = 1 << 9,
#if ENABLE_SELINUX
		OPT_SET_SECURITY_CONTEXT = 1 << 10,
		OPT_PRESERVE_SECURITY_CONTEXT = 1 << 11,
#endif
	};

#if ENABLE_FEATURE_INSTALL_LONG_OPTIONS
	applet_long_options = install_longopts;
#endif
	opt_complementary = "s--d:d--s" IF_FEATURE_INSTALL_LONG_OPTIONS(IF_SELINUX(":Z--\xff:\xff--Z"));
	/* -c exists for backwards compatibility, it's needed */
	/* -v is ignored ("print name of each created directory") */
	/* -b is ignored ("make a backup of each existing destination file") */
	opts = getopt32(argv, "cvb" "Ddpsg:m:o:" IF_SELINUX("Z:"),
			&gid_str, &mode_str, &uid_str IF_SELINUX(, &scontext));
	argc -= optind;
	argv += optind;

#if ENABLE_SELINUX
	if (opts & (OPT_PRESERVE_SECURITY_CONTEXT|OPT_SET_SECURITY_CONTEXT)) {
		selinux_or_die();
		use_default_selinux_context = 0;
		if (opts & OPT_PRESERVE_SECURITY_CONTEXT) {
			copy_flags |= FILEUTILS_PRESERVE_SECURITY_CONTEXT;
		}
		if (opts & OPT_SET_SECURITY_CONTEXT) {
			setfscreatecon_or_die(scontext);
			copy_flags |= FILEUTILS_SET_SECURITY_CONTEXT;
		}
	}
#endif

	/* preserve access and modification time, this is GNU behaviour,
	 * BSD only preserves modification time */
	if (opts & OPT_PRESERVE_TIME) {
		copy_flags |= FILEUTILS_PRESERVE_STATUS;
	}
	mode = 0755; /* GNU coreutils 6.10 compat */
	if (opts & OPT_MODE)
		bb_parse_mode(mode_str, &mode);
	uid = (opts & OPT_OWNER) ? get_ug_id(uid_str, xuname2uid) : getuid();
	gid = (opts & OPT_GROUP) ? get_ug_id(gid_str, xgroup2gid) : getgid();

	last = argv[argc - 1];
	if (!(opts & OPT_DIRECTORY)) {
		argv[argc - 1] = NULL;
		min_args++;

		/* coreutils install resolves link in this case, don't use lstat */
		isdir = stat(last, &statbuf) < 0 ? 0 : S_ISDIR(statbuf.st_mode);
	}

	if (argc < min_args)
		bb_show_usage();

	while ((arg = *argv++) != NULL) {
		char *dest = last;
		if (opts & OPT_DIRECTORY) {
			dest = arg;
			/* GNU coreutils 6.9 does not set uid:gid
			 * on intermediate created directories
			 * (only on last one) */
			if (bb_make_directory(dest, 0755, FILEUTILS_RECUR)) {
				ret = EXIT_FAILURE;
				goto next;
			}
		} else {
			if (opts & OPT_MKDIR_LEADING) {
				char *ddir = xstrdup(dest);
				bb_make_directory(dirname(ddir), 0755, FILEUTILS_RECUR);
				/* errors are not checked. copy_file
				 * will fail if dir is not created. */
				free(ddir);
			}
			if (isdir)
				dest = concat_path_file(last, bb_basename(arg));
			if (copy_file(arg, dest, copy_flags) != 0) {
				/* copy is not made */
				ret = EXIT_FAILURE;
				goto next;
			}
			if (opts & OPT_STRIP) {
				char *args[4];
				args[0] = (char*)"strip";
				args[1] = (char*)"-p"; /* -p --preserve-dates */
				args[2] = dest;
				args[3] = NULL;
				if (spawn_and_wait(args)) {
					bb_perror_msg("strip");
					ret = EXIT_FAILURE;
				}
			}
		}

		/* Set the file mode (always, not only with -m).
		 * GNU coreutils 6.10 is not affected by umask. */
		if (chmod(dest, mode) == -1) {
			bb_perror_msg("can't change %s of %s", "permissions", dest);
			ret = EXIT_FAILURE;
		}
#if ENABLE_SELINUX
		if (use_default_selinux_context)
			setdefaultfilecon(dest);
#endif
		/* Set the user and group id */
		if ((opts & (OPT_OWNER|OPT_GROUP))
		 && lchown(dest, uid, gid) == -1
		) {
			bb_perror_msg("can't change %s of %s", "ownership", dest);
			ret = EXIT_FAILURE;
		}
 next:
		if (ENABLE_FEATURE_CLEAN_UP && isdir)
			free(dest);
	}

	return ret;
}
Exemplo n.º 12
0
int microcom_main(int argc UNUSED_PARAM, char **argv)
{
	int sfd;
	int nfd;
	struct pollfd pfd[2];
	struct termios tio0, tiosfd, tio;
	char *device_lock_file;
	enum {
		OPT_X = 1 << 0, // do not respect Ctrl-X, Ctrl-@
		OPT_s = 1 << 1, // baudrate
		OPT_d = 1 << 2, // wait for device response, ms
		OPT_t = 1 << 3, // timeout, ms
	};
	speed_t speed = 9600;
	int delay = -1;
	int timeout = -1;
	unsigned opts;

	// fetch options
	opt_complementary = "=1:s+:d+:t+"; // exactly one arg, numeric options
	opts = getopt32(argv, "Xs:d:t:", &speed, &delay, &timeout);
//	argc -= optind;
	argv += optind;

	// try to create lock file in /var/lock
	device_lock_file = (char *)bb_basename(argv[0]);
	device_lock_file = xasprintf("/var/lock/LCK..%s", device_lock_file);
	sfd = open(device_lock_file, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0644);
	if (sfd < 0) {
		// device already locked -> bail out
		if (errno == EEXIST)
			bb_perror_msg_and_die("can't create %s", device_lock_file);
		// can't create lock -> don't care
		if (ENABLE_FEATURE_CLEAN_UP)
			free(device_lock_file);
		device_lock_file = NULL;
	} else {
		// %4d to make concurrent mgetty (if any) happy.
		// Mgetty treats 4-bytes lock files as binary,
		// not text, PID. Making 5+ char file. Brrr...
		fdprintf(sfd, "%4d\n", getpid());
		close(sfd);
	}

	// setup signals
	bb_signals(0
		+ (1 << SIGHUP)
		+ (1 << SIGINT)
		+ (1 << SIGTERM)
		+ (1 << SIGPIPE)
		, signal_handler);

	// error exit code if we fail to open the device
	signalled = 1;

	// open device
	sfd = open_or_warn(argv[0], O_RDWR | O_NOCTTY | O_NONBLOCK);
	if (sfd < 0)
		goto done;
	fcntl(sfd, F_SETFL, 0);

	// put device to "raw mode"
	xget1(sfd, &tio, &tiosfd);
	// set device speed
	cfsetspeed(&tio, tty_value_to_baud(speed));
	if (xset1(sfd, &tio, argv[0]))
		goto done;

	// put stdin to "raw mode" (if stdin is a TTY),
	// handle one character at a time
	if (isatty(STDIN_FILENO)) {
		xget1(STDIN_FILENO, &tio, &tio0);
		if (xset1(STDIN_FILENO, &tio, "stdin"))
			goto done;
	}

	// main loop: check with poll(), then read/write bytes across
	pfd[0].fd = sfd;
	pfd[0].events = POLLIN;
	pfd[1].fd = STDIN_FILENO;
	pfd[1].events = POLLIN;

	signalled = 0;
	nfd = 2;
	while (!signalled && safe_poll(pfd, nfd, timeout) > 0) {
		if (nfd > 1 && pfd[1].revents) {
			char c;
			// read from stdin -> write to device
			if (safe_read(STDIN_FILENO, &c, 1) < 1) {
				// don't poll stdin anymore if we got EOF/error
				nfd--;
				goto skip_write;
			}
			// do we need special processing?
			if (!(opts & OPT_X)) {
				// ^@ sends Break
				if (VINTR == c) {
					tcsendbreak(sfd, 0);
					goto skip_write;
				}
				// ^X exits
				if (24 == c)
					break;
			}
			write(sfd, &c, 1);
			if (delay >= 0)
				safe_poll(pfd, 1, delay);
skip_write: ;
		}
		if (pfd[0].revents) {
#define iobuf bb_common_bufsiz1
			ssize_t len;
			// read from device -> write to stdout
			len = safe_read(sfd, iobuf, sizeof(iobuf));
			if (len > 0)
				full_write(STDOUT_FILENO, iobuf, len);
			else {
				// EOF/error -> bail out
				signalled = SIGHUP;
				break;
			}
		}
	}

	// restore device mode
	tcsetattr(sfd, TCSAFLUSH, &tiosfd);

	if (isatty(STDIN_FILENO))
		tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio0);

done:
	if (device_lock_file)
		unlink(device_lock_file);

	return signalled;
}
Exemplo n.º 13
0
	}
}

static int FAST_FUNC config_file_action(const char *filename,
					struct stat *statbuf UNUSED_PARAM,
					void *userdata UNUSED_PARAM,
					int depth)
{
	char *tokens[3];
	parser_t *p;
	struct module_entry *m;
	int rc = TRUE;
	const char *base, *ext;

	/* Skip files that begin with a "." */
	base = bb_basename(filename);
	if (base[0] == '.')
		goto error;

	/* "man modprobe.d" from kmod version 22 suggests
	 * that we shouldn't recurse into /etc/modprobe.d/dir/
	 * _subdirectories_:
	 */
	if (depth > 1)
		return SKIP; /* stop recursing */
//TODO: instead, can use dirAction in recursive_action() to SKIP dirs
//on depth == 1 level. But that's more code...

	/* In dir recursion, skip files that do not end with a ".conf"
	 * depth==0: read_config("modules.{symbols,alias}") must work,
	 * "include FILE_NOT_ENDING_IN_CONF" must work too.
Exemplo n.º 14
0
int microcom_main(int argc, char **argv)
{
	struct pollfd pfd[2];
#define sfd (pfd[1].fd)
	char *device_lock_file = NULL;
	const char *s;
	const char *opt_s = "9600";
	unsigned speed;
	int len;
	int exitcode = 1;
	struct termios tio0, tiosfd, tio;

	getopt32(argv, "s:", &opt_s);
	argc -= optind;
	argv += optind;
	if (!argv[0])
		bb_show_usage();
	speed = xatou(opt_s);

	// try to create lock file in /var/lock
	s = bb_basename(argv[0]);
	if (!s[0]) {
		errno = ENODEV;
		bb_perror_msg_and_die("can't lock device");
	}
	device_lock_file = xasprintf("/var/lock/LCK..%s", s);
	sfd = open(device_lock_file, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0644);
	if (sfd < 0) {
		if (ENABLE_FEATURE_CLEAN_UP)
			free(device_lock_file);
		device_lock_file = NULL;
		if (errno == EEXIST)
			bb_perror_msg_and_die("can't lock device");
		// We don't abort on other errors: /var/lock can be
		// non-writable or non-existent
	} else {
		// %4d to make mgetty happy. It treats 4-bytes lock files as binary,
		// not text, PID. Making 5+ char file. Brrr...
		s = xasprintf("%4d\n", getpid());
		write(sfd, s, strlen(s));
		if (ENABLE_FEATURE_CLEAN_UP)
			free((char*)s);
		close(sfd);
	}

	// open device
	sfd = open(argv[0], O_RDWR);
	if (sfd < 0) {
		bb_perror_msg("can't open device");
		goto unlock_and_exit;
	}

	// put stdin to "raw mode", handle one character at a time
	tcgetattr(STDIN_FILENO, &tio0);
	tio = tio0;
	tio.c_lflag &= ~(ICANON|ECHO);
	tio.c_iflag &= ~(IXON|ICRNL);
	tio.c_oflag &= ~(ONLCR);
	tio.c_cc[VMIN] = 1;
	tio.c_cc[VTIME] = 0;
	if (tcsetattr(STDIN_FILENO, TCSANOW, &tio)) {
		bb_perror_msg("can't tcsetattr for %s", "stdin");
		goto unlock_and_exit;
	}

	/* same thing for modem (plus: set baud rate) - TODO: make CLI option */
	tcgetattr(sfd, &tiosfd);
	tio = tiosfd;
	tio.c_lflag &= ~(ICANON|ECHO);
	tio.c_iflag &= ~(IXON|ICRNL);
	tio.c_oflag &= ~(ONLCR);
	tio.c_cc[VMIN] = 1;
	tio.c_cc[VTIME] = 0;
	cfsetispeed(&tio, tty_value_to_baud(speed));
	cfsetospeed(&tio, tty_value_to_baud(speed));
	if (tcsetattr(sfd, TCSANOW, &tio)) {
		bb_perror_msg("can't tcsetattr for %s", "device");
		goto unlock_and_exit;
	}

	// disable SIGINT
	signal(SIGINT, SIG_IGN);

	// drain stdin
	tcflush(STDIN_FILENO, TCIFLUSH);
	printf("connected to '%s' (%d bps), exit with ctrl-X...\r\n", argv[0], speed);

	// main loop: check with poll(), then read/write bytes across
	pfd[0].fd = STDIN_FILENO;
	pfd[0].events = POLLIN;
	/*pfd[1].fd = sfd;*/
	pfd[1].events = POLLIN;
	while (1) {
		int i;
		safe_poll(pfd, 2, -1);
		for (i = 0; i < 2; ++i) {
			if (pfd[i].revents & POLLIN) {
				len = read(pfd[i].fd, bb_common_bufsiz1, COMMON_BUFSIZE);
				if (len > 0) {
					if (!i && 24 == bb_common_bufsiz1[0])
						goto done; // ^X exits
					write(pfd[1-i].fd, bb_common_bufsiz1, len);
				}
			}
		}
	}
 done:
	tcsetattr(sfd, TCSANOW, &tiosfd);
	tcsetattr(STDIN_FILENO, TCSANOW, &tio0);
	tcflush(STDIN_FILENO, TCIFLUSH);

	if (ENABLE_FEATURE_CLEAN_UP)
		close(sfd);
	exitcode = 0;

 unlock_and_exit:
	// delete lock file
	if (device_lock_file) {
		unlink(device_lock_file);
		if (ENABLE_FEATURE_CLEAN_UP)
			free(device_lock_file);
	}
	return exitcode;
}
Exemplo n.º 15
0
/*
 * This function builds a list of dependency rules from /lib/modules/`uname -r`/modules.dep.
 * It then fills every modules and aliases with their default options, found by parsing
 * modprobe.conf (or modules.conf, or conf.modules).
 */
static struct dep_t *build_dep(void)
{
	int fd;
	struct utsname un;
	struct dep_t *first = NULL;
	struct dep_t *current = NULL;
	char *filename;
	int continuation_line = 0;
	int k_version;

	if (uname(&un))
		bb_error_msg_and_die("can't determine kernel version");

	k_version = 0;
	if (un.release[0] == '2') {
		k_version = un.release[2] - '0';
	}

	filename = xasprintf(CONFIG_DEFAULT_MODULES_DIR"/%s/"CONFIG_DEFAULT_DEPMOD_FILE, un.release);
	fd = open(filename, O_RDONLY);
	if (ENABLE_FEATURE_CLEAN_UP)
		free(filename);
	if (fd < 0) {
		/* Ok, that didn't work.  Fall back to looking in /lib/modules */
		fd = open(CONFIG_DEFAULT_MODULES_DIR"/"CONFIG_DEFAULT_DEPMOD_FILE, O_RDONLY);
		if (fd < 0) {
			bb_error_msg_and_die("cannot parse " CONFIG_DEFAULT_DEPMOD_FILE);
		}
	}

	while (reads(fd, line_buffer, sizeof(line_buffer))) {
		int l = strlen(line_buffer);
		char *p = 0;

		while (l > 0 && isspace(line_buffer[l-1])) {
			line_buffer[l-1] = '\0';
			l--;
		}

		if (l == 0) {
			continuation_line = 0;
			continue;
		}

		/* Is this a new module dep description? */
		if (!continuation_line) {
			/* find the dep beginning */
			char *col = strchr(line_buffer, ':');
			char *dot = col;

			if (col) {
				/* This line is a dep description */
				const char *mods;
				char *modpath;
				char *mod;

				/* Find the beginning of the module file name */
				*col = '\0';
				mods = bb_basename(line_buffer);

				/* find the path of the module */
				modpath = strchr(line_buffer, '/'); /* ... and this is the path */
				if (!modpath)
					modpath = line_buffer; /* module with no path */
				/* find the end of the module name in the file name */
				if (ENABLE_FEATURE_2_6_MODULES &&
				    (k_version > 4) && (col[-3] == '.') &&
				    (col[-2] == 'k') && (col[-1] == 'o'))
					dot = col - 3;
				else if ((col[-2] == '.') && (col[-1] == 'o'))
					dot = col - 2;

				mod = xstrndup(mods, dot - mods);

				/* enqueue new module */
				if (!current) {
					first = current = xzalloc(sizeof(struct dep_t));
				} else {
					current->m_next = xzalloc(sizeof(struct dep_t));
					current = current->m_next;
				}
				current->m_name = mod;
				current->m_path = xstrdup(modpath);
				/*current->m_options = NULL; - xzalloc did it*/
				/*current->m_isalias = 0;*/
				/*current->m_depcnt = 0;*/
				/*current->m_deparr = 0;*/
				/*current->m_next = 0;*/

				p = col + 1;
			} else
				/* this line is not a dep description */
				p = NULL;
		} else
			/* It's a dep description continuation */
			p = line_buffer;

		/* p points to the first dependable module; if NULL, no dependable module */
		if (p && (p = skip_whitespace(p))[0] != '\0') {
			char *end = &line_buffer[l-1];
			const char *deps;
			char *dep;
			char *next;
			int ext = 0;

			while (isblank(*end) || (*end == '\\'))
				end--;

			do {
				/* search the end of the dependency */
				next = strchr(p, ' ');
				if (next) {
					*next = '\0';
					next--;
				} else
					next = end;

				/* find the beginning of the module file name */
				deps = bb_basename(p);
				if (deps == p)
					deps = skip_whitespace(deps);

				/* find the end of the module name in the file name */
				if (ENABLE_FEATURE_2_6_MODULES
				 && (k_version > 4) && (next[-2] == '.')
				 && (next[-1] == 'k') && (next[0] == 'o'))
					ext = 3;
				else if ((next[-1] == '.') && (next[0] == 'o'))
					ext = 2;

				/* Cope with blank lines */
				if ((next-deps-ext+1) <= 0)
					continue;
				dep = xstrndup(deps, next - deps - ext + 1);

				/* Add the new dependable module name */
				current->m_depcnt++;
				current->m_deparr = xrealloc(current->m_deparr,
						sizeof(char *) * current->m_depcnt);
				current->m_deparr[current->m_depcnt - 1] = dep;

				p = next + 2;
			} while (next < end);
		}

		/* is there other dependable module(s) ? */
		continuation_line = (line_buffer[l-1] == '\\');
	} /* while (reads(...)) */
	close(fd);

	/*
	 * First parse system-specific options and aliases
	 * as they take precedence over the kernel ones.
	 * >=2.6: we only care about modprobe.conf
	 * <=2.4: we care about modules.conf and conf.modules
	 */
	if (ENABLE_FEATURE_2_6_MODULES
	 && (fd = open("/etc/modprobe.conf", O_RDONLY)) < 0)
		if (ENABLE_FEATURE_2_4_MODULES
		 && (fd = open("/etc/modules.conf", O_RDONLY)) < 0)
			if (ENABLE_FEATURE_2_4_MODULES)
				fd = open("/etc/conf.modules", O_RDONLY);

	if (fd >= 0) {
		include_conf(&first, &current, line_buffer, sizeof(line_buffer), fd);
		close(fd);
	}

	/* Only 2.6 has a modules.alias file */
	if (ENABLE_FEATURE_2_6_MODULES) {
		/* Parse kernel-declared module aliases */
		filename = xasprintf(CONFIG_DEFAULT_MODULES_DIR"/%s/modules.alias", un.release);
		fd = open(filename, O_RDONLY);
		if (fd < 0) {
			/* Ok, that didn't work.  Fall back to looking in /lib/modules */
			fd = open(CONFIG_DEFAULT_MODULES_DIR"/modules.alias", O_RDONLY);
		}
		if (ENABLE_FEATURE_CLEAN_UP)
			free(filename);

		if (fd >= 0) {
			include_conf(&first, &current, line_buffer, sizeof(line_buffer), fd);
			close(fd);
		}

		/* Parse kernel-declared symbol aliases */
		filename = xasprintf(CONFIG_DEFAULT_MODULES_DIR"/%s/modules.symbols", un.release);
		fd = open(filename, O_RDONLY);
		if (fd < 0) {
			/* Ok, that didn't work.  Fall back to looking in /lib/modules */
			fd = open(CONFIG_DEFAULT_MODULES_DIR"/modules.symbols", O_RDONLY);
		}
		if (ENABLE_FEATURE_CLEAN_UP)
			free(filename);

		if (fd >= 0) {
			include_conf(&first, &current, line_buffer, sizeof(line_buffer), fd);
			close(fd);
		}
	}

	return first;
}