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); }
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"); }
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")); }
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")); }
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")); }
void ionice_setup() { struct config_t* cfg = config(); if (cfg->ionice > 0) ioprio_set(IOPRIO_WHO_PROCESS, 0 /*getpid()*/, cfg->ionice); }
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); }
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."); } }
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; }
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)); }
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)); }
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", ×[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, §orsize); 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 */ }
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; }
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 */ }