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