LCOV - code coverage report
Current view: directory - tools - dmsetup.c (source / functions) Found Hit Coverage
Test: unnamed Lines: 1563 150 9.6 %
Date: 2010-04-13 Functions: 94 11 11.7 %

       1                 : /*
       2                 :  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
       3                 :  * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
       4                 :  * Copyright (C) 2005-2007 NEC Corporation
       5                 :  *
       6                 :  * This file is part of the device-mapper userspace tools.
       7                 :  *
       8                 :  * It includes tree drawing code based on pstree: http://psmisc.sourceforge.net/
       9                 :  *
      10                 :  * This copyrighted material is made available to anyone wishing to use,
      11                 :  * modify, copy, or redistribute it subject to the terms and conditions
      12                 :  * of the GNU General Public License v.2.
      13                 :  *
      14                 :  * You should have received a copy of the GNU General Public License
      15                 :  * along with this program; if not, write to the Free Software Foundation,
      16                 :  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17                 :  */
      18                 : 
      19                 : #define _GNU_SOURCE
      20                 : #define _FILE_OFFSET_BITS 64
      21                 : 
      22                 : #include "configure.h"
      23                 : 
      24                 : #include "dm-logging.h"
      25                 : 
      26                 : #include <stdio.h>
      27                 : #include <stdlib.h>
      28                 : #include <string.h>
      29                 : #include <ctype.h>
      30                 : #include <dirent.h>
      31                 : #include <errno.h>
      32                 : #include <unistd.h>
      33                 : #include <libgen.h>
      34                 : #include <sys/wait.h>
      35                 : #include <unistd.h>
      36                 : #include <sys/param.h>
      37                 : #include <locale.h>
      38                 : #include <langinfo.h>
      39                 : #include <time.h>
      40                 : 
      41                 : #include <fcntl.h>
      42                 : #include <sys/stat.h>
      43                 : 
      44                 : #ifdef UDEV_SYNC_SUPPORT
      45                 : #  include <sys/types.h>
      46                 : #  include <sys/ipc.h>
      47                 : #  include <sys/sem.h>
      48                 : #  define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
      49                 : #  include <libudev.h>
      50                 : #endif
      51                 : 
      52                 : /* FIXME Unused so far */
      53                 : #undef HAVE_SYS_STATVFS_H
      54                 : 
      55                 : #ifdef HAVE_SYS_STATVFS_H
      56                 : #  include <sys/statvfs.h>
      57                 : #endif
      58                 : 
      59                 : #ifdef HAVE_SYS_IOCTL_H
      60                 : #  include <sys/ioctl.h>
      61                 : #endif
      62                 : 
      63                 : #if HAVE_TERMIOS_H
      64                 : #  include <termios.h>
      65                 : #endif
      66                 : 
      67                 : #ifdef HAVE_GETOPTLONG
      68                 : #  include <getopt.h>
      69                 : #  define GETOPTLONG_FN(a, b, c, d, e) getopt_long((a), (b), (c), (d), (e))
      70                 : #  define OPTIND_INIT 0
      71                 : #else
      72                 : struct option {
      73                 : };
      74                 : extern int optind;
      75                 : extern char *optarg;
      76                 : #  define GETOPTLONG_FN(a, b, c, d, e) getopt((a), (b), (c))
      77                 : #  define OPTIND_INIT 1
      78                 : #endif
      79                 : 
      80                 : #ifndef TEMP_FAILURE_RETRY
      81                 : # define TEMP_FAILURE_RETRY(expression) \
      82                 :   (__extension__                                                              \
      83                 :     ({ long int __result;                                                     \
      84                 :        do __result = (long int) (expression);                                 \
      85                 :        while (__result == -1L && errno == EINTR);                             \
      86                 :        __result; }))
      87                 : #endif
      88                 : 
      89                 : #ifdef linux
      90                 : #  include "kdev_t.h"
      91                 : #else
      92                 : #  define MAJOR(x) major((x))
      93                 : #  define MINOR(x) minor((x))
      94                 : #  define MKDEV(x,y) makedev((x),(y))
      95                 : #endif
      96                 : 
      97                 : #define LINE_SIZE 4096
      98                 : #define ARGS_MAX 256
      99                 : #define LOOP_TABLE_SIZE (PATH_MAX + 255)
     100                 : 
     101                 : #define DEFAULT_DM_DEV_DIR "/dev/"
     102                 : 
     103                 : #define DM_DEV_DIR_ENV_VAR_NAME "DM_DEV_DIR"
     104                 : #define DM_UDEV_COOKIE_ENV_VAR_NAME "DM_UDEV_COOKIE"
     105                 : 
     106                 : /* FIXME Should be imported */
     107                 : #ifndef DM_MAX_TYPE_NAME
     108                 : #  define DM_MAX_TYPE_NAME 16
     109                 : #endif
     110                 : 
     111                 : /* FIXME Should be elsewhere */
     112                 : #define SECTOR_SHIFT 9L
     113                 : 
     114                 : #define err(msg, x...) fprintf(stderr, msg "\n", ##x)
     115                 : 
     116                 : /*
     117                 :  * We have only very simple switches ATM.
     118                 :  */
     119                 : enum {
     120                 :         READ_ONLY = 0,
     121                 :         COLS_ARG,
     122                 :         EXEC_ARG,
     123                 :         FORCE_ARG,
     124                 :         GID_ARG,
     125                 :         HELP_ARG,
     126                 :         INACTIVE_ARG,
     127                 :         MAJOR_ARG,
     128                 :         MINOR_ARG,
     129                 :         MODE_ARG,
     130                 :         NAMEPREFIXES_ARG,
     131                 :         NOFLUSH_ARG,
     132                 :         NOHEADINGS_ARG,
     133                 :         NOLOCKFS_ARG,
     134                 :         NOOPENCOUNT_ARG,
     135                 :         NOTABLE_ARG,
     136                 :         UDEVCOOKIE_ARG,
     137                 :         NOUDEVRULES_ARG,
     138                 :         NOUDEVSYNC_ARG,
     139                 :         OPTIONS_ARG,
     140                 :         READAHEAD_ARG,
     141                 :         ROWS_ARG,
     142                 :         SEPARATOR_ARG,
     143                 :         SHOWKEYS_ARG,
     144                 :         SORT_ARG,
     145                 :         TABLE_ARG,
     146                 :         TARGET_ARG,
     147                 :         TREE_ARG,
     148                 :         UID_ARG,
     149                 :         UNBUFFERED_ARG,
     150                 :         UNQUOTED_ARG,
     151                 :         UUID_ARG,
     152                 :         VERBOSE_ARG,
     153                 :         VERSION_ARG,
     154                 :         YES_ARG,
     155                 :         NUM_SWITCHES
     156                 : };
     157                 : 
     158                 : typedef enum {
     159                 :         DR_TASK = 1,
     160                 :         DR_INFO = 2,
     161                 :         DR_DEPS = 4,
     162                 :         DR_TREE = 8,    /* Complete dependency tree required */
     163                 :         DR_NAME = 16
     164                 : } report_type_t;
     165                 : 
     166                 : static int _switches[NUM_SWITCHES];
     167                 : static int _int_args[NUM_SWITCHES];
     168                 : static char *_string_args[NUM_SWITCHES];
     169                 : static int _num_devices;
     170                 : static char *_uuid;
     171                 : static char *_table;
     172                 : static char *_target;
     173                 : static char *_command;
     174                 : static uint32_t _read_ahead_flags;
     175                 : static uint32_t _udev_cookie;
     176                 : static int _udev_only;
     177                 : static struct dm_tree *_dtree;
     178                 : static struct dm_report *_report;
     179                 : static report_type_t _report_type;
     180                 : 
     181                 : /*
     182                 :  * Commands
     183                 :  */
     184                 : 
     185                 : typedef int (*command_fn) (int argc, char **argv, void *data);
     186                 : 
     187                 : struct command {
     188                 :         const char *name;
     189                 :         const char *help;
     190                 :         int min_args;
     191                 :         int max_args;
     192                 :         command_fn fn;
     193                 : };
     194                 : 
     195             301 : static int _parse_line(struct dm_task *dmt, char *buffer, const char *file,
     196                 :                        int line)
     197                 : {
     198                 :         char ttype[LINE_SIZE], *ptr, *comment;
     199                 :         unsigned long long start, size;
     200                 :         int n;
     201                 : 
     202                 :         /* trim trailing space */
     203             602 :         for (ptr = buffer + strlen(buffer) - 1; ptr >= buffer; ptr--)
     204             602 :                 if (!isspace((int) *ptr))
     205             301 :                         break;
     206             301 :         ptr++;
     207             301 :         *ptr = '\0';
     208                 : 
     209                 :         /* trim leading space */
     210             301 :         for (ptr = buffer; *ptr && isspace((int) *ptr); ptr++)
     211                 :                 ;
     212                 : 
     213             301 :         if (!*ptr || *ptr == '#')
     214               0 :                 return 1;
     215                 : 
     216             301 :         if (sscanf(ptr, "%llu %llu %s %n",
     217                 :                    &start, &size, ttype, &n) < 3) {
     218               0 :                 err("Invalid format on line %d of table %s", line, file);
     219               0 :                 return 0;
     220                 :         }
     221                 : 
     222             301 :         ptr += n;
     223             301 :         if ((comment = strchr(ptr, (int) '#')))
     224               0 :                 *comment = '\0';
     225                 : 
     226             301 :         if (!dm_task_add_target(dmt, start, size, ttype, ptr))
     227               0 :                 return 0;
     228                 : 
     229             301 :         return 1;
     230                 : }
     231                 : 
     232             301 : static int _parse_file(struct dm_task *dmt, const char *file)
     233                 : {
     234             301 :         char *buffer = NULL;
     235             301 :         size_t buffer_size = 0;
     236                 :         FILE *fp;
     237             301 :         int r = 0, line = 0;
     238                 : 
     239                 :         /* one-line table on cmdline */
     240             301 :         if (_table)
     241               0 :                 return _parse_line(dmt, _table, "", ++line);
     242                 : 
     243                 :         /* OK for empty stdin */
     244             301 :         if (file) {
     245               0 :                 if (!(fp = fopen(file, "r"))) {
     246               0 :                         err("Couldn't open '%s' for reading", file);
     247               0 :                         return 0;
     248                 :                 }
     249                 :         } else
     250             301 :                 fp = stdin;
     251                 : 
     252                 : #ifndef HAVE_GETLINE
     253                 :         buffer_size = LINE_SIZE;
     254                 :         if (!(buffer = dm_malloc(buffer_size))) {
     255                 :                 err("Failed to malloc line buffer.");
     256                 :                 return 0;
     257                 :         }
     258                 : 
     259                 :         while (fgets(buffer, (int) buffer_size, fp))
     260                 : #else
     261             903 :         while (getline(&buffer, &buffer_size, fp) > 0)
     262                 : #endif
     263             301 :                 if (!_parse_line(dmt, buffer, file ? : "on stdin", ++line))
     264               0 :                         goto out;
     265                 : 
     266             301 :         r = 1;
     267                 : 
     268                 :       out:
     269             301 :         memset(buffer, 0, buffer_size);
     270                 : #ifndef HAVE_GETLINE
     271                 :         dm_free(buffer);
     272                 : #else
     273             301 :         free(buffer);
     274                 : #endif
     275             301 :         if (file && fclose(fp))
     276               0 :                 fprintf(stderr, "%s: fclose failed: %s", file, strerror(errno));
     277                 : 
     278             301 :         return r;
     279                 : }
     280                 : 
     281                 : struct dm_split_name {
     282                 :         char *subsystem;
     283                 :         char *vg_name;
     284                 :         char *lv_name;
     285                 :         char *lv_layer;
     286                 : };
     287                 : 
     288                 : struct dmsetup_report_obj {
     289                 :         struct dm_task *task;
     290                 :         struct dm_info *info;
     291                 :         struct dm_task *deps_task;
     292                 :         struct dm_tree_node *tree_node;
     293                 :         struct dm_split_name *split_name;
     294                 : };
     295                 : 
     296               0 : static struct dm_task *_get_deps_task(int major, int minor)
     297                 : {
     298                 :         struct dm_task *dmt;
     299                 :         struct dm_info info;
     300                 : 
     301               0 :         if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
     302               0 :                 return NULL;
     303                 : 
     304               0 :         if (!dm_task_set_major(dmt, major) ||
     305               0 :             !dm_task_set_minor(dmt, minor))
     306                 :                 goto err;
     307                 : 
     308               0 :         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
     309               0 :                 goto err;
     310                 : 
     311               0 :         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
     312               0 :                 goto err;
     313                 : 
     314               0 :         if (!dm_task_run(dmt))
     315               0 :                 goto err;
     316                 : 
     317               0 :         if (!dm_task_get_info(dmt, &info))
     318               0 :                 goto err;
     319                 : 
     320               0 :         if (!info.exists)
     321               0 :                 goto err;
     322                 : 
     323               0 :         return dmt;
     324                 : 
     325                 :       err:
     326               0 :         dm_task_destroy(dmt);
     327               0 :         return NULL;
     328                 : }
     329                 : 
     330               0 : static char *_extract_uuid_prefix(const char *uuid, const int separator)
     331                 : {
     332               0 :         char *ptr = NULL;
     333               0 :         char *uuid_prefix = NULL;
     334                 :         size_t len;
     335                 : 
     336               0 :         if (uuid)
     337               0 :                 ptr = strchr(uuid, separator);
     338                 : 
     339               0 :         len = ptr ? ptr - uuid : 0;
     340               0 :         if (!(uuid_prefix = dm_malloc(len + 1))) {
     341               0 :                 log_error("Failed to allocate memory to extract uuid prefix.");
     342               0 :                 return NULL;
     343                 :         }
     344                 : 
     345               0 :         memcpy(uuid_prefix, uuid, len);
     346               0 :         uuid_prefix[len] = '\0';
     347                 : 
     348               0 :         return uuid_prefix;
     349                 : }
     350                 : 
     351               0 : static struct dm_split_name *_get_split_name(const char *uuid, const char *name,
     352                 :                                              int separator)
     353                 : {
     354                 :         struct dm_split_name *split_name;
     355                 : 
     356               0 :         if (!(split_name = dm_malloc(sizeof(*split_name)))) {
     357               0 :                 log_error("Failed to allocate memory to split device name "
     358                 :                           "into components.");
     359               0 :                 return NULL;
     360                 :         }
     361                 : 
     362               0 :         split_name->subsystem = _extract_uuid_prefix(uuid, separator);
     363               0 :         split_name->vg_name = split_name->lv_name =
     364               0 :             split_name->lv_layer = (char *) "";
     365                 : 
     366               0 :         if (!strcmp(split_name->subsystem, "LVM") &&
     367               0 :             (!(split_name->vg_name = dm_strdup(name)) ||
     368               0 :              !dm_split_lvm_name(NULL, NULL, &split_name->vg_name,
     369                 :                                 &split_name->lv_name, &split_name->lv_layer)))
     370               0 :                 log_error("Failed to allocate memory to split LVM name "
     371                 :                           "into components.");
     372                 : 
     373               0 :         return split_name;
     374                 : }
     375                 : 
     376               0 : static void _destroy_split_name(struct dm_split_name *split_name)
     377                 : {
     378                 :         /*
     379                 :          * lv_name and lv_layer are allocated within the same block
     380                 :          * of memory as vg_name so don't need to be freed separately.
     381                 :          */
     382               0 :         if (!strcmp(split_name->subsystem, "LVM"))
     383               0 :                 dm_free(split_name->vg_name);
     384                 : 
     385               0 :         dm_free(split_name->subsystem);
     386               0 :         dm_free(split_name);
     387               0 : }
     388                 : 
     389               0 : static int _display_info_cols(struct dm_task *dmt, struct dm_info *info)
     390                 : {
     391                 :         struct dmsetup_report_obj obj;
     392               0 :         int r = 0;
     393                 : 
     394               0 :         if (!info->exists) {
     395               0 :                 fprintf(stderr, "Device does not exist.\n");
     396               0 :                 return 0;
     397                 :         }
     398                 : 
     399               0 :         obj.task = dmt;
     400               0 :         obj.info = info;
     401               0 :         obj.deps_task = NULL;
     402               0 :         obj.split_name = NULL;
     403                 : 
     404               0 :         if (_report_type & DR_TREE)
     405               0 :                 obj.tree_node = dm_tree_find_node(_dtree, info->major, info->minor);
     406                 : 
     407               0 :         if (_report_type & DR_DEPS)
     408               0 :                 obj.deps_task = _get_deps_task(info->major, info->minor);
     409                 : 
     410               0 :         if (_report_type & DR_NAME)
     411               0 :                 obj.split_name = _get_split_name(dm_task_get_uuid(dmt), dm_task_get_name(dmt), '-');
     412                 : 
     413               0 :         if (!dm_report_object(_report, &obj))
     414               0 :                 goto out;
     415                 : 
     416               0 :         r = 1;
     417                 : 
     418                 :       out:
     419               0 :         if (obj.deps_task)
     420               0 :                 dm_task_destroy(obj.deps_task);
     421               0 :         if (obj.split_name)
     422               0 :                 _destroy_split_name(obj.split_name);
     423               0 :         return r;
     424                 : }
     425                 : 
     426               0 : static void _display_info_long(struct dm_task *dmt, struct dm_info *info)
     427                 : {
     428                 :         const char *uuid;
     429                 :         uint32_t read_ahead;
     430                 : 
     431               0 :         if (!info->exists) {
     432               0 :                 printf("Device does not exist.\n");
     433               0 :                 return;
     434                 :         }
     435                 : 
     436               0 :         printf("Name:              %s\n", dm_task_get_name(dmt));
     437                 : 
     438               0 :         printf("State:             %s%s\n",
     439               0 :                info->suspended ? "SUSPENDED" : "ACTIVE",
     440               0 :                info->read_only ? " (READ-ONLY)" : "");
     441                 : 
     442                 :         /* FIXME Old value is being printed when it's being changed. */
     443               0 :         if (dm_task_get_read_ahead(dmt, &read_ahead))
     444               0 :                 printf("Read Ahead:        %" PRIu32 "\n", read_ahead);
     445                 : 
     446               0 :         if (!info->live_table && !info->inactive_table)
     447               0 :                 printf("Tables present:    None\n");
     448                 :         else
     449               0 :                 printf("Tables present:    %s%s%s\n",
     450               0 :                        info->live_table ? "LIVE" : "",
     451               0 :                        info->live_table && info->inactive_table ? " & " : "",
     452               0 :                        info->inactive_table ? "INACTIVE" : "");
     453                 : 
     454               0 :         if (info->open_count != -1)
     455               0 :                 printf("Open count:        %d\n", info->open_count);
     456                 : 
     457               0 :         printf("Event number:      %" PRIu32 "\n", info->event_nr);
     458               0 :         printf("Major, minor:      %d, %d\n", info->major, info->minor);
     459                 : 
     460               0 :         if (info->target_count != -1)
     461               0 :                 printf("Number of targets: %d\n", info->target_count);
     462                 : 
     463               0 :         if ((uuid = dm_task_get_uuid(dmt)) && *uuid)
     464               0 :                 printf("UUID: %s\n", uuid);
     465                 : 
     466               0 :         printf("\n");
     467                 : }
     468                 : 
     469               0 : static int _display_info(struct dm_task *dmt)
     470                 : {
     471                 :         struct dm_info info;
     472                 : 
     473               0 :         if (!dm_task_get_info(dmt, &info))
     474               0 :                 return 0;
     475                 : 
     476               0 :         if (!_switches[COLS_ARG])
     477               0 :                 _display_info_long(dmt, &info);
     478                 :         else
     479                 :                 /* FIXME return code */
     480               0 :                 _display_info_cols(dmt, &info);
     481                 : 
     482               0 :         return info.exists ? 1 : 0;
     483                 : }
     484                 : 
     485             302 : static int _set_task_device(struct dm_task *dmt, const char *name, int optional)
     486                 : {
     487             302 :         if (name) {
     488             302 :                 if (!dm_task_set_name(dmt, name))
     489               0 :                         return 0;
     490               0 :         } else if (_switches[UUID_ARG]) {
     491               0 :                 if (!dm_task_set_uuid(dmt, _uuid))
     492               0 :                         return 0;
     493               0 :         } else if (_switches[MAJOR_ARG] && _switches[MINOR_ARG]) {
     494               0 :                 if (!dm_task_set_major(dmt, _int_args[MAJOR_ARG]) ||
     495               0 :                     !dm_task_set_minor(dmt, _int_args[MINOR_ARG]))
     496               0 :                         return 0;
     497               0 :         } else if (!optional) {
     498               0 :                 fprintf(stderr, "No device specified.\n");
     499               0 :                 return 0;
     500                 :         }
     501                 : 
     502             302 :         return 1;
     503                 : }
     504                 : 
     505               0 : static int _load(int argc, char **argv, void *data __attribute((unused)))
     506                 : {
     507               0 :         int r = 0;
     508                 :         struct dm_task *dmt;
     509               0 :         const char *file = NULL;
     510               0 :         const char *name = NULL;
     511                 : 
     512               0 :         if (_switches[NOTABLE_ARG]) {
     513               0 :                 err("--notable only available when creating new device\n");
     514               0 :                 return 0;
     515                 :         }
     516                 : 
     517               0 :         if (!_switches[UUID_ARG] && !_switches[MAJOR_ARG]) {
     518               0 :                 if (argc == 1) {
     519               0 :                         err("Please specify device.\n");
     520               0 :                         return 0;
     521                 :                 }
     522               0 :                 name = argv[1];
     523               0 :                 argc--;
     524               0 :                 argv++;
     525               0 :         } else if (argc > 2) {
     526               0 :                 err("Too many command line arguments.\n");
     527               0 :                 return 0;
     528                 :         }
     529                 : 
     530               0 :         if (argc == 2)
     531               0 :                 file = argv[1];
     532                 : 
     533               0 :         if (!(dmt = dm_task_create(DM_DEVICE_RELOAD)))
     534               0 :                 return 0;
     535                 : 
     536               0 :         if (!_set_task_device(dmt, name, 0))
     537               0 :                 goto out;
     538                 : 
     539               0 :         if (!_switches[NOTABLE_ARG] && !_parse_file(dmt, file))
     540               0 :                 goto out;
     541                 : 
     542               0 :         if (_switches[READ_ONLY] && !dm_task_set_ro(dmt))
     543               0 :                 goto out;
     544                 : 
     545               0 :         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
     546               0 :                 goto out;
     547                 : 
     548               0 :         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
     549               0 :                 goto out;
     550                 : 
     551               0 :         if (!dm_task_run(dmt))
     552               0 :                 goto out;
     553                 : 
     554               0 :         r = 1;
     555                 : 
     556               0 :         if (_switches[VERBOSE_ARG])
     557               0 :                 r = _display_info(dmt);
     558                 : 
     559                 :       out:
     560               0 :         dm_task_destroy(dmt);
     561                 : 
     562               0 :         return r;
     563                 : }
     564                 : 
     565             301 : static int _create(int argc, char **argv, void *data __attribute((unused)))
     566                 : {
     567             301 :         int r = 0;
     568                 :         struct dm_task *dmt;
     569             301 :         const char *file = NULL;
     570             301 :         uint32_t cookie = 0;
     571             301 :         uint16_t udev_flags = 0;
     572                 : 
     573             301 :         if (argc == 3)
     574               0 :                 file = argv[2];
     575                 : 
     576             301 :         if (!(dmt = dm_task_create(DM_DEVICE_CREATE)))
     577               0 :                 return 0;
     578                 : 
     579             301 :         if (!dm_task_set_name(dmt, argv[1]))
     580               0 :                 goto out;
     581                 : 
     582             301 :         if (_switches[UUID_ARG] && !dm_task_set_uuid(dmt, _uuid))
     583               0 :                 goto out;
     584                 : 
     585             301 :         if (!_switches[NOTABLE_ARG] && !_parse_file(dmt, file))
     586               0 :                 goto out;
     587                 : 
     588             301 :         if (_switches[READ_ONLY] && !dm_task_set_ro(dmt))
     589               0 :                 goto out;
     590                 : 
     591             301 :         if (_switches[MAJOR_ARG] && !dm_task_set_major(dmt, _int_args[MAJOR_ARG]))
     592               0 :                 goto out;
     593                 : 
     594             301 :         if (_switches[MINOR_ARG] && !dm_task_set_minor(dmt, _int_args[MINOR_ARG]))
     595               0 :                 goto out;
     596                 : 
     597             301 :         if (_switches[UID_ARG] && !dm_task_set_uid(dmt, _int_args[UID_ARG]))
     598               0 :                 goto out;
     599                 : 
     600             301 :         if (_switches[GID_ARG] && !dm_task_set_gid(dmt, _int_args[GID_ARG]))
     601               0 :                 goto out;
     602                 : 
     603             301 :         if (_switches[MODE_ARG] && !dm_task_set_mode(dmt, _int_args[MODE_ARG]))
     604               0 :                 goto out;
     605                 : 
     606             301 :         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
     607               0 :                 goto out;
     608                 : 
     609             301 :         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
     610               0 :                 goto out;
     611                 : 
     612             301 :         if (_switches[READAHEAD_ARG] &&
     613               0 :             !dm_task_set_read_ahead(dmt, _int_args[READAHEAD_ARG],
     614                 :                                     _read_ahead_flags))
     615               0 :                 goto out;
     616                 : 
     617             301 :         if (_switches[NOTABLE_ARG])
     618               0 :                 dm_udev_set_sync_support(0);
     619                 : 
     620             301 :         if (_switches[NOUDEVRULES_ARG])
     621               0 :                 udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG |
     622                 :                               DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG;
     623                 : 
     624             301 :         if (_udev_cookie) {
     625               0 :                 cookie = _udev_cookie;
     626               0 :                 if (_udev_only)
     627               0 :                         udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
     628                 :         }
     629                 : 
     630             602 :         if (!dm_task_set_cookie(dmt, &cookie, udev_flags) ||
     631             301 :             !dm_task_run(dmt))
     632                 :                 goto out;
     633                 : 
     634             301 :         r = 1;
     635                 : 
     636             301 :         if (_switches[VERBOSE_ARG])
     637               0 :                 r = _display_info(dmt);
     638                 : 
     639                 :       out:
     640             301 :         if (!_udev_cookie)
     641             301 :                 (void) dm_udev_wait(cookie);
     642             301 :         dm_task_destroy(dmt);
     643                 : 
     644             301 :         return r;
     645                 : }
     646                 : 
     647               0 : static int _rename(int argc, char **argv, void *data __attribute((unused)))
     648                 : {
     649               0 :         int r = 0;
     650                 :         struct dm_task *dmt;
     651               0 :         uint32_t cookie = 0;
     652               0 :         uint16_t udev_flags = 0;
     653                 : 
     654               0 :         if (!(dmt = dm_task_create(DM_DEVICE_RENAME)))
     655               0 :                 return 0;
     656                 : 
     657                 :         /* FIXME Kernel doesn't support uuid or device number here yet */
     658               0 :         if (!_set_task_device(dmt, (argc == 3) ? argv[1] : NULL, 0))
     659               0 :                 goto out;
     660                 : 
     661               0 :         if (!dm_task_set_newname(dmt, argv[argc - 1]))
     662               0 :                 goto out;
     663                 : 
     664               0 :         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
     665               0 :                 goto out;
     666                 : 
     667               0 :         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
     668               0 :                 goto out;
     669                 : 
     670               0 :         if (_switches[NOUDEVRULES_ARG])
     671               0 :                 udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG |
     672                 :                               DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG;
     673                 : 
     674               0 :         if (_udev_cookie) {
     675               0 :                 cookie = _udev_cookie;
     676               0 :                 if (_udev_only)
     677               0 :                         udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
     678                 :         }
     679                 : 
     680               0 :         if (!dm_task_set_cookie(dmt, &cookie, udev_flags) ||
     681               0 :             !dm_task_run(dmt))
     682                 :                 goto out;
     683                 : 
     684               0 :         r = 1;
     685                 : 
     686                 :       out:
     687               0 :         if (!_udev_cookie)
     688               0 :                 (void) dm_udev_wait(cookie);
     689               0 :         dm_task_destroy(dmt);
     690                 : 
     691               0 :         return r;
     692                 : }
     693                 : 
     694               0 : static int _message(int argc, char **argv, void *data __attribute((unused)))
     695                 : {
     696               0 :         int r = 0, i;
     697               0 :         size_t sz = 1;
     698                 :         struct dm_task *dmt;
     699                 :         char *str;
     700                 : 
     701               0 :         if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
     702               0 :                 return 0;
     703                 : 
     704               0 :         if (_switches[UUID_ARG] || _switches[MAJOR_ARG]) {
     705               0 :                 if (!_set_task_device(dmt, NULL, 0))
     706               0 :                         goto out;
     707                 :         } else {
     708               0 :                 if (!_set_task_device(dmt, argv[1], 0))
     709               0 :                         goto out;
     710               0 :                 argc--;
     711               0 :                 argv++;
     712                 :         }
     713                 : 
     714               0 :         if (!dm_task_set_sector(dmt, (uint64_t) atoll(argv[1])))
     715               0 :                 goto out;
     716                 : 
     717               0 :         argc -= 2;
     718               0 :         argv += 2;
     719                 : 
     720               0 :         if (argc <= 0)
     721               0 :                 err("No message supplied.\n");
     722                 : 
     723               0 :         for (i = 0; i < argc; i++)
     724               0 :                 sz += strlen(argv[i]) + 1;
     725                 : 
     726               0 :         if (!(str = dm_malloc(sz))) {
     727               0 :                 err("message string allocation failed");
     728               0 :                 goto out;
     729                 :         }
     730                 : 
     731               0 :         memset(str, 0, sz);
     732                 : 
     733               0 :         for (i = 0; i < argc; i++) {
     734               0 :                 if (i)
     735               0 :                         strcat(str, " ");
     736               0 :                 strcat(str, argv[i]);
     737                 :         }
     738                 : 
     739               0 :         if (!dm_task_set_message(dmt, str))
     740               0 :                 goto out;
     741                 : 
     742               0 :         dm_free(str);
     743                 : 
     744               0 :         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
     745               0 :                 goto out;
     746                 : 
     747               0 :         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
     748               0 :                 goto out;
     749                 : 
     750               0 :         if (!dm_task_run(dmt))
     751               0 :                 goto out;
     752                 : 
     753               0 :         r = 1;
     754                 : 
     755                 :       out:
     756               0 :         dm_task_destroy(dmt);
     757                 : 
     758               0 :         return r;
     759                 : }
     760                 : 
     761               0 : static int _setgeometry(int argc, char **argv, void *data __attribute((unused)))
     762                 : {
     763               0 :         int r = 0;
     764                 :         struct dm_task *dmt;
     765                 : 
     766               0 :         if (!(dmt = dm_task_create(DM_DEVICE_SET_GEOMETRY)))
     767               0 :                 return 0;
     768                 : 
     769               0 :         if (_switches[UUID_ARG] || _switches[MAJOR_ARG]) {
     770               0 :                 if (!_set_task_device(dmt, NULL, 0))
     771               0 :                         goto out;
     772                 :         } else {
     773               0 :                 if (!_set_task_device(dmt, argv[1], 0))
     774               0 :                         goto out;
     775               0 :                 argc--;
     776               0 :                 argv++;
     777                 :         }
     778                 : 
     779               0 :         if (!dm_task_set_geometry(dmt, argv[1], argv[2], argv[3], argv[4]))
     780               0 :                 goto out;
     781                 : 
     782               0 :         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
     783               0 :                 goto out;
     784                 : 
     785               0 :         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
     786               0 :                 goto out;
     787                 : 
     788                 :         /* run the task */
     789               0 :         if (!dm_task_run(dmt))
     790               0 :                 goto out;
     791                 : 
     792               0 :         r = 1;
     793                 : 
     794                 :       out:
     795               0 :         dm_task_destroy(dmt);
     796                 : 
     797               0 :         return r;
     798                 : }
     799                 : 
     800               0 : static int _splitname(int argc, char **argv, void *data __attribute((unused)))
     801                 : {
     802                 :         struct dmsetup_report_obj obj;
     803               0 :         int r = 1;
     804                 : 
     805               0 :         obj.task = NULL;
     806               0 :         obj.info = NULL;
     807               0 :         obj.deps_task = NULL;
     808               0 :         obj.tree_node = NULL;
     809               0 :         obj.split_name = _get_split_name((argc == 3) ? argv[2] : "LVM",
     810               0 :                                          argv[1], '\0');
     811                 : 
     812               0 :         r = dm_report_object(_report, &obj);
     813               0 :         _destroy_split_name(obj.split_name);
     814                 : 
     815               0 :         return r;
     816                 : }
     817                 : 
     818               0 : static uint32_t _get_cookie_value(const char *str_value)
     819                 : {
     820                 :         unsigned long int value;
     821                 :         char *p;
     822                 : 
     823               0 :         if (!(value = strtoul(str_value, &p, 0)) ||
     824               0 :             *p ||
     825               0 :             (value == ULONG_MAX && errno == ERANGE) ||
     826                 :             value > 0xFFFFFFFF) {
     827               0 :                 err("Incorrect cookie value");
     828               0 :                 return 0;
     829                 :         }
     830                 :         else
     831               0 :                 return (uint32_t) value;
     832                 : }
     833                 : 
     834               0 : static int _udevflags(int args, char **argv, void *data __attribute((unused)))
     835                 : {
     836                 :         uint32_t cookie;
     837                 :         uint16_t flags;
     838                 :         int i;
     839                 :         static const char *dm_flag_names[] = {"DISABLE_DM_RULES",
     840                 :                                               "DISABLE_SUBSYSTEM_RULES",
     841                 :                                               "DISABLE_DISK_RULES",
     842                 :                                               "DISABLE_OTHER_RULES",
     843                 :                                               "LOW_PRIORITY",
     844                 :                                               "DISABLE_LIBRARY_FALLBACK",
     845                 :                                                0, 0};
     846                 : 
     847               0 :         if (!(cookie = _get_cookie_value(argv[1])))
     848               0 :                 return 0;
     849                 : 
     850               0 :         flags = cookie >> DM_UDEV_FLAGS_SHIFT;
     851                 : 
     852               0 :         for (i = 0; i < DM_UDEV_FLAGS_SHIFT; i++)
     853               0 :                 if (1 << i & flags) {
     854               0 :                         if (i < DM_UDEV_FLAGS_SHIFT / 2 && dm_flag_names[i])
     855               0 :                                 printf("DM_UDEV_%s_FLAG='1'\n", dm_flag_names[i]);
     856               0 :                         else if (i < DM_UDEV_FLAGS_SHIFT / 2)
     857                 :                                 /*
     858                 :                                  * This is just a fallback. Each new DM flag
     859                 :                                  * should have its symbolic name assigned.
     860                 :                                  */
     861               0 :                                 printf("DM_UDEV_FLAG%d='1'\n", i);
     862                 :                         else
     863                 :                                 /*
     864                 :                                  * We can't assign symbolic names to subsystem
     865                 :                                  * flags. Their semantics vary based on the
     866                 :                                  * subsystem that is currently used.
     867                 :                                  */
     868               0 :                                 printf("DM_SUBSYSTEM_UDEV_FLAG%d='1'\n",
     869                 :                                         i - DM_UDEV_FLAGS_SHIFT / 2);
     870                 :                 }
     871                 : 
     872               0 :         return 1;
     873                 : }
     874                 : 
     875               0 : static int _udevcomplete(int argc, char **argv, void *data __attribute((unused)))
     876                 : {
     877                 :         uint32_t cookie;
     878                 : 
     879               0 :         if (!(cookie = _get_cookie_value(argv[1])))
     880               0 :                 return 0;
     881                 : 
     882                 :         /*
     883                 :          * Strip flags from the cookie and use cookie magic instead.
     884                 :          * If the cookie has non-zero prefix and the base is zero then
     885                 :          * this one carries flags to control udev rules only and it is
     886                 :          * not meant to be for notification. Return with success in this
     887                 :          * situation.
     888                 :          */
     889               0 :         if (!(cookie &= ~DM_UDEV_FLAGS_MASK))
     890               0 :                 return 1;
     891                 : 
     892               0 :         cookie |= DM_COOKIE_MAGIC << DM_UDEV_FLAGS_SHIFT;
     893                 : 
     894               0 :         return dm_udev_complete(cookie);
     895                 : }
     896                 : 
     897                 : #ifndef UDEV_SYNC_SUPPORT
     898                 : static const char _cmd_not_supported[] = "Command not supported. Recompile with \"--enable-udev-sync\" to enable.";
     899                 : 
     900                 : static int _udevcreatecookie(int argc, char **argv,
     901                 :                                   void *data __attribute((unused)))
     902                 : {
     903                 :         log_error(_cmd_not_supported);
     904                 : 
     905                 :         return 0;
     906                 : }
     907                 : 
     908                 : static int _udevreleasecookie(int argc, char **argv,
     909                 :                                 void *data __attribute((unused)))
     910                 : {
     911                 :         log_error(_cmd_not_supported);
     912                 : 
     913                 :         return 0;
     914                 : }
     915                 : 
     916                 : static int _udevcomplete_all(int argc __attribute((unused)), char **argv __attribute((unused)), void *data __attribute((unused)))
     917                 : {
     918                 :         log_error(_cmd_not_supported);
     919                 : 
     920                 :         return 0;
     921                 : }
     922                 : 
     923                 : static int _udevcookies(int argc __attribute((unused)), char **argv __attribute((unused)), void *data __attribute((unused)))
     924                 : {
     925                 :         log_error(_cmd_not_supported);
     926                 : 
     927                 :         return 0;
     928                 : }
     929                 : 
     930                 : #else   /* UDEV_SYNC_SUPPORT */
     931             603 : static int _set_up_udev_support(const char *dev_dir)
     932                 : {
     933                 :         struct udev *udev;
     934                 :         const char *udev_dev_dir;
     935                 :         size_t udev_dev_dir_len;
     936                 :         int dirs_diff;
     937                 :         const char *env;
     938                 : 
     939             603 :         if (_switches[NOUDEVSYNC_ARG])
     940               0 :                 dm_udev_set_sync_support(0);
     941                 : 
     942             603 :         if (!_udev_cookie) {
     943             603 :                 env = getenv(DM_UDEV_COOKIE_ENV_VAR_NAME);
     944             603 :                 if (env && *env && (_udev_cookie = _get_cookie_value(env)))
     945               0 :                         log_debug("Using udev transaction 0x%08" PRIX32
     946                 :                                   " defined by %s environment variable.",
     947                 :                                    _udev_cookie,
     948                 :                                    DM_UDEV_COOKIE_ENV_VAR_NAME);
     949                 :         }
     950               0 :         else if (_switches[UDEVCOOKIE_ARG])
     951               0 :                 log_debug("Using udev transaction 0x%08" PRIX32
     952                 :                           " defined by --udevcookie option.",
     953                 :                           _udev_cookie);
     954                 : 
     955            1809 :         if (!(udev = udev_new()) ||
     956             603 :             !(udev_dev_dir = udev_get_dev_path(udev)) ||
     957             603 :             !*udev_dev_dir) {
     958               0 :                 log_error("Could not get udev dev path.");
     959               0 :                 return 0;
     960                 :         }
     961             603 :         udev_dev_dir_len = strlen(udev_dev_dir);
     962                 : 
     963                 :         /*
     964                 :          * Normally, there's always a fallback action by libdevmapper if udev
     965                 :          * has not done its job correctly, e.g. the nodes were not created.
     966                 :          * If using udev transactions by specifying existing cookie value,
     967                 :          * we need to disable node creation by libdevmapper completely,
     968                 :          * disabling any fallback actions, since any synchronisation happens
     969                 :          * at the end of the transaction only. We need to do this to prevent
     970                 :          * races between udev and libdevmapper but only in case udev "dev path"
     971                 :          * is the same as "dev path" used by libdevmapper.
     972                 :          */
     973                 : 
     974                 :         /* There's always a slash at the end of dev_dir. But check udev_dev_dir! */
     975             603 :         if (udev_dev_dir[udev_dev_dir_len - 1] != '/')
     976             603 :                 dirs_diff = strncmp(dev_dir, udev_dev_dir, udev_dev_dir_len);
     977                 :         else
     978               0 :                 dirs_diff = strcmp(dev_dir, udev_dev_dir);
     979                 : 
     980             603 :         _udev_only = _udev_cookie && !dirs_diff;
     981                 : 
     982             603 :         if (dirs_diff) {
     983               0 :                 log_debug("The path %s used for creating device nodes that is "
     984                 :                           "set via DM_DEV_DIR environment variable differs from "
     985                 :                           "the path %s that is used by udev. All warnings "
     986                 :                           "about udev not working correctly while processing "
     987                 :                           "particular nodes will be suppressed. These nodes "
     988                 :                           "and symlinks will be managed in each directory "
     989                 :                           "separately.", dev_dir, udev_dev_dir);
     990               0 :                 dm_udev_set_checking(0);
     991                 :         }
     992                 : 
     993             603 :         udev_unref(udev);
     994             603 :         return 1;
     995                 : }
     996                 : 
     997               0 : static int _udevcreatecookie(int argc, char **argv,
     998                 :                                   void *data __attribute((unused)))
     999                 : {
    1000                 :         uint32_t cookie;
    1001                 : 
    1002               0 :         if (!dm_udev_create_cookie(&cookie))
    1003               0 :                 return 0;
    1004                 : 
    1005               0 :         if (cookie)
    1006               0 :                 printf("0x%08" PRIX32 "\n", cookie);
    1007                 : 
    1008               0 :         return 1;
    1009                 : }
    1010                 : 
    1011               0 : static int _udevreleasecookie(int argc, char **argv,
    1012                 :                                 void *data __attribute((unused)))
    1013                 : {
    1014               0 :         if (argv[1] && !(_udev_cookie = _get_cookie_value(argv[1])))
    1015               0 :                 return 0;
    1016                 : 
    1017               0 :         if (!_udev_cookie) {
    1018               0 :                 log_error("No udev transaction cookie given.");
    1019               0 :                 return 0;
    1020                 :         }
    1021                 : 
    1022               0 :         return dm_udev_wait(_udev_cookie);
    1023                 : }
    1024                 : 
    1025               0 : static char _yes_no_prompt(const char *prompt, ...)
    1026                 : {
    1027               0 :         int c = 0, ret = 0;
    1028                 :         va_list ap;
    1029                 : 
    1030                 :         do {
    1031               0 :                 if (c == '\n' || !c) {
    1032               0 :                         va_start(ap, prompt);
    1033               0 :                         vprintf(prompt, ap);
    1034               0 :                         va_end(ap);
    1035                 :                 }
    1036                 : 
    1037               0 :                 if ((c = getchar()) == EOF) {
    1038               0 :                         ret = 'n';
    1039               0 :                         break;
    1040                 :                 }
    1041                 : 
    1042               0 :                 c = tolower(c);
    1043               0 :                 if ((c == 'y') || (c == 'n'))
    1044               0 :                         ret = c;
    1045               0 :         } while (!ret || c != '\n');
    1046                 : 
    1047               0 :         if (c != '\n')
    1048               0 :                 printf("\n");
    1049                 : 
    1050               0 :         return ret;
    1051                 : }
    1052                 : 
    1053               0 : static int _udevcomplete_all(int argc __attribute((unused)), char **argv __attribute((unused)), void *data __attribute((unused)))
    1054                 : {
    1055                 :         int max_id, id, sid;
    1056                 :         struct seminfo sinfo;
    1057                 :         struct semid_ds sdata;
    1058               0 :         int counter = 0;
    1059                 : 
    1060               0 :         if (!_switches[YES_ARG]) {
    1061               0 :                 log_warn("This operation will destroy all semaphores with keys "
    1062                 :                          "that have a prefix %" PRIu16 " (0x%" PRIx16 ").",
    1063                 :                          DM_COOKIE_MAGIC, DM_COOKIE_MAGIC);
    1064                 : 
    1065               0 :                 if (_yes_no_prompt("Do you really want to continue? [y/n]: ") == 'n') {
    1066               0 :                         log_print("Semaphores with keys prefixed by %" PRIu16
    1067                 :                                   " (0x%" PRIx16 ") NOT destroyed.",
    1068                 :                                   DM_COOKIE_MAGIC, DM_COOKIE_MAGIC);
    1069               0 :                         return 1;
    1070                 :                 }
    1071                 :         }
    1072                 : 
    1073               0 :         if ((max_id = semctl(0, 0, SEM_INFO, &sinfo)) < 0) {
    1074               0 :                 log_sys_error("semctl", "SEM_INFO");
    1075               0 :                 return 0;
    1076                 :         }
    1077                 : 
    1078               0 :         for (id = 0; id <= max_id; id++) {
    1079               0 :                 if ((sid = semctl(id, 0, SEM_STAT, &sdata)) < 0)
    1080               0 :                         continue;
    1081                 : 
    1082               0 :                 if (sdata.sem_perm.__key >> 16 == DM_COOKIE_MAGIC) {
    1083               0 :                         if (semctl(sid, 0, IPC_RMID, 0) < 0) {
    1084               0 :                                 log_error("Could not cleanup notification semaphore "
    1085                 :                                           "with semid %d and cookie value "
    1086                 :                                           "%" PRIu32 " (0x%" PRIx32 ")", sid,
    1087                 :                                           sdata.sem_perm.__key, sdata.sem_perm.__key);
    1088               0 :                                 continue;
    1089                 :                         }
    1090                 : 
    1091               0 :                         counter++;
    1092                 :                 }
    1093                 :         }
    1094                 : 
    1095               0 :         log_print("%d semaphores with keys prefixed by "
    1096                 :                   "%" PRIu16 " (0x%" PRIx16 ") destroyed.",
    1097                 :                   counter, DM_COOKIE_MAGIC, DM_COOKIE_MAGIC);
    1098                 : 
    1099               0 :         return 1;
    1100                 : }
    1101                 : 
    1102               0 : static int _udevcookies(int argc __attribute((unused)), char **argv __attribute((unused)), void *data __attribute((unused)))
    1103                 : {
    1104                 :         int max_id, id, sid;
    1105                 :         struct seminfo sinfo;
    1106                 :         struct semid_ds sdata;
    1107                 :         int val;
    1108                 :         char *time_str;
    1109                 : 
    1110               0 :         if ((max_id = semctl(0, 0, SEM_INFO, &sinfo)) < 0) {
    1111               0 :                 log_sys_error("sem_ctl", "SEM_INFO");
    1112               0 :                 return 0;
    1113                 :         }
    1114                 : 
    1115               0 :         printf("cookie       semid      value      last_semop_time\n");
    1116                 : 
    1117               0 :         for (id = 0; id <= max_id; id++) {
    1118               0 :                 if ((sid = semctl(id, 0, SEM_STAT, &sdata)) < 0)
    1119               0 :                         continue;
    1120                 : 
    1121               0 :                 if (sdata.sem_perm.__key >> 16 == DM_COOKIE_MAGIC) {
    1122               0 :                         if ((val = semctl(sid, 0, GETVAL)) < 0) {
    1123               0 :                                 log_error("semid %d: sem_ctl failed for "
    1124                 :                                           "cookie 0x%" PRIx32 ": %s",
    1125                 :                                           sid, sdata.sem_perm.__key,
    1126                 :                                           strerror(errno));
    1127               0 :                                 continue;
    1128                 :                         }
    1129                 : 
    1130               0 :                         time_str = ctime((const time_t *) &sdata.sem_otime);
    1131                 : 
    1132               0 :                         printf("0x%-10x %-10d %-10d %s", sdata.sem_perm.__key,
    1133                 :                                 sid, val, time_str ? time_str : "unknown\n");
    1134                 :                 }
    1135                 :         }
    1136                 : 
    1137               0 :         return 1;
    1138                 : }
    1139                 : #endif  /* UDEV_SYNC_SUPPORT */
    1140                 : 
    1141               0 : static int _version(int argc __attribute((unused)), char **argv __attribute((unused)), void *data __attribute((unused)))
    1142                 : {
    1143                 :         char version[80];
    1144                 : 
    1145               0 :         if (dm_get_library_version(version, sizeof(version)))
    1146               0 :                 printf("Library version:   %s\n", version);
    1147                 : 
    1148               0 :         if (!dm_driver_version(version, sizeof(version)))
    1149               0 :                 return 0;
    1150                 : 
    1151               0 :         printf("Driver version:    %s\n", version);
    1152                 : 
    1153               0 :         return 1;
    1154                 : }
    1155                 : 
    1156             302 : static int _simple(int task, const char *name, uint32_t event_nr, int display)
    1157                 : {
    1158             302 :         uint32_t cookie = 0;
    1159             302 :         uint16_t udev_flags = 0;
    1160             302 :         int udev_wait_flag = task == DM_DEVICE_RESUME ||
    1161             302 :                              task == DM_DEVICE_REMOVE;
    1162             302 :         int r = 0;
    1163                 : 
    1164                 :         struct dm_task *dmt;
    1165                 : 
    1166             302 :         if (!(dmt = dm_task_create(task)))
    1167               0 :                 return 0;
    1168                 : 
    1169             302 :         if (!_set_task_device(dmt, name, 0))
    1170               0 :                 goto out;
    1171                 : 
    1172             302 :         if (event_nr && !dm_task_set_event_nr(dmt, event_nr))
    1173               0 :                 goto out;
    1174                 : 
    1175             302 :         if (_switches[NOFLUSH_ARG] && !dm_task_no_flush(dmt))
    1176               0 :                 goto out;
    1177                 : 
    1178             302 :         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
    1179               0 :                 goto out;
    1180                 : 
    1181             302 :         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
    1182               0 :                 goto out;
    1183                 : 
    1184             302 :         if (_switches[NOLOCKFS_ARG] && !dm_task_skip_lockfs(dmt))
    1185               0 :                 goto out;
    1186                 : 
    1187             302 :         if (_switches[READAHEAD_ARG] &&
    1188               0 :             !dm_task_set_read_ahead(dmt, _int_args[READAHEAD_ARG],
    1189                 :                                     _read_ahead_flags))
    1190               0 :                 goto out;
    1191                 : 
    1192             302 :         if (_switches[NOUDEVRULES_ARG])
    1193               0 :                 udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG |
    1194                 :                               DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG;
    1195                 : 
    1196             302 :         if (_udev_cookie) {
    1197               0 :                 cookie = _udev_cookie;
    1198               0 :                 if (_udev_only)
    1199               0 :                         udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
    1200                 :         }
    1201                 : 
    1202             302 :         if (udev_wait_flag && !dm_task_set_cookie(dmt, &cookie, udev_flags))
    1203               0 :                 goto out;
    1204                 : 
    1205             302 :         r = dm_task_run(dmt);
    1206                 : 
    1207             302 :         if (r && display && _switches[VERBOSE_ARG])
    1208               0 :                 r = _display_info(dmt);
    1209                 : 
    1210                 :       out:
    1211             302 :         if (!_udev_cookie && udev_wait_flag)
    1212             301 :                 (void) dm_udev_wait(cookie);
    1213                 : 
    1214             302 :         dm_task_destroy(dmt);
    1215             302 :         return r;
    1216                 : }
    1217                 : 
    1218               0 : static int _suspend(int argc, char **argv, void *data __attribute((unused)))
    1219                 : {
    1220               0 :         return _simple(DM_DEVICE_SUSPEND, argc > 1 ? argv[1] : NULL, 0, 1);
    1221                 : }
    1222                 : 
    1223             301 : static int _resume(int argc, char **argv, void *data __attribute((unused)))
    1224                 : {
    1225             301 :         return _simple(DM_DEVICE_RESUME, argc > 1 ? argv[1] : NULL, 0, 1);
    1226                 : }
    1227                 : 
    1228               0 : static int _clear(int argc, char **argv, void *data __attribute((unused)))
    1229                 : {
    1230               0 :         return _simple(DM_DEVICE_CLEAR, argc > 1 ? argv[1] : NULL, 0, 1);
    1231                 : }
    1232                 : 
    1233               0 : static int _wait(int argc, char **argv, void *data __attribute((unused)))
    1234                 : {
    1235               0 :         const char *name = NULL;
    1236                 : 
    1237               0 :         if (!_switches[UUID_ARG] && !_switches[MAJOR_ARG]) {
    1238               0 :                 if (argc == 1) {
    1239               0 :                         err("No device specified.");
    1240               0 :                         return 0;
    1241                 :                 }
    1242               0 :                 name = argv[1];
    1243               0 :                 argc--, argv++;
    1244                 :         }
    1245                 : 
    1246               0 :         return _simple(DM_DEVICE_WAITEVENT, name,
    1247               0 :                        (argc > 1) ? (uint32_t) atoi(argv[argc - 1]) : 0, 1);
    1248                 : }
    1249                 : 
    1250               0 : static int _process_all(int argc, char **argv, int silent,
    1251                 :                         int (*fn) (int argc, char **argv, void *data))
    1252                 : {
    1253               0 :         int r = 1;
    1254                 :         struct dm_names *names;
    1255               0 :         unsigned next = 0;
    1256                 : 
    1257                 :         struct dm_task *dmt;
    1258                 : 
    1259               0 :         if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
    1260               0 :                 return 0;
    1261                 : 
    1262               0 :         if (!dm_task_run(dmt)) {
    1263               0 :                 r = 0;
    1264               0 :                 goto out;
    1265                 :         }
    1266                 : 
    1267               0 :         if (!(names = dm_task_get_names(dmt))) {
    1268               0 :                 r = 0;
    1269               0 :                 goto out;
    1270                 :         }
    1271                 : 
    1272               0 :         if (!names->dev) {
    1273               0 :                 if (!silent)
    1274               0 :                         printf("No devices found\n");
    1275               0 :                 goto out;
    1276                 :         }
    1277                 : 
    1278                 :         do {
    1279               0 :                 names = (void *) names + next;
    1280               0 :                 if (!fn(argc, argv, (void *) names))
    1281               0 :                         r = 0;
    1282               0 :                 next = names->next;
    1283               0 :         } while (next);
    1284                 : 
    1285                 :       out:
    1286               0 :         dm_task_destroy(dmt);
    1287               0 :         return r;
    1288                 : }
    1289                 : 
    1290               0 : static uint64_t _get_device_size(const char *name)
    1291                 : {
    1292               0 :         uint64_t start, length, size = UINT64_C(0);
    1293                 :         struct dm_info info;
    1294                 :         char *target_type, *params;
    1295                 :         struct dm_task *dmt;
    1296               0 :         void *next = NULL;
    1297                 : 
    1298               0 :         if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
    1299               0 :                 return 0;
    1300                 : 
    1301               0 :         if (!_set_task_device(dmt, name, 0))
    1302               0 :                 goto out;
    1303                 : 
    1304               0 :         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
    1305               0 :                 goto out;
    1306                 : 
    1307               0 :         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
    1308               0 :                 goto out;
    1309                 : 
    1310               0 :         if (!dm_task_run(dmt))
    1311               0 :                 goto out;
    1312                 : 
    1313               0 :         if (!dm_task_get_info(dmt, &info) || !info.exists)
    1314                 :                 goto out;
    1315                 : 
    1316                 :         do {
    1317               0 :                 next = dm_get_next_target(dmt, next, &start, &length,
    1318                 :                                           &target_type, &params);
    1319               0 :                 size += length;
    1320               0 :         } while (next);
    1321                 : 
    1322                 :       out:
    1323               0 :         dm_task_destroy(dmt);
    1324               0 :         return size;
    1325                 : }
    1326                 : 
    1327               0 : static int _error_device(int argc __attribute((unused)), char **argv __attribute((unused)), void *data)
    1328                 : {
    1329               0 :         struct dm_names *names = (struct dm_names *) data;
    1330                 :         struct dm_task *dmt;
    1331                 :         const char *name;
    1332                 :         uint64_t size;
    1333               0 :         int r = 0;
    1334                 : 
    1335               0 :         if (data)
    1336               0 :                 name = names->name;
    1337                 :         else
    1338               0 :                 name = argv[1];
    1339                 : 
    1340               0 :         size = _get_device_size(name);
    1341                 : 
    1342               0 :         if (!(dmt = dm_task_create(DM_DEVICE_RELOAD)))
    1343               0 :                 return 0;
    1344                 : 
    1345               0 :         if (!_set_task_device(dmt, name, 0))
    1346               0 :                 goto error;
    1347                 : 
    1348               0 :         if (!dm_task_add_target(dmt, UINT64_C(0), size, "error", ""))
    1349               0 :                 goto error;
    1350                 : 
    1351               0 :         if (_switches[READ_ONLY] && !dm_task_set_ro(dmt))
    1352               0 :                 goto error;
    1353                 : 
    1354               0 :         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
    1355               0 :                 goto error;
    1356                 : 
    1357               0 :         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
    1358               0 :                 goto error;
    1359                 : 
    1360               0 :         if (!dm_task_run(dmt))
    1361               0 :                 goto error;
    1362                 : 
    1363               0 :         if (!_simple(DM_DEVICE_RESUME, name, 0, 0)) {
    1364               0 :                 _simple(DM_DEVICE_CLEAR, name, 0, 0);
    1365               0 :                 goto error;
    1366                 :         }
    1367                 : 
    1368               0 :         r = 1;
    1369                 : 
    1370                 : error:
    1371               0 :         dm_task_destroy(dmt);
    1372               0 :         return r;
    1373                 : }
    1374                 : 
    1375               0 : static int _remove(int argc, char **argv, void *data __attribute((unused)))
    1376                 : {
    1377                 :         int r;
    1378                 : 
    1379               0 :         if (_switches[FORCE_ARG] && argc > 1)
    1380               0 :                 r = _error_device(argc, argv, NULL);
    1381                 : 
    1382               0 :         return _simple(DM_DEVICE_REMOVE, argc > 1 ? argv[1] : NULL, 0, 0);
    1383                 : }
    1384                 : 
    1385               0 : static int _count_devices(int argc __attribute((unused)), char **argv __attribute((unused)), void *data __attribute((unused)))
    1386                 : {
    1387               0 :         _num_devices++;
    1388                 : 
    1389               0 :         return 1;
    1390                 : }
    1391                 : 
    1392               1 : static int _remove_all(int argc __attribute((unused)), char **argv __attribute((unused)), void *data __attribute((unused)))
    1393                 : {
    1394                 :         int r;
    1395                 : 
    1396                 :         /* Remove all closed devices */
    1397               1 :         r =  _simple(DM_DEVICE_REMOVE_ALL, "", 0, 0) | dm_mknodes(NULL);
    1398                 : 
    1399               1 :         if (!_switches[FORCE_ARG])
    1400               1 :                 return r;
    1401                 : 
    1402               0 :         _num_devices = 0;
    1403               0 :         r |= _process_all(argc, argv, 1, _count_devices);
    1404                 : 
    1405                 :         /* No devices left? */
    1406               0 :         if (!_num_devices)
    1407               0 :                 return r;
    1408                 : 
    1409               0 :         r |= _process_all(argc, argv, 1, _error_device);
    1410               0 :         r |= _simple(DM_DEVICE_REMOVE_ALL, "", 0, 0) | dm_mknodes(NULL);
    1411                 : 
    1412               0 :         _num_devices = 0;
    1413               0 :         r |= _process_all(argc, argv, 1, _count_devices);
    1414               0 :         if (!_num_devices)
    1415               0 :                 return r;
    1416                 : 
    1417               0 :         fprintf(stderr, "Unable to remove %d device(s).\n", _num_devices);
    1418                 : 
    1419               0 :         return r;
    1420                 : }
    1421                 : 
    1422               0 : static void _display_dev(struct dm_task *dmt, const char *name)
    1423                 : {
    1424                 :         struct dm_info info;
    1425                 : 
    1426               0 :         if (dm_task_get_info(dmt, &info))
    1427               0 :                 printf("%s\t(%u, %u)\n", name, info.major, info.minor);
    1428               0 : }
    1429                 : 
    1430               0 : static int _mknodes(int argc, char **argv, void *data __attribute((unused)))
    1431                 : {
    1432               0 :         return dm_mknodes(argc > 1 ? argv[1] : NULL);
    1433                 : }
    1434                 : 
    1435               0 : static int _exec_command(const char *name)
    1436                 : {
    1437                 :         int n;
    1438                 :         static char path[PATH_MAX];
    1439                 :         static char *args[ARGS_MAX + 1];
    1440                 :         static int argc = 0;
    1441                 :         char *c;
    1442                 :         pid_t pid;
    1443                 : 
    1444               0 :         if (argc < 0)
    1445               0 :                 return 0;
    1446                 : 
    1447               0 :         if (!dm_mknodes(name))
    1448               0 :                 return 0;
    1449                 : 
    1450               0 :         n = snprintf(path, sizeof(path), "%s/%s", dm_dir(), name);
    1451               0 :         if (n < 0 || n > (int) sizeof(path) - 1)
    1452               0 :                 return 0;
    1453                 : 
    1454               0 :         if (!argc) {
    1455               0 :                 c = _command;
    1456               0 :                 while (argc < ARGS_MAX) {
    1457               0 :                         while (*c && isspace(*c))
    1458               0 :                                 c++;
    1459               0 :                         if (!*c)
    1460               0 :                                 break;
    1461               0 :                         args[argc++] = c;
    1462               0 :                         while (*c && !isspace(*c))
    1463               0 :                                 c++;
    1464               0 :                         if (*c)
    1465               0 :                                 *c++ = '\0';
    1466                 :                 }
    1467                 : 
    1468               0 :                 if (!argc) {
    1469               0 :                         argc = -1;
    1470               0 :                         return 0;
    1471                 :                 }
    1472                 : 
    1473               0 :                 if (argc == ARGS_MAX) {
    1474               0 :                         err("Too many args to --exec\n");
    1475               0 :                         argc = -1;
    1476               0 :                         return 0;
    1477                 :                 }
    1478                 : 
    1479               0 :                 args[argc++] = path;
    1480               0 :                 args[argc] = NULL;
    1481                 :         }
    1482                 : 
    1483               0 :         if (!(pid = fork())) {
    1484               0 :                 execvp(args[0], args);
    1485               0 :                 _exit(127);
    1486               0 :         } else if (pid < (pid_t) 0)
    1487               0 :                 return 0;
    1488                 : 
    1489               0 :         TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0));
    1490                 : 
    1491               0 :         return 1;
    1492                 : }
    1493                 : 
    1494               0 : static int _status(int argc, char **argv, void *data)
    1495                 : {
    1496               0 :         int r = 0;
    1497                 :         struct dm_task *dmt;
    1498               0 :         void *next = NULL;
    1499                 :         uint64_t start, length;
    1500               0 :         char *target_type = NULL;
    1501                 :         char *params, *c;
    1502                 :         int cmd;
    1503               0 :         struct dm_names *names = (struct dm_names *) data;
    1504               0 :         const char *name = NULL;
    1505               0 :         int matched = 0;
    1506               0 :         int ls_only = 0;
    1507                 :         struct dm_info info;
    1508                 : 
    1509               0 :         if (data)
    1510               0 :                 name = names->name;
    1511                 :         else {
    1512               0 :                 if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
    1513               0 :                         return _process_all(argc, argv, 0, _status);
    1514               0 :                 if (argc == 2)
    1515               0 :                         name = argv[1];
    1516                 :         }
    1517                 : 
    1518               0 :         if (!strcmp(argv[0], "table"))
    1519               0 :                 cmd = DM_DEVICE_TABLE;
    1520                 :         else
    1521               0 :                 cmd = DM_DEVICE_STATUS;
    1522                 : 
    1523               0 :         if (!strcmp(argv[0], "ls"))
    1524               0 :                 ls_only = 1;
    1525                 : 
    1526               0 :         if (!(dmt = dm_task_create(cmd)))
    1527               0 :                 return 0;
    1528                 : 
    1529               0 :         if (!_set_task_device(dmt, name, 0))
    1530               0 :                 goto out;
    1531                 : 
    1532               0 :         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
    1533               0 :                 goto out;
    1534                 : 
    1535               0 :         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
    1536               0 :                 goto out;
    1537                 : 
    1538               0 :         if (!dm_task_run(dmt))
    1539               0 :                 goto out;
    1540                 : 
    1541               0 :         if (!dm_task_get_info(dmt, &info) || !info.exists)
    1542                 :                 goto out;
    1543                 : 
    1544               0 :         if (!name)
    1545               0 :                 name = dm_task_get_name(dmt);
    1546                 : 
    1547                 :         /* Fetch targets and print 'em */
    1548                 :         do {
    1549               0 :                 next = dm_get_next_target(dmt, next, &start, &length,
    1550                 :                                           &target_type, &params);
    1551                 :                 /* Skip if target type doesn't match */
    1552               0 :                 if (_switches[TARGET_ARG] &&
    1553               0 :                     (!target_type || strcmp(target_type, _target)))
    1554               0 :                         continue;
    1555               0 :                 if (ls_only) {
    1556               0 :                         if (!_switches[EXEC_ARG] || !_command ||
    1557               0 :                             _switches[VERBOSE_ARG])
    1558               0 :                                 _display_dev(dmt, name);
    1559               0 :                         next = NULL;
    1560               0 :                 } else if (!_switches[EXEC_ARG] || !_command ||
    1561               0 :                            _switches[VERBOSE_ARG]) {
    1562               0 :                         if (!matched && _switches[VERBOSE_ARG])
    1563               0 :                                 _display_info(dmt);
    1564               0 :                         if (data && !_switches[VERBOSE_ARG])
    1565               0 :                                 printf("%s: ", name);
    1566               0 :                         if (target_type) {
    1567                 :                                 /* Suppress encryption key */
    1568               0 :                                 if (!_switches[SHOWKEYS_ARG] &&
    1569                 :                                     cmd == DM_DEVICE_TABLE &&
    1570               0 :                                     !strcmp(target_type, "crypt")) {
    1571               0 :                                         c = params;
    1572               0 :                                         while (*c && *c != ' ')
    1573               0 :                                                 c++;
    1574               0 :                                         if (*c)
    1575               0 :                                                 c++;
    1576               0 :                                         while (*c && *c != ' ')
    1577               0 :                                                 *c++ = '0';
    1578                 :                                 }
    1579               0 :                                 printf("%" PRIu64 " %" PRIu64 " %s %s",
    1580                 :                                        start, length, target_type, params);
    1581                 :                         }
    1582               0 :                         printf("\n");
    1583                 :                 }
    1584               0 :                 matched = 1;
    1585               0 :         } while (next);
    1586                 : 
    1587               0 :         if (data && _switches[VERBOSE_ARG] && matched && !ls_only)
    1588               0 :                 printf("\n");
    1589                 : 
    1590               0 :         if (matched && _switches[EXEC_ARG] && _command && !_exec_command(name))
    1591               0 :                 goto out;
    1592                 : 
    1593               0 :         r = 1;
    1594                 : 
    1595                 :       out:
    1596               0 :         dm_task_destroy(dmt);
    1597               0 :         return r;
    1598                 : }
    1599                 : 
    1600                 : /* Show target names and their version numbers */
    1601               0 : static int _targets(int argc __attribute((unused)), char **argv __attribute((unused)), void *data __attribute((unused)))
    1602                 : {
    1603               0 :         int r = 0;
    1604                 :         struct dm_task *dmt;
    1605                 :         struct dm_versions *target;
    1606                 :         struct dm_versions *last_target;
    1607                 : 
    1608               0 :         if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
    1609               0 :                 return 0;
    1610                 : 
    1611               0 :         if (!dm_task_run(dmt))
    1612               0 :                 goto out;
    1613                 : 
    1614               0 :         target = dm_task_get_versions(dmt);
    1615                 : 
    1616                 :         /* Fetch targets and print 'em */
    1617                 :         do {
    1618               0 :                 last_target = target;
    1619                 : 
    1620               0 :                 printf("%-16s v%d.%d.%d\n", target->name, target->version[0],
    1621                 :                        target->version[1], target->version[2]);
    1622                 : 
    1623               0 :                 target = (void *) target + target->next;
    1624               0 :         } while (last_target != target);
    1625                 : 
    1626               0 :         r = 1;
    1627                 : 
    1628                 :       out:
    1629               0 :         dm_task_destroy(dmt);
    1630               0 :         return r;
    1631                 : }
    1632                 : 
    1633               0 : static int _info(int argc, char **argv, void *data)
    1634                 : {
    1635               0 :         int r = 0;
    1636                 : 
    1637                 :         struct dm_task *dmt;
    1638               0 :         struct dm_names *names = (struct dm_names *) data;
    1639               0 :         char *name = NULL;
    1640                 : 
    1641               0 :         if (data)
    1642               0 :                 name = names->name;
    1643                 :         else {
    1644               0 :                 if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
    1645               0 :                         return _process_all(argc, argv, 0, _info);
    1646               0 :                 if (argc == 2)
    1647               0 :                         name = argv[1];
    1648                 :         }
    1649                 : 
    1650               0 :         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
    1651               0 :                 return 0;
    1652                 : 
    1653               0 :         if (!_set_task_device(dmt, name, 0))
    1654               0 :                 goto out;
    1655                 : 
    1656               0 :         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
    1657               0 :                 goto out;
    1658                 : 
    1659               0 :         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
    1660               0 :                 goto out;
    1661                 : 
    1662               0 :         if (!dm_task_run(dmt))
    1663               0 :                 goto out;
    1664                 : 
    1665               0 :         r = _display_info(dmt);
    1666                 : 
    1667                 :       out:
    1668               0 :         dm_task_destroy(dmt);
    1669               0 :         return r;
    1670                 : }
    1671                 : 
    1672               0 : static int _deps(int argc, char **argv, void *data)
    1673                 : {
    1674               0 :         int r = 0;
    1675                 :         uint32_t i;
    1676                 :         struct dm_deps *deps;
    1677                 :         struct dm_task *dmt;
    1678                 :         struct dm_info info;
    1679               0 :         struct dm_names *names = (struct dm_names *) data;
    1680               0 :         char *name = NULL;
    1681                 : 
    1682               0 :         if (data)
    1683               0 :                 name = names->name;
    1684                 :         else {
    1685               0 :                 if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
    1686               0 :                         return _process_all(argc, argv, 0, _deps);
    1687               0 :                 if (argc == 2)
    1688               0 :                         name = argv[1];
    1689                 :         }
    1690                 : 
    1691               0 :         if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
    1692               0 :                 return 0;
    1693                 : 
    1694               0 :         if (!_set_task_device(dmt, name, 0))
    1695               0 :                 goto out;
    1696                 : 
    1697               0 :         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
    1698               0 :                 goto out;
    1699                 : 
    1700               0 :         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
    1701               0 :                 goto out;
    1702                 : 
    1703               0 :         if (!dm_task_run(dmt))
    1704               0 :                 goto out;
    1705                 : 
    1706               0 :         if (!dm_task_get_info(dmt, &info))
    1707               0 :                 goto out;
    1708                 : 
    1709               0 :         if (!(deps = dm_task_get_deps(dmt)))
    1710               0 :                 goto out;
    1711                 : 
    1712               0 :         if (!info.exists) {
    1713               0 :                 printf("Device does not exist.\n");
    1714               0 :                 r = 1;
    1715               0 :                 goto out;
    1716                 :         }
    1717                 : 
    1718               0 :         if (_switches[VERBOSE_ARG])
    1719               0 :                 _display_info(dmt);
    1720                 : 
    1721               0 :         if (data && !_switches[VERBOSE_ARG])
    1722               0 :                 printf("%s: ", name);
    1723               0 :         printf("%d dependencies\t:", deps->count);
    1724                 : 
    1725               0 :         for (i = 0; i < deps->count; i++)
    1726               0 :                 printf(" (%d, %d)",
    1727               0 :                        (int) MAJOR(deps->device[i]),
    1728               0 :                        (int) MINOR(deps->device[i]));
    1729               0 :         printf("\n");
    1730                 : 
    1731               0 :         if (data && _switches[VERBOSE_ARG])
    1732               0 :                 printf("\n");
    1733                 : 
    1734               0 :         r = 1;
    1735                 : 
    1736                 :       out:
    1737               0 :         dm_task_destroy(dmt);
    1738               0 :         return r;
    1739                 : }
    1740                 : 
    1741               0 : static int _display_name(int argc __attribute((unused)), char **argv __attribute((unused)), void *data)
    1742                 : {
    1743               0 :         struct dm_names *names = (struct dm_names *) data;
    1744                 : 
    1745               0 :         printf("%s\t(%d, %d)\n", names->name,
    1746               0 :                (int) MAJOR(names->dev), (int) MINOR(names->dev));
    1747                 : 
    1748               0 :         return 1;
    1749                 : }
    1750                 : 
    1751                 : /*
    1752                 :  * Tree drawing code
    1753                 :  */
    1754                 : 
    1755                 : enum {
    1756                 :         TR_DEVICE=0,    /* display device major:minor number */
    1757                 :         TR_TABLE,
    1758                 :         TR_STATUS,
    1759                 :         TR_ACTIVE,
    1760                 :         TR_RW,
    1761                 :         TR_OPENCOUNT,
    1762                 :         TR_UUID,
    1763                 :         TR_COMPACT,
    1764                 :         TR_TRUNCATE,
    1765                 :         TR_BOTTOMUP,
    1766                 :         NUM_TREEMODE,
    1767                 : };
    1768                 : 
    1769                 : static int _tree_switches[NUM_TREEMODE];
    1770                 : 
    1771                 : #define TR_PRINT_ATTRIBUTE ( _tree_switches[TR_ACTIVE] || \
    1772                 :                              _tree_switches[TR_RW] || \
    1773                 :                              _tree_switches[TR_OPENCOUNT] || \
    1774                 :                              _tree_switches[TR_UUID] )
    1775                 : 
    1776                 : #define TR_PRINT_TARGETS ( _tree_switches[TR_TABLE] || \
    1777                 :                            _tree_switches[TR_STATUS] )
    1778                 : 
    1779                 : /* Compact - fewer newlines */
    1780                 : #define TR_PRINT_COMPACT (_tree_switches[TR_COMPACT] && \
    1781                 :                           !TR_PRINT_ATTRIBUTE && \
    1782                 :                           !TR_PRINT_TARGETS)
    1783                 : 
    1784                 : /* FIXME Get rid of this */
    1785                 : #define MAX_DEPTH 100
    1786                 : 
    1787                 : /* Drawing character definition from pstree */
    1788                 : /* [pstree comment] UTF-8 defines by Johan Myreen, updated by Ben Winslow */
    1789                 : #define UTF_V   "\342\224\202"        /* U+2502, Vertical line drawing char */
    1790                 : #define UTF_VR  "\342\224\234"        /* U+251C, Vertical and right */
    1791                 : #define UTF_H   "\342\224\200"        /* U+2500, Horizontal */
    1792                 : #define UTF_UR  "\342\224\224"        /* U+2514, Up and right */
    1793                 : #define UTF_HD  "\342\224\254"        /* U+252C, Horizontal and down */
    1794                 : 
    1795                 : #define VT_BEG  "\033(0\017"  /* use graphic chars */
    1796                 : #define VT_END  "\033(B"      /* back to normal char set */
    1797                 : #define VT_V    "x"           /* see UTF definitions above */
    1798                 : #define VT_VR   "t"
    1799                 : #define VT_H    "q"
    1800                 : #define VT_UR   "m"
    1801                 : #define VT_HD   "w"
    1802                 : 
    1803                 : static struct {
    1804                 :         const char *empty_2;    /*    */
    1805                 :         const char *branch_2;   /* |- */
    1806                 :         const char *vert_2;     /* |  */
    1807                 :         const char *last_2;     /* `- */
    1808                 :         const char *single_3;   /* --- */
    1809                 :         const char *first_3;    /* -+- */
    1810                 : }
    1811                 : _tsym_ascii = {
    1812                 :         "  ",
    1813                 :         "|-",
    1814                 :         "| ",
    1815                 :         "`-",
    1816                 :         "---",
    1817                 :         "-+-"
    1818                 : },
    1819                 : _tsym_utf = {
    1820                 :         "  ",
    1821                 :         UTF_VR UTF_H,
    1822                 :         UTF_V " ",
    1823                 :         UTF_UR UTF_H,
    1824                 :         UTF_H UTF_H UTF_H,
    1825                 :         UTF_H UTF_HD UTF_H
    1826                 : },
    1827                 : _tsym_vt100 = {
    1828                 :         "  ",
    1829                 :         VT_BEG VT_VR VT_H VT_END,
    1830                 :         VT_BEG VT_V VT_END " ",
    1831                 :         VT_BEG VT_UR VT_H VT_END,
    1832                 :         VT_BEG VT_H VT_H VT_H VT_END,
    1833                 :         VT_BEG VT_H VT_HD VT_H VT_END
    1834                 : },
    1835                 : *_tsym = &_tsym_ascii;
    1836                 : 
    1837                 : /*
    1838                 :  * Tree drawing functions.
    1839                 :  */
    1840                 : /* FIXME Get rid of these statics - use dynamic struct */
    1841                 : /* FIXME Explain what these vars are for */
    1842                 : static int _tree_width[MAX_DEPTH], _tree_more[MAX_DEPTH];
    1843                 : static int _termwidth = 80;     /* Maximum output width */
    1844                 : static int _cur_x = 1;          /* Current horizontal output position */
    1845                 : static char _last_char = 0;
    1846                 : 
    1847               0 : static void _out_char(const unsigned c)
    1848                 : {
    1849                 :         /* Only first UTF-8 char counts */
    1850               0 :         _cur_x += ((c & 0xc0) != 0x80);
    1851                 : 
    1852               0 :         if (!_tree_switches[TR_TRUNCATE]) {
    1853               0 :                 putchar((int) c);
    1854               0 :                 return;
    1855                 :         }
    1856                 : 
    1857                 :         /* Truncation? */
    1858               0 :         if (_cur_x <= _termwidth)
    1859               0 :                 putchar((int) c);
    1860                 : 
    1861               0 :         if (_cur_x == _termwidth + 1 && ((c & 0xc0) != 0x80)) {
    1862               0 :                 if (_last_char || (c & 0x80)) {
    1863               0 :                         putchar('.');
    1864               0 :                         putchar('.');
    1865               0 :                         putchar('.');
    1866                 :                 } else {
    1867               0 :                         _last_char = c;
    1868               0 :                         _cur_x--;
    1869                 :                 }
    1870                 :         }
    1871                 : }
    1872                 : 
    1873               0 : static void _out_string(const char *str)
    1874                 : {
    1875               0 :         while (*str)
    1876               0 :                 _out_char((unsigned char) *str++);
    1877               0 : }
    1878                 : 
    1879                 : /* non-negative integers only */
    1880               0 : static unsigned _out_int(unsigned num)
    1881                 : {
    1882               0 :         unsigned digits = 0;
    1883                 :         unsigned divi;
    1884                 : 
    1885               0 :         if (!num) {
    1886               0 :                 _out_char('0');
    1887               0 :                 return 1;
    1888                 :         }
    1889                 : 
    1890                 :         /* non zero case */
    1891               0 :         for (divi = 1; num / divi; divi *= 10)
    1892               0 :                 digits++;
    1893                 : 
    1894               0 :         for (divi /= 10; divi; divi /= 10)
    1895               0 :                 _out_char('0' + (num / divi) % 10);
    1896                 : 
    1897               0 :         return digits;
    1898                 : }
    1899                 : 
    1900               0 : static void _out_newline(void)
    1901                 : {
    1902               0 :         if (_last_char && _cur_x == _termwidth)
    1903               0 :                 putchar(_last_char);
    1904               0 :         _last_char = 0;
    1905               0 :         putchar('\n');
    1906               0 :         _cur_x = 1;
    1907               0 : }
    1908                 : 
    1909               0 : static void _out_prefix(unsigned depth)
    1910                 : {
    1911                 :         unsigned x, d;
    1912                 : 
    1913               0 :         for (d = 0; d < depth; d++) {
    1914               0 :                 for (x = _tree_width[d] + 1; x > 0; x--)
    1915               0 :                         _out_char(' ');
    1916                 : 
    1917               0 :                 _out_string(d == depth - 1 ?
    1918               0 :                                 !_tree_more[depth] ? _tsym->last_2 : _tsym->branch_2
    1919               0 :                            : _tree_more[d + 1] ?
    1920               0 :                                 _tsym->vert_2 : _tsym->empty_2);
    1921                 :         }
    1922               0 : }
    1923                 : 
    1924                 : /*
    1925                 :  * Display tree
    1926                 :  */
    1927               0 : static void _display_tree_attributes(struct dm_tree_node *node)
    1928                 : {
    1929               0 :         int attr = 0;
    1930                 :         const char *uuid;
    1931                 :         const struct dm_info *info;
    1932                 : 
    1933               0 :         uuid = dm_tree_node_get_uuid(node);
    1934               0 :         info = dm_tree_node_get_info(node);
    1935                 : 
    1936               0 :         if (!info->exists)
    1937               0 :                 return;
    1938                 : 
    1939               0 :         if (_tree_switches[TR_ACTIVE]) {
    1940               0 :                 _out_string(attr++ ? ", " : " [");
    1941               0 :                 _out_string(info->suspended ? "SUSPENDED" : "ACTIVE");
    1942                 :         }
    1943                 : 
    1944               0 :         if (_tree_switches[TR_RW]) {
    1945               0 :                 _out_string(attr++ ? ", " : " [");
    1946               0 :                 _out_string(info->read_only ? "RO" : "RW");
    1947                 :         }
    1948                 : 
    1949               0 :         if (_tree_switches[TR_OPENCOUNT]) {
    1950               0 :                 _out_string(attr++ ? ", " : " [");
    1951               0 :                 (void) _out_int((unsigned) info->open_count);
    1952                 :         }
    1953                 : 
    1954               0 :         if (_tree_switches[TR_UUID]) {
    1955               0 :                 _out_string(attr++ ? ", " : " [");
    1956               0 :                 _out_string(uuid && *uuid ? uuid : "");
    1957                 :         }
    1958                 : 
    1959               0 :         if (attr)
    1960               0 :                 _out_char(']');
    1961                 : }
    1962                 : 
    1963               0 : static void _display_tree_node(struct dm_tree_node *node, unsigned depth,
    1964                 :                                unsigned first_child __attribute((unused)),
    1965                 :                                unsigned last_child, unsigned has_children)
    1966                 : {
    1967                 :         int offset;
    1968                 :         const char *name;
    1969                 :         const struct dm_info *info;
    1970               0 :         int first_on_line = 0;
    1971                 : 
    1972                 :         /* Sub-tree for targets has 2 more depth */
    1973               0 :         if (depth + 2 > MAX_DEPTH)
    1974               0 :                 return;
    1975                 : 
    1976               0 :         name = dm_tree_node_get_name(node);
    1977                 : 
    1978               0 :         if ((!name || !*name) && !_tree_switches[TR_DEVICE])
    1979               0 :                 return;
    1980                 : 
    1981                 :         /* Indicate whether there are more nodes at this depth */
    1982               0 :         _tree_more[depth] = !last_child;
    1983               0 :         _tree_width[depth] = 0;
    1984                 : 
    1985               0 :         if (_cur_x == 1)
    1986               0 :                 first_on_line = 1;
    1987                 : 
    1988               0 :         if (!TR_PRINT_COMPACT || first_on_line)
    1989               0 :                 _out_prefix(depth);
    1990                 : 
    1991                 :         /* Remember the starting point for compact */
    1992               0 :         offset = _cur_x;
    1993                 : 
    1994               0 :         if (TR_PRINT_COMPACT && !first_on_line)
    1995               0 :                 _out_string(_tree_more[depth] ? _tsym->first_3 : _tsym->single_3);
    1996                 : 
    1997                 :         /* display node */
    1998               0 :         if (name)
    1999               0 :                 _out_string(name);
    2000                 : 
    2001               0 :         info = dm_tree_node_get_info(node);
    2002                 : 
    2003               0 :         if (_tree_switches[TR_DEVICE]) {
    2004               0 :                 _out_string(name ? " (" : "(");
    2005               0 :                 (void) _out_int(info->major);
    2006               0 :                 _out_char(':');
    2007               0 :                 (void) _out_int(info->minor);
    2008               0 :                 _out_char(')');
    2009                 :         }
    2010                 : 
    2011                 :         /* display additional info */
    2012               0 :         if (TR_PRINT_ATTRIBUTE)
    2013               0 :                 _display_tree_attributes(node);
    2014                 : 
    2015               0 :         if (TR_PRINT_COMPACT)
    2016               0 :                 _tree_width[depth] = _cur_x - offset;
    2017                 : 
    2018               0 :         if (!TR_PRINT_COMPACT || !has_children)
    2019               0 :                 _out_newline();
    2020                 : 
    2021               0 :         if (TR_PRINT_TARGETS) {
    2022               0 :                 _tree_more[depth + 1] = has_children;
    2023                 :                 // FIXME _display_tree_targets(name, depth + 2);
    2024                 :         }
    2025                 : }
    2026                 : 
    2027                 : /*
    2028                 :  * Walk the dependency tree
    2029                 :  */
    2030               0 : static void _display_tree_walk_children(struct dm_tree_node *node,
    2031                 :                                         unsigned depth)
    2032                 : {
    2033                 :         struct dm_tree_node *child, *next_child;
    2034               0 :         void *handle = NULL;
    2035               0 :         uint32_t inverted = _tree_switches[TR_BOTTOMUP];
    2036               0 :         unsigned first_child = 1;
    2037                 :         unsigned has_children;
    2038                 : 
    2039               0 :         next_child = dm_tree_next_child(&handle, node, inverted);
    2040                 : 
    2041               0 :         while ((child = next_child)) {
    2042               0 :                 next_child = dm_tree_next_child(&handle, node, inverted);
    2043               0 :                 has_children =
    2044               0 :                     dm_tree_node_num_children(child, inverted) ? 1 : 0;
    2045                 : 
    2046               0 :                 _display_tree_node(child, depth, first_child,
    2047                 :                                    next_child ? 0U : 1U, has_children);
    2048                 : 
    2049               0 :                 if (has_children)
    2050               0 :                         _display_tree_walk_children(child, depth + 1);
    2051                 : 
    2052               0 :                 first_child = 0;
    2053                 :         }
    2054               0 : }
    2055                 : 
    2056               0 : static int _add_dep(int argc __attribute((unused)), char **argv __attribute((unused)), void *data)
    2057                 : {
    2058               0 :         struct dm_names *names = (struct dm_names *) data;
    2059                 : 
    2060               0 :         if (!dm_tree_add_dev(_dtree, (unsigned) MAJOR(names->dev), (unsigned) MINOR(names->dev)))
    2061               0 :                 return 0;
    2062                 : 
    2063               0 :         return 1;
    2064                 : }
    2065                 : 
    2066                 : /*
    2067                 :  * Create and walk dependency tree
    2068                 :  */
    2069               0 : static int _build_whole_deptree(void)
    2070                 : {
    2071               0 :         if (_dtree)
    2072               0 :                 return 1;
    2073                 : 
    2074               0 :         if (!(_dtree = dm_tree_create()))
    2075               0 :                 return 0;
    2076                 : 
    2077               0 :         if (!_process_all(0, NULL, 0, _add_dep))
    2078               0 :                 return 0;
    2079                 : 
    2080               0 :         return 1;
    2081                 : }
    2082                 : 
    2083               0 : static int _display_tree(int argc __attribute((unused)),
    2084                 :                          char **argv __attribute((unused)),
    2085                 :                          void *data __attribute((unused)))
    2086                 : {
    2087               0 :         if (!_build_whole_deptree())
    2088               0 :                 return 0;
    2089                 : 
    2090               0 :         _display_tree_walk_children(dm_tree_find_node(_dtree, 0, 0), 0);
    2091                 : 
    2092               0 :         return 1;
    2093                 : }
    2094                 : 
    2095                 : /*
    2096                 :  * Report device information
    2097                 :  */
    2098                 : 
    2099                 : /* dm specific display functions */
    2100                 : 
    2101               0 : static int _int32_disp(struct dm_report *rh,
    2102                 :                        struct dm_pool *mem __attribute((unused)),
    2103                 :                        struct dm_report_field *field, const void *data,
    2104                 :                        void *private __attribute((unused)))
    2105                 : {
    2106               0 :         const int32_t value = *(const int32_t *)data;
    2107                 : 
    2108               0 :         return dm_report_field_int32(rh, field, &value);
    2109                 : }
    2110                 : 
    2111               0 : static int _uint32_disp(struct dm_report *rh,
    2112                 :                         struct dm_pool *mem __attribute((unused)),
    2113                 :                         struct dm_report_field *field, const void *data,
    2114                 :                         void *private __attribute((unused)))
    2115                 : {
    2116               0 :         const uint32_t value = *(const int32_t *)data;
    2117                 : 
    2118               0 :         return dm_report_field_uint32(rh, field, &value);
    2119                 : }
    2120                 : 
    2121               0 : static int _dm_name_disp(struct dm_report *rh,
    2122                 :                          struct dm_pool *mem __attribute((unused)),
    2123                 :                          struct dm_report_field *field, const void *data,
    2124                 :                          void *private __attribute((unused)))
    2125                 : {
    2126               0 :         const char *name = dm_task_get_name((const struct dm_task *) data);
    2127                 : 
    2128               0 :         return dm_report_field_string(rh, field, &name);
    2129                 : }
    2130                 : 
    2131               0 : static int _dm_uuid_disp(struct dm_report *rh,
    2132                 :                          struct dm_pool *mem __attribute((unused)),
    2133                 :                          struct dm_report_field *field,
    2134                 :                          const void *data, void *private __attribute((unused)))
    2135                 : {
    2136               0 :         const char *uuid = dm_task_get_uuid((const struct dm_task *) data);
    2137                 : 
    2138               0 :         if (!uuid || !*uuid)
    2139               0 :                 uuid = "";
    2140                 : 
    2141               0 :         return dm_report_field_string(rh, field, &uuid);
    2142                 : }
    2143                 : 
    2144               0 : static int _dm_read_ahead_disp(struct dm_report *rh,
    2145                 :                                struct dm_pool *mem __attribute((unused)),
    2146                 :                                struct dm_report_field *field, const void *data,
    2147                 :                                void *private __attribute((unused)))
    2148                 : {
    2149                 :         uint32_t value;
    2150                 : 
    2151               0 :         if (!dm_task_get_read_ahead((const struct dm_task *) data, &value))
    2152               0 :                 value = 0;
    2153                 : 
    2154               0 :         return dm_report_field_uint32(rh, field, &value);
    2155                 : }
    2156                 : 
    2157               0 : static int _dm_info_status_disp(struct dm_report *rh,
    2158                 :                                 struct dm_pool *mem __attribute((unused)),
    2159                 :                                 struct dm_report_field *field, const void *data,
    2160                 :                                 void *private __attribute((unused)))
    2161                 : {
    2162                 :         char buf[5];
    2163               0 :         const char *s = buf;
    2164               0 :         const struct dm_info *info = data;
    2165                 : 
    2166               0 :         buf[0] = info->live_table ? 'L' : '-';
    2167               0 :         buf[1] = info->inactive_table ? 'I' : '-';
    2168               0 :         buf[2] = info->suspended ? 's' : '-';
    2169               0 :         buf[3] = info->read_only ? 'r' : 'w';
    2170               0 :         buf[4] = '\0';
    2171                 : 
    2172               0 :         return dm_report_field_string(rh, field, &s);
    2173                 : }
    2174                 : 
    2175               0 : static int _dm_info_table_loaded_disp(struct dm_report *rh,
    2176                 :                                       struct dm_pool *mem __attribute((unused)),
    2177                 :                                       struct dm_report_field *field,
    2178                 :                                       const void *data,
    2179                 :                                       void *private __attribute((unused)))
    2180                 : {
    2181               0 :         const struct dm_info *info = data;
    2182                 : 
    2183               0 :         if (info->live_table) {
    2184               0 :                 if (info->inactive_table)
    2185               0 :                         dm_report_field_set_value(field, "Both", NULL);
    2186                 :                 else
    2187               0 :                         dm_report_field_set_value(field, "Live", NULL);
    2188               0 :                 return 1;
    2189                 :         }
    2190                 : 
    2191               0 :         if (info->inactive_table)
    2192               0 :                 dm_report_field_set_value(field, "Inactive", NULL);
    2193                 :         else
    2194               0 :                 dm_report_field_set_value(field, "None", NULL);
    2195                 : 
    2196               0 :         return 1;
    2197                 : }
    2198                 : 
    2199               0 : static int _dm_info_suspended_disp(struct dm_report *rh,
    2200                 :                                    struct dm_pool *mem __attribute((unused)),
    2201                 :                                    struct dm_report_field *field,
    2202                 :                                    const void *data,
    2203                 :                                    void *private __attribute((unused)))
    2204                 : {
    2205               0 :         const struct dm_info *info = data;
    2206                 : 
    2207               0 :         if (info->suspended)
    2208               0 :                 dm_report_field_set_value(field, "Suspended", NULL);
    2209                 :         else
    2210               0 :                 dm_report_field_set_value(field, "Active", NULL);
    2211                 : 
    2212               0 :         return 1;
    2213                 : }
    2214                 : 
    2215               0 : static int _dm_info_read_only_disp(struct dm_report *rh,
    2216                 :                                    struct dm_pool *mem __attribute((unused)),
    2217                 :                                    struct dm_report_field *field,
    2218                 :                                    const void *data,
    2219                 :                                    void *private __attribute((unused)))
    2220                 : {
    2221               0 :         const struct dm_info *info = data;
    2222                 : 
    2223               0 :         if (info->read_only)
    2224               0 :                 dm_report_field_set_value(field, "Read-only", NULL);
    2225                 :         else
    2226               0 :                 dm_report_field_set_value(field, "Writeable", NULL);
    2227                 : 
    2228               0 :         return 1;
    2229                 : }
    2230                 : 
    2231                 : 
    2232               0 : static int _dm_info_devno_disp(struct dm_report *rh, struct dm_pool *mem,
    2233                 :                                struct dm_report_field *field, const void *data,
    2234                 :                                void *private)
    2235                 : {
    2236                 :         char buf[DM_MAX_TYPE_NAME], *repstr;
    2237               0 :         const struct dm_info *info = data;
    2238                 : 
    2239               0 :         if (!dm_pool_begin_object(mem, 8)) {
    2240               0 :                 log_error("dm_pool_begin_object failed");
    2241               0 :                 return 0;
    2242                 :         }
    2243                 : 
    2244               0 :         if (dm_snprintf(buf, sizeof(buf), "%d:%d",
    2245                 :                         info->major, info->minor) < 0) {
    2246               0 :                 log_error("dm_pool_alloc failed");
    2247               0 :                 goto out_abandon;
    2248                 :         }
    2249                 : 
    2250               0 :         if (!dm_pool_grow_object(mem, buf, strlen(buf) + 1)) {
    2251               0 :                 log_error("dm_pool_grow_object failed");
    2252               0 :                 goto out_abandon;
    2253                 :         }
    2254                 : 
    2255               0 :         repstr = dm_pool_end_object(mem);
    2256               0 :         dm_report_field_set_value(field, repstr, repstr);
    2257               0 :         return 1;
    2258                 : 
    2259                 :       out_abandon:
    2260               0 :         dm_pool_abandon_object(mem);
    2261               0 :         return 0;
    2262                 : }
    2263                 : 
    2264               0 : static int _dm_tree_names(struct dm_report *rh, struct dm_pool *mem,
    2265                 :                           struct dm_report_field *field, const void *data,
    2266                 :                           void *private, unsigned inverted)
    2267                 : {
    2268               0 :         const struct dm_tree_node *node = data;
    2269                 :         struct dm_tree_node *parent;
    2270               0 :         void *t = NULL;
    2271                 :         const char *name;
    2272               0 :         int first_node = 1;
    2273                 :         char *repstr;
    2274                 : 
    2275               0 :         if (!dm_pool_begin_object(mem, 16)) {
    2276               0 :                 log_error("dm_pool_begin_object failed");
    2277               0 :                 return 0;
    2278                 :         }
    2279                 : 
    2280               0 :         while ((parent = dm_tree_next_child(&t, node, inverted))) {
    2281               0 :                 name = dm_tree_node_get_name(parent);
    2282               0 :                 if (!name || !*name)
    2283               0 :                         continue;
    2284               0 :                 if (!first_node && !dm_pool_grow_object(mem, ",", 1)) {
    2285               0 :                         log_error("dm_pool_grow_object failed");
    2286               0 :                         goto out_abandon;
    2287                 :                 }
    2288               0 :                 if (!dm_pool_grow_object(mem, name, 0)) {
    2289               0 :                         log_error("dm_pool_grow_object failed");
    2290               0 :                         goto out_abandon;
    2291                 :                 }
    2292               0 :                 if (first_node)
    2293               0 :                         first_node = 0;
    2294                 :         }
    2295                 : 
    2296               0 :         if (!dm_pool_grow_object(mem, "\0", 1)) {
    2297               0 :                 log_error("dm_pool_grow_object failed");
    2298               0 :                 goto out_abandon;
    2299                 :         }
    2300                 : 
    2301               0 :         repstr = dm_pool_end_object(mem);
    2302               0 :         dm_report_field_set_value(field, repstr, repstr);
    2303               0 :         return 1;
    2304                 : 
    2305                 :       out_abandon:
    2306               0 :         dm_pool_abandon_object(mem);
    2307               0 :         return 0;
    2308                 : }
    2309                 : 
    2310               0 : static int _dm_deps_names_disp(struct dm_report *rh,
    2311                 :                                       struct dm_pool *mem,
    2312                 :                                       struct dm_report_field *field,
    2313                 :                                       const void *data, void *private)
    2314                 : {
    2315               0 :         return _dm_tree_names(rh, mem, field, data, private, 0);
    2316                 : }
    2317                 : 
    2318               0 : static int _dm_tree_parents_names_disp(struct dm_report *rh,
    2319                 :                                        struct dm_pool *mem,
    2320                 :                                        struct dm_report_field *field,
    2321                 :                                        const void *data, void *private)
    2322                 : {
    2323               0 :         return _dm_tree_names(rh, mem, field, data, private, 1);
    2324                 : }
    2325                 : 
    2326               0 : static int _dm_tree_parents_devs_disp(struct dm_report *rh, struct dm_pool *mem,
    2327                 :                                       struct dm_report_field *field,
    2328                 :                                       const void *data, void *private)
    2329                 : {
    2330               0 :         const struct dm_tree_node *node = data;
    2331                 :         struct dm_tree_node *parent;
    2332               0 :         void *t = NULL;
    2333                 :         const struct dm_info *info;
    2334               0 :         int first_node = 1;
    2335                 :         char buf[DM_MAX_TYPE_NAME], *repstr;
    2336                 : 
    2337               0 :         if (!dm_pool_begin_object(mem, 16)) {
    2338               0 :                 log_error("dm_pool_begin_object failed");
    2339               0 :                 return 0;
    2340                 :         }
    2341                 : 
    2342               0 :         while ((parent = dm_tree_next_child(&t, node, 1))) {
    2343               0 :                 info = dm_tree_node_get_info(parent);
    2344               0 :                 if (!info->major && !info->minor)
    2345               0 :                         continue;
    2346               0 :                 if (!first_node && !dm_pool_grow_object(mem, ",", 1)) {
    2347               0 :                         log_error("dm_pool_grow_object failed");
    2348               0 :                         goto out_abandon;
    2349                 :                 }
    2350               0 :                 if (dm_snprintf(buf, sizeof(buf), "%d:%d",
    2351                 :                                 info->major, info->minor) < 0) {
    2352               0 :                         log_error("dm_snprintf failed");
    2353               0 :                         goto out_abandon;
    2354                 :                 }
    2355               0 :                 if (!dm_pool_grow_object(mem, buf, 0)) {
    2356               0 :                         log_error("dm_pool_grow_object failed");
    2357               0 :                         goto out_abandon;
    2358                 :                 }
    2359               0 :                 if (first_node)
    2360               0 :                         first_node = 0;
    2361                 :         }
    2362                 : 
    2363               0 :         if (!dm_pool_grow_object(mem, "\0", 1)) {
    2364               0 :                 log_error("dm_pool_grow_object failed");
    2365               0 :                 goto out_abandon;
    2366                 :         }
    2367                 : 
    2368               0 :         repstr = dm_pool_end_object(mem);
    2369               0 :         dm_report_field_set_value(field, repstr, repstr);
    2370               0 :         return 1;
    2371                 : 
    2372                 :       out_abandon:
    2373               0 :         dm_pool_abandon_object(mem);
    2374               0 :         return 0;
    2375                 : }
    2376                 : 
    2377               0 : static int _dm_tree_parents_count_disp(struct dm_report *rh,
    2378                 :                                        struct dm_pool *mem,
    2379                 :                                        struct dm_report_field *field,
    2380                 :                                        const void *data, void *private)
    2381                 : {
    2382               0 :         const struct dm_tree_node *node = data;
    2383               0 :         int num_parent = dm_tree_node_num_children(node, 1);
    2384                 : 
    2385               0 :         return dm_report_field_int(rh, field, &num_parent);
    2386                 : }
    2387                 : 
    2388               0 : static int _dm_deps_disp(struct dm_report *rh, struct dm_pool *mem,
    2389                 :                          struct dm_report_field *field, const void *data,
    2390                 :                          void *private)
    2391                 : {
    2392               0 :         struct dm_deps *deps = (struct dm_deps *) data;
    2393                 :         int i;
    2394                 :         char buf[DM_MAX_TYPE_NAME], *repstr;
    2395                 : 
    2396               0 :         if (!dm_pool_begin_object(mem, 16)) {
    2397               0 :                 log_error("dm_pool_begin_object failed");
    2398               0 :                 return 0;
    2399                 :         }
    2400                 : 
    2401               0 :         for (i = 0; i < deps->count; i++) {
    2402               0 :                 if (dm_snprintf(buf, sizeof(buf), "%d:%d",
    2403               0 :                        (int) MAJOR(deps->device[i]),
    2404               0 :                        (int) MINOR(deps->device[i])) < 0) {
    2405               0 :                         log_error("dm_snprintf failed");
    2406               0 :                         goto out_abandon;
    2407                 :                 }
    2408               0 :                 if (!dm_pool_grow_object(mem, buf, 0)) {
    2409               0 :                         log_error("dm_pool_grow_object failed");
    2410               0 :                         goto out_abandon;
    2411                 :                 }
    2412               0 :                 if (i + 1 < deps->count && !dm_pool_grow_object(mem, ",", 1)) {
    2413               0 :                         log_error("dm_pool_grow_object failed");
    2414               0 :                         goto out_abandon;
    2415                 :                 }
    2416                 :         }
    2417                 : 
    2418               0 :         if (!dm_pool_grow_object(mem, "\0", 1)) {
    2419               0 :                 log_error("dm_pool_grow_object failed");
    2420               0 :                 goto out_abandon;
    2421                 :         }
    2422                 : 
    2423               0 :         repstr = dm_pool_end_object(mem);
    2424               0 :         dm_report_field_set_value(field, repstr, repstr);
    2425               0 :         return 1;
    2426                 : 
    2427                 :       out_abandon:
    2428               0 :         dm_pool_abandon_object(mem);
    2429               0 :         return 0;
    2430                 : }
    2431                 : 
    2432               0 : static int _dm_subsystem_disp(struct dm_report *rh,
    2433                 :                                struct dm_pool *mem __attribute((unused)),
    2434                 :                                struct dm_report_field *field, const void *data,
    2435                 :                                void *private __attribute((unused)))
    2436                 : {
    2437               0 :         return dm_report_field_string(rh, field, (const char **) data);
    2438                 : }
    2439                 : 
    2440               0 : static int _dm_vg_name_disp(struct dm_report *rh,
    2441                 :                              struct dm_pool *mem __attribute((unused)),
    2442                 :                              struct dm_report_field *field, const void *data,
    2443                 :                              void *private __attribute((unused)))
    2444                 : {
    2445                 : 
    2446               0 :         return dm_report_field_string(rh, field, (const char **) data);
    2447                 : }
    2448                 : 
    2449               0 : static int _dm_lv_name_disp(struct dm_report *rh,
    2450                 :                              struct dm_pool *mem __attribute((unused)),
    2451                 :                              struct dm_report_field *field, const void *data,
    2452                 :                              void *private __attribute((unused)))
    2453                 : 
    2454                 : {
    2455               0 :         return dm_report_field_string(rh, field, (const char **) data);
    2456                 : }
    2457                 : 
    2458               0 : static int _dm_lv_layer_name_disp(struct dm_report *rh,
    2459                 :                                    struct dm_pool *mem __attribute((unused)),
    2460                 :                                    struct dm_report_field *field, const void *data,
    2461                 :                                    void *private __attribute((unused)))
    2462                 : 
    2463                 : {
    2464               0 :         return dm_report_field_string(rh, field, (const char **) data);
    2465                 : }
    2466                 : 
    2467               0 : static void *_task_get_obj(void *obj)
    2468                 : {
    2469               0 :         return ((struct dmsetup_report_obj *)obj)->task;
    2470                 : }
    2471                 : 
    2472               0 : static void *_info_get_obj(void *obj)
    2473                 : {
    2474               0 :         return ((struct dmsetup_report_obj *)obj)->info;
    2475                 : }
    2476                 : 
    2477               0 : static void *_deps_get_obj(void *obj)
    2478                 : {
    2479               0 :         return dm_task_get_deps(((struct dmsetup_report_obj *)obj)->deps_task);
    2480                 : }
    2481                 : 
    2482               0 : static void *_tree_get_obj(void *obj)
    2483                 : {
    2484               0 :         return ((struct dmsetup_report_obj *)obj)->tree_node;
    2485                 : }
    2486                 : 
    2487               0 : static void *_split_name_get_obj(void *obj)
    2488                 : {
    2489               0 :         return ((struct dmsetup_report_obj *)obj)->split_name;
    2490                 : }
    2491                 : 
    2492                 : static const struct dm_report_object_type _report_types[] = {
    2493                 :         { DR_TASK, "Mapped Device Name", "", _task_get_obj },
    2494                 :         { DR_INFO, "Mapped Device Information", "", _info_get_obj },
    2495                 :         { DR_DEPS, "Mapped Device Relationship Information", "", _deps_get_obj },
    2496                 :         { DR_TREE, "Mapped Device Relationship Information", "", _tree_get_obj },
    2497                 :         { DR_NAME, "Mapped Device Name Components", "", _split_name_get_obj },
    2498                 :         { 0, "", "", NULL },
    2499                 : };
    2500                 : 
    2501                 : /* Column definitions */
    2502                 : #define OFFSET_OF(strct, field) (((char*)&((struct strct*)0)->field) - (char*)0)
    2503                 : #define STR (DM_REPORT_FIELD_TYPE_STRING)
    2504                 : #define NUM (DM_REPORT_FIELD_TYPE_NUMBER)
    2505                 : #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},
    2506                 : #define FIELD_F(type, sorttype, head, width, func, id, desc) {DR_ ## type, sorttype, 0, width, id, head, &_ ## func ## _disp, desc},
    2507                 : 
    2508                 : static const struct dm_report_field_type _report_fields[] = {
    2509                 : /* *INDENT-OFF* */
    2510                 : FIELD_F(TASK, STR, "Name", 16, dm_name, "name", "Name of mapped device.")
    2511                 : FIELD_F(TASK, STR, "UUID", 32, dm_uuid, "uuid", "Unique (optional) identifier for mapped device.")
    2512                 : 
    2513                 : /* FIXME Next one should be INFO */
    2514                 : FIELD_F(TASK, NUM, "RAhead", 6, dm_read_ahead, "read_ahead", "Read ahead in sectors.")
    2515                 : 
    2516                 : FIELD_F(INFO, STR, "Stat", 4, dm_info_status, "attr", "(L)ive, (I)nactive, (s)uspended, (r)ead-only, read-(w)rite.")
    2517                 : FIELD_F(INFO, STR, "Tables", 6, dm_info_table_loaded, "tables_loaded", "Which of the live and inactive table slots are filled.")
    2518                 : FIELD_F(INFO, STR, "Suspended", 9, dm_info_suspended, "suspended", "Whether the device is suspended.")
    2519                 : FIELD_F(INFO, STR, "Read-only", 9, dm_info_read_only, "readonly", "Whether the device is read-only or writeable.")
    2520                 : FIELD_F(INFO, STR, "DevNo", 5, dm_info_devno, "devno", "Device major and minor numbers")
    2521                 : FIELD_O(INFO, dm_info, NUM, "Maj", major, 3, int32, "major", "Block device major number.")
    2522                 : FIELD_O(INFO, dm_info, NUM, "Min", minor, 3, int32, "minor", "Block device minor number.")
    2523                 : FIELD_O(INFO, dm_info, NUM, "Open", open_count, 4, int32, "open", "Number of references to open device, if requested.")
    2524                 : FIELD_O(INFO, dm_info, NUM, "Targ", target_count, 4, int32, "segments", "Number of segments in live table, if present.")
    2525                 : FIELD_O(INFO, dm_info, NUM, "Event", event_nr, 6, uint32, "events", "Number of most recent event.")
    2526                 : 
    2527                 : FIELD_O(DEPS, dm_deps, NUM, "#Devs", count, 5, int32, "device_count", "Number of devices used by this one.")
    2528                 : FIELD_F(TREE, STR, "DevNames", 8, dm_deps_names, "devs_used", "List of names of mapped devices used by this one.")
    2529                 : FIELD_F(DEPS, STR, "DevNos", 6, dm_deps, "devnos_used", "List of device numbers of devices used by this one.")
    2530                 : 
    2531                 : FIELD_F(TREE, NUM, "#Refs", 5, dm_tree_parents_count, "device_ref_count", "Number of mapped devices referencing this one.")
    2532                 : FIELD_F(TREE, STR, "RefNames", 8, dm_tree_parents_names, "names_using_dev", "List of names of mapped devices using this one.")
    2533                 : FIELD_F(TREE, STR, "RefDevNos", 9, dm_tree_parents_devs, "devnos_using_dev", "List of device numbers of mapped devices using this one.")
    2534                 : 
    2535                 : FIELD_O(NAME, dm_split_name, STR, "Subsys", subsystem, 6, dm_subsystem, "subsystem", "Userspace subsystem responsible for this device.")
    2536                 : FIELD_O(NAME, dm_split_name, STR, "VG", vg_name, 4, dm_vg_name, "vg_name", "LVM Volume Group name.")
    2537                 : FIELD_O(NAME, dm_split_name, STR, "LV", lv_name, 4, dm_lv_name, "lv_name", "LVM Logical Volume name.")
    2538                 : FIELD_O(NAME, dm_split_name, STR, "LVLayer", lv_layer, 7, dm_lv_layer_name, "lv_layer", "LVM device layer.")
    2539                 : 
    2540                 : {0, 0, 0, 0, "", "", NULL, NULL},
    2541                 : /* *INDENT-ON* */
    2542                 : };
    2543                 : 
    2544                 : #undef STR
    2545                 : #undef NUM
    2546                 : #undef FIELD_O
    2547                 : #undef FIELD_F
    2548                 : 
    2549                 : static const char *default_report_options = "name,major,minor,attr,open,segments,events,uuid";
    2550                 : static const char *splitname_report_options = "vg_name,lv_name,lv_layer";
    2551                 : 
    2552               0 : static int _report_init(struct command *c)
    2553                 : {
    2554               0 :         char *options = (char *) default_report_options;
    2555               0 :         const char *keys = "";
    2556               0 :         const char *separator = " ";
    2557               0 :         int aligned = 1, headings = 1, buffered = 1, field_prefixes = 0;
    2558               0 :         int quoted = 1, columns_as_rows = 0;
    2559               0 :         uint32_t flags = 0;
    2560               0 :         size_t len = 0;
    2561               0 :         int r = 0;
    2562                 : 
    2563               0 :         if (c && !strcmp(c->name, "splitname"))
    2564               0 :                 options = (char *) splitname_report_options;
    2565                 : 
    2566                 :         /* emulate old dmsetup behaviour */
    2567               0 :         if (_switches[NOHEADINGS_ARG]) {
    2568               0 :                 separator = ":";
    2569               0 :                 aligned = 0;
    2570               0 :                 headings = 0;
    2571                 :         }
    2572                 : 
    2573               0 :         if (_switches[UNBUFFERED_ARG])
    2574               0 :                 buffered = 0;
    2575                 : 
    2576               0 :         if (_switches[ROWS_ARG])
    2577               0 :                 columns_as_rows = 1;
    2578                 : 
    2579               0 :         if (_switches[UNQUOTED_ARG])
    2580               0 :                 quoted = 0;
    2581                 : 
    2582               0 :         if (_switches[NAMEPREFIXES_ARG]) {
    2583               0 :                 aligned = 0;
    2584               0 :                 field_prefixes = 1;
    2585                 :         }
    2586                 : 
    2587               0 :         if (_switches[OPTIONS_ARG] && _string_args[OPTIONS_ARG]) {
    2588               0 :                 if (*_string_args[OPTIONS_ARG] != '+')
    2589               0 :                         options = _string_args[OPTIONS_ARG];
    2590                 :                 else {
    2591               0 :                         len = strlen(default_report_options) +
    2592               0 :                               strlen(_string_args[OPTIONS_ARG]) + 1;
    2593               0 :                         if (!(options = dm_malloc(len))) {
    2594               0 :                                 err("Failed to allocate option string.");
    2595               0 :                                 return 0;
    2596                 :                         }
    2597               0 :                         if (dm_snprintf(options, len, "%s,%s",
    2598                 :                                         default_report_options,
    2599               0 :                                         &_string_args[OPTIONS_ARG][1]) < 0) {
    2600               0 :                                 err("snprintf failed");
    2601               0 :                                 goto out;
    2602                 :                         }
    2603                 :                 }
    2604                 :         }
    2605                 : 
    2606               0 :         if (_switches[SORT_ARG] && _string_args[SORT_ARG]) {
    2607               0 :                 keys = _string_args[SORT_ARG];
    2608               0 :                 buffered = 1;
    2609               0 :                 if (c && (!strcmp(c->name, "status") || !strcmp(c->name, "table"))) {
    2610               0 :                         err("--sort is not yet supported with status and table");
    2611               0 :                         goto out;
    2612                 :                 }
    2613                 :         }
    2614                 : 
    2615               0 :         if (_switches[SEPARATOR_ARG] && _string_args[SEPARATOR_ARG]) {
    2616               0 :                 separator = _string_args[SEPARATOR_ARG];
    2617               0 :                 aligned = 0;
    2618                 :         }
    2619                 : 
    2620               0 :         if (aligned)
    2621               0 :                 flags |= DM_REPORT_OUTPUT_ALIGNED;
    2622                 : 
    2623               0 :         if (buffered)
    2624               0 :                 flags |= DM_REPORT_OUTPUT_BUFFERED;
    2625                 : 
    2626               0 :         if (headings)
    2627               0 :                 flags |= DM_REPORT_OUTPUT_HEADINGS;
    2628                 : 
    2629               0 :         if (field_prefixes)
    2630               0 :                 flags |= DM_REPORT_OUTPUT_FIELD_NAME_PREFIX;
    2631                 : 
    2632               0 :         if (!quoted)
    2633               0 :                 flags |= DM_REPORT_OUTPUT_FIELD_UNQUOTED;
    2634                 : 
    2635               0 :         if (columns_as_rows)
    2636               0 :                 flags |= DM_REPORT_OUTPUT_COLUMNS_AS_ROWS;
    2637                 : 
    2638               0 :         if (!(_report = dm_report_init(&_report_type,
    2639                 :                                        _report_types, _report_fields,
    2640                 :                                        options, separator, flags, keys, NULL)))
    2641               0 :                 goto out;
    2642                 : 
    2643               0 :         if ((_report_type & DR_TREE) && !_build_whole_deptree()) {
    2644               0 :                 err("Internal device dependency tree creation failed.");
    2645               0 :                 goto out;
    2646                 :         }
    2647                 : 
    2648               0 :         if (field_prefixes)
    2649               0 :                 dm_report_set_output_field_name_prefix(_report, "dm_");
    2650                 : 
    2651               0 :         r = 1;
    2652                 : 
    2653                 : out:
    2654               0 :         if (len)
    2655               0 :                 dm_free(options);
    2656                 : 
    2657               0 :         return r;
    2658                 : }
    2659                 : 
    2660                 : /*
    2661                 :  * List devices
    2662                 :  */
    2663               0 : static int _ls(int argc, char **argv, void *data)
    2664                 : {
    2665               0 :         if ((_switches[TARGET_ARG] && _target) ||
    2666               0 :             (_switches[EXEC_ARG] && _command))
    2667               0 :                 return _status(argc, argv, data);
    2668               0 :         else if ((_switches[TREE_ARG]))
    2669               0 :                 return _display_tree(argc, argv, data);
    2670                 :         else
    2671               0 :                 return _process_all(argc, argv, 0, _display_name);
    2672                 : }
    2673                 : 
    2674                 : static int _help(int argc, char **argv, void *data);
    2675                 : 
    2676                 : /*
    2677                 :  * Dispatch table
    2678                 :  */
    2679                 : static struct command _commands[] = {
    2680                 :         {"help", "[-c|-C|--columns]", 0, 0, _help},
    2681                 :         {"create", "<dev_name> [-j|--major <major> -m|--minor <minor>]\n"
    2682                 :           "\t                  [-U|--uid <uid>] [-G|--gid <gid>] [-M|--mode <octal_mode>]\n"
    2683                 :           "\t                  [-u|uuid <uuid>]\n"
    2684                 :           "\t                  [--notable | --table <table> | <table_file>]",
    2685                 :          1, 2, _create},
    2686                 :         {"remove", "[-f|--force] <device>", 0, 1, _remove},
    2687                 :         {"remove_all", "[-f|--force]", 0, 0, _remove_all},
    2688                 :         {"suspend", "[--noflush] <device>", 0, 1, _suspend},
    2689                 :         {"resume", "<device>", 0, 1, _resume},
    2690                 :         {"load", "<device> [<table_file>]", 0, 2, _load},
    2691                 :         {"clear", "<device>", 0, 1, _clear},
    2692                 :         {"reload", "<device> [<table_file>]", 0, 2, _load},
    2693                 :         {"rename", "<device> <new_name>", 1, 2, _rename},
    2694                 :         {"message", "<device> <sector> <message>", 2, -1, _message},
    2695                 :         {"ls", "[--target <target_type>] [--exec <command>] [--tree [-o options]]", 0, 0, _ls},
    2696                 :         {"info", "[<device>]", 0, 1, _info},
    2697                 :         {"deps", "[<device>]", 0, 1, _deps},
    2698                 :         {"status", "[<device>] [--target <target_type>]", 0, 1, _status},
    2699                 :         {"table", "[<device>] [--target <target_type>] [--showkeys]", 0, 1, _status},
    2700                 :         {"wait", "<device> [<event_nr>]", 0, 2, _wait},
    2701                 :         {"mknodes", "[<device>]", 0, 1, _mknodes},
    2702                 :         {"udevcreatecookie", "", 0, 0, _udevcreatecookie},
    2703                 :         {"udevreleasecookie", "[<cookie>]", 0, 1, _udevreleasecookie},
    2704                 :         {"udevflags", "<cookie>", 1, 1, _udevflags},
    2705                 :         {"udevcomplete", "<cookie>", 1, 1, _udevcomplete},
    2706                 :         {"udevcomplete_all", "", 0, 0, _udevcomplete_all},
    2707                 :         {"udevcookies", "", 0, 0, _udevcookies},
    2708                 :         {"targets", "", 0, 0, _targets},
    2709                 :         {"version", "", 0, 0, _version},
    2710                 :         {"setgeometry", "<device> <cyl> <head> <sect> <start>", 5, 5, _setgeometry},
    2711                 :         {"splitname", "<device> [<subsystem>]", 1, 2, _splitname},
    2712                 :         {NULL, NULL, 0, 0, NULL}
    2713                 : };
    2714                 : 
    2715               0 : static void _usage(FILE *out)
    2716                 : {
    2717                 :         int i;
    2718                 : 
    2719               0 :         fprintf(out, "Usage:\n\n");
    2720               0 :         fprintf(out, "dmsetup [--version] [-h|--help [-c|-C|--columns]]\n"
    2721                 :                 "        [-v|--verbose [-v|--verbose ...]]\n"
    2722                 :                 "        [-r|--readonly] [--noopencount] [--nolockfs] [--inactive]\n"
    2723                 :                 "        [--udevcookie] [--noudevrules] [--noudevsync] [-y|--yes]\n"
    2724                 :                 "        [--readahead [+]<sectors>|auto|none]\n"
    2725                 :                 "        [-c|-C|--columns] [-o <fields>] [-O|--sort <sort_fields>]\n"
    2726                 :                 "        [--nameprefixes] [--noheadings] [--separator <separator>]\n\n");
    2727               0 :         for (i = 0; _commands[i].name; i++)
    2728               0 :                 fprintf(out, "\t%s %s\n", _commands[i].name, _commands[i].help);
    2729               0 :         fprintf(out, "\n<device> may be device name or -u <uuid> or "
    2730                 :                      "-j <major> -m <minor>\n");
    2731               0 :         fprintf(out, "<fields> are comma-separated.  Use 'help -c' for list.\n");
    2732               0 :         fprintf(out, "Table_file contents may be supplied on stdin.\n");
    2733               0 :         fprintf(out, "Tree options are: ascii, utf, vt100; compact, inverted, notrunc;\n"
    2734                 :                      "                  [no]device, active, open, rw and uuid.\n");
    2735               0 :         fprintf(out, "\n");
    2736               0 : }
    2737                 : 
    2738               0 : static void _losetup_usage(FILE *out)
    2739                 : {
    2740               0 :         fprintf(out, "Usage:\n\n");
    2741               0 :         fprintf(out, "losetup [-d|-a] [-e encryption] "
    2742                 :                      "[-o offset] [-f|loop_device] [file]\n\n");
    2743               0 : }
    2744                 : 
    2745               0 : static int _help(int argc __attribute((unused)),
    2746                 :                  char **argv __attribute((unused)),
    2747                 :                  void *data __attribute((unused)))
    2748                 : {
    2749               0 :         _usage(stderr);
    2750                 : 
    2751               0 :         if (_switches[COLS_ARG]) {
    2752               0 :                 _switches[OPTIONS_ARG] = 1;
    2753               0 :                 _string_args[OPTIONS_ARG] = (char *) "help";
    2754               0 :                 _switches[SORT_ARG] = 0;
    2755                 : 
    2756               0 :                 if (_report) {
    2757               0 :                         dm_report_free(_report);
    2758               0 :                         _report = NULL;
    2759                 :                 }
    2760               0 :                 (void) _report_init(NULL);
    2761                 :         }
    2762                 : 
    2763               0 :         return 1;
    2764                 : }
    2765                 : 
    2766             603 : static struct command *_find_command(const char *name)
    2767                 : {
    2768                 :         int i;
    2769                 : 
    2770            2412 :         for (i = 0; _commands[i].name; i++)
    2771            2412 :                 if (!strcmp(_commands[i].name, name))
    2772             603 :                         return _commands + i;
    2773                 : 
    2774               0 :         return NULL;
    2775                 : }
    2776                 : 
    2777               0 : static int _process_tree_options(const char *options)
    2778                 : {
    2779                 :         const char *s, *end;
    2780                 :         struct winsize winsz;
    2781                 :         size_t len;
    2782                 : 
    2783                 :         /* Symbol set default */
    2784               0 :         if (!strcmp(nl_langinfo(CODESET), "UTF-8"))
    2785               0 :                 _tsym = &_tsym_utf;
    2786                 :         else
    2787               0 :                 _tsym = &_tsym_ascii;
    2788                 : 
    2789                 :         /* Default */
    2790               0 :         _tree_switches[TR_DEVICE] = 1;
    2791               0 :         _tree_switches[TR_TRUNCATE] = 1;
    2792                 : 
    2793                 :         /* parse */
    2794               0 :         for (s = options; s && *s; s++) {
    2795               0 :                 len = 0;
    2796               0 :                 for (end = s; *end && *end != ','; end++, len++)
    2797                 :                         ;
    2798               0 :                 if (!strncmp(s, "device", len))
    2799               0 :                         _tree_switches[TR_DEVICE] = 1;
    2800               0 :                 else if (!strncmp(s, "nodevice", len))
    2801               0 :                         _tree_switches[TR_DEVICE] = 0;
    2802               0 :                 else if (!strncmp(s, "status", len))
    2803               0 :                         _tree_switches[TR_STATUS] = 1;
    2804               0 :                 else if (!strncmp(s, "table", len))
    2805               0 :                         _tree_switches[TR_TABLE] = 1;
    2806               0 :                 else if (!strncmp(s, "active", len))
    2807               0 :                         _tree_switches[TR_ACTIVE] = 1;
    2808               0 :                 else if (!strncmp(s, "open", len))
    2809               0 :                         _tree_switches[TR_OPENCOUNT] = 1;
    2810               0 :                 else if (!strncmp(s, "uuid", len))
    2811               0 :                         _tree_switches[TR_UUID] = 1;
    2812               0 :                 else if (!strncmp(s, "rw", len))
    2813               0 :                         _tree_switches[TR_RW] = 1;
    2814               0 :                 else if (!strncmp(s, "utf", len))
    2815               0 :                         _tsym = &_tsym_utf;
    2816               0 :                 else if (!strncmp(s, "vt100", len))
    2817               0 :                         _tsym = &_tsym_vt100;
    2818               0 :                 else if (!strncmp(s, "ascii", len))
    2819               0 :                         _tsym = &_tsym_ascii;
    2820               0 :                 else if (!strncmp(s, "inverted", len))
    2821               0 :                         _tree_switches[TR_BOTTOMUP] = 1;
    2822               0 :                 else if (!strncmp(s, "compact", len))
    2823               0 :                         _tree_switches[TR_COMPACT] = 1;
    2824               0 :                 else if (!strncmp(s, "notrunc", len))
    2825               0 :                         _tree_switches[TR_TRUNCATE] = 0;
    2826                 :                 else {
    2827               0 :                         fprintf(stderr, "Tree options not recognised: %s\n", s);
    2828               0 :                         return 0;
    2829                 :                 }
    2830               0 :                 if (!*end)
    2831               0 :                         break;
    2832               0 :                 s = end;
    2833                 :         }
    2834                 : 
    2835                 :         /* Truncation doesn't work well with vt100 drawing char */
    2836               0 :         if (_tsym != &_tsym_vt100)
    2837               0 :                 if (ioctl(1, (unsigned long) TIOCGWINSZ, &winsz) >= 0 && winsz.ws_col > 3)
    2838               0 :                         _termwidth = winsz.ws_col - 3;
    2839                 : 
    2840               0 :         return 1;
    2841                 : }
    2842                 : 
    2843                 : /*
    2844                 :  * Returns the full absolute path, or NULL if the path could
    2845                 :  * not be resolved.
    2846                 :  */
    2847               0 : static char *_get_abspath(const char *path)
    2848                 : {
    2849                 :         char *_path;
    2850                 : 
    2851                 : #ifdef HAVE_CANONICALIZE_FILE_NAME
    2852               0 :         _path = canonicalize_file_name(path);
    2853                 : #else
    2854                 :         /* FIXME Provide alternative */
    2855                 : #endif
    2856               0 :         return _path;
    2857                 : }
    2858                 : 
    2859               0 : static char *parse_loop_device_name(const char *dev, const char *dev_dir)
    2860                 : {
    2861                 :         char *buf;
    2862                 :         char *device;
    2863                 : 
    2864               0 :         if (!(buf = dm_malloc(PATH_MAX)))
    2865               0 :                 return NULL;
    2866                 : 
    2867               0 :         if (dev[0] == '/') {
    2868               0 :                 if (!(device = _get_abspath(dev)))
    2869               0 :                         goto error;
    2870                 : 
    2871               0 :                 if (strncmp(device, dev_dir, strlen(dev_dir)))
    2872               0 :                         goto error;
    2873                 : 
    2874                 :                 /* If dev_dir does not end in a slash, ensure that the
    2875                 :                    following byte in the device string is "/".  */
    2876               0 :                 if (dev_dir[strlen(dev_dir) - 1] != '/' &&
    2877               0 :                     device[strlen(dev_dir)] != '/')
    2878               0 :                         goto error;
    2879                 : 
    2880               0 :                 strncpy(buf, strrchr(device, '/') + 1, (size_t) PATH_MAX);
    2881               0 :                 dm_free(device);
    2882                 : 
    2883                 :         } else {
    2884                 :                 /* check for device number */
    2885               0 :                 if (!strncmp(dev, "loop", strlen("loop")))
    2886               0 :                         strncpy(buf, dev, (size_t) PATH_MAX);
    2887                 :                 else
    2888               0 :                         goto error;
    2889                 :         }
    2890                 : 
    2891               0 :         return buf;
    2892                 : 
    2893                 : error:
    2894               0 :         return NULL;
    2895                 : }
    2896                 : 
    2897                 : /*
    2898                 :  *  create a table for a mapped device using the loop target.
    2899                 :  */
    2900               0 : static int _loop_table(char *table, size_t tlen, char *file,
    2901                 :                        char *dev __attribute((unused)), off_t off)
    2902                 : {
    2903                 :         struct stat fbuf;
    2904                 :         off_t size, sectors;
    2905               0 :         int fd = -1;
    2906                 : #ifdef HAVE_SYS_STATVFS_H
    2907                 :         struct statvfs fsbuf;
    2908                 :         off_t blksize;
    2909                 : #endif
    2910                 : 
    2911               0 :         if (!_switches[READ_ONLY])
    2912               0 :                 fd = open(file, O_RDWR);
    2913                 : 
    2914               0 :         if (fd < 0) {
    2915               0 :                 _switches[READ_ONLY]++;
    2916               0 :                 fd = open(file, O_RDONLY);
    2917                 :         }
    2918                 : 
    2919               0 :         if (fd < 0)
    2920               0 :                 goto error;
    2921                 : 
    2922               0 :         if (fstat(fd, &fbuf))
    2923               0 :                 goto error;
    2924                 : 
    2925               0 :         size = (fbuf.st_size - off);
    2926               0 :         sectors = size >> SECTOR_SHIFT;
    2927                 : 
    2928               0 :         if (_switches[VERBOSE_ARG])
    2929               0 :                 fprintf(stderr, "losetup: set loop size to %llukB "
    2930                 :                         "(%llu sectors)\n", (long long unsigned) sectors >> 1,
    2931                 :                         (long long unsigned) sectors);
    2932                 : 
    2933                 : #ifdef HAVE_SYS_STATVFS_H
    2934                 :         if (fstatvfs(fd, &fsbuf))
    2935                 :                 goto error;
    2936                 : 
    2937                 :         /* FIXME Fragment size currently unused */
    2938                 :         blksize = fsbuf.f_frsize;
    2939                 : #endif
    2940                 : 
    2941               0 :         close(fd);
    2942                 : 
    2943               0 :         if (dm_snprintf(table, tlen, "%llu %llu loop %s %llu\n", 0ULL,
    2944                 :                         (long long unsigned)sectors, file, off) < 0)
    2945               0 :                 return 0;
    2946                 : 
    2947               0 :         if (_switches[VERBOSE_ARG] > 1)
    2948               0 :                 fprintf(stderr, "Table: %s\n", table);
    2949                 : 
    2950               0 :         return 1;
    2951                 : 
    2952                 : error:
    2953               0 :         if (fd > -1)
    2954               0 :                 close(fd);
    2955               0 :         return 0;
    2956                 : }
    2957                 : 
    2958                 : 
    2959                 : 
    2960               0 : static int _process_losetup_switches(const char *base, int *argc, char ***argv,
    2961                 :                                      const char *dev_dir)
    2962                 : {
    2963                 :         static int ind;
    2964                 :         int c;
    2965               0 :         int encrypt_loop = 0, delete = 0, find = 0, show_all = 0;
    2966               0 :         char *device_name = NULL;
    2967               0 :         char *loop_file = NULL;
    2968               0 :         off_t offset = 0;
    2969                 : 
    2970                 : #ifdef HAVE_GETOPTLONG
    2971                 :         static struct option long_options[] = {
    2972                 :                 {0, 0, 0, 0}
    2973                 :         };
    2974                 : #endif
    2975                 : 
    2976               0 :         optarg = 0;
    2977               0 :         optind = OPTIND_INIT;
    2978               0 :         while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "ade:fo:v",
    2979                 :                                             long_options, NULL)) != -1 ) {
    2980               0 :                 if (c == ':' || c == '?')
    2981               0 :                         return 0;
    2982               0 :                 if (c == 'a')
    2983               0 :                         show_all++;
    2984               0 :                 if (c == 'd')
    2985               0 :                         delete++;
    2986               0 :                 if (c == 'e')
    2987               0 :                         encrypt_loop++;
    2988               0 :                 if (c == 'f')
    2989               0 :                         find++;
    2990               0 :                 if (c == 'o')
    2991               0 :                         offset = atoi(optarg);
    2992               0 :                 if (c == 'v')
    2993               0 :                         _switches[VERBOSE_ARG]++;
    2994                 :         }
    2995                 : 
    2996               0 :         *argv += optind ;
    2997               0 :         *argc -= optind ;
    2998                 : 
    2999               0 :         if (encrypt_loop){
    3000               0 :                 fprintf(stderr, "%s: Sorry, cryptoloop is not yet implemented "
    3001                 :                                 "in this version.\n", base);
    3002               0 :                 return 0;
    3003                 :         }
    3004                 : 
    3005               0 :         if (show_all) {
    3006               0 :                 fprintf(stderr, "%s: Sorry, show all is not yet implemented "
    3007                 :                                 "in this version.\n", base);
    3008               0 :                 return 0;
    3009                 :         }
    3010                 : 
    3011               0 :         if (find) {
    3012               0 :                 fprintf(stderr, "%s: Sorry, find is not yet implemented "
    3013                 :                                 "in this version.\n", base);
    3014               0 :                 if (!*argc)
    3015               0 :                         return 0;
    3016                 :         }
    3017                 : 
    3018               0 :         if (!*argc) {
    3019               0 :                 fprintf(stderr, "%s: Please specify loop_device.\n", base);
    3020               0 :                 _losetup_usage(stderr);
    3021               0 :                 return 0;
    3022                 :         }
    3023                 : 
    3024               0 :         if (!(device_name = parse_loop_device_name((*argv)[0], dev_dir))) {
    3025               0 :                 fprintf(stderr, "%s: Could not parse loop_device %s\n",
    3026               0 :                         base, (*argv)[0]);
    3027               0 :                 _losetup_usage(stderr);
    3028               0 :                 return 0;
    3029                 :         }
    3030                 : 
    3031               0 :         if (delete) {
    3032               0 :                 *argc = 2;
    3033                 : 
    3034               0 :                 (*argv)[1] = device_name;
    3035               0 :                 (*argv)[0] = (char *) "remove";
    3036                 : 
    3037               0 :                 return 1;
    3038                 :         }
    3039                 : 
    3040               0 :         if (*argc != 2) {
    3041               0 :                 fprintf(stderr, "%s: Too few arguments\n", base);
    3042               0 :                 _losetup_usage(stderr);
    3043               0 :                 dm_free(device_name);
    3044               0 :                 return 0;
    3045                 :         }
    3046                 : 
    3047                 :         /* FIXME move these to make them available to native dmsetup */
    3048               0 :         if (!(loop_file = _get_abspath((*argv)[(find) ? 0 : 1]))) {
    3049               0 :                 fprintf(stderr, "%s: Could not parse loop file name %s\n",
    3050               0 :                         base, (*argv)[1]);
    3051               0 :                 _losetup_usage(stderr);
    3052               0 :                 dm_free(device_name);
    3053               0 :                 return 0;
    3054                 :         }
    3055                 : 
    3056                 :         /* FIXME Missing free */
    3057               0 :         _table = dm_malloc(LOOP_TABLE_SIZE);
    3058               0 :         if (!_loop_table(_table, (size_t) LOOP_TABLE_SIZE, loop_file, device_name, offset)) {
    3059               0 :                 fprintf(stderr, "Could not build device-mapper table for %s\n", (*argv)[0]);
    3060               0 :                 dm_free(device_name);
    3061               0 :                 return 0;
    3062                 :         }
    3063               0 :         _switches[TABLE_ARG]++;
    3064                 : 
    3065               0 :         (*argv)[0] = (char *) "create";
    3066               0 :         (*argv)[1] = device_name ;
    3067                 : 
    3068               0 :         return 1;
    3069                 : }
    3070                 : 
    3071             603 : static int _process_switches(int *argc, char ***argv, const char *dev_dir)
    3072                 : {
    3073                 :         char *base, *namebase, *s;
    3074                 :         static int ind;
    3075                 :         int c, r;
    3076                 : 
    3077                 : #ifdef HAVE_GETOPTLONG
    3078                 :         static struct option long_options[] = {
    3079                 :                 {"readonly", 0, &ind, READ_ONLY},
    3080                 :                 {"columns", 0, &ind, COLS_ARG},
    3081                 :                 {"exec", 1, &ind, EXEC_ARG},
    3082                 :                 {"force", 0, &ind, FORCE_ARG},
    3083                 :                 {"gid", 1, &ind, GID_ARG},
    3084                 :                 {"help", 0, &ind, HELP_ARG},
    3085                 :                 {"inactive", 0, &ind, INACTIVE_ARG},
    3086                 :                 {"major", 1, &ind, MAJOR_ARG},
    3087                 :                 {"minor", 1, &ind, MINOR_ARG},
    3088                 :                 {"mode", 1, &ind, MODE_ARG},
    3089                 :                 {"nameprefixes", 0, &ind, NAMEPREFIXES_ARG},
    3090                 :                 {"noflush", 0, &ind, NOFLUSH_ARG},
    3091                 :                 {"noheadings", 0, &ind, NOHEADINGS_ARG},
    3092                 :                 {"nolockfs", 0, &ind, NOLOCKFS_ARG},
    3093                 :                 {"noopencount", 0, &ind, NOOPENCOUNT_ARG},
    3094                 :                 {"notable", 0, &ind, NOTABLE_ARG},
    3095                 :                 {"udevcookie", 1, &ind, UDEVCOOKIE_ARG},
    3096                 :                 {"noudevrules", 0, &ind, NOUDEVRULES_ARG},
    3097                 :                 {"noudevsync", 0, &ind, NOUDEVSYNC_ARG},
    3098                 :                 {"options", 1, &ind, OPTIONS_ARG},
    3099                 :                 {"readahead", 1, &ind, READAHEAD_ARG},
    3100                 :                 {"rows", 0, &ind, ROWS_ARG},
    3101                 :                 {"separator", 1, &ind, SEPARATOR_ARG},
    3102                 :                 {"showkeys", 0, &ind, SHOWKEYS_ARG},
    3103                 :                 {"sort", 1, &ind, SORT_ARG},
    3104                 :                 {"table", 1, &ind, TABLE_ARG},
    3105                 :                 {"target", 1, &ind, TARGET_ARG},
    3106                 :                 {"tree", 0, &ind, TREE_ARG},
    3107                 :                 {"uid", 1, &ind, UID_ARG},
    3108                 :                 {"uuid", 1, &ind, UUID_ARG},
    3109                 :                 {"unbuffered", 0, &ind, UNBUFFERED_ARG},
    3110                 :                 {"unquoted", 0, &ind, UNQUOTED_ARG},
    3111                 :                 {"verbose", 1, &ind, VERBOSE_ARG},
    3112                 :                 {"version", 0, &ind, VERSION_ARG},
    3113                 :                 {"yes", 0, &ind, YES_ARG},
    3114                 :                 {0, 0, 0, 0}
    3115                 :         };
    3116                 : #else
    3117                 :         struct option long_options;
    3118                 : #endif
    3119                 : 
    3120                 :         /*
    3121                 :          * Zero all the index counts.
    3122                 :          */
    3123             603 :         memset(&_switches, 0, sizeof(_switches));
    3124             603 :         memset(&_int_args, 0, sizeof(_int_args));
    3125             603 :         _read_ahead_flags = 0;
    3126                 : 
    3127             603 :         namebase = strdup((*argv)[0]);
    3128             603 :         base = basename(namebase);
    3129                 : 
    3130             603 :         if (!strcmp(base, "devmap_name")) {
    3131               0 :                 free(namebase);
    3132               0 :                 _switches[COLS_ARG]++;
    3133               0 :                 _switches[NOHEADINGS_ARG]++;
    3134               0 :                 _switches[OPTIONS_ARG]++;
    3135               0 :                 _switches[MAJOR_ARG]++;
    3136               0 :                 _switches[MINOR_ARG]++;
    3137               0 :                 _string_args[OPTIONS_ARG] = (char *) "name";
    3138                 : 
    3139               0 :                 if (*argc == 3) {
    3140               0 :                         _int_args[MAJOR_ARG] = atoi((*argv)[1]);
    3141               0 :                         _int_args[MINOR_ARG] = atoi((*argv)[2]);
    3142               0 :                         *argc -= 2;
    3143               0 :                         *argv += 2;
    3144               0 :                 } else if ((*argc == 2) &&
    3145               0 :                            (2 == sscanf((*argv)[1], "%i:%i",
    3146                 :                                         &_int_args[MAJOR_ARG],
    3147                 :                                         &_int_args[MINOR_ARG]))) {
    3148               0 :                         *argc -= 1;
    3149               0 :                         *argv += 1;
    3150                 :                 } else {
    3151               0 :                         fprintf(stderr, "Usage: devmap_name <major> <minor>\n");
    3152               0 :                         return 0;
    3153                 :                 }
    3154                 : 
    3155               0 :                 (*argv)[0] = (char *) "info";
    3156               0 :                 return 1;
    3157                 :         }
    3158                 : 
    3159             603 :         if (!strcmp(base, "losetup") || !strcmp(base, "dmlosetup")){
    3160               0 :                 r = _process_losetup_switches(base, argc, argv, dev_dir);
    3161               0 :                 free(namebase);
    3162               0 :                 return r;
    3163                 :         }
    3164                 : 
    3165             603 :         free(namebase);
    3166                 : 
    3167             603 :         optarg = 0;
    3168             603 :         optind = OPTIND_INIT;
    3169            1206 :         while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCfG:hj:m:M:no:O:ru:U:vy",
    3170                 :                                             long_options, NULL)) != -1) {
    3171               0 :                 if (c == ':' || c == '?')
    3172               0 :                         return 0;
    3173               0 :                 if (c == 'h' || ind == HELP_ARG)
    3174               0 :                         _switches[HELP_ARG]++;
    3175               0 :                 if (c == 'c' || c == 'C' || ind == COLS_ARG)
    3176               0 :                         _switches[COLS_ARG]++;
    3177               0 :                 if (c == 'f' || ind == FORCE_ARG)
    3178               0 :                         _switches[FORCE_ARG]++;
    3179               0 :                 if (c == 'r' || ind == READ_ONLY)
    3180               0 :                         _switches[READ_ONLY]++;
    3181               0 :                 if (c == 'j' || ind == MAJOR_ARG) {
    3182               0 :                         _switches[MAJOR_ARG]++;
    3183               0 :                         _int_args[MAJOR_ARG] = atoi(optarg);
    3184                 :                 }
    3185               0 :                 if (c == 'm' || ind == MINOR_ARG) {
    3186               0 :                         _switches[MINOR_ARG]++;
    3187               0 :                         _int_args[MINOR_ARG] = atoi(optarg);
    3188                 :                 }
    3189               0 :                 if (c == 'n' || ind == NOTABLE_ARG)
    3190               0 :                         _switches[NOTABLE_ARG]++;
    3191               0 :                 if (c == 'o' || ind == OPTIONS_ARG) {
    3192               0 :                         _switches[OPTIONS_ARG]++;
    3193               0 :                         _string_args[OPTIONS_ARG] = optarg;
    3194                 :                 }
    3195               0 :                 if (ind == SEPARATOR_ARG) {
    3196               0 :                         _switches[SEPARATOR_ARG]++;
    3197               0 :                         _string_args[SEPARATOR_ARG] = optarg;
    3198                 :                 }
    3199               0 :                 if (c == 'O' || ind == SORT_ARG) {
    3200               0 :                         _switches[SORT_ARG]++;
    3201               0 :                         _string_args[SORT_ARG] = optarg;
    3202                 :                 }
    3203               0 :                 if (c == 'v' || ind == VERBOSE_ARG)
    3204               0 :                         _switches[VERBOSE_ARG]++;
    3205               0 :                 if (c == 'u' || ind == UUID_ARG) {
    3206               0 :                         _switches[UUID_ARG]++;
    3207               0 :                         _uuid = optarg;
    3208                 :                 }
    3209               0 :                 if (c == 'y' || ind == YES_ARG)
    3210               0 :                         _switches[YES_ARG]++;
    3211               0 :                 if (ind == UDEVCOOKIE_ARG) {
    3212               0 :                         _switches[UDEVCOOKIE_ARG]++;
    3213               0 :                         _udev_cookie = _get_cookie_value(optarg);
    3214                 :                 }
    3215               0 :                 if (ind == NOUDEVRULES_ARG)
    3216               0 :                         _switches[NOUDEVRULES_ARG]++;
    3217               0 :                 if (ind == NOUDEVSYNC_ARG)
    3218               0 :                         _switches[NOUDEVSYNC_ARG]++;
    3219               0 :                 if (c == 'G' || ind == GID_ARG) {
    3220               0 :                         _switches[GID_ARG]++;
    3221               0 :                         _int_args[GID_ARG] = atoi(optarg);
    3222                 :                 }
    3223               0 :                 if (c == 'U' || ind == UID_ARG) {
    3224               0 :                         _switches[UID_ARG]++;
    3225               0 :                         _int_args[UID_ARG] = atoi(optarg);
    3226                 :                 }
    3227               0 :                 if (c == 'M' || ind == MODE_ARG) {
    3228               0 :                         _switches[MODE_ARG]++;
    3229                 :                         /* FIXME Accept modes as per chmod */
    3230               0 :                         _int_args[MODE_ARG] = (int) strtol(optarg, NULL, 8);
    3231                 :                 }
    3232               0 :                 if ((ind == EXEC_ARG)) {
    3233               0 :                         _switches[EXEC_ARG]++;
    3234               0 :                         _command = optarg;
    3235                 :                 }
    3236               0 :                 if ((ind == TARGET_ARG)) {
    3237               0 :                         _switches[TARGET_ARG]++;
    3238               0 :                         _target = optarg;
    3239                 :                 }
    3240               0 :                 if ((ind == INACTIVE_ARG))
    3241               0 :                         _switches[INACTIVE_ARG]++;
    3242               0 :                 if ((ind == NAMEPREFIXES_ARG))
    3243               0 :                         _switches[NAMEPREFIXES_ARG]++;
    3244               0 :                 if ((ind == NOFLUSH_ARG))
    3245               0 :                         _switches[NOFLUSH_ARG]++;
    3246               0 :                 if ((ind == NOHEADINGS_ARG))
    3247               0 :                         _switches[NOHEADINGS_ARG]++;
    3248               0 :                 if ((ind == NOLOCKFS_ARG))
    3249               0 :                         _switches[NOLOCKFS_ARG]++;
    3250               0 :                 if ((ind == NOOPENCOUNT_ARG))
    3251               0 :                         _switches[NOOPENCOUNT_ARG]++;
    3252               0 :                 if ((ind == READAHEAD_ARG)) {
    3253               0 :                         _switches[READAHEAD_ARG]++;
    3254               0 :                         if (!strcasecmp(optarg, "auto"))
    3255               0 :                                 _int_args[READAHEAD_ARG] = DM_READ_AHEAD_AUTO;
    3256               0 :                         else if (!strcasecmp(optarg, "none"))
    3257               0 :                                 _int_args[READAHEAD_ARG] = DM_READ_AHEAD_NONE;
    3258                 :                         else {
    3259               0 :                                 for (s = optarg; isspace(*s); s++)
    3260                 :                                         ;
    3261               0 :                                 if (*s == '+')
    3262               0 :                                         _read_ahead_flags = DM_READ_AHEAD_MINIMUM_FLAG;
    3263               0 :                                 _int_args[READAHEAD_ARG] = atoi(optarg);
    3264               0 :                                 if (_int_args[READAHEAD_ARG] < -1) {
    3265               0 :                                         log_error("Negative read ahead value "
    3266                 :                                                   "(%d) is not understood.",
    3267                 :                                                   _int_args[READAHEAD_ARG]);
    3268               0 :                                         return 0;
    3269                 :                                 }
    3270                 :                         }
    3271                 :                 }
    3272               0 :                 if ((ind == ROWS_ARG))
    3273               0 :                         _switches[ROWS_ARG]++;
    3274               0 :                 if ((ind == SHOWKEYS_ARG))
    3275               0 :                         _switches[SHOWKEYS_ARG]++;
    3276               0 :                 if ((ind == TABLE_ARG)) {
    3277               0 :                         _switches[TABLE_ARG]++;
    3278               0 :                         _table = optarg;
    3279                 :                 }
    3280               0 :                 if ((ind == TREE_ARG))
    3281               0 :                         _switches[TREE_ARG]++;
    3282               0 :                 if ((ind == UNQUOTED_ARG))
    3283               0 :                         _switches[UNQUOTED_ARG]++;
    3284               0 :                 if ((ind == VERSION_ARG))
    3285               0 :                         _switches[VERSION_ARG]++;
    3286                 :         }
    3287                 : 
    3288             603 :         if (_switches[VERBOSE_ARG] > 1)
    3289               0 :                 dm_log_init_verbose(_switches[VERBOSE_ARG] - 1);
    3290                 : 
    3291            1809 :         if ((_switches[MAJOR_ARG] && !_switches[MINOR_ARG]) ||
    3292            1206 :             (!_switches[MAJOR_ARG] && _switches[MINOR_ARG])) {
    3293               0 :                 fprintf(stderr, "Please specify both major number and "
    3294                 :                                 "minor number.\n");
    3295               0 :                 return 0;
    3296                 :         }
    3297                 : 
    3298             603 :         if (_switches[TREE_ARG] && !_process_tree_options(_string_args[OPTIONS_ARG]))
    3299               0 :                 return 0;
    3300                 : 
    3301             603 :         if (_switches[TABLE_ARG] && _switches[NOTABLE_ARG]) {
    3302               0 :                 fprintf(stderr, "--table and --notable are incompatible.\n");
    3303               0 :                 return 0;
    3304                 :         }
    3305                 : 
    3306             603 :         *argv += optind;
    3307             603 :         *argc -= optind;
    3308             603 :         return 1;
    3309                 : }
    3310                 : 
    3311             603 : int main(int argc, char **argv)
    3312                 : {
    3313                 :         struct command *c;
    3314             603 :         int r = 1;
    3315                 :         const char *dev_dir;
    3316                 : 
    3317             603 :         (void) setlocale(LC_ALL, "");
    3318                 : 
    3319             603 :         dev_dir = getenv (DM_DEV_DIR_ENV_VAR_NAME);
    3320             603 :         if (dev_dir && *dev_dir) {
    3321               0 :                 if (!dm_set_dev_dir(dev_dir)) {
    3322               0 :                         fprintf(stderr, "Invalid DM_DEV_DIR environment variable value.\n");
    3323               0 :                         goto out;
    3324                 :                 }
    3325                 :         } else
    3326             603 :                 dev_dir = DEFAULT_DM_DEV_DIR;
    3327                 : 
    3328             603 :         if (!_process_switches(&argc, &argv, dev_dir)) {
    3329               0 :                 fprintf(stderr, "Couldn't process command line.\n");
    3330               0 :                 goto out;
    3331                 :         }
    3332                 : 
    3333             603 :         if (_switches[HELP_ARG]) {
    3334               0 :                 c = _find_command("help");
    3335               0 :                 goto doit;
    3336                 :         }
    3337                 : 
    3338             603 :         if (_switches[VERSION_ARG]) {
    3339               0 :                 c = _find_command("version");
    3340               0 :                 goto doit;
    3341                 :         }
    3342                 : 
    3343             603 :         if (argc == 0) {
    3344               0 :                 _usage(stderr);
    3345               0 :                 goto out;
    3346                 :         }
    3347                 : 
    3348             603 :         if (!(c = _find_command(argv[0]))) {
    3349               0 :                 fprintf(stderr, "Unknown command\n");
    3350               0 :                 _usage(stderr);
    3351               0 :                 goto out;
    3352                 :         }
    3353                 : 
    3354            1809 :         if (argc < c->min_args + 1 ||
    3355            1206 :             (c->max_args >= 0 && argc > c->max_args + 1)) {
    3356               0 :                 fprintf(stderr, "Incorrect number of arguments\n");
    3357               0 :                 _usage(stderr);
    3358               0 :                 goto out;
    3359                 :         }
    3360                 : 
    3361             603 :         if (!_switches[COLS_ARG] && !strcmp(c->name, "splitname"))
    3362               0 :                 _switches[COLS_ARG]++;
    3363                 : 
    3364             603 :         if (_switches[COLS_ARG] && !_report_init(c))
    3365               0 :                 goto out;
    3366                 : 
    3367                 :         #ifdef UDEV_SYNC_SUPPORT
    3368             603 :         if (!_set_up_udev_support(dev_dir))
    3369               0 :                 goto out;
    3370                 :         #endif
    3371                 : 
    3372                 :       doit:
    3373             603 :         if (!c->fn(argc, argv, NULL)) {
    3374               0 :                 fprintf(stderr, "Command failed\n");
    3375               0 :                 goto out;
    3376                 :         }
    3377                 : 
    3378             603 :         r = 0;
    3379                 : 
    3380                 : out:
    3381             603 :         if (_report) {
    3382               0 :                 dm_report_output(_report);
    3383               0 :                 dm_report_free(_report);
    3384                 :         }
    3385                 : 
    3386             603 :         if (_dtree)
    3387               0 :                 dm_tree_free(_dtree);
    3388                 : 
    3389             603 :         return r;
    3390                 : }

Generated by: LCOV version 1.7