summaryrefslogtreecommitdiff
path: root/usr/src/lib/libproject/common/setproject.c
diff options
context:
space:
mode:
authorrd117015 <none@none>2007-02-20 10:39:20 -0800
committerrd117015 <none@none>2007-02-20 10:39:20 -0800
commit532877c46d04a2d0b254f9b5797720078adcea07 (patch)
tree6a099b60988ee5b9c2a654492f35be5dce1ffee8 /usr/src/lib/libproject/common/setproject.c
parent0a9f9c2a7d4d961e3ed3221accb2c04919531d23 (diff)
downloadillumos-gate-532877c46d04a2d0b254f9b5797720078adcea07.tar.gz
PSARC 2006/554 setproject(3PROJECT) defining, and enhancing behaviour
6194864 simultaneous setproject()'s on the same project can fail to set rctl 6449567 setproject(3PROJECT) deletes resource controls set through prctl(1M) 6450539 projmod(1M) does not provide a mechanism to refresh "in-core" enforced resource controls 6491754 project.max-contracts should not allow basic privileges 6491804 task.final project property is not honoured if pools are not enabled
Diffstat (limited to 'usr/src/lib/libproject/common/setproject.c')
-rw-r--r--usr/src/lib/libproject/common/setproject.c169
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) {
/*