1 /* GKrellM
2 |  Copyright (C) 1999-2019 Bill Wilson
3 |
4 |  Author:  Bill Wilson    billw@gkrellm.net
5 |  Latest versions might be found at:  http://gkrellm.net
6 |
7 |  solaris.c code is Copyright (C) Daisuke Yabuki <dxy@acm.org>
8 |
9 |
10 |  GKrellM is free software: you can redistribute it and/or modify it
11 |  under the terms of the GNU General Public License as published by
12 |  the Free Software Foundation, either version 3 of the License, or
13 |  (at your option) any later version.
14 |
15 |  GKrellM is distributed in the hope that it will be useful, but WITHOUT
16 |  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17 |  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
18 |  License for more details.
19 |
20 |  You should have received a copy of the GNU General Public License
21 |  along with this program. If not, see http://www.gnu.org/licenses/
22 |
23 |
24 |  Additional permission under GNU GPL version 3 section 7
25 |
26 |  If you modify this program, or any covered work, by linking or
27 |  combining it with the OpenSSL project's OpenSSL library (or a
28 |  modified version of that library), containing parts covered by
29 |  the terms of the OpenSSL or SSLeay licenses, you are granted
30 |  additional permission to convey the resulting work.
31 |  Corresponding Source for a non-source form of such a combination
32 |  shall include the source code for the parts of OpenSSL used as well
33 |  as that of the covered work.
34 */
35 
36 #include <kstat.h>
37 #include <kvm.h>
38 #include <fcntl.h>
39 
40 kstat_ctl_t *kc;
41 kvm_t *kd = NULL;
42 
43 struct nlist nl[] = {
44     { "mpid" },
45     { 0 }
46 };
47 
48 extern void solaris_list_harddisks(void);
49 
50 
51 void
gkrellm_sys_main_init(void)52 gkrellm_sys_main_init(void)
53 	{
54 	/*
55 	 * Most of stats (cpu, proc, disk, memory, net and uptime) are
56 	 * unavailable if kstat_open() failed. So we just exit in that case.
57 	 */
58 	if ((kc = kstat_open()) == NULL) {
59 		perror("kstat_open");
60 		exit(1);
61 	}
62 
63 	/*
64 	 * kvm is utilized solely for getting a value for proc.n_forks
65 	 * from kernel variable called mpid. Even if kvm_open() fails,
66 	 * we proceed without it.
67 	 */
68 	if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL)) != NULL) {
69 		kvm_nlist(kd, nl);
70 	}
71 
72         /*
73          * a function called by the following requires sys gid privilege.
74          * the following function should be performed here just for that reason.
75          */
76         solaris_list_harddisks();
77 
78         if (setgid(getgid()) != 0) {
79 		perror("Failed to drop setgid privilege");
80 		exit(1);
81         }
82 	}
83 
84 void
gkrellm_sys_main_cleanup(void)85 gkrellm_sys_main_cleanup(void)
86 	{
87 	}
88 
89 
90 /* ===================================================================== */
91 /* CPU monitor interface */
92 
93 #include <kstat.h>
94 #include <sys/sysinfo.h>
95 
96 void
gkrellm_sys_cpu_read_data(void)97 gkrellm_sys_cpu_read_data(void)
98 {
99     extern kstat_ctl_t *kc;
100     kstat_t *ksp;
101     cpu_stat_t cs;
102 
103     if (kstat_chain_update(kc) == -1) {
104         perror("kstat_chain_update");
105         return;
106     }
107 
108     for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
109         if (strcmp(ksp->ks_module, "cpu_stat"))
110             continue;
111         if (kstat_read(kc, ksp, &cs) == -1) {
112             perror("kstat_read");
113             continue;
114         }
115 		gkrellm_cpu_assign_data(ksp->ks_instance,
116 				cs.cpu_sysinfo.cpu[CPU_USER],
117 				cs.cpu_sysinfo.cpu[CPU_WAIT],
118 				cs.cpu_sysinfo.cpu[CPU_KERNEL],
119 				cs.cpu_sysinfo.cpu[CPU_IDLE]);
120 
121     }
122 }
123 
124 /*
125  * note: on some SPARC systems, you can monitor temperature of CPUs
126  * with kstat (unix::temperature:[min/max/state/trend...])
127  */
128 
129 gboolean
gkrellm_sys_cpu_init()130 gkrellm_sys_cpu_init() {
131     extern kstat_ctl_t *kc;
132     kstat_t *ksp;
133 	gint	n_cpus = 0;
134 
135     if(kstat_chain_update(kc) == -1) {
136         perror("kstat_chain_update");
137         return FALSE;
138     }
139 
140     for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
141         if (strcmp(ksp->ks_module, "cpu_stat"))
142             continue;
143         if (kstat_read(kc, ksp, NULL) != -1) {
144 			gkrellm_cpu_add_instance(ksp->ks_instance);
145 			++n_cpus;
146 			}
147     }
148 	gkrellm_cpu_set_number_of_cpus(n_cpus);
149 	return TRUE;
150 }
151 
152 
153 /* ===================================================================== */
154 /* Proc monitor interface */
155 
156 #include <utmp.h>
157 #include <sys/types.h>
158 #include <dirent.h>
159 #include <sys/loadavg.h>
160 #include <kstat.h>
161 #include <fcntl.h>
162 #include <kvm.h>
163 #include <sys/sysinfo.h>
164 
165 void
gkrellm_sys_proc_read_data(void)166 gkrellm_sys_proc_read_data(void)
167 {
168 
169     double avenrun[LOADAVG_NSTATS], fload = 0;
170 	guint	n_processes = 0, n_forks = 0;
171     int last_pid;
172     extern kstat_ctl_t *kc;
173     kstat_t *ksp;
174     kstat_named_t *knp;
175 
176     extern kvm_t *kd;
177     extern struct nlist nl[];
178 
179     if (!GK.second_tick) /* Only one read per second */
180         return;
181 
182     if (getloadavg(avenrun, LOADAVG_NSTATS) > 0)
183         fload = avenrun[LOADAVG_1MIN];
184 
185     if (kstat_chain_update(kc) == -1) {
186         perror("kstat_chain_update");
187         return;
188     }
189     ksp = kstat_lookup(kc, "unix", -1, "system_misc");
190     if (ksp && kstat_read(kc, ksp, NULL) >= 0) {
191         knp = (kstat_named_t *)kstat_data_lookup(ksp, "nproc");
192         if (knp) {
193             n_processes = knp->value.ui32;
194         }
195     }
196 
197     if (kd) {
198         if (kvm_kread(kd, nl[0].n_value, (char *)&last_pid, sizeof(int)) != -1)
199             n_forks = last_pid;
200     } else {
201         n_forks = 0;
202     }
203     /* NOTE: code to get 'n_running' is not implemented (stays untouched).
204      * but it wouldn't do any harm since nobody seems to refer to it.
205      */
206 	gkrellm_proc_assign_data(n_processes, 0, n_forks, fload);
207 }
208 
209 
210 void
gkrellm_sys_proc_read_users(void)211 gkrellm_sys_proc_read_users(void)
212 	{
213     static struct utmp *utmpp;
214 	gint	n_users;
215 
216     n_users = 0;
217     setutent();
218     while ((utmpp = getutent()) != NULL) {
219         if (utmpp->ut_type == USER_PROCESS && utmpp->ut_name[0] != '\0')
220             n_users++;
221     }
222 	gkrellm_proc_assign_users(n_users);
223 }
224 
225 gboolean
gkrellm_sys_proc_init(void)226 gkrellm_sys_proc_init(void)
227     {
228 	return TRUE;
229 	}
230 
231 
232 
233 /* ===================================================================== */
234 /* Disk monitor interface */
235 
236 #include <sys/types.h>
237 #include <sys/sysinfo.h>
238 #include <unistd.h>
239 #include <kstat.h>
240 #include <libdevinfo.h>
241 #include <errno.h>
242 #include <sys/dkio.h>
243 
244 #define UNIT_SHIFT 3
245 
246 #define NAME2MAJOR 0
247 #define MAJOR2NAME 1
248 
249 typedef struct {
250     gint major;
251     gchar name[32];
252 } name_to_major_t;
253 
254 static gint check_media_type(kstat_t *);
255 static gint isharddisk(kstat_t *);
256 void solaris_list_harddisks(void);                   /* called from main.c */
257 
258 static gint lookup_name_to_major(name_to_major_t *, int);
259 static gint get_major(gchar *);
260 static gint get_devname(gint, gchar *);
261 static gint get_minor(gint);
262 static gint get_instance(gint);
263 
264 typedef struct {
265     char name[8];
266 } probed_harddisk;
267 
268 GList *hard_disk_list;
269 
270 
271 gchar *
gkrellm_sys_disk_name_from_device(gint device_number,gint unit_number,gint * order)272 gkrellm_sys_disk_name_from_device(gint device_number, gint unit_number,
273 			gint *order)
274 	{
275 	return NULL;	/* Disk data by device not implemented in Solaris */
276 	}
277 
278 gint
gkrellm_sys_disk_order_from_name(const gchar * name)279 gkrellm_sys_disk_order_from_name(const gchar *name)
280 	{
281 	return -1;  /* Append as added */
282 	}
283 
284 void
gkrellm_sys_disk_read_data(void)285 gkrellm_sys_disk_read_data(void)
286 {
287     probed_harddisk *drive;
288     GList *list;
289 
290     extern kstat_ctl_t *kc;
291     kstat_t *ksp;
292     kstat_io_t kios;
293 
294     if (kstat_chain_update(kc) == -1) {
295         perror("kstat_chain_update");
296         return;
297     }
298     for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
299 	for (list = hard_disk_list; list; list = list->next) {
300             drive = (probed_harddisk *)list->data;
301 
302             if(strcmp(drive->name, ksp->ks_name))
303                 continue;
304 
305             memset((void *)&kios, 0, sizeof(kstat_io_t));
306             kstat_read(kc, ksp, &kios);
307 
308 	    gkrellm_disk_assign_data_by_name(drive->name,
309 						kios.nread, kios.nwritten, FALSE);
310 	}
311     }
312 }
313 
314 gboolean
gkrellm_sys_disk_init(void)315 gkrellm_sys_disk_init(void)
316 	{
317 	return TRUE;
318 	}
319 
320 
321   /* Is this needed any longer? */
322 static gint
lookup_name_to_major(name_to_major_t * name_to_major,gint type)323 lookup_name_to_major(name_to_major_t *name_to_major, gint type) {
324     FILE *fp;
325     char line[80];
326     char *name, *maj;
327     gint name2major, major2name;
328     gint majnum;
329 
330     name2major = major2name = 0;
331     switch (type) {
332         case NAME2MAJOR:
333             name2major = 1;
334             break;
335         case MAJOR2NAME:
336             major2name = 1;
337             break;
338         default:
339             break;
340     }
341 
342     if ((fp = fopen("/etc/name_to_major", "r")) == NULL) {
343         perror("fopen");
344         return -1;
345     }
346 
347     while (fgets(line, sizeof(line), fp) != NULL) {
348         name = strtok(line, " \t");
349         if (name == NULL)
350             continue;
351 
352         maj = strtok(NULL, "\n");
353         if (maj == NULL)
354             continue;
355         majnum = (gint) atol(maj);
356 
357         if (name2major) {
358             if (strcmp(name_to_major->name, name) == 0) {
359                 name_to_major->major = majnum;
360                 fclose(fp);
361                 return 0;
362             }
363         } else if (major2name) {
364             if (name_to_major->major == majnum) {
365                 strcpy(name_to_major->name, name);
366                 fclose(fp);
367                 return 0;
368             }
369         }
370     }
371     fclose(fp);
372     return -1;
373 }
374 
375 #if 0
376   /* Is this needed any longer? */
377 static gint
378 get_major(gchar *devname) {
379     /* xlation from device name to major (e.g. sd -> 32) */
380     name_to_major_t name_to_major;
381 
382     strcpy(name_to_major.name, devname);
383     if (lookup_name_to_major(&name_to_major, NAME2MAJOR) < 0)
384         return -1;
385     return name_to_major.major;
386 }
387 
388   /* Is this needed any longer? */
389 static gint
390 get_devname(gint major, gchar *devname) {
391     /* xlation from major to device name (e.g. 118 -> ssd) */
392     name_to_major_t name_to_major;
393 
394     name_to_major.major = major;
395     if (lookup_name_to_major(&name_to_major, MAJOR2NAME) < 0)
396         return -1;
397     strcpy(devname, name_to_major.name);
398     return 0;
399 }
400 
401   /* Is this needed any longer? */
402 static gint
403 get_minor(gint instance) {
404     return instance << UNIT_SHIFT;
405 }
406 
407   /* Is this needed any longer? */
408 static gint
409 get_instance(gint minor) {
410     return minor >> UNIT_SHIFT;
411 }
412 #endif
413 
414 /*
415  * An sd instance could be a cdrom or a harddrive. You can't simply tell,
416  * from contents of kstat, which type of device an sd device is
417  * (well, maybe you could, but at least i can't.)
418  * It, however, doesn't make much sense to count cdrom read/write as
419  * "Disk" activity. So I'd like to exclude removable media's from
420  * monitoring target. In order to do this, I try to open a physical
421  * device of a corresponding sd instance. If it's succeeded, I assume
422  * it's a hard drive. If I get ENXIO or EBUSY, I'll guess it's CDROM.
423  * If you come up with a better (simpler or safer) way to tell it's
424  * a removable media or a hard drive, please drop me an e-mail at
425  * Daisuke Yabuki <dxy@acm.org>.
426  * I don't know any other driver which handle both hard drive and
427  * removable media, by the way. I hope it wouldn't do any harm on
428  * other type of devices, i.e. ssd, or IDE drivers.
429  */
430 static gint
check_media_type(kstat_t * ksp)431 check_media_type(kstat_t *ksp) {
432     gint fd;
433     char *phys_path, devices_path[256]; /* or OBP_MAXPATHLEN? */
434     di_node_t node;
435     static di_node_t root_node = NULL;
436 #if 0
437     /* Not supported on Solaris 7 */
438     struct dk_minfo dk;
439 #else
440     int dkRemovable;
441 #endif
442 
443     if (root_node == NULL) {
444         if ((root_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
445                 perror("di_init");
446                 return -1;
447         }
448     }
449 
450     node = di_drv_first_node(ksp->ks_module, root_node);
451     while (node != DI_NODE_NIL) {
452         if (di_instance(node) != ksp->ks_instance) {
453             node = di_drv_next_node(node);
454             continue;
455         }
456         if ((phys_path = di_devfs_path(node)) == NULL) {
457             perror("di_devfs_path");
458             return -1;
459         }
460         if (sprintf(devices_path, "/devices%s:c,raw", phys_path) <= 0) {
461             di_devfs_path_free(phys_path);
462             return -1;
463         }
464         if ((fd = open(devices_path, O_RDONLY)) == -1) {
465             if (errno == ENXIO || errno == EBUSY) {
466                 close(fd);
467                 di_devfs_path_free(phys_path);
468                 return 0; /* guess it's removable media */
469             } else {
470 #ifdef DEBUG
471                 g_message("opening %s\n", devices_path);
472                 g_message("unexpected errno: %d\n", errno);
473                 g_message("disabled auto-detection/exclusion of removable media\n");
474 #endif
475                 close(fd);
476                 di_devfs_path_free(phys_path);
477                 return -1; /* EACCESS (unless setgid sys) or suchlike */
478             }
479         }
480 #if 0
481 	/* Not supported on Solaris 7 */
482         if (ioctl(fd, DKIOCGMEDIAINFO, &dk) < 0)
483 #else
484 	if (ioctl(fd, DKIOCREMOVABLE, &dkRemovable) < 0)
485 #endif
486 	{
487             close(fd);
488             di_devfs_path_free(phys_path);
489             return -1;
490         }
491 #if 0
492         if (dk.dki_media_type == DK_FIXED_DISK)
493 #else
494         if (!dkRemovable)
495 #endif
496 	{
497 	   close(fd);
498 	   di_devfs_path_free(phys_path);
499 	   return 1;
500         }
501 	return 0;
502     }
503     return -1; /* shouldn't be reached */
504 }
505 
506 static gint
isharddisk(kstat_t * ksp)507 isharddisk(kstat_t *ksp) {
508     if (ksp->ks_type != KSTAT_TYPE_IO)
509         return 0;
510     if (strncmp(ksp->ks_class, "disk", 4))
511         return 0; /* excluding nfs etc. */
512     if (!strcmp(ksp->ks_module, "fd"))
513         return 0; /* excluding fd */
514     if (check_media_type(ksp) == 0)
515         return 0; /* guess it's removable media (e.g. CD-ROM, CD-R/W etc) */
516     return 1;
517 }
518 
519 /*
520  * creating a preliminary list of drives, which should be a complete
521  * list of drives available on the system. the list is not supposed to
522  * contain nfs, fd, cdrom, cdrw etc.
523  */
524 void
solaris_list_harddisks(void)525 solaris_list_harddisks(void) {
526     extern kstat_ctl_t *kc;
527     kstat_t *ksp;
528     probed_harddisk *drive;
529 
530     if (kstat_chain_update(kc) == -1) {
531         perror("kstat_chain_update");
532         return;
533     }
534 
535     for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
536         if(isharddisk(ksp)) {
537              drive = g_new0(probed_harddisk, 1);
538              hard_disk_list = g_list_append(hard_disk_list, drive);
539              strcpy(drive->name, ksp->ks_name);
540         }
541     }
542 }
543 
544 
545 /* ===================================================================== */
546 /* Inet monitor interface */
547 
548 #include "../inet.h"
549 
550 #include <stropts.h>
551 #include <inet/mib2.h>
552 #include <fcntl.h>
553 #include <sys/tihdr.h>
554 
555 void
gkrellm_sys_inet_read_tcp_data()556 gkrellm_sys_inet_read_tcp_data() {
557 
558     ActiveTCP tcp;
559     gint tcp_status;
560 
561     static int tcpfd = 0;
562 
563     mib2_tcpConnEntry_t *tp;
564 #if defined(INET6)
565     mib2_tcp6ConnEntry_t *tp6;
566 #endif
567 
568     char buf[512];
569     int i, flags, getcode, num_ent;
570     struct strbuf ctlbuf, databuf;
571     struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf;
572     struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf;
573     struct T_error_ack   *tea = (struct T_error_ack *)buf;
574     struct opthdr        *mibhdr;
575 
576     if (tcpfd == 0) {
577         if ((tcpfd = open("/dev/tcp", O_RDWR)) == -1) {
578             perror("open");
579         }
580     }
581 
582     tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
583     tor->OPT_offset = sizeof (struct T_optmgmt_req);
584     tor->OPT_length = sizeof (struct opthdr);
585     tor->MGMT_flags = T_CURRENT;
586     mibhdr = (struct opthdr *)&tor[1];
587     mibhdr->level = MIB2_TCP;
588     mibhdr->name  = 0;
589     mibhdr->len   = 0;
590 
591     ctlbuf.buf = buf;
592     ctlbuf.len = tor->OPT_offset + tor->OPT_length;
593     flags = 0; /* request to be sent in non-priority */
594 
595     if (putmsg(tcpfd, &ctlbuf, (struct strbuf *)0, flags) == -1) {
596         perror("putmsg");
597     }
598 
599     mibhdr = (struct opthdr *)&toa[1];
600     ctlbuf.maxlen = sizeof (buf);
601 
602     /* now receiving response from stream */
603 
604     for (;;) {
605         flags = 0; /* read any messages available */
606         getcode = getmsg(tcpfd, &ctlbuf, (struct strbuf *)0, &flags);
607 
608         if (getcode != MOREDATA ||
609                  ctlbuf.len < sizeof (struct T_optmgmt_ack) ||
610                  toa->PRIM_type != T_OPTMGMT_ACK ||
611                  toa->MGMT_flags != T_SUCCESS) {
612              break;
613         }
614 
615         if (ctlbuf.len >= sizeof (struct T_error_ack) &&
616                  tea->PRIM_type == T_ERROR_ACK) {
617              perror("ERROR_ACK");
618              return;
619         }
620 
621         if (getcode == 0 &&
622                  ctlbuf.len >= sizeof (struct T_optmgmt_ack) &&
623                  toa->PRIM_type == T_OPTMGMT_ACK &&
624                  toa->MGMT_flags == T_SUCCESS) {
625              return;
626         }
627 
628         /* prepare for receiving data */
629         databuf.maxlen = mibhdr->len;
630         databuf.len    = 0;
631         databuf.buf    = (char *)malloc((int)mibhdr->len);
632         if(!databuf.buf) {
633             perror("malloc");
634             break;
635         }
636         flags = 0;
637 
638         getcode = getmsg(tcpfd, (struct strbuf *)0, &databuf, &flags);
639 
640         if (mibhdr->level == MIB2_TCP && mibhdr->name == MIB2_TCP_13) {
641             tp = (mib2_tcpConnEntry_t *)databuf.buf;
642             num_ent = mibhdr->len / sizeof(mib2_tcpConnEntry_t);
643             for (i = 0; i < num_ent; i++, tp++) {
644                 if (tp->tcpConnState != MIB2_TCP_established)
645                     continue;
646                 tcp.local_port         = tp->tcpConnLocalPort;
647                 tcp.remote_addr.s_addr = tp->tcpConnRemAddress;
648                 tcp.remote_port        = tp->tcpConnRemPort;
649                 tcp.family             = AF_INET;
650                 tcp_status = (tp->tcpConnState == MIB2_TCP_established);
651                 if (tcp_status == TCP_ALIVE)
652                     gkrellm_inet_log_tcp_port_data(&tcp);
653             }
654         }
655 
656 #if defined(INET6)
657         if (mibhdr->level == MIB2_TCP6 && mibhdr->name == MIB2_TCP6_CONN) {
658             tp6 = (mib2_tcp6ConnEntry_t *)databuf.buf;
659             num_ent = mibhdr->len / sizeof(mib2_tcp6ConnEntry_t);
660             for (i = 0; i < num_ent; i++, tp6++) {
661                 if (tp6->tcp6ConnState != MIB2_TCP_established)
662                     continue;
663                 tcp.local_port          = tp6->tcp6ConnLocalPort;
664                 tcp.remote_port         = tp6->tcp6ConnRemPort;
665                 memcpy(&tcp.remote_addr6, &tp6->tcp6ConnRemAddress,
666 			sizeof(struct in6_addr));
667                 tcp.family              = AF_INET6;
668                 tcp_status = (tp6->tcp6ConnState == MIB2_TCP_established);
669                 if (tcp_status == TCP_ALIVE)
670                     gkrellm_inet_log_tcp_port_data(&tcp);
671             }
672         }
673 #endif /* INET6 */
674 
675         free(databuf.buf);
676     }
677 
678 }
679 
680 gboolean
gkrellm_sys_inet_init(void)681 gkrellm_sys_inet_init(void)
682 	{
683 	return TRUE;
684 	}
685 
686 
687 /* ===================================================================== */
688 /* Net monitor interface */
689 
690 #include <kstat.h>
691 #include <net/if.h>
692 #include <sys/sockio.h>
693 
694 /*
695  * FIXME: I haven't tested Net timer (and never will), but I believe it's
696  * not going to work. Name of the lock file is different from one on Linux.
697  * If you need this functionality, feel free to modify my code.
698  */
699 
700 void
gkrellm_sys_net_read_data(void)701 gkrellm_sys_net_read_data(void)
702 	{
703 	gulong	rx, tx;
704     extern kstat_ctl_t *kc;
705     kstat_t *ksp;
706     kstat_named_t *knp;
707 
708 	if (kstat_chain_update(kc) == -1) {
709 			perror("kstat_chain_update");
710 			return;
711 	}
712 
713     for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
714 	    if (!strcmp(ksp->ks_class, "net")) {
715 		    kstat_read(kc, ksp, NULL);
716 
717 		    knp = kstat_data_lookup(ksp, "rbytes");
718 		    if (knp == NULL)
719 			    continue;
720 		    rx = knp->value.ui32;
721 
722 		    knp = kstat_data_lookup(ksp, "obytes");
723 		    if (knp == NULL)
724 			    continue;
725 		    tx = knp->value.ui32;
726 
727 		    gkrellm_net_assign_data(ksp->ks_name, rx, tx);
728 	    }
729     }
730 
731 	}
732 
733 #if 0
734 /* New way is for above gkrellm_sys_net_read_data() to just assign data
735 |  for all net interfaces.
736 */
737 void
738 gkrellm_sys_net_sync(void)
739 	{
740     GList *list;
741     int numifs, numifreqs;
742     int i, sockfd;
743     size_t bufsize;
744     gchar	*buf;
745     struct ifreq ifr, *ifrp;
746     struct ifconf ifc;
747 
748     if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
749 	return;
750 
751     if (ioctl(sockfd, SIOCGIFNUM, (char *)&numifs) < 0) {
752         perror("SIOCGIFNUM");
753         close(sockfd);
754         return;
755     }
756 
757     bufsize = ((size_t)numifs) * sizeof(struct ifreq);
758     buf = (char *)malloc(bufsize);
759     if (!buf) {
760         perror("malloc");
761         close(sockfd);
762         return;
763     }
764 
765     ifc.ifc_len = bufsize;
766     ifc.ifc_buf = buf;
767 
768     if (ioctl(sockfd, SIOCGIFCONF, (char *)&ifc) < 0) {
769         perror("SIOCGIFCONF");
770         free(buf);
771         close(sockfd);
772         return;
773     }
774 
775 #ifdef DEBUG
776     g_message("interfaces probed: ");
777     for (i=0; i < numifs; i++) {
778         g_message("%s ", ifc.ifc_req[i].ifr_name);
779     }
780     g_message("\n");
781 #endif
782 
783     ifrp = ifc.ifc_req;
784     numifreqs = ifc.ifc_len / sizeof(struct ifreq);
785 
786     for (i = 0; i < numifreqs; i++, ifrp++)
787 		{
788 		memset((char *)&ifr, 0, sizeof(ifr));
789 		strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name));
790 		if (!strncmp(ifr.ifr_name, "lo", 2))
791 			continue;
792 		if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0)
793 			{
794 			perror("SIOCGIFFLAGS");
795 			continue;
796 			}
797 		if (ifr.ifr_flags & IFF_UP)
798 			gkrellm_net_interface_is_up(ifr.ifr_name);
799     	}
800     free(buf);
801     close(sockfd);
802 	}
803 #endif
804 
805 gboolean
gkrellm_sys_net_isdn_online(void)806 gkrellm_sys_net_isdn_online(void)
807 	{
808 	return FALSE;
809 	}
810 
811 void
gkrellm_sys_net_check_routes(void)812 gkrellm_sys_net_check_routes(void)
813 {
814 }
815 
816 gboolean
gkrellm_sys_net_init(void)817 gkrellm_sys_net_init(void)
818 	{
819 	gkrellm_net_set_lock_directory("/var/spool/locks");
820 	gkrellm_net_add_timer_type_ppp("ipdptp0");
821 	gkrellm_net_add_timer_type_ppp("ppp0");
822 	return TRUE;
823 	}
824 
825 
826 
827 /* ===================================================================== */
828 /* Memory/Swap monitor interface */
829 
830 #include <unistd.h>
831 #include <kstat.h>
832 #include <sys/stat.h>
833 #include <sys/swap.h>
834 
835 static guint64  swap_total, swap_used;
836 
837 void
gkrellm_sys_mem_read_data()838 gkrellm_sys_mem_read_data() {
839 
840     gulong pagesize;
841 	guint64	total, used = 0, free = 0;
842     static gulong pageshift = 0, physpages = 0;
843     extern kstat_ctl_t *kc;
844     kstat_t *ksp;
845     kstat_named_t *knp;
846 
847     struct anoninfo ai;
848 
849     if (!GK.second_tick)
850         return;
851 
852     if (pageshift == 0) {
853         for (pagesize = sysconf(_SC_PAGESIZE); pagesize > 1; pagesize >>= 1)
854             pageshift++;
855     }
856     if (physpages == 0) {
857         physpages = sysconf(_SC_PHYS_PAGES);
858     }
859 
860     total = physpages;
861     total <<= pageshift;
862 
863     ksp = kstat_lookup(kc, "unix", -1, "system_pages");
864     if (ksp && kstat_read(kc, ksp, NULL) >= 0) {
865         knp = (kstat_named_t *)kstat_data_lookup(ksp, "pagesfree");
866         if (knp) {
867             free = knp->value.ui32;
868             free <<= pageshift;
869             used = total - free;
870         }
871     }
872 	gkrellm_mem_assign_data(total, used, free, 0, 0, 0);
873     if (swapctl(SC_AINFO, &ai) == -1) {
874         perror("swapctl");
875     }
876 	swap_total = ai.ani_max;
877 	swap_total <<= pageshift;
878 
879     swap_used  = ai.ani_resv;
880     swap_used  <<= pageshift;
881 
882     /* NEED TO BE COMPLETED
883      * mem.x_used, mem.shared, mem.buffers, mem.cached
884      * swap_chart.page_in, swap_chart.page_out (for swap pages in/out chart)
885      */
886 
887 }
888 
889 void
gkrellm_sys_swap_read_data(void)890 gkrellm_sys_swap_read_data(void)
891 	{
892     /* page in/out UNIMPLEMENTED */
893 	gkrellm_swap_assign_data(swap_total, swap_used, 0, 0);
894 	}
895 
896 gboolean
gkrellm_sys_mem_init(void)897 gkrellm_sys_mem_init(void)
898 	{
899 	return TRUE;
900 	}
901 
902 
903 /* ===================================================================== */
904 /* FS monitor interface */
905 
906 #include <sys/mnttab.h>
907 #include <sys/vfstab.h>
908 #include <sys/statvfs.h>
909 #include <sys/cdio.h>
910 
911 gboolean
gkrellm_sys_fs_fstab_modified(void)912 gkrellm_sys_fs_fstab_modified(void)
913 	{
914 	struct stat		s;
915 	static time_t	fstab_mtime;
916 	gint			modified = FALSE;
917 
918 	if (stat("/etc/fstab", &s) == 0 && s.st_mtime != fstab_mtime)
919 		modified = TRUE;
920 	fstab_mtime = s.st_mtime;
921 	return modified;
922 	}
923 
924 
925 void
gkrellm_sys_fs_get_fstab_list()926 gkrellm_sys_fs_get_fstab_list(){
927     FILE *fp;
928     struct vfstab vfsbuf;
929 
930     if ((fp = fopen(VFSTAB, "r")) == NULL)
931         return;
932 
933     while (getvfsent(fp, &vfsbuf) == 0) {
934         if (!vfsbuf.vfs_fstype || strcmp(vfsbuf.vfs_fstype, "ufs"))
935             continue;
936 		gkrellm_fs_add_to_fstab_list(
937 				vfsbuf.vfs_mountp  ? vfsbuf.vfs_mountp  : "",
938 				vfsbuf.vfs_special ? vfsbuf.vfs_special : "",
939 				vfsbuf.vfs_fstype  ? vfsbuf.vfs_fstype  : "",
940 				vfsbuf.vfs_mntopts ? vfsbuf.vfs_mntopts : "");
941     }
942 
943     fclose(fp);
944 }
945 
946 void
gkrellm_sys_fs_get_mounts_list(void)947 gkrellm_sys_fs_get_mounts_list(void){
948     FILE *fp;
949     struct mnttab mntbuf;
950 
951     if ((fp = fopen(MNTTAB, "r")) == NULL)
952         return;
953 
954     while (getmntent(fp, &mntbuf) == 0) {
955         if (strcmp(mntbuf.mnt_fstype, "ufs") &&
956                                   strcmp(mntbuf.mnt_fstype, "nfs"))
957             continue;
958 		gkrellm_fs_add_to_mounts_list(
959 				mntbuf.mnt_mountp  ? mntbuf.mnt_mountp  : "",
960 				mntbuf.mnt_special ? mntbuf.mnt_special : "",
961 				mntbuf.mnt_fstype  ? mntbuf.mnt_fstype  : "");
962     }
963     fclose(fp);
964 }
965 
966 void
gkrellm_sys_fs_get_fsusage(gpointer fs,gchar * dir)967 gkrellm_sys_fs_get_fsusage(gpointer fs, gchar *dir){
968     struct statvfs st;
969 
970 	if (dir && statvfs(dir, &st) == 0) {
971 		gkrellm_fs_assign_fsusage_data(fs,
972 					(gint64) st.f_blocks, (gint64) st.f_bavail,
973 					(glong) st.f_bfree, (glong) st.f_bsize);
974     } else {
975 		gkrellm_fs_assign_fsusage_data(fs, 0, 0, 0, 0);
976     }
977 }
978 
979 static void
eject_solaris_cdrom(gchar * device)980 eject_solaris_cdrom(gchar *device) {
981 #if defined(CDROMEJECT)
982         gint    d;
983 
984 		if ((d = open(device, O_RDONLY)) >= 0) {
985 				ioctl(d, CDROMEJECT);
986 				close(d);
987         }
988 #endif
989 }
990 
991 gboolean
gkrellm_sys_fs_init(void)992 gkrellm_sys_fs_init(void)
993 	{
994 	gkrellm_fs_setup_eject(NULL, NULL, eject_solaris_cdrom, NULL);
995 	return TRUE;
996 	}
997 
998 
999 /* ===================================================================== */
1000 /* Battery monitor interface */
1001 void
gkrellm_sys_battery_read_data(void)1002 gkrellm_sys_battery_read_data(void)
1003 	{
1004 	}
1005 
1006 gboolean
gkrellm_sys_battery_init()1007 gkrellm_sys_battery_init()
1008 	{
1009 	return FALSE;
1010 	}
1011 
1012 
1013 /* ===================================================================== */
1014 /* Uptime monitor interface */
1015 
1016 #include <time.h>
1017 #include <kstat.h>
1018 
1019 time_t
gkrellm_sys_uptime_read_uptime(void)1020 gkrellm_sys_uptime_read_uptime(void)
1021 	{
1022 	return (time_t) 0;  /* Will calculate using base_uptime */
1023 	}
1024 
1025 gboolean
gkrellm_sys_uptime_init(void)1026 gkrellm_sys_uptime_init(void) {
1027     time_t      boot, now, base_uptime;
1028 
1029     extern kstat_ctl_t *kc;
1030     kstat_t *ksp;
1031     kstat_named_t *knp;
1032 
1033     boot = 0;
1034 
1035     if (kstat_chain_update(kc) == -1) {
1036         perror("kstat_chain_update");
1037         return FALSE;
1038     }
1039     ksp = kstat_lookup(kc, "unix", -1, "system_misc");
1040     if (ksp && kstat_read(kc, ksp, NULL) >= 0) {
1041         knp = (kstat_named_t *)kstat_data_lookup(ksp, "boot_time");
1042         if (knp) {
1043             boot = knp->value.ui32;
1044         }
1045     }
1046     if (time(&now) < 0)
1047         return FALSE;
1048     if (now <= boot)
1049         return FALSE;
1050 
1051     base_uptime = now - boot;
1052     base_uptime += 30;
1053 	gkrellm_uptime_set_base_uptime(base_uptime);
1054 
1055     return (base_uptime == (time_t) 0) ? FALSE : TRUE;
1056 }
1057 
1058 
1059 /* ===================================================================== */
1060 /* Sensor monitor interface */
1061 /* (nonfunctional) */
1062 
1063 gboolean
gkrellm_sys_sensors_init(void)1064 gkrellm_sys_sensors_init(void)
1065 {
1066 	return FALSE;
1067 }
1068 
1069 gboolean
gkrellm_sys_sensors_get_temperature(gchar * name,gint id,gint iodev,gint inter,gfloat * t)1070 gkrellm_sys_sensors_get_temperature(gchar *name, gint id, gint iodev, gint inter, gfloat *t)
1071 {
1072 	return FALSE;
1073 }
1074 
1075 gboolean
gkrellm_sys_sensors_get_fan(gchar * name,gint id,gint iodev,gint inter,gfloat * t)1076 gkrellm_sys_sensors_get_fan(gchar *name, gint id, gint iodev, gint inter, gfloat *t)
1077 {
1078 	return FALSE;
1079 }
1080 
1081 gboolean
gkrellm_sys_sensors_get_voltage(gchar * name,gint id,gint iodev,gint inter,gfloat * t)1082 gkrellm_sys_sensors_get_voltage(gchar *name, gint id, gint iodev, gint inter, gfloat *t)
1083 {
1084 	return FALSE;
1085 }
1086 
1087