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