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 OUTPUT:
 240         RETVAL
 241 
 242 
 243 int
 244 getprojidbyname(proj)
 245         char    *proj
 246 PREINIT:
 247         int     id;
 248 PPCODE:
 249         if ((id = getprojidbyname(proj)) == -1) {
 250                 XSRETURN_UNDEF;
 251         } else {
 252                 XSRETURN_IV(id);
 253         }
 254 
 255 
 256 # rctl_get_info(name)
 257 #
 258 # For the given rctl name, returns the list
 259 # ($max, $flags), where $max is the integer value
 260 # of the system rctl, and $flags are the rctl's
 261 # global flags, as returned by rctlblk_get_global_flags
 262 #
 263 # This function is private to Project.pm
 264 void
 265 rctl_get_info(name)
 266         char    *name
 267 PREINIT:
 268         rctlblk_t *blk1 = NULL;
 269         rctlblk_t *blk2 = NULL;
 270         rctlblk_t *tmp = NULL;
 271         rctl_priv_t priv;
 272         rctl_qty_t value;
 273         int flags;
 274         int ret;
 275         int err = 0;
 276         char string[24];        /* 24 will always hold a uint64_t */
 277 PPCODE:
 278         Newc(0, blk1, rctlblk_size(), char, rctlblk_t);
 279         if (blk1 == NULL) {
 280                 err = 1;
 281                 goto out;
 282         }
 283         Newc(1, blk2, rctlblk_size(), char, rctlblk_t);
 284         if (blk2 == NULL) {
 285                 err = 1;
 286                 goto out;
 287         }
 288         ret = getrctl(name, NULL, blk1, RCTL_FIRST);
 289         if (ret != 0) {
 290                 err = 1;
 291                 goto out;
 292         }
 293         priv = rctlblk_get_privilege(blk1);
 294         while (priv != RCPRIV_SYSTEM) {
 295                 tmp = blk2;
 296                 blk2 = blk1;
 297                 blk1 = tmp;
 298                 ret = getrctl(name, blk2, blk1, RCTL_NEXT);
 299                 if (ret != 0) {
 300                         err = 1;
 301                         goto out;
 302                 }
 303                 priv = rctlblk_get_privilege(blk1);
 304         }
 305         value = rctlblk_get_value(blk1);
 306         flags = rctlblk_get_global_flags(blk1);
 307         ret = sprintf(string, "%llu", value);
 308         if (ret <= 0) {
 309                 err = 1;
 310         }
 311         out:
 312         if (blk1)
 313                 Safefree(blk1);
 314         if (blk2)
 315                 Safefree(blk2);
 316         if (err)
 317                 XSRETURN(0);
 318 
 319         XPUSHs(sv_2mortal(newSVpv(string, 0)));
 320         XPUSHs(sv_2mortal(newSViv(flags)));
 321         XSRETURN(2);
 322 
 323 #
 324 # pool_exists(name)
 325 #
 326 # Returns 0 a pool with the given name exists on the current system.
 327 # Returns 1 if pools are disabled or the pool does not exist
 328 #
 329 # Used internally by project.pm to validate the project.pool attribute
 330 #
 331 # This function is private to Project.pm
 332 void
 333 pool_exists(name)
 334         char    *name
 335 PREINIT:
 336         pool_conf_t *conf;
 337         pool_t *pool;
 338         pool_status_t status;
 339         int fd;
 340 PPCODE:
 341 
 342         /*
 343          * Determine if pools are enabled using /dev/pool directly, as
 344          * libpool may not be present.
 345          */
 346         if (getzoneid() != GLOBAL_ZONEID) {
 347                 XSRETURN_IV(1);
 348         }
 349         if ((fd = open("/dev/pool", O_RDONLY)) < 0) {
 350                 XSRETURN_IV(1);
 351         }
 352         if (ioctl(fd, POOL_STATUSQ, &status) < 0) {
 353                 (void) close(fd);
 354                 XSRETURN_IV(1);
 355         }
 356         close(fd);
 357         if (status.ps_io_state != 1) {
 358                 XSRETURN_IV(1);
 359         }
 360 
 361         /*
 362          * If pools are enabled, assume libpool is present.
 363          */
 364         conf = pool_conf_alloc();
 365         if (conf == NULL) {
 366                 XSRETURN_IV(1);
 367         }
 368         if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY)) {
 369                 pool_conf_free(conf);
 370                 XSRETURN_IV(1);
 371         }
 372         pool = pool_get_pool(conf, name);
 373         if (pool == NULL) {
 374                 pool_conf_close(conf);
 375                 pool_conf_free(conf);
 376                 XSRETURN_IV(1);
 377         }
 378         pool_conf_close(conf);
 379         pool_conf_free(conf);
 380         XSRETURN_IV(0);
 381