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
name2id(char * name,int type)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 *
id2name(int id,int type)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
printgroup(int type)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
printgroups(int type)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
resset(ac_res_t * res,int id,int state)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
resget(ac_res_t * res,int id)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
str2buf(ac_res_t * buf,char * str,int state,int type)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 *
buf2str(ac_res_t * buffer,size_t bufsz,int state,int type)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