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