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