Example #1
0
int spawn_and_wait(char **argv)
{
	int rc;
#if ENABLE_FEATURE_PREFER_APPLETS
	const struct bb_applet *a = find_applet_by_name(argv[0]);

	if (a && (a->nofork
#if BB_MMU
		 || a->noexec /* NOEXEC trick needs fork() */
#endif
	)) {
#if BB_MMU
		if (a->nofork)
#endif
		{
			return run_nofork_applet(a, argv);
		}
#if BB_MMU
		/* MMU only */
		/* a->noexec is true */
		rc = fork();
		if (rc) /* parent or error */
			return wait4pid(rc);
		/* child */
		xfunc_error_retval = EXIT_FAILURE;
		current_applet = a;
		run_current_applet_and_exit(argv);
#endif
	}
#endif /* FEATURE_PREFER_APPLETS */
	rc = spawn(argv);
	return wait4pid(rc);
}
int FAST_FUNC spawn_and_wait(char **argv)
{
	int rc;
#if ENABLE_FEATURE_PREFER_APPLETS
	int a = find_applet_by_name(argv[0]);

	if (a >= 0 && (APPLET_IS_NOFORK(a)
# if BB_MMU
	               || APPLET_IS_NOEXEC(a) /* NOEXEC trick needs fork() */
# endif
	              )) {
# if BB_MMU
		if (APPLET_IS_NOFORK(a))
# endif
		{
			return run_nofork_applet(a, argv);
		}
# if BB_MMU
		/* MMU only */
		/* a->noexec is true */
		rc = fork();
		if (rc) /* parent or error */
			return wait4pid(rc);
		/* child */
		xfunc_error_retval = EXIT_FAILURE;
		run_applet_no_and_exit(a, argv);
# endif
	}
#endif /* FEATURE_PREFER_APPLETS */
	rc = spawn(argv);
	return wait4pid(rc);
}
Example #3
0
static void edit_file(const struct passwd *pas, const char *file)
{
	const char *ptr;
	pid_t pid;

	pid = xvfork();
	if (pid) { /* parent */
		wait4pid(pid);
		return;
	}

	/* CHILD - change user and run editor */
	/* initgroups, setgid, setuid */
	change_identity(pas);
	setup_environment(pas->pw_shell,
			SETUP_ENV_CHANGEENV | SETUP_ENV_TO_TMP,
			pas);
	ptr = getenv("VISUAL");
	if (!ptr) {
		ptr = getenv("EDITOR");
		if (!ptr)
			ptr = "vi";
	}

	BB_EXECLP(ptr, ptr, file, NULL);
	bb_perror_msg_and_die("can't execute '%s'", ptr);
}
Example #4
0
/**
 * Run a script.
 * argv[0]:intf argv[1]:script_name argv[2]:junk argv[3]:NULL
 */
static int run(char *argv[3], const char *param, struct in_addr *ip)
{
	int status;
	char *addr = addr; /* for gcc */
	const char *fmt = "%s %s %s" + 3;

	argv[2] = (char*)param;

	VDBG("%s run %s %s\n", argv[0], argv[1], argv[2]);

	if (ip) {
		addr = inet_ntoa(*ip);
		xsetenv("ip", addr);
		fmt -= 3;
	}
	bb_info_msg(fmt, argv[2], argv[0], addr);

	status = wait4pid(spawn(argv + 1));
	if (status < 0) {
		bb_perror_msg("%s %s %s" + 3, argv[2], argv[0]);
		return -errno;
	}
	if (status != 0)
		bb_error_msg("script %s %s failed, exitcode=%d", argv[1], argv[2], status);
	return status;
}
Example #5
0
static int open_as_user(const struct passwd *pas, const char *file)
{
	pid_t pid;
	char c;

	pid = xvfork();
	if (pid) { /* PARENT */
		if (wait4pid(pid) == 0) {
			/* exitcode 0: child says it can read */
			return open(file, O_RDONLY);
		}
		return -1;
	}

	/* CHILD */
	/* initgroups, setgid, setuid */
	change_identity(pas);
	/* We just try to read one byte. If it works, file is readable
	 * under this user. We signal that by exiting with 0. */
	_exit(safe_read(xopen(file, O_RDONLY), &c, 1) < 0);
}
Example #6
0
static void edit_file(const struct passwd *pas, const char *file)
{
	const char *ptr;
	int pid = vfork();

	if (pid < 0) /* failure */
		bb_perror_msg_and_die("vfork");
	if (pid) { /* parent */
		wait4pid(pid);
		return;
	}

	/* CHILD - change user and run editor */
	change_user(pas);
	ptr = getenv("VISUAL");
	if (!ptr) {
		ptr = getenv("EDITOR");
		if (!ptr)
			ptr = "vi";
	}

	BB_EXECLP(ptr, ptr, file, NULL);
	bb_perror_msg_and_die("exec %s", ptr);
}
Example #7
0
/* Call a script with a par file and env vars */
void FAST_FUNC udhcp_run_script(struct dhcp_packet *packet, const char *name)
{
	char **envp, **curr;
	char *argv[3];

	if (client_config.script == NULL)
		return;

	envp = fill_envp(packet);

	/* call script */
	log1("Executing %s", client_config.script);
	argv[0] = (char*) client_config.script;
	argv[1] = (char*) name;
	argv[2] = NULL;
	wait4pid(spawn(argv));

	for (curr = envp; *curr; curr++) {
		log2(" %s", *curr);
		bb_unsetenv(*curr);
		free(*curr);
	}
	free(envp);
}
Example #8
0
static int parse(const char *boundary, char **argv)
{
	char *line, *s, *p;
	const char *type;
	int boundary_len = strlen(boundary);
	const char *delims = " ;\"\t\r\n";
	const char *uniq;
	int ntokens;
	const char *tokens[32]; // 32 is enough

	// prepare unique string pattern
	uniq = xasprintf("%%llu.%u.%s", (unsigned)getpid(), safe_gethostname());

//bb_info_msg("PARSE[%s]", terminator);

	while ((line = xmalloc_fgets_str(stdin, "\r\n\r\n")) != NULL) {

		// seek to start of MIME section
		// N.B. to avoid false positives let us seek to the _last_ occurance
		p = NULL;
		s = line;
		while ((s=strcasestr(s, "Content-Type:")) != NULL)
			p = s++;
		if (!p)
			goto next;
//bb_info_msg("L[%s]", p);

		// split to tokens
		// TODO: strip of comments which are of form: (comment-text)
		ntokens = 0;
		tokens[ntokens] = NULL;
		for (s = strtok(p, delims); s; s = strtok(NULL, delims)) {
			tokens[ntokens] = s;
			if (ntokens < ARRAY_SIZE(tokens) - 1)
				ntokens++;
//bb_info_msg("L[%d][%s]", ntokens, s);
		}
		tokens[ntokens] = NULL;
//bb_info_msg("N[%d]", ntokens);

		// analyse tokens
		type = find_token(tokens, "Content-Type:", "text/plain");
//bb_info_msg("T[%s]", type);
		if (0 == strncasecmp(type, "multipart/", 10)) {
			if (0 == strcasecmp(type+10, "mixed")) {
				parse(xfind_token(tokens, "boundary="), argv);
			} else
				bb_error_msg_and_die("no support of content type '%s'", type);
		} else {
			pid_t pid = pid;
			int rc;
			FILE *fp;
			// fetch charset
			const char *charset = find_token(tokens, "charset=", CONFIG_FEATURE_MIME_CHARSET);
			// fetch encoding
			const char *encoding = find_token(tokens, "Content-Transfer-Encoding:", "7bit");
			// compose target filename
			char *filename = (char *)find_token(tokens, "filename=", NULL);
			if (!filename)
				filename = xasprintf(uniq, monotonic_us());
			else
				filename = bb_get_last_path_component_strip(xstrdup(filename));

			// start external helper, if any
			if (opts & OPT_X) {
				int fd[2];
				xpipe(fd);
				pid = vfork();
				if (0 == pid) {
					// child reads from fd[0]
					xdup2(fd[0], STDIN_FILENO);
					close(fd[0]); close(fd[1]);
					xsetenv("CONTENT_TYPE", type);
					xsetenv("CHARSET", charset);
					xsetenv("ENCODING", encoding);
					xsetenv("FILENAME", filename);
					BB_EXECVP(*argv, argv);
					_exit(EXIT_FAILURE);
				}
				// parent dumps to fd[1]
				close(fd[0]);
				fp = fdopen(fd[1], "w");
				signal(SIGPIPE, SIG_IGN); // ignore EPIPE
			// or create a file for dump
			} else {
				char *fname = xasprintf("%s%s", *argv, filename);
				fp = xfopen_for_write(fname);
				free(fname);
			}

			// housekeeping
			free(filename);

			// dump to fp
			if (0 == strcasecmp(encoding, "base64")) {
				decode_base64(stdin, fp);
			} else if (0 != strcasecmp(encoding, "7bit")
				&& 0 != strcasecmp(encoding, "8bit")) {
				// quoted-printable, binary, user-defined are unsupported so far
				bb_error_msg_and_die("no support of encoding '%s'", encoding);
			} else {
				// N.B. we have written redundant \n. so truncate the file
				// The following weird 2-tacts reading technique is due to
				// we have to not write extra \n at the end of the file
				// In case of -x option we could truncate the resulting file as
				// fseek(fp, -1, SEEK_END);
				// if (ftruncate(fileno(fp), ftell(fp)))
				//	bb_perror_msg("ftruncate");
				// But in case of -X we have to be much more careful. There is
				// no means to truncate what we already have sent to the helper.
				p = xmalloc_fgets_str(stdin, "\r\n");
				while (p) {
					if ((s = xmalloc_fgets_str(stdin, "\r\n")) == NULL)
						break;
					if ('-' == s[0] && '-' == s[1]
						&& 0 == strncmp(s+2, boundary, boundary_len))
						break;
					fputs(p, fp);
					p = s;
				}

/*
				while ((s = xmalloc_fgetline_str(stdin, "\r\n")) != NULL) {
					if ('-' == s[0] && '-' == s[1]
						&& 0 == strncmp(s+2, boundary, boundary_len))
						break;
					fprintf(fp, "%s\n", s);
				}
				// N.B. we have written redundant \n. so truncate the file
				fseek(fp, -1, SEEK_END);
				if (ftruncate(fileno(fp), ftell(fp)))
					bb_perror_msg("ftruncate");
*/
			}
			fclose(fp);

			// finalize helper
			if (opts & OPT_X) {
				signal(SIGPIPE, SIG_DFL);
				// exit if helper exited >0
				rc = wait4pid(pid);
				if (rc)
					return rc+20;
			}

			// check multipart finalized
			if (s && '-' == s[2+boundary_len] && '-' == s[2+boundary_len+1]) {
				free(line);
				break;
			}
		}
 next:
 		free(line);
	}

//bb_info_msg("ENDPARSE[%s]", boundary);

	return EXIT_SUCCESS;
}
Example #9
0
int
do_aspawn(SV* really, SV **mark, SV **sp)
{
 char   **a,
        *tmps;
 struct inheritance inherit;
 pid_t  pid;
 int    status,
        fd,
        nFd,
        fdMap[3];
 SV     *sv,
        **p_sv;
 STRLEN	n_a;

    status = FAIL;
    if (sp > mark)
    {
       Newx(PL_Argv, sp - mark + 1, char*);
       a = PL_Argv;
       while (++mark <= sp)
       {
           if (*mark)
              *a++ = SvPVx(*mark, n_a);
           else
              *a++ = "";
       }
       inherit.flags        = SPAWN_SETGROUP;
       inherit.pgroup       = SPAWN_NEWPGROUP;
       fdMap[STDIN_FILENO]  = Perl_stdin_fd;
       fdMap[STDOUT_FILENO] = Perl_stdout_fd;
       fdMap[STDERR_FILENO] = STDERR_FILENO;
       nFd                  = 3;
       *a = NULL;
       /*-----------------------------------------------------*/
       /* Will execvp() use PATH?                             */
       /*-----------------------------------------------------*/
       if (*PL_Argv[0] != '/')
           TAINT_ENV();
       if (really && *(tmps = SvPV(really, n_a)))
           pid = spawnp(tmps, nFd, fdMap, &inherit,
                        (const char **) PL_Argv,
                        (const char **) environ);
       else
           pid = spawnp(PL_Argv[0], nFd, fdMap, &inherit,
                        (const char **) PL_Argv,
                        (const char **) environ);
       if (pid < 0)
       {
          status = FAIL;
          if (ckWARN(WARN_EXEC))
             warner(WARN_EXEC,"Can't exec \"%s\": %s",
                    PL_Argv[0],
                    Strerror(errno));
       }
       else
       {
          /*------------------------------------------------*/
          /* If the file descriptors have been remapped then*/
          /* we've been called following a my_popen request */
          /* therefore we don't want to wait for spawnned   */
          /* program to complete. We need to set the fdpid  */
          /* value to the value of the spawnned process' pid*/
          /*------------------------------------------------*/
          fd = 0;
          if (Perl_stdin_fd != STDIN_FILENO)
             fd = Perl_stdin_fd;
          else
             if (Perl_stdout_fd != STDOUT_FILENO)
                fd = Perl_stdout_fd;
          if (fd != 0)
          {
             /*---------------------------------------------*/
             /* Get the fd of the other end of the pipe,    */
             /* use this to reference the fdpid which will  */
             /* be used by my_pclose                        */
             /*---------------------------------------------*/
             close(fd);
             MUTEX_LOCK(&PL_fdpid_mutex);
             p_sv  = av_fetch(PL_fdpid,fd,TRUE);
             fd    = (int) SvIVX(*p_sv);
             SvREFCNT_dec(*p_sv);
             *p_sv = &PL_sv_undef;
             sv    = *av_fetch(PL_fdpid,fd,TRUE);
             MUTEX_UNLOCK(&PL_fdpid_mutex);
             (void) SvUPGRADE(sv, SVt_IV);
             SvIVX(sv) = pid;
             status    = 0;
          }
          else
             wait4pid(pid, &status, 0);
       }
       do_execfree();
    }
Example #10
0
static int mod_process ( struct mod_list_t *list, int do_insert )
{
	int rc = 0;
	char **argv = NULL;
	struct mod_opt_t *opts;
	int argc_malloc; /* never used when CONFIG_FEATURE_CLEAN_UP not defined */
	int argc;

	while ( list ) {
		argc = 0;
		if( ENABLE_FEATURE_CLEAN_UP )
			argc_malloc = 0;
		/* If CONFIG_FEATURE_CLEAN_UP is not defined, then we leak memory
		 * each time we allocate memory for argv.
		 * But it is (quite) small amounts of memory that leak each
		 * time a module is loaded,  and it is reclaimed when modprobe
		 * exits anyway (even when standalone shell?).
		 * This could become a problem when loading a module with LOTS of
		 * dependencies, with LOTS of options for each dependencies, with
		 * very little memory on the target... But in that case, the module
		 * would not load because there is no more memory, so there's no
		 * problem. */
		/* enough for minimal insmod (5 args + NULL) or rmmod (3 args + NULL) */
		argv = (char**) malloc( 6 * sizeof( char* ) );
		if ( do_insert ) {
			if (already_loaded (list->m_name) != 1) {
				argv[argc++] = "insmod";
				if (ENABLE_FEATURE_2_4_MODULES) {
					if (do_syslog)
						argv[argc++] = "-s";
					if (autoclean)
						argv[argc++] = "-k";
					if (quiet)
						argv[argc++] = "-q";
					else if(verbose) /* verbose and quiet are mutually exclusive */
						argv[argc++] = "-v";
				}
				argv[argc++] = list-> m_path;
				if( ENABLE_FEATURE_CLEAN_UP )
					argc_malloc = argc;
				opts = list-> m_options;
				while( opts ) {
					/* Add one more option */
					argc++;
					argv = (char**) xrealloc( argv, ( argc + 1 ) * sizeof( char* ) );
					argv[argc-1] = opts-> m_opt_val;
					opts = opts-> m_next;
				}
			}
		} else {
			/* modutils uses short name for removal */
			if (already_loaded (list->m_name) != 0) {
				argv[argc++] = "rmmod";
				if (do_syslog)
					argv[argc++] = "-s";
				argv[argc++] = list->m_name;
				if( ENABLE_FEATURE_CLEAN_UP )
					argc_malloc = argc;
			}
		}
		argv[argc] = NULL;

		if (argc) {
			if (verbose) {
				printf("%s module %s\n", do_insert?"Loading":"Unloading", list-> m_name );
			}
			if (!show_only) {
				int rc2 = wait4pid(bb_spawn(argv));

				if (do_insert) {
					rc = rc2; /* only last module matters */
				}
				else if (!rc2) {
					rc = 0; /* success if remove any mod */
				}
			}
			if( ENABLE_FEATURE_CLEAN_UP )
				/* the last value in the array has index == argc, but
				 * it is the terminating NULL, so we must not free it. */
				while( argc_malloc < argc ) {
					free( argv[argc_malloc++] );
			}
		}
		if( ENABLE_FEATURE_CLEAN_UP ) {
			free( argv );
			argv = NULL;
		}
		list = do_insert ? list-> m_prev : list-> m_next;
	}
	return (show_only) ? 0 : rc;
}
Example #11
0
int inotifyd_main(int argc UNUSED_PARAM, char **argv)
{
	int n;
	unsigned mask = IN_ALL_EVENTS; // assume we want all events
	struct pollfd pfd;
	char **watched = ++argv; // watched name list
	const char *args[] = { *argv, NULL, NULL, NULL, NULL };

	// sanity check: agent and at least one watch must be given
	if (!argv[1])
		bb_show_usage();

	// open inotify
	pfd.fd = inotify_init();
	if (pfd.fd < 0)
		bb_perror_msg_and_die("no kernel support");

	// setup watched
	while (*++argv) {
		char *path = *argv;
		char *masks = strchr(path, ':');
		// if mask is specified ->
		if (masks) {
			*masks = '\0'; // split path and mask
			// convert mask names to mask bitset
			mask = 0;
			while (*++masks) {
				int i = strchr(mask_names, *masks) - mask_names;
				if (i >= 0) {
					mask |= (1 << i);
				}
			}
		}
		// add watch
		n = inotify_add_watch(pfd.fd, path, mask);
		if (n < 0)
			bb_perror_msg_and_die("add watch (%s) failed", path);
		//bb_error_msg("added %d [%s]:%4X", n, path, mask);
	}

	// setup signals
	bb_signals(BB_FATAL_SIGS, record_signo);

	// do watch
	pfd.events = POLLIN;
	while (1) {
		ssize_t len;
		void *buf;
		struct inotify_event *ie;

 again:
		if (bb_got_signal)
			break;
		n = poll(&pfd, 1, -1);
		/* Signal interrupted us? */
		if (n < 0 && errno == EINTR)
			goto again;
		// Under Linux, above if() is not necessary.
		// Non-fatal signals, e.g. SIGCHLD, when set to SIG_DFL,
		// are not interrupting poll().
		// Thus we can just break if n <= 0 (see below),
		// because EINTR will happen only on SIGTERM et al.
		// But this might be not true under other Unixes,
		// and is generally way too subtle to depend on.
		if (n <= 0) // strange error?
			break;

		// read out all pending events
		xioctl(pfd.fd, FIONREAD, &len);
#define eventbuf bb_common_bufsiz1
		ie = buf = (len <= sizeof(eventbuf)) ? eventbuf : xmalloc(len);
		len = full_read(pfd.fd, buf, len);
		// process events. N.B. events may vary in length
		while (len > 0) {
			int i;
			char events[sizeof(mask_names)];
			char *s = events;
			unsigned m = ie->mask;

			for (i = 0; i < sizeof(mask_names)-1; ++i, m >>= 1) {
				if (m & 1)
					*s++ = mask_names[i];
			}
			*s = '\0';
			//bb_error_msg("exec %s %08X\t%s\t%s\t%s", agent,
			// ie->mask, events, watched[ie->wd], ie->len ? ie->name : "");
			args[1] = events;
			args[2] = watched[ie->wd];
			args[3] = ie->len ? ie->name : NULL;
			wait4pid(xspawn((char **)args));
			// next event
			i = sizeof(struct inotify_event) + ie->len;
			len -= i;
			ie = (void*)((char*)ie + i);
		}
		if (eventbuf != buf)
			free(buf);
	}

	return EXIT_SUCCESS;
}
Example #12
0
int run_parts_main(int argc, char **argv)
{
	const char *umask_p = "22";
	llist_t *arg_list = NULL;
	unsigned n;
	int ret;

#if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS
	applet_long_options = runparts_longopts;
#endif
	/* We require exactly one argument: the directory name */
	opt_complementary = "=1:a::";
	getopt32(argv, "a:u:t"USE_FEATURE_RUN_PARTS_FANCY("l"), &arg_list, &umask_p);

	umask(xstrtou_range(umask_p, 8, 0, 07777));

	n = 1;
	while (arg_list && n < NUM_CMD) {
		cmd[n] = arg_list->data;
		arg_list = arg_list->link;
		n++;
	}
	/* cmd[n] = NULL; - is already zeroed out */

	/* run-parts has to sort executables by name before running them */

	recursive_action(argv[optind],
			ACTION_RECURSE|ACTION_FOLLOWLINKS,
			act,            /* file action */
			act,            /* dir action */
			NULL,           /* user data */
			1               /* depth */
		);

	if (!names)
		return 0;

	qsort(names, cur, sizeof(char *), bb_alphasort);

	n = 0;
	while (1) {
		char *name = *names++;
		if (!name)
			break;
		if (option_mask32 & (RUN_PARTS_OPT_t | RUN_PARTS_OPT_l)) {
			puts(name);
			continue;
		}
		cmd[0] = name;
		ret = wait4pid(spawn(cmd));
		if (ret == 0)
			continue;
		n = 1;
		if (ret < 0)
			bb_perror_msg("failed to exec %s", name);
		else /* ret > 0 */
			bb_error_msg("%s exited with return code %d", name, ret);
	}

	return n;
}
static int run_script(const char *action)
{
    char *argv[5];
    int r;

    bb_error_msg("executing '%s %s %s'", G.script_name, G.iface, action);

#if 1

    argv[0] = (char*) G.script_name;
    argv[1] = (char*) G.iface;
    argv[2] = (char*) action;
    argv[3] = (char*) G.extra_arg;
    argv[4] = NULL;

    /* r < 0 - can't exec, 0 <= r < 1000 - exited, >1000 - killed by sig (r-1000) */
    r = wait4pid(spawn(argv));

    bb_error_msg("exit code: %d", r);
    return (option_mask32 & FLAG_IGNORE_RETVAL) ? 0 : r;

#else /* insanity */

    struct fd_pair pipe_pair;
    char buf[256];
    int i = 0;

    xpiped_pair(pipe_pair);

    pid = vfork();
    if (pid < 0) {
        bb_perror_msg("fork");
        return -1;
    }

    /* child */
    if (pid == 0) {
        xmove_fd(pipe_pair.wr, 1);
        xdup2(1, 2);
        if (pipe_pair.rd > 2)
            close(pipe_pair.rd);

        // umask(0022); // Set up a sane umask

        execlp(G.script_name, G.script_name, G.iface, action, G.extra_arg, NULL);
        _exit(EXIT_FAILURE);
    }

    /* parent */
    close(pipe_pair.wr);

    while (1) {
        if (bb_got_signal && bb_got_signal != SIGCHLD) {
            bb_error_msg("killing child");
            kill(pid, SIGTERM);
            bb_got_signal = 0;
            break;
        }

        r = read(pipe_pair.rd, &buf[i], 1);

        if (buf[i] == '\n' || i == sizeof(buf)-2 || r != 1) {
            if (r == 1 && buf[i] != '\n')
                i++;

            buf[i] = '\0';

            if (i > 0)
                bb_error_msg("client: %s", buf);

            i = 0;
        } else {
            i++;
        }

        if (r != 1)
            break;
    }

    close(pipe_pair.rd);

    wait(&r);

    if (!WIFEXITED(r) || WEXITSTATUS(r) != 0) {
        bb_error_msg("program execution failed, return value is %i",
                     WEXITSTATUS(r));
        return option_mask32 & FLAG_IGNORE_RETVAL ? 0 : WEXITSTATUS(r);
    }
    bb_error_msg("program executed successfully");
    return 0;
#endif
}