10Sstevel@tonic-gate /*
2*12388SJohn.Sonnenschein@Sun.COM * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
30Sstevel@tonic-gate */
40Sstevel@tonic-gate /*
50Sstevel@tonic-gate * Project.xs contains XS wrappers for the project database maniplulation
60Sstevel@tonic-gate * functions as provided by libproject and described in getprojent(3EXACCT).
70Sstevel@tonic-gate */
80Sstevel@tonic-gate
90Sstevel@tonic-gate /* Solaris includes. */
103671Ssl108498 #include <zone.h>
110Sstevel@tonic-gate #include <project.h>
120Sstevel@tonic-gate #include <pool.h>
133671Ssl108498 #include <sys/pool_impl.h>
140Sstevel@tonic-gate #include <rctl.h>
150Sstevel@tonic-gate #include <stdio.h>
160Sstevel@tonic-gate
170Sstevel@tonic-gate /* Perl includes. */
180Sstevel@tonic-gate #include "EXTERN.h"
190Sstevel@tonic-gate #include "perl.h"
200Sstevel@tonic-gate #include "XSUB.h"
210Sstevel@tonic-gate
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate * Convert and save a struct project on the perl XS return stack.
240Sstevel@tonic-gate * In a void context it returns nothing, in a scalar context it returns just
250Sstevel@tonic-gate * the name of the project and in a list context it returns a 6-element list
260Sstevel@tonic-gate * consisting of (name, projid, comment, users, groups, attr), where users and
270Sstevel@tonic-gate * groups are references to arrays containing the appropriate lists.
280Sstevel@tonic-gate */
290Sstevel@tonic-gate static int
pushret_project(const struct project * proj)300Sstevel@tonic-gate pushret_project(const struct project *proj)
310Sstevel@tonic-gate {
320Sstevel@tonic-gate char **cp;
330Sstevel@tonic-gate AV *ary;
340Sstevel@tonic-gate
350Sstevel@tonic-gate dSP;
360Sstevel@tonic-gate if (GIMME_V == G_SCALAR) {
370Sstevel@tonic-gate EXTEND(SP, 1);
380Sstevel@tonic-gate PUSHs(sv_2mortal(newSVpv(proj->pj_name, 0)));
390Sstevel@tonic-gate PUTBACK;
400Sstevel@tonic-gate return (1);
410Sstevel@tonic-gate } else if (GIMME_V == G_ARRAY) {
420Sstevel@tonic-gate EXTEND(SP, 6);
430Sstevel@tonic-gate PUSHs(sv_2mortal(newSVpv(proj->pj_name, 0)));
440Sstevel@tonic-gate PUSHs(sv_2mortal(newSViv(proj->pj_projid)));
450Sstevel@tonic-gate PUSHs(sv_2mortal(newSVpv(proj->pj_comment, 0)));
460Sstevel@tonic-gate ary = newAV();
470Sstevel@tonic-gate for (cp = proj->pj_users; *cp != NULL; cp++) {
480Sstevel@tonic-gate av_push(ary, newSVpv(*cp, 0));
490Sstevel@tonic-gate }
500Sstevel@tonic-gate PUSHs(sv_2mortal(newRV_noinc((SV *)ary)));
510Sstevel@tonic-gate ary = newAV();
520Sstevel@tonic-gate for (cp = proj->pj_groups; *cp != NULL; cp++) {
530Sstevel@tonic-gate av_push(ary, newSVpv(*cp, 0));
540Sstevel@tonic-gate }
550Sstevel@tonic-gate PUSHs(sv_2mortal(newRV_noinc((SV *)ary)));
560Sstevel@tonic-gate PUSHs(sv_2mortal(newSVpv(proj->pj_attr, 0)));
570Sstevel@tonic-gate PUTBACK;
580Sstevel@tonic-gate return (6);
590Sstevel@tonic-gate } else {
600Sstevel@tonic-gate return (0);
610Sstevel@tonic-gate }
620Sstevel@tonic-gate }
630Sstevel@tonic-gate
640Sstevel@tonic-gate static int
pwalk_cb(const projid_t project,void * walk_data)650Sstevel@tonic-gate pwalk_cb(const projid_t project, void *walk_data)
660Sstevel@tonic-gate {
670Sstevel@tonic-gate int *nitemsp;
680Sstevel@tonic-gate
690Sstevel@tonic-gate dSP;
700Sstevel@tonic-gate nitemsp = (int *) walk_data;
710Sstevel@tonic-gate EXTEND(SP, 1);
720Sstevel@tonic-gate PUSHs(sv_2mortal(newSViv(project)));
730Sstevel@tonic-gate (*nitemsp)++;
740Sstevel@tonic-gate PUTBACK;
750Sstevel@tonic-gate return (0);
760Sstevel@tonic-gate }
770Sstevel@tonic-gate
780Sstevel@tonic-gate /*
790Sstevel@tonic-gate * The XS code exported to perl is below here. Note that the XS preprocessor
800Sstevel@tonic-gate * has its own commenting syntax, so all comments from this point on are in
810Sstevel@tonic-gate * that form. Note also that the PUTBACK; lines are necessary to synchronise
820Sstevel@tonic-gate * the local and global views of the perl stack before calling pushret_project,
830Sstevel@tonic-gate * as the code generated by the perl XS compiler twiddles with the stack on
840Sstevel@tonic-gate * entry to an XSUB.
850Sstevel@tonic-gate */
860Sstevel@tonic-gate
870Sstevel@tonic-gate MODULE = Sun::Solaris::Project PACKAGE = Sun::Solaris::Project
880Sstevel@tonic-gate PROTOTYPES: ENABLE
890Sstevel@tonic-gate
900Sstevel@tonic-gate #
910Sstevel@tonic-gate # Define any constants that need to be exported. By doing it this way we can
920Sstevel@tonic-gate # avoid the overhead of using the DynaLoader package, and in addition constants
930Sstevel@tonic-gate # defined using this mechanism are eligible for inlining by the perl
940Sstevel@tonic-gate # interpreter at compile time.
950Sstevel@tonic-gate #
960Sstevel@tonic-gate BOOT:
970Sstevel@tonic-gate {
980Sstevel@tonic-gate HV *stash;
990Sstevel@tonic-gate char buf[128];
1000Sstevel@tonic-gate stash = gv_stashpv("Sun::Solaris::Project", TRUE);
1010Sstevel@tonic-gate newCONSTSUB(stash, "MAXPROJID", newSViv(MAXPROJID));
1020Sstevel@tonic-gate newCONSTSUB(stash, "PROJNAME_MAX", newSViv(PROJNAME_MAX));
1030Sstevel@tonic-gate newCONSTSUB(stash, "PROJF_PATH",
1040Sstevel@tonic-gate newSVpv(PROJF_PATH, sizeof (PROJF_PATH) - 1));
1050Sstevel@tonic-gate newCONSTSUB(stash, "PROJECT_BUFSZ", newSViv(PROJECT_BUFSZ));
1060Sstevel@tonic-gate newCONSTSUB(stash, "SETPROJ_ERR_TASK", newSViv(SETPROJ_ERR_TASK));
1070Sstevel@tonic-gate newCONSTSUB(stash, "SETPROJ_ERR_POOL", newSViv(SETPROJ_ERR_POOL));
1080Sstevel@tonic-gate newCONSTSUB(stash, "RCTL_GLOBAL_NOBASIC",
1090Sstevel@tonic-gate newSViv(RCTL_GLOBAL_NOBASIC));
1100Sstevel@tonic-gate newCONSTSUB(stash, "RCTL_GLOBAL_LOWERABLE",
1110Sstevel@tonic-gate newSViv(RCTL_GLOBAL_LOWERABLE));
1120Sstevel@tonic-gate newCONSTSUB(stash, "RCTL_GLOBAL_DENY_ALWAYS",
1130Sstevel@tonic-gate newSViv(RCTL_GLOBAL_DENY_ALWAYS));
1140Sstevel@tonic-gate newCONSTSUB(stash, "RCTL_GLOBAL_DENY_NEVER",
1150Sstevel@tonic-gate newSViv(RCTL_GLOBAL_DENY_NEVER));
1160Sstevel@tonic-gate newCONSTSUB(stash, "RCTL_GLOBAL_FILE_SIZE",
1170Sstevel@tonic-gate newSViv(RCTL_GLOBAL_FILE_SIZE));
1180Sstevel@tonic-gate newCONSTSUB(stash, "RCTL_GLOBAL_CPU_TIME",
1190Sstevel@tonic-gate newSViv(RCTL_GLOBAL_CPU_TIME));
1200Sstevel@tonic-gate newCONSTSUB(stash, "RCTL_GLOBAL_SIGNAL_NEVER",
1210Sstevel@tonic-gate newSViv(RCTL_GLOBAL_SIGNAL_NEVER));
1220Sstevel@tonic-gate newCONSTSUB(stash, "RCTL_GLOBAL_INFINITE",
1230Sstevel@tonic-gate newSViv(RCTL_GLOBAL_INFINITE));
1240Sstevel@tonic-gate newCONSTSUB(stash, "RCTL_GLOBAL_UNOBSERVABLE",
1250Sstevel@tonic-gate newSViv(RCTL_GLOBAL_UNOBSERVABLE));
1260Sstevel@tonic-gate newCONSTSUB(stash, "RCTL_GLOBAL_BYTES",
1270Sstevel@tonic-gate newSViv(RCTL_GLOBAL_BYTES));
1280Sstevel@tonic-gate newCONSTSUB(stash, "RCTL_GLOBAL_SECONDS",
1290Sstevel@tonic-gate newSViv(RCTL_GLOBAL_SECONDS));
1300Sstevel@tonic-gate newCONSTSUB(stash, "RCTL_GLOBAL_COUNT",
1310Sstevel@tonic-gate newSViv(RCTL_GLOBAL_COUNT));
1320Sstevel@tonic-gate sprintf(buf, "%llu", UINT64_MAX);
1330Sstevel@tonic-gate newCONSTSUB(stash, "RCTL_MAX_VALUE",
1340Sstevel@tonic-gate newSVpv(buf, strlen(buf)));
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate
1370Sstevel@tonic-gate projid_t
1380Sstevel@tonic-gate getprojid()
1390Sstevel@tonic-gate
1400Sstevel@tonic-gate int
1410Sstevel@tonic-gate setproject(name, user_name, flags)
1420Sstevel@tonic-gate const char *name;
1430Sstevel@tonic-gate const char *user_name
1440Sstevel@tonic-gate uint_t flags
1450Sstevel@tonic-gate
1460Sstevel@tonic-gate void
1470Sstevel@tonic-gate activeprojects()
1480Sstevel@tonic-gate PREINIT:
1490Sstevel@tonic-gate int nitems;
1500Sstevel@tonic-gate PPCODE:
1510Sstevel@tonic-gate PUTBACK;
1520Sstevel@tonic-gate nitems = 0;
1530Sstevel@tonic-gate project_walk(&pwalk_cb, (void*)&nitems);
1540Sstevel@tonic-gate XSRETURN(nitems);
1550Sstevel@tonic-gate
1560Sstevel@tonic-gate void
1570Sstevel@tonic-gate getprojent()
1580Sstevel@tonic-gate PREINIT:
1590Sstevel@tonic-gate struct project proj, *projp;
1600Sstevel@tonic-gate char buf[PROJECT_BUFSZ];
1610Sstevel@tonic-gate PPCODE:
1620Sstevel@tonic-gate PUTBACK;
1630Sstevel@tonic-gate if (projp = getprojent(&proj, buf, sizeof (buf))) {
1640Sstevel@tonic-gate XSRETURN(pushret_project(projp));
1650Sstevel@tonic-gate } else {
1660Sstevel@tonic-gate XSRETURN_EMPTY;
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate void
1700Sstevel@tonic-gate setprojent()
1710Sstevel@tonic-gate
1720Sstevel@tonic-gate void
1730Sstevel@tonic-gate endprojent()
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate void
1760Sstevel@tonic-gate getprojbyname(name)
1770Sstevel@tonic-gate char *name
1780Sstevel@tonic-gate PREINIT:
1790Sstevel@tonic-gate struct project proj, *projp;
1800Sstevel@tonic-gate char buf[PROJECT_BUFSZ];
1810Sstevel@tonic-gate PPCODE:
1820Sstevel@tonic-gate PUTBACK;
1830Sstevel@tonic-gate if (projp = getprojbyname(name, &proj, buf, sizeof (buf))) {
1840Sstevel@tonic-gate XSRETURN(pushret_project(projp));
1850Sstevel@tonic-gate } else {
1860Sstevel@tonic-gate XSRETURN_EMPTY;
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate
1890Sstevel@tonic-gate void
1900Sstevel@tonic-gate getprojbyid(id)
1910Sstevel@tonic-gate projid_t id
1920Sstevel@tonic-gate PREINIT:
1930Sstevel@tonic-gate struct project proj, *projp;
1940Sstevel@tonic-gate char buf[PROJECT_BUFSZ];
1950Sstevel@tonic-gate PPCODE:
1960Sstevel@tonic-gate PUTBACK;
1970Sstevel@tonic-gate if (projp = getprojbyid(id, &proj, buf, sizeof (buf))) {
1980Sstevel@tonic-gate XSRETURN(pushret_project(projp));
1990Sstevel@tonic-gate } else {
2000Sstevel@tonic-gate XSRETURN_EMPTY;
2010Sstevel@tonic-gate }
2020Sstevel@tonic-gate
2030Sstevel@tonic-gate void
2040Sstevel@tonic-gate getdefaultproj(user)
2050Sstevel@tonic-gate char *user
2060Sstevel@tonic-gate PREINIT:
2070Sstevel@tonic-gate struct project proj, *projp;
2080Sstevel@tonic-gate char buf[PROJECT_BUFSZ];
2090Sstevel@tonic-gate PPCODE:
2100Sstevel@tonic-gate PUTBACK;
2110Sstevel@tonic-gate if (projp = getdefaultproj(user, &proj, buf, sizeof (buf))) {
2120Sstevel@tonic-gate XSRETURN(pushret_project(projp));
2130Sstevel@tonic-gate } else {
2140Sstevel@tonic-gate XSRETURN_EMPTY;
2150Sstevel@tonic-gate }
2160Sstevel@tonic-gate
2170Sstevel@tonic-gate void
2180Sstevel@tonic-gate fgetprojent(fh)
2190Sstevel@tonic-gate FILE *fh
2200Sstevel@tonic-gate PREINIT:
2210Sstevel@tonic-gate struct project proj, *projp;
2220Sstevel@tonic-gate char buf[PROJECT_BUFSZ];
2230Sstevel@tonic-gate PPCODE:
2240Sstevel@tonic-gate PUTBACK;
2250Sstevel@tonic-gate if (projp = fgetprojent(fh, &proj, buf, sizeof (buf))) {
2260Sstevel@tonic-gate XSRETURN(pushret_project(projp));
2270Sstevel@tonic-gate } else {
2280Sstevel@tonic-gate XSRETURN_EMPTY;
2290Sstevel@tonic-gate }
2300Sstevel@tonic-gate
2310Sstevel@tonic-gate bool
2320Sstevel@tonic-gate inproj(user, proj)
2330Sstevel@tonic-gate char *user
2340Sstevel@tonic-gate char *proj
2350Sstevel@tonic-gate PREINIT:
2360Sstevel@tonic-gate char buf[PROJECT_BUFSZ];
2370Sstevel@tonic-gate CODE:
2380Sstevel@tonic-gate RETVAL = inproj(user, proj, buf, sizeof (buf));
2390Sstevel@tonic-gate
2400Sstevel@tonic-gate
2410Sstevel@tonic-gate int
2420Sstevel@tonic-gate getprojidbyname(proj)
2430Sstevel@tonic-gate char *proj
2440Sstevel@tonic-gate PREINIT:
2450Sstevel@tonic-gate int id;
2460Sstevel@tonic-gate PPCODE:
2470Sstevel@tonic-gate if ((id = getprojidbyname(proj)) == -1) {
2480Sstevel@tonic-gate XSRETURN_UNDEF;
2490Sstevel@tonic-gate } else {
2500Sstevel@tonic-gate XSRETURN_IV(id);
2510Sstevel@tonic-gate }
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate
2540Sstevel@tonic-gate # rctl_get_info(name)
2550Sstevel@tonic-gate #
2560Sstevel@tonic-gate # For the given rctl name, returns the list
2570Sstevel@tonic-gate # ($max, $flags), where $max is the integer value
2580Sstevel@tonic-gate # of the system rctl, and $flags are the rctl's
2590Sstevel@tonic-gate # global flags, as returned by rctlblk_get_global_flags
2600Sstevel@tonic-gate #
2610Sstevel@tonic-gate # This function is private to Project.pm
2620Sstevel@tonic-gate void
2630Sstevel@tonic-gate rctl_get_info(name)
2640Sstevel@tonic-gate char *name
2650Sstevel@tonic-gate PREINIT:
2660Sstevel@tonic-gate rctlblk_t *blk1 = NULL;
2670Sstevel@tonic-gate rctlblk_t *blk2 = NULL;
2680Sstevel@tonic-gate rctlblk_t *tmp = NULL;
2690Sstevel@tonic-gate rctl_priv_t priv;
2700Sstevel@tonic-gate rctl_qty_t value;
2710Sstevel@tonic-gate int flags;
2720Sstevel@tonic-gate int ret;
2730Sstevel@tonic-gate int err = 0;
2740Sstevel@tonic-gate char string[24]; /* 24 will always hold a uint64_t */
2750Sstevel@tonic-gate PPCODE:
2760Sstevel@tonic-gate Newc(0, blk1, rctlblk_size(), char, rctlblk_t);
2770Sstevel@tonic-gate if (blk1 == NULL) {
2780Sstevel@tonic-gate err = 1;
2790Sstevel@tonic-gate goto out;
2800Sstevel@tonic-gate }
2810Sstevel@tonic-gate Newc(1, blk2, rctlblk_size(), char, rctlblk_t);
2820Sstevel@tonic-gate if (blk2 == NULL) {
2830Sstevel@tonic-gate err = 1;
2840Sstevel@tonic-gate goto out;
2850Sstevel@tonic-gate }
2860Sstevel@tonic-gate ret = getrctl(name, NULL, blk1, RCTL_FIRST);
2870Sstevel@tonic-gate if (ret != 0) {
2880Sstevel@tonic-gate err = 1;
2890Sstevel@tonic-gate goto out;
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate priv = rctlblk_get_privilege(blk1);
2920Sstevel@tonic-gate while (priv != RCPRIV_SYSTEM) {
2930Sstevel@tonic-gate tmp = blk2;
2940Sstevel@tonic-gate blk2 = blk1;
2950Sstevel@tonic-gate blk1 = tmp;
2960Sstevel@tonic-gate ret = getrctl(name, blk2, blk1, RCTL_NEXT);
2970Sstevel@tonic-gate if (ret != 0) {
2980Sstevel@tonic-gate err = 1;
2990Sstevel@tonic-gate goto out;
3000Sstevel@tonic-gate }
3010Sstevel@tonic-gate priv = rctlblk_get_privilege(blk1);
3020Sstevel@tonic-gate }
3030Sstevel@tonic-gate value = rctlblk_get_value(blk1);
3040Sstevel@tonic-gate flags = rctlblk_get_global_flags(blk1);
3050Sstevel@tonic-gate ret = sprintf(string, "%llu", value);
3060Sstevel@tonic-gate if (ret <= 0) {
3070Sstevel@tonic-gate err = 1;
3080Sstevel@tonic-gate }
3090Sstevel@tonic-gate out:
3100Sstevel@tonic-gate if (blk1)
3110Sstevel@tonic-gate Safefree(blk1);
3120Sstevel@tonic-gate if (blk2)
3130Sstevel@tonic-gate Safefree(blk2);
3140Sstevel@tonic-gate if (err)
3150Sstevel@tonic-gate XSRETURN(0);
3160Sstevel@tonic-gate
3170Sstevel@tonic-gate XPUSHs(sv_2mortal(newSVpv(string, 0)));
3180Sstevel@tonic-gate XPUSHs(sv_2mortal(newSViv(flags)));
3190Sstevel@tonic-gate XSRETURN(2);
3200Sstevel@tonic-gate
3210Sstevel@tonic-gate #
3220Sstevel@tonic-gate # pool_exists(name)
3230Sstevel@tonic-gate #
3240Sstevel@tonic-gate # Returns 0 a pool with the given name exists on the current system.
3250Sstevel@tonic-gate # Returns 1 if pools are disabled or the pool does not exist
3260Sstevel@tonic-gate #
3270Sstevel@tonic-gate # Used internally by project.pm to validate the project.pool attribute
3280Sstevel@tonic-gate #
3290Sstevel@tonic-gate # This function is private to Project.pm
3300Sstevel@tonic-gate void
3310Sstevel@tonic-gate pool_exists(name)
3320Sstevel@tonic-gate char *name
3330Sstevel@tonic-gate PREINIT:
3340Sstevel@tonic-gate pool_conf_t *conf;
3350Sstevel@tonic-gate pool_t *pool;
3363671Ssl108498 pool_status_t status;
3373671Ssl108498 int fd;
3380Sstevel@tonic-gate PPCODE:
3393671Ssl108498
3403671Ssl108498 /*
3413671Ssl108498 * Determine if pools are enabled using /dev/pool directly, as
3423671Ssl108498 * libpool may not be present.
3433671Ssl108498 */
3443671Ssl108498 if (getzoneid() != GLOBAL_ZONEID) {
3453671Ssl108498 XSRETURN_IV(1);
3463671Ssl108498 }
3473671Ssl108498 if ((fd = open("/dev/pool", O_RDONLY)) < 0) {
3483671Ssl108498 XSRETURN_IV(1);
3493671Ssl108498 }
3503671Ssl108498 if (ioctl(fd, POOL_STATUSQ, &status) < 0) {
3513671Ssl108498 (void) close(fd);
3523671Ssl108498 XSRETURN_IV(1);
3533671Ssl108498 }
3543671Ssl108498 close(fd);
3553671Ssl108498 if (status.ps_io_state != 1) {
3563671Ssl108498 XSRETURN_IV(1);
3573671Ssl108498 }
3583671Ssl108498
3593671Ssl108498 /*
3603671Ssl108498 * If pools are enabled, assume libpool is present.
3613671Ssl108498 */
3620Sstevel@tonic-gate conf = pool_conf_alloc();
3630Sstevel@tonic-gate if (conf == NULL) {
3640Sstevel@tonic-gate XSRETURN_IV(1);
3650Sstevel@tonic-gate }
3660Sstevel@tonic-gate if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY)) {
3670Sstevel@tonic-gate pool_conf_free(conf);
3680Sstevel@tonic-gate XSRETURN_IV(1);
3690Sstevel@tonic-gate }
3700Sstevel@tonic-gate pool = pool_get_pool(conf, name);
3710Sstevel@tonic-gate if (pool == NULL) {
3720Sstevel@tonic-gate pool_conf_close(conf);
3730Sstevel@tonic-gate pool_conf_free(conf);
3740Sstevel@tonic-gate XSRETURN_IV(1);
3750Sstevel@tonic-gate }
3760Sstevel@tonic-gate pool_conf_close(conf);
3770Sstevel@tonic-gate pool_conf_free(conf);
3780Sstevel@tonic-gate XSRETURN_IV(0);
3790Sstevel@tonic-gate
380