/*
 * tools/pvdisplay.c
 *
 * Copyright (C) 1997 - 2002  Heinz Mauelshagen, Sistina Software
 *
 * March 1997
 * May,September 1998
 * February,October 1999
 * February 2000
 * January,July 2001
 * February 2002
 *
 * 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
 *
 *    05/05/1998 - implemented option s
 *    12/05/1998 - checked for new physical volume
 *    04/09/1998 - corrected some messages
 *    21/02/1999 - remove 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()
 *    23/01/2001 - added call to lvm_init [JT]
 *    20/07/2001 - added pv_from_disk var [JT]
 *    06/02/2002 - cope with changed pv_get_size() return cast
 *    07/02/2002 - fixes for > 1TB support
 *    17/02/2002 - avoid pv_get_size() altogether
 *
 */

#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_s = 0;
   int opt_v = 0;
   int ret = 0;
   char *dummy = NULL;
   char *options = "ch?sv" DEBUG_SHORT_OPTION;
   struct option long_options[] = {
      { "colon",   no_argument, NULL, 'c'},
      DEBUG_LONG_OPTION
      { "help",    no_argument, NULL, 'h'},
      { "short",   no_argument, NULL, 's'},
      { "verbose", no_argument, NULL, 'v'},
      { NULL, 0, NULL, 0}
   };
   char *pv_name = NULL;
   pv_t *pv_from_disk = NULL, *pv = 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 'h':
         case '?':
            printf ( "\n%s  (IOP %d)\n\n%s -- Physical Volume Display\n\n"
                     "Synopsis:\n"
                     "---------\n\n"
                     "%s\n"
                     "\t[-c/--colon]\n"
                     DEBUG_HELP
                     "\t[-h/--help]\n"
                     "\t[-s/--short]\n"
                     "\t[-v[v]/--verbose [--verbose]]\n"
                     "\tPhysicalVolumePath [PhysicalVolumePath...]\n\n",
                     lvm_version, LVM_LIB_IOP_VERSION,  cmd, cmd);
            return 0;
            break;

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

         case 'v':
            if ( opt_v > 1) {
               fprintf ( stderr, "%s -- v option already given two times\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 ( optind == argc) {
      fprintf ( stderr, "%s -- please enter a physical volume path\n\n", cmd);
      return LVM_EPVDISPLAY_PV_MISSING;
   }

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

   LVM_CHECK_IOP;

   for ( ; optind < argc; optind++) {
      pv_name = argv[optind];

      if ( opt_v > 1) printf ( "%s -- checking physical volume name \"%s\"\n",
                               cmd, pv_name);
      if ( pv_check_name ( pv_name) != 0) {
         fprintf ( stderr, "%s -- invalid physical volume name \"%s\"\n\n",
                   cmd, pv_name);
         continue;
      }

      if ( opt_v > 1) printf ( "%s -- reading data of physical volume "
                               "\"%s\" from disk\n", cmd, pv_name);
      if ( ( ret = pv_read ( pv_name, &pv, NULL)) < 0 &&
           ret != -LVM_EPV_READ_MD_DEVICE) {
         if ( ret == -LVM_EPV_READ_PV_EXPORTED ) {
            pv->vg_name[strlen(pv->vg_name)-strlen(EXPORTED)] = 0;
            printf ( "%s -- physical volume \"%s\" of volume group \"%s\" "
                     "is exported\n\n", cmd, pv_name, pv->vg_name);
         } else if ( ret == -LVM_EPV_READ_ID_INVALID) {
            fprintf ( stderr, "%s -- no physical volume identifier "
                              "on \"%s\"\n\n",
                              cmd, pv_name);
         } else {
            fprintf ( stderr, "%s -- ERROR \"%s\" no VALID physical "
                              "volume \"%s\"\n\n",
                              cmd, lvm_error ( ret), pv_name);
         }
         continue;
      }

      if ( opt_s > 0) {
         printf ( "%s -- physical volume \"%s\" has a capacity of %s\n",
                  cmd, pv_name,
                  ( dummy = lvm_show_size ( pv->pv_size / 2, SHORT)));
         free  ( dummy); dummy = NULL;
         continue;
      }

      if ( opt_v > 1) printf ( "%s -- creating physical volume device number "
                               "from name \"%s\"\n",
                               cmd, pv_name);
      if ( ( ret = pv_create_kdev_t ( pv_name)) == 0) {
         fprintf ( stderr, "%s -- ERROR: stat of \"%s\"\n\n", cmd, pv_name);
         continue;
      }

      if ( pv_check_new ( pv) == TRUE) {
         printf ( "%s -- \"%s\" is a new physical volume of %s\n",
                  cmd, pv_name,
                  ( dummy = lvm_show_size ( pv->pv_size / 2, SHORT)));
         free  ( dummy); dummy = NULL;
         continue;
      }

      /*
       * the pv copied from the kernel will not have a valid pe_start,
       * so we save the from disk pointer for use with pv_show
       */
      pv_from_disk = pv;

      if ( opt_v > 1) printf ( "%s -- checking physical volume activity\n",
                                cmd);
      if ( pv_check_active ( pv->vg_name, pv->pv_name) == TRUE) {
         if ( ( ret = pv_status  ( pv->vg_name, pv->pv_name, &pv)) != 0) {
            if ( ret == -ENXIO) {
               fprintf ( stderr, "%s -- no such physical volume \"%s\"\n\n",
                                 cmd, pv_name);
               continue;
            } else {
               fprintf ( stderr, "%s -- ERROR \"%s\" getting status of "
                                 "physical volume \"%s\"\n\n",
                                 cmd, lvm_error ( ret), pv_name);
               continue;
            }
         }
      }

      if ( opt_v > 1) printf ( "%s -- checking physical volume consistency\n",
                               cmd);
      if ( ( ret = pv_check_consistency ( pv)) < 0) {
         fprintf ( stderr, "%s -- ERROR \"%s\" checking consistency of physical"
                           " volume \"%s\"\n\n",
                           cmd, lvm_error ( ret), pv_name);
         return LVM_EPVDISPLAY_PV_CHECK_CONSISTENCY;
      }

      /* restore the from disk pointer */
      pv = pv_from_disk;

      if ( opt_c == 0) {
         pv_show ( pv);

         if ( opt_v > 0) {
            if ( pv->pe_allocated > 0) {
               if ( ( ret = pv_read_pe ( pv, &pv->pe)) != 0) {
                  fprintf ( stderr, "%s -- ERROR \"%s\" reading physical"
                                    " extent information\n\n",
                                    cmd, lvm_error ( ret));
                  return LVM_EPVDISPLAY_PV_READ_PE;
               }
               printf ( "\n");
               pv_show_pe_text ( pv, pv->pe, pv->pe_total);
            } else {
               printf ( "\n%s -- no logical volume on physical volume \"%s\"\n",
                        cmd, pv_name);
            }
         }
         putchar ( '\n');
      } else {
         pv_show_colon ( pv);
      }

   }

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