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