diff options
Diffstat (limited to 'usr/src/lib/libproject/common/setproject.c')
-rw-r--r-- | usr/src/lib/libproject/common/setproject.c | 169 |
1 files changed, 118 insertions, 51 deletions
diff --git a/usr/src/lib/libproject/common/setproject.c b/usr/src/lib/libproject/common/setproject.c index d22878a36f..e15c719c5c 100644 --- a/usr/src/lib/libproject/common/setproject.c +++ b/usr/src/lib/libproject/common/setproject.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -36,6 +36,7 @@ #include <signal.h> #include <stdlib.h> #include <string.h> +#include <strings.h> #include <nss_dbdefs.h> #include <pwd.h> #include <pool.h> @@ -45,6 +46,7 @@ #include <zone.h> #include <sys/pool.h> #include <sys/pool_impl.h> +#include <sys/rctl_impl.h> static void xstrtolower(char *s) @@ -177,7 +179,7 @@ build_rctlblk(rctlblk_t *blk, int comp_num, char *component) #define BADSPEC 5 static int -rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr) +rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr, int flags) { int error = 0; uint_t component = 0; @@ -185,18 +187,68 @@ rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr) uint_t state = 0; char *component_head; rctlblk_t *blk; - - remove_spaces(val); - if ((blk = malloc(rctlblk_size())) == NULL) { + rctlblk_t *ablk; + int project_entity = 0; + int count = 0; + char *tmp; + int local_action; + + /* We cannot modify a zone resource control */ + if (strncmp(ctl_name, "zone.", strlen("zone.")) == 0) { return (SETFAILED); } + remove_spaces(val); + /* - * Tear down everything with this ctl name. + * As we are operating in a new task, both process and task + * rctls are referenced by this process alone. Tear down + * matching process and task rctls only. + * + * blk will be the RCPRIV_SYSTEM for this resource control, + * populated by the last pr_setrctl(). */ - while (pr_getrctl(Pr, ctl_name, NULL, blk, RCTL_FIRST) != -1 && - rctlblk_get_privilege(blk) != RCPRIV_SYSTEM) { - (void) pr_setrctl(Pr, ctl_name, NULL, blk, RCTL_DELETE); + if ((strncmp(ctl_name, "process.", strlen("process.")) == 0) || + (strncmp(ctl_name, "task.", strlen("task.")) == 0)) { + + if ((blk = (rctlblk_t *)malloc(rctlblk_size())) == NULL) { + return (SETFAILED); + } + + + while (pr_getrctl(Pr, ctl_name, NULL, blk, RCTL_FIRST) != -1 && + rctlblk_get_privilege(blk) != RCPRIV_SYSTEM) { + (void) pr_setrctl(Pr, ctl_name, NULL, blk, RCTL_DELETE); + } + + } else if (strncmp(ctl_name, "project.", strlen("project.")) == 0) { + project_entity = 1; + + /* Determine how many attributes we'll be setting */ + for (tmp = val; *tmp != '\0'; tmp++) { + if (*tmp == '(') + count++; + } + + /* Allocate sufficient memory for rctl blocks */ + if ((count == 0) || ((ablk = + (rctlblk_t *)malloc(rctlblk_size() * count)) == NULL)) { + return (SETFAILED); + } + blk = ablk; + + /* + * In order to set the new rctl's local_action, we'll need the + * current value of global_flags. We obtain global_flags by + * performing a pr_getrctl(). + * + * The ctl_name has been verified as valid, so we have no reason + * to suspect that pr_getrctl() will return an error. + */ + (void) pr_getrctl(Pr, ctl_name, NULL, blk, RCTL_FIRST); + + } else { + return (SETFAILED); } /* @@ -205,11 +257,13 @@ rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr) rctlblk_set_privilege(blk, RCPRIV_PRIVILEGED); rctlblk_set_value(blk, 0); rctlblk_set_local_flags(blk, 0); + if (rctlblk_get_global_flags(blk) & RCTL_GLOBAL_DENY_ALWAYS) - rctlblk_set_local_action(blk, RCTL_LOCAL_DENY, 0); + local_action = RCTL_LOCAL_DENY; else - rctlblk_set_local_action(blk, RCTL_LOCAL_NOACTION, 0); + local_action = RCTL_LOCAL_NOACTION; + rctlblk_set_local_action(blk, local_action, 0); for (; ; val++) { switch (*val) { @@ -238,22 +292,35 @@ rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr) state &= ~INPAREN; component = 0; valuecount++; - if (pr_setrctl(Pr, ctl_name, NULL, blk, - RCTL_INSERT) == -1) + + if (project_entity && + (rctlblk_get_privilege(blk) == + RCPRIV_BASIC)) { error = SETFAILED; + } else if (project_entity) { + if (valuecount > count) + return (SETFAILED); + + if (valuecount != count) + blk = RCTLBLK_INC(ablk, + valuecount); + } else { + if (pr_setrctl(Pr, ctl_name, + NULL, blk, RCTL_INSERT) == + -1) + error = SETFAILED; + } /* re-initialize block */ - rctlblk_set_privilege(blk, - RCPRIV_PRIVILEGED); - rctlblk_set_value(blk, 0); - rctlblk_set_local_flags(blk, 0); - if (rctlblk_get_global_flags(blk) & - RCTL_GLOBAL_DENY_ALWAYS) - rctlblk_set_local_action(blk, - RCTL_LOCAL_DENY, 0); - else + if (!project_entity || + (valuecount != count)) { + rctlblk_set_privilege(blk, + RCPRIV_PRIVILEGED); + rctlblk_set_value(blk, 0); + rctlblk_set_local_flags(blk, 0); rctlblk_set_local_action(blk, - RCTL_LOCAL_NOACTION, 0); + local_action, 0); + } } else { error = CLOSEBEFOREOPEN; } @@ -288,6 +355,12 @@ rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr) break; } + if (project_entity) { + blk = ablk; + if (pr_setprojrctl(Pr, ctl_name, blk, count, flags) == -1) + error = SETFAILED; + } + free(blk); if (valuecount == 0) @@ -465,6 +538,7 @@ setproject_proc(const char *project_name, const char *user_name, int flags, int ret = 0; kva_t *kv_array; struct project local_proj; /* space to store proj if not provided */ + const char *pool_name = NULL; if (project_name != NULL) { /* @@ -508,45 +582,37 @@ setproject_proc(const char *project_name, const char *user_name, int flags, projid = getprojid(); } + + if ((kv_array = _str2kva(proj->pj_attr, KV_ASSIGN, + KV_DELIMITER)) != NULL) { + for (i = 0; i < kv_array->length; i++) { + if (strcmp(kv_array->data[i].key, + "project.pool") == 0) { + pool_name = kv_array->data[i].value; + } + if (strcmp(kv_array->data[i].key, "task.final") == 0) { + flags |= TASK_FINAL; + } + } + } + /* - * Only bind to a pool if pools are configured. + * Bind process to a pool only if pools are configured */ if (pools_enabled() == 1) { - const char *pool_name = NULL; char *old_pool_name; - int taskflags = flags; /* * Attempt to bind to pool before calling * settaskid(). */ - if ((kv_array = _str2kva(proj->pj_attr, KV_ASSIGN, - KV_DELIMITER)) != NULL) { - for (i = 0; i < kv_array->length; i++) { - if (strcmp(kv_array->data[i].key, - "project.pool") == 0) { - pool_name = kv_array->data[i].value; - break; - } - if (strcmp(kv_array->data[i].key, - "task.final") == 0) { - taskflags |= TASK_FINAL; - } - } - } - old_pool_name = pool_get_binding(pid); - - /* - * If parent is not bound to the default pool, then we want - * to preserve same binding as parent. - */ - if (pool_name != NULL && bind_to_pool(pool_name, pid, 0) != 0) { + if (bind_to_pool(pool_name, pid, 0) != 0) { if (old_pool_name) free(old_pool_name); _kva_free(kv_array); return (SETPROJ_ERR_POOL); } - if (pr_settaskid(Pr, projid, taskflags) == -1) { + if (pr_settaskid(Pr, projid, flags & TASK_MASK) == -1) { int saved_errno = errno; /* @@ -568,9 +634,10 @@ setproject_proc(const char *project_name, const char *user_name, int flags, /* * Pools are not configured, so simply create new task. */ - if (pr_settaskid(Pr, projid, flags) == -1) + if (pr_settaskid(Pr, projid, flags & TASK_MASK) == -1) { + _kva_free(kv_array); return (SETPROJ_ERR_TASK); - kv_array = _str2kva(proj->pj_attr, KV_ASSIGN, KV_DELIMITER); + } } if (project_name == NULL) { @@ -612,7 +679,7 @@ setproject_proc(const char *project_name, const char *user_name, int flags, } ret = rctl_set(kv_array->data[i].key, - kv_array->data[i].value, Pr); + kv_array->data[i].value, Pr, flags & TASK_PROJ_MASK); if (ret && unknown == 0) { /* |