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 .
2005-10-16 18:33:22 +04:00
* Copyright ( C ) 2004 - 2005 Red Hat , Inc . All rights reserved .
* Copyright ( C ) 2005 NEC Corperation
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 ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2001-11-21 15:47:42 +03:00
*/
2005-05-17 00:46:46 +04:00
# define _GNU_SOURCE
# define _FILE_OFFSET_BITS 64
2001-11-21 18:15:37 +03:00
# include "libdevmapper.h"
2004-02-24 21:50:09 +03:00
# include "log.h"
2001-11-21 15:47:42 +03:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <ctype.h>
2003-11-13 16:14:28 +03:00
# include <dirent.h>
# include <errno.h>
2003-11-12 20:30:32 +03:00
# include <unistd.h>
2005-03-27 15:37:46 +04:00
# include <libgen.h>
2005-05-17 00:46:46 +04:00
# include <sys/wait.h>
# include <unistd.h>
# include <sys/param.h>
2005-10-16 18:33:22 +04:00
# include <locale.h>
# include <langinfo.h>
# ifdef HAVE_SYS_IOCTL_H
# include <sys / ioctl.h>
# endif
# if HAVE_TERMIOS_H
# 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) \
( __extension__ \
( { long int __result ; \
do __result = ( long int ) ( expression ) ; \
while ( __result = = - 1L & & errno = = EINTR ) ; \
__result ; } ) )
# endif
2003-11-12 20:30:32 +03: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
# define LINE_SIZE 1024
2005-05-17 00:46:46 +04:00
# define ARGS_MAX 256
2001-11-21 15:47:42 +03:00
# define err(msg, x...) fprintf(stderr, msg "\n", ##x)
2002-01-03 13:39:21 +03:00
/*
* We have only very simple switches ATM .
*/
enum {
READ_ONLY = 0 ,
2004-06-16 20:44:12 +04:00
COLS_ARG ,
2005-05-17 00:46:46 +04:00
EXEC_ARG ,
2006-02-03 17:23:22 +03:00
GID_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 ,
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 ,
2003-11-12 20:30:32 +03:00
NOTABLE_ARG ,
2005-03-27 15:37:46 +04:00
OPTIONS_ARG ,
2005-05-16 18:53:23 +04:00
TARGET_ARG ,
2005-10-16 18:33:22 +04:00
TREE_ARG ,
2006-02-03 17:23:22 +03:00
UID_ARG ,
2003-11-12 20:30:32 +03:00
UUID_ARG ,
2003-01-22 00:25:51 +03:00
VERBOSE_ARG ,
2003-07-04 23:38:49 +04:00
VERSION_ARG ,
2002-01-03 13:39:21 +03:00
NUM_SWITCHES
} ;
static int _switches [ NUM_SWITCHES ] ;
2002-01-11 15:12:46 +03:00
static int _values [ NUM_SWITCHES ] ;
2003-11-12 20:30:32 +03:00
static char * _uuid ;
2005-03-27 15:37:46 +04:00
static char * _fields ;
2005-05-16 18:53:23 +04:00
static char * _target ;
2005-05-17 00:46:46 +04:00
static char * _command ;
2005-11-09 17:10:50 +03:00
static struct dm_tree * _dtree ;
2002-01-03 13:39:21 +03:00
/*
* Commands
*/
2001-11-21 15:47:42 +03:00
static int _parse_file ( struct dm_task * dmt , const char * file )
{
2004-03-19 18:52:22 +03:00
char buffer [ LINE_SIZE ] , ttype [ LINE_SIZE ] , * ptr , * comment ;
2003-11-12 20:30:32 +03:00
FILE * fp ;
2002-03-07 23:56:10 +03:00
unsigned long long start , size ;
int r = 0 , n , line = 0 ;
2001-11-21 15:47:42 +03:00
2003-11-12 20:30:32 +03:00
/* OK for empty stdin */
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
2002-03-07 23:56:10 +03:00
while ( fgets ( buffer , sizeof ( buffer ) , fp ) ) {
2001-11-21 15:47:42 +03:00
line + + ;
/* trim trailing space */
for ( ptr = buffer + strlen ( buffer ) - 1 ; ptr > = buffer ; ptr - - )
if ( ! isspace ( ( int ) * ptr ) )
break ;
ptr + + ;
* ptr = ' \0 ' ;
/* trim leading space */
2002-03-07 23:56:10 +03:00
for ( ptr = buffer ; * ptr & & isspace ( ( int ) * ptr ) ; ptr + + ) ;
2001-11-21 15:47:42 +03:00
2002-03-07 23:56:10 +03:00
if ( ! * ptr | | * ptr = = ' # ' )
continue ;
2001-11-21 15:47:42 +03:00
2004-03-19 18:52:22 +03:00
if ( sscanf ( ptr , " %llu %llu %s %n " ,
& start , & size , ttype , & n ) < 3 ) {
2002-03-07 23:56:10 +03:00
err ( " %s:%d Invalid format " , file , line ) ;
goto out ;
}
2001-11-21 15:47:42 +03:00
ptr + = n ;
if ( ( comment = strchr ( ptr , ( int ) ' # ' ) ) )
* comment = ' \0 ' ;
2002-03-07 23:56:10 +03:00
if ( ! dm_task_add_target ( dmt , start , size , ttype , ptr ) )
goto out ;
}
r = 1 ;
2001-11-21 15:47:42 +03:00
2002-03-07 23:56:10 +03:00
out :
2003-11-12 20:30:32 +03:00
if ( file )
fclose ( fp ) ;
2002-03-07 23:56:10 +03:00
return r ;
2001-11-21 15:47:42 +03:00
}
2004-10-12 20:42:40 +04:00
static void _display_info_cols_noheadings ( struct dm_task * dmt ,
struct dm_info * info )
{
const char * uuid ;
if ( ! info - > exists )
return ;
uuid = dm_task_get_uuid ( dmt ) ;
2005-03-27 15:37:46 +04:00
if ( _switches [ OPTIONS_ARG ] )
printf ( " %s \n " , dm_task_get_name ( dmt ) ) ;
else
printf ( " %s:%d:%d:%s%s%s%s:%d:%d:% " PRIu32 " :%s \n " ,
dm_task_get_name ( dmt ) ,
info - > major , info - > minor ,
info - > live_table ? " L " : " - " ,
info - > inactive_table ? " I " : " - " ,
info - > suspended ? " s " : " - " ,
info - > read_only ? " r " : " w " ,
info - > open_count , info - > target_count , info - > event_nr ,
uuid & & * uuid ? uuid : " " ) ;
2004-10-12 20:42:40 +04:00
}
2004-06-16 20:44:12 +04:00
static void _display_info_cols ( struct dm_task * dmt , struct dm_info * info )
2003-07-02 01:20:58 +04:00
{
2004-06-16 20:44:12 +04:00
static int _headings = 0 ;
2003-07-02 01:20:58 +04:00
const char * uuid ;
2004-06-16 20:44:12 +04:00
if ( ! info - > exists ) {
printf ( " Device does not exist. \n " ) ;
2003-07-02 01:20:58 +04:00
return ;
2004-06-16 20:44:12 +04:00
}
2003-07-02 01:20:58 +04:00
2004-06-16 20:44:12 +04:00
if ( ! _headings ) {
2005-03-27 15:37:46 +04:00
if ( _switches [ OPTIONS_ARG ] )
printf ( " Name \n " ) ;
else
printf ( " Name Maj Min Stat Open Targ "
" Event UUID \n " ) ;
2004-06-16 20:44:12 +04:00
_headings = 1 ;
}
2005-03-27 15:37:46 +04:00
if ( _switches [ OPTIONS_ARG ] )
printf ( " %s \n " , dm_task_get_name ( dmt ) ) ;
else {
printf ( " %-16s %3d %3d %s%s%s%s %4d %4d %6 " PRIu32 " " ,
dm_task_get_name ( dmt ) ,
info - > major , info - > minor ,
info - > live_table ? " L " : " - " ,
info - > inactive_table ? " I " : " - " ,
info - > suspended ? " s " : " - " ,
info - > read_only ? " r " : " w " ,
info - > open_count , info - > target_count , info - > event_nr ) ;
if ( ( uuid = dm_task_get_uuid ( dmt ) ) & & * uuid )
printf ( " %s " , uuid ) ;
2004-06-16 20:44:12 +04:00
2005-03-27 15:37:46 +04:00
printf ( " \n " ) ;
}
2004-06-16 20:44:12 +04:00
}
static void _display_info_long ( struct dm_task * dmt , struct dm_info * info )
{
const char * uuid ;
if ( ! info - > exists ) {
2003-07-02 01:20:58 +04:00
printf ( " Device does not exist. \n " ) ;
return ;
}
printf ( " Name: %s \n " , dm_task_get_name ( dmt ) ) ;
printf ( " State: %s%s \n " ,
2004-06-16 20:44:12 +04:00
info - > suspended ? " SUSPENDED " : " ACTIVE " ,
info - > read_only ? " (READ-ONLY) " : " " ) ;
2003-07-02 01:20:58 +04: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 ) )
2005-03-27 15:37:46 +04: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 if ( _switches [ NOHEADINGS_ARG ] )
_display_info_cols_noheadings ( dmt , & info ) ;
else
_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 ) )
return 0 ;
} else if ( _switches [ UUID_ARG ] ) {
if ( ! dm_task_set_uuid ( dmt , _uuid ) )
return 0 ;
} else if ( _switches [ MAJOR_ARG ] & & _switches [ MINOR_ARG ] ) {
if ( ! dm_task_set_major ( dmt , _values [ MAJOR_ARG ] ) | |
! dm_task_set_minor ( dmt , _values [ MINOR_ARG ] ) )
return 0 ;
} else if ( ! optional ) {
fprintf ( stderr , " No device specified. \n " ) ;
return 0 ;
}
return 1 ;
}
static int _load ( int argc , char * * argv , void * data )
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 ] ) {
if ( argc = = 1 ) {
err ( " Please specify device. \n " ) ;
return 0 ;
}
name = argv [ 1 ] ;
argc - - ;
argv + + ;
} else if ( argc > 2 ) {
err ( " Too many command line arguments. \n " ) ;
return 0 ;
}
2001-11-21 15:47:42 +03:00
2004-10-01 23:11:37 +04:00
if ( argc = = 2 )
file = argv [ 1 ] ;
2002-03-12 01:44:36 +03:00
2004-10-01 23:11:37 +04:00
if ( ! ( dmt = dm_task_create ( DM_DEVICE_RELOAD ) ) )
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 ) )
2002-01-03 13:39:21 +03:00
goto out ;
2004-10-01 23:11:37 +04:00
if ( ! _switches [ NOTABLE_ARG ] & & ! _parse_file ( dmt , file ) )
2003-04-04 17:22:58 +04:00
goto out ;
2004-10-01 23:11:37 +04:00
if ( _switches [ READ_ONLY ] & & ! dm_task_set_ro ( dmt ) )
2002-01-11 15:12:46 +03:00
goto out ;
2005-01-13 01:10:14 +03:00
if ( _switches [ NOOPENCOUNT_ARG ] & & ! dm_task_no_open_count ( dmt ) )
goto out ;
2001-11-21 15:47:42 +03:00
if ( ! dm_task_run ( dmt ) )
goto out ;
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
2002-03-07 23:56:10 +03:00
out :
2001-11-21 15:47:42 +03:00
dm_task_destroy ( dmt ) ;
return r ;
}
2003-09-16 18:13:51 +04:00
static int _create ( int argc , char * * argv , void * data )
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 ;
2001-11-21 15:47:42 +03:00
2004-10-01 23:11:37 +04:00
if ( argc = = 3 )
file = argv [ 2 ] ;
if ( ! ( dmt = dm_task_create ( DM_DEVICE_CREATE ) ) )
2003-11-12 20:30:32 +03:00
return 0 ;
2004-10-01 23:11:37 +04:00
if ( ! dm_task_set_name ( dmt , argv [ 1 ] ) )
goto out ;
if ( _switches [ UUID_ARG ] & & ! dm_task_set_uuid ( dmt , _uuid ) )
goto out ;
if ( ! _switches [ NOTABLE_ARG ] & & ! _parse_file ( dmt , file ) )
goto out ;
if ( _switches [ READ_ONLY ] & & ! dm_task_set_ro ( dmt ) )
goto out ;
if ( _switches [ MAJOR_ARG ] & & ! dm_task_set_major ( dmt , _values [ MAJOR_ARG ] ) )
goto out ;
if ( _switches [ MINOR_ARG ] & & ! dm_task_set_minor ( dmt , _values [ MINOR_ARG ] ) )
goto out ;
2006-02-03 17:23:22 +03:00
if ( _switches [ UID_ARG ] & & ! dm_task_set_uid ( dmt , _values [ UID_ARG ] ) )
goto out ;
if ( _switches [ GID_ARG ] & & ! dm_task_set_gid ( dmt , _values [ GID_ARG ] ) )
goto out ;
if ( _switches [ MODE_ARG ] & & ! dm_task_set_mode ( dmt , _values [ MODE_ARG ] ) )
goto out ;
2005-01-13 01:10:14 +03:00
if ( _switches [ NOOPENCOUNT_ARG ] & & ! dm_task_no_open_count ( dmt ) )
goto out ;
2004-10-01 23:11:37 +04:00
if ( ! dm_task_run ( dmt ) )
goto out ;
r = 1 ;
if ( _switches [ VERBOSE_ARG ] )
2005-03-27 15:37:46 +04:00
r = _display_info ( dmt ) ;
2004-10-01 23:11:37 +04:00
out :
dm_task_destroy ( dmt ) ;
return r ;
2001-11-21 15:47:42 +03:00
}
2003-09-16 18:13:51 +04:00
static int _rename ( int argc , char * * argv , void * data )
2002-01-11 15:12:46 +03:00
{
int r = 0 ;
struct dm_task * dmt ;
2002-03-07 23:56:10 +03:00
if ( ! ( dmt = dm_task_create ( DM_DEVICE_RENAME ) ) )
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 */
if ( ! _set_task_device ( dmt , ( argc = = 3 ) ? argv [ 1 ] : NULL , 0 ) )
2002-03-07 23:56:10 +03:00
goto out ;
2002-01-11 15:12:46 +03:00
2004-10-01 23:11:37 +04:00
if ( ! dm_task_set_newname ( dmt , argv [ argc - 1 ] ) )
2002-01-11 15:12:46 +03:00
goto out ;
2005-01-13 01:10:14 +03:00
if ( _switches [ NOOPENCOUNT_ARG ] & & ! dm_task_no_open_count ( dmt ) )
goto out ;
2002-03-07 23:56:10 +03:00
if ( ! dm_task_run ( dmt ) )
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
2002-03-07 23:56:10 +03:00
out :
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
2004-06-09 00:34:40 +04:00
static int _message ( int argc , char * * argv , void * data )
{
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 ;
if ( ! ( dmt = dm_task_create ( DM_DEVICE_TARGET_MSG ) ) )
return 0 ;
2004-10-01 23:11:37 +04:00
if ( _switches [ UUID_ARG ] | | _switches [ MAJOR_ARG ] ) {
if ( ! _set_task_device ( dmt , NULL , 0 ) )
goto out ;
} else {
if ( ! _set_task_device ( dmt , argv [ 1 ] , 0 ) )
goto out ;
argc - - ;
argv + + ;
}
2004-06-09 00:34:40 +04:00
2006-01-31 17:50:38 +03:00
if ( ! dm_task_set_sector ( dmt , ( uint64_t ) atoll ( argv [ 1 ] ) ) )
2004-06-09 00:34:40 +04:00
goto out ;
2004-10-01 23:11:37 +04:00
argc - = 2 ;
argv + = 2 ;
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 ;
str = malloc ( sz ) ;
2004-06-10 20:14:16 +04:00
memset ( str , 0 , sz ) ;
2004-06-09 00:34:40 +04:00
for ( i = 0 ; i < argc ; i + + ) {
if ( i )
strcat ( str , " " ) ;
strcat ( str , argv [ i ] ) ;
}
if ( ! dm_task_set_message ( dmt , str ) )
goto out ;
free ( str ) ;
2005-01-13 01:10:14 +03:00
if ( _switches [ NOOPENCOUNT_ARG ] & & ! dm_task_no_open_count ( dmt ) )
goto out ;
2004-06-09 00:34:40 +04:00
if ( ! dm_task_run ( dmt ) )
goto out ;
r = 1 ;
out :
dm_task_destroy ( dmt ) ;
return r ;
}
2003-09-16 18:13:51 +04:00
static int _version ( int argc , char * * argv , void * data )
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 ) ) )
2002-01-15 18:21:57 +03:00
return 0 ;
printf ( " Driver version: %s \n " , version ) ;
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
{
int r = 0 ;
struct dm_task * dmt ;
if ( ! ( dmt = dm_task_create ( task ) ) )
return 0 ;
2004-10-01 23:11:37 +04:00
if ( ! _set_task_device ( dmt , name , 0 ) )
2001-11-21 15:47:42 +03:00
goto out ;
2004-01-23 17:09:33 +03:00
if ( event_nr & & ! dm_task_set_event_nr ( dmt , event_nr ) )
goto out ;
2005-01-13 01:10:14 +03:00
if ( _switches [ NOOPENCOUNT_ARG ] & & ! dm_task_no_open_count ( dmt ) )
goto out ;
2005-10-05 00:12:32 +04:00
if ( _switches [ NOLOCKFS_ARG ] & & ! dm_task_skip_lockfs ( dmt ) )
goto out ;
2001-11-21 15:47:42 +03:00
r = dm_task_run ( dmt ) ;
2003-07-04 23:38:49 +04:00
if ( r & & display & & _switches [ VERBOSE_ARG ] )
2005-03-27 15:37:46 +04:00
r = _display_info ( dmt ) ;
2003-07-02 01:20:58 +04:00
2002-03-07 23:56:10 +03:00
out :
2001-11-21 15:47:42 +03:00
dm_task_destroy ( dmt ) ;
return r ;
}
2003-09-16 18:13:51 +04:00
static int _remove_all ( int argc , char * * argv , void * data )
2002-03-07 23:56:10 +03:00
{
2004-01-23 17:09:33 +03:00
return _simple ( DM_DEVICE_REMOVE_ALL , " " , 0 , 0 ) ;
2002-03-07 23:56:10 +03:00
}
2003-09-16 18:13:51 +04:00
static int _remove ( int argc , char * * argv , void * data )
2001-11-21 15:47:42 +03:00
{
2004-10-01 23:11:37 +04:00
return _simple ( DM_DEVICE_REMOVE , argc > 1 ? argv [ 1 ] : NULL , 0 , 0 ) ;
2001-11-21 15:47:42 +03:00
}
2003-09-16 18:13:51 +04:00
static int _suspend ( int argc , char * * argv , void * data )
2001-11-21 15:47:42 +03:00
{
2004-10-01 23:11:37 +04:00
return _simple ( DM_DEVICE_SUSPEND , argc > 1 ? argv [ 1 ] : NULL , 0 , 1 ) ;
2001-11-21 15:47:42 +03:00
}
2003-09-16 18:13:51 +04:00
static int _resume ( int argc , char * * argv , void * data )
2001-11-21 15:47:42 +03:00
{
2004-10-01 23:11:37 +04:00
return _simple ( DM_DEVICE_RESUME , argc > 1 ? argv [ 1 ] : NULL , 0 , 1 ) ;
2003-07-02 01:20:58 +04:00
}
2003-09-16 18:13:51 +04:00
static int _clear ( int argc , char * * argv , void * data )
2003-07-02 01:20:58 +04:00
{
2004-10-01 23:11:37 +04:00
return _simple ( DM_DEVICE_CLEAR , argc > 1 ? argv [ 1 ] : NULL , 0 , 1 ) ;
2001-11-21 15:47:42 +03:00
}
2003-09-16 18:13:51 +04:00
static int _wait ( int argc , char * * argv , void * data )
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 ] ) {
if ( argc = = 1 ) {
err ( " No device specified. " ) ;
return 0 ;
}
name = argv [ 1 ] ;
argc - - , argv + + ;
}
return _simple ( DM_DEVICE_WAITEVENT , name ,
2006-01-31 17:50:38 +03:00
( argc > 1 ) ? ( uint32_t ) atoi ( argv [ argc - 1 ] ) : 0 , 1 ) ;
2002-05-03 15:55:58 +04:00
}
2003-09-16 18:13:51 +04:00
static int _process_all ( int argc , char * * argv ,
2003-11-13 16:14:28 +03:00
int ( * fn ) ( int argc , char * * argv , void * data ) )
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 ) ) )
return 0 ;
2003-11-13 16:14:28 +03:00
if ( ! dm_task_run ( dmt ) ) {
r = 0 ;
2003-09-16 18:13:51 +04: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 ;
2003-09-16 18:13:51 +04:00
goto out ;
2003-11-13 16:14:28 +03:00
}
2003-09-16 18:13:51 +04:00
if ( ! names - > dev ) {
printf ( " No devices found \n " ) ;
goto out ;
}
do {
names = ( void * ) names + next ;
2003-11-13 16:14:28 +03:00
if ( ! fn ( argc , argv , ( void * ) names ) )
2003-09-16 18:13:51 +04:00
r = 0 ;
next = names - > next ;
} while ( next ) ;
out :
dm_task_destroy ( dmt ) ;
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 ) ;
}
2005-05-17 00:46:46 +04:00
static int _mknodes ( int argc , char * * argv , void * data )
{
2005-10-17 02:57:20 +04:00
return dm_mknodes ( argc > 1 ? argv [ 1 ] : 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 )
return 0 ;
2005-10-17 02:57:20 +04:00
if ( ! dm_mknodes ( name ) )
2005-05-17 00:46:46 +04:00
return 0 ;
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 )
2005-05-17 00:46:46 +04:00
return 0 ;
if ( ! argc ) {
c = _command ;
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 ;
return 0 ;
}
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 ) ;
exit ( 127 ) ;
} else if ( pid < ( pid_t ) 0 )
return 0 ;
TEMP_FAILURE_RETRY ( waitpid ( pid , NULL , 0 ) ) ;
return 1 ;
}
2003-09-16 18:13:51 +04:00
static int _status ( int argc , char * * argv , void * data )
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 ;
char * params ;
int cmd ;
2003-11-13 16:14:28 +03:00
struct dm_names * names = ( struct dm_names * ) data ;
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
if ( data )
name = names - > name ;
2004-10-01 23:11:37 +04:00
else {
if ( argc = = 1 & & ! _switches [ UUID_ARG ] & & ! _switches [ MAJOR_ARG ] )
return _process_all ( argc , argv , _status ) ;
if ( argc = = 2 )
name = argv [ 1 ] ;
}
2002-05-03 15:55:58 +04:00
2003-11-13 16:14:28 +03:00
if ( ! strcmp ( argv [ 0 ] , " table " ) )
2002-05-10 19:25:38 +04:00
cmd = DM_DEVICE_TABLE ;
2003-11-13 16:14:28 +03:00
else
cmd = DM_DEVICE_STATUS ;
2002-05-03 15:55:58 +04:00
2005-05-16 20:04:34 +04:00
if ( ! strcmp ( argv [ 0 ] , " ls " ) )
ls_only = 1 ;
2002-05-03 15:55:58 +04:00
if ( ! ( dmt = dm_task_create ( cmd ) ) )
return 0 ;
2004-10-01 23:11:37 +04:00
if ( ! _set_task_device ( dmt , name , 0 ) )
2002-05-03 15:55:58 +04:00
goto out ;
2005-01-13 01:10:14 +03:00
if ( _switches [ NOOPENCOUNT_ARG ] & & ! dm_task_no_open_count ( dmt ) )
goto out ;
2002-05-03 15:55:58 +04:00
if ( ! dm_task_run ( dmt ) )
goto out ;
2005-10-26 21:50:15 +04:00
if ( ! dm_task_get_info ( dmt , & info ) | | ! info . exists )
goto out ;
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 ) {
2005-05-17 00:46:46 +04:00
if ( ! _switches [ EXEC_ARG ] | | ! _command | |
_switches [ VERBOSE_ARG ] )
_display_dev ( dmt , name ) ;
2005-05-16 20:04:34 +04:00
next = NULL ;
2005-05-17 00:46:46 +04:00
} else if ( ! _switches [ EXEC_ARG ] | | ! _command | |
_switches [ VERBOSE_ARG ] ) {
2005-05-16 20:04:34 +04:00
if ( ! matched & & _switches [ VERBOSE_ARG ] )
_display_info ( dmt ) ;
if ( data & & ! _switches [ VERBOSE_ARG ] )
printf ( " %s: " , name ) ;
if ( target_type ) {
printf ( " % " PRIu64 " % " PRIu64 " %s %s " ,
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 ) ;
2005-05-16 20:04:34 +04:00
if ( data & & _switches [ VERBOSE_ARG ] & & matched & & ! ls_only )
2003-09-16 18:13:51 +04:00
printf ( " \n " ) ;
2005-05-17 00:46:46 +04:00
if ( matched & & _switches [ EXEC_ARG ] & & _command & & ! _exec_command ( name ) )
goto out ;
2002-05-03 15:55:58 +04:00
r = 1 ;
out :
dm_task_destroy ( dmt ) ;
return r ;
}
2004-01-23 17:37:47 +03:00
/* Show target names and their version numbers */
static int _targets ( int argc , char * * argv , void * data )
{
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 ) ) )
return 0 ;
if ( ! dm_task_run ( dmt ) )
goto out ;
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 ] ) ;
target = ( void * ) target + target - > next ;
} while ( last_target ! = target ) ;
r = 1 ;
out :
dm_task_destroy ( dmt ) ;
return r ;
}
2003-09-16 18:13:51 +04:00
static int _info ( int argc , char * * argv , void * data )
2001-11-21 15:47:42 +03:00
{
int r = 0 ;
struct dm_task * dmt ;
2003-11-13 16:14:28 +03:00
struct dm_names * names = ( struct dm_names * ) data ;
2004-03-30 18:31:58 +04:00
char * name = NULL ;
2003-09-16 18:13:51 +04:00
if ( data )
name = names - > name ;
2004-10-01 23:11:37 +04:00
else {
if ( argc = = 1 & & ! _switches [ UUID_ARG ] & & ! _switches [ MAJOR_ARG ] )
return _process_all ( argc , argv , _info ) ;
if ( argc = = 2 )
name = argv [ 1 ] ;
}
2001-11-21 15:47:42 +03:00
2004-03-30 18:31:58 +04:00
if ( ! ( dmt = dm_task_create ( DM_DEVICE_INFO ) ) )
2001-11-21 15:47:42 +03:00
return 0 ;
2004-10-01 23:11:37 +04:00
if ( ! _set_task_device ( dmt , name , 0 ) )
2001-11-21 15:47:42 +03:00
goto out ;
2005-01-13 01:10:14 +03:00
if ( _switches [ NOOPENCOUNT_ARG ] & & ! dm_task_no_open_count ( dmt ) )
goto out ;
2001-11-21 15:47:42 +03:00
if ( ! dm_task_run ( dmt ) )
goto out ;
2005-03-27 15:37:46 +04:00
r = _display_info ( dmt ) ;
2001-11-21 15:47:42 +03:00
2002-03-07 23:56:10 +03:00
out :
2001-11-21 15:47:42 +03:00
dm_task_destroy ( dmt ) ;
return r ;
}
2003-09-16 18:13:51 +04:00
static int _deps ( int argc , char * * argv , void * data )
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 ;
2003-11-13 16:14:28 +03:00
struct dm_names * names = ( struct dm_names * ) data ;
2004-10-01 23:11:37 +04:00
char * name = NULL ;
2003-09-16 18:13:51 +04:00
if ( data )
name = names - > name ;
2004-10-01 23:11:37 +04:00
else {
if ( argc = = 1 & & ! _switches [ UUID_ARG ] & & ! _switches [ MAJOR_ARG ] )
return _process_all ( argc , argv , _deps ) ;
if ( argc = = 2 )
name = argv [ 1 ] ;
}
2002-03-06 17:38:25 +03:00
if ( ! ( dmt = dm_task_create ( DM_DEVICE_DEPS ) ) )
return 0 ;
2004-10-01 23:11:37 +04:00
if ( ! _set_task_device ( dmt , name , 0 ) )
2002-03-06 17:38:25 +03:00
goto out ;
2005-01-13 01:10:14 +03:00
if ( _switches [ NOOPENCOUNT_ARG ] & & ! dm_task_no_open_count ( dmt ) )
goto out ;
2002-03-06 17:38:25 +03:00
if ( ! dm_task_run ( dmt ) )
goto out ;
2002-03-06 22:42:23 +03:00
if ( ! dm_task_get_info ( dmt , & info ) )
goto out ;
2002-03-06 17:38:25 +03:00
if ( ! ( deps = dm_task_get_deps ( dmt ) ) )
goto out ;
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
2003-09-16 18:13:51 +04:00
if ( data & & ! _switches [ VERBOSE_ARG ] )
printf ( " %s: " , name ) ;
2002-03-06 17:38:25 +03:00
printf ( " %d dependencies \t : " , deps - > count ) ;
for ( i = 0 ; i < deps - > count ; i + + )
printf ( " (%d, %d) " ,
( int ) MAJOR ( deps - > device [ i ] ) ,
( int ) MINOR ( deps - > device [ i ] ) ) ;
printf ( " \n " ) ;
2003-09-16 18:13:51 +04:00
if ( data & & _switches [ VERBOSE_ARG ] )
printf ( " \n " ) ;
2002-03-06 17:38:25 +03:00
r = 1 ;
2002-03-07 23:56:10 +03:00
out :
2002-03-06 17:38:25 +03:00
dm_task_destroy ( dmt ) ;
return r ;
}
2003-09-16 18:13:51 +04:00
static int _display_name ( int argc , char * * argv , void * data )
2003-07-02 01:20:58 +04:00
{
2003-11-13 16:14:28 +03:00
struct dm_names * names = ( struct dm_names * ) data ;
2003-07-02 01:20:58 +04:00
2003-09-16 18:13:51 +04:00
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 */
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 ;
static void _out_char ( char c )
{
/* Only first UTF-8 char counts */
_cur_x + = ( ( c & 0xc0 ) ! = 0x80 ) ;
if ( ! _tree_switches [ TR_TRUNCATE ] ) {
putchar ( c ) ;
return ;
}
/* Truncation? */
if ( _cur_x < = _termwidth )
putchar ( c ) ;
if ( _cur_x = = _termwidth + 1 & & ( ( c & 0xc0 ) ! = 0x80 ) ) {
if ( _last_char | | ( c & 0x80 ) ) {
putchar ( ' . ' ) ;
putchar ( ' . ' ) ;
putchar ( ' . ' ) ;
} else {
_last_char = c ;
_cur_x - - ;
}
}
}
static void _out_string ( const char * str )
{
while ( * str )
_out_char ( * str + + ) ;
}
/* 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 ;
}
static void _out_prefix ( int depth )
{
int x , d ;
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 + + ? " , " : " [ " ) ;
( void ) _out_int ( info - > open_count ) ;
}
if ( _tree_switches [ TR_UUID ] ) {
_out_string ( attr + + ? " , " : " [ " ) ;
_out_string ( uuid & & * uuid ? uuid : " " ) ;
}
if ( attr )
_out_char ( ' ] ' ) ;
}
2005-11-09 17:10:50 +03:00
static void _display_tree_node ( struct dm_tree_node * node , unsigned depth ,
2005-10-16 18:33:22 +04:00
unsigned first_child , unsigned last_child ,
unsigned has_children )
{
int offset ;
const char * name ;
const struct dm_info * info ;
int first_on_line = 0 ;
/* 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
if ( ( ! name | | ! * name ) & & ! _tree_switches [ TR_DEVICE ] )
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
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 ;
// FIXME _display_tree_targets(name, depth + 2);
}
}
/*
* Walk the dependency tree
*/
2005-11-09 17:10:50 +03:00
static void _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 ,
next_child ? 0 : 1 , has_children ) ;
if ( has_children )
_tree_walk_children ( child , depth + 1 ) ;
first_child = 0 ;
}
}
static int _add_dep ( int argc , char * * argv , void * data )
{
struct dm_names * names = ( struct dm_names * ) data ;
2005-11-09 17:10:50 +03:00
if ( ! dm_tree_add_dev ( _dtree , MAJOR ( names - > dev ) , MINOR ( names - > dev ) ) )
2005-10-16 18:33:22 +04:00
return 0 ;
return 1 ;
}
/*
* Create and walk dependency tree
*/
static int _tree ( int argc , char * * argv , void * data )
{
2005-11-09 17:10:50 +03:00
if ( ! ( _dtree = dm_tree_create ( ) ) )
2005-10-16 18:33:22 +04:00
return 0 ;
if ( ! _process_all ( argc , argv , _add_dep ) )
return 0 ;
2005-11-09 17:10:50 +03:00
_tree_walk_children ( dm_tree_find_node ( _dtree , 0 , 0 ) , 0 ) ;
2005-10-16 18:33:22 +04:00
2005-11-09 17:10:50 +03:00
dm_tree_free ( _dtree ) ;
2005-10-16 18:33:22 +04:00
return 1 ;
}
/*
* List devices
*/
2003-09-16 18:13:51 +04:00
static int _ls ( int argc , char * * argv , void * data )
{
2005-05-17 00:46:46 +04:00
if ( ( _switches [ TARGET_ARG ] & & _target ) | |
( _switches [ EXEC_ARG ] & & _command ) )
2005-05-16 20:04:34 +04:00
return _status ( argc , argv , data ) ;
2005-10-16 18:33:22 +04:00
else if ( ( _switches [ TREE_ARG ] ) )
return _tree ( argc , argv , data ) ;
2005-05-16 20:04:34 +04:00
else
return _process_all ( argc , argv , _display_name ) ;
2003-07-02 01:20:58 +04:00
}
2001-11-21 15:47:42 +03:00
/*
* dispatch table
*/
2003-09-16 18:13:51 +04:00
typedef int ( * command_fn ) ( int argc , char * * argv , void * data ) ;
2001-11-21 15:47:42 +03:00
struct command {
2003-01-22 00:25:51 +03:00
const char * name ;
const char * help ;
2002-03-12 01:44:36 +03:00
int min_args ;
int max_args ;
2001-11-21 15:47:42 +03:00
command_fn fn ;
} ;
static struct command _commands [ ] = {
2004-10-01 23:11:37 +04:00
{ " create " , " <dev_name> [-j|--major <major> -m|--minor <minor>] \n "
2006-02-03 17:23:22 +03:00
" \t [-U|--uid <uid>] [-G|--gid <gid>] [-M|--mode <octal_mode>] \n "
2004-10-01 23:11:37 +04:00
" \t [-u|uuid <uuid>] [--notable] [<table_file>] " ,
2003-11-12 20:30:32 +03:00
1 , 2 , _create } ,
2004-10-01 23:11:37 +04:00
{ " remove " , " <device> " , 0 , 1 , _remove } ,
2002-03-12 01:44:36 +03:00
{ " remove_all " , " " , 0 , 0 , _remove_all } ,
2004-10-01 23:11:37 +04:00
{ " suspend " , " <device> " , 0 , 1 , _suspend } ,
{ " resume " , " <device> " , 0 , 1 , _resume } ,
{ " load " , " <device> [<table_file>] " , 0 , 2 , _load } ,
{ " clear " , " <device> " , 0 , 1 , _clear } ,
{ " reload " , " <device> [<table_file>] " , 0 , 2 , _load } ,
{ " rename " , " <device> <new_name> " , 1 , 2 , _rename } ,
{ " message " , " <device> <sector> <message> " , 2 , - 1 , _message } ,
2005-10-16 18:33:22 +04:00
{ " ls " , " [--target <target_type>] [--exec <command>] [--tree] " , 0 , 0 , _ls } ,
2004-10-01 23:11:37 +04:00
{ " info " , " [<device>] " , 0 , 1 , _info } ,
{ " deps " , " [<device>] " , 0 , 1 , _deps } ,
2005-05-16 18:53:23 +04:00
{ " status " , " [<device>] [--target <target_type>] " , 0 , 1 , _status } ,
{ " table " , " [<device>] [--target <target_type>] " , 0 , 1 , _status } ,
2004-10-01 23:11:37 +04:00
{ " wait " , " <device> [<event_nr>] " , 0 , 2 , _wait } ,
{ " mknodes " , " [<device>] " , 0 , 1 , _mknodes } ,
2004-01-23 17:37:47 +03:00
{ " targets " , " " , 0 , 0 , _targets } ,
2002-03-12 01:44:36 +03:00
{ " version " , " " , 0 , 0 , _version } ,
{ NULL , NULL , 0 , 0 , NULL }
2001-11-21 15:47:42 +03:00
} ;
2003-04-04 17:22:58 +04:00
static void _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 " ) ;
fprintf ( out , " dmsetup [--version] [-v|--verbose [-v|--verbose ...]] \n "
2005-10-05 00:12:32 +04:00
" [-r|--readonly] [--noopencount] [--nolockfs] \n \n " ) ;
2001-11-21 15:47:42 +03:00
for ( i = 0 ; _commands [ i ] . name ; i + + )
2002-03-07 23:56:10 +03:00
fprintf ( out , " \t %s %s \n " , _commands [ i ] . name , _commands [ i ] . help ) ;
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 " ) ;
fprintf ( out , " Table_file contents may be supplied on stdin. \n \n " ) ;
2001-11-21 15:47:42 +03:00
return ;
}
2002-01-03 13:39:21 +03:00
static struct command * _find_command ( const char * name )
2001-11-21 15:47:42 +03:00
{
int i ;
for ( i = 0 ; _commands [ i ] . name ; i + + )
if ( ! strcmp ( _commands [ i ] . name , name ) )
return _commands + i ;
return NULL ;
}
2005-10-16 18:33:22 +04:00
static int _process_tree_options ( const char * options )
{
const char * s , * end ;
struct winsize winsz ;
int len ;
/* 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 ;
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 )
if ( ioctl ( 1 , TIOCGWINSZ , & winsz ) > = 0 & & winsz . ws_col > 3 )
_termwidth = winsz . ws_col - 3 ;
return 1 ;
}
2002-01-03 13:39:21 +03:00
static int _process_switches ( int * argc , char * * * argv )
{
2005-03-27 15:37:46 +04:00
char * base , * namebase ;
2005-05-16 18:53:23 +04:00
static int ind ;
2002-10-09 00:16:44 +04:00
int c ;
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 } ,
{ " columns " , 0 , & ind , COLS_ARG } ,
2005-05-17 00:46:46 +04:00
{ " exec " , 1 , & ind , EXEC_ARG } ,
2006-02-03 17:23:22 +03:00
{ " gid " , 1 , & ind , GID_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 } ,
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 } ,
{ " notable " , 0 , & ind , NOTABLE_ARG } ,
{ " options " , 1 , & ind , OPTIONS_ARG } ,
{ " 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 } ,
2005-05-16 18:53:23 +04:00
{ " uuid " , 1 , & ind , UUID_ARG } ,
{ " verbose " , 1 , & ind , VERBOSE_ARG } ,
{ " version " , 0 , & ind , VERSION_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 ) ) ;
2002-01-11 15:12:46 +03:00
memset ( & _values , 0 , sizeof ( _values ) ) ;
2002-01-03 13:39:21 +03:00
2005-03-27 15:37:46 +04:00
namebase = strdup ( ( * argv ) [ 0 ] ) ;
base = basename ( namebase ) ;
if ( ! strcmp ( base , " devmap_name " ) ) {
free ( namebase ) ;
_switches [ COLS_ARG ] + + ;
_switches [ NOHEADINGS_ARG ] + + ;
_switches [ OPTIONS_ARG ] + + ;
_switches [ MAJOR_ARG ] + + ;
_switches [ MINOR_ARG ] + + ;
_fields = ( char * ) " name " ;
if ( * argc = = 3 ) {
_values [ MAJOR_ARG ] = atoi ( ( * argv ) [ 1 ] ) ;
_values [ MINOR_ARG ] = atoi ( ( * argv ) [ 2 ] ) ;
* argc - = 2 ;
* argv + = 2 ;
} else if ( ( * argc = = 2 ) & &
( 2 = = sscanf ( ( * argv ) [ 1 ] , " %i:%i " ,
& _values [ MAJOR_ARG ] ,
& _values [ MINOR_ARG ] ) ) ) {
* argc - = 1 ;
* argv + = 1 ;
} else {
fprintf ( stderr , " Usage: devmap_name <major> <minor> \n " ) ;
return 0 ;
}
( * argv ) [ 0 ] = ( char * ) " info " ;
return 1 ;
}
free ( namebase ) ;
2003-11-12 20:30:32 +03:00
optarg = 0 ;
optind = OPTIND_INIT ;
2006-02-03 17:23:22 +03:00
while ( ( ind = - 1 , c = GETOPTLONG_FN ( * argc , * argv , " cCGj:m:Mno:ru:Uv " ,
2005-05-16 18:53:23 +04:00
long_options , NULL ) ) ! = - 1 ) {
2004-06-16 20:44:12 +04:00
if ( c = = ' c ' | | c = = ' C ' | | ind = = COLS_ARG )
_switches [ COLS_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 ] + + ;
2003-04-04 17:22:58 +04:00
if ( c = = ' j ' | | ind = = MAJOR_ARG ) {
_switches [ MAJOR_ARG ] + + ;
_values [ MAJOR_ARG ] = atoi ( optarg ) ;
}
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 ] + + ;
_values [ MINOR_ARG ] = atoi ( optarg ) ;
}
2003-11-12 20:30:32 +03:00
if ( c = = ' n ' | | ind = = NOTABLE_ARG )
_switches [ NOTABLE_ARG ] + + ;
2005-03-27 15:37:46 +04:00
if ( c = = ' o ' | | ind = = OPTIONS_ARG ) {
_switches [ OPTIONS_ARG ] + + ;
_fields = 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 ;
}
2006-02-03 17:23:22 +03:00
if ( c = = ' G ' | | ind = = GID_ARG ) {
_switches [ GID_ARG ] + + ;
_values [ GID_ARG ] = atoi ( optarg ) ;
}
if ( c = = ' U ' | | ind = = UID_ARG ) {
_switches [ UID_ARG ] + + ;
_values [ UID_ARG ] = atoi ( optarg ) ;
}
if ( c = = ' M ' | | ind = = MODE_ARG ) {
_switches [ MODE_ARG ] + + ;
/* FIXME Accept modes as per chmod */
_values [ MODE_ARG ] = ( int ) strtol ( optarg , NULL , 8 ) ;
}
2005-05-17 00:46:46 +04:00
if ( ( ind = = EXEC_ARG ) ) {
_switches [ EXEC_ARG ] + + ;
_command = optarg ;
}
2005-05-16 18:53:23 +04:00
if ( ( ind = = TARGET_ARG ) ) {
_switches [ TARGET_ARG ] + + ;
_target = optarg ;
}
2004-10-12 20:42:40 +04:00
if ( ( ind = = NOHEADINGS_ARG ) )
_switches [ NOHEADINGS_ARG ] + + ;
2005-10-05 00:12:32 +04:00
if ( ( ind = = NOLOCKFS_ARG ) )
_switches [ NOLOCKFS_ARG ] + + ;
2005-01-13 01:10:14 +03:00
if ( ( ind = = NOOPENCOUNT_ARG ) )
_switches [ NOOPENCOUNT_ARG ] + + ;
2005-10-16 18:33:22 +04:00
if ( ( ind = = TREE_ARG ) )
_switches [ TREE_ARG ] + + ;
2003-07-04 23:38:49 +04:00
if ( ( ind = = VERSION_ARG ) )
_switches [ VERSION_ARG ] + + ;
2002-01-11 15:12:46 +03:00
}
2002-01-03 13:39:21 +03:00
2003-07-04 23:38:49 +04:00
if ( _switches [ VERBOSE_ARG ] > 1 )
dm_log_init_verbose ( _switches [ VERBOSE_ARG ] - 1 ) ;
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 ;
}
2005-10-16 18:33:22 +04:00
if ( _switches [ COLS_ARG ] & & _switches [ OPTIONS_ARG ] & &
strcmp ( _fields , " name " ) ) {
2005-03-27 15:37:46 +04:00
fprintf ( stderr , " Only -o name is supported so far. \n " ) ;
return 0 ;
}
2005-10-16 18:33:22 +04:00
if ( _switches [ TREE_ARG ] & & ! _process_tree_options ( _fields ) )
return 0 ;
2002-01-03 13:39:21 +03:00
* argv + = optind ;
* argc - = optind ;
return 1 ;
}
2001-11-21 15:47:42 +03:00
int main ( int argc , char * * argv )
{
struct command * c ;
2005-10-16 18:33:22 +04:00
int r = 1 ;
( void ) setlocale ( LC_ALL , " " ) ;
2001-11-21 15:47:42 +03:00
2002-01-03 13:39:21 +03:00
if ( ! _process_switches ( & argc , & argv ) ) {
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
}
2003-07-04 23:38:49 +04:00
if ( _switches [ VERSION_ARG ] ) {
c = _find_command ( " version " ) ;
goto doit ;
}
2002-01-15 18:21:57 +03:00
if ( argc = = 0 ) {
2001-11-21 15:47:42 +03:00
_usage ( stderr ) ;
2005-10-16 18:33:22 +04:00
goto out ;
2001-11-21 15:47:42 +03:00
}
2002-01-03 13:39:21 +03:00
if ( ! ( c = _find_command ( argv [ 0 ] ) ) ) {
2001-11-21 15:47:42 +03:00
fprintf ( stderr , " Unknown command \n " ) ;
_usage ( stderr ) ;
2005-10-16 18:33:22 +04:00
goto out ;
2001-11-21 15:47:42 +03:00
}
2004-06-09 00:34:40 +04:00
if ( argc < c - > min_args + 1 | |
( c - > max_args > = 0 & & argc > c - > max_args + 1 ) ) {
2001-11-21 15:47:42 +03:00
fprintf ( stderr , " Incorrect number of arguments \n " ) ;
_usage ( stderr ) ;
2005-10-16 18:33:22 +04:00
goto out ;
2001-11-21 15:47:42 +03:00
}
2003-07-04 23:38:49 +04:00
doit :
2003-09-16 18:13:51 +04:00
if ( ! c - > fn ( argc , argv , NULL ) ) {
2001-12-14 16:30:04 +03:00
fprintf ( stderr , " Command failed \n " ) ;
2005-10-16 18:33:22 +04:00
goto out ;
2001-11-21 15:47:42 +03:00
}
2005-10-16 18:33:22 +04:00
r = 0 ;
out :
return r ;
2001-11-21 15:47:42 +03:00
}