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.
27 #include <sys/types.h>
28 #include <sys/acctctl.h>
29 #include <sys/param.h>
45 static char PNAME_FMT
[] = "%s: ";
46 static char ERRNO_FMT
[] = ": %s\n";
52 warn(const char *format
, ...)
57 (void) fprintf(stderr
, gettext(PNAME_FMT
), pname
);
58 va_start(alist
, format
);
59 (void) vfprintf(stderr
, format
, alist
);
61 if (strchr(format
, '\n') == NULL
)
62 (void) fprintf(stderr
, gettext(ERRNO_FMT
), strerror(err
));
67 die(char *format
, ...)
73 (void) fprintf(stderr
, gettext(PNAME_FMT
), pname
);
74 va_start(alist
, format
);
75 (void) vfprintf(stderr
, format
, alist
);
77 if (strchr(format
, '\n') == NULL
)
78 (void) fprintf(stderr
, gettext(ERRNO_FMT
), strerror(err
));
80 /* close the libdladm handle if it was opened */
81 if (dld_handle
!= NULL
)
82 dladm_close(dld_handle
);
90 char *p
= strrchr(arg0
, '/');
101 * Return the localized name of an accounting type.
104 ac_type_name(int type
)
108 return (gettext("process"));
110 return (gettext("flow"));
112 return (gettext("task"));
114 return (gettext("net"));
116 die(gettext("invalid type %d\n"), type
);
123 * Open an accounting file. The filename specified must be an absolute
124 * pathname and the existing contents of the file (if any) must be of the
125 * requested type. Needs euid 0 to open the root-owned accounting file.
126 * file_dac_write is required to create a new file in a directory not owned
127 * by root (/var/adm/exacct is owned by 'adm'). Assumes sys_acct privilege is
128 * already asserted by caller.
131 open_exacct_file(const char *file
, int type
)
136 if (file
[0] != '/') {
137 warn(gettext("%s is not an absolute pathname\n"), file
);
140 if (!verify_exacct_file(file
, type
)) {
141 warn(gettext("%s is not a %s accounting file\n"), file
,
145 if (seteuid(0) == -1 || setegid(0) == -1) {
146 warn(gettext("seteuid()/setegid() failed"));
149 assert(priv_ineffect(PRIV_SYS_ACCT
));
150 (void) priv_set(PRIV_ON
, PRIV_EFFECTIVE
, PRIV_FILE_DAC_WRITE
, NULL
);
151 rc
= acctctl(type
| AC_FILE_SET
, (void *) file
, strlen(file
) + 1);
152 if (rc
== -1 && (err
= errno
) == EBUSY
) {
153 char name
[MAXPATHLEN
];
158 * The file is already open as an accounting file somewhere.
159 * If the file we're trying to open is the same as we have
160 * currently open then we're ok.
162 if (acctctl(type
| AC_FILE_GET
, name
, sizeof (name
)) == 0 &&
163 stat(file
, &new) != -1 && stat(name
, &cur
) != -1 &&
164 new.st_dev
== cur
.st_dev
&& new.st_ino
== cur
.st_ino
)
169 * euid 0, egid 0 and the file_dac_write privilege are no longer
170 * required; give them up permanently.
172 (void) priv_set(PRIV_OFF
, PRIV_PERMITTED
, PRIV_FILE_DAC_WRITE
, NULL
);
173 if (setreuid(getuid(), getuid()) == -1 ||
174 setregid(getgid(), getgid()) == -1)
175 die(gettext("setreuid()/setregid() failed"));
179 warn(gettext("cannot open %s accounting file %s: %s\n"),
180 ac_type_name(type
), file
, strerror(err
));
185 * Verify that the file contents (if any) are extended accounting records
186 * of the desired type.
189 verify_exacct_file(const char *file
, int type
)
196 if (stat(file
, &st
) != -1 && st
.st_size
!= 0) {
197 if (seteuid(0) == -1)
199 err
= ea_open(&ef
, file
, "SunOS", EO_TAIL
, O_RDONLY
, 0);
200 if (seteuid(getuid()) == 1)
201 die(gettext("seteuid() failed"));
205 bzero(&eo
, sizeof (eo
));
206 if (ea_previous_object(&ef
, &eo
) == EO_ERROR
) {
208 * EXR_EOF indicates there are no non-header objects
209 * in the file. It can't be determined that this
210 * file is or is not the proper type of extended
211 * accounting file, which isn't necessarily an error.
212 * Since it is a proper (albeit empty) extended
213 * accounting file, it matches any desired type.
215 * if ea_previous_object() failed for any other reason
216 * than EXR_EOF, the file must be corrupt.
218 if (ea_error() != EXR_EOF
) {
219 (void) ea_close(&ef
);
224 * A non-header object exists. Insist that it be
225 * either a process, task, flow or net accounting
226 * record, the same type as is desired.
227 * xxx-venu:check 101 merge for EXD_GROUP_NET_*
229 uint_t c
= eo
.eo_catalog
& EXD_DATA_MASK
;
231 if (eo
.eo_type
!= EO_GROUP
||
232 (eo
.eo_catalog
& EXC_CATALOG_MASK
) != EXC_NONE
||
233 (!(c
== EXD_GROUP_PROC
&& type
== AC_PROC
||
234 c
== EXD_GROUP_TASK
&& type
== AC_TASK
||
235 c
== EXD_GROUP_FLOW
&& type
== AC_FLOW
||
236 (c
== EXD_GROUP_NET_LINK_DESC
||
237 c
== EXD_GROUP_NET_FLOW_DESC
||
238 c
== EXD_GROUP_NET_LINK_STATS
||
239 c
== EXD_GROUP_NET_FLOW_STATS
) &&
241 (void) ea_close(&ef
);
245 (void) ea_close(&ef
);