Merge branch 'vendor/OPENSSL'
[dragonfly.git] / usr.sbin / sa / pdb.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  * $FreeBSD: src/usr.sbin/sa/pdb.c,v 1.7 1999/08/28 01:19:53 peter Exp $
31  */
32
33 #include <sys/types.h>
34 #include <sys/acct.h>
35 #include <err.h>
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include "extern.h"
41 #include "pathnames.h"
42
43 static int check_junk(struct cmdinfo *);
44 static void add_ci(const struct cmdinfo *, struct cmdinfo *);
45 static void print_ci(const struct cmdinfo *, const struct cmdinfo *);
46
47 static DB       *pacct_db;
48
49 int
50 pacct_init(void)
51 {
52         DB *saved_pacct_db;
53         int error;
54
55         pacct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL);
56         if (pacct_db == NULL)
57                 return (-1);
58
59         error = 0;
60         if (!iflag) {
61                 DBT key, data;
62                 int serr, nerr;
63
64                 saved_pacct_db = dbopen(_PATH_SAVACCT, O_RDONLY, 0, DB_BTREE,
65                     NULL);
66                 if (saved_pacct_db == NULL) {
67                         error = errno == ENOENT ? 0 : -1;
68                         if (error)
69                                 warn("retrieving process accounting summary");
70                         goto out;
71                 }
72
73                 serr = DB_SEQ(saved_pacct_db, &key, &data, R_FIRST);
74                 if (serr < 0) {
75                         warn("retrieving process accounting summary");
76                         error = -1;
77                         goto closeout;
78                 }
79                 while (serr == 0) {
80                         nerr = DB_PUT(pacct_db, &key, &data, 0);
81                         if (nerr < 0) {
82                                 warn("initializing process accounting stats");
83                                 error = -1;
84                                 break;
85                         }
86
87                         serr = DB_SEQ(saved_pacct_db, &key, &data, R_NEXT);
88                         if (serr < 0) {
89                                 warn("retrieving process accounting summary");
90                                 error = -1;
91                                 break;
92                         }
93                 }
94
95 closeout:       if (DB_CLOSE(saved_pacct_db) < 0) {
96                         warn("closing process accounting summary");
97                         error = -1;
98                 }
99         }
100
101 out:    if (error != 0)
102                 pacct_destroy();
103         return (error);
104 }
105
106 void
107 pacct_destroy(void)
108 {
109         if (DB_CLOSE(pacct_db) < 0)
110                 warn("destroying process accounting stats");
111 }
112
113 int
114 pacct_add(const struct cmdinfo *ci)
115 {
116         DBT key, data;
117         struct cmdinfo newci;
118         char keydata[sizeof ci->ci_comm];
119         int rv;
120
121         bcopy(ci->ci_comm, &keydata, sizeof keydata);
122         key.data = &keydata;
123         key.size = strlen(keydata);
124
125         rv = DB_GET(pacct_db, &key, &data, 0);
126         if (rv < 0) {
127                 warn("get key %s from process accounting stats", ci->ci_comm);
128                 return (-1);
129         } else if (rv == 0) {   /* it's there; copy whole thing */
130                 /* XXX compare size if paranoid */
131                 /* add the old data to the new data */
132                 bcopy(data.data, &newci, data.size);
133         } else {                /* it's not there; zero it and copy the key */
134                 bzero(&newci, sizeof newci);
135                 bcopy(key.data, newci.ci_comm, key.size);
136         }
137
138         add_ci(ci, &newci);
139
140         data.data = &newci;
141         data.size = sizeof newci;
142         rv = DB_PUT(pacct_db, &key, &data, 0);
143         if (rv < 0) {
144                 warn("add key %s to process accounting stats", ci->ci_comm);
145                 return (-1);
146         } else if (rv == 1) {
147                 warnx("duplicate key %s in process accounting stats",
148                     ci->ci_comm);
149                 return (-1);
150         }
151
152         return (0);
153 }
154
155 int
156 pacct_update(void)
157 {
158         DB *saved_pacct_db;
159         DBT key, data;
160         int error, serr, nerr;
161
162         saved_pacct_db = dbopen(_PATH_SAVACCT, O_RDWR|O_CREAT|O_TRUNC, 0644,
163             DB_BTREE, NULL);
164         if (saved_pacct_db == NULL) {
165                 warn("creating process accounting summary");
166                 return (-1);
167         }
168
169         error = 0;
170
171         serr = DB_SEQ(pacct_db, &key, &data, R_FIRST);
172         if (serr < 0) {
173                 warn("retrieving process accounting stats");
174                 error = -1;
175         }
176         while (serr == 0) {
177                 nerr = DB_PUT(saved_pacct_db, &key, &data, 0);
178                 if (nerr < 0) {
179                         warn("saving process accounting summary");
180                         error = -1;
181                         break;
182                 }
183
184                 serr = DB_SEQ(pacct_db, &key, &data, R_NEXT);
185                 if (serr < 0) {
186                         warn("retrieving process accounting stats");
187                         error = -1;
188                         break;
189                 }
190         }
191
192         if (DB_SYNC(saved_pacct_db, 0) < 0) {
193                 warn("syncing process accounting summary");
194                 error = -1;
195         }
196         if (DB_CLOSE(saved_pacct_db) < 0) {
197                 warn("closing process accounting summary");
198                 error = -1;
199         }
200         return error;
201 }
202
203 void
204 pacct_print(void)
205 {
206         BTREEINFO bti;
207         DBT key, data, ndata;
208         DB *output_pacct_db;
209         struct cmdinfo *cip, ci, ci_total, ci_other, ci_junk;
210         int rv;
211
212         bzero(&ci_total, sizeof ci_total);
213         strcpy(ci_total.ci_comm, "");
214         bzero(&ci_other, sizeof ci_other);
215         strcpy(ci_other.ci_comm, "***other");
216         bzero(&ci_junk, sizeof ci_junk);
217         strcpy(ci_junk.ci_comm, "**junk**");
218
219         /*
220          * Retrieve them into new DB, sorted by appropriate key.
221          * At the same time, cull 'other' and 'junk'
222          */
223         bzero(&bti, sizeof bti);
224         bti.compare = sa_cmp;
225         output_pacct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti);
226         if (output_pacct_db == NULL) {
227                 warn("couldn't sort process accounting stats");
228                 return;
229         }
230
231         ndata.data = NULL;
232         ndata.size = 0;
233         rv = DB_SEQ(pacct_db, &key, &data, R_FIRST);
234         if (rv < 0)
235                 warn("retrieving process accounting stats");
236         while (rv == 0) {
237                 cip = (struct cmdinfo *) data.data;
238                 bcopy(cip, &ci, sizeof ci);
239
240                 /* add to total */
241                 add_ci(&ci, &ci_total);
242
243                 if (vflag && ci.ci_calls <= cutoff &&
244                     (fflag || check_junk(&ci))) {
245                         /* put it into **junk** */
246                         add_ci(&ci, &ci_junk);
247                         goto next;
248                 }
249                 if (!aflag &&
250                     ((ci.ci_flags & CI_UNPRINTABLE) != 0 || ci.ci_calls <= 1)) {
251                         /* put into ***other */
252                         add_ci(&ci, &ci_other);
253                         goto next;
254                 }
255                 rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
256                 if (rv < 0)
257                         warn("sorting process accounting stats");
258
259 next:           rv = DB_SEQ(pacct_db, &key, &data, R_NEXT);
260                 if (rv < 0)
261                         warn("retrieving process accounting stats");
262         }
263
264         /* insert **junk** and ***other */
265         if (ci_junk.ci_calls != 0) {
266                 data.data = &ci_junk;
267                 data.size = sizeof ci_junk;
268                 rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
269                 if (rv < 0)
270                         warn("sorting process accounting stats");
271         }
272         if (ci_other.ci_calls != 0) {
273                 data.data = &ci_other;
274                 data.size = sizeof ci_other;
275                 rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
276                 if (rv < 0)
277                         warn("sorting process accounting stats");
278         }
279
280         /* print out the total */
281         print_ci(&ci_total, &ci_total);
282
283         /* print out; if reversed, print first (smallest) first */
284         rv = DB_SEQ(output_pacct_db, &data, &ndata, rflag ? R_FIRST : R_LAST);
285         if (rv < 0)
286                 warn("retrieving process accounting report");
287         while (rv == 0) {
288                 cip = (struct cmdinfo *) data.data;
289                 bcopy(cip, &ci, sizeof ci);
290
291                 print_ci(&ci, &ci_total);
292
293                 rv = DB_SEQ(output_pacct_db, &data, &ndata,
294                     rflag ? R_NEXT : R_PREV);
295                 if (rv < 0)
296                         warn("retrieving process accounting report");
297         }
298         DB_CLOSE(output_pacct_db);
299 }
300
301 static int
302 check_junk(struct cmdinfo *cip)
303 {
304         char *cp;
305         size_t len;
306
307         fprintf(stderr, "%s (%ju) -- ", cip->ci_comm,
308             (uintmax_t)cip->ci_calls);
309         cp = fgetln(stdin, &len);
310
311         return (cp && (cp[0] == 'y' || cp[0] == 'Y')) ? 1 : 0;
312 }
313
314 static void
315 add_ci(const struct cmdinfo *fromcip, struct cmdinfo *tocip)
316 {
317         tocip->ci_calls += fromcip->ci_calls;
318         tocip->ci_etime += fromcip->ci_etime;
319         tocip->ci_utime += fromcip->ci_utime;
320         tocip->ci_stime += fromcip->ci_stime;
321         tocip->ci_mem += fromcip->ci_mem;
322         tocip->ci_io += fromcip->ci_io;
323 }
324
325 static void
326 print_ci(const struct cmdinfo *cip, const struct cmdinfo *totalcip)
327 {
328         double t, c;
329         int uflow;
330
331         c = cip->ci_calls ? cip->ci_calls : 1;
332         t = (cip->ci_utime + cip->ci_stime) / (double) AHZ;
333         if (t < 0.01) {
334                 t = 0.01;
335                 uflow = 1;
336         } else
337                 uflow = 0;
338
339         printf("%8ju ", (uintmax_t)cip->ci_calls);
340         if (cflag) {
341                 if (cip != totalcip)
342                         printf(" %4.2f%%  ",
343                             cip->ci_calls / (double) totalcip->ci_calls);
344                 else
345                         printf(" %4s   ", "");
346         }
347
348         if (jflag)
349                 printf("%11.2fre ", cip->ci_etime / (double) (AHZ * c));
350         else
351                 printf("%11.2fre ", cip->ci_etime / (60.0 * AHZ));
352         if (cflag) {
353                 if (cip != totalcip)
354                         printf(" %4.2f%%  ",
355                             cip->ci_etime / (double) totalcip->ci_etime);
356                 else
357                         printf(" %4s   ", "");
358         }
359
360         if (!lflag) {
361                 if (jflag)
362                         printf("%11.2fcp ", t / (double) cip->ci_calls);
363                 else
364                         printf("%11.2fcp ", t / 60.0);
365                 if (cflag) {
366                         if (cip != totalcip)
367                                 printf(" %4.2f%%  ",
368                                     (cip->ci_utime + cip->ci_stime) / (double)
369                                     (totalcip->ci_utime + totalcip->ci_stime));
370                         else
371                                 printf(" %4s   ", "");
372                 }
373         } else {
374                 if (jflag)
375                         printf("%11.2fu ", cip->ci_utime / (double) (AHZ * c));
376                 else
377                         printf("%11.2fu ", cip->ci_utime / (60.0 * AHZ));
378                 if (cflag) {
379                         if (cip != totalcip)
380                                 printf(" %4.2f%%  ", cip->ci_utime / (double) totalcip->ci_utime);
381                         else
382                                 printf(" %4s   ", "");
383                 }
384                 if (jflag)
385                         printf("%11.2fs ", cip->ci_stime / (double) (AHZ * c));
386                 else
387                         printf("%11.2fs ", cip->ci_stime / (60.0 * AHZ));
388                 if (cflag) {
389                         if (cip != totalcip)
390                                 printf(" %4.2f%%  ", cip->ci_stime / (double) totalcip->ci_stime);
391                         else
392                                 printf(" %4s   ", "");
393                 }
394         }
395
396         if (tflag) {
397                 if (!uflow)
398                         printf("%8.2fre/cp ", cip->ci_etime / (double) (cip->ci_utime + cip->ci_stime));
399                 else
400                         printf("*ignore*      ");
401         }
402
403         if (Dflag)
404                 printf("%10jutio ", (uintmax_t)cip->ci_io);
405         else
406                 printf("%8.0favio ", cip->ci_io / c);
407
408         if (Kflag)
409                 printf("%10juk*sec ", (uintmax_t)cip->ci_mem);
410         else
411                 printf("%8.0fk ", cip->ci_mem / t);
412
413         printf("  %s\n", cip->ci_comm);
414 }