1 /*
2  * Copyright (c) 2004-2009 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 <errno.h>
20 #include <stdio.h>
21 
22 #ifndef WIN32
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <sys/time.h>
26 #endif
27 #if defined(__OpenBSD__) || defined(__FreeBSD__)
28 #include <netinet/in.h>
29 #endif
30 #ifndef WIN32
31 #include <arpa/inet.h>
32 #endif
33 
34 #include "sigar.h"
35 #include "sigar_private.h"
36 #include "sigar_util.h"
37 #include "sigar_os.h"
38 #include "sigar_format.h"
39 
sigar_open(sigar_t **sigar)40 SIGAR_DECLARE(int) sigar_open(sigar_t **sigar)
41 {
42     int status = sigar_os_open(sigar);
43 
44     if (status == SIGAR_OK) {
45         /* use env to revert to old behavior */
46         (*sigar)->cpu_list_cores = getenv("SIGAR_CPU_LIST_SOCKETS") ? 0 : 1;
47         (*sigar)->pid = 0;
48         (*sigar)->ifconf_buf = NULL;
49         (*sigar)->ifconf_len = 0;
50         (*sigar)->log_level = -1; /* log nothing by default */
51         (*sigar)->log_impl = NULL;
52         (*sigar)->log_data = NULL;
53         (*sigar)->ptql_re_impl = NULL;
54         (*sigar)->ptql_re_data = NULL;
55         (*sigar)->self_path = NULL;
56         (*sigar)->fsdev = NULL;
57         (*sigar)->pids = NULL;
58         (*sigar)->proc_cpu = NULL;
59         (*sigar)->net_listen = NULL;
60         (*sigar)->net_services_tcp = NULL;
61         (*sigar)->net_services_udp = NULL;
62     }
63 
64     return status;
65 }
66 
sigar_close(sigar_t *sigar)67 SIGAR_DECLARE(int) sigar_close(sigar_t *sigar)
68 {
69     if (sigar->ifconf_buf) {
70         free(sigar->ifconf_buf);
71     }
72     if (sigar->self_path) {
73         free(sigar->self_path);
74     }
75     if (sigar->pids) {
76         sigar_proc_list_destroy(sigar, sigar->pids);
77         free(sigar->pids);
78     }
79     if (sigar->fsdev) {
80         sigar_cache_destroy(sigar->fsdev);
81     }
82     if (sigar->proc_cpu) {
83         sigar_cache_destroy(sigar->proc_cpu);
84     }
85     if (sigar->net_listen) {
86         sigar_cache_destroy(sigar->net_listen);
87     }
88     if (sigar->net_services_tcp) {
89         sigar_cache_destroy(sigar->net_services_tcp);
90     }
91     if (sigar->net_services_udp) {
92         sigar_cache_destroy(sigar->net_services_udp);
93     }
94 
95     return sigar_os_close(sigar);
96 }
97 
98 #ifndef __linux__ /* linux has a special case */
SIGAR_DECLAREnull99 SIGAR_DECLARE(sigar_pid_t) sigar_pid_get(sigar_t *sigar)
100 {
101     if (!sigar->pid) {
102         sigar->pid = getpid();
103     }
104 
105     return sigar->pid;
106 }
107 #endif
108 
109 /* XXX: add clear() function */
110 /* XXX: check for stale-ness using start_time */
sigar_proc_cpu_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_cpu_t *proccpu)111 SIGAR_DECLARE(int) sigar_proc_cpu_get(sigar_t *sigar, sigar_pid_t pid,
112                                       sigar_proc_cpu_t *proccpu)
113 {
114     sigar_cache_entry_t *entry;
115     sigar_proc_cpu_t *prev;
116     sigar_uint64_t otime, time_now = sigar_time_now_millis();
117     sigar_uint64_t time_diff, total_diff;
118     int status;
119 
120     if (!sigar->proc_cpu) {
121         sigar->proc_cpu = sigar_cache_new(128);
122     }
123 
124     entry = sigar_cache_get(sigar->proc_cpu, pid);
125     if (entry->value) {
126         prev = (sigar_proc_cpu_t *)entry->value;
127     }
128     else {
129         prev = entry->value = malloc(sizeof(*prev));
130         SIGAR_ZERO(prev);
131     }
132 
133     time_diff = time_now - prev->last_time;
134     proccpu->last_time = prev->last_time = time_now;
135 
136     if (time_diff == 0) {
137         /* we were just called within < 1 second ago. */
138         memcpy(proccpu, prev, sizeof(*proccpu));
139         return SIGAR_OK;
140     }
141 
142     otime = prev->total;
143 
144     status =
145         sigar_proc_time_get(sigar, pid,
146                             (sigar_proc_time_t *)proccpu);
147 
148     if (status != SIGAR_OK) {
149         return status;
150     }
151 
152     memcpy(prev, proccpu, sizeof(*prev));
153 
154     if (proccpu->total < otime) {
155         /* XXX this should not happen */
156         otime = 0;
157     }
158 
159     if (otime == 0) {
160         proccpu->percent = 0.0;
161         /* first time called */
162         return SIGAR_OK;
163     }
164 
165     total_diff = proccpu->total - otime;
166     proccpu->percent = total_diff / (double)time_diff;
167 
168     return SIGAR_OK;
169 }
170 
sigar_proc_stat_get(sigar_t *sigar, sigar_proc_stat_t *procstat)171 SIGAR_DECLARE(int) sigar_proc_stat_get(sigar_t *sigar,
172                                        sigar_proc_stat_t *procstat)
173 {
174     int status, i;
175     sigar_proc_list_t *pids;
176 
177     SIGAR_ZERO(procstat);
178     procstat->threads = SIGAR_FIELD_NOTIMPL;
179 
180     if ((status = sigar_proc_list_get(sigar, NULL)) != SIGAR_OK) {
181         return status;
182     }
183 
184     pids = sigar->pids;
185     procstat->total = pids->number;
186 
187     for (i=0; i<pids->number; i++) {
188         sigar_proc_state_t state;
189 
190         status = sigar_proc_state_get(sigar, pids->data[i], &state);
191         if (status != SIGAR_OK) {
192             continue;
193         }
194 
195         if (state.threads != SIGAR_FIELD_NOTIMPL) {
196             procstat->threads += state.threads;
197         }
198 
199         switch (state.state) {
200           case SIGAR_PROC_STATE_IDLE:
201             procstat->idle++;
202             break;
203           case SIGAR_PROC_STATE_RUN:
204             procstat->running++;
205             break;
206           case SIGAR_PROC_STATE_SLEEP:
207             procstat->sleeping++;
208             break;
209           case SIGAR_PROC_STATE_STOP:
210             procstat->stopped++;
211             break;
212           case SIGAR_PROC_STATE_ZOMBIE:
213             procstat->zombie++;
214             break;
215           default:
216             break;
217         }
218     }
219 
220     return SIGAR_OK;
221 }
222 
sigar_sys_info_get(sigar_t *sigar, sigar_sys_info_t *sysinfo)223 SIGAR_DECLARE(int) sigar_sys_info_get(sigar_t *sigar,
224                                       sigar_sys_info_t *sysinfo)
225 {
226     SIGAR_ZERO(sysinfo);
227 
228 #ifndef WIN32
229     sigar_sys_info_get_uname(sysinfo);
230 #endif
231 
232     sigar_os_sys_info_get(sigar, sysinfo);
233 
234     return SIGAR_OK;
235 }
236 
237 #ifndef WIN32
238 
239 #include <sys/utsname.h>
240 
sigar_sys_info_get_uname(sigar_sys_info_t *sysinfo)241 int sigar_sys_info_get_uname(sigar_sys_info_t *sysinfo)
242 {
243     struct utsname name;
244 
245     uname(&name);
246 
247     SIGAR_SSTRCPY(sysinfo->version, name.release);
248     SIGAR_SSTRCPY(sysinfo->vendor_name, name.sysname);
249     SIGAR_SSTRCPY(sysinfo->name, name.sysname);
250     SIGAR_SSTRCPY(sysinfo->machine, name.machine);
251     SIGAR_SSTRCPY(sysinfo->arch, name.machine);
252     SIGAR_SSTRCPY(sysinfo->patch_level, "unknown");
253 
254     return SIGAR_OK;
255 }
256 
257 SIGAR_DECLARE(int)
sigar_proc_cred_name_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_cred_name_t *proccredname)258 sigar_proc_cred_name_get(sigar_t *sigar, sigar_pid_t pid,
259                          sigar_proc_cred_name_t *proccredname)
260 {
261     sigar_proc_cred_t cred;
262 
263     int status = sigar_proc_cred_get(sigar, pid, &cred);
264 
265     if (status != SIGAR_OK) {
266         return status;
267     }
268 
269     status = sigar_user_name_get(sigar, cred.uid,
270                                  proccredname->user,
271                                  sizeof(proccredname->user));
272 
273     if (status != SIGAR_OK) {
274         return status;
275     }
276 
277     status = sigar_group_name_get(sigar, cred.gid,
278                                   proccredname->group,
279                                   sizeof(proccredname->group));
280 
281     return status;
282 }
283 
284 #endif /* WIN32 */
285 
sigar_proc_list_create(sigar_proc_list_t *proclist)286 int sigar_proc_list_create(sigar_proc_list_t *proclist)
287 {
288     proclist->number = 0;
289     proclist->size = SIGAR_PROC_LIST_MAX;
290     proclist->data = malloc(sizeof(*(proclist->data)) *
291                             proclist->size);
292     return SIGAR_OK;
293 }
294 
sigar_proc_list_grow(sigar_proc_list_t *proclist)295 int sigar_proc_list_grow(sigar_proc_list_t *proclist)
296 {
297     proclist->data = realloc(proclist->data,
298                              sizeof(*(proclist->data)) *
299                              (proclist->size + SIGAR_PROC_LIST_MAX));
300     proclist->size += SIGAR_PROC_LIST_MAX;
301 
302     return SIGAR_OK;
303 }
304 
sigar_proc_list_destroy(sigar_t *sigar, sigar_proc_list_t *proclist)305 SIGAR_DECLARE(int) sigar_proc_list_destroy(sigar_t *sigar,
306                                            sigar_proc_list_t *proclist)
307 {
308     if (proclist->size) {
309         free(proclist->data);
310         proclist->number = proclist->size = 0;
311     }
312 
313     return SIGAR_OK;
314 }
315 
sigar_proc_list_get(sigar_t *sigar, sigar_proc_list_t *proclist)316 SIGAR_DECLARE(int) sigar_proc_list_get(sigar_t *sigar,
317                                        sigar_proc_list_t *proclist)
318 {
319     if (proclist == NULL) {
320         /* internal re-use */
321         if (sigar->pids == NULL) {
322             sigar->pids = malloc(sizeof(*sigar->pids));
323             sigar_proc_list_create(sigar->pids);
324         }
325         else {
326             sigar->pids->number = 0;
327         }
328         proclist = sigar->pids;
329     }
330     else {
331         sigar_proc_list_create(proclist);
332     }
333 
334     return sigar_os_proc_list_get(sigar, proclist);
335 }
336 
sigar_proc_args_create(sigar_proc_args_t *procargs)337 int sigar_proc_args_create(sigar_proc_args_t *procargs)
338 {
339     procargs->number = 0;
340     procargs->size = SIGAR_PROC_ARGS_MAX;
341     procargs->data = malloc(sizeof(*(procargs->data)) *
342                             procargs->size);
343     return SIGAR_OK;
344 }
345 
sigar_proc_args_grow(sigar_proc_args_t *procargs)346 int sigar_proc_args_grow(sigar_proc_args_t *procargs)
347 {
348     procargs->data = realloc(procargs->data,
349                              sizeof(*(procargs->data)) *
350                              (procargs->size + SIGAR_PROC_ARGS_MAX));
351     procargs->size += SIGAR_PROC_ARGS_MAX;
352 
353     return SIGAR_OK;
354 }
355 
sigar_proc_args_destroy(sigar_t *sigar, sigar_proc_args_t *procargs)356 SIGAR_DECLARE(int) sigar_proc_args_destroy(sigar_t *sigar,
357                                            sigar_proc_args_t *procargs)
358 {
359     unsigned int i;
360 
361     if (procargs->size) {
362         for (i=0; i<procargs->number; i++) {
363             free(procargs->data[i]);
364         }
365         free(procargs->data);
366         procargs->number = procargs->size = 0;
367     }
368 
369     return SIGAR_OK;
370 }
371 
sigar_proc_args_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_args_t *procargs)372 SIGAR_DECLARE(int) sigar_proc_args_get(sigar_t *sigar,
373                                        sigar_pid_t pid,
374                                        sigar_proc_args_t *procargs)
375 {
376     int status;
377     sigar_proc_args_create(procargs);
378     status = sigar_os_proc_args_get(sigar, pid, procargs);
379     if (status != SIGAR_OK) {
380         sigar_proc_args_destroy(sigar, procargs);
381     }
382     return status;
383 }
384 
sigar_file_system_list_create(sigar_file_system_list_t *fslist)385 int sigar_file_system_list_create(sigar_file_system_list_t *fslist)
386 {
387     fslist->number = 0;
388     fslist->size = SIGAR_FS_MAX;
389     fslist->data = malloc(sizeof(*(fslist->data)) *
390                           fslist->size);
391     return SIGAR_OK;
392 }
393 
sigar_file_system_list_grow(sigar_file_system_list_t *fslist)394 int sigar_file_system_list_grow(sigar_file_system_list_t *fslist)
395 {
396     fslist->data = realloc(fslist->data,
397                            sizeof(*(fslist->data)) *
398                            (fslist->size + SIGAR_FS_MAX));
399     fslist->size += SIGAR_FS_MAX;
400 
401     return SIGAR_OK;
402 }
403 
404 /* indexed with sigar_file_system_type_e */
405 static const char *fstype_names[] = {
406     "unknown", "none", "local", "remote", "ram", "cdrom", "swap"
407 };
408 
sigar_common_fs_type_get(sigar_file_system_t *fsp)409 static int sigar_common_fs_type_get(sigar_file_system_t *fsp)
410 {
411     char *type = fsp->sys_type_name;
412 
413     switch (*type) {
414       case 'n':
415         if (strnEQ(type, "nfs", 3)) {
416             fsp->type = SIGAR_FSTYPE_NETWORK;
417         }
418         break;
419       case 's':
420         if (strEQ(type, "smbfs")) { /* samba */
421             fsp->type = SIGAR_FSTYPE_NETWORK;
422         }
423         else if (strEQ(type, "swap")) {
424             fsp->type = SIGAR_FSTYPE_SWAP;
425         }
426         break;
427       case 'a':
428         if (strEQ(type, "afs")) {
429             fsp->type = SIGAR_FSTYPE_NETWORK;
430         }
431         break;
432       case 'i':
433         if (strEQ(type, "iso9660")) {
434             fsp->type = SIGAR_FSTYPE_CDROM;
435         }
436         break;
437       case 'c':
438         if (strEQ(type, "cvfs")) {
439             fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
440         }
441         else if (strEQ(type, "cifs")) {
442             fsp->type = SIGAR_FSTYPE_NETWORK;
443         }
444         break;
445       case 'm':
446         if (strEQ(type, "msdos") || strEQ(type, "minix")) {
447             fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
448         }
449         break;
450       case 'h':
451         if (strEQ(type, "hpfs")) {
452             fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
453         }
454         break;
455       case 'v':
456         if (strEQ(type, "vxfs")) {
457             fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
458         }
459         else if (strEQ(type, "vfat")) {
460             fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
461         }
462         break;
463       case 'z':
464         if (strEQ(type, "zfs")) {
465             fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
466         }
467         break;
468     }
469 
470     return fsp->type;
471 }
472 
sigar_fs_type_get(sigar_file_system_t *fsp)473 void sigar_fs_type_get(sigar_file_system_t *fsp)
474 {
475     if (!(fsp->type ||                    /* already set */
476           sigar_os_fs_type_get(fsp) ||    /* try os specifics first */
477           sigar_common_fs_type_get(fsp))) /* try common ones last */
478     {
479         fsp->type = SIGAR_FSTYPE_NONE;
480     }
481 
482     if (fsp->type >= SIGAR_FSTYPE_MAX) {
483         fsp->type = SIGAR_FSTYPE_NONE;
484     }
485 
486     strcpy(fsp->type_name, fstype_names[fsp->type]);
487 }
488 
489 
490 SIGAR_DECLARE(int)
sigar_file_system_list_destroy(sigar_t *sigar, sigar_file_system_list_t *fslist)491 sigar_file_system_list_destroy(sigar_t *sigar,
492                                sigar_file_system_list_t *fslist)
493 {
494     if (fslist->size) {
495         free(fslist->data);
496         fslist->number = fslist->size = 0;
497     }
498 
499     return SIGAR_OK;
500 }
501 
502 #ifndef NFS_PROGRAM
503 #define NFS_PROGRAM 100003
504 #endif
505 
506 #ifndef NFS_VERSION
507 #define NFS_VERSION 2
508 #endif
509 
510 SIGAR_DECLARE(int)
sigar_file_system_ping(sigar_t *sigar, sigar_file_system_t *fs)511 sigar_file_system_ping(sigar_t *sigar,
512                        sigar_file_system_t *fs)
513 {
514     int status = SIGAR_OK;
515 #ifndef WIN32
516     char *ptr;
517 
518     if ((fs->type == SIGAR_FSTYPE_NETWORK) &&
519         strEQ(fs->sys_type_name, "nfs") &&
520         (ptr = strchr(fs->dev_name, ':')))
521     {
522         *ptr = '\0'; /* "hostname:/mount" -> "hostname" */
523 
524         status = sigar_rpc_ping(fs->dev_name,
525                                 SIGAR_NETCONN_UDP,
526                                 NFS_PROGRAM, NFS_VERSION);
527 
528         if (SIGAR_LOG_IS_DEBUG(sigar)) {
529             sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
530                              "[fs_ping] %s -> %s: %s",
531                              fs->dir_name, fs->dev_name,
532                              ((status == SIGAR_OK) ?
533                               "OK" : sigar_rpc_strerror(status)));
534         }
535 
536         *ptr = ':'; /* "hostname" -> "hostname:/mount" */
537     }
538 #endif
539     return status;
540 }
541 
sigar_cpu_info_list_create(sigar_cpu_info_list_t *cpu_infos)542 int sigar_cpu_info_list_create(sigar_cpu_info_list_t *cpu_infos)
543 {
544     cpu_infos->number = 0;
545     cpu_infos->size = SIGAR_CPU_INFO_MAX;
546     cpu_infos->data = malloc(sizeof(*(cpu_infos->data)) *
547                              cpu_infos->size);
548     return SIGAR_OK;
549 }
550 
sigar_cpu_info_list_grow(sigar_cpu_info_list_t *cpu_infos)551 int sigar_cpu_info_list_grow(sigar_cpu_info_list_t *cpu_infos)
552 {
553     cpu_infos->data = realloc(cpu_infos->data,
554                               sizeof(*(cpu_infos->data)) *
555                               (cpu_infos->size + SIGAR_CPU_INFO_MAX));
556     cpu_infos->size += SIGAR_CPU_INFO_MAX;
557 
558     return SIGAR_OK;
559 }
560 
561 SIGAR_DECLARE(int)
sigar_cpu_info_list_destroy(sigar_t *sigar, sigar_cpu_info_list_t *cpu_infos)562 sigar_cpu_info_list_destroy(sigar_t *sigar,
563                             sigar_cpu_info_list_t *cpu_infos)
564 {
565     if (cpu_infos->size) {
566         free(cpu_infos->data);
567         cpu_infos->number = cpu_infos->size = 0;
568     }
569 
570     return SIGAR_OK;
571 }
572 
sigar_cpu_list_create(sigar_cpu_list_t *cpulist)573 int sigar_cpu_list_create(sigar_cpu_list_t *cpulist)
574 {
575     cpulist->number = 0;
576     cpulist->size = SIGAR_CPU_INFO_MAX;
577     cpulist->data = malloc(sizeof(*(cpulist->data)) *
578                            cpulist->size);
579     return SIGAR_OK;
580 }
581 
sigar_cpu_list_grow(sigar_cpu_list_t *cpulist)582 int sigar_cpu_list_grow(sigar_cpu_list_t *cpulist)
583 {
584     cpulist->data = realloc(cpulist->data,
585                             sizeof(*(cpulist->data)) *
586                             (cpulist->size + SIGAR_CPU_INFO_MAX));
587     cpulist->size += SIGAR_CPU_INFO_MAX;
588 
589     return SIGAR_OK;
590 }
591 
sigar_cpu_list_destroy(sigar_t *sigar, sigar_cpu_list_t *cpulist)592 SIGAR_DECLARE(int) sigar_cpu_list_destroy(sigar_t *sigar,
593                                           sigar_cpu_list_t *cpulist)
594 {
595     if (cpulist->size) {
596         free(cpulist->data);
597         cpulist->number = cpulist->size = 0;
598     }
599 
600     return SIGAR_OK;
601 }
602 
sigar_net_route_list_create(sigar_net_route_list_t *routelist)603 int sigar_net_route_list_create(sigar_net_route_list_t *routelist)
604 {
605     routelist->number = 0;
606     routelist->size = SIGAR_NET_ROUTE_LIST_MAX;
607     routelist->data = malloc(sizeof(*(routelist->data)) *
608                              routelist->size);
609     return SIGAR_OK;
610 }
611 
sigar_net_route_list_grow(sigar_net_route_list_t *routelist)612 int sigar_net_route_list_grow(sigar_net_route_list_t *routelist)
613 {
614     routelist->data =
615         realloc(routelist->data,
616                 sizeof(*(routelist->data)) *
617                 (routelist->size + SIGAR_NET_ROUTE_LIST_MAX));
618     routelist->size += SIGAR_NET_ROUTE_LIST_MAX;
619 
620     return SIGAR_OK;
621 }
622 
sigar_net_route_list_destroy(sigar_t *sigar, sigar_net_route_list_t *routelist)623 SIGAR_DECLARE(int) sigar_net_route_list_destroy(sigar_t *sigar,
624                                                 sigar_net_route_list_t *routelist)
625 {
626     if (routelist->size) {
627         free(routelist->data);
628         routelist->number = routelist->size = 0;
629     }
630 
631     return SIGAR_OK;
632 }
633 
sigar_net_interface_list_create(sigar_net_interface_list_t *iflist)634 int sigar_net_interface_list_create(sigar_net_interface_list_t *iflist)
635 {
636     iflist->number = 0;
637     iflist->size = SIGAR_NET_IFLIST_MAX;
638     iflist->data = malloc(sizeof(*(iflist->data)) *
639                           iflist->size);
640     return SIGAR_OK;
641 }
642 
sigar_net_interface_list_grow(sigar_net_interface_list_t *iflist)643 int sigar_net_interface_list_grow(sigar_net_interface_list_t *iflist)
644 {
645     iflist->data = realloc(iflist->data,
646                            sizeof(*(iflist->data)) *
647                            (iflist->size + SIGAR_NET_IFLIST_MAX));
648     iflist->size += SIGAR_NET_IFLIST_MAX;
649 
650     return SIGAR_OK;
651 }
652 
653 SIGAR_DECLARE(int)
sigar_net_interface_list_destroy(sigar_t *sigar, sigar_net_interface_list_t *iflist)654 sigar_net_interface_list_destroy(sigar_t *sigar,
655                                  sigar_net_interface_list_t *iflist)
656 {
657     unsigned int i;
658 
659     if (iflist->size) {
660         for (i=0; i<iflist->number; i++) {
661             free(iflist->data[i]);
662         }
663         free(iflist->data);
664         iflist->number = iflist->size = 0;
665     }
666 
667     return SIGAR_OK;
668 }
669 
sigar_net_connection_list_create(sigar_net_connection_list_t *connlist)670 int sigar_net_connection_list_create(sigar_net_connection_list_t *connlist)
671 {
672     connlist->number = 0;
673     connlist->size = SIGAR_NET_CONNLIST_MAX;
674     connlist->data = malloc(sizeof(*(connlist->data)) *
675                             connlist->size);
676     return SIGAR_OK;
677 }
678 
sigar_net_connection_list_grow(sigar_net_connection_list_t *connlist)679 int sigar_net_connection_list_grow(sigar_net_connection_list_t *connlist)
680 {
681     connlist->data =
682         realloc(connlist->data,
683                 sizeof(*(connlist->data)) *
684                 (connlist->size + SIGAR_NET_CONNLIST_MAX));
685     connlist->size += SIGAR_NET_CONNLIST_MAX;
686 
687     return SIGAR_OK;
688 }
689 
690 SIGAR_DECLARE(int)
sigar_net_connection_list_destroy(sigar_t *sigar, sigar_net_connection_list_t *connlist)691 sigar_net_connection_list_destroy(sigar_t *sigar,
692                                   sigar_net_connection_list_t *connlist)
693 {
694     if (connlist->size) {
695         free(connlist->data);
696         connlist->number = connlist->size = 0;
697     }
698 
699     return SIGAR_OK;
700 }
701 
702 #if !defined(__linux__)
703 /*
704  * implement sigar_net_connection_list_get using sigar_net_connection_walk
705  * linux has its own list_get impl.
706  */
net_connection_list_walker(sigar_net_connection_walker_t *walker, sigar_net_connection_t *conn)707 static int net_connection_list_walker(sigar_net_connection_walker_t *walker,
708                                       sigar_net_connection_t *conn)
709 {
710     sigar_net_connection_list_t *connlist =
711         (sigar_net_connection_list_t *)walker->data;
712 
713     SIGAR_NET_CONNLIST_GROW(connlist);
714     memcpy(&connlist->data[connlist->number++],
715            conn, sizeof(*conn));
716 
717     return SIGAR_OK; /* continue loop */
718 }
719 
720 SIGAR_DECLARE(int)
sigar_net_connection_list_get(sigar_t *sigar, sigar_net_connection_list_t *connlist, int flags)721 sigar_net_connection_list_get(sigar_t *sigar,
722                               sigar_net_connection_list_t *connlist,
723                               int flags)
724 {
725     int status;
726     sigar_net_connection_walker_t walker;
727 
728     sigar_net_connection_list_create(connlist);
729 
730     walker.sigar = sigar;
731     walker.flags = flags;
732     walker.data = connlist;
733     walker.add_connection = net_connection_list_walker;
734 
735     status = sigar_net_connection_walk(&walker);
736 
737     if (status != SIGAR_OK) {
738         sigar_net_connection_list_destroy(sigar, connlist);
739     }
740 
741     return status;
742 }
743 #endif
744 
sigar_net_listen_address_add(sigar_t *sigar, sigar_net_connection_t *conn)745 static void sigar_net_listen_address_add(sigar_t *sigar,
746                                          sigar_net_connection_t *conn)
747 {
748     sigar_cache_entry_t *entry =
749         sigar_cache_get(sigar->net_listen, conn->local_port);
750 
751     if (entry->value) {
752         if (conn->local_address.family == SIGAR_AF_INET6) {
753             return; /* prefer ipv4 */
754         }
755     }
756     else {
757         entry->value = malloc(sizeof(conn->local_address));
758     }
759 
760     memcpy(entry->value, &conn->local_address,
761            sizeof(conn->local_address));
762 }
763 
764 SIGAR_DECLARE(int)
sigar_net_listen_address_get(sigar_t *sigar, unsigned long port, sigar_net_address_t *address)765 sigar_net_listen_address_get(sigar_t *sigar,
766                              unsigned long port,
767                              sigar_net_address_t *address)
768 {
769     if (!sigar->net_listen ||
770         !sigar_cache_find(sigar->net_listen, port))
771     {
772         sigar_net_stat_t netstat;
773         int status =
774             sigar_net_stat_get(sigar, &netstat,
775                                SIGAR_NETCONN_SERVER|SIGAR_NETCONN_TCP);
776 
777         if (status != SIGAR_OK) {
778             return status;
779         }
780     }
781 
782     if (sigar_cache_find(sigar->net_listen, port)) {
783         void *value = sigar_cache_get(sigar->net_listen, port)->value;
784         memcpy(address, value, sizeof(*address));
785         return SIGAR_OK;
786     }
787     else {
788         return ENOENT;
789     }
790 }
791 
792 typedef struct {
793     sigar_net_stat_t *netstat;
794     sigar_net_connection_list_t *connlist;
795 } net_stat_getter_t;
796 
net_stat_walker(sigar_net_connection_walker_t *walker, sigar_net_connection_t *conn)797 static int net_stat_walker(sigar_net_connection_walker_t *walker,
798                            sigar_net_connection_t *conn)
799 {
800     int state = conn->state;
801     sigar_cache_t *listen_ports = walker->sigar->net_listen;
802     net_stat_getter_t *getter =
803         (net_stat_getter_t *)walker->data;
804 
805     if (conn->type == SIGAR_NETCONN_TCP) {
806         getter->netstat->tcp_states[state]++;
807 
808         /* XXX listen_ports may get stale */
809         if (state == SIGAR_TCP_LISTEN) {
810             sigar_net_listen_address_add(walker->sigar, conn);
811         }
812         else {
813             if (sigar_cache_find(listen_ports,
814                                  conn->local_port))
815             {
816                 getter->netstat->tcp_inbound_total++;
817             }
818             else {
819                 getter->netstat->tcp_outbound_total++;
820             }
821         }
822     }
823     else if (conn->type == SIGAR_NETCONN_UDP) {
824         /*XXX*/
825     }
826 
827     getter->netstat->all_inbound_total =
828         getter->netstat->tcp_inbound_total;
829 
830     getter->netstat->all_outbound_total =
831         getter->netstat->tcp_outbound_total;
832 
833     return SIGAR_OK;
834 }
835 
836 SIGAR_DECLARE(int)
sigar_net_stat_get(sigar_t *sigar, sigar_net_stat_t *netstat, int flags)837 sigar_net_stat_get(sigar_t *sigar,
838                    sigar_net_stat_t *netstat,
839                    int flags)
840 {
841     sigar_net_connection_walker_t walker;
842     net_stat_getter_t getter;
843 
844     if (!sigar->net_listen) {
845         sigar->net_listen = sigar_cache_new(32);
846     }
847 
848     SIGAR_ZERO(netstat);
849 
850     getter.netstat = netstat;
851 
852     walker.sigar = sigar;
853     walker.data = &getter;
854     walker.add_connection = net_stat_walker;
855 
856     walker.flags = flags;
857 
858     return sigar_net_connection_walk(&walker);
859 }
860 
861 typedef struct {
862     sigar_net_stat_t *netstat;
863     sigar_net_address_t *address;
864     unsigned long port;
865 } net_stat_port_getter_t;
866 
net_stat_port_walker(sigar_net_connection_walker_t *walker, sigar_net_connection_t *conn)867 static int net_stat_port_walker(sigar_net_connection_walker_t *walker,
868                                 sigar_net_connection_t *conn)
869 {
870     net_stat_port_getter_t *getter =
871         (net_stat_port_getter_t *)walker->data;
872     sigar_net_stat_t *netstat = getter->netstat;
873 
874     if (conn->type == SIGAR_NETCONN_TCP) {
875         if (conn->local_port == getter->port) {
876             netstat->all_inbound_total++;
877 
878             if (sigar_net_address_equals(getter->address,
879                                          &conn->local_address) == SIGAR_OK)
880             {
881                 netstat->tcp_inbound_total++;
882             }
883         }
884         else if (conn->remote_port == getter->port) {
885             netstat->all_outbound_total++;
886 
887             if (sigar_net_address_equals(getter->address,
888                                          &conn->remote_address) == SIGAR_OK)
889             {
890                 netstat->tcp_outbound_total++;
891             }
892         }
893         else {
894             return SIGAR_OK;
895         }
896 
897         netstat->tcp_states[conn->state]++;
898     }
899     else if (conn->type == SIGAR_NETCONN_UDP) {
900         /*XXX*/
901     }
902 
903     return SIGAR_OK;
904 }
905 
906 SIGAR_DECLARE(int)
sigar_net_stat_port_get(sigar_t *sigar, sigar_net_stat_t *netstat, int flags, sigar_net_address_t *address, unsigned long port)907 sigar_net_stat_port_get(sigar_t *sigar,
908                         sigar_net_stat_t *netstat,
909                         int flags,
910                         sigar_net_address_t *address,
911                         unsigned long port)
912 {
913     sigar_net_connection_walker_t walker;
914     net_stat_port_getter_t getter;
915 
916     SIGAR_ZERO(netstat);
917 
918     getter.netstat = netstat;
919     getter.address = address;
920     getter.port = port;
921 
922     walker.sigar = sigar;
923     walker.data = &getter;
924     walker.add_connection = net_stat_port_walker;
925 
926     walker.flags = flags;
927 
928     if (SIGAR_LOG_IS_DEBUG(sigar)) {
929         char name[SIGAR_FQDN_LEN];
930         sigar_net_address_to_string(sigar, address, name);
931 
932         sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
933                          "[net_stat_port] using address '%s:%d'",
934                          name, port);
935     }
936 
937     return sigar_net_connection_walk(&walker);
938 }
939 
tcp_curr_estab_count(sigar_net_connection_walker_t *walker, sigar_net_connection_t *conn)940 static int tcp_curr_estab_count(sigar_net_connection_walker_t *walker,
941                                 sigar_net_connection_t *conn)
942 {
943     if ((conn->state == SIGAR_TCP_ESTABLISHED) ||
944         (conn->state == SIGAR_TCP_CLOSE_WAIT))
945     {
946         ((sigar_tcp_t *)walker->data)->curr_estab++;
947     }
948 
949     return SIGAR_OK;
950 }
951 
952 /* TCP-MIB::tcpCurrEstab */
sigar_tcp_curr_estab(sigar_t *sigar, sigar_tcp_t *tcp)953 int sigar_tcp_curr_estab(sigar_t *sigar, sigar_tcp_t *tcp)
954 {
955     sigar_net_connection_walker_t walker;
956 
957     walker.sigar = sigar;
958     walker.data = tcp;
959     walker.add_connection = tcp_curr_estab_count;
960     walker.flags = SIGAR_NETCONN_CLIENT|SIGAR_NETCONN_TCP;
961 
962     tcp->curr_estab = 0;
963 
964     return sigar_net_connection_walk(&walker);
965 }
966 
sigar_arp_list_create(sigar_arp_list_t *arplist)967 int sigar_arp_list_create(sigar_arp_list_t *arplist)
968 {
969     arplist->number = 0;
970     arplist->size = SIGAR_ARP_LIST_MAX;
971     arplist->data = malloc(sizeof(*(arplist->data)) *
972                            arplist->size);
973     return SIGAR_OK;
974 }
975 
sigar_arp_list_grow(sigar_arp_list_t *arplist)976 int sigar_arp_list_grow(sigar_arp_list_t *arplist)
977 {
978     arplist->data = realloc(arplist->data,
979                             sizeof(*(arplist->data)) *
980                             (arplist->size + SIGAR_ARP_LIST_MAX));
981     arplist->size += SIGAR_ARP_LIST_MAX;
982 
983     return SIGAR_OK;
984 }
985 
sigar_arp_list_destroy(sigar_t *sigar, sigar_arp_list_t *arplist)986 SIGAR_DECLARE(int) sigar_arp_list_destroy(sigar_t *sigar,
987                                           sigar_arp_list_t *arplist)
988 {
989     if (arplist->size) {
990         free(arplist->data);
991         arplist->number = arplist->size = 0;
992     }
993 
994     return SIGAR_OK;
995 }
996 
sigar_who_list_create(sigar_who_list_t *wholist)997 int sigar_who_list_create(sigar_who_list_t *wholist)
998 {
999     wholist->number = 0;
1000     wholist->size = SIGAR_WHO_LIST_MAX;
1001     wholist->data = malloc(sizeof(*(wholist->data)) *
1002                            wholist->size);
1003     return SIGAR_OK;
1004 }
1005 
sigar_who_list_grow(sigar_who_list_t *wholist)1006 int sigar_who_list_grow(sigar_who_list_t *wholist)
1007 {
1008     wholist->data = realloc(wholist->data,
1009                             sizeof(*(wholist->data)) *
1010                             (wholist->size + SIGAR_WHO_LIST_MAX));
1011     wholist->size += SIGAR_WHO_LIST_MAX;
1012 
1013     return SIGAR_OK;
1014 }
1015 
sigar_who_list_destroy(sigar_t *sigar, sigar_who_list_t *wholist)1016 SIGAR_DECLARE(int) sigar_who_list_destroy(sigar_t *sigar,
1017                                           sigar_who_list_t *wholist)
1018 {
1019     if (wholist->size) {
1020         free(wholist->data);
1021         wholist->number = wholist->size = 0;
1022     }
1023 
1024     return SIGAR_OK;
1025 }
1026 
1027 #ifdef DARWIN
1028 #include <AvailabilityMacros.h>
1029 #endif
1030 #ifdef MAC_OS_X_VERSION_10_5
1031 #  if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
1032 #    define SIGAR_NO_UTMP
1033 #  endif
1034 /* else 10.4 and earlier or compiled with -mmacosx-version-min=10.3 */
1035 #endif
1036 
1037 #if defined(__sun)
1038 #  include <utmpx.h>
1039 #  define SIGAR_UTMP_FILE _UTMPX_FILE
1040 #  define ut_time ut_tv.tv_sec
1041 #elif defined(WIN32)
1042 /* XXX may not be the default */
1043 #define SIGAR_UTMP_FILE "C:\\cygwin\\var\\run\\utmp"
1044 #define UT_LINESIZE	16
1045 #define UT_NAMESIZE	16
1046 #define UT_HOSTSIZE	256
1047 #define UT_IDLEN	2
1048 #define ut_name ut_user
1049 
1050 struct utmp {
1051     short ut_type;
1052     int ut_pid;
1053     char ut_line[UT_LINESIZE];
1054     char ut_id[UT_IDLEN];
1055     time_t ut_time;
1056     char ut_user[UT_NAMESIZE];
1057     char ut_host[UT_HOSTSIZE];
1058     long ut_addr;
1059 };
1060 #elif defined(NETWARE)
getpass(const char *prompt)1061 static char *getpass(const char *prompt)
1062 {
1063     static char password[BUFSIZ];
1064 
1065     fputs(prompt, stderr);
1066     fgets((char *)&password, sizeof(password), stdin);
1067 
1068     return (char *)&password;
1069 }
1070 #elif !defined(SIGAR_NO_UTMP)
1071 #  include <utmp.h>
1072 #  ifdef UTMP_FILE
1073 #    define SIGAR_UTMP_FILE UTMP_FILE
1074 #  else
1075 #    define SIGAR_UTMP_FILE _PATH_UTMP
1076 #  endif
1077 #endif
1078 
1079 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(DARWIN)
1080 #  define ut_user ut_name
1081 #endif
1082 
1083 #ifdef DARWIN
1084 /* XXX from utmpx.h; sizeof changed in 10.5 */
1085 /* additionally, utmpx does not work on 10.4 */
1086 #define SIGAR_HAS_UTMPX
1087 #define _PATH_UTMPX     "/var/run/utmpx"
1088 #define _UTX_USERSIZE   256     /* matches MAXLOGNAME */
1089 #define _UTX_LINESIZE   32
1090 #define _UTX_IDSIZE     4
1091 #define _UTX_HOSTSIZE   256
1092 struct utmpx {
1093     char ut_user[_UTX_USERSIZE];    /* login name */
1094     char ut_id[_UTX_IDSIZE];        /* id */
1095     char ut_line[_UTX_LINESIZE];    /* tty name */
1096     pid_t ut_pid;                   /* process id creating the entry */
1097     short ut_type;                  /* type of this entry */
1098     struct timeval ut_tv;           /* time entry was created */
1099     char ut_host[_UTX_HOSTSIZE];    /* host name */
1100     __uint32_t ut_pad[16];          /* reserved for future use */
1101 };
1102 #define ut_xtime ut_tv.tv_sec
1103 #define UTMPX_USER_PROCESS      7
1104 /* end utmpx.h */
1105 #define SIGAR_UTMPX_FILE _PATH_UTMPX
1106 #endif
1107 
1108 #if !defined(NETWARE) && !defined(_AIX)
1109 
1110 #define WHOCPY(dest, src) \
1111     SIGAR_SSTRCPY(dest, src); \
1112     if (sizeof(src) < sizeof(dest)) \
1113         dest[sizeof(src)] = '\0'
1114 
1115 #ifdef SIGAR_HAS_UTMPX
sigar_who_utmpx(sigar_t *sigar, sigar_who_list_t *wholist)1116 static int sigar_who_utmpx(sigar_t *sigar,
1117                            sigar_who_list_t *wholist)
1118 {
1119     FILE *fp;
1120     struct utmpx ut;
1121 
1122     if (!(fp = fopen(SIGAR_UTMPX_FILE, "r"))) {
1123         return errno;
1124     }
1125 
1126     while (fread(&ut, sizeof(ut), 1, fp) == 1) {
1127         sigar_who_t *who;
1128 
1129         if (*ut.ut_user == '\0') {
1130             continue;
1131         }
1132 
1133 #ifdef UTMPX_USER_PROCESS
1134         if (ut.ut_type != UTMPX_USER_PROCESS) {
1135             continue;
1136         }
1137 #endif
1138 
1139         SIGAR_WHO_LIST_GROW(wholist);
1140         who = &wholist->data[wholist->number++];
1141 
1142         WHOCPY(who->user, ut.ut_user);
1143         WHOCPY(who->device, ut.ut_line);
1144         WHOCPY(who->host, ut.ut_host);
1145 
1146         who->time = ut.ut_xtime;
1147     }
1148 
1149     fclose(fp);
1150 
1151     return SIGAR_OK;
1152 }
1153 #endif
1154 
1155 #if defined(SIGAR_NO_UTMP) && defined(SIGAR_HAS_UTMPX)
1156 #define sigar_who_utmp sigar_who_utmpx
1157 #else
sigar_who_utmp(sigar_t *sigar, sigar_who_list_t *wholist)1158 static int sigar_who_utmp(sigar_t *sigar,
1159                           sigar_who_list_t *wholist)
1160 {
1161     FILE *fp;
1162 #ifdef __sun
1163     /* use futmpx w/ pid32_t for sparc64 */
1164     struct futmpx ut;
1165 #else
1166     struct utmp ut;
1167 #endif
1168     if (!(fp = fopen(SIGAR_UTMP_FILE, "r"))) {
1169 #ifdef SIGAR_HAS_UTMPX
1170         /* Darwin 10.5 */
1171         return sigar_who_utmpx(sigar, wholist);
1172 #endif
1173         return errno;
1174     }
1175 
1176     while (fread(&ut, sizeof(ut), 1, fp) == 1) {
1177         sigar_who_t *who;
1178 
1179         if (*ut.ut_name == '\0') {
1180             continue;
1181         }
1182 
1183 #ifdef USER_PROCESS
1184         if (ut.ut_type != USER_PROCESS) {
1185             continue;
1186         }
1187 #endif
1188 
1189         SIGAR_WHO_LIST_GROW(wholist);
1190         who = &wholist->data[wholist->number++];
1191 
1192         WHOCPY(who->user, ut.ut_user);
1193         WHOCPY(who->device, ut.ut_line);
1194         WHOCPY(who->host, ut.ut_host);
1195 
1196         who->time = ut.ut_time;
1197     }
1198 
1199     fclose(fp);
1200 
1201     return SIGAR_OK;
1202 }
1203 #endif /* SIGAR_NO_UTMP */
1204 #endif /* NETWARE */
1205 
1206 #if defined(WIN32)
1207 
1208 int sigar_who_list_get_win32(sigar_t *sigar,
1209                              sigar_who_list_t *wholist);
1210 
sigar_who_list_get(sigar_t *sigar, sigar_who_list_t *wholist)1211 SIGAR_DECLARE(int) sigar_who_list_get(sigar_t *sigar,
1212                                       sigar_who_list_t *wholist)
1213 {
1214     sigar_who_list_create(wholist);
1215 
1216     /* cygwin ssh */
1217     sigar_who_utmp(sigar, wholist);
1218 
1219     sigar_who_list_get_win32(sigar, wholist);
1220 
1221     return SIGAR_OK;
1222 }
1223 
sigar_resource_limit_get(sigar_t *sigar, sigar_resource_limit_t *rlimit)1224 SIGAR_DECLARE(int) sigar_resource_limit_get(sigar_t *sigar,
1225                                             sigar_resource_limit_t *rlimit)
1226 {
1227     MEMORY_BASIC_INFORMATION meminfo;
1228     memset(rlimit, 0x7fffffff, sizeof(*rlimit));
1229 
1230     if (VirtualQuery((LPCVOID)&meminfo, &meminfo, sizeof(meminfo))) {
1231         rlimit->stack_cur =
1232             (DWORD)&meminfo - (DWORD)meminfo.AllocationBase;
1233         rlimit->stack_max =
1234             ((DWORD)meminfo.BaseAddress + meminfo.RegionSize) -
1235             (DWORD)meminfo.AllocationBase;
1236     }
1237 
1238     rlimit->virtual_memory_max = rlimit->virtual_memory_cur =
1239         0x80000000UL;
1240 
1241     return SIGAR_OK;
1242 }
1243 
1244 #elif defined(NETWARE)
sigar_resource_limit_get(sigar_t *sigar, sigar_resource_limit_t *rlimit)1245 int sigar_resource_limit_get(sigar_t *sigar,
1246                              sigar_resource_limit_t *rlimit)
1247 {
1248     return SIGAR_ENOTIMPL;
1249 }
1250 
sigar_who_list_get(sigar_t *sigar, sigar_who_list_t *wholist)1251 int sigar_who_list_get(sigar_t *sigar,
1252                        sigar_who_list_t *wholist)
1253 {
1254     return SIGAR_ENOTIMPL;
1255 }
1256 #else
1257 
1258 #ifndef _AIX
sigar_who_list_get(sigar_t *sigar, sigar_who_list_t *wholist)1259 int sigar_who_list_get(sigar_t *sigar,
1260                        sigar_who_list_t *wholist)
1261 {
1262     int status;
1263 
1264     sigar_who_list_create(wholist);
1265 
1266     status = sigar_who_utmp(sigar, wholist);
1267     if (status != SIGAR_OK) {
1268         sigar_who_list_destroy(sigar, wholist);
1269         return status;
1270     }
1271 
1272     return SIGAR_OK;
1273 }
1274 #endif
1275 
sigar_get_default_gateway(sigar_t *sigar, sigar_net_info_t *netinfo)1276 static int sigar_get_default_gateway(sigar_t *sigar,
1277                                      sigar_net_info_t *netinfo)
1278 {
1279     int status, i;
1280     sigar_net_route_list_t routelist;
1281 
1282     status = sigar_net_route_list_get(sigar, &routelist);
1283     if (status != SIGAR_OK) {
1284         return status;
1285     }
1286 
1287     for (i=0; i<routelist.number; i++) {
1288         if ((routelist.data[i].flags & SIGAR_RTF_GATEWAY) &&
1289             (routelist.data[i].destination.addr.in == 0))
1290         {
1291             sigar_net_address_to_string(sigar,
1292                                         &routelist.data[i].gateway,
1293                                         netinfo->default_gateway);
1294 
1295             SIGAR_STRNCPY(netinfo->default_gateway_interface,
1296                           routelist.data[i].ifname,
1297                           sizeof(netinfo->default_gateway_interface));
1298             break;
1299         }
1300     }
1301 
1302     sigar_net_route_list_destroy(sigar, &routelist);
1303 
1304     return SIGAR_OK;
1305 }
1306 
sigar_net_info_get(sigar_t *sigar, sigar_net_info_t *netinfo)1307 int sigar_net_info_get(sigar_t *sigar,
1308                        sigar_net_info_t *netinfo)
1309 {
1310     int size;
1311     char buffer[BUFSIZ], *ptr;
1312     FILE *fp;
1313 
1314     SIGAR_ZERO(netinfo);
1315 
1316     if ((fp = fopen("/etc/resolv.conf", "r"))) {
1317         while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
1318             int len;
1319 
1320             SIGAR_SKIP_SPACE(ptr);
1321             if ((*ptr == '#') ||
1322                 !(ptr = strstr(ptr, "nameserver")))
1323             {
1324                 continue;
1325             }
1326             ptr += 10;
1327             SIGAR_SKIP_SPACE(ptr);
1328 
1329             len = strlen(ptr);
1330             ptr[len-1] = '\0'; /* chop \n */
1331 
1332             if (!netinfo->primary_dns[0]) {
1333                 SIGAR_SSTRCPY(netinfo->primary_dns, ptr);
1334             }
1335             else if (!netinfo->secondary_dns[0]) {
1336                 SIGAR_SSTRCPY(netinfo->secondary_dns, ptr);
1337             }
1338             else {
1339                 break;
1340             }
1341         }
1342         fclose(fp);
1343     } /* else /etc/resolv.conf may not exist if unplugged (MacOSX) */
1344 
1345     size = sizeof(netinfo->host_name)-1;
1346     if (gethostname(netinfo->host_name, size) == 0) {
1347         netinfo->host_name[size] = '\0';
1348     }
1349     else {
1350         netinfo->host_name[0] = '\0';
1351     }
1352 
1353     size = sizeof(netinfo->domain_name)-1;
1354     if (getdomainname(netinfo->domain_name, size) == 0) {
1355         netinfo->domain_name[size] = '\0';
1356     }
1357     else {
1358         netinfo->domain_name[0] = '\0';
1359     }
1360 
1361     sigar_get_default_gateway(sigar, netinfo);
1362 
1363     return SIGAR_OK;
1364 }
1365 
1366 #include <sys/resource.h>
1367 
1368 #define OffsetOf(structure, field) \
1369    (size_t)(&((structure *)NULL)->field)
1370 
1371 #define RlimitOffsets(field) \
1372     OffsetOf(sigar_resource_limit_t, field##_cur), \
1373     OffsetOf(sigar_resource_limit_t, field##_max)
1374 
1375 #define RlimitSet(structure, ptr, val) \
1376     *(sigar_uint64_t *)((char *)structure + (int)(long)ptr) = val
1377 
1378 typedef struct {
1379     int resource;
1380     int factor;
1381     size_t cur;
1382     size_t max;
1383 } rlimit_field_t;
1384 
1385 #ifndef RLIMIT_RSS
1386 #define RLIMIT_RSS (RLIM_NLIMITS+1)
1387 #endif
1388 
1389 #ifndef RLIMIT_NPROC
1390 #define RLIMIT_NPROC (RLIM_NLIMITS+2)
1391 #endif
1392 
1393 #define RLIMIT_PSIZE (RLIM_NLIMITS+3)
1394 
1395 #ifndef RLIMIT_AS
1396 #  if defined(RLIMIT_VMEM)
1397 #    define RLIMIT_AS RLIMIT_VMEM
1398 #  elif defined(RLIMIT_RSS)
1399 #    define RLIMIT_AS RLIMIT_RSS
1400 #  endif
1401 #endif
1402 
1403 static rlimit_field_t sigar_rlimits[] = {
1404     { RLIMIT_CPU,    1,    RlimitOffsets(cpu) },
1405     { RLIMIT_FSIZE,  1024, RlimitOffsets(file_size) },
1406     { RLIMIT_DATA,   1024, RlimitOffsets(data) },
1407     { RLIMIT_STACK,  1024, RlimitOffsets(stack) },
1408     { RLIMIT_PSIZE,   512, RlimitOffsets(pipe_size) },
1409     { RLIMIT_CORE,   1024, RlimitOffsets(core) },
1410     { RLIMIT_RSS,    1024, RlimitOffsets(memory) },
1411     { RLIMIT_NPROC,  1,    RlimitOffsets(processes) },
1412     { RLIMIT_NOFILE, 1,    RlimitOffsets(open_files) },
1413     { RLIMIT_AS,     1024, RlimitOffsets(virtual_memory) },
1414     { -1 }
1415 };
1416 
1417 #define RlimitScale(val) \
1418     if (val != RLIM_INFINITY) val /= r->factor
1419 
1420 #define RlimitHS(val) \
1421     rl.rlim_cur = rl.rlim_max = (val)
1422 
sigar_resource_limit_get(sigar_t *sigar, sigar_resource_limit_t *rlimit)1423 int sigar_resource_limit_get(sigar_t *sigar,
1424                              sigar_resource_limit_t *rlimit)
1425 {
1426     int i;
1427 
1428     for (i=0; sigar_rlimits[i].resource != -1; i++) {
1429         struct rlimit rl;
1430         rlimit_field_t *r = &sigar_rlimits[i];
1431 
1432         if (r->resource > RLIM_NLIMITS) {
1433             switch (r->resource) {
1434               case RLIMIT_NPROC:
1435                 RlimitHS(sysconf(_SC_CHILD_MAX));
1436                 break;
1437               case RLIMIT_PSIZE:
1438                 RlimitHS(PIPE_BUF/512);
1439                 break;
1440               default:
1441                 RlimitHS(RLIM_INFINITY);
1442                 break;
1443             }
1444         }
1445         else if (getrlimit(r->resource, &rl) != 0) {
1446             RlimitHS(RLIM_INFINITY);
1447         }
1448         else {
1449             RlimitScale(rl.rlim_cur);
1450             RlimitScale(rl.rlim_max);
1451         }
1452 
1453         RlimitSet(rlimit, r->cur, rl.rlim_cur);
1454         RlimitSet(rlimit, r->max, rl.rlim_max);
1455     }
1456 
1457     return SIGAR_OK;
1458 }
1459 #endif
1460 
1461 #ifdef HAVE_LIBDLPI_H
1462 #include <libdlpi.h>
1463 
hwaddr_libdlpi_lookup(sigar_t *sigar, sigar_net_interface_config_t *ifconfig)1464 static void hwaddr_libdlpi_lookup(sigar_t *sigar, sigar_net_interface_config_t *ifconfig)
1465 {
1466     dlpi_handle_t handle;
1467     dlpi_info_t linkinfo;
1468     uchar_t addr[DLPI_PHYSADDR_MAX];
1469     uint_t alen = sizeof(addr);
1470 
1471     if (dlpi_open(ifconfig->name, &handle, 0) != DLPI_SUCCESS) {
1472         return;
1473     }
1474 
1475     if (dlpi_get_physaddr(handle, DL_CURR_PHYS_ADDR, addr, &alen) == DLPI_SUCCESS &&
1476         dlpi_info(handle, &linkinfo, 0) == DLPI_SUCCESS) {
1477         if (alen < sizeof(ifconfig->hwaddr.addr.mac)) {
1478             sigar_net_address_mac_set(ifconfig->hwaddr, addr, alen);
1479             SIGAR_SSTRCPY(ifconfig->type, dlpi_mactype(linkinfo.di_mactype));
1480         }
1481     }
1482 
1483     dlpi_close(handle);
1484 }
1485 #endif
1486 
1487 
1488 #if !defined(WIN32) && !defined(NETWARE) && !defined(DARWIN) && \
1489     !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
1490 
1491 /* XXX: prolly will be moving these stuffs into os_net.c */
1492 #include <sys/ioctl.h>
1493 #include <net/if.h>
1494 
1495 #ifndef SIOCGIFCONF
1496 #include <sys/sockio.h>
1497 #endif
1498 
1499 #if defined(_AIX) || defined(__osf__) /* good buddies */
1500 
1501 #include <net/if_dl.h>
1502 
hwaddr_aix_lookup(sigar_t *sigar, sigar_net_interface_config_t *ifconfig)1503 static void hwaddr_aix_lookup(sigar_t *sigar, sigar_net_interface_config_t *ifconfig)
1504 {
1505     char *ent, *end;
1506     struct ifreq *ifr;
1507 
1508     /* XXX: assumes sigar_net_interface_list_get has been called */
1509     end = sigar->ifconf_buf + sigar->ifconf_len;
1510 
1511     for (ent = sigar->ifconf_buf;
1512          ent < end;
1513          ent += sizeof(*ifr))
1514     {
1515         ifr = (struct ifreq *)ent;
1516 
1517         if (ifr->ifr_addr.sa_family != AF_LINK) {
1518             continue;
1519         }
1520 
1521         if (strEQ(ifr->ifr_name, ifconfig->name)) {
1522             struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifr->ifr_addr;
1523 
1524             sigar_net_address_mac_set(ifconfig->hwaddr,
1525                                       LLADDR(sdl),
1526                                       sdl->sdl_alen);
1527             return;
1528         }
1529     }
1530 
1531     sigar_hwaddr_set_null(ifconfig);
1532 }
1533 
1534 #elif !defined(SIOCGIFHWADDR)
1535 
1536 #include <net/if_arp.h>
1537 
hwaddr_arp_lookup(sigar_net_interface_config_t *ifconfig, int sock)1538 static void hwaddr_arp_lookup(sigar_net_interface_config_t *ifconfig, int sock)
1539 {
1540     struct arpreq areq;
1541     struct sockaddr_in *sa;
1542 
1543     memset(&areq, 0, sizeof(areq));
1544     sa = (struct sockaddr_in *)&areq.arp_pa;
1545     sa->sin_family = AF_INET;
1546     sa->sin_addr.s_addr = ifconfig->address.addr.in;
1547 
1548     if (ioctl(sock, SIOCGARP, &areq) < 0) {
1549         /* ho-hum */
1550         sigar_hwaddr_set_null(ifconfig);
1551     }
1552     else {
1553         sigar_net_address_mac_set(ifconfig->hwaddr,
1554                                   areq.arp_ha.sa_data,
1555                                   SIGAR_IFHWADDRLEN);
1556     }
1557 }
1558 
1559 #endif
1560 
1561 #ifdef __linux__
1562 
1563 #include <net/if_arp.h>
1564 
1565 #ifndef ARPHRD_CISCO /* not in 2.2 kernel headers */
1566 #define ARPHRD_CISCO 513 /* Cisco HDLC. */
1567 #endif
1568 
get_interface_type(sigar_net_interface_config_t *ifconfig, int family)1569 static void get_interface_type(sigar_net_interface_config_t *ifconfig,
1570                                int family)
1571 {
1572     char *type;
1573 
1574     switch (family) {
1575       case ARPHRD_SLIP:
1576         type = SIGAR_NIC_SLIP;
1577         break;
1578       case ARPHRD_CSLIP:
1579         type = SIGAR_NIC_CSLIP;
1580         break;
1581       case ARPHRD_SLIP6:
1582         type = SIGAR_NIC_SLIP6;
1583         break;
1584       case ARPHRD_CSLIP6:
1585         type = SIGAR_NIC_CSLIP6;
1586         break;
1587       case ARPHRD_ADAPT:
1588         type = SIGAR_NIC_ADAPTIVE;
1589         break;
1590       case ARPHRD_ETHER:
1591         type = SIGAR_NIC_ETHERNET;
1592         break;
1593       case ARPHRD_ASH:
1594         type = SIGAR_NIC_ASH;
1595         break;
1596       case ARPHRD_FDDI:
1597         type = SIGAR_NIC_FDDI;
1598         break;
1599       case ARPHRD_HIPPI:
1600         type = SIGAR_NIC_HIPPI;
1601         break;
1602       case ARPHRD_AX25:
1603         type = SIGAR_NIC_AX25;
1604         break;
1605       case ARPHRD_ROSE:
1606         type = SIGAR_NIC_ROSE;
1607         break;
1608       case ARPHRD_NETROM:
1609         type = SIGAR_NIC_NETROM;
1610         break;
1611       case ARPHRD_X25:
1612         type = SIGAR_NIC_X25;
1613         break;
1614       case ARPHRD_TUNNEL:
1615         type = SIGAR_NIC_TUNNEL;
1616         break;
1617       case ARPHRD_PPP:
1618         type = SIGAR_NIC_PPP;
1619         break;
1620       case ARPHRD_CISCO:
1621         type = SIGAR_NIC_HDLC;
1622         break;
1623       case ARPHRD_LAPB:
1624         type = SIGAR_NIC_LAPB;
1625         break;
1626       case ARPHRD_ARCNET:
1627         type = SIGAR_NIC_ARCNET;
1628         break;
1629       case ARPHRD_DLCI:
1630         type = SIGAR_NIC_DLCI;
1631         break;
1632       case ARPHRD_FRAD:
1633         type = SIGAR_NIC_FRAD;
1634         break;
1635       case ARPHRD_SIT:
1636         type = SIGAR_NIC_SIT;
1637         break;
1638       case ARPHRD_IRDA:
1639         type = SIGAR_NIC_IRDA;
1640         break;
1641       case ARPHRD_ECONET:
1642         type = SIGAR_NIC_EC;
1643         break;
1644       default:
1645         type = SIGAR_NIC_UNSPEC;
1646         break;
1647     }
1648 
1649     SIGAR_SSTRCPY(ifconfig->type, type);
1650 }
1651 
1652 #endif
1653 
sigar_net_interface_config_get(sigar_t *sigar, const char *name, sigar_net_interface_config_t *ifconfig)1654 int sigar_net_interface_config_get(sigar_t *sigar, const char *name,
1655                                    sigar_net_interface_config_t *ifconfig)
1656 {
1657     int sock;
1658     struct ifreq ifr;
1659 
1660     if (!name) {
1661         return sigar_net_interface_config_primary_get(sigar, ifconfig);
1662     }
1663 
1664     SIGAR_ZERO(ifconfig);
1665 
1666     if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1667         return errno;
1668     }
1669 
1670     SIGAR_SSTRCPY(ifconfig->name, name);
1671     SIGAR_SSTRCPY(ifr.ifr_name, name);
1672 
1673 #define ifr_s_addr(ifr) \
1674     ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr
1675 
1676     if (!ioctl(sock, SIOCGIFADDR, &ifr)) {
1677         sigar_net_address_set(ifconfig->address,
1678                               ifr_s_addr(ifr));
1679     }
1680 
1681     if (!ioctl(sock, SIOCGIFNETMASK, &ifr)) {
1682         sigar_net_address_set(ifconfig->netmask,
1683                               ifr_s_addr(ifr));
1684     }
1685 
1686     if (!ioctl(sock, SIOCGIFFLAGS, &ifr)) {
1687         sigar_uint64_t flags = ifr.ifr_flags;
1688 #ifdef __linux__
1689 # ifndef IFF_DYNAMIC
1690 #  define IFF_DYNAMIC 0x8000 /* not in 2.2 kernel */
1691 # endif /* IFF_DYNAMIC */
1692         int is_mcast = flags & IFF_MULTICAST;
1693         int is_slave = flags & IFF_SLAVE;
1694         int is_master = flags & IFF_MASTER;
1695         int is_dynamic = flags & IFF_DYNAMIC;
1696         /*
1697          * XXX: should just define SIGAR_IFF_*
1698          * and test IFF_* bits on given platform.
1699          * this is the only diff between solaris/hpux/linux
1700          * for the flags we care about.
1701          *
1702          */
1703         flags &= ~(IFF_MULTICAST|IFF_SLAVE|IFF_MASTER);
1704         if (is_mcast) {
1705             flags |= SIGAR_IFF_MULTICAST;
1706         }
1707         if (is_slave) {
1708             flags |= SIGAR_IFF_SLAVE;
1709         }
1710         if (is_master) {
1711             flags |= SIGAR_IFF_MASTER;
1712         }
1713         if (is_dynamic) {
1714             flags |= SIGAR_IFF_DYNAMIC;
1715         }
1716 #endif
1717         ifconfig->flags = flags;
1718     }
1719     else {
1720         /* should always be able to get flags for existing device */
1721         /* other ioctls may fail if device is not enabled: ok */
1722         close(sock);
1723         return errno;
1724     }
1725 
1726     if (ifconfig->flags & IFF_LOOPBACK) {
1727         sigar_net_address_set(ifconfig->destination,
1728                               ifconfig->address.addr.in);
1729         sigar_net_address_set(ifconfig->broadcast, 0);
1730         sigar_hwaddr_set_null(ifconfig);
1731         SIGAR_SSTRCPY(ifconfig->type,
1732                       SIGAR_NIC_LOOPBACK);
1733     }
1734     else {
1735         if (!ioctl(sock, SIOCGIFDSTADDR, &ifr)) {
1736             sigar_net_address_set(ifconfig->destination,
1737                                   ifr_s_addr(ifr));
1738         }
1739 
1740         if (!ioctl(sock, SIOCGIFBRDADDR, &ifr)) {
1741             sigar_net_address_set(ifconfig->broadcast,
1742                                   ifr_s_addr(ifr));
1743         }
1744 
1745 #if defined(HAVE_LIBDLPI_H)
1746         hwaddr_libdlpi_lookup(sigar, ifconfig);
1747 #elif defined(SIOCGIFHWADDR)
1748         if (!ioctl(sock, SIOCGIFHWADDR, &ifr)) {
1749             get_interface_type(ifconfig,
1750                                ifr.ifr_hwaddr.sa_family);
1751             sigar_net_address_mac_set(ifconfig->hwaddr,
1752                                       ifr.ifr_hwaddr.sa_data,
1753                                       IFHWADDRLEN);
1754         }
1755 #elif defined(_AIX) || defined(__osf__)
1756         hwaddr_aix_lookup(sigar, ifconfig);
1757         SIGAR_SSTRCPY(ifconfig->type,
1758                       SIGAR_NIC_ETHERNET);
1759 #else
1760         hwaddr_arp_lookup(ifconfig, sock);
1761         SIGAR_SSTRCPY(ifconfig->type,
1762                       SIGAR_NIC_ETHERNET);
1763 #endif
1764     }
1765 
1766 #if defined(SIOCGLIFMTU) && !defined(__hpux)
1767     {
1768         struct lifreq lifr;
1769         SIGAR_SSTRCPY(lifr.lifr_name, name);
1770         if(!ioctl(sock, SIOCGLIFMTU, &lifr)) {
1771             ifconfig->mtu = lifr.lifr_mtu;
1772         }
1773     }
1774 #elif defined(SIOCGIFMTU)
1775     if (!ioctl(sock, SIOCGIFMTU, &ifr)) {
1776 #  if defined(__hpux)
1777         ifconfig->mtu = ifr.ifr_metric;
1778 #  else
1779         ifconfig->mtu = ifr.ifr_mtu;
1780 #endif
1781     }
1782 #else
1783     ifconfig->mtu = 0; /*XXX*/
1784 #endif
1785 
1786     if (!ioctl(sock, SIOCGIFMETRIC, &ifr)) {
1787         ifconfig->metric = ifr.ifr_metric ? ifr.ifr_metric : 1;
1788     }
1789 
1790 #if defined(SIOCGIFTXQLEN)
1791     if (!ioctl(sock, SIOCGIFTXQLEN, &ifr)) {
1792         ifconfig->tx_queue_len = ifr.ifr_qlen;
1793     }
1794     else {
1795         ifconfig->tx_queue_len = -1; /* net-tools behaviour */
1796     }
1797 #else
1798     ifconfig->tx_queue_len = -1;
1799 #endif
1800 
1801     close(sock);
1802 
1803     /* XXX can we get a better description like win32? */
1804     SIGAR_SSTRCPY(ifconfig->description,
1805                   ifconfig->name);
1806 
1807     sigar_net_interface_ipv6_config_init(ifconfig);
1808     sigar_net_interface_ipv6_config_get(sigar, name, ifconfig);
1809 
1810     return SIGAR_OK;
1811 }
1812 
1813 #ifdef _AIX
1814 #  define MY_SIOCGIFCONF CSIOCGIFCONF
1815 #else
1816 #  define MY_SIOCGIFCONF SIOCGIFCONF
1817 #endif
1818 
1819 #ifdef __osf__
sigar_netif_configured(sigar_t *sigar, char *name)1820 static int sigar_netif_configured(sigar_t *sigar, char *name)
1821 {
1822     int status;
1823     sigar_net_interface_config_t ifconfig;
1824 
1825     status = sigar_net_interface_config_get(sigar, name, &ifconfig);
1826 
1827     return status == SIGAR_OK;
1828 }
1829 #endif
1830 
1831 #ifdef __linux__
has_interface(sigar_net_interface_list_t *iflist, char *name)1832 static  int has_interface(sigar_net_interface_list_t *iflist,
1833                                       char *name)
1834 {
1835     register int i;
1836     register int num = iflist->number;
1837     register char **data = iflist->data;
1838     for (i=0; i<num; i++) {
1839         if (strEQ(name, data[i])) {
1840             return 1;
1841         }
1842     }
1843     return 0;
1844 }
1845 
proc_net_interface_list_get(sigar_t *sigar, sigar_net_interface_list_t *iflist)1846 static int proc_net_interface_list_get(sigar_t *sigar,
1847                                        sigar_net_interface_list_t *iflist)
1848 {
1849     /* certain interfaces such as VMware vmnic
1850      * are not returned by ioctl(SIOCGIFCONF).
1851      * check /proc/net/dev for any ioctl missed.
1852      */
1853     char buffer[BUFSIZ];
1854     FILE *fp = fopen("/proc/net/dev", "r");
1855 
1856     if (!fp) {
1857         return errno;
1858     }
1859 
1860     /* skip header */
1861     fgets(buffer, sizeof(buffer), fp);
1862     fgets(buffer, sizeof(buffer), fp);
1863 
1864     while (fgets(buffer, sizeof(buffer), fp)) {
1865         char *ptr, *dev;
1866 
1867         dev = buffer;
1868         while (isspace(*dev)) {
1869             dev++;
1870         }
1871 
1872         if (!(ptr = strchr(dev, ':'))) {
1873             continue;
1874         }
1875 
1876         *ptr++ = 0;
1877 
1878         if (has_interface(iflist, dev)) {
1879             continue;
1880         }
1881 
1882         SIGAR_NET_IFLIST_GROW(iflist);
1883 
1884         iflist->data[iflist->number++] =
1885             sigar_strdup(dev);
1886     }
1887 
1888     fclose(fp);
1889 
1890     return SIGAR_OK;
1891 }
1892 #endif
1893 
sigar_net_interface_list_get(sigar_t *sigar, sigar_net_interface_list_t *iflist)1894 int sigar_net_interface_list_get(sigar_t *sigar,
1895                                  sigar_net_interface_list_t *iflist)
1896 {
1897     int n, lastlen=0;
1898     struct ifreq *ifr;
1899     struct ifconf ifc;
1900     int sock = socket(AF_INET, SOCK_DGRAM, 0);
1901 
1902     if (sock < 0) {
1903         return errno;
1904     }
1905 
1906     for (;;) {
1907         if (!sigar->ifconf_buf || lastlen) {
1908             sigar->ifconf_len += sizeof(struct ifreq) * SIGAR_NET_IFLIST_MAX;
1909             sigar->ifconf_buf = realloc(sigar->ifconf_buf, sigar->ifconf_len);
1910         }
1911 
1912         ifc.ifc_len = sigar->ifconf_len;
1913         ifc.ifc_buf = sigar->ifconf_buf;
1914 
1915         if (ioctl(sock, MY_SIOCGIFCONF, &ifc) < 0) {
1916             /* EINVAL should mean num_interfaces > ifc.ifc_len */
1917             if ((errno != EINVAL) ||
1918                 (lastlen == ifc.ifc_len))
1919             {
1920                 free(ifc.ifc_buf);
1921                 return errno;
1922             }
1923         }
1924 
1925         if (ifc.ifc_len < sigar->ifconf_len) {
1926             break; /* got em all */
1927         }
1928 
1929         if (ifc.ifc_len != lastlen) {
1930             /* might be more */
1931             lastlen = ifc.ifc_len;
1932             continue;
1933         }
1934 
1935         break;
1936     }
1937 
1938     close(sock);
1939 
1940     iflist->number = 0;
1941     iflist->size = ifc.ifc_len;
1942     iflist->data = malloc(sizeof(*(iflist->data)) *
1943                           iflist->size);
1944 
1945     ifr = ifc.ifc_req;
1946     for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq), ifr++) {
1947 #if defined(_AIX) || defined(__osf__) /* pass the bourbon */
1948         if (ifr->ifr_addr.sa_family != AF_LINK) {
1949             /* XXX: dunno if this is right.
1950              * otherwise end up with two 'en0' and three 'lo0'
1951              * with the same ip address.
1952              */
1953             continue;
1954         }
1955 #   ifdef __osf__
1956         /* weed out "sl0", "tun0" and the like */
1957         /* XXX must be a better way to check this */
1958         if (!sigar_netif_configured(sigar, ifr->ifr_name)) {
1959             continue;
1960         }
1961 #   endif
1962 #endif
1963         iflist->data[iflist->number++] =
1964             sigar_strdup(ifr->ifr_name);
1965     }
1966 
1967 #ifdef __linux__
1968     proc_net_interface_list_get(sigar, iflist);
1969 #endif
1970 
1971     return SIGAR_OK;
1972 }
1973 
1974 #endif /* WIN32 */
1975 
1976 SIGAR_DECLARE(int)
sigar_net_interface_config_primary_get(sigar_t *sigar, sigar_net_interface_config_t *ifconfig)1977 sigar_net_interface_config_primary_get(sigar_t *sigar,
1978                                        sigar_net_interface_config_t *ifconfig)
1979 {
1980     int i, status, found=0;
1981     sigar_net_interface_list_t iflist;
1982     sigar_net_interface_config_t possible_config;
1983 
1984     possible_config.flags = 0;
1985 
1986     if ((status = sigar_net_interface_list_get(sigar, &iflist)) != SIGAR_OK) {
1987         return status;
1988     }
1989 
1990     for (i=0; i<iflist.number; i++) {
1991         status = sigar_net_interface_config_get(sigar,
1992                                                 iflist.data[i], ifconfig);
1993 
1994         if ((status != SIGAR_OK) ||
1995             (ifconfig->flags & SIGAR_IFF_LOOPBACK) ||
1996             !ifconfig->hwaddr.addr.in)   /* no mac address */
1997         {
1998             continue;
1999         }
2000 
2001         if (!possible_config.flags) {
2002             /* save for later for use if we're not connected to the net
2003              * or all interfaces are aliases (e.g. solaris zone)
2004              */
2005             memcpy(&possible_config, ifconfig, sizeof(*ifconfig));
2006         }
2007         if (!ifconfig->address.addr.in) {
2008             continue; /* no ip address */
2009         }
2010         if (strchr(iflist.data[i], ':')) {
2011             continue; /* alias */
2012         }
2013 
2014         found = 1;
2015         break;
2016     }
2017 
2018     sigar_net_interface_list_destroy(sigar, &iflist);
2019 
2020     if (found) {
2021         return SIGAR_OK;
2022     }
2023     else if (possible_config.flags) {
2024         memcpy(ifconfig, &possible_config, sizeof(*ifconfig));
2025         return SIGAR_OK;
2026     }
2027     else {
2028         return SIGAR_ENXIO;
2029     }
2030 }
2031 
fqdn_ip_get(sigar_t *sigar, char *name)2032 static int fqdn_ip_get(sigar_t *sigar, char *name)
2033 {
2034     sigar_net_interface_config_t ifconfig;
2035     int status;
2036 
2037     status = sigar_net_interface_config_primary_get(sigar, &ifconfig);
2038 
2039     if (status != SIGAR_OK) {
2040         return status;
2041     }
2042     if (!ifconfig.address.addr.in) {
2043         return SIGAR_ENXIO;
2044     }
2045 
2046     sigar_net_address_to_string(sigar, &ifconfig.address, name);
2047 
2048     sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
2049                      "[fqdn] using ip address '%s' for fqdn",
2050                      name);
2051 
2052     return SIGAR_OK;
2053 }
2054 
sigar_gethostbyname(const char *name, sigar_hostent_t *data)2055 struct hostent *sigar_gethostbyname(const char *name,
2056                                     sigar_hostent_t *data)
2057 {
2058     struct hostent *hp = NULL;
2059 
2060 #if defined(__linux__)
2061     gethostbyname_r(name, &data->hs,
2062                     data->buffer, sizeof(data->buffer),
2063                     &hp, &data->error);
2064 #elif defined(__sun)
2065     hp = gethostbyname_r(name, &data->hs,
2066                          data->buffer, sizeof(data->buffer),
2067                          &data->error);
2068 #elif defined(SIGAR_HAS_HOSTENT_DATA)
2069     if (gethostbyname_r(name, &data->hs, &data->hd) == 0) {
2070         hp = &data->hs;
2071     }
2072     else {
2073         data->error = h_errno;
2074     }
2075 #else
2076     hp = gethostbyname(name);
2077 #endif
2078 
2079     return hp;
2080 }
2081 
sigar_gethostbyaddr(const char *addr, int len, int type, sigar_hostent_t *data)2082 static struct hostent *sigar_gethostbyaddr(const char *addr,
2083                                            int len, int type,
2084                                            sigar_hostent_t *data)
2085 {
2086     struct hostent *hp = NULL;
2087 
2088 #if defined(__linux__)
2089     gethostbyaddr_r(addr, len, type,
2090                     &data->hs,
2091                     data->buffer, sizeof(data->buffer),
2092                     &hp, &data->error);
2093 #elif defined(__sun)
2094     hp = gethostbyaddr_r(addr, len, type,
2095                          &data->hs,
2096                          data->buffer, sizeof(data->buffer),
2097                          &data->error);
2098 #elif defined(SIGAR_HAS_HOSTENT_DATA)
2099     if (gethostbyaddr_r((char *)addr, len, type,
2100                         &data->hs, &data->hd) == 0)
2101     {
2102         hp = &data->hs;
2103     }
2104     else {
2105         data->error = h_errno;
2106     }
2107 #else
2108     if (!(hp = gethostbyaddr(addr, len, type))) {
2109         data->error = h_errno;
2110     }
2111 #endif
2112 
2113     return hp;
2114 }
2115 #define IS_FQDN(name) \
2116     (name && strchr(name, '.'))
2117 
2118 #define IS_FQDN_MATCH(lookup, name) \
2119     (IS_FQDN(lookup) && strnEQ(lookup, name, strlen(name)))
2120 
2121 #define FQDN_SET(fqdn) \
2122     SIGAR_STRNCPY(name, fqdn, namelen)
2123 
sigar_fqdn_get(sigar_t *sigar, char *name, int namelen)2124 SIGAR_DECLARE(int) sigar_fqdn_get(sigar_t *sigar, char *name, int namelen)
2125 {
2126     register int is_debug = SIGAR_LOG_IS_DEBUG(sigar);
2127     sigar_hostent_t data;
2128     struct hostent *p;
2129     char domain[SIGAR_FQDN_LEN + 1];
2130 #ifdef WIN32
2131     int status = sigar_wsa_init(sigar);
2132 
2133     if (status != SIGAR_OK) {
2134         return status;
2135     }
2136 #endif
2137 
2138     if (gethostname(name, namelen - 1) != 0) {
2139         sigar_log_printf(sigar, SIGAR_LOG_ERROR,
2140                          "[fqdn] gethostname failed: %s",
2141                          sigar_strerror(sigar, errno));
2142         return errno;
2143     }
2144     else {
2145         if (is_debug) {
2146             sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
2147                              "[fqdn] gethostname()=='%s'",
2148                              name);
2149         }
2150     }
2151 
2152     if (!(p = sigar_gethostbyname(name, &data))) {
2153         if (is_debug) {
2154             sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
2155                              "[fqdn] gethostbyname(%s) failed: %s",
2156                              name, sigar_strerror(sigar, errno));
2157         }
2158 
2159         if (!IS_FQDN(name)) {
2160             fqdn_ip_get(sigar, name);
2161         }
2162 
2163         return SIGAR_OK;
2164     }
2165 
2166     if (IS_FQDN_MATCH(p->h_name, name)) {
2167         FQDN_SET(p->h_name);
2168 
2169         sigar_log(sigar, SIGAR_LOG_DEBUG,
2170                   "[fqdn] resolved using gethostbyname.h_name");
2171 
2172         return SIGAR_OK;
2173     }
2174     else {
2175         sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
2176                          "[fqdn] unresolved using gethostbyname.h_name");
2177     }
2178 
2179     if (p->h_aliases) {
2180         int i;
2181 
2182         for (i=0; p->h_aliases[i]; i++) {
2183             if (IS_FQDN_MATCH(p->h_aliases[i], name)) {
2184                 FQDN_SET(p->h_aliases[i]);
2185 
2186                 sigar_log(sigar, SIGAR_LOG_DEBUG,
2187                           "[fqdn] resolved using gethostbyname.h_aliases");
2188 
2189                 return SIGAR_OK;
2190             }
2191             else if (is_debug) {
2192                 sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
2193                                  "[fqdn] gethostbyname(%s).alias[%d]=='%s'",
2194                                  name, i, p->h_aliases[i]);
2195             }
2196         }
2197     }
2198 
2199     sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
2200                      "[fqdn] unresolved using gethostbyname.h_aliases");
2201 
2202     if (p->h_addr_list) {
2203         int i,j;
2204 
2205         for (i=0; p->h_addr_list[i]; i++) {
2206             char addr[SIGAR_INET6_ADDRSTRLEN];
2207             struct in_addr *in =
2208                 (struct in_addr *)p->h_addr_list[i];
2209 
2210             struct hostent *q =
2211                 sigar_gethostbyaddr(p->h_addr_list[i],
2212                                     p->h_length,
2213                                     p->h_addrtype,
2214                                     &data);
2215 
2216             if (is_debug) {
2217                 sigar_inet_ntoa(sigar, in->s_addr, addr);
2218             }
2219 
2220             if (!q) {
2221                 if (is_debug) {
2222                     sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
2223                                      "[fqdn] gethostbyaddr(%s) failed: %s",
2224                                      addr,
2225                                      sigar_strerror(sigar, errno));
2226                 }
2227                 continue;
2228             }
2229 
2230             if (IS_FQDN_MATCH(q->h_name, name)) {
2231                 FQDN_SET(q->h_name);
2232 
2233                 sigar_log(sigar, SIGAR_LOG_DEBUG,
2234                           "[fqdn] resolved using gethostbyaddr.h_name");
2235 
2236                 return SIGAR_OK;
2237             }
2238             else {
2239                 if (is_debug) {
2240                     sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
2241                                      "[fqdn] gethostbyaddr(%s)=='%s'",
2242                                      addr, q->h_name);
2243                 }
2244 
2245                 for (j=0; q->h_aliases[j]; j++) {
2246                     if (IS_FQDN_MATCH(q->h_aliases[j], name)) {
2247                         FQDN_SET(q->h_aliases[j]);
2248 
2249                         sigar_log(sigar, SIGAR_LOG_DEBUG,
2250                                   "[fqdn] resolved using "
2251                                   "gethostbyaddr.h_aliases");
2252 
2253                         return SIGAR_OK;
2254                     }
2255                     else if (is_debug) {
2256                         sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
2257                                          "[fqdn] gethostbyaddr(%s).alias[%d]=='%s'",
2258                                          addr, j, q->h_aliases[j]);
2259                     }
2260                 }
2261             }
2262         }
2263     }
2264 
2265     sigar_log(sigar, SIGAR_LOG_DEBUG,
2266               "[fqdn] unresolved using gethostbyname.h_addr_list");
2267 
2268 #if !defined(WIN32) && !defined(NETWARE)
2269     if (!IS_FQDN(name) && /* e.g. aix gethostname is already fqdn */
2270         (getdomainname(domain, sizeof(domain) - 1) == 0) &&
2271         (domain[0] != '\0') &&
2272         (domain[0] != '('))  /* linux default is "(none)" */
2273     {
2274         /* sprintf(name, "%s.%s", name, domain); */
2275         char *ptr = name;
2276         int len = strlen(name);
2277         ptr += len;
2278         *ptr++ = '.';
2279         namelen -= (len+1);
2280         SIGAR_STRNCPY(ptr, domain, namelen);
2281 
2282         sigar_log(sigar, SIGAR_LOG_DEBUG,
2283                   "[fqdn] resolved using getdomainname");
2284     }
2285     else {
2286         sigar_log(sigar, SIGAR_LOG_DEBUG,
2287                   "[fqdn] getdomainname failed");
2288     }
2289 #endif
2290 
2291     if (!IS_FQDN(name)) {
2292         fqdn_ip_get(sigar, name);
2293     }
2294 
2295     return SIGAR_OK;
2296 }
2297 
2298 #ifndef MAX_STRING_LEN
2299 #define MAX_STRING_LEN 8192
2300 #endif
2301 
2302 #ifdef WIN32
2303 /* The windows version of getPasswordNative was lifted from apr */
sigar_password_get(const char *prompt)2304 SIGAR_DECLARE(char *) sigar_password_get(const char *prompt)
2305 {
2306     static char password[MAX_STRING_LEN];
2307     int n = 0;
2308     int ch;
2309 
2310     fputs(prompt, stderr);
2311     fflush(stderr);
2312 
2313     while ((ch = _getch()) != '\r') {
2314         if (ch == EOF) /* EOF */ {
2315             return NULL;
2316         }
2317         else if (ch == 0 || ch == 0xE0) {
2318             /* FN Keys (0 or E0) are a sentinal for a FN code */
2319             ch = (ch << 4) | _getch();
2320             /* Catch {DELETE}, {<--}, Num{DEL} and Num{<--} */
2321             if ((ch == 0xE53 || ch == 0xE4B || ch == 0x053 || ch == 0x04b) && n) {
2322                 password[--n] = '\0';
2323                 fputs("\b \b", stderr);
2324                 fflush(stderr);
2325             }
2326             else {
2327                 fputc('\a', stderr);
2328                 fflush(stderr);
2329             }
2330         }
2331         else if ((ch == '\b' || ch == 127) && n) /* BS/DEL */ {
2332             password[--n] = '\0';
2333             fputs("\b \b", stderr);
2334             fflush(stderr);
2335         }
2336         else if (ch == 3) /* CTRL+C */ {
2337             /* _getch() bypasses Ctrl+C but not Ctrl+Break detection! */
2338             fputs("^C\n", stderr);
2339             fflush(stderr);
2340             exit(-1);
2341         }
2342         else if (ch == 26) /* CTRL+Z */ {
2343             fputs("^Z\n", stderr);
2344             fflush(stderr);
2345             return NULL;
2346         }
2347 	else if (ch == 27) /* ESC */ {
2348             fputc('\n', stderr);
2349             fputs(prompt, stderr);
2350             fflush(stderr);
2351             n = 0;
2352         }
2353         else if ((n < sizeof(password) - 1) && !iscntrl(ch)) {
2354             password[n++] = ch;
2355             fputc(' ', stderr);
2356             fflush(stderr);
2357         }
2358 	else {
2359             fputc('\a', stderr);
2360             fflush(stderr);
2361         }
2362     }
2363 
2364     fputc('\n', stderr);
2365     fflush(stderr);
2366     password[n] = '\0';
2367 
2368     return password;
2369 }
2370 
2371 #else
2372 
2373 /* linux/hpux/solaris getpass() prototype lives here */
2374 #include <unistd.h>
2375 
2376 #include <termios.h>
2377 
2378 /* from apr_getpass.c */
2379 
2380 #if defined(SIGAR_HPUX)
2381 #   define getpass termios_getpass
2382 #elif defined(SIGAR_SOLARIS)
2383 #   define getpass getpassphrase
2384 #endif
2385 
2386 #ifdef SIGAR_HPUX
termios_getpass(const char *prompt)2387 static char *termios_getpass(const char *prompt)
2388 {
2389     struct termios attr;
2390     static char password[MAX_STRING_LEN];
2391     unsigned int n=0;
2392 
2393     fputs(prompt, stderr);
2394     fflush(stderr);
2395 
2396     if (tcgetattr(STDIN_FILENO, &attr) != 0) {
2397         return NULL;
2398     }
2399 
2400     attr.c_lflag &= ~(ECHO);
2401 
2402     if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr) != 0) {
2403         return NULL;
2404     }
2405 
2406     while ((password[n] = getchar()) != '\n') {
2407         if (n < (sizeof(password) - 1) &&
2408             (password[n] >= ' ') &&
2409             (password[n] <= '~'))
2410         {
2411             n++;
2412         }
2413         else {
2414             fprintf(stderr, "\n");
2415             fputs(prompt, stderr);
2416             fflush(stderr);
2417             n = 0;
2418         }
2419     }
2420 
2421     password[n] = '\0';
2422     printf("\n");
2423 
2424     if (n > (MAX_STRING_LEN - 1)) {
2425         password[MAX_STRING_LEN - 1] = '\0';
2426     }
2427 
2428     attr.c_lflag |= ECHO;
2429     tcsetattr(STDIN_FILENO, TCSANOW, &attr);
2430 
2431     return (char *)&password;
2432 }
2433 #endif
2434 
sigar_password_get(const char *prompt)2435 SIGAR_DECLARE(char *) sigar_password_get(const char *prompt)
2436 {
2437     char *buf = NULL;
2438 
2439     /* the linux version of getpass prints the prompt to the tty; ok.
2440      * the solaris version prints the prompt to stderr; not ok.
2441      * so print the prompt to /dev/tty ourselves if possible (always should be)
2442      */
2443 
2444     FILE *tty = NULL;
2445 
2446     if ((tty = fopen("/dev/tty", "w"))) {
2447         fprintf(tty, "%s", prompt);
2448         fflush(tty);
2449 
2450         buf = getpass(tty ? "" : prompt);
2451         fclose(tty);
2452     }
2453 
2454     return buf;
2455 }
2456 
2457 #endif /* WIN32 */
2458