17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
5074e084ml * Common Development and Distribution License (the "License").
6074e084ml * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
217c478bdstevel@tonic-gate/*
22074e084ml * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bdstevel@tonic-gate * Use is subject to license terms.
247c478bdstevel@tonic-gate */
257c478bdstevel@tonic-gate
267c478bdstevel@tonic-gate#include <stdlib.h>
277c478bdstevel@tonic-gate#include <stdio.h>
287c478bdstevel@tonic-gate#include <libintl.h>
297c478bdstevel@tonic-gate#include <string.h>
307c478bdstevel@tonic-gate#include <sys/acctctl.h>
317c478bdstevel@tonic-gate
327c478bdstevel@tonic-gate#include "utils.h"
337c478bdstevel@tonic-gate#include "aconf.h"
347c478bdstevel@tonic-gate#include "res.h"
357c478bdstevel@tonic-gate
367c478bdstevel@tonic-gate/*
377c478bdstevel@tonic-gate * resource names
387c478bdstevel@tonic-gate */
397c478bdstevel@tonic-gatestatic ac_resname_t ac_names[] = {
407c478bdstevel@tonic-gate	/*
417c478bdstevel@tonic-gate	 * Process accounting resources
427c478bdstevel@tonic-gate	 */
437c478bdstevel@tonic-gate	{ AC_PROC,	AC_PROC_PID,		"pid"		},
447c478bdstevel@tonic-gate	{ AC_PROC,	AC_PROC_UID,		"uid"		},
457c478bdstevel@tonic-gate	{ AC_PROC,	AC_PROC_GID,		"gid"		},
467c478bdstevel@tonic-gate	{ AC_PROC,	AC_PROC_PROJID,		"projid"	},
477c478bdstevel@tonic-gate	{ AC_PROC,	AC_PROC_TASKID,		"taskid"	},
487c478bdstevel@tonic-gate	{ AC_PROC,	AC_PROC_CPU,		"cpu"		},
497c478bdstevel@tonic-gate	{ AC_PROC,	AC_PROC_TIME,		"time"		},
507c478bdstevel@tonic-gate	{ AC_PROC,	AC_PROC_COMMAND,	"command"	},
517c478bdstevel@tonic-gate	{ AC_PROC,	AC_PROC_TTY,		"tty"		},
527c478bdstevel@tonic-gate	{ AC_PROC,	AC_PROC_HOSTNAME,	"host"		},
537c478bdstevel@tonic-gate	{ AC_PROC,	AC_PROC_MICROSTATE,	"mstate"	},
547c478bdstevel@tonic-gate	{ AC_PROC,	AC_PROC_FLAG,		"flag"		},
557c478bdstevel@tonic-gate	{ AC_PROC,	AC_PROC_ANCPID,		"ancpid"	},
567c478bdstevel@tonic-gate	{ AC_PROC,	AC_PROC_WAIT_STATUS,	"wait-status"	},
577c478bdstevel@tonic-gate	{ AC_PROC,	AC_PROC_ZONENAME,	"zone"		},
587c478bdstevel@tonic-gate	{ AC_PROC,	AC_PROC_MEM,		"memory"	},
597c478bdstevel@tonic-gate
607c478bdstevel@tonic-gate	/*
617c478bdstevel@tonic-gate	 * Task accounting resources
627c478bdstevel@tonic-gate	 */
637c478bdstevel@tonic-gate	{ AC_TASK,	AC_TASK_TASKID,		"taskid"	},
647c478bdstevel@tonic-gate	{ AC_TASK,	AC_TASK_PROJID,		"projid"	},
657c478bdstevel@tonic-gate	{ AC_TASK,	AC_TASK_CPU,		"cpu"		},
667c478bdstevel@tonic-gate	{ AC_TASK,	AC_TASK_TIME,		"time"		},
677c478bdstevel@tonic-gate	{ AC_TASK,	AC_TASK_HOSTNAME,	"host"		},
687c478bdstevel@tonic-gate	{ AC_TASK,	AC_TASK_MICROSTATE,	"mstate"	},
697c478bdstevel@tonic-gate	{ AC_TASK,	AC_TASK_ANCTASKID,	"anctaskid"	},
707c478bdstevel@tonic-gate	{ AC_TASK,	AC_TASK_ZONENAME,	"zone"		},
717c478bdstevel@tonic-gate
727c478bdstevel@tonic-gate	/*
737c478bdstevel@tonic-gate	 * Flow accounting resources
747c478bdstevel@tonic-gate	 */
757c478bdstevel@tonic-gate	{ AC_FLOW,	AC_FLOW_SADDR,		"saddr"		},
767c478bdstevel@tonic-gate	{ AC_FLOW,	AC_FLOW_DADDR,		"daddr"		},
777c478bdstevel@tonic-gate	{ AC_FLOW,	AC_FLOW_SPORT,		"sport"		},
787c478bdstevel@tonic-gate	{ AC_FLOW,	AC_FLOW_DPORT,		"dport"		},
797c478bdstevel@tonic-gate	{ AC_FLOW,	AC_FLOW_PROTOCOL,	"proto"		},
807c478bdstevel@tonic-gate	{ AC_FLOW,	AC_FLOW_DSFIELD,	"dsfield"	},
817c478bdstevel@tonic-gate	{ AC_FLOW,	AC_FLOW_NBYTES,		"nbytes"	},
827c478bdstevel@tonic-gate	{ AC_FLOW,	AC_FLOW_NPKTS,		"npkts"		},
837c478bdstevel@tonic-gate	{ AC_FLOW,	AC_FLOW_CTIME,		"ctime"		},
847c478bdstevel@tonic-gate	{ AC_FLOW,	AC_FLOW_LSEEN,		"lseen"		},
857c478bdstevel@tonic-gate	{ AC_FLOW,	AC_FLOW_PROJID,		"projid"	},
867c478bdstevel@tonic-gate	{ AC_FLOW,	AC_FLOW_UID,		"uid"		},
877c478bdstevel@tonic-gate	{ AC_FLOW,	AC_FLOW_ANAME,		"action"	},
887c478bdstevel@tonic-gate
897c478bdstevel@tonic-gate	/*
90da14cebEric Cheng	 * Net accounting resources
91da14cebEric Cheng	 */
92da14cebEric Cheng
93da14cebEric Cheng	{ AC_NET,	AC_NET_NAME,		"name"		},
94da14cebEric Cheng	{ AC_NET,	AC_NET_EHOST,		"ehost"		},
95da14cebEric Cheng	{ AC_NET,	AC_NET_EDEST,		"edest"		},
96da14cebEric Cheng	{ AC_NET,	AC_NET_VLAN_TPID,	"vlan_pid"	},
97da14cebEric Cheng	{ AC_NET,	AC_NET_VLAN_TCI,	"vlan_tci"	},
98da14cebEric Cheng	{ AC_NET,	AC_NET_SAP,		"sap"		},
99da14cebEric Cheng	{ AC_NET,	AC_NET_PRIORITY,	"priority"	},
100da14cebEric Cheng	{ AC_NET,	AC_NET_BWLIMIT,		"bwlimit"	},
101da14cebEric Cheng	{ AC_NET,	AC_NET_DEVNAME,		"devname"	},
102da14cebEric Cheng	{ AC_NET,	AC_NET_SADDR,		"src_ip"	},
103da14cebEric Cheng	{ AC_NET,	AC_NET_DADDR,		"dst_ip"	},
104da14cebEric Cheng	{ AC_NET,	AC_NET_SPORT,		"src_port"	},
105da14cebEric Cheng	{ AC_NET,	AC_NET_DPORT,		"dst_port"	},
106da14cebEric Cheng	{ AC_NET,	AC_NET_PROTOCOL,	"protocol"	},
107da14cebEric Cheng	{ AC_NET,	AC_NET_DSFIELD,		"dsfield"	},
108da14cebEric Cheng	{ AC_NET,	AC_NET_CURTIME,		"curtime"	},
109da14cebEric Cheng	{ AC_NET,	AC_NET_IBYTES,		"ibytes"	},
110da14cebEric Cheng	{ AC_NET,	AC_NET_OBYTES,		"obytes"	},
111da14cebEric Cheng	{ AC_NET,	AC_NET_IPKTS,		"ipkts"		},
112da14cebEric Cheng	{ AC_NET,	AC_NET_OPKTS,		"opkts"		},
113da14cebEric Cheng	{ AC_NET,	AC_NET_IERRPKTS,	"ierrpkts"	},
114da14cebEric Cheng	{ AC_NET,	AC_NET_OERRPKTS,	"oerrpkts"	},
115da14cebEric Cheng
116da14cebEric Cheng	/*
1177c478bdstevel@tonic-gate	 * These are included for compatibility with old acctadm that
1187c478bdstevel@tonic-gate	 * didn't have resource groups for individual accounting types.
1197c478bdstevel@tonic-gate	 * It was possible to have resource "pid" enabled for task
1207c478bdstevel@tonic-gate	 * accounting even though we couldn't actually track it.
1217c478bdstevel@tonic-gate	 */
1227c478bdstevel@tonic-gate	{ AC_TASK,	AC_NONE,		"pid"		},
1237c478bdstevel@tonic-gate	{ AC_TASK,	AC_NONE,		"uid"		},
1247c478bdstevel@tonic-gate	{ AC_TASK,	AC_NONE,		"gid"		},
1257c478bdstevel@tonic-gate	{ AC_TASK,	AC_NONE,		"command"	},
1267c478bdstevel@tonic-gate	{ AC_TASK,	AC_NONE,		"tty"		},
1277c478bdstevel@tonic-gate	{ AC_TASK,	AC_NONE,		"flag"		},
1287c478bdstevel@tonic-gate
1297c478bdstevel@tonic-gate	{ AC_NONE,	AC_NONE,		NULL		}
1307c478bdstevel@tonic-gate};
1317c478bdstevel@tonic-gate
1327c478bdstevel@tonic-gate/*
1337c478bdstevel@tonic-gate * resource groups
1347c478bdstevel@tonic-gate */
1357c478bdstevel@tonic-gatestatic ac_group_t ac_groups[] = {
1367c478bdstevel@tonic-gate	{ AC_PROC,	"extended",
1377c478bdstevel@tonic-gate		{ AC_PROC_PID, AC_PROC_UID, AC_PROC_GID, AC_PROC_CPU,
1387c478bdstevel@tonic-gate		AC_PROC_TIME, AC_PROC_COMMAND, AC_PROC_TTY, AC_PROC_PROJID,
1397c478bdstevel@tonic-gate		AC_PROC_TASKID, AC_PROC_ANCPID, AC_PROC_WAIT_STATUS,
1407c478bdstevel@tonic-gate		AC_PROC_ZONENAME, AC_PROC_FLAG, AC_PROC_MEM,
1417c478bdstevel@tonic-gate		AC_PROC_MICROSTATE, AC_NONE } },
1427c478bdstevel@tonic-gate	{ AC_PROC,	"basic",
1437c478bdstevel@tonic-gate		{ AC_PROC_PID, AC_PROC_UID, AC_PROC_GID, AC_PROC_CPU,
1447c478bdstevel@tonic-gate		AC_PROC_TIME, AC_PROC_COMMAND, AC_PROC_TTY, AC_PROC_FLAG,
1457c478bdstevel@tonic-gate		AC_NONE } },
1467c478bdstevel@tonic-gate	{ AC_TASK,	"extended",
1477c478bdstevel@tonic-gate		{ AC_TASK_TASKID, AC_TASK_PROJID, AC_TASK_CPU, AC_TASK_TIME,
1487c478bdstevel@tonic-gate		AC_TASK_HOSTNAME, AC_TASK_MICROSTATE, AC_TASK_ANCTASKID,
1497c478bdstevel@tonic-gate		AC_TASK_ZONENAME, AC_NONE } },
1507c478bdstevel@tonic-gate	{ AC_TASK,	"basic",
1517c478bdstevel@tonic-gate		{ AC_TASK_TASKID, AC_TASK_PROJID, AC_TASK_CPU, AC_TASK_TIME,
1527c478bdstevel@tonic-gate		AC_NONE } },
1537c478bdstevel@tonic-gate	{ AC_FLOW,	"extended",
1547c478bdstevel@tonic-gate		{ AC_FLOW_SADDR, AC_FLOW_DADDR, AC_FLOW_SPORT, AC_FLOW_DPORT,
1557c478bdstevel@tonic-gate		AC_FLOW_PROTOCOL, AC_FLOW_DSFIELD, AC_FLOW_NBYTES,
1567c478bdstevel@tonic-gate		AC_FLOW_NPKTS, AC_FLOW_ANAME, AC_FLOW_CTIME, AC_FLOW_LSEEN,
1577c478bdstevel@tonic-gate		AC_FLOW_PROJID, AC_FLOW_UID, AC_NONE } },
1587c478bdstevel@tonic-gate	{ AC_FLOW,	"basic",
1597c478bdstevel@tonic-gate		{ AC_FLOW_SADDR, AC_FLOW_DADDR, AC_FLOW_SPORT, AC_FLOW_DPORT,
1607c478bdstevel@tonic-gate		AC_FLOW_PROTOCOL, AC_FLOW_NBYTES, AC_FLOW_NPKTS, AC_FLOW_ANAME,
1617c478bdstevel@tonic-gate		AC_NONE } },
162da14cebEric Cheng	{ AC_NET,	"extended",
163da14cebEric Cheng		{ AC_NET_NAME, AC_NET_EHOST, AC_NET_EDEST, AC_NET_VLAN_TPID,
164da14cebEric Cheng		AC_NET_VLAN_TCI, AC_NET_SAP, AC_NET_PRIORITY,
165da14cebEric Cheng		AC_NET_BWLIMIT, AC_NET_DEVNAME, AC_NET_SADDR, AC_NET_DADDR,
166da14cebEric Cheng		AC_NET_SPORT, AC_NET_DPORT, AC_NET_PROTOCOL, AC_NET_DSFIELD,
167da14cebEric Cheng		AC_NET_CURTIME, AC_NET_IBYTES, AC_NET_OBYTES, AC_NET_IPKTS,
168da14cebEric Cheng		AC_NET_OPKTS, AC_NET_IERRPKTS, AC_NET_OERRPKTS, AC_NONE } },
169da14cebEric Cheng	{ AC_NET,	"basic",
170da14cebEric Cheng		{ AC_NET_NAME, AC_NET_DEVNAME, AC_NET_EHOST, AC_NET_EDEST,
171da14cebEric Cheng		AC_NET_VLAN_TPID, AC_NET_VLAN_TCI, AC_NET_SAP,
172da14cebEric Cheng		AC_NET_PRIORITY, AC_NET_BWLIMIT, AC_NET_CURTIME, AC_NET_IBYTES,
173da14cebEric Cheng		AC_NET_OBYTES, AC_NET_IPKTS, AC_NET_OPKTS, AC_NET_IERRPKTS,
174da14cebEric Cheng		AC_NET_OERRPKTS, AC_NONE } },
1757c478bdstevel@tonic-gate	{ AC_NONE,	NULL,
1767c478bdstevel@tonic-gate		{ AC_NONE } }
1777c478bdstevel@tonic-gate};
1787c478bdstevel@tonic-gate
1797c478bdstevel@tonic-gate/*
1807c478bdstevel@tonic-gate * this function returns the id of the named resource
1817c478bdstevel@tonic-gate */
1827c478bdstevel@tonic-gatestatic int
1837c478bdstevel@tonic-gatename2id(char *name, int type)
1847c478bdstevel@tonic-gate{
1857c478bdstevel@tonic-gate	ac_resname_t *acname = ac_names;
1867c478bdstevel@tonic-gate	while (acname->ar_type != AC_NONE) {
1877c478bdstevel@tonic-gate		if (acname->ar_type == type &&
1887c478bdstevel@tonic-gate		    strcmp(acname->ar_name, name) == 0) {
1897c478bdstevel@tonic-gate			if (acname->ar_id == AC_NONE)
1907c478bdstevel@tonic-gate				/*
1917c478bdstevel@tonic-gate				 * For compatibility with older versions.
1927c478bdstevel@tonic-gate				 */
1937c478bdstevel@tonic-gate				return (-1);
1947c478bdstevel@tonic-gate			else
1957c478bdstevel@tonic-gate				return (acname->ar_id);
1967c478bdstevel@tonic-gate		}
1977c478bdstevel@tonic-gate		acname++;
1987c478bdstevel@tonic-gate	}
1997c478bdstevel@tonic-gate	return (0);
2007c478bdstevel@tonic-gate}
2017c478bdstevel@tonic-gate
2027c478bdstevel@tonic-gate/*
2037c478bdstevel@tonic-gate * this function gives name of the resource by its id
2047c478bdstevel@tonic-gate */
2057c478bdstevel@tonic-gatestatic char *
2067c478bdstevel@tonic-gateid2name(int id, int type)
2077c478bdstevel@tonic-gate{
2087c478bdstevel@tonic-gate	ac_resname_t *acname = ac_names;
2097c478bdstevel@tonic-gate	while (acname->ar_id != AC_NONE) {
2107c478bdstevel@tonic-gate		if (acname->ar_type == type &&
2117c478bdstevel@tonic-gate		    acname->ar_id == id)
2127c478bdstevel@tonic-gate			return (acname->ar_name);
2137c478bdstevel@tonic-gate		acname++;
2147c478bdstevel@tonic-gate	}
2157c478bdstevel@tonic-gate	return (NULL);
2167c478bdstevel@tonic-gate}
2177c478bdstevel@tonic-gate
2187c478bdstevel@tonic-gatestatic void
2197c478bdstevel@tonic-gateprintgroup(int type)
2207c478bdstevel@tonic-gate{
2217c478bdstevel@tonic-gate	int r, g, id;
2227c478bdstevel@tonic-gate
2237c478bdstevel@tonic-gate	for (g = 0; ac_groups[g].ag_type != AC_NONE; g++) {
2247c478bdstevel@tonic-gate		if (ac_groups[g].ag_type != type)
2257c478bdstevel@tonic-gate			continue;
2267c478bdstevel@tonic-gate		(void) printf("%-9s", ac_groups[g].ag_name);
2277c478bdstevel@tonic-gate		(void) printf("%s", id2name(ac_groups[g].ag_mem[0], type));
2287c478bdstevel@tonic-gate		for (r = 1; (id = ac_groups[g].ag_mem[r]) != AC_NONE; r++)
2297c478bdstevel@tonic-gate			(void) printf(",%s", id2name(id, type));
2307c478bdstevel@tonic-gate		(void) printf("\n");
2317c478bdstevel@tonic-gate	}
2327c478bdstevel@tonic-gate}
2337c478bdstevel@tonic-gate
2347c478bdstevel@tonic-gate
2357c478bdstevel@tonic-gate/*
2367c478bdstevel@tonic-gate * this function prints the list of resource groups and their members
2377c478bdstevel@tonic-gate */
2387c478bdstevel@tonic-gatevoid
2397c478bdstevel@tonic-gateprintgroups(int type)
2407c478bdstevel@tonic-gate{
2417c478bdstevel@tonic-gate	int header = 0;
2427c478bdstevel@tonic-gate
243da14cebEric Cheng	if ((type & AC_PROC) && (type & AC_TASK) && (type & AC_FLOW) &&
244da14cebEric Cheng	    (type & AC_NET)) {
2457c478bdstevel@tonic-gate		header = 1;
246da14cebEric Cheng	}
2477c478bdstevel@tonic-gate	if (type & AC_PROC) {
2487c478bdstevel@tonic-gate		if (header == 1)
2497c478bdstevel@tonic-gate			(void) printf("process:\n");
2507c478bdstevel@tonic-gate		printgroup(AC_PROC);
2517c478bdstevel@tonic-gate	}
2527c478bdstevel@tonic-gate	if (type & AC_TASK) {
2537c478bdstevel@tonic-gate		if (header == 1)
2547c478bdstevel@tonic-gate			(void) printf("task:\n");
2557c478bdstevel@tonic-gate		printgroup(AC_TASK);
2567c478bdstevel@tonic-gate	}
2577c478bdstevel@tonic-gate	if (type & AC_FLOW) {
2587c478bdstevel@tonic-gate		if (header == 1)
2597c478bdstevel@tonic-gate			(void) printf("flow:\n");
2607c478bdstevel@tonic-gate		printgroup(AC_FLOW);
2617c478bdstevel@tonic-gate	}
262da14cebEric Cheng	if (type & AC_NET) {
263da14cebEric Cheng		if (header == 1)
264da14cebEric Cheng			(void) printf("net:\n");
265da14cebEric Cheng		printgroup(AC_NET);
266da14cebEric Cheng	}
2677c478bdstevel@tonic-gate}
2687c478bdstevel@tonic-gate
2697c478bdstevel@tonic-gate/*
2707c478bdstevel@tonic-gate * this function sets the state of the particular resource
2717c478bdstevel@tonic-gate */
2727c478bdstevel@tonic-gatestatic void
2737c478bdstevel@tonic-gateresset(ac_res_t *res, int id, int state)
2747c478bdstevel@tonic-gate{
2757c478bdstevel@tonic-gate	ac_res_t *resp;
2767c478bdstevel@tonic-gate	resp = (ac_res_t *)((uintptr_t)res + (sizeof (ac_res_t) * (id - 1)));
2777c478bdstevel@tonic-gate	resp->ar_state = state;
2787c478bdstevel@tonic-gate	resp->ar_id = id;
2797c478bdstevel@tonic-gate}
2807c478bdstevel@tonic-gate
2817c478bdstevel@tonic-gate/*
2827c478bdstevel@tonic-gate * this function gets the state of the particular resource
2837c478bdstevel@tonic-gate */
2847c478bdstevel@tonic-gatestatic int
2857c478bdstevel@tonic-gateresget(ac_res_t *res, int id)
2867c478bdstevel@tonic-gate{
2877c478bdstevel@tonic-gate	ac_res_t *resp;
2887c478bdstevel@tonic-gate	resp = (ac_res_t *)((uintptr_t)res + (sizeof (ac_res_t) * (id - 1)));
2897c478bdstevel@tonic-gate	return (resp->ar_state);
2907c478bdstevel@tonic-gate}
2917c478bdstevel@tonic-gate
2927c478bdstevel@tonic-gate/*
2937c478bdstevel@tonic-gate * this function converts a string of resources into a buffer which then
2947c478bdstevel@tonic-gate * can be used for acctctl() system call
2957c478bdstevel@tonic-gate */
2967c478bdstevel@tonic-gatevoid
2977c478bdstevel@tonic-gatestr2buf(ac_res_t *buf, char *str, int state, int type)
2987c478bdstevel@tonic-gate{
2997c478bdstevel@tonic-gate	int i, j, id, ok;
3007c478bdstevel@tonic-gate	char *p, *g, *copy;
3017c478bdstevel@tonic-gate
3027c478bdstevel@tonic-gate	if (strcmp(str, AC_STR_NONE) == 0)
3037c478bdstevel@tonic-gate		return;
3047c478bdstevel@tonic-gate	/*
3057c478bdstevel@tonic-gate	 * Take a lap through str, processing resources, modifying buf copy
3067c478bdstevel@tonic-gate	 * as appropriate and making sure that all resource names are valid.
3077c478bdstevel@tonic-gate	 */
3087c478bdstevel@tonic-gate	if ((copy = malloc(strlen(str) + 1)) == NULL)
3097c478bdstevel@tonic-gate		die(gettext("not enough memory\n"));
3107c478bdstevel@tonic-gate	(void) memcpy(copy, str, strlen(str) + 1);
3117c478bdstevel@tonic-gate	p = strtok(copy, ", ");
3127c478bdstevel@tonic-gate	while (p != NULL) {
3137c478bdstevel@tonic-gate		/*
3147c478bdstevel@tonic-gate		 * check if str contains any resource groups
3157c478bdstevel@tonic-gate		 */
3167c478bdstevel@tonic-gate		for (ok = 0, i = 0; (g = ac_groups[i].ag_name) != NULL; i++) {
3177c478bdstevel@tonic-gate			if (strcmp(p, g) == 0 && ac_groups[i].ag_type == type) {
3187c478bdstevel@tonic-gate				for (j = 0; (id = ac_groups[i].ag_mem[j]) !=
3197c478bdstevel@tonic-gate				    AC_NONE; j++)
3207c478bdstevel@tonic-gate					resset(buf, id, state);
3217c478bdstevel@tonic-gate				ok = 1;
3227c478bdstevel@tonic-gate				break;
3237c478bdstevel@tonic-gate			}
3247c478bdstevel@tonic-gate		}
3257c478bdstevel@tonic-gate		if (ok == 0) {
3267c478bdstevel@tonic-gate			id = name2id(p, type);
3277c478bdstevel@tonic-gate			if (id > 0)
3287c478bdstevel@tonic-gate				resset(buf, id, state);
3297c478bdstevel@tonic-gate			else if (id == 0)
3307c478bdstevel@tonic-gate				die(gettext("unknown %s resource: %s\n"),
331074e084ml				    ac_type_name(type), p);
3327c478bdstevel@tonic-gate		}
3337c478bdstevel@tonic-gate		p = strtok(NULL, ", ");
3347c478bdstevel@tonic-gate	}
3357c478bdstevel@tonic-gate	free(copy);
3367c478bdstevel@tonic-gate}
3377c478bdstevel@tonic-gate
3387c478bdstevel@tonic-gate/*
3397c478bdstevel@tonic-gate * this function converts a buffer into a string of resource names.
3407c478bdstevel@tonic-gate * state (on/off) for resources of interest is selected by the third argument.
3417c478bdstevel@tonic-gate * accounting type is selected by the fourth argument.
3427c478bdstevel@tonic-gate * it is caller's responsibility to free the allocated string buffer.
3437c478bdstevel@tonic-gate */
3447c478bdstevel@tonic-gatechar *
3457c478bdstevel@tonic-gatebuf2str(ac_res_t *buffer, size_t bufsz, int state, int type)
3467c478bdstevel@tonic-gate{
3477c478bdstevel@tonic-gate	int i, j, ok, id;
3487c478bdstevel@tonic-gate	char *str, *g;
3497c478bdstevel@tonic-gate	ac_res_t *buf, *cur;
3507c478bdstevel@tonic-gate
3517c478bdstevel@tonic-gate	if ((buf = malloc(bufsz)) == NULL ||
3527c478bdstevel@tonic-gate	    (str = malloc(MAXRESLEN)) == NULL)
3537c478bdstevel@tonic-gate		die(gettext("not enough memory\n"));
3547c478bdstevel@tonic-gate	(void) memset(str, 0, MAXRESLEN);
3557c478bdstevel@tonic-gate	(void) memcpy(buf, buffer, bufsz);
3567c478bdstevel@tonic-gate	/*
3577c478bdstevel@tonic-gate	 * check if buf has any resource groups in it
3587c478bdstevel@tonic-gate	 */
3597c478bdstevel@tonic-gate	for (i = 0; (g = ac_groups[i].ag_name) != NULL; i++) {
3607c478bdstevel@tonic-gate		if (ac_groups[i].ag_type != type)
3617c478bdstevel@tonic-gate			continue;
3627c478bdstevel@tonic-gate		for (j = 0; (id = ac_groups[i].ag_mem[j]) != AC_NONE; j++) {
3637c478bdstevel@tonic-gate			ok = 1;
3647c478bdstevel@tonic-gate			if (resget(buf, id) != state) {
3657c478bdstevel@tonic-gate				ok = 0;
3667c478bdstevel@tonic-gate				break;
3677c478bdstevel@tonic-gate			}
3687c478bdstevel@tonic-gate		}
3697c478bdstevel@tonic-gate		if (ok) {	/* buf contains this resource group */
3707c478bdstevel@tonic-gate			if (strlen(str) != 0)
3717c478bdstevel@tonic-gate				(void) strcat(str, ",");
3727c478bdstevel@tonic-gate			(void) strcat(str, g);
3737c478bdstevel@tonic-gate			for (j = 0; (id = ac_groups[i].ag_mem[j]) != AC_NONE;
3747c478bdstevel@tonic-gate			    j++)
3757c478bdstevel@tonic-gate				resset(buf, id,
3767c478bdstevel@tonic-gate				    state == AC_ON ? AC_OFF : AC_ON);
3777c478bdstevel@tonic-gate			ok = 0;
3787c478bdstevel@tonic-gate		}
3797c478bdstevel@tonic-gate	}
3807c478bdstevel@tonic-gate	/*
3817c478bdstevel@tonic-gate	 * browse through the rest of the buf for all remaining resources
3827c478bdstevel@tonic-gate	 * that are not a part of any groups
3837c478bdstevel@tonic-gate	 */
3847c478bdstevel@tonic-gate	for (cur = buf; cur->ar_id != AC_NONE; cur++) {
3857c478bdstevel@tonic-gate		if (cur->ar_state == state) {
3867c478bdstevel@tonic-gate			if (strlen(str) != 0)
3877c478bdstevel@tonic-gate				(void) strcat(str, ",");
3887c478bdstevel@tonic-gate			if (id2name(cur->ar_id, type) == NULL)
3897c478bdstevel@tonic-gate				die(gettext("unknown %s resource id (%d)\n"),
390074e084ml				    ac_type_name(type), cur->ar_id);
3917c478bdstevel@tonic-gate			(void) strcat(str, id2name(cur->ar_id, type));
3927c478bdstevel@tonic-gate		}
3937c478bdstevel@tonic-gate	}
3947c478bdstevel@tonic-gate	if (strlen(str) == 0)
3957c478bdstevel@tonic-gate		(void) strcpy(str, AC_STR_NONE);
3967c478bdstevel@tonic-gate	free(buf);
3977c478bdstevel@tonic-gate	return (str);
3987c478bdstevel@tonic-gate}
399