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
40SIGAR_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
67SIGAR_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 */
99SIGAR_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 */
111SIGAR_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
171SIGAR_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
223SIGAR_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
241int 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
257SIGAR_DECLARE(int)
258sigar_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
286int 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
295int 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
305SIGAR_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
316SIGAR_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
337int 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
346int 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
356SIGAR_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
372SIGAR_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
385int 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
394int 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 */
405static const char *fstype_names[] = {
406    "unknown", "none", "local", "remote", "ram", "cdrom", "swap"
407};
408
409static 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
473void 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
490SIGAR_DECLARE(int)
491sigar_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
510SIGAR_DECLARE(int)
511sigar_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
542int 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
551int 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
561SIGAR_DECLARE(int)
562sigar_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
573int 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
582int 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
592SIGAR_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
603int 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
612int 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
623SIGAR_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
634int 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
643int 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
653SIGAR_DECLARE(int)
654sigar_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
670int 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
679int 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
690SIGAR_DECLARE(int)
691sigar_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 */
707static 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
720SIGAR_DECLARE(int)
721sigar_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
745static 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
764SIGAR_DECLARE(int)
765sigar_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
792typedef struct {
793    sigar_net_stat_t *netstat;
794    sigar_net_connection_list_t *connlist;
795} net_stat_getter_t;
796
797static 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
836SIGAR_DECLARE(int)
837sigar_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
861typedef struct {
862    sigar_net_stat_t *netstat;
863    sigar_net_address_t *address;
864    unsigned long port;
865} net_stat_port_getter_t;
866
867static 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
906SIGAR_DECLARE(int)
907sigar_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
940static 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 */
953int 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
967int 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
976int 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
986SIGAR_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
997int 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
1006int 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
1016SIGAR_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
1050struct 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)
1061static 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
1092struct 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
1116static 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
1158static 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
1208int sigar_who_list_get_win32(sigar_t *sigar,
1209                             sigar_who_list_t *wholist);
1210
1211SIGAR_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
1224SIGAR_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)
1245int sigar_resource_limit_get(sigar_t *sigar,
1246                             sigar_resource_limit_t *rlimit)
1247{
1248    return SIGAR_ENOTIMPL;
1249}
1250
1251int 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
1259int 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
1276static 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
1307int 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
1378typedef 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
1403static 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
1423int 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
1464static 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
1503static 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
1538static 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
1569static 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
1654int 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__
1820static 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__
1832static  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
1846static 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
1894int 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
1976SIGAR_DECLARE(int)
1977sigar_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
2032static 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
2055struct 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
2082static 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
2124SIGAR_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 */
2304SIGAR_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
2387static 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
2435SIGAR_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