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
191d43cc
Unverified
Commit
191d43cc
authored
Oct 22, 2017
by
Christian Brauner
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
lxccontainer: add console_log() API extension
commands: add LXC_CMD_CONSOLE_LOG Closes #1870. Signed-off-by:
Christian Brauner
<
christian.brauner@ubuntu.com
>
parent
fe84a562
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
168 additions
and
5 deletions
+168
-5
commands.c
src/lxc/commands.c
+103
-5
commands.h
src/lxc/commands.h
+11
-0
lxccontainer.c
src/lxc/lxccontainer.c
+20
-0
lxccontainer.h
src/lxc/lxccontainer.h
+34
-0
No files found.
src/lxc/commands.c
View file @
191d43cc
...
...
@@ -92,6 +92,7 @@ static const char *lxc_cmd_str(lxc_cmd_t cmd)
[
LXC_CMD_GET_LXCPATH
]
=
"get_lxcpath"
,
[
LXC_CMD_ADD_STATE_CLIENT
]
=
"add_state_client"
,
[
LXC_CMD_SET_CONFIG_ITEM
]
=
"set_config_item"
,
[
LXC_CMD_CONSOLE_LOG
]
=
"console_log"
,
};
if
(
cmd
>=
LXC_CMD_MAX
)
...
...
@@ -156,7 +157,8 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
return
ret
;
}
if
(
rsp
->
datalen
>
LXC_CMD_DATA_MAX
)
{
if
((
rsp
->
datalen
>
LXC_CMD_DATA_MAX
)
&&
(
cmd
->
req
.
cmd
!=
LXC_CMD_CONSOLE_LOG
))
{
errno
=
EFBIG
;
ERROR
(
"%s - Response data for command
\"
%s
\"
is too long: %d "
"bytes > %d"
,
strerror
(
errno
),
lxc_cmd_str
(
cmd
->
req
.
cmd
),
...
...
@@ -164,7 +166,12 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
return
-
EFBIG
;
}
rsp
->
data
=
malloc
(
rsp
->
datalen
);
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
);
}
if
(
!
rsp
->
data
)
{
errno
=
ENOMEM
;
ERROR
(
"%s - Failed to allocate response buffer for command "
...
...
@@ -977,6 +984,79 @@ static int lxc_cmd_add_state_client_callback(int fd, struct lxc_cmd_req *req,
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
;
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
)
{
*
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_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 */
if
(
log
->
read
&&
(
buf
->
r_off
==
buf
->
w_off
))
rsp
.
ret
=
-
ENODATA
;
else
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
,
struct
lxc_handler
*
handler
)
{
...
...
@@ -995,6 +1075,7 @@ static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,
[
LXC_CMD_GET_LXCPATH
]
=
lxc_cmd_get_lxcpath_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_CONSOLE_LOG
]
=
lxc_cmd_console_log_callback
,
};
if
(
req
->
cmd
>=
LXC_CMD_MAX
)
{
...
...
@@ -1017,6 +1098,7 @@ static int lxc_cmd_handler(int fd, uint32_t events, void *data,
{
int
ret
;
struct
lxc_cmd_req
req
;
void
*
reqdata
=
NULL
;
struct
lxc_handler
*
handler
=
data
;
ret
=
lxc_abstract_unix_rcv_credential
(
fd
,
&
req
,
sizeof
(
req
));
...
...
@@ -1044,7 +1126,8 @@ static int lxc_cmd_handler(int fd, uint32_t events, void *data,
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 "
"command
\"
%s
\"
"
,
req
.
datalen
,
lxc_cmd_str
(
req
.
cmd
));
errno
=
EFBIG
;
...
...
@@ -1053,9 +1136,21 @@ static int lxc_cmd_handler(int fd, uint32_t events, void *data,
}
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
);
if
(
!
reqdata
)
{
ERROR
(
"Failed to allocate memory for
\"
%s
\"
command"
,
lxc_cmd_str
(
req
.
cmd
));
errno
=
ENOMEM
;
ret
=
-
ENOMEM
;
goto
out_close
;
}
reqdata
=
alloca
(
req
.
datalen
);
ret
=
recv
(
fd
,
reqdata
,
req
.
datalen
,
0
);
if
(
ret
!=
req
.
datalen
)
{
WARN
(
"Failed to receive full command request. Ignoring "
...
...
@@ -1075,6 +1170,9 @@ static int lxc_cmd_handler(int fd, uint32_t events, void *data,
}
out:
if
(
req
.
cmd
==
LXC_CMD_CONSOLE_LOG
&&
reqdata
)
free
(
reqdata
);
return
ret
;
out_close:
...
...
src/lxc/commands.h
View file @
191d43cc
...
...
@@ -29,6 +29,7 @@
#include <sys/types.h>
#include "state.h"
#include "lxccontainer.h"
#define LXC_CMD_DATA_MAX (MAXPATHLEN * 2)
...
...
@@ -49,6 +50,7 @@ typedef enum {
LXC_CMD_GET_LXCPATH
,
LXC_CMD_ADD_STATE_CLIENT
,
LXC_CMD_SET_CONFIG_ITEM
,
LXC_CMD_CONSOLE_LOG
,
LXC_CMD_MAX
,
}
lxc_cmd_t
;
...
...
@@ -79,6 +81,13 @@ struct lxc_cmd_set_config_item_req_data {
void
*
value
;
};
struct
lxc_cmd_console_log
{
bool
clear
;
bool
read
;
uint64_t
read_max
;
};
extern
int
lxc_cmd_console_winch
(
const
char
*
name
,
const
char
*
lxcpath
);
extern
int
lxc_cmd_console
(
const
char
*
name
,
int
*
ttynum
,
int
*
fd
,
const
char
*
lxcpath
);
...
...
@@ -124,5 +133,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
,
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 */
src/lxc/lxccontainer.c
View file @
191d43cc
...
...
@@ -516,6 +516,25 @@ static int lxcapi_console(struct lxc_container *c, int ttynum, int stdinfd,
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
(
"%s - The console log is empty"
,
strerror
(
-
ret
));
else
if
(
ret
==
-
EFAULT
)
NOTICE
(
"%s - The container does not have a console log configured"
,
strerror
(
-
ret
));
else
ERROR
(
"%s - Failed to retrieve console log"
,
strerror
(
-
ret
));
}
return
ret
;
}
WRAP_API_1
(
int
,
lxcapi_console_log
,
struct
lxc_console_log
*
)
static
pid_t
do_lxcapi_init_pid
(
struct
lxc_container
*
c
)
{
if
(
!
c
)
...
...
@@ -4607,6 +4626,7 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
c
->
checkpoint
=
lxcapi_checkpoint
;
c
->
restore
=
lxcapi_restore
;
c
->
migrate
=
lxcapi_migrate
;
c
->
console_log
=
lxcapi_console_log
;
return
c
;
...
...
src/lxc/lxccontainer.h
View file @
191d43cc
...
...
@@ -51,6 +51,8 @@ struct lxc_lock;
struct
migrate_opts
;
struct
lxc_console_log
;
/*!
* An LXC container.
*
...
...
@@ -834,6 +836,16 @@ struct lxc_container {
* \return \c true on success, else \c false.
*/
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,28 @@ struct migrate_opts {
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
;
};
/*!
* \brief Create a new container.
*
...
...
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