2011-09-23 12:00:45 +04:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
2011-10-13 19:43:52 +04:00
|
|
|
#include <getopt.h>
|
|
|
|
#include <string.h>
|
2012-02-17 22:51:23 +04:00
|
|
|
#include <ctype.h>
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#include "types.h"
|
|
|
|
|
|
|
|
#include "compiler.h"
|
|
|
|
#include "crtools.h"
|
|
|
|
#include "util.h"
|
2011-12-19 18:52:50 +04:00
|
|
|
#include "log.h"
|
2011-12-26 22:12:03 +04:00
|
|
|
#include "sockets.h"
|
2012-01-31 22:28:22 +04:00
|
|
|
#include "syscall.h"
|
2012-03-27 12:01:14 +04:00
|
|
|
#include "uts_ns.h"
|
|
|
|
#include "ipc_ns.h"
|
2012-04-28 17:15:12 +04:00
|
|
|
#include "files.h"
|
|
|
|
#include "sk-inet.h"
|
2012-05-04 13:38:00 +04:00
|
|
|
#include "eventfd.h"
|
2012-05-04 13:38:00 +04:00
|
|
|
#include "eventpoll.h"
|
2012-05-04 13:38:00 +04:00
|
|
|
#include "inotify.h"
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-04-19 11:48:00 +04:00
|
|
|
struct cr_options opts;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2011-10-13 13:33:32 +04:00
|
|
|
/*
|
|
|
|
* The cr fd set is the set of files where the information
|
|
|
|
* about dumped processes is stored. Each file carries some
|
|
|
|
* small portion of info about the whole picture, see below
|
|
|
|
* for more details.
|
|
|
|
*/
|
|
|
|
|
2011-11-15 18:35:55 +04:00
|
|
|
struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX] = {
|
2011-10-13 13:33:32 +04:00
|
|
|
|
|
|
|
/* info about file descriptiors */
|
2011-09-23 12:00:45 +04:00
|
|
|
[CR_FD_FDINFO] = {
|
2011-11-15 18:35:55 +04:00
|
|
|
.fmt = FMT_FNAME_FDINFO,
|
2011-09-23 12:00:45 +04:00
|
|
|
.magic = FDINFO_MAGIC,
|
2012-03-27 12:01:14 +04:00
|
|
|
.show = show_files,
|
2011-09-23 12:00:45 +04:00
|
|
|
},
|
2011-10-13 13:33:32 +04:00
|
|
|
|
|
|
|
/* private memory pages data */
|
2011-09-23 12:00:45 +04:00
|
|
|
[CR_FD_PAGES] = {
|
2011-11-15 18:35:55 +04:00
|
|
|
.fmt = FMT_FNAME_PAGES,
|
2011-09-23 12:00:45 +04:00
|
|
|
.magic = PAGES_MAGIC,
|
2012-03-27 12:01:14 +04:00
|
|
|
.show = show_pages,
|
2011-09-23 12:00:45 +04:00
|
|
|
},
|
2011-10-13 13:33:32 +04:00
|
|
|
|
|
|
|
/* shared memory pages data */
|
2012-03-21 10:12:00 +04:00
|
|
|
[CR_FD_SHMEM_PAGES] = {
|
|
|
|
.fmt = FMT_FNAME_SHMEM_PAGES,
|
2011-09-23 12:00:45 +04:00
|
|
|
.magic = PAGES_MAGIC,
|
2012-03-27 12:01:14 +04:00
|
|
|
.show = show_pages,
|
2011-09-23 12:00:45 +04:00
|
|
|
},
|
2011-10-13 13:33:32 +04:00
|
|
|
|
2012-03-25 20:24:53 +04:00
|
|
|
[CR_FD_REG_FILES] = {
|
|
|
|
.fmt = FMT_FNAME_REG_FILES,
|
|
|
|
.magic = REG_FILES_MAGIC,
|
2012-03-27 12:01:14 +04:00
|
|
|
.show = show_reg_files,
|
2012-03-25 20:24:53 +04:00
|
|
|
},
|
|
|
|
|
2012-05-04 13:38:00 +04:00
|
|
|
/* eventfd */
|
|
|
|
[CR_FD_EVENTFD] = {
|
|
|
|
.fmt = FMT_FNAME_EVENTFD,
|
|
|
|
.magic = EVENTFD_MAGIC,
|
|
|
|
.show = show_eventfds,
|
|
|
|
},
|
|
|
|
|
2012-05-04 13:38:00 +04:00
|
|
|
/* eventpoll */
|
|
|
|
[CR_FD_EVENTPOLL] = {
|
|
|
|
.fmt = FMT_FNAME_EVENTPOLL,
|
|
|
|
.magic = EVENTPOLL_MAGIC,
|
|
|
|
.show = show_eventpoll,
|
|
|
|
},
|
|
|
|
|
|
|
|
/* eventpoll target file descriptors */
|
|
|
|
[CR_FD_EVENTPOLL_TFD] = {
|
|
|
|
.fmt = FMT_FNAME_EVENTPOLL_TFD,
|
|
|
|
.magic = EVENTPOLL_TFD_MAGIC,
|
|
|
|
.show = show_eventpoll_tfd,
|
|
|
|
},
|
|
|
|
|
2012-05-04 13:38:00 +04:00
|
|
|
/* inotify descriptors */
|
|
|
|
[CR_FD_INOTIFY] = {
|
|
|
|
.fmt = FMT_FNAME_INOTIFY,
|
|
|
|
.magic = INOTIFY_MAGIC,
|
|
|
|
.show = show_inotify,
|
|
|
|
},
|
|
|
|
|
|
|
|
/* inotify descriptors */
|
|
|
|
[CR_FD_INOTIFY_WD] = {
|
|
|
|
.fmt = FMT_FNAME_INOTIFY_WD,
|
|
|
|
.magic = INOTIFY_WMAGIC,
|
|
|
|
.show = show_inotify_wd,
|
|
|
|
},
|
|
|
|
|
2011-11-15 18:35:55 +04:00
|
|
|
/* core data, such as regs and vmas and such */
|
2011-09-23 12:00:45 +04:00
|
|
|
[CR_FD_CORE] = {
|
2011-11-15 18:35:55 +04:00
|
|
|
.fmt = FMT_FNAME_CORE,
|
2011-09-23 12:00:45 +04:00
|
|
|
.magic = CORE_MAGIC,
|
2012-03-27 12:01:14 +04:00
|
|
|
.show = show_core,
|
2011-09-23 12:00:45 +04:00
|
|
|
},
|
2011-10-13 13:33:32 +04:00
|
|
|
|
2012-04-09 14:51:37 +04:00
|
|
|
[CR_FD_MM] = {
|
|
|
|
.fmt = FMT_FNAME_MM,
|
|
|
|
.magic = MM_MAGIC,
|
|
|
|
.show = show_mm,
|
|
|
|
},
|
|
|
|
|
2012-03-21 14:22:00 +04:00
|
|
|
[CR_FD_VMAS] = {
|
|
|
|
.fmt = FMT_FNAME_VMAS,
|
|
|
|
.magic = VMAS_MAGIC,
|
2012-03-27 12:01:14 +04:00
|
|
|
.show = show_vmas,
|
2012-03-21 14:22:00 +04:00
|
|
|
},
|
|
|
|
|
2011-10-13 13:33:32 +04:00
|
|
|
/* info about pipes - fds, pipe id and pipe data */
|
2011-09-23 12:00:45 +04:00
|
|
|
[CR_FD_PIPES] = {
|
2011-11-15 18:35:55 +04:00
|
|
|
.fmt = FMT_FNAME_PIPES,
|
2011-09-23 12:00:45 +04:00
|
|
|
.magic = PIPES_MAGIC,
|
2012-03-27 12:01:14 +04:00
|
|
|
.show = show_pipes,
|
2011-09-23 12:00:45 +04:00
|
|
|
},
|
2011-10-13 13:33:32 +04:00
|
|
|
|
2012-04-05 20:02:00 +04:00
|
|
|
/* info about pipes - fds, pipe id and pipe data */
|
|
|
|
[CR_FD_PIPES_DATA] = {
|
|
|
|
.fmt = FMT_FNAME_PIPES_DATA,
|
|
|
|
.magic = PIPES_DATA_MAGIC,
|
|
|
|
.show = show_pipes_data,
|
|
|
|
},
|
|
|
|
|
2011-10-13 13:33:32 +04:00
|
|
|
/* info about process linkage */
|
2011-09-23 12:00:45 +04:00
|
|
|
[CR_FD_PSTREE] = {
|
2011-11-15 18:35:55 +04:00
|
|
|
.fmt = FMT_FNAME_PSTREE,
|
2011-09-23 12:00:45 +04:00
|
|
|
.magic = PSTREE_MAGIC,
|
2012-03-27 12:01:14 +04:00
|
|
|
.show = show_pstree,
|
2011-09-23 12:00:45 +04:00
|
|
|
},
|
2011-10-13 13:33:32 +04:00
|
|
|
|
2011-11-30 23:33:28 +04:00
|
|
|
/* info about signal handlers */
|
2011-11-29 15:12:25 +03:00
|
|
|
[CR_FD_SIGACT] = {
|
|
|
|
.fmt = FMT_FNAME_SIGACTS,
|
|
|
|
.magic = SIGACT_MAGIC,
|
2012-03-27 12:01:14 +04:00
|
|
|
.show = show_sigacts,
|
2011-11-29 15:12:25 +03:00
|
|
|
},
|
2011-12-26 22:12:03 +04:00
|
|
|
|
|
|
|
/* info about unix sockets */
|
|
|
|
[CR_FD_UNIXSK] = {
|
|
|
|
.fmt = FMT_FNAME_UNIXSK,
|
|
|
|
.magic = UNIXSK_MAGIC,
|
2012-03-27 12:01:14 +04:00
|
|
|
.show = show_unixsk,
|
2011-12-26 22:12:03 +04:00
|
|
|
},
|
2012-01-17 21:30:00 +04:00
|
|
|
|
|
|
|
/* info about inet sockets */
|
|
|
|
[CR_FD_INETSK] = {
|
|
|
|
.fmt = FMT_FNAME_INETSK,
|
|
|
|
.magic = INETSK_MAGIC,
|
2012-03-27 12:01:14 +04:00
|
|
|
.show = show_inetsk,
|
2012-01-17 21:30:00 +04:00
|
|
|
},
|
|
|
|
|
2012-02-29 16:06:48 +03:00
|
|
|
[CR_FD_SK_QUEUES] = {
|
|
|
|
.fmt = FMT_FNAME_SK_QUEUES,
|
|
|
|
.magic = SK_QUEUES_MAGIC,
|
2012-03-27 12:01:14 +04:00
|
|
|
.show = show_sk_queues,
|
2012-02-29 16:06:48 +03:00
|
|
|
},
|
|
|
|
|
2012-01-24 16:45:19 +04:00
|
|
|
/* interval timers (itimers) */
|
|
|
|
[CR_FD_ITIMERS] = {
|
|
|
|
.fmt = FMT_FNAME_ITIMERS,
|
|
|
|
.magic = ITIMERS_MAGIC,
|
2012-03-27 12:01:14 +04:00
|
|
|
.show = show_itimers,
|
2012-01-24 16:45:19 +04:00
|
|
|
},
|
2012-01-26 15:28:00 +04:00
|
|
|
|
2012-01-27 21:43:32 +04:00
|
|
|
/* creds */
|
|
|
|
[CR_FD_CREDS] = {
|
|
|
|
.fmt = FMT_FNAME_CREDS,
|
|
|
|
.magic = CREDS_MAGIC,
|
2012-03-27 12:01:14 +04:00
|
|
|
.show = show_creds,
|
2012-01-27 21:43:32 +04:00
|
|
|
},
|
|
|
|
|
2012-01-26 15:28:00 +04:00
|
|
|
/* UTS namespace */
|
|
|
|
[CR_FD_UTSNS] = {
|
|
|
|
.fmt = FMT_FNAME_UTSNS,
|
|
|
|
.magic = UTSNS_MAGIC,
|
2012-03-27 12:01:14 +04:00
|
|
|
.show = show_utsns,
|
2012-01-26 15:28:00 +04:00
|
|
|
},
|
2012-01-31 22:28:55 +04:00
|
|
|
|
2012-02-08 12:13:38 +03:00
|
|
|
/* IPC namespace variables */
|
|
|
|
[CR_FD_IPCNS_VAR] = {
|
|
|
|
.fmt = FMT_FNAME_IPCNS_VAR,
|
|
|
|
.magic = IPCNS_VAR_MAGIC,
|
2012-03-27 12:01:14 +04:00
|
|
|
.show = show_ipc_var,
|
2012-01-31 22:28:55 +04:00
|
|
|
},
|
2012-02-09 12:09:41 +03:00
|
|
|
|
|
|
|
/* IPC namespace shared memory */
|
|
|
|
[CR_FD_IPCNS_SHM] = {
|
|
|
|
.fmt = FMT_FNAME_IPCNS_SHM,
|
|
|
|
.magic = IPCNS_SHM_MAGIC,
|
2012-03-27 12:01:14 +04:00
|
|
|
.show = show_ipc_shm,
|
2012-02-09 12:09:41 +03:00
|
|
|
},
|
2012-02-13 20:27:35 +03:00
|
|
|
|
|
|
|
/* IPC namespace message queues */
|
|
|
|
[CR_FD_IPCNS_MSG] = {
|
|
|
|
.fmt = FMT_FNAME_IPCNS_MSG,
|
|
|
|
.magic = IPCNS_MSG_MAGIC,
|
2012-03-27 12:01:14 +04:00
|
|
|
.show = show_ipc_msg,
|
2012-02-13 20:27:35 +03:00
|
|
|
},
|
2012-02-14 19:54:06 +03:00
|
|
|
|
|
|
|
/* IPC namespace semaphores sets */
|
|
|
|
[CR_FD_IPCNS_SEM] = {
|
|
|
|
.fmt = FMT_FNAME_IPCNS_SEM,
|
|
|
|
.magic = IPCNS_SEM_MAGIC,
|
2012-03-27 12:01:14 +04:00
|
|
|
.show = show_ipc_sem,
|
2012-02-14 19:54:06 +03:00
|
|
|
},
|
2012-04-09 13:41:05 +04:00
|
|
|
|
|
|
|
[CR_FD_FS] = {
|
|
|
|
.fmt = FMT_FNAME_FS,
|
|
|
|
.magic = FS_MAGIC,
|
|
|
|
.show = show_fs,
|
|
|
|
},
|
2012-04-13 17:54:36 +04:00
|
|
|
|
|
|
|
[CR_FD_REMAP_FPATH] = {
|
|
|
|
.fmt = FMT_FNAME_REMAP_FPATH,
|
|
|
|
.magic = REMAP_FPATH_MAGIC,
|
|
|
|
.show = show_remap_files,
|
|
|
|
},
|
|
|
|
|
|
|
|
[CR_FD_GHOST_FILE] = {
|
|
|
|
.fmt = FMT_FNAME_GHOST_FILE,
|
|
|
|
.magic = GHOST_FILE_MAGIC,
|
|
|
|
.show = show_ghost_file,
|
|
|
|
},
|
2012-04-28 17:29:14 +04:00
|
|
|
|
|
|
|
[CR_FD_TCP_STREAM] = {
|
|
|
|
.fmt = FMT_FNAME_TCP_STREAM,
|
|
|
|
.magic = TCP_STREAM_MAGIC,
|
|
|
|
.show = show_tcp_stream,
|
|
|
|
},
|
2011-09-23 12:00:45 +04:00
|
|
|
};
|
|
|
|
|
fdset: Introduce new fdsets
Current fdsets are ugly, limited (bitmask will exhaust in several months) and
suffer from unknown problems with fdsets reuse :(
With new approach (this set) the images management is simple. The basic function
is open_image, which gives you an fd for an image. If you want to pre-open several
images at once instead of calling open_image every single time, you can use the
new fdsets.
Images CR_FD_ descriptors should be grouped like
_CR_FD_FOO_FROM,
CR_FD_FOO_ITEM1,
CR_FD_FOO_ITEM2,
..
CR_FD_FOO_ITEMN,
_CR_FD_FOO_TO,
After this you can call cr_fd_open() specifying ranges -- _FROM and _TO macros,
it will give you an cr_fdset object. Then the fdset_fd(set, type) will give you
the descriptor of the open "set" group corresponding to the "type" type.
3 groups are introduced in this set -- tasks, ns and global.
That's it.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2012-03-26 17:46:39 +04:00
|
|
|
static struct cr_fdset *alloc_cr_fdset(int nr)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
struct cr_fdset *cr_fdset;
|
|
|
|
unsigned int i;
|
|
|
|
|
2012-01-12 15:17:51 +04:00
|
|
|
cr_fdset = xmalloc(sizeof(*cr_fdset));
|
fdset: Introduce new fdsets
Current fdsets are ugly, limited (bitmask will exhaust in several months) and
suffer from unknown problems with fdsets reuse :(
With new approach (this set) the images management is simple. The basic function
is open_image, which gives you an fd for an image. If you want to pre-open several
images at once instead of calling open_image every single time, you can use the
new fdsets.
Images CR_FD_ descriptors should be grouped like
_CR_FD_FOO_FROM,
CR_FD_FOO_ITEM1,
CR_FD_FOO_ITEM2,
..
CR_FD_FOO_ITEMN,
_CR_FD_FOO_TO,
After this you can call cr_fd_open() specifying ranges -- _FROM and _TO macros,
it will give you an cr_fdset object. Then the fdset_fd(set, type) will give you
the descriptor of the open "set" group corresponding to the "type" type.
3 groups are introduced in this set -- tasks, ns and global.
That's it.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2012-03-26 17:46:39 +04:00
|
|
|
if (cr_fdset == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
cr_fdset->_fds = xmalloc(nr * sizeof(int));
|
|
|
|
if (cr_fdset->_fds == NULL) {
|
|
|
|
xfree(cr_fdset);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-03-27 11:04:23 +04:00
|
|
|
for (i = 0; i < nr; i++)
|
|
|
|
cr_fdset->_fds[i] = -1;
|
fdset: Introduce new fdsets
Current fdsets are ugly, limited (bitmask will exhaust in several months) and
suffer from unknown problems with fdsets reuse :(
With new approach (this set) the images management is simple. The basic function
is open_image, which gives you an fd for an image. If you want to pre-open several
images at once instead of calling open_image every single time, you can use the
new fdsets.
Images CR_FD_ descriptors should be grouped like
_CR_FD_FOO_FROM,
CR_FD_FOO_ITEM1,
CR_FD_FOO_ITEM2,
..
CR_FD_FOO_ITEMN,
_CR_FD_FOO_TO,
After this you can call cr_fd_open() specifying ranges -- _FROM and _TO macros,
it will give you an cr_fdset object. Then the fdset_fd(set, type) will give you
the descriptor of the open "set" group corresponding to the "type" type.
3 groups are introduced in this set -- tasks, ns and global.
That's it.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2012-03-26 17:46:39 +04:00
|
|
|
cr_fdset->fd_nr = nr;
|
2011-09-23 12:00:45 +04:00
|
|
|
return cr_fdset;
|
|
|
|
}
|
|
|
|
|
2012-03-26 17:41:40 +04:00
|
|
|
static void __close_cr_fdset(struct cr_fdset *cr_fdset)
|
2012-01-31 18:26:51 +04:00
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
if (!cr_fdset)
|
|
|
|
return;
|
|
|
|
|
fdset: Introduce new fdsets
Current fdsets are ugly, limited (bitmask will exhaust in several months) and
suffer from unknown problems with fdsets reuse :(
With new approach (this set) the images management is simple. The basic function
is open_image, which gives you an fd for an image. If you want to pre-open several
images at once instead of calling open_image every single time, you can use the
new fdsets.
Images CR_FD_ descriptors should be grouped like
_CR_FD_FOO_FROM,
CR_FD_FOO_ITEM1,
CR_FD_FOO_ITEM2,
..
CR_FD_FOO_ITEMN,
_CR_FD_FOO_TO,
After this you can call cr_fd_open() specifying ranges -- _FROM and _TO macros,
it will give you an cr_fdset object. Then the fdset_fd(set, type) will give you
the descriptor of the open "set" group corresponding to the "type" type.
3 groups are introduced in this set -- tasks, ns and global.
That's it.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2012-03-26 17:46:39 +04:00
|
|
|
for (i = 0; i < cr_fdset->fd_nr; i++) {
|
2012-03-26 17:43:29 +04:00
|
|
|
if (cr_fdset->_fds[i] == -1)
|
2012-01-31 18:26:51 +04:00
|
|
|
continue;
|
2012-03-26 17:43:29 +04:00
|
|
|
close_safe(&cr_fdset->_fds[i]);
|
|
|
|
cr_fdset->_fds[i] = -1;
|
2012-01-31 18:26:51 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void close_cr_fdset(struct cr_fdset **cr_fdset)
|
|
|
|
{
|
|
|
|
if (!cr_fdset || !*cr_fdset)
|
|
|
|
return;
|
|
|
|
|
|
|
|
__close_cr_fdset(*cr_fdset);
|
|
|
|
|
fdset: Introduce new fdsets
Current fdsets are ugly, limited (bitmask will exhaust in several months) and
suffer from unknown problems with fdsets reuse :(
With new approach (this set) the images management is simple. The basic function
is open_image, which gives you an fd for an image. If you want to pre-open several
images at once instead of calling open_image every single time, you can use the
new fdsets.
Images CR_FD_ descriptors should be grouped like
_CR_FD_FOO_FROM,
CR_FD_FOO_ITEM1,
CR_FD_FOO_ITEM2,
..
CR_FD_FOO_ITEMN,
_CR_FD_FOO_TO,
After this you can call cr_fd_open() specifying ranges -- _FROM and _TO macros,
it will give you an cr_fdset object. Then the fdset_fd(set, type) will give you
the descriptor of the open "set" group corresponding to the "type" type.
3 groups are introduced in this set -- tasks, ns and global.
That's it.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2012-03-26 17:46:39 +04:00
|
|
|
xfree((*cr_fdset)->_fds);
|
2012-01-31 18:26:51 +04:00
|
|
|
xfree(*cr_fdset);
|
|
|
|
*cr_fdset = NULL;
|
|
|
|
}
|
|
|
|
|
fdset: Introduce new fdsets
Current fdsets are ugly, limited (bitmask will exhaust in several months) and
suffer from unknown problems with fdsets reuse :(
With new approach (this set) the images management is simple. The basic function
is open_image, which gives you an fd for an image. If you want to pre-open several
images at once instead of calling open_image every single time, you can use the
new fdsets.
Images CR_FD_ descriptors should be grouped like
_CR_FD_FOO_FROM,
CR_FD_FOO_ITEM1,
CR_FD_FOO_ITEM2,
..
CR_FD_FOO_ITEMN,
_CR_FD_FOO_TO,
After this you can call cr_fd_open() specifying ranges -- _FROM and _TO macros,
it will give you an cr_fdset object. Then the fdset_fd(set, type) will give you
the descriptor of the open "set" group corresponding to the "type" type.
3 groups are introduced in this set -- tasks, ns and global.
That's it.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2012-03-26 17:46:39 +04:00
|
|
|
static struct cr_fdset *cr_fdset_open(int pid, int from, int to,
|
2012-03-26 17:41:40 +04:00
|
|
|
unsigned long flags)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
2012-01-31 18:26:51 +04:00
|
|
|
struct cr_fdset *fdset;
|
2011-09-23 12:00:45 +04:00
|
|
|
unsigned int i;
|
|
|
|
int ret = -1;
|
|
|
|
|
fdset: Introduce new fdsets
Current fdsets are ugly, limited (bitmask will exhaust in several months) and
suffer from unknown problems with fdsets reuse :(
With new approach (this set) the images management is simple. The basic function
is open_image, which gives you an fd for an image. If you want to pre-open several
images at once instead of calling open_image every single time, you can use the
new fdsets.
Images CR_FD_ descriptors should be grouped like
_CR_FD_FOO_FROM,
CR_FD_FOO_ITEM1,
CR_FD_FOO_ITEM2,
..
CR_FD_FOO_ITEMN,
_CR_FD_FOO_TO,
After this you can call cr_fd_open() specifying ranges -- _FROM and _TO macros,
it will give you an cr_fdset object. Then the fdset_fd(set, type) will give you
the descriptor of the open "set" group corresponding to the "type" type.
3 groups are introduced in this set -- tasks, ns and global.
That's it.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2012-03-26 17:46:39 +04:00
|
|
|
fdset = alloc_cr_fdset(to - from);
|
2012-03-26 17:41:40 +04:00
|
|
|
if (!fdset)
|
|
|
|
goto err;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
fdset: Introduce new fdsets
Current fdsets are ugly, limited (bitmask will exhaust in several months) and
suffer from unknown problems with fdsets reuse :(
With new approach (this set) the images management is simple. The basic function
is open_image, which gives you an fd for an image. If you want to pre-open several
images at once instead of calling open_image every single time, you can use the
new fdsets.
Images CR_FD_ descriptors should be grouped like
_CR_FD_FOO_FROM,
CR_FD_FOO_ITEM1,
CR_FD_FOO_ITEM2,
..
CR_FD_FOO_ITEMN,
_CR_FD_FOO_TO,
After this you can call cr_fd_open() specifying ranges -- _FROM and _TO macros,
it will give you an cr_fdset object. Then the fdset_fd(set, type) will give you
the descriptor of the open "set" group corresponding to the "type" type.
3 groups are introduced in this set -- tasks, ns and global.
That's it.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2012-03-26 17:46:39 +04:00
|
|
|
from++;
|
|
|
|
fdset->fd_off = from;
|
|
|
|
for (i = from; i < to; i++) {
|
2012-03-19 15:38:00 +04:00
|
|
|
ret = open_image(i, flags, pid);
|
2012-01-12 15:17:51 +04:00
|
|
|
if (ret < 0) {
|
2012-02-08 20:19:39 +03:00
|
|
|
if (!(flags & O_CREAT))
|
|
|
|
/* caller should check himself */
|
|
|
|
continue;
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
fdset: Introduce new fdsets
Current fdsets are ugly, limited (bitmask will exhaust in several months) and
suffer from unknown problems with fdsets reuse :(
With new approach (this set) the images management is simple. The basic function
is open_image, which gives you an fd for an image. If you want to pre-open several
images at once instead of calling open_image every single time, you can use the
new fdsets.
Images CR_FD_ descriptors should be grouped like
_CR_FD_FOO_FROM,
CR_FD_FOO_ITEM1,
CR_FD_FOO_ITEM2,
..
CR_FD_FOO_ITEMN,
_CR_FD_FOO_TO,
After this you can call cr_fd_open() specifying ranges -- _FROM and _TO macros,
it will give you an cr_fdset object. Then the fdset_fd(set, type) will give you
the descriptor of the open "set" group corresponding to the "type" type.
3 groups are introduced in this set -- tasks, ns and global.
That's it.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2012-03-26 17:46:39 +04:00
|
|
|
fdset->_fds[i - from] = ret;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
2012-01-31 18:26:51 +04:00
|
|
|
|
|
|
|
return fdset;
|
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
err:
|
2012-03-26 17:41:40 +04:00
|
|
|
close_cr_fdset(&fdset);
|
2012-01-31 18:26:51 +04:00
|
|
|
return NULL;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2012-03-26 17:45:08 +04:00
|
|
|
struct cr_fdset *cr_task_fdset_open(int pid, int mode)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
fdset: Introduce new fdsets
Current fdsets are ugly, limited (bitmask will exhaust in several months) and
suffer from unknown problems with fdsets reuse :(
With new approach (this set) the images management is simple. The basic function
is open_image, which gives you an fd for an image. If you want to pre-open several
images at once instead of calling open_image every single time, you can use the
new fdsets.
Images CR_FD_ descriptors should be grouped like
_CR_FD_FOO_FROM,
CR_FD_FOO_ITEM1,
CR_FD_FOO_ITEM2,
..
CR_FD_FOO_ITEMN,
_CR_FD_FOO_TO,
After this you can call cr_fd_open() specifying ranges -- _FROM and _TO macros,
it will give you an cr_fdset object. Then the fdset_fd(set, type) will give you
the descriptor of the open "set" group corresponding to the "type" type.
3 groups are introduced in this set -- tasks, ns and global.
That's it.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2012-03-26 17:46:39 +04:00
|
|
|
return cr_fdset_open(pid, _CR_FD_TASK_FROM, _CR_FD_TASK_TO, mode);
|
2012-02-08 20:19:39 +03:00
|
|
|
}
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-03-26 17:45:08 +04:00
|
|
|
struct cr_fdset *cr_ns_fdset_open(int pid, int mode)
|
2012-02-08 20:19:39 +03:00
|
|
|
{
|
fdset: Introduce new fdsets
Current fdsets are ugly, limited (bitmask will exhaust in several months) and
suffer from unknown problems with fdsets reuse :(
With new approach (this set) the images management is simple. The basic function
is open_image, which gives you an fd for an image. If you want to pre-open several
images at once instead of calling open_image every single time, you can use the
new fdsets.
Images CR_FD_ descriptors should be grouped like
_CR_FD_FOO_FROM,
CR_FD_FOO_ITEM1,
CR_FD_FOO_ITEM2,
..
CR_FD_FOO_ITEMN,
_CR_FD_FOO_TO,
After this you can call cr_fd_open() specifying ranges -- _FROM and _TO macros,
it will give you an cr_fdset object. Then the fdset_fd(set, type) will give you
the descriptor of the open "set" group corresponding to the "type" type.
3 groups are introduced in this set -- tasks, ns and global.
That's it.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2012-03-26 17:46:39 +04:00
|
|
|
return cr_fdset_open(pid, _CR_FD_NS_FROM, _CR_FD_NS_TO, mode);
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2012-03-26 17:47:38 +04:00
|
|
|
struct cr_fdset *cr_glob_fdset_open(int mode)
|
|
|
|
{
|
|
|
|
return cr_fdset_open(-1 /* ignored */, _CR_FD_GLOB_FROM, _CR_FD_GLOB_TO, mode);
|
|
|
|
}
|
|
|
|
|
2012-01-31 22:28:22 +04:00
|
|
|
static int parse_ns_string(const char *ptr, unsigned int *flags)
|
|
|
|
{
|
|
|
|
const char *end = ptr + strlen(ptr);
|
|
|
|
|
|
|
|
do {
|
|
|
|
if (ptr[3] != ',' && ptr[3] != '\0')
|
|
|
|
goto bad_ns;
|
|
|
|
if (!strncmp(ptr, "uts", 3))
|
|
|
|
opts.namespaces_flags |= CLONE_NEWUTS;
|
2012-01-31 22:28:55 +04:00
|
|
|
else if (!strncmp(ptr, "ipc", 3))
|
|
|
|
opts.namespaces_flags |= CLONE_NEWIPC;
|
2012-01-31 22:28:22 +04:00
|
|
|
else
|
|
|
|
goto bad_ns;
|
|
|
|
ptr += 4;
|
|
|
|
} while (ptr < end);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
bad_ns:
|
|
|
|
pr_err("Unknown namespace '%s'\n", ptr);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
2011-12-28 20:39:00 +04:00
|
|
|
pid_t pid = 0;
|
2011-09-23 12:00:45 +04:00
|
|
|
int ret = -1;
|
2011-10-13 19:43:52 +04:00
|
|
|
int opt, idx;
|
|
|
|
int action = -1;
|
2011-12-08 18:39:00 +04:00
|
|
|
int log_inited = 0;
|
2012-02-17 22:51:23 +04:00
|
|
|
int log_level = 0;
|
2011-10-13 19:43:52 +04:00
|
|
|
|
2012-04-19 11:48:00 +04:00
|
|
|
static const char short_opts[] = "dsf:p:t:hcD:o:n:vx";
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
BUILD_BUG_ON(PAGE_SIZE != PAGE_IMAGE_SIZE);
|
|
|
|
|
2012-03-02 14:01:08 +04:00
|
|
|
if (argc < 2)
|
2011-09-23 12:00:45 +04:00
|
|
|
goto usage;
|
|
|
|
|
2012-01-18 18:53:49 +03:00
|
|
|
action = argv[1][0];
|
|
|
|
|
2011-11-22 22:09:28 +04:00
|
|
|
/* Default options */
|
2012-03-01 19:09:02 +04:00
|
|
|
opts.final_state = TASK_DEAD;
|
2011-11-22 22:09:28 +04:00
|
|
|
|
2012-04-16 14:14:41 +04:00
|
|
|
while (1) {
|
2012-04-16 14:23:05 +04:00
|
|
|
static struct option long_opts[] = {
|
|
|
|
{ "pid", required_argument, 0, 'p' },
|
|
|
|
{ "tree", required_argument, 0, 't' },
|
|
|
|
{ "leave-stopped", no_argument, 0, 's' },
|
|
|
|
{ "restore-detached", no_argument, 0, 'd' },
|
|
|
|
{ "contents", no_argument, 0, 'c' },
|
|
|
|
{ "file", required_argument, 0, 'f' },
|
|
|
|
{ "images-dir", required_argument, 0, 'D' },
|
|
|
|
{ "log-file", required_argument, 0, 'o' },
|
|
|
|
{ "namespaces", required_argument, 0, 'n' },
|
2012-04-19 11:48:00 +04:00
|
|
|
{ "ext-unix-sk", no_argument, 0, 'x' },
|
2012-04-16 14:23:05 +04:00
|
|
|
{ "help", no_argument, 0, 'h' },
|
2012-04-28 17:15:12 +04:00
|
|
|
{ SK_EST_PARAM, no_argument, 0, 42 },
|
2012-04-28 20:37:54 +04:00
|
|
|
{ "close", required_argument, 0, 43 },
|
2012-04-16 14:23:05 +04:00
|
|
|
{ },
|
|
|
|
};
|
|
|
|
|
|
|
|
opt = getopt_long(argc - 1, argv + 1, short_opts, long_opts, &idx);
|
2012-04-16 14:14:41 +04:00
|
|
|
if (opt == -1)
|
|
|
|
break;
|
|
|
|
|
2011-10-13 19:43:52 +04:00
|
|
|
switch (opt) {
|
ctrools: Rewrite task/threads stopping engine is back
This commit brings the former "Rewrite task/threads stopping engine"
commit back. Handling it separately is too complex so better try
to handle it in-place.
Note some tests might fault, it's expected.
---
Stopping tasks with STOP and proceeding with SEIZE is actually excessive --
the SEIZE if enough. Moreover, just killing a task with STOP is also racy,
since task should be given some time to come to sleep before its proc
can be parsed.
Rewrite all this code to SEIZE task and all its threads from the very beginning.
With this we can distinguish stopped task state and migrate it properly (not
supported now, need to implement).
This thing however has one BIG problem -- after we SEIZE-d a task we should
seize
it's threads, but we should do it in a loop -- reading /proc/pid/task and
seizing
them again and again, until the contents of this dir stops changing (not done
now).
Besides, after we seized a task and all its threads we cannot scan it's children
list once -- task can get reparented to init and any task's child can call clone
with CLONE_PARENT flag thus repopulating the children list of the already seized
task (not done also)
This patch is ugly, yes, but splitting it doesn't help to review it much, sorry
:(
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-02-01 19:45:31 +04:00
|
|
|
case 's':
|
2012-03-01 19:09:02 +04:00
|
|
|
opts.final_state = TASK_STOPPED;
|
ctrools: Rewrite task/threads stopping engine is back
This commit brings the former "Rewrite task/threads stopping engine"
commit back. Handling it separately is too complex so better try
to handle it in-place.
Note some tests might fault, it's expected.
---
Stopping tasks with STOP and proceeding with SEIZE is actually excessive --
the SEIZE if enough. Moreover, just killing a task with STOP is also racy,
since task should be given some time to come to sleep before its proc
can be parsed.
Rewrite all this code to SEIZE task and all its threads from the very beginning.
With this we can distinguish stopped task state and migrate it properly (not
supported now, need to implement).
This thing however has one BIG problem -- after we SEIZE-d a task we should
seize
it's threads, but we should do it in a loop -- reading /proc/pid/task and
seizing
them again and again, until the contents of this dir stops changing (not done
now).
Besides, after we seized a task and all its threads we cannot scan it's children
list once -- task can get reparented to init and any task's child can call clone
with CLONE_PARENT flag thus repopulating the children list of the already seized
task (not done also)
This patch is ugly, yes, but splitting it doesn't help to review it much, sorry
:(
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-02-01 19:45:31 +04:00
|
|
|
break;
|
2012-04-19 11:48:00 +04:00
|
|
|
case 'x':
|
|
|
|
opts.ext_unix_sk = true;
|
|
|
|
break;
|
2011-10-13 19:43:52 +04:00
|
|
|
case 'p':
|
|
|
|
pid = atoi(optarg);
|
|
|
|
opts.leader_only = true;
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
pid = atoi(optarg);
|
|
|
|
opts.leader_only = false;
|
|
|
|
break;
|
2011-12-05 15:57:47 +04:00
|
|
|
case 'c':
|
|
|
|
opts.show_pages_content = true;
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
opts.show_dump_file = optarg;
|
|
|
|
break;
|
2012-01-18 23:24:37 +04:00
|
|
|
case 'd':
|
|
|
|
opts.restore_detach = true;
|
|
|
|
break;
|
2011-12-07 13:48:00 +04:00
|
|
|
case 'D':
|
|
|
|
if (chdir(optarg)) {
|
2012-02-01 02:08:04 +04:00
|
|
|
pr_perror("Can't change directory to %s",
|
|
|
|
optarg);
|
2011-12-19 16:51:26 +04:00
|
|
|
return -1;
|
2011-12-07 13:48:00 +04:00
|
|
|
}
|
|
|
|
break;
|
2011-12-08 18:39:00 +04:00
|
|
|
case 'o':
|
2012-03-01 18:52:42 +04:00
|
|
|
if (log_init(optarg))
|
2011-12-19 16:51:26 +04:00
|
|
|
return -1;
|
2011-12-08 18:39:00 +04:00
|
|
|
log_inited = 1;
|
|
|
|
break;
|
2012-01-26 15:27:00 +04:00
|
|
|
case 'n':
|
2012-01-31 22:28:22 +04:00
|
|
|
if (parse_ns_string(optarg, &opts.namespaces_flags))
|
|
|
|
return -1;
|
2012-01-26 15:27:00 +04:00
|
|
|
break;
|
2012-02-17 22:51:23 +04:00
|
|
|
case 'v':
|
|
|
|
if (optind < argc - 1) {
|
|
|
|
char *opt = argv[optind + 1];
|
|
|
|
|
|
|
|
if (isdigit(*opt)) {
|
|
|
|
log_level = -atoi(opt);
|
|
|
|
optind++;
|
|
|
|
} else {
|
|
|
|
if (log_level >= 0)
|
|
|
|
log_level++;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (log_level >= 0)
|
|
|
|
log_level++;
|
|
|
|
}
|
|
|
|
break;
|
2012-04-28 17:15:12 +04:00
|
|
|
case 42:
|
|
|
|
pr_info("Will dump TCP connections\n");
|
|
|
|
opts.tcp_established_ok = true;
|
|
|
|
break;
|
2012-04-28 20:37:54 +04:00
|
|
|
case 43: {
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
fd = atoi(optarg);
|
|
|
|
pr_info("Closing fd %d\n", fd);
|
|
|
|
close(fd);
|
|
|
|
break;
|
|
|
|
}
|
2011-10-13 19:43:52 +04:00
|
|
|
case 'h':
|
|
|
|
default:
|
|
|
|
goto usage;
|
|
|
|
}
|
2011-10-04 01:50:19 +04:00
|
|
|
}
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-02-17 22:51:23 +04:00
|
|
|
if (log_level < 0)
|
|
|
|
log_level = -log_level;
|
2012-03-01 18:52:42 +04:00
|
|
|
log_set_loglevel(log_level);
|
2012-02-17 22:51:23 +04:00
|
|
|
|
2011-12-13 15:03:33 +04:00
|
|
|
if (!log_inited) {
|
2012-03-01 18:52:42 +04:00
|
|
|
ret = log_init(NULL);
|
2011-12-13 15:03:33 +04:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
2011-12-08 18:39:00 +04:00
|
|
|
|
2012-03-16 17:24:00 +04:00
|
|
|
ret = open_image_dir();
|
|
|
|
if (ret < 0) {
|
|
|
|
pr_perror("can't open currect directory");
|
2011-12-13 15:03:33 +04:00
|
|
|
return -1;
|
2011-12-07 13:48:00 +04:00
|
|
|
}
|
|
|
|
|
2012-01-18 18:53:49 +03:00
|
|
|
if (strcmp(argv[1], "dump") &&
|
|
|
|
strcmp(argv[1], "restore") &&
|
2012-03-02 14:01:08 +04:00
|
|
|
strcmp(argv[1], "show") &&
|
|
|
|
strcmp(argv[1], "check")) {
|
2012-01-18 18:53:49 +03:00
|
|
|
pr_err("Unknown command");
|
|
|
|
goto usage;
|
|
|
|
}
|
|
|
|
|
2011-10-13 19:43:52 +04:00
|
|
|
switch (action) {
|
|
|
|
case 'd':
|
2012-03-27 11:04:23 +04:00
|
|
|
if (!pid)
|
|
|
|
goto opt_pid_missing;
|
2011-10-04 01:50:19 +04:00
|
|
|
ret = cr_dump_tasks(pid, &opts);
|
2011-10-13 19:43:52 +04:00
|
|
|
break;
|
|
|
|
case 'r':
|
2012-03-27 11:04:23 +04:00
|
|
|
if (!pid)
|
|
|
|
goto opt_pid_missing;
|
2011-10-04 01:50:19 +04:00
|
|
|
ret = cr_restore_tasks(pid, &opts);
|
2011-10-13 19:43:52 +04:00
|
|
|
break;
|
|
|
|
case 's':
|
2012-03-27 11:04:23 +04:00
|
|
|
ret = cr_show(&opts);
|
2011-10-13 19:43:52 +04:00
|
|
|
break;
|
2012-03-02 14:01:08 +04:00
|
|
|
case 'c':
|
|
|
|
ret = cr_check();
|
|
|
|
break;
|
2011-10-13 19:43:52 +04:00
|
|
|
default:
|
2011-09-23 12:00:45 +04:00
|
|
|
goto usage;
|
2011-10-13 19:43:52 +04:00
|
|
|
break;
|
|
|
|
}
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
usage:
|
2012-03-01 18:52:42 +04:00
|
|
|
pr_msg("\nUsage:\n");
|
2012-04-29 09:23:12 +04:00
|
|
|
pr_msg(" %s dump -p|-t pid [<options>]\n", argv[0]);
|
|
|
|
pr_msg(" %s restore -p|-t pid [<options>]\n", argv[0]);
|
|
|
|
pr_msg(" %s show (-D dir)|(-f file) [<options>]\n", argv[0]);
|
2012-03-02 14:01:08 +04:00
|
|
|
pr_msg(" %s check\n", argv[0]);
|
2012-03-01 18:52:42 +04:00
|
|
|
|
|
|
|
pr_msg("\nCommands:\n");
|
2012-04-29 09:23:12 +04:00
|
|
|
pr_msg(" dump checkpoint a process/tree identified by pid\n");
|
|
|
|
pr_msg(" restore restore a process/tree identified by pid\n");
|
2012-03-27 11:04:23 +04:00
|
|
|
pr_msg(" show show dump file(s) contents\n");
|
2012-03-02 14:01:08 +04:00
|
|
|
pr_msg(" check checks whether the kernel support is up-to-date\n");
|
2012-04-29 09:23:12 +04:00
|
|
|
|
|
|
|
pr_msg("\nDump/Restore options:\n");
|
|
|
|
|
|
|
|
pr_msg("\n* Generic:\n");
|
2012-04-16 14:23:05 +04:00
|
|
|
pr_msg(" -p|--pid checkpoint/restore only a single process identified by pid\n");
|
|
|
|
pr_msg(" -t|--tree checkpoint/restore the whole process tree identified by pid\n");
|
|
|
|
pr_msg(" -d|--restore-detached detach after restore\n");
|
|
|
|
pr_msg(" -s|--leave-stopped leave tasks in stopped state after checkpoint instead of killing them\n");
|
2012-04-29 09:23:12 +04:00
|
|
|
pr_msg(" -D|--images-dir directory where to put images to\n");
|
|
|
|
|
|
|
|
pr_msg("\n* Special resources support:\n");
|
2012-04-16 14:23:05 +04:00
|
|
|
pr_msg(" -n|--namespaces checkpoint/restore namespaces - values must be separated by comma\n");
|
|
|
|
pr_msg(" supported: uts, ipc\n");
|
2012-04-19 11:48:00 +04:00
|
|
|
pr_msg(" -x|--ext-unix-sk allow external unix connections\n");
|
2012-04-29 09:23:12 +04:00
|
|
|
pr_msg(" --%s checkpoint/restore established TCP connections\n", SK_EST_PARAM);
|
2012-03-01 18:52:42 +04:00
|
|
|
|
2012-04-29 09:23:12 +04:00
|
|
|
pr_msg("\n* Logging:\n");
|
|
|
|
pr_msg(" -o|--log-file log file name (relative path is relative to --images-dir)\n");
|
2012-04-16 14:23:05 +04:00
|
|
|
pr_msg(" -v [num] set logging level\n");
|
|
|
|
pr_msg(" 0 - silent (only error messages)\n");
|
|
|
|
pr_msg(" 1 - informative (default)\n");
|
|
|
|
pr_msg(" 2 - debug\n");
|
2012-03-01 18:52:42 +04:00
|
|
|
pr_msg(" -vv same as -v 1\n");
|
|
|
|
pr_msg(" -vvv same as -v 2\n");
|
2012-04-29 09:23:12 +04:00
|
|
|
|
|
|
|
pr_msg("\nShow options:\n");
|
|
|
|
pr_msg(" -f|--file show contents of a checkpoint file\n");
|
|
|
|
pr_msg(" -D|--images-dir directory where to get images from\n");
|
|
|
|
pr_msg(" -c|--contents show contents of pages dumped in hexdump format\n");
|
2011-12-05 15:57:47 +04:00
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
return -1;
|
2011-12-20 19:47:06 +04:00
|
|
|
|
|
|
|
opt_pid_missing:
|
2012-03-01 18:52:42 +04:00
|
|
|
pr_msg("No pid specified (-t or -p option missing)\n");
|
2011-12-20 19:47:06 +04:00
|
|
|
return -1;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|