root/usr/src/lib/libc/port/gen/psecflags.c
/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */

/* Copyright 2015, Richard Lowe. */

#include "lint.h"

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>

#include <sys/proc.h>
#include <sys/procset.h>
#include <sys/syscall.h>
#include <sys/secflags.h>

extern int __psecflagsset(procset_t *, psecflagwhich_t, secflagdelta_t *);

int
psecflags(idtype_t idtype, id_t id, psecflagwhich_t which,
    secflagdelta_t *delta)
{
        procset_t procset;

        setprocset(&procset, POP_AND, idtype, id, P_ALL, 0);

        return (__psecflagsset(&procset, which, delta));
}

int
secflags_parse(const secflagset_t *defaults, const char *flags,
    secflagdelta_t *ret)
{
        char *flag;
        char *s, *ss;
        boolean_t current = B_FALSE;

        /* Guarantee a clean base */
        bzero(ret, sizeof (*ret));

        if ((ss = s = strdup(flags)) == NULL)
                return (-1);    /* errno set for us */


        while ((flag = strsep(&s, ",")) != NULL) {
                secflag_t sf = 0;
                boolean_t del = B_FALSE;

                if (strcasecmp(flag, "default") == 0) {
                        if (defaults != NULL) {
                                secflags_union(&ret->psd_add, defaults);
                        } else {
                                free(ss);
                                errno = EINVAL;
                                return (-1);
                        }
                        continue;
                } else if (strcasecmp(flag, "all") == 0) {
                        secflags_fullset(&ret->psd_add);
                        continue;
                } else if (strcasecmp(flag, "none") == 0) {
                        secflags_fullset(&ret->psd_rem);
                        continue;
                } else if (strcasecmp(flag, "current") == 0) {
                        current = B_TRUE;
                        continue;
                }

                if ((flag[0] == '-') || (flag[0] == '!')) {
                        flag++;
                        del = B_TRUE;
                } else if (flag[0] == '+') {
                        flag++;
                }

                if ((secflag_by_name(flag, &sf)) != B_TRUE) {
                        free(ss);
                        errno = EINVAL;
                        return (-1);
                }

                if (del)
                        secflag_set(&(ret->psd_rem), sf);
                else
                        secflag_set(&(ret->psd_add), sf);
        }

        /*
         * If we're not using the current flags, this is strict assignment.
         * Negatives "win".
         */
        if (!current) {
                secflags_copy(&ret->psd_assign, &ret->psd_add);
                secflags_difference(&ret->psd_assign, &ret->psd_rem);
                ret->psd_ass_active = B_TRUE;
                secflags_zero(&ret->psd_add);
                secflags_zero(&ret->psd_rem);
        }

        free(ss);
        return (0);
}