xref: /illumos-gate/usr/src/cmd/acctadm/res.c (revision 074e084f68dd0b08686612bec695a0cfe249da6d)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*074e084fSml93401  * Common Development and Distribution License (the "License").
6*074e084fSml93401  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*074e084fSml93401  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <stdlib.h>
297c478bd9Sstevel@tonic-gate #include <stdio.h>
307c478bd9Sstevel@tonic-gate #include <libintl.h>
317c478bd9Sstevel@tonic-gate #include <string.h>
327c478bd9Sstevel@tonic-gate #include <sys/acctctl.h>
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include "utils.h"
357c478bd9Sstevel@tonic-gate #include "aconf.h"
367c478bd9Sstevel@tonic-gate #include "res.h"
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate /*
397c478bd9Sstevel@tonic-gate  * resource names
407c478bd9Sstevel@tonic-gate  */
417c478bd9Sstevel@tonic-gate static ac_resname_t ac_names[] = {
427c478bd9Sstevel@tonic-gate 	/*
437c478bd9Sstevel@tonic-gate 	 * Process accounting resources
447c478bd9Sstevel@tonic-gate 	 */
457c478bd9Sstevel@tonic-gate 	{ AC_PROC,	AC_PROC_PID,		"pid"		},
467c478bd9Sstevel@tonic-gate 	{ AC_PROC,	AC_PROC_UID,		"uid"		},
477c478bd9Sstevel@tonic-gate 	{ AC_PROC,	AC_PROC_GID,		"gid"		},
487c478bd9Sstevel@tonic-gate 	{ AC_PROC,	AC_PROC_PROJID,		"projid"	},
497c478bd9Sstevel@tonic-gate 	{ AC_PROC,	AC_PROC_TASKID,		"taskid"	},
507c478bd9Sstevel@tonic-gate 	{ AC_PROC,	AC_PROC_CPU,		"cpu"		},
517c478bd9Sstevel@tonic-gate 	{ AC_PROC,	AC_PROC_TIME,		"time"		},
527c478bd9Sstevel@tonic-gate 	{ AC_PROC,	AC_PROC_COMMAND,	"command"	},
537c478bd9Sstevel@tonic-gate 	{ AC_PROC,	AC_PROC_TTY,		"tty"		},
547c478bd9Sstevel@tonic-gate 	{ AC_PROC,	AC_PROC_HOSTNAME,	"host"		},
557c478bd9Sstevel@tonic-gate 	{ AC_PROC,	AC_PROC_MICROSTATE,	"mstate"	},
567c478bd9Sstevel@tonic-gate 	{ AC_PROC,	AC_PROC_FLAG,		"flag"		},
577c478bd9Sstevel@tonic-gate 	{ AC_PROC,	AC_PROC_ANCPID,		"ancpid"	},
587c478bd9Sstevel@tonic-gate 	{ AC_PROC,	AC_PROC_WAIT_STATUS,	"wait-status"	},
597c478bd9Sstevel@tonic-gate 	{ AC_PROC,	AC_PROC_ZONENAME,	"zone"		},
607c478bd9Sstevel@tonic-gate 	{ AC_PROC,	AC_PROC_MEM,		"memory"	},
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate 	/*
637c478bd9Sstevel@tonic-gate 	 * Task accounting resources
647c478bd9Sstevel@tonic-gate 	 */
657c478bd9Sstevel@tonic-gate 	{ AC_TASK,	AC_TASK_TASKID,		"taskid"	},
667c478bd9Sstevel@tonic-gate 	{ AC_TASK,	AC_TASK_PROJID,		"projid"	},
677c478bd9Sstevel@tonic-gate 	{ AC_TASK,	AC_TASK_CPU,		"cpu"		},
687c478bd9Sstevel@tonic-gate 	{ AC_TASK,	AC_TASK_TIME,		"time"		},
697c478bd9Sstevel@tonic-gate 	{ AC_TASK,	AC_TASK_HOSTNAME,	"host"		},
707c478bd9Sstevel@tonic-gate 	{ AC_TASK,	AC_TASK_MICROSTATE,	"mstate"	},
717c478bd9Sstevel@tonic-gate 	{ AC_TASK,	AC_TASK_ANCTASKID,	"anctaskid"	},
727c478bd9Sstevel@tonic-gate 	{ AC_TASK,	AC_TASK_ZONENAME,	"zone"		},
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate 	/*
757c478bd9Sstevel@tonic-gate 	 * Flow accounting resources
767c478bd9Sstevel@tonic-gate 	 */
777c478bd9Sstevel@tonic-gate 	{ AC_FLOW,	AC_FLOW_SADDR,		"saddr"		},
787c478bd9Sstevel@tonic-gate 	{ AC_FLOW,	AC_FLOW_DADDR,		"daddr"		},
797c478bd9Sstevel@tonic-gate 	{ AC_FLOW,	AC_FLOW_SPORT,		"sport"		},
807c478bd9Sstevel@tonic-gate 	{ AC_FLOW,	AC_FLOW_DPORT,		"dport"		},
817c478bd9Sstevel@tonic-gate 	{ AC_FLOW,	AC_FLOW_PROTOCOL,	"proto"		},
827c478bd9Sstevel@tonic-gate 	{ AC_FLOW,	AC_FLOW_DSFIELD,	"dsfield"	},
837c478bd9Sstevel@tonic-gate 	{ AC_FLOW,	AC_FLOW_NBYTES,		"nbytes"	},
847c478bd9Sstevel@tonic-gate 	{ AC_FLOW,	AC_FLOW_NPKTS,		"npkts"		},
857c478bd9Sstevel@tonic-gate 	{ AC_FLOW,	AC_FLOW_CTIME,		"ctime"		},
867c478bd9Sstevel@tonic-gate 	{ AC_FLOW,	AC_FLOW_LSEEN,		"lseen"		},
877c478bd9Sstevel@tonic-gate 	{ AC_FLOW,	AC_FLOW_PROJID,		"projid"	},
887c478bd9Sstevel@tonic-gate 	{ AC_FLOW,	AC_FLOW_UID,		"uid"		},
897c478bd9Sstevel@tonic-gate 	{ AC_FLOW,	AC_FLOW_ANAME,		"action"	},
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 	/*
927c478bd9Sstevel@tonic-gate 	 * These are included for compatibility with old acctadm that
937c478bd9Sstevel@tonic-gate 	 * didn't have resource groups for individual accounting types.
947c478bd9Sstevel@tonic-gate 	 * It was possible to have resource "pid" enabled for task
957c478bd9Sstevel@tonic-gate 	 * accounting even though we couldn't actually track it.
967c478bd9Sstevel@tonic-gate 	 */
977c478bd9Sstevel@tonic-gate 	{ AC_TASK,	AC_NONE,		"pid"		},
987c478bd9Sstevel@tonic-gate 	{ AC_TASK,	AC_NONE,		"uid"		},
997c478bd9Sstevel@tonic-gate 	{ AC_TASK,	AC_NONE,		"gid"		},
1007c478bd9Sstevel@tonic-gate 	{ AC_TASK,	AC_NONE,		"command"	},
1017c478bd9Sstevel@tonic-gate 	{ AC_TASK,	AC_NONE,		"tty"		},
1027c478bd9Sstevel@tonic-gate 	{ AC_TASK,	AC_NONE,		"flag"		},
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	{ AC_NONE,	AC_NONE,		NULL		}
1057c478bd9Sstevel@tonic-gate };
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate /*
1087c478bd9Sstevel@tonic-gate  * resource groups
1097c478bd9Sstevel@tonic-gate  */
1107c478bd9Sstevel@tonic-gate static ac_group_t ac_groups[] = {
1117c478bd9Sstevel@tonic-gate 	{ AC_PROC,	"extended",
1127c478bd9Sstevel@tonic-gate 		{ AC_PROC_PID, AC_PROC_UID, AC_PROC_GID, AC_PROC_CPU,
1137c478bd9Sstevel@tonic-gate 		AC_PROC_TIME, AC_PROC_COMMAND, AC_PROC_TTY, AC_PROC_PROJID,
1147c478bd9Sstevel@tonic-gate 		AC_PROC_TASKID, AC_PROC_ANCPID, AC_PROC_WAIT_STATUS,
1157c478bd9Sstevel@tonic-gate 		AC_PROC_ZONENAME, AC_PROC_FLAG, AC_PROC_MEM,
1167c478bd9Sstevel@tonic-gate 		AC_PROC_MICROSTATE, AC_NONE } },
1177c478bd9Sstevel@tonic-gate 	{ AC_PROC,	"basic",
1187c478bd9Sstevel@tonic-gate 		{ AC_PROC_PID, AC_PROC_UID, AC_PROC_GID, AC_PROC_CPU,
1197c478bd9Sstevel@tonic-gate 		AC_PROC_TIME, AC_PROC_COMMAND, AC_PROC_TTY, AC_PROC_FLAG,
1207c478bd9Sstevel@tonic-gate 		AC_NONE } },
1217c478bd9Sstevel@tonic-gate 	{ AC_TASK,	"extended",
1227c478bd9Sstevel@tonic-gate 		{ AC_TASK_TASKID, AC_TASK_PROJID, AC_TASK_CPU, AC_TASK_TIME,
1237c478bd9Sstevel@tonic-gate 		AC_TASK_HOSTNAME, AC_TASK_MICROSTATE, AC_TASK_ANCTASKID,
1247c478bd9Sstevel@tonic-gate 		AC_TASK_ZONENAME, AC_NONE } },
1257c478bd9Sstevel@tonic-gate 	{ AC_TASK,	"basic",
1267c478bd9Sstevel@tonic-gate 		{ AC_TASK_TASKID, AC_TASK_PROJID, AC_TASK_CPU, AC_TASK_TIME,
1277c478bd9Sstevel@tonic-gate 		AC_NONE } },
1287c478bd9Sstevel@tonic-gate 	{ AC_FLOW,	"extended",
1297c478bd9Sstevel@tonic-gate 		{ AC_FLOW_SADDR, AC_FLOW_DADDR, AC_FLOW_SPORT, AC_FLOW_DPORT,
1307c478bd9Sstevel@tonic-gate 		AC_FLOW_PROTOCOL, AC_FLOW_DSFIELD, AC_FLOW_NBYTES,
1317c478bd9Sstevel@tonic-gate 		AC_FLOW_NPKTS, AC_FLOW_ANAME, AC_FLOW_CTIME, AC_FLOW_LSEEN,
1327c478bd9Sstevel@tonic-gate 		AC_FLOW_PROJID, AC_FLOW_UID, AC_NONE } },
1337c478bd9Sstevel@tonic-gate 	{ AC_FLOW,	"basic",
1347c478bd9Sstevel@tonic-gate 		{ AC_FLOW_SADDR, AC_FLOW_DADDR, AC_FLOW_SPORT, AC_FLOW_DPORT,
1357c478bd9Sstevel@tonic-gate 		AC_FLOW_PROTOCOL, AC_FLOW_NBYTES, AC_FLOW_NPKTS, AC_FLOW_ANAME,
1367c478bd9Sstevel@tonic-gate 		AC_NONE } },
1377c478bd9Sstevel@tonic-gate 	{ AC_NONE,	NULL,
1387c478bd9Sstevel@tonic-gate 		{ AC_NONE } }
1397c478bd9Sstevel@tonic-gate };
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate /*
1427c478bd9Sstevel@tonic-gate  * this function returns the id of the named resource
1437c478bd9Sstevel@tonic-gate  */
1447c478bd9Sstevel@tonic-gate static int
1457c478bd9Sstevel@tonic-gate name2id(char *name, int type)
1467c478bd9Sstevel@tonic-gate {
1477c478bd9Sstevel@tonic-gate 	ac_resname_t *acname = ac_names;
1487c478bd9Sstevel@tonic-gate 	while (acname->ar_type != AC_NONE) {
1497c478bd9Sstevel@tonic-gate 		if (acname->ar_type == type &&
1507c478bd9Sstevel@tonic-gate 		    strcmp(acname->ar_name, name) == 0) {
1517c478bd9Sstevel@tonic-gate 			if (acname->ar_id == AC_NONE)
1527c478bd9Sstevel@tonic-gate 				/*
1537c478bd9Sstevel@tonic-gate 				 * For compatibility with older versions.
1547c478bd9Sstevel@tonic-gate 				 */
1557c478bd9Sstevel@tonic-gate 				return (-1);
1567c478bd9Sstevel@tonic-gate 			else
1577c478bd9Sstevel@tonic-gate 				return (acname->ar_id);
1587c478bd9Sstevel@tonic-gate 		}
1597c478bd9Sstevel@tonic-gate 		acname++;
1607c478bd9Sstevel@tonic-gate 	}
1617c478bd9Sstevel@tonic-gate 	return (0);
1627c478bd9Sstevel@tonic-gate }
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate /*
1657c478bd9Sstevel@tonic-gate  * this function gives name of the resource by its id
1667c478bd9Sstevel@tonic-gate  */
1677c478bd9Sstevel@tonic-gate static char *
1687c478bd9Sstevel@tonic-gate id2name(int id, int type)
1697c478bd9Sstevel@tonic-gate {
1707c478bd9Sstevel@tonic-gate 	ac_resname_t *acname = ac_names;
1717c478bd9Sstevel@tonic-gate 	while (acname->ar_id != AC_NONE) {
1727c478bd9Sstevel@tonic-gate 		if (acname->ar_type == type &&
1737c478bd9Sstevel@tonic-gate 		    acname->ar_id == id)
1747c478bd9Sstevel@tonic-gate 			return (acname->ar_name);
1757c478bd9Sstevel@tonic-gate 		acname++;
1767c478bd9Sstevel@tonic-gate 	}
1777c478bd9Sstevel@tonic-gate 	return (NULL);
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate static void
1817c478bd9Sstevel@tonic-gate printgroup(int type)
1827c478bd9Sstevel@tonic-gate {
1837c478bd9Sstevel@tonic-gate 	int r, g, id;
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	for (g = 0; ac_groups[g].ag_type != AC_NONE; g++) {
1867c478bd9Sstevel@tonic-gate 		if (ac_groups[g].ag_type != type)
1877c478bd9Sstevel@tonic-gate 			continue;
1887c478bd9Sstevel@tonic-gate 		(void) printf("%-9s", ac_groups[g].ag_name);
1897c478bd9Sstevel@tonic-gate 		(void) printf("%s", id2name(ac_groups[g].ag_mem[0], type));
1907c478bd9Sstevel@tonic-gate 		for (r = 1; (id = ac_groups[g].ag_mem[r]) != AC_NONE; r++)
1917c478bd9Sstevel@tonic-gate 			(void) printf(",%s", id2name(id, type));
1927c478bd9Sstevel@tonic-gate 		(void) printf("\n");
1937c478bd9Sstevel@tonic-gate 	}
1947c478bd9Sstevel@tonic-gate }
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate /*
1987c478bd9Sstevel@tonic-gate  * this function prints the list of resource groups and their members
1997c478bd9Sstevel@tonic-gate  */
2007c478bd9Sstevel@tonic-gate void
2017c478bd9Sstevel@tonic-gate printgroups(int type)
2027c478bd9Sstevel@tonic-gate {
2037c478bd9Sstevel@tonic-gate 	int header = 0;
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	if ((type & AC_PROC) && (type & AC_TASK) && (type & AC_FLOW))
2067c478bd9Sstevel@tonic-gate 		header = 1;
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	if (type & AC_PROC) {
2097c478bd9Sstevel@tonic-gate 		if (header == 1)
2107c478bd9Sstevel@tonic-gate 			(void) printf("process:\n");
2117c478bd9Sstevel@tonic-gate 		printgroup(AC_PROC);
2127c478bd9Sstevel@tonic-gate 	}
2137c478bd9Sstevel@tonic-gate 	if (type & AC_TASK) {
2147c478bd9Sstevel@tonic-gate 		if (header == 1)
2157c478bd9Sstevel@tonic-gate 			(void) printf("task:\n");
2167c478bd9Sstevel@tonic-gate 		printgroup(AC_TASK);
2177c478bd9Sstevel@tonic-gate 	}
2187c478bd9Sstevel@tonic-gate 	if (type & AC_FLOW) {
2197c478bd9Sstevel@tonic-gate 		if (header == 1)
2207c478bd9Sstevel@tonic-gate 			(void) printf("flow:\n");
2217c478bd9Sstevel@tonic-gate 		printgroup(AC_FLOW);
2227c478bd9Sstevel@tonic-gate 	}
2237c478bd9Sstevel@tonic-gate }
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate /*
2267c478bd9Sstevel@tonic-gate  * this function sets the state of the particular resource
2277c478bd9Sstevel@tonic-gate  */
2287c478bd9Sstevel@tonic-gate static void
2297c478bd9Sstevel@tonic-gate resset(ac_res_t *res, int id, int state)
2307c478bd9Sstevel@tonic-gate {
2317c478bd9Sstevel@tonic-gate 	ac_res_t *resp;
2327c478bd9Sstevel@tonic-gate 	resp = (ac_res_t *)((uintptr_t)res + (sizeof (ac_res_t) * (id - 1)));
2337c478bd9Sstevel@tonic-gate 	resp->ar_state = state;
2347c478bd9Sstevel@tonic-gate 	resp->ar_id = id;
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate /*
2387c478bd9Sstevel@tonic-gate  * this function gets the state of the particular resource
2397c478bd9Sstevel@tonic-gate  */
2407c478bd9Sstevel@tonic-gate static int
2417c478bd9Sstevel@tonic-gate resget(ac_res_t *res, int id)
2427c478bd9Sstevel@tonic-gate {
2437c478bd9Sstevel@tonic-gate 	ac_res_t *resp;
2447c478bd9Sstevel@tonic-gate 	resp = (ac_res_t *)((uintptr_t)res + (sizeof (ac_res_t) * (id - 1)));
2457c478bd9Sstevel@tonic-gate 	return (resp->ar_state);
2467c478bd9Sstevel@tonic-gate }
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate /*
2497c478bd9Sstevel@tonic-gate  * this function converts a string of resources into a buffer which then
2507c478bd9Sstevel@tonic-gate  * can be used for acctctl() system call
2517c478bd9Sstevel@tonic-gate  */
2527c478bd9Sstevel@tonic-gate void
2537c478bd9Sstevel@tonic-gate str2buf(ac_res_t *buf, char *str, int state, int type)
2547c478bd9Sstevel@tonic-gate {
2557c478bd9Sstevel@tonic-gate 	int i, j, id, ok;
2567c478bd9Sstevel@tonic-gate 	char *p, *g, *copy;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	if (strcmp(str, AC_STR_NONE) == 0)
2597c478bd9Sstevel@tonic-gate 		return;
2607c478bd9Sstevel@tonic-gate 	/*
2617c478bd9Sstevel@tonic-gate 	 * Take a lap through str, processing resources, modifying buf copy
2627c478bd9Sstevel@tonic-gate 	 * as appropriate and making sure that all resource names are valid.
2637c478bd9Sstevel@tonic-gate 	 */
2647c478bd9Sstevel@tonic-gate 	if ((copy = malloc(strlen(str) + 1)) == NULL)
2657c478bd9Sstevel@tonic-gate 		die(gettext("not enough memory\n"));
2667c478bd9Sstevel@tonic-gate 	(void) memcpy(copy, str, strlen(str) + 1);
2677c478bd9Sstevel@tonic-gate 	p = strtok(copy, ", ");
2687c478bd9Sstevel@tonic-gate 	while (p != NULL) {
2697c478bd9Sstevel@tonic-gate 		/*
2707c478bd9Sstevel@tonic-gate 		 * check if str contains any resource groups
2717c478bd9Sstevel@tonic-gate 		 */
2727c478bd9Sstevel@tonic-gate 		for (ok = 0, i = 0; (g = ac_groups[i].ag_name) != NULL; i++) {
2737c478bd9Sstevel@tonic-gate 			if (strcmp(p, g) == 0 && ac_groups[i].ag_type == type) {
2747c478bd9Sstevel@tonic-gate 				for (j = 0; (id = ac_groups[i].ag_mem[j]) !=
2757c478bd9Sstevel@tonic-gate 				    AC_NONE; j++)
2767c478bd9Sstevel@tonic-gate 					resset(buf, id, state);
2777c478bd9Sstevel@tonic-gate 				ok = 1;
2787c478bd9Sstevel@tonic-gate 				break;
2797c478bd9Sstevel@tonic-gate 			}
2807c478bd9Sstevel@tonic-gate 		}
2817c478bd9Sstevel@tonic-gate 		if (ok == 0) {
2827c478bd9Sstevel@tonic-gate 			id = name2id(p, type);
2837c478bd9Sstevel@tonic-gate 			if (id > 0)
2847c478bd9Sstevel@tonic-gate 				resset(buf, id, state);
2857c478bd9Sstevel@tonic-gate 			else if (id == 0)
2867c478bd9Sstevel@tonic-gate 				die(gettext("unknown %s resource: %s\n"),
287*074e084fSml93401 				    ac_type_name(type), p);
2887c478bd9Sstevel@tonic-gate 		}
2897c478bd9Sstevel@tonic-gate 		p = strtok(NULL, ", ");
2907c478bd9Sstevel@tonic-gate 	}
2917c478bd9Sstevel@tonic-gate 	free(copy);
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate /*
2957c478bd9Sstevel@tonic-gate  * this function converts a buffer into a string of resource names.
2967c478bd9Sstevel@tonic-gate  * state (on/off) for resources of interest is selected by the third argument.
2977c478bd9Sstevel@tonic-gate  * accounting type is selected by the fourth argument.
2987c478bd9Sstevel@tonic-gate  * it is caller's responsibility to free the allocated string buffer.
2997c478bd9Sstevel@tonic-gate  */
3007c478bd9Sstevel@tonic-gate char *
3017c478bd9Sstevel@tonic-gate buf2str(ac_res_t *buffer, size_t bufsz, int state, int type)
3027c478bd9Sstevel@tonic-gate {
3037c478bd9Sstevel@tonic-gate 	int i, j, ok, id;
3047c478bd9Sstevel@tonic-gate 	char *str, *g;
3057c478bd9Sstevel@tonic-gate 	ac_res_t *buf, *cur;
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	if ((buf = malloc(bufsz)) == NULL ||
3087c478bd9Sstevel@tonic-gate 	    (str = malloc(MAXRESLEN)) == NULL)
3097c478bd9Sstevel@tonic-gate 		die(gettext("not enough memory\n"));
3107c478bd9Sstevel@tonic-gate 	(void) memset(str, 0, MAXRESLEN);
3117c478bd9Sstevel@tonic-gate 	(void) memcpy(buf, buffer, bufsz);
3127c478bd9Sstevel@tonic-gate 	/*
3137c478bd9Sstevel@tonic-gate 	 * check if buf has any resource groups in it
3147c478bd9Sstevel@tonic-gate 	 */
3157c478bd9Sstevel@tonic-gate 	for (i = 0; (g = ac_groups[i].ag_name) != NULL; i++) {
3167c478bd9Sstevel@tonic-gate 		if (ac_groups[i].ag_type != type)
3177c478bd9Sstevel@tonic-gate 			continue;
3187c478bd9Sstevel@tonic-gate 		for (j = 0; (id = ac_groups[i].ag_mem[j]) != AC_NONE; j++) {
3197c478bd9Sstevel@tonic-gate 			ok = 1;
3207c478bd9Sstevel@tonic-gate 			if (resget(buf, id) != state) {
3217c478bd9Sstevel@tonic-gate 				ok = 0;
3227c478bd9Sstevel@tonic-gate 				break;
3237c478bd9Sstevel@tonic-gate 			}
3247c478bd9Sstevel@tonic-gate 		}
3257c478bd9Sstevel@tonic-gate 		if (ok) {	/* buf contains this resource group */
3267c478bd9Sstevel@tonic-gate 			if (strlen(str) != 0)
3277c478bd9Sstevel@tonic-gate 				(void) strcat(str, ",");
3287c478bd9Sstevel@tonic-gate 			(void) strcat(str, g);
3297c478bd9Sstevel@tonic-gate 			for (j = 0; (id = ac_groups[i].ag_mem[j]) != AC_NONE;
3307c478bd9Sstevel@tonic-gate 			    j++)
3317c478bd9Sstevel@tonic-gate 				resset(buf, id,
3327c478bd9Sstevel@tonic-gate 				    state == AC_ON ? AC_OFF : AC_ON);
3337c478bd9Sstevel@tonic-gate 			ok = 0;
3347c478bd9Sstevel@tonic-gate 		}
3357c478bd9Sstevel@tonic-gate 	}
3367c478bd9Sstevel@tonic-gate 	/*
3377c478bd9Sstevel@tonic-gate 	 * browse through the rest of the buf for all remaining resources
3387c478bd9Sstevel@tonic-gate 	 * that are not a part of any groups
3397c478bd9Sstevel@tonic-gate 	 */
3407c478bd9Sstevel@tonic-gate 	for (cur = buf; cur->ar_id != AC_NONE; cur++) {
3417c478bd9Sstevel@tonic-gate 		if (cur->ar_state == state) {
3427c478bd9Sstevel@tonic-gate 			if (strlen(str) != 0)
3437c478bd9Sstevel@tonic-gate 				(void) strcat(str, ",");
3447c478bd9Sstevel@tonic-gate 			if (id2name(cur->ar_id, type) == NULL)
3457c478bd9Sstevel@tonic-gate 				die(gettext("unknown %s resource id (%d)\n"),
346*074e084fSml93401 				    ac_type_name(type), cur->ar_id);
3477c478bd9Sstevel@tonic-gate 			(void) strcat(str, id2name(cur->ar_id, type));
3487c478bd9Sstevel@tonic-gate 		}
3497c478bd9Sstevel@tonic-gate 	}
3507c478bd9Sstevel@tonic-gate 	if (strlen(str) == 0)
3517c478bd9Sstevel@tonic-gate 		(void) strcpy(str, AC_STR_NONE);
3527c478bd9Sstevel@tonic-gate 	free(buf);
3537c478bd9Sstevel@tonic-gate 	return (str);
3547c478bd9Sstevel@tonic-gate }
355