/*
 * tools/lvdisplay.c
 *
 * Copyright (C) 1997 - 2001  Heinz Mauelshagen, Sistina Software
 *
 * March 1997
 * May-June,August,September 1998
 * February,October,November 1999
 * February,November 2000
 * March,July 2001
 *
 * LVM is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 * 
 * LVM is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with LVM; see the file COPYING.  If not, write to
 * the Free Software Foundation, 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA. 
 *
 */

/*
 * Changelog
 *
 *    29/04/1998 - avoided lv_create_kdev_t() using [lvm_tab_]lv_check_exist()
 *    16/05/1998 - added lvmtab checking
 *    07/06/1998 - added warning message for option -Z
 *    27/06/1998 - changed lvm_tab_* calling convention
 *                 changed to new lv_show_current_pe_text() calling convention
 *    07/09/1998 - used lv_status_byname() instead of obsolete
 *                 lv_status_with_pe()
 *    21/02/1999 - removed LVM_LOCK and LVM_UNLOCK
 *    06/10/1999 - implemented support for long options
 *    03/11/1999 - implemented option -c for colon seperated output
 *    15/02/2000 - use lvm_error()
 *    07/11/2000 - used LVM_VG_NAME environment variable
 *    23/01/2001 - added call to lvm_init (JT)
 *    06/03/2001 - removed misleading "(lvmtab)" string in display in
 *                 case of -D (HM)
 *               - changed inactivity checking in order to get data of
 *                 deactivated logical volumes from kernel to display
 *                 it as well (HM)
 *    25/07/2001 - avoid misleading "(null)" in error message (AGK)
 *
 */

#include <lvm_user.h>

char *cmd = NULL;

#ifdef DEBUG
int opt_d = 0;
#endif

int main ( int argc, char **argv) {
   int c = 0;
   int opt_c = 0;
   int opt_D = 0;
   int opt_v = 0;
   int ret = 0;
   char *lv_name = NULL;
   char *options = "cDh?v" DEBUG_SHORT_OPTION;
   struct option long_options[] = {
      { "colon",      no_argument,       NULL, 'c'},
      DEBUG_LONG_OPTION
      { "disk",       no_argument,       NULL, 'D'},
      { "help",       no_argument,       NULL, 'h'},
      { "verbose",    no_argument,       NULL, 'v'},
      { NULL, 0, NULL, 0}
   };
   char *vg_name = NULL;
   lv_t *lv = NULL;

   /* lvm_init(argc, argv); */
   cmd = basename ( argv[0]);

   LVMTAB_CHECK;

   while ( ( c = getopt_long ( argc, argv, options,
                               long_options, NULL)) != EOF) {
      switch ( c) {
         case 'c':
            if ( opt_c > 0) {
               fprintf ( stderr, "%s -- c option already given\n\n", cmd);
               return LVM_EINVALID_CMD_LINE;
            }
            opt_c++;
            break;

         DEBUG_HANDLE_CASE_D;

         case 'D':
            if ( opt_D > 0) {
               fprintf ( stderr, "%s -- D option already given\n\n", cmd);
               return LVM_EINVALID_CMD_LINE;
            }
            opt_D++;
            break;

         case 'h':
         case '?':
            printf ( "\n%s (IOP %d)\n\n%s -- Logical Volume Display\n\n"
                     "Synopsis:\n"
                     "---------\n\n"
                     "%s\n"
                     "\t[-c/--colon]\n"
                     DEBUG_HELP
                     "\t[-D/--disk]\n"
                     "\t[-h/--help]\n"
                     "\t[-v[v]/--verbose [--verbose]]\n"
                     "\tLogicalVolume[Path] [LogicalVolume[Path]...]\n\n",
                     lvm_version, LVM_LIB_IOP_VERSION,  cmd, cmd);
            return 0;
            break;

         case 'v':
            if ( opt_v > 1) {
               fprintf ( stderr, "%s -- v option already given twice\n\n", cmd);
               return LVM_EINVALID_CMD_LINE;
            }
            opt_v++;
            break;

         default:
            fprintf ( stderr, "%s -- invalid command line option \"%c\"\n",
                      cmd, c);
            return LVM_EINVALID_CMD_LINE;
      }
   }

   CMD_MINUS_CHK;

   if ( argc == optind) {
      fprintf ( stderr, "%s -- please enter a logical volume path\n\n", cmd);
      return LVM_ELVDISPLAY_LV_MISSING;
   }

   if ( opt_c > 0 && opt_v > 0) {
      fprintf ( stderr, "%s -- option v not allowed with option c\n\n", cmd);
      return LVM_ELVDISPLAY_LV_MISSING;
   }

   LVM_CHECK_IOP;

   for ( ;optind < argc; optind++) {
      char buffer[NAME_LEN];

      lv_name = argv[optind];

      LVM_CHECK_DEFAULT_VG_NAME ( lv_name, buffer, NAME_LEN);

      if ( lv_name == NULL) {
         fprintf ( stderr, "%s -- a path needs supplying for "
                            "logical volume argument \"%s\"\n\n",
                            cmd, argv[optind]);
         continue;
      }

      if ( opt_v > 1) printf ( "%s -- checking logical volume name \"%s\"\n",
                               cmd, lv_name);
      if ( ( ret = lv_check_name ( lv_name)) < 0) {
         fprintf ( stderr, "%s -- invalid logical volume name \"%s\"\n\n",
                   cmd, lv_name);
         continue;
      }
   
      vg_name = vg_name_of_lv ( lv_name);

      if ( opt_v > 1) printf ( "%s -- checking logical volume \"%s\" "
                               "existence\n", cmd, lv_name);
      if ( opt_D > 0) ret = lv_check_exist ( lv_name);
      else            ret = lvm_tab_lv_check_exist ( lv_name);
      if ( ret != TRUE) {
         fprintf ( stderr, "%s -- logical volume \"%s\" doesn't exist\n\n",
                           cmd, lv_name);
         continue;
      }
   
      if ( opt_v > 1) printf ( "%s -- checking volume group activity "
                               "of \"%s\"\n", cmd, vg_name);
      if ( vg_check_active ( vg_name) != TRUE && opt_D == 0) {
         fprintf ( stderr, "%s -- volume group \"%s\" of logical volume \"%s\""
                           "is not active\n%s -- try -D, please\n\n",
                           cmd, vg_name, lv_name, cmd);
         continue;
      }

      if ( opt_v > 1) printf ( "%s -- getting logical volume data for \"%s\" "
                               "from ", cmd, lv_name);
      /* from disk(s) */
      if ( opt_D > 0) {
         if ( opt_v > 1) printf ( "DISK\n");
         if ( ( ret = lv_read_with_pe ( vg_name, lv_name, &lv)) < 0) {
            fprintf ( stderr, "%s -- ERROR \"%s\" no VALID logical volume "
                              "\"%s\"\n\n",
                              cmd, lvm_error ( ret), lv_name);
            continue;
         }
         if ( opt_v > 1) printf ( "%s -- checking logical volume consistency\n",
                                  cmd);
      /* from kernel */
      } else {
         if ( opt_v > 1) printf ( "KERNEL\n");
         if ( ( ret = lv_status_byname ( vg_name, lv_name, &lv)) < 0) {
            if ( ret == -LVM_ELV_STATUS_INTERNAL_OPEN ||
                 ret == -ENXIO) {
               fprintf ( stderr, "%s -- logical volume \"%s\" "
                                 "doesn't exist\n\n",
                                 cmd, lv_name);
               continue;
            } else {
               fprintf ( stderr, "%s -- ERROR \"%s\" getting logical"
                                 " volume info of \"%s\"\n\n",
                                 cmd, lvm_error ( ret), lv_name);
               continue;
            }
         }
      }
   
      if ( lv == NULL) {
         fprintf ( stderr, "%s -- logical volume \"%s\" doesn't exist\n",
                           cmd, lv_name);
         continue;
      }

      if ( ( ret = lv_check_consistency ( lv)) < 0) {
         fprintf ( stderr, "%s -- ERROR \"%s\" logical volume \"%s\" "
                           "is inconsistent\n\n",
                           cmd, lvm_error ( ret), lv_name);
         continue;
      }

      if ( opt_c == 0) {
         lv_show ( lv);
         if ( opt_v > 0) {
            printf ( "\n");
            lv_show_current_pe_text ( lv);
         }
         putchar ( '\n');
      } else {
         lv_show_colon ( lv);
      }
   }

   putchar ( '\n');
   return 0;
}
