Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e077554304 | ||
|
|
b9f31b2445 | ||
|
|
76036a6535 | ||
|
|
cce55fac21 | ||
|
|
a72075036a | ||
|
|
84184c644a | ||
|
|
7f238c2599 | ||
|
|
170b3df0af | ||
|
|
4a68866201 | ||
|
|
5e89ebc550 | ||
|
|
7e95f7a8ae | ||
|
|
968cafe21b | ||
|
|
d4e5ea7c0a | ||
|
|
e6793f9b54 | ||
|
|
5976434285 |
2
mud
2
mud
Submodule mud updated: 06e165e664...a91f8e2971
10
src/bench.c
10
src/bench.c
@@ -65,11 +65,15 @@ gt_bench(int argc, char **argv)
|
||||
duration /= 1000;
|
||||
|
||||
int term = isatty(1);
|
||||
int aes = argz_is_set(bench_argz, "aes");
|
||||
int chacha = argz_is_set(bench_argz, "chacha");
|
||||
|
||||
if (!chacha && !crypto_aead_aes256gcm_is_available()) {
|
||||
gt_log("aes is not available on your platform\n");
|
||||
return 1;
|
||||
if (!crypto_aead_aes256gcm_is_available()) {
|
||||
if (aes) {
|
||||
gt_log("aes is not available on your platform\n");
|
||||
return 1;
|
||||
}
|
||||
chacha = 1;
|
||||
}
|
||||
|
||||
unsigned char *buf = calloc(1, bufsize + crypto_aead_aes256gcm_ABYTES);
|
||||
|
||||
58
src/bind.c
58
src/bind.c
@@ -18,13 +18,13 @@
|
||||
#define O_CLOEXEC 0
|
||||
#endif
|
||||
|
||||
static void
|
||||
static int
|
||||
fd_set_nonblock(int fd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (fd == -1)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
int ret;
|
||||
|
||||
do {
|
||||
ret = fcntl(fd, F_GETFL, 0);
|
||||
@@ -36,8 +36,7 @@ fd_set_nonblock(int fd)
|
||||
ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||||
} while (ret == -1 && errno == EINTR);
|
||||
|
||||
if (ret == -1)
|
||||
perror("fcntl O_NONBLOCK");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -50,7 +49,7 @@ gt_setup_secretkey(struct mud *mud, const char *keyfile)
|
||||
} while (fd == -1 && errno == EINTR);
|
||||
|
||||
if (fd == -1) {
|
||||
perror("open keyfile");
|
||||
gt_log("couldn't open %s: %s\n", keyfile, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -73,7 +72,7 @@ gt_setup_secretkey(struct mud *mud, const char *keyfile)
|
||||
close(fd);
|
||||
|
||||
if (size != sizeof(buf)) {
|
||||
gt_log("unable to read secret key\n");
|
||||
gt_log("couldn't read secret key\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -96,7 +95,7 @@ gt_setup_mtu(struct mud *mud, size_t old, const char *tun_name)
|
||||
return mtu;
|
||||
|
||||
if (iface_set_mtu(tun_name, mtu) == -1)
|
||||
perror("tun_set_mtu");
|
||||
gt_log("couldn't setup MTU at %zu on device %s\n", mtu, tun_name);
|
||||
|
||||
return mtu;
|
||||
}
|
||||
@@ -165,7 +164,7 @@ gt_bind(int argc, char **argv)
|
||||
}
|
||||
|
||||
char tun_name[64];
|
||||
const int tun_fd = tun_create(tun_name, sizeof(tun_name) - 1, dev);
|
||||
const int tun_fd = tun_create(tun_name, sizeof(tun_name), dev);
|
||||
|
||||
if (tun_fd == -1) {
|
||||
gt_log("couldn't create tun device\n");
|
||||
@@ -174,8 +173,10 @@ gt_bind(int argc, char **argv)
|
||||
|
||||
size_t mtu = gt_setup_mtu(mud, 0, tun_name);
|
||||
|
||||
if (tun_set_persist(tun_fd, persist) == -1)
|
||||
perror("tun_set_persist");
|
||||
if (tun_set_persist(tun_fd, persist) == -1) {
|
||||
gt_log("couldn't %sable persist mode on device %s\n",
|
||||
persist ? "en" : "dis", tun_name);
|
||||
}
|
||||
|
||||
if (peer_addr.ss_family) {
|
||||
if (mud_peer(mud, (struct sockaddr *)&peer_addr)) {
|
||||
@@ -187,13 +188,17 @@ gt_bind(int argc, char **argv)
|
||||
const int ctl_fd = ctl_create(GT_RUNDIR, tun_name);
|
||||
|
||||
if (ctl_fd == -1) {
|
||||
perror("ctl_create");
|
||||
gt_log("couldn't create "GT_RUNDIR"/%s: %s\n",
|
||||
tun_name, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
fd_set_nonblock(tun_fd);
|
||||
fd_set_nonblock(mud_fd);
|
||||
fd_set_nonblock(ctl_fd);
|
||||
if (fd_set_nonblock(tun_fd) ||
|
||||
fd_set_nonblock(mud_fd) ||
|
||||
fd_set_nonblock(ctl_fd)) {
|
||||
gt_log("couldn't setup non-blocking fds\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
const long pid = (long)getpid();
|
||||
|
||||
@@ -309,11 +314,18 @@ gt_bind(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (FD_ISSET(mud_fd, &rfds)) {
|
||||
const int r = mud_recv(mud, buf, sizeof(buf));
|
||||
if (FD_ISSET(mud_fd, &rfds)) {
|
||||
int n = 1000;
|
||||
|
||||
if (r > 0 && ip_is_valid(buf, r))
|
||||
tun_write(tun_fd, buf, (size_t)r);
|
||||
while (n--) {
|
||||
const int r = mud_recv(mud, buf, sizeof(buf));
|
||||
|
||||
if (r <= 0)
|
||||
break;
|
||||
|
||||
if (ip_is_valid(buf, r))
|
||||
tun_write(tun_fd, buf, (size_t)r);
|
||||
}
|
||||
}
|
||||
|
||||
if (FD_ISSET(tun_fd, &rfds) && !mud_send_wait(mud)) {
|
||||
@@ -333,10 +345,8 @@ gt_bind(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (gt_reload && tun_fd >= 0) {
|
||||
if (tun_set_persist(tun_fd, 1) == -1)
|
||||
perror("tun_set_persist");
|
||||
}
|
||||
if (gt_reload && tun_fd >= 0)
|
||||
tun_set_persist(tun_fd, 1);
|
||||
|
||||
mud_delete(mud);
|
||||
ctl_delete(ctl_fd);
|
||||
|
||||
25
src/ctl.c
25
src/ctl.c
@@ -2,6 +2,7 @@
|
||||
#include "ctl.h"
|
||||
#include "str.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/socket.h>
|
||||
@@ -22,7 +23,7 @@ ctl_reply(int fd, struct ctl_msg *res, struct ctl_msg *req)
|
||||
return -1;
|
||||
|
||||
if (res->type != req->type || !res->reply) {
|
||||
errno = EINTR;
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -41,17 +42,15 @@ ctl_setsun(struct sockaddr_un *dst, const char *dir, const char *file)
|
||||
.sun_family = AF_UNIX,
|
||||
};
|
||||
|
||||
const char *path[] = {dir, "/", file};
|
||||
const size_t len = sizeof(sun.sun_path) - 1;
|
||||
int ret = snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%s", dir, file);
|
||||
|
||||
if (str_cat(sun.sun_path, len, path, COUNT(path)) == len) {
|
||||
if (str_cat(NULL, len + 1, path, COUNT(path)) > len) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (ret <= 0 || (size_t)ret >= sizeof(sun.sun_path)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*dst = sun;
|
||||
if (dst)
|
||||
*dst = sun;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -70,20 +69,14 @@ ctl_bind(int fd, const char *dir, const char *file)
|
||||
|
||||
if (ctl_setsun(&sun, dir, name))
|
||||
return -1;
|
||||
|
||||
if (!bind(fd, (struct sockaddr *)&sun, sizeof(sun)))
|
||||
return 0;
|
||||
} else {
|
||||
if (ctl_setsun(&sun, dir, file))
|
||||
return -1;
|
||||
|
||||
unlink(sun.sun_path);
|
||||
|
||||
if (!bind(fd, (struct sockaddr *)&sun, sizeof(sun)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
return bind(fd, (struct sockaddr *)&sun, sizeof(sun));
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
14
src/iface.c
14
src/iface.c
@@ -1,7 +1,7 @@
|
||||
#include "common.h"
|
||||
#include "iface.h"
|
||||
#include "str.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
@@ -17,13 +17,11 @@ iface_set_mtu(const char *dev_name, size_t mtu)
|
||||
.ifr_mtu = (int)mtu,
|
||||
};
|
||||
|
||||
const size_t len = sizeof(ifr.ifr_name) - 1;
|
||||
int ret = snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", dev_name);
|
||||
|
||||
if (str_cpy(ifr.ifr_name, len, dev_name) == len) {
|
||||
if (str_len(dev_name, len + 1) > len) {
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
if (ret <= 0 || (size_t)ret >= sizeof(ifr.ifr_name)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
@@ -31,7 +29,7 @@ iface_set_mtu(const char *dev_name, size_t mtu)
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
int ret = ioctl(fd, SIOCSIFMTU, &ifr);
|
||||
ret = ioctl(fd, SIOCSIFMTU, &ifr);
|
||||
|
||||
int err = errno;
|
||||
close(fd);
|
||||
|
||||
17
src/main.c
17
src/main.c
@@ -1,8 +1,11 @@
|
||||
#include "common.h"
|
||||
#include "str.h"
|
||||
|
||||
#include <sodium.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../argz/argz.h"
|
||||
|
||||
volatile sig_atomic_t gt_alarm;
|
||||
volatile sig_atomic_t gt_reload;
|
||||
volatile sig_atomic_t gt_quit;
|
||||
@@ -46,7 +49,19 @@ gt_set_signal(void)
|
||||
static int
|
||||
gt_version(int argc, char **argv)
|
||||
{
|
||||
printf(PACKAGE_VERSION "\n");
|
||||
struct argz version_argz[] = {
|
||||
{"libsodium", NULL, NULL, argz_option},
|
||||
{NULL}};
|
||||
|
||||
if (argz(version_argz, argc, argv))
|
||||
return 1;
|
||||
|
||||
if (argz_is_set(version_argz, "libsodium")) {
|
||||
printf("%s\n", sodium_version_string());
|
||||
} else {
|
||||
printf("%s\n", PACKAGE_VERSION);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
143
src/path.c
143
src/path.c
@@ -8,6 +8,71 @@
|
||||
|
||||
#include "../argz/argz.h"
|
||||
|
||||
static void
|
||||
gt_path_print_status(struct mud_path *path, int term)
|
||||
{
|
||||
char bindstr[INET6_ADDRSTRLEN];
|
||||
char publstr[INET6_ADDRSTRLEN];
|
||||
char peerstr[INET6_ADDRSTRLEN];
|
||||
|
||||
gt_toaddr(bindstr, sizeof(bindstr),
|
||||
(struct sockaddr *)&path->local_addr);
|
||||
gt_toaddr(publstr, sizeof(publstr),
|
||||
(struct sockaddr *)&path->r_addr);
|
||||
gt_toaddr(peerstr, sizeof(peerstr),
|
||||
(struct sockaddr *)&path->addr);
|
||||
|
||||
const char *statestr = NULL;
|
||||
|
||||
switch (path->state) {
|
||||
case MUD_UP: statestr = "UP"; break;
|
||||
case MUD_BACKUP: statestr = "BACKUP"; break;
|
||||
case MUD_DOWN: statestr = "DOWN"; break;
|
||||
default: return;
|
||||
}
|
||||
|
||||
const char *statusstr = path->ok ? "OK" : "DEGRADED";
|
||||
|
||||
printf(term ? "path %s\n"
|
||||
" status: %s\n"
|
||||
" bind: %s port %"PRIu16"\n"
|
||||
" public: %s port %"PRIu16"\n"
|
||||
" peer: %s port %"PRIu16"\n"
|
||||
" mtu: %zu bytes\n"
|
||||
" rtt: %.3f ms\n"
|
||||
" rttvar: %.3f ms\n"
|
||||
" rate tx: %"PRIu64" bytes/sec\n"
|
||||
" rate rx: %"PRIu64" bytes/sec\n"
|
||||
" total tx: %"PRIu64" packets\n"
|
||||
" total rx: %"PRIu64" packets\n"
|
||||
: "path %s %s"
|
||||
" %s %"PRIu16
|
||||
" %s %"PRIu16
|
||||
" %s %"PRIu16
|
||||
" %zu"
|
||||
" %.3f %.3f"
|
||||
" %"PRIu64
|
||||
" %"PRIu64
|
||||
" %"PRIu64
|
||||
" %"PRIu64
|
||||
"\n",
|
||||
statestr,
|
||||
statusstr,
|
||||
bindstr[0] ? bindstr : "-",
|
||||
gt_get_port((struct sockaddr *)&path->local_addr),
|
||||
publstr[0] ? publstr : "-",
|
||||
gt_get_port((struct sockaddr *)&path->r_addr),
|
||||
peerstr[0] ? peerstr : "-",
|
||||
gt_get_port((struct sockaddr *)&path->addr),
|
||||
path->mtu.ok,
|
||||
(double)path->rtt.val / 1e3,
|
||||
(double)path->rtt.var / 1e3,
|
||||
path->rate_tx,
|
||||
path->rate_rx,
|
||||
path->send.total,
|
||||
path->recv.total);
|
||||
}
|
||||
|
||||
static int
|
||||
gt_path_status(int fd)
|
||||
{
|
||||
@@ -18,79 +83,29 @@ gt_path_status(int fd)
|
||||
if (send(fd, &req, sizeof(struct ctl_msg), 0) == -1)
|
||||
return -1;
|
||||
|
||||
int term = isatty(1);
|
||||
struct mud_path path[MUD_PATH_MAX];
|
||||
int count = 0;
|
||||
|
||||
do {
|
||||
while (1) {
|
||||
if (recv(fd, &res, sizeof(struct ctl_msg), 0) == -1)
|
||||
return -1;
|
||||
|
||||
if (res.type != req.type)
|
||||
return -2;
|
||||
|
||||
if (!res.ret)
|
||||
return 0;
|
||||
if (res.ret == EAGAIN) {
|
||||
memcpy(&path[count], &res.path_status, sizeof(struct mud_path));
|
||||
count++;
|
||||
} else if (res.ret) {
|
||||
errno = res.ret;
|
||||
return -1;
|
||||
} else break;
|
||||
}
|
||||
|
||||
char bindstr[INET6_ADDRSTRLEN];
|
||||
char publstr[INET6_ADDRSTRLEN];
|
||||
char peerstr[INET6_ADDRSTRLEN];
|
||||
int term = isatty(1);
|
||||
|
||||
gt_toaddr(bindstr, sizeof(bindstr),
|
||||
(struct sockaddr *)&res.path_status.local_addr);
|
||||
gt_toaddr(publstr, sizeof(publstr),
|
||||
(struct sockaddr *)&res.path_status.r_addr);
|
||||
gt_toaddr(peerstr, sizeof(peerstr),
|
||||
(struct sockaddr *)&res.path_status.addr);
|
||||
|
||||
const char *statestr = NULL;
|
||||
|
||||
switch (res.path_status.state) {
|
||||
case MUD_UP: statestr = "UP"; break;
|
||||
case MUD_BACKUP: statestr = "BACKUP"; break;
|
||||
case MUD_DOWN: statestr = "DOWN"; break;
|
||||
default: return -2;
|
||||
}
|
||||
|
||||
const char *statusstr = res.path_status.ok ? "OK" : "DEGRADED";
|
||||
|
||||
printf(term ? "path %s\n"
|
||||
" status: %s\n"
|
||||
" bind: %s port %"PRIu16"\n"
|
||||
" public: %s port %"PRIu16"\n"
|
||||
" peer: %s port %"PRIu16"\n"
|
||||
" mtu: %zu bytes\n"
|
||||
" rtt: %.3f ms\n"
|
||||
" rttvar: %.3f ms\n"
|
||||
" rate tx: %"PRIu64" bytes/sec\n"
|
||||
" rate rx: %"PRIu64" bytes/sec\n"
|
||||
" total tx: %"PRIu64" packets\n"
|
||||
" total rx: %"PRIu64" packets\n"
|
||||
: "path %s %s"
|
||||
" %s %"PRIu16
|
||||
" %s %"PRIu16
|
||||
" %s %"PRIu16
|
||||
" %zu"
|
||||
" %.3f %.3f"
|
||||
" %"PRIu64
|
||||
" %"PRIu64
|
||||
" %"PRIu64
|
||||
" %"PRIu64
|
||||
"\n",
|
||||
statestr,
|
||||
statusstr,
|
||||
bindstr[0] ? bindstr : "-",
|
||||
gt_get_port((struct sockaddr *)&res.path_status.local_addr),
|
||||
publstr[0] ? publstr : "-",
|
||||
gt_get_port((struct sockaddr *)&res.path_status.r_addr),
|
||||
peerstr[0] ? peerstr : "-",
|
||||
gt_get_port((struct sockaddr *)&res.path_status.addr),
|
||||
res.path_status.mtu.ok,
|
||||
(double)res.path_status.rtt.val / 1e3,
|
||||
(double)res.path_status.rtt.var / 1e3,
|
||||
res.path_status.rate_tx,
|
||||
res.path_status.rate_rx,
|
||||
res.path_status.send.total,
|
||||
res.path_status.recv.total);
|
||||
} while (res.ret == EAGAIN);
|
||||
for (int i = 0; i < count; i++)
|
||||
gt_path_print_status(&path[i], term);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
29
src/str.h
29
src/str.h
@@ -31,32 +31,3 @@ str_len(const char *restrict str, size_t len)
|
||||
|
||||
return strnlen(str, len);
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
str_cat(char *dst, size_t dst_len, const char **src, size_t count)
|
||||
{
|
||||
if (count && !src)
|
||||
return 0;
|
||||
|
||||
size_t len = 0;
|
||||
|
||||
for (size_t i = 0; i < count && dst_len > len; i++) {
|
||||
size_t n = str_len(src[i], dst_len - len);
|
||||
|
||||
if (dst && n)
|
||||
memmove(&dst[len], src[i], n);
|
||||
|
||||
len += n;
|
||||
}
|
||||
|
||||
if (dst)
|
||||
dst[len] = 0;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
str_cpy(char *dst, size_t dst_len, const char *src)
|
||||
{
|
||||
return str_cat(dst, dst_len, &src, 1);
|
||||
}
|
||||
|
||||
37
src/tun.c
37
src/tun.c
@@ -32,9 +32,9 @@
|
||||
static int
|
||||
tun_create_by_id(char *name, size_t len, unsigned id)
|
||||
{
|
||||
int ret = snprintf(name, len + 1, "utun%u", id);
|
||||
int ret = snprintf(name, len, "utun%u", id);
|
||||
|
||||
if (ret <= 0 || ret > len) {
|
||||
if (ret <= 0 || (size_t)ret >= len) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@@ -44,8 +44,9 @@ tun_create_by_id(char *name, size_t len, unsigned id)
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
struct ctl_info ci = {0};
|
||||
str_cpy(ci.ctl_name, sizeof(ci.ctl_name) - 1, UTUN_CONTROL_NAME);
|
||||
struct ctl_info ci = {
|
||||
.ctl_name = UTUN_CONTROL_NAME,
|
||||
};
|
||||
|
||||
if (ioctl(fd, CTLIOCGINFO, &ci)) {
|
||||
int err = errno;
|
||||
@@ -92,14 +93,20 @@ tun_create_by_name(char *name, size_t len, const char *dev_name)
|
||||
static int
|
||||
tun_create_by_name(char *name, size_t len, const char *dev_name)
|
||||
{
|
||||
int ret = snprintf(name, len, "%s", dev_name);
|
||||
|
||||
if (ret <= 0 || (size_t)ret >= len) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct ifreq ifr = {
|
||||
.ifr_flags = IFF_TUN | IFF_NO_PI,
|
||||
};
|
||||
|
||||
const size_t ifr_len = sizeof(ifr.ifr_name) - 1;
|
||||
ret = snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", dev_name);
|
||||
|
||||
if ((len < ifr_len) ||
|
||||
(str_len(dev_name, ifr_len + 1) > ifr_len)) {
|
||||
if (ret <= 0 || (size_t)ret >= sizeof(ifr.ifr_name)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@@ -109,8 +116,6 @@ tun_create_by_name(char *name, size_t len, const char *dev_name)
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
str_cpy(ifr.ifr_name, ifr_len, dev_name);
|
||||
|
||||
if (ioctl(fd, TUNSETIFF, &ifr)) {
|
||||
int err = errno;
|
||||
close(fd);
|
||||
@@ -118,8 +123,6 @@ tun_create_by_name(char *name, size_t len, const char *dev_name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
str_cpy(name, len, ifr.ifr_name);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
@@ -128,21 +131,13 @@ tun_create_by_name(char *name, size_t len, const char *dev_name)
|
||||
static int
|
||||
tun_create_by_name(char *name, size_t len, const char *dev_name)
|
||||
{
|
||||
char tmp[128];
|
||||
int ret = snprintf(tmp, sizeof(tmp), "/dev/%s", dev_name);
|
||||
int ret = snprintf(name, len, "/dev/%s", dev_name);
|
||||
|
||||
if (ret <= 0 || (size_t)ret >= sizeof(tmp)) {
|
||||
if (ret <= 0 || (size_t)ret >= len) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (str_cpy(name, len, dev_name) == len) {
|
||||
if (str_len(dev_name, len + 1) > len) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return open(tmp, O_RDWR);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user