#include "uv.h"
#include "internal.h"
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <utmp.h>
#include <libgen.h>
#include <sys/protosw.h>
#include <procinfo.h>
#include <sys/proc.h>
#include <sys/procfs.h>
#include <sys/poll.h>
#include <sys/pollset.h>
#include <ctype.h>
#include <sys/mntctl.h>
#include <sys/vmount.h>
#include <limits.h>
#include <strings.h>
#include <sys/vnode.h>
uint64_t uv__hrtime(uv_clocktype_t type) {
uint64_t G = 1000000000;
timebasestruct_t t;
read_wall_time(&t, TIMEBASE_SZ);
time_base_to_time(&t, TIMEBASE_SZ);
return
(uint64_t) t.tb_high * G + t.tb_low;
}
int
uv_exepath(
char
* buffer,
size_t
* size) {
int
res;
char
args[PATH_MAX];
char
abspath[PATH_MAX];
size_t
abspath_size;
struct
procsinfo pi;
if
(buffer == NULL || size == NULL || *size == 0)
return
UV_EINVAL;
pi.pi_pid = getpid();
res = getargs(&pi,
sizeof
(pi), args,
sizeof
(args));
if
(res < 0)
return
UV_EINVAL;
if
(
strchr
(args,
'/'
) != NULL) {
if
(realpath(args, abspath) != abspath)
return
UV__ERR(
errno
);
abspath_size =
strlen
(abspath);
*size -= 1;
if
(*size > abspath_size)
*size = abspath_size;
memcpy
(buffer, abspath, *size);
buffer[*size] =
'\0'
;
return
0;
}
else
{
char
trypath[PATH_MAX];
char
*clonedpath = NULL;
char
*token = NULL;
char
*path =
getenv
(
"PATH"
);
if
(path == NULL)
return
UV_EINVAL;
clonedpath = uv__strdup(path);
if
(clonedpath == NULL)
return
UV_ENOMEM;
token =
strtok
(clonedpath,
":"
);
while
(token != NULL) {
snprintf(trypath,
sizeof
(trypath) - 1,
"%s/%s"
, token, args);
if
(realpath(trypath, abspath) == abspath) {
if
(access(abspath, X_OK) == 0) {
abspath_size =
strlen
(abspath);
*size -= 1;
if
(*size > abspath_size)
*size = abspath_size;
memcpy
(buffer, abspath, *size);
buffer[*size] =
'\0'
;
uv__free(clonedpath);
return
0;
}
}
token =
strtok
(NULL,
":"
);
}
uv__free(clonedpath);
return
UV_EINVAL;
}
}
void
uv_free_cpu_info(uv_cpu_info_t* cpu_infos,
int
count) {
int
i;
for
(i = 0; i < count; ++i) {
uv__free(cpu_infos[i].model);
}
uv__free(cpu_infos);
}
int
uv_interface_addresses(uv_interface_address_t** addresses,
int
* count) {
uv_interface_address_t* address;
int
sockfd, inet6, size = 1;
struct
ifconf ifc;
struct
ifreq *ifr, *p, flg;
struct
sockaddr_dl* sa_addr;
*count = 0;
*addresses = NULL;
if
(0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
return
UV__ERR(
errno
);
}
if
(ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) {
uv__close(sockfd);
return
UV__ERR(
errno
);
}
ifc.ifc_req = (
struct
ifreq*)uv__malloc(size);
ifc.ifc_len = size;
if
(ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
uv__close(sockfd);
return
UV__ERR(
errno
);
}
#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
ifr = ifc.ifc_req;
while
((
char
*)ifr < (
char
*)ifc.ifc_req + ifc.ifc_len) {
p = ifr;
ifr = (
struct
ifreq*)
((
char
*)ifr +
sizeof
(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
if
(!(p->ifr_addr.sa_family == AF_INET6 ||
p->ifr_addr.sa_family == AF_INET))
continue
;
memcpy
(flg.ifr_name, p->ifr_name,
sizeof
(flg.ifr_name));
if
(ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
uv__close(sockfd);
return
UV__ERR(
errno
);
}
if
(!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
continue
;
(*count)++;
}
if
(*count == 0) {
uv__close(sockfd);
return
0;
}
*addresses = uv__malloc(*count *
sizeof
(uv_interface_address_t));
if
(!(*addresses)) {
uv__close(sockfd);
return
UV_ENOMEM;
}
address = *addresses;
ifr = ifc.ifc_req;
while
((
char
*)ifr < (
char
*)ifc.ifc_req + ifc.ifc_len) {
p = ifr;
ifr = (
struct
ifreq*)
((
char
*)ifr +
sizeof
(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
if
(!(p->ifr_addr.sa_family == AF_INET6 ||
p->ifr_addr.sa_family == AF_INET))
continue
;
inet6 = (p->ifr_addr.sa_family == AF_INET6);
memcpy
(flg.ifr_name, p->ifr_name,
sizeof
(flg.ifr_name));
if
(ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
uv__close(sockfd);
return
UV_ENOSYS;
}
if
(!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
continue
;
address->name = uv__strdup(p->ifr_name);
if
(inet6)
address->address.address6 = *((
struct
sockaddr_in6*) &p->ifr_addr);
else
address->address.address4 = *((
struct
sockaddr_in*) &p->ifr_addr);
sa_addr = (
struct
sockaddr_dl*) &p->ifr_addr;
memcpy
(address->phys_addr, LLADDR(sa_addr),
sizeof
(address->phys_addr));
if
(ioctl(sockfd, SIOCGIFNETMASK, p) == -1) {
uv__close(sockfd);
return
UV_ENOSYS;
}
if
(inet6)
address->netmask.netmask6 = *((
struct
sockaddr_in6*) &p->ifr_addr);
else
address->netmask.netmask4 = *((
struct
sockaddr_in*) &p->ifr_addr);
address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
address++;
}
#undef ADDR_SIZE
uv__close(sockfd);
return
0;
}
void
uv_free_interface_addresses(uv_interface_address_t* addresses,
int
count) {
int
i;
for
(i = 0; i < count; ++i) {
uv__free(addresses[i].name);
}
uv__free(addresses);
}