10Sstevel@tonic-gate /*
2*12388SJohn.Sonnenschein@Sun.COM * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * Exacct.xs contains XS code for creating various exacct-related constants,
50Sstevel@tonic-gate * and for providing wrappers around exacct error handling and
60Sstevel@tonic-gate * accounting-related system calls. It also contains commonly-used utility
70Sstevel@tonic-gate * code shared by its sub-modules.
80Sstevel@tonic-gate */
90Sstevel@tonic-gate
100Sstevel@tonic-gate #include <string.h>
110Sstevel@tonic-gate #include "exacct_common.xh"
120Sstevel@tonic-gate
130Sstevel@tonic-gate /*
140Sstevel@tonic-gate * Pull in the file generated by extract_defines. This contains a table
150Sstevel@tonic-gate * of numeric constants and their string equivalents which have been extracted
160Sstevel@tonic-gate * from the various exacct header files by the extract_defines script.
170Sstevel@tonic-gate */
180Sstevel@tonic-gate #include "ExacctDefs.xi"
190Sstevel@tonic-gate
200Sstevel@tonic-gate /*
210Sstevel@tonic-gate * Object stash pointers - caching these speeds up the creation and
220Sstevel@tonic-gate * typechecking of perl objects by removing the need to do a hash lookup.
230Sstevel@tonic-gate * The peculiar variable names are so that typemaps can generate the correct
240Sstevel@tonic-gate * package name using the typemap '$Package' variable as the root of the name.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate HV *Sun_Solaris_Exacct_Catalog_stash;
270Sstevel@tonic-gate HV *Sun_Solaris_Exacct_File_stash;
280Sstevel@tonic-gate HV *Sun_Solaris_Exacct_Object_Item_stash;
290Sstevel@tonic-gate HV *Sun_Solaris_Exacct_Object_Group_stash;
300Sstevel@tonic-gate HV *Sun_Solaris_Exacct_Object__Array_stash;
310Sstevel@tonic-gate
320Sstevel@tonic-gate /*
330Sstevel@tonic-gate * Pointer to part of the hash tree built by define_catalog_constants in
340Sstevel@tonic-gate * Catalog.xs. This is used by catalog_id_str() when mapping from a catalog
350Sstevel@tonic-gate * to an id string.
360Sstevel@tonic-gate */
370Sstevel@tonic-gate HV *IdValueHash = NULL;
380Sstevel@tonic-gate
390Sstevel@tonic-gate /*
400Sstevel@tonic-gate * Last buffer size used for packing and unpacking exacct objects.
410Sstevel@tonic-gate */
420Sstevel@tonic-gate static int last_bufsz = 0;
430Sstevel@tonic-gate
440Sstevel@tonic-gate /*
450Sstevel@tonic-gate * Common utility code. This is placed here instead of in the sub-modules to
460Sstevel@tonic-gate * reduce the number of cross-module linker dependencies that are required,
470Sstevel@tonic-gate * although most of the code more properly belongs in the sub-modules.
480Sstevel@tonic-gate */
490Sstevel@tonic-gate
500Sstevel@tonic-gate /*
510Sstevel@tonic-gate * This function populates the various stash pointers used by the ::Exacct
520Sstevel@tonic-gate * module. It is called from each of the module BOOT sections to ensure the
530Sstevel@tonic-gate * stash pointers are initialised on startup.
540Sstevel@tonic-gate */
550Sstevel@tonic-gate void
init_stashes(void)560Sstevel@tonic-gate init_stashes(void)
570Sstevel@tonic-gate {
580Sstevel@tonic-gate if (Sun_Solaris_Exacct_Catalog_stash == NULL) {
590Sstevel@tonic-gate Sun_Solaris_Exacct_Catalog_stash =
600Sstevel@tonic-gate gv_stashpv(PKGBASE "::Catalog", TRUE);
610Sstevel@tonic-gate Sun_Solaris_Exacct_File_stash =
620Sstevel@tonic-gate gv_stashpv(PKGBASE "::File", TRUE);
630Sstevel@tonic-gate Sun_Solaris_Exacct_Object_Item_stash =
640Sstevel@tonic-gate gv_stashpv(PKGBASE "::Object::Item", TRUE);
650Sstevel@tonic-gate Sun_Solaris_Exacct_Object_Group_stash =
660Sstevel@tonic-gate gv_stashpv(PKGBASE "::Object::Group", TRUE);
670Sstevel@tonic-gate Sun_Solaris_Exacct_Object__Array_stash =
680Sstevel@tonic-gate gv_stashpv(PKGBASE "::Object::_Array", TRUE);
690Sstevel@tonic-gate }
700Sstevel@tonic-gate }
710Sstevel@tonic-gate
720Sstevel@tonic-gate /*
730Sstevel@tonic-gate * This function populates the @_Constants array in the specified package
740Sstevel@tonic-gate * based on the values extracted from the exacct header files by the
750Sstevel@tonic-gate * extract_defines script and written to the .xi file which is included above.
760Sstevel@tonic-gate * It also creates a const sub for each constant that returns the associcated
770Sstevel@tonic-gate * value. It should be called from the BOOT sections of modules that export
780Sstevel@tonic-gate * constants.
790Sstevel@tonic-gate */
800Sstevel@tonic-gate #define CONST_NAME "::_Constants"
810Sstevel@tonic-gate void
define_constants(const char * pkg,constval_t * cvp)820Sstevel@tonic-gate define_constants(const char *pkg, constval_t *cvp)
830Sstevel@tonic-gate {
840Sstevel@tonic-gate HV *stash;
850Sstevel@tonic-gate char *name;
860Sstevel@tonic-gate AV *constants;
870Sstevel@tonic-gate
880Sstevel@tonic-gate /* Create the new perl @_Constants variable. */
890Sstevel@tonic-gate stash = gv_stashpv(pkg, TRUE);
900Sstevel@tonic-gate name = New(0, name, strlen(pkg) + sizeof (CONST_NAME), char);
910Sstevel@tonic-gate PERL_ASSERT(name != NULL);
920Sstevel@tonic-gate strcpy(name, pkg);
930Sstevel@tonic-gate strcat(name, CONST_NAME);
940Sstevel@tonic-gate constants = perl_get_av(name, TRUE);
950Sstevel@tonic-gate Safefree(name);
960Sstevel@tonic-gate
970Sstevel@tonic-gate /* Populate @_Constants from the contents of the generated array. */
980Sstevel@tonic-gate for (; cvp->name != NULL; cvp++) {
990Sstevel@tonic-gate newCONSTSUB(stash, (char *)cvp->name, newSVuv(cvp->value));
1000Sstevel@tonic-gate av_push(constants, newSVpvn((char *)cvp->name, cvp->len));
1010Sstevel@tonic-gate }
1020Sstevel@tonic-gate }
1030Sstevel@tonic-gate #undef CONST_NAME
1040Sstevel@tonic-gate
1050Sstevel@tonic-gate /*
1060Sstevel@tonic-gate * Return a new Catalog object - only accepts an integer catalog value.
1070Sstevel@tonic-gate * Use this purely for speed when creating Catalog objects from other XS code.
1080Sstevel@tonic-gate * All other Catalog object creation should be done with the perl new() method.
1090Sstevel@tonic-gate */
1100Sstevel@tonic-gate SV*
new_catalog(uint32_t cat)1110Sstevel@tonic-gate new_catalog(uint32_t cat)
1120Sstevel@tonic-gate {
1130Sstevel@tonic-gate SV *iv, *ref;
1140Sstevel@tonic-gate
1150Sstevel@tonic-gate iv = newSVuv(cat);
1160Sstevel@tonic-gate ref = newRV_noinc(iv);
1170Sstevel@tonic-gate sv_bless(ref, Sun_Solaris_Exacct_Catalog_stash);
1180Sstevel@tonic-gate SvREADONLY_on(iv);
1190Sstevel@tonic-gate return (ref);
1200Sstevel@tonic-gate }
1210Sstevel@tonic-gate
1220Sstevel@tonic-gate /*
1230Sstevel@tonic-gate * Return the integer catalog value from the passed Catalog or IV.
1240Sstevel@tonic-gate * Calls croak() if the SV is not of the correct type.
1250Sstevel@tonic-gate */
1260Sstevel@tonic-gate ea_catalog_t
catalog_value(SV * catalog)1270Sstevel@tonic-gate catalog_value(SV *catalog)
1280Sstevel@tonic-gate {
1290Sstevel@tonic-gate SV *sv;
1300Sstevel@tonic-gate
1310Sstevel@tonic-gate /* If a reference, dereference and check it is a Catalog. */
1320Sstevel@tonic-gate if (SvROK(catalog)) {
1330Sstevel@tonic-gate sv = SvRV(catalog);
1340Sstevel@tonic-gate if (SvIOK(sv) &&
1350Sstevel@tonic-gate SvSTASH(sv) == Sun_Solaris_Exacct_Catalog_stash) {
1360Sstevel@tonic-gate return (SvIV(sv));
1370Sstevel@tonic-gate } else {
1380Sstevel@tonic-gate croak("Parameter is not a Catalog or integer");
1390Sstevel@tonic-gate }
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate /* For a plain IV, just return the value. */
1420Sstevel@tonic-gate } else if (SvIOK(catalog)) {
1430Sstevel@tonic-gate return (SvIV(catalog));
1440Sstevel@tonic-gate
1450Sstevel@tonic-gate /* Anything else is an error */
1460Sstevel@tonic-gate } else {
1470Sstevel@tonic-gate croak("Parameter is not a Catalog or integer");
1480Sstevel@tonic-gate }
1490Sstevel@tonic-gate }
1500Sstevel@tonic-gate
1510Sstevel@tonic-gate /*
1520Sstevel@tonic-gate * Return the string value of the id subfield of an ea_catalog_t.
1530Sstevel@tonic-gate */
1540Sstevel@tonic-gate char *
catalog_id_str(ea_catalog_t catalog)1550Sstevel@tonic-gate catalog_id_str(ea_catalog_t catalog)
1560Sstevel@tonic-gate {
1570Sstevel@tonic-gate static ea_catalog_t cat_val = ~0U;
1580Sstevel@tonic-gate static HV *cat_hash = NULL;
1590Sstevel@tonic-gate ea_catalog_t cat;
1600Sstevel@tonic-gate ea_catalog_t id;
1610Sstevel@tonic-gate char key[12]; /* Room for dec(2^32) digits. */
1620Sstevel@tonic-gate SV **svp;
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate cat = catalog & EXC_CATALOG_MASK;
1650Sstevel@tonic-gate id = catalog & EXD_DATA_MASK;
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate /* Fetch the correct id subhash if the catalog has changed. */
1680Sstevel@tonic-gate if (cat_val != cat) {
1690Sstevel@tonic-gate snprintf(key, sizeof (key), "%d", cat);
1700Sstevel@tonic-gate PERL_ASSERT(IdValueHash != NULL);
1710Sstevel@tonic-gate svp = hv_fetch(IdValueHash, key, strlen(key), FALSE);
1720Sstevel@tonic-gate if (svp == NULL) {
1730Sstevel@tonic-gate cat_val = ~0U;
1740Sstevel@tonic-gate cat_hash = NULL;
1750Sstevel@tonic-gate } else {
1760Sstevel@tonic-gate HV *hv;
1770Sstevel@tonic-gate
1780Sstevel@tonic-gate cat_val = cat;
1790Sstevel@tonic-gate hv = (HV *)SvRV(*svp);
1800Sstevel@tonic-gate PERL_ASSERT(hv != NULL);
1810Sstevel@tonic-gate svp = hv_fetch(hv, "value", 5, FALSE);
1820Sstevel@tonic-gate PERL_ASSERT(svp != NULL);
1830Sstevel@tonic-gate cat_hash = (HV *)SvRV(*svp);
1840Sstevel@tonic-gate PERL_ASSERT(cat_hash != NULL);
1850Sstevel@tonic-gate }
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate /* If we couldn't find the hash, it is a catalog we don't know about. */
1890Sstevel@tonic-gate if (cat_hash == NULL) {
1900Sstevel@tonic-gate return ("UNKNOWN_ID");
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate /* Fetch the value from the selected catalog and return it. */
1940Sstevel@tonic-gate snprintf(key, sizeof (key), "%d", id);
1950Sstevel@tonic-gate svp = hv_fetch(cat_hash, key, strlen(key), TRUE);
1960Sstevel@tonic-gate if (svp == NULL) {
1970Sstevel@tonic-gate return ("UNKNOWN_ID");
1980Sstevel@tonic-gate }
1990Sstevel@tonic-gate return (SvPVX(*svp));
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate
2020Sstevel@tonic-gate /*
2030Sstevel@tonic-gate * Create a new ::Object by wrapping an ea_object_t in a perl SV. This is used
2040Sstevel@tonic-gate * to wrap exacct records that have been read from a file, or packed records
2050Sstevel@tonic-gate * that have been inflated.
2060Sstevel@tonic-gate */
2070Sstevel@tonic-gate SV *
new_xs_ea_object(ea_object_t * ea_obj)2080Sstevel@tonic-gate new_xs_ea_object(ea_object_t *ea_obj)
2090Sstevel@tonic-gate {
2100Sstevel@tonic-gate xs_ea_object_t *xs_obj;
2110Sstevel@tonic-gate SV *sv_obj;
2120Sstevel@tonic-gate
2130Sstevel@tonic-gate /* Allocate space - use perl allocator. */
2140Sstevel@tonic-gate New(0, xs_obj, 1, xs_ea_object_t);
2150Sstevel@tonic-gate PERL_ASSERT(xs_obj != NULL);
2160Sstevel@tonic-gate xs_obj->ea_obj = ea_obj;
2170Sstevel@tonic-gate xs_obj->perl_obj = NULL;
2180Sstevel@tonic-gate sv_obj = NEWSV(0, 0);
2190Sstevel@tonic-gate PERL_ASSERT(sv_obj != NULL);
2200Sstevel@tonic-gate
2210Sstevel@tonic-gate /*
2220Sstevel@tonic-gate * Initialise according to the type of the passed exacct object,
2230Sstevel@tonic-gate * and bless the perl object into the appropriate class.
2240Sstevel@tonic-gate */
2250Sstevel@tonic-gate if (ea_obj->eo_type == EO_ITEM) {
2260Sstevel@tonic-gate if ((ea_obj->eo_catalog & EXT_TYPE_MASK) == EXT_EXACCT_OBJECT) {
2270Sstevel@tonic-gate INIT_EMBED_ITEM_FLAGS(xs_obj);
2280Sstevel@tonic-gate } else {
2290Sstevel@tonic-gate INIT_PLAIN_ITEM_FLAGS(xs_obj);
2300Sstevel@tonic-gate }
2310Sstevel@tonic-gate sv_setiv(newSVrv(sv_obj, NULL), PTR2IV(xs_obj));
2320Sstevel@tonic-gate sv_bless(sv_obj, Sun_Solaris_Exacct_Object_Item_stash);
2330Sstevel@tonic-gate } else {
2340Sstevel@tonic-gate INIT_GROUP_FLAGS(xs_obj);
2350Sstevel@tonic-gate sv_setiv(newSVrv(sv_obj, NULL), PTR2IV(xs_obj));
2360Sstevel@tonic-gate sv_bless(sv_obj, Sun_Solaris_Exacct_Object_Group_stash);
2370Sstevel@tonic-gate }
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate /*
2400Sstevel@tonic-gate * We are passing back a pointer masquerading as a perl IV,
2410Sstevel@tonic-gate * so make sure it can't be modified.
2420Sstevel@tonic-gate */
2430Sstevel@tonic-gate SvREADONLY_on(SvRV(sv_obj));
2440Sstevel@tonic-gate return (sv_obj);
2450Sstevel@tonic-gate }
2460Sstevel@tonic-gate
2470Sstevel@tonic-gate /*
2480Sstevel@tonic-gate * Convert the perl form of an ::Object into the corresponding exacct form.
2490Sstevel@tonic-gate * This is used prior to writing an ::Object to a file, or passing it to
2500Sstevel@tonic-gate * putacct. This is only required for embedded items and groups - for normal
2510Sstevel@tonic-gate * items it is a no-op.
2520Sstevel@tonic-gate */
2530Sstevel@tonic-gate ea_object_t *
deflate_xs_ea_object(SV * sv)2540Sstevel@tonic-gate deflate_xs_ea_object(SV *sv)
2550Sstevel@tonic-gate {
2560Sstevel@tonic-gate xs_ea_object_t *xs_obj;
2570Sstevel@tonic-gate ea_object_t *ea_obj;
2580Sstevel@tonic-gate
2590Sstevel@tonic-gate /* Get the source xs_ea_object_t. */
2600Sstevel@tonic-gate PERL_ASSERT(sv != NULL);
2610Sstevel@tonic-gate sv = SvRV(sv);
2620Sstevel@tonic-gate PERL_ASSERT(sv != NULL);
2630Sstevel@tonic-gate xs_obj = INT2PTR(xs_ea_object_t *, SvIV(sv));
2640Sstevel@tonic-gate PERL_ASSERT(xs_obj != NULL);
2650Sstevel@tonic-gate ea_obj = xs_obj->ea_obj;
2660Sstevel@tonic-gate PERL_ASSERT(ea_obj != NULL);
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate /* Break any list this object is a part of. */
2690Sstevel@tonic-gate ea_obj->eo_next = NULL;
2700Sstevel@tonic-gate
2710Sstevel@tonic-gate /* Deal with Items containing embedded Objects. */
2720Sstevel@tonic-gate if (IS_EMBED_ITEM(xs_obj)) {
2730Sstevel@tonic-gate xs_ea_object_t *child_xs_obj;
2740Sstevel@tonic-gate SV *perl_obj;
2750Sstevel@tonic-gate size_t bufsz;
2760Sstevel@tonic-gate
2770Sstevel@tonic-gate /* Get the underlying perl object an deflate that in turn. */
2780Sstevel@tonic-gate perl_obj = xs_obj->perl_obj;
2790Sstevel@tonic-gate PERL_ASSERT(perl_obj != NULL);
2800Sstevel@tonic-gate deflate_xs_ea_object(perl_obj);
2810Sstevel@tonic-gate perl_obj = SvRV(perl_obj);
2820Sstevel@tonic-gate PERL_ASSERT(perl_obj != NULL);
2830Sstevel@tonic-gate child_xs_obj = INT2PTR(xs_ea_object_t *, SvIV(perl_obj));
2840Sstevel@tonic-gate PERL_ASSERT(child_xs_obj->ea_obj != NULL);
2850Sstevel@tonic-gate
2860Sstevel@tonic-gate /* Free any existing object contents. */
2870Sstevel@tonic-gate if (ea_obj->eo_item.ei_object != NULL) {
2880Sstevel@tonic-gate ea_free(ea_obj->eo_item.ei_object,
2890Sstevel@tonic-gate ea_obj->eo_item.ei_size);
2900Sstevel@tonic-gate ea_obj->eo_item.ei_object = NULL;
2910Sstevel@tonic-gate ea_obj->eo_item.ei_size = 0;
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate
2940Sstevel@tonic-gate /* Pack the object. */
2950Sstevel@tonic-gate while (1) {
2960Sstevel@tonic-gate /* Use the last buffer size as a best guess. */
2970Sstevel@tonic-gate if (last_bufsz != 0) {
2980Sstevel@tonic-gate ea_obj->eo_item.ei_object =
2990Sstevel@tonic-gate ea_alloc(last_bufsz);
3000Sstevel@tonic-gate PERL_ASSERT(ea_obj->eo_item.ei_object != NULL);
3010Sstevel@tonic-gate } else {
3020Sstevel@tonic-gate ea_obj->eo_item.ei_object = NULL;
3030Sstevel@tonic-gate }
3040Sstevel@tonic-gate
3050Sstevel@tonic-gate /*
3060Sstevel@tonic-gate * Pack the object. If the buffer is too small,
3070Sstevel@tonic-gate * we will go around again with the correct size.
3080Sstevel@tonic-gate * If unsucessful, we will bail.
3090Sstevel@tonic-gate */
3100Sstevel@tonic-gate if ((bufsz = ea_pack_object(child_xs_obj->ea_obj,
3110Sstevel@tonic-gate ea_obj->eo_item.ei_object, last_bufsz)) == -1) {
3120Sstevel@tonic-gate ea_free(ea_obj->eo_item.ei_object, last_bufsz);
3130Sstevel@tonic-gate ea_obj->eo_item.ei_object = NULL;
3140Sstevel@tonic-gate return (NULL);
3150Sstevel@tonic-gate } else if (bufsz > last_bufsz) {
3160Sstevel@tonic-gate ea_free(ea_obj->eo_item.ei_object, last_bufsz);
3170Sstevel@tonic-gate last_bufsz = bufsz;
3180Sstevel@tonic-gate continue;
3190Sstevel@tonic-gate } else {
3200Sstevel@tonic-gate ea_obj->eo_item.ei_size = bufsz;
3210Sstevel@tonic-gate break;
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate }
3240Sstevel@tonic-gate
3250Sstevel@tonic-gate /* Deal with Groups. */
3260Sstevel@tonic-gate } else if (IS_GROUP(xs_obj)) {
3270Sstevel@tonic-gate MAGIC *mg;
3280Sstevel@tonic-gate AV *av;
3290Sstevel@tonic-gate int len, i;
3300Sstevel@tonic-gate xs_ea_object_t *ary_xs;
3310Sstevel@tonic-gate ea_object_t *ary_ea, *prev_ea;
3320Sstevel@tonic-gate
3330Sstevel@tonic-gate /* Find the AV underlying the tie. */
3340Sstevel@tonic-gate mg = mg_find(SvRV(xs_obj->perl_obj), 'P');
3350Sstevel@tonic-gate PERL_ASSERT(mg != NULL);
3360Sstevel@tonic-gate av = (AV*)SvRV(mg->mg_obj);
3370Sstevel@tonic-gate PERL_ASSERT(av != NULL);
3380Sstevel@tonic-gate
3390Sstevel@tonic-gate /*
3400Sstevel@tonic-gate * Step along the AV, deflating each object and linking it into
3410Sstevel@tonic-gate * the exacct group item list.
3420Sstevel@tonic-gate */
3430Sstevel@tonic-gate prev_ea = ary_ea = NULL;
3440Sstevel@tonic-gate len = av_len(av) + 1;
3450Sstevel@tonic-gate ea_obj->eo_group.eg_nobjs = 0;
3460Sstevel@tonic-gate ea_obj->eo_group.eg_objs = NULL;
3470Sstevel@tonic-gate for (i = 0; i < len; i++) {
3480Sstevel@tonic-gate /*
3490Sstevel@tonic-gate * Get the source xs_ea_object_t. If the current slot
3500Sstevel@tonic-gate * in the array is empty, skip it.
3510Sstevel@tonic-gate */
3520Sstevel@tonic-gate SV **ary_svp;
3530Sstevel@tonic-gate if ((ary_svp = av_fetch(av, i, FALSE)) == NULL) {
3540Sstevel@tonic-gate continue;
3550Sstevel@tonic-gate }
3560Sstevel@tonic-gate PERL_ASSERT(*ary_svp != NULL);
3570Sstevel@tonic-gate
3580Sstevel@tonic-gate /* Deflate it. */
3590Sstevel@tonic-gate ary_ea = deflate_xs_ea_object(*ary_svp);
3600Sstevel@tonic-gate PERL_ASSERT(ary_ea != NULL);
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate /* Link into the list. */
3630Sstevel@tonic-gate ary_ea->eo_next = NULL;
3640Sstevel@tonic-gate if (ea_obj->eo_group.eg_objs == NULL) {
3650Sstevel@tonic-gate ea_obj->eo_group.eg_objs = ary_ea;
3660Sstevel@tonic-gate }
3670Sstevel@tonic-gate ea_obj->eo_group.eg_nobjs++;
3680Sstevel@tonic-gate if (prev_ea != NULL) {
3690Sstevel@tonic-gate prev_ea->eo_next = ary_ea;
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate prev_ea = ary_ea;
3720Sstevel@tonic-gate }
3730Sstevel@tonic-gate }
3740Sstevel@tonic-gate return (ea_obj);
3750Sstevel@tonic-gate }
3760Sstevel@tonic-gate
3770Sstevel@tonic-gate /*
3780Sstevel@tonic-gate * Private Sun::Solaris::Exacct utility code.
3790Sstevel@tonic-gate */
3800Sstevel@tonic-gate
3810Sstevel@tonic-gate /*
3820Sstevel@tonic-gate * Return a string representation of an ea_error.
3830Sstevel@tonic-gate */
3840Sstevel@tonic-gate static const char *
error_str(int eno)3850Sstevel@tonic-gate error_str(int eno)
3860Sstevel@tonic-gate {
3870Sstevel@tonic-gate switch (eno) {
3880Sstevel@tonic-gate case EXR_OK:
3890Sstevel@tonic-gate return ("no error");
3900Sstevel@tonic-gate case EXR_SYSCALL_FAIL:
3910Sstevel@tonic-gate return ("system call failed");
3920Sstevel@tonic-gate case EXR_CORRUPT_FILE:
3930Sstevel@tonic-gate return ("corrupt file");
3940Sstevel@tonic-gate case EXR_EOF:
3950Sstevel@tonic-gate return ("end of file");
3960Sstevel@tonic-gate case EXR_NO_CREATOR:
3970Sstevel@tonic-gate return ("no creator");
3980Sstevel@tonic-gate case EXR_INVALID_BUF:
3990Sstevel@tonic-gate return ("invalid buffer");
4000Sstevel@tonic-gate case EXR_NOTSUPP:
4010Sstevel@tonic-gate return ("not supported");
4020Sstevel@tonic-gate case EXR_UNKN_VERSION:
4030Sstevel@tonic-gate return ("unknown version");
4040Sstevel@tonic-gate case EXR_INVALID_OBJ:
4050Sstevel@tonic-gate return ("invalid object");
4060Sstevel@tonic-gate default:
4070Sstevel@tonic-gate return ("unknown error");
4080Sstevel@tonic-gate }
4090Sstevel@tonic-gate }
4100Sstevel@tonic-gate
4110Sstevel@tonic-gate /*
4120Sstevel@tonic-gate * The XS code exported to perl is below here. Note that the XS preprocessor
4130Sstevel@tonic-gate * has its own commenting syntax, so all comments from this point on are in
4140Sstevel@tonic-gate * that form.
4150Sstevel@tonic-gate */
4160Sstevel@tonic-gate
4170Sstevel@tonic-gate MODULE = Sun::Solaris::Exacct PACKAGE = Sun::Solaris::Exacct
4180Sstevel@tonic-gate PROTOTYPES: ENABLE
4190Sstevel@tonic-gate
4200Sstevel@tonic-gate #
4210Sstevel@tonic-gate # Define the stash pointers if required and create and populate @_Constants.
4220Sstevel@tonic-gate #
4230Sstevel@tonic-gate BOOT:
4240Sstevel@tonic-gate init_stashes();
4250Sstevel@tonic-gate define_constants(PKGBASE, constants);
4260Sstevel@tonic-gate
4270Sstevel@tonic-gate #
4280Sstevel@tonic-gate # Return the last exacct error as a dual-typed SV. In a numeric context the
4290Sstevel@tonic-gate # SV will evaluate to the value of an EXR_* constant, in string context to a
4300Sstevel@tonic-gate # error message.
4310Sstevel@tonic-gate #
4320Sstevel@tonic-gate SV*
4330Sstevel@tonic-gate ea_error()
4340Sstevel@tonic-gate PREINIT:
4350Sstevel@tonic-gate int eno;
4360Sstevel@tonic-gate const char *msg;
4370Sstevel@tonic-gate CODE:
4380Sstevel@tonic-gate eno = ea_error();
4390Sstevel@tonic-gate msg = error_str(eno);
4400Sstevel@tonic-gate RETVAL = newSViv(eno);
4410Sstevel@tonic-gate sv_setpv(RETVAL, (char*) msg);
4420Sstevel@tonic-gate SvIOK_on(RETVAL);
4430Sstevel@tonic-gate OUTPUT:
4440Sstevel@tonic-gate RETVAL
4450Sstevel@tonic-gate
4460Sstevel@tonic-gate #
4470Sstevel@tonic-gate # Return a string describing the last error to be encountered. If the value
4480Sstevel@tonic-gate # returned by ea_error is EXR_SYSCALL_FAIL, a string describing the value of
4490Sstevel@tonic-gate # errno will be returned. For all other values returned by ea_error() a string
4500Sstevel@tonic-gate # describing the exacct error will be returned.
4510Sstevel@tonic-gate #
4520Sstevel@tonic-gate char*
4530Sstevel@tonic-gate ea_error_str()
4540Sstevel@tonic-gate PREINIT:
4550Sstevel@tonic-gate int eno;
4560Sstevel@tonic-gate CODE:
4570Sstevel@tonic-gate eno = ea_error();
4580Sstevel@tonic-gate if (eno == EXR_SYSCALL_FAIL) {
4590Sstevel@tonic-gate RETVAL = strerror(errno);
4600Sstevel@tonic-gate if (RETVAL == NULL) {
4610Sstevel@tonic-gate RETVAL = "unknown system error";
4620Sstevel@tonic-gate }
4630Sstevel@tonic-gate } else {
4640Sstevel@tonic-gate RETVAL = (char*) error_str(eno);
4650Sstevel@tonic-gate }
4660Sstevel@tonic-gate OUTPUT:
4670Sstevel@tonic-gate RETVAL
4680Sstevel@tonic-gate
4690Sstevel@tonic-gate #
4700Sstevel@tonic-gate # Return an accounting record for the specified task or process. idtype is
4710Sstevel@tonic-gate # either P_TASKID or P_PID and id is a process or task id.
4720Sstevel@tonic-gate #
4730Sstevel@tonic-gate SV*
4740Sstevel@tonic-gate getacct(idtype, id)
4750Sstevel@tonic-gate idtype_t idtype;
4760Sstevel@tonic-gate id_t id;
4770Sstevel@tonic-gate PREINIT:
4780Sstevel@tonic-gate int bufsz;
4790Sstevel@tonic-gate char *buf;
4800Sstevel@tonic-gate ea_object_t *ea_obj;
4810Sstevel@tonic-gate CODE:
4820Sstevel@tonic-gate /* Get the required accounting buffer. */
4830Sstevel@tonic-gate while (1) {
4840Sstevel@tonic-gate /* Use the last buffer size as a best guess. */
4850Sstevel@tonic-gate if (last_bufsz != 0) {
4860Sstevel@tonic-gate buf = ea_alloc(last_bufsz);
4870Sstevel@tonic-gate PERL_ASSERT(buf != NULL);
4880Sstevel@tonic-gate } else {
4890Sstevel@tonic-gate buf = NULL;
4900Sstevel@tonic-gate }
4910Sstevel@tonic-gate
4920Sstevel@tonic-gate /*
4930Sstevel@tonic-gate * get the accounting record. If the buffer is too small,
4940Sstevel@tonic-gate * we will go around again with the correct size.
4950Sstevel@tonic-gate * If unsucessful, we will bail.
4960Sstevel@tonic-gate */
4970Sstevel@tonic-gate if ((bufsz = getacct(idtype, id, buf, last_bufsz)) == -1) {
4980Sstevel@tonic-gate if (last_bufsz != 0) {
4990Sstevel@tonic-gate ea_free(buf, last_bufsz);
5000Sstevel@tonic-gate }
5010Sstevel@tonic-gate XSRETURN_UNDEF;
5020Sstevel@tonic-gate } else if (bufsz > last_bufsz) {
5030Sstevel@tonic-gate ea_free(buf, last_bufsz);
5040Sstevel@tonic-gate last_bufsz = bufsz;
5050Sstevel@tonic-gate continue;
5060Sstevel@tonic-gate } else {
5070Sstevel@tonic-gate break;
5080Sstevel@tonic-gate }
5090Sstevel@tonic-gate }
5100Sstevel@tonic-gate
5110Sstevel@tonic-gate /* Unpack the buffer. */
5120Sstevel@tonic-gate if (ea_unpack_object(&ea_obj, EUP_ALLOC, buf, bufsz) == -1) {
5130Sstevel@tonic-gate ea_free(buf, last_bufsz);
5140Sstevel@tonic-gate XSRETURN_UNDEF;
5150Sstevel@tonic-gate }
5160Sstevel@tonic-gate ea_free(buf, last_bufsz);
5170Sstevel@tonic-gate RETVAL = new_xs_ea_object(ea_obj);
5180Sstevel@tonic-gate OUTPUT:
5190Sstevel@tonic-gate RETVAL
5200Sstevel@tonic-gate
5210Sstevel@tonic-gate #
5220Sstevel@tonic-gate # Write an accounting record into the system accounting file. idtype is
5230Sstevel@tonic-gate # either P_TASKID or P_PID and id is a process or task id. value may be either
5240Sstevel@tonic-gate # an ::Exacct::Object, in which case it will be packed and inserted in the
5250Sstevel@tonic-gate # file, or a SV which will be converted to a string and inserted into the file.
5260Sstevel@tonic-gate #
5270Sstevel@tonic-gate SV*
5280Sstevel@tonic-gate putacct(idtype, id, value)
5290Sstevel@tonic-gate idtype_t idtype;
5300Sstevel@tonic-gate id_t id;
5310Sstevel@tonic-gate SV *value;
5320Sstevel@tonic-gate PREINIT:
5330Sstevel@tonic-gate HV *stash;
5340Sstevel@tonic-gate unsigned int bufsz;
5350Sstevel@tonic-gate int flags, ret;
5360Sstevel@tonic-gate char *buf;
5370Sstevel@tonic-gate CODE:
5380Sstevel@tonic-gate /* If it is an ::Object::Item or ::Object::Group, pack it. */
5390Sstevel@tonic-gate stash = SvROK(value) ? SvSTASH(SvRV(value)) : NULL;
5400Sstevel@tonic-gate if (stash == Sun_Solaris_Exacct_Object_Item_stash ||
5410Sstevel@tonic-gate stash == Sun_Solaris_Exacct_Object_Group_stash) {
5420Sstevel@tonic-gate ea_object_t *obj;
5430Sstevel@tonic-gate
5440Sstevel@tonic-gate /* Deflate the object. */
5450Sstevel@tonic-gate if ((obj = deflate_xs_ea_object(value)) == NULL) {
5460Sstevel@tonic-gate XSRETURN_NO;
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate
5490Sstevel@tonic-gate /* Pack the object. */
5500Sstevel@tonic-gate while (1) {
5510Sstevel@tonic-gate /* Use the last buffer size as a best guess. */
5520Sstevel@tonic-gate if (last_bufsz != 0) {
5530Sstevel@tonic-gate buf = ea_alloc(last_bufsz);
5540Sstevel@tonic-gate PERL_ASSERT(buf != NULL);
5550Sstevel@tonic-gate } else {
5560Sstevel@tonic-gate buf = NULL;
5570Sstevel@tonic-gate }
5580Sstevel@tonic-gate
5590Sstevel@tonic-gate /*
5600Sstevel@tonic-gate * Pack the object. If the buffer is too small, we
5610Sstevel@tonic-gate * will go around again with the correct size.
5620Sstevel@tonic-gate * If unsucessful, we will bail.
5630Sstevel@tonic-gate */
5640Sstevel@tonic-gate if ((bufsz = ea_pack_object(obj, buf, last_bufsz))
5650Sstevel@tonic-gate == -1) {
5660Sstevel@tonic-gate if (last_bufsz != 0) {
5670Sstevel@tonic-gate ea_free(buf, last_bufsz);
5680Sstevel@tonic-gate }
5690Sstevel@tonic-gate XSRETURN_NO;
5700Sstevel@tonic-gate } else if (bufsz > last_bufsz) {
5710Sstevel@tonic-gate ea_free(buf, last_bufsz);
5720Sstevel@tonic-gate last_bufsz = bufsz;
5730Sstevel@tonic-gate continue;
5740Sstevel@tonic-gate } else {
5750Sstevel@tonic-gate break;
5760Sstevel@tonic-gate }
5770Sstevel@tonic-gate }
5780Sstevel@tonic-gate flags = EP_EXACCT_OBJECT;
5790Sstevel@tonic-gate
5800Sstevel@tonic-gate /* Otherwise treat it as normal SV - convert to a string. */
5810Sstevel@tonic-gate } else {
5820Sstevel@tonic-gate buf = SvPV(value, bufsz);
5830Sstevel@tonic-gate flags = EP_RAW;
5840Sstevel@tonic-gate }
5850Sstevel@tonic-gate
5860Sstevel@tonic-gate /* Call putacct to write the buffer */
5870Sstevel@tonic-gate RETVAL = putacct(idtype, id, buf, bufsz, flags) == 0
5880Sstevel@tonic-gate ? &PL_sv_yes : &PL_sv_no;
5890Sstevel@tonic-gate
5900Sstevel@tonic-gate /* Clean up if we allocated a buffer. */
5910Sstevel@tonic-gate if (flags == EP_EXACCT_OBJECT) {
5920Sstevel@tonic-gate ea_free(buf, last_bufsz);
5930Sstevel@tonic-gate }
5940Sstevel@tonic-gate OUTPUT:
5950Sstevel@tonic-gate RETVAL
5960Sstevel@tonic-gate
5970Sstevel@tonic-gate #
5980Sstevel@tonic-gate # Write an accounting record for the specified task or process. idtype is
5990Sstevel@tonic-gate # either P_TASKID or P_PID, id is a process or task id and flags is either
6000Sstevel@tonic-gate # EW_PARTIAL or EW_INTERVAL.
6010Sstevel@tonic-gate #
6020Sstevel@tonic-gate int
6030Sstevel@tonic-gate wracct(idtype, id, flags)
6040Sstevel@tonic-gate idtype_t idtype;
6050Sstevel@tonic-gate id_t id;
6060Sstevel@tonic-gate int flags;
607