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