Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
L
lxc
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Chen Yisong
lxc
Commits
5cc2545c
Unverified
Commit
5cc2545c
authored
Nov 08, 2017
by
Serge Hallyn
Committed by
GitHub
Nov 08, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1871 from brauner/2017-10-21/api_extension_console_ringbuffer
API: add console ringbuffer extension
parents
29e4eb31
a52c1c68
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
740 additions
and
307 deletions
+740
-307
.gitignore
.gitignore
+1
-0
commands.c
src/lxc/commands.c
+297
-196
commands.h
src/lxc/commands.h
+12
-0
conf.c
src/lxc/conf.c
+1
-59
conf.h
src/lxc/conf.h
+1
-1
console.c
src/lxc/console.c
+141
-45
console.h
src/lxc/console.h
+2
-0
lxccontainer.c
src/lxc/lxccontainer.c
+24
-0
lxccontainer.h
src/lxc/lxccontainer.h
+40
-0
start.c
src/lxc/start.c
+1
-5
Makefile.am
src/tests/Makefile.am
+3
-1
console_log.c
src/tests/console_log.c
+217
-0
No files found.
.gitignore
View file @
5cc2545c
...
@@ -78,6 +78,7 @@ src/tests/lxc-test-cgpath
...
@@ -78,6 +78,7 @@ src/tests/lxc-test-cgpath
src/tests/lxc-test-clonetest
src/tests/lxc-test-clonetest
src/tests/lxc-test-concurrent
src/tests/lxc-test-concurrent
src/tests/lxc-test-console
src/tests/lxc-test-console
src/tests/lxc-test-console-log
src/tests/lxc-test-containertests
src/tests/lxc-test-containertests
src/tests/lxc-test-createtest
src/tests/lxc-test-createtest
src/tests/lxc-test-destroytest
src/tests/lxc-test-destroytest
...
...
src/lxc/commands.c
View file @
5cc2545c
...
@@ -21,53 +21,54 @@
...
@@ -21,53 +21,54 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
*/
#include <stdio.h>
#include "config.h"
#include <errno.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <fcntl.h>
#include <malloc.h>
#include <poll.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/un.h>
#include <sys/param.h>
#include <malloc.h>
#include <stdlib.h>
#include "log.h"
#include "af_unix.h"
#include "lxc.h"
#include "conf.h"
#include "start.h"
/* for struct lxc_handler */
#include "utils.h"
#include "cgroup.h"
#include "cgroup.h"
#include "commands.h"
#include "commands.h"
#include "commands_utils.h"
#include "commands_utils.h"
#include "con
sole
.h"
#include "con
f
.h"
#include "confile.h"
#include "confile.h"
#include "console.h"
#include "log.h"
#include "lxc.h"
#include "lxclock.h"
#include "lxclock.h"
#include "mainloop.h"
#include "mainloop.h"
#include "monitor.h"
#include "monitor.h"
#include "
af_unix
.h"
#include "
start
.h"
#include "
config
.h"
#include "
utils
.h"
/*
/*
* This file provides the different functions for clients to
* This file provides the different functions for clients to
query/command the
*
query/command the server. The client is typically some lxc
*
server. The client is typically some lxc tool and the server is typically the
*
tool and the server is typically the
container (ie. lxc-start).
* container (ie. lxc-start).
*
*
* Each command is transactional, the clients send a request to
* Each command is transactional, the clients send a request to
the server and
* the server an
d the server answers the request with a message
* the server an
swers the request with a message giving the request's status
*
giving the request's status (zero or a negative errno value).
*
(zero or a negative errno value). Both the request and response may contain
*
Both the request and response may contain
additional data.
* additional data.
*
*
* Each command is wrapped in a ancillary message in order to pass
* Each command is wrapped in a ancillary message in order to pass
a credential
*
a credential making possible to the server to check if the client
*
making possible to the server to check if the client is allowed to ask for
*
is allowed to ask for
this command or not.
* this command or not.
*
*
* IMPORTANTLY: Note that semantics for current commands are fixed.
If you
* IMPORTANTLY: Note that semantics for current commands are fixed.
If you wish
*
wish to make any changes to how, say, LXC_CMD_GET_CONFIG_ITEM works by
*
to make any changes to how, say, LXC_CMD_GET_CONFIG_ITEM works by adding
*
adding
information to the end of cmd.data, then you must introduce a new
* information to the end of cmd.data, then you must introduce a new
* LXC_CMD_GET_CONFIG_ITEM_V2 define with a new number.
You may wish t
o
* LXC_CMD_GET_CONFIG_ITEM_V2 define with a new number.
You may wish to als
o
*
also
mark LXC_CMD_GET_CONFIG_ITEM deprecated in commands.h.
* mark LXC_CMD_GET_CONFIG_ITEM deprecated in commands.h.
*
*
* This is necessary in order to avoid having a newly compiled lxc command
* This is necessary in order to avoid having a newly compiled lxc command
* communicating with a running (old) monitor from crashing the running
* communicating with a running (old) monitor from crashing the running
...
@@ -78,7 +79,7 @@ lxc_log_define(lxc_commands, lxc);
...
@@ -78,7 +79,7 @@ lxc_log_define(lxc_commands, lxc);
static
const
char
*
lxc_cmd_str
(
lxc_cmd_t
cmd
)
static
const
char
*
lxc_cmd_str
(
lxc_cmd_t
cmd
)
{
{
static
const
char
*
const
cmdname
[
LXC_CMD_MAX
]
=
{
static
const
char
*
const
cmdname
[
LXC_CMD_MAX
]
=
{
[
LXC_CMD_CONSOLE
]
=
"console"
,
[
LXC_CMD_CONSOLE
]
=
"console"
,
[
LXC_CMD_CONSOLE_WINCH
]
=
"console_winch"
,
[
LXC_CMD_CONSOLE_WINCH
]
=
"console_winch"
,
[
LXC_CMD_STOP
]
=
"stop"
,
[
LXC_CMD_STOP
]
=
"stop"
,
...
@@ -91,10 +92,12 @@ static const char *lxc_cmd_str(lxc_cmd_t cmd)
...
@@ -91,10 +92,12 @@ static const char *lxc_cmd_str(lxc_cmd_t cmd)
[
LXC_CMD_GET_LXCPATH
]
=
"get_lxcpath"
,
[
LXC_CMD_GET_LXCPATH
]
=
"get_lxcpath"
,
[
LXC_CMD_ADD_STATE_CLIENT
]
=
"add_state_client"
,
[
LXC_CMD_ADD_STATE_CLIENT
]
=
"add_state_client"
,
[
LXC_CMD_SET_CONFIG_ITEM
]
=
"set_config_item"
,
[
LXC_CMD_SET_CONFIG_ITEM
]
=
"set_config_item"
,
[
LXC_CMD_CONSOLE_LOG
]
=
"console_log"
,
};
};
if
(
cmd
>=
LXC_CMD_MAX
)
if
(
cmd
>=
LXC_CMD_MAX
)
return
"Unknown cmd"
;
return
"Unknown cmd"
;
return
cmdname
[
cmd
];
return
cmdname
[
cmd
];
}
}
...
@@ -122,11 +125,11 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
...
@@ -122,11 +125,11 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
ret
=
lxc_abstract_unix_recv_fds
(
sock
,
&
rspfd
,
1
,
rsp
,
sizeof
(
*
rsp
));
ret
=
lxc_abstract_unix_recv_fds
(
sock
,
&
rspfd
,
1
,
rsp
,
sizeof
(
*
rsp
));
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
WARN
(
"
Command %s failed to receive response: %s.
"
,
WARN
(
"
%s - Failed to receive response for command
\"
%s
\"
"
,
lxc_cmd_str
(
cmd
->
req
.
cmd
),
strerror
(
errno
));
strerror
(
errno
),
lxc_cmd_str
(
cmd
->
req
.
cmd
));
return
-
1
;
return
-
1
;
}
}
TRACE
(
"Command
\"
%s received response"
,
lxc_cmd_str
(
cmd
->
req
.
cmd
));
TRACE
(
"Command
\"
%s
\"
received response"
,
lxc_cmd_str
(
cmd
->
req
.
cmd
));
if
(
cmd
->
req
.
cmd
==
LXC_CMD_CONSOLE
)
{
if
(
cmd
->
req
.
cmd
==
LXC_CMD_CONSOLE
)
{
struct
lxc_cmd_console_rsp_data
*
rspdata
;
struct
lxc_cmd_console_rsp_data
*
rspdata
;
...
@@ -139,9 +142,9 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
...
@@ -139,9 +142,9 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
rspdata
=
malloc
(
sizeof
(
*
rspdata
));
rspdata
=
malloc
(
sizeof
(
*
rspdata
));
if
(
!
rspdata
)
{
if
(
!
rspdata
)
{
ERROR
(
"
Command %s couldn't allocate response buffer.
"
,
ERROR
(
"
Failed to allocate response buffer for command
\"
%s
\"
"
,
lxc_cmd_str
(
cmd
->
req
.
cmd
));
lxc_cmd_str
(
cmd
->
req
.
cmd
));
return
-
1
;
return
-
ENOMEM
;
}
}
rspdata
->
masterfd
=
rspfd
;
rspdata
->
masterfd
=
rspfd
;
rspdata
->
ttynum
=
PTR_TO_INT
(
rsp
->
data
);
rspdata
->
ttynum
=
PTR_TO_INT
(
rsp
->
data
);
...
@@ -149,26 +152,36 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
...
@@ -149,26 +152,36 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
}
}
if
(
rsp
->
datalen
==
0
)
{
if
(
rsp
->
datalen
==
0
)
{
DEBUG
(
"
command %s response data length
is 0"
,
DEBUG
(
"
Response data length for command
\"
%s
\"
is 0"
,
lxc_cmd_str
(
cmd
->
req
.
cmd
));
lxc_cmd_str
(
cmd
->
req
.
cmd
));
return
ret
;
return
ret
;
}
}
if
(
rsp
->
datalen
>
LXC_CMD_DATA_MAX
)
{
ERROR
(
"Command %s response data %d too long."
,
if
((
rsp
->
datalen
>
LXC_CMD_DATA_MAX
)
&&
lxc_cmd_str
(
cmd
->
req
.
cmd
),
rsp
->
datalen
);
(
cmd
->
req
.
cmd
!=
LXC_CMD_CONSOLE_LOG
))
{
errno
=
EFBIG
;
errno
=
EFBIG
;
return
-
1
;
ERROR
(
"%s - Response data for command
\"
%s
\"
is too long: %d "
"bytes > %d"
,
strerror
(
errno
),
lxc_cmd_str
(
cmd
->
req
.
cmd
),
rsp
->
datalen
,
LXC_CMD_DATA_MAX
);
return
-
EFBIG
;
}
}
if
(
cmd
->
req
.
cmd
==
LXC_CMD_CONSOLE_LOG
)
{
rsp
->
data
=
malloc
(
rsp
->
datalen
+
1
);
((
char
*
)
rsp
->
data
)[
rsp
->
datalen
]
=
'\0'
;
}
else
{
rsp
->
data
=
malloc
(
rsp
->
datalen
);
rsp
->
data
=
malloc
(
rsp
->
datalen
);
}
if
(
!
rsp
->
data
)
{
if
(
!
rsp
->
data
)
{
ERROR
(
"Command %s was unable to allocate response buffer."
,
errno
=
ENOMEM
;
lxc_cmd_str
(
cmd
->
req
.
cmd
));
ERROR
(
"%s - Failed to allocate response buffer for command "
return
-
1
;
"
\"
%s
\"
"
,
strerror
(
errno
),
lxc_cmd_str
(
cmd
->
req
.
cmd
));
return
-
ENOMEM
;
}
}
ret
=
recv
(
sock
,
rsp
->
data
,
rsp
->
datalen
,
0
);
ret
=
recv
(
sock
,
rsp
->
data
,
rsp
->
datalen
,
0
);
if
(
ret
!=
rsp
->
datalen
)
{
if
(
ret
!=
rsp
->
datalen
)
{
ERROR
(
"
Command %s failed to receive response data: %s.
"
,
ERROR
(
"
%s - Failed to receive response data for command
\"
%s
\"
"
,
lxc_cmd_str
(
cmd
->
req
.
cmd
),
strerror
(
errno
));
lxc_cmd_str
(
cmd
->
req
.
cmd
),
strerror
(
errno
));
if
(
ret
>=
0
)
if
(
ret
>=
0
)
ret
=
-
1
;
ret
=
-
1
;
...
@@ -187,23 +200,25 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
...
@@ -187,23 +200,25 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
*/
*/
static
int
lxc_cmd_rsp_send
(
int
fd
,
struct
lxc_cmd_rsp
*
rsp
)
static
int
lxc_cmd_rsp_send
(
int
fd
,
struct
lxc_cmd_rsp
*
rsp
)
{
{
in
t
ret
;
ssize_
t
ret
;
ret
=
send
(
fd
,
rsp
,
sizeof
(
*
rsp
),
0
);
ret
=
send
(
fd
,
rsp
,
sizeof
(
*
rsp
),
0
);
if
(
ret
!=
sizeof
(
*
rsp
))
{
if
(
ret
<
0
||
(
size_t
)
ret
!=
sizeof
(
*
rsp
))
{
ERROR
(
"
Failed to send command response %d: %s."
,
ret
,
ERROR
(
"
%s - Failed to send command response %zd"
,
strerror
(
errno
));
strerror
(
errno
)
,
ret
);
return
-
1
;
return
-
1
;
}
}
if
(
rsp
->
datalen
>
0
)
{
if
(
rsp
->
datalen
<=
0
)
return
0
;
ret
=
send
(
fd
,
rsp
->
data
,
rsp
->
datalen
,
0
);
ret
=
send
(
fd
,
rsp
->
data
,
rsp
->
datalen
,
0
);
if
(
ret
!=
rsp
->
datalen
)
{
if
(
ret
<
0
||
ret
!=
(
ssize_t
)
rsp
->
datalen
)
{
WARN
(
"Failed to send command response data %d: %s.
"
,
WARN
(
"%s - Failed to send command response data %zd
"
,
ret
,
strerror
(
errno
)
);
strerror
(
errno
),
ret
);
return
-
1
;
return
-
1
;
}
}
}
return
0
;
return
0
;
}
}
...
@@ -211,19 +226,19 @@ static int lxc_cmd_send(const char *name, struct lxc_cmd_rr *cmd,
...
@@ -211,19 +226,19 @@ static int lxc_cmd_send(const char *name, struct lxc_cmd_rr *cmd,
const
char
*
lxcpath
,
const
char
*
hashed_sock_name
)
const
char
*
lxcpath
,
const
char
*
hashed_sock_name
)
{
{
int
client_fd
;
int
client_fd
;
in
t
ret
=
-
1
;
ssize_
t
ret
=
-
1
;
client_fd
=
lxc_cmd_connect
(
name
,
lxcpath
,
hashed_sock_name
);
client_fd
=
lxc_cmd_connect
(
name
,
lxcpath
,
hashed_sock_name
);
if
(
client_fd
<
0
&&
client_fd
==
-
ECONNREFUSED
)
if
(
client_fd
<
0
)
{
if
(
client_fd
==
-
ECONNREFUSED
)
return
-
ECONNREFUSED
;
return
-
ECONNREFUSED
;
else
if
(
client_fd
<
0
)
return
-
1
;
TRACE
(
"Command
\"
%s
\"
connected to command socket"
,
return
-
1
;
lxc_cmd_str
(
cmd
->
req
.
cmd
));
}
ret
=
lxc_abstract_unix_send_credential
(
client_fd
,
&
cmd
->
req
,
sizeof
(
cmd
->
req
));
ret
=
lxc_abstract_unix_send_credential
(
client_fd
,
&
cmd
->
req
,
if
(
ret
!=
sizeof
(
cmd
->
req
))
{
sizeof
(
cmd
->
req
));
if
(
ret
<
0
||
(
size_t
)
ret
!=
sizeof
(
cmd
->
req
))
{
close
(
client_fd
);
close
(
client_fd
);
if
(
errno
==
EPIPE
)
if
(
errno
==
EPIPE
)
...
@@ -235,12 +250,11 @@ static int lxc_cmd_send(const char *name, struct lxc_cmd_rr *cmd,
...
@@ -235,12 +250,11 @@ static int lxc_cmd_send(const char *name, struct lxc_cmd_rr *cmd,
return
-
1
;
return
-
1
;
}
}
TRACE
(
"Command
\"
%s
\"
requested data of length %d"
,
if
(
cmd
->
req
.
datalen
<=
0
)
lxc_cmd_str
(
cmd
->
req
.
cmd
),
cmd
->
req
.
datalen
)
;
return
client_fd
;
if
(
cmd
->
req
.
datalen
>
0
)
{
ret
=
send
(
client_fd
,
cmd
->
req
.
data
,
cmd
->
req
.
datalen
,
MSG_NOSIGNAL
);
ret
=
send
(
client_fd
,
cmd
->
req
.
data
,
cmd
->
req
.
datalen
,
MSG_NOSIGNAL
);
if
(
ret
!=
cmd
->
req
.
datalen
)
{
if
(
ret
<
0
||
ret
!=
(
ssize_t
)
cmd
->
req
.
datalen
)
{
close
(
client_fd
);
close
(
client_fd
);
if
(
errno
==
EPIPE
)
if
(
errno
==
EPIPE
)
...
@@ -251,7 +265,6 @@ static int lxc_cmd_send(const char *name, struct lxc_cmd_rr *cmd,
...
@@ -251,7 +265,6 @@ static int lxc_cmd_send(const char *name, struct lxc_cmd_rr *cmd,
return
-
1
;
return
-
1
;
}
}
}
return
client_fd
;
return
client_fd
;
}
}
...
@@ -278,7 +291,8 @@ static int lxc_cmd_send(const char *name, struct lxc_cmd_rr *cmd,
...
@@ -278,7 +291,8 @@ static int lxc_cmd_send(const char *name, struct lxc_cmd_rr *cmd,
static
int
lxc_cmd
(
const
char
*
name
,
struct
lxc_cmd_rr
*
cmd
,
int
*
stopped
,
static
int
lxc_cmd
(
const
char
*
name
,
struct
lxc_cmd_rr
*
cmd
,
int
*
stopped
,
const
char
*
lxcpath
,
const
char
*
hashed_sock_name
)
const
char
*
lxcpath
,
const
char
*
hashed_sock_name
)
{
{
int
client_fd
,
ret
=
-
1
;
int
client_fd
;
int
ret
=
-
1
;
bool
stay_connected
=
false
;
bool
stay_connected
=
false
;
if
(
cmd
->
req
.
cmd
==
LXC_CMD_CONSOLE
||
if
(
cmd
->
req
.
cmd
==
LXC_CMD_CONSOLE
||
...
@@ -287,13 +301,10 @@ static int lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, int *stopped,
...
@@ -287,13 +301,10 @@ static int lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, int *stopped,
*
stopped
=
0
;
*
stopped
=
0
;
TRACE
(
"command %s tries to connect command socket"
,
lxc_cmd_str
(
cmd
->
req
.
cmd
));
client_fd
=
lxc_cmd_send
(
name
,
cmd
,
lxcpath
,
hashed_sock_name
);
client_fd
=
lxc_cmd_send
(
name
,
cmd
,
lxcpath
,
hashed_sock_name
);
if
(
client_fd
<
0
)
{
if
(
client_fd
<
0
)
{
TRACE
(
"
command %s failed to connect command socket: %s
"
,
TRACE
(
"
%s - Command
\"
%s
\"
failed to connect command socket
"
,
lxc_cmd_str
(
cmd
->
req
.
cmd
),
strerror
(
errno
));
strerror
(
errno
),
lxc_cmd_str
(
cmd
->
req
.
cmd
));
if
(
client_fd
==
-
ECONNREFUSED
)
{
if
(
client_fd
==
-
ECONNREFUSED
)
{
*
stopped
=
1
;
*
stopped
=
1
;
return
-
1
;
return
-
1
;
...
@@ -309,6 +320,7 @@ static int lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, int *stopped,
...
@@ -309,6 +320,7 @@ static int lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, int *stopped,
out:
out:
if
(
!
stay_connected
||
ret
<=
0
)
if
(
!
stay_connected
||
ret
<=
0
)
close
(
client_fd
);
close
(
client_fd
);
if
(
stay_connected
&&
ret
>
0
)
if
(
stay_connected
&&
ret
>
0
)
cmd
->
rsp
.
ret
=
client_fd
;
cmd
->
rsp
.
ret
=
client_fd
;
...
@@ -327,7 +339,6 @@ int lxc_try_cmd(const char *name, const char *lxcpath)
...
@@ -327,7 +339,6 @@ int lxc_try_cmd(const char *name, const char *lxcpath)
};
};
ret
=
lxc_cmd
(
name
,
&
cmd
,
&
stopped
,
lxcpath
,
NULL
);
ret
=
lxc_cmd
(
name
,
&
cmd
,
&
stopped
,
lxcpath
,
NULL
);
if
(
stopped
)
if
(
stopped
)
return
0
;
return
0
;
if
(
ret
>
0
&&
cmd
.
rsp
.
ret
<
0
)
{
if
(
ret
>
0
&&
cmd
.
rsp
.
ret
<
0
)
{
...
@@ -337,14 +348,11 @@ int lxc_try_cmd(const char *name, const char *lxcpath)
...
@@ -337,14 +348,11 @@ int lxc_try_cmd(const char *name, const char *lxcpath)
if
(
ret
>
0
)
if
(
ret
>
0
)
return
0
;
return
0
;
/*
/* At this point we weren't denied access, and the container *was*
* At this point we weren't denied access, and the
* started. There was some inexplicable error in the protocol. I'm not
* container *was* started. There was some inexplicable
* clear on whether we should return -1 here, but we didn't receive a
* error in the protocol.
* -EACCES, so technically it's not that we're not allowed to control
* I'm not clear on whether we should return -1 here, but
* the container - it's just not behaving.
* we didn't receive a -EACCES, so technically it's not that
* we're not allowed to control the container - it's just not
* behaving.
*/
*/
return
0
;
return
0
;
}
}
...
@@ -430,31 +438,20 @@ char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
...
@@ -430,31 +438,20 @@ char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
struct
lxc_cmd_rr
cmd
=
{
struct
lxc_cmd_rr
cmd
=
{
.
req
=
{
.
req
=
{
.
cmd
=
LXC_CMD_GET_CGROUP
,
.
cmd
=
LXC_CMD_GET_CGROUP
,
.
datalen
=
strlen
(
subsystem
)
+
1
,
.
datalen
=
strlen
(
subsystem
)
+
1
,
.
data
=
subsystem
,
.
data
=
subsystem
,
},
},
};
};
ret
=
lxc_cmd
(
name
,
&
cmd
,
&
stopped
,
lxcpath
,
NULL
);
ret
=
lxc_cmd
(
name
,
&
cmd
,
&
stopped
,
lxcpath
,
NULL
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
TRACE
(
"command %s failed for container
\"
%s
\"
: %s."
,
lxc_cmd_str
(
cmd
.
req
.
cmd
),
name
,
strerror
(
errno
));
return
NULL
;
return
NULL
;
}
if
(
!
ret
)
{
if
(
ret
==
0
)
WARN
(
"container
\"
%s
\"
has stopped before sending its state"
,
name
);
return
NULL
;
return
NULL
;
}
if
(
cmd
.
rsp
.
ret
<
0
||
cmd
.
rsp
.
datalen
<
0
)
{
if
(
cmd
.
rsp
.
ret
<
0
||
cmd
.
rsp
.
datalen
<
0
)
ERROR
(
"command %s failed for container
\"
%s
\"
: %s"
,
lxc_cmd_str
(
cmd
.
req
.
cmd
),
name
,
strerror
(
-
cmd
.
rsp
.
ret
));
return
NULL
;
return
NULL
;
}
TRACE
(
"command %s successful for container
\"
%s
\"
"
,
lxc_cmd_str
(
cmd
.
req
.
cmd
),
name
);
return
cmd
.
rsp
.
data
;
return
cmd
.
rsp
.
data
;
}
}
...
@@ -462,8 +459,8 @@ char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
...
@@ -462,8 +459,8 @@ char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
static
int
lxc_cmd_get_cgroup_callback
(
int
fd
,
struct
lxc_cmd_req
*
req
,
static
int
lxc_cmd_get_cgroup_callback
(
int
fd
,
struct
lxc_cmd_req
*
req
,
struct
lxc_handler
*
handler
)
struct
lxc_handler
*
handler
)
{
{
struct
lxc_cmd_rsp
rsp
;
const
char
*
path
;
const
char
*
path
;
struct
lxc_cmd_rsp
rsp
;
if
(
req
->
datalen
<
1
)
if
(
req
->
datalen
<
1
)
return
-
1
;
return
-
1
;
...
@@ -471,9 +468,10 @@ static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
...
@@ -471,9 +468,10 @@ static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
path
=
cgroup_get_cgroup
(
handler
,
req
->
data
);
path
=
cgroup_get_cgroup
(
handler
,
req
->
data
);
if
(
!
path
)
if
(
!
path
)
return
-
1
;
return
-
1
;
rsp
.
datalen
=
strlen
(
path
)
+
1
,
rsp
.
data
=
(
char
*
)
path
;
rsp
.
ret
=
0
;
rsp
.
ret
=
0
;
rsp
.
datalen
=
strlen
(
path
)
+
1
;
rsp
.
data
=
(
char
*
)
path
;
return
lxc_cmd_rsp_send
(
fd
,
&
rsp
);
return
lxc_cmd_rsp_send
(
fd
,
&
rsp
);
}
}
...
@@ -495,7 +493,7 @@ char *lxc_cmd_get_config_item(const char *name, const char *item,
...
@@ -495,7 +493,7 @@ char *lxc_cmd_get_config_item(const char *name, const char *item,
struct
lxc_cmd_rr
cmd
=
{
struct
lxc_cmd_rr
cmd
=
{
.
req
=
{
.
cmd
=
LXC_CMD_GET_CONFIG_ITEM
,
.
req
=
{
.
cmd
=
LXC_CMD_GET_CONFIG_ITEM
,
.
data
=
item
,
.
data
=
item
,
.
datalen
=
strlen
(
item
)
+
1
,
.
datalen
=
strlen
(
item
)
+
1
,
},
},
};
};
...
@@ -505,6 +503,7 @@ char *lxc_cmd_get_config_item(const char *name, const char *item,
...
@@ -505,6 +503,7 @@ char *lxc_cmd_get_config_item(const char *name, const char *item,
if
(
cmd
.
rsp
.
ret
==
0
)
if
(
cmd
.
rsp
.
ret
==
0
)
return
cmd
.
rsp
.
data
;
return
cmd
.
rsp
.
data
;
return
NULL
;
return
NULL
;
}
}
...
@@ -512,14 +511,15 @@ static int lxc_cmd_get_config_item_callback(int fd, struct lxc_cmd_req *req,
...
@@ -512,14 +511,15 @@ static int lxc_cmd_get_config_item_callback(int fd, struct lxc_cmd_req *req,
struct
lxc_handler
*
handler
)
struct
lxc_handler
*
handler
)
{
{
int
cilen
;
int
cilen
;
struct
lxc_cmd_rsp
rsp
;
char
*
cidata
;
char
*
cidata
;
struct
lxc_config_t
*
item
;
struct
lxc_config_t
*
item
;
struct
lxc_cmd_rsp
rsp
;
memset
(
&
rsp
,
0
,
sizeof
(
rsp
));
memset
(
&
rsp
,
0
,
sizeof
(
rsp
));
item
=
lxc_get_config
(
req
->
data
);
item
=
lxc_get_config
(
req
->
data
);
if
(
!
item
)
if
(
!
item
)
goto
err1
;
goto
err1
;
cilen
=
item
->
get
(
req
->
data
,
NULL
,
0
,
handler
->
conf
,
NULL
);
cilen
=
item
->
get
(
req
->
data
,
NULL
,
0
,
handler
->
conf
,
NULL
);
if
(
cilen
<=
0
)
if
(
cilen
<=
0
)
goto
err1
;
goto
err1
;
...
@@ -527,6 +527,7 @@ static int lxc_cmd_get_config_item_callback(int fd, struct lxc_cmd_req *req,
...
@@ -527,6 +527,7 @@ static int lxc_cmd_get_config_item_callback(int fd, struct lxc_cmd_req *req,
cidata
=
alloca
(
cilen
+
1
);
cidata
=
alloca
(
cilen
+
1
);
if
(
item
->
get
(
req
->
data
,
cidata
,
cilen
+
1
,
handler
->
conf
,
NULL
)
!=
cilen
)
if
(
item
->
get
(
req
->
data
,
cidata
,
cilen
+
1
,
handler
->
conf
,
NULL
)
!=
cilen
)
goto
err1
;
goto
err1
;
cidata
[
cilen
]
=
'\0'
;
cidata
[
cilen
]
=
'\0'
;
rsp
.
data
=
cidata
;
rsp
.
data
=
cidata
;
rsp
.
datalen
=
cilen
+
1
;
rsp
.
datalen
=
cilen
+
1
;
...
@@ -589,6 +590,7 @@ static int lxc_cmd_set_config_item_callback(int fd, struct lxc_cmd_req *req,
...
@@ -589,6 +590,7 @@ static int lxc_cmd_set_config_item_callback(int fd, struct lxc_cmd_req *req,
memset
(
&
rsp
,
0
,
sizeof
(
rsp
));
memset
(
&
rsp
,
0
,
sizeof
(
rsp
));
rsp
.
ret
=
lxc_set_config_item_locked
(
handler
->
conf
,
key
,
value
);
rsp
.
ret
=
lxc_set_config_item_locked
(
handler
->
conf
,
key
,
value
);
return
lxc_cmd_rsp_send
(
fd
,
&
rsp
);
return
lxc_cmd_rsp_send
(
fd
,
&
rsp
);
}
}
...
@@ -615,12 +617,13 @@ int lxc_cmd_get_state(const char *name, const char *lxcpath)
...
@@ -615,12 +617,13 @@ int lxc_cmd_get_state(const char *name, const char *lxcpath)
return
-
1
;
return
-
1
;
if
(
!
ret
)
{
if
(
!
ret
)
{
WARN
(
"Container
\"
%s
\"
has stopped before sending its state
.
"
,
name
);
WARN
(
"Container
\"
%s
\"
has stopped before sending its state"
,
name
);
return
-
1
;
return
-
1
;
}
}
DEBUG
(
"Container
\"
%s
\"
is in
\"
%s
\"
state
.
"
,
name
,
DEBUG
(
"Container
\"
%s
\"
is in
\"
%s
\"
state"
,
name
,
lxc_state2str
(
PTR_TO_INT
(
cmd
.
rsp
.
data
)));
lxc_state2str
(
PTR_TO_INT
(
cmd
.
rsp
.
data
)));
return
PTR_TO_INT
(
cmd
.
rsp
.
data
);
return
PTR_TO_INT
(
cmd
.
rsp
.
data
);
}
}
...
@@ -651,22 +654,23 @@ int lxc_cmd_stop(const char *name, const char *lxcpath)
...
@@ -651,22 +654,23 @@ int lxc_cmd_stop(const char *name, const char *lxcpath)
ret
=
lxc_cmd
(
name
,
&
cmd
,
&
stopped
,
lxcpath
,
NULL
);
ret
=
lxc_cmd
(
name
,
&
cmd
,
&
stopped
,
lxcpath
,
NULL
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
if
(
stopped
)
{
if
(
stopped
)
{
INFO
(
"Container
\"
%s
\"
is already stopped
.
"
,
name
);
INFO
(
"Container
\"
%s
\"
is already stopped"
,
name
);
return
0
;
return
0
;
}
}
return
-
1
;
return
-
1
;
}
}
/*
w
e do not expect any answer, because we wait for the connection to be
/*
W
e do not expect any answer, because we wait for the connection to be
* closed
* closed
.
*/
*/
if
(
ret
>
0
)
{
if
(
ret
>
0
)
{
ERROR
(
"
Failed to stop container
\"
%s
\"
: %s."
,
name
,
ERROR
(
"
%s - Failed to stop container
\"
%s
\"
"
,
strerror
(
-
cmd
.
rsp
.
ret
));
strerror
(
-
cmd
.
rsp
.
ret
)
,
name
);
return
-
1
;
return
-
1
;
}
}
INFO
(
"Container
\"
%s
\"
has stopped
.
"
,
name
);
INFO
(
"Container
\"
%s
\"
has stopped"
,
name
);
return
0
;
return
0
;
}
}
...
@@ -681,14 +685,15 @@ static int lxc_cmd_stop_callback(int fd, struct lxc_cmd_req *req,
...
@@ -681,14 +685,15 @@ static int lxc_cmd_stop_callback(int fd, struct lxc_cmd_req *req,
memset
(
&
rsp
,
0
,
sizeof
(
rsp
));
memset
(
&
rsp
,
0
,
sizeof
(
rsp
));
rsp
.
ret
=
kill
(
handler
->
pid
,
stopsignal
);
rsp
.
ret
=
kill
(
handler
->
pid
,
stopsignal
);
if
(
!
rsp
.
ret
)
{
if
(
!
rsp
.
ret
)
{
/*
w
e can't just use lxc_unfreeze() since we are already in the
/*
W
e can't just use lxc_unfreeze() since we are already in the
* context of handling the STOP cmd in lxc-start, and calling
* context of handling the STOP cmd in lxc-start, and calling
* lxc_unfreeze() would do another cmd (GET_CGROUP) which would
* lxc_unfreeze() would do another cmd (GET_CGROUP) which would
* deadlock us
* deadlock us
.
*/
*/
if
(
cgroup_unfreeze
(
handler
))
if
(
cgroup_unfreeze
(
handler
))
return
0
;
return
0
;
ERROR
(
"Failed to unfreeze container
\"
%s
\"
."
,
handler
->
name
);
ERROR
(
"Failed to unfreeze container
\"
%s
\"
"
,
handler
->
name
);
rsp
.
ret
=
-
1
;
rsp
.
ret
=
-
1
;
}
}
...
@@ -723,6 +728,7 @@ static int lxc_cmd_console_winch_callback(int fd, struct lxc_cmd_req *req,
...
@@ -723,6 +728,7 @@ static int lxc_cmd_console_winch_callback(int fd, struct lxc_cmd_req *req,
struct
lxc_cmd_rsp
rsp
=
{
.
data
=
0
};
struct
lxc_cmd_rsp
rsp
=
{
.
data
=
0
};
lxc_console_sigwinch
(
SIGWINCH
);
lxc_console_sigwinch
(
SIGWINCH
);
return
lxc_cmd_rsp_send
(
fd
,
&
rsp
);
return
lxc_cmd_rsp_send
(
fd
,
&
rsp
);
}
}
...
@@ -750,27 +756,28 @@ int lxc_cmd_console(const char *name, int *ttynum, int *fd, const char *lxcpath)
...
@@ -750,27 +756,28 @@ int lxc_cmd_console(const char *name, int *ttynum, int *fd, const char *lxcpath)
return
ret
;
return
ret
;
if
(
cmd
.
rsp
.
ret
<
0
)
{
if
(
cmd
.
rsp
.
ret
<
0
)
{
ERROR
(
"
Console access denied: %s.
"
,
strerror
(
-
cmd
.
rsp
.
ret
));
ERROR
(
"
%s - Denied access to tty
"
,
strerror
(
-
cmd
.
rsp
.
ret
));
ret
=
-
1
;
ret
=
-
1
;
goto
out
;
goto
out
;
}
}
if
(
ret
==
0
)
{
if
(
ret
==
0
)
{
ERROR
(
"
Console %d invalid, busy or all consoles busy.
"
,
*
ttynum
);
ERROR
(
"
tty number %d invalid, busy or all ttys busy
"
,
*
ttynum
);
ret
=
-
1
;
ret
=
-
1
;
goto
out
;
goto
out
;
}
}
rspdata
=
cmd
.
rsp
.
data
;
rspdata
=
cmd
.
rsp
.
data
;
if
(
rspdata
->
masterfd
<
0
)
{
if
(
rspdata
->
masterfd
<
0
)
{
ERROR
(
"Unable to allocate fd for tty %d
.
"
,
rspdata
->
ttynum
);
ERROR
(
"Unable to allocate fd for tty %d"
,
rspdata
->
ttynum
);
goto
out
;
goto
out
;
}
}
ret
=
cmd
.
rsp
.
ret
;
/* sock
fd */
ret
=
cmd
.
rsp
.
ret
;
/* socket
fd */
*
fd
=
rspdata
->
masterfd
;
*
fd
=
rspdata
->
masterfd
;
*
ttynum
=
rspdata
->
ttynum
;
*
ttynum
=
rspdata
->
ttynum
;
INFO
(
"tty %d allocated fd %d sock %d."
,
rspdata
->
ttynum
,
*
fd
,
ret
);
INFO
(
"Alloced fd %d for tty %d via socket %d"
,
*
fd
,
rspdata
->
ttynum
,
ret
);
out:
out:
free
(
cmd
.
rsp
.
data
);
free
(
cmd
.
rsp
.
data
);
return
ret
;
return
ret
;
...
@@ -779,9 +786,9 @@ out:
...
@@ -779,9 +786,9 @@ out:
static
int
lxc_cmd_console_callback
(
int
fd
,
struct
lxc_cmd_req
*
req
,
static
int
lxc_cmd_console_callback
(
int
fd
,
struct
lxc_cmd_req
*
req
,
struct
lxc_handler
*
handler
)
struct
lxc_handler
*
handler
)
{
{
int
ttynum
=
PTR_TO_INT
(
req
->
data
);
int
masterfd
,
ret
;
int
masterfd
;
struct
lxc_cmd_rsp
rsp
;
struct
lxc_cmd_rsp
rsp
;
int
ttynum
=
PTR_TO_INT
(
req
->
data
);
masterfd
=
lxc_console_allocate
(
handler
->
conf
,
fd
,
&
ttynum
);
masterfd
=
lxc_console_allocate
(
handler
->
conf
,
fd
,
&
ttynum
);
if
(
masterfd
<
0
)
if
(
masterfd
<
0
)
...
@@ -789,8 +796,9 @@ static int lxc_cmd_console_callback(int fd, struct lxc_cmd_req *req,
...
@@ -789,8 +796,9 @@ static int lxc_cmd_console_callback(int fd, struct lxc_cmd_req *req,
memset
(
&
rsp
,
0
,
sizeof
(
rsp
));
memset
(
&
rsp
,
0
,
sizeof
(
rsp
));
rsp
.
data
=
INT_TO_PTR
(
ttynum
);
rsp
.
data
=
INT_TO_PTR
(
ttynum
);
if
(
lxc_abstract_unix_send_fds
(
fd
,
&
masterfd
,
1
,
&
rsp
,
sizeof
(
rsp
))
<
0
)
{
ret
=
lxc_abstract_unix_send_fds
(
fd
,
&
masterfd
,
1
,
&
rsp
,
sizeof
(
rsp
));
ERROR
(
"Failed to send tty to client."
);
if
(
ret
<
0
)
{
ERROR
(
"Failed to send tty to client"
);
lxc_console_free
(
handler
->
conf
,
fd
);
lxc_console_free
(
handler
->
conf
,
fd
);
goto
out_close
;
goto
out_close
;
}
}
...
@@ -798,8 +806,8 @@ static int lxc_cmd_console_callback(int fd, struct lxc_cmd_req *req,
...
@@ -798,8 +806,8 @@ static int lxc_cmd_console_callback(int fd, struct lxc_cmd_req *req,
return
0
;
return
0
;
out_close:
out_close:
/*
s
pecial indicator to lxc_cmd_handler() to close the fd and do
/*
S
pecial indicator to lxc_cmd_handler() to close the fd and do
* related cleanup
* related cleanup
.
*/
*/
return
1
;
return
1
;
}
}
...
@@ -819,12 +827,12 @@ char *lxc_cmd_get_name(const char *hashed_sock_name)
...
@@ -819,12 +827,12 @@ char *lxc_cmd_get_name(const char *hashed_sock_name)
};
};
ret
=
lxc_cmd
(
NULL
,
&
cmd
,
&
stopped
,
NULL
,
hashed_sock_name
);
ret
=
lxc_cmd
(
NULL
,
&
cmd
,
&
stopped
,
NULL
,
hashed_sock_name
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
return
NULL
;
return
NULL
;
}
if
(
cmd
.
rsp
.
ret
==
0
)
if
(
cmd
.
rsp
.
ret
==
0
)
return
cmd
.
rsp
.
data
;
return
cmd
.
rsp
.
data
;
return
NULL
;
return
NULL
;
}
}
...
@@ -857,12 +865,12 @@ char *lxc_cmd_get_lxcpath(const char *hashed_sock_name)
...
@@ -857,12 +865,12 @@ char *lxc_cmd_get_lxcpath(const char *hashed_sock_name)
};
};
ret
=
lxc_cmd
(
NULL
,
&
cmd
,
&
stopped
,
NULL
,
hashed_sock_name
);
ret
=
lxc_cmd
(
NULL
,
&
cmd
,
&
stopped
,
NULL
,
hashed_sock_name
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
return
NULL
;
return
NULL
;
}
if
(
cmd
.
rsp
.
ret
==
0
)
if
(
cmd
.
rsp
.
ret
==
0
)
return
cmd
.
rsp
.
data
;
return
cmd
.
rsp
.
data
;
return
NULL
;
return
NULL
;
}
}
...
@@ -873,9 +881,9 @@ static int lxc_cmd_get_lxcpath_callback(int fd, struct lxc_cmd_req *req,
...
@@ -873,9 +881,9 @@ static int lxc_cmd_get_lxcpath_callback(int fd, struct lxc_cmd_req *req,
memset
(
&
rsp
,
0
,
sizeof
(
rsp
));
memset
(
&
rsp
,
0
,
sizeof
(
rsp
));
rsp
.
ret
=
0
;
rsp
.
data
=
(
char
*
)
handler
->
lxcpath
;
rsp
.
data
=
(
char
*
)
handler
->
lxcpath
;
rsp
.
datalen
=
strlen
(
handler
->
lxcpath
)
+
1
;
rsp
.
datalen
=
strlen
(
handler
->
lxcpath
)
+
1
;
rsp
.
ret
=
0
;
return
lxc_cmd_rsp_send
(
fd
,
&
rsp
);
return
lxc_cmd_rsp_send
(
fd
,
&
rsp
);
}
}
...
@@ -903,53 +911,49 @@ int lxc_cmd_add_state_client(const char *name, const char *lxcpath,
...
@@ -903,53 +911,49 @@ int lxc_cmd_add_state_client(const char *name, const char *lxcpath,
state
=
lxc_getstate
(
name
,
lxcpath
);
state
=
lxc_getstate
(
name
,
lxcpath
);
if
(
state
<
0
)
{
if
(
state
<
0
)
{
process_unlock
();
process_unlock
();
TRACE
(
"failed to retrieve state of container: %s"
,
TRACE
(
"%s - Failed to retrieve state of container"
,
strerror
(
errno
));
strerror
(
errno
));
return
-
1
;
return
-
1
;
}
else
if
(
states
[
state
])
{
}
else
if
(
states
[
state
])
{
process_unlock
();
process_unlock
();
TRACE
(
"
c
ontainer is %s state"
,
lxc_state2str
(
state
));
TRACE
(
"
C
ontainer is %s state"
,
lxc_state2str
(
state
));
return
state
;
return
state
;
}
}
if
((
state
==
STARTING
)
&&
!
states
[
RUNNING
]
&&
!
states
[
STOPPING
]
&&
!
states
[
STOPPED
])
{
if
((
state
==
STARTING
)
&&
!
states
[
RUNNING
]
&&
!
states
[
STOPPING
]
&&
!
states
[
STOPPED
])
{
process_unlock
();
process_unlock
();
TRACE
(
"container is in %s state and caller requested to be "
TRACE
(
"Container is in %s state and caller requested to be "
"informed about a previous state"
,
"informed about a previous state"
,
lxc_state2str
(
state
));
lxc_state2str
(
state
));
return
state
;
return
state
;
}
else
if
((
state
==
RUNNING
)
&&
!
states
[
STOPPING
]
&&
!
states
[
STOPPED
])
{
}
else
if
((
state
==
RUNNING
)
&&
!
states
[
STOPPING
]
&&
!
states
[
STOPPED
])
{
process_unlock
();
process_unlock
();
TRACE
(
"container is in %s state and caller requested to be "
TRACE
(
"Container is in %s state and caller requested to be "
"informed about a previous state"
,
"informed about a previous state"
,
lxc_state2str
(
state
));
lxc_state2str
(
state
));
return
state
;
return
state
;
}
else
if
((
state
==
STOPPING
)
&&
!
states
[
STOPPED
])
{
}
else
if
((
state
==
STOPPING
)
&&
!
states
[
STOPPED
])
{
process_unlock
();
process_unlock
();
TRACE
(
"container is in %s state and caller requested to be "
TRACE
(
"Container is in %s state and caller requested to be "
"informed about a previous state"
,
"informed about a previous state"
,
lxc_state2str
(
state
));
lxc_state2str
(
state
));
return
state
;
return
state
;
}
else
if
((
state
==
STOPPED
)
||
(
state
==
ABORTING
))
{
}
else
if
((
state
==
STOPPED
)
||
(
state
==
ABORTING
))
{
process_unlock
();
process_unlock
();
TRACE
(
"container is in %s state and caller requested to be "
TRACE
(
"Container is in %s state and caller requested to be "
"informed about a previous state"
,
"informed about a previous state"
,
lxc_state2str
(
state
));
lxc_state2str
(
state
));
return
state
;
return
state
;
}
}
ret
=
lxc_cmd
(
name
,
&
cmd
,
&
stopped
,
lxcpath
,
NULL
);
ret
=
lxc_cmd
(
name
,
&
cmd
,
&
stopped
,
lxcpath
,
NULL
);
process_unlock
();
process_unlock
();
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
ERROR
(
"
failed to execute command: %s
"
,
strerror
(
errno
));
ERROR
(
"
%s - Failed to execute command
"
,
strerror
(
errno
));
return
-
1
;
return
-
1
;
}
}
/* We should now be guaranteed to get an answer from the state sending
/* We should now be guaranteed to get an answer from the state sending
* function.
* function.
*/
*/
if
(
cmd
.
rsp
.
ret
<
0
)
{
if
(
cmd
.
rsp
.
ret
<
0
)
{
ERROR
(
"
f
ailed to receive socket fd"
);
ERROR
(
"
F
ailed to receive socket fd"
);
return
-
1
;
return
-
1
;
}
}
...
@@ -962,20 +966,14 @@ static int lxc_cmd_add_state_client_callback(int fd, struct lxc_cmd_req *req,
...
@@ -962,20 +966,14 @@ static int lxc_cmd_add_state_client_callback(int fd, struct lxc_cmd_req *req,
{
{
struct
lxc_cmd_rsp
rsp
=
{
0
};
struct
lxc_cmd_rsp
rsp
=
{
0
};
if
(
req
->
datalen
<
0
)
{
if
(
req
->
datalen
<
0
)
TRACE
(
"Requested datalen was < 0"
);
return
-
1
;
return
-
1
;
}
if
(
req
->
datalen
>
(
sizeof
(
lxc_state_t
)
*
MAX_STATE
))
{
if
(
req
->
datalen
>
(
sizeof
(
lxc_state_t
)
*
MAX_STATE
))
TRACE
(
"Requested datalen was too large"
);
return
-
1
;
return
-
1
;
}
if
(
!
req
->
data
)
{
if
(
!
req
->
data
)
TRACE
(
"No states requested"
);
return
-
1
;
return
-
1
;
}
rsp
.
ret
=
lxc_add_state_client
(
fd
,
handler
,
(
lxc_state_t
*
)
req
->
data
);
rsp
.
ret
=
lxc_add_state_client
(
fd
,
handler
,
(
lxc_state_t
*
)
req
->
data
);
if
(
rsp
.
ret
<
0
)
if
(
rsp
.
ret
<
0
)
...
@@ -986,6 +984,92 @@ static int lxc_cmd_add_state_client_callback(int fd, struct lxc_cmd_req *req,
...
@@ -986,6 +984,92 @@ static int lxc_cmd_add_state_client_callback(int fd, struct lxc_cmd_req *req,
return
lxc_cmd_rsp_send
(
fd
,
&
rsp
);
return
lxc_cmd_rsp_send
(
fd
,
&
rsp
);
}
}
int
lxc_cmd_console_log
(
const
char
*
name
,
const
char
*
lxcpath
,
struct
lxc_console_log
*
log
)
{
int
ret
,
stopped
;
struct
lxc_cmd_console_log
data
;
struct
lxc_cmd_rr
cmd
;
data
.
clear
=
log
->
clear
;
data
.
read
=
log
->
read
;
data
.
read_max
=
*
log
->
read_max
;
data
.
write_logfile
=
log
->
write_logfile
;
cmd
.
req
.
cmd
=
LXC_CMD_CONSOLE_LOG
;
cmd
.
req
.
data
=
&
data
;
cmd
.
req
.
datalen
=
sizeof
(
struct
lxc_cmd_console_log
);
ret
=
lxc_cmd
(
name
,
&
cmd
,
&
stopped
,
lxcpath
,
NULL
);
if
(
ret
<
0
)
return
ret
;
/* There is nothing to be read from the buffer. So clear any values we
* where passed to clearly indicate to the user that nothing went wrong.
*/
if
(
cmd
.
rsp
.
ret
==
-
ENODATA
||
cmd
.
rsp
.
ret
==
-
EFAULT
||
cmd
.
rsp
.
ret
==
-
ENOENT
)
{
*
log
->
read_max
=
0
;
log
->
data
=
NULL
;
}
/* This is a proper error so don't touch any values we were passed. */
if
(
cmd
.
rsp
.
ret
<
0
)
return
cmd
.
rsp
.
ret
;
*
log
->
read_max
=
cmd
.
rsp
.
datalen
;
log
->
data
=
cmd
.
rsp
.
data
;
return
0
;
}
static
int
lxc_cmd_console_log_callback
(
int
fd
,
struct
lxc_cmd_req
*
req
,
struct
lxc_handler
*
handler
)
{
struct
lxc_cmd_rsp
rsp
;
uint64_t
logsize
=
handler
->
conf
->
console
.
log_size
;
const
struct
lxc_cmd_console_log
*
log
=
req
->
data
;
struct
lxc_console
*
console
=
&
handler
->
conf
->
console
;
struct
lxc_ringbuf
*
buf
=
&
handler
->
conf
->
console
.
ringbuf
;
rsp
.
ret
=
-
EFAULT
;
rsp
.
datalen
=
0
;
rsp
.
data
=
NULL
;
if
(
logsize
<=
0
)
goto
out
;
rsp
.
datalen
=
lxc_ringbuf_used
(
buf
);
if
(
log
->
read
)
rsp
.
data
=
lxc_ringbuf_get_read_addr
(
buf
);
if
(
log
->
read_max
>
0
&&
(
log
->
read_max
<=
rsp
.
datalen
))
rsp
.
datalen
=
log
->
read_max
;
/* there's nothing to read */
rsp
.
ret
=
-
ENODATA
;
if
(
log
->
read
&&
(
buf
->
r_off
==
buf
->
w_off
))
goto
out
;
if
(
log
->
write_logfile
&&
rsp
.
datalen
>
0
)
{
rsp
.
ret
=
-
ENOENT
;
if
(
!
console
->
log_path
)
goto
out
;
rsp
.
ret
=
lxc_console_write_ringbuffer
(
console
);
if
(
rsp
.
ret
<
0
)
goto
out
;
}
rsp
.
ret
=
0
;
if
(
log
->
clear
)
lxc_ringbuf_clear
(
buf
);
else
if
(
rsp
.
datalen
>
0
)
lxc_ringbuf_move_read_addr
(
buf
,
rsp
.
datalen
);
out:
return
lxc_cmd_rsp_send
(
fd
,
&
rsp
);
}
static
int
lxc_cmd_process
(
int
fd
,
struct
lxc_cmd_req
*
req
,
static
int
lxc_cmd_process
(
int
fd
,
struct
lxc_cmd_req
*
req
,
struct
lxc_handler
*
handler
)
struct
lxc_handler
*
handler
)
{
{
...
@@ -1004,10 +1088,11 @@ static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,
...
@@ -1004,10 +1088,11 @@ static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,
[
LXC_CMD_GET_LXCPATH
]
=
lxc_cmd_get_lxcpath_callback
,
[
LXC_CMD_GET_LXCPATH
]
=
lxc_cmd_get_lxcpath_callback
,
[
LXC_CMD_ADD_STATE_CLIENT
]
=
lxc_cmd_add_state_client_callback
,
[
LXC_CMD_ADD_STATE_CLIENT
]
=
lxc_cmd_add_state_client_callback
,
[
LXC_CMD_SET_CONFIG_ITEM
]
=
lxc_cmd_set_config_item_callback
,
[
LXC_CMD_SET_CONFIG_ITEM
]
=
lxc_cmd_set_config_item_callback
,
[
LXC_CMD_CONSOLE_LOG
]
=
lxc_cmd_console_log_callback
,
};
};
if
(
req
->
cmd
>=
LXC_CMD_MAX
)
{
if
(
req
->
cmd
>=
LXC_CMD_MAX
)
{
ERROR
(
"Undefined command id %d
received.
"
,
req
->
cmd
);
ERROR
(
"Undefined command id %d"
,
req
->
cmd
);
return
-
1
;
return
-
1
;
}
}
return
cb
[
req
->
cmd
](
fd
,
req
,
handler
);
return
cb
[
req
->
cmd
](
fd
,
req
,
handler
);
...
@@ -1026,69 +1111,83 @@ static int lxc_cmd_handler(int fd, uint32_t events, void *data,
...
@@ -1026,69 +1111,83 @@ static int lxc_cmd_handler(int fd, uint32_t events, void *data,
{
{
int
ret
;
int
ret
;
struct
lxc_cmd_req
req
;
struct
lxc_cmd_req
req
;
void
*
reqdata
=
NULL
;
struct
lxc_handler
*
handler
=
data
;
struct
lxc_handler
*
handler
=
data
;
ret
=
lxc_abstract_unix_rcv_credential
(
fd
,
&
req
,
sizeof
(
req
));
ret
=
lxc_abstract_unix_rcv_credential
(
fd
,
&
req
,
sizeof
(
req
));
if
(
ret
==
-
EACCES
)
{
if
(
ret
==
-
EACCES
)
{
/*
we don't care for the peer, just send and close
*/
/*
We don't care for the peer, just send and close.
*/
struct
lxc_cmd_rsp
rsp
=
{
.
ret
=
ret
};
struct
lxc_cmd_rsp
rsp
=
{
.
ret
=
ret
};
lxc_cmd_rsp_send
(
fd
,
&
rsp
);
lxc_cmd_rsp_send
(
fd
,
&
rsp
);
goto
out_close
;
goto
out_close
;
}
}
TRACE
(
"Processing
\"
%s
\"
command"
,
lxc_cmd_str
(
req
.
cmd
));
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to receive data on command socket for
\"
%s
\"
"
,
SYSERROR
(
"Failed to receive data on command socket for
command "
lxc_cmd_str
(
req
.
cmd
));
"
\"
%s
\"
"
,
lxc_cmd_str
(
req
.
cmd
));
goto
out_close
;
goto
out_close
;
}
}
if
(
!
ret
)
{
if
(
ret
==
0
)
DEBUG
(
"Peer has disconnected for
\"
%s
\"
"
,
lxc_cmd_str
(
req
.
cmd
));
goto
out_close
;
goto
out_close
;
}
if
(
ret
!=
sizeof
(
req
))
{
if
(
ret
!=
sizeof
(
req
))
{
WARN
(
"Failed to receive full command request. Ignoring request "
WARN
(
"Failed to receive full command request. Ignoring request "
"for
\"
%s
\"
"
,
"for
\"
%s
\"
"
,
lxc_cmd_str
(
req
.
cmd
));
lxc_cmd_str
(
req
.
cmd
));
ret
=
-
1
;
ret
=
-
1
;
goto
out_close
;
goto
out_close
;
}
}
if
(
req
.
datalen
>
LXC_CMD_DATA_MAX
)
{
if
((
req
.
datalen
>
LXC_CMD_DATA_MAX
)
&&
(
req
.
cmd
!=
LXC_CMD_CONSOLE_LOG
))
{
ERROR
(
"Received command data length %d is too large for "
ERROR
(
"Received command data length %d is too large for "
"command
\"
%s
\"
"
,
"command
\"
%s
\"
"
,
req
.
datalen
,
lxc_cmd_str
(
req
.
cmd
));
req
.
datalen
,
lxc_cmd_str
(
req
.
cmd
))
;
errno
=
EFBIG
;
ret
=
-
1
;
ret
=
-
EFBIG
;
goto
out_close
;
goto
out_close
;
}
}
if
(
req
.
datalen
>
0
)
{
if
(
req
.
datalen
>
0
)
{
void
*
reqdata
;
/* LXC_CMD_CONSOLE_LOG needs to be able to allocate data
* that exceeds LXC_CMD_DATA_MAX: use malloc() for that.
*/
if
(
req
.
cmd
==
LXC_CMD_CONSOLE_LOG
)
reqdata
=
malloc
(
req
.
datalen
);
else
reqdata
=
alloca
(
req
.
datalen
);
reqdata
=
alloca
(
req
.
datalen
);
if
(
!
reqdata
)
{
ERROR
(
"Failed to allocate memory for
\"
%s
\"
command"
,
lxc_cmd_str
(
req
.
cmd
));
errno
=
ENOMEM
;
ret
=
-
ENOMEM
;
goto
out_close
;
}
ret
=
recv
(
fd
,
reqdata
,
req
.
datalen
,
0
);
ret
=
recv
(
fd
,
reqdata
,
req
.
datalen
,
0
);
if
(
ret
!=
req
.
datalen
)
{
if
(
ret
!=
req
.
datalen
)
{
WARN
(
"Failed to receive full command request. Ignoring "
WARN
(
"Failed to receive full command request. Ignoring "
"request for
\"
%s
\"
"
,
"request for
\"
%s
\"
"
,
lxc_cmd_str
(
req
.
cmd
));
lxc_cmd_str
(
req
.
cmd
));
ret
=
-
1
;
ret
=
-
1
;
goto
out_close
;
goto
out_close
;
}
}
req
.
data
=
reqdata
;
req
.
data
=
reqdata
;
}
}
ret
=
lxc_cmd_process
(
fd
,
&
req
,
handler
);
ret
=
lxc_cmd_process
(
fd
,
&
req
,
handler
);
if
(
ret
)
{
if
(
ret
)
{
/*
this is not an error, but only a request to close fd
*/
/*
This is not an error, but only a request to close fd.
*/
ret
=
0
;
ret
=
0
;
goto
out_close
;
goto
out_close
;
}
}
out:
out:
if
(
req
.
cmd
==
LXC_CMD_CONSOLE_LOG
&&
reqdata
)
free
(
reqdata
);
return
ret
;
return
ret
;
out_close:
out_close:
lxc_cmd_fd_cleanup
(
fd
,
handler
,
descr
);
lxc_cmd_fd_cleanup
(
fd
,
handler
,
descr
);
goto
out
;
goto
out
;
...
@@ -1097,7 +1196,8 @@ out_close:
...
@@ -1097,7 +1196,8 @@ out_close:
static
int
lxc_cmd_accept
(
int
fd
,
uint32_t
events
,
void
*
data
,
static
int
lxc_cmd_accept
(
int
fd
,
uint32_t
events
,
void
*
data
,
struct
lxc_epoll_descr
*
descr
)
struct
lxc_epoll_descr
*
descr
)
{
{
int
opt
=
1
,
ret
=
-
1
,
connection
;
int
connection
;
int
opt
=
1
,
ret
=
-
1
;
connection
=
accept
(
fd
,
NULL
,
0
);
connection
=
accept
(
fd
,
NULL
,
0
);
if
(
connection
<
0
)
{
if
(
connection
<
0
)
{
...
@@ -1105,20 +1205,21 @@ static int lxc_cmd_accept(int fd, uint32_t events, void *data,
...
@@ -1105,20 +1205,21 @@ static int lxc_cmd_accept(int fd, uint32_t events, void *data,
return
-
1
;
return
-
1
;
}
}
if
(
fcntl
(
connection
,
F_SETFD
,
FD_CLOEXEC
))
{
ret
=
fcntl
(
connection
,
F_SETFD
,
FD_CLOEXEC
);
SYSERROR
(
"Failed to set close-on-exec on incoming command connection."
);
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to set close-on-exec on incoming command connection"
);
goto
out_close
;
goto
out_close
;
}
}
if
(
setsockopt
(
connection
,
SOL_SOCKET
,
ret
=
setsockopt
(
connection
,
SOL_SOCKET
,
SO_PASSCRED
,
&
opt
,
sizeof
(
opt
));
SO_PASSCRED
,
&
opt
,
sizeof
(
opt
))
)
{
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to enable necessary credentials on command socket
.
"
);
SYSERROR
(
"Failed to enable necessary credentials on command socket"
);
goto
out_close
;
goto
out_close
;
}
}
ret
=
lxc_mainloop_add_handler
(
descr
,
connection
,
lxc_cmd_handler
,
data
);
ret
=
lxc_mainloop_add_handler
(
descr
,
connection
,
lxc_cmd_handler
,
data
);
if
(
ret
)
{
if
(
ret
)
{
ERROR
(
"Failed to add command handler
.
"
);
ERROR
(
"Failed to add command handler"
);
goto
out_close
;
goto
out_close
;
}
}
...
@@ -1133,10 +1234,9 @@ out_close:
...
@@ -1133,10 +1234,9 @@ out_close:
int
lxc_cmd_init
(
const
char
*
name
,
struct
lxc_handler
*
handler
,
int
lxc_cmd_init
(
const
char
*
name
,
struct
lxc_handler
*
handler
,
const
char
*
lxcpath
)
const
char
*
lxcpath
)
{
{
int
fd
;
int
fd
,
len
,
ret
;
char
path
[
sizeof
(((
struct
sockaddr_un
*
)
0
)
->
sun_path
)]
=
{
0
};
char
path
[
sizeof
(((
struct
sockaddr_un
*
)
0
)
->
sun_path
)]
=
{
0
};
char
*
offset
=
&
path
[
1
];
char
*
offset
=
&
path
[
1
];
int
len
;
/* -2 here because this is an abstract unix socket so it needs a
/* -2 here because this is an abstract unix socket so it needs a
* leading \0, and we null terminate, so it needs a trailing \0.
* leading \0, and we null terminate, so it needs a trailing \0.
...
@@ -1144,21 +1244,22 @@ int lxc_cmd_init(const char *name, struct lxc_handler *handler,
...
@@ -1144,21 +1244,22 @@ int lxc_cmd_init(const char *name, struct lxc_handler *handler,
* because we print the sockname out sometimes.
* because we print the sockname out sometimes.
*/
*/
len
=
sizeof
(
path
)
-
2
;
len
=
sizeof
(
path
)
-
2
;
if
(
lxc_make_abstract_socket_name
(
offset
,
len
,
name
,
lxcpath
,
NULL
,
ret
=
lxc_make_abstract_socket_name
(
offset
,
len
,
name
,
lxcpath
,
NULL
,
"command"
);
"command"
)
)
if
(
ret
<
0
)
return
-
1
;
return
-
1
;
fd
=
lxc_abstract_unix_open
(
path
,
SOCK_STREAM
,
0
);
fd
=
lxc_abstract_unix_open
(
path
,
SOCK_STREAM
,
0
);
if
(
fd
<
0
)
{
if
(
fd
<
0
)
{
ERROR
(
"
Failed to create the command service point %s: %s.
"
,
ERROR
(
"
%s - Failed to create command socket %s
"
,
offset
,
strerror
(
errno
)
);
strerror
(
errno
),
offset
);
if
(
errno
==
EADDRINUSE
)
if
(
errno
==
EADDRINUSE
)
ERROR
(
"Container
\"
%s
\"
appears to be already running
!
"
,
name
);
ERROR
(
"Container
\"
%s
\"
appears to be already running"
,
name
);
return
-
1
;
return
-
1
;
}
}
if
(
fcntl
(
fd
,
F_SETFD
,
FD_CLOEXEC
))
{
ret
=
fcntl
(
fd
,
F_SETFD
,
FD_CLOEXEC
);
SYSERROR
(
"Failed to set FD_CLOEXEC on signal file descriptor."
);
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to set FD_CLOEXEC on command socket file descriptor"
);
close
(
fd
);
close
(
fd
);
return
-
1
;
return
-
1
;
}
}
...
@@ -1167,15 +1268,15 @@ int lxc_cmd_init(const char *name, struct lxc_handler *handler,
...
@@ -1167,15 +1268,15 @@ int lxc_cmd_init(const char *name, struct lxc_handler *handler,
return
0
;
return
0
;
}
}
int
lxc_cmd_mainloop_add
(
const
char
*
name
,
int
lxc_cmd_mainloop_add
(
const
char
*
name
,
struct
lxc_epoll_descr
*
descr
,
struct
lxc_epoll_descr
*
descr
,
struct
lxc_handler
*
handler
)
struct
lxc_handler
*
handler
)
{
{
int
ret
,
fd
=
handler
->
conf
->
maincmd_fd
;
int
ret
;
int
fd
=
handler
->
conf
->
maincmd_fd
;
ret
=
lxc_mainloop_add_handler
(
descr
,
fd
,
lxc_cmd_accept
,
handler
);
ret
=
lxc_mainloop_add_handler
(
descr
,
fd
,
lxc_cmd_accept
,
handler
);
if
(
ret
)
{
if
(
ret
<
0
)
{
ERROR
(
"Failed to add handler for command socket
.
"
);
ERROR
(
"Failed to add handler for command socket"
);
close
(
fd
);
close
(
fd
);
}
}
...
...
src/lxc/commands.h
View file @
5cc2545c
...
@@ -29,6 +29,7 @@
...
@@ -29,6 +29,7 @@
#include <sys/types.h>
#include <sys/types.h>
#include "state.h"
#include "state.h"
#include "lxccontainer.h"
#define LXC_CMD_DATA_MAX (MAXPATHLEN * 2)
#define LXC_CMD_DATA_MAX (MAXPATHLEN * 2)
...
@@ -49,6 +50,7 @@ typedef enum {
...
@@ -49,6 +50,7 @@ typedef enum {
LXC_CMD_GET_LXCPATH
,
LXC_CMD_GET_LXCPATH
,
LXC_CMD_ADD_STATE_CLIENT
,
LXC_CMD_ADD_STATE_CLIENT
,
LXC_CMD_SET_CONFIG_ITEM
,
LXC_CMD_SET_CONFIG_ITEM
,
LXC_CMD_CONSOLE_LOG
,
LXC_CMD_MAX
,
LXC_CMD_MAX
,
}
lxc_cmd_t
;
}
lxc_cmd_t
;
...
@@ -79,6 +81,14 @@ struct lxc_cmd_set_config_item_req_data {
...
@@ -79,6 +81,14 @@ struct lxc_cmd_set_config_item_req_data {
void
*
value
;
void
*
value
;
};
};
struct
lxc_cmd_console_log
{
bool
clear
;
bool
read
;
uint64_t
read_max
;
bool
write_logfile
;
};
extern
int
lxc_cmd_console_winch
(
const
char
*
name
,
const
char
*
lxcpath
);
extern
int
lxc_cmd_console_winch
(
const
char
*
name
,
const
char
*
lxcpath
);
extern
int
lxc_cmd_console
(
const
char
*
name
,
int
*
ttynum
,
int
*
fd
,
extern
int
lxc_cmd_console
(
const
char
*
name
,
int
*
ttynum
,
int
*
fd
,
const
char
*
lxcpath
);
const
char
*
lxcpath
);
...
@@ -124,5 +134,7 @@ extern int lxc_try_cmd(const char *name, const char *lxcpath);
...
@@ -124,5 +134,7 @@ extern int lxc_try_cmd(const char *name, const char *lxcpath);
extern
int
lxc_cmd_set_config_item
(
const
char
*
name
,
const
char
*
item
,
extern
int
lxc_cmd_set_config_item
(
const
char
*
name
,
const
char
*
item
,
const
char
*
value
,
const
char
*
lxcpath
);
const
char
*
value
,
const
char
*
lxcpath
);
extern
int
lxc_cmd_console_log
(
const
char
*
name
,
const
char
*
lxcpath
,
struct
lxc_console_log
*
log
);
#endif
/* __commands_h */
#endif
/* __commands_h */
src/lxc/conf.c
View file @
5cc2545c
...
@@ -3083,65 +3083,7 @@ static bool verify_start_hooks(struct lxc_conf *conf)
...
@@ -3083,65 +3083,7 @@ static bool verify_start_hooks(struct lxc_conf *conf)
return
true
;
return
true
;
}
}
/**
int
lxc_setup
(
struct
lxc_handler
*
handler
)
* Note that this function needs to run before the mainloop starts. Since we
* register a handler for the console's masterfd when we create the mainloop
* the console handler needs to see an allocated ringbuffer.
*/
static
int
lxc_setup_console_ringbuf
(
struct
lxc_console
*
console
)
{
int
ret
;
struct
lxc_ringbuf
*
buf
=
&
console
->
ringbuf
;
uint64_t
size
=
console
->
log_size
;
/* no ringbuffer previously allocated and no ringbuffer requested */
if
(
!
buf
->
addr
&&
size
<=
0
)
return
0
;
/* ringbuffer allocated but no new ringbuffer requested */
if
(
buf
->
addr
&&
size
<=
0
)
{
lxc_ringbuf_release
(
buf
);
buf
->
addr
=
NULL
;
buf
->
r_off
=
0
;
buf
->
w_off
=
0
;
buf
->
size
=
0
;
TRACE
(
"Deallocated console ringbuffer"
);
return
0
;
}
if
(
size
<=
0
)
return
0
;
/* check wether the requested size for the ringbuffer has changed */
if
(
buf
->
addr
&&
buf
->
size
!=
size
)
{
TRACE
(
"Console ringbuffer size changed from %"
PRIu64
" to %"
PRIu64
" bytes. Deallocating console ringbuffer"
,
buf
->
size
,
size
);
lxc_ringbuf_release
(
buf
);
}
ret
=
lxc_ringbuf_create
(
buf
,
size
);
if
(
ret
<
0
)
{
ERROR
(
"Failed to setup %"
PRIu64
" byte console ringbuffer"
,
size
);
return
-
1
;
}
TRACE
(
"Allocated %"
PRIu64
" byte console ringbuffer"
,
size
);
return
0
;
}
int
lxc_setup_parent
(
struct
lxc_handler
*
handler
)
{
int
ret
;
ret
=
lxc_setup_console_ringbuf
(
&
handler
->
conf
->
console
);
if
(
ret
<
0
)
return
-
1
;
return
0
;
}
int
lxc_setup_child
(
struct
lxc_handler
*
handler
)
{
{
int
ret
;
int
ret
;
const
char
*
name
=
handler
->
name
;
const
char
*
name
=
handler
->
name
;
...
...
src/lxc/conf.h
View file @
5cc2545c
...
@@ -379,7 +379,7 @@ extern int lxc_delete_autodev(struct lxc_handler *handler);
...
@@ -379,7 +379,7 @@ extern int lxc_delete_autodev(struct lxc_handler *handler);
extern
void
lxc_clear_includes
(
struct
lxc_conf
*
conf
);
extern
void
lxc_clear_includes
(
struct
lxc_conf
*
conf
);
extern
int
do_rootfs_setup
(
struct
lxc_conf
*
conf
,
const
char
*
name
,
extern
int
do_rootfs_setup
(
struct
lxc_conf
*
conf
,
const
char
*
name
,
const
char
*
lxcpath
);
const
char
*
lxcpath
);
extern
int
lxc_setup
_child
(
struct
lxc_handler
*
handler
);
extern
int
lxc_setup
(
struct
lxc_handler
*
handler
);
extern
int
lxc_setup_parent
(
struct
lxc_handler
*
handler
);
extern
int
lxc_setup_parent
(
struct
lxc_handler
*
handler
);
extern
int
setup_resource_limits
(
struct
lxc_list
*
limits
,
pid_t
pid
);
extern
int
setup_resource_limits
(
struct
lxc_list
*
limits
,
pid_t
pid
);
extern
int
find_unmapped_nsid
(
struct
lxc_conf
*
conf
,
enum
idtype
idtype
);
extern
int
find_unmapped_nsid
(
struct
lxc_conf
*
conf
,
enum
idtype
idtype
);
...
...
src/lxc/console.c
View file @
5cc2545c
...
@@ -512,11 +512,50 @@ out:
...
@@ -512,11 +512,50 @@ out:
return
ret
;
return
ret
;
}
}
int
lxc_console_write_ringbuffer
(
struct
lxc_console
*
console
)
{
int
fd
;
char
*
r_addr
;
ssize_t
ret
;
uint64_t
used
;
struct
lxc_ringbuf
*
buf
=
&
console
->
ringbuf
;
if
(
!
console
->
log_path
)
return
0
;
used
=
lxc_ringbuf_used
(
buf
);
if
(
used
==
0
)
return
0
;
fd
=
lxc_unpriv
(
open
(
console
->
log_path
,
O_CLOEXEC
|
O_RDWR
|
O_CREAT
|
O_TRUNC
,
0600
));
if
(
fd
<
0
)
{
SYSERROR
(
"Failed to open console log file
\"
%s
\"
"
,
console
->
log_path
);
return
-
EIO
;
}
DEBUG
(
"Using
\"
%s
\"
as console log file"
,
console
->
log_path
);
r_addr
=
lxc_ringbuf_get_read_addr
(
buf
);
ret
=
lxc_write_nointr
(
fd
,
r_addr
,
used
);
close
(
fd
);
if
(
ret
<
0
)
return
-
EIO
;
return
0
;
}
void
lxc_console_delete
(
struct
lxc_console
*
console
)
void
lxc_console_delete
(
struct
lxc_console
*
console
)
{
{
if
(
console
->
tios
&&
console
->
peer
>=
0
&&
int
ret
;
tcsetattr
(
console
->
peer
,
TCSAFLUSH
,
console
->
tios
))
WARN
(
"failed to set old terminal settings"
);
ret
=
lxc_console_write_ringbuffer
(
console
);
if
(
ret
<
0
)
WARN
(
"Failed to write console log to disk"
);
if
(
console
->
tios
&&
console
->
peer
>=
0
)
{
ret
=
tcsetattr
(
console
->
peer
,
TCSAFLUSH
,
console
->
tios
);
if
(
ret
<
0
)
WARN
(
"%s - Failed to set old terminal settings"
,
strerror
(
errno
));
}
free
(
console
->
tios
);
free
(
console
->
tios
);
console
->
tios
=
NULL
;
console
->
tios
=
NULL
;
...
@@ -525,66 +564,120 @@ void lxc_console_delete(struct lxc_console *console)
...
@@ -525,66 +564,120 @@ void lxc_console_delete(struct lxc_console *console)
close
(
console
->
slave
);
close
(
console
->
slave
);
if
(
console
->
log_fd
>=
0
)
if
(
console
->
log_fd
>=
0
)
close
(
console
->
log_fd
);
close
(
console
->
log_fd
);
console
->
peer
=
-
1
;
console
->
peer
=
-
1
;
console
->
master
=
-
1
;
console
->
master
=
-
1
;
console
->
slave
=
-
1
;
console
->
slave
=
-
1
;
console
->
log_fd
=
-
1
;
console
->
log_fd
=
-
1
;
}
}
/**
* Note that this function needs to run before the mainloop starts. Since we
* register a handler for the console's masterfd when we create the mainloop
* the console handler needs to see an allocated ringbuffer.
*/
static
int
lxc_setup_console_ringbuf
(
struct
lxc_console
*
console
)
{
int
ret
;
struct
lxc_ringbuf
*
buf
=
&
console
->
ringbuf
;
uint64_t
size
=
console
->
log_size
;
/* no ringbuffer previously allocated and no ringbuffer requested */
if
(
!
buf
->
addr
&&
size
<=
0
)
return
0
;
/* ringbuffer allocated but no new ringbuffer requested */
if
(
buf
->
addr
&&
size
<=
0
)
{
lxc_ringbuf_release
(
buf
);
buf
->
addr
=
NULL
;
buf
->
r_off
=
0
;
buf
->
w_off
=
0
;
buf
->
size
=
0
;
TRACE
(
"Deallocated console ringbuffer"
);
return
0
;
}
if
(
size
<=
0
)
return
0
;
/* check wether the requested size for the ringbuffer has changed */
if
(
buf
->
addr
&&
buf
->
size
!=
size
)
{
TRACE
(
"Console ringbuffer size changed from %"
PRIu64
" to %"
PRIu64
" bytes. Deallocating console ringbuffer"
,
buf
->
size
,
size
);
lxc_ringbuf_release
(
buf
);
}
ret
=
lxc_ringbuf_create
(
buf
,
size
);
if
(
ret
<
0
)
{
ERROR
(
"Failed to setup %"
PRIu64
" byte console ringbuffer"
,
size
);
return
-
1
;
}
TRACE
(
"Allocated %"
PRIu64
" byte console ringbuffer"
,
size
);
return
0
;
}
int
lxc_console_create
(
struct
lxc_conf
*
conf
)
int
lxc_console_create
(
struct
lxc_conf
*
conf
)
{
{
int
ret
,
saved_errno
;
struct
lxc_console
*
console
=
&
conf
->
console
;
struct
lxc_console
*
console
=
&
conf
->
console
;
int
ret
;
if
(
!
conf
->
rootfs
.
path
)
{
if
(
!
conf
->
rootfs
.
path
)
{
INFO
(
"container does not have a rootfs, console device will be shared with the host"
);
INFO
(
"Container does not have a rootfs. The console will be "
"shared with the host"
);
return
0
;
return
0
;
}
}
if
(
console
->
path
&&
!
strcmp
(
console
->
path
,
"none"
))
{
if
(
console
->
path
&&
!
strcmp
(
console
->
path
,
"none"
))
{
INFO
(
"
no console
requested"
);
INFO
(
"
No console was
requested"
);
return
0
;
return
0
;
}
}
process_lock
();
process_lock
();
ret
=
openpty
(
&
console
->
master
,
&
console
->
slave
,
console
->
name
,
NULL
,
NULL
);
ret
=
openpty
(
&
console
->
master
,
&
console
->
slave
,
console
->
name
,
NULL
,
NULL
);
saved_errno
=
errno
;
process_unlock
();
process_unlock
();
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
SYSERROR
(
"failed to allocate a pty"
);
ERROR
(
"%s - Failed to allocate a pty"
,
strerror
(
saved_errno
)
);
return
-
1
;
return
-
1
;
}
}
if
(
fcntl
(
console
->
master
,
F_SETFD
,
FD_CLOEXEC
))
{
ret
=
fcntl
(
console
->
master
,
F_SETFD
,
FD_CLOEXEC
);
SYSERROR
(
"failed to set console master to close-on-exec"
);
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to set FD_CLOEXEC flag on console master"
);
goto
err
;
goto
err
;
}
}
if
(
fcntl
(
console
->
slave
,
F_SETFD
,
FD_CLOEXEC
))
{
ret
=
fcntl
(
console
->
slave
,
F_SETFD
,
FD_CLOEXEC
);
SYSERROR
(
"failed to set console slave to close-on-exec"
);
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to set FD_CLOEXEC flag on console slave"
);
goto
err
;
goto
err
;
}
}
ret
=
lxc_console_peer_default
(
console
);
ret
=
lxc_console_peer_default
(
console
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
ERROR
(
"
failed to allocate peer t
ty device"
);
ERROR
(
"
Failed to allocate a peer p
ty device"
);
goto
err
;
goto
err
;
}
}
if
(
console
->
log_path
)
{
if
(
console
->
log_path
&&
console
->
log_size
<=
0
)
{
console
->
log_fd
=
lxc_unpriv
(
open
(
console
->
log_path
,
O_CLOEXEC
|
O_RDWR
|
O_CREAT
|
O_APPEND
,
0600
));
console
->
log_fd
=
lxc_unpriv
(
open
(
console
->
log_path
,
O_CLOEXEC
|
O_RDWR
|
O_CREAT
|
O_APPEND
,
0600
));
if
(
console
->
log_fd
<
0
)
{
if
(
console
->
log_fd
<
0
)
{
SYSERROR
(
"
f
ailed to open console log file
\"
%s
\"
"
,
console
->
log_path
);
SYSERROR
(
"
F
ailed to open console log file
\"
%s
\"
"
,
console
->
log_path
);
goto
err
;
goto
err
;
}
}
DEBUG
(
"
u
sing
\"
%s
\"
as console log file"
,
console
->
log_path
);
DEBUG
(
"
U
sing
\"
%s
\"
as console log file"
,
console
->
log_path
);
}
}
ret
=
lxc_setup_console_ringbuf
(
console
);
if
(
ret
<
0
)
goto
err
;
return
0
;
return
0
;
err
:
err
:
lxc_console_delete
(
console
);
lxc_console_delete
(
console
);
return
-
1
;
return
-
ENODEV
;
}
}
int
lxc_console_set_stdfds
(
int
fd
)
int
lxc_console_set_stdfds
(
int
fd
)
...
@@ -687,18 +780,16 @@ int lxc_console(struct lxc_container *c, int ttynum,
...
@@ -687,18 +780,16 @@ int lxc_console(struct lxc_container *c, int ttynum,
istty
=
isatty
(
stdinfd
);
istty
=
isatty
(
stdinfd
);
if
(
istty
)
{
if
(
istty
)
{
ret
=
lxc_setup_tios
(
stdinfd
,
&
oldtios
);
ret
=
lxc_setup_tios
(
stdinfd
,
&
oldtios
);
if
(
ret
)
{
if
(
ret
<
0
)
ERROR
(
"failed to setup terminal properties"
);
return
-
1
;
return
-
1
;
}
}
else
{
}
else
{
INFO
(
"
fd
%d does not refer to a tty device"
,
stdinfd
);
INFO
(
"
File descriptor
%d does not refer to a tty device"
,
stdinfd
);
}
}
ttyfd
=
lxc_cmd_console
(
c
->
name
,
&
ttynum
,
&
masterfd
,
c
->
config_path
);
ttyfd
=
lxc_cmd_console
(
c
->
name
,
&
ttynum
,
&
masterfd
,
c
->
config_path
);
if
(
ttyfd
<
0
)
{
if
(
ttyfd
<
0
)
{
ret
=
ttyfd
;
ret
=
ttyfd
;
goto
err1
;
goto
restore_tios
;
}
}
fprintf
(
stderr
,
"
\n
"
fprintf
(
stderr
,
"
\n
"
...
@@ -708,13 +799,13 @@ int lxc_console(struct lxc_container *c, int ttynum,
...
@@ -708,13 +799,13 @@ int lxc_console(struct lxc_container *c, int ttynum,
ttynum
,
'a'
+
escape
-
1
);
ttynum
,
'a'
+
escape
-
1
);
ret
=
setsid
();
ret
=
setsid
();
if
(
ret
)
if
(
ret
<
0
)
INFO
(
"
already group leader"
);
TRACE
(
"Process is
already group leader"
);
ts
=
lxc_console_sigwinch_init
(
stdinfd
,
masterfd
);
ts
=
lxc_console_sigwinch_init
(
stdinfd
,
masterfd
);
if
(
!
ts
)
{
if
(
!
ts
)
{
ret
=
-
1
;
ret
=
-
1
;
goto
err2
;
goto
close_fds
;
}
}
ts
->
escape
=
escape
;
ts
->
escape
=
escape
;
ts
->
winch_proxy
=
c
->
name
;
ts
->
winch_proxy
=
c
->
name
;
...
@@ -728,52 +819,57 @@ int lxc_console(struct lxc_container *c, int ttynum,
...
@@ -728,52 +819,57 @@ int lxc_console(struct lxc_container *c, int ttynum,
ret
=
lxc_mainloop_open
(
&
descr
);
ret
=
lxc_mainloop_open
(
&
descr
);
if
(
ret
)
{
if
(
ret
)
{
ERROR
(
"
f
ailed to create mainloop"
);
ERROR
(
"
F
ailed to create mainloop"
);
goto
err3
;
goto
sigwinch_fini
;
}
}
if
(
ts
->
sigfd
!=
-
1
)
{
if
(
ts
->
sigfd
!=
-
1
)
{
ret
=
lxc_mainloop_add_handler
(
&
descr
,
ts
->
sigfd
,
ret
=
lxc_mainloop_add_handler
(
&
descr
,
ts
->
sigfd
,
lxc_console_cb_sigwinch_fd
,
ts
);
lxc_console_cb_sigwinch_fd
,
ts
);
if
(
ret
)
{
if
(
ret
<
0
)
{
ERROR
(
"
failed to add handler for SIGWINCH fd
"
);
ERROR
(
"
Failed to add SIGWINCH handler
"
);
goto
err4
;
goto
close_mainloop
;
}
}
}
}
ret
=
lxc_mainloop_add_handler
(
&
descr
,
ts
->
stdinfd
,
ret
=
lxc_mainloop_add_handler
(
&
descr
,
ts
->
stdinfd
,
lxc_console_cb_tty_stdin
,
ts
);
lxc_console_cb_tty_stdin
,
ts
);
if
(
ret
)
{
if
(
ret
<
0
)
{
ERROR
(
"
failed to add handler for stdinfd
"
);
ERROR
(
"
Failed to add stdin handler
"
);
goto
err4
;
goto
close_mainloop
;
}
}
ret
=
lxc_mainloop_add_handler
(
&
descr
,
ts
->
masterfd
,
ret
=
lxc_mainloop_add_handler
(
&
descr
,
ts
->
masterfd
,
lxc_console_cb_tty_master
,
ts
);
lxc_console_cb_tty_master
,
ts
);
if
(
ret
)
{
if
(
ret
<
0
)
{
ERROR
(
"
failed to add handler for masterfd
"
);
ERROR
(
"
Failed to add master handler
"
);
goto
err4
;
goto
close_mainloop
;
}
}
ret
=
lxc_mainloop
(
&
descr
,
-
1
);
ret
=
lxc_mainloop
(
&
descr
,
-
1
);
if
(
ret
)
{
if
(
ret
<
0
)
{
ERROR
(
"mainloop returned an error"
);
ERROR
(
"
The
mainloop returned an error"
);
goto
err4
;
goto
close_mainloop
;
}
}
ret
=
0
;
ret
=
0
;
err4
:
close_mainloop
:
lxc_mainloop_close
(
&
descr
);
lxc_mainloop_close
(
&
descr
);
err3
:
sigwinch_fini
:
lxc_console_sigwinch_fini
(
ts
);
lxc_console_sigwinch_fini
(
ts
);
err2
:
close_fds
:
close
(
masterfd
);
close
(
masterfd
);
close
(
ttyfd
);
close
(
ttyfd
);
err1
:
restore_tios
:
if
(
istty
)
{
if
(
istty
)
{
if
(
tcsetattr
(
stdinfd
,
TCSAFLUSH
,
&
oldtios
)
<
0
)
istty
=
tcsetattr
(
stdinfd
,
TCSAFLUSH
,
&
oldtios
);
WARN
(
"failed to reset terminal properties: %s."
,
strerror
(
errno
));
if
(
istty
<
0
)
WARN
(
"%s - Failed to restore terminal properties"
,
strerror
(
errno
));
}
}
return
ret
;
return
ret
;
...
...
src/lxc/console.h
View file @
5cc2545c
...
@@ -215,4 +215,6 @@ extern int lxc_console_cb_sigwinch_fd(int fd, uint32_t events, void *cbdata,
...
@@ -215,4 +215,6 @@ extern int lxc_console_cb_sigwinch_fd(int fd, uint32_t events, void *cbdata,
*/
*/
extern
void
lxc_console_sigwinch_fini
(
struct
lxc_tty_state
*
ts
);
extern
void
lxc_console_sigwinch_fini
(
struct
lxc_tty_state
*
ts
);
extern
int
lxc_console_write_ringbuffer
(
struct
lxc_console
*
console
);
#endif
#endif
src/lxc/lxccontainer.c
View file @
5cc2545c
...
@@ -516,6 +516,29 @@ static int lxcapi_console(struct lxc_container *c, int ttynum, int stdinfd,
...
@@ -516,6 +516,29 @@ static int lxcapi_console(struct lxc_container *c, int ttynum, int stdinfd,
return
ret
;
return
ret
;
}
}
static
int
do_lxcapi_console_log
(
struct
lxc_container
*
c
,
struct
lxc_console_log
*
log
)
{
int
ret
;
ret
=
lxc_cmd_console_log
(
c
->
name
,
do_lxcapi_get_config_path
(
c
),
log
);
if
(
ret
<
0
)
{
if
(
ret
==
-
ENODATA
)
NOTICE
(
"The console log is empty"
);
else
if
(
ret
==
-
EFAULT
)
NOTICE
(
"The container does not keep a console log"
);
else
if
(
ret
==
-
ENOENT
)
NOTICE
(
"The container does not keep a console log file"
);
else
if
(
ret
==
-
EIO
)
NOTICE
(
"Failed to write console log to log file"
);
else
ERROR
(
"Failed to retrieve console log"
);
}
return
ret
;
}
WRAP_API_1
(
int
,
lxcapi_console_log
,
struct
lxc_console_log
*
)
static
pid_t
do_lxcapi_init_pid
(
struct
lxc_container
*
c
)
static
pid_t
do_lxcapi_init_pid
(
struct
lxc_container
*
c
)
{
{
if
(
!
c
)
if
(
!
c
)
...
@@ -4607,6 +4630,7 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
...
@@ -4607,6 +4630,7 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
c
->
checkpoint
=
lxcapi_checkpoint
;
c
->
checkpoint
=
lxcapi_checkpoint
;
c
->
restore
=
lxcapi_restore
;
c
->
restore
=
lxcapi_restore
;
c
->
migrate
=
lxcapi_migrate
;
c
->
migrate
=
lxcapi_migrate
;
c
->
console_log
=
lxcapi_console_log
;
return
c
;
return
c
;
...
...
src/lxc/lxccontainer.h
View file @
5cc2545c
...
@@ -51,6 +51,8 @@ struct lxc_lock;
...
@@ -51,6 +51,8 @@ struct lxc_lock;
struct
migrate_opts
;
struct
migrate_opts
;
struct
lxc_console_log
;
/*!
/*!
* An LXC container.
* An LXC container.
*
*
...
@@ -834,6 +836,16 @@ struct lxc_container {
...
@@ -834,6 +836,16 @@ struct lxc_container {
* \return \c true on success, else \c false.
* \return \c true on success, else \c false.
*/
*/
bool
(
*
set_running_config_item
)(
struct
lxc_container
*
c
,
const
char
*
key
,
const
char
*
value
);
bool
(
*
set_running_config_item
)(
struct
lxc_container
*
c
,
const
char
*
key
,
const
char
*
value
);
/*!
* \brief Query the console log of a container.
*
* \param c Container.
* \param opts A lxc_console_log struct filled with relevant options.
*
* \return \c 0 on success, nonzero on failure.
*/
int
(
*
console_log
)(
struct
lxc_container
*
c
,
struct
lxc_console_log
*
log
);
};
};
/*!
/*!
...
@@ -921,6 +933,34 @@ struct migrate_opts {
...
@@ -921,6 +933,34 @@ struct migrate_opts {
uint64_t
ghost_limit
;
uint64_t
ghost_limit
;
};
};
struct
lxc_console_log
{
/* Clear the console log. */
bool
clear
;
/* Retrieve the console log. */
bool
read
;
/* This specifies the maximum size to read from the ringbuffer. Setting
* it to 0 means that the a read can be as big as the whole ringbuffer.
* On return callers can check how many bytes were actually read.
* If "read" and "clear" are set to false and a non-zero value is
* specified then up to "read_max" bytes of data will be discarded from
* the ringbuffer.
*/
uint64_t
*
read_max
;
/* Data that was read from the ringbuffer. If "read_max" is 0 on return
* "data" is invalid.
*/
char
*
data
;
/* If a console log file was specified this flag indicates whether the
* contents of the ringbuffer should be written to the logfile when a
* request is sent to the ringbuffer.
*/
bool
write_logfile
;
};
/*!
/*!
* \brief Create a new container.
* \brief Create a new container.
*
*
...
...
src/lxc/start.c
View file @
5cc2545c
...
@@ -904,7 +904,7 @@ static int do_start(void *data)
...
@@ -904,7 +904,7 @@ static int do_start(void *data)
}
}
/* Setup the container, ip, names, utsname, ... */
/* Setup the container, ip, names, utsname, ... */
ret
=
lxc_setup
_child
(
handler
);
ret
=
lxc_setup
(
handler
);
close
(
handler
->
data_sock
[
0
]);
close
(
handler
->
data_sock
[
0
]);
close
(
handler
->
data_sock
[
1
]);
close
(
handler
->
data_sock
[
1
]);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
...
@@ -1266,10 +1266,6 @@ static int lxc_spawn(struct lxc_handler *handler)
...
@@ -1266,10 +1266,6 @@ static int lxc_spawn(struct lxc_handler *handler)
flags
&=
~
CLONE_NEWNET
;
flags
&=
~
CLONE_NEWNET
;
}
}
ret
=
lxc_setup_parent
(
handler
);
if
(
ret
<
0
)
goto
out_delete_net
;
if
(
fork_before_clone
)
if
(
fork_before_clone
)
handler
->
pid
=
lxc_fork_attach_clone
(
do_start
,
handler
,
flags
|
CLONE_PARENT
);
handler
->
pid
=
lxc_fork_attach_clone
(
do_start
,
handler
,
flags
|
CLONE_PARENT
);
else
else
...
...
src/tests/Makefile.am
View file @
5cc2545c
...
@@ -15,6 +15,7 @@ lxc_test_lxcpath_SOURCES = lxcpath.c
...
@@ -15,6 +15,7 @@ lxc_test_lxcpath_SOURCES = lxcpath.c
lxc_test_cgpath_SOURCES
=
cgpath.c
lxc_test_cgpath_SOURCES
=
cgpath.c
lxc_test_clonetest_SOURCES
=
clonetest.c
lxc_test_clonetest_SOURCES
=
clonetest.c
lxc_test_console_SOURCES
=
console.c
lxc_test_console_SOURCES
=
console.c
lxc_test_console_log_SOURCES
=
console_log.c lxctest.h
lxc_test_snapshot_SOURCES
=
snapshot.c
lxc_test_snapshot_SOURCES
=
snapshot.c
lxc_test_concurrent_SOURCES
=
concurrent.c
lxc_test_concurrent_SOURCES
=
concurrent.c
lxc_test_may_control_SOURCES
=
may_control.c
lxc_test_may_control_SOURCES
=
may_control.c
...
@@ -52,7 +53,7 @@ endif
...
@@ -52,7 +53,7 @@ endif
bin_PROGRAMS
=
lxc-test-containertests lxc-test-locktests lxc-test-startone
\
bin_PROGRAMS
=
lxc-test-containertests lxc-test-locktests lxc-test-startone
\
lxc-test-destroytest lxc-test-saveconfig lxc-test-createtest
\
lxc-test-destroytest lxc-test-saveconfig lxc-test-createtest
\
lxc-test-shutdowntest lxc-test-get_item lxc-test-getkeys lxc-test-lxcpath
\
lxc-test-shutdowntest lxc-test-get_item lxc-test-getkeys lxc-test-lxcpath
\
lxc-test-cgpath lxc-test-clonetest lxc-test-console
\
lxc-test-cgpath lxc-test-clonetest lxc-test-console
lxc-test-console-log
\
lxc-test-snapshot lxc-test-concurrent lxc-test-may-control
\
lxc-test-snapshot lxc-test-concurrent lxc-test-may-control
\
lxc-test-reboot lxc-test-list lxc-test-attach lxc-test-device-add-remove
\
lxc-test-reboot lxc-test-list lxc-test-attach lxc-test-device-add-remove
\
lxc-test-apparmor lxc-test-utils lxc-test-parse-config-file
\
lxc-test-apparmor lxc-test-utils lxc-test-parse-config-file
\
...
@@ -85,6 +86,7 @@ EXTRA_DIST = \
...
@@ -85,6 +86,7 @@ EXTRA_DIST = \
concurrent.c
\
concurrent.c
\
config_jump_table.c
\
config_jump_table.c
\
console.c
\
console.c
\
console_log.c
\
containertests.c
\
containertests.c
\
createtest.c
\
createtest.c
\
destroytest.c
\
destroytest.c
\
...
...
src/tests/console_log.c
0 → 100644
View file @
5cc2545c
/* liblxcapi
*
* Copyright © 2017 Christian Brauner <christian.brauner@ubuntu.com>.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#define __STDC_FORMAT_MACROS
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <lxc/lxccontainer.h>
#include "lxctest.h"
#include "utils.h"
int
main
(
int
argc
,
char
*
argv
[])
{
int
logfd
,
ret
;
char
buf
[
4096
+
1
];
ssize_t
bytes
;
struct
stat
st
;
struct
lxc_container
*
c
;
struct
lxc_console_log
log
;
bool
do_unlink
=
false
;
int
fret
=
EXIT_FAILURE
;
c
=
lxc_container_new
(
"console-log"
,
NULL
);
if
(
!
c
)
{
lxc_error
(
"%s"
,
"Failed to create container
\"
console-log
\"
"
);
exit
(
fret
);
}
if
(
c
->
is_defined
(
c
))
{
lxc_error
(
"%s
\n
"
,
"Container
\"
console-log
\"
is defined"
);
goto
on_error_put
;
}
/* Set console ringbuffer size. */
if
(
!
c
->
set_config_item
(
c
,
"lxc.console.logsize"
,
"4096"
))
{
lxc_error
(
"%s
\n
"
,
"Failed to set config item
\"
lxc.console.logsize
\"
"
);
goto
on_error_put
;
}
/* Set on-disk logfile. */
if
(
!
c
->
set_config_item
(
c
,
"lxc.console.logfile"
,
"/tmp/console-log.log"
))
{
lxc_error
(
"%s
\n
"
,
"Failed to set config item
\"
lxc.console.logfile
\"
"
);
goto
on_error_put
;
}
if
(
!
c
->
createl
(
c
,
"busybox"
,
NULL
,
NULL
,
0
,
NULL
))
{
lxc_error
(
"%s
\n
"
,
"Failed to create busybox container
\"
console-log
\"
"
);
goto
on_error_put
;
}
if
(
!
c
->
is_defined
(
c
))
{
lxc_error
(
"%s
\n
"
,
"Container
\"
console-log
\"
is not defined"
);
goto
on_error_put
;
}
c
->
clear_config
(
c
);
if
(
!
c
->
load_config
(
c
,
NULL
))
{
lxc_error
(
"%s
\n
"
,
"Failed to load config for container
\"
console-log
\"
"
);
goto
on_error_stop
;
}
if
(
!
c
->
want_daemonize
(
c
,
true
))
{
lxc_error
(
"%s
\n
"
,
"Failed to mark container
\"
console-log
\"
daemonized"
);
goto
on_error_stop
;
}
if
(
!
c
->
startl
(
c
,
0
,
NULL
))
{
lxc_error
(
"%s
\n
"
,
"Failed to start container
\"
console-log
\"
daemonized"
);
goto
on_error_stop
;
}
/* Leave some time for the container to write something to the log. */
sleep
(
2
);
/* Retrieve the contents of the ringbuffer. */
log
.
clear
=
false
;
log
.
read_max
=
&
(
uint64_t
){
0
};
log
.
read
=
true
;
log
.
write_logfile
=
false
;
ret
=
c
->
console_log
(
c
,
&
log
);
if
(
ret
<
0
)
{
lxc_error
(
"%s - Failed to retrieve console log
\n
"
,
strerror
(
-
ret
));
goto
on_error_stop
;
}
else
{
lxc_debug
(
"Retrieved %"
PRIu64
" bytes from console log. Contents are
\"
%s
\"\n
"
,
*
log
.
read_max
,
log
.
data
);
}
/* Leave another two seconds to ensure boot is finished. */
sleep
(
2
);
/* Clear the console ringbuffer. */
log
.
read_max
=
&
(
uint64_t
){
0
};
log
.
read
=
false
;
log
.
write_logfile
=
false
;
log
.
clear
=
true
;
ret
=
c
->
console_log
(
c
,
&
log
);
if
(
ret
<
0
)
{
if
(
ret
!=
-
ENODATA
)
{
lxc_error
(
"%s - Failed to retrieve console log
\n
"
,
strerror
(
-
ret
));
goto
on_error_stop
;
}
}
if
(
!
c
->
stop
(
c
))
{
lxc_error
(
"%s
\n
"
,
"Failed to stop container
\"
console-log
\"
"
);
goto
on_error_stop
;
}
if
(
!
c
->
startl
(
c
,
0
,
NULL
))
{
lxc_error
(
"%s
\n
"
,
"Failed to start container
\"
console-log
\"
daemonized"
);
goto
on_error_destroy
;
}
do_unlink
=
true
;
/* Leave some time for the container to write something to the log. */
sleep
(
2
);
log
.
read_max
=
&
(
uint64_t
){
0
};
log
.
read
=
true
;
log
.
write_logfile
=
true
;
log
.
clear
=
false
;
ret
=
c
->
console_log
(
c
,
&
log
);
if
(
ret
<
0
)
{
lxc_error
(
"%s - Failed to retrieve console log
\n
"
,
strerror
(
-
ret
));
goto
on_error_stop
;
}
else
{
lxc_debug
(
"Retrieved %"
PRIu64
" bytes from console log. Contents are
\"
%s
\"\n
"
,
*
log
.
read_max
,
log
.
data
);
}
logfd
=
open
(
"/tmp/console-log.log"
,
O_RDONLY
);
if
(
logfd
<
0
)
{
lxc_error
(
"%s - Failed to open console log file "
"
\"
/tmp/console-log.log
\"\n
"
,
strerror
(
errno
));
goto
on_error_stop
;
}
bytes
=
lxc_read_nointr
(
logfd
,
buf
,
4096
+
1
);
close
(
logfd
);
if
(
bytes
<
0
||
((
uint64_t
)
bytes
!=
*
log
.
read_max
))
{
lxc_error
(
"%s - Failed to read console log file "
"
\"
/tmp/console-log.log
\"\n
"
,
strerror
(
errno
));
goto
on_error_stop
;
}
ret
=
stat
(
"/tmp/console-log.log"
,
&
st
);
if
(
ret
<
0
)
{
lxc_error
(
"%s - Failed to stat on-disk logfile
\n
"
,
strerror
(
errno
));
goto
on_error_stop
;
}
if
((
uint64_t
)
st
.
st_size
!=
*
log
.
read_max
)
{
lxc_error
(
"On-disk logfile size and used ringbuffer size do "
"not match: %"
PRIu64
" != %"
PRIu64
"
\n
"
,
(
uint64_t
)
st
.
st_size
,
*
log
.
read_max
);
goto
on_error_stop
;
}
if
(
memcmp
(
log
.
data
,
buf
,
*
log
.
read_max
))
{
lxc_error
(
"%s - Contents of in-memory ringbuffer and on-disk "
"logfile do not match
\n
"
,
strerror
(
errno
));
goto
on_error_stop
;
}
else
{
lxc_debug
(
"Retrieved %"
PRIu64
" bytes from console log and "
"console log file. Contents are:
\"
%s
\"
-
\"
%s
\"\n
"
,
*
log
.
read_max
,
log
.
data
,
buf
);
}
fret
=
0
;
on_error_stop:
if
(
c
->
is_running
(
c
)
&&
!
c
->
stop
(
c
))
lxc_error
(
"%s
\n
"
,
"Failed to stop container
\"
console-log
\"
"
);
on_error_destroy:
if
(
!
c
->
destroy
(
c
))
lxc_error
(
"%s
\n
"
,
"Failed to destroy container
\"
console-log
\"
"
);
on_error_put:
lxc_container_put
(
c
);
if
(
do_unlink
)
{
ret
=
unlink
(
"/tmp/console-log.log"
);
if
(
ret
<
0
)
lxc_error
(
"%s - Failed to remove container log file
\n
"
,
strerror
(
errno
));
}
exit
(
fret
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment