/*
 * tools/lib/pv_status.c
 *
 * Copyright (C) 1997 - 2001  Heinz Mauelshagen, Sistina Software
 *
 * March,November 1997
 * May 1998
 * January,September,October 1999
 * January 2000
 * April 2001
 *
 *
 * 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
 *
 *    18/11/1997 - enhanced disk loop (see disk_type)
 *    09/05/1998 - enxtended pv_status_all_pv_of_vg () to search /dev/dsk too
 *                 for future use
 *    03/05/1998 - enhanced disk loop once more (see lvm_dir_cache()) and
 *                 avoided /dev/dsk in here
 *    26/01/1999 - made volume group directory prefix a preprocessor option
 *    29/10/1999 - fixed possible free() bug
 *    08/02/2000 - use debug_enter()/debug_leave()
 *    09/04/2001 - cleaned up debug output (Andreas Dilger)
 *
 */

#include <liblvm.h>

int pv_status ( char *vg_name, char *pv_name, pv_t **pv) {
   int group = -1;
   int ret = 0;
   char group_file[NAME_LEN];
   static pv_t pv_this;
   pv_status_req_t req;

   debug_enter ( "pv_status -- CALLED with VG %s, PV: \"%s\"\n",
                 vg_name, pv_name);

   if ( vg_name == NULL ||
        pv_name == NULL ||
        vg_check_name ( vg_name) < 0 ||
        pv_check_name ( pv_name) < 0 ||
        pv == NULL) ret = -LVM_EPARAM;
   else {
      *pv = NULL;
      memset ( group_file, 0, sizeof ( group_file));
      snprintf ( group_file, sizeof ( group_file) - 1,
                             LVM_DIR_PREFIX "%s/group", vg_name);
      memset ( &req, 0, sizeof ( req));
      strncpy ( req.pv_name, pv_name, sizeof ( req.pv_name) - 1);
      req.pv = &pv_this;
      if ( ( group = open ( group_file, O_RDONLY)) == -1)
         ret = -LVM_EPV_STATUS_OPEN;
      else {
         ret = ioctl ( group, PV_STATUS, &req);
         if ( ret == -1) ret = -errno;
         else            *pv = &pv_this;
         close ( group);
      }
   }

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


int pv_status_all_pv_of_vg ( char *vg_name, pv_t ***pv) {
   int cache_size = 0;
   int n = 0;
   int np = 0;
   int p = 0;
   int ret = 0;
   char *pv_name = NULL;
   pv_t **pv_this_sav = NULL;
   pv_t **pv_this = NULL;
   pv_t *pv_tmp = NULL;
   dir_cache_t *dir_cache = NULL;

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

   if ( vg_name == NULL ||
        vg_check_name ( vg_name) < 0 ||
        pv == NULL) {
      ret = -LVM_EPARAM;
      goto pv_status_all_pv_of_vg_end;
   }

   *pv = NULL;

   if ( ( cache_size = lvm_dir_cache ( &dir_cache)) < 0) {
      ret = -LVM_EPV_STATUS_ALL_PV_LVM_DIR_CACHE;
      goto pv_status_all_pv_of_vg_end;
   }

   for ( n = np = 0; n < cache_size; n++) {
      pv_name = dir_cache[n].dev_name;
      debug ( "pv_status_all_pv_of_vg -- calling pv_status "
               "with %s  %s\n", vg_name, pv_name);
      if ( ( ret = pv_status ( vg_name, pv_name, &pv_tmp)) == 0) {
         debug ( "pv_status_all_pv_of_vg -- pv_status is o.k. "
                 "--> allocating memory\n");
         pv_this_sav = pv_this;
         if ( ( pv_this = realloc ( pv_this,
                                    ( np+2) * sizeof ( pv_t*))) == NULL) {
            fprintf ( stderr, "realloc error in %s [line %d]\n",
                              __FILE__, __LINE__);
            for ( p = 0; pv_this_sav[p] != NULL; p++) free ( pv_this_sav[p]);
            free ( pv_this_sav);
            ret = -LVM_EPV_STATUS_ALL_PV_OF_VG_MALLOC;
            goto pv_status_all_pv_of_vg_end;
         }
         if ( ( pv_this[np] = malloc ( sizeof ( pv_t))) == NULL) {
            fprintf ( stderr, "malloc error in %s [line %d]\n",
                              __FILE__, __LINE__);
            for ( p = 0; pv_this[p] != NULL; p++) free ( pv_this[p]);
            free ( pv_this);
            pv_this = NULL;
            ret = -LVM_EPV_STATUS_ALL_PV_OF_VG_MALLOC;
            goto pv_status_all_pv_of_vg_end;
         }
         memcpy ( pv_this[np], pv_tmp, sizeof ( pv_t));
         np++;
         pv_this[np] = NULL;
      }
   }
   if ( np == 0) ret = -LVM_EPV_STATUS_ALL_PV_OF_VG_NP;
   else {
      ret = 0;
      *pv = pv_this;
   }

pv_status_all_pv_of_vg_end:

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