GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/sa/usrdb.c Lines: 76 127 59.8 %
Date: 2017-11-13 Branches: 33 65 50.8 %

Line Branch Exec Source
1
/*	$OpenBSD: usrdb.c,v 1.10 2016/08/14 22:29:01 krw Exp $	*/
2
/*
3
 * Copyright (c) 1994 Christopher G. Demetriou
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 * 3. All advertising materials mentioning features or use of this software
15
 *    must display the following acknowledgement:
16
 *      This product includes software developed by Christopher G. Demetriou.
17
 * 4. The name of the author may not be used to endorse or promote products
18
 *    derived from this software without specific prior written permission
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
 */
31
32
#include <sys/types.h>
33
#include <sys/acct.h>
34
#include <err.h>
35
#include <errno.h>
36
#include <fcntl.h>
37
#include <pwd.h>
38
#include <stdio.h>
39
#include <string.h>
40
#include "extern.h"
41
#include "pathnames.h"
42
43
static int uid_compare(const DBT *, const DBT *);
44
45
static DB	*usracct_db;
46
47
int
48
usracct_init(void)
49
{
50
	DB *saved_usracct_db;
51
10
	BTREEINFO bti;
52
	int error;
53
54
5
	memset(&bti, 0, sizeof(bti));
55
5
	bti.compare = uid_compare;
56
57
5
	usracct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti);
58
5
	if (usracct_db == NULL)
59
		return (-1);
60
61
	error = 0;
62
5
	if (!iflag) {
63
5
		DBT key, data;
64
		int serr, nerr;
65
66
5
		saved_usracct_db = dbopen(_PATH_USRACCT, O_RDONLY, 0, DB_BTREE,
67
		    &bti);
68
5
		if (saved_usracct_db == NULL) {
69
1
			error = (errno == ENOENT) ? 0 : -1;
70
1
			if (error)
71
				warn("retrieving user accounting summary");
72
1
			goto out;
73
		}
74
75
4
		serr = DB_SEQ(saved_usracct_db, &key, &data, R_FIRST);
76
4
		if (serr < 0) {
77
			warn("retrieving user accounting summary");
78
			error = -1;
79
			goto closeout;
80
		}
81
94
		while (serr == 0) {
82
43
			nerr = DB_PUT(usracct_db, &key, &data, 0);
83
43
			if (nerr < 0) {
84
				warn("initializing user accounting stats");
85
				error = -1;
86
				break;
87
			}
88
89
43
			serr = DB_SEQ(saved_usracct_db, &key, &data, R_NEXT);
90
43
			if (serr < 0) {
91
				warn("retrieving user accounting summary");
92
				error = -1;
93
				break;
94
			}
95
		}
96
97
closeout:
98
4
		if (DB_CLOSE(saved_usracct_db) < 0) {
99
			warn("closing user accounting summary");
100
			error = -1;
101
		}
102
14
	}
103
104
out:
105
5
	if (error != 0)
106
		usracct_destroy();
107
5
	return (error);
108
5
}
109
110
void
111
usracct_destroy(void)
112
{
113
10
	if (DB_CLOSE(usracct_db) < 0)
114
		warn("destroying user accounting stats");
115
5
}
116
117
int
118
usracct_add(const struct cmdinfo *ci)
119
{
120
596246
	DBT key, data;
121
298123
	struct userinfo newui;
122
298123
	uid_t uid;
123
	int rv;
124
125
298123
	uid = ci->ci_uid;
126
298123
	key.data = &uid;
127
298123
	key.size = sizeof(uid);
128
129
298123
	rv = DB_GET(usracct_db, &key, &data, 0);
130
298123
	if (rv < 0) {
131
		warn("get key %u from user accounting stats", uid);
132
		return (-1);
133
298123
	} else if (rv == 0) {	/* it's there; copy whole thing */
134
		/* add the old data to the new data */
135
298108
		memcpy(&newui, data.data, data.size);
136
298108
		if (newui.ui_uid != uid) {
137
			warnx("key %u != expected record number %u",
138
			    newui.ui_uid, uid);
139
			warnx("inconsistent user accounting stats");
140
			return (-1);
141
		}
142
	} else {		/* it's not there; zero it and copy the key */
143
15
		memset(&newui, 0, sizeof(newui));
144
15
		newui.ui_uid = ci->ci_uid;
145
	}
146
147
298123
	newui.ui_calls += ci->ci_calls;
148
298123
	newui.ui_utime += ci->ci_utime;
149
298123
	newui.ui_stime += ci->ci_stime;
150
298123
	newui.ui_mem += ci->ci_mem;
151
298123
	newui.ui_io += ci->ci_io;
152
153
298123
	data.data = &newui;
154
298123
	data.size = sizeof(newui);
155
298123
	rv = DB_PUT(usracct_db, &key, &data, 0);
156
298123
	if (rv < 0) {
157
		warn("add key %u to user accounting stats", uid);
158
		return (-1);
159
298123
	} else if (rv != 0) {
160
		warnx("DB_PUT returned 1");
161
		return (-1);
162
	}
163
164
298123
	return (0);
165
298123
}
166
167
int
168
usracct_update(void)
169
{
170
	DB *saved_usracct_db;
171
10
	DBT key, data;
172
5
	BTREEINFO bti;
173
	int error, serr, nerr;
174
175
5
	memset(&bti, 0, sizeof(bti));
176
5
	bti.compare = uid_compare;
177
178
5
	saved_usracct_db = dbopen(_PATH_USRACCT, O_RDWR|O_CREAT|O_TRUNC, 0644,
179
	    DB_BTREE, &bti);
180
5
	if (saved_usracct_db == NULL) {
181
		warn("creating user accounting summary");
182
		return (-1);
183
	}
184
185
	error = 0;
186
187
5
	serr = DB_SEQ(usracct_db, &key, &data, R_FIRST);
188
5
	if (serr < 0) {
189
		warn("retrieving user accounting stats");
190
		error = -1;
191
	}
192
126
	while (serr == 0) {
193
58
		nerr = DB_PUT(saved_usracct_db, &key, &data, 0);
194
58
		if (nerr < 0) {
195
			warn("saving user accounting summary");
196
			error = -1;
197
			break;
198
		}
199
200
58
		serr = DB_SEQ(usracct_db, &key, &data, R_NEXT);
201
58
		if (serr < 0) {
202
			warn("retrieving user accounting stats");
203
			error = -1;
204
			break;
205
		}
206
	}
207
208
5
	if (DB_SYNC(saved_usracct_db, 0) < 0) {
209
		warn("syncing process accounting summary");
210
		error = -1;
211
	}
212
5
	if (DB_CLOSE(saved_usracct_db) < 0) {
213
		warn("closing process accounting summary");
214
		error = -1;
215
	}
216
5
	return error;
217
5
}
218
219
void
220
usracct_print(void)
221
{
222
	DBT key, data;
223
	struct userinfo uistore, *ui = &uistore;
224
	double t;
225
	int rv;
226
227
	rv = DB_SEQ(usracct_db, &key, &data, R_FIRST);
228
	if (rv < 0)
229
		warn("retrieving user accounting stats");
230
231
	while (rv == 0) {
232
		memcpy(ui, data.data, sizeof(struct userinfo));
233
234
		printf("%-8s %9llu ",
235
		    user_from_uid(ui->ui_uid, 0), ui->ui_calls);
236
237
		t = (double) (ui->ui_utime + ui->ui_stime) /
238
		    (double) AHZ;
239
		if (t < 0.0001)		/* kill divide by zero */
240
			t = 0.0001;
241
242
		printf("%12.2f%s ", t / 60.0, "cpu");
243
244
		/* ui->ui_calls is always != 0 */
245
		if (dflag)
246
			printf("%12llu%s", ui->ui_io / ui->ui_calls, "avio");
247
		else
248
			printf("%12llu%s", ui->ui_io, "tio");
249
250
		/* t is always >= 0.0001; see above */
251
		if (kflag)
252
			printf("%12.0f%s", ui->ui_mem / t, "k");
253
		else
254
			printf("%12llu%s", ui->ui_mem, "k*sec");
255
256
		printf("\n");
257
258
		rv = DB_SEQ(usracct_db, &key, &data, R_NEXT);
259
		if (rv < 0)
260
			warn("retrieving user accounting stats");
261
	}
262
}
263
264
static int
265
uid_compare(const DBT *k1, const DBT *k2)
266
{
267
	uid_t d1, d2;
268
269
4549276
	memcpy(&d1, k1->data, sizeof(d1));
270
2274638
	memcpy(&d2, k2->data, sizeof(d2));
271
272
2274638
	if (d1 < d2)
273
1671664
		return -1;
274
602974
	else if (d1 == d2)
275
596216
		return 0;
276
	else
277
6758
		return 1;
278
2274638
}