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