[lxc-devel] [lxd/master] Move some cgo to separate packages
stgraber on Github
lxc-bot at linuxcontainers.org
Wed May 8 22:35:45 UTC 2019
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190508/27054700/attachment.bin>
-------------- next part --------------
From 2768b6646834078e4a702e7012d028965cb318dc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 8 May 2019 18:10:05 -0400
Subject: [PATCH 1/2] shared: Move network cgo to shared/netutils
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/container_exec.go | 3 ++-
lxd/container_lxc.go | 3 ++-
lxd/main_checkfeature.go | 2 +-
lxd/main_forknet.go | 4 ++--
lxd/main_forkuevent.go | 2 +-
shared/{ => netutils}/netns_getifaddrs.c | 0
shared/{ => netutils}/network.c | 2 +-
shared/{ => netutils}/network_linux.go | 9 +++++----
shared/network.go | 6 +++---
9 files changed, 17 insertions(+), 14 deletions(-)
rename shared/{ => netutils}/netns_getifaddrs.c (100%)
rename shared/{ => netutils}/network.c (99%)
rename shared/{ => netutils}/network_linux.go (96%)
diff --git a/lxd/container_exec.go b/lxd/container_exec.go
index 238b1df3a0..76159915d5 100644
--- a/lxd/container_exec.go
+++ b/lxd/container_exec.go
@@ -21,6 +21,7 @@ import (
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/logger"
+ "github.com/lxc/lxd/shared/netutils"
"github.com/lxc/lxd/shared/version"
log "github.com/lxc/lxd/shared/log15"
@@ -238,7 +239,7 @@ func (s *execWs) Do(op *operation) error {
s.connsLock.Unlock()
logger.Debugf("Starting to mirror websocket")
- readDone, writeDone := shared.WebsocketExecMirror(conn, ptys[0], ptys[0], attachedChildIsDead, int(ptys[0].Fd()))
+ readDone, writeDone := netutils.WebsocketExecMirror(conn, ptys[0], ptys[0], attachedChildIsDead, int(ptys[0].Fd()))
<-readDone
<-writeDone
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 508a8db697..6c0af09783 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -38,6 +38,7 @@ import (
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/idmap"
"github.com/lxc/lxd/shared/logger"
+ "github.com/lxc/lxd/shared/netutils"
"github.com/lxc/lxd/shared/osarch"
log "github.com/lxc/lxd/shared/log15"
@@ -6354,7 +6355,7 @@ func (c *containerLXC) networkState() map[string]api.ContainerStateNetwork {
couldUseNetnsGetifaddrs := c.state.OS.NetnsGetifaddrs
if couldUseNetnsGetifaddrs {
- nw, err := shared.NetnsGetifaddrs(int32(pid))
+ nw, err := netutils.NetnsGetifaddrs(int32(pid))
if err != nil {
couldUseNetnsGetifaddrs = false
logger.Error("Failed to retrieve network information via netlink", log.Ctx{"container": c.name, "pid": pid})
diff --git a/lxd/main_checkfeature.go b/lxd/main_checkfeature.go
index 3b12811b0c..87fced5fd7 100644
--- a/lxd/main_checkfeature.go
+++ b/lxd/main_checkfeature.go
@@ -24,7 +24,7 @@ import (
#include <linux/audit.h>
#include <sys/ptrace.h>
-#include "../shared/netns_getifaddrs.c"
+#include "../shared/netutils/netns_getifaddrs.c"
#include "include/memory_utils.h"
bool netnsid_aware = false;
diff --git a/lxd/main_forknet.go b/lxd/main_forknet.go
index e7ef06e664..1c04dea924 100644
--- a/lxd/main_forknet.go
+++ b/lxd/main_forknet.go
@@ -6,7 +6,7 @@ import (
"github.com/spf13/cobra"
- "github.com/lxc/lxd/shared"
+ "github.com/lxc/lxd/shared/netutils"
)
/*
@@ -93,7 +93,7 @@ func (c *cmdForknet) Command() *cobra.Command {
}
func (c *cmdForknet) RunInfo(cmd *cobra.Command, args []string) error {
- networks, err := shared.NetnsGetifaddrs(-1)
+ networks, err := netutils.NetnsGetifaddrs(-1)
if err != nil {
return err
}
diff --git a/lxd/main_forkuevent.go b/lxd/main_forkuevent.go
index ed2ab419d3..8c769bb259 100644
--- a/lxd/main_forkuevent.go
+++ b/lxd/main_forkuevent.go
@@ -25,7 +25,7 @@ import (
#include <time.h>
#include <unistd.h>
-#include "../shared/network.c"
+#include "../shared/netutils/network.c"
#include "include/memory_utils.h"
#ifndef UEVENT_SEND
diff --git a/shared/netns_getifaddrs.c b/shared/netutils/netns_getifaddrs.c
similarity index 100%
rename from shared/netns_getifaddrs.c
rename to shared/netutils/netns_getifaddrs.c
diff --git a/shared/network.c b/shared/netutils/network.c
similarity index 99%
rename from shared/network.c
rename to shared/netutils/network.c
index d0f40b0393..882a1972c4 100644
--- a/shared/network.c
+++ b/shared/netutils/network.c
@@ -19,7 +19,7 @@
#include <sys/socket.h>
#include <unistd.h>
-#include "../lxd/include/macro.h"
+#include "../../lxd/include/macro.h"
#ifndef NETNS_RTA
#define NETNS_RTA(r) \
diff --git a/shared/network_linux.go b/shared/netutils/network_linux.go
similarity index 96%
rename from shared/network_linux.go
rename to shared/netutils/network_linux.go
index 3e920f3ccb..afe3aa31c6 100644
--- a/shared/network_linux.go
+++ b/shared/netutils/network_linux.go
@@ -1,7 +1,7 @@
// +build linux
// +build cgo
-package shared
+package netutils
import (
"fmt"
@@ -12,12 +12,13 @@ import (
"github.com/gorilla/websocket"
+ "github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/logger"
)
/*
-#include "../shared/netns_getifaddrs.c"
+#include "../../shared/netutils/netns_getifaddrs.c"
*/
// #cgo CFLAGS: -std=gnu11 -Wvla
import "C"
@@ -173,10 +174,10 @@ func WebsocketExecMirror(conn *websocket.Conn, w io.WriteCloser, r io.ReadCloser
readDone := make(chan bool, 1)
writeDone := make(chan bool, 1)
- go defaultWriter(conn, w, writeDone)
+ go shared.DefaultWriter(conn, w, writeDone)
go func(conn *websocket.Conn, r io.ReadCloser) {
- in := ExecReaderToChannel(r, -1, exited, fd)
+ in := shared.ExecReaderToChannel(r, -1, exited, fd)
for {
buf, ok := <-in
if !ok {
diff --git a/shared/network.go b/shared/network.go
index 9a37468c0c..00e200001e 100644
--- a/shared/network.go
+++ b/shared/network.go
@@ -326,7 +326,7 @@ func defaultReader(conn *websocket.Conn, r io.ReadCloser, readDone chan<- bool)
r.Close()
}
-func defaultWriter(conn *websocket.Conn, w io.WriteCloser, writeDone chan<- bool) {
+func DefaultWriter(conn *websocket.Conn, w io.WriteCloser, writeDone chan<- bool) {
for {
mt, r, err := conn.NextReader()
if err != nil {
@@ -382,7 +382,7 @@ func WebsocketMirror(conn *websocket.Conn, w io.WriteCloser, r io.ReadCloser, Re
WriteFunc := Writer
if WriteFunc == nil {
- WriteFunc = defaultWriter
+ WriteFunc = DefaultWriter
}
go ReadFunc(conn, r, readDone)
@@ -395,7 +395,7 @@ func WebsocketConsoleMirror(conn *websocket.Conn, w io.WriteCloser, r io.ReadClo
readDone := make(chan bool, 1)
writeDone := make(chan bool, 1)
- go defaultWriter(conn, w, writeDone)
+ go DefaultWriter(conn, w, writeDone)
go func(conn *websocket.Conn, r io.ReadCloser) {
in := ReaderToChannel(r, -1)
From 36c779639ae4536aaa1d0e964112188098f65d9f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 8 May 2019 18:33:39 -0400
Subject: [PATCH 2/2] shared/netutils: Move send/recv fd functions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Closes #5725
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/main_forkproxy.go | 5 +-
lxd/seccomp.go | 3 +-
shared/netutils/network_linux.go | 40 +++++++++
shared/netutils/unixfd.c | 114 +++++++++++++++++++++++++
shared/util_linux_cgo.go | 142 -------------------------------
5 files changed, 159 insertions(+), 145 deletions(-)
create mode 100644 shared/netutils/unixfd.c
diff --git a/lxd/main_forkproxy.go b/lxd/main_forkproxy.go
index dc1563d6a7..696953068f 100644
--- a/lxd/main_forkproxy.go
+++ b/lxd/main_forkproxy.go
@@ -16,6 +16,7 @@ import (
"github.com/spf13/cobra"
"github.com/lxc/lxd/shared"
+ "github.com/lxc/lxd/shared/netutils"
)
/*
@@ -508,7 +509,7 @@ func (c *cmdForkproxy) Run(cmd *cobra.Command, args []string) error {
}
sAgain:
- err = shared.AbstractUnixSendFd(forkproxyUDSSockFDNum, int(file.Fd()))
+ err = netutils.AbstractUnixSendFd(forkproxyUDSSockFDNum, int(file.Fd()))
if err != nil {
errno, ok := shared.GetErrno(err)
if ok && (errno == syscall.EAGAIN) {
@@ -566,7 +567,7 @@ func (c *cmdForkproxy) Run(cmd *cobra.Command, args []string) error {
files := []*os.File{}
for range lAddr.addr {
rAgain:
- f, err := shared.AbstractUnixReceiveFd(forkproxyUDSSockFDNum)
+ f, err := netutils.AbstractUnixReceiveFd(forkproxyUDSSockFDNum)
if err != nil {
errno, ok := shared.GetErrno(err)
if ok && (errno == syscall.EAGAIN) {
diff --git a/lxd/seccomp.go b/lxd/seccomp.go
index 90a934a750..13ebcb3458 100644
--- a/lxd/seccomp.go
+++ b/lxd/seccomp.go
@@ -20,6 +20,7 @@ import (
"github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/logger"
+ "github.com/lxc/lxd/shared/netutils"
"github.com/lxc/lxd/shared/osarch"
)
@@ -361,7 +362,7 @@ func NewSeccompServer(d *Daemon, path string) (*SeccompServer, error) {
for {
buf := make([]byte, C.SECCOMP_PROXY_MSG_SIZE)
- fdMem, err := shared.AbstractUnixReceiveFdData(int(unixFile.Fd()), buf)
+ fdMem, err := netutils.AbstractUnixReceiveFdData(int(unixFile.Fd()), buf)
if err != nil || err == io.EOF {
logger.Debugf("Disconnected from seccomp socket after receive: pid=%v", ucred.pid)
c.Close()
diff --git a/shared/netutils/network_linux.go b/shared/netutils/network_linux.go
index afe3aa31c6..957080a239 100644
--- a/shared/netutils/network_linux.go
+++ b/shared/netutils/network_linux.go
@@ -9,6 +9,7 @@ import (
"net"
"os"
"strings"
+ "unsafe"
"github.com/gorilla/websocket"
@@ -19,6 +20,7 @@ import (
/*
#include "../../shared/netutils/netns_getifaddrs.c"
+#include "../../shared/netutils/unixfd.c"
*/
// #cgo CFLAGS: -std=gnu11 -Wvla
import "C"
@@ -208,3 +210,41 @@ func WebsocketExecMirror(conn *websocket.Conn, w io.WriteCloser, r io.ReadCloser
return readDone, writeDone
}
+
+func AbstractUnixSendFd(sockFD int, sendFD int) error {
+ fd := C.int(sendFD)
+ sk_fd := C.int(sockFD)
+ ret := C.lxc_abstract_unix_send_fds(sk_fd, &fd, C.int(1), nil, C.size_t(0))
+ if ret < 0 {
+ return fmt.Errorf("Failed to send file descriptor via abstract unix socket")
+ }
+
+ return nil
+}
+
+func AbstractUnixReceiveFd(sockFD int) (*os.File, error) {
+ fd := C.int(-1)
+ sk_fd := C.int(sockFD)
+ ret := C.lxc_abstract_unix_recv_fds(sk_fd, &fd, C.int(1), nil, C.size_t(0))
+ if ret < 0 {
+ return nil, fmt.Errorf("Failed to receive file descriptor via abstract unix socket")
+ }
+
+ file := os.NewFile(uintptr(fd), "")
+ return file, nil
+}
+
+func AbstractUnixReceiveFdData(sockFD int, buf []byte) (int, error) {
+ fd := C.int(-1)
+ sk_fd := C.int(sockFD)
+ ret := C.lxc_abstract_unix_recv_fds(sk_fd, &fd, C.int(1), unsafe.Pointer(&buf[0]), C.size_t(len(buf)))
+ if ret < 0 {
+ return int(-C.EBADF), fmt.Errorf("Failed to receive file descriptor via abstract unix socket")
+ }
+
+ if ret == 0 {
+ return int(-C.EBADF), io.EOF
+ }
+
+ return int(fd), nil
+}
diff --git a/shared/netutils/unixfd.c b/shared/netutils/unixfd.c
new file mode 100644
index 0000000000..6aac9da772
--- /dev/null
+++ b/shared/netutils/unixfd.c
@@ -0,0 +1,114 @@
+// +build none
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <limits.h>
+#include <poll.h>
+#include <pty.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#include "../../lxd/include/memory_utils.h"
+
+int lxc_abstract_unix_send_fds(int fd, int *sendfds, int num_sendfds,
+ void *data, size_t size)
+{
+ __do_free char *cmsgbuf = NULL;
+ struct msghdr msg;
+ struct iovec iov;
+ struct cmsghdr *cmsg = NULL;
+ char buf[1] = {0};
+ size_t cmsgbufsize = CMSG_SPACE(num_sendfds * sizeof(int));
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&iov, 0, sizeof(iov));
+
+ cmsgbuf = malloc(cmsgbufsize);
+ if (!cmsgbuf)
+ return -1;
+
+ msg.msg_control = cmsgbuf;
+ msg.msg_controllen = cmsgbufsize;
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(num_sendfds * sizeof(int));
+
+ msg.msg_controllen = cmsg->cmsg_len;
+
+ memcpy(CMSG_DATA(cmsg), sendfds, num_sendfds * sizeof(int));
+
+ iov.iov_base = data ? data : buf;
+ iov.iov_len = data ? size : sizeof(buf);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ return sendmsg(fd, &msg, MSG_NOSIGNAL);
+}
+
+int lxc_abstract_unix_recv_fds(int fd, int *recvfds, int num_recvfds,
+ void *data, size_t size)
+{
+ __do_free char *cmsgbuf = NULL;
+ int ret;
+ struct msghdr msg;
+ struct iovec iov;
+ struct cmsghdr *cmsg = NULL;
+ char buf[1] = {0};
+ size_t cmsgbufsize = CMSG_SPACE(sizeof(struct ucred)) +
+ CMSG_SPACE(num_recvfds * sizeof(int));
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&iov, 0, sizeof(iov));
+
+ cmsgbuf = malloc(cmsgbufsize);
+ if (!cmsgbuf) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ msg.msg_control = cmsgbuf;
+ msg.msg_controllen = cmsgbufsize;
+
+ iov.iov_base = data ? data : buf;
+ iov.iov_len = data ? size : sizeof(buf);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+again:
+ ret = recvmsg(fd, &msg, 0);
+ if (ret < 0) {
+ if (errno == EINTR)
+ goto again;
+
+ goto out;
+ }
+ if (ret == 0)
+ goto out;
+
+ // If SO_PASSCRED is set we will always get a ucred message.
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_type != SCM_RIGHTS)
+ continue;
+
+ memset(recvfds, -1, num_recvfds * sizeof(int));
+ if (cmsg &&
+ cmsg->cmsg_len == CMSG_LEN(num_recvfds * sizeof(int)) &&
+ cmsg->cmsg_level == SOL_SOCKET)
+ memcpy(recvfds, CMSG_DATA(cmsg), num_recvfds * sizeof(int));
+ break;
+ }
+
+out:
+ return ret;
+}
diff --git a/shared/util_linux_cgo.go b/shared/util_linux_cgo.go
index acd8f9b218..d648a58d66 100644
--- a/shared/util_linux_cgo.go
+++ b/shared/util_linux_cgo.go
@@ -35,16 +35,6 @@ import (
#include <sys/types.h>
#include <sys/un.h>
-#include "../lxd/include/memory_utils.h"
-
-#ifndef AT_SYMLINK_FOLLOW
-#define AT_SYMLINK_FOLLOW 0x400
-#endif
-
-#ifndef AT_EMPTY_PATH
-#define AT_EMPTY_PATH 0x1000
-#endif
-
#define ABSTRACT_UNIX_SOCK_LEN sizeof(((struct sockaddr_un *)0)->sun_path)
// This is an adaption from https://codereview.appspot.com/4589049, to be
@@ -144,100 +134,6 @@ again:
return ret;
}
-
-int lxc_abstract_unix_send_fds(int fd, int *sendfds, int num_sendfds,
- void *data, size_t size)
-{
- __do_free char *cmsgbuf = NULL;
- struct msghdr msg;
- struct iovec iov;
- struct cmsghdr *cmsg = NULL;
- char buf[1] = {0};
- size_t cmsgbufsize = CMSG_SPACE(num_sendfds * sizeof(int));
-
- memset(&msg, 0, sizeof(msg));
- memset(&iov, 0, sizeof(iov));
-
- cmsgbuf = malloc(cmsgbufsize);
- if (!cmsgbuf)
- return -1;
-
- msg.msg_control = cmsgbuf;
- msg.msg_controllen = cmsgbufsize;
-
- cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(num_sendfds * sizeof(int));
-
- msg.msg_controllen = cmsg->cmsg_len;
-
- memcpy(CMSG_DATA(cmsg), sendfds, num_sendfds * sizeof(int));
-
- iov.iov_base = data ? data : buf;
- iov.iov_len = data ? size : sizeof(buf);
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
-
- return sendmsg(fd, &msg, MSG_NOSIGNAL);
-}
-
-int lxc_abstract_unix_recv_fds(int fd, int *recvfds, int num_recvfds,
- void *data, size_t size)
-{
- __do_free char *cmsgbuf = NULL;
- int ret;
- struct msghdr msg;
- struct iovec iov;
- struct cmsghdr *cmsg = NULL;
- char buf[1] = {0};
- size_t cmsgbufsize = CMSG_SPACE(sizeof(struct ucred)) +
- CMSG_SPACE(num_recvfds * sizeof(int));
-
- memset(&msg, 0, sizeof(msg));
- memset(&iov, 0, sizeof(iov));
-
- cmsgbuf = malloc(cmsgbufsize);
- if (!cmsgbuf) {
- errno = ENOMEM;
- return -1;
- }
-
- msg.msg_control = cmsgbuf;
- msg.msg_controllen = cmsgbufsize;
-
- iov.iov_base = data ? data : buf;
- iov.iov_len = data ? size : sizeof(buf);
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
-
-again:
- ret = recvmsg(fd, &msg, 0);
- if (ret < 0) {
- if (errno == EINTR)
- goto again;
-
- goto out;
- }
- if (ret == 0)
- goto out;
-
- // If SO_PASSCRED is set we will always get a ucred message.
- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
- if (cmsg->cmsg_type != SCM_RIGHTS)
- continue;
-
- memset(recvfds, -1, num_recvfds * sizeof(int));
- if (cmsg &&
- cmsg->cmsg_len == CMSG_LEN(num_recvfds * sizeof(int)) &&
- cmsg->cmsg_level == SOL_SOCKET)
- memcpy(recvfds, CMSG_DATA(cmsg), num_recvfds * sizeof(int));
- break;
- }
-
-out:
- return ret;
-}
*/
// #cgo CFLAGS: -std=gnu11 -Wvla
import "C"
@@ -264,44 +160,6 @@ func GetPollRevents(fd int, timeout int, flags int) (int, int, error) {
return int(ret), int(revents), err
}
-func AbstractUnixSendFd(sockFD int, sendFD int) error {
- fd := C.int(sendFD)
- sk_fd := C.int(sockFD)
- ret := C.lxc_abstract_unix_send_fds(sk_fd, &fd, C.int(1), nil, C.size_t(0))
- if ret < 0 {
- return fmt.Errorf("Failed to send file descriptor via abstract unix socket")
- }
-
- return nil
-}
-
-func AbstractUnixReceiveFd(sockFD int) (*os.File, error) {
- fd := C.int(-1)
- sk_fd := C.int(sockFD)
- ret := C.lxc_abstract_unix_recv_fds(sk_fd, &fd, C.int(1), nil, C.size_t(0))
- if ret < 0 {
- return nil, fmt.Errorf("Failed to receive file descriptor via abstract unix socket")
- }
-
- file := os.NewFile(uintptr(fd), "")
- return file, nil
-}
-
-func AbstractUnixReceiveFdData(sockFD int, buf []byte) (int, error) {
- fd := C.int(-1)
- sk_fd := C.int(sockFD)
- ret := C.lxc_abstract_unix_recv_fds(sk_fd, &fd, C.int(1), unsafe.Pointer(&buf[0]), C.size_t(len(buf)))
- if ret < 0 {
- return int(-C.EBADF), fmt.Errorf("Failed to receive file descriptor via abstract unix socket")
- }
-
- if ret == 0 {
- return int(-C.EBADF), io.EOF
- }
-
- return int(fd), nil
-}
-
func OpenPty(uid, gid int64) (master *os.File, slave *os.File, err error) {
fd_master := C.int(-1)
fd_slave := C.int(-1)
More information about the lxc-devel
mailing list