1 /*
2  * Copyright (c) 2004-2008 Hyperic, Inc.
3  * Copyright (c) 2009 SpringSource, Inc.
4  * Copyright (c) 2009-2010 VMware, Inc.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #include "sigar.h"
20 #include "sigar_private.h"
21 #include "sigar_util.h"
22 #include "sigar_os.h"
23 
24 #include <inet/ip.h>
25 #include <inet/tcp.h>
26 #include <net/if.h>
27 #include <net/route.h>
28 #include <sys/lwp.h>
29 #include <sys/proc.h>
30 #include <sys/sockio.h>
31 #include <sys/swap.h>
32 #include <sys/stat.h>
33 #include <sys/systeminfo.h>
34 #include <sys/utsname.h>
35 #include <dlfcn.h>
36 #include <dirent.h>
37 
38 #define PROC_ERRNO ((errno == ENOENT) ? ESRCH : errno)
39 #define SIGAR_USR_UCB_PS "/usr/ucb/ps"
40 
41 
42 /* like kstat_lookup but start w/ ksp->ks_next instead of kc->kc_chain */
43 static kstat_t *
kstat_next(kstat_t *ksp, char *ks_module, int ks_instance, char *ks_name)44 kstat_next(kstat_t *ksp, char *ks_module, int ks_instance, char *ks_name)
45 {
46     if (ksp) {
47         ksp = ksp->ks_next;
48     }
49     for (; ksp; ksp = ksp->ks_next) {
50         if ((ks_module == NULL ||
51              strcmp(ksp->ks_module, ks_module) == 0) &&
52             (ks_instance == -1 || ksp->ks_instance == ks_instance) &&
53             (ks_name == NULL || strcmp(ksp->ks_name, ks_name) == 0))
54             return ksp;
55     }
56 
57     errno = ENOENT;
58     return NULL;
59 }
60 
sigar_os_open(sigar_t **sig)61 int sigar_os_open(sigar_t **sig)
62 {
63     kstat_ctl_t *kc;
64     kstat_t *ksp;
65     sigar_t *sigar;
66     int i, status;
67     struct utsname name;
68     char *ptr;
69 
70     if ((kc = kstat_open()) == NULL) {
71        *sig = NULL;
72        return errno;
73     }
74 
75     /*
76      * Use calloc instead of malloc to set everything to 0
77      * to avoid having to set each individual member to 0/NULL
78      * later.
79      */
80     if ((*sig = sigar = calloc(1, sizeof(*sigar))) == NULL) {
81        return ENOMEM;
82     }
83 
84     uname(&name);
85     if ((ptr = strchr(name.release, '.'))) {
86         sigar->solaris_version = atoi(ptr + 1);
87     }
88     else {
89         sigar->solaris_version = 6;
90     }
91 
92     if ((ptr = getenv("SIGAR_USE_UCB_PS"))) {
93         sigar->use_ucb_ps = strEQ(ptr, "true");
94     }
95 
96     if (sigar->use_ucb_ps) {
97         if (access(SIGAR_USR_UCB_PS, X_OK) == -1) {
98             sigar->use_ucb_ps = 0;
99         }
100         else {
101             sigar->use_ucb_ps = 1;
102         }
103     }
104 
105     sigar->pagesize = 0;
106     i = sysconf(_SC_PAGESIZE);
107     while ((i >>= 1) > 0) {
108         sigar->pagesize++;
109     }
110 
111     sigar->ticks = sysconf(_SC_CLK_TCK);
112     sigar->kc = kc;
113 
114     sigar->koffsets.system[0] = -1;
115     sigar->koffsets.mempages[0] = -1;
116     sigar->koffsets.syspages[0] = -1;
117 
118     if ((status = sigar_get_kstats(sigar)) != SIGAR_OK) {
119         fprintf(stderr, "status=%d\n", status);
120     }
121 
122     if ((ksp = sigar->ks.system) &&
123         (kstat_read(kc, ksp, NULL) >= 0))
124     {
125         sigar_koffsets_init_system(sigar, ksp);
126 
127         sigar->boot_time = kSYSTEM(KSTAT_SYSTEM_BOOT_TIME);
128     }
129 
130     sigar->last_pid = -1;
131     sigar->mib2.sd = -1;
132 
133     return SIGAR_OK;
134 }
135 
sigar_cpu_list_destroy(sigar_t *sigar, sigar_cpu_list_t *cpulist)136 static int sigar_cpu_list_destroy(sigar_t *sigar, sigar_cpu_list_t *cpulist)
137 {
138     if (cpulist->size) {
139         free(cpulist->data);
140         cpulist->number = cpulist->size = 0;
141     }
142 
143     return SIGAR_OK;
144 }
145 
sigar_os_close(sigar_t *sigar)146 int sigar_os_close(sigar_t *sigar)
147 {
148     kstat_close(sigar->kc);
149     if (sigar->mib2.sd != -1) {
150         close_mib2(&sigar->mib2);
151     }
152 
153     if (sigar->ks.lcpu) {
154         free(sigar->ks.cpu);
155         free(sigar->ks.cpu_info);
156         free(sigar->ks.cpuid);
157     }
158     if (sigar->pinfo) {
159         free(sigar->pinfo);
160     }
161     if (sigar->cpulist.size != 0) {
162         sigar_cpu_list_destroy(sigar, &sigar->cpulist);
163     }
164     if (sigar->plib) {
165         dlclose(sigar->plib);
166     }
167     if (sigar->pargs) {
168         sigar_cache_destroy(sigar->pargs);
169     }
170     free(sigar);
171     return SIGAR_OK;
172 }
173 
sigar_os_error_string(sigar_t *sigar, int err)174 char *sigar_os_error_string(sigar_t *sigar, int err)
175 {
176     switch (err) {
177       case SIGAR_EMIB2:
178         return sigar->mib2.errmsg;
179       default:
180         return NULL;
181     }
182 }
183 
sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)184 int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)
185 {
186     kstat_ctl_t *kc = sigar->kc;
187     kstat_t *ksp;
188     sigar_uint64_t kern = 0;
189 
190     SIGAR_ZERO(mem);
191 
192     /* XXX: is mem hot swappable or can we just do this during open ? */
193     mem->total = sysconf(_SC_PHYS_PAGES);
194     mem->total <<= sigar->pagesize;
195 
196     if (sigar_kstat_update(sigar) == -1) {
197         return errno;
198     }
199 
200     if ((ksp = sigar->ks.syspages) && kstat_read(kc, ksp, NULL) >= 0) {
201         sigar_koffsets_init_syspages(sigar, ksp);
202 
203         mem->free = kSYSPAGES(KSTAT_SYSPAGES_FREE);
204         mem->free <<= sigar->pagesize;
205 
206         mem->used = mem->total - mem->free;
207     }
208 
209     if ((ksp = sigar->ks.mempages) && kstat_read(kc, ksp, NULL) >= 0) {
210         sigar_koffsets_init_mempages(sigar, ksp);
211     }
212 
213     /* XXX mdb ::memstat cachelist/freelist not available to kstat, see: */
214     /* http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id=6821980 */
215 
216     /* ZFS ARC cache. see: http://opensolaris.org/jive/thread.jspa?messageID=393695 */
217     if ((ksp = kstat_lookup(sigar->kc, "zfs", 0, "arcstats")) &&
218         (kstat_read(sigar->kc, ksp, NULL) != -1))
219     {
220         kstat_named_t *kn;
221 
222         if ((kn = (kstat_named_t *)kstat_data_lookup(ksp, "size"))) {
223             kern = kn->value.i64;
224         }
225         if ((kn = (kstat_named_t *)kstat_data_lookup(ksp, "c_min"))) {
226             /* c_min cannot be reclaimed they say */
227             if (kern > kn->value.i64) {
228                 kern -= kn->value.i64;
229             }
230         }
231     }
232 
233     mem->actual_free = mem->free + kern;
234     mem->actual_used = mem->used - kern;
235 
236     sigar_mem_calc_ram(sigar, mem);
237 
238     return SIGAR_OK;
239 }
240 
sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)241 int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)
242 {
243     kstat_t *ksp;
244     kstat_named_t *kn;
245     swaptbl_t *stab;
246     int num, i;
247     char path[PATH_MAX+1]; /* {un,re}used */
248 
249     /* see: man swapctl(2) */
250     if ((num = swapctl(SC_GETNSWP, NULL)) == -1) {
251         return errno;
252     }
253 
254     stab = malloc(num * sizeof(stab->swt_ent[0]) + sizeof(*stab));
255 
256     stab->swt_n = num;
257     for (i=0; i<num; i++) {
258         stab->swt_ent[i].ste_path = path;
259     }
260 
261     if ((num = swapctl(SC_LIST, stab)) == -1) {
262         free(stab);
263         return errno;
264     }
265 
266     num = num < stab->swt_n ? num : stab->swt_n;
267     swap->total = swap->free = 0;
268     for (i=0; i<num; i++) {
269         if (stab->swt_ent[i].ste_flags & ST_INDEL) {
270             continue; /* swap file is being deleted */
271         }
272         swap->total += stab->swt_ent[i].ste_pages;
273         swap->free  += stab->swt_ent[i].ste_free;
274     }
275     free(stab);
276 
277     swap->total <<= sigar->pagesize;
278     swap->free  <<= sigar->pagesize;
279     swap->used  = swap->total - swap->free;
280 
281     swap->allocstall = -1;
282     swap->allocstall_dma = -1;
283     swap->allocstall_dma32 = -1;
284     swap->allocstall_normal = -1;
285     swap->allocstall_movable = -1;
286 
287     if (sigar_kstat_update(sigar) == -1) {
288         return errno;
289     }
290     if (!(ksp = kstat_lookup(sigar->kc, "cpu", -1, "vm"))) {
291         swap->page_in = swap->page_out = SIGAR_FIELD_NOTIMPL;
292         return SIGAR_OK;
293     }
294 
295     swap->page_in = swap->page_out = 0;
296 
297     /* XXX: these stats do not exist in this form on solaris 8 or 9.
298      * they are in the raw cpu_stat struct, but thats not
299      * binary compatible
300      */
301     do {
302         if (kstat_read(sigar->kc, ksp, NULL) < 0) {
303             break;
304         }
305 
306         if ((kn = (kstat_named_t *)kstat_data_lookup(ksp, "pgin"))) {
307             swap->page_in += kn->value.i64;  /* vmstat -s | grep "page ins" */
308         }
309         if ((kn = (kstat_named_t *)kstat_data_lookup(ksp, "pgout"))) {
310             swap->page_out += kn->value.i64; /* vmstat -s | grep "page outs" */
311         }
312     } while ((ksp = kstat_next(ksp, "cpu", -1, "vm")));
313 
314     return SIGAR_OK;
315 }
316 
317 #ifndef KSTAT_NAMED_STR_PTR
318 /* same offset as KSTAT_NAMED_STR_PTR(brand) */
319 #define KSTAT_NAMED_STR_PTR(n) (char *)((n)->value.i32)
320 #endif
321 
322 
free_chip_id(void *ptr)323 static void free_chip_id(void *ptr)
324 {
325     /*noop*/
326 }
327 
get_chip_id(sigar_t *sigar, int processor)328 static int get_chip_id(sigar_t *sigar, int processor)
329 {
330     kstat_t *ksp = sigar->ks.cpu_info[processor];
331     kstat_named_t *chipid;
332 
333     if (ksp &&
334         (kstat_read(sigar->kc, ksp, NULL) != -1) &&
335         (chipid = (kstat_named_t *)kstat_data_lookup(ksp, "chip_id")))
336     {
337         return chipid->value.i32;
338     }
339     else {
340         return -1;
341     }
342 }
343 
344 static int sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist);
345 
sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)346 int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)
347 {
348     int status, i;
349 
350     status = sigar_cpu_list_get(sigar, &sigar->cpulist);
351 
352     if (status != SIGAR_OK) {
353         return status;
354     }
355 
356     SIGAR_ZERO(cpu);
357 
358     for (i=0; i<sigar->cpulist.number; i++) {
359         sigar_cpu_t *xcpu = &sigar->cpulist.data[i];
360 
361         cpu->user  += xcpu->user;
362         cpu->sys   += xcpu->sys;
363         cpu->idle  += xcpu->idle;
364         cpu->nice  += xcpu->nice;
365         cpu->wait  += xcpu->wait;
366         cpu->total += xcpu->total;
367     }
368 
369     return SIGAR_OK;
370 }
371 
372 
373 
374 static int sigar_cpu_list_create(sigar_cpu_list_t *cpulist);
375 
376 static int sigar_cpu_list_grow(sigar_cpu_list_t *cpulist);
377 
378 #define SIGAR_CPU_LIST_GROW(cpulist) \
379     if (cpulist->number >= cpulist->size) { \
380         sigar_cpu_list_grow(cpulist); \
381     }
382 
sigar_cpu_list_create(sigar_cpu_list_t *cpulist)383 static int sigar_cpu_list_create(sigar_cpu_list_t *cpulist)
384 {
385     cpulist->number = 0;
386     cpulist->size = SIGAR_CPU_INFO_MAX;
387     cpulist->data = malloc(sizeof(*(cpulist->data)) *
388                            cpulist->size);
389     return SIGAR_OK;
390 }
391 
sigar_cpu_list_grow(sigar_cpu_list_t *cpulist)392 static int sigar_cpu_list_grow(sigar_cpu_list_t *cpulist)
393 {
394     cpulist->data = realloc(cpulist->data,
395                             sizeof(*(cpulist->data)) *
396                             (cpulist->size + SIGAR_CPU_INFO_MAX));
397     cpulist->size += SIGAR_CPU_INFO_MAX;
398 
399     return SIGAR_OK;
400 }
401 
402 
403 
404 
sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist)405 static int sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist)
406 {
407     kstat_ctl_t *kc = sigar->kc;
408     kstat_t *ksp;
409     uint_t cpuinfo[CPU_STATES];
410     unsigned int i;
411     int is_debug = SIGAR_LOG_IS_DEBUG(sigar);
412     sigar_cache_t *chips;
413 
414     if (sigar_kstat_update(sigar) == -1) {
415         return errno;
416     }
417 
418     if (cpulist == &sigar->cpulist) {
419         if (sigar->cpulist.size == 0) {
420             /* create once */
421             sigar_cpu_list_create(cpulist);
422         }
423         else {
424             /* reset, re-using cpulist.data */
425             sigar->cpulist.number = 0;
426         }
427     }
428     else {
429         sigar_cpu_list_create(cpulist);
430     }
431 
432     if (is_debug) {
433         sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
434                          "[cpu_list] OS reports %d CPUs",
435                          sigar->ncpu);
436     }
437 
438     chips = sigar_cache_new(16);
439     chips->free_value = free_chip_id;
440 
441     for (i=0; i<sigar->ncpu; i++) {
442         sigar_cpu_t *cpu;
443         char *buf;
444         int chip_id;
445         sigar_cache_entry_t *ent;
446 
447         if (!CPU_ONLINE(sigar->ks.cpuid[i])) {
448             sigar_log_printf(sigar, SIGAR_LOG_INFO,
449                              "cpu %d (id=%d) is offline",
450                              i, sigar->ks.cpuid[i]);
451             continue;
452         }
453 
454         if (!(ksp = sigar->ks.cpu[i])) {
455             sigar_log_printf(sigar, SIGAR_LOG_ERROR,
456                              "NULL ksp for cpu %d (id=%d)",
457                              i, sigar->ks.cpuid[i]);
458             continue; /* shouldnot happen */
459         }
460 
461         if (kstat_read(kc, ksp, NULL) < 0) {
462             sigar_log_printf(sigar, SIGAR_LOG_ERROR,
463                              "kstat_read failed for cpu %d (id=%d): %s",
464                              i, sigar->ks.cpuid[i],
465                              sigar_strerror(sigar, errno));
466             continue; /* shouldnot happen */
467         }
468 
469         /*
470          * cpu_stat_t is not binary compatible between solaris versions.
471          * since cpu_stat is a 'raw' kstat and not 'named' we cannot
472          * use name based lookups as we do for others.
473          * the start of the cpu_stat_t structure is binary compatible,
474          * which looks like so:
475          * typedef struct cpu_stat {
476          *    kmutex_t        cpu_stat_lock;
477          *    cpu_sysinfo_t   cpu_sysinfo;
478          *    ...
479          *    typedef struct cpu_sysinfo {
480          *       ulong cpu[CPU_STATES];
481          *       ...
482          * we just copy the piece we need below:
483          */
484         buf = ksp->ks_data;
485         buf += sizeof(kmutex_t);
486         memcpy(&cpuinfo[0], buf, sizeof(cpuinfo));
487         chip_id = sigar->cpu_list_cores ? -1 : get_chip_id(sigar, i);
488 
489         if (chip_id == -1) {
490             SIGAR_CPU_LIST_GROW(cpulist);
491             cpu = &cpulist->data[cpulist->number++];
492             SIGAR_ZERO(cpu);
493         }
494         else {
495             /* merge times of logical processors */
496             ent = sigar_cache_get(chips, chip_id);
497             if (ent->value) {
498                 cpu = &cpulist->data[(long)ent->value-1];
499             }
500             else {
501                 SIGAR_CPU_LIST_GROW(cpulist);
502                 cpu = &cpulist->data[cpulist->number++];
503                 ent->value = (void *)(long)cpulist->number;
504                 SIGAR_ZERO(cpu);
505 
506                 if (is_debug) {
507                     sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
508                                      "[cpu_list] Merging times of"
509                                      " logical processors for chip_id=%d",
510                                      chip_id);
511                 }
512             }
513         }
514 
515         cpu->user += SIGAR_TICK2MSEC(cpuinfo[CPU_USER]);
516         cpu->sys  += SIGAR_TICK2MSEC(cpuinfo[CPU_KERNEL]);
517         cpu->idle += SIGAR_TICK2MSEC(cpuinfo[CPU_IDLE]);
518         cpu->wait += SIGAR_TICK2MSEC(cpuinfo[CPU_WAIT]);
519         cpu->nice += 0; /* no cpu->nice */
520         cpu->total = cpu->user + cpu->sys + cpu->idle + cpu->wait;
521     }
522 
523     sigar_cache_destroy(chips);
524 
525     return SIGAR_OK;
526 }
527 
528 #define LIBPROC "/usr/lib/libproc.so"
529 
530 #define CHECK_PSYM(s) \
531     if (!sigar->s) { \
532         sigar_log_printf(sigar, SIGAR_LOG_WARN, \
533                          "[%s] Symbol not found: %s", \
534                          SIGAR_FUNC, #s); \
535         dlclose(sigar->plib); \
536         sigar->plib = NULL; \
537         return SIGAR_ENOTIMPL; \
538     }
539 
540 
541 /* from libproc.h, not included w/ solaris distro */
542 /* Error codes from Pgrab(), Pfgrab_core(), and Pgrab_core() */
543 #define G_STRANGE       -1      /* Unanticipated error, errno is meaningful */
544 #define G_NOPROC        1       /* No such process */
545 #define G_NOCORE        2       /* No such core file */
546 #define G_NOPROCORCORE  3       /* No such proc or core (for proc_arg_grab) */
547 #define G_NOEXEC        4       /* Cannot locate executable file */
548 #define G_ZOMB          5       /* Zombie process */
549 #define G_PERM          6       /* No permission */
550 #define G_BUSY          7       /* Another process has control */
551 #define G_SYS           8       /* System process */
552 #define G_SELF          9       /* Process is self */
553 #define G_INTR          10      /* Interrupt received while grabbing */
554 #define G_LP64          11      /* Process is _LP64, self is ILP32 */
555 #define G_FORMAT        12      /* File is not an ELF format core file */
556 #define G_ELF           13      /* Libelf error, elf_errno() is meaningful */
557 #define G_NOTE          14      /* Required PT_NOTE Phdr not present in core */
558 
559 
sigar_os_proc_list_get(sigar_t *sigar, sigar_proc_list_t *proclist)560 int sigar_os_proc_list_get(sigar_t *sigar,
561                            sigar_proc_list_t *proclist)
562 {
563     return sigar_proc_list_procfs_get(sigar, proclist);
564 }
565 
sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_mem_t *procmem)566 int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
567                        sigar_proc_mem_t *procmem)
568 {
569     int status = sigar_proc_psinfo_get(sigar, pid);
570     psinfo_t *pinfo = sigar->pinfo;
571     prusage_t usage;
572 
573     if (status != SIGAR_OK) {
574         return status;
575     }
576 
577     procmem->size     = pinfo->pr_size << 10;
578     procmem->resident = pinfo->pr_rssize << 10;
579     procmem->share    = SIGAR_FIELD_NOTIMPL;
580 
581     if (sigar_proc_usage_get(sigar, &usage, pid) == SIGAR_OK) {
582         procmem->minor_faults = usage.pr_minf;
583         procmem->major_faults = usage.pr_majf;
584         procmem->page_faults =
585             procmem->minor_faults +
586             procmem->major_faults;
587     }
588     else {
589         procmem->minor_faults = SIGAR_FIELD_NOTIMPL;
590         procmem->major_faults = SIGAR_FIELD_NOTIMPL;
591         procmem->page_faults = SIGAR_FIELD_NOTIMPL;
592     }
593 
594     return SIGAR_OK;
595 }
596 
597 #define TIMESTRUCT_2MSEC(t) \
598     ((t.tv_sec * MILLISEC) + (t.tv_nsec / (NANOSEC/MILLISEC)))
599 
sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_time_t *proctime)600 int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid,
601                         sigar_proc_time_t *proctime)
602 {
603     prusage_t usage;
604     int status;
605 
606     if ((status = sigar_proc_usage_get(sigar, &usage, pid)) != SIGAR_OK) {
607         return status;
608     }
609 
610     proctime->start_time = usage.pr_create.tv_sec + sigar->boot_time;
611     proctime->start_time *= MILLISEC;
612 
613     if (usage.pr_utime.tv_sec < 0) {
614         /* XXX wtf?  seen on solaris 10, only for the self process */
615         pstatus_t pstatus;
616 
617         status = sigar_proc_status_get(sigar, &pstatus, pid);
618         if (status != SIGAR_OK) {
619             return status;
620         }
621 
622         usage.pr_utime.tv_sec  = pstatus.pr_utime.tv_sec;
623         usage.pr_utime.tv_nsec = pstatus.pr_utime.tv_nsec;
624         usage.pr_stime.tv_sec  = pstatus.pr_stime.tv_sec;
625         usage.pr_stime.tv_nsec = pstatus.pr_stime.tv_nsec;
626     }
627 
628     proctime->user = TIMESTRUCT_2MSEC(usage.pr_utime);
629     proctime->sys  = TIMESTRUCT_2MSEC(usage.pr_stime);
630     proctime->total = proctime->user + proctime->sys;
631 
632     return SIGAR_OK;
633 }
634 
sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_state_t *procstate)635 int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid,
636                          sigar_proc_state_t *procstate)
637 {
638     int status = sigar_proc_psinfo_get(sigar, pid);
639     psinfo_t *pinfo = sigar->pinfo;
640 
641     if (status != SIGAR_OK) {
642         return status;
643     }
644 
645     SIGAR_SSTRCPY(procstate->name, pinfo->pr_fname);
646     procstate->ppid = pinfo->pr_ppid;
647     procstate->tty  = pinfo->pr_ttydev;
648     procstate->priority = pinfo->pr_lwp.pr_pri;
649     procstate->nice     = pinfo->pr_lwp.pr_nice - NZERO;
650     procstate->threads  = pinfo->pr_nlwp;
651     procstate->processor = pinfo->pr_lwp.pr_onpro;
652 
653     switch (pinfo->pr_lwp.pr_state) {
654       case SONPROC:
655       case SRUN:
656         procstate->state = 'R';
657         break;
658       case SZOMB:
659         procstate->state = 'Z';
660         break;
661       case SSLEEP:
662         procstate->state = 'S';
663         break;
664       case SSTOP:
665         procstate->state = 'T';
666         break;
667       case SIDL:
668         procstate->state = 'D';
669         break;
670     }
671 
672     return SIGAR_OK;
673 }
674 
675 #include <sys/mnttab.h>
676 
sigar_os_fs_type_get(sigar_file_system_t *fsp)677 int sigar_os_fs_type_get(sigar_file_system_t *fsp)
678 {
679     char *type = fsp->sys_type_name;
680 
681     switch (*type) {
682       case 'u':
683         if (strEQ(type, "ufs")) {
684             fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
685         }
686         break;
687         /* XXX */
688     }
689 
690     return fsp->type;
691 }
692 
sigar_file_system_list_get(sigar_t *sigar, sigar_file_system_list_t *fslist)693 int sigar_file_system_list_get(sigar_t *sigar,
694                                sigar_file_system_list_t *fslist)
695 {
696     struct mnttab ent;
697     sigar_file_system_t *fsp;
698     FILE *fp = fopen(MNTTAB, "r");
699 
700     if (!fp) {
701         return errno;
702     }
703 
704     sigar_file_system_list_create(fslist);
705 
706     while (getmntent(fp, &ent) == 0) {
707         if (strstr(ent.mnt_mntopts, "ignore")) {
708             continue; /* e.g. vold */
709         }
710 
711         SIGAR_FILE_SYSTEM_LIST_GROW(fslist);
712 
713         fsp = &fslist->data[fslist->number++];
714 
715         SIGAR_SSTRCPY(fsp->dir_name, ent.mnt_mountp);
716         SIGAR_SSTRCPY(fsp->dev_name, ent.mnt_special);
717         SIGAR_SSTRCPY(fsp->sys_type_name, ent.mnt_fstype);
718         SIGAR_SSTRCPY(fsp->options, ent.mnt_mntopts);
719         sigar_fs_type_init(fsp);
720     }
721 
722     fclose(fp);
723 
724     return SIGAR_OK;
725 }
726 
sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, sigar_net_interface_config_t *ifconfig)727 int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name,
728                                         sigar_net_interface_config_t *ifconfig)
729 {
730     int sock;
731     struct lifreq lifr;
732 
733     if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
734         return errno;
735     }
736 
737     SIGAR_SSTRCPY(lifr.lifr_name, name);
738 
739     if (ioctl(sock, SIOCGLIFADDR, &lifr) == 0) {
740         struct in6_addr *addr = SIGAR_SIN6_ADDR(&lifr.lifr_addr);
741 
742         sigar_net_address6_set(ifconfig->address6, addr);
743         sigar_net_interface_scope6_set(ifconfig, addr);
744         ifconfig->prefix6_length = lifr.lifr_addrlen;
745     }
746 
747     close(sock);
748     return SIGAR_OK;
749 }
750 
751 #define TCPQ_SIZE(s) ((s) >= 0 ? (s) : 0)
752 
tcp_connection_get(sigar_net_connection_walker_t *walker, struct mib2_tcpConnEntry *entry, int len)753 static int tcp_connection_get(sigar_net_connection_walker_t *walker,
754                               struct mib2_tcpConnEntry *entry,
755                               int len)
756 {
757     int flags = walker->flags;
758     int status;
759     char *end = (char *)entry + len;
760 
761     while ((char *)entry < end) {
762         int state = entry->tcpConnEntryInfo.ce_state;
763 
764         if (((flags & SIGAR_NETCONN_SERVER) && (state == TCPS_LISTEN)) ||
765             ((flags & SIGAR_NETCONN_CLIENT) && (state != TCPS_LISTEN)))
766         {
767             sigar_net_connection_t conn;
768 
769             SIGAR_ZERO(&conn);
770 
771             sigar_net_address_set(conn.local_address, entry->tcpConnLocalAddress);
772             sigar_net_address_set(conn.remote_address, entry->tcpConnRemAddress);
773 
774             conn.local_port = entry->tcpConnLocalPort;
775             conn.remote_port = entry->tcpConnRemPort;
776             conn.type = SIGAR_NETCONN_TCP;
777             conn.send_queue =
778                 TCPQ_SIZE(entry->tcpConnEntryInfo.ce_snxt -
779                           entry->tcpConnEntryInfo.ce_suna - 1);
780             conn.receive_queue =
781                 TCPQ_SIZE(entry->tcpConnEntryInfo.ce_rnxt -
782                           entry->tcpConnEntryInfo.ce_rack);
783 
784             switch (state) {
785               case TCPS_CLOSED:
786                 conn.state = SIGAR_TCP_CLOSE;
787                 break;
788               case TCPS_IDLE:
789                 conn.state = SIGAR_TCP_IDLE;
790                 break;
791               case TCPS_BOUND:
792                 conn.state = SIGAR_TCP_BOUND;
793                 break;
794               case TCPS_LISTEN:
795                 conn.state = SIGAR_TCP_LISTEN;
796                 break;
797               case TCPS_SYN_SENT:
798                 conn.state = SIGAR_TCP_SYN_SENT;
799                 break;
800               case TCPS_SYN_RCVD:
801                 conn.state = SIGAR_TCP_SYN_RECV;
802                 break;
803               case TCPS_ESTABLISHED:
804                 conn.state = SIGAR_TCP_ESTABLISHED;
805                 break;
806               case TCPS_CLOSE_WAIT:
807                 conn.state = SIGAR_TCP_CLOSE_WAIT;
808                 break;
809               case TCPS_FIN_WAIT_1:
810                 conn.state = SIGAR_TCP_FIN_WAIT1;
811                 break;
812               case TCPS_CLOSING:
813                 conn.state = SIGAR_TCP_CLOSING;
814                 break;
815               case TCPS_LAST_ACK:
816                 conn.state = SIGAR_TCP_LAST_ACK;
817                 break;
818               case TCPS_FIN_WAIT_2:
819                 conn.state = SIGAR_TCP_FIN_WAIT2;
820                 break;
821               case TCPS_TIME_WAIT:
822                 conn.state = SIGAR_TCP_TIME_WAIT;
823                 break;
824               default:
825                 conn.state = SIGAR_TCP_UNKNOWN;
826                 break;
827             }
828 
829             status = walker->add_connection(walker, &conn);
830             if (status != SIGAR_OK) {
831                 return status;
832             }
833         }
834 
835         entry++;
836     }
837 
838     return SIGAR_OK;
839 }
840 
udp_connection_get(sigar_net_connection_walker_t *walker, struct mib2_udpEntry *entry, int len)841 static int udp_connection_get(sigar_net_connection_walker_t *walker,
842                               struct mib2_udpEntry *entry,
843                               int len)
844 {
845     int flags = walker->flags;
846     int status;
847     char *end = (char *)entry + len;
848 
849     while ((char *)entry < end) {
850         int state = entry->udpEntryInfo.ue_state;
851 
852         /* XXX dunno if this state check is right */
853         if (((flags & SIGAR_NETCONN_SERVER) && (state == MIB2_UDP_idle)) ||
854             ((flags & SIGAR_NETCONN_CLIENT) && (state != MIB2_UDP_idle)))
855         {
856             sigar_net_connection_t conn;
857 
858             SIGAR_ZERO(&conn);
859 
860             sigar_net_address_set(conn.local_address, entry->udpLocalAddress);
861             sigar_net_address_set(conn.remote_address, 0);
862 
863             conn.local_port = entry->udpLocalPort;
864             conn.remote_port = 0;
865             conn.type = SIGAR_NETCONN_UDP;
866 
867             status = walker->add_connection(walker, &conn);
868             if (status != SIGAR_OK) {
869                 return status;
870             }
871         }
872 
873         entry++;
874     }
875 
876     return SIGAR_OK;
877 }
878 
sigar_net_connection_walk(sigar_net_connection_walker_t *walker)879 int sigar_net_connection_walk(sigar_net_connection_walker_t *walker)
880 {
881     sigar_t *sigar = walker->sigar;
882     int flags = walker->flags;
883     int status;
884     int want_tcp = flags & SIGAR_NETCONN_TCP;
885     int want_udp = flags & SIGAR_NETCONN_UDP;
886     char *data;
887     int len;
888     int rc;
889     struct opthdr *op;
890 
891     while ((rc = get_mib2(&sigar->mib2, &op, &data, &len)) == GET_MIB2_OK) {
892         if ((op->level == MIB2_TCP) &&
893             (op->name == MIB2_TCP_13) &&
894             want_tcp)
895         {
896             status =
897                 tcp_connection_get(walker,
898                                    (struct mib2_tcpConnEntry *)data,
899                                    len);
900         }
901         else if ((op->level == MIB2_UDP) &&
902                  (op->name == MIB2_UDP_5) &&
903                  want_udp)
904         {
905             status =
906                 udp_connection_get(walker,
907                                    (struct mib2_udpEntry *)data,
908                                    len);
909         }
910         else {
911             status = SIGAR_OK;
912         }
913 
914         if (status != SIGAR_OK) {
915             break;
916         }
917     }
918 
919     if (rc != GET_MIB2_EOD) {
920         close_mib2(&sigar->mib2);
921         return SIGAR_EMIB2;
922     }
923 
924     return SIGAR_OK;
925 }
926