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.
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.
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]
23 * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <sys/acctctl.h>
34 #include <libdllink.h>
44 #define ACCTADM_NET_LOG_INTERVAL 20
46 static const char USAGE
[] = "\
48 acctadm [ {process | task | flow | net} ]\n\
50 acctadm -r [ {process | task | flow | net} ]\n\
51 acctadm -x|-E|-D {process | task | flow | net}\n\
52 acctadm -f filename {process | task | flow | net}\n\
53 acctadm -e resources -d resources {process | task | flow | net}\n";
55 static const char OPTS
[] = "rsxf:e:d:ED";
57 dladm_handle_t dld_handle
= NULL
;
62 (void) fprintf(stderr
, gettext(USAGE
));
71 if (seteuid(getuid()) == -1 || setegid(getgid()) == -1)
72 die(gettext("seteuid()/setegid() failed"));
75 * Add our privileges and remove unneeded 'basic' privileges from the
78 if ((privset
= priv_str_to_set("basic", ",", NULL
)) == NULL
)
79 die(gettext("cannot setup privileges"));
81 (void) priv_addset(privset
, PRIV_SYS_ACCT
);
82 (void) priv_addset(privset
, PRIV_FILE_DAC_WRITE
);
83 (void) priv_addset(privset
, PRIV_SYS_DL_CONFIG
);
84 (void) priv_delset(privset
, PRIV_FILE_LINK_ANY
);
85 (void) priv_delset(privset
, PRIV_PROC_EXEC
);
86 (void) priv_delset(privset
, PRIV_PROC_FORK
);
87 (void) priv_delset(privset
, PRIV_PROC_INFO
);
88 (void) priv_delset(privset
, PRIV_PROC_SESSION
);
89 priv_inverse(privset
);
90 if (setppriv(PRIV_OFF
, PRIV_PERMITTED
, privset
) == -1)
91 die(gettext("cannot setup privileges"));
92 priv_freeset(privset
);
95 * Clear the Inheritable and Limit sets.
97 if ((privset
= priv_allocset()) == NULL
)
98 die(gettext("cannot setup privileges"));
99 priv_emptyset(privset
);
100 if (setppriv(PRIV_SET
, PRIV_INHERITABLE
, privset
) == -1 ||
101 setppriv(PRIV_SET
, PRIV_LIMIT
, privset
) == -1)
102 die(gettext("cannot setup privileges"));
105 * Turn off the sys_acct, file_dac_write and dl_config privileges
108 (void) priv_set(PRIV_OFF
, PRIV_EFFECTIVE
, PRIV_FILE_DAC_WRITE
,
109 PRIV_SYS_ACCT
, PRIV_SYS_DL_CONFIG
, NULL
);
113 main(int argc
, char *argv
[])
115 int c
; /* options character */
116 int type
= 0; /* type of accounting */
117 int modified
= 0; /* have we modified any properties? */
118 acctconf_t ac
; /* current configuration */
119 char *typestr
= NULL
; /* type of accounting argument string */
120 char *enabled
= NULL
; /* enabled resources string */
121 char *disabled
= NULL
; /* disabled resources string */
130 const char *fmri
; /* FMRI for this instance */
135 (void) setlocale(LC_ALL
, "");
136 (void) textdomain(TEXT_DOMAIN
);
137 (void) setpname(argv
[0]);
139 for (; optind
< argc
; optind
++) {
140 while ((c
= getopt(argc
, argv
, OPTS
)) != (int)EOF
) {
179 * Permanently give up euid 0, egid 0 and privileges we
180 * don't need for the specified options.
182 if (!(file
|| sflg
)) {
183 if (setreuid(getuid(), getuid()) == -1 ||
184 setregid(getgid(), getgid()) == -1)
185 die(gettext("setreuid()/setregid() failed"));
186 (void) priv_set(PRIV_OFF
, PRIV_PERMITTED
,
187 PRIV_FILE_DAC_WRITE
, NULL
);
189 if (!(disabled
|| enabled
|| Dflg
|| Eflg
|| file
|| sflg
||
191 (void) priv_set(PRIV_OFF
, PRIV_PERMITTED
,
192 PRIV_SYS_ACCT
, PRIV_SYS_DL_CONFIG
, NULL
);
195 if (typestr
!= NULL
) {
196 warn(gettext("illegal argument -- %s\n"),
200 typestr
= argv
[optind
];
204 if (typestr
!= NULL
) {
205 if (strcmp(typestr
, "process") == 0 ||
206 strcmp(typestr
, "proc") == 0)
208 else if (strcmp(typestr
, "task") == 0)
210 else if (strcmp(typestr
, "flow") == 0)
212 else if (strcmp(typestr
, "net") == 0)
215 warn(gettext("unknown accounting type -- %s\n"),
220 type
= AC_PROC
| AC_TASK
| AC_FLOW
| AC_NET
;
223 * Drop the DL config privilege if we are not working with
226 if ((type
& AC_NET
) == 0) {
227 (void) priv_set(PRIV_OFF
, PRIV_PERMITTED
,
228 PRIV_SYS_DL_CONFIG
, NULL
);
231 * check for invalid options
237 * XXX For AC_NET, enabled/disabled should only be "basic" or
238 * "extended" - need to check it here.
240 if ((enabled
|| disabled
) && (rflg
|| Dflg
|| sflg
|| xflg
|| Eflg
))
243 if ((file
|| xflg
|| Dflg
|| Eflg
|| enabled
|| disabled
) &&
245 warn(gettext("accounting type must be specified\n"));
255 * If no arguments have been passed then just print out the current
258 if (!enabled
&& !disabled
&& !file
&&
259 !Eflg
&& !rflg
&& !Dflg
&& !sflg
&& !xflg
) {
260 aconf_print(stdout
, type
);
264 /* Open the libdladm handle */
265 if (dladm_open(&dld_handle
) != DLADM_STATUS_OK
)
266 die(gettext("failed to open dladm handle\n"));
269 * smf(5) start method. The FMRI to operate on is retrieved from the
270 * SMF_FMRI environment variable that the restarter provides.
273 if ((fmri
= getenv("SMF_FMRI")) != NULL
) {
274 int ret
= aconf_setup(fmri
);
275 dladm_close(dld_handle
);
279 die(gettext("-s option should only be invoked by smf(5)\n"));
282 assert(type
== AC_PROC
|| type
== AC_TASK
|| type
== AC_FLOW
||
285 if ((type
== AC_FLOW
|| type
== AC_NET
) && getzoneid() != GLOBAL_ZONEID
)
286 die(gettext("%s accounting cannot be configured in "
287 "non-global zones\n"), ac_type_name(type
));
289 fmri
= aconf_type2fmri(type
);
290 if (aconf_scf_init(fmri
) == -1)
291 die(gettext("cannot connect to repository for %s\n"), fmri
);
294 * Since the sys_acct the privilege allows use of acctctl() regardless
295 * of the accounting type, we check the smf(5) authorizations granted
296 * to the user to determine whether the user is allowed to change the
297 * configuration for this particular accounting type.
299 if (!aconf_have_smf_auths())
300 die(gettext("insufficient authorization to change %s extended "
301 "accounting configuration\n"), ac_type_name(type
));
305 * Turn off the specified accounting and close its file
309 * Stop net logging before turning it off so that the last
310 * set of logs can be written.
313 (void) priv_set(PRIV_ON
, PRIV_EFFECTIVE
,
314 PRIV_SYS_DL_CONFIG
, NULL
);
315 err
= dladm_stop_usagelog(dld_handle
,
317 (void) priv_set(PRIV_OFF
, PRIV_EFFECTIVE
,
318 PRIV_SYS_DL_CONFIG
, NULL
);
319 if (err
!= DLADM_STATUS_OK
) {
320 die(gettext("failed to stop logging network "
321 "information, error %d\n"), errno
);
326 (void) priv_set(PRIV_ON
, PRIV_EFFECTIVE
, PRIV_SYS_ACCT
, NULL
);
327 if (acctctl(type
| AC_STATE_SET
, &state
, sizeof (int)) == -1)
328 die(gettext("cannot disable %s accounting"),
330 if (acctctl(type
| AC_FILE_SET
, NULL
, 0) == -1)
331 die(gettext("cannot close %s accounting file\n"),
333 (void) priv_set(PRIV_OFF
, PRIV_EFFECTIVE
, PRIV_SYS_ACCT
, NULL
);
335 if (aconf_set_bool(AC_PROP_STATE
, B_FALSE
) == -1)
336 die(gettext("cannot update %s property\n"),
338 if (aconf_set_string(AC_PROP_FILE
, AC_STR_NONE
) == -1)
339 die(gettext("cannot update %s property\n"),
344 if (enabled
|| disabled
) {
345 char *tracked
, *untracked
;
349 * Enable/disable resources
351 if ((buf
= malloc(AC_BUFSIZE
)) == NULL
)
352 die(gettext("not enough memory\n"));
353 (void) memset(buf
, 0, AC_BUFSIZE
);
354 if (acctctl(type
| AC_RES_GET
, buf
, AC_BUFSIZE
) == -1) {
356 die(gettext("cannot obtain list of resources\n"));
360 * Stop net logging before turning it off so that the
361 * last set of logs can be written.
364 (void) priv_set(PRIV_ON
, PRIV_EFFECTIVE
,
365 PRIV_SYS_DL_CONFIG
, NULL
);
366 err
= dladm_stop_usagelog(dld_handle
,
367 strcmp(disabled
, "basic") == 0 ?
368 DLADM_LOGTYPE_LINK
: DLADM_LOGTYPE_FLOW
);
369 (void) priv_set(PRIV_OFF
, PRIV_EFFECTIVE
,
370 PRIV_SYS_DL_CONFIG
, NULL
);
371 if (err
!= DLADM_STATUS_OK
) {
372 die(gettext("failed to stop logging "
373 "network information, error %d\n"),
377 str2buf(buf
, disabled
, AC_OFF
, type
);
378 } else if (enabled
) {
379 str2buf(buf
, enabled
, AC_ON
, type
);
381 (void) priv_set(PRIV_ON
, PRIV_EFFECTIVE
, PRIV_SYS_ACCT
, NULL
);
382 if (acctctl(type
| AC_RES_SET
, buf
, AC_BUFSIZE
) == -1) {
384 die(gettext("cannot enable/disable %s accounting "
385 "resources\n"), ac_type_name(type
));
387 (void) priv_set(PRIV_OFF
, PRIV_EFFECTIVE
, PRIV_SYS_ACCT
, NULL
);
388 tracked
= buf2str(buf
, AC_BUFSIZE
, AC_ON
, type
);
389 untracked
= buf2str(buf
, AC_BUFSIZE
, AC_OFF
, type
);
390 if (aconf_set_string(AC_PROP_TRACKED
, tracked
) == -1)
391 die(gettext("cannot update %s property\n"),
393 if (aconf_set_string(AC_PROP_UNTRACKED
, untracked
) == -1)
394 die(gettext("cannot update %s property\n"),
404 * Open new accounting file
406 (void) priv_set(PRIV_ON
, PRIV_EFFECTIVE
, PRIV_SYS_ACCT
, NULL
);
407 if (open_exacct_file(file
, type
) == -1) {
408 dladm_close(dld_handle
);
411 if (aconf_set_string(AC_PROP_FILE
, file
) == -1)
412 die(gettext("cannot update %s property\n"),
416 if (acctctl(type
| AC_STATE_SET
, &state
, sizeof (int)) == -1)
417 die(gettext("cannot enable %s accounting"),
419 (void) priv_set(PRIV_OFF
, PRIV_EFFECTIVE
, PRIV_SYS_ACCT
, NULL
);
421 if (aconf_set_bool(AC_PROP_STATE
, B_TRUE
) == -1)
422 die(gettext("cannot update %s property\n"),
428 * Let's get network logging started. We do this after turning on
429 * accounting and opening the file so that we can start writing
432 if (enabled
&& (type
& AC_NET
)) {
434 * Default logging interval for AC_NET is
435 * ACCTADM_NET_LOG_INTERVAL.
437 (void) priv_set(PRIV_ON
, PRIV_EFFECTIVE
,
438 PRIV_SYS_DL_CONFIG
, NULL
);
439 err
= dladm_start_usagelog(dld_handle
,
440 strcmp(enabled
, "basic") == 0 ?
441 DLADM_LOGTYPE_LINK
: DLADM_LOGTYPE_FLOW
,
442 ACCTADM_NET_LOG_INTERVAL
);
443 (void) priv_set(PRIV_OFF
, PRIV_EFFECTIVE
,
444 PRIV_SYS_DL_CONFIG
, NULL
);
445 if (err
!= DLADM_STATUS_OK
) {
446 die(gettext("failed to start logging "
447 "network information, error %d\n"),
458 * Stop net logging before turning it off so that the last
459 * set of logs can be written.
462 (void) priv_set(PRIV_ON
, PRIV_EFFECTIVE
,
463 PRIV_SYS_DL_CONFIG
, NULL
);
464 err
= dladm_stop_usagelog(dld_handle
,
466 (void) priv_set(PRIV_OFF
, PRIV_EFFECTIVE
,
467 PRIV_SYS_DL_CONFIG
, NULL
);
468 if (err
!= DLADM_STATUS_OK
) {
469 die(gettext("failed to stop logging "
470 "network information, error %d\n"), errno
);
475 (void) priv_set(PRIV_ON
, PRIV_EFFECTIVE
, PRIV_SYS_ACCT
, NULL
);
476 if (acctctl(type
| AC_STATE_SET
, &state
, sizeof (int)) == -1)
477 die(gettext("cannot disable %s accounting"),
479 (void) priv_set(PRIV_OFF
, PRIV_EFFECTIVE
, PRIV_SYS_ACCT
, NULL
);
481 if (aconf_set_bool(AC_PROP_STATE
, B_FALSE
) == -1)
482 die(gettext("cannot update %s property\n"),
493 * Let's get network logging started.
497 * Default logging interval for AC_NET is
498 * ACCTADM_NET_LOG_INTERVAL.
500 (void) priv_set(PRIV_ON
, PRIV_EFFECTIVE
,
501 PRIV_SYS_DL_CONFIG
, NULL
);
502 err
= dladm_start_usagelog(dld_handle
,
503 DLADM_LOGTYPE_FLOW
, ACCTADM_NET_LOG_INTERVAL
);
504 (void) priv_set(PRIV_OFF
, PRIV_EFFECTIVE
,
505 PRIV_SYS_DL_CONFIG
, NULL
);
506 if (err
!= DLADM_STATUS_OK
) {
507 die(gettext("failed to start logging "
508 "network information, error %d\n"), errno
);
513 (void) priv_set(PRIV_ON
, PRIV_EFFECTIVE
, PRIV_SYS_ACCT
, NULL
);
514 if (acctctl(type
| AC_STATE_SET
, &state
, sizeof (int)) == -1)
515 die(gettext("cannot enable %s accounting"),
517 (void) priv_set(PRIV_OFF
, PRIV_EFFECTIVE
, PRIV_SYS_ACCT
, NULL
);
519 if (aconf_set_bool(AC_PROP_STATE
, B_TRUE
) == -1)
520 die(gettext("cannot update %s property\n"),
524 (void) priv_set(PRIV_OFF
, PRIV_PERMITTED
, PRIV_SYS_ACCT
, NULL
);
529 if (aconf_save() == -1)
530 die(gettext("cannot save %s accounting "
531 "configuration\n"), ac_type_name(type
));
534 * Enable or disable the instance depending on the effective
535 * configuration. If the effective configuration results in
536 * extended accounting being 'on', the instance is enabled so
537 * the configuration is applied at the next boot.
539 smf_state
= smf_get_state(fmri
);
540 aconf_init(&ac
, type
);
542 if (ac
.state
== AC_ON
||
543 strcmp(ac
.file
, AC_STR_NONE
) != 0 ||
544 strcmp(ac
.tracked
, AC_STR_NONE
) != 0) {
545 if (strcmp(smf_state
, SCF_STATE_STRING_ONLINE
) != 0)
546 if (smf_enable_instance(fmri
, 0) == -1)
547 die(gettext("cannot enable %s\n"),
550 if (strcmp(smf_state
, SCF_STATE_STRING_ONLINE
) == 0)
551 if (smf_disable_instance(fmri
, 0) == -1)
552 die(gettext("cannot disable %s\n"),
558 dladm_close(dld_handle
);