2001-11-21 15:47:42 +03:00
/*
2004-03-30 23:08:57 +04:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2015-09-18 15:35:52 +03:00
* Copyright ( C ) 2004 - 2015 Red Hat , Inc . All rights reserved .
2007-08-21 20:26:07 +04:00
* Copyright ( C ) 2005 - 2007 NEC Corporation
2001-11-21 15:47:42 +03:00
*
2004-03-30 23:08:57 +04:00
* This file is part of the device - mapper userspace tools .
*
2005-10-16 18:33:22 +04:00
* It includes tree drawing code based on pstree : http : //psmisc.sourceforge.net/
*
2004-03-30 23:08:57 +04:00
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
* of the GNU General Public License v .2 .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
2016-01-21 13:49:46 +03:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2001-11-21 15:47:42 +03:00
*/
2015-07-06 19:30:18 +03:00
# include "tool.h"
2005-05-17 00:46:46 +04:00
2008-10-30 20:24:04 +03:00
# include "dm-logging.h"
2001-11-21 15:47:42 +03:00
# include <ctype.h>
2003-11-13 16:14:28 +03:00
# include <dirent.h>
2005-05-17 00:46:46 +04:00
# include <sys/wait.h>
# include <sys/param.h>
2005-10-16 18:33:22 +04:00
# include <locale.h>
# include <langinfo.h>
2009-08-06 19:05:10 +04:00
# include <time.h>
2005-10-16 18:33:22 +04:00
2006-10-12 19:42:25 +04:00
# include <fcntl.h>
# include <sys/stat.h>
2009-08-06 19:04:30 +04:00
# ifdef UDEV_SYNC_SUPPORT
# include <sys / types.h>
# include <sys / ipc.h>
# include <sys / sem.h>
2010-02-15 19:21:33 +03:00
# include <libudev.h>
# endif
2009-08-06 19:04:30 +04:00
2006-10-12 19:42:25 +04:00
/* FIXME Unused so far */
# undef HAVE_SYS_STATVFS_H
# ifdef HAVE_SYS_STATVFS_H
# include <sys / statvfs.h>
# endif
2005-10-16 18:33:22 +04:00
# ifdef HAVE_SYS_IOCTL_H
# include <sys / ioctl.h>
# endif
2015-08-17 16:11:00 +03:00
# ifdef HAVE_SYS_TIMERFD_H
2015-08-09 01:59:06 +03:00
# include <sys / timerfd.h>
# endif
2015-08-17 16:11:00 +03:00
# ifdef HAVE_TERMIOS_H
2005-10-16 18:33:22 +04:00
# include <termios.h>
# endif
2003-11-12 20:30:32 +03:00
# ifdef HAVE_GETOPTLONG
# include <getopt.h>
# define GETOPTLONG_FN(a, b, c, d, e) getopt_long((a), (b), (c), (d), (e))
# define OPTIND_INIT 0
# else
struct option {
} ;
extern int optind ;
extern char * optarg ;
# define GETOPTLONG_FN(a, b, c, d, e) getopt((a), (b), (c))
# define OPTIND_INIT 1
# endif
2005-05-17 00:46:46 +04:00
# ifndef TEMP_FAILURE_RETRY
# define TEMP_FAILURE_RETRY(expression) \
2015-08-05 07:03:33 +03:00
( __extension__ \
( { long int __result ; \
do __result = ( long int ) ( expression ) ; \
while ( __result = = - 1L & & errno = = EINTR ) ; \
2005-05-17 00:46:46 +04:00
__result ; } ) )
# endif
2013-11-13 17:56:29 +04:00
# ifdef __linux__
2004-07-01 19:14:29 +04:00
# include "kdev_t.h"
2003-11-12 20:30:32 +03:00
# else
# define MAJOR(x) major((x))
# define MINOR(x) minor((x))
# define MKDEV(x,y) makedev((x),(y))
# endif
2001-11-21 15:47:42 +03:00
2006-04-20 00:43:30 +04:00
# define LINE_SIZE 4096
2005-05-17 00:46:46 +04:00
# define ARGS_MAX 256
2006-10-12 19:42:25 +04:00
# define LOOP_TABLE_SIZE (PATH_MAX + 255)
2010-02-15 19:21:33 +03:00
# define DEFAULT_DM_DEV_DIR " / dev / "
# define DM_DEV_DIR_ENV_VAR_NAME "DM_DEV_DIR"
# define DM_UDEV_COOKIE_ENV_VAR_NAME "DM_UDEV_COOKIE"
2007-10-09 16:14:48 +04:00
2007-06-15 22:20:28 +04:00
/* FIXME Should be imported */
# ifndef DM_MAX_TYPE_NAME
# define DM_MAX_TYPE_NAME 16
# endif
2006-10-12 19:42:25 +04:00
/* FIXME Should be elsewhere */
# define SECTOR_SHIFT 9L
2001-11-21 15:47:42 +03:00
# define err(msg, x...) fprintf(stderr, msg "\n", ##x)
2015-08-05 12:40:00 +03:00
/* program_id used for dmstats-managed statistics regions */
# define DM_STATS_PROGRAM_ID "dmstats"
2015-08-14 00:30:39 +03:00
/*
* Basic commands this code implments .
*/
typedef enum {
DMSETUP_CMD = 0 ,
LOSETUP_CMD = 1 ,
DMLOSETUP_CMD = 2 ,
DMSTATS_CMD = 3 ,
DMSETUP_STATS_CMD = 4 ,
DEVMAP_NAME_CMD = 5
} cmd_name_t ;
typedef enum {
DMSETUP_TYPE = 0 ,
LOSETUP_TYPE = 1 ,
STATS_TYPE = 2 ,
DEVMAP_NAME_TYPE = 3
} cmd_type_t ;
2015-08-13 15:10:23 +03:00
# define DMSETUP_CMD_NAME "dmsetup"
# define LOSETUP_CMD_NAME "losetup"
# define DMLOSETUP_CMD_NAME "dmlosetup"
# define DMSTATS_CMD_NAME "dmstats"
2015-08-14 00:30:39 +03:00
# define DMSETUP_STATS_CMD_NAME "dmsetup stats"
# define DEVMAP_NAME_CMD_NAME "devmap_name"
static const struct {
cmd_name_t command ;
const char name [ 14 ] ;
cmd_type_t type ;
} _base_commands [ ] = {
{ DMSETUP_CMD , DMSETUP_CMD_NAME , DMSETUP_TYPE } ,
{ LOSETUP_CMD , LOSETUP_CMD_NAME , LOSETUP_TYPE } ,
{ DMLOSETUP_CMD , DMLOSETUP_CMD_NAME , LOSETUP_TYPE } ,
{ DMSTATS_CMD , DMSTATS_CMD_NAME , STATS_TYPE } ,
{ DMSETUP_STATS_CMD , DMSETUP_STATS_CMD_NAME , STATS_TYPE } ,
{ DEVMAP_NAME_CMD , DEVMAP_NAME_CMD_NAME , DEVMAP_NAME_TYPE } ,
} ;
static const int _num_base_commands = DM_ARRAY_SIZE ( _base_commands ) ;
2015-08-13 15:10:23 +03:00
2002-01-03 13:39:21 +03:00
/*
* We have only very simple switches ATM .
*/
enum {
READ_ONLY = 0 ,
2011-07-01 18:09:19 +04:00
ADD_NODE_ON_CREATE_ARG ,
ADD_NODE_ON_RESUME_ARG ,
2015-08-13 16:42:55 +03:00
ALL_DEVICES_ARG ,
2015-08-05 12:40:00 +03:00
ALL_PROGRAMS_ARG ,
ALL_REGIONS_ARG ,
AREAS_ARG ,
AREA_SIZE_ARG ,
AUX_DATA_ARG ,
2015-09-04 01:00:44 +03:00
BOUNDS_ARG ,
2011-07-01 18:09:19 +04:00
CHECKS_ARG ,
2015-08-05 12:40:00 +03:00
CLEAR_ARG ,
2004-06-16 20:44:12 +04:00
COLS_ARG ,
2015-07-31 23:59:34 +03:00
COUNT_ARG ,
2014-08-16 03:34:48 +04:00
DEFERRED_ARG ,
2014-05-29 11:38:49 +04:00
SELECT_ARG ,
2005-05-17 00:46:46 +04:00
EXEC_ARG ,
2006-06-18 15:35:04 +04:00
FORCE_ARG ,
2006-02-03 17:23:22 +03:00
GID_ARG ,
2010-03-08 19:05:07 +03:00
HELP_ARG ,
2015-08-18 14:40:03 +03:00
HISTOGRAM_ARG ,
2009-11-06 03:43:08 +03:00
INACTIVE_ARG ,
2015-07-31 23:59:34 +03:00
INTERVAL_ARG ,
2015-08-05 12:40:00 +03:00
LENGTH_ARG ,
2012-02-15 16:02:58 +04:00
MANGLENAME_ARG ,
2003-04-04 17:22:58 +04:00
MAJOR_ARG ,
2002-01-11 15:12:46 +03:00
MINOR_ARG ,
2006-02-03 17:23:22 +03:00
MODE_ARG ,
2008-06-06 22:53:08 +04:00
NAMEPREFIXES_ARG ,
2006-10-12 19:42:25 +04:00
NOFLUSH_ARG ,
2004-10-12 20:42:40 +04:00
NOHEADINGS_ARG ,
2005-10-05 00:12:32 +04:00
NOLOCKFS_ARG ,
2005-01-13 01:10:14 +03:00
NOOPENCOUNT_ARG ,
2015-08-05 12:40:00 +03:00
NOSUFFIX_ARG ,
2003-11-12 20:30:32 +03:00
NOTABLE_ARG ,
2015-09-03 23:55:25 +03:00
NOTIMESUFFIX_ARG ,
2010-02-15 19:21:33 +03:00
UDEVCOOKIE_ARG ,
2010-01-07 22:45:12 +03:00
NOUDEVRULES_ARG ,
2009-07-31 21:51:45 +04:00
NOUDEVSYNC_ARG ,
2005-03-27 15:37:46 +04:00
OPTIONS_ARG ,
2015-08-18 14:39:34 +03:00
PRECISE_ARG ,
2015-08-05 12:40:00 +03:00
PROGRAM_ID_ARG ,
2015-08-14 19:42:03 +03:00
RAW_ARG ,
2007-11-27 23:57:05 +03:00
READAHEAD_ARG ,
2015-08-05 12:40:00 +03:00
REGION_ID_ARG ,
2015-08-18 14:40:03 +03:00
RELATIVE_ARG ,
2011-09-22 21:12:28 +04:00
RETRY_ARG ,
2008-06-25 02:53:48 +04:00
ROWS_ARG ,
2007-01-18 20:47:58 +03:00
SEPARATOR_ARG ,
2010-10-15 05:10:27 +04:00
SETUUID_ARG ,
2006-10-19 19:34:50 +04:00
SHOWKEYS_ARG ,
2007-01-18 20:47:58 +03:00
SORT_ARG ,
2015-08-05 12:40:00 +03:00
START_ARG ,
2006-08-10 18:11:03 +04:00
TABLE_ARG ,
2005-05-16 18:53:23 +04:00
TARGET_ARG ,
2015-08-05 12:40:00 +03:00
SEGMENTS_ARG ,
2005-10-16 18:33:22 +04:00
TREE_ARG ,
2006-02-03 17:23:22 +03:00
UID_ARG ,
2007-06-15 22:20:28 +04:00
UNBUFFERED_ARG ,
2015-08-05 12:40:00 +03:00
UNITS_ARG ,
2008-06-25 00:16:47 +04:00
UNQUOTED_ARG ,
2003-11-12 20:30:32 +03:00
UUID_ARG ,
2003-01-22 00:25:51 +03:00
VERBOSE_ARG ,
2011-06-28 01:43:58 +04:00
VERIFYUDEV_ARG ,
2003-07-04 23:38:49 +04:00
VERSION_ARG ,
2009-09-11 19:53:57 +04:00
YES_ARG ,
2002-01-03 13:39:21 +03:00
NUM_SWITCHES
} ;
2007-06-11 17:20:29 +04:00
typedef enum {
DR_TASK = 1 ,
DR_INFO = 2 ,
2007-06-15 22:20:28 +04:00
DR_DEPS = 4 ,
2009-06-03 22:35:39 +04:00
DR_TREE = 8 , /* Complete dependency tree required */
2015-08-05 12:40:00 +03:00
DR_NAME = 16 ,
2015-08-13 23:14:57 +03:00
DR_STATS = 32 , /* Requires populated stats handle. */
DR_STATS_META = 64 , /* Requires listed stats handle. */
2007-06-11 17:20:29 +04:00
} report_type_t ;
2012-01-11 16:46:19 +04:00
typedef enum {
DN_DEVNO , /* Major and minor number pair */
DN_BLK , /* Block device name (e.g. dm-0) */
DN_MAP /* Map name (for dm devices only, equal to DN_BLK otherwise) */
} dev_name_t ;
2015-08-14 00:30:39 +03:00
static cmd_name_t _base_command = DMSETUP_CMD ; /* Default command is 'dmsetup' */
static cmd_type_t _base_command_type = DMSETUP_TYPE ;
2002-01-03 13:39:21 +03:00
static int _switches [ NUM_SWITCHES ] ;
2007-01-18 20:47:58 +03:00
static int _int_args [ NUM_SWITCHES ] ;
static char * _string_args [ NUM_SWITCHES ] ;
2006-06-18 15:35:04 +04:00
static int _num_devices ;
2003-11-12 20:30:32 +03:00
static char * _uuid ;
2006-08-10 18:11:03 +04:00
static char * _table ;
2005-05-16 18:53:23 +04:00
static char * _target ;
2015-08-14 00:30:39 +03:00
static char * _command_to_exec ; /* --exec <command> */
static const char * _command ; /* dmsetup <command> */
2007-11-29 17:44:28 +03:00
static uint32_t _read_ahead_flags ;
2010-02-15 19:21:33 +03:00
static uint32_t _udev_cookie ;
static int _udev_only ;
2005-11-09 17:10:50 +03:00
static struct dm_tree * _dtree ;
2007-01-24 21:09:07 +03:00
static struct dm_report * _report ;
2007-06-11 17:20:29 +04:00
static report_type_t _report_type ;
2012-01-11 16:46:19 +04:00
static dev_name_t _dev_name_type ;
2015-07-31 23:59:34 +03:00
static uint32_t _count = 1 ; /* count of repeating reports */
2015-08-05 10:28:35 +03:00
static struct dm_timestamp * _initial_timestamp = NULL ;
2015-08-05 12:40:00 +03:00
static uint64_t _disp_factor = 512 ; /* display sizes in sectors */
static char _disp_units = ' s ' ;
2015-08-14 01:03:46 +03:00
const char * _program_id = DM_STATS_PROGRAM_ID ; /* program_id used for reports. */
2015-08-14 22:40:13 +03:00
static int _stats_report_by_areas = 1 ; /* output per-area info for stats reports. */
2015-08-05 12:40:00 +03:00
/* report timekeeping */
2015-08-09 01:59:06 +03:00
static struct dm_timestamp * _cycle_timestamp = NULL ;
2015-08-07 18:15:21 +03:00
static uint64_t _interval = 0 ; /* configured interval in nsecs */
2015-08-09 01:59:06 +03:00
static uint64_t _new_interval = 0 ; /* flag top-of-interval */
static uint64_t _last_interval = 0 ; /* approx. measured interval in nsecs */
static int _timer_fd = - 1 ; /* timerfd file descriptor. */
/* Invalid fd value used to signal end-of-reporting. */
# define TIMER_STOPPED -2
2015-07-31 23:59:34 +03:00
# define NSEC_PER_USEC UINT64_C(1000)
# define NSEC_PER_MSEC UINT64_C(1000000)
# define NSEC_PER_SEC UINT64_C(1000000000)
2002-01-03 13:39:21 +03:00
/*
* Commands
*/
2007-01-24 21:09:07 +03:00
2011-03-02 05:44:56 +03:00
struct command ;
2015-07-31 19:47:03 +03:00
# define CMD_ARGS const struct command *cmd, const char *subcommand, int argc, char **argv, struct dm_names *names, int multiple_devices
2011-03-02 05:44:56 +03:00
typedef int ( * command_fn ) ( CMD_ARGS ) ;
2007-01-24 21:09:07 +03:00
struct command {
const char * name ;
const char * help ;
int min_args ;
int max_args ;
2011-03-02 05:44:56 +03:00
int repeatable_cmd ; /* Repeat to process device list? */
2015-07-31 21:09:31 +03:00
int has_subcommands ; /* Command implements sub-commands. */
2007-01-24 21:09:07 +03:00
command_fn fn ;
} ;
2006-08-10 18:11:03 +04:00
static int _parse_line ( struct dm_task * dmt , char * buffer , const char * file ,
int line )
{
char ttype [ LINE_SIZE ] , * ptr , * comment ;
unsigned long long start , size ;
int n ;
/* trim trailing space */
for ( ptr = buffer + strlen ( buffer ) - 1 ; ptr > = buffer ; ptr - - )
if ( ! isspace ( ( int ) * ptr ) )
break ;
ptr + + ;
* ptr = ' \0 ' ;
/* trim leading space */
for ( ptr = buffer ; * ptr & & isspace ( ( int ) * ptr ) ; ptr + + )
;
if ( ! * ptr | | * ptr = = ' # ' )
return 1 ;
if ( sscanf ( ptr , " %llu %llu %s %n " ,
& start , & size , ttype , & n ) < 3 ) {
err ( " Invalid format on line %d of table %s " , line , file ) ;
return 0 ;
}
ptr + = n ;
if ( ( comment = strchr ( ptr , ( int ) ' # ' ) ) )
* comment = ' \0 ' ;
if ( ! dm_task_add_target ( dmt , start , size , ttype , ptr ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2006-08-10 18:11:03 +04:00
return 1 ;
}
2001-11-21 15:47:42 +03:00
static int _parse_file ( struct dm_task * dmt , const char * file )
{
2006-05-10 23:38:25 +04:00
char * buffer = NULL ;
size_t buffer_size = 0 ;
2003-11-12 20:30:32 +03:00
FILE * fp ;
2006-08-10 18:11:03 +04:00
int r = 0 , line = 0 ;
2001-11-21 15:47:42 +03:00
2006-08-10 18:11:03 +04:00
/* one-line table on cmdline */
if ( _table )
return _parse_line ( dmt , _table , " " , + + line ) ;
2003-11-12 20:30:32 +03:00
2006-08-10 18:11:03 +04:00
/* OK for empty stdin */
2003-11-12 20:30:32 +03:00
if ( file ) {
if ( ! ( fp = fopen ( file , " r " ) ) ) {
err ( " Couldn't open '%s' for reading " , file ) ;
return 0 ;
}
} else
fp = stdin ;
2001-11-21 15:47:42 +03:00
2006-05-10 23:38:25 +04:00
# ifndef HAVE_GETLINE
buffer_size = LINE_SIZE ;
2006-10-12 19:42:25 +04:00
if ( ! ( buffer = dm_malloc ( buffer_size ) ) ) {
2006-05-10 23:38:25 +04:00
err ( " Failed to malloc line buffer. " ) ;
return 0 ;
}
2006-08-10 18:11:03 +04:00
while ( fgets ( buffer , ( int ) buffer_size , fp ) )
2006-05-10 23:38:25 +04:00
# else
2006-08-10 18:11:03 +04:00
while ( getline ( & buffer , & buffer_size , fp ) > 0 )
2006-05-10 23:38:25 +04:00
# endif
2006-08-10 18:11:03 +04:00
if ( ! _parse_line ( dmt , buffer , file ? : " on stdin " , + + line ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2001-11-21 15:47:42 +03:00
2002-03-07 23:56:10 +03:00
r = 1 ;
2001-11-21 15:47:42 +03:00
2015-09-06 01:56:30 +03:00
out :
2010-04-07 19:57:20 +04:00
memset ( buffer , 0 , buffer_size ) ;
2006-10-19 19:34:50 +04:00
# ifndef HAVE_GETLINE
2006-10-12 19:42:25 +04:00
dm_free ( buffer ) ;
2006-10-19 19:34:50 +04:00
# else
free ( buffer ) ;
# endif
2007-01-25 17:16:20 +03:00
if ( file & & fclose ( fp ) )
fprintf ( stderr , " %s: fclose failed: %s " , file , strerror ( errno ) ) ;
2002-03-07 23:56:10 +03:00
return r ;
2001-11-21 15:47:42 +03:00
}
2009-06-03 22:35:39 +04:00
struct dm_split_name {
2015-08-05 07:03:33 +03:00
char * subsystem ;
char * vg_name ;
char * lv_name ;
char * lv_layer ;
2009-06-03 22:35:39 +04:00
} ;
2007-01-24 21:09:07 +03:00
struct dmsetup_report_obj {
struct dm_task * task ;
struct dm_info * info ;
2007-06-15 22:20:28 +04:00
struct dm_task * deps_task ;
2007-06-11 17:20:29 +04:00
struct dm_tree_node * tree_node ;
2009-06-03 22:35:39 +04:00
struct dm_split_name * split_name ;
2015-08-05 12:40:00 +03:00
struct dm_stats * stats ;
2007-01-24 21:09:07 +03:00
} ;
2004-10-12 20:42:40 +04:00
2015-08-05 10:28:35 +03:00
static int _task_run ( struct dm_task * dmt )
{
int r ;
uint64_t delta ;
2015-11-08 21:27:22 +03:00
struct dm_timestamp * ts ;
2015-08-05 10:28:35 +03:00
if ( _initial_timestamp )
dm_task_set_record_timestamp ( dmt ) ;
r = dm_task_run ( dmt ) ;
2015-11-08 21:27:22 +03:00
if ( _initial_timestamp & &
( ts = dm_task_get_ioctl_timestamp ( dmt ) ) ) {
delta = dm_timestamp_delta ( ts , _initial_timestamp ) ;
log_debug ( " Timestamp: %7 " PRIu64 " .%09 " PRIu64 " seconds " ,
delta / NSEC_PER_SEC , delta % NSEC_PER_SEC ) ;
2015-08-05 10:28:35 +03:00
}
return r ;
}
2007-06-15 22:20:28 +04:00
static struct dm_task * _get_deps_task ( int major , int minor )
{
struct dm_task * dmt ;
struct dm_info info ;
if ( ! ( dmt = dm_task_create ( DM_DEVICE_DEPS ) ) )
2015-09-06 01:56:30 +03:00
return_NULL ;
2007-06-15 22:20:28 +04:00
if ( ! dm_task_set_major ( dmt , major ) | |
! dm_task_set_minor ( dmt , minor ) )
2015-09-06 01:56:30 +03:00
goto_bad ;
2007-06-15 22:20:28 +04:00
if ( _switches [ NOOPENCOUNT_ARG ] & & ! dm_task_no_open_count ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_bad ;
2007-06-15 22:20:28 +04:00
2009-11-06 03:43:08 +03:00
if ( _switches [ INACTIVE_ARG ] & & ! dm_task_query_inactive_table ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_bad ;
2009-11-06 03:43:08 +03:00
2011-07-01 18:09:19 +04:00
if ( _switches [ CHECKS_ARG ] & & ! dm_task_enable_checks ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_bad ;
2011-07-01 18:09:19 +04:00
2015-08-05 10:28:35 +03:00
if ( ! _task_run ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_bad ;
2007-06-15 22:20:28 +04:00
if ( ! dm_task_get_info ( dmt , & info ) )
2015-09-06 01:56:30 +03:00
goto_bad ;
2007-06-15 22:20:28 +04:00
if ( ! info . exists )
2015-09-06 01:56:30 +03:00
goto_bad ;
2007-06-15 22:20:28 +04:00
return dmt ;
2015-09-06 01:56:30 +03:00
bad :
2007-06-15 22:20:28 +04:00
dm_task_destroy ( dmt ) ;
return NULL ;
}
2009-06-04 00:44:42 +04:00
static char * _extract_uuid_prefix ( const char * uuid , const int separator )
2009-06-03 22:35:39 +04:00
{
char * ptr = NULL ;
char * uuid_prefix = NULL ;
size_t len ;
if ( uuid )
2009-06-04 00:44:42 +04:00
ptr = strchr ( uuid , separator ) ;
2009-06-03 22:35:39 +04:00
len = ptr ? ptr - uuid : 0 ;
if ( ! ( uuid_prefix = dm_malloc ( len + 1 ) ) ) {
log_error ( " Failed to allocate memory to extract uuid prefix. " ) ;
return NULL ;
}
2010-12-01 01:53:37 +03:00
if ( uuid )
memcpy ( uuid_prefix , uuid , len ) ;
2009-06-03 22:35:39 +04:00
uuid_prefix [ len ] = ' \0 ' ;
return uuid_prefix ;
}
2009-06-04 00:44:42 +04:00
static struct dm_split_name * _get_split_name ( const char * uuid , const char * name ,
int separator )
2009-06-03 22:35:39 +04:00
{
struct dm_split_name * split_name ;
if ( ! ( split_name = dm_malloc ( sizeof ( * split_name ) ) ) ) {
log_error ( " Failed to allocate memory to split device name "
" into components. " ) ;
return NULL ;
}
2012-08-16 22:12:38 +04:00
if ( ! ( split_name - > subsystem = _extract_uuid_prefix ( uuid , separator ) ) ) {
dm_free ( split_name ) ;
2012-03-02 01:49:32 +04:00
return_NULL ;
2012-08-16 22:12:38 +04:00
}
2012-03-02 01:49:32 +04:00
2009-06-03 22:35:39 +04:00
split_name - > vg_name = split_name - > lv_name =
split_name - > lv_layer = ( char * ) " " ;
if ( ! strcmp ( split_name - > subsystem , " LVM " ) & &
( ! ( split_name - > vg_name = dm_strdup ( name ) ) | |
! dm_split_lvm_name ( NULL , NULL , & split_name - > vg_name ,
2015-08-05 07:03:33 +03:00
& split_name - > lv_name , & split_name - > lv_layer ) ) )
2009-06-03 22:35:39 +04:00
log_error ( " Failed to allocate memory to split LVM name "
" into components. " ) ;
return split_name ;
}
static void _destroy_split_name ( struct dm_split_name * split_name )
{
/*
* lv_name and lv_layer are allocated within the same block
* of memory as vg_name so don ' t need to be freed separately .
*/
if ( ! strcmp ( split_name - > subsystem , " LVM " ) )
dm_free ( split_name - > vg_name ) ;
dm_free ( split_name - > subsystem ) ;
dm_free ( split_name ) ;
}
2015-08-09 01:59:06 +03:00
/*
* Stats clock :
*
* Use either Linux timerfds or usleep to implement the reporting
* interval wait .
*
* _start_timer ( ) - Start the timer running .
* _do_timer_wait ( ) - Wait until the beginning of the next interval .
*
* _update_interval_times ( ) - Update timestamps and interval estimate .
*/
2015-08-12 21:46:11 +03:00
/*
* Return the current interval number counting upwards from one .
*/
static uint64_t _interval_num ( void )
{
return 1 + ( uint64_t ) _int_args [ COUNT_ARG ] - _count ;
}
2015-08-17 16:11:00 +03:00
# ifdef HAVE_SYS_TIMERFD_H
2015-08-09 01:59:06 +03:00
static int _start_timerfd_timer ( void )
{
struct itimerspec interval_timer ;
time_t secs ;
long nsecs ;
log_debug ( " Using timerfd for interval timekeeping. " ) ;
/* timer running? */
if ( _timer_fd ! = - 1 )
return 1 ;
memset ( & interval_timer , 0 , sizeof ( interval_timer ) ) ;
/* Use CLOCK_MONOTONIC to avoid warp on RTC adjustments. */
if ( ( _timer_fd = timerfd_create ( CLOCK_MONOTONIC , TFD_CLOEXEC ) ) < 0 ) {
log_error ( " Could not create timer: %s " , strerror ( errno ) ) ;
return 0 ;
}
secs = ( time_t ) _interval / NSEC_PER_SEC ;
nsecs = ( long ) _interval % NSEC_PER_SEC ;
/* Must set interval and value to create an armed periodic timer. */
interval_timer . it_interval . tv_sec = secs ;
interval_timer . it_interval . tv_nsec = nsecs ;
interval_timer . it_value . tv_sec = secs ;
interval_timer . it_value . tv_nsec = nsecs ;
2015-08-18 16:28:56 +03:00
log_debug ( " Setting interval timer to: " FMTu64 " s %ldns " , ( uint64_t ) secs , nsecs ) ;
2015-08-09 01:59:06 +03:00
if ( timerfd_settime ( _timer_fd , 0 , & interval_timer , NULL ) ) {
log_error ( " Could not set interval timer: %s " , strerror ( errno ) ) ;
return 0 ;
}
return 1 ;
}
static int _do_timerfd_wait ( void )
{
uint64_t expired ;
2015-08-17 21:26:44 +03:00
ssize_t bytes ;
2015-08-09 01:59:06 +03:00
if ( _timer_fd < 0 )
2015-09-06 01:56:30 +03:00
return_0 ;
2015-08-09 01:59:06 +03:00
/* read on timerfd returns a uint64_t in host byte order. */
2015-08-17 21:26:44 +03:00
bytes = read ( _timer_fd , & expired , sizeof ( expired ) ) ;
if ( bytes < 0 ) {
2015-08-09 01:59:06 +03:00
/* EBADF from invalid timerfd or EINVAL from too small buffer. */
log_error ( " Interval timer wait failed: %s " ,
strerror ( errno ) ) ;
return 0 ;
}
2015-08-17 21:26:44 +03:00
/* read(2) on a timerfd descriptor is guaranteed to return 8 bytes. */
if ( bytes ! = 8 )
2015-08-18 13:59:13 +03:00
log_error ( " Unexpected byte count on timerfd read: " FMTssize_t , bytes ) ;
2015-08-17 21:26:44 +03:00
2015-08-09 01:59:06 +03:00
/* FIXME: attempt to rebase clock? */
if ( expired > 1 )
log_warn ( " WARNING: Try increasing --interval ( " FMTu64
" missed timer events). " , expired - 1 ) ;
/* Signal that a new interval has begun. */
_new_interval = 1 ;
/* Final interval? */
if ( _count = = 2 ) {
if ( close ( _timer_fd ) )
stack ;
/* Tell _update_interval_times() to shut down. */
_timer_fd = TIMER_STOPPED ;
}
return 1 ;
}
static int _start_timer ( void )
{
return _start_timerfd_timer ( ) ;
}
static int _do_timer_wait ( void )
{
return _do_timerfd_wait ( ) ;
}
# else /* !HAVE_SYS_TIMERFD_H */
static int _start_usleep_timer ( void )
{
log_debug ( " Using usleep for interval timekeeping. " ) ;
return 1 ;
}
static int _do_usleep_wait ( void )
{
static struct dm_timestamp * _last_sleep , * _now = NULL ;
uint64_t this_interval ;
int64_t delta_t ;
/*
* Report clock : compensate for time spent in userspace and stats
* message ioctls by keeping track of the last wake time and
* adjusting the sleep interval accordingly .
*/
if ( ! _last_sleep & & ! _now ) {
if ( ! ( _last_sleep = dm_timestamp_alloc ( ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2015-08-09 01:59:06 +03:00
if ( ! ( _now = dm_timestamp_alloc ( ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2015-08-09 01:59:06 +03:00
dm_timestamp_get ( _now ) ;
this_interval = _interval ;
log_error ( " Using " FMTu64 " as first interval. " , this_interval ) ;
} else {
dm_timestamp_get ( _now ) ;
delta_t = dm_timestamp_delta ( _now , _last_sleep ) ;
log_debug ( " Interval timer delta_t: " FMTi64 , delta_t ) ;
/* FIXME: usleep timer drift over large counts. */
/* adjust for time spent populating and reporting */
this_interval = 2 * _interval - delta_t ;
log_debug ( " Using " FMTu64 " as interval. " , this_interval ) ;
}
/* Signal that a new interval has begun. */
_new_interval = 1 ;
dm_timestamp_copy ( _last_sleep , _now ) ;
if ( usleep ( this_interval / NSEC_PER_USEC ) ) {
if ( errno = = EINTR )
log_error ( " Report interval interrupted by signal. " ) ;
if ( errno = = EINVAL )
log_error ( " Report interval too short. " ) ;
2015-09-06 01:56:30 +03:00
return_0 ;
2015-08-09 01:59:06 +03:00
}
2015-09-06 01:56:30 +03:00
if ( _count = = 2 ) {
2015-08-09 01:59:06 +03:00
dm_timestamp_destroy ( _last_sleep ) ;
dm_timestamp_destroy ( _now ) ;
}
return 1 ;
}
static int _start_timer ( void )
{
return _start_usleep_timer ( ) ;
}
static int _do_timer_wait ( void )
{
return _do_usleep_wait ( ) ;
}
# endif /* HAVE_SYS_TIMERFD_H */
static int _update_interval_times ( void )
{
static struct dm_timestamp * this_timestamp = NULL ;
2015-08-12 21:46:11 +03:00
uint64_t delta_t , interval_num = _interval_num ( ) ;
2015-08-09 01:59:06 +03:00
int r = 0 ;
2015-08-12 21:16:05 +03:00
/*
* Clock shutdown for exit - nothing to do .
*/
if ( _timer_fd = = TIMER_STOPPED & & ! _cycle_timestamp )
return 1 ;
2015-08-09 01:59:06 +03:00
/*
* Current timestamp . If _new_interval is set this is used as
* the new cycle start timestamp .
*/
if ( ! this_timestamp ) {
if ( ! ( this_timestamp = dm_timestamp_alloc ( ) ) )
return_0 ;
}
/*
* Take cycle timstamp as close as possible to ioctl return .
*
* FIXME : use per - region timestamp deltas for interval estimate .
*/
if ( ! dm_timestamp_get ( this_timestamp ) )
goto_out ;
/*
* Stats clock : maintain a single timestamp taken just after the
* call to dm_stats_populate ( ) and take a delta between the current
* and last value to determine the sampling interval .
*
* A new interval is started when the _new_interval flag is set
* on return from _do_report_wait ( ) .
*
* The first interval is treated as a special case : since the
* time since the last clear of the counters is unknown ( no
* previous timestamp exists ) the duration is assumed to be the
* configured value .
*/
if ( _cycle_timestamp )
/* Current delta_t: time from start of cycle to now. */
delta_t = dm_timestamp_delta ( this_timestamp , _cycle_timestamp ) ;
else {
_cycle_timestamp = dm_timestamp_alloc ( ) ;
if ( ! _cycle_timestamp ) {
log_error ( " Could not allocate timestamp object. " ) ;
goto out ;
}
/* Pretend we have the configured interval. */
delta_t = _interval ;
/* start the first cycle */
log_debug ( " Beginning first interval " ) ;
_new_interval = 1 ;
}
2015-08-12 21:46:11 +03:00
log_debug ( " Interval #%-4 " PRIu64 " time delta: %12 "
PRIu64 " ns " , interval_num , delta_t ) ;
2015-08-09 01:59:06 +03:00
if ( _new_interval ) {
/* Update timestamp and interval and clear _new_interval */
dm_timestamp_copy ( _cycle_timestamp , this_timestamp ) ;
_last_interval = delta_t ;
_new_interval = 0 ;
/*
2015-08-14 15:52:33 +03:00
* Log interval duration and current error .
2015-08-09 01:59:06 +03:00
*/
2015-08-14 15:52:33 +03:00
log_debug ( " Interval #%-5 " PRIu64 " current err: %12 " PRIi64 " ns " ,
interval_num , ( ( int64_t ) _last_interval - ( int64_t ) _interval ) ) ;
2015-08-12 21:46:11 +03:00
log_debug ( " End interval #%-9 " PRIu64 " duration: %12 " PRIu64 " ns " ,
interval_num , _last_interval ) ;
2015-08-09 01:59:06 +03:00
}
r = 1 ;
out :
if ( ! r | | _timer_fd = = TIMER_STOPPED ) {
/* The _cycle_timestamp has not yet been allocated if we
* fail to obtain this_timestamp on the first interval .
*/
if ( _cycle_timestamp )
dm_timestamp_destroy ( _cycle_timestamp ) ;
dm_timestamp_destroy ( this_timestamp ) ;
2015-08-12 21:16:05 +03:00
/* Clear timestamp pointers to signal shutdown. */
_cycle_timestamp = this_timestamp = NULL ;
2015-08-09 01:59:06 +03:00
}
return r ;
}
2007-01-24 21:09:07 +03:00
static int _display_info_cols ( struct dm_task * dmt , struct dm_info * info )
2003-07-02 01:20:58 +04:00
{
2007-01-24 21:09:07 +03:00
struct dmsetup_report_obj obj ;
2015-08-09 01:59:06 +03:00
2007-06-11 17:20:29 +04:00
int r = 0 ;
2003-07-02 01:20:58 +04:00
2004-06-16 20:44:12 +04:00
if ( ! info - > exists ) {
2007-01-24 21:09:07 +03:00
fprintf ( stderr , " Device does not exist. \n " ) ;
return 0 ;
2004-06-16 20:44:12 +04:00
}
2003-07-02 01:20:58 +04:00
2007-01-24 21:09:07 +03:00
obj . task = dmt ;
obj . info = info ;
2007-06-15 22:20:28 +04:00
obj . deps_task = NULL ;
2009-06-03 22:35:39 +04:00
obj . split_name = NULL ;
2015-08-05 12:40:00 +03:00
obj . stats = NULL ;
2004-06-16 20:44:12 +04:00
2007-06-11 17:20:29 +04:00
if ( _report_type & DR_TREE )
2012-02-13 15:13:44 +04:00
if ( ! ( obj . tree_node = dm_tree_find_node ( _dtree , info - > major , info - > minor ) ) ) {
log_error ( " Cannot find node %d:%d. " , info - > major , info - > minor ) ;
goto out ;
}
2007-06-11 17:20:29 +04:00
2007-06-15 22:20:28 +04:00
if ( _report_type & DR_DEPS )
2012-02-13 15:13:44 +04:00
if ( ! ( obj . deps_task = _get_deps_task ( info - > major , info - > minor ) ) ) {
log_error ( " Cannot get deps for %d:%d. " , info - > major , info - > minor ) ;
goto out ;
}
2007-06-15 22:20:28 +04:00
2009-06-03 22:35:39 +04:00
if ( _report_type & DR_NAME )
2012-02-13 15:13:44 +04:00
if ( ! ( obj . split_name = _get_split_name ( dm_task_get_uuid ( dmt ) ,
dm_task_get_name ( dmt ) , ' - ' ) ) )
goto_out ;
2009-06-03 22:35:39 +04:00
2015-08-05 12:40:00 +03:00
/*
* Obtain statistics for the current reporting object and set
* the interval estimate used for stats rate conversion .
*/
if ( _report_type & DR_STATS ) {
if ( ! ( obj . stats = dm_stats_create ( DM_STATS_PROGRAM_ID ) ) )
goto_out ;
dm_stats_bind_devno ( obj . stats , info - > major , info - > minor ) ;
2015-08-09 01:59:06 +03:00
2015-08-14 01:03:46 +03:00
if ( ! dm_stats_populate ( obj . stats , _program_id , DM_STATS_REGIONS_ALL ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2015-08-09 01:59:06 +03:00
/* Update timestamps and handle end-of-interval accounting. */
_update_interval_times ( ) ;
2015-08-12 21:46:11 +03:00
log_debug ( " Adjusted sample interval duration: %12 " PRIu64 " ns " , _last_interval ) ;
2015-08-09 01:59:06 +03:00
/* use measured approximation for calculations */
dm_stats_set_sampling_interval_ns ( obj . stats , _last_interval ) ;
2015-08-05 12:40:00 +03:00
}
2004-06-16 20:44:12 +04:00
2015-08-14 01:03:46 +03:00
/* Only a dm_stats_list is needed for DR_STATS_META reports. */
if ( ! obj . stats & & ( _report_type & DR_STATS_META ) ) {
if ( ! ( obj . stats = dm_stats_create ( DM_STATS_PROGRAM_ID ) ) )
goto_out ;
dm_stats_bind_devno ( obj . stats , info - > major , info - > minor ) ;
if ( ! dm_stats_list ( obj . stats , _program_id ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2015-08-14 01:03:46 +03:00
/* No regions to report */
if ( ! dm_stats_get_nr_regions ( obj . stats ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2015-08-14 01:03:46 +03:00
}
2015-08-05 12:40:00 +03:00
/*
* Walk any statistics regions contained in the current
* reporting object : for objects with a NULL stats handle ,
* or a handle containing no registered regions , this loop
* always executes exactly once .
*/
dm_stats_walk_do ( obj . stats ) {
if ( ! dm_report_object ( _report , & obj ) )
goto_out ;
2015-08-14 22:40:13 +03:00
if ( _stats_report_by_areas )
dm_stats_walk_next ( obj . stats ) ;
else
dm_stats_walk_next_region ( obj . stats ) ;
2015-08-05 12:40:00 +03:00
} dm_stats_walk_while ( obj . stats ) ;
2007-06-11 17:20:29 +04:00
r = 1 ;
2015-09-06 01:56:30 +03:00
out :
2007-06-15 22:20:28 +04:00
if ( obj . deps_task )
dm_task_destroy ( obj . deps_task ) ;
2009-06-03 22:35:39 +04:00
if ( obj . split_name )
_destroy_split_name ( obj . split_name ) ;
2015-08-05 12:40:00 +03:00
if ( obj . stats )
dm_stats_destroy ( obj . stats ) ;
2007-06-11 17:20:29 +04:00
return r ;
2004-06-16 20:44:12 +04:00
}
static void _display_info_long ( struct dm_task * dmt , struct dm_info * info )
{
const char * uuid ;
2007-11-30 17:59:57 +03:00
uint32_t read_ahead ;
2004-06-16 20:44:12 +04:00
if ( ! info - > exists ) {
2013-11-01 15:40:27 +04:00
fprintf ( stderr , " Device does not exist. \n " ) ;
2003-07-02 01:20:58 +04:00
return ;
}
printf ( " Name: %s \n " , dm_task_get_name ( dmt ) ) ;
2014-08-16 03:34:48 +04:00
printf ( " State: %s%s%s \n " ,
2004-06-16 20:44:12 +04:00
info - > suspended ? " SUSPENDED " : " ACTIVE " ,
2014-08-16 03:34:48 +04:00
info - > read_only ? " (READ-ONLY) " : " " ,
info - > deferred_remove ? " (DEFERRED REMOVE) " : " " ) ;
2003-07-02 01:20:58 +04:00
2007-12-04 01:53:04 +03:00
/* FIXME Old value is being printed when it's being changed. */
2007-11-30 17:59:57 +03:00
if ( dm_task_get_read_ahead ( dmt , & read_ahead ) )
2007-12-04 01:48:36 +03:00
printf ( " Read Ahead: % " PRIu32 " \n " , read_ahead ) ;
2007-11-27 23:57:05 +03:00
2004-06-16 20:44:12 +04:00
if ( ! info - > live_table & & ! info - > inactive_table )
2003-07-02 01:20:58 +04:00
printf ( " Tables present: None \n " ) ;
else
printf ( " Tables present: %s%s%s \n " ,
2004-06-16 20:44:12 +04:00
info - > live_table ? " LIVE " : " " ,
info - > live_table & & info - > inactive_table ? " & " : " " ,
info - > inactive_table ? " INACTIVE " : " " ) ;
2003-07-02 01:20:58 +04:00
2004-06-16 20:44:12 +04:00
if ( info - > open_count ! = - 1 )
printf ( " Open count: %d \n " , info - > open_count ) ;
2003-07-02 01:20:58 +04:00
2004-06-16 20:44:12 +04:00
printf ( " Event number: % " PRIu32 " \n " , info - > event_nr ) ;
printf ( " Major, minor: %d, %d \n " , info - > major , info - > minor ) ;
2003-07-02 01:20:58 +04:00
2004-06-16 20:44:12 +04:00
if ( info - > target_count ! = - 1 )
printf ( " Number of targets: %d \n " , info - > target_count ) ;
2003-07-02 01:20:58 +04:00
if ( ( uuid = dm_task_get_uuid ( dmt ) ) & & * uuid )
printf ( " UUID: %s \n " , uuid ) ;
2003-07-04 23:38:49 +04:00
printf ( " \n " ) ;
2003-07-02 01:20:58 +04:00
}
2005-03-27 15:37:46 +04:00
static int _display_info ( struct dm_task * dmt )
2004-06-16 20:44:12 +04:00
{
struct dm_info info ;
if ( ! dm_task_get_info ( dmt , & info ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2004-06-16 20:44:12 +04:00
2004-10-12 20:42:40 +04:00
if ( ! _switches [ COLS_ARG ] )
2004-06-16 20:44:12 +04:00
_display_info_long ( dmt , & info ) ;
2004-10-12 20:42:40 +04:00
else
2007-01-24 21:09:07 +03:00
/* FIXME return code */
2004-10-12 20:42:40 +04:00
_display_info_cols ( dmt , & info ) ;
2005-03-27 15:37:46 +04:00
return info . exists ? 1 : 0 ;
2004-06-16 20:44:12 +04:00
}
2004-10-01 23:11:37 +04:00
static int _set_task_device ( struct dm_task * dmt , const char * name , int optional )
{
if ( name ) {
if ( ! dm_task_set_name ( dmt , name ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2004-10-01 23:11:37 +04:00
} else if ( _switches [ UUID_ARG ] ) {
if ( ! dm_task_set_uuid ( dmt , _uuid ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2004-10-01 23:11:37 +04:00
} else if ( _switches [ MAJOR_ARG ] & & _switches [ MINOR_ARG ] ) {
2007-01-18 20:47:58 +03:00
if ( ! dm_task_set_major ( dmt , _int_args [ MAJOR_ARG ] ) | |
! dm_task_set_minor ( dmt , _int_args [ MINOR_ARG ] ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2004-10-01 23:11:37 +04:00
} else if ( ! optional ) {
fprintf ( stderr , " No device specified. \n " ) ;
return 0 ;
}
return 1 ;
}
2011-02-05 01:17:54 +03:00
static int _set_task_add_node ( struct dm_task * dmt )
{
if ( ! dm_task_set_add_node ( dmt , DEFAULT_DM_ADD_NODE ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2011-02-05 01:17:54 +03:00
if ( _switches [ ADD_NODE_ON_RESUME_ARG ] & &
! dm_task_set_add_node ( dmt , DM_ADD_NODE_ON_RESUME ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2011-02-05 01:17:54 +03:00
if ( _switches [ ADD_NODE_ON_CREATE_ARG ] & &
! dm_task_set_add_node ( dmt , DM_ADD_NODE_ON_CREATE ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2011-02-05 01:17:54 +03:00
return 1 ;
}
2011-03-02 05:44:56 +03:00
static int _load ( CMD_ARGS )
2001-11-21 15:47:42 +03:00
{
int r = 0 ;
struct dm_task * dmt ;
2004-10-01 23:11:37 +04:00
const char * file = NULL ;
const char * name = NULL ;
2001-11-21 15:47:42 +03:00
2004-10-01 23:11:37 +04:00
if ( _switches [ NOTABLE_ARG ] ) {
err ( " --notable only available when creating new device \n " ) ;
2001-11-21 15:47:42 +03:00
return 0 ;
2004-10-01 23:11:37 +04:00
}
2001-11-21 15:47:42 +03:00
2004-10-01 23:11:37 +04:00
if ( ! _switches [ UUID_ARG ] & & ! _switches [ MAJOR_ARG ] ) {
2015-08-14 00:30:39 +03:00
if ( ! argc ) {
2004-10-01 23:11:37 +04:00
err ( " Please specify device. \n " ) ;
return 0 ;
}
2015-08-14 00:30:39 +03:00
name = argv [ 0 ] ;
2004-10-01 23:11:37 +04:00
argc - - ;
argv + + ;
2015-08-14 00:30:39 +03:00
} else if ( argc > 1 ) {
2004-10-01 23:11:37 +04:00
err ( " Too many command line arguments. \n " ) ;
return 0 ;
}
2001-11-21 15:47:42 +03:00
2015-08-14 00:30:39 +03:00
if ( argc = = 1 )
file = argv [ 0 ] ;
2002-03-12 01:44:36 +03:00
2004-10-01 23:11:37 +04:00
if ( ! ( dmt = dm_task_create ( DM_DEVICE_RELOAD ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2003-11-13 16:14:28 +03:00
2004-10-01 23:11:37 +04:00
if ( ! _set_task_device ( dmt , name , 0 ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2002-01-03 13:39:21 +03:00
2004-10-01 23:11:37 +04:00
if ( ! _switches [ NOTABLE_ARG ] & & ! _parse_file ( dmt , file ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2003-04-04 17:22:58 +04:00
2004-10-01 23:11:37 +04:00
if ( _switches [ READ_ONLY ] & & ! dm_task_set_ro ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2002-01-11 15:12:46 +03:00
2005-01-13 01:10:14 +03:00
if ( _switches [ NOOPENCOUNT_ARG ] & & ! dm_task_no_open_count ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2005-01-13 01:10:14 +03:00
2009-11-06 03:43:08 +03:00
if ( _switches [ INACTIVE_ARG ] & & ! dm_task_query_inactive_table ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2009-11-06 03:43:08 +03:00
2011-07-01 18:09:19 +04:00
if ( _switches [ CHECKS_ARG ] & & ! dm_task_enable_checks ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2011-07-01 18:09:19 +04:00
2015-08-05 10:28:35 +03:00
if ( ! _task_run ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2001-11-21 15:47:42 +03:00
r = 1 ;
2003-07-04 23:38:49 +04:00
if ( _switches [ VERBOSE_ARG ] )
2005-03-27 15:37:46 +04:00
r = _display_info ( dmt ) ;
2003-07-02 01:20:58 +04:00
2015-09-06 01:56:30 +03:00
out :
2001-11-21 15:47:42 +03:00
dm_task_destroy ( dmt ) ;
return r ;
}
2011-03-02 05:44:56 +03:00
static int _create ( CMD_ARGS )
2001-11-21 15:47:42 +03:00
{
2004-10-01 23:11:37 +04:00
int r = 0 ;
struct dm_task * dmt ;
const char * file = NULL ;
2009-07-31 21:51:45 +04:00
uint32_t cookie = 0 ;
2010-01-07 22:45:12 +03:00
uint16_t udev_flags = 0 ;
2001-11-21 15:47:42 +03:00
2015-08-14 00:30:39 +03:00
if ( argc = = 2 )
file = argv [ 1 ] ;
2006-06-18 15:35:04 +04:00
2004-10-01 23:11:37 +04:00
if ( ! ( dmt = dm_task_create ( DM_DEVICE_CREATE ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2003-11-12 20:30:32 +03:00
2015-08-14 00:30:39 +03:00
if ( ! dm_task_set_name ( dmt , argv [ 0 ] ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2004-10-01 23:11:37 +04:00
if ( _switches [ UUID_ARG ] & & ! dm_task_set_uuid ( dmt , _uuid ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2004-10-01 23:11:37 +04:00
if ( ! _switches [ NOTABLE_ARG ] & & ! _parse_file ( dmt , file ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2004-10-01 23:11:37 +04:00
if ( _switches [ READ_ONLY ] & & ! dm_task_set_ro ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2004-10-01 23:11:37 +04:00
2007-01-18 20:47:58 +03:00
if ( _switches [ MAJOR_ARG ] & & ! dm_task_set_major ( dmt , _int_args [ MAJOR_ARG ] ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2004-10-01 23:11:37 +04:00
2007-01-18 20:47:58 +03:00
if ( _switches [ MINOR_ARG ] & & ! dm_task_set_minor ( dmt , _int_args [ MINOR_ARG ] ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2004-10-01 23:11:37 +04:00
2007-01-18 20:47:58 +03:00
if ( _switches [ UID_ARG ] & & ! dm_task_set_uid ( dmt , _int_args [ UID_ARG ] ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2006-02-03 17:23:22 +03:00
2007-01-18 20:47:58 +03:00
if ( _switches [ GID_ARG ] & & ! dm_task_set_gid ( dmt , _int_args [ GID_ARG ] ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2006-02-03 17:23:22 +03:00
2007-01-18 20:47:58 +03:00
if ( _switches [ MODE_ARG ] & & ! dm_task_set_mode ( dmt , _int_args [ MODE_ARG ] ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2006-02-03 17:23:22 +03:00
2005-01-13 01:10:14 +03:00
if ( _switches [ NOOPENCOUNT_ARG ] & & ! dm_task_no_open_count ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2005-01-13 01:10:14 +03:00
2009-11-06 03:43:08 +03:00
if ( _switches [ INACTIVE_ARG ] & & ! dm_task_query_inactive_table ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2009-11-06 03:43:08 +03:00
2007-11-27 23:57:05 +03:00
if ( _switches [ READAHEAD_ARG ] & &
2007-11-29 17:44:28 +03:00
! dm_task_set_read_ahead ( dmt , _int_args [ READAHEAD_ARG ] ,
_read_ahead_flags ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2007-11-27 23:57:05 +03:00
2009-07-31 21:51:45 +04:00
if ( _switches [ NOTABLE_ARG ] )
dm_udev_set_sync_support ( 0 ) ;
2010-01-07 22:45:12 +03:00
if ( _switches [ NOUDEVRULES_ARG ] )
udev_flags | = DM_UDEV_DISABLE_DM_RULES_FLAG |
DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG ;
2011-07-01 18:09:19 +04:00
if ( _switches [ CHECKS_ARG ] & & ! dm_task_enable_checks ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2011-02-04 22:33:53 +03:00
2011-02-05 01:17:54 +03:00
if ( ! _set_task_add_node ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2011-02-04 22:33:53 +03:00
2011-06-17 18:55:51 +04:00
if ( _udev_cookie )
2010-02-15 19:21:33 +03:00
cookie = _udev_cookie ;
2011-06-17 18:55:51 +04:00
if ( _udev_only )
udev_flags | = DM_UDEV_DISABLE_LIBRARY_FALLBACK ;
2010-02-15 19:21:33 +03:00
2010-01-07 22:45:12 +03:00
if ( ! dm_task_set_cookie ( dmt , & cookie , udev_flags ) | |
2015-08-05 10:28:35 +03:00
! _task_run ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2004-10-01 23:11:37 +04:00
r = 1 ;
2015-09-06 01:56:30 +03:00
out :
2010-08-03 17:04:32 +04:00
if ( ! _udev_cookie )
( void ) dm_udev_wait ( cookie ) ;
2011-03-02 03:29:57 +03:00
if ( r & & _switches [ VERBOSE_ARG ] )
2005-03-27 15:37:46 +04:00
r = _display_info ( dmt ) ;
2004-10-01 23:11:37 +04:00
2010-08-03 17:04:32 +04:00
dm_task_destroy ( dmt ) ;
2004-10-01 23:11:37 +04:00
return r ;
2001-11-21 15:47:42 +03:00
}
2012-02-15 16:08:57 +04:00
static int _do_rename ( const char * name , const char * new_name , const char * new_uuid ) {
2002-01-11 15:12:46 +03:00
int r = 0 ;
struct dm_task * dmt ;
2009-07-31 21:51:45 +04:00
uint32_t cookie = 0 ;
2010-01-07 22:45:12 +03:00
uint16_t udev_flags = 0 ;
2002-01-11 15:12:46 +03:00
2002-03-07 23:56:10 +03:00
if ( ! ( dmt = dm_task_create ( DM_DEVICE_RENAME ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2002-01-11 15:12:46 +03:00
2004-10-01 23:11:37 +04:00
/* FIXME Kernel doesn't support uuid or device number here yet */
2012-02-15 16:08:57 +04:00
if ( ! _set_task_device ( dmt , name , 0 ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2002-01-11 15:12:46 +03:00
2012-02-15 16:08:57 +04:00
if ( new_uuid ) {
if ( ! dm_task_set_newuuid ( dmt , new_uuid ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2012-02-27 04:19:23 +04:00
} else if ( ! new_name | | ! dm_task_set_newname ( dmt , new_name ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2002-01-11 15:12:46 +03:00
2005-01-13 01:10:14 +03:00
if ( _switches [ NOOPENCOUNT_ARG ] & & ! dm_task_no_open_count ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2005-01-13 01:10:14 +03:00
2009-11-06 03:43:08 +03:00
if ( _switches [ INACTIVE_ARG ] & & ! dm_task_query_inactive_table ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2009-11-06 03:43:08 +03:00
2011-07-01 18:09:19 +04:00
if ( _switches [ CHECKS_ARG ] & & ! dm_task_enable_checks ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2011-07-01 18:09:19 +04:00
2010-01-07 22:45:12 +03:00
if ( _switches [ NOUDEVRULES_ARG ] )
udev_flags | = DM_UDEV_DISABLE_DM_RULES_FLAG |
DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG ;
2011-06-17 18:55:51 +04:00
if ( _udev_cookie )
2010-02-15 19:21:33 +03:00
cookie = _udev_cookie ;
2011-06-17 18:55:51 +04:00
if ( _udev_only )
udev_flags | = DM_UDEV_DISABLE_LIBRARY_FALLBACK ;
2010-02-15 19:21:33 +03:00
2010-01-07 22:45:12 +03:00
if ( ! dm_task_set_cookie ( dmt , & cookie , udev_flags ) | |
2015-08-05 10:28:35 +03:00
! _task_run ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2002-01-11 15:12:46 +03:00
2002-03-07 23:56:10 +03:00
r = 1 ;
2002-01-11 15:12:46 +03:00
2015-09-06 01:56:30 +03:00
out :
2010-02-15 19:21:33 +03:00
if ( ! _udev_cookie )
( void ) dm_udev_wait ( cookie ) ;
2011-03-02 03:29:57 +03:00
2002-03-07 23:56:10 +03:00
dm_task_destroy ( dmt ) ;
2002-01-11 15:12:46 +03:00
2002-03-07 23:56:10 +03:00
return r ;
2002-01-11 15:12:46 +03:00
}
2001-11-21 15:47:42 +03:00
2012-02-15 16:08:57 +04:00
static int _rename ( CMD_ARGS )
{
2015-08-14 00:30:39 +03:00
const char * name = ( argc = = 2 ) ? argv [ 0 ] : NULL ;
2012-02-15 16:08:57 +04:00
return _switches [ SETUUID_ARG ] ? _do_rename ( name , NULL , argv [ argc - 1 ] ) :
_do_rename ( name , argv [ argc - 1 ] , NULL ) ;
}
2011-03-02 05:44:56 +03:00
static int _message ( CMD_ARGS )
2004-06-09 00:34:40 +04:00
{
2006-01-31 17:50:38 +03:00
int r = 0 , i ;
size_t sz = 1 ;
2004-06-09 00:34:40 +04:00
struct dm_task * dmt ;
char * str ;
2013-08-16 18:25:39 +04:00
const char * response ;
2013-09-18 04:24:19 +04:00
uint64_t sector ;
char * endptr ;
2004-06-09 00:34:40 +04:00
if ( ! ( dmt = dm_task_create ( DM_DEVICE_TARGET_MSG ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2004-06-09 00:34:40 +04:00
2004-10-01 23:11:37 +04:00
if ( _switches [ UUID_ARG ] | | _switches [ MAJOR_ARG ] ) {
if ( ! _set_task_device ( dmt , NULL , 0 ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2004-10-01 23:11:37 +04:00
} else {
2015-08-14 00:30:39 +03:00
if ( ! _set_task_device ( dmt , argv [ 0 ] , 0 ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2004-10-01 23:11:37 +04:00
argc - - ;
argv + + ;
}
2004-06-09 00:34:40 +04:00
2015-08-14 00:30:39 +03:00
sector = strtoull ( argv [ 0 ] , & endptr , 10 ) ;
if ( * endptr | | endptr = = argv [ 0 ] ) {
2013-09-18 04:24:19 +04:00
err ( " invalid sector " ) ;
goto out ;
}
if ( ! dm_task_set_sector ( dmt , sector ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2004-06-09 00:34:40 +04:00
2015-08-14 00:30:39 +03:00
argc - - ;
argv + + ;
2004-10-01 23:11:37 +04:00
if ( argc < = 0 )
err ( " No message supplied. \n " ) ;
2004-06-09 00:34:40 +04:00
for ( i = 0 ; i < argc ; i + + )
sz + = strlen ( argv [ i ] ) + 1 ;
2010-10-01 01:06:50 +04:00
if ( ! ( str = dm_zalloc ( sz ) ) ) {
2007-01-16 01:05:50 +03:00
err ( " message string allocation failed " ) ;
goto out ;
}
2004-06-09 00:34:40 +04:00
for ( i = 0 ; i < argc ; i + + ) {
if ( i )
strcat ( str , " " ) ;
strcat ( str , argv [ i ] ) ;
}
2011-08-04 16:40:24 +04:00
i = dm_task_set_message ( dmt , str ) ;
2004-06-09 00:34:40 +04:00
2006-10-12 19:42:25 +04:00
dm_free ( str ) ;
2004-06-09 00:34:40 +04:00
2011-08-04 16:40:24 +04:00
if ( ! i )
2015-09-06 01:56:30 +03:00
goto_out ;
2011-08-04 16:40:24 +04:00
2005-01-13 01:10:14 +03:00
if ( _switches [ NOOPENCOUNT_ARG ] & & ! dm_task_no_open_count ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2005-01-13 01:10:14 +03:00
2009-11-06 03:43:08 +03:00
if ( _switches [ INACTIVE_ARG ] & & ! dm_task_query_inactive_table ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2009-11-06 03:43:08 +03:00
2011-07-01 18:09:19 +04:00
if ( _switches [ CHECKS_ARG ] & & ! dm_task_enable_checks ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2011-07-01 18:09:19 +04:00
2015-08-05 10:28:35 +03:00
if ( ! _task_run ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2004-06-09 00:34:40 +04:00
2013-08-16 18:25:39 +04:00
if ( ( response = dm_task_get_message_response ( dmt ) ) ) {
if ( ! * response | | response [ strlen ( response ) - 1 ] = = ' \n ' )
fputs ( response , stdout ) ;
else
puts ( response ) ;
}
2004-06-09 00:34:40 +04:00
r = 1 ;
2015-09-06 01:56:30 +03:00
out :
2004-06-09 00:34:40 +04:00
dm_task_destroy ( dmt ) ;
return r ;
}
2011-03-02 05:44:56 +03:00
static int _setgeometry ( CMD_ARGS )
2006-02-21 02:55:58 +03:00
{
int r = 0 ;
struct dm_task * dmt ;
if ( ! ( dmt = dm_task_create ( DM_DEVICE_SET_GEOMETRY ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2006-02-21 02:55:58 +03:00
if ( _switches [ UUID_ARG ] | | _switches [ MAJOR_ARG ] ) {
if ( ! _set_task_device ( dmt , NULL , 0 ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2006-02-21 02:55:58 +03:00
} else {
2015-08-14 00:30:39 +03:00
if ( ! _set_task_device ( dmt , argv [ 0 ] , 0 ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2006-02-21 02:55:58 +03:00
argc - - ;
argv + + ;
}
2015-08-14 00:30:39 +03:00
if ( ! dm_task_set_geometry ( dmt , argv [ 0 ] , argv [ 1 ] , argv [ 2 ] , argv [ 3 ] ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2006-02-21 02:55:58 +03:00
2009-11-06 03:43:08 +03:00
if ( _switches [ NOOPENCOUNT_ARG ] & & ! dm_task_no_open_count ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2009-11-06 03:43:08 +03:00
if ( _switches [ INACTIVE_ARG ] & & ! dm_task_query_inactive_table ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2009-11-06 03:43:08 +03:00
2011-07-01 18:09:19 +04:00
if ( _switches [ CHECKS_ARG ] & & ! dm_task_enable_checks ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2011-07-01 18:09:19 +04:00
2006-02-21 02:55:58 +03:00
/* run the task */
2015-08-05 10:28:35 +03:00
if ( ! _task_run ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2006-02-21 02:55:58 +03:00
r = 1 ;
2015-09-06 01:56:30 +03:00
out :
2006-02-21 02:55:58 +03:00
dm_task_destroy ( dmt ) ;
return r ;
}
2011-03-02 05:44:56 +03:00
static int _splitname ( CMD_ARGS )
2009-06-04 00:44:42 +04:00
{
2014-08-19 16:30:52 +04:00
struct dmsetup_report_obj obj = { NULL } ;
2014-08-19 16:19:11 +04:00
int r ;
2009-06-04 00:44:42 +04:00
2015-08-14 00:30:39 +03:00
if ( ! ( obj . split_name = _get_split_name ( ( argc = = 2 ) ? argv [ 1 ] : " LVM " ,
argv [ 0 ] , ' \0 ' ) ) )
2015-08-05 07:03:33 +03:00
return_0 ;
2009-06-04 00:44:42 +04:00
r = dm_report_object ( _report , & obj ) ;
_destroy_split_name ( obj . split_name ) ;
return r ;
}
2010-02-15 19:21:33 +03:00
static uint32_t _get_cookie_value ( const char * str_value )
2009-07-31 21:51:45 +04:00
{
2009-10-22 16:55:47 +04:00
unsigned long int value ;
2009-07-31 21:51:45 +04:00
char * p ;
2015-05-26 17:01:40 +03:00
errno = 0 ;
2009-10-22 16:55:47 +04:00
if ( ! ( value = strtoul ( str_value , & p , 0 ) ) | |
* p | |
( value = = ULONG_MAX & & errno = = ERANGE ) | |
value > 0xFFFFFFFF ) {
2009-07-31 21:51:45 +04:00
err ( " Incorrect cookie value " ) ;
return 0 ;
}
2009-10-22 16:55:47 +04:00
else
return ( uint32_t ) value ;
}
2011-03-02 05:44:56 +03:00
static int _udevflags ( CMD_ARGS )
2009-10-22 16:55:47 +04:00
{
uint32_t cookie ;
uint16_t flags ;
int i ;
2009-10-26 17:29:33 +03:00
static const char * dm_flag_names [ ] = { " DISABLE_DM_RULES " ,
" DISABLE_SUBSYSTEM_RULES " ,
2009-10-22 16:55:47 +04:00
" DISABLE_DISK_RULES " ,
2009-10-26 17:29:33 +03:00
" DISABLE_OTHER_RULES " ,
2009-10-22 16:55:47 +04:00
" LOW_PRIORITY " ,
2010-02-15 19:21:33 +03:00
" DISABLE_LIBRARY_FALLBACK " ,
2010-04-28 17:37:36 +04:00
" PRIMARY_SOURCE " ,
0 } ;
2009-10-22 16:55:47 +04:00
2015-08-14 00:30:39 +03:00
if ( ! ( cookie = _get_cookie_value ( argv [ 0 ] ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2009-10-22 16:55:47 +04:00
flags = cookie > > DM_UDEV_FLAGS_SHIFT ;
for ( i = 0 ; i < DM_UDEV_FLAGS_SHIFT ; i + + )
if ( 1 < < i & flags ) {
if ( i < DM_UDEV_FLAGS_SHIFT / 2 & & dm_flag_names [ i ] )
printf ( " DM_UDEV_%s_FLAG='1' \n " , dm_flag_names [ i ] ) ;
else if ( i < DM_UDEV_FLAGS_SHIFT / 2 )
/*
* This is just a fallback . Each new DM flag
* should have its symbolic name assigned .
*/
printf ( " DM_UDEV_FLAG%d='1' \n " , i ) ;
else
/*
* We can ' t assign symbolic names to subsystem
* flags . Their semantics vary based on the
* subsystem that is currently used .
*/
printf ( " DM_SUBSYSTEM_UDEV_FLAG%d='1' \n " ,
i - DM_UDEV_FLAGS_SHIFT / 2 ) ;
}
return 1 ;
}
2011-03-02 05:44:56 +03:00
static int _udevcomplete ( CMD_ARGS )
2009-10-22 16:55:47 +04:00
{
uint32_t cookie ;
2015-08-14 00:30:39 +03:00
if ( ! ( cookie = _get_cookie_value ( argv [ 0 ] ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2009-10-22 16:55:47 +04:00
2009-11-13 15:43:21 +03:00
/*
* Strip flags from the cookie and use cookie magic instead .
* If the cookie has non - zero prefix and the base is zero then
* this one carries flags to control udev rules only and it is
* not meant to be for notification . Return with success in this
* situation .
*/
if ( ! ( cookie & = ~ DM_UDEV_FLAGS_MASK ) )
return 1 ;
cookie | = DM_COOKIE_MAGIC < < DM_UDEV_FLAGS_SHIFT ;
2009-07-31 21:51:45 +04:00
return dm_udev_complete ( cookie ) ;
}
2009-08-06 19:04:30 +04:00
# ifndef UDEV_SYNC_SUPPORT
2012-06-28 23:32:24 +04:00
static const char _cmd_not_supported [ ] = " Command not supported. Recompile with \" --enable-udev_sync \" to enable. " ;
2009-09-11 19:53:57 +04:00
2011-03-02 05:44:56 +03:00
static int _udevcreatecookie ( CMD_ARGS )
2010-02-15 19:21:33 +03:00
{
log_error ( _cmd_not_supported ) ;
return 0 ;
}
2011-03-02 05:44:56 +03:00
static int _udevreleasecookie ( CMD_ARGS )
2010-02-15 19:21:33 +03:00
{
log_error ( _cmd_not_supported ) ;
return 0 ;
}
2011-03-02 05:44:56 +03:00
static int _udevcomplete_all ( CMD_ARGS )
2009-08-06 19:04:30 +04:00
{
2009-09-11 19:53:57 +04:00
log_error ( _cmd_not_supported ) ;
return 0 ;
2009-08-06 19:04:30 +04:00
}
2011-03-02 05:44:56 +03:00
static int _udevcookies ( CMD_ARGS )
2009-08-06 19:56:50 +04:00
{
2009-09-11 19:53:57 +04:00
log_error ( _cmd_not_supported ) ;
return 0 ;
2009-08-06 19:56:50 +04:00
}
2009-09-11 19:53:57 +04:00
# else /* UDEV_SYNC_SUPPORT */
2010-02-15 19:21:33 +03:00
static int _set_up_udev_support ( const char * dev_dir )
{
int dirs_diff ;
const char * env ;
2012-05-29 12:09:10 +04:00
size_t len = strlen ( dev_dir ) , udev_dir_len = strlen ( DM_UDEV_DEV_DIR ) ;
2010-02-15 19:21:33 +03:00
if ( _switches [ NOUDEVSYNC_ARG ] )
dm_udev_set_sync_support ( 0 ) ;
if ( ! _udev_cookie ) {
env = getenv ( DM_UDEV_COOKIE_ENV_VAR_NAME ) ;
if ( env & & * env & & ( _udev_cookie = _get_cookie_value ( env ) ) )
log_debug ( " Using udev transaction 0x%08 " PRIX32
" defined by %s environment variable. " ,
_udev_cookie ,
DM_UDEV_COOKIE_ENV_VAR_NAME ) ;
}
else if ( _switches [ UDEVCOOKIE_ARG ] )
log_debug ( " Using udev transaction 0x%08 " PRIX32
" defined by --udevcookie option. " ,
_udev_cookie ) ;
/*
* Normally , there ' s always a fallback action by libdevmapper if udev
* has not done its job correctly , e . g . the nodes were not created .
* If using udev transactions by specifying existing cookie value ,
* we need to disable node creation by libdevmapper completely ,
* disabling any fallback actions , since any synchronisation happens
* at the end of the transaction only . We need to do this to prevent
* races between udev and libdevmapper but only in case udev " dev path "
* is the same as " dev path " used by libdevmapper .
*/
2012-05-29 12:09:10 +04:00
/*
* DM_UDEV_DEV_DIR always has ' / ' at its end .
* If the dev_dir does not have it , be sure
* to make the right comparison without the ' / ' char !
*/
if ( dev_dir [ len - 1 ] ! = ' / ' )
udev_dir_len - - ;
dirs_diff = udev_dir_len ! = len | |
strncmp ( DM_UDEV_DEV_DIR , dev_dir , len ) ;
2011-06-28 01:43:58 +04:00
_udev_only = ! dirs_diff & & ( _udev_cookie | | ! _switches [ VERIFYUDEV_ARG ] ) ;
2010-02-15 19:21:33 +03:00
if ( dirs_diff ) {
log_debug ( " The path %s used for creating device nodes that is "
" set via DM_DEV_DIR environment variable differs from "
" the path %s that is used by udev. All warnings "
" about udev not working correctly while processing "
" particular nodes will be suppressed. These nodes "
" and symlinks will be managed in each directory "
2012-05-29 12:09:10 +04:00
" separately. " , dev_dir , DM_UDEV_DEV_DIR ) ;
2010-02-15 19:21:33 +03:00
dm_udev_set_checking ( 0 ) ;
}
return 1 ;
}
2011-03-02 05:44:56 +03:00
static int _udevcreatecookie ( CMD_ARGS )
2010-02-15 19:21:33 +03:00
{
uint32_t cookie ;
if ( ! dm_udev_create_cookie ( & cookie ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2010-02-15 19:21:33 +03:00
2010-03-23 17:43:18 +03:00
if ( cookie )
printf ( " 0x%08 " PRIX32 " \n " , cookie ) ;
2010-02-15 19:21:33 +03:00
return 1 ;
}
2011-03-02 05:44:56 +03:00
static int _udevreleasecookie ( CMD_ARGS )
2010-02-15 19:21:33 +03:00
{
2015-08-14 00:30:39 +03:00
if ( argv [ 0 ] & & ! ( _udev_cookie = _get_cookie_value ( argv [ 0 ] ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2010-02-15 19:21:33 +03:00
if ( ! _udev_cookie ) {
log_error ( " No udev transaction cookie given. " ) ;
return 0 ;
}
return dm_udev_wait ( _udev_cookie ) ;
}
2009-08-06 19:04:30 +04:00
2011-03-30 01:56:53 +04:00
__attribute__ ( ( format ( printf , 1 , 2 ) ) )
2009-08-06 19:56:50 +04:00
static char _yes_no_prompt ( const char * prompt , . . . )
{
int c = 0 , ret = 0 ;
va_list ap ;
do {
if ( c = = ' \n ' | | ! c ) {
va_start ( ap , prompt ) ;
vprintf ( prompt , ap ) ;
va_end ( ap ) ;
}
if ( ( c = getchar ( ) ) = = EOF ) {
ret = ' n ' ;
break ;
}
c = tolower ( c ) ;
if ( ( c = = ' y ' ) | | ( c = = ' n ' ) )
ret = c ;
} while ( ! ret | | c ! = ' \n ' ) ;
if ( c ! = ' \n ' )
printf ( " \n " ) ;
return ret ;
}
2011-03-02 05:44:56 +03:00
static int _udevcomplete_all ( CMD_ARGS )
2009-08-06 19:04:30 +04:00
{
int max_id , id , sid ;
struct seminfo sinfo ;
struct semid_ds sdata ;
int counter = 0 ;
2011-06-30 01:56:46 +04:00
int skipped = 0 ;
unsigned age = 0 ;
time_t t ;
2015-08-14 00:30:39 +03:00
if ( argc = = 1 & & ( sscanf ( argv [ 0 ] , " %u " , & age ) ! = 1 ) ) {
2011-06-30 01:56:46 +04:00
log_error ( " Failed to read age_in_minutes parameter. " ) ;
return 0 ;
}
2009-08-06 19:04:30 +04:00
2009-09-11 19:53:57 +04:00
if ( ! _switches [ YES_ARG ] ) {
2011-06-30 01:56:46 +04:00
log_warn ( " This operation will destroy all semaphores %s%.0d%swith keys "
2009-09-11 19:53:57 +04:00
" that have a prefix % " PRIu16 " (0x% " PRIx16 " ). " ,
2011-06-30 01:56:46 +04:00
age ? " older than " : " " , age , age ? " minutes " : " " ,
2009-09-11 19:53:57 +04:00
DM_COOKIE_MAGIC , DM_COOKIE_MAGIC ) ;
2009-08-06 19:04:30 +04:00
2009-09-11 19:53:57 +04:00
if ( _yes_no_prompt ( " Do you really want to continue? [y/n]: " ) = = ' n ' ) {
log_print ( " Semaphores with keys prefixed by % " PRIu16
" (0x% " PRIx16 " ) NOT destroyed. " ,
DM_COOKIE_MAGIC , DM_COOKIE_MAGIC ) ;
return 1 ;
}
2009-08-06 19:04:30 +04:00
}
if ( ( max_id = semctl ( 0 , 0 , SEM_INFO , & sinfo ) ) < 0 ) {
log_sys_error ( " semctl " , " SEM_INFO " ) ;
return 0 ;
}
for ( id = 0 ; id < = max_id ; id + + ) {
if ( ( sid = semctl ( id , 0 , SEM_STAT , & sdata ) ) < 0 )
continue ;
if ( sdata . sem_perm . __key > > 16 = = DM_COOKIE_MAGIC ) {
2011-06-30 01:56:46 +04:00
t = time ( NULL ) ;
if ( sdata . sem_ctime + age * 60 > t | |
sdata . sem_otime + age * 60 > t ) {
skipped + + ;
continue ;
}
2009-08-06 19:04:30 +04:00
if ( semctl ( sid , 0 , IPC_RMID , 0 ) < 0 ) {
log_error ( " Could not cleanup notification semaphore "
" with semid %d and cookie value "
2015-07-06 17:09:17 +03:00
FMTu32 " (0x " FMTx32 " ) " , sid ,
2009-08-06 19:04:30 +04:00
sdata . sem_perm . __key , sdata . sem_perm . __key ) ;
continue ;
}
counter + + ;
}
}
log_print ( " %d semaphores with keys prefixed by "
2015-07-06 17:09:17 +03:00
FMTu16 " (0x " FMTx16 " ) destroyed. %d skipped. " ,
2011-06-30 01:56:46 +04:00
counter , DM_COOKIE_MAGIC , DM_COOKIE_MAGIC , skipped ) ;
2009-08-06 19:04:30 +04:00
return 1 ;
}
2011-03-02 05:44:56 +03:00
static int _udevcookies ( CMD_ARGS )
2009-08-06 19:05:10 +04:00
{
int max_id , id , sid ;
struct seminfo sinfo ;
struct semid_ds sdata ;
int val ;
2011-06-30 01:56:46 +04:00
char otime_str [ 26 ] , ctime_str [ 26 ] ;
char * otimes , * ctimes ;
2009-08-06 19:05:10 +04:00
if ( ( max_id = semctl ( 0 , 0 , SEM_INFO , & sinfo ) ) < 0 ) {
log_sys_error ( " sem_ctl " , " SEM_INFO " ) ;
return 0 ;
}
2011-06-30 01:56:46 +04:00
printf ( " Cookie Semid Value Last semop time Last change time \n " ) ;
2009-08-06 19:05:10 +04:00
for ( id = 0 ; id < = max_id ; id + + ) {
if ( ( sid = semctl ( id , 0 , SEM_STAT , & sdata ) ) < 0 )
continue ;
if ( sdata . sem_perm . __key > > 16 = = DM_COOKIE_MAGIC ) {
if ( ( val = semctl ( sid , 0 , GETVAL ) ) < 0 ) {
log_error ( " semid %d: sem_ctl failed for "
" cookie 0x% " PRIx32 " : %s " ,
sid , sdata . sem_perm . __key ,
strerror ( errno ) ) ;
continue ;
}
2011-06-30 01:56:46 +04:00
if ( ( otimes = ctime_r ( ( const time_t * ) & sdata . sem_otime , ( char * ) & otime_str ) ) )
otime_str [ strlen ( otimes ) - 1 ] = ' \0 ' ;
if ( ( ctimes = ctime_r ( ( const time_t * ) & sdata . sem_ctime , ( char * ) & ctime_str ) ) )
ctime_str [ strlen ( ctimes ) - 1 ] = ' \0 ' ;
2009-08-06 19:05:10 +04:00
2011-06-30 01:56:46 +04:00
printf ( " 0x%-10x %-10d %-10d %s %s \n " , sdata . sem_perm . __key ,
sid , val , otimes ? : " unknown " ,
ctimes ? : " unknown " ) ;
2009-08-06 19:05:10 +04:00
}
}
return 1 ;
}
2009-09-11 19:53:57 +04:00
# endif /* UDEV_SYNC_SUPPORT */
2009-08-06 19:05:10 +04:00
2011-03-02 05:44:56 +03:00
static int _version ( CMD_ARGS )
2002-01-15 18:21:57 +03:00
{
2002-01-17 16:19:55 +03:00
char version [ 80 ] ;
2002-01-15 18:21:57 +03:00
2002-01-17 17:13:25 +03:00
if ( dm_get_library_version ( version , sizeof ( version ) ) )
printf ( " Library version: %s \n " , version ) ;
2006-01-03 23:53:57 +03:00
if ( ! dm_driver_version ( version , sizeof ( version ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2002-01-15 18:21:57 +03:00
printf ( " Driver version: %s \n " , version ) ;
2015-08-05 12:40:00 +03:00
/* don't output column headings for 'dmstats version'. */
if ( _report ) {
dm_report_free ( _report ) ;
_report = NULL ;
}
2005-10-17 22:05:39 +04:00
return 1 ;
2002-01-15 18:21:57 +03:00
}
2004-01-23 17:09:33 +03:00
static int _simple ( int task , const char * name , uint32_t event_nr , int display )
2001-11-21 15:47:42 +03:00
{
2009-07-31 21:51:45 +04:00
uint32_t cookie = 0 ;
2010-01-07 22:45:12 +03:00
uint16_t udev_flags = 0 ;
2009-07-31 21:51:45 +04:00
int udev_wait_flag = task = = DM_DEVICE_RESUME | |
task = = DM_DEVICE_REMOVE ;
2001-11-21 15:47:42 +03:00
int r = 0 ;
struct dm_task * dmt ;
if ( ! ( dmt = dm_task_create ( task ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2001-11-21 15:47:42 +03:00
2004-10-01 23:11:37 +04:00
if ( ! _set_task_device ( dmt , name , 0 ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2001-11-21 15:47:42 +03:00
2004-01-23 17:09:33 +03:00
if ( event_nr & & ! dm_task_set_event_nr ( dmt , event_nr ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2004-01-23 17:09:33 +03:00
2006-10-12 19:42:25 +04:00
if ( _switches [ NOFLUSH_ARG ] & & ! dm_task_no_flush ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2006-10-12 19:42:25 +04:00
2005-01-13 01:10:14 +03:00
if ( _switches [ NOOPENCOUNT_ARG ] & & ! dm_task_no_open_count ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2005-01-13 01:10:14 +03:00
2009-11-06 03:43:08 +03:00
if ( _switches [ INACTIVE_ARG ] & & ! dm_task_query_inactive_table ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2009-11-06 03:43:08 +03:00
2005-10-05 00:12:32 +04:00
if ( _switches [ NOLOCKFS_ARG ] & & ! dm_task_skip_lockfs ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2005-10-05 00:12:32 +04:00
2011-07-01 18:09:19 +04:00
if ( _switches [ CHECKS_ARG ] & & ! dm_task_enable_checks ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2011-07-01 18:09:19 +04:00
2011-02-05 01:17:54 +03:00
/* FIXME: needs to coperate with udev */
if ( ! _set_task_add_node ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2011-02-05 01:17:54 +03:00
2007-11-27 23:57:05 +03:00
if ( _switches [ READAHEAD_ARG ] & &
2007-11-29 17:44:28 +03:00
! dm_task_set_read_ahead ( dmt , _int_args [ READAHEAD_ARG ] ,
_read_ahead_flags ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2007-11-27 23:57:05 +03:00
2010-01-07 22:45:12 +03:00
if ( _switches [ NOUDEVRULES_ARG ] )
udev_flags | = DM_UDEV_DISABLE_DM_RULES_FLAG |
DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG ;
2011-06-17 18:55:51 +04:00
if ( _udev_cookie )
2010-02-15 19:21:33 +03:00
cookie = _udev_cookie ;
2011-06-17 18:55:51 +04:00
if ( _udev_only )
udev_flags | = DM_UDEV_DISABLE_LIBRARY_FALLBACK ;
2010-02-15 19:21:33 +03:00
2010-01-07 22:45:12 +03:00
if ( udev_wait_flag & & ! dm_task_set_cookie ( dmt , & cookie , udev_flags ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2009-07-31 21:51:45 +04:00
2011-09-22 21:12:28 +04:00
if ( _switches [ RETRY_ARG ] & & task = = DM_DEVICE_REMOVE )
dm_task_retry_remove ( dmt ) ;
2014-08-16 03:34:48 +04:00
if ( _switches [ DEFERRED_ARG ] & & ( task = = DM_DEVICE_REMOVE | | task = = DM_DEVICE_REMOVE_ALL ) )
dm_task_deferred_remove ( dmt ) ;
2015-08-05 10:28:35 +03:00
r = _task_run ( dmt ) ;
2001-11-21 15:47:42 +03:00
2015-09-06 01:56:30 +03:00
out :
2010-02-15 19:21:33 +03:00
if ( ! _udev_cookie & & udev_wait_flag )
2009-08-03 22:01:45 +04:00
( void ) dm_udev_wait ( cookie ) ;
2011-03-02 03:29:57 +03:00
if ( r & & display & & _switches [ VERBOSE_ARG ] )
r = _display_info ( dmt ) ;
2001-11-21 15:47:42 +03:00
dm_task_destroy ( dmt ) ;
2011-03-02 03:29:57 +03:00
2001-11-21 15:47:42 +03:00
return r ;
}
2011-03-02 05:44:56 +03:00
static int _suspend ( CMD_ARGS )
2001-11-21 15:47:42 +03:00
{
2015-08-14 00:30:39 +03:00
return _simple ( DM_DEVICE_SUSPEND , argc ? argv [ 0 ] : NULL , 0 , 1 ) ;
2001-11-21 15:47:42 +03:00
}
2011-03-02 05:44:56 +03:00
static int _resume ( CMD_ARGS )
2001-11-21 15:47:42 +03:00
{
2015-08-14 00:30:39 +03:00
return _simple ( DM_DEVICE_RESUME , argc ? argv [ 0 ] : NULL , 0 , 1 ) ;
2003-07-02 01:20:58 +04:00
}
2011-03-02 05:44:56 +03:00
static int _clear ( CMD_ARGS )
2003-07-02 01:20:58 +04:00
{
2015-08-14 00:30:39 +03:00
return _simple ( DM_DEVICE_CLEAR , argc ? argv [ 0 ] : NULL , 0 , 1 ) ;
2001-11-21 15:47:42 +03:00
}
2011-03-02 05:44:56 +03:00
static int _wait ( CMD_ARGS )
2002-05-03 15:55:58 +04:00
{
2004-10-01 23:11:37 +04:00
const char * name = NULL ;
if ( ! _switches [ UUID_ARG ] & & ! _switches [ MAJOR_ARG ] ) {
2015-08-14 00:30:39 +03:00
if ( ! argc ) {
2004-10-01 23:11:37 +04:00
err ( " No device specified. " ) ;
return 0 ;
}
2015-08-14 00:30:39 +03:00
name = argv [ 0 ] ;
2004-10-01 23:11:37 +04:00
argc - - , argv + + ;
}
return _simple ( DM_DEVICE_WAITEVENT , name ,
2015-08-14 00:30:39 +03:00
( argc ) ? ( uint32_t ) atoi ( argv [ argc - 1 ] ) : 0 , 1 ) ;
2002-05-03 15:55:58 +04:00
}
2015-07-31 19:47:03 +03:00
static int _process_all ( const struct command * cmd , const char * subcommand , int argc , char * * argv , int silent ,
2011-03-02 05:44:56 +03:00
int ( * fn ) ( CMD_ARGS ) )
2003-09-16 18:13:51 +04:00
{
2003-11-13 16:14:28 +03:00
int r = 1 ;
2003-09-16 18:13:51 +04:00
struct dm_names * names ;
unsigned next = 0 ;
struct dm_task * dmt ;
if ( ! ( dmt = dm_task_create ( DM_DEVICE_LIST ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2003-09-16 18:13:51 +04:00
2011-07-01 18:09:19 +04:00
if ( _switches [ CHECKS_ARG ] & & ! dm_task_enable_checks ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2011-07-01 18:09:19 +04:00
2015-08-05 10:28:35 +03:00
if ( ! _task_run ( dmt ) ) {
2003-11-13 16:14:28 +03:00
r = 0 ;
2015-09-06 01:56:30 +03:00
goto_out ;
2003-11-13 16:14:28 +03:00
}
2003-09-16 18:13:51 +04:00
2003-11-13 16:14:28 +03:00
if ( ! ( names = dm_task_get_names ( dmt ) ) ) {
r = 0 ;
2015-09-06 01:56:30 +03:00
goto_out ;
2003-11-13 16:14:28 +03:00
}
2003-09-16 18:13:51 +04:00
if ( ! names - > dev ) {
2006-06-18 15:51:46 +04:00
if ( ! silent )
printf ( " No devices found \n " ) ;
2003-09-16 18:13:51 +04:00
goto out ;
}
do {
2010-12-20 16:37:26 +03:00
names = ( struct dm_names * ) ( ( char * ) names + next ) ;
2015-07-31 19:47:03 +03:00
if ( ! fn ( cmd , subcommand , argc , argv , names , 1 ) )
2003-09-16 18:13:51 +04:00
r = 0 ;
next = names - > next ;
} while ( next ) ;
2015-09-06 01:56:30 +03:00
out :
2003-09-16 18:13:51 +04:00
dm_task_destroy ( dmt ) ;
return r ;
}
2006-06-18 15:35:04 +04:00
static uint64_t _get_device_size ( const char * name )
{
uint64_t start , length , size = UINT64_C ( 0 ) ;
struct dm_info info ;
char * target_type , * params ;
struct dm_task * dmt ;
2006-06-18 15:51:46 +04:00
void * next = NULL ;
2006-06-18 15:35:04 +04:00
if ( ! ( dmt = dm_task_create ( DM_DEVICE_TABLE ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2006-06-18 15:35:04 +04:00
2006-06-18 15:51:46 +04:00
if ( ! _set_task_device ( dmt , name , 0 ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2006-06-18 15:51:46 +04:00
2006-06-18 15:35:04 +04:00
if ( _switches [ NOOPENCOUNT_ARG ] & & ! dm_task_no_open_count ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2006-06-18 15:35:04 +04:00
2009-11-06 03:43:08 +03:00
if ( _switches [ INACTIVE_ARG ] & & ! dm_task_query_inactive_table ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2009-11-06 03:43:08 +03:00
2011-07-01 18:09:19 +04:00
if ( _switches [ CHECKS_ARG ] & & ! dm_task_enable_checks ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2011-07-01 18:09:19 +04:00
2015-08-05 10:28:35 +03:00
if ( ! _task_run ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2006-06-18 15:35:04 +04:00
if ( ! dm_task_get_info ( dmt , & info ) | | ! info . exists )
2015-09-06 01:56:30 +03:00
goto_out ;
2006-06-18 15:35:04 +04:00
do {
next = dm_get_next_target ( dmt , next , & start , & length ,
& target_type , & params ) ;
size + = length ;
} while ( next ) ;
2015-09-06 01:56:30 +03:00
out :
2006-06-18 15:35:04 +04:00
dm_task_destroy ( dmt ) ;
return size ;
}
2011-03-02 05:44:56 +03:00
static int _error_device ( CMD_ARGS )
2006-06-18 15:35:04 +04:00
{
struct dm_task * dmt ;
const char * name ;
uint64_t size ;
2006-06-18 15:51:46 +04:00
int r = 0 ;
2006-06-18 15:35:04 +04:00
2015-08-14 00:30:39 +03:00
name = names ? names - > name : argv [ 0 ] ;
2006-06-18 15:35:04 +04:00
size = _get_device_size ( name ) ;
2006-08-10 18:11:03 +04:00
if ( ! ( dmt = dm_task_create ( DM_DEVICE_RELOAD ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2006-06-18 15:35:04 +04:00
2006-06-18 15:51:46 +04:00
if ( ! _set_task_device ( dmt , name , 0 ) )
2015-09-06 01:56:30 +03:00
goto_bad ;
2006-06-18 15:51:46 +04:00
2007-04-27 18:52:41 +04:00
if ( ! dm_task_add_target ( dmt , UINT64_C ( 0 ) , size , " error " , " " ) )
2015-09-06 01:56:30 +03:00
goto_bad ;
2006-06-18 15:35:04 +04:00
2006-08-10 18:11:03 +04:00
if ( _switches [ READ_ONLY ] & & ! dm_task_set_ro ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_bad ;
2006-06-18 15:35:04 +04:00
2006-08-10 18:11:03 +04:00
if ( _switches [ NOOPENCOUNT_ARG ] & & ! dm_task_no_open_count ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_bad ;
2006-06-18 15:35:04 +04:00
2009-11-06 03:43:08 +03:00
if ( _switches [ INACTIVE_ARG ] & & ! dm_task_query_inactive_table ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_bad ;
2009-11-06 03:43:08 +03:00
2011-07-01 18:09:19 +04:00
if ( _switches [ CHECKS_ARG ] & & ! dm_task_enable_checks ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_bad ;
2011-07-01 18:09:19 +04:00
2015-08-05 10:28:35 +03:00
if ( ! _task_run ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_bad ;
2006-06-18 15:35:04 +04:00
2015-09-18 15:35:52 +03:00
if ( _switches [ FORCE_ARG ] )
/* Avoid hang on flushing with --force */
_switches [ NOLOCKFS_ARG ] = _switches [ NOFLUSH_ARG ] = 1 ;
2006-06-18 15:51:46 +04:00
if ( ! _simple ( DM_DEVICE_RESUME , name , 0 , 0 ) ) {
_simple ( DM_DEVICE_CLEAR , name , 0 , 0 ) ;
2015-09-06 01:56:30 +03:00
goto_bad ;
2006-06-18 15:51:46 +04:00
}
2006-06-18 15:35:04 +04:00
2006-06-18 15:51:46 +04:00
r = 1 ;
2006-06-18 15:35:04 +04:00
2015-09-06 01:56:30 +03:00
bad :
2006-06-18 15:35:04 +04:00
dm_task_destroy ( dmt ) ;
2006-06-18 15:51:46 +04:00
return r ;
2006-06-18 15:35:04 +04:00
}
2011-03-02 05:44:56 +03:00
static int _remove ( CMD_ARGS )
2006-06-18 15:35:04 +04:00
{
2015-08-14 00:30:39 +03:00
if ( _switches [ FORCE_ARG ] & & argc ) {
2014-05-27 00:51:04 +04:00
/*
* ' remove - - force ' option is doing 2 operations on the same device
* this is not compatible with the use of - - udevcookie / DM_UDEV_COOKIE .
* Udevd collision could be partially avoided with - - retry .
*/
if ( _udev_cookie )
log_warn ( " WARNING: Use of cookie and --force is not compatible. " ) ;
2015-07-31 19:47:03 +03:00
( void ) _error_device ( cmd , NULL , argc , argv , NULL , 0 ) ;
2014-05-27 00:51:04 +04:00
}
2006-06-18 15:35:04 +04:00
2015-08-14 00:30:39 +03:00
return _simple ( DM_DEVICE_REMOVE , argc ? argv [ 0 ] : NULL , 0 , 0 ) ;
2006-06-18 15:35:04 +04:00
}
2011-03-02 05:44:56 +03:00
static int _count_devices ( CMD_ARGS )
2006-06-18 15:35:04 +04:00
{
_num_devices + + ;
return 1 ;
}
2011-03-02 05:44:56 +03:00
static int _remove_all ( CMD_ARGS )
2006-06-18 15:35:04 +04:00
{
int r ;
/* Remove all closed devices */
r = _simple ( DM_DEVICE_REMOVE_ALL , " " , 0 , 0 ) | dm_mknodes ( NULL ) ;
if ( ! _switches [ FORCE_ARG ] )
return r ;
_num_devices = 0 ;
2015-07-31 19:47:03 +03:00
r | = _process_all ( cmd , NULL , argc , argv , 1 , _count_devices ) ;
2006-06-18 15:35:04 +04:00
/* No devices left? */
if ( ! _num_devices )
return r ;
2015-07-31 19:47:03 +03:00
r | = _process_all ( cmd , NULL , argc , argv , 1 , _error_device ) ;
2006-06-18 15:35:04 +04:00
r | = _simple ( DM_DEVICE_REMOVE_ALL , " " , 0 , 0 ) | dm_mknodes ( NULL ) ;
_num_devices = 0 ;
2015-07-31 19:47:03 +03:00
r | = _process_all ( cmd , NULL , argc , argv , 1 , _count_devices ) ;
2006-06-18 15:35:04 +04:00
if ( ! _num_devices )
return r ;
2006-06-18 15:51:46 +04:00
fprintf ( stderr , " Unable to remove %d device(s). \n " , _num_devices ) ;
2006-06-18 15:35:04 +04:00
return r ;
}
2006-01-31 17:50:38 +03:00
static void _display_dev ( struct dm_task * dmt , const char * name )
2005-05-16 20:04:34 +04:00
{
struct dm_info info ;
if ( dm_task_get_info ( dmt , & info ) )
printf ( " %s \t (%u, %u) \n " , name , info . major , info . minor ) ;
}
2011-03-02 05:44:56 +03:00
static int _mknodes ( CMD_ARGS )
2005-05-17 00:46:46 +04:00
{
2015-08-14 00:30:39 +03:00
return dm_mknodes ( argc ? argv [ 0 ] : NULL ) ;
2005-05-17 00:46:46 +04:00
}
2006-01-31 17:50:38 +03:00
static int _exec_command ( const char * name )
2005-05-17 00:46:46 +04:00
{
int n ;
static char path [ PATH_MAX ] ;
static char * args [ ARGS_MAX + 1 ] ;
static int argc = 0 ;
char * c ;
pid_t pid ;
if ( argc < 0 )
2015-09-06 01:56:30 +03:00
return_0 ;
2005-05-17 00:46:46 +04:00
2005-10-17 02:57:20 +04:00
if ( ! dm_mknodes ( name ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2005-05-17 00:46:46 +04:00
n = snprintf ( path , sizeof ( path ) , " %s/%s " , dm_dir ( ) , name ) ;
2006-01-31 17:50:38 +03:00
if ( n < 0 | | n > ( int ) sizeof ( path ) - 1 )
2015-09-06 01:56:30 +03:00
return_0 ;
2005-05-17 00:46:46 +04:00
if ( ! argc ) {
2015-08-14 00:30:39 +03:00
c = _command_to_exec ;
2005-05-17 00:46:46 +04:00
while ( argc < ARGS_MAX ) {
while ( * c & & isspace ( * c ) )
c + + ;
if ( ! * c )
break ;
args [ argc + + ] = c ;
while ( * c & & ! isspace ( * c ) )
c + + ;
if ( * c )
* c + + = ' \0 ' ;
}
if ( ! argc ) {
argc = - 1 ;
2015-09-06 01:56:30 +03:00
return_0 ;
2005-05-17 00:46:46 +04:00
}
if ( argc = = ARGS_MAX ) {
err ( " Too many args to --exec \n " ) ;
argc = - 1 ;
return 0 ;
}
args [ argc + + ] = path ;
args [ argc ] = NULL ;
}
if ( ! ( pid = fork ( ) ) ) {
execvp ( args [ 0 ] , args ) ;
2009-07-14 01:26:41 +04:00
_exit ( 127 ) ;
2005-05-17 00:46:46 +04:00
} else if ( pid < ( pid_t ) 0 )
return 0 ;
TEMP_FAILURE_RETRY ( waitpid ( pid , NULL , 0 ) ) ;
return 1 ;
}
2011-03-02 05:44:56 +03:00
static int _status ( CMD_ARGS )
2002-05-03 15:55:58 +04:00
{
int r = 0 ;
struct dm_task * dmt ;
void * next = NULL ;
2002-05-10 19:25:38 +04:00
uint64_t start , length ;
2002-05-03 15:55:58 +04:00
char * target_type = NULL ;
2006-10-19 19:34:50 +04:00
char * params , * c ;
2011-03-02 05:44:56 +03:00
int cmdno ;
2006-01-31 17:50:38 +03:00
const char * name = NULL ;
2005-05-16 18:53:23 +04:00
int matched = 0 ;
2005-05-16 20:04:34 +04:00
int ls_only = 0 ;
2005-10-26 21:50:15 +04:00
struct dm_info info ;
2003-09-16 18:13:51 +04:00
2011-03-02 05:44:56 +03:00
if ( names )
2003-09-16 18:13:51 +04:00
name = names - > name ;
2004-10-01 23:11:37 +04:00
else {
2015-08-14 00:30:39 +03:00
if ( ! argc & & ! _switches [ UUID_ARG ] & & ! _switches [ MAJOR_ARG ] )
2015-07-31 19:47:03 +03:00
return _process_all ( cmd , NULL , argc , argv , 0 , _status ) ;
2015-08-14 00:30:39 +03:00
name = argv [ 0 ] ;
2004-10-01 23:11:37 +04:00
}
2002-05-03 15:55:58 +04:00
2011-03-02 05:44:56 +03:00
if ( ! strcmp ( cmd - > name , " table " ) )
cmdno = DM_DEVICE_TABLE ;
2003-11-13 16:14:28 +03:00
else
2011-03-02 05:44:56 +03:00
cmdno = DM_DEVICE_STATUS ;
2002-05-03 15:55:58 +04:00
2011-03-02 05:44:56 +03:00
if ( ! strcmp ( cmd - > name , " ls " ) )
2005-05-16 20:04:34 +04:00
ls_only = 1 ;
2011-03-02 05:44:56 +03:00
if ( ! ( dmt = dm_task_create ( cmdno ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2002-05-03 15:55:58 +04:00
2004-10-01 23:11:37 +04:00
if ( ! _set_task_device ( dmt , name , 0 ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2002-05-03 15:55:58 +04:00
2005-01-13 01:10:14 +03:00
if ( _switches [ NOOPENCOUNT_ARG ] & & ! dm_task_no_open_count ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2005-01-13 01:10:14 +03:00
2009-11-06 03:43:08 +03:00
if ( _switches [ INACTIVE_ARG ] & & ! dm_task_query_inactive_table ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2009-11-06 03:43:08 +03:00
2011-07-01 18:09:19 +04:00
if ( _switches [ CHECKS_ARG ] & & ! dm_task_enable_checks ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2011-07-01 18:09:19 +04:00
2012-07-27 23:03:07 +04:00
if ( _switches [ NOFLUSH_ARG ] & & ! dm_task_no_flush ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2012-07-27 23:03:07 +04:00
2015-08-05 10:28:35 +03:00
if ( ! _task_run ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2002-05-03 15:55:58 +04:00
2005-10-26 21:50:15 +04:00
if ( ! dm_task_get_info ( dmt , & info ) | | ! info . exists )
2015-09-06 01:56:30 +03:00
goto_out ;
2005-10-26 21:50:15 +04:00
2005-07-29 20:11:23 +04:00
if ( ! name )
2006-01-31 17:50:38 +03:00
name = dm_task_get_name ( dmt ) ;
2005-07-29 20:11:23 +04:00
2002-05-03 15:55:58 +04:00
/* Fetch targets and print 'em */
do {
2002-05-10 19:25:38 +04:00
next = dm_get_next_target ( dmt , next , & start , & length ,
& target_type , & params ) ;
2005-05-16 18:53:23 +04:00
/* Skip if target type doesn't match */
2005-07-29 20:11:23 +04:00
if ( _switches [ TARGET_ARG ] & &
( ! target_type | | strcmp ( target_type , _target ) ) )
2005-05-16 18:53:23 +04:00
continue ;
2005-05-16 20:04:34 +04:00
if ( ls_only ) {
2015-08-14 00:30:39 +03:00
if ( ! _switches [ EXEC_ARG ] | | ! _command_to_exec | |
2005-05-17 00:46:46 +04:00
_switches [ VERBOSE_ARG ] )
_display_dev ( dmt , name ) ;
2005-05-16 20:04:34 +04:00
next = NULL ;
2015-08-14 00:30:39 +03:00
} else if ( ! _switches [ EXEC_ARG ] | | ! _command_to_exec | |
2005-05-17 00:46:46 +04:00
_switches [ VERBOSE_ARG ] ) {
2005-05-16 20:04:34 +04:00
if ( ! matched & & _switches [ VERBOSE_ARG ] )
_display_info ( dmt ) ;
2011-03-02 05:44:56 +03:00
if ( multiple_devices & & ! _switches [ VERBOSE_ARG ] )
2005-05-16 20:04:34 +04:00
printf ( " %s: " , name ) ;
if ( target_type ) {
2007-04-27 19:12:26 +04:00
/* Suppress encryption key */
if ( ! _switches [ SHOWKEYS_ARG ] & &
2011-03-02 05:44:56 +03:00
cmdno = = DM_DEVICE_TABLE & &
2007-04-27 19:12:26 +04:00
! strcmp ( target_type , " crypt " ) ) {
c = params ;
while ( * c & & * c ! = ' ' )
c + + ;
if ( * c )
c + + ;
while ( * c & & * c ! = ' ' )
* c + + = ' 0 ' ;
}
2015-07-06 17:09:17 +03:00
printf ( FMTu64 " " FMTu64 " %s %s " ,
2005-05-16 20:04:34 +04:00
start , length , target_type , params ) ;
}
printf ( " \n " ) ;
2002-05-10 19:25:38 +04:00
}
2005-05-16 18:53:23 +04:00
matched = 1 ;
2002-05-03 15:55:58 +04:00
} while ( next ) ;
2011-03-02 05:44:56 +03:00
if ( multiple_devices & & _switches [ VERBOSE_ARG ] & & matched & & ! ls_only )
2003-09-16 18:13:51 +04:00
printf ( " \n " ) ;
2015-08-14 00:30:39 +03:00
if ( matched & & _switches [ EXEC_ARG ] & & _command_to_exec & & ! _exec_command ( name ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2005-05-17 00:46:46 +04:00
2002-05-03 15:55:58 +04:00
r = 1 ;
2015-09-06 01:56:30 +03:00
out :
2002-05-03 15:55:58 +04:00
dm_task_destroy ( dmt ) ;
return r ;
}
2004-01-23 17:37:47 +03:00
/* Show target names and their version numbers */
2011-03-02 05:44:56 +03:00
static int _targets ( CMD_ARGS )
2004-01-23 17:37:47 +03:00
{
int r = 0 ;
struct dm_task * dmt ;
struct dm_versions * target ;
struct dm_versions * last_target ;
if ( ! ( dmt = dm_task_create ( DM_DEVICE_LIST_VERSIONS ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2004-01-23 17:37:47 +03:00
2011-07-01 18:09:19 +04:00
if ( _switches [ CHECKS_ARG ] & & ! dm_task_enable_checks ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2011-07-01 18:09:19 +04:00
2015-08-05 10:28:35 +03:00
if ( ! _task_run ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2004-01-23 17:37:47 +03:00
target = dm_task_get_versions ( dmt ) ;
/* Fetch targets and print 'em */
do {
last_target = target ;
printf ( " %-16s v%d.%d.%d \n " , target - > name , target - > version [ 0 ] ,
target - > version [ 1 ] , target - > version [ 2 ] ) ;
2010-12-20 16:37:26 +03:00
target = ( struct dm_versions * ) ( ( char * ) target + target - > next ) ;
2004-01-23 17:37:47 +03:00
} while ( last_target ! = target ) ;
r = 1 ;
2015-09-06 01:56:30 +03:00
out :
2004-01-23 17:37:47 +03:00
dm_task_destroy ( dmt ) ;
return r ;
}
2011-03-02 05:44:56 +03:00
static int _info ( CMD_ARGS )
2001-11-21 15:47:42 +03:00
{
int r = 0 ;
struct dm_task * dmt ;
2004-03-30 18:31:58 +04:00
char * name = NULL ;
2003-09-16 18:13:51 +04:00
2011-03-02 05:44:56 +03:00
if ( names )
2003-09-16 18:13:51 +04:00
name = names - > name ;
2004-10-01 23:11:37 +04:00
else {
2015-08-14 00:30:39 +03:00
if ( ! argc & & ! _switches [ UUID_ARG ] & & ! _switches [ MAJOR_ARG ] )
2015-07-31 19:47:03 +03:00
return _process_all ( cmd , NULL , argc , argv , 0 , _info ) ;
2015-08-14 00:30:39 +03:00
name = argv [ 0 ] ;
2004-10-01 23:11:37 +04:00
}
2001-11-21 15:47:42 +03:00
2004-03-30 18:31:58 +04:00
if ( ! ( dmt = dm_task_create ( DM_DEVICE_INFO ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2001-11-21 15:47:42 +03:00
2004-10-01 23:11:37 +04:00
if ( ! _set_task_device ( dmt , name , 0 ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2001-11-21 15:47:42 +03:00
2005-01-13 01:10:14 +03:00
if ( _switches [ NOOPENCOUNT_ARG ] & & ! dm_task_no_open_count ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2005-01-13 01:10:14 +03:00
2009-11-06 03:43:08 +03:00
if ( _switches [ INACTIVE_ARG ] & & ! dm_task_query_inactive_table ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2009-11-06 03:43:08 +03:00
2011-07-01 18:09:19 +04:00
if ( _switches [ CHECKS_ARG ] & & ! dm_task_enable_checks ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2011-07-01 18:09:19 +04:00
2015-08-05 10:28:35 +03:00
if ( ! _task_run ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2001-11-21 15:47:42 +03:00
2005-03-27 15:37:46 +04:00
r = _display_info ( dmt ) ;
2001-11-21 15:47:42 +03:00
2015-09-06 01:56:30 +03:00
out :
2001-11-21 15:47:42 +03:00
dm_task_destroy ( dmt ) ;
return r ;
}
2011-03-02 05:44:56 +03:00
static int _deps ( CMD_ARGS )
2002-03-06 17:38:25 +03:00
{
2003-03-28 21:58:59 +03:00
int r = 0 ;
uint32_t i ;
2002-03-06 17:38:25 +03:00
struct dm_deps * deps ;
struct dm_task * dmt ;
struct dm_info info ;
2004-10-01 23:11:37 +04:00
char * name = NULL ;
2012-01-11 16:46:19 +04:00
char dev_name [ PATH_MAX ] ;
int major , minor ;
2003-09-16 18:13:51 +04:00
2011-03-02 05:44:56 +03:00
if ( names )
2003-09-16 18:13:51 +04:00
name = names - > name ;
2004-10-01 23:11:37 +04:00
else {
2015-08-14 00:30:39 +03:00
if ( ! argc & & ! _switches [ UUID_ARG ] & & ! _switches [ MAJOR_ARG ] )
2015-07-31 19:47:03 +03:00
return _process_all ( cmd , NULL , argc , argv , 0 , _deps ) ;
2015-08-14 00:30:39 +03:00
name = argv [ 0 ] ;
2004-10-01 23:11:37 +04:00
}
2002-03-06 17:38:25 +03:00
if ( ! ( dmt = dm_task_create ( DM_DEVICE_DEPS ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2002-03-06 17:38:25 +03:00
2004-10-01 23:11:37 +04:00
if ( ! _set_task_device ( dmt , name , 0 ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2002-03-06 17:38:25 +03:00
2005-01-13 01:10:14 +03:00
if ( _switches [ NOOPENCOUNT_ARG ] & & ! dm_task_no_open_count ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2005-01-13 01:10:14 +03:00
2009-11-06 03:43:08 +03:00
if ( _switches [ INACTIVE_ARG ] & & ! dm_task_query_inactive_table ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2009-11-06 03:43:08 +03:00
2011-07-01 18:09:19 +04:00
if ( _switches [ CHECKS_ARG ] & & ! dm_task_enable_checks ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2011-07-01 18:09:19 +04:00
2015-08-05 10:28:35 +03:00
if ( ! _task_run ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2002-03-06 17:38:25 +03:00
2002-03-06 22:42:23 +03:00
if ( ! dm_task_get_info ( dmt , & info ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2002-03-06 22:42:23 +03:00
2002-03-06 17:38:25 +03:00
if ( ! ( deps = dm_task_get_deps ( dmt ) ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2002-03-06 17:38:25 +03:00
if ( ! info . exists ) {
printf ( " Device does not exist. \n " ) ;
r = 1 ;
goto out ;
}
2003-07-04 23:38:49 +04:00
if ( _switches [ VERBOSE_ARG ] )
_display_info ( dmt ) ;
2003-07-02 01:20:58 +04:00
2011-03-02 05:44:56 +03:00
if ( multiple_devices & & ! _switches [ VERBOSE_ARG ] )
2003-09-16 18:13:51 +04:00
printf ( " %s: " , name ) ;
2002-03-06 17:38:25 +03:00
printf ( " %d dependencies \t : " , deps - > count ) ;
2012-01-11 16:46:19 +04:00
for ( i = 0 ; i < deps - > count ; i + + ) {
major = ( int ) MAJOR ( deps - > device [ i ] ) ;
minor = ( int ) MINOR ( deps - > device [ i ] ) ;
if ( ( _dev_name_type = = DN_BLK | | _dev_name_type = = DN_MAP ) & &
dm_device_get_name ( major , minor , _dev_name_type = = DN_BLK ,
dev_name , PATH_MAX ) )
printf ( " (%s) " , dev_name ) ;
else
printf ( " (%d, %d) " , major , minor ) ;
}
2002-03-06 17:38:25 +03:00
printf ( " \n " ) ;
2011-03-02 05:44:56 +03:00
if ( multiple_devices & & _switches [ VERBOSE_ARG ] )
2003-09-16 18:13:51 +04:00
printf ( " \n " ) ;
2002-03-06 17:38:25 +03:00
r = 1 ;
2015-09-06 01:56:30 +03:00
out :
2002-03-06 17:38:25 +03:00
dm_task_destroy ( dmt ) ;
return r ;
}
2011-03-02 05:44:56 +03:00
static int _display_name ( CMD_ARGS )
2003-07-02 01:20:58 +04:00
{
2012-01-11 16:46:19 +04:00
char dev_name [ PATH_MAX ] ;
2012-03-02 01:56:44 +04:00
if ( ! names )
return 1 ;
2012-01-11 16:46:19 +04:00
if ( ( _dev_name_type = = DN_BLK | | _dev_name_type = = DN_MAP ) & &
dm_device_get_name ( ( int ) MAJOR ( names - > dev ) , ( int ) MINOR ( names - > dev ) ,
_dev_name_type = = DN_BLK , dev_name , PATH_MAX ) )
printf ( " %s \t (%s) \n " , names - > name , dev_name ) ;
else
printf ( " %s \t (%d:%d) \n " , names - > name ,
( int ) MAJOR ( names - > dev ) ,
( int ) MINOR ( names - > dev ) ) ;
2003-07-02 01:20:58 +04:00
2003-09-16 18:13:51 +04:00
return 1 ;
}
2003-07-02 01:20:58 +04:00
2005-10-16 18:33:22 +04:00
/*
* Tree drawing code
*/
enum {
TR_DEVICE = 0 , /* display device major:minor number */
2012-01-11 16:46:19 +04:00
TR_BLKDEVNAME , /* display device kernel name */
2005-10-16 18:33:22 +04:00
TR_TABLE ,
TR_STATUS ,
TR_ACTIVE ,
TR_RW ,
TR_OPENCOUNT ,
TR_UUID ,
TR_COMPACT ,
TR_TRUNCATE ,
TR_BOTTOMUP ,
NUM_TREEMODE ,
} ;
static int _tree_switches [ NUM_TREEMODE ] ;
# define TR_PRINT_ATTRIBUTE ( _tree_switches[TR_ACTIVE] || \
_tree_switches [ TR_RW ] | | \
_tree_switches [ TR_OPENCOUNT ] | | \
_tree_switches [ TR_UUID ] )
# define TR_PRINT_TARGETS ( _tree_switches[TR_TABLE] || \
_tree_switches [ TR_STATUS ] )
/* Compact - fewer newlines */
# define TR_PRINT_COMPACT (_tree_switches[TR_COMPACT] && \
! TR_PRINT_ATTRIBUTE & & \
! TR_PRINT_TARGETS )
/* FIXME Get rid of this */
# define MAX_DEPTH 100
/* Drawing character definition from pstree */
/* [pstree comment] UTF-8 defines by Johan Myreen, updated by Ben Winslow */
# define UTF_V "\342\224\202" /* U+2502, Vertical line drawing char */
# define UTF_VR "\342\224\234" /* U+251C, Vertical and right */
# define UTF_H "\342\224\200" /* U+2500, Horizontal */
# define UTF_UR "\342\224\224" /* U+2514, Up and right */
# define UTF_HD "\342\224\254" /* U+252C, Horizontal and down */
# define VT_BEG "\033(0\017" /* use graphic chars */
# define VT_END "\033(B" /* back to normal char set */
# define VT_V "x" /* see UTF definitions above */
# define VT_VR "t"
# define VT_H "q"
# define VT_UR "m"
# define VT_HD "w"
static struct {
const char * empty_2 ; /* */
const char * branch_2 ; /* |- */
const char * vert_2 ; /* | */
const char * last_2 ; /* `- */
const char * single_3 ; /* --- */
const char * first_3 ; /* -+- */
}
_tsym_ascii = {
" " ,
" |- " ,
" | " ,
" `- " ,
" --- " ,
" -+- "
} ,
_tsym_utf = {
" " ,
UTF_VR UTF_H ,
UTF_V " " ,
UTF_UR UTF_H ,
UTF_H UTF_H UTF_H ,
UTF_H UTF_HD UTF_H
} ,
_tsym_vt100 = {
" " ,
VT_BEG VT_VR VT_H VT_END ,
VT_BEG VT_V VT_END " " ,
VT_BEG VT_UR VT_H VT_END ,
VT_BEG VT_H VT_H VT_H VT_END ,
VT_BEG VT_H VT_HD VT_H VT_END
} ,
* _tsym = & _tsym_ascii ;
/*
* Tree drawing functions .
*/
/* FIXME Get rid of these statics - use dynamic struct */
/* FIXME Explain what these vars are for */
static int _tree_width [ MAX_DEPTH ] , _tree_more [ MAX_DEPTH ] ;
static int _termwidth = 80 ; /* Maximum output width */
static int _cur_x = 1 ; /* Current horizontal output position */
static char _last_char = 0 ;
2006-05-16 20:20:29 +04:00
static void _out_char ( const unsigned c )
2005-10-16 18:33:22 +04:00
{
/* Only first UTF-8 char counts */
_cur_x + = ( ( c & 0xc0 ) ! = 0x80 ) ;
if ( ! _tree_switches [ TR_TRUNCATE ] ) {
2006-05-16 20:20:29 +04:00
putchar ( ( int ) c ) ;
2005-10-16 18:33:22 +04:00
return ;
}
/* Truncation? */
if ( _cur_x < = _termwidth )
2006-05-16 20:20:29 +04:00
putchar ( ( int ) c ) ;
2005-10-16 18:33:22 +04:00
if ( _cur_x = = _termwidth + 1 & & ( ( c & 0xc0 ) ! = 0x80 ) ) {
if ( _last_char | | ( c & 0x80 ) ) {
putchar ( ' . ' ) ;
putchar ( ' . ' ) ;
putchar ( ' . ' ) ;
} else {
_last_char = c ;
_cur_x - - ;
}
}
}
2007-04-27 18:52:41 +04:00
static void _out_string ( const char * str )
2005-10-16 18:33:22 +04:00
{
while ( * str )
2007-04-27 18:52:41 +04:00
_out_char ( ( unsigned char ) * str + + ) ;
2005-10-16 18:33:22 +04:00
}
/* non-negative integers only */
static unsigned _out_int ( unsigned num )
{
unsigned digits = 0 ;
unsigned divi ;
if ( ! num ) {
_out_char ( ' 0 ' ) ;
return 1 ;
}
/* non zero case */
for ( divi = 1 ; num / divi ; divi * = 10 )
digits + + ;
for ( divi / = 10 ; divi ; divi / = 10 )
_out_char ( ' 0 ' + ( num / divi ) % 10 ) ;
return digits ;
}
static void _out_newline ( void )
{
if ( _last_char & & _cur_x = = _termwidth )
putchar ( _last_char ) ;
_last_char = 0 ;
putchar ( ' \n ' ) ;
_cur_x = 1 ;
}
2006-05-16 20:20:29 +04:00
static void _out_prefix ( unsigned depth )
2005-10-16 18:33:22 +04:00
{
2006-05-16 20:20:29 +04:00
unsigned x , d ;
2005-10-16 18:33:22 +04:00
for ( d = 0 ; d < depth ; d + + ) {
for ( x = _tree_width [ d ] + 1 ; x > 0 ; x - - )
_out_char ( ' ' ) ;
_out_string ( d = = depth - 1 ?
! _tree_more [ depth ] ? _tsym - > last_2 : _tsym - > branch_2
: _tree_more [ d + 1 ] ?
_tsym - > vert_2 : _tsym - > empty_2 ) ;
}
}
/*
* Display tree
*/
2005-11-09 17:10:50 +03:00
static void _display_tree_attributes ( struct dm_tree_node * node )
2005-10-16 18:33:22 +04:00
{
int attr = 0 ;
const char * uuid ;
const struct dm_info * info ;
2005-11-09 17:10:50 +03:00
uuid = dm_tree_node_get_uuid ( node ) ;
info = dm_tree_node_get_info ( node ) ;
2005-10-16 18:33:22 +04:00
if ( ! info - > exists )
return ;
if ( _tree_switches [ TR_ACTIVE ] ) {
_out_string ( attr + + ? " , " : " [ " ) ;
_out_string ( info - > suspended ? " SUSPENDED " : " ACTIVE " ) ;
}
if ( _tree_switches [ TR_RW ] ) {
_out_string ( attr + + ? " , " : " [ " ) ;
_out_string ( info - > read_only ? " RO " : " RW " ) ;
}
if ( _tree_switches [ TR_OPENCOUNT ] ) {
_out_string ( attr + + ? " , " : " [ " ) ;
2006-05-16 20:20:29 +04:00
( void ) _out_int ( ( unsigned ) info - > open_count ) ;
2005-10-16 18:33:22 +04:00
}
if ( _tree_switches [ TR_UUID ] ) {
_out_string ( attr + + ? " , " : " [ " ) ;
_out_string ( uuid & & * uuid ? uuid : " " ) ;
}
if ( attr )
_out_char ( ' ] ' ) ;
}
2011-12-01 18:57:30 +04:00
/* FIXME Display table or status line. (Disallow both?) */
static void _display_tree_targets ( struct dm_tree_node * node , unsigned depth )
{
}
2005-11-09 17:10:50 +03:00
static void _display_tree_node ( struct dm_tree_node * node , unsigned depth ,
2010-07-09 19:34:40 +04:00
unsigned first_child __attribute__ ( ( unused ) ) ,
2006-05-16 20:20:29 +04:00
unsigned last_child , unsigned has_children )
2005-10-16 18:33:22 +04:00
{
int offset ;
const char * name ;
const struct dm_info * info ;
int first_on_line = 0 ;
2012-01-11 16:46:19 +04:00
char dev_name [ PATH_MAX ] ;
2005-10-16 18:33:22 +04:00
/* Sub-tree for targets has 2 more depth */
if ( depth + 2 > MAX_DEPTH )
return ;
2005-11-09 17:10:50 +03:00
name = dm_tree_node_get_name ( node ) ;
2005-10-16 18:33:22 +04:00
2012-01-11 16:46:19 +04:00
if ( ( ! name | | ! * name ) & &
( ! _tree_switches [ TR_DEVICE ] & & ! _tree_switches [ TR_BLKDEVNAME ] ) )
2005-10-16 18:33:22 +04:00
return ;
/* Indicate whether there are more nodes at this depth */
_tree_more [ depth ] = ! last_child ;
_tree_width [ depth ] = 0 ;
if ( _cur_x = = 1 )
first_on_line = 1 ;
if ( ! TR_PRINT_COMPACT | | first_on_line )
_out_prefix ( depth ) ;
/* Remember the starting point for compact */
offset = _cur_x ;
if ( TR_PRINT_COMPACT & & ! first_on_line )
_out_string ( _tree_more [ depth ] ? _tsym - > first_3 : _tsym - > single_3 ) ;
/* display node */
if ( name )
_out_string ( name ) ;
2005-11-09 17:10:50 +03:00
info = dm_tree_node_get_info ( node ) ;
2005-10-16 18:33:22 +04:00
2012-01-11 16:46:19 +04:00
if ( _tree_switches [ TR_BLKDEVNAME ] & &
dm_device_get_name ( info - > major , info - > minor , 1 , dev_name , PATH_MAX ) ) {
_out_string ( name ? " < " : " < " ) ;
_out_string ( dev_name ) ;
_out_char ( ' > ' ) ;
}
2005-10-16 18:33:22 +04:00
if ( _tree_switches [ TR_DEVICE ] ) {
_out_string ( name ? " ( " : " ( " ) ;
( void ) _out_int ( info - > major ) ;
_out_char ( ' : ' ) ;
( void ) _out_int ( info - > minor ) ;
_out_char ( ' ) ' ) ;
}
/* display additional info */
if ( TR_PRINT_ATTRIBUTE )
_display_tree_attributes ( node ) ;
if ( TR_PRINT_COMPACT )
_tree_width [ depth ] = _cur_x - offset ;
if ( ! TR_PRINT_COMPACT | | ! has_children )
_out_newline ( ) ;
if ( TR_PRINT_TARGETS ) {
_tree_more [ depth + 1 ] = has_children ;
2011-12-01 18:57:30 +04:00
_display_tree_targets ( node , depth + 2 ) ;
2005-10-16 18:33:22 +04:00
}
}
/*
* Walk the dependency tree
*/
2007-06-11 17:20:29 +04:00
static void _display_tree_walk_children ( struct dm_tree_node * node ,
unsigned depth )
2005-10-16 18:33:22 +04:00
{
2005-11-09 17:10:50 +03:00
struct dm_tree_node * child , * next_child ;
2005-10-16 18:33:22 +04:00
void * handle = NULL ;
uint32_t inverted = _tree_switches [ TR_BOTTOMUP ] ;
unsigned first_child = 1 ;
unsigned has_children ;
2005-11-09 17:10:50 +03:00
next_child = dm_tree_next_child ( & handle , node , inverted ) ;
2005-10-16 18:33:22 +04:00
while ( ( child = next_child ) ) {
2005-11-09 17:10:50 +03:00
next_child = dm_tree_next_child ( & handle , node , inverted ) ;
2005-10-16 18:33:22 +04:00
has_children =
2005-11-09 17:10:50 +03:00
dm_tree_node_num_children ( child , inverted ) ? 1 : 0 ;
2005-10-16 18:33:22 +04:00
_display_tree_node ( child , depth , first_child ,
2006-05-16 20:20:29 +04:00
next_child ? 0U : 1U , has_children ) ;
2005-10-16 18:33:22 +04:00
if ( has_children )
2007-06-11 17:20:29 +04:00
_display_tree_walk_children ( child , depth + 1 ) ;
2005-10-16 18:33:22 +04:00
first_child = 0 ;
}
}
2011-03-02 05:44:56 +03:00
static int _add_dep ( CMD_ARGS )
2005-10-16 18:33:22 +04:00
{
2012-03-02 01:56:44 +04:00
if ( names & &
! dm_tree_add_dev ( _dtree , ( unsigned ) MAJOR ( names - > dev ) , ( unsigned ) MINOR ( names - > dev ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2005-10-16 18:33:22 +04:00
return 1 ;
}
/*
* Create and walk dependency tree
*/
2011-03-02 05:44:56 +03:00
static int _build_whole_deptree ( const struct command * cmd )
2005-10-16 18:33:22 +04:00
{
2007-06-11 17:20:29 +04:00
if ( _dtree )
return 1 ;
2005-11-09 17:10:50 +03:00
if ( ! ( _dtree = dm_tree_create ( ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2005-10-16 18:33:22 +04:00
2015-07-31 19:47:03 +03:00
if ( ! _process_all ( cmd , NULL , 0 , NULL , 0 , _add_dep ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2005-10-16 18:33:22 +04:00
2007-06-11 17:20:29 +04:00
return 1 ;
}
2005-10-16 18:33:22 +04:00
2011-03-02 05:44:56 +03:00
static int _display_tree ( CMD_ARGS )
2007-06-11 17:20:29 +04:00
{
2011-03-02 05:44:56 +03:00
if ( ! _build_whole_deptree ( cmd ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2007-06-11 17:20:29 +04:00
_display_tree_walk_children ( dm_tree_find_node ( _dtree , 0 , 0 ) , 0 ) ;
2005-10-16 18:33:22 +04:00
return 1 ;
}
2007-01-24 21:09:07 +03:00
/*
* Report device information
*/
/* dm specific display functions */
static int _int32_disp ( struct dm_report * rh ,
2010-07-09 19:34:40 +04:00
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
2007-01-24 21:09:07 +03:00
struct dm_report_field * field , const void * data ,
2010-07-09 19:34:40 +04:00
void * private __attribute__ ( ( unused ) ) )
2007-01-24 21:09:07 +03:00
{
const int32_t value = * ( const int32_t * ) data ;
return dm_report_field_int32 ( rh , field , & value ) ;
}
static int _uint32_disp ( struct dm_report * rh ,
2010-07-09 19:34:40 +04:00
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
2007-06-11 17:20:29 +04:00
struct dm_report_field * field , const void * data ,
2010-07-09 19:34:40 +04:00
void * private __attribute__ ( ( unused ) ) )
2007-01-24 21:09:07 +03:00
{
const uint32_t value = * ( const int32_t * ) data ;
return dm_report_field_uint32 ( rh , field , & value ) ;
}
2015-08-05 12:40:00 +03:00
static int _show_units ( void )
{
/* --nosuffix overrides --units */
if ( _switches [ NOSUFFIX_ARG ] )
2015-09-06 01:56:30 +03:00
return_0 ;
2015-08-05 12:40:00 +03:00
return ( _int_args [ UNITS_ARG ] ) ? 1 : 0 ;
}
2007-01-24 21:09:07 +03:00
static int _dm_name_disp ( struct dm_report * rh ,
2010-07-09 19:34:40 +04:00
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
2007-01-24 21:09:07 +03:00
struct dm_report_field * field , const void * data ,
2010-07-09 19:34:40 +04:00
void * private __attribute__ ( ( unused ) ) )
2007-01-24 21:09:07 +03:00
{
2007-04-27 18:52:41 +04:00
const char * name = dm_task_get_name ( ( const struct dm_task * ) data ) ;
2007-01-24 21:09:07 +03:00
return dm_report_field_string ( rh , field , & name ) ;
}
2012-02-15 16:06:17 +04:00
static int _dm_mangled_name_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
char * name ;
int r = 0 ;
if ( ( name = dm_task_get_name_mangled ( ( const struct dm_task * ) data ) ) ) {
2012-08-17 14:15:36 +04:00
r = dm_report_field_string ( rh , field , ( const char * const * ) & name ) ;
2012-02-15 16:06:17 +04:00
dm_free ( name ) ;
}
return r ;
}
static int _dm_unmangled_name_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
char * name ;
int r = 0 ;
if ( ( name = dm_task_get_name_unmangled ( ( const struct dm_task * ) data ) ) ) {
2012-08-17 14:15:36 +04:00
r = dm_report_field_string ( rh , field , ( const char * const * ) & name ) ;
2012-02-15 16:06:17 +04:00
dm_free ( name ) ;
}
return r ;
}
2007-01-24 21:09:07 +03:00
static int _dm_uuid_disp ( struct dm_report * rh ,
2010-07-09 19:34:40 +04:00
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
2007-01-24 21:09:07 +03:00
struct dm_report_field * field ,
2010-07-09 19:34:40 +04:00
const void * data , void * private __attribute__ ( ( unused ) ) )
2007-01-24 21:09:07 +03:00
{
2007-04-27 18:52:41 +04:00
const char * uuid = dm_task_get_uuid ( ( const struct dm_task * ) data ) ;
2007-01-24 21:09:07 +03:00
if ( ! uuid | | ! * uuid )
uuid = " " ;
return dm_report_field_string ( rh , field , & uuid ) ;
}
2012-10-10 19:02:59 +04:00
static int _dm_mangled_uuid_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field ,
const void * data , void * private __attribute__ ( ( unused ) ) )
{
char * uuid ;
int r = 0 ;
if ( ( uuid = dm_task_get_uuid_mangled ( ( const struct dm_task * ) data ) ) ) {
r = dm_report_field_string ( rh , field , ( const char * const * ) & uuid ) ;
dm_free ( uuid ) ;
}
return r ;
}
static int _dm_unmangled_uuid_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field ,
const void * data , void * private __attribute__ ( ( unused ) ) )
{
char * uuid ;
int r = 0 ;
if ( ( uuid = dm_task_get_uuid_unmangled ( ( const struct dm_task * ) data ) ) ) {
r = dm_report_field_string ( rh , field , ( const char * const * ) & uuid ) ;
dm_free ( uuid ) ;
}
return r ;
}
2007-11-27 23:57:05 +03:00
static int _dm_read_ahead_disp ( struct dm_report * rh ,
2010-07-09 19:34:40 +04:00
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
2007-11-27 23:57:05 +03:00
struct dm_report_field * field , const void * data ,
2010-07-09 19:34:40 +04:00
void * private __attribute__ ( ( unused ) ) )
2007-11-27 23:57:05 +03:00
{
2007-11-30 17:59:57 +03:00
uint32_t value ;
2007-11-27 23:57:05 +03:00
2007-11-30 17:59:57 +03:00
if ( ! dm_task_get_read_ahead ( ( const struct dm_task * ) data , & value ) )
value = 0 ;
return dm_report_field_uint32 ( rh , field , & value ) ;
2007-11-27 23:57:05 +03:00
}
2012-01-11 16:46:19 +04:00
static int _dm_blk_name_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
char dev_name [ PATH_MAX ] ;
const char * s = dev_name ;
const struct dm_info * info = data ;
if ( ! dm_device_get_name ( info - > major , info - > minor , 1 , dev_name , PATH_MAX ) ) {
log_error ( " Could not resolve block device name for %d:%d. " ,
info - > major , info - > minor ) ;
return 0 ;
}
return dm_report_field_string ( rh , field , & s ) ;
}
2007-01-24 21:09:07 +03:00
static int _dm_info_status_disp ( struct dm_report * rh ,
2010-07-09 19:34:40 +04:00
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
2007-01-24 21:09:07 +03:00
struct dm_report_field * field , const void * data ,
2010-07-09 19:34:40 +04:00
void * private __attribute__ ( ( unused ) ) )
2007-01-24 21:09:07 +03:00
{
char buf [ 5 ] ;
const char * s = buf ;
2007-04-27 18:52:41 +04:00
const struct dm_info * info = data ;
2007-01-24 21:09:07 +03:00
buf [ 0 ] = info - > live_table ? ' L ' : ' - ' ;
buf [ 1 ] = info - > inactive_table ? ' I ' : ' - ' ;
buf [ 2 ] = info - > suspended ? ' s ' : ' - ' ;
buf [ 3 ] = info - > read_only ? ' r ' : ' w ' ;
buf [ 4 ] = ' \0 ' ;
return dm_report_field_string ( rh , field , & s ) ;
}
2008-04-21 17:16:30 +04:00
static int _dm_info_table_loaded_disp ( struct dm_report * rh ,
2010-07-09 19:34:40 +04:00
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
2008-04-21 17:16:30 +04:00
struct dm_report_field * field ,
const void * data ,
2010-07-09 19:34:40 +04:00
void * private __attribute__ ( ( unused ) ) )
2008-04-21 17:16:30 +04:00
{
const struct dm_info * info = data ;
if ( info - > live_table ) {
if ( info - > inactive_table )
dm_report_field_set_value ( field , " Both " , NULL ) ;
else
dm_report_field_set_value ( field , " Live " , NULL ) ;
return 1 ;
}
if ( info - > inactive_table )
dm_report_field_set_value ( field , " Inactive " , NULL ) ;
else
dm_report_field_set_value ( field , " None " , NULL ) ;
return 1 ;
}
static int _dm_info_suspended_disp ( struct dm_report * rh ,
2010-07-09 19:34:40 +04:00
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
2008-04-21 17:16:30 +04:00
struct dm_report_field * field ,
const void * data ,
2010-07-09 19:34:40 +04:00
void * private __attribute__ ( ( unused ) ) )
2008-04-21 17:16:30 +04:00
{
const struct dm_info * info = data ;
if ( info - > suspended )
dm_report_field_set_value ( field , " Suspended " , NULL ) ;
else
2008-04-21 20:57:11 +04:00
dm_report_field_set_value ( field , " Active " , NULL ) ;
2008-04-21 17:16:30 +04:00
return 1 ;
}
static int _dm_info_read_only_disp ( struct dm_report * rh ,
2010-07-09 19:34:40 +04:00
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
2008-04-21 17:16:30 +04:00
struct dm_report_field * field ,
const void * data ,
2010-07-09 19:34:40 +04:00
void * private __attribute__ ( ( unused ) ) )
2008-04-21 17:16:30 +04:00
{
const struct dm_info * info = data ;
if ( info - > read_only )
dm_report_field_set_value ( field , " Read-only " , NULL ) ;
else
dm_report_field_set_value ( field , " Writeable " , NULL ) ;
return 1 ;
}
2007-06-15 22:20:28 +04:00
static int _dm_info_devno_disp ( struct dm_report * rh , struct dm_pool * mem ,
struct dm_report_field * field , const void * data ,
void * private )
{
2012-01-11 16:46:19 +04:00
char buf [ PATH_MAX ] , * repstr ;
2010-01-14 13:15:23 +03:00
const struct dm_info * info = data ;
2007-06-15 22:20:28 +04:00
if ( ! dm_pool_begin_object ( mem , 8 ) ) {
log_error ( " dm_pool_begin_object failed " ) ;
return 0 ;
}
2012-01-11 16:46:19 +04:00
if ( private ) {
if ( ! dm_device_get_name ( info - > major , info - > minor ,
2015-09-06 01:56:30 +03:00
1 , buf , PATH_MAX ) ) {
stack ;
2012-01-11 16:46:19 +04:00
goto out_abandon ;
2015-09-06 01:56:30 +03:00
}
2012-01-11 16:46:19 +04:00
}
else {
if ( dm_snprintf ( buf , sizeof ( buf ) , " %d:%d " ,
info - > major , info - > minor ) < 0 ) {
log_error ( " dm_pool_alloc failed " ) ;
goto out_abandon ;
}
2007-06-15 22:20:28 +04:00
}
2007-06-19 19:47:20 +04:00
if ( ! dm_pool_grow_object ( mem , buf , strlen ( buf ) + 1 ) ) {
2007-06-15 22:20:28 +04:00
log_error ( " dm_pool_grow_object failed " ) ;
goto out_abandon ;
}
repstr = dm_pool_end_object ( mem ) ;
dm_report_field_set_value ( field , repstr , repstr ) ;
return 1 ;
out_abandon :
dm_pool_abandon_object ( mem ) ;
return 0 ;
}
static int _dm_tree_names ( struct dm_report * rh , struct dm_pool * mem ,
struct dm_report_field * field , const void * data ,
void * private , unsigned inverted )
{
2010-01-14 13:15:23 +03:00
const struct dm_tree_node * node = data ;
struct dm_tree_node * parent ;
2007-06-15 22:20:28 +04:00
void * t = NULL ;
const char * name ;
int first_node = 1 ;
char * repstr ;
if ( ! dm_pool_begin_object ( mem , 16 ) ) {
log_error ( " dm_pool_begin_object failed " ) ;
return 0 ;
}
while ( ( parent = dm_tree_next_child ( & t , node , inverted ) ) ) {
name = dm_tree_node_get_name ( parent ) ;
if ( ! name | | ! * name )
continue ;
2007-06-19 20:50:38 +04:00
if ( ! first_node & & ! dm_pool_grow_object ( mem , " , " , 1 ) ) {
2007-06-15 22:20:28 +04:00
log_error ( " dm_pool_grow_object failed " ) ;
goto out_abandon ;
}
2008-04-19 19:50:18 +04:00
if ( ! dm_pool_grow_object ( mem , name , 0 ) ) {
2007-06-15 22:20:28 +04:00
log_error ( " dm_pool_grow_object failed " ) ;
goto out_abandon ;
}
if ( first_node )
first_node = 0 ;
}
if ( ! dm_pool_grow_object ( mem , " \0 " , 1 ) ) {
log_error ( " dm_pool_grow_object failed " ) ;
goto out_abandon ;
}
repstr = dm_pool_end_object ( mem ) ;
dm_report_field_set_value ( field , repstr , repstr ) ;
return 1 ;
out_abandon :
dm_pool_abandon_object ( mem ) ;
return 0 ;
}
static int _dm_deps_names_disp ( struct dm_report * rh ,
struct dm_pool * mem ,
struct dm_report_field * field ,
const void * data , void * private )
{
return _dm_tree_names ( rh , mem , field , data , private , 0 ) ;
}
static int _dm_tree_parents_names_disp ( struct dm_report * rh ,
struct dm_pool * mem ,
struct dm_report_field * field ,
const void * data , void * private )
{
return _dm_tree_names ( rh , mem , field , data , private , 1 ) ;
}
static int _dm_tree_parents_devs_disp ( struct dm_report * rh , struct dm_pool * mem ,
struct dm_report_field * field ,
const void * data , void * private )
{
2010-01-14 13:15:23 +03:00
const struct dm_tree_node * node = data ;
struct dm_tree_node * parent ;
2007-06-15 22:20:28 +04:00
void * t = NULL ;
const struct dm_info * info ;
int first_node = 1 ;
char buf [ DM_MAX_TYPE_NAME ] , * repstr ;
if ( ! dm_pool_begin_object ( mem , 16 ) ) {
log_error ( " dm_pool_begin_object failed " ) ;
return 0 ;
}
while ( ( parent = dm_tree_next_child ( & t , node , 1 ) ) ) {
info = dm_tree_node_get_info ( parent ) ;
if ( ! info - > major & & ! info - > minor )
continue ;
if ( ! first_node & & ! dm_pool_grow_object ( mem , " , " , 1 ) ) {
log_error ( " dm_pool_grow_object failed " ) ;
goto out_abandon ;
}
if ( dm_snprintf ( buf , sizeof ( buf ) , " %d:%d " ,
info - > major , info - > minor ) < 0 ) {
log_error ( " dm_snprintf failed " ) ;
goto out_abandon ;
}
2008-04-19 19:50:18 +04:00
if ( ! dm_pool_grow_object ( mem , buf , 0 ) ) {
2007-06-15 22:20:28 +04:00
log_error ( " dm_pool_grow_object failed " ) ;
goto out_abandon ;
}
if ( first_node )
first_node = 0 ;
}
if ( ! dm_pool_grow_object ( mem , " \0 " , 1 ) ) {
log_error ( " dm_pool_grow_object failed " ) ;
goto out_abandon ;
}
repstr = dm_pool_end_object ( mem ) ;
dm_report_field_set_value ( field , repstr , repstr ) ;
return 1 ;
out_abandon :
dm_pool_abandon_object ( mem ) ;
return 0 ;
}
2007-06-11 17:20:29 +04:00
static int _dm_tree_parents_count_disp ( struct dm_report * rh ,
struct dm_pool * mem ,
struct dm_report_field * field ,
const void * data , void * private )
{
2010-01-14 13:15:23 +03:00
const struct dm_tree_node * node = data ;
2007-06-11 17:20:29 +04:00
int num_parent = dm_tree_node_num_children ( node , 1 ) ;
return dm_report_field_int ( rh , field , & num_parent ) ;
}
2007-01-24 21:09:07 +03:00
2012-01-11 16:46:19 +04:00
static int _dm_deps_disp_common ( struct dm_report * rh , struct dm_pool * mem ,
struct dm_report_field * field , const void * data ,
void * private , int disp_blk_dev_names )
2007-06-15 22:20:28 +04:00
{
2010-10-25 17:36:57 +04:00
const struct dm_deps * deps = data ;
2012-01-11 16:46:19 +04:00
char buf [ PATH_MAX ] , * repstr ;
int major , minor ;
2011-04-08 18:40:18 +04:00
unsigned i ;
2007-06-15 22:20:28 +04:00
if ( ! dm_pool_begin_object ( mem , 16 ) ) {
log_error ( " dm_pool_begin_object failed " ) ;
return 0 ;
}
for ( i = 0 ; i < deps - > count ; i + + ) {
2012-01-11 16:46:19 +04:00
major = ( int ) MAJOR ( deps - > device [ i ] ) ;
minor = ( int ) MINOR ( deps - > device [ i ] ) ;
if ( disp_blk_dev_names ) {
if ( ! dm_device_get_name ( major , minor , 1 , buf , PATH_MAX ) ) {
log_error ( " Could not resolve block device "
" name for %d:%d. " , major , minor ) ;
goto out_abandon ;
}
}
else if ( dm_snprintf ( buf , sizeof ( buf ) , " %d:%d " ,
major , minor ) < 0 ) {
2007-06-15 22:20:28 +04:00
log_error ( " dm_snprintf failed " ) ;
goto out_abandon ;
}
2012-01-11 16:46:19 +04:00
2008-04-19 19:50:18 +04:00
if ( ! dm_pool_grow_object ( mem , buf , 0 ) ) {
2007-06-15 22:20:28 +04:00
log_error ( " dm_pool_grow_object failed " ) ;
goto out_abandon ;
}
2012-01-11 16:46:19 +04:00
2007-06-15 22:20:28 +04:00
if ( i + 1 < deps - > count & & ! dm_pool_grow_object ( mem , " , " , 1 ) ) {
log_error ( " dm_pool_grow_object failed " ) ;
goto out_abandon ;
}
}
if ( ! dm_pool_grow_object ( mem , " \0 " , 1 ) ) {
log_error ( " dm_pool_grow_object failed " ) ;
goto out_abandon ;
}
repstr = dm_pool_end_object ( mem ) ;
dm_report_field_set_value ( field , repstr , repstr ) ;
return 1 ;
out_abandon :
dm_pool_abandon_object ( mem ) ;
return 0 ;
}
2012-01-11 16:46:19 +04:00
static int _dm_deps_disp ( struct dm_report * rh , struct dm_pool * mem ,
struct dm_report_field * field , const void * data ,
void * private )
{
return _dm_deps_disp_common ( rh , mem , field , data , private , 0 ) ;
}
static int _dm_deps_blk_names_disp ( struct dm_report * rh , struct dm_pool * mem ,
struct dm_report_field * field ,
const void * data , void * private )
{
return _dm_deps_disp_common ( rh , mem , field , data , private , 1 ) ;
}
2009-06-03 22:35:39 +04:00
static int _dm_subsystem_disp ( struct dm_report * rh ,
2010-07-09 19:34:40 +04:00
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
2009-06-03 22:35:39 +04:00
struct dm_report_field * field , const void * data ,
2010-07-09 19:34:40 +04:00
void * private __attribute__ ( ( unused ) ) )
2009-06-03 22:35:39 +04:00
{
2011-03-30 01:49:18 +04:00
return dm_report_field_string ( rh , field , ( const char * const * ) data ) ;
2009-06-03 22:35:39 +04:00
}
static int _dm_vg_name_disp ( struct dm_report * rh ,
2010-07-09 19:34:40 +04:00
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
2009-06-03 22:35:39 +04:00
struct dm_report_field * field , const void * data ,
2010-07-09 19:34:40 +04:00
void * private __attribute__ ( ( unused ) ) )
2009-06-03 22:35:39 +04:00
{
2011-03-30 01:49:18 +04:00
return dm_report_field_string ( rh , field , ( const char * const * ) data ) ;
2009-06-03 22:35:39 +04:00
}
static int _dm_lv_name_disp ( struct dm_report * rh ,
2010-07-09 19:34:40 +04:00
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
2009-06-03 22:35:39 +04:00
struct dm_report_field * field , const void * data ,
2010-07-09 19:34:40 +04:00
void * private __attribute__ ( ( unused ) ) )
2009-06-03 22:35:39 +04:00
{
2011-03-30 01:49:18 +04:00
return dm_report_field_string ( rh , field , ( const char * const * ) data ) ;
2009-06-03 22:35:39 +04:00
}
static int _dm_lv_layer_name_disp ( struct dm_report * rh ,
2010-07-09 19:34:40 +04:00
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
2009-06-03 22:35:39 +04:00
struct dm_report_field * field , const void * data ,
2010-07-09 19:34:40 +04:00
void * private __attribute__ ( ( unused ) ) )
2009-06-03 22:35:39 +04:00
{
2011-03-30 01:49:18 +04:00
return dm_report_field_string ( rh , field , ( const char * const * ) data ) ;
2009-06-03 22:35:39 +04:00
}
2015-08-05 12:40:00 +03:00
/**
* All _dm_stats_ * _disp functions for basic counters are identical :
* obtain the value for the current region and area and pass it to
* dm_report_field_uint64 ( ) .
*/
# define MK_STATS_COUNTER_DISP_FN(counter) \
static int _dm_stats_ # # counter # # _disp ( struct dm_report * rh , \
struct dm_pool * mem __attribute__ ( ( unused ) ) , \
struct dm_report_field * field , const void * data , \
void * private __attribute__ ( ( unused ) ) ) \
{ \
const struct dm_stats * dms = ( const struct dm_stats * ) data ; \
uint64_t value = dm_stats_get_ # # counter ( dms , DM_STATS_REGION_CURRENT , \
DM_STATS_AREA_CURRENT ) ; \
return dm_report_field_uint64 ( rh , field , & value ) ; \
2007-01-24 21:09:07 +03:00
}
2015-08-05 12:40:00 +03:00
MK_STATS_COUNTER_DISP_FN ( reads )
MK_STATS_COUNTER_DISP_FN ( reads_merged )
MK_STATS_COUNTER_DISP_FN ( read_sectors )
MK_STATS_COUNTER_DISP_FN ( read_nsecs )
MK_STATS_COUNTER_DISP_FN ( writes )
MK_STATS_COUNTER_DISP_FN ( writes_merged )
MK_STATS_COUNTER_DISP_FN ( write_sectors )
MK_STATS_COUNTER_DISP_FN ( write_nsecs )
MK_STATS_COUNTER_DISP_FN ( io_in_progress )
MK_STATS_COUNTER_DISP_FN ( io_nsecs )
MK_STATS_COUNTER_DISP_FN ( weighted_io_nsecs )
MK_STATS_COUNTER_DISP_FN ( total_read_nsecs )
MK_STATS_COUNTER_DISP_FN ( total_write_nsecs )
# undef MK_STATS_COUNTER_DISP_FN
static int _dm_stats_region_id_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
2007-01-24 21:09:07 +03:00
{
2015-08-05 12:40:00 +03:00
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
uint64_t region_id = dm_stats_get_current_region ( dms ) ;
return dm_report_field_uint64 ( rh , field , & region_id ) ;
2007-01-24 21:09:07 +03:00
}
2015-08-05 12:40:00 +03:00
static int _dm_stats_region_start_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
2007-06-15 22:20:28 +04:00
{
2015-08-05 12:40:00 +03:00
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
uint64_t region_start ;
const char * repstr ;
double * sortval ;
char units = _disp_units ;
uint64_t factor = _disp_factor ;
if ( ! dm_stats_get_current_region_start ( dms , & region_start ) )
return_0 ;
if ( ! ( repstr = dm_size_to_string ( mem , region_start , units , 1 , factor ,
_show_units ( ) , DM_SIZE_UNIT ) ) )
return_0 ;
if ( ! ( sortval = dm_pool_alloc ( mem , sizeof ( uint64_t ) ) ) )
return_0 ;
* sortval = ( double ) region_start ;
dm_report_field_set_value ( field , repstr , sortval ) ;
return 1 ;
2007-06-15 22:20:28 +04:00
}
2015-08-05 12:40:00 +03:00
static int _dm_stats_region_len_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
2007-06-11 17:20:29 +04:00
{
2015-08-05 12:40:00 +03:00
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
uint64_t region_length ;
const char * repstr ;
double * sortval ;
char units = _disp_units ;
uint64_t factor = _disp_factor ;
if ( ! dm_stats_get_current_region_len ( dms , & region_length ) )
return_0 ;
if ( ! ( repstr = dm_size_to_string ( mem , region_length , units , 1 , factor ,
_show_units ( ) , DM_SIZE_UNIT ) ) )
return_0 ;
if ( ! ( sortval = dm_pool_alloc ( mem , sizeof ( uint64_t ) ) ) )
return_0 ;
* sortval = ( double ) region_length ;
dm_report_field_set_value ( field , repstr , sortval ) ;
return 1 ;
2007-06-11 17:20:29 +04:00
}
2015-08-05 12:40:00 +03:00
static int _dm_stats_area_id_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
2009-06-03 22:35:39 +04:00
{
2015-08-05 12:40:00 +03:00
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
uint64_t area_id = dm_stats_get_current_area ( dms ) ;
return dm_report_field_uint64 ( rh , field , & area_id ) ;
2009-06-03 22:35:39 +04:00
}
2015-08-05 12:40:00 +03:00
static int _dm_stats_area_start_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
uint64_t area_start ;
const char * repstr ;
double * sortval ;
char units = _disp_units ;
uint64_t factor = _disp_factor ;
if ( ! dm_stats_get_current_area_start ( dms , & area_start ) )
return_0 ;
2007-01-24 21:09:07 +03:00
2015-08-05 12:40:00 +03:00
if ( ! ( repstr = dm_size_to_string ( mem , area_start , units , 1 , factor ,
_show_units ( ) , DM_SIZE_UNIT ) ) )
return_0 ;
2007-01-24 21:09:07 +03:00
2015-08-05 12:40:00 +03:00
if ( ! ( sortval = dm_pool_alloc ( mem , sizeof ( uint64_t ) ) ) )
return_0 ;
2007-11-27 23:57:05 +03:00
2015-08-05 12:40:00 +03:00
* sortval = ( double ) area_start ;
2007-11-27 23:57:05 +03:00
2015-08-05 12:40:00 +03:00
dm_report_field_set_value ( field , repstr , sortval ) ;
return 1 ;
}
2007-06-15 22:20:28 +04:00
2015-08-14 23:49:40 +03:00
static int _dm_stats_area_offset_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
uint64_t area_offset ;
const char * repstr ;
double * sortval ;
char units = _disp_units ;
uint64_t factor = _disp_factor ;
if ( ! dm_stats_get_current_area_offset ( dms , & area_offset ) )
return_0 ;
if ( ! ( repstr = dm_size_to_string ( mem , area_offset , units , 1 , factor ,
_show_units ( ) , DM_SIZE_UNIT ) ) )
return_0 ;
if ( ! ( sortval = dm_pool_alloc ( mem , sizeof ( uint64_t ) ) ) )
return_0 ;
* sortval = ( double ) area_offset ;
dm_report_field_set_value ( field , repstr , sortval ) ;
return 1 ;
}
2015-08-05 12:40:00 +03:00
static int _dm_stats_area_len_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
uint64_t area_len ;
const char * repstr ;
double * sortval ;
char units = _disp_units ;
uint64_t factor = _disp_factor ;
if ( ! dm_stats_get_current_area_len ( dms , & area_len ) )
return_0 ;
2007-06-15 22:20:28 +04:00
2015-08-05 12:40:00 +03:00
if ( ! ( repstr = dm_size_to_string ( mem , area_len , units , 1 , factor ,
_show_units ( ) , DM_SIZE_UNIT ) ) )
return_0 ;
2009-06-03 22:35:39 +04:00
2015-08-05 12:40:00 +03:00
if ( ! ( sortval = dm_pool_alloc ( mem , sizeof ( uint64_t ) ) ) )
return_0 ;
2009-06-03 22:35:39 +04:00
2015-08-05 12:40:00 +03:00
* sortval = ( double ) area_len ;
2007-01-24 21:09:07 +03:00
2015-08-05 12:40:00 +03:00
dm_report_field_set_value ( field , repstr , sortval ) ;
return 1 ;
}
2007-01-24 21:09:07 +03:00
2015-08-05 12:40:00 +03:00
static int _dm_stats_area_count_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
uint64_t area_count , region ;
2007-01-24 21:09:07 +03:00
2015-08-05 12:40:00 +03:00
region = dm_stats_get_current_region ( dms ) ;
if ( ! ( area_count = dm_stats_get_region_nr_areas ( dms , region ) ) )
return_0 ;
return dm_report_field_uint64 ( rh , field , & area_count ) ;
}
static int _dm_stats_program_id_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
2007-01-24 21:09:07 +03:00
{
2015-08-05 12:40:00 +03:00
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
const char * program_id ;
if ( ! ( program_id = dm_stats_get_current_region_program_id ( dms ) ) )
return_0 ;
2015-08-17 19:30:38 +03:00
return dm_report_field_string ( rh , field , ( const char * const * ) & program_id ) ;
2015-08-05 12:40:00 +03:00
}
2007-01-24 21:09:07 +03:00
2015-08-05 12:40:00 +03:00
static int _dm_stats_aux_data_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
const char * aux_data ;
if ( ! ( aux_data = dm_stats_get_current_region_aux_data ( dms ) ) )
return_0 ;
2015-08-17 19:30:38 +03:00
return dm_report_field_string ( rh , field , ( const char * const * ) & aux_data ) ;
2015-08-05 12:40:00 +03:00
}
2009-06-04 00:44:42 +04:00
2015-08-17 20:09:43 +03:00
static int _dm_stats_precise_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
int precise ;
precise = dm_stats_get_current_region_precise_timestamps ( dms ) ;
return dm_report_field_int ( rh , field , ( const int * ) & precise ) ;
}
2015-08-18 14:40:03 +03:00
static const char * _get_histogram_string ( const struct dm_stats * dms , int rel ,
int vals , int bounds )
{
const struct dm_histogram * dmh ;
2015-09-03 23:56:34 +03:00
int flags = 0 , width = ( _switches [ NOHEADINGS_ARG ] ) ? - 1 : 0 ;
2015-08-18 14:40:03 +03:00
if ( ! ( dmh = dm_stats_get_histogram ( dms , DM_STATS_REGION_CURRENT ,
DM_STATS_AREA_CURRENT ) ) )
return " " ; /* No histogram. */
flags | = ( vals ) ? DM_HISTOGRAM_VALUES
: 0 ;
flags | = bounds ;
flags | = ( rel ) ? DM_HISTOGRAM_PERCENT
: 0 ;
2015-09-03 23:55:25 +03:00
flags | = ( _switches [ NOTIMESUFFIX_ARG ] ) ? 0 : DM_HISTOGRAM_SUFFIX ;
2015-08-18 14:40:03 +03:00
/* FIXME: make unit conversion optional. */
2015-09-03 23:56:34 +03:00
return dm_histogram_to_string ( dmh , - 1 , width , flags ) ;
2015-08-18 14:40:03 +03:00
}
static int _stats_hist_count_disp ( struct dm_report * rh ,
struct dm_report_field * field , const void * data ,
int bounds )
{
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
const char * histogram ;
histogram = _get_histogram_string ( dms , 0 , 1 , bounds ) ; /* counts */
if ( ! histogram )
return_0 ;
return dm_report_field_string ( rh , field , ( const char * const * ) & histogram ) ;
}
static int _dm_stats_hist_count_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
return _stats_hist_count_disp ( rh , field , data , 0 ) ;
}
static int _dm_stats_hist_count_bounds_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
return _stats_hist_count_disp ( rh , field , data , DM_HISTOGRAM_BOUNDS_LOWER ) ;
}
static int _dm_stats_hist_count_ranges_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
return _stats_hist_count_disp ( rh , field , data , DM_HISTOGRAM_BOUNDS_RANGE ) ;
}
static int _stats_hist_percent_disp ( struct dm_report * rh ,
struct dm_report_field * field , const void * data ,
int bounds )
{
/* FIXME: configurable to-string options. */
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
const char * histogram ;
histogram = _get_histogram_string ( dms , 1 , 1 , bounds ) ; /* relative values */
if ( ! histogram )
return_0 ;
return dm_report_field_string ( rh , field , ( const char * const * ) & histogram ) ;
}
static int _dm_stats_hist_percent_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
return _stats_hist_percent_disp ( rh , field , data , 0 ) ;
}
static int _dm_stats_hist_percent_bounds_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
return _stats_hist_percent_disp ( rh , field , data , DM_HISTOGRAM_BOUNDS_LOWER ) ;
}
static int _dm_stats_hist_percent_ranges_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
return _stats_hist_percent_disp ( rh , field , data , DM_HISTOGRAM_BOUNDS_RANGE ) ;
}
static int _stats_hist_bounds_disp ( struct dm_report * rh ,
struct dm_report_field * field , const void * data ,
int bounds )
{
/* FIXME: configurable to-string options. */
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
const char * histogram ;
histogram = _get_histogram_string ( dms , 0 , 0 , bounds ) ;
if ( ! histogram )
return_0 ;
return dm_report_field_string ( rh , field , ( const char * const * ) & histogram ) ;
}
static int _dm_stats_hist_bounds_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
return _stats_hist_bounds_disp ( rh , field , data , DM_HISTOGRAM_BOUNDS_LOWER ) ;
}
static int _dm_stats_hist_ranges_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
return _stats_hist_bounds_disp ( rh , field , data , DM_HISTOGRAM_BOUNDS_RANGE ) ;
}
static int _dm_stats_hist_bins_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
int bins ;
bins = dm_stats_get_region_nr_histogram_bins ( dms , DM_STATS_REGION_CURRENT ) ;
return dm_report_field_int ( rh , field , ( const int * ) & bins ) ;
}
2015-08-05 12:40:00 +03:00
static int _dm_stats_rrqm_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
char buf [ 64 ] ;
char * repstr ;
double * sortval , rrqm ;
2007-01-24 21:09:07 +03:00
2015-08-05 12:40:00 +03:00
if ( ! dm_stats_get_rd_merges_per_sec ( dms , & rrqm ,
DM_STATS_REGION_CURRENT ,
DM_STATS_AREA_CURRENT ) )
return_0 ;
2007-06-15 22:20:28 +04:00
2015-08-05 12:40:00 +03:00
if ( ! dm_snprintf ( buf , sizeof ( buf ) , " %.2f " , rrqm ) )
return_0 ;
2008-06-25 02:53:48 +04:00
2015-08-05 12:40:00 +03:00
if ( ! ( repstr = dm_pool_strdup ( mem , buf ) ) )
return_0 ;
2008-06-25 00:16:47 +04:00
2015-08-05 12:40:00 +03:00
if ( ! ( sortval = dm_pool_alloc ( mem , sizeof ( uint64_t ) ) ) )
return_0 ;
2008-04-21 15:59:22 +04:00
2015-08-05 12:40:00 +03:00
* sortval = rrqm ;
2007-01-24 21:09:07 +03:00
2015-08-05 12:40:00 +03:00
dm_report_field_set_value ( field , repstr , sortval ) ;
return 1 ;
2007-01-24 21:09:07 +03:00
2015-08-05 12:40:00 +03:00
}
2007-01-24 21:09:07 +03:00
2015-08-05 12:40:00 +03:00
static int _dm_stats_wrqm_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
char buf [ 64 ] ;
char * repstr ;
double * sortval , wrqm ;
2014-05-29 11:38:49 +04:00
2015-08-05 12:40:00 +03:00
if ( ! dm_stats_get_wr_merges_per_sec ( dms , & wrqm ,
DM_STATS_REGION_CURRENT ,
DM_STATS_AREA_CURRENT ) )
return_0 ;
2007-01-24 21:09:07 +03:00
2015-08-05 12:40:00 +03:00
if ( ! dm_snprintf ( buf , sizeof ( buf ) , " %.2f " , wrqm ) )
return_0 ;
2007-01-24 21:09:07 +03:00
2015-08-05 12:40:00 +03:00
if ( ! ( repstr = dm_pool_strdup ( mem , buf ) ) )
return_0 ;
2007-01-24 21:09:07 +03:00
2015-08-05 12:40:00 +03:00
if ( ! ( sortval = dm_pool_alloc ( mem , sizeof ( uint64_t ) ) ) )
return_0 ;
2008-04-21 15:59:22 +04:00
2015-08-05 12:40:00 +03:00
* sortval = wrqm ;
2008-06-25 00:16:47 +04:00
2015-08-05 12:40:00 +03:00
dm_report_field_set_value ( field , repstr , sortval ) ;
return 1 ;
2008-06-25 02:53:48 +04:00
2015-08-05 12:40:00 +03:00
}
2007-06-11 17:20:29 +04:00
2015-08-05 12:40:00 +03:00
static int _dm_stats_rs_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
char buf [ 64 ] ;
char * repstr ;
double * sortval , rs ;
2007-01-24 21:09:07 +03:00
2015-08-05 12:40:00 +03:00
if ( ! dm_stats_get_reads_per_sec ( dms , & rs ,
DM_STATS_REGION_CURRENT ,
DM_STATS_AREA_CURRENT ) )
return_0 ;
2015-07-31 23:59:34 +03:00
2015-08-05 12:40:00 +03:00
if ( ! dm_snprintf ( buf , sizeof ( buf ) , " %.2f " , rs ) )
return_0 ;
2015-07-31 23:59:34 +03:00
2015-08-05 12:40:00 +03:00
if ( ! ( repstr = dm_pool_strdup ( mem , buf ) ) )
return_0 ;
2008-04-21 15:59:22 +04:00
2015-08-05 12:40:00 +03:00
if ( ! ( sortval = dm_pool_alloc ( mem , sizeof ( uint64_t ) ) ) )
return_0 ;
2007-01-24 21:09:07 +03:00
2015-08-05 12:40:00 +03:00
* sortval = rs ;
2007-01-24 21:09:07 +03:00
2015-08-05 12:40:00 +03:00
dm_report_field_set_value ( field , repstr , sortval ) ;
return 1 ;
2007-01-24 21:09:07 +03:00
2003-07-02 01:20:58 +04:00
}
2015-08-05 12:40:00 +03:00
static int _dm_stats_ws_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
char buf [ 64 ] ;
char * repstr ;
double * sortval , ws ;
if ( ! dm_stats_get_writes_per_sec ( dms , & ws ,
DM_STATS_REGION_CURRENT ,
DM_STATS_AREA_CURRENT ) )
return_0 ;
if ( ! dm_snprintf ( buf , sizeof ( buf ) , " %.2f " , ws ) )
return_0 ;
if ( ! ( repstr = dm_pool_strdup ( mem , buf ) ) )
return_0 ;
if ( ! ( sortval = dm_pool_alloc ( mem , sizeof ( uint64_t ) ) ) )
return_0 ;
* sortval = ws ;
dm_report_field_set_value ( field , repstr , sortval ) ;
return 1 ;
}
static int _dm_stats_read_secs_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
const char * repstr ;
double * sortval , rsec ;
char units = _disp_units ;
uint64_t factor = _disp_factor ;
if ( ! dm_stats_get_read_sectors_per_sec ( dms , & rsec ,
DM_STATS_REGION_CURRENT ,
DM_STATS_AREA_CURRENT ) )
return_0 ;
if ( ! ( repstr = dm_size_to_string ( mem , ( uint64_t ) rsec , units , 1 ,
factor , _show_units ( ) , DM_SIZE_UNIT ) ) )
return_0 ;
if ( ! ( sortval = dm_pool_alloc ( mem , sizeof ( uint64_t ) ) ) )
return_0 ;
* sortval = rsec ;
dm_report_field_set_value ( field , repstr , sortval ) ;
return 1 ;
}
static int _dm_stats_write_secs_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
const char * repstr ;
double * sortval , wsec ;
char units = _disp_units ;
uint64_t factor = _disp_factor ;
if ( ! dm_stats_get_write_sectors_per_sec ( dms , & wsec ,
DM_STATS_REGION_CURRENT ,
DM_STATS_AREA_CURRENT ) )
return_0 ;
if ( ! ( repstr = dm_size_to_string ( mem , ( uint64_t ) wsec , units , 1 ,
factor , _show_units ( ) , DM_SIZE_UNIT ) ) )
return_0 ;
if ( ! ( sortval = dm_pool_alloc ( mem , sizeof ( uint64_t ) ) ) )
return_0 ;
* sortval = wsec ;
dm_report_field_set_value ( field , repstr , sortval ) ;
return 1 ;
}
static int _dm_stats_arqsz_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
const char * repstr ;
double * sortval , arqsz ;
char units = _disp_units ;
uint64_t factor = _disp_factor ;
if ( ! dm_stats_get_average_request_size ( dms , & arqsz ,
DM_STATS_REGION_CURRENT ,
DM_STATS_AREA_CURRENT ) )
return_0 ;
if ( ! ( repstr = dm_size_to_string ( mem , ( uint64_t ) arqsz , units , 1 ,
factor , _show_units ( ) , DM_SIZE_UNIT ) ) )
return_0 ;
if ( ! ( sortval = dm_pool_alloc ( mem , sizeof ( uint64_t ) ) ) )
return_0 ;
* sortval = arqsz ;
dm_report_field_set_value ( field , repstr , sortval ) ;
return 1 ;
}
static int _dm_stats_qusz_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
char buf [ 64 ] ;
char * repstr ;
double * sortval , qusz ;
if ( ! dm_stats_get_average_queue_size ( dms , & qusz ,
DM_STATS_REGION_CURRENT ,
DM_STATS_AREA_CURRENT ) )
return_0 ;
if ( ! dm_snprintf ( buf , sizeof ( buf ) , " %.2f " , qusz ) )
return_0 ;
if ( ! ( repstr = dm_pool_strdup ( mem , buf ) ) )
return_0 ;
if ( ! ( sortval = dm_pool_alloc ( mem , sizeof ( uint64_t ) ) ) )
return_0 ;
* sortval = qusz ;
dm_report_field_set_value ( field , repstr , sortval ) ;
return 1 ;
}
static int _dm_stats_await_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
char buf [ 64 ] ;
char * repstr ;
double * sortval , await ;
if ( ! dm_stats_get_average_wait_time ( dms , & await ,
DM_STATS_REGION_CURRENT ,
DM_STATS_AREA_CURRENT ) )
return_0 ;
/* FIXME: make scale configurable */
/* display in msecs */
await / = NSEC_PER_MSEC ;
if ( ! dm_snprintf ( buf , sizeof ( buf ) , " %.2f " , await ) )
return_0 ;
if ( ! ( repstr = dm_pool_strdup ( mem , buf ) ) )
return_0 ;
if ( ! ( sortval = dm_pool_alloc ( mem , sizeof ( uint64_t ) ) ) )
return_0 ;
* sortval = await ;
dm_report_field_set_value ( field , repstr , sortval ) ;
return 1 ;
}
static int _dm_stats_r_await_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
char buf [ 64 ] ;
char * repstr ;
double * sortval , r_await ;
if ( ! dm_stats_get_average_rd_wait_time ( dms , & r_await ,
DM_STATS_REGION_CURRENT ,
DM_STATS_AREA_CURRENT ) )
return_0 ;
/* FIXME: make scale configurable */
/* display in msecs */
r_await / = NSEC_PER_MSEC ;
if ( ! dm_snprintf ( buf , sizeof ( buf ) , " %.2f " , r_await ) )
return_0 ;
if ( ! ( repstr = dm_pool_strdup ( mem , buf ) ) )
return_0 ;
if ( ! ( sortval = dm_pool_alloc ( mem , sizeof ( uint64_t ) ) ) )
return_0 ;
* sortval = r_await ;
dm_report_field_set_value ( field , repstr , sortval ) ;
return 1 ;
}
static int _dm_stats_w_await_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
char buf [ 64 ] ;
char * repstr ;
double * sortval , w_await ;
if ( ! dm_stats_get_average_wr_wait_time ( dms , & w_await ,
DM_STATS_REGION_CURRENT ,
DM_STATS_AREA_CURRENT ) )
return_0 ;
/* FIXME: make scale configurable */
/* display in msecs */
w_await / = NSEC_PER_MSEC ;
if ( ! dm_snprintf ( buf , sizeof ( buf ) , " %.2f " , w_await ) )
return_0 ;
if ( ! ( repstr = dm_pool_strdup ( mem , buf ) ) )
return_0 ;
if ( ! ( sortval = dm_pool_alloc ( mem , sizeof ( uint64_t ) ) ) )
return_0 ;
* sortval = w_await ;
dm_report_field_set_value ( field , repstr , sortval ) ;
return 1 ;
}
static int _dm_stats_tput_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
char buf [ 64 ] ;
char * repstr ;
double * sortval , tput ;
if ( ! dm_stats_get_throughput ( dms , & tput ,
DM_STATS_REGION_CURRENT ,
DM_STATS_AREA_CURRENT ) )
return_0 ;
if ( ! dm_snprintf ( buf , sizeof ( buf ) , " %.2f " , tput ) )
return_0 ;
if ( ! ( repstr = dm_pool_strdup ( mem , buf ) ) )
return_0 ;
if ( ! ( sortval = dm_pool_alloc ( mem , sizeof ( uint64_t ) ) ) )
return_0 ;
* sortval = tput ;
dm_report_field_set_value ( field , repstr , sortval ) ;
return 1 ;
}
static int _dm_stats_svctm_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
char buf [ 64 ] ;
char * repstr ;
double * sortval , svctm ;
if ( ! dm_stats_get_service_time ( dms , & svctm ,
DM_STATS_REGION_CURRENT ,
DM_STATS_AREA_CURRENT ) )
return_0 ;
/* FIXME: make scale configurable */
/* display in msecs */
svctm / = NSEC_PER_MSEC ;
if ( ! dm_snprintf ( buf , sizeof ( buf ) , " %.2f " , svctm ) )
return_0 ;
if ( ! ( repstr = dm_pool_strdup ( mem , buf ) ) )
return_0 ;
if ( ! ( sortval = dm_pool_alloc ( mem , sizeof ( uint64_t ) ) ) )
return_0 ;
* sortval = svctm ;
dm_report_field_set_value ( field , repstr , sortval ) ;
return 1 ;
}
static int _dm_stats_util_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
const struct dm_stats * dms = ( const struct dm_stats * ) data ;
dm_percent_t util ;
if ( ! dm_stats_get_utilization ( dms , & util ,
DM_STATS_REGION_CURRENT ,
DM_STATS_AREA_CURRENT ) )
return_0 ;
dm_report_field_percent ( rh , field , & util ) ;
return 1 ;
}
2015-08-13 23:14:57 +03:00
static int _dm_stats_sample_interval_ns_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
/* FIXME: use internal interval estimate when supported by libdm */
return dm_report_field_uint64 ( rh , field , & _last_interval ) ;
}
static int _dm_stats_sample_interval_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field , const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
char buf [ 64 ] ;
char * repstr ;
double * sortval ;
if ( ! ( sortval = dm_pool_alloc ( mem , sizeof ( * sortval ) ) ) )
return_0 ;
* sortval = ( double ) _last_interval / ( double ) NSEC_PER_SEC ;
if ( ! dm_snprintf ( buf , sizeof ( buf ) , " %2.6f " , * sortval ) )
return_0 ;
if ( ! ( repstr = dm_pool_strdup ( mem , buf ) ) )
return_0 ;
dm_report_field_set_value ( field , repstr , sortval ) ;
return 1 ;
}
2015-08-05 12:40:00 +03:00
static void * _task_get_obj ( void * obj )
{
return ( ( struct dmsetup_report_obj * ) obj ) - > task ;
}
static void * _info_get_obj ( void * obj )
{
return ( ( struct dmsetup_report_obj * ) obj ) - > info ;
}
static void * _deps_get_obj ( void * obj )
{
return dm_task_get_deps ( ( ( struct dmsetup_report_obj * ) obj ) - > deps_task ) ;
}
static void * _tree_get_obj ( void * obj )
{
return ( ( struct dmsetup_report_obj * ) obj ) - > tree_node ;
}
static void * _split_name_get_obj ( void * obj )
{
return ( ( struct dmsetup_report_obj * ) obj ) - > split_name ;
}
static void * _stats_get_obj ( void * obj )
{
return ( ( struct dmsetup_report_obj * ) obj ) - > stats ;
}
static const struct dm_report_object_type _report_types [ ] = {
2015-08-14 23:14:29 +03:00
{ DR_TASK , " Mapped Device Name " , " name_ " , _task_get_obj } ,
{ DR_INFO , " Mapped Device Information " , " info_ " , _info_get_obj } ,
{ DR_DEPS , " Mapped Device Relationship Information " , " deps_ " , _deps_get_obj } ,
{ DR_TREE , " Mapped Device Relationship Information " , " tree_ " , _tree_get_obj } ,
{ DR_NAME , " Mapped Device Name Components " , " splitname_ " , _split_name_get_obj } ,
2015-08-14 19:10:47 +03:00
{ DR_STATS , " Mapped Device Statistics " , " stats_ " , _stats_get_obj } ,
2015-08-15 01:53:42 +03:00
{ DR_STATS_META , " Mapped Device Statistics Region Information " , " region_ " , _stats_get_obj } ,
2015-08-05 12:40:00 +03:00
{ 0 , " " , " " , NULL }
} ;
/* Column definitions */
/* N.B. Field names must not contain the substring 'help' as this will disable --count. */
# define OFFSET_OF(strct, field) (((char*)&((struct strct*)0)->field) - (char*)0)
# define STR (DM_REPORT_FIELD_TYPE_STRING)
# define NUM (DM_REPORT_FIELD_TYPE_NUMBER)
# define SIZ (DM_REPORT_FIELD_TYPE_SIZE)
# define TIM (DM_REPORT_FIELD_TYPE_TIME)
# define FIELD_O(type, strct, sorttype, head, field, width, func, id, desc) {DR_ ## type, sorttype, OFFSET_OF(strct, field), width, id, head, &_ ## func ## _disp, desc},
# define FIELD_F(type, sorttype, head, width, func, id, desc) {DR_ ## type, sorttype, 0, width, id, head, &_ ## func ## _disp, desc},
static const struct dm_report_field_type _report_fields [ ] = {
/* *INDENT-OFF* */
FIELD_F ( TASK , STR , " Name " , 16 , dm_name , " name " , " Name of mapped device. " )
FIELD_F ( TASK , STR , " MangledName " , 16 , dm_mangled_name , " mangled_name " , " Mangled name of mapped device. " )
FIELD_F ( TASK , STR , " UnmangledName " , 16 , dm_unmangled_name , " unmangled_name " , " Unmangled name of mapped device. " )
FIELD_F ( TASK , STR , " UUID " , 32 , dm_uuid , " uuid " , " Unique (optional) identifier for mapped device. " )
FIELD_F ( TASK , STR , " MangledUUID " , 32 , dm_mangled_uuid , " mangled_uuid " , " Mangled unique (optional) identifier for mapped device. " )
FIELD_F ( TASK , STR , " UnmangledUUID " , 32 , dm_unmangled_uuid , " unmangled_uuid " , " Unmangled unique (optional) identifier for mapped device. " )
/* FIXME Next one should be INFO */
FIELD_F ( TASK , NUM , " RAhead " , 6 , dm_read_ahead , " read_ahead " , " Read ahead value. " )
FIELD_F ( INFO , STR , " BlkDevName " , 16 , dm_blk_name , " blkdevname " , " Name of block device. " )
FIELD_F ( INFO , STR , " Stat " , 4 , dm_info_status , " attr " , " (L)ive, (I)nactive, (s)uspended, (r)ead-only, read-(w)rite. " )
FIELD_F ( INFO , STR , " Tables " , 6 , dm_info_table_loaded , " tables_loaded " , " Which of the live and inactive table slots are filled. " )
FIELD_F ( INFO , STR , " Suspended " , 9 , dm_info_suspended , " suspended " , " Whether the device is suspended. " )
FIELD_F ( INFO , STR , " Read-only " , 9 , dm_info_read_only , " readonly " , " Whether the device is read-only or writeable. " )
FIELD_F ( INFO , STR , " DevNo " , 5 , dm_info_devno , " devno " , " Device major and minor numbers " )
FIELD_O ( INFO , dm_info , NUM , " Maj " , major , 3 , int32 , " major " , " Block device major number. " )
FIELD_O ( INFO , dm_info , NUM , " Min " , minor , 3 , int32 , " minor " , " Block device minor number. " )
FIELD_O ( INFO , dm_info , NUM , " Open " , open_count , 4 , int32 , " open " , " Number of references to open device, if requested. " )
FIELD_O ( INFO , dm_info , NUM , " Targ " , target_count , 4 , int32 , " segments " , " Number of segments in live table, if present. " )
FIELD_O ( INFO , dm_info , NUM , " Event " , event_nr , 6 , uint32 , " events " , " Number of most recent event. " )
FIELD_O ( DEPS , dm_deps , NUM , " #Devs " , count , 5 , int32 , " device_count " , " Number of devices used by this one. " )
FIELD_F ( TREE , STR , " DevNamesUsed " , 16 , dm_deps_names , " devs_used " , " List of names of mapped devices used by this one. " )
FIELD_F ( DEPS , STR , " DevNosUsed " , 16 , dm_deps , " devnos_used " , " List of device numbers of devices used by this one. " )
FIELD_F ( DEPS , STR , " BlkDevNamesUsed " , 16 , dm_deps_blk_names , " blkdevs_used " , " List of names of block devices used by this one. " )
FIELD_F ( TREE , NUM , " #Refs " , 5 , dm_tree_parents_count , " device_ref_count " , " Number of mapped devices referencing this one. " )
FIELD_F ( TREE , STR , " RefNames " , 8 , dm_tree_parents_names , " names_using_dev " , " List of names of mapped devices using this one. " )
FIELD_F ( TREE , STR , " RefDevNos " , 9 , dm_tree_parents_devs , " devnos_using_dev " , " List of device numbers of mapped devices using this one. " )
FIELD_O ( NAME , dm_split_name , STR , " Subsys " , subsystem , 6 , dm_subsystem , " subsystem " , " Userspace subsystem responsible for this device. " )
FIELD_O ( NAME , dm_split_name , STR , " VG " , vg_name , 4 , dm_vg_name , " vg_name " , " LVM Volume Group name. " )
FIELD_O ( NAME , dm_split_name , STR , " LV " , lv_name , 4 , dm_lv_name , " lv_name " , " LVM Logical Volume name. " )
FIELD_O ( NAME , dm_split_name , STR , " LVLayer " , lv_layer , 7 , dm_lv_layer_name , " lv_layer " , " LVM device layer. " )
/* basic stats counters */
2015-08-22 21:35:43 +03:00
FIELD_F ( STATS , NUM , " #Reads " , 6 , dm_stats_reads , " read_count " , " Count of reads completed. " )
FIELD_F ( STATS , NUM , " #RdMrgs " , 7 , dm_stats_reads_merged , " reads_merged_count " , " Count of read requests merged. " )
FIELD_F ( STATS , NUM , " #RdSectors " , 10 , dm_stats_read_sectors , " read_sector_count " , " Count of sectors read. " )
FIELD_F ( STATS , NUM , " AccRdTime " , 11 , dm_stats_read_nsecs , " read_time " , " Accumulated duration of all read requests (ns). " )
FIELD_F ( STATS , NUM , " #Writes " , 7 , dm_stats_writes , " write_count " , " Count of writes completed. " )
FIELD_F ( STATS , NUM , " #WrMrgs " , 7 , dm_stats_writes_merged , " writes_merged_count " , " Count of write requests merged. " )
FIELD_F ( STATS , NUM , " #WrSectors " , 10 , dm_stats_write_sectors , " write_sector_count " , " Count of sectors written. " )
FIELD_F ( STATS , NUM , " AccWrTime " , 11 , dm_stats_write_nsecs , " write_time " , " Accumulated duration of all writes (ns). " )
FIELD_F ( STATS , NUM , " #InProg " , 7 , dm_stats_io_in_progress , " in_progress_count " , " Count of requests currently in progress. " )
FIELD_F ( STATS , NUM , " IoTicks " , 7 , dm_stats_io_nsecs , " io_ticks " , " Nanoseconds spent servicing requests. " )
FIELD_F ( STATS , NUM , " QueueTicks " , 10 , dm_stats_weighted_io_nsecs , " queue_ticks " , " Total nanoseconds spent in queue. " )
FIELD_F ( STATS , NUM , " RdTicks " , 7 , dm_stats_total_read_nsecs , " read_ticks " , " Nanoseconds spent servicing reads. " )
FIELD_F ( STATS , NUM , " WrTicks " , 7 , dm_stats_total_write_nsecs , " write_ticks " , " Nanoseconds spent servicing writes. " )
2015-08-05 12:40:00 +03:00
/* Stats derived metrics */
2015-08-22 21:35:43 +03:00
FIELD_F ( STATS , NUM , " RMrg/s " , 6 , dm_stats_rrqm , " reads_merged_per_sec " , " Read requests merged per second. " )
FIELD_F ( STATS , NUM , " WMrg/s " , 6 , dm_stats_wrqm , " writes_merged_per_sec " , " Write requests merged per second. " )
FIELD_F ( STATS , NUM , " R/s " , 3 , dm_stats_rs , " reads_per_sec " , " Reads per second. " )
FIELD_F ( STATS , NUM , " W/s " , 3 , dm_stats_ws , " writes_per_sec " , " Writes per second. " )
FIELD_F ( STATS , NUM , " RSz/s " , 5 , dm_stats_read_secs , " read_size_per_sec " , " Size of data read per second. " )
FIELD_F ( STATS , NUM , " WSz/s " , 5 , dm_stats_write_secs , " write_size_per_sec " , " Size of data written per second. " )
FIELD_F ( STATS , NUM , " AvgRqSz " , 7 , dm_stats_arqsz , " avg_request_size " , " Average request size. " )
FIELD_F ( STATS , NUM , " QSize " , 5 , dm_stats_qusz , " queue_size " , " Average queue size. " )
2015-08-05 12:40:00 +03:00
FIELD_F ( STATS , NUM , " AWait " , 5 , dm_stats_await , " await " , " Averate wait time. " )
2015-08-22 21:35:43 +03:00
FIELD_F ( STATS , NUM , " RdAWait " , 7 , dm_stats_r_await , " read_await " , " Averate read wait time. " )
FIELD_F ( STATS , NUM , " WrAWait " , 7 , dm_stats_w_await , " write_await " , " Averate write wait time. " )
FIELD_F ( STATS , NUM , " Throughput " , 10 , dm_stats_tput , " throughput " , " Throughput. " )
FIELD_F ( STATS , NUM , " SvcTm " , 5 , dm_stats_svctm , " service_time " , " Service time. " )
2015-08-16 21:35:06 +03:00
FIELD_F ( STATS , NUM , " Util% " , 5 , dm_stats_util , " util " , " Utilization. " )
2015-08-05 12:40:00 +03:00
2015-08-18 14:40:03 +03:00
/* Histogram fields */
FIELD_F ( STATS , STR , " Histogram Counts " , 16 , dm_stats_hist_count , " hist_count " , " Latency histogram counts. " )
FIELD_F ( STATS , STR , " Histogram Counts " , 16 , dm_stats_hist_count_bounds , " hist_count_bounds " , " Latency histogram counts with bin boundaries. " )
FIELD_F ( STATS , STR , " Histogram Counts " , 16 , dm_stats_hist_count_ranges , " hist_count_ranges " , " Latency histogram counts with bin ranges. " )
FIELD_F ( STATS , STR , " Histogram% " , 10 , dm_stats_hist_percent , " hist_percent " , " Relative latency histogram. " )
FIELD_F ( STATS , STR , " Histogram% " , 10 , dm_stats_hist_percent_bounds , " hist_percent_bounds " , " Relative latency histogram with bin boundaries. " )
FIELD_F ( STATS , STR , " Histogram% " , 10 , dm_stats_hist_percent_ranges , " hist_percent_ranges " , " Relative latency histogram with bin ranges. " )
2015-08-13 23:14:57 +03:00
/* Stats interval duration estimates */
2015-08-22 21:35:43 +03:00
FIELD_F ( STATS , NUM , " IntervalNs " , 10 , dm_stats_sample_interval_ns , " interval_ns " , " Sampling interval in nanoseconds. " )
2015-08-13 23:14:57 +03:00
FIELD_F ( STATS , NUM , " Interval " , 8 , dm_stats_sample_interval , " interval " , " Sampling interval. " )
/* Stats report meta-fields */
2015-08-16 21:35:06 +03:00
FIELD_F ( STATS_META , NUM , " RgID " , 4 , dm_stats_region_id , " region_id " , " Region ID. " )
2015-08-22 21:35:43 +03:00
FIELD_F ( STATS_META , SIZ , " RgStart " , 5 , dm_stats_region_start , " region_start " , " Region start. " )
FIELD_F ( STATS_META , SIZ , " RgSize " , 5 , dm_stats_region_len , " region_len " , " Region length. " )
2015-08-16 21:35:06 +03:00
FIELD_F ( STATS_META , NUM , " ArID " , 4 , dm_stats_area_id , " area_id " , " Area ID. " )
2015-08-22 21:35:43 +03:00
FIELD_F ( STATS_META , SIZ , " ArStart " , 7 , dm_stats_area_start , " area_start " , " Area offset from start of device. " )
FIELD_F ( STATS_META , SIZ , " ArSize " , 6 , dm_stats_area_len , " area_len " , " Area length. " )
FIELD_F ( STATS_META , SIZ , " ArOff " , 5 , dm_stats_area_offset , " area_offset " , " Area offset from start of region. " )
FIELD_F ( STATS_META , NUM , " #Areas " , 6 , dm_stats_area_count , " area_count " , " Area count. " )
2015-08-13 23:14:57 +03:00
FIELD_F ( STATS_META , STR , " ProgID " , 6 , dm_stats_program_id , " program_id " , " Program ID. " )
FIELD_F ( STATS_META , STR , " AuxDat " , 6 , dm_stats_aux_data , " aux_data " , " Auxiliary data. " )
2015-08-18 14:40:03 +03:00
FIELD_F ( STATS_META , STR , " Precise " , 7 , dm_stats_precise , " precise " , " Set if nanosecond precision counters are enabled. " )
FIELD_F ( STATS_META , STR , " #Bins " , 9 , dm_stats_hist_bins , " hist_bins " , " The number of histogram bins configured. " )
FIELD_F ( STATS_META , STR , " Histogram Bounds " , 16 , dm_stats_hist_bounds , " hist_bounds " , " Latency histogram bin boundaries. " )
FIELD_F ( STATS_META , STR , " Histogram Ranges " , 16 , dm_stats_hist_ranges , " hist_ranges " , " Latency histogram bin ranges. " )
2015-08-05 12:40:00 +03:00
{ 0 , 0 , 0 , 0 , " " , " " , NULL , NULL } ,
/* *INDENT-ON* */
} ;
# undef FIELD_O
# undef FIELD_F
# undef STR
# undef NUM
# undef SIZ
static const char * default_report_options = " name,major,minor,attr,open,segments,events,uuid " ;
static const char * splitname_report_options = " vg_name,lv_name,lv_layer " ;
2015-08-14 22:40:13 +03:00
/* Stats counters & derived metrics. */
2015-08-22 21:35:43 +03:00
# define RD_COUNTERS "read_count,reads_merged_count,read_sector_count,read_time,read_ticks"
# define WR_COUNTERS "write_count,writes_merged_count,write_sector_count,write_time,write_ticks"
# define IO_COUNTERS "in_progress_count,io_ticks,queue_ticks"
2015-08-14 19:42:03 +03:00
# define COUNTERS RD_COUNTERS "," WR_COUNTERS "," IO_COUNTERS
2015-08-14 22:40:13 +03:00
2015-08-22 21:35:43 +03:00
# define METRICS "reads_merged_per_sec,writes_merged_per_sec," \
" reads_per_sec,writes_per_sec, " \
" read_size_per_sec,write_size_per_sec, " \
" avg_request_size,queue_size,util, " \
" await,read_await,write_await "
2015-08-14 22:40:13 +03:00
/* Device, region and area metadata. */
# define STATS_DEV_INFO "name,region_id"
2015-08-18 14:40:03 +03:00
# define STATS_AREA_INFO "area_id,area_start,area_len"
# define STATS_AREA_INFO_FULL STATS_DEV_INFO ",region_start,region_len,area_count,area_id,area_start,area_len"
2015-08-14 22:40:13 +03:00
# define STATS_REGION_INFO STATS_DEV_INFO ",region_start,region_len,area_count,area_len"
2015-08-18 14:40:03 +03:00
/* Minimal set of fields for histogram report. */
# define STATS_HIST STATS_REGION_INFO ",util,await"
2015-08-14 22:40:13 +03:00
/* Default stats report options. */
2015-08-18 14:40:03 +03:00
static const char * _stats_default_report_options = STATS_DEV_INFO " , " STATS_AREA_INFO " , " METRICS ;
static const char * _stats_raw_report_options = STATS_DEV_INFO " , " STATS_AREA_INFO " , " COUNTERS ;
2015-08-14 22:40:13 +03:00
static const char * _stats_list_options = STATS_REGION_INFO " ,program_id " ;
2015-08-18 14:40:03 +03:00
static const char * _stats_area_list_options = STATS_AREA_INFO_FULL " ,program_id " ;
2015-09-04 01:00:44 +03:00
static const char * _stats_hist_list_options = STATS_REGION_INFO " ,hist_bins,hist_bounds " ;
static const char * _stats_hist_area_list_options = STATS_AREA_INFO_FULL " ,hist_bins,hist_bounds " ;
2015-08-18 14:40:03 +03:00
static const char * _stats_hist_options = STATS_HIST " ,hist_count_bounds " ;
static const char * _stats_hist_relative_options = STATS_HIST " ,hist_percent_bounds " ;
2015-08-05 12:40:00 +03:00
2015-08-14 01:03:46 +03:00
static int _report_init ( const struct command * cmd , const char * subcommand )
2015-08-05 12:40:00 +03:00
{
char * options = ( char * ) default_report_options ;
char * opt_fields = NULL ; /* optional fields from command line */
const char * keys = " " ;
const char * separator = " " ;
const char * selection = NULL ;
int aligned = 1 , headings = 1 , buffered = 1 , field_prefixes = 0 ;
int quoted = 1 , columns_as_rows = 0 ;
uint32_t flags = 0 ;
size_t len = 0 ;
int r = 0 ;
2015-08-14 00:30:39 +03:00
if ( cmd & & ! strcmp ( cmd - > name , " splitname " ) ) {
2015-08-05 12:40:00 +03:00
options = ( char * ) splitname_report_options ;
2015-08-14 00:30:39 +03:00
_report_type | = DR_NAME ;
}
2015-08-05 12:40:00 +03:00
2015-08-14 00:30:39 +03:00
if ( cmd & & ! strcmp ( cmd - > name , " stats " ) ) {
2015-08-14 01:03:46 +03:00
_report_type | = DR_STATS_META ;
2015-09-04 01:00:44 +03:00
if ( ! strcmp ( subcommand , " list " ) ) {
if ( ! _switches [ HISTOGRAM_ARG ] )
options = ( char * ) ( ( _switches [ VERBOSE_ARG ] )
? _stats_area_list_options
: _stats_list_options ) ;
else
options = ( char * ) ( ( _switches [ VERBOSE_ARG ] )
? _stats_hist_area_list_options
: _stats_hist_list_options ) ;
} else {
if ( _switches [ HISTOGRAM_ARG ] )
options = ( char * ) ( ( _switches [ RELATIVE_ARG ] )
? _stats_hist_relative_options
: _stats_hist_options ) ;
else
options = ( char * ) ( ( ! _switches [ RAW_ARG ] )
? _stats_default_report_options
: _stats_raw_report_options ) ;
2015-08-14 01:03:46 +03:00
_report_type | = DR_STATS ;
}
2015-08-14 00:30:39 +03:00
}
2015-08-05 12:40:00 +03:00
2015-08-14 00:30:39 +03:00
if ( cmd & & ! strcmp ( cmd - > name , " list " ) ) {
2015-08-05 12:40:00 +03:00
options = ( char * ) _stats_list_options ;
2015-08-13 23:14:57 +03:00
_report_type | = DR_STATS_META ;
2015-08-14 00:30:39 +03:00
}
2015-08-05 12:40:00 +03:00
/* emulate old dmsetup behaviour */
if ( _switches [ NOHEADINGS_ARG ] ) {
separator = " : " ;
aligned = 0 ;
headings = 0 ;
}
if ( _switches [ UNBUFFERED_ARG ] )
buffered = 0 ;
if ( _switches [ ROWS_ARG ] )
columns_as_rows = 1 ;
if ( _switches [ UNQUOTED_ARG ] )
quoted = 0 ;
if ( _switches [ NAMEPREFIXES_ARG ] ) {
aligned = 0 ;
field_prefixes = 1 ;
}
if ( _switches [ OPTIONS_ARG ] & & _string_args [ OPTIONS_ARG ] ) {
/* Count & interval forbidden for help. */
2015-08-14 00:30:39 +03:00
/* FIXME Detect "help" correctly and exit */
2015-08-05 12:40:00 +03:00
if ( strstr ( _string_args [ OPTIONS_ARG ] , " help " ) ) {
_switches [ COUNT_ARG ] = 0 ;
_count = 1 ;
_switches [ INTERVAL_ARG ] = 0 ;
2015-08-14 00:30:39 +03:00
headings = 0 ;
2015-08-05 12:40:00 +03:00
}
if ( * _string_args [ OPTIONS_ARG ] ! = ' + ' )
options = _string_args [ OPTIONS_ARG ] ;
else {
char * tmpopts ;
opt_fields = _string_args [ OPTIONS_ARG ] + 1 ;
len = strlen ( options ) + strlen ( opt_fields ) + 2 ;
if ( ! ( tmpopts = dm_malloc ( len ) ) ) {
err ( " Failed to allocate option string. " ) ;
return 0 ;
}
if ( dm_snprintf ( tmpopts , len , " %s,%s " ,
options , opt_fields ) < 0 ) {
dm_free ( tmpopts ) ;
return 0 ;
}
options = tmpopts ;
}
}
if ( _switches [ SORT_ARG ] & & _string_args [ SORT_ARG ] ) {
keys = _string_args [ SORT_ARG ] ;
buffered = 1 ;
if ( cmd & & ( ! strcmp ( cmd - > name , " status " ) | | ! strcmp ( cmd - > name , " table " ) ) ) {
err ( " --sort is not yet supported with status and table " ) ;
goto out ;
}
}
if ( _switches [ SEPARATOR_ARG ] & & _string_args [ SEPARATOR_ARG ] ) {
separator = _string_args [ SEPARATOR_ARG ] ;
aligned = 0 ;
}
if ( _switches [ SELECT_ARG ] & & _string_args [ SELECT_ARG ] )
selection = _string_args [ SELECT_ARG ] ;
if ( aligned )
flags | = DM_REPORT_OUTPUT_ALIGNED ;
if ( buffered )
flags | = DM_REPORT_OUTPUT_BUFFERED ;
if ( headings )
flags | = DM_REPORT_OUTPUT_HEADINGS ;
if ( field_prefixes )
flags | = DM_REPORT_OUTPUT_FIELD_NAME_PREFIX ;
if ( ! quoted )
flags | = DM_REPORT_OUTPUT_FIELD_UNQUOTED ;
if ( columns_as_rows )
flags | = DM_REPORT_OUTPUT_COLUMNS_AS_ROWS ;
if ( ! ( _report = dm_report_init_with_selection ( & _report_type , _report_types ,
_report_fields , options , separator , flags , keys ,
selection , NULL , NULL ) ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2015-08-05 12:40:00 +03:00
2016-02-23 23:02:36 +03:00
if ( ( _report_type & DR_TREE ) & & cmd & & ! _build_whole_deptree ( cmd ) ) {
2015-08-05 12:40:00 +03:00
err ( " Internal device dependency tree creation failed. " ) ;
goto out ;
}
if ( ! _switches [ INTERVAL_ARG ] )
_int_args [ INTERVAL_ARG ] = 1 ; /* 1s default. */
_interval = NSEC_PER_SEC * ( uint64_t ) _int_args [ INTERVAL_ARG ] ;
if ( field_prefixes )
dm_report_set_output_field_name_prefix ( _report , " dm_ " ) ;
r = 1 ;
out :
if ( len )
dm_free ( options ) ;
return r ;
}
/*
* List devices
*/
static int _ls ( CMD_ARGS )
{
if ( ( _switches [ TARGET_ARG ] & & _target ) | |
2015-08-14 00:30:39 +03:00
( _switches [ EXEC_ARG ] & & _command_to_exec ) )
2015-08-05 12:40:00 +03:00
return _status ( cmd , NULL , argc , argv , NULL , 0 ) ;
else if ( ( _switches [ TREE_ARG ] ) )
return _display_tree ( cmd , NULL , 0 , NULL , NULL , 0 ) ;
else
return _process_all ( cmd , NULL , argc , argv , 0 , _display_name ) ;
}
static int _mangle ( CMD_ARGS )
{
const char * name , * uuid ;
char * new_name = NULL , * new_uuid = NULL ;
struct dm_task * dmt ;
struct dm_info info ;
int r = 0 ;
int target_format ;
if ( names )
name = names - > name ;
else {
2015-08-14 00:30:39 +03:00
if ( ! argc & & ! _switches [ UUID_ARG ] & & ! _switches [ MAJOR_ARG ] )
2015-08-05 12:40:00 +03:00
return _process_all ( cmd , NULL , argc , argv , 0 , _mangle ) ;
2015-08-14 00:30:39 +03:00
name = argv [ 0 ] ;
2015-08-05 12:40:00 +03:00
}
if ( ! ( dmt = dm_task_create ( DM_DEVICE_STATUS ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2015-08-05 12:40:00 +03:00
if ( ! ( _set_task_device ( dmt , name , 0 ) ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2015-08-05 12:40:00 +03:00
if ( ! _switches [ CHECKS_ARG ] & & ! dm_task_enable_checks ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2015-08-05 12:40:00 +03:00
if ( ! _task_run ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2015-08-05 12:40:00 +03:00
if ( ! dm_task_get_info ( dmt , & info ) | | ! info . exists )
2015-09-06 01:56:30 +03:00
goto_out ;
2015-08-05 12:40:00 +03:00
uuid = dm_task_get_uuid ( dmt ) ;
target_format = _switches [ MANGLENAME_ARG ] ? _int_args [ MANGLENAME_ARG ]
: DEFAULT_DM_NAME_MANGLING ;
if ( target_format = = DM_STRING_MANGLING_AUTO ) {
if ( strstr ( name , " \\ x5cx " ) ) {
log_error ( " The name \" %s \" seems to be mangled more than once. "
" Manual intervention required to rename the device. " , name ) ;
goto out ;
}
if ( strstr ( uuid , " \\ x5cx " ) ) {
log_error ( " The UUID \" %s \" seems to be mangled more than once. "
" Manual intervention required to correct the device UUID. " , uuid ) ;
goto out ;
}
}
if ( target_format = = DM_STRING_MANGLING_NONE ) {
if ( ! ( new_name = dm_task_get_name_unmangled ( dmt ) ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2015-08-05 12:40:00 +03:00
if ( ! ( new_uuid = dm_task_get_uuid_unmangled ( dmt ) ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2015-08-05 12:40:00 +03:00
}
else {
if ( ! ( new_name = dm_task_get_name_mangled ( dmt ) ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2015-08-05 12:40:00 +03:00
if ( ! ( new_uuid = dm_task_get_uuid_mangled ( dmt ) ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2015-08-05 12:40:00 +03:00
}
/* We can't rename the UUID, the device must be reactivated manually. */
if ( strcmp ( uuid , new_uuid ) ) {
log_error ( " %s: %s: UUID in incorrect form. " , name , uuid ) ;
log_error ( " Unable to change device UUID. The device must be deactivated first. " ) ;
r = 0 ;
goto out ;
}
/* Nothing to do if the name is in correct form already. */
if ( ! strcmp ( name , new_name ) ) {
log_print ( " %s: %s: name %salready in correct form " , name ,
* uuid ? uuid : " [no UUID] " , * uuid ? " and UUID " : " " ) ;
r = 1 ;
goto out ;
}
else
log_print ( " %s: renaming to %s " , name , new_name ) ;
/* Rename to correct form of the name. */
r = _do_rename ( name , new_name , NULL ) ;
out :
dm_free ( new_name ) ;
dm_free ( new_uuid ) ;
dm_task_destroy ( dmt ) ;
return r ;
}
static int _stats ( CMD_ARGS ) ;
static int _bind_stats_device ( struct dm_stats * dms , const char * name )
{
if ( name & & ! dm_stats_bind_name ( dms , name ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2015-08-05 12:40:00 +03:00
else if ( _switches [ UUID_ARG ] & & ! dm_stats_bind_uuid ( dms , _uuid ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2015-08-05 12:40:00 +03:00
else if ( _switches [ MAJOR_ARG ] & & _switches [ MINOR_ARG ]
& & ! dm_stats_bind_devno ( dms , _int_args [ MAJOR_ARG ] ,
_int_args [ MINOR_ARG ] ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2015-08-05 12:40:00 +03:00
return 1 ;
}
static int _stats_clear_regions ( struct dm_stats * dms , uint64_t region_id )
{
int allregions = ( region_id = = DM_STATS_REGIONS_ALL ) ;
if ( ! dm_stats_list ( dms , NULL ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2015-08-05 12:40:00 +03:00
if ( ! dm_stats_get_nr_regions ( dms ) )
2015-09-06 01:56:30 +03:00
return 1 ;
2015-08-05 12:40:00 +03:00
dm_stats_walk_do ( dms ) {
if ( allregions )
region_id = dm_stats_get_current_region ( dms ) ;
if ( ! dm_stats_region_present ( dms , region_id ) ) {
log_error ( " No such region: % " PRIu64 " . " , region_id ) ;
2015-09-06 01:56:30 +03:00
return 0 ;
2015-08-05 12:40:00 +03:00
}
if ( ! dm_stats_clear_region ( dms , region_id ) ) {
log_error ( " Clearing statistics region % " PRIu64 " failed. " ,
region_id ) ;
2015-09-06 01:56:30 +03:00
return 0 ;
2015-08-05 12:40:00 +03:00
}
log_info ( " Cleared statistics region % " PRIu64 " . " , region_id ) ;
dm_stats_walk_next_region ( dms ) ;
} dm_stats_walk_while ( dms ) ;
2015-09-06 01:56:30 +03:00
return 1 ;
2015-08-05 12:40:00 +03:00
}
static int _stats_clear ( CMD_ARGS )
{
struct dm_stats * dms ;
uint64_t region_id ;
char * name = NULL ;
int allregions = _switches [ ALL_REGIONS_ARG ] ;
2015-08-12 23:14:00 +03:00
/* clear does not use a report */
if ( _report ) {
dm_report_free ( _report ) ;
_report = NULL ;
}
2015-08-05 12:40:00 +03:00
if ( ! _switches [ REGION_ID_ARG ] & & ! _switches [ ALL_REGIONS_ARG ] ) {
2015-08-13 20:12:56 +03:00
err ( " Please specify a --regionid or use --allregions. " ) ;
2015-08-05 12:40:00 +03:00
return 0 ;
}
if ( names )
name = names - > name ;
else {
2015-08-14 00:30:39 +03:00
if ( ! argc & & ! _switches [ UUID_ARG ] & & ! _switches [ MAJOR_ARG ] )
2015-08-05 12:40:00 +03:00
return _process_all ( cmd , subcommand , argc , argv , 0 , _stats_clear ) ;
2015-08-14 00:30:39 +03:00
name = argv [ 0 ] ;
2015-08-05 12:40:00 +03:00
}
region_id = ( allregions ) ? DM_STATS_REGIONS_ALL
: ( uint64_t ) _int_args [ REGION_ID_ARG ] ;
2015-11-09 18:02:33 +03:00
if ( ! ( dms = dm_stats_create ( DM_STATS_PROGRAM_ID ) ) )
return_0 ;
2015-08-05 12:40:00 +03:00
if ( ! _bind_stats_device ( dms , name ) )
goto_out ;
if ( ! _stats_clear_regions ( dms , region_id ) )
goto_out ;
dm_stats_destroy ( dms ) ;
return 1 ;
out :
dm_stats_destroy ( dms ) ;
return 0 ;
}
static uint64_t _factor_from_units ( char * argptr , char * unit_type )
{
return dm_units_to_factor ( argptr , unit_type , 0 , NULL ) ;
}
/**
* Parse a start , length , or area size argument in bytes from a string
* using optional units as supported by _factor_from_units ( ) .
*/
static int _size_from_string ( char * argptr , uint64_t * size , const char * name )
{
uint64_t factor ;
char * endptr = NULL , unit_type ;
if ( ! argptr )
2015-09-06 01:56:30 +03:00
return_0 ;
2015-08-05 12:40:00 +03:00
* size = strtoull ( argptr , & endptr , 10 ) ;
if ( endptr = = argptr ) {
* size = 0 ;
log_error ( " Invalid %s argument: \" %s \" " ,
name , ( * argptr ) ? argptr : " " ) ;
return 0 ;
}
if ( * endptr = = ' \0 ' ) {
* size * = 512 ;
return 1 ;
}
factor = _factor_from_units ( endptr , & unit_type ) ;
if ( factor )
* size * = factor ;
return 1 ;
}
2015-08-13 14:42:35 +03:00
/*
* FIXME : expose this from libdm - stats
*/
static uint64_t _nr_areas_from_step ( uint64_t len , int64_t step )
2015-08-05 12:40:00 +03:00
{
2015-08-17 20:31:11 +03:00
/* Default is one area. */
if ( ! step | | ! len )
return 1 ;
2015-08-13 14:42:35 +03:00
/* --areas */
if ( step < 0 )
return ( uint64_t ) ( - step ) ;
/* --areasize - cast step to unsigned as it cannot be -ve here. */
return ( len / ( step ? : len ) ) + ! ! ( len % ( uint64_t ) step ) ;
}
/*
* Create a single region starting at start and spanning len sectors ,
* or , if the segments argument is no - zero create one region for each
2015-08-13 22:54:21 +03:00
* segment present in the mapped device . Passing zero for segments ,
* start , and length will create a single segment spanning the whole
* device .
2015-08-13 14:42:35 +03:00
*/
static int _do_stats_create_regions ( struct dm_stats * dms ,
const char * name , uint64_t start ,
uint64_t len , int64_t step ,
int segments ,
const char * program_id ,
const char * aux_data )
{
2015-08-15 18:51:31 +03:00
uint64_t this_start = 0 , this_len = len , region_id = UINT64_C ( 0 ) ;
2015-09-04 01:00:44 +03:00
const char * devname = NULL , * histogram = _string_args [ BOUNDS_ARG ] ;
2015-08-18 14:40:03 +03:00
int r = 0 , precise = _switches [ PRECISE_ARG ] ;
struct dm_histogram * bounds = NULL ; /* histogram bounds */
2015-08-05 12:40:00 +03:00
char * target_type , * params ; /* unused */
struct dm_task * dmt ;
struct dm_info info ;
void * next = NULL ;
2015-08-18 14:40:03 +03:00
if ( histogram & & ! ( bounds = dm_histogram_bounds_from_string ( histogram ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2015-08-05 12:40:00 +03:00
2015-08-13 14:42:35 +03:00
if ( ! ( dmt = dm_task_create ( DM_DEVICE_TABLE ) ) ) {
2015-09-07 13:14:28 +03:00
dm_histogram_bounds_destroy ( bounds ) ;
2015-08-13 14:42:35 +03:00
dm_stats_destroy ( dms ) ;
2015-09-06 01:56:30 +03:00
return_0 ;
2015-08-13 14:42:35 +03:00
}
2015-08-05 12:40:00 +03:00
if ( ! _set_task_device ( dmt , name , 0 ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2015-08-05 12:40:00 +03:00
if ( ! dm_task_no_open_count ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2015-08-05 12:40:00 +03:00
if ( _switches [ CHECKS_ARG ] & & ! dm_task_enable_checks ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2015-08-05 12:40:00 +03:00
if ( ! _task_run ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2015-08-05 12:40:00 +03:00
if ( ! dm_task_get_info ( dmt , & info ) | | ! info . exists )
2015-09-06 01:56:30 +03:00
goto_out ;
2015-08-05 12:40:00 +03:00
if ( ! ( devname = dm_task_get_name ( dmt ) ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2015-08-05 12:40:00 +03:00
do {
2015-08-13 14:42:35 +03:00
uint64_t segment_start , segment_len ;
next = dm_get_next_target ( dmt , next , & segment_start , & segment_len ,
2015-08-05 12:40:00 +03:00
& target_type , & params ) ;
2015-08-13 14:42:35 +03:00
/* Accumulate whole-device size for nr_areas calculation. */
if ( ! segments & & ! len )
this_len + = segment_len ;
/* Segments or whole-device. */
if ( segments | | ! next ) {
/*
* this_start and this_len hold the start and length in
* sectors of the to - be - created region : this is either the
* segment start / len ( for - - segments ) , the value of the
* - - start / - - length arguments , or 0 / 0 for a default
* whole - device region ) .
*/
2015-08-13 22:54:21 +03:00
this_start = ( segments ) ? segment_start : start ;
2015-08-15 02:32:59 +03:00
this_len = ( segments ) ? segment_len : this_len ;
2015-08-13 14:42:35 +03:00
if ( ! dm_stats_create_region ( dms , & region_id ,
this_start , this_len , step ,
2015-08-18 14:40:03 +03:00
precise , bounds ,
2015-08-13 14:42:35 +03:00
program_id , aux_data ) ) {
log_error ( " %s: Could not create statistics region. " ,
devname ) ;
goto out ;
}
printf ( " %s: Created new region with " FMTu64 " area(s) as "
" region ID " FMTu64 " \n " , devname ,
_nr_areas_from_step ( this_len , step ) , region_id ) ;
2015-08-05 12:40:00 +03:00
}
} while ( next ) ;
2015-08-13 14:42:35 +03:00
r = 1 ;
2015-08-05 12:40:00 +03:00
out :
dm_task_destroy ( dmt ) ;
2015-08-13 14:42:35 +03:00
dm_stats_destroy ( dms ) ;
2015-08-18 14:40:03 +03:00
dm_histogram_bounds_destroy ( bounds ) ;
2015-08-13 14:42:35 +03:00
return r ;
2015-08-05 12:40:00 +03:00
}
static int _stats_create ( CMD_ARGS )
{
struct dm_stats * dms ;
const char * name , * aux_data = " " , * program_id = DM_STATS_PROGRAM_ID ;
uint64_t start = 0 , len = 0 , areas = 0 , area_size = 0 ;
int64_t step = 0 ;
2015-08-12 23:14:00 +03:00
/* create does not use a report */
if ( _report ) {
dm_report_free ( _report ) ;
_report = NULL ;
}
2015-08-05 12:40:00 +03:00
if ( _switches [ ALL_REGIONS_ARG ] ) {
log_error ( " Cannot use --allregions with create. " ) ;
return 0 ;
}
if ( _switches [ ALL_PROGRAMS_ARG ] ) {
log_error ( " Cannot use --allprograms with create. " ) ;
return 0 ;
}
if ( _switches [ AREAS_ARG ] & & _switches [ AREA_SIZE_ARG ] ) {
log_error ( " Please specify one of --areas and --areasize. " ) ;
return 0 ;
}
if ( _switches [ PROGRAM_ID_ARG ]
& & ! strlen ( _string_args [ PROGRAM_ID_ARG ] ) & & ! _switches [ FORCE_ARG ] ) {
log_error ( " Creating a region with no program "
" id requires --force. " ) ;
return 0 ;
}
if ( names )
name = names - > name ;
else {
2015-08-14 00:30:39 +03:00
if ( ! argc & & ! _switches [ UUID_ARG ] & & ! _switches [ MAJOR_ARG ] ) {
2015-08-13 16:42:55 +03:00
if ( ! _switches [ ALL_DEVICES_ARG ] ) {
log_error ( " Please specify device(s) or use "
" --alldevices. " ) ;
2015-08-05 12:40:00 +03:00
return 0 ;
}
return _process_all ( cmd , subcommand , argc , argv , 0 , _stats_create ) ;
}
2015-08-14 00:30:39 +03:00
name = argv [ 0 ] ;
2015-08-05 12:40:00 +03:00
}
if ( _switches [ AREAS_ARG ] )
areas = ( uint64_t ) _int_args [ AREAS_ARG ] ;
if ( _switches [ AREA_SIZE_ARG ] )
if ( ! _size_from_string ( _string_args [ AREA_SIZE_ARG ] ,
& area_size , " areasize " ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2015-08-05 12:40:00 +03:00
areas = ( areas ) ? areas : 1 ;
2015-08-13 14:42:35 +03:00
/* bytes to sectors or -(areas): promote to signed before conversion */
2015-08-05 12:40:00 +03:00
step = ( area_size ) ? ( ( int64_t ) area_size / 512 ) : - ( ( int64_t ) areas ) ;
if ( _switches [ START_ARG ] ) {
if ( ! _size_from_string ( _string_args [ START_ARG ] ,
& start , " start " ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2015-08-05 12:40:00 +03:00
}
/* bytes to sectors */
start / = 512 ;
if ( _switches [ LENGTH_ARG ] ) {
if ( ! _size_from_string ( _string_args [ LENGTH_ARG ] ,
& len , " length " ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2015-08-05 12:40:00 +03:00
}
/* bytes to sectors */
len / = 512 ;
if ( _switches [ PROGRAM_ID_ARG ] )
program_id = _string_args [ PROGRAM_ID_ARG ] ;
if ( ! strlen ( program_id ) & & ! _switches [ FORCE_ARG ] )
program_id = DM_STATS_PROGRAM_ID ;
if ( _switches [ AUX_DATA_ARG ] )
aux_data = _string_args [ AUX_DATA_ARG ] ;
2015-11-09 11:45:53 +03:00
if ( ! ( dms = dm_stats_create ( DM_STATS_PROGRAM_ID ) ) )
return_0 ;
2015-08-05 12:40:00 +03:00
if ( ! _bind_stats_device ( dms , name ) )
2015-09-06 01:56:30 +03:00
goto_bad ;
2015-08-05 12:40:00 +03:00
2015-08-18 14:39:34 +03:00
if ( _switches [ PRECISE_ARG ] ) {
if ( ! dm_stats_driver_supports_precise ( ) ) {
log_error ( " Using --precise requires driver version "
" 4.32.0 or later. " ) ;
2015-09-06 01:56:30 +03:00
goto bad ;
2015-08-18 14:39:34 +03:00
}
}
2015-09-04 01:00:44 +03:00
if ( _switches [ BOUNDS_ARG ] ) {
2015-08-18 14:40:03 +03:00
if ( ! dm_stats_driver_supports_histogram ( ) ) {
2015-09-04 01:00:44 +03:00
log_error ( " Using --bounds requires driver version "
2015-08-18 14:40:03 +03:00
" 4.32.0 or later. " ) ;
2015-09-06 01:56:30 +03:00
goto bad ;
2015-08-18 14:40:03 +03:00
}
}
2015-08-05 12:40:00 +03:00
if ( ! strlen ( program_id ) )
/* force creation of a region with no id */
dm_stats_set_program_id ( dms , 1 , NULL ) ;
2015-08-13 14:42:35 +03:00
return _do_stats_create_regions ( dms , name , start , len , step ,
_switches [ SEGMENTS_ARG ] ,
program_id , aux_data ) ;
2015-08-05 12:40:00 +03:00
2015-09-06 01:56:30 +03:00
bad :
2015-08-05 12:40:00 +03:00
dm_stats_destroy ( dms ) ;
return 0 ;
}
static int _stats_delete ( CMD_ARGS )
{
struct dm_stats * dms ;
uint64_t region_id ;
char * name = NULL ;
const char * program_id = DM_STATS_PROGRAM_ID ;
int allregions = _switches [ ALL_REGIONS_ARG ] ;
2015-09-06 01:56:30 +03:00
int r = 0 ;
2015-08-05 12:40:00 +03:00
2015-08-12 23:14:00 +03:00
/* delete does not use a report */
if ( _report ) {
dm_report_free ( _report ) ;
_report = NULL ;
}
2015-08-05 12:40:00 +03:00
if ( ! _switches [ REGION_ID_ARG ] & & ! allregions ) {
2015-08-13 20:12:56 +03:00
err ( " Please specify a --regionid or use --allregions. " ) ;
2015-08-05 12:40:00 +03:00
return 0 ;
}
if ( names )
name = names - > name ;
else {
2015-08-14 00:30:39 +03:00
if ( ! argc & & ! _switches [ UUID_ARG ] & & ! _switches [ MAJOR_ARG ] ) {
2015-08-13 16:42:55 +03:00
if ( ! _switches [ ALL_DEVICES_ARG ] ) {
log_error ( " Please specify device(s) or use "
" --alldevices. " ) ;
2015-08-05 12:40:00 +03:00
return 0 ;
}
return _process_all ( cmd , subcommand , argc , argv , 0 , _stats_delete ) ;
}
2015-08-14 00:30:39 +03:00
name = argv [ 0 ] ;
2015-08-05 12:40:00 +03:00
}
if ( _switches [ ALL_PROGRAMS_ARG ] )
program_id = DM_STATS_ALL_PROGRAMS ;
region_id = ( uint64_t ) _int_args [ REGION_ID_ARG ] ;
2015-11-09 11:45:53 +03:00
if ( ! ( dms = dm_stats_create ( program_id ) ) )
return_0 ;
2015-08-05 12:40:00 +03:00
if ( ! _bind_stats_device ( dms , name ) )
goto_out ;
if ( allregions & & ! dm_stats_list ( dms , program_id ) )
goto_out ;
2015-09-06 01:56:30 +03:00
if ( allregions & & ! dm_stats_get_nr_regions ( dms ) ) {
2015-08-05 12:40:00 +03:00
/* no regions present */
2015-09-06 01:56:30 +03:00
r = 1 ;
goto out ;
}
2015-08-05 12:40:00 +03:00
dm_stats_walk_do ( dms ) {
if ( _switches [ ALL_REGIONS_ARG ] )
region_id = dm_stats_get_current_region ( dms ) ;
if ( ! dm_stats_delete_region ( dms , region_id ) ) {
log_error ( " Could not delete statistics region. " ) ;
goto out ;
}
log_info ( " Deleted statistics region % " PRIu64 , region_id ) ;
dm_stats_walk_next_region ( dms ) ;
} dm_stats_walk_while ( dms ) ;
2015-09-06 01:56:30 +03:00
r = 1 ;
2015-08-05 12:40:00 +03:00
out :
dm_stats_destroy ( dms ) ;
2015-09-06 01:56:30 +03:00
return r ;
2015-08-05 12:40:00 +03:00
}
static int _stats_print ( CMD_ARGS )
{
struct dm_stats * dms ;
char * name , * stbuff = NULL ;
uint64_t region_id ;
unsigned clear = ( unsigned ) _switches [ CLEAR_ARG ] ;
int allregions = _switches [ ALL_REGIONS_ARG ] ;
2015-09-06 01:56:30 +03:00
int r = 0 ;
2015-08-05 12:40:00 +03:00
2015-08-12 23:14:00 +03:00
/* print does not use a report */
if ( _report ) {
dm_report_free ( _report ) ;
_report = NULL ;
}
2015-08-05 12:40:00 +03:00
if ( ! _switches [ REGION_ID_ARG ] & & ! allregions ) {
2015-08-13 20:12:56 +03:00
err ( " Please specify a --regionid or use --allregions. " ) ;
2015-08-05 12:40:00 +03:00
return 0 ;
}
if ( names )
name = names - > name ;
else {
2015-08-14 00:30:39 +03:00
if ( ! argc & & ! _switches [ UUID_ARG ] & & ! _switches [ MAJOR_ARG ] )
2015-08-05 12:40:00 +03:00
return _process_all ( cmd , subcommand , argc , argv , 0 , _stats_print ) ;
2015-08-14 00:30:39 +03:00
name = argv [ 0 ] ;
2015-08-05 12:40:00 +03:00
}
region_id = ( uint64_t ) _int_args [ REGION_ID_ARG ] ;
2015-11-09 11:45:53 +03:00
if ( ! ( dms = dm_stats_create ( DM_STATS_PROGRAM_ID ) ) )
return_0 ;
2015-08-05 12:40:00 +03:00
if ( ! _bind_stats_device ( dms , name ) )
goto_out ;
if ( ! dm_stats_list ( dms , NULL ) )
goto_out ;
2015-09-06 01:56:30 +03:00
if ( allregions & & ! dm_stats_get_nr_regions ( dms ) ) {
r = 1 ;
goto out ;
}
2015-08-05 12:40:00 +03:00
dm_stats_walk_do ( dms ) {
if ( _switches [ ALL_REGIONS_ARG ] )
region_id = dm_stats_get_current_region ( dms ) ;
if ( ! dm_stats_region_present ( dms , region_id ) ) {
log_error ( " No such region: % " PRIu64 " . " , region_id ) ;
2012-10-10 19:03:47 +04:00
goto out ;
}
2015-08-05 12:40:00 +03:00
/*FIXME: line control for large regions */
if ( ! ( stbuff = dm_stats_print_region ( dms , region_id , 0 , 0 , clear ) ) ) {
log_error ( " Could not print statistics region. " ) ;
2012-10-10 19:03:47 +04:00
goto out ;
}
2012-03-05 16:48:12 +04:00
2015-08-05 12:40:00 +03:00
printf ( " %s " , stbuff ) ;
dm_stats_buffer_destroy ( dms , stbuff ) ;
dm_stats_walk_next_region ( dms ) ;
} dm_stats_walk_while ( dms ) ;
2015-09-06 01:56:30 +03:00
r = 1 ;
2015-08-05 12:40:00 +03:00
out :
dm_stats_destroy ( dms ) ;
2015-09-06 01:56:30 +03:00
return r ;
2015-08-05 12:40:00 +03:00
}
static int _stats_report ( CMD_ARGS )
{
int r = 0 ;
struct dm_task * dmt ;
char * name = NULL ;
2015-08-14 01:03:46 +03:00
if ( _switches [ PROGRAM_ID_ARG ] )
_program_id = _string_args [ PROGRAM_ID_ARG ] ;
if ( _switches [ ALL_PROGRAMS_ARG ] )
_program_id = " " ;
2015-08-14 22:40:13 +03:00
if ( ! _switches [ VERBOSE_ARG ] & & ! strcmp ( subcommand , " list " ) )
_stats_report_by_areas = 0 ;
2015-08-05 12:40:00 +03:00
if ( names )
name = names - > name ;
2012-10-10 19:03:47 +04:00
else {
2015-08-14 00:30:39 +03:00
if ( ! argc & & ! _switches [ UUID_ARG ] & & ! _switches [ MAJOR_ARG ] )
2015-08-05 12:40:00 +03:00
return _process_all ( cmd , subcommand , argc , argv , 0 , _info ) ;
2015-08-14 00:30:39 +03:00
name = argv [ 0 ] ;
2012-10-10 19:03:47 +04:00
}
2015-08-05 12:40:00 +03:00
if ( ! ( dmt = dm_task_create ( DM_DEVICE_INFO ) ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2015-08-05 12:40:00 +03:00
if ( ! _set_task_device ( dmt , name , 0 ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2012-02-15 16:08:57 +04:00
2015-08-05 12:40:00 +03:00
if ( _switches [ CHECKS_ARG ] & & ! dm_task_enable_checks ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2012-02-15 16:08:57 +04:00
2015-08-05 12:40:00 +03:00
if ( ! _task_run ( dmt ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2015-08-05 12:40:00 +03:00
r = _display_info ( dmt ) ;
2015-09-06 01:56:30 +03:00
out :
2012-02-15 16:08:57 +04:00
dm_task_destroy ( dmt ) ;
2015-09-06 01:56:30 +03:00
2015-08-13 00:02:23 +03:00
if ( ! r & & _report ) {
dm_report_free ( _report ) ;
_report = NULL ;
}
2015-09-06 01:56:30 +03:00
2012-02-15 16:08:57 +04:00
return r ;
}
2015-08-05 12:40:00 +03:00
/*
* Command dispatch tables and usage .
*/
static int _stats_help ( CMD_ARGS ) ;
2007-01-29 21:18:41 +03:00
2001-11-21 15:47:42 +03:00
/*
2015-08-05 12:40:00 +03:00
* dmsetup stats < cmd > [ options ] [ device_name ]
* dmstats < cmd > [ options ] [ device_name ]
*
* clear [ - - regionid id ] < device_name >
* create [ - - areas nr_areas ] [ - - areasize size ]
* [ [ - - start start ] [ - - length len ] | [ - - segments ] ]
* [ - - auxdata data ] [ - - programid id ] [ < device_name > ]
* delete [ - - regionid ] < device_name >
* delete_all [ - - programid id ]
* list [ - - programid id ] [ < device_name > ]
* print [ - - clear ] [ - - programid id ] [ - - regionid id ] [ < device_name > ]
* report [ - - interval seconds ] [ - - count count ] [ - - units units ] [ - - regionid id ]
* [ - - programid id ] [ < device > ]
2001-11-21 15:47:42 +03:00
*/
2015-08-05 12:40:00 +03:00
# define AREA_OPTS "[--areas <nr_areas>] [--areasize <size>] "
# define CREATE_OPTS "[--start <start> [--length <len>]]\n\t\t" AREA_OPTS
# define ID_OPTS "[--programid <id>] [--auxdata <data> ] "
# define SELECT_OPTS "[--programid <id>] [--regionid <id>] "
# define PRINT_OPTS "[--clear] " SELECT_OPTS
# define REPORT_OPTS "[--interval <seconds>] [--count <cnt>]\n\t\t[--units <u>]" SELECT_OPTS
static struct command _stats_subcommands [ ] = {
{ " help " , " " , 0 , 0 , 0 , 0 , _stats_help } ,
{ " clear " , " --regionid <id> [<device>] " , 0 , - 1 , 1 , 0 , _stats_clear } ,
{ " create " , CREATE_OPTS " \n \t \t " ID_OPTS " [<device>] " , 0 , - 1 , 1 , 0 , _stats_create } ,
{ " delete " , " --regionid <id> <device> " , 1 , - 1 , 1 , 0 , _stats_delete } ,
2015-08-14 01:03:46 +03:00
{ " list " , " [--programid <id>] [<device>] " , 0 , - 1 , 1 , 0 , _stats_report } ,
2015-08-05 12:40:00 +03:00
{ " print " , PRINT_OPTS " [<device>] " , 0 , - 1 , 1 , 0 , _stats_print } ,
{ " report " , REPORT_OPTS " [<device>] " , 0 , - 1 , 1 , 0 , _stats_report } ,
{ " version " , " " , 0 , - 1 , 1 , 0 , _version } ,
{ NULL , NULL , 0 , 0 , 0 , 0 , NULL }
} ;
# undef AREA_OPTS
# undef CREATE_OPTS
# undef ID_OPTS
# undef PRINT_OPTS
# undef REPORT_OPTS
# undef SELECT_OPTS
static int _dmsetup_help ( CMD_ARGS ) ;
2015-07-31 18:13:45 +03:00
static struct command _dmsetup_commands [ ] = {
2015-07-31 21:09:31 +03:00
{ " help " , " [-c|-C|--columns] " , 0 , 0 , 0 , 0 , _dmsetup_help } ,
2015-07-31 18:26:38 +03:00
{ " create " , " <dev_name> \n "
" \t [-j|--major <major> -m|--minor <minor>] \n "
" \t [-U|--uid <uid>] [-G|--gid <gid>] [-M|--mode <octal_mode>] \n "
2015-09-18 15:37:50 +03:00
" \t [-u|uuid <uuid>] [--addnodeonresume|--addnodeoncreate] \n "
" \t [--readahead {[+]<sectors>|auto|none}] \n "
" \t [-n|--notable|--table {<table>|<table_file>}] " , 1 , 2 , 0 , 0 , _create } ,
{ " remove " , " [--deferred] [-f|--force] [--retry] <device> " , 0 , - 1 , 1 , 0 , _remove } ,
2015-08-05 12:40:00 +03:00
{ " remove_all " , " [-f|--force] " , 0 , 0 , 0 , 0 , _remove_all } ,
2015-09-18 15:37:50 +03:00
{ " suspend " , " [--noflush] [--nolockfs] <device> " , 0 , - 1 , 1 , 0 , _suspend } ,
{ " resume " , " [--noflush] [--nolockfs] <device> \n "
" \t [--addnodeonresume|--addnodeoncreate] \n "
" \t [--readahead {[+]<sectors>|auto|none}] " , 0 , - 1 , 1 , 0 , _resume } ,
{ " load " , " <device> [<table>|<table_file>] " , 0 , 2 , 0 , 0 , _load } ,
2015-07-31 21:09:31 +03:00
{ " clear " , " <device> " , 0 , - 1 , 1 , 0 , _clear } ,
2015-09-18 15:37:50 +03:00
{ " reload " , " <device> [<table>|<table_file>] " , 0 , 2 , 0 , 0 , _load } ,
{ " wipe_table " , " [-f|--force] [--noflush] [--nolockfs] <device> " , 1 , - 1 , 1 , 0 , _error_device } ,
2015-07-31 21:09:31 +03:00
{ " rename " , " <device> [--setuuid] <new_name_or_uuid> " , 1 , 2 , 0 , 0 , _rename } ,
{ " message " , " <device> <sector> <message> " , 2 , - 1 , 0 , 0 , _message } ,
2015-09-18 15:37:50 +03:00
{ " ls " , " [--target <target_type>] [--exec <command>] [-o <options>] [--tree] " , 0 , 0 , 0 , 0 , _ls } ,
2015-07-31 21:09:31 +03:00
{ " info " , " [<device>] " , 0 , - 1 , 1 , 0 , _info } ,
2015-09-18 15:37:50 +03:00
{ " deps " , " [-o <options>] [<device>] " , 0 , - 1 , 1 , 0 , _deps } ,
2015-08-05 12:40:00 +03:00
{ " stats " , " <command> [<options>] [<devices>] " , 1 , - 1 , 1 , 1 , _stats } ,
2015-07-31 21:09:31 +03:00
{ " status " , " [<device>] [--noflush] [--target <target_type>] " , 0 , - 1 , 1 , 0 , _status } ,
{ " table " , " [<device>] [--target <target_type>] [--showkeys] " , 0 , - 1 , 1 , 0 , _status } ,
{ " wait " , " <device> [<event_nr>] [--noflush] " , 0 , 2 , 0 , 0 , _wait } ,
{ " mknodes " , " [<device>] " , 0 , - 1 , 1 , 0 , _mknodes } ,
{ " mangle " , " [<device>] " , 0 , - 1 , 1 , 0 , _mangle } ,
{ " udevcreatecookie " , " " , 0 , 0 , 0 , 0 , _udevcreatecookie } ,
{ " udevreleasecookie " , " [<cookie>] " , 0 , 1 , 0 , 0 , _udevreleasecookie } ,
{ " udevflags " , " <cookie> " , 1 , 1 , 0 , 0 , _udevflags } ,
{ " udevcomplete " , " <cookie> " , 1 , 1 , 0 , 0 , _udevcomplete } ,
2015-09-18 15:37:50 +03:00
{ " udevcomplete_all " , " [<age_in_minutes>] " , 0 , 1 , 0 , 0 , _udevcomplete_all } ,
2015-07-31 21:09:31 +03:00
{ " udevcookies " , " " , 0 , 0 , 0 , 0 , _udevcookies } ,
{ " targets " , " " , 0 , 0 , 0 , 0 , _targets } ,
{ " version " , " " , 0 , 0 , 0 , 0 , _version } ,
{ " setgeometry " , " <device> <cyl> <head> <sect> <start> " , 5 , 5 , 0 , 0 , _setgeometry } ,
{ " splitname " , " <device> [<subsystem>] " , 1 , 2 , 0 , 0 , _splitname } ,
{ NULL , NULL , 0 , 0 , 0 , 0 , NULL }
2001-11-21 15:47:42 +03:00
} ;
2015-08-05 12:40:00 +03:00
/*
* Usage and help text .
*/
2015-08-14 00:30:39 +03:00
static void _devmap_name_usage ( FILE * out )
{
fprintf ( out , " Usage: " DEVMAP_NAME_CMD_NAME " <major> <minor> \n \n " ) ;
}
2015-08-05 12:40:00 +03:00
static void _stats_usage ( FILE * out )
{
int i ;
2015-08-14 00:30:39 +03:00
fprintf ( out , " Usage: \n \n " ) ;
fprintf ( out , " %s \n " , _base_commands [ _base_command ] . name ) ;
fprintf ( out , " [-h|--help] \n " ) ;
2015-08-05 12:40:00 +03:00
fprintf ( out , " [-v|--verbose [-v|--verbose ...]] \n " ) ;
fprintf ( out , " [--areas <nr_areas>] [--areasize <size>] \n " ) ;
fprintf ( out , " [--auxdata <data>] [--clear] \n " ) ;
fprintf ( out , " [--count <count>] [--interval <seconds>] \n " ) ;
fprintf ( out , " [-o <fields>] [-O|--sort <sort_fields>] \n " ) ;
2015-08-14 00:30:39 +03:00
fprintf ( out , " [--programid <id>] \n " ) ;
2015-08-05 12:40:00 +03:00
fprintf ( out , " [--start <start>] [--length <length>] \n " ) ;
fprintf ( out , " [--segments] [--units <units>] \n \n " ) ;
2015-08-14 00:30:39 +03:00
2015-08-05 12:40:00 +03:00
for ( i = 0 ; _stats_subcommands [ i ] . name ; i + + )
fprintf ( out , " \t %s %s \n " , _stats_subcommands [ i ] . name , _stats_subcommands [ i ] . help ) ;
2015-08-14 00:30:39 +03:00
2015-08-05 12:40:00 +03:00
fprintf ( out , " <device> may be device name or -u <uuid> or "
" -j <major> -m <minor> \n " ) ;
fprintf ( out , " <fields> are comma-separated. Use 'help -c' for list. \n " ) ;
fprintf ( out , " \n " ) ;
}
2015-07-31 18:26:38 +03:00
static void _dmsetup_usage ( FILE * out )
2001-11-21 15:47:42 +03:00
{
int i ;
2003-07-04 23:38:49 +04:00
fprintf ( out , " Usage: \n \n " ) ;
2015-08-14 00:30:39 +03:00
fprintf ( out , " %s \n "
" [--version] [-h|--help [-c|-C|--columns]] \n "
2015-09-18 15:37:50 +03:00
" [-v|--verbose [-v|--verbose ...]] [-f|--force] \n "
" [--checks] [--manglename {none|hex|auto}] \n "
" [-r|--readonly] [--noopencount] [--noflush] [--nolockfs] [--inactive] \n "
" [--udevcookie <cookie>] [--noudevrules] [--noudevsync] [--verifyudev] \n "
" [-y|--yes] [--readahead {[+]<sectors>|auto|none}] [--retry] \n "
2007-01-29 21:45:08 +03:00
" [-c|-C|--columns] [-o <fields>] [-O|--sort <sort_fields>] \n "
2014-05-29 11:38:49 +04:00
" [-S|--select <selection>] [--nameprefixes] [--noheadings] \n "
2015-08-14 00:30:39 +03:00
" [--separator <separator>] \n \n " ,
_base_commands [ _base_command ] . name ) ;
2015-07-31 18:13:45 +03:00
for ( i = 0 ; _dmsetup_commands [ i ] . name ; i + + )
fprintf ( out , " \t %s %s \n " , _dmsetup_commands [ i ] . name , _dmsetup_commands [ i ] . help ) ;
2015-08-14 00:30:39 +03:00
2004-10-01 23:11:37 +04:00
fprintf ( out , " \n <device> may be device name or -u <uuid> or "
" -j <major> -m <minor> \n " ) ;
2012-02-15 16:02:58 +04:00
fprintf ( out , " <mangling_mode> is one of 'none', 'auto' and 'hex'. \n " ) ;
2007-01-29 21:37:57 +03:00
fprintf ( out , " <fields> are comma-separated. Use 'help -c' for list. \n " ) ;
2006-04-06 20:20:40 +04:00
fprintf ( out , " Table_file contents may be supplied on stdin. \n " ) ;
2012-01-11 16:46:19 +04:00
fprintf ( out , " Options are: devno, devname, blkdevname. \n " ) ;
fprintf ( out , " Tree specific options are: ascii, utf, vt100; compact, inverted, notrunc; \n "
" blkdevname, [no]device, active, open, rw and uuid. \n " ) ;
2007-01-29 21:18:41 +03:00
fprintf ( out , " \n " ) ;
2001-11-21 15:47:42 +03:00
}
2006-10-12 19:42:25 +04:00
static void _losetup_usage ( FILE * out )
{
fprintf ( out , " Usage: \n \n " ) ;
2015-08-14 00:30:39 +03:00
fprintf ( out , " %s [-d|-a] [-e encryption] "
" [-o offset] [-f|loop_device] [file] \n \n " ,
_base_commands [ _base_command ] . name ) ;
2006-10-12 19:42:25 +04:00
}
2015-08-14 00:30:39 +03:00
static void _usage ( FILE * out )
2015-08-05 12:40:00 +03:00
{
2015-08-14 00:30:39 +03:00
switch ( _base_commands [ _base_command ] . type ) {
case DMSETUP_TYPE :
return _dmsetup_usage ( out ) ;
case LOSETUP_TYPE :
return _losetup_usage ( out ) ;
case STATS_TYPE :
return _stats_usage ( out ) ;
case DEVMAP_NAME_TYPE :
return _devmap_name_usage ( out ) ;
}
}
2015-08-05 12:40:00 +03:00
2015-08-14 00:30:39 +03:00
static int _stats_help ( CMD_ARGS )
{
_usage ( stderr ) ;
2015-08-05 12:40:00 +03:00
2015-08-14 00:30:39 +03:00
if ( _switches [ COLS_ARG ] | | ( argc & & ! strcmp ( argv [ 0 ] , " report " ) ) ) {
2015-08-05 12:40:00 +03:00
_switches [ OPTIONS_ARG ] = 1 ;
_string_args [ OPTIONS_ARG ] = ( char * ) " help " ;
_switches [ SORT_ARG ] = 0 ;
if ( _report ) {
dm_report_free ( _report ) ;
_report = NULL ;
}
2015-08-14 00:30:39 +03:00
2015-08-14 01:03:46 +03:00
( void ) _report_init ( cmd , " help " ) ;
2015-08-14 00:30:39 +03:00
if ( _report ) {
dm_report_free ( _report ) ;
_report = NULL ;
}
2015-08-05 12:40:00 +03:00
}
return 1 ;
}
2015-07-31 18:26:38 +03:00
static int _dmsetup_help ( CMD_ARGS )
2007-01-29 21:18:41 +03:00
{
2015-08-14 00:30:39 +03:00
_usage ( stderr ) ;
2007-01-29 21:18:41 +03:00
2007-01-29 21:37:57 +03:00
if ( _switches [ COLS_ARG ] ) {
_switches [ OPTIONS_ARG ] = 1 ;
_string_args [ OPTIONS_ARG ] = ( char * ) " help " ;
_switches [ SORT_ARG ] = 0 ;
2009-12-11 16:04:30 +03:00
if ( _report ) {
dm_report_free ( _report ) ;
_report = NULL ;
}
2015-08-14 01:03:46 +03:00
( void ) _report_init ( cmd , " " ) ;
2015-08-14 00:30:39 +03:00
if ( _report ) {
dm_report_free ( _report ) ;
_report = NULL ;
}
2007-01-29 21:37:57 +03:00
}
2007-01-29 21:18:41 +03:00
return 1 ;
}
2015-07-31 18:58:14 +03:00
static const struct command * _find_command ( const struct command * commands ,
const char * name )
2001-11-21 15:47:42 +03:00
{
int i ;
2015-07-31 18:13:45 +03:00
for ( i = 0 ; commands [ i ] . name ; i + + )
if ( ! strcmp ( commands [ i ] . name , name ) )
return commands + i ;
2001-11-21 15:47:42 +03:00
return NULL ;
}
2015-07-31 18:58:14 +03:00
static const struct command * _find_dmsetup_command ( const char * name )
2015-07-31 18:13:45 +03:00
{
return _find_command ( _dmsetup_commands , name ) ;
}
2015-08-05 12:40:00 +03:00
static const struct command * _find_stats_subcommand ( const char * name )
{
return _find_command ( _stats_subcommands , name ) ;
}
static int _stats ( CMD_ARGS )
{
const struct command * stats_cmd ;
if ( ! ( stats_cmd = _find_stats_subcommand ( subcommand ) ) ) {
log_error ( " Unknown stats command. " ) ;
_stats_help ( stats_cmd , NULL , argc , argv , NULL , multiple_devices ) ;
return 0 ;
}
if ( _switches [ ALL_PROGRAMS_ARG ] & & _switches [ PROGRAM_ID_ARG ] ) {
log_error ( " Please supply one of --allprograms and --programid " ) ;
return 0 ;
}
if ( _switches [ ALL_REGIONS_ARG ] & & _switches [ REGION_ID_ARG ] ) {
log_error ( " Please supply one of --allregions and --regionid " ) ;
return 0 ;
}
2015-08-14 22:40:13 +03:00
/*
* Pass the sub - command through to allow a single function to be
* used to implement several distinct sub - commands ( e . g . ' report '
* and ' list ' share a single implementation .
*/
if ( ! stats_cmd - > fn ( stats_cmd , subcommand , argc , argv , NULL ,
multiple_devices ) )
2015-09-06 01:56:30 +03:00
return_0 ;
2015-08-05 12:40:00 +03:00
return 1 ;
}
2005-10-16 18:33:22 +04:00
static int _process_tree_options ( const char * options )
{
const char * s , * end ;
struct winsize winsz ;
2007-04-27 18:52:41 +04:00
size_t len ;
2005-10-16 18:33:22 +04:00
/* Symbol set default */
if ( ! strcmp ( nl_langinfo ( CODESET ) , " UTF-8 " ) )
_tsym = & _tsym_utf ;
else
_tsym = & _tsym_ascii ;
/* Default */
_tree_switches [ TR_DEVICE ] = 1 ;
_tree_switches [ TR_TRUNCATE ] = 1 ;
/* parse */
for ( s = options ; s & & * s ; s + + ) {
len = 0 ;
for ( end = s ; * end & & * end ! = ' , ' ; end + + , len + + )
;
if ( ! strncmp ( s , " device " , len ) )
_tree_switches [ TR_DEVICE ] = 1 ;
2012-01-11 16:46:19 +04:00
else if ( ! strncmp ( s , " blkdevname " , len ) )
_tree_switches [ TR_BLKDEVNAME ] = 1 ;
2005-10-16 18:33:22 +04:00
else if ( ! strncmp ( s , " nodevice " , len ) )
_tree_switches [ TR_DEVICE ] = 0 ;
else if ( ! strncmp ( s , " status " , len ) )
_tree_switches [ TR_STATUS ] = 1 ;
else if ( ! strncmp ( s , " table " , len ) )
_tree_switches [ TR_TABLE ] = 1 ;
else if ( ! strncmp ( s , " active " , len ) )
_tree_switches [ TR_ACTIVE ] = 1 ;
else if ( ! strncmp ( s , " open " , len ) )
_tree_switches [ TR_OPENCOUNT ] = 1 ;
else if ( ! strncmp ( s , " uuid " , len ) )
_tree_switches [ TR_UUID ] = 1 ;
else if ( ! strncmp ( s , " rw " , len ) )
_tree_switches [ TR_RW ] = 1 ;
else if ( ! strncmp ( s , " utf " , len ) )
_tsym = & _tsym_utf ;
else if ( ! strncmp ( s , " vt100 " , len ) )
_tsym = & _tsym_vt100 ;
else if ( ! strncmp ( s , " ascii " , len ) )
_tsym = & _tsym_ascii ;
else if ( ! strncmp ( s , " inverted " , len ) )
_tree_switches [ TR_BOTTOMUP ] = 1 ;
else if ( ! strncmp ( s , " compact " , len ) )
_tree_switches [ TR_COMPACT ] = 1 ;
else if ( ! strncmp ( s , " notrunc " , len ) )
_tree_switches [ TR_TRUNCATE ] = 0 ;
else {
fprintf ( stderr , " Tree options not recognised: %s \n " , s ) ;
return 0 ;
}
if ( ! * end )
break ;
s = end ;
}
/* Truncation doesn't work well with vt100 drawing char */
if ( _tsym ! = & _tsym_vt100 )
2007-04-27 18:52:41 +04:00
if ( ioctl ( 1 , ( unsigned long ) TIOCGWINSZ , & winsz ) > = 0 & & winsz . ws_col > 3 )
2005-10-16 18:33:22 +04:00
_termwidth = winsz . ws_col - 3 ;
return 1 ;
}
2006-10-12 19:42:25 +04:00
/*
* Returns the full absolute path , or NULL if the path could
* not be resolved .
*/
2007-10-09 16:14:48 +04:00
static char * _get_abspath ( const char * path )
2006-10-12 19:42:25 +04:00
{
char * _path ;
# ifdef HAVE_CANONICALIZE_FILE_NAME
_path = canonicalize_file_name ( path ) ;
# else
/* FIXME Provide alternative */
2012-02-13 16:06:39 +04:00
log_error ( INTERNAL_ERROR " Unimplemented _get_abspath. " ) ;
_path = NULL ;
2006-10-12 19:42:25 +04:00
# endif
return _path ;
}
2007-10-09 16:14:48 +04:00
static char * parse_loop_device_name ( const char * dev , const char * dev_dir )
2006-10-12 19:42:25 +04:00
{
char * buf ;
2012-02-13 16:06:39 +04:00
char * device = NULL ;
2006-10-12 19:42:25 +04:00
2007-01-17 00:13:07 +03:00
if ( ! ( buf = dm_malloc ( PATH_MAX ) ) )
2015-09-06 01:56:30 +03:00
return_NULL ;
2006-10-12 19:42:25 +04:00
if ( dev [ 0 ] = = ' / ' ) {
if ( ! ( device = _get_abspath ( dev ) ) )
2015-09-06 01:56:30 +03:00
goto_bad ;
2006-10-12 19:42:25 +04:00
2007-10-09 16:14:48 +04:00
if ( strncmp ( device , dev_dir , strlen ( dev_dir ) ) )
2015-09-06 01:56:30 +03:00
goto_bad ;
2007-10-09 16:14:48 +04:00
/* If dev_dir does not end in a slash, ensure that the
following byte in the device string is " / " . */
2007-12-05 20:05:04 +03:00
if ( dev_dir [ strlen ( dev_dir ) - 1 ] ! = ' / ' & &
device [ strlen ( dev_dir ) ] ! = ' / ' )
2015-09-06 01:56:30 +03:00
goto_bad ;
2006-10-12 19:42:25 +04:00
2012-02-10 21:34:12 +04:00
if ( ! dm_strncpy ( buf , strrchr ( device , ' / ' ) + 1 , PATH_MAX ) )
2015-09-06 01:56:30 +03:00
goto_bad ;
2006-10-12 19:42:25 +04:00
dm_free ( device ) ;
} else {
/* check for device number */
2012-02-10 21:34:12 +04:00
if ( strncmp ( dev , " loop " , sizeof ( " loop " ) - 1 ) )
2015-09-06 01:56:30 +03:00
goto_bad ;
2012-02-10 21:34:12 +04:00
if ( ! dm_strncpy ( buf , dev , PATH_MAX ) )
2015-09-06 01:56:30 +03:00
goto_bad ;
2006-10-12 19:42:25 +04:00
}
return buf ;
2015-09-06 01:56:30 +03:00
bad :
2012-02-13 16:06:39 +04:00
dm_free ( device ) ;
2010-11-24 12:43:18 +03:00
dm_free ( buf ) ;
2012-02-13 16:06:39 +04:00
2006-10-12 19:42:25 +04:00
return NULL ;
}
/*
* create a table for a mapped device using the loop target .
*/
2007-01-22 18:03:57 +03:00
static int _loop_table ( char * table , size_t tlen , char * file ,
2010-07-09 19:34:40 +04:00
char * dev __attribute__ ( ( unused ) ) , off_t off )
2006-10-12 19:42:25 +04:00
{
struct stat fbuf ;
off_t size , sectors ;
int fd = - 1 ;
# ifdef HAVE_SYS_STATVFS_H
struct statvfs fsbuf ;
off_t blksize ;
# endif
if ( ! _switches [ READ_ONLY ] )
fd = open ( file , O_RDWR ) ;
if ( fd < 0 ) {
_switches [ READ_ONLY ] + + ;
fd = open ( file , O_RDONLY ) ;
}
if ( fd < 0 )
2015-09-06 01:56:30 +03:00
goto_bad ;
2006-10-12 19:42:25 +04:00
if ( fstat ( fd , & fbuf ) )
2015-09-06 01:56:30 +03:00
goto_bad ;
2006-10-12 19:42:25 +04:00
size = ( fbuf . st_size - off ) ;
sectors = size > > SECTOR_SHIFT ;
if ( _switches [ VERBOSE_ARG ] )
2015-08-13 15:10:23 +03:00
fprintf ( stderr , LOSETUP_CMD_NAME " : set loop size to %llukB "
2007-04-27 18:52:41 +04:00
" (%llu sectors) \n " , ( long long unsigned ) sectors > > 1 ,
( long long unsigned ) sectors ) ;
2006-10-12 19:42:25 +04:00
# ifdef HAVE_SYS_STATVFS_H
if ( fstatvfs ( fd , & fsbuf ) )
2015-09-06 01:56:30 +03:00
goto_bad ;
2006-10-12 19:42:25 +04:00
/* FIXME Fragment size currently unused */
blksize = fsbuf . f_frsize ;
# endif
2012-02-27 15:28:47 +04:00
if ( close ( fd ) )
2015-08-05 07:03:33 +03:00
log_sys_error ( " close " , file ) ;
2006-10-12 19:42:25 +04:00
2007-01-18 20:47:58 +03:00
if ( dm_snprintf ( table , tlen , " %llu %llu loop %s %llu \n " , 0ULL ,
2010-07-06 02:56:31 +04:00
( long long unsigned ) sectors , file , ( long long unsigned ) off ) < 0 )
2015-09-06 01:56:30 +03:00
return_0 ;
2006-10-12 19:42:25 +04:00
if ( _switches [ VERBOSE_ARG ] > 1 )
fprintf ( stderr , " Table: %s \n " , table ) ;
return 1 ;
2015-09-06 01:56:30 +03:00
bad :
2012-02-27 15:28:47 +04:00
if ( fd > - 1 & & close ( fd ) )
log_sys_error ( " close " , file ) ;
2015-09-06 01:56:30 +03:00
return_0 ;
2006-10-12 19:42:25 +04:00
}
2015-08-01 00:53:38 +03:00
static int _process_losetup_switches ( const char * base , int * argcp , char * * * argvp ,
2007-10-09 16:14:48 +04:00
const char * dev_dir )
2006-10-12 19:42:25 +04:00
{
int c ;
int encrypt_loop = 0 , delete = 0 , find = 0 , show_all = 0 ;
char * device_name = NULL ;
char * loop_file = NULL ;
off_t offset = 0 ;
# ifdef HAVE_GETOPTLONG
static struct option long_options [ ] = {
{ 0 , 0 , 0 , 0 }
} ;
# endif
optarg = 0 ;
optind = OPTIND_INIT ;
2015-08-01 00:53:38 +03:00
while ( ( c = GETOPTLONG_FN ( * argcp , * argvp , " ade:fo:v " ,
2011-02-18 19:17:56 +03:00
long_options , NULL ) ) ! = - 1 ) {
2006-10-12 19:42:25 +04:00
if ( c = = ' : ' | | c = = ' ? ' )
2015-09-06 01:56:30 +03:00
return_0 ;
2006-10-12 19:42:25 +04:00
if ( c = = ' a ' )
show_all + + ;
if ( c = = ' d ' )
delete + + ;
if ( c = = ' e ' )
encrypt_loop + + ;
if ( c = = ' f ' )
find + + ;
if ( c = = ' o ' )
offset = atoi ( optarg ) ;
if ( c = = ' v ' )
_switches [ VERBOSE_ARG ] + + ;
}
2015-08-01 00:53:38 +03:00
* argvp + = optind ;
* argcp - = optind ;
2006-10-12 19:42:25 +04:00
if ( encrypt_loop ) {
fprintf ( stderr , " %s: Sorry, cryptoloop is not yet implemented "
" in this version. \n " , base ) ;
return 0 ;
}
if ( show_all ) {
fprintf ( stderr , " %s: Sorry, show all is not yet implemented "
" in this version. \n " , base ) ;
return 0 ;
}
if ( find ) {
fprintf ( stderr , " %s: Sorry, find is not yet implemented "
" in this version. \n " , base ) ;
2015-08-01 00:53:38 +03:00
if ( ! * argcp )
2006-10-12 19:42:25 +04:00
return 0 ;
}
2015-08-01 00:53:38 +03:00
if ( ! * argcp ) {
2006-10-12 19:42:25 +04:00
fprintf ( stderr , " %s: Please specify loop_device. \n " , base ) ;
2015-08-14 00:30:39 +03:00
_usage ( stderr ) ;
2006-10-12 19:42:25 +04:00
return 0 ;
}
2015-08-01 00:53:38 +03:00
if ( ! ( device_name = parse_loop_device_name ( ( * argvp ) [ 0 ] , dev_dir ) ) ) {
2006-10-12 19:42:25 +04:00
fprintf ( stderr , " %s: Could not parse loop_device %s \n " ,
2015-08-01 00:53:38 +03:00
base , ( * argvp ) [ 0 ] ) ;
2015-08-14 00:30:39 +03:00
_usage ( stderr ) ;
2006-10-12 19:42:25 +04:00
return 0 ;
}
if ( delete ) {
2015-08-14 00:30:39 +03:00
* argcp = 1 ;
2006-10-12 19:42:25 +04:00
2015-08-14 00:30:39 +03:00
( * argvp ) [ 0 ] = device_name ;
_command = " remove " ;
2006-10-12 19:42:25 +04:00
return 1 ;
}
2015-08-01 00:53:38 +03:00
if ( * argcp ! = 2 ) {
2006-10-12 19:42:25 +04:00
fprintf ( stderr , " %s: Too few arguments \n " , base ) ;
2015-08-14 00:30:39 +03:00
_usage ( stderr ) ;
2007-02-14 18:12:16 +03:00
dm_free ( device_name ) ;
2006-10-12 19:42:25 +04:00
return 0 ;
}
/* FIXME move these to make them available to native dmsetup */
2015-08-01 00:53:38 +03:00
if ( ! ( loop_file = _get_abspath ( ( * argvp ) [ ( find ) ? 0 : 1 ] ) ) ) {
2006-10-12 19:42:25 +04:00
fprintf ( stderr , " %s: Could not parse loop file name %s \n " ,
2015-08-01 00:53:38 +03:00
base , ( * argvp ) [ 1 ] ) ;
2015-08-14 00:30:39 +03:00
_usage ( stderr ) ;
2007-02-14 18:12:16 +03:00
dm_free ( device_name ) ;
2006-10-12 19:42:25 +04:00
return 0 ;
}
_table = dm_malloc ( LOOP_TABLE_SIZE ) ;
2012-02-13 15:13:44 +04:00
if ( ! _table | |
! _loop_table ( _table , ( size_t ) LOOP_TABLE_SIZE , loop_file , device_name , offset ) ) {
2015-08-01 00:53:38 +03:00
fprintf ( stderr , " Could not build device-mapper table for %s \n " , ( * argvp ) [ 0 ] ) ;
2007-02-14 18:12:16 +03:00
dm_free ( device_name ) ;
2006-10-12 19:42:25 +04:00
return 0 ;
}
_switches [ TABLE_ARG ] + + ;
2015-08-14 00:30:39 +03:00
_command = " create " ;
( * argvp ) [ 0 ] = device_name ;
* argcp = 1 ;
2006-10-12 19:42:25 +04:00
return 1 ;
}
2012-01-11 16:46:19 +04:00
static int _process_options ( const char * options )
{
const char * s , * end ;
size_t len ;
/* Tree options are processed separately. */
if ( _switches [ TREE_ARG ] )
return _process_tree_options ( _string_args [ OPTIONS_ARG ] ) ;
/* Column options are processed separately by _report_init (called later). */
if ( _switches [ COLS_ARG ] )
return 1 ;
/* No options specified. */
if ( ! _switches [ OPTIONS_ARG ] )
return 1 ;
/* Set defaults. */
_dev_name_type = DN_DEVNO ;
/* Parse. */
for ( s = options ; s & & * s ; s + + ) {
len = 0 ;
for ( end = s ; * end & & * end ! = ' , ' ; end + + , len + + )
;
if ( ! strncmp ( s , " devno " , len ) )
_dev_name_type = DN_DEVNO ;
else if ( ! strncmp ( s , " blkdevname " , len ) )
_dev_name_type = DN_BLK ;
else if ( ! strncmp ( s , " devname " , len ) )
_dev_name_type = DN_MAP ;
else {
fprintf ( stderr , " Option not recognised: %s \n " , s ) ;
return 0 ;
}
if ( ! * end )
break ;
s = end ;
}
return 1 ;
}
2015-08-01 00:53:38 +03:00
static int _process_switches ( int * argcp , char * * * argvp , const char * dev_dir )
2002-01-03 13:39:21 +03:00
{
2012-03-02 01:56:44 +04:00
const char * base ;
char * namebase , * s ;
2005-05-16 18:53:23 +04:00
static int ind ;
2015-08-14 00:30:39 +03:00
int c , r , i ;
2002-01-03 13:39:21 +03:00
2003-11-12 20:30:32 +03:00
# ifdef HAVE_GETOPTLONG
2002-01-03 13:39:21 +03:00
static struct option long_options [ ] = {
2005-05-16 18:53:23 +04:00
{ " readonly " , 0 , & ind , READ_ONLY } ,
2015-08-13 16:42:55 +03:00
{ " alldevices " , 0 , & ind , ALL_DEVICES_ARG } ,
2015-08-05 12:40:00 +03:00
{ " allprograms " , 0 , & ind , ALL_PROGRAMS_ARG } ,
{ " allregions " , 0 , & ind , ALL_REGIONS_ARG } ,
{ " areas " , 1 , & ind , AREAS_ARG } ,
{ " areasize " , 1 , & ind , AREA_SIZE_ARG } ,
{ " auxdata " , 1 , & ind , AUX_DATA_ARG } ,
2015-09-04 01:00:44 +03:00
{ " bounds " , 1 , & ind , BOUNDS_ARG } ,
2011-07-01 18:09:19 +04:00
{ " checks " , 0 , & ind , CHECKS_ARG } ,
2015-08-05 12:40:00 +03:00
{ " clear " , 0 , & ind , CLEAR_ARG } ,
2005-05-16 18:53:23 +04:00
{ " columns " , 0 , & ind , COLS_ARG } ,
2015-07-31 23:59:34 +03:00
{ " count " , 1 , & ind , COUNT_ARG } ,
2014-08-16 03:34:48 +04:00
{ " deferred " , 0 , & ind , DEFERRED_ARG } ,
2014-05-29 11:38:49 +04:00
{ " select " , 1 , & ind , SELECT_ARG } ,
2005-05-17 00:46:46 +04:00
{ " exec " , 1 , & ind , EXEC_ARG } ,
2006-06-18 15:35:04 +04:00
{ " force " , 0 , & ind , FORCE_ARG } ,
2006-02-03 17:23:22 +03:00
{ " gid " , 1 , & ind , GID_ARG } ,
2010-03-08 19:05:07 +03:00
{ " help " , 0 , & ind , HELP_ARG } ,
2015-09-04 01:00:44 +03:00
{ " histogram " , 0 , & ind , HISTOGRAM_ARG } ,
2009-11-06 03:43:08 +03:00
{ " inactive " , 0 , & ind , INACTIVE_ARG } ,
2015-07-31 23:59:34 +03:00
{ " interval " , 1 , & ind , INTERVAL_ARG } ,
2015-08-05 12:40:00 +03:00
{ " length " , 1 , & ind , LENGTH_ARG } ,
2012-02-15 16:02:58 +04:00
{ " manglename " , 1 , & ind , MANGLENAME_ARG } ,
2005-05-16 18:53:23 +04:00
{ " major " , 1 , & ind , MAJOR_ARG } ,
{ " minor " , 1 , & ind , MINOR_ARG } ,
2006-02-03 17:23:22 +03:00
{ " mode " , 1 , & ind , MODE_ARG } ,
2008-06-06 22:53:08 +04:00
{ " nameprefixes " , 0 , & ind , NAMEPREFIXES_ARG } ,
2006-10-12 19:42:25 +04:00
{ " noflush " , 0 , & ind , NOFLUSH_ARG } ,
2005-05-16 18:53:23 +04:00
{ " noheadings " , 0 , & ind , NOHEADINGS_ARG } ,
2005-10-05 00:12:32 +04:00
{ " nolockfs " , 0 , & ind , NOLOCKFS_ARG } ,
2005-05-16 18:53:23 +04:00
{ " noopencount " , 0 , & ind , NOOPENCOUNT_ARG } ,
2015-08-05 12:40:00 +03:00
{ " nosuffix " , 0 , & ind , NOSUFFIX_ARG } ,
2005-05-16 18:53:23 +04:00
{ " notable " , 0 , & ind , NOTABLE_ARG } ,
2015-09-03 23:55:25 +03:00
{ " notimesuffix " , 0 , & ind , NOTIMESUFFIX_ARG } ,
2010-02-15 19:21:33 +03:00
{ " udevcookie " , 1 , & ind , UDEVCOOKIE_ARG } ,
2010-01-07 22:45:12 +03:00
{ " noudevrules " , 0 , & ind , NOUDEVRULES_ARG } ,
2009-07-31 21:51:45 +04:00
{ " noudevsync " , 0 , & ind , NOUDEVSYNC_ARG } ,
2005-05-16 18:53:23 +04:00
{ " options " , 1 , & ind , OPTIONS_ARG } ,
2015-08-18 14:39:34 +03:00
{ " precise " , 0 , & ind , PRECISE_ARG } ,
2015-08-05 12:40:00 +03:00
{ " programid " , 1 , & ind , PROGRAM_ID_ARG } ,
2015-08-14 19:42:03 +03:00
{ " raw " , 0 , & ind , RAW_ARG } ,
2007-11-27 23:57:05 +03:00
{ " readahead " , 1 , & ind , READAHEAD_ARG } ,
2015-08-05 12:40:00 +03:00
{ " regionid " , 1 , & ind , REGION_ID_ARG } ,
2015-08-18 14:40:03 +03:00
{ " relative " , 0 , & ind , RELATIVE_ARG } ,
2011-09-22 21:12:28 +04:00
{ " retry " , 0 , & ind , RETRY_ARG } ,
2008-06-25 02:53:48 +04:00
{ " rows " , 0 , & ind , ROWS_ARG } ,
2015-08-05 12:40:00 +03:00
{ " segments " , 0 , & ind , SEGMENTS_ARG } ,
2007-01-18 20:47:58 +03:00
{ " separator " , 1 , & ind , SEPARATOR_ARG } ,
2010-10-15 05:10:27 +04:00
{ " setuuid " , 0 , & ind , SETUUID_ARG } ,
2006-10-19 19:34:50 +04:00
{ " showkeys " , 0 , & ind , SHOWKEYS_ARG } ,
2007-01-18 20:47:58 +03:00
{ " sort " , 1 , & ind , SORT_ARG } ,
2015-08-05 12:40:00 +03:00
{ " start " , 1 , & ind , START_ARG } ,
2006-08-10 18:11:03 +04:00
{ " table " , 1 , & ind , TABLE_ARG } ,
2005-05-16 18:53:23 +04:00
{ " target " , 1 , & ind , TARGET_ARG } ,
2005-10-16 18:33:22 +04:00
{ " tree " , 0 , & ind , TREE_ARG } ,
2006-02-03 17:23:22 +03:00
{ " uid " , 1 , & ind , UID_ARG } ,
2015-08-05 12:40:00 +03:00
{ " units " , 1 , & ind , UNITS_ARG } ,
2005-05-16 18:53:23 +04:00
{ " uuid " , 1 , & ind , UUID_ARG } ,
2007-06-15 22:20:28 +04:00
{ " unbuffered " , 0 , & ind , UNBUFFERED_ARG } ,
2008-06-25 00:16:47 +04:00
{ " unquoted " , 0 , & ind , UNQUOTED_ARG } ,
2005-05-16 18:53:23 +04:00
{ " verbose " , 1 , & ind , VERBOSE_ARG } ,
2011-06-28 01:43:58 +04:00
{ " verifyudev " , 0 , & ind , VERIFYUDEV_ARG } ,
2005-05-16 18:53:23 +04:00
{ " version " , 0 , & ind , VERSION_ARG } ,
2009-09-11 19:53:57 +04:00
{ " yes " , 0 , & ind , YES_ARG } ,
2011-02-04 22:33:53 +03:00
{ " addnodeonresume " , 0 , & ind , ADD_NODE_ON_RESUME_ARG } ,
{ " addnodeoncreate " , 0 , & ind , ADD_NODE_ON_CREATE_ARG } ,
2005-08-18 23:40:19 +04:00
{ 0 , 0 , 0 , 0 }
2002-01-03 13:39:21 +03:00
} ;
2003-11-12 20:30:32 +03:00
# else
struct option long_options ;
# endif
2002-01-03 13:39:21 +03:00
/*
* Zero all the index counts .
*/
memset ( & _switches , 0 , sizeof ( _switches ) ) ;
2007-01-18 20:47:58 +03:00
memset ( & _int_args , 0 , sizeof ( _int_args ) ) ;
2007-11-29 17:44:28 +03:00
_read_ahead_flags = 0 ;
2002-01-03 13:39:21 +03:00
2015-08-01 00:53:38 +03:00
if ( ! ( namebase = strdup ( ( * argvp ) [ 0 ] ) ) ) {
2012-02-13 15:13:44 +04:00
fprintf ( stderr , " Failed to duplicate name. \n " ) ;
return 0 ;
}
2015-08-14 00:30:39 +03:00
2012-03-02 01:56:44 +04:00
base = dm_basename ( namebase ) ;
2005-03-27 15:37:46 +04:00
2015-08-14 00:30:39 +03:00
i = 0 ;
do {
if ( ! strcmp ( base , _base_commands [ i ] . name ) ) {
_base_command = _base_commands [ i ] . command ;
_base_command_type = _base_commands [ i ] . type ;
break ;
}
} while ( + + i < _num_base_commands ) ;
free ( namebase ) ;
if ( _base_command_type = = DEVMAP_NAME_TYPE ) {
2005-03-27 15:37:46 +04:00
_switches [ COLS_ARG ] + + ;
_switches [ NOHEADINGS_ARG ] + + ;
_switches [ OPTIONS_ARG ] + + ;
_switches [ MAJOR_ARG ] + + ;
_switches [ MINOR_ARG ] + + ;
2007-01-18 20:47:58 +03:00
_string_args [ OPTIONS_ARG ] = ( char * ) " name " ;
2005-03-27 15:37:46 +04:00
2015-08-01 00:53:38 +03:00
if ( * argcp = = 3 ) {
_int_args [ MAJOR_ARG ] = atoi ( ( * argvp ) [ 1 ] ) ;
_int_args [ MINOR_ARG ] = atoi ( ( * argvp ) [ 2 ] ) ;
* argcp - = 2 ;
* argvp + = 2 ;
} else if ( ( * argcp = = 2 ) & &
( 2 = = sscanf ( ( * argvp ) [ 1 ] , " %i:%i " ,
2007-01-18 20:47:58 +03:00
& _int_args [ MAJOR_ARG ] ,
& _int_args [ MINOR_ARG ] ) ) ) {
2015-08-01 00:53:38 +03:00
* argcp - = 1 ;
* argvp + = 1 ;
2005-03-27 15:37:46 +04:00
} else {
2015-08-14 00:30:39 +03:00
_usage ( stderr ) ;
2005-03-27 15:37:46 +04:00
return 0 ;
}
2015-08-14 00:30:39 +03:00
_command = " info " ;
( * argvp ) + + ;
( * argcp ) - - ;
2005-03-27 15:37:46 +04:00
return 1 ;
}
2015-08-14 00:30:39 +03:00
if ( _base_command_type = = LOSETUP_TYPE ) {
r = _process_losetup_switches ( _base_commands [ _base_command ] . name , argcp , argvp , dev_dir ) ;
2006-10-12 19:42:25 +04:00
return r ;
}
2003-11-12 20:30:32 +03:00
optarg = 0 ;
optind = OPTIND_INIT ;
2015-08-01 00:53:38 +03:00
while ( ( ind = - 1 , c = GETOPTLONG_FN ( * argcp , * argvp , " cCfG:hj:m:M:no:O:rS:u:U:vy " ,
2005-05-16 18:53:23 +04:00
long_options , NULL ) ) ! = - 1 ) {
2015-08-13 16:42:55 +03:00
if ( ind = = ALL_DEVICES_ARG )
_switches [ ALL_DEVICES_ARG ] + + ;
2015-08-05 12:40:00 +03:00
if ( ind = = ALL_PROGRAMS_ARG )
_switches [ ALL_PROGRAMS_ARG ] + + ;
if ( ind = = ALL_REGIONS_ARG )
_switches [ ALL_REGIONS_ARG ] + + ;
if ( ind = = AREAS_ARG ) {
_switches [ AREAS_ARG ] + + ;
_int_args [ AREAS_ARG ] = atoi ( optarg ) ;
}
if ( ind = = AREA_SIZE_ARG ) {
_switches [ AREA_SIZE_ARG ] + + ;
_string_args [ AREA_SIZE_ARG ] = optarg ;
}
if ( ind = = AUX_DATA_ARG ) {
_switches [ AUX_DATA_ARG ] + + ;
_string_args [ AUX_DATA_ARG ] = optarg ;
}
2006-08-11 00:53:21 +04:00
if ( c = = ' : ' | | c = = ' ? ' )
2015-09-06 01:56:30 +03:00
return_0 ;
2010-03-08 19:05:07 +03:00
if ( c = = ' h ' | | ind = = HELP_ARG )
_switches [ HELP_ARG ] + + ;
2015-09-04 01:00:44 +03:00
if ( ind = = BOUNDS_ARG ) {
_switches [ BOUNDS_ARG ] + + ;
_string_args [ BOUNDS_ARG ] = optarg ;
2015-08-18 14:40:03 +03:00
}
2015-08-05 12:40:00 +03:00
if ( ind = = CLEAR_ARG )
_switches [ CLEAR_ARG ] + + ;
2004-06-16 20:44:12 +04:00
if ( c = = ' c ' | | c = = ' C ' | | ind = = COLS_ARG )
_switches [ COLS_ARG ] + + ;
2006-06-18 15:35:04 +04:00
if ( c = = ' f ' | | ind = = FORCE_ARG )
_switches [ FORCE_ARG ] + + ;
2003-01-22 00:25:51 +03:00
if ( c = = ' r ' | | ind = = READ_ONLY )
2002-01-03 13:39:21 +03:00
_switches [ READ_ONLY ] + + ;
2015-09-04 01:00:44 +03:00
if ( ind = = HISTOGRAM_ARG )
_switches [ HISTOGRAM_ARG ] + + ;
2015-08-05 12:40:00 +03:00
if ( ind = = LENGTH_ARG ) {
_switches [ LENGTH_ARG ] + + ;
_string_args [ LENGTH_ARG ] = optarg ;
}
2003-04-04 17:22:58 +04:00
if ( c = = ' j ' | | ind = = MAJOR_ARG ) {
_switches [ MAJOR_ARG ] + + ;
2007-01-18 20:47:58 +03:00
_int_args [ MAJOR_ARG ] = atoi ( optarg ) ;
2003-04-04 17:22:58 +04:00
}
2003-01-22 00:25:51 +03:00
if ( c = = ' m ' | | ind = = MINOR_ARG ) {
2002-01-11 15:12:46 +03:00
_switches [ MINOR_ARG ] + + ;
2007-01-18 20:47:58 +03:00
_int_args [ MINOR_ARG ] = atoi ( optarg ) ;
2002-01-11 15:12:46 +03:00
}
2015-08-05 12:40:00 +03:00
if ( ind = = NOSUFFIX_ARG )
_switches [ NOSUFFIX_ARG ] + + ;
2003-11-12 20:30:32 +03:00
if ( c = = ' n ' | | ind = = NOTABLE_ARG )
_switches [ NOTABLE_ARG ] + + ;
2015-09-03 23:55:25 +03:00
if ( ind = = NOTIMESUFFIX_ARG )
_switches [ NOTIMESUFFIX_ARG ] + + ;
2005-03-27 15:37:46 +04:00
if ( c = = ' o ' | | ind = = OPTIONS_ARG ) {
_switches [ OPTIONS_ARG ] + + ;
2007-01-18 20:47:58 +03:00
_string_args [ OPTIONS_ARG ] = optarg ;
}
2015-08-05 12:40:00 +03:00
if ( ind = = PROGRAM_ID_ARG ) {
_switches [ PROGRAM_ID_ARG ] + + ;
_string_args [ PROGRAM_ID_ARG ] = optarg ;
}
2015-08-18 14:39:34 +03:00
if ( ind = = PRECISE_ARG )
_switches [ PRECISE_ARG ] + + ;
2015-08-14 19:42:03 +03:00
if ( ind = = RAW_ARG )
_switches [ RAW_ARG ] + + ;
2015-08-05 12:40:00 +03:00
if ( ind = = REGION_ID_ARG ) {
_switches [ REGION_ID_ARG ] + + ;
_int_args [ REGION_ID_ARG ] = atoi ( optarg ) ;
}
2015-08-18 14:40:03 +03:00
if ( ind = = RELATIVE_ARG )
_switches [ RELATIVE_ARG ] + + ;
2007-01-18 20:47:58 +03:00
if ( ind = = SEPARATOR_ARG ) {
_switches [ SEPARATOR_ARG ] + + ;
_string_args [ SEPARATOR_ARG ] = optarg ;
}
2015-08-05 12:40:00 +03:00
if ( ind = = UNITS_ARG ) {
_switches [ UNITS_ARG ] + + ;
_string_args [ UNITS_ARG ] = optarg ;
}
2007-01-18 20:47:58 +03:00
if ( c = = ' O ' | | ind = = SORT_ARG ) {
_switches [ SORT_ARG ] + + ;
_string_args [ SORT_ARG ] = optarg ;
2005-03-27 15:37:46 +04:00
}
2014-05-29 11:38:49 +04:00
if ( c = = ' S ' | | ind = = SELECT_ARG ) {
_switches [ SELECT_ARG ] + + ;
_string_args [ SELECT_ARG ] = optarg ;
}
2015-08-05 12:40:00 +03:00
if ( ind = = START_ARG ) {
_switches [ START_ARG ] + + ;
_string_args [ START_ARG ] = optarg ;
}
2003-01-22 00:25:51 +03:00
if ( c = = ' v ' | | ind = = VERBOSE_ARG )
_switches [ VERBOSE_ARG ] + + ;
2003-11-12 20:30:32 +03:00
if ( c = = ' u ' | | ind = = UUID_ARG ) {
_switches [ UUID_ARG ] + + ;
_uuid = optarg ;
}
2009-09-11 19:53:57 +04:00
if ( c = = ' y ' | | ind = = YES_ARG )
_switches [ YES_ARG ] + + ;
2011-02-04 22:33:53 +03:00
if ( ind = = ADD_NODE_ON_RESUME_ARG )
_switches [ ADD_NODE_ON_RESUME_ARG ] + + ;
if ( ind = = ADD_NODE_ON_CREATE_ARG )
_switches [ ADD_NODE_ON_CREATE_ARG ] + + ;
2011-07-01 18:09:19 +04:00
if ( ind = = CHECKS_ARG )
_switches [ CHECKS_ARG ] + + ;
2015-07-31 23:59:34 +03:00
if ( ind = = COUNT_ARG ) {
_switches [ COUNT_ARG ] + + ;
_int_args [ COUNT_ARG ] = atoi ( optarg ) ;
if ( _int_args [ COUNT_ARG ] < 0 ) {
log_error ( " Count must be zero or greater. " ) ;
return 0 ;
}
}
2010-02-15 19:21:33 +03:00
if ( ind = = UDEVCOOKIE_ARG ) {
_switches [ UDEVCOOKIE_ARG ] + + ;
_udev_cookie = _get_cookie_value ( optarg ) ;
}
2010-01-07 22:45:12 +03:00
if ( ind = = NOUDEVRULES_ARG )
_switches [ NOUDEVRULES_ARG ] + + ;
2009-07-31 21:51:45 +04:00
if ( ind = = NOUDEVSYNC_ARG )
_switches [ NOUDEVSYNC_ARG ] + + ;
2011-06-28 01:43:58 +04:00
if ( ind = = VERIFYUDEV_ARG )
_switches [ VERIFYUDEV_ARG ] + + ;
2006-02-03 17:23:22 +03:00
if ( c = = ' G ' | | ind = = GID_ARG ) {
_switches [ GID_ARG ] + + ;
2007-01-18 20:47:58 +03:00
_int_args [ GID_ARG ] = atoi ( optarg ) ;
2006-02-03 17:23:22 +03:00
}
if ( c = = ' U ' | | ind = = UID_ARG ) {
_switches [ UID_ARG ] + + ;
2007-01-18 20:47:58 +03:00
_int_args [ UID_ARG ] = atoi ( optarg ) ;
2006-02-03 17:23:22 +03:00
}
if ( c = = ' M ' | | ind = = MODE_ARG ) {
_switches [ MODE_ARG ] + + ;
/* FIXME Accept modes as per chmod */
2007-01-18 20:47:58 +03:00
_int_args [ MODE_ARG ] = ( int ) strtol ( optarg , NULL , 8 ) ;
2006-02-03 17:23:22 +03:00
}
2014-08-16 03:34:48 +04:00
if ( ind = = DEFERRED_ARG )
_switches [ DEFERRED_ARG ] + + ;
2012-01-20 14:58:17 +04:00
if ( ind = = EXEC_ARG ) {
2005-05-17 00:46:46 +04:00
_switches [ EXEC_ARG ] + + ;
2015-08-14 00:30:39 +03:00
_command_to_exec = optarg ;
2005-05-17 00:46:46 +04:00
}
2012-01-20 14:58:17 +04:00
if ( ind = = TARGET_ARG ) {
2005-05-16 18:53:23 +04:00
_switches [ TARGET_ARG ] + + ;
_target = optarg ;
}
2015-08-05 12:40:00 +03:00
if ( ind = = SEGMENTS_ARG )
_switches [ SEGMENTS_ARG ] + + ;
2012-01-20 14:58:17 +04:00
if ( ind = = INACTIVE_ARG )
_switches [ INACTIVE_ARG ] + + ;
2015-07-31 23:59:34 +03:00
if ( ind = = INTERVAL_ARG ) {
_switches [ INTERVAL_ARG ] + + ;
_int_args [ INTERVAL_ARG ] = atoi ( optarg ) ;
if ( _int_args [ INTERVAL_ARG ] < = 0 ) {
log_error ( " Interval must be a positive integer. " ) ;
return 0 ;
}
}
2013-02-04 23:31:56 +04:00
if ( ind = = MANGLENAME_ARG ) {
2012-02-15 16:02:58 +04:00
_switches [ MANGLENAME_ARG ] + + ;
if ( ! strcasecmp ( optarg , " none " ) )
_int_args [ MANGLENAME_ARG ] = DM_STRING_MANGLING_NONE ;
else if ( ! strcasecmp ( optarg , " auto " ) )
_int_args [ MANGLENAME_ARG ] = DM_STRING_MANGLING_AUTO ;
else if ( ! strcasecmp ( optarg , " hex " ) )
_int_args [ MANGLENAME_ARG ] = DM_STRING_MANGLING_HEX ;
else {
log_error ( " Unknown name mangling mode " ) ;
return 0 ;
}
2012-02-28 18:24:57 +04:00
dm_set_name_mangling_mode ( ( dm_string_mangling_t ) _int_args [ MANGLENAME_ARG ] ) ;
2012-02-15 16:02:58 +04:00
}
2012-01-20 14:58:17 +04:00
if ( ind = = NAMEPREFIXES_ARG )
2008-06-06 22:53:08 +04:00
_switches [ NAMEPREFIXES_ARG ] + + ;
2012-01-20 14:58:17 +04:00
if ( ind = = NOFLUSH_ARG )
2006-10-12 19:42:25 +04:00
_switches [ NOFLUSH_ARG ] + + ;
2012-01-20 14:58:17 +04:00
if ( ind = = NOHEADINGS_ARG )
2004-10-12 20:42:40 +04:00
_switches [ NOHEADINGS_ARG ] + + ;
2012-01-20 14:58:17 +04:00
if ( ind = = NOLOCKFS_ARG )
2005-10-05 00:12:32 +04:00
_switches [ NOLOCKFS_ARG ] + + ;
2012-01-20 14:58:17 +04:00
if ( ind = = NOOPENCOUNT_ARG )
2005-01-13 01:10:14 +03:00
_switches [ NOOPENCOUNT_ARG ] + + ;
2012-01-20 14:58:17 +04:00
if ( ind = = READAHEAD_ARG ) {
2007-11-27 23:57:05 +03:00
_switches [ READAHEAD_ARG ] + + ;
2007-11-29 17:44:28 +03:00
if ( ! strcasecmp ( optarg , " auto " ) )
_int_args [ READAHEAD_ARG ] = DM_READ_AHEAD_AUTO ;
else if ( ! strcasecmp ( optarg , " none " ) )
2012-01-20 14:58:17 +04:00
_int_args [ READAHEAD_ARG ] = DM_READ_AHEAD_NONE ;
2007-11-29 17:44:28 +03:00
else {
for ( s = optarg ; isspace ( * s ) ; s + + )
;
if ( * s = = ' + ' )
_read_ahead_flags = DM_READ_AHEAD_MINIMUM_FLAG ;
_int_args [ READAHEAD_ARG ] = atoi ( optarg ) ;
if ( _int_args [ READAHEAD_ARG ] < - 1 ) {
log_error ( " Negative read ahead value "
" (%d) is not understood. " ,
_int_args [ READAHEAD_ARG ] ) ;
return 0 ;
}
}
2007-11-27 23:57:05 +03:00
}
2012-01-20 14:58:17 +04:00
if ( ind = = RETRY_ARG )
2011-09-22 21:12:28 +04:00
_switches [ RETRY_ARG ] + + ;
2012-01-20 14:58:17 +04:00
if ( ind = = ROWS_ARG )
2008-06-25 02:53:48 +04:00
_switches [ ROWS_ARG ] + + ;
2012-01-20 14:58:17 +04:00
if ( ind = = SETUUID_ARG )
2010-10-15 05:10:27 +04:00
_switches [ SETUUID_ARG ] + + ;
2012-01-20 14:58:17 +04:00
if ( ind = = SHOWKEYS_ARG )
2006-10-19 19:34:50 +04:00
_switches [ SHOWKEYS_ARG ] + + ;
2012-01-20 14:58:17 +04:00
if ( ind = = TABLE_ARG ) {
2006-08-10 18:11:03 +04:00
_switches [ TABLE_ARG ] + + ;
2012-02-15 18:27:53 +04:00
if ( ! ( _table = dm_strdup ( optarg ) ) ) {
2012-02-15 18:20:59 +04:00
log_error ( " Could not allocate memory for table string. " ) ;
return 0 ;
}
2006-08-10 18:11:03 +04:00
}
2012-01-20 14:58:17 +04:00
if ( ind = = TREE_ARG )
2005-10-16 18:33:22 +04:00
_switches [ TREE_ARG ] + + ;
2012-01-20 14:58:17 +04:00
if ( ind = = UNQUOTED_ARG )
2008-06-25 00:16:47 +04:00
_switches [ UNQUOTED_ARG ] + + ;
2012-01-20 14:58:17 +04:00
if ( ind = = VERSION_ARG )
2003-07-04 23:38:49 +04:00
_switches [ VERSION_ARG ] + + ;
2002-01-11 15:12:46 +03:00
}
2002-01-03 13:39:21 +03:00
2015-08-05 10:28:35 +03:00
if ( _switches [ VERBOSE_ARG ] > 1 ) {
2003-07-04 23:38:49 +04:00
dm_log_init_verbose ( _switches [ VERBOSE_ARG ] - 1 ) ;
2015-08-05 10:28:35 +03:00
if ( _switches [ VERBOSE_ARG ] > 2 ) {
if ( ! ( _initial_timestamp = dm_timestamp_alloc ( ) ) )
stack ;
else if ( ! dm_timestamp_get ( _initial_timestamp ) )
stack ;
else
log_debug ( " Timestamp: 0.000000000 seconds " ) ;
}
}
2003-01-22 00:25:51 +03:00
2004-10-01 23:11:37 +04:00
if ( ( _switches [ MAJOR_ARG ] & & ! _switches [ MINOR_ARG ] ) | |
( ! _switches [ MAJOR_ARG ] & & _switches [ MINOR_ARG ] ) ) {
fprintf ( stderr , " Please specify both major number and "
" minor number. \n " ) ;
return 0 ;
}
2006-08-10 18:11:03 +04:00
if ( _switches [ TABLE_ARG ] & & _switches [ NOTABLE_ARG ] ) {
fprintf ( stderr , " --table and --notable are incompatible. \n " ) ;
return 0 ;
}
2011-02-04 22:33:53 +03:00
if ( _switches [ ADD_NODE_ON_RESUME_ARG ] & & _switches [ ADD_NODE_ON_CREATE_ARG ] ) {
fprintf ( stderr , " --addnodeonresume and --addnodeoncreate are incompatible. \n " ) ;
return 0 ;
}
2015-08-01 00:53:38 +03:00
* argvp + = optind ;
* argcp - = optind ;
2015-08-05 12:40:00 +03:00
2015-08-14 00:30:39 +03:00
if ( ! * argcp )
_command = NULL ;
else if ( ! strcmp ( ( * argvp ) [ 0 ] , " stats " ) ) {
_base_command = DMSETUP_STATS_CMD ;
_base_command_type = STATS_TYPE ;
_command = " stats " ;
( * argvp ) + + ;
( * argcp ) - - ;
} else if ( _base_command = = DMSTATS_CMD ) {
_command = " stats " ;
} else if ( * argcp ) {
_command = ( * argvp ) [ 0 ] ;
( * argvp ) + + ;
( * argcp ) - - ;
2015-08-05 12:40:00 +03:00
}
2002-01-03 13:39:21 +03:00
return 1 ;
}
2001-11-21 15:47:42 +03:00
2015-07-31 21:09:31 +03:00
static int _perform_command_for_all_repeatable_args ( CMD_ARGS )
{
do {
2015-08-14 00:30:39 +03:00
if ( ! cmd - > fn ( cmd , subcommand , argc , argv + + , NULL , multiple_devices ) ) {
2015-07-31 21:09:31 +03:00
fprintf ( stderr , " Command failed \n " ) ;
2015-08-14 00:30:39 +03:00
return 0 ;
2015-07-31 21:09:31 +03:00
}
2015-08-14 00:30:39 +03:00
} while ( cmd - > repeatable_cmd & & argc - - > 1 ) ;
2015-07-31 21:09:31 +03:00
2015-08-14 00:30:39 +03:00
return 1 ;
2015-07-31 21:09:31 +03:00
}
2015-08-07 18:15:21 +03:00
static int _do_report_wait ( void )
{
2015-08-09 01:59:06 +03:00
return _do_timer_wait ( ) ;
2015-08-07 18:15:21 +03:00
}
2001-11-21 15:47:42 +03:00
int main ( int argc , char * * argv )
{
2015-08-14 02:09:40 +03:00
int ret = 1 , r ;
2007-10-09 16:14:48 +04:00
const char * dev_dir ;
2011-03-02 05:44:56 +03:00
const struct command * cmd ;
2015-11-09 12:48:40 +03:00
const char * subcommand = " " ;
2011-03-02 05:44:56 +03:00
int multiple_devices ;
2005-10-16 18:33:22 +04:00
2006-08-10 18:11:03 +04:00
( void ) setlocale ( LC_ALL , " " ) ;
2001-11-21 15:47:42 +03:00
2010-02-15 19:21:33 +03:00
dev_dir = getenv ( DM_DEV_DIR_ENV_VAR_NAME ) ;
2007-10-09 16:14:48 +04:00
if ( dev_dir & & * dev_dir ) {
if ( ! dm_set_dev_dir ( dev_dir ) ) {
2007-12-05 20:05:04 +03:00
fprintf ( stderr , " Invalid DM_DEV_DIR environment variable value. \n " ) ;
2007-10-09 16:14:48 +04:00
goto out ;
}
2007-12-05 20:05:04 +03:00
} else
2007-10-09 16:14:48 +04:00
dev_dir = DEFAULT_DM_DEV_DIR ;
if ( ! _process_switches ( & argc , & argv , dev_dir ) ) {
2005-03-27 15:37:46 +04:00
fprintf ( stderr , " Couldn't process command line. \n " ) ;
2005-10-16 18:33:22 +04:00
goto out ;
2002-01-03 13:39:21 +03:00
}
2015-08-14 00:30:39 +03:00
if ( _switches [ HELP_ARG ] ) {
switch ( _base_command_type ) {
case STATS_TYPE :
if ( ( cmd = _find_stats_subcommand ( " help " ) ) )
goto doit ;
goto unknown ;
default :
if ( ( cmd = _find_dmsetup_command ( " help " ) ) )
goto doit ;
goto unknown ;
}
2010-03-08 19:05:07 +03:00
}
2003-07-04 23:38:49 +04:00
if ( _switches [ VERSION_ARG ] ) {
2015-08-14 00:30:39 +03:00
switch ( _base_command_type ) {
case STATS_TYPE :
if ( ( cmd = _find_stats_subcommand ( " version " ) ) )
goto doit ;
goto unknown ;
default :
if ( ( cmd = _find_dmsetup_command ( " version " ) ) )
goto doit ;
goto unknown ;
}
2003-07-04 23:38:49 +04:00
}
2015-08-14 00:30:39 +03:00
if ( ! _command ) {
_usage ( stderr ) ;
2005-10-16 18:33:22 +04:00
goto out ;
2001-11-21 15:47:42 +03:00
}
2015-08-14 00:30:39 +03:00
if ( ! ( cmd = _find_dmsetup_command ( _command ) ) ) {
2014-11-13 19:40:30 +03:00
unknown :
2001-11-21 15:47:42 +03:00
fprintf ( stderr , " Unknown command \n " ) ;
2015-08-14 00:30:39 +03:00
_usage ( stderr ) ;
2005-10-16 18:33:22 +04:00
goto out ;
2001-11-21 15:47:42 +03:00
}
2015-08-14 00:30:39 +03:00
if ( argc < cmd - > min_args | |
( cmd - > max_args > = 0 & & argc > cmd - > max_args ) ) {
2001-11-21 15:47:42 +03:00
fprintf ( stderr , " Incorrect number of arguments \n " ) ;
2015-08-14 00:30:39 +03:00
_usage ( stderr ) ;
2005-10-16 18:33:22 +04:00
goto out ;
2001-11-21 15:47:42 +03:00
}
2011-03-02 05:44:56 +03:00
if ( ! _switches [ COLS_ARG ] & & ! strcmp ( cmd - > name , " splitname " ) )
2009-06-04 00:44:42 +04:00
_switches [ COLS_ARG ] + + ;
2015-08-05 12:40:00 +03:00
if ( ! strcmp ( cmd - > name , " stats " ) ) {
_switches [ COLS_ARG ] + + ;
if ( ! _switches [ UNITS_ARG ] ) {
_switches [ UNITS_ARG ] + + ;
_string_args [ UNITS_ARG ] = ( char * ) " h " ;
}
}
2012-02-15 16:08:57 +04:00
if ( ! strcmp ( cmd - > name , " mangle " ) )
dm_set_name_mangling_mode ( DM_STRING_MANGLING_NONE ) ;
2013-03-12 15:37:24 +04:00
if ( ! _process_options ( _string_args [ OPTIONS_ARG ] ) ) {
fprintf ( stderr , " Couldn't process command line. \n " ) ;
goto out ;
}
2015-07-31 23:59:34 +03:00
# ifdef UDEV_SYNC_SUPPORT
if ( ! _set_up_udev_support ( dev_dir ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2015-07-31 23:59:34 +03:00
# endif
2007-01-24 21:09:07 +03:00
2015-08-14 01:03:46 +03:00
/*
* Extract subcommand ?
* dmsetup < command > < subcommand > [ args . . . ]
*/
if ( cmd - > has_subcommands ) {
subcommand = argv [ 0 ] ;
argc - - , argv + + ;
2015-11-09 12:48:40 +03:00
}
2015-08-14 01:03:46 +03:00
if ( _switches [ COLS_ARG ] & & ! _report_init ( cmd , subcommand ) )
2015-09-06 01:56:30 +03:00
goto_out ;
2015-07-31 23:59:34 +03:00
if ( _switches [ COUNT_ARG ] )
2015-08-05 12:40:00 +03:00
_count = ( ( uint32_t ) _int_args [ COUNT_ARG ] ) ? : UINT32_MAX ;
2015-07-31 23:59:34 +03:00
else if ( _switches [ INTERVAL_ARG ] )
_count = UINT32_MAX ;
2010-01-11 18:36:24 +03:00
2015-08-05 12:40:00 +03:00
if ( _switches [ UNITS_ARG ] ) {
_disp_factor = _factor_from_units ( _string_args [ UNITS_ARG ] ,
& _disp_units ) ;
if ( ! _disp_factor ) {
log_error ( " Invalid --units argument. " ) ;
goto out ;
}
}
2015-08-09 01:59:06 +03:00
/* Start interval timer. */
if ( _count > 1 )
if ( ! _start_timer ( ) )
goto_out ;
2015-07-31 23:59:34 +03:00
doit :
2015-08-14 00:30:39 +03:00
multiple_devices = ( cmd - > repeatable_cmd & & argc ! = 1 & &
( argc | | ( ! _switches [ UUID_ARG ] & & ! _switches [ MAJOR_ARG ] ) ) ) ;
2001-11-21 15:47:42 +03:00
2015-07-31 23:59:34 +03:00
do {
r = _perform_command_for_all_repeatable_args ( cmd , subcommand , argc , argv , NULL , multiple_devices ) ;
if ( _report ) {
2015-08-05 12:40:00 +03:00
/* only output headings for repeating reports */
2015-08-14 00:30:39 +03:00
if ( _int_args [ COUNT_ARG ] ! = 1 & & ! dm_report_is_empty ( _report ) )
2015-08-07 20:11:23 +03:00
dm_report_column_headings ( _report ) ;
2015-07-31 23:59:34 +03:00
dm_report_output ( _report ) ;
2015-08-14 00:30:39 +03:00
if ( _count > 1 & & r ) {
2015-07-31 23:59:34 +03:00
printf ( " \n " ) ;
2015-08-07 18:15:21 +03:00
/* wait for --interval and update timestamps */
if ( ! _do_report_wait ( ) )
goto_out ;
2015-07-31 23:59:34 +03:00
}
}
2015-08-13 00:02:23 +03:00
2015-08-14 00:30:39 +03:00
if ( ! r )
2015-08-14 02:09:40 +03:00
goto_out ;
2015-07-31 23:59:34 +03:00
} while ( - - _count ) ;
2005-10-16 18:33:22 +04:00
2015-08-14 02:09:40 +03:00
/* Success */
ret = 0 ;
2005-10-16 18:33:22 +04:00
out :
2015-07-31 23:59:34 +03:00
if ( _report )
2007-01-24 21:09:07 +03:00
dm_report_free ( _report ) ;
2007-06-11 17:20:29 +04:00
if ( _dtree )
dm_tree_free ( _dtree ) ;
2012-02-13 15:13:44 +04:00
dm_free ( _table ) ;
2015-08-05 10:28:35 +03:00
if ( _initial_timestamp )
dm_timestamp_destroy ( _initial_timestamp ) ;
2015-08-14 02:09:40 +03:00
return ret ;
2001-11-21 15:47:42 +03:00
}