Home | History | Annotate | Download | only in acctadm
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <stdlib.h>
     27 #include <stdio.h>
     28 #include <libintl.h>
     29 #include <string.h>
     30 #include <sys/acctctl.h>
     31 
     32 #include "utils.h"
     33 #include "aconf.h"
     34 #include "res.h"
     35 
     36 /*
     37  * resource names
     38  */
     39 static ac_resname_t ac_names[] = {
     40 	/*
     41 	 * Process accounting resources
     42 	 */
     43 	{ AC_PROC,	AC_PROC_PID,		"pid"		},
     44 	{ AC_PROC,	AC_PROC_UID,		"uid"		},
     45 	{ AC_PROC,	AC_PROC_GID,		"gid"		},
     46 	{ AC_PROC,	AC_PROC_PROJID,		"projid"	},
     47 	{ AC_PROC,	AC_PROC_TASKID,		"taskid"	},
     48 	{ AC_PROC,	AC_PROC_CPU,		"cpu"		},
     49 	{ AC_PROC,	AC_PROC_TIME,		"time"		},
     50 	{ AC_PROC,	AC_PROC_COMMAND,	"command"	},
     51 	{ AC_PROC,	AC_PROC_TTY,		"tty"		},
     52 	{ AC_PROC,	AC_PROC_HOSTNAME,	"host"		},
     53 	{ AC_PROC,	AC_PROC_MICROSTATE,	"mstate"	},
     54 	{ AC_PROC,	AC_PROC_FLAG,		"flag"		},
     55 	{ AC_PROC,	AC_PROC_ANCPID,		"ancpid"	},
     56 	{ AC_PROC,	AC_PROC_WAIT_STATUS,	"wait-status"	},
     57 	{ AC_PROC,	AC_PROC_ZONENAME,	"zone"		},
     58 	{ AC_PROC,	AC_PROC_MEM,		"memory"	},
     59 
     60 	/*
     61 	 * Task accounting resources
     62 	 */
     63 	{ AC_TASK,	AC_TASK_TASKID,		"taskid"	},
     64 	{ AC_TASK,	AC_TASK_PROJID,		"projid"	},
     65 	{ AC_TASK,	AC_TASK_CPU,		"cpu"		},
     66 	{ AC_TASK,	AC_TASK_TIME,		"time"		},
     67 	{ AC_TASK,	AC_TASK_HOSTNAME,	"host"		},
     68 	{ AC_TASK,	AC_TASK_MICROSTATE,	"mstate"	},
     69 	{ AC_TASK,	AC_TASK_ANCTASKID,	"anctaskid"	},
     70 	{ AC_TASK,	AC_TASK_ZONENAME,	"zone"		},
     71 
     72 	/*
     73 	 * Flow accounting resources
     74 	 */
     75 	{ AC_FLOW,	AC_FLOW_SADDR,		"saddr"		},
     76 	{ AC_FLOW,	AC_FLOW_DADDR,		"daddr"		},
     77 	{ AC_FLOW,	AC_FLOW_SPORT,		"sport"		},
     78 	{ AC_FLOW,	AC_FLOW_DPORT,		"dport"		},
     79 	{ AC_FLOW,	AC_FLOW_PROTOCOL,	"proto"		},
     80 	{ AC_FLOW,	AC_FLOW_DSFIELD,	"dsfield"	},
     81 	{ AC_FLOW,	AC_FLOW_NBYTES,		"nbytes"	},
     82 	{ AC_FLOW,	AC_FLOW_NPKTS,		"npkts"		},
     83 	{ AC_FLOW,	AC_FLOW_CTIME,		"ctime"		},
     84 	{ AC_FLOW,	AC_FLOW_LSEEN,		"lseen"		},
     85 	{ AC_FLOW,	AC_FLOW_PROJID,		"projid"	},
     86 	{ AC_FLOW,	AC_FLOW_UID,		"uid"		},
     87 	{ AC_FLOW,	AC_FLOW_ANAME,		"action"	},
     88 
     89 	/*
     90 	 * Net accounting resources
     91 	 */
     92 
     93 	{ AC_NET,	AC_NET_NAME,		"name"		},
     94 	{ AC_NET,	AC_NET_EHOST,		"ehost"		},
     95 	{ AC_NET,	AC_NET_EDEST,		"edest"		},
     96 	{ AC_NET,	AC_NET_VLAN_TPID,	"vlan_pid"	},
     97 	{ AC_NET,	AC_NET_VLAN_TCI,	"vlan_tci"	},
     98 	{ AC_NET,	AC_NET_SAP,		"sap"		},
     99 	{ AC_NET,	AC_NET_PRIORITY,	"priority"	},
    100 	{ AC_NET,	AC_NET_BWLIMIT,		"bwlimit"	},
    101 	{ AC_NET,	AC_NET_DEVNAME,		"devname"	},
    102 	{ AC_NET,	AC_NET_SADDR,		"src_ip"	},
    103 	{ AC_NET,	AC_NET_DADDR,		"dst_ip"	},
    104 	{ AC_NET,	AC_NET_SPORT,		"src_port"	},
    105 	{ AC_NET,	AC_NET_DPORT,		"dst_port"	},
    106 	{ AC_NET,	AC_NET_PROTOCOL,	"protocol"	},
    107 	{ AC_NET,	AC_NET_DSFIELD,		"dsfield"	},
    108 	{ AC_NET,	AC_NET_CURTIME,		"curtime"	},
    109 	{ AC_NET,	AC_NET_IBYTES,		"ibytes"	},
    110 	{ AC_NET,	AC_NET_OBYTES,		"obytes"	},
    111 	{ AC_NET,	AC_NET_IPKTS,		"ipkts"		},
    112 	{ AC_NET,	AC_NET_OPKTS,		"opkts"		},
    113 	{ AC_NET,	AC_NET_IERRPKTS,	"ierrpkts"	},
    114 	{ AC_NET,	AC_NET_OERRPKTS,	"oerrpkts"	},
    115 
    116 	/*
    117 	 * These are included for compatibility with old acctadm that
    118 	 * didn't have resource groups for individual accounting types.
    119 	 * It was possible to have resource "pid" enabled for task
    120 	 * accounting even though we couldn't actually track it.
    121 	 */
    122 	{ AC_TASK,	AC_NONE,		"pid"		},
    123 	{ AC_TASK,	AC_NONE,		"uid"		},
    124 	{ AC_TASK,	AC_NONE,		"gid"		},
    125 	{ AC_TASK,	AC_NONE,		"command"	},
    126 	{ AC_TASK,	AC_NONE,		"tty"		},
    127 	{ AC_TASK,	AC_NONE,		"flag"		},
    128 
    129 	{ AC_NONE,	AC_NONE,		NULL		}
    130 };
    131 
    132 /*
    133  * resource groups
    134  */
    135 static ac_group_t ac_groups[] = {
    136 	{ AC_PROC,	"extended",
    137 		{ AC_PROC_PID, AC_PROC_UID, AC_PROC_GID, AC_PROC_CPU,
    138 		AC_PROC_TIME, AC_PROC_COMMAND, AC_PROC_TTY, AC_PROC_PROJID,
    139 		AC_PROC_TASKID, AC_PROC_ANCPID, AC_PROC_WAIT_STATUS,
    140 		AC_PROC_ZONENAME, AC_PROC_FLAG, AC_PROC_MEM,
    141 		AC_PROC_MICROSTATE, AC_NONE } },
    142 	{ AC_PROC,	"basic",
    143 		{ AC_PROC_PID, AC_PROC_UID, AC_PROC_GID, AC_PROC_CPU,
    144 		AC_PROC_TIME, AC_PROC_COMMAND, AC_PROC_TTY, AC_PROC_FLAG,
    145 		AC_NONE } },
    146 	{ AC_TASK,	"extended",
    147 		{ AC_TASK_TASKID, AC_TASK_PROJID, AC_TASK_CPU, AC_TASK_TIME,
    148 		AC_TASK_HOSTNAME, AC_TASK_MICROSTATE, AC_TASK_ANCTASKID,
    149 		AC_TASK_ZONENAME, AC_NONE } },
    150 	{ AC_TASK,	"basic",
    151 		{ AC_TASK_TASKID, AC_TASK_PROJID, AC_TASK_CPU, AC_TASK_TIME,
    152 		AC_NONE } },
    153 	{ AC_FLOW,	"extended",
    154 		{ AC_FLOW_SADDR, AC_FLOW_DADDR, AC_FLOW_SPORT, AC_FLOW_DPORT,
    155 		AC_FLOW_PROTOCOL, AC_FLOW_DSFIELD, AC_FLOW_NBYTES,
    156 		AC_FLOW_NPKTS, AC_FLOW_ANAME, AC_FLOW_CTIME, AC_FLOW_LSEEN,
    157 		AC_FLOW_PROJID, AC_FLOW_UID, AC_NONE } },
    158 	{ AC_FLOW,	"basic",
    159 		{ AC_FLOW_SADDR, AC_FLOW_DADDR, AC_FLOW_SPORT, AC_FLOW_DPORT,
    160 		AC_FLOW_PROTOCOL, AC_FLOW_NBYTES, AC_FLOW_NPKTS, AC_FLOW_ANAME,
    161 		AC_NONE } },
    162 	{ AC_NET,	"extended",
    163 		{ AC_NET_NAME, AC_NET_EHOST, AC_NET_EDEST, AC_NET_VLAN_TPID,
    164 		AC_NET_VLAN_TCI, AC_NET_SAP, AC_NET_PRIORITY,
    165 		AC_NET_BWLIMIT, AC_NET_DEVNAME, AC_NET_SADDR, AC_NET_DADDR,
    166 		AC_NET_SPORT, AC_NET_DPORT, AC_NET_PROTOCOL, AC_NET_DSFIELD,
    167 		AC_NET_CURTIME, AC_NET_IBYTES, AC_NET_OBYTES, AC_NET_IPKTS,
    168 		AC_NET_OPKTS, AC_NET_IERRPKTS, AC_NET_OERRPKTS, AC_NONE } },
    169 	{ AC_NET,	"basic",
    170 		{ AC_NET_NAME, AC_NET_DEVNAME, AC_NET_EHOST, AC_NET_EDEST,
    171 		AC_NET_VLAN_TPID, AC_NET_VLAN_TCI, AC_NET_SAP,
    172 		AC_NET_PRIORITY, AC_NET_BWLIMIT, AC_NET_CURTIME, AC_NET_IBYTES,
    173 		AC_NET_OBYTES, AC_NET_IPKTS, AC_NET_OPKTS, AC_NET_IERRPKTS,
    174 		AC_NET_OERRPKTS, AC_NONE } },
    175 	{ AC_NONE,	NULL,
    176 		{ AC_NONE } }
    177 };
    178 
    179 /*
    180  * this function returns the id of the named resource
    181  */
    182 static int
    183 name2id(char *name, int type)
    184 {
    185 	ac_resname_t *acname = ac_names;
    186 	while (acname->ar_type != AC_NONE) {
    187 		if (acname->ar_type == type &&
    188 		    strcmp(acname->ar_name, name) == 0) {
    189 			if (acname->ar_id == AC_NONE)
    190 				/*
    191 				 * For compatibility with older versions.
    192 				 */
    193 				return (-1);
    194 			else
    195 				return (acname->ar_id);
    196 		}
    197 		acname++;
    198 	}
    199 	return (0);
    200 }
    201 
    202 /*
    203  * this function gives name of the resource by its id
    204  */
    205 static char *
    206 id2name(int id, int type)
    207 {
    208 	ac_resname_t *acname = ac_names;
    209 	while (acname->ar_id != AC_NONE) {
    210 		if (acname->ar_type == type &&
    211 		    acname->ar_id == id)
    212 			return (acname->ar_name);
    213 		acname++;
    214 	}
    215 	return (NULL);
    216 }
    217 
    218 static void
    219 printgroup(int type)
    220 {
    221 	int r, g, id;
    222 
    223 	for (g = 0; ac_groups[g].ag_type != AC_NONE; g++) {
    224 		if (ac_groups[g].ag_type != type)
    225 			continue;
    226 		(void) printf("%-9s", ac_groups[g].ag_name);
    227 		(void) printf("%s", id2name(ac_groups[g].ag_mem[0], type));
    228 		for (r = 1; (id = ac_groups[g].ag_mem[r]) != AC_NONE; r++)
    229 			(void) printf(",%s", id2name(id, type));
    230 		(void) printf("\n");
    231 	}
    232 }
    233 
    234 
    235 /*
    236  * this function prints the list of resource groups and their members
    237  */
    238 void
    239 printgroups(int type)
    240 {
    241 	int header = 0;
    242 
    243 	if ((type & AC_PROC) && (type & AC_TASK) && (type & AC_FLOW) &&
    244 	    (type & AC_NET)) {
    245 		header = 1;
    246 	}
    247 	if (type & AC_PROC) {
    248 		if (header == 1)
    249 			(void) printf("process:\n");
    250 		printgroup(AC_PROC);
    251 	}
    252 	if (type & AC_TASK) {
    253 		if (header == 1)
    254 			(void) printf("task:\n");
    255 		printgroup(AC_TASK);
    256 	}
    257 	if (type & AC_FLOW) {
    258 		if (header == 1)
    259 			(void) printf("flow:\n");
    260 		printgroup(AC_FLOW);
    261 	}
    262 	if (type & AC_NET) {
    263 		if (header == 1)
    264 			(void) printf("net:\n");
    265 		printgroup(AC_NET);
    266 	}
    267 }
    268 
    269 /*
    270  * this function sets the state of the particular resource
    271  */
    272 static void
    273 resset(ac_res_t *res, int id, int state)
    274 {
    275 	ac_res_t *resp;
    276 	resp = (ac_res_t *)((uintptr_t)res + (sizeof (ac_res_t) * (id - 1)));
    277 	resp->ar_state = state;
    278 	resp->ar_id = id;
    279 }
    280 
    281 /*
    282  * this function gets the state of the particular resource
    283  */
    284 static int
    285 resget(ac_res_t *res, int id)
    286 {
    287 	ac_res_t *resp;
    288 	resp = (ac_res_t *)((uintptr_t)res + (sizeof (ac_res_t) * (id - 1)));
    289 	return (resp->ar_state);
    290 }
    291 
    292 /*
    293  * this function converts a string of resources into a buffer which then
    294  * can be used for acctctl() system call
    295  */
    296 void
    297 str2buf(ac_res_t *buf, char *str, int state, int type)
    298 {
    299 	int i, j, id, ok;
    300 	char *p, *g, *copy;
    301 
    302 	if (strcmp(str, AC_STR_NONE) == 0)
    303 		return;
    304 	/*
    305 	 * Take a lap through str, processing resources, modifying buf copy
    306 	 * as appropriate and making sure that all resource names are valid.
    307 	 */
    308 	if ((copy = malloc(strlen(str) + 1)) == NULL)
    309 		die(gettext("not enough memory\n"));
    310 	(void) memcpy(copy, str, strlen(str) + 1);
    311 	p = strtok(copy, ", ");
    312 	while (p != NULL) {
    313 		/*
    314 		 * check if str contains any resource groups
    315 		 */
    316 		for (ok = 0, i = 0; (g = ac_groups[i].ag_name) != NULL; i++) {
    317 			if (strcmp(p, g) == 0 && ac_groups[i].ag_type == type) {
    318 				for (j = 0; (id = ac_groups[i].ag_mem[j]) !=
    319 				    AC_NONE; j++)
    320 					resset(buf, id, state);
    321 				ok = 1;
    322 				break;
    323 			}
    324 		}
    325 		if (ok == 0) {
    326 			id = name2id(p, type);
    327 			if (id > 0)
    328 				resset(buf, id, state);
    329 			else if (id == 0)
    330 				die(gettext("unknown %s resource: %s\n"),
    331 				    ac_type_name(type), p);
    332 		}
    333 		p = strtok(NULL, ", ");
    334 	}
    335 	free(copy);
    336 }
    337 
    338 /*
    339  * this function converts a buffer into a string of resource names.
    340  * state (on/off) for resources of interest is selected by the third argument.
    341  * accounting type is selected by the fourth argument.
    342  * it is caller's responsibility to free the allocated string buffer.
    343  */
    344 char *
    345 buf2str(ac_res_t *buffer, size_t bufsz, int state, int type)
    346 {
    347 	int i, j, ok, id;
    348 	char *str, *g;
    349 	ac_res_t *buf, *cur;
    350 
    351 	if ((buf = malloc(bufsz)) == NULL ||
    352 	    (str = malloc(MAXRESLEN)) == NULL)
    353 		die(gettext("not enough memory\n"));
    354 	(void) memset(str, 0, MAXRESLEN);
    355 	(void) memcpy(buf, buffer, bufsz);
    356 	/*
    357 	 * check if buf has any resource groups in it
    358 	 */
    359 	for (i = 0; (g = ac_groups[i].ag_name) != NULL; i++) {
    360 		if (ac_groups[i].ag_type != type)
    361 			continue;
    362 		for (j = 0; (id = ac_groups[i].ag_mem[j]) != AC_NONE; j++) {
    363 			ok = 1;
    364 			if (resget(buf, id) != state) {
    365 				ok = 0;
    366 				break;
    367 			}
    368 		}
    369 		if (ok) {	/* buf contains this resource group */
    370 			if (strlen(str) != 0)
    371 				(void) strcat(str, ",");
    372 			(void) strcat(str, g);
    373 			for (j = 0; (id = ac_groups[i].ag_mem[j]) != AC_NONE;
    374 			    j++)
    375 				resset(buf, id,
    376 				    state == AC_ON ? AC_OFF : AC_ON);
    377 			ok = 0;
    378 		}
    379 	}
    380 	/*
    381 	 * browse through the rest of the buf for all remaining resources
    382 	 * that are not a part of any groups
    383 	 */
    384 	for (cur = buf; cur->ar_id != AC_NONE; cur++) {
    385 		if (cur->ar_state == state) {
    386 			if (strlen(str) != 0)
    387 				(void) strcat(str, ",");
    388 			if (id2name(cur->ar_id, type) == NULL)
    389 				die(gettext("unknown %s resource id (%d)\n"),
    390 				    ac_type_name(type), cur->ar_id);
    391 			(void) strcat(str, id2name(cur->ar_id, type));
    392 		}
    393 	}
    394 	if (strlen(str) == 0)
    395 		(void) strcpy(str, AC_STR_NONE);
    396 	free(buf);
    397 	return (str);
    398 }
    399