/*
 * tools/lib/pv_check_consistency.c
 *
 * Copyright (C) 1997 - 2002  Heinz Mauelshagen, Sistina Software
 *
 * March 1997
 * May,September,December 1998
 * February 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
 *
 *    20/05/1998 - included check of LVM_ID
 *    26/05/1998 - used lvm_check_dev()
 *    06/09/1998 - added PE consistency check in pv_check_consistency_all_pv()
 *    22/12/1998 - enhanced PE consistency check in           "
 *    31/01/2000 - use debug_enter()/debug_leave()
 *    07/02/2002 - removed checks for pv_name; gets replaced
 *                 and checked in pv_read() anyway
 *
 */

#include <liblvm.h>

/* validate pv->pv_name and pv->vg_name directly */
int pv_check_consistency ( pv_t *pv) {
   uint ret = 0;
   uint size = 0;
   struct stat stat_b;

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

   if ( pv == NULL) ret = -LVM_EPARAM;
   else {
      stat_b.st_rdev = pv->pv_dev;
   
      if ( strncmp ( pv->id, LVM_ID, sizeof ( pv->id)) != 0)
         ret = -LVM_EPV_CHECK_CONSISTENCY_LVM_ID;
      else if (!lvm_pv_check_version(pv))
         ret = -LVM_EPV_CHECK_CONSISTENCY_STRUCT_VERSION;
      else if ( pv_check_name ( pv->pv_name) < 0)
         ret = -LVM_EPV_CHECK_CONSISTENCY_PV_NAME;
      else if ( vg_check_name ( pv->vg_name) < 0)
         ret = -LVM_EPV_CHECK_CONSISTENCY_VG_NAME;
/*
      else if ( lvm_check_dev ( &stat_b, FALSE) == FALSE)
         ret = -LVM_EPV_CHECK_CONSISTENCY_MAJOR;
*/
      else if ( pv->pv_status != 0 && pv->pv_status != PV_ACTIVE)
         ret = -LVM_EPV_CHECK_CONSISTENCY_PV_STATUS;
      else if ( pv->pv_allocatable != 0 && pv->pv_allocatable != PV_ALLOCATABLE)
         ret = -LVM_EPV_CHECK_CONSISTENCY_PV_ALLOCATABLE;
/*
      else if ( pv->pv_size > LVM_MAX_SIZE)
         ret = -LVM_EPV_CHECK_CONSISTENCY_PV_SIZE;
*/
      else if ( pv->lv_cur > MAX_LV)
         ret = -LVM_EPV_CHECK_CONSISTENCY_LV_CUR;
      else {
         size = pv->pe_size / LVM_MIN_PE_SIZE * LVM_MIN_PE_SIZE;
         if ( pv_check_new ( pv) == FALSE &&
                   ( pv->pe_size != size ||
                     pv->pe_size < LVM_MIN_PE_SIZE ||
                     pv->pe_size > LVM_MAX_PE_SIZE))
            ret = -LVM_EPV_CHECK_CONSISTENCY_PE_SIZE;
         else if ( pv->pe_total > ( pv->pe_on_disk.size / sizeof ( pe_disk_t)))
            ret = -LVM_EPV_CHECK_CONSISTENCY_PE_TOTAL;
         else if ( pv->pe_allocated > pv->pe_total)
            ret = -LVM_EPV_CHECK_CONSISTENCY_PE_ALLOCATED;
         else if ( pv->pe_stale > pv->pe_allocated)
            ret = -LVM_EPV_CHECK_CONSISTENCY_PE_STALE;
      }
   }

   debug_leave ( "pv_check_consistency -- LEAVING with ret: %d\n", ret);
   return ret;
}


int pv_check_consistency_all_pv ( vg_t *vg) {
   int p = 0;
   int pe = 0;
   int pe_count = 0;
   int ret = 0;

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

   if ( vg == NULL) ret = -LVM_EPARAM;
   else if ( ( ret = vg_check_consistency ( vg)) == 0) {
      for ( p = 0; p < vg->pv_cur; p++) {
         if ( ( ret = pv_check_consistency ( vg->pv[p])) < 0) {
         debug ( "pv_check_consistency_all_pv -- pv_check_consistency of %s "
                  "returned %d\n", vg->pv[p]->pv_name, ret);
            goto pv_check_consistency_all_pv_end;
         }
         
         for ( pe = pe_count = 0; pe < vg->pv[p]->pe_total; pe++) {
            if ( vg->pv[p]->pe[pe].lv_num > 0) pe_count++;
            if ( vg->pv[p]->pe[pe].lv_num > vg->lv_max ||
                 vg->pv[p]->pe[pe].le_num > vg->pe_total) {
               ret = -LVM_EPV_CHECK_CONSISTENCY_ALL_PV_PE;
               goto pv_check_consistency_all_pv_end;
            }
         }

         /* vg->pv[p]->pe_allocated != 0 because vgmerge has to set it to 0
            befaure doing lv_create() for the merged LVs */
         if ( pe_count != vg->pv[p]->pe_allocated &&
              vg->pv[p]->pe_allocated != 0) {
            ret = -LVM_EPV_CHECK_CONSISTENCY_ALL_PV_PE;
            goto pv_check_consistency_all_pv_end;
         }
      }
   }

pv_check_consistency_all_pv_end:

   debug_leave ( "pv_check_consistency_all_pv -- LEAVING with ret: %d\n", ret);
   return ret;
}
