1 /*
2 * ascpu is the CPU statistics monitor utility for X Windows
3 * Copyright (c) 1998-2005 Albert Dorofeev <albert@tigr.net>
4 * For the updates see http://www.tigr.net/
5 *
6 * This software is distributed under GPL. For details see LICENSE file.
7 */
8
9 #include <stdio.h>
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <unistd.h>
13 #include <ctype.h>
14 #include <stdlib.h>
15 #include <math.h>
16 #include <time.h>
17 #ifdef __FreeBSD__
18 #include <nlist.h>
19 #include <fcntl.h>
20 #include <kvm.h>
21 #include <sys/types.h>
22 #include <err.h>
23 #include <string.h>
24 #include <sys/resource.h>
25 #include <sys/sysctl.h>
26 #include <sys/wait.h>
27 #endif
28
29 #ifdef __hpux__
30 #include <sys/pstat.h>
31 #include <sys/dk.h>
32 #endif
33
34 #ifdef _AIX32 /* AIX > 3.1 */
35 #include <nlist.h>
36 #include <sys/param.h>
37 #include <sys/sysinfo.h>
38 #endif /* _AIX32 */
39
40 #include <X11/Xlib.h>
41 #include <X11/xpm.h>
42 #include <X11/Xatom.h>
43
44 #include "x_color.h"
45 #include "background.xpm"
46 #include "state.h"
47
48 #define FOR_CLICK 1
49
50 #ifdef FOR_CLICK
51 extern char Command[255];
52 #endif
53
54 struct ascpu_state state;
55
56 /* nice idea from ascd */
57 typedef struct _XpmIcon {
58 Pixmap pixmap;
59 Pixmap mask;
60 XpmAttributes attributes;
61 } XpmIcon;
62
63 XpmIcon backgroundXpm;
64
65 /* X windows related global variables */
66 Display * mainDisplay = 0; /* The display we are working on */
67 Window Root; /* The root window of X11 */
68 Window mainWindow; /* Application window */
69 Window iconWindow; /* Icon window */
70 XGCValues mainGCV; /* graphics context values */
71 GC mainGC; /* Graphics context */
72 Atom wm_delete_window;
73 Atom wm_protocols;
74
75 Pixel back_pix, fore_pix;
76
77 /* background pixmap colors */
78 char bgpixmap_color[3][50];
79
80 /* pixels we need */
81 Pixel pix[4];
82
83 /* last time we updated */
84 time_t last_time = 0;
85
86 /* requests for update */
87 int update_request = 0;
88
89 #ifdef __FreeBSD__
90 static int cp_time_mib[2];
91 static int cp_times_mib[2];
92 static kvm_t *kd;
93 static struct nlist nlst[] = {
94 {"_cp_time"}, {0}
95 };
96 #endif
97
98 #ifdef __linux__
99 char proc_extended = 0;
100 #endif
101
102 #ifdef _AIX32 /* AIX > 3.1 */
103 /* Kernel memory file */
104 #define KMEM_FILE "/dev/kmem"
105 /* Descriptor of kernel memory file */
106 static int kmem;
107 /* Offset of sysinfo structure in kernel memory file */
108 static long sysinfo_offset;
109 /* Structure to access kernel symbol table */
110 static struct nlist namelist[] = {
111 { {"sysinfo"}, 0, 0, {0}, 0, 0 },
112 { {0}, 0, 0, {0}, 0, 0 }
113 };
114 #endif /* _AIX32 */
115
116 /*
117 * The information over the CPU load is always kept in 4 variables
118 * The order is:
119 * user
120 * nice
121 * system
122 * interrupt(FreeBSD specific)
123 * idle
124 */
125 struct cpu_load_struct {
126 unsigned long int load[5];
127 };
128
129 /*
130 * The structure for the line sizes - the same as the
131 * CPU structure only in pixels - ready to draw
132 */
133 struct line_size_struct {
134 unsigned short int len[4];
135 };
136 /* last time and just now read values */
137 struct cpu_load_struct last = {{0, 0, 0, 0}};
138 struct cpu_load_struct fresh = {{0, 0, 0, 0, 0}};
139
140 /* The running history window values: load, calculated lines, counter */
141 struct cpu_load_struct running_last = {{0, 0, 0, 0}};
142 struct line_size_struct running_lines = {{0, 0, 0, 0}};
143 unsigned long int running_counter = 0;
144
145 /* the average load gadget values */
146 struct cpu_load_struct average_diff = {{0, 0, 0, 0}};
147 struct line_size_struct average_lines = {{0, 0, 0, 0}};
148 struct {
149 float load[4];
150 } average = {{0, 0, 0, 0}};
151 struct cpu_load_struct *average_history = 0;
152 unsigned long int average_counter = 0;
153 unsigned long int average_ptr = 0;
154
155
156 /*
157 * This function clears up all X related
158 * stuff and exits. It is called in case
159 * of emergencies .
160 */
161
ascpu_cleanup()162 void ascpu_cleanup()
163 {
164 if ( mainDisplay ) {
165 XCloseDisplay(mainDisplay);
166 }
167 if ( average_history )
168 free( average_history );
169 exit(0);
170 }
171
172
update_running()173 void update_running()
174 {
175 unsigned short total;
176 float factor;
177 struct cpu_load_struct running_diff;
178 int i, last_offset, new_offset;
179 long diff_buf;
180
181 ++running_counter;
182 if ( running_counter < state.hist_samples )
183 return;
184
185 total = 0;
186 for (i=0; i<4; ++i) {
187 diff_buf = fresh.load[i] - running_last.load[i];
188 running_diff.load[i] = (diff_buf < 0) ? 0:diff_buf;
189 total += running_diff.load[i];
190 }
191 if (total) {
192 factor = ((float)(backgroundXpm.attributes.height - 2)) / total;
193 for ( i=0; i<4; ++i )
194 running_lines.len[i] =
195 rint((float)running_diff.load[i] * factor);
196 /* Make sure we have the exact number of pixels to
197 * draw - errors of rounding may make up for an extra
198 * or a missing pixel */
199 while ( ( running_lines.len[0] + running_lines.len[1] +
200 running_lines.len[2] + running_lines.len[3] ) >
201 (backgroundXpm.attributes.height - 2) ) {
202 if ( running_lines.len[0] )
203 --running_lines.len[0];
204 else if ( running_lines.len[1] )
205 --running_lines.len[1];
206 else if ( running_lines.len[2] )
207 --running_lines.len[2];
208 else
209 --running_lines.len[3];
210 }
211 while ( ( running_lines.len[0] + running_lines.len[1] +
212 running_lines.len[2] + running_lines.len[3] ) <
213 (backgroundXpm.attributes.height - 2) ) {
214 ++running_lines.len[3];
215 }
216 } else {
217 /* Just in case something goes wrong *shrug* */
218 running_lines.len[0] = running_lines.len[1] =
219 running_lines.len[2] = 0;
220 running_lines.len[3] = backgroundXpm.attributes.height - 2;
221 }
222
223 #ifdef DEBUG
224 printf("Running : %d %d %d %d =%d\n",
225 running_lines.len[0], running_lines.len[1],
226 running_lines.len[2], running_lines.len[3],
227 running_lines.len[0] + running_lines.len[1] +
228 running_lines.len[2] + running_lines.len[3] );
229 #endif
230 running_counter = 0;
231 memcpy( &running_last, &fresh, sizeof(running_last) );
232
233 /*
234 * And now draw the lines we got into the bitmap
235 * of the background. We shift what we had there
236 * before to the left and draw an extra line
237 * that we just calculated on the right side.
238 */
239 XCopyArea(
240 mainDisplay,
241 backgroundXpm.pixmap,
242 backgroundXpm.pixmap,
243 mainGC,
244 7,
245 1,
246 (backgroundXpm.attributes.width - 8),
247 (backgroundXpm.attributes.height - 2),
248 6,
249 1
250 );
251 last_offset = new_offset = 1;
252 for ( i=0; i<4; ++i ) {
253 mainGCV.foreground = pix[i];
254 XChangeGC(
255 mainDisplay,
256 mainGC,
257 GCForeground,
258 &mainGCV
259 );
260 new_offset += running_lines.len[3-i];
261 XDrawLine(
262 mainDisplay,
263 backgroundXpm.pixmap,
264 mainGC,
265 (backgroundXpm.attributes.width - 2),
266 last_offset,
267 (backgroundXpm.attributes.width - 2),
268 new_offset
269 );
270 last_offset = new_offset;
271 }
272 ++update_request;
273 }
274
275 /*
276 * Calculate the average load values when the average
277 * time is 1 - this is the case when we just have the
278 * momentary values.
279 */
momentary_average()280 void momentary_average()
281 {
282 unsigned short total;
283 float factor;
284 int i;
285
286 total = average_diff.load[0] + average_diff.load[1] +
287 average_diff.load[2] + average_diff.load[3];
288 if (total) {
289 factor = ((float)(backgroundXpm.attributes.height - 2)) / total;
290 for ( i=0; i<4; ++i )
291 average_lines.len[i] =
292 rint((float)average_diff.load[i] * factor);
293 /* Make sure we have the exact number of pixels to
294 * draw - errors of rounding may make up for an extra
295 * or a missing pixel */
296 while ( ( average_lines.len[0] + average_lines.len[1] +
297 average_lines.len[2] + average_lines.len[3] ) >
298 (backgroundXpm.attributes.height - 2) ) {
299 if ( average_lines.len[0] )
300 --average_lines.len[0];
301 else if ( average_lines.len[1] )
302 --average_lines.len[1];
303 else if ( average_lines.len[2] )
304 --average_lines.len[2];
305 else
306 --average_lines.len[3];
307 }
308 while ( ( average_lines.len[0] + average_lines.len[1] +
309 average_lines.len[2] + average_lines.len[3] ) <
310 (backgroundXpm.attributes.height - 2) ) {
311 ++average_lines.len[3];
312 }
313 } else {
314 /* Just in case something goes wrong *shrug* */
315 average_lines.len[0] = average_lines.len[1] =
316 average_lines.len[2] = 0;
317 average_lines.len[3] = backgroundXpm.attributes.height - 2;
318 }
319
320 #ifdef DEBUG
321 printf("Average : %d %d %d %d =%d\n",
322 average_lines.len[0], average_lines.len[1],
323 average_lines.len[2], average_lines.len[3],
324 average_lines.len[0] + average_lines.len[1] +
325 average_lines.len[2] + average_lines.len[3] );
326 #endif
327 }
328
329 /*
330 * Calculate and update the value of the average load
331 * for the past hist_samples intervals. The oldest value
332 * is thrown out of the average and the new value is added.
333 */
real_average()334 void real_average()
335 {
336 int i;
337 unsigned short total;
338 float factor;
339
340 if ( average_counter >= state.avg_samples ) {
341 for ( i=0; i<4; ++i ) {
342 average.load[i] =
343 (average.load[i] * average_counter -
344 average_history[average_ptr].load[i]) /
345 ( average_counter - 1 );
346 }
347 --average_counter;
348 }
349 for ( i=0; i<4; ++i ) {
350 average_history[average_ptr].load[i] =
351 average_diff.load[i];
352 average.load[i] = (average.load[i] * average_counter +
353 average_history[average_ptr].load[i]) /
354 ( average_counter + 1 );
355 }
356 ++average_counter;
357 ++average_ptr;
358 if ( average_ptr >= state.avg_samples ) average_ptr = 0;
359
360 /*
361 * And now the lines for the indicator
362 */
363 total = average.load[0] + average.load[1] +
364 average.load[2] + average.load[3];
365 if (total) {
366 factor = ((float)(backgroundXpm.attributes.height - 2)) / total;
367 for ( i=0; i<4; ++i )
368 average_lines.len[i] =
369 rint((float)average.load[i] * factor);
370 /* Make sure we have the exact number of pixels to
371 * draw - errors of rounding may make up for an extra
372 * or a missing pixel */
373 while ( ( average_lines.len[0] + average_lines.len[1] +
374 average_lines.len[2] + average_lines.len[3] ) >
375 (backgroundXpm.attributes.height - 2) ) {
376 if ( average_lines.len[0] )
377 --average_lines.len[0];
378 else if ( average_lines.len[1] )
379 --average_lines.len[1];
380 else if ( average_lines.len[2] )
381 --average_lines.len[2];
382 else
383 --average_lines.len[3];
384 }
385 while ( ( average_lines.len[0] + average_lines.len[1] +
386 average_lines.len[2] + average_lines.len[3] ) <
387 (backgroundXpm.attributes.height - 2) ) {
388 ++average_lines.len[3];
389 }
390 } else {
391 /* Just in case something goes wrong *shrug* */
392 average_lines.len[0] = average_lines.len[1] =
393 average_lines.len[2] = 0;
394 average_lines.len[3] = backgroundXpm.attributes.height - 2;
395 }
396
397 #ifdef DEBUG
398 printf("Average : %d %d %d %d =%d\n",
399 average_lines.len[0], average_lines.len[1],
400 average_lines.len[2], average_lines.len[3],
401 average_lines.len[0] + average_lines.len[1] +
402 average_lines.len[2] + average_lines.len[3] );
403 #endif
404 }
405
406 /*
407 * Trigger calculation of the average value and then
408 * draw the calculated lines.
409 */
update_average()410 void update_average()
411 {
412 int offset;
413 int i;
414 long diff_buf;
415 for (i=0; i<4; ++i) {
416 diff_buf = fresh.load[i] - last.load[i];
417 average_diff.load[i] = (diff_buf < 0) ? 0:diff_buf;
418 }
419 if ( state.avg_samples > 1 ) {
420 real_average();
421 } else {
422 momentary_average();
423 }
424 /*
425 * And now draw the line that was calculated
426 */
427 offset = 1;
428 for ( i=0; i<4; ++i ) {
429 mainGCV.foreground = pix[i];
430 XChangeGC(
431 mainDisplay,
432 mainGC,
433 GCForeground,
434 &mainGCV
435 );
436 XFillRectangle(
437 mainDisplay,
438 backgroundXpm.pixmap,
439 mainGC,
440 1,
441 offset,
442 3,
443 average_lines.len[3-i]
444 );
445 offset += average_lines.len[3-i];
446 }
447 ++update_request;
448 }
449
draw_window(Window win)450 void draw_window(Window win)
451 {
452 XCopyArea(
453 mainDisplay,
454 backgroundXpm.pixmap,
455 win,
456 mainGC,
457 0,
458 0,
459 backgroundXpm.attributes.width,
460 backgroundXpm.attributes.height,
461 0,
462 0
463 );
464 }
465
466
467 static char buffer[MAX_CPU*40]; /* about 35 chars per line of CPU info */
468 static char scan_format[MAX_CPU*30]; /* 26 is correct I think but not sure */
469 /*
470 * Prepares the format for reading the /proc/stat
471 */
prepare_format()472 void prepare_format()
473 {
474 int i;
475 scan_format[0] = '\0';
476 #ifdef __linux__
477 int fd, len, major, minor, micro;
478 if ((fd = open("/proc/sys/kernel/osrelease", O_RDONLY)) == -1) {
479 printf("ascpu : cannot open /proc/sys/kernel/osrelease\n");
480 exit(1);
481 }
482 if ((len = read(fd, buffer, sizeof(buffer)-1)) < 0) {
483 printf("ascpu : cannot read /proc/sys/kernel/osrelease\n");
484 exit(1);
485 }
486 buffer[len] = '\0';
487 close(fd);
488 if (!sscanf(buffer, "%d.%d.%d", &major, &minor, µ)) {
489 printf("ascpu : cannot get Linux Major/Minor version\n");
490 exit(1);
491 }
492 if (major > 2 || (major == 2 && minor > 6) || (major == 2 && minor == 6 && micro >= 10)) {
493 #ifdef DEBUG
494 printf("Linux Kernel >= 2.6.10 detected\n");
495 #endif
496 proc_extended = 2;
497 } else if (major == 2 && minor >= 5) {
498 #ifdef DEBUG
499 printf("Linux Kernel >= 2.5 and < 2.6.10 detected\n");
500 #endif
501 proc_extended = 1;
502 } else {
503 proc_extended = 0;
504 #ifdef DEBUG
505 printf("Linux Kernel < 2.5 detected\n");
506 #endif
507 }
508 if ( state.cpu_number < 0 ) {
509 sprintf(scan_format, proc_extended?((proc_extended-1)?"cpu %%ld %%ld %%ld %%ld %%*ld %%*ld %%*ld %%*ld\n":"cpu %%ld %%ld %%ld %%ld %%*ld %%*ld %%*ld\n"):"cpu %%ld %%ld %%ld %%ld\n");
510 } else {
511 sprintf(scan_format, proc_extended?((proc_extended-1)?"cpu %%*ld %%*ld %%*ld %%*ld %%*ld %%*ld %%*ld %%*ld\n":"cpu %%*ld %%*ld %%*ld %%*ld %%*ld %%*ld %%*ld\n"):"cpu %%*ld %%*ld %%*ld %%*ld\n");
512 for (i=0; i<state.cpu_number; ++i) {
513 sprintf(&scan_format[strlen(scan_format)],
514 proc_extended?((proc_extended-1)?"cpu%d %%*ld %%*ld %%*ld %%*ld %%*ld %%*ld %%*ld %%*ld\n":"cpu%d %%*ld %%*ld %%*ld %%*ld %%*ld %%*ld %%*ld\n"):"cpu%d %%*ld %%*ld %%*ld %%*ld\n",
515 i);
516 }
517 sprintf(&scan_format[strlen(scan_format)],
518 proc_extended?((proc_extended-1)?"cpu%d %%ld %%ld %%ld %%ld %%*ld %%*ld %%*ld %%*ld\n":"cpu%d %%ld %%ld %%ld %%ld %%*ld %%*ld %%*ld\n"):"cpu%d %%ld %%ld %%ld %%ld\n",
519 state.cpu_number);
520 }
521 #else
522 if ( state.cpu_number < 0 ) {
523 sprintf(scan_format, "cpu %%ld %%ld %%ld %%ld\n");
524 } else {
525 sprintf(scan_format, "cpu %%*ld %%*ld %%*ld %%*ld\n");
526 for (i=0; i<state.cpu_number; ++i) {
527 sprintf(&scan_format[strlen(scan_format)],
528 "cpu%d %%*ld %%*ld %%*ld %%*ld\n",
529 i);
530 }
531 sprintf(&scan_format[strlen(scan_format)],
532 "cpu%d %%ld %%ld %%ld %%ld\n",
533 state.cpu_number);
534 }
535 #endif
536 #ifdef DEBUG
537 printf("The format is [%s]\n", scan_format);
538 #endif
539 }
540
541 /*
542 * reads the /proc/stat
543 */
read_stat()544 void read_stat()
545 {
546 int fd, len;
547
548 #ifdef __hpux__
549 struct pst_dynamic store_pst_dynamic;
550 long int *p;
551 int i;
552 #endif
553
554 #ifdef _AIX32 /* AIX > 3.1 */
555 time_t *p;
556 struct sysinfo sysinfo;
557 #endif
558
559 /*
560 * Save the old values
561 */
562 memcpy(&last, &fresh, sizeof(last));
563
564 #ifdef __FreeBSD__
565 if (state.cpu_number >= 0 && cp_times_mib[0] != 0) {
566 long cp_times[MAX_CPU][CPUSTATES];
567 size_t cp_times_len = sizeof(cp_times);
568 int error = sysctl(cp_times_mib, 2, cp_times, &cp_times_len, NULL, 0);
569 if (error) {
570 printf("ascpu: cannot sysctl cp_times\n");
571 exit(1);
572 }
573
574 long *cp_time = cp_times[state.cpu_number];
575 fresh.load[0] = cp_time[CP_USER];
576 fresh.load[1] = cp_time[CP_NICE];
577 fresh.load[2] = cp_time[CP_SYS] + cp_time[CP_INTR];
578 fresh.load[3] = cp_time[CP_IDLE];
579 } else if (state.cpu_number == -1 && cp_time_mib[0] != 0) {
580 long cp_time[CPUSTATES];
581 size_t cp_time_len = sizeof(cp_time);
582 int error = sysctl(cp_time_mib, 2, cp_time, &cp_time_len, NULL, 0);
583 if (error) {
584 printf("ascpu: cannot sysctl cp_time\n");
585 exit(1);
586 }
587
588 fresh.load[0] = cp_time[CP_USER];
589 fresh.load[1] = cp_time[CP_NICE];
590 fresh.load[2] = cp_time[CP_SYS] + cp_time[CP_INTR];
591 fresh.load[3] = cp_time[CP_IDLE];
592 } else {
593 if (nlst[0].n_type == 0) {
594 printf("ascpu : cannot get nlist\n");
595 exit(1);
596 }
597 if (kvm_read(kd, nlst[0].n_value, &fresh, sizeof(fresh)) != sizeof(fresh)) {
598 printf("ascpu : cannot read kvm\n");
599 exit(1);
600 }
601 /* compatible with Linux(overwrite 'interrupt' with 'idle' field) */
602 fresh.load[3] = fresh.load[4];
603 }
604 #endif
605
606 #ifdef __hpux__
607
608 /*
609 params: structure buf pointer, structure size, num of structs
610 some index. HP say always 1, 0 for the last two. the order in
611 fresh[] matches HP's psd_cpu_time[] and psd_mp_cpu_time[N][],
612 so I can use the indices in dk.h for everything
613 */
614
615 if( pstat_getdynamic( &store_pst_dynamic, \
616 sizeof store_pst_dynamic, 1, 0 )) {
617
618 if( state.cpu_number < 0 ) {
619 /* give the average over all processors */
620 p = store_pst_dynamic.psd_cpu_time;
621 }
622 else {
623 /* user-specified processor only */
624 p = store_pst_dynamic.psd_mp_cpu_time[state.cpu_number];
625 }
626
627 fresh.load[CP_USER] = p[CP_USER];
628 fresh.load[CP_NICE] = p[CP_NICE];
629 fresh.load[CP_SYS] = p[CP_SYS] + p[CP_BLOCK] +\
630 p[CP_INTR] + p[CP_SSYS] + p[CP_SWAIT];
631 fresh.load[CP_IDLE] = p[CP_IDLE] + p[CP_WAIT];
632
633 }
634 else {
635 printf("ascpu: Error while calling pstat_getdynamic(2)\n");
636 ascpu_cleanup();
637 }
638
639 #endif
640
641 #ifdef _AIX32 /* AIX > 3.1 */
642 if (lseek (kmem, sysinfo_offset, SEEK_SET) != sysinfo_offset) {
643 printf("ascpu : cannot lseek %s\n", KMEM_FILE);
644 ascpu_cleanup();
645 }
646 if (read (kmem, (char *)&sysinfo, sizeof(struct sysinfo))
647 != sizeof(struct sysinfo)) {
648 printf("ascpu : cannot read %s\n", KMEM_FILE);
649 ascpu_cleanup();
650 }
651 p = sysinfo.cpu;
652 fresh.load[0] = p[CPU_USER];
653 fresh.load[1] = p[CPU_WAIT];
654 fresh.load[2] = p[CPU_KERNEL];
655 fresh.load[3] = fresh.load[4] = p[CPU_IDLE];
656 #endif /* _AIX32 */
657
658 #ifdef __linux__
659
660 if ((fd = open(state.proc_stat_filename, O_RDONLY)) == -1) {
661 printf("ascpu : cannot open %s\n", state.proc_stat_filename);
662 exit(1);
663 }
664 len = read(fd, buffer, sizeof(buffer)-1);
665 close(fd);
666 if (len == 0) return; /* EOF? */
667 if (len < 0) {
668 printf("ascpu : cannot read %s\n", state.proc_stat_filename);
669 exit(1);
670 }
671 buffer[len] = '\0';
672
673 len = sscanf(buffer, scan_format,
674 &fresh.load[0],
675 &fresh.load[1],
676 &fresh.load[2],
677 &fresh.load[3]);
678 if ( len <= 0 ) {
679 printf("ascpu : invalid character while reading %s\n",
680 state.proc_stat_filename);
681 }
682 #endif
683 /*
684 * Check if need "nice" CPU time at all
685 */
686 if ( state.no_nice ) {
687 fresh.load[3] += fresh.load[1];
688 fresh.load[1] = 0;
689 }
690 #ifdef DEBUG
691 printf("diff: %ld %ld %ld %ld %ld\n",
692 fresh.load[0] - last.load[0],
693 fresh.load[1] - last.load[1],
694 fresh.load[2] - last.load[2],
695 fresh.load[3] - last.load[3],
696 fresh.load[4] - last.load[4] );
697 #endif
698 }
699
700
701 #ifdef FOR_CLICK
702 /*
703 * This function executes an external command while
704 * checking whether we should drop the privileges.
705 *
706 * Since we might need privileges later we fork and
707 * then drop privileges in one of the instances which
708 * will then execute the command and die.
709 *
710 * This fixes the security hole for FreeBSD and AIX
711 * where this program needs privileges to access
712 * the system information.
713 */
ExecuteExternal()714 void ExecuteExternal()
715 {
716 uid_t ruid, euid;
717 int pid;
718 #ifdef DEBUG
719 printf("ascpu: system(%s)\n",Command);
720 #endif
721
722 if (setgid(getgid()) != 0)
723 err(1, "Can't drop setgid privileges");
724 if (setuid(getuid()) != 0)
725 err(1, "Can't drop setuid privileges");
726
727 if( ! Command ) {
728 return;
729 }
730 ruid = getuid();
731 euid = geteuid();
732 if ( ruid == euid ) {
733 system( Command );
734 return;
735 }
736 pid = fork();
737 if ( pid == -1 ) {
738 printf("ascpu : fork() failed (%s), command not executed",
739 strerror(errno));
740 return;
741 }
742 if ( pid != 0 ) {
743 /* parent process simply waits for the child and continues */
744 if ( waitpid(pid, 0, 0) == -1 ) {
745 printf("ascpu : waitpid() for child failed (%s)",
746 strerror(errno));
747 }
748 return;
749 }
750 /*
751 * child process drops the privileges
752 * executes the command and dies
753 */
754 if ( setuid(ruid) ) {
755 printf("ascpu : setuid failed (%s), command not executed",
756 strerror(errno));
757 exit(127);
758 }
759 system( Command );
760 exit(0);
761 }
762 #endif
763
764 /*
765 * This checks for X11 events. We distinguish the following:
766 #ifdef FOR_CLICK
767 * - request to execute some command
768 #endif
769 * - request to repaint the window
770 * - request to quit (Close button)
771 */
CheckX11Events()772 void CheckX11Events()
773 {
774 XEvent Event;
775 while (XPending(mainDisplay)) {
776 XNextEvent(mainDisplay, &Event);
777 switch(Event.type)
778 {
779 #ifdef FOR_CLICK
780 case ButtonPress:
781 ExecuteExternal();
782 break;
783 #endif
784 case Expose:
785 if(Event.xexpose.count == 0) {
786 ++update_request;
787 }
788 break;
789 case ClientMessage:
790 if ((Event.xclient.message_type == wm_protocols)
791 && (Event.xclient.data.l[0] == wm_delete_window))
792 {
793 #ifdef DEBUG
794 printf("caught wm_delete_window, closing\n");
795 #endif
796 ascpu_cleanup();
797 }
798 break;
799 }
800 }
801 }
802
ascpu_redraw()803 void ascpu_redraw()
804 {
805 draw_window(mainWindow);
806 draw_window(iconWindow);
807 update_request = 0;
808 }
809
ascpu_update()810 void ascpu_update()
811 {
812 time_t cur_time;
813 cur_time = time(0);
814 if ( abs(cur_time - last_time) >= state.update_interval ) {
815 last_time = cur_time;
816 read_stat();
817 update_running();
818 update_average();
819 }
820 CheckX11Events();
821 if ( update_request ) {
822 ascpu_redraw();
823 }
824 }
825
ascpu_initialize(int argc,char ** argv,char * window_name,char * display_name,char * mainGeometry,int withdrawn,int iconic,int pushed_in,int sys_color_defined,char * sys_color,int nice_color_defined,char * nice_color,int user_color_defined,char * user_color,int idle_color_defined,char * idle_color)826 void ascpu_initialize(
827 int argc, char** argv,
828 char * window_name,
829 char * display_name,
830 char * mainGeometry,
831 int withdrawn,
832 int iconic,
833 int pushed_in,
834 int sys_color_defined,
835 char * sys_color,
836 int nice_color_defined,
837 char * nice_color,
838 int user_color_defined,
839 char * user_color,
840 int idle_color_defined,
841 char * idle_color)
842 {
843 int screen;
844 Status status;
845 XWindowAttributes winAttr;
846 XSizeHints SizeHints;
847 XTextProperty title;
848 XClassHint classHint;
849 int gravity;
850 XWMHints WmHints;
851 XEvent Event;
852 int color_depth;
853 int tmp;
854 int result;
855 int x_negative = 0;
856 int y_negative = 0;
857
858 mainDisplay = XOpenDisplay(display_name);
859 if ( ! mainDisplay ) {
860 printf("ascpu : grrrr... can't open display %s. Sorry ...\n",
861 XDisplayName(display_name));
862 exit(1);
863 }
864 screen = DefaultScreen(mainDisplay);
865 Root = RootWindow(mainDisplay, screen);
866 back_pix = GetColor(state.bgcolor, mainDisplay, Root);
867 fore_pix = GetColor(state.fgcolor, mainDisplay, Root);
868 color_depth = DefaultDepth(mainDisplay, screen);
869 #ifdef DEBUG
870 printf("ascpu : detected color depth %d bpp, using %d bpp\n",
871 color_depth, color_depth);
872 #endif
873 /* adjust the background pixmap */
874 if (pushed_in) {
875 sprintf(bgpixmap_color[0],
876 ". c %s",
877 DarkenCharColor(state.bgcolor, 1.6, mainDisplay, Root));
878 sprintf(bgpixmap_color[1],
879 "c c %s",
880 state.bgcolor);
881 sprintf(bgpixmap_color[2],
882 "q c %s",
883 LightenCharColor(state.bgcolor, 2.8, mainDisplay, Root));
884 } else {
885 sprintf(bgpixmap_color[2],
886 "q c %s",
887 DarkenCharColor(state.bgcolor, 1.2, mainDisplay, Root));
888 sprintf(bgpixmap_color[1],
889 "c c %s",
890 state.bgcolor);
891 sprintf(bgpixmap_color[0],
892 ". c %s",
893 LightenCharColor(state.bgcolor, 2.5, mainDisplay, Root));
894 }
895 for (tmp = 0; tmp < 3; ++tmp)
896 background[tmp+1] = bgpixmap_color[tmp];
897
898 backgroundXpm.attributes.valuemask |=
899 (XpmReturnPixels | XpmReturnExtensions);
900 status = XpmCreatePixmapFromData(
901 mainDisplay, /* display */
902 Root, /* window */
903 background, /* xpm */
904 &backgroundXpm.pixmap, /* resulting pixmap */
905 &backgroundXpm.mask,
906 &backgroundXpm.attributes
907 );
908 if(status != XpmSuccess) {
909 printf("ascpu : (%d) not enough free color cells for background.\n", status);
910 ascpu_cleanup();
911 }
912 #ifdef DEBUG
913 printf("bg pixmap %d x %d\n",
914 backgroundXpm.attributes.width,
915 backgroundXpm.attributes.height);
916 #endif
917 if (strlen(mainGeometry)) {
918 /* Check the user-specified size */
919 result = XParseGeometry(
920 mainGeometry,
921 &SizeHints.x,
922 &SizeHints.y,
923 &SizeHints.width,
924 &SizeHints.height
925 );
926 if (result & XNegative)
927 x_negative = 1;
928 if (result & YNegative)
929 y_negative = 1;
930 }
931
932 SizeHints.flags= USSize|USPosition;
933 SizeHints.x = 0;
934 SizeHints.y = 0;
935 XWMGeometry(
936 mainDisplay,
937 screen,
938 mainGeometry,
939 NULL,
940 1,
941 & SizeHints,
942 &SizeHints.x,
943 &SizeHints.y,
944 &SizeHints.width,
945 &SizeHints.height,
946 &gravity
947 );
948 SizeHints.min_width =
949 SizeHints.max_width =
950 SizeHints.width = backgroundXpm.attributes.width;
951 SizeHints.min_height =
952 SizeHints.max_height =
953 SizeHints.height= backgroundXpm.attributes.height;
954 SizeHints.flags |= PMinSize|PMaxSize;
955
956 /* Correct the offsets if the X/Y are negative */
957 SizeHints.win_gravity = NorthWestGravity;
958 if (x_negative) {
959 SizeHints.x -= SizeHints.width;
960 SizeHints.win_gravity = NorthEastGravity;
961 }
962 if (y_negative) {
963 SizeHints.y -= SizeHints.height;
964 if (x_negative)
965 SizeHints.win_gravity = SouthEastGravity;
966 else
967 SizeHints.win_gravity = SouthWestGravity;
968 }
969 SizeHints.flags |= PWinGravity;
970
971 mainWindow = XCreateSimpleWindow(
972 mainDisplay, /* display */
973 Root, /* parent */
974 SizeHints.x, /* x */
975 SizeHints.y, /* y */
976 SizeHints.width, /* width */
977 SizeHints.height, /* height */
978 0, /* border_width */
979 fore_pix, /* border */
980 back_pix /* background */
981 );
982
983 iconWindow = XCreateSimpleWindow(
984 mainDisplay, /* display */
985 Root, /* parent */
986 SizeHints.x, /* x */
987 SizeHints.y, /* y */
988 SizeHints.width, /* width */
989 SizeHints.height, /* height */
990 0, /* border_width */
991 fore_pix, /* border */
992 back_pix /* background */
993 );
994
995 XSetWMNormalHints(mainDisplay, mainWindow, &SizeHints);
996 status = XClearWindow(mainDisplay, mainWindow);
997
998 status = XGetWindowAttributes(
999 mainDisplay, /* display */
1000 mainWindow, /* window */
1001 & winAttr /* window_attributes_return */
1002 );
1003 status = XSetWindowBackgroundPixmap(
1004 mainDisplay, /* display */
1005 mainWindow, /* window */
1006 backgroundXpm.pixmap /* background_pixmap */
1007 );
1008 status = XSetWindowBackgroundPixmap(
1009 mainDisplay, /* display */
1010 iconWindow, /* window */
1011 backgroundXpm.pixmap /* background_pixmap */
1012 );
1013
1014 status = XStringListToTextProperty(&window_name, 1, &title);
1015 XSetWMName(mainDisplay, mainWindow, &title);
1016 XSetWMName(mainDisplay, iconWindow, &title);
1017
1018 classHint.res_name = "ascpu" ;
1019 classHint.res_class = "ASCPU";
1020 XSetClassHint(mainDisplay, mainWindow, &classHint);
1021 XStoreName(mainDisplay, mainWindow, window_name);
1022 XSetIconName(mainDisplay, mainWindow, window_name);
1023
1024 status = XSelectInput(
1025 mainDisplay, /* display */
1026 mainWindow, /* window */
1027 ExposureMask /* event_mask */
1028 #ifdef FOR_CLICK
1029 | ButtonPressMask
1030 #endif
1031 );
1032
1033 status = XSelectInput(
1034 mainDisplay, /* display */
1035 iconWindow, /* window */
1036 ExposureMask /* event_mask */
1037 #ifdef FOR_CLICK
1038 | ButtonPressMask
1039 #endif
1040 );
1041
1042 /* Creating Graphics context */
1043 mainGCV.foreground = fore_pix;
1044 mainGCV.background = back_pix;
1045 mainGCV.graphics_exposures = False;
1046 mainGCV.line_style = LineSolid;
1047 mainGCV.fill_style = FillSolid;
1048 mainGCV.line_width = 1;
1049 mainGC = XCreateGC(
1050 mainDisplay,
1051 mainWindow,
1052 GCForeground|GCBackground|GCLineWidth|
1053 GCLineStyle|GCFillStyle,
1054 &mainGCV
1055 );
1056
1057 status = XSetCommand(mainDisplay, mainWindow, argv, argc);
1058
1059 /* Set up the event for quitting the window */
1060 wm_delete_window = XInternAtom(
1061 mainDisplay,
1062 "WM_DELETE_WINDOW", /* atom_name */
1063 False /* only_if_exists */
1064 );
1065 wm_protocols = XInternAtom(
1066 mainDisplay,
1067 "WM_PROTOCOLS", /* atom_name */
1068 False /* only_if_exists */
1069 );
1070 status = XSetWMProtocols(
1071 mainDisplay,
1072 mainWindow,
1073 &wm_delete_window,
1074 1
1075 );
1076 status = XSetWMProtocols(
1077 mainDisplay,
1078 iconWindow,
1079 &wm_delete_window,
1080 1
1081 );
1082
1083 WmHints.flags = StateHint | IconWindowHint;
1084 WmHints.initial_state =
1085 withdrawn ? WithdrawnState :
1086 iconic ? IconicState : NormalState;
1087 WmHints.icon_window = iconWindow;
1088 if ( withdrawn ) {
1089 WmHints.window_group = mainWindow;
1090 WmHints.flags |= WindowGroupHint;
1091 }
1092 if ( iconic || withdrawn ) {
1093 WmHints.icon_x = SizeHints.x;
1094 WmHints.icon_y = SizeHints.y;
1095 WmHints.flags |= IconPositionHint;
1096 }
1097 XSetWMHints(
1098 mainDisplay,
1099 mainWindow,
1100 &WmHints);
1101
1102 /* Finally show the window */
1103 status = XMapWindow(
1104 mainDisplay,
1105 mainWindow
1106 );
1107
1108 /* Get colors while waiting for Expose */
1109 if (idle_color_defined)
1110 pix[0] = GetColor(idle_color, mainDisplay, Root);
1111 else
1112 pix[0] = GetColor(state.bgcolor, mainDisplay, Root);
1113 if (sys_color_defined)
1114 pix[1] = GetColor(sys_color, mainDisplay, Root);
1115 else
1116 pix[1] = GetColor(state.fgcolor, mainDisplay, Root);
1117 if (nice_color_defined)
1118 pix[2] = GetColor(nice_color, mainDisplay, Root);
1119 else
1120 pix[2] = DarkenColor(state.fgcolor, 1.2, mainDisplay, Root);
1121 if (user_color_defined)
1122 pix[3] = GetColor(user_color, mainDisplay, Root);
1123 else
1124 pix[3] = DarkenColor(state.fgcolor, 1.4, mainDisplay, Root);
1125
1126 /*
1127 * We have to "reset" the values of load by reading it in advance
1128 */
1129 average_history = malloc(sizeof(struct cpu_load_struct) *
1130 state.avg_samples);
1131 if (! average_history ) {
1132 printf("ascpu: failed to malloc average list (%ld bytes)\n",
1133 sizeof(struct cpu_load_struct) * state.avg_samples);
1134 ascpu_cleanup();
1135 }
1136 #ifdef __FreeBSD__
1137 size_t len = 2;
1138 sysctlnametomib("kern.cp_times", cp_times_mib, &len);
1139 len = 2;
1140 sysctlnametomib("kern.cp_time", cp_time_mib, &len);
1141 if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open")) != NULL) {
1142 kvm_nlist(kd, nlst);
1143 }
1144 #endif
1145
1146 #ifdef _AIX32 /* AIX > 3.1 */
1147 nlist ("/unix", namelist);
1148 if (namelist[0].n_value == 0) {
1149 printf("ascpu : cannot get nlist\n");
1150 exit(1);
1151 }
1152 sysinfo_offset = namelist[0].n_value;
1153 kmem = open (KMEM_FILE, O_RDONLY);
1154 if (kmem < 0) {
1155 printf("ascpu : cannot open %s\n", KMEM_FILE);
1156 exit(1);
1157 }
1158 #endif /* _AIX32 */
1159
1160 /*running_counter = state.hist_samples;*/
1161 prepare_format();
1162 read_stat();
1163
1164 /* wait for the Expose event now */
1165 XNextEvent(mainDisplay, &Event);
1166 /* We 've got Expose -> draw the parts of the window. */
1167 ascpu_redraw();
1168 XFlush(mainDisplay);
1169 }
1170
1171