1
0
Files
irix-657m-src/eoe/cmd/xactl/xactl.c
2022-09-29 17:59:04 +03:00

1666 lines
41 KiB
C

/*
* xactl/xactl.c
* Extended Accounting Control
*
* Copyright 1997, Silicon Graphics, Inc.
* ALL RIGHTS RESERVED
*
* UNPUBLISHED -- Rights reserved under the copyright laws of the United
* States. Use of a copyright notice is precautionary only and does not
* imply publication or disclosure.
*
* U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
* in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or
* in similar or successor clauses in the FAR, or the DOD or NASA FAR
* Supplement. Contractor/manufacturer is Silicon Graphics, Inc.,
* 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
*
* THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY
* INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION,
* DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY
* PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON
* GRAPHICS, INC.
*/
#ident "$Revision: 1.1 $"
#include <sys/types.h>
#include <sys/arsess.h>
#include <sys/capability.h>
#include <sys/extacct.h>
#include <sys/syssgi.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <time.h>
#include <unistd.h>
/*
* Constants
*/
#define MAX_CMD_LEN 128
#define MY_NAME "xactl"
/* Global options */
typedef struct options {
char *progname; /* Name we were invoked with */
char *subcmd; /* Name of requested subcommand */
int got; /* Map of specified options */
int flags; /* Binary option flags */
ash_t ash; /* Array session handle */
int format; /* SPI format */
int length; /* SPI length */
int fill; /* SPI fill byte */
/* specific SPI fields */
char company[8]; /* spi_company */
char initiator[8]; /* spi_initiator */
char jobname[32]; /* spi_jobname */
char origin[16]; /* spi_origin */
char spi[16]; /* spi_spi */
int64_t exectime; /* spi_exectime */
int64_t subtime; /* spi_subtime */
int64_t waittime; /* spi_waittime */
} options_t;
#define OPT_BRIEF 0x00000001 /* Brief output */
#define OPT_VERBOSE 0x00000002 /* Debugging output */
#define GOT_ASH 0x00000001
#define GOT_FORMAT 0x00000002
#define GOT_LENGTH 0x00000004
#define GOT_CLEAR 0x00000008
#define GOT_DEFAULT 0x00000010
#define GOT_FILL 0x00000020
#define GOT_COMPANY 0x00000040
#define GOT_INITIATOR 0x00000080
#define GOT_ORIGIN 0x00000100
#define GOT_SPI 0x00000200
#define GOT_JOBNAME 0x00000400
#define GOT_EXECTIME 0x00000800
#define GOT_SUBTIME 0x00001000
#define GOT_WAITTIME 0x00002000
#define GOT_FORMAT_0 (GOT_CLEAR | GOT_DEFAULT | GOT_FILL)
#define GOT_FORMAT_1 (GOT_COMPANY | GOT_INITIATOR | GOT_ORIGIN | GOT_SPI)
#define GOT_FORMAT_2 (GOT_JOBNAME | GOT_EXECTIME | GOT_SUBTIME | \
GOT_WAITTIME)
#define GOT_FORMAT_1_OR_2 (GOT_FORMAT_1 | GOT_FORMAT_2)
/* Command handlers */
void doALLOWNEW(options_t *);
void doFLUSHALLSESSIONS(options_t *);
void doFLUSHSESSION(options_t *);
void doGETDFLTSPI(options_t *);
void doGETDFLTSPILEN(options_t *);
void doGETSAF(options_t *);
void doGETSPI(options_t *);
void doGETSPILEN(options_t *);
void doRESTRICTNEW(options_t *);
void doSESSIONINFO(options_t *);
void doSETDFLTSPI(options_t *);
void doSETDFLTSPILEN(options_t *);
void doSETSAF(options_t *);
void doSETSPI(options_t *);
void doSETSPILEN(options_t *);
typedef struct cmdinfo {
char *name;
void (*handler)(options_t *);
char *info;
} cmdinfo_t;
cmdinfo_t commands[] = {
{ "ALLOWNEW", doALLOWNEW,
"Allow array session to start new array sessions" },
{ "FLUSHALLSESSIONS", doFLUSHALLSESSIONS,
"Flush session accounting data for all array sessions" },
{ "FLUSHSESSION", doFLUSHSESSION,
"Flush session accounting data for an array session" },
{ "GETDFLTSPI", doGETDFLTSPI,
"Print default Service Provider Info" },
{ "GETDFLTSPILEN", doGETDFLTSPILEN,
"Print default length of Service Provider Info" },
{ "GETSAF", doGETSAF,
"Print session accounting format" },
{ "GETSPI", doGETSPI,
"Get Service Provider Info for an array session" },
{ "GETSPILEN", doGETSPILEN,
"Get length of Service Provider Info for an array session" },
{ "RESTRICTNEW", doRESTRICTNEW,
"Restrict array session from starting new array sessions" },
{ "SESSIONINFO", doSESSIONINFO,
"Print session accounting information" },
{ "SETDFLTSPI", doSETDFLTSPI,
"Set the default Service Provider Info" },
{ "SETDFLTSPILEN", doSETDFLTSPILEN,
"Set the default length of Service Provider Info" },
{ "SETSAF", doSETSAF,
"Set the session accounting format" },
{ "SETSPI", doSETSPI,
"Set Service Provider Info for an array session" },
{ "SETSPILEN", doSETSPILEN,
"Set length of Service Provider Info for an array session" },
};
#define NUM_CMDS (sizeof(commands) / sizeof(commands[0]))
/* Utility functions */
void assert_privilege(options_t *, cap_value_t);
int build_spi(options_t *, char *, int);
int parse_ash(char **, int, ash_t *);
int parse_int(char **, int, int *, int, int);
int parse_string(char **, int, char *, int);
int parse_ticks(char **, int, int64_t *);
void print_spi(options_t *, void *);
void print_usage(void);
int
main(int argc, char **argv)
{
cmdinfo_t *command = NULL;
int error = 0;
int i;
options_t options;
/* Initialize the options buffer */
bzero(&options, sizeof(options));
options.progname = argv[0];
/* Be intolerant of too few arguments */
if (argc < 2) {
print_usage();
exit(0);
}
/* Parse the generic command line args */
for (i = 1; i < argc; ++i) {
if (strcmp(argv[i], "-b") == 0 ||
strcmp(argv[i], "-brief") == 0)
{
options.flags |= OPT_BRIEF;
}
else if (strcmp(argv[i], "-clear") == 0) {
options.got |= GOT_CLEAR;
options.fill = '\0';
}
else if (strcmp(argv[i], "-company") == 0) {
if (parse_string(argv, i, options.company, 8) == 0) {
options.got |= GOT_COMPANY;
}
else {
error = 1;
}
++i;
}
else if (strcmp(argv[i], "-default") == 0) {
options.got |= GOT_DEFAULT;
options.fill = '\0';
}
else if (strcmp(argv[i], "-exectime") == 0) {
if (parse_ticks(argv, i, &options.exectime) == 0) {
options.got |= GOT_EXECTIME;
}
else {
error = 1;
}
++i;
}
else if (strcmp(argv[i], "-fill") == 0) {
if (parse_int(argv, i, &options.fill, 0, 255) == 0) {
options.got |= GOT_FILL;
}
else {
error = 1;
}
++i;
}
else if (strcmp(argv[i], "-format") == 0) {
if (parse_int(argv, i, &options.format, 0, 2) == 0) {
options.got |= GOT_FORMAT;
}
else {
error = 1;
}
++i;
}
else if (strcmp(argv[i], "-h") == 0 ||
strcmp(argv[i], "-ash") == 0)
{
if (parse_ash(argv, i, &options.ash) == 0) {
options.got |= GOT_ASH;
}
else {
error = 1;
}
++ i;
}
else if (strcmp(argv[i], "-initiator") == 0) {
if (parse_string(argv, i, options.initiator, 8) == 0) {
options.got |= GOT_INITIATOR;
}
else {
error = 1;
}
++i;
}
else if (strcmp(argv[i], "-jobname") == 0) {
if (parse_string(argv, i, options.jobname, 32) == 0) {
options.got |= GOT_JOBNAME;
}
else {
error = 1;
}
++i;
}
else if (strcmp(argv[i], "-length") == 0) {
if (parse_int(argv, i, &options.length, 0, MAX_SPI_LEN)
== 0)
{
options.got |= GOT_LENGTH;
}
else {
error = 1;
}
++i;
}
else if (strcmp(argv[i], "-origin") == 0) {
if (parse_string(argv, i, options.origin, 16) == 0) {
options.got |= GOT_ORIGIN;
}
else {
error = 1;
}
++i;
}
else if (strcmp(argv[i], "-spi") == 0) {
if (parse_string(argv, i, options.spi, 8) == 0) {
options.got |= GOT_SPI;
}
else {
error = 1;
}
++i;
}
else if (strcmp(argv[i], "-subtime") == 0) {
if (parse_ticks(argv, i, &options.subtime) == 0) {
options.got |= GOT_SUBTIME;
}
else {
error = 1;
}
++i;
}
else if (strcmp(argv[i], "-v") == 0) {
options.flags |= OPT_VERBOSE;
}
else if (strcmp(argv[i], "-waittime") == 0) {
if (parse_ticks(argv, i, &options.waittime) == 0) {
options.got |= GOT_WAITTIME;
}
else {
error = 1;
}
++i;
}
else if (argv[i][0] == '-') {
fprintf(stderr,
"%s: \"%s\" is not a valid option\n",
argv[0], argv[i]);
error = 1;
}
else if (options.subcmd == NULL) {
options.subcmd = argv[i];
}
else {
fprintf(stderr,
"%s: \"%s\" is extraneous, a subcommand has "
"already been specified\n",
argv[0], argv[i]);
error = 1;
}
}
/* If no ASH was specified, use our own */
if (!(options.got & GOT_ASH)) {
options.ash = getash();
}
/* If we are being verbose, spill our guts */
if (options.flags & OPT_VERBOSE) {
printf("\n");
printf("program: %s\n", options.progname);
printf("subcmd: %s\n",
(options.subcmd == NULL) ? "<none>" : options.subcmd);
printf("brief: %s\n",
(options.flags & OPT_BRIEF) ? "yes" : "no");
printf("ASH: 0x%016llx\n", options.ash);
printf("\n");
printf("\"got\" flags: 0x%08x (0=%x 1=%x 2=%x)\n",
options.got,
options.got & GOT_FORMAT_0,
options.got & GOT_FORMAT_1,
options.got & GOT_FORMAT_2);
if (options.got & GOT_FORMAT) {
printf("-format %d\n", options.format);
}
if (options.got & GOT_LENGTH) {
printf("-length %d\n", options.length);
}
if (options.got & GOT_CLEAR) {
printf("-clear\n");
}
if (options.got & GOT_FILL) {
printf("-fill 0x%02x\n", options.fill);
}
if (options.got & GOT_COMPANY) {
printf("-company \"%.8s\"\n", options.company);
}
if (options.got & GOT_INITIATOR) {
printf("-initiator \"%.8s\"\n", options.initiator);
}
if (options.got & GOT_ORIGIN) {
printf("-origin \"%.16s\"\n", options.origin);
}
if (options.got & GOT_SPI) {
printf("-spi \"%.16s\"\n", options.spi);
}
if (options.got & GOT_JOBNAME) {
printf("-jobname \"%.32s\"\n", options.jobname);
}
if (options.got & GOT_EXECTIME) {
printf("-exectime 0x%llx\n", options.exectime);
}
if (options.got & GOT_SUBTIME) {
printf("-subtime 0x%llx\n", options.subtime);
}
if (options.got & GOT_WAITTIME) {
printf("-waittime 0x%llx\n", options.waittime);
}
printf("\n");
}
/* Make sure a subcommand was specified */
if (options.subcmd == NULL) {
fprintf(stderr,
"%s: no subcommand was specified\n",
argv[0]);
error = 1;
}
/* Make sure we recognize the subcommand */
else {
for (i = 0; command == NULL && i < NUM_CMDS; ++i) {
if (strcasecmp(options.subcmd, commands[i].name) == 0)
{
command = &commands[i];
}
}
if (command == NULL) {
fprintf(stderr,
"%s: \"%s\" is not a valid subcommand\n",
argv[0], options.subcmd);
error = 1;
}
}
/* Bail out now if a command-line error occurred */
if (error) {
print_usage();
exit(1);
}
/* Call the appropriate handler */
(command->handler)(&options);
exit(0);
}
void
doALLOWNEW(options_t *options)
{
/* Allow the array session to do newarraysess() */
assert_privilege(options, CAP_ACCT_MGT);
if (!(options->flags & OPT_BRIEF)) {
printf("Allowing new array sessions in ASH 0x%016llx\n",
options->ash);
}
if (arsop(ARSOP_ALLOW_NEW, options->ash, NULL, 0) != 0) {
perror("ARSOP_ALLOW_NEW");
exit(2);
}
}
void
doFLUSHALLSESSIONS(options_t *options)
{
ash_t *ashlist;
int i;
int numashs;
int size;
/* Make sure the user is allowed to do this */
assert_privilege(options, CAP_ACCT_MGT);
/* Allocate an initial block of storage for the array of ASHs */
size = 200;
ashlist = malloc(size * sizeof(ash_t));
if (ashlist == NULL) {
fprintf(stderr,
"%s: unable to allocate storage for ASH list\n",
options->progname);
exit(2);
}
/* Keep syssgi'ing until we don't get an ENOMEM error */
numashs = syssgi(SGI_ENUMASHS, ashlist, size);
while (numashs < 0 && errno == ENOMEM) {
size += 100;
ashlist = realloc(ashlist, size * sizeof(ash_t));
if (ashlist == NULL) {
fprintf(stderr,
"%s: unable to reallocate storage for %d "
"ASHs\n",
options->progname, size);
exit(2);
}
numashs = syssgi(SGI_ENUMASHS, ashlist, size);
}
/* If syssgi failed for another reason, bail out */
if (numashs < 0) {
perror("SGI_ENUMASHS");
exit(2);
}
/* Say what we are about to do if desired */
if (!(options->flags & OPT_BRIEF)) {
printf("\nFlushing session accounting data for the following "
"array sessions:\n");
}
/* Invoke ARSOP_FLUSHACCT on each ASH in the list */
for (i = 0; i < numashs; ++i) {
if (!(options->flags & OPT_BRIEF)) {
printf(" 0x%016llx\n", ashlist[i]);
}
if (arsop(ARSOP_FLUSHACCT, ashlist[i], NULL, 0) != 0) {
perror("ARSOP_FLUSHACCT");
exit(2);
}
}
}
void
doFLUSHSESSION(options_t *options)
{
/* Flush session accounting data for an array session */
assert_privilege(options, CAP_ACCT_MGT);
if (!(options->flags & OPT_BRIEF)) {
printf("Flushing session accounting data for ASH 0x%016llx\n",
options->ash);
}
if (arsop(ARSOP_FLUSHACCT, options->ash, NULL, 0) != 0) {
perror("ARSOP_FLUSHACCT");
exit(2);
}
}
void
doGETDFLTSPI(options_t *options)
{
/* Print the default Service Provider Information */
char spibuf[MAX_SPI_LEN];
int maxspilen;
/* Determine the length of the service provider info if necessary */
if (!(options->got & GOT_LENGTH)) {
if (arsctl(ARSCTL_GETDFLTSPILEN,
&options->length,
sizeof(options->length)) != 0)
{
perror("ARSCTL_GETDFLTSPILEN");
exit(2);
}
}
/* Extract the default service provider info */
if (arsctl(ARSCTL_GETDFLTSPI, spibuf, options->length) != 0) {
perror("ARSCTL_GETDFLTSPI");
exit(2);
}
/* Print it out */
if (!(options->flags & OPT_BRIEF)) {
printf("\nDefault service provider information\n");
printf("------------------------------------\n");
}
print_spi(options, spibuf);
}
void
doGETDFLTSPILEN(options_t *options)
{
/* Print the default Service Provider Information length */
int length;
/* Extract it from the kernel */
if (arsctl(ARSCTL_GETDFLTSPILEN, &length, sizeof(length)) != 0) {
perror("ARSCTL_GETDFLTSPILEN");
exit(2);
}
/* Print it out in the desired style */
if (options->flags & OPT_BRIEF) {
printf("%d\n", length);
}
else {
printf("Default length of service provider information "
"in new array sessions is %d\n",
length);
}
}
void
doGETSAF(options_t *options)
{
/* Print the session accounting format */
int saf;
/* Extract it from the kernel */
if (arsctl(ARSCTL_GETSAF, &saf, sizeof(saf)) != 0) {
perror("ARSCTL_GETSAF");
exit(2);
}
/* Print it out in the desired style */
if (options->flags & OPT_BRIEF) {
printf("%d\n", saf);
}
else {
printf("Session accounting records are being written in "
"format %d\n",
saf);
}
}
void
doGETSPI(options_t *options)
{
/* Print the Service Provider Information for an array session */
char spibuf[MAX_SPI_LEN];
int maxspilen;
/* Determine the length of the service provider info if necessary */
if (!(options->got & GOT_LENGTH)) {
if (arsop(ARSOP_GETSPILEN,
options->ash,
&options->length,
sizeof(options->length)) != 0)
{
perror("ARSOP_GETSPILEN");
exit(2);
}
}
/* Extract the default service provider info */
if (arsop(ARSOP_GETSPI, options->ash, spibuf, options->length) != 0) {
perror("ARSOP_GETSPI");
exit(2);
}
/* Print it out */
if (!(options->flags & OPT_BRIEF)) {
printf("\nService provider information for ASH 0x%016llx:\n",
options->ash);
printf("-----------------------------------------------"
"---------\n");
}
print_spi(options, spibuf);
}
void
doGETSPILEN(options_t *options)
{
/* Print the Service Provider Information length of an array session */
int length;
/* Extract it from the kernel */
if (arsop(ARSOP_GETSPILEN,
options->ash,
&length,
sizeof(length)) != 0)
{
perror("ARSOP_GETSPILEN");
exit(2);
}
/* Print it out in the desired style */
if (options->flags & OPT_BRIEF) {
printf("%d\n", length);
}
else {
printf("Maximum size of service provider information in ASH "
"0x%016llx is %d\n",
options->ash, length);
}
}
void
doRESTRICTNEW(options_t *options)
{
/* Restrict the array session from doing newarraysess() */
if (!(options->flags & OPT_BRIEF)) {
printf("Restricting new array sessions in ASH 0x%016llx\n",
options->ash);
}
if (arsop(ARSOP_RESTRICT_NEW, options->ash, NULL, 0) != 0) {
perror("ARSOP_RESTRICT_NEW");
exit(2);
}
}
void
doSESSIONINFO(options_t *options)
{
/* Print accounting information for an array session */
arsess_t arsess;
shacct_t shacct;
/* Gather the information from the kernel */
if (arsop(ARSOP_GETINFO, options->ash, &arsess, sizeof(arsess)) != 0) {
perror("ARSOP_GETINFO");
exit(2);
}
if ((arsess.as_flag & AS_GOT_CHGD_INFO) &&
arsop(ARSOP_GETCHGD, options->ash, &shacct, sizeof(shacct)) != 0)
{
perror("ARSOP_GETCHGD");
exit(2);
}
/* Print it out */
if (options->flags & OPT_BRIEF) {
printf("%lld\n", arsess.as_prid);
printf("%s", ctime(&arsess.as_start));
printf("%d\n", arsess.as_ticks);
printf("%d\n", arsess.as_pid);
printf("0x%08x\n", arsess.as_flag);
printf("%d\n", arsess.as_nice);
if (arsess.as_flag & AS_GOT_CHGD_INFO) {
printf("%lld %lld\n",
arsess.as_timers.ac_utime,
shacct.sha_timers.ac_utime);
printf("%lld %lld\n",
arsess.as_timers.ac_stime,
shacct.sha_timers.ac_stime);
printf("%lld %lld\n",
arsess.as_timers.ac_bwtime,
shacct.sha_timers.ac_bwtime);
printf("%lld %lld\n",
arsess.as_timers.ac_rwtime,
shacct.sha_timers.ac_rwtime);
printf("%lld %lld\n",
arsess.as_timers.ac_qwtime,
shacct.sha_timers.ac_qwtime);
printf("%lld %lld\n",
arsess.as_counts.ac_mem,
shacct.sha_counts.ac_mem);
printf("%lld %lld\n",
arsess.as_counts.ac_swaps,
shacct.sha_counts.ac_swaps);
printf("%lld %lld\n",
arsess.as_counts.ac_chr,
shacct.sha_counts.ac_chr);
printf("%lld %lld\n",
arsess.as_counts.ac_chw,
shacct.sha_counts.ac_chw);
printf("%lld %lld\n",
arsess.as_counts.ac_br,
shacct.sha_counts.ac_br);
printf("%lld %lld\n",
arsess.as_counts.ac_bw,
shacct.sha_counts.ac_bw);
printf("%lld %lld\n",
arsess.as_counts.ac_syscr,
shacct.sha_counts.ac_syscr);
printf("%lld %lld\n",
arsess.as_counts.ac_syscw,
shacct.sha_counts.ac_syscw);
}
else {
printf("%lld\n",
arsess.as_timers.ac_utime);
printf("%lld\n",
arsess.as_timers.ac_stime);
printf("%lld\n",
arsess.as_timers.ac_bwtime);
printf("%lld\n",
arsess.as_timers.ac_rwtime);
printf("%lld\n",
arsess.as_timers.ac_qwtime);
printf("%lld\n",
arsess.as_counts.ac_mem);
printf("%lld\n",
arsess.as_counts.ac_swaps);
printf("%lld\n",
arsess.as_counts.ac_chr);
printf("%lld\n",
arsess.as_counts.ac_chw);
printf("%lld\n",
arsess.as_counts.ac_br);
printf("%lld\n",
arsess.as_counts.ac_bw);
printf("%lld\n",
arsess.as_counts.ac_syscr);
printf("%lld\n",
arsess.as_counts.ac_syscw);
}
}
else {
printf("\nInformation about ASH 0x%016llx:\n", options->ash);
printf("-----------------------------------------\n");
printf("Project ID: %lld\n", arsess.as_prid);
printf("Start time: %s", ctime(&arsess.as_start));
printf("Total ticks: %d\n", arsess.as_ticks);
printf("Initial PID: %d\n", arsess.as_pid);
printf("Flags: 0x%08x ", arsess.as_flag);
if (arsess.as_flag & AS_NEW_RESTRICTED) {
printf(" NEW_RESTRICTED");
}
if (arsess.as_flag & AS_GOT_CHGD_INFO) {
printf(" GOT_CHGD_INFO");
}
if (arsess.as_flag & AS_FLUSHED) {
printf(" FLUSHED");
}
printf("\n");
printf("Initial nice: %d\n", arsess.as_nice);
printf("\n");
if (arsess.as_flag & AS_GOT_CHGD_INFO) {
printf("User time: %14lld ns "
"(%lld ns already charged)\n",
arsess.as_timers.ac_utime,
shacct.sha_timers.ac_utime);
printf("System time: %14lld ns "
"(%lld ns already charged)\n",
arsess.as_timers.ac_stime,
shacct.sha_timers.ac_stime);
printf("Block I/O wait: %14lld ns "
"(%lld ns already charged)\n",
arsess.as_timers.ac_bwtime,
shacct.sha_timers.ac_bwtime);
printf("Raw I/O wait: %14lld ns "
"(%lld ns already charged)\n",
arsess.as_timers.ac_rwtime,
shacct.sha_timers.ac_rwtime);
printf("Run queue wait: %14lld ns "
"(%lld ns already charged)\n",
arsess.as_timers.ac_qwtime,
shacct.sha_timers.ac_qwtime);
printf("\n");
printf("Mem integral: %8lld "
"(%lld already charged)\n",
arsess.as_counts.ac_mem,
shacct.sha_counts.ac_mem);
printf("# swaps: %8lld "
"(%lld already charged)\n",
arsess.as_counts.ac_swaps,
shacct.sha_counts.ac_swaps);
printf("Bytes read: %8lld "
"(%lld already charged)\n",
arsess.as_counts.ac_chr,
shacct.sha_counts.ac_chr);
printf("Bytes written: %8lld "
"(%lld already charged)\n",
arsess.as_counts.ac_chw,
shacct.sha_counts.ac_chw);
printf("Blocks read: %8lld "
"(%lld already charged)\n",
arsess.as_counts.ac_br,
shacct.sha_counts.ac_br);
printf("Blocks written: %8lld "
"(%lld already charged)\n",
arsess.as_counts.ac_bw,
shacct.sha_counts.ac_bw);
printf("Read syscalls: %8lld "
"(%lld already charged)\n",
arsess.as_counts.ac_syscr,
shacct.sha_counts.ac_syscr);
printf("Write syscalls: %8lld "
"(%lld already charged)\n",
arsess.as_counts.ac_syscw,
shacct.sha_counts.ac_syscw);
printf("\n");
}
else {
printf("User time: %lld ns\n",
arsess.as_timers.ac_utime);
printf("System time: %lld ns\n",
arsess.as_timers.ac_stime);
printf("Block I/O wait: %lld ns\n",
arsess.as_timers.ac_bwtime);
printf("Raw I/O wait: %lld ns\n",
arsess.as_timers.ac_rwtime);
printf("Run queue wait: %lld ns\n",
arsess.as_timers.ac_qwtime);
printf("\n");
printf("Mem integral: %lld\n",
arsess.as_counts.ac_mem);
printf("# swaps: %lld\n",
arsess.as_counts.ac_swaps);
printf("Bytes read: %lld\n",
arsess.as_counts.ac_chr);
printf("Bytes written: %lld\n",
arsess.as_counts.ac_chw);
printf("Blocks read: %lld\n",
arsess.as_counts.ac_br);
printf("Blocks written: %lld\n",
arsess.as_counts.ac_bw);
printf("Read syscalls: %lld\n",
arsess.as_counts.ac_syscr);
printf("Write syscalls: %lld\n",
arsess.as_counts.ac_syscw);
printf("\n");
}
}
}
void
doSETDFLTSPI(options_t *options)
{
/* Set the default service provider information */
char spibuf[MAX_SPI_LEN];
int maxspilen;
/* Make sure the user is allowed to do this */
assert_privilege(options, CAP_SYSINFO_MGT);
/* Determine the maximum length of the service provider info */
if (arsctl(ARSCTL_GETDFLTSPILEN, &maxspilen, sizeof(maxspilen)) != 0) {
perror("ARSCTL_GETDFLTSPILEN");
exit(2);
}
/* Make sure the user's length isn't too big */
if (options->got & GOT_LENGTH) {
if (options->length > maxspilen) {
fprintf(stderr,
"%s: specified length %d exceeds the current "
"maximum of %d\n",
options->progname, options->length, maxspilen);
exit(1);
}
}
else {
options->length = maxspilen;
options->got |= GOT_LENGTH;
}
/* Start with a clean buffer */
bzero(spibuf, options->length);
/* Build the service provider information */
if (build_spi(options, spibuf, options->length) < 0) {
exit(1);
}
/* Be verbose if necessary */
if (!(options->flags & OPT_BRIEF)) {
printf("\nAbout to set the following default service provider "
"information:\n");
printf("----------------------------------------------------"
"------------\n");
print_spi(options, spibuf);
}
/* Do it */
if (arsctl(ARSCTL_SETDFLTSPI, spibuf, options->length) != 0) {
perror("ARSCTL_SETDFLTSPI");
exit(2);
}
}
void
doSETDFLTSPILEN(options_t *options)
{
/* Set the default length of service provider information */
/* Make sure the user is allowed to do this */
assert_privilege(options, CAP_SYSINFO_MGT);
/* Make sure a length was specified in the first place */
if (!(options->got & GOT_LENGTH)) {
fprintf(stderr,
"%s: the -length option is required for "
"setdfltspilen\n",
options->progname);
exit(1);
}
/* Be verbose if necessary */
if (!(options->flags & OPT_BRIEF)) {
printf("Setting default length of service provider "
"information to %d\n",
options->length);
}
/* Do it */
if (arsctl(ARSCTL_SETDFLTSPILEN,
&options->length,
sizeof(options->length)) != 0)
{
perror("ARSCTL_SETDFLTSPILEN");
exit(2);
}
}
void
doSETSAF(options_t *options)
{
/* Set the session accounting format */
/* Make sure the user is allowed to do this */
assert_privilege(options, CAP_SYSINFO_MGT);
/* Make sure a format was specified in the first place */
if (!(options->got & GOT_FORMAT)) {
fprintf(stderr,
"%s: the -format option is required for setsaf",
options->progname);
exit(1);
}
/* The initial command-line options parsing allows format "0" */
/* but that isn't a valid session accounting format. */
if (options->format < 1 || options->format > 2) {
fprintf(stderr,
"%s: %d is not a valid session accounting format\n",
options->progname, options->format);
exit(1);
}
/* Be verbose if necessary */
if (!(options->flags & OPT_BRIEF)) {
printf("Setting the session accounting format to %d\n",
options->format);
}
/* Do it */
if (arsctl(ARSCTL_SETSAF, &options->format, sizeof(options->format))
!= 0)
{
perror("ARSCTL_SETSAF");
exit(2);
}
}
void
doSETSPI(options_t *options)
{
/* Set the service provider information for an array session */
char spibuf[MAX_SPI_LEN];
int maxspilen;
/* Make sure the user is allowed to do this */
assert_privilege(options, CAP_ACCT_MGT);
/* Determine the maximum length of the service provider info */
if (arsop(ARSOP_GETSPILEN,
options->ash,
&maxspilen,
sizeof(maxspilen)) != 0)
{
perror("ARSOP_GETSPILEN");
exit(2);
}
/* Make sure the user's length isn't too big */
if (options->got & GOT_LENGTH) {
if (options->length > maxspilen) {
fprintf(stderr,
"%s: specified length %d exceeds the current "
"maximum of %d\n",
options->progname, options->length, maxspilen);
exit(1);
}
}
else {
options->length = maxspilen;
options->got |= GOT_LENGTH;
}
/* Start with a clean buffer */
bzero(spibuf, options->length);
/* Build the service provider information */
if (build_spi(options, spibuf, options->length) < 0) {
exit(1);
}
/* Proceed differently if -default was specified */
if (options->got & GOT_DEFAULT) {
if (!(options->flags & OPT_BRIEF)) {
printf("Restoring default service provider "
"information for ASH 0x%016llx\n",
options->ash);
}
if (arsop(ARSOP_SETSPI, options->ash, NULL, 0) != 0) {
perror("ARSOP_SETSPI");
exit(2);
}
}
else {
/* Be verbose if necessary */
if (!(options->flags & OPT_BRIEF)) {
printf("\nAbout to set service provider information "
"for ASH 0x%016llx to:\n",
options->ash);
printf("----------------------------------------------"
"--------------------------\n");
print_spi(options, spibuf);
}
/* Do it */
if (arsop(ARSOP_SETSPI, options->ash, spibuf, options->length)
!= 0)
{
perror("ARSOP_SETSPI");
exit(2);
}
}
}
void
doSETSPILEN(options_t *options)
{
/* Set the length of service provider info for an array session */
/* Make sure the user is allowed to do this */
assert_privilege(options, CAP_ACCT_MGT);
/* Make sure a length was specified in the first place */
if (!(options->got & GOT_LENGTH)) {
fprintf(stderr,
"%s: the -length option is required for "
"setspilen\n",
options->progname);
exit(1);
}
/* Be verbose if necessary */
if (!(options->flags & OPT_BRIEF)) {
printf("Setting size of service provider "
"information for ASH 0x%016llx to %d\n",
options->ash,
options->length);
}
/* Do it */
if (arsop(ARSOP_SETSPILEN,
options->ash,
&options->length,
sizeof(options->length)) != 0)
{
perror("ARSOP_SETSPILEN");
exit(2);
}
}
/*
* assert_privilege
* Checks if the user has the specified capability. If not,
* an error message is printed and the program exits. Code
* stolen brazenly from mkpart (which got it from su?).
*/
void
assert_privilege(options_t *options, cap_value_t cap)
{
cap_t cap_state;
int cap_enabled;
/* Find out what style of capabilities are done here */
cap_enabled = sysconf(_SC_CAP);
if (cap_enabled < 0) {
cap_enabled = CAP_SYS_DISABLED;
}
/* In a strict or augmented superuser environment, an effective */
/* UID of 0 (root) is proof enough */
if (cap_enabled == CAP_SYS_DISABLED ||
cap_enabled == CAP_SYS_SUPERUSER)
{
if (geteuid() == 0) {
return; /* Success */
}
fprintf(stderr,
"%s: you must be root to use that function\n",
options->progname);
exit(1);
}
/* In a no-superuser environment, we must check the specific */
/* capabilities */
cap_state = cap_get_proc();
if (cap_state == NULL) {
perror("cap_get_proc");
exit(2);
}
if (!CAP_ID_ISSET(cap, cap_state->cap_effective)) {
fprintf(stderr,
"%s: you must have %s capability to use that "
"function\n",
options->progname,
cap_value_to_text(cap));
exit(1);
}
return; /* Success */
}
/*
* build_spi
* Given an options_t with command-line options, build a buffer
* containing the corresponding service provider information.
* An error will occur if the buffer is not large enough to hold
* the specified fields, if incompatible options are specified,
* or if an invalid value is specified. Returns 0 if successful,
* -1 if not.
*/
int
build_spi(options_t *options, char *spibuf, int buflen)
{
/* Infer the format from the specified options if necessary */
if (!(options->got & GOT_FORMAT)) {
if (options->got & GOT_FORMAT_0) {
options->format = 0;
}
else if (options->got & GOT_FORMAT_2) {
options->format = 2;
}
else {
options->format = 1;
}
if (options->flags & OPT_VERBOSE) {
printf("Inferred SPI format %d\n\n", options->format);
}
}
/* Infer the length from the format if necessary */
if (!(options->got & GOT_LENGTH)) {
switch (options->format) {
case 0:
options->length = buflen;
break;
case 1:
options->length = sizeof(acct_spi_t);
break;
case 2:
options->length = sizeof(acct_spi_2_t);
break;
default:
fprintf(stderr,
"%s: internal error at line %d\n",
options->progname, __LINE__);
break;
}
if (options->flags & OPT_VERBOSE) {
printf("Inferred SPI length %d\n\n", options->length);
}
}
/* Make sure no conflicting options were specified */
if (((options->got & GOT_FORMAT_0) &&
(options->got & GOT_FORMAT_1_OR_2))
||
((options->got & GOT_FILL) &&
(options->got & GOT_CLEAR) &&
(options->fill != 0))
||
((options->got & GOT_DEFAULT) &&
(options->got & GOT_FILL))
||
((options->got & GOT_DEFAULT) &&
(options->got & GOT_CLEAR)))
{
fprintf(stderr,
"%s: conflicting service provider info options\n",
options->progname);
return -1;
}
/* If an explicit format was specified, don't allow options from */
/* other formats */
if (options->got & GOT_FORMAT) {
if ((options->format == 0 &&
(options->got & GOT_FORMAT_1_OR_2))
||
(options->format == 1 &&
(options->got & GOT_FORMAT_0))
||
(options->format == 1 &&
(options->got & GOT_FORMAT_2))
||
(options->format == 2 &&
(options->got & GOT_FORMAT_0)))
{
fprintf(stderr,
"%s: service provider options inconsistent "
"with format %d were specified\n",
options->progname, options->format);
return -1;
}
}
/* Make sure the length is consistent with the format */
if ((options->format == 1 &&
options->length < sizeof(acct_spi_t))
||
(options->format == 2 &&
options->length < sizeof(acct_spi_2_t)))
{
fprintf(stderr,
"%s: SPI length too small (%d bytes) for format %d\n",
options->progname, options->length, options->format);
return -1;
}
/* It is now safe to start filling the SPI buffer with data */
switch (options->format) {
case 0:
memset(spibuf, options->fill, options->length);
break;
case 1:
{
acct_spi_t *s = (acct_spi_t *) spibuf;
strncpy(s->spi_company,
options->company,
sizeof(options->company));
strncpy(s->spi_initiator,
options->initiator,
sizeof(options->initiator));
strncpy(s->spi_origin,
options->origin,
sizeof(options->origin));
strncpy(s->spi_spi,
options->spi,
sizeof(options->spi));
break;
}
case 2:
{
acct_spi_2_t *s = (acct_spi_2_t *) spibuf;
strncpy(s->spi_company,
options->company,
sizeof(options->company));
strncpy(s->spi_initiator,
options->initiator,
sizeof(options->initiator));
strncpy(s->spi_origin,
options->origin,
sizeof(options->origin));
strncpy(s->spi_spi,
options->spi,
sizeof(options->spi));
strncpy(s->spi_jobname,
options->jobname,
sizeof(options->jobname));
s->spi_exectime = options->exectime;
s->spi_subtime = options->subtime;
s->spi_waittime = options->waittime;
break;
}
default:
fprintf(stderr,
"%s: internal error at line %d",
options->progname, __LINE__);
exit(2);
}
return 0;
}
/*
* parse_ash
* Parse an ASH argument to a command line option. The specified
* arg number should be the index of the option itself, the ASH
* is assumed to be the next argument. An error occurs if the
* argument does not exist or is invalid. Returns 0 if successful,
* or -1 if not.
*/
int
parse_ash(char **argv, int optnum, ash_t *resultp)
{
char *ptr = NULL;
int argnum = optnum + 1;
ash_t value;
if (argv[argnum] == NULL) {
fprintf(stderr,
"%s: %s requires an argument\n",
argv[0], argv[optnum]);
return -1;
}
errno = 0;
value = strtoll(argv[argnum], &ptr, 0);
if (ptr == NULL || *ptr != '\0' || errno != 0 || value < 0LL) {
fprintf(stderr,
"%s: \"%s\" is not a valid ASH argument for %s\n",
argv[0],
argv[argnum],
argv[optnum]);
return -1;
}
*resultp = value;
return 0;
}
/*
* parse_int
* Parse an integer argument to a command line option. The specified
* arg number should be the index of the option itself, the integer
* is assumed to be the next argument. An error occurs if the
* argument does not exist, is invalid, or is outside of the
* specified range. Returns 0 if successful or -1 if not.
*/
int
parse_int(char **argv, int optnum, int *resultp, int minval, int maxval)
{
char *ptr = NULL;
int argnum = optnum + 1;
long value;
if (argv[argnum] == NULL) {
fprintf(stderr,
"%s: %s requires an argument\n",
argv[0], argv[optnum]);
return -1;
}
errno = 0;
value = strtol(argv[argnum], &ptr, 0);
if (ptr == NULL || *ptr != '\0' || errno != 0) {
fprintf(stderr,
"%s: \"%s\" is not a valid integer argument for %s\n",
argv[0], argv[argnum], argv[optnum]);
return -1;
}
if (value < minval || value > maxval) {
fprintf(stderr,
"%s: the argument for %s must be between %d and %d\n",
argv[0], argv[optnum], minval, maxval);
return -1;
}
*resultp = (int) value;
return 0;
}
/*
* parse_string
* Parse a string argument to a command line option. The specified
* arg number should be the index of the option itself, the string
* is assumed to be the next argument. An error occurs if the
* string does not exist or is bigger than the specified buffer.
* Returns 0 if successful, -1 if not.
*/
int
parse_string(char **argv, int optnum, char *buffer, int maxlen)
{
int strnum = optnum + 1;
if (argv[strnum] == NULL) {
fprintf(stderr,
"%s: %s requires an argument\n",
argv[0], argv[optnum]);
return -1;
}
if (strlen(argv[strnum]) > maxlen) {
fprintf(stderr,
"%s: argument for %s (\"%s\") is too long\n",
argv[0],
argv[optnum],
argv[strnum]);
return -1;
}
strncpy(buffer, argv[strnum], maxlen);
return 0;
}
/*
* parse_ticks
* Parse a "ticks" argument to a command line option. The specified
* arg number should be the index of the option itself, the "ticks"
* value is assumed to be the next argument. An error occurs if the
* argument does not exist, or is invalid. Returns 0 if successful,
* or -1 if not.
*/
int
parse_ticks(char **argv, int optnum, int64_t *resultp)
{
char *ptr = NULL;
int argnum = optnum + 1;
int64_t value;
if (argv[argnum] == NULL) {
fprintf(stderr,
"%s: %s requires an argument\n",
argv[0], argv[optnum]);
return -1;
}
errno = 0;
value = strtoll(argv[argnum], &ptr, 0);
if (ptr == NULL || *ptr != '\0' || errno != 0) {
fprintf(stderr,
"%s: \"%s\" is not a valid argument for %s\n",
argv[0], argv[argnum], argv[optnum]);
return -1;
}
*resultp = value;
return 0;
}
/*
* print_spi
* Print the specified service provider information in human-readable
* format.
*/
void
print_spi(options_t *options, void *bufptr)
{
int format;
/* Infer the format of the service provider info if necessary */
if (!(options->got & GOT_FORMAT)) {
if (options->length == sizeof(acct_spi_t)) {
format = 1;
}
else if (options->length == sizeof(acct_spi_2_t)) {
format = 2;
}
else {
format = 0;
}
}
else {
format = options->format;
}
/* Proceed according to the format */
switch (format) {
case 0:
{
char *spibuf = (char *) bufptr;
int i ;
for (i = 0; i < options->length; ++i) {
if (i % 16 == 0) {
printf("\n");
}
else if (i % 4 == 0) {
printf(" ");
}
printf("%02x", spibuf[i]);
}
printf("\n");
break;
}
case 1:
{
acct_spi_t *spi = (acct_spi_t *) bufptr;
if (options->flags & OPT_BRIEF) {
printf("%s\n", spi->spi_company);
printf("%s\n", spi->spi_initiator);
printf("%s\n", spi->spi_origin);
printf("%s\n", spi->spi_spi);
}
else {
printf("Company : %.8s\n", spi->spi_company);
printf("Initiator: %.8s\n", spi->spi_initiator);
printf("Origin : %.16s\n", spi->spi_origin);
printf("SPI : %.16s\n", spi->spi_spi);
}
break;
}
case 2:
{
acct_spi_2_t *spi = (acct_spi_2_t *) bufptr;
if (options->flags & OPT_BRIEF) {
printf("%s\n", spi->spi_company);
printf("%s\n", spi->spi_initiator);
printf("%s\n", spi->spi_origin);
printf("%s\n", spi->spi_spi);
printf("%s\n", spi->spi_jobname);
printf("%lld\n", spi->spi_subtime);
printf("%lld\n", spi->spi_exectime);
printf("%lld\n", spi->spi_waittime);
}
else {
printf("Company : %.8s\n", spi->spi_company);
printf("Initiator: %.8s\n", spi->spi_initiator);
printf("Origin : %.16s\n", spi->spi_origin);
printf("SPI : %.16s\n", spi->spi_spi);
printf("Job Name : %.32s\n", spi->spi_jobname);
printf("Sub Time : %lld\n", spi->spi_subtime);
printf("Exec Time: %lld\n", spi->spi_exectime);
printf("Wait Time: %lld\n", spi->spi_waittime);
}
break;
}
default:
{
fprintf(stderr,
"%s: internal error at line %d\n",
options->progname, __LINE__);
exit(2);
}
}
}
/*
* print_usage
* Print a usage message to stderr
*/
void
print_usage(void)
{
int i;
fprintf(stderr,
"\nUsage: " MY_NAME " <options> <subcmd> [<args>...]\n");
fprintf(stderr, "options:\n");
fprintf(stderr, " -ash <array-session-handle>\n");
fprintf(stderr, " -brief\n");
fprintf(stderr, " -format <fmt>\n");
fprintf(stderr, " -length <len>\n");
fprintf(stderr, "subcommands:\n");
for (i = 0; i < NUM_CMDS; ++i) {
fprintf(stderr, " %-16s %s\n",
commands[i].name,
commands[i].info);
}
fprintf(stderr, "Specifying Service Provider Info:\n");
fprintf(stderr, " format 0 (unformatted):\n");
fprintf(stderr, " -clear\n");
fprintf(stderr, " -fill <byte>\n");
fprintf(stderr, " format 1:\n");
fprintf(stderr, " -company <up-to-8-chars>\n");
fprintf(stderr, " -initiator <up-to-8-chars>\n");
fprintf(stderr, " -origin <up-to-16-chars>\n");
fprintf(stderr, " -spi <up-to-16-chars>\n");
fprintf(stderr, " format 2 adds these:\n");
fprintf(stderr, " -jobname <up-to-32-chars>\n");
fprintf(stderr, " -subtime <ticks>\n");
fprintf(stderr, " -exectime <ticks>\n");
fprintf(stderr, " -waittime <ticks>\n");
fprintf(stderr, "\n");
}