]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/sa/usrdb.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.sbin / sa / usrdb.c
1 /*
2  * Copyright (c) 1994 Christopher G. Demetriou
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Christopher G. Demetriou.
16  * 4. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/param.h>
35 #include <sys/types.h>
36 #include <sys/acct.h>
37 #include <err.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <pwd.h>
41 #include <stdint.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include "extern.h"
46 #include "pathnames.h"
47
48 static int uid_compare(const DBT *, const DBT *);
49
50 static DB       *usracct_db;
51
52 /* Legacy format in AHZV1 units. */
53 struct userinfov1 {
54         uid_t           ui_uid;                 /* user id; for consistency */
55         u_quad_t        ui_calls;               /* number of invocations */
56         u_quad_t        ui_utime;               /* user time */
57         u_quad_t        ui_stime;               /* system time */
58         u_quad_t        ui_mem;                 /* memory use */
59         u_quad_t        ui_io;                  /* number of disk i/o ops */
60 };
61
62 /*
63  * Convert a v1 data record into the current version.
64  * Return 0 if OK, -1 on error, setting errno.
65  */
66 static int
67 v1_to_v2(DBT *key, DBT *data)
68 {
69         struct userinfov1 uiv1;
70         static struct userinfo uiv2;
71         static uid_t uid;
72
73         if (key->size != sizeof(u_long) || data->size != sizeof(uiv1)) {
74                 errno = EFTYPE;
75                 return (-1);
76         }
77
78         /* Convert key. */
79         key->size = sizeof(uid_t);
80         uid = (uid_t)*(u_long *)(key->data);
81         key->data = &uid;
82
83         /* Convert data. */
84         memcpy(&uiv1, data->data, data->size);
85         memset(&uiv2, 0, sizeof(uiv2));
86         uiv2.ui_uid = uiv1.ui_uid;
87         uiv2.ui_calls = uiv1.ui_calls;
88         uiv2.ui_utime = ((double)uiv1.ui_utime / AHZV1) * 1000000;
89         uiv2.ui_stime = ((double)uiv1.ui_stime / AHZV1) * 1000000;
90         uiv2.ui_mem = uiv1.ui_mem;
91         uiv2.ui_io = uiv1.ui_io;
92         data->size = sizeof(uiv2);
93         data->data = &uiv2;
94
95         return (0);
96 }
97
98 /* Copy usrdb_file to in-memory usracct_db. */
99 int
100 usracct_init(void)
101 {
102         BTREEINFO bti;
103
104         bzero(&bti, sizeof bti);
105         bti.compare = uid_compare;
106
107         return (db_copy_in(&usracct_db, usrdb_file, "user accounting",
108             &bti, v1_to_v2));
109 }
110
111 void
112 usracct_destroy(void)
113 {
114         db_destroy(usracct_db, "user accounting");
115 }
116
117 int
118 usracct_add(const struct cmdinfo *ci)
119 {
120         DBT key, data;
121         struct userinfo newui;
122         uid_t uid;
123         int rv;
124
125         uid = ci->ci_uid;
126         key.data = &uid;
127         key.size = sizeof uid;
128
129         rv = DB_GET(usracct_db, &key, &data, 0);
130         if (rv < 0) {
131                 warn("get key %u from user accounting stats", uid);
132                 return (-1);
133         } else if (rv == 0) {   /* it's there; copy whole thing */
134                 /* add the old data to the new data */
135                 bcopy(data.data, &newui, data.size);
136                 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                 bzero(&newui, sizeof newui);
144                 newui.ui_uid = ci->ci_uid;
145         }
146
147         newui.ui_calls += ci->ci_calls;
148         newui.ui_utime += ci->ci_utime;
149         newui.ui_stime += ci->ci_stime;
150         newui.ui_mem += ci->ci_mem;
151         newui.ui_io += ci->ci_io;
152
153         data.data = &newui;
154         data.size = sizeof newui;
155         rv = DB_PUT(usracct_db, &key, &data, 0);
156         if (rv < 0) {
157                 warn("add key %u to user accounting stats", uid);
158                 return (-1);
159         } else if (rv != 0) {
160                 warnx("DB_PUT returned 1");
161                 return (-1);
162         }
163
164         return (0);
165 }
166
167 /* Copy in-memory usracct_db to usrdb_file. */
168 int
169 usracct_update(void)
170 {
171         BTREEINFO bti;
172
173         bzero(&bti, sizeof bti);
174         bti.compare = uid_compare;
175
176         return (db_copy_out(usracct_db, usrdb_file, "user accounting",
177             &bti));
178 }
179
180 void
181 usracct_print(void)
182 {
183         DBT key, data;
184         struct userinfo uistore, *ui = &uistore;
185         double t;
186         int rv;
187
188         rv = DB_SEQ(usracct_db, &key, &data, R_FIRST);
189         if (rv < 0)
190                 warn("retrieving user accounting stats");
191
192         while (rv == 0) {
193                 memcpy(ui, data.data, sizeof(struct userinfo));
194
195                 printf("%-*s %9ju ", MAXLOGNAME - 1,
196                     user_from_uid(ui->ui_uid, 0), (uintmax_t)ui->ui_calls);
197
198                 t = (ui->ui_utime + ui->ui_stime) / 1000000;
199                 if (t < 0.000001)               /* kill divide by zero */
200                         t = 0.000001;
201
202                 printf("%12.2f%s ", t / 60.0, "cpu");
203
204                 /* ui->ui_calls is always != 0 */
205                 if (dflag)
206                         printf("%12.0f%s",
207                             ui->ui_io / ui->ui_calls, "avio");
208                 else
209                         printf("%12.0f%s", ui->ui_io, "tio");
210
211                 /* t is always >= 0.000001; see above. */
212                 if (kflag)
213                         printf("%12.0f%s", ui->ui_mem / t, "k");
214                 else
215                         printf("%12.0f%s", ui->ui_mem, "k*sec");
216
217                 printf("\n");
218
219                 rv = DB_SEQ(usracct_db, &key, &data, R_NEXT);
220                 if (rv < 0)
221                         warn("retrieving user accounting stats");
222         }
223 }
224
225 static int
226 uid_compare(const DBT *k1, const DBT *k2)
227 {
228         uid_t d1, d2;
229
230         bcopy(k1->data, &d1, sizeof d1);
231         bcopy(k2->data, &d2, sizeof d2);
232
233         if (d1 < d2)
234                 return -1;
235         else if (d1 == d2)
236                 return 0;
237         else
238                 return 1;
239 }