dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / acctadm / utils.c
blob289111e210d6ef61e97725ee73eab31ca97a6a68
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
23 * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <assert.h>
27 #include <sys/types.h>
28 #include <sys/acctctl.h>
29 #include <sys/param.h>
30 #include <sys/stat.h>
31 #include <libintl.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <strings.h>
37 #include <unistd.h>
38 #include <errno.h>
39 #include <exacct.h>
40 #include <fcntl.h>
41 #include <priv.h>
43 #include "utils.h"
45 static char PNAME_FMT[] = "%s: ";
46 static char ERRNO_FMT[] = ": %s\n";
48 static char *pname;
50 /*PRINTFLIKE1*/
51 void
52 warn(const char *format, ...)
54 int err = errno;
55 va_list alist;
56 if (pname != NULL)
57 (void) fprintf(stderr, gettext(PNAME_FMT), pname);
58 va_start(alist, format);
59 (void) vfprintf(stderr, format, alist);
60 va_end(alist);
61 if (strchr(format, '\n') == NULL)
62 (void) fprintf(stderr, gettext(ERRNO_FMT), strerror(err));
65 /*PRINTFLIKE1*/
66 void
67 die(char *format, ...)
69 int err = errno;
70 va_list alist;
72 if (pname != NULL)
73 (void) fprintf(stderr, gettext(PNAME_FMT), pname);
74 va_start(alist, format);
75 (void) vfprintf(stderr, format, alist);
76 va_end(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);
84 exit(E_ERROR);
87 char *
88 setpname(char *arg0)
90 char *p = strrchr(arg0, '/');
92 if (p == NULL)
93 p = arg0;
94 else
95 p++;
96 pname = p;
97 return (pname);
101 * Return the localized name of an accounting type.
103 const char *
104 ac_type_name(int type)
106 switch (type) {
107 case AC_PROC:
108 return (gettext("process"));
109 case AC_FLOW:
110 return (gettext("flow"));
111 case AC_TASK:
112 return (gettext("task"));
113 case AC_NET:
114 return (gettext("net"));
115 default:
116 die(gettext("invalid type %d\n"), type);
118 /* NOTREACHED */
119 return (NULL);
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)
133 int rc;
134 int err;
136 if (file[0] != '/') {
137 warn(gettext("%s is not an absolute pathname\n"), file);
138 return (-1);
140 if (!verify_exacct_file(file, type)) {
141 warn(gettext("%s is not a %s accounting file\n"), file,
142 ac_type_name(type));
143 return (-1);
145 if (seteuid(0) == -1 || setegid(0) == -1) {
146 warn(gettext("seteuid()/setegid() failed"));
147 return (-1);
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];
154 struct stat cur;
155 struct stat new;
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)
165 rc = 0;
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"));
176 if (rc == 0)
177 return (0);
179 warn(gettext("cannot open %s accounting file %s: %s\n"),
180 ac_type_name(type), file, strerror(err));
181 return (-1);
185 * Verify that the file contents (if any) are extended accounting records
186 * of the desired type.
188 boolean_t
189 verify_exacct_file(const char *file, int type)
191 ea_file_t ef;
192 ea_object_t eo;
193 struct stat st;
194 int err;
196 if (stat(file, &st) != -1 && st.st_size != 0) {
197 if (seteuid(0) == -1)
198 return (B_FALSE);
199 err = ea_open(&ef, file, "SunOS", EO_TAIL, O_RDONLY, 0);
200 if (seteuid(getuid()) == 1)
201 die(gettext("seteuid() failed"));
202 if (err == -1)
203 return (B_FALSE);
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);
220 return (B_FALSE);
222 } else {
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) &&
240 type == AC_NET))) {
241 (void) ea_close(&ef);
242 return (B_FALSE);
245 (void) ea_close(&ef);
247 return (B_TRUE);