Example #1
0
int
main(int argc, char **argv)
{
	long ioprio = DEFPRIO;
	int ch;
	char *ep;

	while ((ch = getopt(argc, argv, "n:")) != -1) {
		switch (ch) {
		case 'n':
			errno = 0;
			ioprio = strtol(optarg, &ep, 10);
			if (ep == optarg || *ep != '\0' || errno ||
			    ioprio < INT_MIN || ioprio > INT_MAX)
				errx(1, "%s: invalid ioprio value", optarg);
			break;
		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;

	if (argc == 0)
		usage();

	errno = 0;
	if (ioprio_set(PRIO_PROCESS, 0, (int)ioprio))
		warn("ioprio_set");
	execvp(*argv, argv);
	err(errno == ENOENT || errno == ENOTDIR ? 127 : 126, "%s", *argv);
}
Example #2
0
static void ioprio_setpid(pid_t pid, int ioprio, int ioclass)
{
	int ret = ioprio_set(ioprio_who_process, pid,
			     ioprio | ioclass << IOPRIO_CLASS_SHIFT);
	if (ret < 0)
		panic("Failed to set io prio for pid!\n");
}
Example #3
0
static void ioprio_setpid(pid_t pid, int ioclass, int data)
{
	int rc = ioprio_set(IOPRIO_WHO_PROCESS, pid,
			    IOPRIO_PRIO_VALUE(ioclass, data));

	if (rc == -1 && !tolerant)
		err(EXIT_FAILURE, _("ioprio_set failed"));
}
Example #4
0
static void ioprio_setid(int which, int ioclass, int data, int who)
{
	int rc = ioprio_set(who, which,
			    IOPRIO_PRIO_VALUE(ioclass, data));

	if (rc == -1 && !tolerant)
		err(EXIT_FAILURE, _("ioprio_set failed"));
}
Example #5
0
static void ioprio_setpid(pid_t pid, int ioprio, int ioclass)
{
	int rc = ioprio_set(IOPRIO_WHO_PROCESS, pid,
			ioprio | ioclass << IOPRIO_CLASS_SHIFT);

	if (rc == -1 && !tolerant)
		err(EXIT_FAILURE, _("ioprio_set failed"));
}
Example #6
0
void ionice_setup() {

	struct config_t* cfg = config();

	if (cfg->ionice > 0)
		ioprio_set(IOPRIO_WHO_PROCESS, 0 /*getpid()*/, cfg->ionice);

}
Example #7
0
static void
ioprio_set_idle()
{
  static constexpr int _IOPRIO_WHO_PROCESS = 1;
  static constexpr int _IOPRIO_CLASS_IDLE = 3;
  static constexpr int _IOPRIO_CLASS_SHIFT = 13;
  static constexpr int _IOPRIO_IDLE =
    (_IOPRIO_CLASS_IDLE << _IOPRIO_CLASS_SHIFT) | 7;

  ioprio_set(_IOPRIO_WHO_PROCESS, 0, _IOPRIO_IDLE);
}
Example #8
0
void
maximize_priority(void)
{
	if (skip_rt) {
		cl_log(LOG_INFO, "Not elevating to realtime (-R specified).");
		return;
	}

        sbd_make_realtime(0, 256, 256);

	if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(),
			IOPRIO_PRIO_VALUE(IOPRIO_CLASS_RT, 1)) != 0) {
		cl_perror("ioprio_set() call failed.");
	}
}
Example #9
0
void setIoPrio(int prio_class, int prio)
{
	if (prio_class < 0 || prio_class > 3)
	{
		eDebug("prio class(%d) out of valid range (0..3)", prio_class);
		return;
	}
	if (prio < 0 || prio > 7)
	{
		eDebug("prio level(%d) out of range (0..7)", prio);
		return;
	}
	if (ioprio_set(IOPRIO_WHO_PROCESS, 0 /*pid 0 .. current process*/, prio | prio_class << IOPRIO_CLASS_SHIFT) == -1)
		eDebug("setIoPrio failed (%m) !");
	else
		eDebug("setIoPrio %s level %d ok", to_prio[prio_class], prio);
}
/*
 * A wrapper around ioprio_set(); sets process I/O priority.
 * ioclass can be either IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE
 * or 0. iodata goes from 0 to 7 depending on ioclass specified.
 */
static PyObject*
linux_ioprio_set(PyObject* self, PyObject* args)
{
    long pid;
    int ioprio, ioclass, iodata;
    int retval;

    if (! PyArg_ParseTuple(args, "lii", &pid, &ioclass, &iodata)) {
        return NULL;
    }
    ioprio = IOPRIO_PRIO_VALUE(ioclass, iodata);
    retval = ioprio_set(IOPRIO_WHO_PROCESS, pid, ioprio);
    if (retval == -1) {
        return PyErr_SetFromErrno(PyExc_OSError);
    }
    Py_INCREF(Py_None);
    return Py_None;
}
Example #11
0
int main(int argc, char **argv)
{
	int devnull_fd = -1;
#ifdef TIOCNOTTY
	int tty_fd = -1;
#endif

#ifdef HAVE_PAM
	pam_handle_t *pamh = NULL;
	int pamr;
	const char *const *pamenv = NULL;
#endif

	int opt;
	bool start = false;
	bool stop = false;
	bool oknodo = false;
	bool test = false;
	char *exec = NULL;
	char *startas = NULL;
	char *name = NULL;
	char *pidfile = NULL;
	char *retry = NULL;
	int sig = -1;
	int nicelevel = 0, ionicec = -1, ioniced = 0;
	bool background = false;
	bool makepidfile = false;
	bool interpreted = false;
	bool progress = false;
	uid_t uid = 0;
	gid_t gid = 0;
	char *home = NULL;
	int tid = 0;
	char *redirect_stderr = NULL;
	char *redirect_stdout = NULL;
	int stdin_fd;
	int stdout_fd;
	int stderr_fd;
	pid_t pid, spid;
	int i;
	char *svcname = getenv("RC_SVCNAME");
	RC_STRINGLIST *env_list;
	RC_STRING *env;
	char *tmp, *newpath, *np;
	char *p;
	char *token;
	char exec_file[PATH_MAX];
	struct passwd *pw;
	struct group *gr;
	char line[130];
	FILE *fp;
	size_t len;
	mode_t numask = 022;
	char **margv;
	unsigned int start_wait = 0;

	applet = basename_c(argv[0]);
	TAILQ_INIT(&schedule);
#ifdef DEBUG_MEMORY
	atexit(cleanup);
#endif

	signal_setup(SIGINT, handle_signal);
	signal_setup(SIGQUIT, handle_signal);
	signal_setup(SIGTERM, handle_signal);

	if ((tmp = getenv("SSD_NICELEVEL")))
		if (sscanf(tmp, "%d", &nicelevel) != 1)
			eerror("%s: invalid nice level `%s' (SSD_NICELEVEL)",
			    applet, tmp);

	/* Get our user name and initial dir */
	p = getenv("USER");
	home = getenv("HOME");
	if (home == NULL || p == NULL) {
		pw = getpwuid(getuid());
		if (pw != NULL) {
			if (p == NULL)
				setenv("USER", pw->pw_name, 1);
			if (home == NULL) {
				setenv("HOME", pw->pw_dir, 1);
				home = pw->pw_dir;
			}
		}
	}

	while ((opt = getopt_long(argc, argv, getoptstring, longopts,
		    (int *) 0)) != -1)
		switch (opt) {
		case 'I': /* --ionice */
			if (sscanf(optarg, "%d:%d", &ionicec, &ioniced) == 0)
				eerrorx("%s: invalid ionice `%s'",
				    applet, optarg);
			if (ionicec == 0)
				ioniced = 0;
			else if (ionicec == 3)
				ioniced = 7;
			ionicec <<= 13; /* class shift */
			break;

		case 'K':  /* --stop */
			stop = true;
			break;

		case 'N':  /* --nice */
			if (sscanf(optarg, "%d", &nicelevel) != 1)
				eerrorx("%s: invalid nice level `%s'",
				    applet, optarg);
			break;

		case 'P':  /* --progress */
			progress = true;
			break;

		case 'R':  /* --retry <schedule>|<timeout> */
			retry = optarg;
			break;

		case 'S':  /* --start */
			start = true;
			break;

		case 'b':  /* --background */
			background = true;
			break;

		case 'c':  /* --chuid <username>|<uid> */
			/* DEPRECATED */
			ewarn("WARNING: -c/--chuid is deprecated and will be removed in the future, please use -u/--user instead");
		case 'u':  /* --user <username>|<uid> */
		{
			p = optarg;
			tmp = strsep(&p, ":");
			changeuser = xstrdup(tmp);
			if (sscanf(tmp, "%d", &tid) != 1)
				pw = getpwnam(tmp);
			else
				pw = getpwuid((uid_t)tid);

			if (pw == NULL)
				eerrorx("%s: user `%s' not found",
				    applet, tmp);
			uid = pw->pw_uid;
			home = pw->pw_dir;
			unsetenv("HOME");
			if (pw->pw_dir)
				setenv("HOME", pw->pw_dir, 1);
			unsetenv("USER");
			if (pw->pw_name)
				setenv("USER", pw->pw_name, 1);
			if (gid == 0)
				gid = pw->pw_gid;

			if (p) {
				tmp = strsep (&p, ":");
				if (sscanf(tmp, "%d", &tid) != 1)
					gr = getgrnam(tmp);
				else
					gr = getgrgid((gid_t) tid);

				if (gr == NULL)
					eerrorx("%s: group `%s'"
					    " not found",
					    applet, tmp);
				gid = gr->gr_gid;
			}
		}
		break;

		case 'd':  /* --chdir /new/dir */
			ch_dir = optarg;
			break;

		case 'e': /* --env */
			putenv(optarg);
			break;

		case 'g':  /* --group <group>|<gid> */
			if (sscanf(optarg, "%d", &tid) != 1)
				gr = getgrnam(optarg);
			else
				gr = getgrgid((gid_t)tid);
			if (gr == NULL)
				eerrorx("%s: group `%s' not found",
				    applet, optarg);
			gid = gr->gr_gid;
			break;

		case 'i': /* --interpreted */
			interpreted = true;
			break;

		case 'k':
			if (parse_mode(&numask, optarg))
				eerrorx("%s: invalid mode `%s'",
				    applet, optarg);
			break;

		case 'm':  /* --make-pidfile */
			makepidfile = true;
			break;

		case 'n':  /* --name <process-name> */
			name = optarg;
			break;

		case 'o':  /* --oknodo */
			/* DEPRECATED */
			ewarn("WARNING: -o/--oknodo is deprecated and will be removed in the future");
			oknodo = true;
			break;

		case 'p':  /* --pidfile <pid-file> */
			pidfile = optarg;
			break;

		case 's':  /* --signal <signal> */
			sig = parse_signal(optarg);
			break;

		case 't':  /* --test */
			test = true;
			break;

		case 'r':  /* --chroot /new/root */
			ch_root = optarg;
			break;

		case 'a': /* --startas <name> */
			/* DEPRECATED */
			ewarn("WARNING: -a/--startas is deprecated and will be removed in the future, please use -x/--exec or -n/--name instead");
			startas = optarg;
			break;
		case 'w':
			if (sscanf(optarg, "%d", &start_wait) != 1)
				eerrorx("%s: `%s' not a number",
				    applet, optarg);
			break;
		case 'x':  /* --exec <executable> */
			exec = optarg;
			break;

		case '1':   /* --stdout /path/to/stdout.lgfile */
			redirect_stdout = optarg;
			break;

		case '2':  /* --stderr /path/to/stderr.logfile */
			redirect_stderr = optarg;
			break;

		case_RC_COMMON_GETOPT
		}

	endpwent();
	argc -= optind;
	argv += optind;

	/* Allow start-stop-daemon --signal HUP --exec /usr/sbin/dnsmasq
	 * instead of forcing --stop --oknodo as well */
	if (!start &&
	    !stop &&
	    sig != SIGINT &&
	    sig != SIGTERM &&
	    sig != SIGQUIT &&
	    sig != SIGKILL)
		oknodo = true;

	if (!exec)
		exec = startas;
	else if (!name)
		name = startas;

	if (!exec) {
		exec = *argv;
		if (!exec)
			exec = name;
		if (name && start)
			*argv = name;
	} else if (name) {
		*--argv = name;
		++argc;
    } else if (exec) {
		*--argv = exec;
		++argc;
	};

	if (stop || sig != -1) {
		if (sig == -1)
			sig = SIGTERM;
		if (!*argv && !pidfile && !name && !uid)
			eerrorx("%s: --stop needs --exec, --pidfile,"
			    " --name or --user", applet);
		if (background)
			eerrorx("%s: --background is only relevant with"
			    " --start", applet);
		if (makepidfile)
			eerrorx("%s: --make-pidfile is only relevant with"
			    " --start", applet);
		if (redirect_stdout || redirect_stderr)
			eerrorx("%s: --stdout and --stderr are only relevant"
			    " with --start", applet);
	} else {
		if (!exec)
			eerrorx("%s: nothing to start", applet);
		if (makepidfile && !pidfile)
			eerrorx("%s: --make-pidfile is only relevant with"
			    " --pidfile", applet);
		if ((redirect_stdout || redirect_stderr) && !background)
			eerrorx("%s: --stdout and --stderr are only relevant"
			    " with --background", applet);
	}

	/* Expand ~ */
	if (ch_dir && *ch_dir == '~')
		ch_dir = expand_home(home, ch_dir);
	if (ch_root && *ch_root == '~')
		ch_root = expand_home(home, ch_root);
	if (exec) {
		if (*exec == '~')
			exec = expand_home(home, exec);

		/* Validate that the binary exists if we are starting */
		if (*exec == '/' || *exec == '.') {
			/* Full or relative path */
			if (ch_root)
				snprintf(exec_file, sizeof(exec_file),
				    "%s/%s", ch_root, exec);
			else
				snprintf(exec_file, sizeof(exec_file),
				    "%s", exec);
		} else {
			/* Something in $PATH */
			p = tmp = xstrdup(getenv("PATH"));
			*exec_file = '\0';
			while ((token = strsep(&p, ":"))) {
				if (ch_root)
					snprintf(exec_file, sizeof(exec_file),
					    "%s/%s/%s",
					    ch_root, token, exec);
				else
					snprintf(exec_file, sizeof(exec_file),
					    "%s/%s", token, exec);
				if (exists(exec_file))
					break;
				*exec_file = '\0';
			}
			free(tmp);
		}
	}
	if (start && !exists(exec_file)) {
		eerror("%s: %s does not exist", applet,
		    *exec_file ? exec_file : exec);
		exit(EXIT_FAILURE);
	}

	/* If we don't have a pidfile we should check if it's interpreted
	 * or not. If it we, we need to pass the interpreter through
	 * to our daemon calls to find it correctly. */
	if (interpreted && !pidfile) {
		fp = fopen(exec_file, "r");
		if (fp) {
			p = fgets(line, sizeof(line), fp);
			fclose(fp);
			if (p != NULL && line[0] == '#' && line[1] == '!') {
				p = line + 2;
				/* Strip leading spaces */
				while (*p == ' ' || *p == '\t')
					p++;
				/* Remove the trailing newline */
				len = strlen(p) - 1;
				if (p[len] == '\n')
					p[len] = '\0';
				token = strsep(&p, " ");
				strncpy(exec_file, token, sizeof(exec_file));
				opt = 0;
				for (nav = argv; *nav; nav++)
					opt++;
				nav = xmalloc(sizeof(char *) * (opt + 3));
				nav[0] = exec_file;
				len = 1;
				if (p)
					nav[len++] = p;
				for (i = 0; i < opt; i++)
					nav[i + len] = argv[i];
				nav[i + len] = '\0';
			}
		}
	}
	margv = nav ? nav : argv;

	if (stop || sig != -1) {
		if (sig == -1)
			sig = SIGTERM;
		if (!stop)
			oknodo = true;
		if (retry)
			parse_schedule(retry, sig);
		else if (test || oknodo)
			parse_schedule("0", sig);
		else
			parse_schedule(NULL, sig);
		i = run_stop_schedule(exec, (const char *const *)margv,
		    pidfile, uid, test, progress);

		if (i < 0)
			/* We failed to stop something */
			exit(EXIT_FAILURE);
		if (test || oknodo)
			return i > 0 ? EXIT_SUCCESS : EXIT_FAILURE;

		/* Even if we have not actually killed anything, we should
		 * remove information about it as it may have unexpectedly
		 * crashed out. We should also return success as the end
		 * result would be the same. */
		if (pidfile && exists(pidfile))
			unlink(pidfile);
		if (svcname)
			rc_service_daemon_set(svcname, exec,
			    (const char *const *)argv,
			    pidfile, false);
		exit(EXIT_SUCCESS);
	}

	if (pidfile)
		pid = get_pid(pidfile);
	else
		pid = 0;

	if (do_stop(exec, (const char * const *)margv, pid, uid,
		0, test) > 0)
		eerrorx("%s: %s is already running", applet, exec);

	if (test) {
		if (rc_yesno(getenv("EINFO_QUIET")))
			exit (EXIT_SUCCESS);

		einfon("Would start");
		while (argc-- > 0)
			printf(" %s", *argv++);
		printf("\n");
		eindent();
		if (uid != 0)
			einfo("as user id %d", uid);
		if (gid != 0)
			einfo("as group id %d", gid);
		if (ch_root)
			einfo("in root `%s'", ch_root);
		if (ch_dir)
			einfo("in dir `%s'", ch_dir);
		if (nicelevel != 0)
			einfo("with a priority of %d", nicelevel);
		if (name)
			einfo ("with a process name of %s", name);
		eoutdent();
		exit(EXIT_SUCCESS);
	}

	ebeginv("Detaching to start `%s'", exec);
	eindentv();

	/* Remove existing pidfile */
	if (pidfile)
		unlink(pidfile);

	if (background)
		signal_setup(SIGCHLD, handle_signal);

	if ((pid = fork()) == -1)
		eerrorx("%s: fork: %s", applet, strerror(errno));

	/* Child process - lets go! */
	if (pid == 0) {
		pid_t mypid = getpid();
		umask(numask);

#ifdef TIOCNOTTY
		tty_fd = open("/dev/tty", O_RDWR);
#endif

		devnull_fd = open("/dev/null", O_RDWR);

		if (nicelevel) {
			if (setpriority(PRIO_PROCESS, mypid, nicelevel) == -1)
				eerrorx("%s: setpritory %d: %s",
				    applet, nicelevel,
				    strerror(errno));
		}

		if (ionicec != -1 &&
		    ioprio_set(1, mypid, ionicec | ioniced) == -1)
			eerrorx("%s: ioprio_set %d %d: %s", applet,
			    ionicec, ioniced, strerror(errno));

		if (ch_root && chroot(ch_root) < 0)
			eerrorx("%s: chroot `%s': %s",
			    applet, ch_root, strerror(errno));

		if (ch_dir && chdir(ch_dir) < 0)
			eerrorx("%s: chdir `%s': %s",
			    applet, ch_dir, strerror(errno));

		if (makepidfile && pidfile) {
			fp = fopen(pidfile, "w");
			if (! fp)
				eerrorx("%s: fopen `%s': %s", applet, pidfile,
				    strerror(errno));
			fprintf(fp, "%d\n", mypid);
			fclose(fp);
		}

#ifdef HAVE_PAM
		if (changeuser != NULL) {
			pamr = pam_start("start-stop-daemon",
			    changeuser, &conv, &pamh);

			if (pamr == PAM_SUCCESS)
				pamr = pam_acct_mgmt(pamh, PAM_SILENT);
			if (pamr == PAM_SUCCESS)
				pamr = pam_open_session(pamh, PAM_SILENT);
			if (pamr != PAM_SUCCESS)
				eerrorx("%s: pam error: %s",
					applet, pam_strerror(pamh, pamr));
		}
#endif

		if (gid && setgid(gid))
			eerrorx("%s: unable to set groupid to %d",
			    applet, gid);
		if (changeuser && initgroups(changeuser, gid))
			eerrorx("%s: initgroups (%s, %d)",
			    applet, changeuser, gid);
		if (uid && setuid(uid))
			eerrorx ("%s: unable to set userid to %d",
			    applet, uid);

		/* Close any fd's to the passwd database */
		endpwent();

#ifdef TIOCNOTTY
		ioctl(tty_fd, TIOCNOTTY, 0);
		close(tty_fd);
#endif

		/* Clean the environment of any RC_ variables */
		env_list = rc_stringlist_new();
		i = 0;
		while (environ[i])
			rc_stringlist_add(env_list, environ[i++]);

#ifdef HAVE_PAM
		if (changeuser != NULL) {
			pamenv = (const char *const *)pam_getenvlist(pamh);
			if (pamenv) {
				while (*pamenv) {
					/* Don't add strings unless they set a var */
					if (strchr(*pamenv, '='))
						putenv(xstrdup(*pamenv));
					else
						unsetenv(*pamenv);
					pamenv++;
				}
			}
		}
#endif

		TAILQ_FOREACH(env, env_list, entries) {
			if ((strncmp(env->value, "RC_", 3) == 0 &&
				strncmp(env->value, "RC_SERVICE=", 10) != 0 &&
				strncmp(env->value, "RC_SVCNAME=", 10) != 0) ||
			    strncmp(env->value, "SSD_NICELEVEL=", 14) == 0)
			{
				p = strchr(env->value, '=');
				*p = '\0';
				unsetenv(env->value);
				continue;
			}
		}
		rc_stringlist_free(env_list);

		/* For the path, remove the rcscript bin dir from it */
		if ((token = getenv("PATH"))) {
			len = strlen(token);
			newpath = np = xmalloc(len + 1);
			while (token && *token) {
				p = strchr(token, ':');
				if (p) {
					*p++ = '\0';
					while (*p == ':')
						p++;
				}
				if (strcmp(token, RC_LIBEXECDIR "/bin") != 0 &&
				    strcmp(token, RC_LIBEXECDIR "/sbin") != 0)
				{
					len = strlen(token);
					if (np != newpath)
						*np++ = ':';
					memcpy(np, token, len);
					np += len;
				}
				token = p;
			}
			*np = '\0';
			unsetenv("PATH");
			setenv("PATH", newpath, 1);
		}

		stdin_fd = devnull_fd;
		stdout_fd = devnull_fd;
		stderr_fd = devnull_fd;
		if (redirect_stdout) {
			if ((stdout_fd = open(redirect_stdout,
				    O_WRONLY | O_CREAT | O_APPEND,
				    S_IRUSR | S_IWUSR)) == -1)
				eerrorx("%s: unable to open the logfile"
				    " for stdout `%s': %s",
				    applet, redirect_stdout, strerror(errno));
		}
		if (redirect_stderr) {
			if ((stderr_fd = open(redirect_stderr,
				    O_WRONLY | O_CREAT | O_APPEND,
				    S_IRUSR | S_IWUSR)) == -1)
				eerrorx("%s: unable to open the logfile"
				    " for stderr `%s': %s",
				    applet, redirect_stderr, strerror(errno));
		}

		if (background)
			dup2(stdin_fd, STDIN_FILENO);
		if (background || redirect_stdout || rc_yesno(getenv("EINFO_QUIET")))
			dup2(stdout_fd, STDOUT_FILENO);
		if (background || redirect_stderr || rc_yesno(getenv("EINFO_QUIET")))
			dup2(stderr_fd, STDERR_FILENO);

		for (i = getdtablesize() - 1; i >= 3; --i)
			close(i);

		setsid();
		execvp(exec, argv);
#ifdef HAVE_PAM
		if (changeuser != NULL && pamr == PAM_SUCCESS)
			pam_close_session(pamh, PAM_SILENT);
#endif
		eerrorx("%s: failed to exec `%s': %s",
		    applet, exec,strerror(errno));
	}
Example #12
0
static void child_process(char *exec, char **argv)
{
	RC_STRINGLIST *env_list;
	RC_STRING *env;
	int i;
	char *p;
	char *token;
	size_t len;
	char *newpath;
	char *np;
	char **c;
	char cmdline[PATH_MAX];

#ifdef HAVE_PAM
	pam_handle_t *pamh = NULL;
	int pamr;
	const char *const *pamenv = NULL;
#endif

	setsid();

	if (nicelevel) {
		if (setpriority(PRIO_PROCESS, getpid(), nicelevel) == -1)
			eerrorx("%s: setpriority %d: %s", applet, nicelevel,
					strerror(errno));
	}

	if (ionicec != -1 && ioprio_set(1, getpid(), ionicec | ioniced) == -1)
		eerrorx("%s: ioprio_set %d %d: %s", applet, ionicec, ioniced,
				strerror(errno));

	if (ch_root && chroot(ch_root) < 0)
		eerrorx("%s: chroot `%s': %s", applet, ch_root, strerror(errno));

	if (ch_dir && chdir(ch_dir) < 0)
		eerrorx("%s: chdir `%s': %s", applet, ch_dir, strerror(errno));

#ifdef HAVE_PAM
	if (changeuser != NULL) {
		pamr = pam_start("supervise-daemon",
		    changeuser, &conv, &pamh);

		if (pamr == PAM_SUCCESS)
			pamr = pam_acct_mgmt(pamh, PAM_SILENT);
		if (pamr == PAM_SUCCESS)
			pamr = pam_open_session(pamh, PAM_SILENT);
		if (pamr != PAM_SUCCESS)
			eerrorx("%s: pam error: %s", applet, pam_strerror(pamh, pamr));
	}
#endif

	if (gid && setgid(gid))
		eerrorx("%s: unable to set groupid to %d", applet, gid);
	if (changeuser && initgroups(changeuser, gid))
		eerrorx("%s: initgroups (%s, %d)", applet, changeuser, gid);
	if (uid && setuid(uid))
		eerrorx ("%s: unable to set userid to %d", applet, uid);

	/* Close any fd's to the passwd database */
	endpwent();

#ifdef TIOCNOTTY
	ioctl(tty_fd, TIOCNOTTY, 0);
	close(tty_fd);
#endif

	/* Clean the environment of any RC_ variables */
	env_list = rc_stringlist_new();
	i = 0;
	while (environ[i])
		rc_stringlist_add(env_list, environ[i++]);

#ifdef HAVE_PAM
	if (changeuser != NULL) {
		pamenv = (const char *const *)pam_getenvlist(pamh);
		if (pamenv) {
			while (*pamenv) {
				/* Don't add strings unless they set a var */
				if (strchr(*pamenv, '='))
					putenv(xstrdup(*pamenv));
				else
					unsetenv(*pamenv);
				pamenv++;
			}
		}
	}
#endif

	TAILQ_FOREACH(env, env_list, entries) {
		if ((strncmp(env->value, "RC_", 3) == 0 &&
			strncmp(env->value, "RC_SERVICE=", 10) != 0 &&
			strncmp(env->value, "RC_SVCNAME=", 10) != 0) ||
		    strncmp(env->value, "SSD_NICELEVEL=", 14) == 0)
		{
			p = strchr(env->value, '=');
			*p = '\0';
			unsetenv(env->value);
			continue;
		}
	}
	rc_stringlist_free(env_list);

	/* For the path, remove the rcscript bin dir from it */
	if ((token = getenv("PATH"))) {
		len = strlen(token);
		newpath = np = xmalloc(len + 1);
		while (token && *token) {
			p = strchr(token, ':');
			if (p) {
				*p++ = '\0';
				while (*p == ':')
					p++;
			}
			if (strcmp(token, RC_LIBEXECDIR "/bin") != 0 &&
			    strcmp(token, RC_LIBEXECDIR "/sbin") != 0)
			{
				len = strlen(token);
				if (np != newpath)
					*np++ = ':';
				memcpy(np, token, len);
				np += len;
				}
			token = p;
		}
		*np = '\0';
		unsetenv("PATH");
		setenv("PATH", newpath, 1);
	}

	stdin_fd = devnull_fd;
	stdout_fd = devnull_fd;
	stderr_fd = devnull_fd;
	if (redirect_stdout) {
		if ((stdout_fd = open(redirect_stdout,
			    O_WRONLY | O_CREAT | O_APPEND,
			    S_IRUSR | S_IWUSR)) == -1)
			eerrorx("%s: unable to open the logfile"
				    " for stdout `%s': %s",
				    applet, redirect_stdout, strerror(errno));
	}
	if (redirect_stderr) {
		if ((stderr_fd = open(redirect_stderr,
			    O_WRONLY | O_CREAT | O_APPEND,
			    S_IRUSR | S_IWUSR)) == -1)
			eerrorx("%s: unable to open the logfile"
			    " for stderr `%s': %s",
			    applet, redirect_stderr, strerror(errno));
	}

	dup2(stdin_fd, STDIN_FILENO);
	if (redirect_stdout || rc_yesno(getenv("EINFO_QUIET")))
		dup2(stdout_fd, STDOUT_FILENO);
	if (redirect_stderr || rc_yesno(getenv("EINFO_QUIET")))
		dup2(stderr_fd, STDERR_FILENO);

	for (i = getdtablesize() - 1; i >= 3; --i)
		close(i);

	*cmdline = '\0';
	c = argv;
	while (*c) {
		strcat(cmdline, *c);
		strcat(cmdline, " ");
		c++;
	}
	syslog(LOG_INFO, "Running command line: %s", cmdline);
	execvp(exec, argv);

#ifdef HAVE_PAM
	if (changeuser != NULL && pamr == PAM_SUCCESS)
		pam_close_session(pamh, PAM_SILENT);
#endif
	eerrorx("%s: failed to exec `%s': %s", applet, exec,strerror(errno));
}
Example #13
0
int main(int argc, char **argv)
{
	char *buffer;
	int i, c, retval, groupcount, groupsize;
	uint32_t sectorsize;
	uint64_t numblocks;
	off64_t offset;
	struct timespec rqtp;
	float rands[RANDNUM], times[RANDNUM];
	char *devname = NULL;

	/* Allocate buffer aligned in memory */
	if (posix_memalign((void **) &buffer, sysconf(_SC_PAGESIZE), sizeof(char)*2*BLOCKNUM)) {
		printf("Failed to posix_memalign buffer size.\n");
		exit(EXIT_FAILURE);
	}

	out[0] = inp[0] = '\0';

	while (1) {
		int option_index = 0;
		
		c = getopt_long(argc, argv, "w:dhvp:i:o:c:t:s:S:P:Z:", long_options,
						&option_index);
		if (c == -1)
			break;
		
		switch (c) {
			case 'w': /* -w or --workload */
				if (!strcmp(optarg,"RAND") || !strcmp(optarg,"0"))
					workload = RANDWKLD;
				else if (!strcmp(optarg,"SEQL") || !strcmp(optarg,"1"))
					workload = SEQLWKLD;
				else if (!strcmp(optarg,"SCRUB") || !strcmp(optarg,"2"))
					workload = SCRUBDEV;
				else if (!strcmp(optarg,"CACHE") || !strcmp(optarg,"3"))
					workload = TESTCACHE;
				break;
			case 'c': /* -c or --count */
				maxcount = atoi(optarg);
				if (maxcount < 0) {
					fprintf(stderr, "bad argument to '--count'\n");
					exit(EXIT_FAILURE);
				}
				break;
			case 't': /* -t or --runtime */
				runtime = atoi(optarg);
				if (runtime < 0) {
					fprintf(stderr, "bad argument to '--runtime'\n");
					exit(EXIT_FAILURE);
				}
				break;
			case 'd': /* -d or --direct */
				direct = 1;
				break;
			case 'h': /* -h or --help */
			case '?':
				usage();
				exit(EXIT_SUCCESS);
			case 'v': /* -v or --verbose */
				++verbose;
				break;
			case 'p': /* -p or --priority */
				if (!strcmp(optarg,"IDLE") || !strcmp(optarg,"0"))
					priority = IDLEPRIO;
				else if (!strcmp(optarg,"DEF") || !strcmp(optarg,"1"))
					priority = DEFPRIO;
				else if (!strcmp(optarg,"RT") || !strcmp(optarg,"2"))
					priority = RTPRIO;
				break;
			case 'i': /* -i or --input */
				if (optarg == NULL) {
					fprintf(stderr, "bad argument to '--input'\n");
					exit(EXIT_FAILURE);
				}
				strcpy(inp, optarg);
				break;
			case 'o': /* -o or --output */
				if (optarg == NULL) {
					fprintf(stderr, "bad argument to '--output'\n");
					exit(EXIT_FAILURE);
				}
				strcpy(out, optarg);
				break;
			case 's': /* -s or --seed */
				seed = atoi(optarg);
				if (seed < 0) {
					fprintf(stderr, "bad argument to '--seed'\n");
					exit(EXIT_FAILURE);
				}
				break;
			case 'S': /* -S or --sectors */
				sectorcount = (uint64_t) atoi(optarg);
				break;
			case 'P': /* -P or --start */
				sectorstart = (uint64_t) atoi(optarg);
				break;
			case 'Z': /* -Z or --thinktime */
				thinkprob = atof(optarg);
				if (thinkprob < 0.0) {
					fprintf(stderr, "bad argument to '--thinktime'\n");
					exit(EXIT_FAILURE);
				}
				break;
			default:
				fprintf(stderr, "unrecognised option code 0x%x ??\n", c);
				usage();
				exit(EXIT_FAILURE);
		}
	}

	if (optind < argc) {
		if (NULL == devname) {
			devname = argv[optind];
			++optind;
		}
		if (optind < argc) {
			for (; optind < argc; ++optind)
				fprintf(stderr, "Unexpected extra argument: %s\n", argv[optind]);
			usage();
			exit(EXIT_FAILURE);
		}
	}

	if (devname == NULL) {
		fprintf(stderr, "no device specified\n");
		usage();
		exit(EXIT_FAILURE);
	}

	/* Set the seed to a specific value */
	srand(seed);

	/* Set the I/O scheduling class and priority for the scrubber */
	if (priority == IDLEPRIO) {
		retval = ioprio_set(IOPRIO_WHO_PROCESS, (int) getpid(),
				IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE,0));
		handle("ioprio_set", retval < 0);
	} else if (priority == RTPRIO) {
		retval = ioprio_set(IOPRIO_WHO_PROCESS, (int) getpid(),
				IOPRIO_PRIO_VALUE(IOPRIO_CLASS_RT,0));
		handle("ioprio_set", retval < 0);
	}

	setvbuf(stdout, NULL, _IONBF, 0);

	if (inp[0] != '\0') {
		inpf = fopen(inp, "r");
		if (inpf == NULL) {
			fprintf(stderr, "failed to open input file '%s'\n", inp);
			exit(EXIT_FAILURE);
		}
	}

	if (out[0] != '\0') {
		outf = fopen(out, "w");
		if (outf == NULL) {
			fprintf(stderr, "failed to open output file '%s'\n", out);
			exit(EXIT_FAILURE);
		}
	}

	if (inpf != NULL) {
		for (num=0; num<RANDNUM; num++)
			fscanf(inpf, "%f", &times[num]);
	} /* else {
		for (num=0; num<RANDNUM; num++)
			times[num] = rand() / (float) RAND_MAX;
	} */

	if (direct)
		dev = open(devname, O_RDONLY|O_DIRECT);
	else
		dev = open(devname, O_RDONLY);
	handle("open", dev < 0);

	/* Retrieve device's size in *sectors* */
	retval = ioctl(dev, BLKGETSIZE, &numblocks);
	handle("ioctl (devsize)", retval == -1);
	if (sectorcount && (sectorstart + sectorcount) < numblocks)
		numblocks = sectorcount;

	/* Retrieve sector size in *bytes* -- most probably 512b */
	retval = ioctl(dev, BLKSSZGET, &sectorsize);
	handle("ioctl (sector)", retval == -1);

	/* Convert number of blocks to number of *requests* */
	numblocks = numblocks / (BLOCKNUM / sectorsize);
	//fprintf(stderr, "Number of blocks = %lu (sector = %u)\n", numblocks, sectorsize);
	handle("numblocks <= 0", numblocks <= 0);

	if (verbose)
		printf("Benchmarking %s [%luMB], press Ctrl-C to terminate.\n",
		       devname, numblocks * BLOCKNUM / (1024*1024));

	/* Start timing program execution */
	gettimeofday(&start, NULL);
	//signal(SIGALRM, &update);
	signal(SIGINT, &done);
	//alarm(1);

	num = 0;
	offset = 0;
	total = 0.0;

	/* Group count and size for CLUST workload */
	groupcount = 0;
	//groupsize = (int) (50 * (rand() / (float) RAND_MAX));
	groupsize = (int) 128;

	/* lap0 and lap1 make sure think time is included when recording */
	lap0.tv_sec = start.tv_sec;
	lap0.tv_usec = start.tv_usec;

	if (workload == TESTCACHE) {
		/* Test whether the cache is on */
		struct timeval ra, rb;
		int k;
		long double total1 = 0.0, total2 = 0.0;

		for (k = 0; k < 16384; k++)
			retval = segread(dev, buffer, sysconf(_SC_PAGESIZE),
					k * sysconf(_SC_PAGESIZE), 1, 0);

		for (k = 0; k < 50; k++) {
			retval = segread(dev, buffer, sysconf(_SC_PAGESIZE),
					testblks[k], 1, 1);
			testtimes1[k] = timediff(ra, rb);
			total1 += testtimes1[k];
		}

		for (k = 0; k < 50; k++) {
			retval = segread(dev, buffer, sysconf(_SC_PAGESIZE),
					testblks[k] + sysconf(_SC_PAGESIZE), 1, 1);
			testtimes2[k] = timediff(ra, rb);
			total2 += testtimes2[k];
		}

		for (k = 0; k < 50; k++) {
			fprintf(stdout, "Sector: %lu -- Self=%Lf, Next=%Lf\n",
				testblks[k], testtimes1[k], testtimes2[k]);
		}

		total1 /= 50.0;
		total2 /= 50.0;
		fprintf(stdout, "\nAverage:: Self=%Lf, Next=%Lf\n", total1, total2);
	} else {
		for (;;) {
			long delay;

			/* Only enter this code block when you're about to think */
			if (thinkprob && (rand() / (float) RAND_MAX) <= thinkprob) {
				//gettimeofday(&lap1, NULL);
				rqtp.tv_sec = 0;
				/* Introduce a delay analogous to the disk's rotational latency */
				delay = times[num++] * 10000000;
				if (num >= 199990) num = 0;
				if (delay >= 1000000000)
					rqtp.tv_nsec = 999999999;
				else
					rqtp.tv_nsec = delay;
				//if (VERBOSE)
				//	printf("Delaying work for %ld.\n", rqtp.tv_nsec);
				//total += timediff(lap0, lap1);
				nanosleep(&rqtp,NULL);
				//gettimeofday(&lap0, NULL);
			}

			/* If the workload is RAND, then choose the next sector in a uniform random manner */
			if (workload == RANDWKLD)
				offset = (off64_t) (numblocks * (rand() / (float) RAND_MAX));
			/* If the workload is CLUST, choose next consequent sector or pick a random one if
			   the group has been read */
			else if (workload == SEQLWKLD) {
				if (groupcount == groupsize) {
					offset = (off64_t) (numblocks * (rand() / (float) RAND_MAX));
					//groupsize = (int) (50 * (rand() / (float) RAND_MAX));
					groupcount = 0;
				} else groupcount++;
			}

			/* Convert offset from request no. to *bytes* and issue the read() */
			retval = segread(dev, buffer, BLOCKNUM, offset * BLOCKNUM, direct, 1);

			/* Keep the output in bytes as well, for readability */
			if (outf != NULL)
				/* fprintf(outf, "%lu\t%Lf\n", offset * BLOCKNUM, timediff(reqa, reqb)); */
				fprintf(outf, "%Lf\n", timediff(reqa, reqb));
			totaltime += timediff(reqa, reqb);

			handle("segread", retval < 0);
			if ((maxcount && count >= maxcount) || (num >= RANDNUM-3))
				done();
			count++;

			if (workload == SEQLWKLD || workload == SCRUBDEV)
				offset = (off64_t) (offset + 1) % numblocks;
		}
	}
	/* notreached */
}
Example #14
0
static int replay(const char *root) {
        _cleanup_close_ int inotify_fd = -1;
        _cleanup_free_ char *pack_fn = NULL;
        _cleanup_fclose_ FILE *pack = NULL;
        bool on_ssd, ready = false;
        char line[LINE_MAX];
        int prio, c;

        assert(root);

        if (asprintf(&pack_fn, "%s/.readahead", root) < 0)
                return log_oom();

        pack = fopen(pack_fn, "re");
        if (!pack) {
                if (errno == ENOENT) {
                        log_debug("No pack file found.");
                        return 0;
                }

                log_error("Failed to open pack file: %m");
                return -errno;
        }

        posix_fadvise(fileno(pack), 0, 0, POSIX_FADV_WILLNEED);

        inotify_fd = open_inotify();
        if (inotify_fd < 0)
                return inotify_fd;

        if (!fgets(line, sizeof(line), pack)) {
                log_error("Premature end of pack file.");
                return -EIO;
        }

        char_array_0(line);

        if (!streq(line, CANONICAL_HOST READAHEAD_PACK_FILE_VERSION)) {
                log_debug("Pack file host or version type mismatch.");
                goto done;
        }

        c = getc(pack);
        if (c == EOF) {
                log_debug("Premature end of pack file.");
                return -EIO;
        }

        /* We do not retest SSD here, so that we can start replaying
         * before udev is up.*/
        on_ssd = c == 'S';
        log_debug("On SSD: %s", yes_no(on_ssd));

        if (on_ssd)
                prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0);
        else
                /* We are not using RT here, since we'd starve IO that
                we didn't record (which is for example blkid, since
                its disk accesses go directly to the block device and
                are thus not visible in fallocate) to death. However,
                we do ask for an IO prio that is slightly higher than
                the default (which is BE. 4) */
                prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 2);

        if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), prio) < 0)
                log_warning("Failed to set IDLE IO priority class: %m");

        sd_notify(0, "STATUS=Replaying readahead data");

        log_debug("Replaying...");

        if (access("/run/systemd/readahead/noreplay", F_OK) >= 0) {
                log_debug("Got termination request");
                goto done;
        }

        while (!feof(pack) && !ferror(pack)) {
                uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX];
                int k;
                ssize_t n;

                n = read(inotify_fd, &inotify_buffer, sizeof(inotify_buffer));
                if (n < 0) {
                        if (errno != EINTR && errno != EAGAIN) {
                                log_error("Failed to read inotify event: %m");
                                return -errno;
                        }
                } else {
                        struct inotify_event *e = (struct inotify_event*) inotify_buffer;

                        while (n > 0) {
                                size_t step;

                                if ((e->mask & IN_CREATE) && streq(e->name, "noreplay")) {
                                        log_debug("Got termination request");
                                        goto done;
                                }

                                step = sizeof(struct inotify_event) + e->len;
                                assert(step <= (size_t) n);

                                e = (struct inotify_event*) ((uint8_t*) e + step);
                                n -= step;
                        }
                }

                k = unpack_file(pack);
                if (k < 0)
                        return k;

                if (!ready) {
                        /* We delay the ready notification until we
                         * queued at least one read */
                        sd_notify(0, "READY=1");
                        ready = true;
                }
        }

done:
        if (ferror(pack)) {
                log_error("Failed to read pack file.");
                return -EIO;
        }

        if (!ready)
                sd_notify(0, "READY=1");

        log_debug("Done.");
        return 0;
}
Example #15
0
CAMLprim value netsys_ioprio_set(value target, value ioprio_arg) {
#ifdef ioprio_supported
    int ioprio;
    int ioprio_class;
    int ioprio_data;
    int sysres;

    if (Is_block(ioprio_arg)) {
	switch (Tag_val(ioprio_arg)) {
	case 0:
	    ioprio_class = IOPRIO_CLASS_RT;
	    ioprio_data = Int_val(Field(ioprio_arg, 0));
	    break;
	case 1:
	    ioprio_class = IOPRIO_CLASS_BE;
	    ioprio_data = Int_val(Field(ioprio_arg, 0));
	    break;
	default:
	    failwith("netsys_ioprio_set: internal error");
	}
    } else {
	switch (Long_val(ioprio_arg)) {
	case 0:
	    /* Makes no sense. We behave in the same way as ionice */
	    ioprio_class = IOPRIO_CLASS_BE;
	    ioprio_data = 4;
	    break;
	case 1:
	    ioprio_class = IOPRIO_CLASS_IDLE;
	    ioprio_data = 7;
	    break;
	default:
	    failwith("netsys_ioprio_set: internal error");
	}
    };

    ioprio = (ioprio_class << IOPRIO_CLASS_SHIFT) | (ioprio_data & IOPRIO_PRIO_MASK);

    switch (Tag_val(target)) {
    case 0:
	sysres = ioprio_set(IOPRIO_WHO_PROCESS, Int_val(Field(target, 0)), ioprio);
	break;
    case 1:
	sysres = ioprio_set(IOPRIO_WHO_PGRP, Int_val(Field(target, 0)), ioprio);
	break;
    case 2:
	sysres = ioprio_set(IOPRIO_WHO_USER, Int_val(Field(target, 0)), ioprio);
	break;
    default:
	failwith("netsys_ioprio_set: internal error");
    }

    if (sysres == -1)
	uerror("ioprio_set", Nothing);

    return Val_unit;
#else
    /* not ioprio_supported: */
    unix_error(ENOSYS, "ioprio_set", Nothing);
#endif
    /* ioprio_supported */
}