/*
 * tools/lib/pv_show.c
 *
 * Copyright (C) 1997 - 2002  Heinz Mauelshagen, Sistina Software
 *
 * March,October 1997
 * May 1998
 * January,November,December 1999
 * January,March 2000
 * February 2002
 *
 *
 * This LVM library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This LVM library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this LVM library; if not, write to the Free
 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA
 *
 */

/*
 * Changelog
 *
 *    01/05/1998 - used lv_read_byindex() in  pv_show_pe_text() to avoid
 *                 string generation of LV names
 *    09/05/1998 - corrected display of 1 free physical extent
 *                 in pv_show_pe_text()
 *    16/05/1998 - fixed display bug in pv_show_pe_text()
 *    20/01/1999 - used LVM_PE_DISK_OFFSET macro in pv_show_pe_text()
 *               - added sector offset on disk to pv_show_pe_text()
 *    03/11/1999 - implemented pv_show_colon to generate colon seperated output
 *    08/12/1999 - avoided invalid free() in pv_show_pe_text()
 *    08/02/2000 - use debug_enter()/debug_leave()
 *    16/03/2000 - added UUID display to pv_show_colon() and pv_show()
 *    13/02/2002 - added sector display to pv_show()
 *
 */


#include <liblvm.h>

void   pv_show_free ( int, int);


void pv_show_colon ( pv_t *pv) {

   debug_enter ( "pv_show_colon -- CALLED\n");

   if ( pv != NULL) {
      printf ( "%s:%s:%u:%d:%d:%d:%d:%d:%d:%d:%d:%s\n",
               pv->pv_name,
               pv->vg_name,
               pv->pv_size,
               pv->pv_number,
               pv->pv_status,
               pv->pv_allocatable,
               pv->lv_cur,
               pv->pe_size / 2,
               pv->pe_total,
               pv->pe_total - pv->pe_allocated,
               pv->pe_allocated,
               strlen(pv->pv_uuid) > 0 ? lvm_show_uuid ( pv->pv_uuid) : "none"
             );
   }

   debug_leave ( "pv_show_colon -- LEAVING\n");
}


void pv_show ( pv_t *pv) {
   ulong pe_free;
   char *dummy = NULL;

   debug_enter ( "pv_show -- CALLED\n");

   if ( pv != NULL) {
      printf ( "---");
      if ( pv->pe_size == 0) printf ( " NEW");
      printf ( " Physical volume ---\n");
      printf ( "PV Name               %s\n", pv->pv_name);
      printf ( "VG Name               %s\n", pv->vg_name);
      printf ( "PV Size               %s [%u secs]",
               ( dummy = lvm_show_size ( pv->pv_size / 2, SHORT)), pv->pv_size);
      free ( dummy);
      if ( pv->pe_size != 0 && pv->pe_total != 0) {
         printf ( " / NOT usable %s ",
                  ( dummy = lvm_show_size ( ( pv->pe_on_disk.base + pv->pe_on_disk.size) / 1024, SHORT)));
         free ( dummy);
         printf ( "[LVM: %s]",
                  ( dummy = lvm_show_size ( ( pv->pe_on_disk.base +
                                              pv->pe_total *
                                              sizeof ( pe_disk_t))
                                            / 1024,
                                        SHORT)));
         free ( dummy);
      }
      printf ( "\n");
      printf ( "PV#                   %u\n", pv->pv_number);
      printf ( "PV Status             ");
      if ( ! ( pv->pv_status & PV_ACTIVE)) printf ( "NOT ");
      printf ( "available\n");
      printf ( "Allocatable           ");
      pe_free = pv->pe_total - pv->pe_allocated;
      if ( pv->pe_total > 0 && ( pv->pv_allocatable & PV_ALLOCATABLE)) {
         printf ( "yes");
         if ( pe_free == 0 && pv->pe_total > 0) printf ( " (but full)");
         printf ( "\n");
      }
      else                                      printf ( "NO\n");
      printf ( "Cur LV                %u\n", pv->lv_cur);
      printf ( "PE Size (KByte)       %u\n", pv->pe_size / 2);
      printf ( "Total PE              %u\n", pv->pe_total);
      printf ( "Free PE               %lu\n", pe_free);
      printf ( "Allocated PE          %u\n", pv->pe_allocated);
#ifdef LVM_FUTURE
      printf ( "Stale PE              %u\n", pv->pe_stale);
#endif
      printf ( "PV UUID               %s\n",
               strlen(pv->pv_uuid) > 0 ? lvm_show_uuid ( pv->pv_uuid) : "none");
   }

   debug_leave ( "pv_show -- LEAVING\n");
   return;
}


void pv_show_short ( pv_t *pv) {

   debug_enter ( "pv_show_short -- CALLED\n");

   if ( pv != NULL) {
      printf ( "PV Name (#)           %s (%u)\n", pv->pv_name, pv->pv_number);
      printf ( "PV Status             ");
      if ( ! ( pv->pv_status & PV_ACTIVE)) printf ( "NOT ");
      printf ( "available / ");
      if ( ! ( pv->pv_allocatable & PV_ALLOCATABLE)) printf ( "NOT ");
      printf ( "allocatable\n");
      printf ( "Total PE / Free PE    %u / %u\n",
               pv->pe_total, pv->pe_total - pv->pe_allocated);
   }

   debug_leave ( "pv_show_short -- LEAVING\n");
   return;
}


void pv_show_all_pv_of_vg ( vg_t *vg) {
   int p = 0;

   debug_enter ( "pv_show_all_pv_of_vg -- CALLED\n");

   if ( vg != NULL &&
        vg_check_consistency ( vg) == 0) {
      for ( p = 0; p < vg->pv_cur; p++) {
         pv_show ( vg->pv[p]);
         printf ( "\n");
      }
   }

   debug_leave ( "pv_show_all_pv_of_vg -- LEAVING\n");
   return;
}


void pv_show_all_pv_of_vg_short ( vg_t *vg) {
   int p = 0;

   debug_enter ( "pv_show_all_pv_of_vg_short -- CALLED\n");

   if ( vg != NULL &&
        vg_check_consistency ( vg) == 0) {
      printf ( "--- Physical volumes ---\n");
      if ( vg->pv_cur != 0) {
         for ( p = 0; p < vg->pv_cur; p++) {
            pv_show_short ( vg->pv[p]);
            printf ( "\n");
         }
      } else printf ( "NONE???\n");
   }

   debug_leave ( "pv_show_all_pv_of_vg_short -- LEAVING\n");
   return;
}


void pv_show_pe ( pv_t *pv, pe_disk_t *pe, int pe_count) {
   int p;

   debug_enter ( "pv_show_pe -- CALLED\n");

   if ( pv != NULL &&
        pv_check_consistency ( pv) == 0 &&
        pe != NULL) {
      for ( p = 0; p < pe_count; p++)
         printf ( "pe#: %4d  vg: %s  lv: %d  le: %d\n",
                  p, pv->vg_name, pe[p].lv_num, pe[p].le_num);
   }

   debug_leave ( "pv_show_pe -- LEAVING\n");
   return;
}


int pv_show_pe_text ( pv_t *pv, pe_disk_t *pe, int pe_count) {
   int flag = 0;
   int lv_num_last = 0;
   int p = 0;
   int pe_free = 0;
   int *pe_this_count = NULL;
   int pt = 0;
   int pt_count = 0;
   int ret = 0;
   char *lv_name_this = NULL;
   char *lv_names = NULL;
   char *lv_names_sav = NULL;
   pe_disk_t *pe_this = NULL;
   vg_t *vg = NULL;

   debug_enter ( "pv_show_text -- CALLED\n");

   if ( pv == NULL || pe == NULL || pe_count == 0 ||
        pv_check_consistency ( pv) < 0) {
      ret = -LVM_EPARAM;
      goto pv_show_pe_text_end;
   }

   if ( ( pe_this = malloc ( pe_count * sizeof ( pe_disk_t))) == NULL) {
      fprintf ( stderr, "malloc error in %s [line %d]\n",
                        __FILE__, __LINE__);
      ret = -LVM_EPV_SHOW_PE_TEXT_MALLOC;
      goto pv_show_pe_text_end;
   }
   if ( ( pe_this_count = malloc ( pe_count * sizeof ( int))) == NULL) {
      fprintf ( stderr, "malloc error in %s [line %d]\n",
                        __FILE__, __LINE__);
      ret = -LVM_EPV_SHOW_PE_TEXT_MALLOC;
      goto pv_show_pe_text_end;
   }
   memset ( pe_this, 0, pe_count * sizeof ( pe_disk_t));
   memset ( pe_this_count, 0, pe_count * sizeof ( int));

   /* get PE and LE summaries */
   pt_count = 0;
   for ( p = pt_count; p < pe_count; p++) {
      if ( pe[p].lv_num != 0) {
         flag = 0;
         for ( pt = 0; pt < pt_count; pt++) {
            if ( pe_this[pt].lv_num == pe[p].lv_num) {
               flag = 1;
               break;
            }
         }
         if ( flag == 0) {
            pe_this[pt_count].lv_num = pe[p].lv_num;
            for ( pt = 0; pt < pe_count; pt++)
                if ( pe_this[pt_count].lv_num == pe[pt].lv_num)
                   pe_this_count[pt_count]++;
            pt_count++;
         }
      }
   }

   if ( lvm_tab_vg_read_with_pv_and_lv ( pv->vg_name, &vg) < 0){
      ret = -LVM_EPV_SHOW_PE_TEXT_VG_READ_WITH_PV_AND_LV;
      goto pv_show_pe_text_end;
   }

   printf ( "   --- Distribution of physical volume ---\n"
            "   LV Name                   LE of LV  PE for LV\n");
   for ( pt = 0; pt < pt_count; pt++) {
      printf ( "   %-25s ", vg->lv[pe_this[pt].lv_num-1]->lv_name);
      if ( strlen ( vg->lv[pe_this[pt].lv_num-1]->lv_name) > 25)
         printf ( "\n                             ");
      printf ( "%-8u  %-8d\n",
               vg->lv[pe_this[pt].lv_num-1]->lv_allocated_le,
               pe_this_count[pt]);
      if ( pe_this[pt].lv_num > lv_num_last) {
         lv_num_last = pe_this[pt].lv_num;
         lv_names_sav = lv_names;
         if ( ( lv_names = realloc ( lv_names,
                                     lv_num_last * NAME_LEN)) == NULL) {
            fprintf ( stderr, "realloc error in %s [line %d]\n",
                              __FILE__, __LINE__);
            ret = -LVM_EPV_SHOW_PE_TEXT_REALLOC;
            goto pv_show_pe_text_end;
         } else lv_names_sav = NULL;
      }
      strcpy ( &lv_names[(pe_this[pt].lv_num-1)*NAME_LEN],
               vg->lv[pe_this[pt].lv_num-1]->lv_name);
   }

   printf ( "\n   --- Physical extents ---\n"
            "   PE    LV                        LE      Disk sector\n");
   pe_free = -1;
   for ( p = 0; p < pe_count; p++) {
      if ( pe[p].lv_num != 0) {
         if ( pe_free > -1) {
            pv_show_free ( pe_free, p);
            pe_free = -1;
         }
         lv_name_this = &lv_names[(pe[p].lv_num-1)*NAME_LEN];
         printf ( "   %05d %-25s ", p, lv_name_this);
         if ( strlen ( lv_name_this) > 25)
            printf ( "\n                                  ");
         printf ( "%05d   %ld\n", pe[p].le_num, get_pe_offset(p, pv));

      } else if ( pe_free == -1) pe_free = p;
   }

   if ( pe_free > 0) pv_show_free ( pe_free, p);

pv_show_pe_text_end:
   if ( lv_names != NULL)           free ( lv_names);
   else if ( lv_names_sav != NULL)  free ( lv_names_sav);
   if ( pe_this != NULL)            free ( pe_this);
   if ( pe_this_count != NULL)      free ( pe_this_count);

   debug_leave ( "pv_show_text -- LEAVING with ret: %d\n", ret);
   return ret;
} /* pv_show_pe_text() */


void  pv_show_free ( int pe_free, int p) {

   debug_enter ( "pv_show_free -- CALLED\n");

   if ( p - pe_free > 1) printf ( "   %05d free\n   .....\n   %05d free\n",
                                  pe_free, p - 1);
   else                  printf ( "   %05d free\n", pe_free);

   debug_leave ( "pv_show_free -- LEAVING\n");
   return;
}
