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 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdlib.h> 29 #include <stdio.h> 30 #include <libintl.h> 31 #include <string.h> 32 #include <sys/acctctl.h> 33 34 #include "utils.h" 35 #include "aconf.h" 36 #include "res.h" 37 38 /* 39 * resource names 40 */ 41 static ac_resname_t ac_names[] = { 42 /* 43 * Process accounting resources 44 */ 45 { AC_PROC, AC_PROC_PID, "pid" }, 46 { AC_PROC, AC_PROC_UID, "uid" }, 47 { AC_PROC, AC_PROC_GID, "gid" }, 48 { AC_PROC, AC_PROC_PROJID, "projid" }, 49 { AC_PROC, AC_PROC_TASKID, "taskid" }, 50 { AC_PROC, AC_PROC_CPU, "cpu" }, 51 { AC_PROC, AC_PROC_TIME, "time" }, 52 { AC_PROC, AC_PROC_COMMAND, "command" }, 53 { AC_PROC, AC_PROC_TTY, "tty" }, 54 { AC_PROC, AC_PROC_HOSTNAME, "host" }, 55 { AC_PROC, AC_PROC_MICROSTATE, "mstate" }, 56 { AC_PROC, AC_PROC_FLAG, "flag" }, 57 { AC_PROC, AC_PROC_ANCPID, "ancpid" }, 58 { AC_PROC, AC_PROC_WAIT_STATUS, "wait-status" }, 59 { AC_PROC, AC_PROC_ZONENAME, "zone" }, 60 { AC_PROC, AC_PROC_MEM, "memory" }, 61 62 /* 63 * Task accounting resources 64 */ 65 { AC_TASK, AC_TASK_TASKID, "taskid" }, 66 { AC_TASK, AC_TASK_PROJID, "projid" }, 67 { AC_TASK, AC_TASK_CPU, "cpu" }, 68 { AC_TASK, AC_TASK_TIME, "time" }, 69 { AC_TASK, AC_TASK_HOSTNAME, "host" }, 70 { AC_TASK, AC_TASK_MICROSTATE, "mstate" }, 71 { AC_TASK, AC_TASK_ANCTASKID, "anctaskid" }, 72 { AC_TASK, AC_TASK_ZONENAME, "zone" }, 73 74 /* 75 * Flow accounting resources 76 */ 77 { AC_FLOW, AC_FLOW_SADDR, "saddr" }, 78 { AC_FLOW, AC_FLOW_DADDR, "daddr" }, 79 { AC_FLOW, AC_FLOW_SPORT, "sport" }, 80 { AC_FLOW, AC_FLOW_DPORT, "dport" }, 81 { AC_FLOW, AC_FLOW_PROTOCOL, "proto" }, 82 { AC_FLOW, AC_FLOW_DSFIELD, "dsfield" }, 83 { AC_FLOW, AC_FLOW_NBYTES, "nbytes" }, 84 { AC_FLOW, AC_FLOW_NPKTS, "npkts" }, 85 { AC_FLOW, AC_FLOW_CTIME, "ctime" }, 86 { AC_FLOW, AC_FLOW_LSEEN, "lseen" }, 87 { AC_FLOW, AC_FLOW_PROJID, "projid" }, 88 { AC_FLOW, AC_FLOW_UID, "uid" }, 89 { AC_FLOW, AC_FLOW_ANAME, "action" }, 90 91 /* 92 * These are included for compatibility with old acctadm that 93 * didn't have resource groups for individual accounting types. 94 * It was possible to have resource "pid" enabled for task 95 * accounting even though we couldn't actually track it. 96 */ 97 { AC_TASK, AC_NONE, "pid" }, 98 { AC_TASK, AC_NONE, "uid" }, 99 { AC_TASK, AC_NONE, "gid" }, 100 { AC_TASK, AC_NONE, "command" }, 101 { AC_TASK, AC_NONE, "tty" }, 102 { AC_TASK, AC_NONE, "flag" }, 103 104 { AC_NONE, AC_NONE, NULL } 105 }; 106 107 /* 108 * resource groups 109 */ 110 static ac_group_t ac_groups[] = { 111 { AC_PROC, "extended", 112 { AC_PROC_PID, AC_PROC_UID, AC_PROC_GID, AC_PROC_CPU, 113 AC_PROC_TIME, AC_PROC_COMMAND, AC_PROC_TTY, AC_PROC_PROJID, 114 AC_PROC_TASKID, AC_PROC_ANCPID, AC_PROC_WAIT_STATUS, 115 AC_PROC_ZONENAME, AC_PROC_FLAG, AC_PROC_MEM, 116 AC_PROC_MICROSTATE, AC_NONE } }, 117 { AC_PROC, "basic", 118 { AC_PROC_PID, AC_PROC_UID, AC_PROC_GID, AC_PROC_CPU, 119 AC_PROC_TIME, AC_PROC_COMMAND, AC_PROC_TTY, AC_PROC_FLAG, 120 AC_NONE } }, 121 { AC_TASK, "extended", 122 { AC_TASK_TASKID, AC_TASK_PROJID, AC_TASK_CPU, AC_TASK_TIME, 123 AC_TASK_HOSTNAME, AC_TASK_MICROSTATE, AC_TASK_ANCTASKID, 124 AC_TASK_ZONENAME, AC_NONE } }, 125 { AC_TASK, "basic", 126 { AC_TASK_TASKID, AC_TASK_PROJID, AC_TASK_CPU, AC_TASK_TIME, 127 AC_NONE } }, 128 { AC_FLOW, "extended", 129 { AC_FLOW_SADDR, AC_FLOW_DADDR, AC_FLOW_SPORT, AC_FLOW_DPORT, 130 AC_FLOW_PROTOCOL, AC_FLOW_DSFIELD, AC_FLOW_NBYTES, 131 AC_FLOW_NPKTS, AC_FLOW_ANAME, AC_FLOW_CTIME, AC_FLOW_LSEEN, 132 AC_FLOW_PROJID, AC_FLOW_UID, AC_NONE } }, 133 { AC_FLOW, "basic", 134 { AC_FLOW_SADDR, AC_FLOW_DADDR, AC_FLOW_SPORT, AC_FLOW_DPORT, 135 AC_FLOW_PROTOCOL, AC_FLOW_NBYTES, AC_FLOW_NPKTS, AC_FLOW_ANAME, 136 AC_NONE } }, 137 { AC_NONE, NULL, 138 { AC_NONE } } 139 }; 140 141 /* 142 * this function returns the id of the named resource 143 */ 144 static int 145 name2id(char *name, int type) 146 { 147 ac_resname_t *acname = ac_names; 148 while (acname->ar_type != AC_NONE) { 149 if (acname->ar_type == type && 150 strcmp(acname->ar_name, name) == 0) { 151 if (acname->ar_id == AC_NONE) 152 /* 153 * For compatibility with older versions. 154 */ 155 return (-1); 156 else 157 return (acname->ar_id); 158 } 159 acname++; 160 } 161 return (0); 162 } 163 164 /* 165 * this function gives name of the resource by its id 166 */ 167 static char * 168 id2name(int id, int type) 169 { 170 ac_resname_t *acname = ac_names; 171 while (acname->ar_id != AC_NONE) { 172 if (acname->ar_type == type && 173 acname->ar_id == id) 174 return (acname->ar_name); 175 acname++; 176 } 177 return (NULL); 178 } 179 180 static void 181 printgroup(int type) 182 { 183 int r, g, id; 184 185 for (g = 0; ac_groups[g].ag_type != AC_NONE; g++) { 186 if (ac_groups[g].ag_type != type) 187 continue; 188 (void) printf("%-9s", ac_groups[g].ag_name); 189 (void) printf("%s", id2name(ac_groups[g].ag_mem[0], type)); 190 for (r = 1; (id = ac_groups[g].ag_mem[r]) != AC_NONE; r++) 191 (void) printf(",%s", id2name(id, type)); 192 (void) printf("\n"); 193 } 194 } 195 196 197 /* 198 * this function prints the list of resource groups and their members 199 */ 200 void 201 printgroups(int type) 202 { 203 int header = 0; 204 205 if ((type & AC_PROC) && (type & AC_TASK) && (type & AC_FLOW)) 206 header = 1; 207 208 if (type & AC_PROC) { 209 if (header == 1) 210 (void) printf("process:\n"); 211 printgroup(AC_PROC); 212 } 213 if (type & AC_TASK) { 214 if (header == 1) 215 (void) printf("task:\n"); 216 printgroup(AC_TASK); 217 } 218 if (type & AC_FLOW) { 219 if (header == 1) 220 (void) printf("flow:\n"); 221 printgroup(AC_FLOW); 222 } 223 } 224 225 /* 226 * this function sets the state of the particular resource 227 */ 228 static void 229 resset(ac_res_t *res, int id, int state) 230 { 231 ac_res_t *resp; 232 resp = (ac_res_t *)((uintptr_t)res + (sizeof (ac_res_t) * (id - 1))); 233 resp->ar_state = state; 234 resp->ar_id = id; 235 } 236 237 /* 238 * this function gets the state of the particular resource 239 */ 240 static int 241 resget(ac_res_t *res, int id) 242 { 243 ac_res_t *resp; 244 resp = (ac_res_t *)((uintptr_t)res + (sizeof (ac_res_t) * (id - 1))); 245 return (resp->ar_state); 246 } 247 248 /* 249 * this function converts a string of resources into a buffer which then 250 * can be used for acctctl() system call 251 */ 252 void 253 str2buf(ac_res_t *buf, char *str, int state, int type) 254 { 255 int i, j, id, ok; 256 char *p, *g, *copy; 257 258 if (strcmp(str, AC_STR_NONE) == 0) 259 return; 260 /* 261 * Take a lap through str, processing resources, modifying buf copy 262 * as appropriate and making sure that all resource names are valid. 263 */ 264 if ((copy = malloc(strlen(str) + 1)) == NULL) 265 die(gettext("not enough memory\n")); 266 (void) memcpy(copy, str, strlen(str) + 1); 267 p = strtok(copy, ", "); 268 while (p != NULL) { 269 /* 270 * check if str contains any resource groups 271 */ 272 for (ok = 0, i = 0; (g = ac_groups[i].ag_name) != NULL; i++) { 273 if (strcmp(p, g) == 0 && ac_groups[i].ag_type == type) { 274 for (j = 0; (id = ac_groups[i].ag_mem[j]) != 275 AC_NONE; j++) 276 resset(buf, id, state); 277 ok = 1; 278 break; 279 } 280 } 281 if (ok == 0) { 282 id = name2id(p, type); 283 if (id > 0) 284 resset(buf, id, state); 285 else if (id == 0) 286 die(gettext("unknown %s resource: %s\n"), 287 ac_type_name(type), p); 288 } 289 p = strtok(NULL, ", "); 290 } 291 free(copy); 292 } 293 294 /* 295 * this function converts a buffer into a string of resource names. 296 * state (on/off) for resources of interest is selected by the third argument. 297 * accounting type is selected by the fourth argument. 298 * it is caller's responsibility to free the allocated string buffer. 299 */ 300 char * 301 buf2str(ac_res_t *buffer, size_t bufsz, int state, int type) 302 { 303 int i, j, ok, id; 304 char *str, *g; 305 ac_res_t *buf, *cur; 306 307 if ((buf = malloc(bufsz)) == NULL || 308 (str = malloc(MAXRESLEN)) == NULL) 309 die(gettext("not enough memory\n")); 310 (void) memset(str, 0, MAXRESLEN); 311 (void) memcpy(buf, buffer, bufsz); 312 /* 313 * check if buf has any resource groups in it 314 */ 315 for (i = 0; (g = ac_groups[i].ag_name) != NULL; i++) { 316 if (ac_groups[i].ag_type != type) 317 continue; 318 for (j = 0; (id = ac_groups[i].ag_mem[j]) != AC_NONE; j++) { 319 ok = 1; 320 if (resget(buf, id) != state) { 321 ok = 0; 322 break; 323 } 324 } 325 if (ok) { /* buf contains this resource group */ 326 if (strlen(str) != 0) 327 (void) strcat(str, ","); 328 (void) strcat(str, g); 329 for (j = 0; (id = ac_groups[i].ag_mem[j]) != AC_NONE; 330 j++) 331 resset(buf, id, 332 state == AC_ON ? AC_OFF : AC_ON); 333 ok = 0; 334 } 335 } 336 /* 337 * browse through the rest of the buf for all remaining resources 338 * that are not a part of any groups 339 */ 340 for (cur = buf; cur->ar_id != AC_NONE; cur++) { 341 if (cur->ar_state == state) { 342 if (strlen(str) != 0) 343 (void) strcat(str, ","); 344 if (id2name(cur->ar_id, type) == NULL) 345 die(gettext("unknown %s resource id (%d)\n"), 346 ac_type_name(type), cur->ar_id); 347 (void) strcat(str, id2name(cur->ar_id, type)); 348 } 349 } 350 if (strlen(str) == 0) 351 (void) strcpy(str, AC_STR_NONE); 352 free(buf); 353 return (str); 354 } 355