Fix #45: add support for rlimit per service/run/task/inetd/tty

This patch extends the existing rlimit implementation to support setting
limits per service, run/task, inetd, and tty.

Use rlimit in /etc/finit.conf to change the global setting, which is
then inherited to each /etc/finit.d/*.conf.  For each .conf file the
rlimit is reinitialized to the global finit.conf settings.

Also, add `unlimited` keyword, to replace the now deprecated `infinity`
keyword.  The latter is however kept, for compatibility with previous
releases, for the foreseeable future.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
This commit is contained in:
Joachim Nilsson
2017-11-26 16:35:37 +01:00
parent 44007c86f2
commit b68c5c1291
12 changed files with 154 additions and 76 deletions
+7 -4
View File
@@ -51,12 +51,15 @@ Syntax
* `network <PATH>` * `network <PATH>`
Script or program to bring up networking, with optional arguments Script or program to bring up networking, with optional arguments
* `rlimit <hard|soft> RESOURCE <LIMIT|infinity>` * `rlimit <hard|soft> RESOURCE <LIMIT|unlimited>`
Set the hard or soft limit for a resource. `RESOURCE` is a lower-case Set the hard or soft limit for a resource. `RESOURCE` is a lower-case
string matching the `RLIMIT_` constants from `setrlimit(2)`, without string matching the `RLIMIT_` constants from `setrlimit(2)`, without
the prefix. E.g. to set `RLIMIT_CPU`, use `cpu`. The limit is an the prefix. E.g. to set `RLIMIT_CPU`, use `cpu`.
integer that depends on the resource being modified, see the man page
for more information. The special limit `infinity` means unlimited. The limit is an integer that depends on the resource being modified,
see the man page, or the kernel `/proc/PID/limits` file, for more
information. Finit versions before v3.1 used `infinity` for
`unlimited`, which is still a supported keyword.
```shell ```shell
# No process is allowed more than 8MB of address space # No process is allowed more than 8MB of address space
+2 -1
View File
@@ -29,6 +29,7 @@
#include "helpers.h" #include "helpers.h"
#include "plugin.h" #include "plugin.h"
#include "service.h" #include "service.h"
#include "conf.h"
#define DAEMON "dbus-daemon" #define DAEMON "dbus-daemon"
#define ARGS "--nofork --system" #define ARGS "--nofork --system"
@@ -58,7 +59,7 @@ static void setup(void *arg)
/* Register service with Finit */ /* Register service with Finit */
snprintf(line, sizeof(line), "[S12345] %s %s -- %s", cmd, ARGS, DESC); snprintf(line, sizeof(line), "[S12345] %s %s -- %s", cmd, ARGS, DESC);
if (service_register(SVC_TYPE_SERVICE, line, NULL)) if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
_pe("Failed registering %s", DAEMON); _pe("Failed registering %s", DAEMON);
free(cmd); free(cmd);
+87 -49
View File
@@ -38,6 +38,7 @@
#define MATCH_CMD(l, c, x) \ #define MATCH_CMD(l, c, x) \
(!strncasecmp(l, c, strlen(c)) && (x = (l) + strlen(c))) (!strncasecmp(l, c, strlen(c)) && (x = (l) + strlen(c)))
struct rlimit global_rlimit[RLIMIT_NLIMITS];
static int parse_conf(char *file); static int parse_conf(char *file);
@@ -163,59 +164,74 @@ static const struct rlimit_name rlimit_names[] = {
{ NULL, 0 } { NULL, 0 }
}; };
void conf_parse_rlimit(char *line) int str2rlim(char *str)
{ {
struct rlimit rlim; const struct rlimit_name *rn;
rlim_t cfg, *set;
const struct rlimit_name *name; for (rn = rlimit_names; rn->name; rn++) {
if (!strcmp(str, rn->name))
return rn->val;
}
return -1;
}
char *rlim2str(int rlim)
{
const struct rlimit_name *rn;
for (rn = rlimit_names; rn->name; rn++) {
if (rn->val == rlim)
return rn->name;
}
return "unknown";
}
void conf_parse_rlimit(char *line, struct rlimit arr[])
{
char *level, *limit, *val;
int resource = -1; int resource = -1;
rlim_t cfg, *set;
char *tok = strtok(line, " \t"); level = strtok(line, " \t");
if (!level)
goto error;
if (tok && !strcmp(tok, "soft")) limit = strtok(NULL, " \t");
set = &rlim.rlim_cur; if (!limit)
else if (tok && !strcmp(tok, "hard")) goto error;
set = &rlim.rlim_max;
resource = str2rlim(limit);
if (resource < 0 || resource > RLIMIT_NLIMITS)
goto error;
val = strtok(NULL, " \t");
if (!val)
goto error;
if (!strcmp(level, "soft"))
set = &arr[resource].rlim_cur;
else if (!strcmp(level, "hard"))
set = &arr[resource].rlim_max;
else else
goto error; goto error;
tok = strtok(NULL, " \t"); /* Official keyword from v3.1 is `unlimited`, from prlimit(1) */
if (!tok) if (!strcmp(val, "unlimited") || !strcmp(val, "infinity")) {
goto error;
for (name = rlimit_names; name->name; name++) {
if (!strcmp(tok, name->name))
resource = name->val;
}
if (resource < 0)
goto fail;
tok = strtok(NULL, " \t");
if (!tok)
goto fail;
if (!strcmp(tok, "infinity")) {
cfg = RLIM_INFINITY; cfg = RLIM_INFINITY;
} else { } else {
const char *err = NULL; const char *err = NULL;
cfg = strtonum(tok, 0, (long long)2 << 31, &err); cfg = strtonum(val, 0, (long long)2 << 31, &err);
if (err) if (err) {
goto fail; logit(LOG_WARNING, "rlimit: invalid %s value: %s",
rlim2str(resource), val);
return;
}
} }
if (getrlimit(resource, &rlim))
goto fail;
*set = cfg; *set = cfg;
if (setrlimit(resource, &rlim))
goto fail;
return;
fail:
logit(LOG_WARNING, "rlimit: Failed setting rlimit %s", name->name ? : "unknown");
return; return;
error: error:
logit(LOG_WARNING, "rlimit: parse error"); logit(LOG_WARNING, "rlimit: parse error");
@@ -289,7 +305,7 @@ static void parse_static(char *line)
} }
} }
static void parse_dynamic(char *line, struct timeval *mtime) static void parse_dynamic(char *line, struct rlimit rlimit[], struct timeval *mtime)
{ {
char *x; char *x;
char cmd[CMD_SIZE]; char cmd[CMD_SIZE];
@@ -315,26 +331,26 @@ static void parse_dynamic(char *line, struct timeval *mtime)
/* Monitored daemon, will be respawned on exit */ /* Monitored daemon, will be respawned on exit */
if (MATCH_CMD(line, "service ", x)) { if (MATCH_CMD(line, "service ", x)) {
service_register(SVC_TYPE_SERVICE, x, mtime); service_register(SVC_TYPE_SERVICE, x, rlimit, mtime);
return; return;
} }
/* One-shot task, will not be respawned */ /* One-shot task, will not be respawned */
if (MATCH_CMD(line, "task ", x)) { if (MATCH_CMD(line, "task ", x)) {
service_register(SVC_TYPE_TASK, x, mtime); service_register(SVC_TYPE_TASK, x, rlimit, mtime);
return; return;
} }
/* Like task but waits for completion, useful w/ [S] */ /* Like task but waits for completion, useful w/ [S] */
if (MATCH_CMD(line, "run ", x)) { if (MATCH_CMD(line, "run ", x)) {
service_register(SVC_TYPE_RUN, x, mtime); service_register(SVC_TYPE_RUN, x, rlimit, mtime);
return; return;
} }
/* Classic inetd service */ /* Classic inetd service */
if (MATCH_CMD(line, "inetd ", x)) { if (MATCH_CMD(line, "inetd ", x)) {
#ifdef INETD_ENABLED #ifdef INETD_ENABLED
service_register(SVC_TYPE_INETD, x, mtime); service_register(SVC_TYPE_INETD, x, rlimit, mtime);
#else #else
_e("Finit built with inetd support disabled, cannot register service inetd %s!", x); _e("Finit built with inetd support disabled, cannot register service inetd %s!", x);
#endif #endif
@@ -343,13 +359,13 @@ static void parse_dynamic(char *line, struct timeval *mtime)
/* Read resource limits */ /* Read resource limits */
if (MATCH_CMD(line, "rlimit ", x)) { if (MATCH_CMD(line, "rlimit ", x)) {
conf_parse_rlimit(x); conf_parse_rlimit(x, rlimit);
return; return;
} }
/* Regular or serial TTYs to run getty */ /* Regular or serial TTYs to run getty */
if (MATCH_CMD(line, "tty ", x)) { if (MATCH_CMD(line, "tty ", x)) {
tty_register(strip_line(x), mtime); tty_register(strip_line(x), rlimit, mtime);
return; return;
} }
} }
@@ -368,6 +384,7 @@ static void tabstospaces(char *line)
static int parse_conf_dynamic(char *file, struct timeval *mtime) static int parse_conf_dynamic(char *file, struct timeval *mtime)
{ {
FILE *fp; FILE *fp;
struct rlimit rlimit[RLIMIT_NLIMITS];
fp = fopen(file, "r"); fp = fopen(file, "r");
if (!fp) { if (!fp) {
@@ -375,6 +392,9 @@ static int parse_conf_dynamic(char *file, struct timeval *mtime)
return 1; return 1;
} }
/* Prepare default limits for each service */
memcpy(rlimit, global_rlimit, sizeof(rlimit));
_d("Parsing %s", file); _d("Parsing %s", file);
while (!feof(fp)) { while (!feof(fp)) {
char line[LINE_SIZE] = ""; char line[LINE_SIZE] = "";
@@ -386,7 +406,7 @@ static int parse_conf_dynamic(char *file, struct timeval *mtime)
tabstospaces(line); tabstospaces(line);
_d("%s", line); _d("%s", line);
parse_dynamic(line, mtime); parse_dynamic(line, rlimit, mtime);
} }
fclose(fp); fclose(fp);
@@ -394,11 +414,19 @@ static int parse_conf_dynamic(char *file, struct timeval *mtime)
return 0; return 0;
} }
/* Reads /etc/finit.conf, once at boot */
static int parse_conf(char *file) static int parse_conf(char *file)
{ {
FILE *fp; FILE *fp;
char line[LINE_SIZE] = ""; char line[LINE_SIZE] = "";
char *x;
/*
* Get current global limits, which may be overridden from both
* finit.conf, for Finit and its services like inetd+getty, and
* *.conf in finit.d/, for each service(s) listed there.
*/
for (int i = 0; i < RLIMIT_NLIMITS; i++)
getrlimit(i, &global_rlimit[i]);
fp = fopen(file, "r"); fp = fopen(file, "r");
if (!fp) if (!fp)
@@ -414,11 +442,17 @@ static int parse_conf(char *file)
_d("%s", line); _d("%s", line);
parse_static(line); parse_static(line);
parse_dynamic(line, NULL); parse_dynamic(line, global_rlimit, NULL);
} }
fclose(fp); fclose(fp);
/* Set global limits */
for (int i = 0; i < RLIMIT_NLIMITS; i++) {
if (setrlimit(i, &global_rlimit[i]) == -1)
logit(LOG_WARNING, "rlimit: Failed setting %s", rlim2str(i));
}
return 0; return 0;
} }
@@ -439,6 +473,10 @@ int conf_reload_dynamic(void)
return 1; return 1;
} }
/* Update global limits in case operator used prlimit(1) on us */
for (i = 0; i < RLIMIT_NLIMITS; i++)
getrlimit(i, &global_rlimit[i]);
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
char *name = e[i]->d_name; char *name = e[i]->d_name;
char path[LINE_SIZE]; char path[LINE_SIZE];
+5
View File
@@ -26,6 +26,11 @@
#include "svc.h" #include "svc.h"
extern struct rlimit global_rlimit[];
int str2rlim(char *str);
char *rlim2str(int rlim);
void conf_parse_cmdline (void); void conf_parse_cmdline (void);
int conf_parse_runlevels (char *runlevels); int conf_parse_runlevels (char *runlevels);
void conf_parse_cond (svc_t *svc, char *cond); void conf_parse_cond (svc_t *svc, char *cond);
+11 -5
View File
@@ -234,7 +234,7 @@ int exec_runtask(char *cmd, char *args[])
return execvp(_PATH_BSHELL, argv); return execvp(_PATH_BSHELL, argv);
} }
static void prepare_tty(char *tty, speed_t speed, char *procname) static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit rlimit[])
{ {
struct sigaction sa; struct sigaction sa;
struct termios term; struct termios term;
@@ -270,6 +270,12 @@ static void prepare_tty(char *tty, speed_t speed, char *procname)
sigaction(SIGINT, &sa, NULL); sigaction(SIGINT, &sa, NULL);
sigaction(SIGQUIT, &sa, NULL); sigaction(SIGQUIT, &sa, NULL);
/* Set configured limits */
for (int i = 0; i < RLIMIT_NLIMITS; i++) {
if (setrlimit(i, &rlimit[i]) == -1)
logit(LOG_WARNING, "%s: rlimit: Failed setting %s", tty, rlim2str(i));
}
/* Create new session and process group */ /* Create new session and process group */
setsid(); setsid();
@@ -348,7 +354,7 @@ static int activate_console(int noclear, int nowait)
* since /bin/login usually only disables ECHO until a password line has * since /bin/login usually only disables ECHO until a password line has
* been entered. Upon starting the user's $SHELL the ISIG flag is reset * been entered. Upon starting the user's $SHELL the ISIG flag is reset
*/ */
pid_t run_getty(char *tty, char *baud, char *term, int noclear, int nowait) pid_t run_getty(char *tty, char *baud, char *term, int noclear, int nowait, struct rlimit rlimit[])
{ {
pid_t pid; pid_t pid;
@@ -362,7 +368,7 @@ pid_t run_getty(char *tty, char *baud, char *term, int noclear, int nowait)
logit(LOG_CRIT, "TTY %s: Invalid speed %s", tty, baud); logit(LOG_CRIT, "TTY %s: Invalid speed %s", tty, baud);
} }
prepare_tty(tty, speed, "finit-getty"); prepare_tty(tty, speed, "finit-getty", rlimit);
if (activate_console(noclear, nowait)) if (activate_console(noclear, nowait))
_exit(getty(tty, speed, term, NULL)); _exit(getty(tty, speed, term, NULL));
} }
@@ -370,7 +376,7 @@ pid_t run_getty(char *tty, char *baud, char *term, int noclear, int nowait)
return pid; return pid;
} }
pid_t run_getty2(char *tty, char *cmd, char *args[], int noclear, int nowait) pid_t run_getty2(char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[])
{ {
pid_t pid; pid_t pid;
@@ -400,7 +406,7 @@ pid_t run_getty2(char *tty, char *cmd, char *args[], int noclear, int nowait)
dup2(fd, STDERR_FILENO); dup2(fd, STDERR_FILENO);
/* Dunno speed, tell stty() to not mess with it */ /* Dunno speed, tell stty() to not mess with it */
prepare_tty(tty, B0, "getty"); prepare_tty(tty, B0, "getty", rlimit);
if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0) if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0)
_pe("Failed TIOCSCTTY"); _pe("Failed TIOCSCTTY");
+1 -1
View File
@@ -357,7 +357,7 @@ int main(int argc, char* argv[])
/* Register udevd as a monitored service, started much later */ /* Register udevd as a monitored service, started much later */
snprintf(cmd, sizeof(cmd), "[12345] %s -- Device event manager daemon", path); snprintf(cmd, sizeof(cmd), "[12345] %s -- Device event manager daemon", path);
if (service_register(SVC_TYPE_SERVICE, cmd, NULL)) { if (service_register(SVC_TYPE_SERVICE, cmd, global_rlimit, NULL)) {
_pe("Failed registering %s", path); _pe("Failed registering %s", path);
udev = 0; udev = 0;
} }
+3 -2
View File
@@ -26,6 +26,7 @@
#define FINIT_HELPERS_H_ #define FINIT_HELPERS_H_
#include <stdarg.h> #include <stdarg.h>
#include <sys/resource.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/ttydefaults.h> /* Not included by default in musl libc */ #include <sys/ttydefaults.h> /* Not included by default in musl libc */
#include <termios.h> #include <termios.h>
@@ -71,8 +72,8 @@ int complete (char *cmd, int pid);
int run (char *cmd); int run (char *cmd);
int run_interactive (char *cmd, char *fmt, ...); int run_interactive (char *cmd, char *fmt, ...);
int exec_runtask (char *cmd, char *args[]); int exec_runtask (char *cmd, char *args[]);
pid_t run_getty (char *tty, char *baud, char *term, int noclear, int nowait); pid_t run_getty (char *tty, char *baud, char *term, int noclear, int nowait, struct rlimit rlimit[]);
pid_t run_getty2 (char *tty, char *cmd, char *args[], int noclear, int nowait); pid_t run_getty2 (char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[]);
int run_parts (char *dir, char *cmd); int run_parts (char *dir, char *cmd);
static inline void create(char *path, mode_t mode, uid_t uid, gid_t gid) static inline void create(char *path, mode_t mode, uid_t uid, gid_t gid)
+19 -7
View File
@@ -26,6 +26,7 @@
#include <ctype.h> /* isblank() */ #include <ctype.h> /* isblank() */
#include <string.h> #include <string.h>
#include <sys/resource.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <net/if.h> #include <net/if.h>
#include <lite/lite.h> #include <lite/lite.h>
@@ -192,6 +193,14 @@ static int service_start(svc_t *svc)
#endif #endif
char *args[MAX_NUM_SVC_ARGS]; char *args[MAX_NUM_SVC_ARGS];
/* Set configured limits */
for (int i = 0; i < RLIMIT_NLIMITS; i++) {
if (setrlimit(i, &svc->rlimit[i]) == -1)
logit(LOG_WARNING,
"%s: rlimit: Failed setting %s",
svc->cmd, rlim2str(i));
}
/* Set desired user+group */ /* Set desired user+group */
if (gid >= 0) if (gid >= 0)
setgid(gid); setgid(gid);
@@ -471,9 +480,10 @@ void service_runlevel(int newlevel)
/** /**
* service_register - Register service, task or run commands * service_register - Register service, task or run commands
* @type: %SVC_TYPE_SERVICE(0), %SVC_TYPE_TASK(1), %SVC_TYPE_RUN(2) * @type: %SVC_TYPE_SERVICE(0), %SVC_TYPE_TASK(1), %SVC_TYPE_RUN(2)
* @svcline: A complete command line with -- separated description text * @cfg: Configuration, complete command, with -- for description text
* @mtime: The modification time if service is loaded from /etc/finit.d * @rlimit: Limits for this service/task/run/inetd, may be global limits
* @mtime: The modification time if service is loaded from /etc/finit.d
* *
* This function is used to register commands to be run on different * This function is used to register commands to be run on different
* system runlevels with optional username. The @type argument details * system runlevels with optional username. The @type argument details
@@ -520,7 +530,7 @@ void service_runlevel(int newlevel)
* Returns: * Returns:
* POSIX OK(0) on success, or non-zero errno exit status on failure. * POSIX OK(0) on success, or non-zero errno exit status on failure.
*/ */
int service_register(int type, char *svcline, struct timeval *mtime) int service_register(int type, char *cfg, struct rlimit rlimit[], struct timeval *mtime)
{ {
int i = 0; int i = 0;
int id = 1; /* Default to ID:1 */ int id = 1; /* Default to ID:1 */
@@ -534,12 +544,12 @@ int service_register(int type, char *svcline, struct timeval *mtime)
svc_t *svc; svc_t *svc;
plugin_t *plugin = NULL; plugin_t *plugin = NULL;
if (!svcline) { if (!cfg) {
_e("Invalid input argument"); _e("Invalid input argument");
return errno = EINVAL; return errno = EINVAL;
} }
line = strdup(svcline); line = strdup(cfg);
if (!line) if (!line)
return 1; return 1;
@@ -555,7 +565,7 @@ int service_register(int type, char *svcline, struct timeval *mtime)
cmd = strtok(line, " "); cmd = strtok(line, " ");
if (!cmd) { if (!cmd) {
incomplete: incomplete:
_e("Incomplete service '%s', cannot register", svcline); _e("Incomplete service '%s', cannot register", cfg);
free(line); free(line);
return errno = ENOENT; return errno = ENOENT;
} }
@@ -718,6 +728,8 @@ recreate:
} }
} }
#endif #endif
/* Set configured limits */
memcpy(svc->rlimit, rlimit, sizeof(svc->rlimit));
/* New, recently modified or unchanged ... used on reload. */ /* New, recently modified or unchanged ... used on reload. */
svc_check_dirty(svc, mtime); svc_check_dirty(svc, mtime);
+1 -1
View File
@@ -28,7 +28,7 @@
#include "svc.h" #include "svc.h"
void service_runlevel (int newlevel); void service_runlevel (int newlevel);
int service_register (int type, char *line, struct timeval *mtime); int service_register (int type, char *line, struct rlimit rlimit[], struct timeval *mtime);
void service_unregister (svc_t *svc); void service_unregister (svc_t *svc);
int service_enabled (svc_t *svc); int service_enabled (svc_t *svc);
+4
View File
@@ -26,6 +26,7 @@
#define FINIT_SVC_H_ #define FINIT_SVC_H_
#include <sys/ipc.h> /* IPC_CREAT */ #include <sys/ipc.h> /* IPC_CREAT */
#include <sys/resource.h>
#include <sys/shm.h> /* shmat() */ #include <sys/shm.h> /* shmat() */
#include <sys/types.h> /* pid_t */ #include <sys/types.h> /* pid_t */
#include <lite/lite.h> #include <lite/lite.h>
@@ -84,6 +85,9 @@ typedef struct svc {
/* Instance specifics */ /* Instance specifics */
int job, id; /* JOB:ID */ int job, id; /* JOB:ID */
/* Limits and scoping */
struct rlimit rlimit[RLIMIT_NLIMITS];
/* Service details */ /* Service details */
pid_t pid; pid_t pid;
const svc_state_t state; /* Paused, Reloading, Restart, Running, ... */ const svc_state_t state; /* Paused, Reloading, Restart, Running, ... */
+9 -5
View File
@@ -127,8 +127,9 @@ void tty_sweep(void)
/** /**
* tty_register - Register a getty on a device * tty_register - Register a getty on a device
* @line: Configuration, text after initial "tty" * @line: Configuration, text after initial "tty"
* @mtime: Modification time, to propagate to lower layers * @rlimit: Limits for this service/task/run/inetd, may be global limits
* @mtime: Modification time, to propagate to lower layers
* *
* A Finit tty line can use the internal getty implementation or an * A Finit tty line can use the internal getty implementation or an
* external one, like the BusyBox getty for instance. This function * external one, like the BusyBox getty for instance. This function
@@ -146,7 +147,7 @@ void tty_sweep(void)
* Different getty implementations prefer the TTY device argument in * Different getty implementations prefer the TTY device argument in
* different order, so take care to investigate this first. * different order, so take care to investigate this first.
*/ */
int tty_register(char *line, struct timeval *mtime) int tty_register(char *line, struct rlimit rlimit[], struct timeval *mtime)
{ {
tty_node_t *entry; tty_node_t *entry;
int insert = 0, noclear = 0, nowait = 0; int insert = 0, noclear = 0, nowait = 0;
@@ -278,6 +279,9 @@ int tty_register(char *line, struct timeval *mtime)
if (insert) if (insert)
LIST_INSERT_HEAD(&tty_list, entry, link); LIST_INSERT_HEAD(&tty_list, entry, link);
/* Register configured limits */
memcpy(entry->data.rlimit, rlimit, sizeof(entry->data.rlimit));
tty_check(entry, mtime); tty_check(entry, mtime);
_d("TTY %s is %sdirty", dev, entry->dirty ? "" : "NOT "); _d("TTY %s is %sdirty", dev, entry->dirty ? "" : "NOT ");
@@ -399,9 +403,9 @@ void tty_start(finit_tty_t *tty)
} }
if (!tty->cmd) if (!tty->cmd)
tty->pid = run_getty(dev, tty->baud, tty->term, tty->noclear, tty->nowait); tty->pid = run_getty(dev, tty->baud, tty->term, tty->noclear, tty->nowait, tty->rlimit);
else else
tty->pid = run_getty2(dev, tty->cmd, tty->args, tty->noclear, tty->nowait); tty->pid = run_getty2(dev, tty->cmd, tty->args, tty->noclear, tty->nowait, tty->rlimit);
} }
void tty_stop(finit_tty_t *tty) void tty_stop(finit_tty_t *tty)
+5 -1
View File
@@ -26,6 +26,7 @@
#define FINIT_TTY_H_ #define FINIT_TTY_H_
#include <limits.h> #include <limits.h>
#include <sys/resource.h>
#include <lite/queue.h> /* BSD sys/queue.h API */ #include <lite/queue.h> /* BSD sys/queue.h API */
#define TTY_MAX_ARGS 16 #define TTY_MAX_ARGS 16
@@ -43,6 +44,9 @@ typedef struct {
char *args[TTY_MAX_ARGS]; char *args[TTY_MAX_ARGS];
int pid; int pid;
/* Limits and scoping */
struct rlimit rlimit[RLIMIT_NLIMITS];
} finit_tty_t; } finit_tty_t;
typedef struct tty_node { typedef struct tty_node {
@@ -61,7 +65,7 @@ void tty_mark (void);
void tty_check (tty_node_t *tty, struct timeval *mtime); void tty_check (tty_node_t *tty, struct timeval *mtime);
void tty_sweep (void); void tty_sweep (void);
int tty_register (char *line, struct timeval *mtime); int tty_register (char *line, struct rlimit rlimit[], struct timeval *mtime);
int tty_unregister (tty_node_t *tty); int tty_unregister (tty_node_t *tty);
tty_node_t *tty_find (char *dev); tty_node_t *tty_find (char *dev);