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