1 /*
   2  * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2014 Racktop Systems.
   4  */
   5 /*
   6  * Project.xs contains XS wrappers for the project database maniplulation
   7  * functions as provided by libproject and described in getprojent(3EXACCT).
   8  */
   9 
  10 /* Solaris includes. */
  11 #include <zone.h>
  12 #include <project.h>
  13 #include <pool.h>
  14 #include <sys/pool_impl.h>
  15 #include <rctl.h>
  16 #include <stdio.h>
  17 
  18 /* Perl includes. */
  19 #include "EXTERN.h"
  20 #include "perl.h"
  21 #include "XSUB.h"
  22 
  23 /*
  24  * Convert and save a struct project on the perl XS return stack.
  25  * In a void context it returns nothing, in a scalar context it returns just
  26  * the name of the project and in a list context it returns a 6-element list
  27  * consisting of (name, projid, comment, users, groups, attr), where users and
  28  * groups are references to arrays containing the appropriate lists.
  29  */
  30 static int
  31 pushret_project(const struct project *proj)
  32 {
  33         char    **cp;
  34         AV      *ary;
  35 
  36         dSP;
  37         if (GIMME_V == G_SCALAR) {
  38                 EXTEND(SP, 1);
  39                 PUSHs(sv_2mortal(newSVpv(proj->pj_name, 0)));
  40                 PUTBACK;
  41                 return (1);
  42         } else if (GIMME_V == G_ARRAY) {
  43                 EXTEND(SP, 6);
  44                 PUSHs(sv_2mortal(newSVpv(proj->pj_name, 0)));
  45                 PUSHs(sv_2mortal(newSViv(proj->pj_projid)));
  46                 PUSHs(sv_2mortal(newSVpv(proj->pj_comment, 0)));
  47                 ary = newAV();
  48                 for (cp = proj->pj_users; *cp != NULL; cp++) {
  49                         av_push(ary, newSVpv(*cp, 0));
  50                 }
  51                 PUSHs(sv_2mortal(newRV_noinc((SV *)ary)));
  52                 ary = newAV();
  53                 for (cp = proj->pj_groups; *cp != NULL; cp++) {
  54                         av_push(ary, newSVpv(*cp, 0));
  55                 }
  56                 PUSHs(sv_2mortal(newRV_noinc((SV *)ary)));
  57                 PUSHs(sv_2mortal(newSVpv(proj->pj_attr, 0)));
  58                 PUTBACK;
  59                 return (6);
  60         } else {
  61                 return (0);
  62         }
  63 }
  64 
  65 static int
  66 pwalk_cb(const projid_t project, void *walk_data)
  67 {
  68         int *nitemsp;
  69 
  70         dSP;
  71         nitemsp = (int *) walk_data;
  72         EXTEND(SP, 1);
  73         PUSHs(sv_2mortal(newSViv(project)));
  74         (*nitemsp)++;
  75         PUTBACK;
  76         return (0);
  77 }
  78 
  79 /*
  80  * The XS code exported to perl is below here.  Note that the XS preprocessor
  81  * has its own commenting syntax, so all comments from this point on are in
  82  * that form.  Note also that the PUTBACK; lines are necessary to synchronise
  83  * the local and global views of the perl stack before calling pushret_project,
  84  * as the code generated by the perl XS compiler twiddles with the stack on
  85  * entry to an XSUB.
  86  */
  87 
  88 MODULE = Sun::Solaris::Project PACKAGE = Sun::Solaris::Project
  89 PROTOTYPES: ENABLE
  90 
  91  #
  92  # Define any constants that need to be exported.  By doing it this way we can
  93  # avoid the overhead of using the DynaLoader package, and in addition constants
  94  # defined using this mechanism are eligible for inlining by the perl
  95  # interpreter at compile time.
  96  #
  97 BOOT:
  98         {
  99         HV *stash;
 100         char buf[128];
 101         stash = gv_stashpv("Sun::Solaris::Project", TRUE);
 102         newCONSTSUB(stash, "MAXPROJID", newSViv(MAXPROJID));
 103         newCONSTSUB(stash, "PROJNAME_MAX", newSViv(PROJNAME_MAX));
 104         newCONSTSUB(stash, "PROJF_PATH",
 105             newSVpv(PROJF_PATH, sizeof (PROJF_PATH) - 1));
 106         newCONSTSUB(stash, "PROJECT_BUFSZ", newSViv(PROJECT_BUFSZ));
 107         newCONSTSUB(stash, "SETPROJ_ERR_TASK", newSViv(SETPROJ_ERR_TASK));
 108         newCONSTSUB(stash, "SETPROJ_ERR_POOL", newSViv(SETPROJ_ERR_POOL));
 109         newCONSTSUB(stash, "RCTL_GLOBAL_NOBASIC",
 110                 newSViv(RCTL_GLOBAL_NOBASIC));
 111         newCONSTSUB(stash, "RCTL_GLOBAL_LOWERABLE",
 112                 newSViv(RCTL_GLOBAL_LOWERABLE));
 113         newCONSTSUB(stash, "RCTL_GLOBAL_DENY_ALWAYS",
 114                 newSViv(RCTL_GLOBAL_DENY_ALWAYS));
 115         newCONSTSUB(stash, "RCTL_GLOBAL_DENY_NEVER",
 116                 newSViv(RCTL_GLOBAL_DENY_NEVER));
 117         newCONSTSUB(stash, "RCTL_GLOBAL_FILE_SIZE",
 118                 newSViv(RCTL_GLOBAL_FILE_SIZE));
 119         newCONSTSUB(stash, "RCTL_GLOBAL_CPU_TIME",
 120                 newSViv(RCTL_GLOBAL_CPU_TIME));
 121         newCONSTSUB(stash, "RCTL_GLOBAL_SIGNAL_NEVER",
 122                 newSViv(RCTL_GLOBAL_SIGNAL_NEVER));
 123         newCONSTSUB(stash, "RCTL_GLOBAL_INFINITE",
 124                 newSViv(RCTL_GLOBAL_INFINITE));
 125         newCONSTSUB(stash, "RCTL_GLOBAL_UNOBSERVABLE",
 126                 newSViv(RCTL_GLOBAL_UNOBSERVABLE));
 127         newCONSTSUB(stash, "RCTL_GLOBAL_BYTES",
 128                 newSViv(RCTL_GLOBAL_BYTES));
 129         newCONSTSUB(stash, "RCTL_GLOBAL_SECONDS",
 130                 newSViv(RCTL_GLOBAL_SECONDS));
 131         newCONSTSUB(stash, "RCTL_GLOBAL_COUNT",
 132                 newSViv(RCTL_GLOBAL_COUNT));
 133         sprintf(buf, "%llu", UINT64_MAX);
 134         newCONSTSUB(stash, "RCTL_MAX_VALUE",
 135                 newSVpv(buf, strlen(buf)));
 136         }
 137 
 138 projid_t
 139 getprojid()
 140 
 141 int
 142 setproject(name, user_name, flags)
 143         const char      *name;
 144         const char      *user_name
 145         uint_t          flags
 146 
 147 void
 148 activeprojects()
 149 PREINIT:
 150         int     nitems;
 151 PPCODE:
 152         PUTBACK;
 153         nitems = 0;
 154         project_walk(&pwalk_cb, (void*)&nitems);
 155         XSRETURN(nitems);
 156 
 157 void
 158 getprojent()
 159 PREINIT:
 160         struct project  proj, *projp;
 161         char            buf[PROJECT_BUFSZ];
 162 PPCODE:
 163         PUTBACK;
 164         if ((projp = getprojent(&proj, buf, sizeof (buf)))) {
 165                 XSRETURN(pushret_project(projp));
 166         } else {
 167                 XSRETURN_EMPTY;
 168         }
 169 
 170 void
 171 setprojent()
 172 
 173 void
 174 endprojent()
 175 
 176 void
 177 getprojbyname(name)
 178         char    *name
 179 PREINIT:
 180         struct project  proj, *projp;
 181         char            buf[PROJECT_BUFSZ];
 182 PPCODE:
 183         PUTBACK;
 184         if ((projp = getprojbyname(name, &proj, buf, sizeof (buf)))) {
 185                 XSRETURN(pushret_project(projp));
 186         } else {
 187                 XSRETURN_EMPTY;
 188         }
 189 
 190 void
 191 getprojbyid(id)
 192         projid_t        id
 193 PREINIT:
 194         struct project  proj, *projp;
 195         char            buf[PROJECT_BUFSZ];
 196 PPCODE:
 197         PUTBACK;
 198         if ((projp = getprojbyid(id, &proj, buf, sizeof (buf)))) {
 199                 XSRETURN(pushret_project(projp));
 200         } else {
 201                 XSRETURN_EMPTY;
 202         }
 203 
 204 void
 205 getdefaultproj(user)
 206         char    *user
 207 PREINIT:
 208         struct project  proj, *projp;
 209         char            buf[PROJECT_BUFSZ];
 210 PPCODE:
 211         PUTBACK;
 212         if ((projp = getdefaultproj(user, &proj, buf, sizeof (buf)))) {
 213                 XSRETURN(pushret_project(projp));
 214         } else {
 215                 XSRETURN_EMPTY;
 216         }
 217 
 218 void
 219 fgetprojent(fh)
 220         FILE    *fh
 221 PREINIT:
 222         struct project  proj, *projp;
 223         char            buf[PROJECT_BUFSZ];
 224 PPCODE:
 225         PUTBACK;
 226         if ((projp = fgetprojent(fh, &proj, buf, sizeof (buf)))) {
 227                 XSRETURN(pushret_project(projp));
 228         } else {
 229                 XSRETURN_EMPTY;
 230         }
 231 
 232 bool
 233 inproj(user, proj)
 234         char    *user
 235         char    *proj
 236 PREINIT:
 237         char    buf[PROJECT_BUFSZ];
 238 CODE:
 239         RETVAL = inproj(user, proj, buf, sizeof (buf));
 240 OUTPUT:
 241         RETVAL
 242 
 243 
 244 int
 245 getprojidbyname(proj)
 246         char    *proj
 247 PREINIT:
 248         int     id;
 249 PPCODE:
 250         if ((id = getprojidbyname(proj)) == -1) {
 251                 XSRETURN_UNDEF;
 252         } else {
 253                 XSRETURN_IV(id);
 254         }
 255 
 256 
 257 # rctl_get_info(name)
 258 #
 259 # For the given rctl name, returns the list
 260 # ($max, $flags), where $max is the integer value
 261 # of the system rctl, and $flags are the rctl's
 262 # global flags, as returned by rctlblk_get_global_flags
 263 #
 264 # This function is private to Project.pm
 265 void
 266 rctl_get_info(name)
 267         char    *name
 268 PREINIT:
 269         rctlblk_t *blk1 = NULL;
 270         rctlblk_t *blk2 = NULL;
 271         rctlblk_t *tmp = NULL;
 272         rctl_priv_t priv;
 273         rctl_qty_t value;
 274         int flags = 0;
 275         int ret;
 276         int err = 0;
 277         char string[24];        /* 24 will always hold a uint64_t */
 278 PPCODE:
 279         Newc(0, blk1, rctlblk_size(), char, rctlblk_t);
 280         if (blk1 == NULL) {
 281                 err = 1;
 282                 goto out;
 283         }
 284         Newc(1, blk2, rctlblk_size(), char, rctlblk_t);
 285         if (blk2 == NULL) {
 286                 err = 1;
 287                 goto out;
 288         }
 289         ret = getrctl(name, NULL, blk1, RCTL_FIRST);
 290         if (ret != 0) {
 291                 err = 1;
 292                 goto out;
 293         }
 294         priv = rctlblk_get_privilege(blk1);
 295         while (priv != RCPRIV_SYSTEM) {
 296                 tmp = blk2;
 297                 blk2 = blk1;
 298                 blk1 = tmp;
 299                 ret = getrctl(name, blk2, blk1, RCTL_NEXT);
 300                 if (ret != 0) {
 301                         err = 1;
 302                         goto out;
 303                 }
 304                 priv = rctlblk_get_privilege(blk1);
 305         }
 306         value = rctlblk_get_value(blk1);
 307         flags = rctlblk_get_global_flags(blk1);
 308         ret = sprintf(string, "%llu", value);
 309         if (ret <= 0) {
 310                 err = 1;
 311         }
 312         out:
 313         if (blk1)
 314                 Safefree(blk1);
 315         if (blk2)
 316                 Safefree(blk2);
 317         if (err)
 318                 XSRETURN(0);
 319 
 320         XPUSHs(sv_2mortal(newSVpv(string, 0)));
 321         XPUSHs(sv_2mortal(newSViv(flags)));
 322         XSRETURN(2);
 323 
 324 #
 325 # pool_exists(name)
 326 #
 327 # Returns 0 a pool with the given name exists on the current system.
 328 # Returns 1 if pools are disabled or the pool does not exist
 329 #
 330 # Used internally by project.pm to validate the project.pool attribute
 331 #
 332 # This function is private to Project.pm
 333 void
 334 pool_exists(name)
 335         char    *name
 336 PREINIT:
 337         pool_conf_t *conf;
 338         pool_t *pool;
 339         pool_status_t status;
 340         int fd;
 341 PPCODE:
 342 
 343         /*
 344          * Determine if pools are enabled using /dev/pool directly, as
 345          * libpool may not be present.
 346          */
 347         if (getzoneid() != GLOBAL_ZONEID) {
 348                 XSRETURN_IV(1);
 349         }
 350         if ((fd = open("/dev/pool", O_RDONLY)) < 0) {
 351                 XSRETURN_IV(1);
 352         }
 353         if (ioctl(fd, POOL_STATUSQ, &status) < 0) {
 354                 (void) close(fd);
 355                 XSRETURN_IV(1);
 356         }
 357         close(fd);
 358         if (status.ps_io_state != 1) {
 359                 XSRETURN_IV(1);
 360         }
 361 
 362         /*
 363          * If pools are enabled, assume libpool is present.
 364          */
 365         conf = pool_conf_alloc();
 366         if (conf == NULL) {
 367                 XSRETURN_IV(1);
 368         }
 369         if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY)) {
 370                 pool_conf_free(conf);
 371                 XSRETURN_IV(1);
 372         }
 373         pool = pool_get_pool(conf, name);
 374         if (pool == NULL) {
 375                 pool_conf_close(conf);
 376                 pool_conf_free(conf);
 377                 XSRETURN_IV(1);
 378         }
 379         pool_conf_close(conf);
 380         pool_conf_free(conf);
 381         XSRETURN_IV(0);
 382