Filewatcher File Search
FTP Search
  
Directory 
  
Content Search 
   
pkg://mkinitrd-debuginfo-6.0.9-5.ppc.rpm:313977/usr/src/debug/mkinitrd-6.0.9/nash/vitals.c  info  downloads

/*
 * vitals.c -- abstraction for the vital data regarding a block device.
 *
 * Peter Jones (pjones@redhat.com)
 *
 * Copyright 2006 Red Hat, Inc.
 *
 * This software may be freely redistributed under the terms of the GNU
 * public license.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#define _GNU_SOURCE 1

#include <sys/types.h>
#include <string.h>
#include <stdlib.h>

#include <nash.h>
#include <bdevid.h>
#include "lib.h"
#include "devtree.h"

#define xstrcmp(s0,s1) (s0 ? (s1 ? strcmp(s0,s1) : -1) : (s1 ? 1 : 0))

int nash_bdev_vitals_get_type(struct nash_bdev_vitals *vitals)
{
    return vitals->type;
}

int nash_bdev_vitals_type_cmp(struct nash_bdev_vitals *v0,
    struct nash_bdev_vitals *v1)
{
    int ret;
    if (v0 == v1)
        return 0;

    /* XXX ignoring everything but disks for now */
    if (v0->type != v1->type) {
#if 0
        printf("%d != %d, returning %d\n", v0->type, v1->type, v1->type - v0->type);
#endif
        return v1->type - v0->type;
    }

    switch (v0->type) {
        case DEV_TYPE_DISK:
            ret = xstrcmp(v0->disk_probe_name, v1->disk_probe_name);
#if 0
            printf("xstrcmp(\"%s\", \"%s\") = %d\n", v0->disk_probe_name,
                    v1->disk_probe_name, ret);
#endif
            if (ret)
                return ret;
            ret = xstrcmp(v0->disk_probe_module, v1->disk_probe_module);
#if 0
            printf("xstrcmp(\"%s\", \"%s\") = %d\n", v0->disk_probe_module,
                    v1->disk_probe_module, ret);
#endif
            if (ret)
                return ret;
            break;
        default:
            /* XXX ignoring everything but disks for now */
            return -1;
    }
#if 0
    printf("returning 0 from type_cmp\n");
#endif
    return 0;
}

int nash_bdev_vitals_cmp(struct nash_bdev_vitals *v0,
    struct nash_bdev_vitals *v1)
{
    int ret = 0;

    if (v0 == v1)
        return 0;

#if 1
    if (!v0)
        printf("no v0?  wtf?\n");
    if (!v1)
        printf("no v1?  wtf?\n");

    if (!v0 || !v1)
        return v0 ? -1 : (v1 ? 1 : -1 );
#endif

    if (v1->type != v0->type)
        return v1->type - v0->type;

    switch (v0->type) {
        case DEV_TYPE_TREE:
            return -1;
        case DEV_TYPE_DISK:
            if ((ret = xstrcmp(v0->unique_id, v1->unique_id))) {
#if 0
                printf("%s: %d: xstrcmp(\"%s\", \"%s\") = %d\n", __func__,
                        __LINE__, v0->unique_id, v1->unique_id, ret);
#endif
                break;
            }
            if ((ret = xstrcmp(v0->disk_vendor, v1->disk_vendor))) {
#if 0
                printf("%s: %d: xstrcmp(\"%s\", \"%s\") = %d\n", __func__,
                        __LINE__, v0->disk_vendor, v1->disk_vendor, ret);
#endif
                break;
            }
            if ((ret = xstrcmp(v0->disk_model, v1->disk_model))) {
#if 0
                printf("%s: %d: xstrcmp(\"%s\", \"%s\") = %d\n", __func__,
                        __LINE__, v0->disk_model, v1->disk_model, ret);
#endif
                break;
            }
            if ((ret = xstrcmp(v0->disk_probe_module, v1->disk_probe_module))) {
#if 0
                printf("%s: %d: xstrcmp(\"%s\", \"%s\") = %d\n", __func__,
                        __LINE__, v0->disk_probe_module, v1->disk_probe_module,
                        ret);
#endif
                break;
            }
            ret = xstrcmp(v0->disk_probe_name, v1->disk_probe_name);
#if 0
            if (ret) {
                printf("%s: %d: xstrcmp(\"%s\", \"%s\") = %d\n", __func__,
                        __LINE__, v0->disk_probe_name, v1->disk_probe_name,
                        ret);
            }
#endif
            break;
        case DEV_TYPE_DM_MPATH:
        case DEV_TYPE_DM_RAID:
            ret = xstrcmp(v0->dmname, v1->dmname);
            break;
        case DEV_TYPE_PARTITION:
            /* XXX fixme */
            ret = -1;
            break;
        case DEV_TYPE_LVM2_PV:
            ret = xstrcmp(v0->unique_id, v1->unique_id);
            break;
        case DEV_TYPE_LVM2_VG:
            if ((ret = xstrcmp(v0->unique_id, v1->unique_id)))
                break;
            ret = xstrcmp(v0->vg_name, v1->vg_name);
            break;
        case DEV_TYPE_LVM2_LV:
            if ((ret = xstrcmp(v0->unique_id, v1->unique_id)))
                break;
            ret = xstrcmp(v0->lv_name, v1->lv_name);
            break;
        case DEV_TYPE_MD_RAID:
            /* XXX fixme */
            ret = -1;
            break;
        case DEV_TYPE_FS:
            if ((ret = xstrcmp(v0->unique_id, v1->unique_id)))
                break;
            ret = xstrcmp(v0->fs_type, v1->fs_type);
            break;
        case DEV_TYPE_NONE:
        default:
            return -1;
            break;
    }
    return ret;
}

void nash_bdev_vitals_free(struct nash_bdev_vitals *vitals)
{
    if (!vitals || --(vitals->refcount))
        return;

    xfree(vitals->name);

    switch (vitals->type) {
        case DEV_TYPE_TREE:
            break;
        case DEV_TYPE_DISK:
            xfree(vitals->unique_id);
            xfree(vitals->disk_device_node);
            xfree(vitals->disk_vendor);
            xfree(vitals->disk_model);
            xfree(vitals->disk_probe_module);
            xfree(vitals->disk_probe_name);
            break;
        case DEV_TYPE_DM_MPATH:
        case DEV_TYPE_DM_RAID:
            xfree(vitals->dmname);
            break;
        case DEV_TYPE_PARTITION:
            break;
        case DEV_TYPE_LVM2_PV:
            xfree(vitals->unique_id);
            break;
        case DEV_TYPE_LVM2_VG:
            xfree(vitals->unique_id);
            xfree(vitals->vg_name);
            break;
        case DEV_TYPE_LVM2_LV:
            xfree(vitals->unique_id);
            xfree(vitals->lv_name);
            break;
        case DEV_TYPE_MD_RAID:
            /* XXX fixme */
            break;
        case DEV_TYPE_FS:
            xfree(vitals->unique_id);
            xfree(vitals->fs_type);
            xfree(vitals->fs_label);
            xfree(vitals->fs_options);
            break;
        case DEV_TYPE_NONE:
        default:
            break;
    }
    free(vitals);
}

void nash_vitals_decref(struct nash_bdev_vitals *vitals)
    __attribute__((alias("nash_bdev_vitals_free")));

void nash_vitals_incref(struct nash_bdev_vitals *vitals)
{
    vitals->refcount++;
}

struct nash_bdev_vitals *nash_bdev_vitals_alloc(void)
{
    struct nash_bdev_vitals *vitals;

    if (!(vitals = calloc(1, sizeof (*vitals))))
        return NULL;

    vitals->type = DEV_TYPE_NONE;
    vitals->refcount = 1;
    return vitals;
}

#if 0
struct nash_bdev_vitals *nash_bdev_vitals_dedupe_helper(nashContext *nc,
        struct nash_bdev_vitals *vitals, struct nash_dev_tree *tree)
{
    struct nash_bdev_vitals *other = NULL;
    struct nash_list_iter *iter = NULL;

    if (!vitals)
        return vitals;

    while ((iter = nash_list_iter_next(tree->devs, iter))) {
        struct nash_dev_node *node = nash_list_iter_data(iter);
        struct nash_list_iter *viter = NULL;

        while ((viter = nash_list_iter_next(node->vitals, viter))) {
            other = nash_list_iter_data(viter);
            if (vitals == other) {
                other = NULL;
                continue;
            }
            if (!nash_bdev_vitals_cmp(other, vitals)) {
                nash_vitals_incref(other);
                nash_vitals_decref(vitals);
                vitals = other;
                nash_list_iter_end(viter);
                break;
            }
        }
        if (vitals == other) {
            nash_list_iter_end(iter);
            break;
        }
    }

    return vitals;
}

struct nash_bdev_vitals *nash_bdev_vitals_dedupe(nashContext *nc,
        struct nash_bdev_vitals *vitals)
{
    if (vitals->type == DEV_TYPE_DISK && !vitals->unique_id) {
        nash_vitals_decref(vitals);
        return NULL;
    }
    vitals = nash_bdev_vitals_dedupe_helper(nc, vitals, nc->blktab);
    return nash_bdev_vitals_dedupe_helper(nc, vitals, nc->devices);
}
#else
struct nash_bdev_vitals *nash_bdev_vitals_dedupe(nashContext *nc,
        struct nash_bdev_vitals *vitals)
{
    if (vitals->type == DEV_TYPE_DISK && !vitals->unique_id) {
        nash_vitals_decref(vitals);
        return NULL;
    }
    return vitals;
}
#endif

struct nash_bdev_vitals *nash_bdev_vitals_from_blkent(nashContext *nc,
        struct blkent *blkent)
{
    struct nash_bdev_vitals *vitals = nash_bdev_vitals_alloc();

    if (!vitals)
        return NULL;

    if (!blkent) {
        vitals->type = DEV_TYPE_NONE;
        return vitals;
    }

    vitals->type = nash_dev_node_get_type_from_blkent(blkent);
    if (vitals->type == DEV_TYPE_NONE) {
    //    eprintf("Invalid block device type '%s'\n", blkent->blk_type);
        goto err;
    }

    if (!(vitals->name = strdup(blkent->blk_name)))
        goto err;

    /* XXX need to check if it exists first? */
    switch (vitals->type) {
        case DEV_TYPE_DISK:
            vitals->unique_id = dupblkopt(blkent->blk_opts, "unique_id");
            vitals->disk_device_node =
                dupblkopt(blkent->blk_opts, "device_node");
            vitals->disk_vendor = dupblkopt(blkent->blk_opts, "vendor");
            vitals->disk_model = dupblkopt(blkent->blk_opts, "model");
            vitals->disk_probe_module =
                dupblkopt(blkent->blk_opts, "module");
            vitals->disk_probe_name =
                dupblkopt(blkent->blk_opts, "probe");
            if (!vitals->unique_id ||
                    !vitals->disk_device_node ||
                    !vitals->disk_vendor ||
                    !vitals->disk_model ||
                    !vitals->disk_probe_module ||
                    !vitals->disk_probe_name)
                goto err;
            break;
        case DEV_TYPE_DM_MPATH:
        case DEV_TYPE_DM_RAID:
            if (!(vitals->dmname = dupblkopt(blkent->blk_opts, "dmname")))
                goto err;
            break;
        case DEV_TYPE_PARTITION:
            /* FIXME: not even sure we really care about partitions... */
            break;
        case DEV_TYPE_LVM2_PV:
            if (!(vitals->unique_id = dupblkopt(blkent->blk_opts, "unique_id")))
                goto err;
            break;
        case DEV_TYPE_LVM2_VG:
            if (!(vitals->unique_id = dupblkopt(blkent->blk_opts, "unique_id")))
                goto err;
            if (!(vitals->vg_name = dupblkopt(blkent->blk_opts, "name")))
                goto err;
            break;
        case DEV_TYPE_LVM2_LV:
            if (!(vitals->unique_id = dupblkopt(blkent->blk_opts, "unique_id")))
                goto err;
            if (!(vitals->lv_name = dupblkopt(blkent->blk_opts, "name")))
                goto err;
            break;
        case DEV_TYPE_MD_RAID:
            /* FIXME */
            break;
        case DEV_TYPE_FS:
            if (!(vitals->unique_id = dupblkopt(blkent->blk_opts, "unique_id")))
                goto err;
            if (!(vitals->fs_type = dupblkopt(blkent->blk_opts, "type"))) 
                goto err;
            if (!(vitals->fs_label = dupblkopt(blkent->blk_opts, "label"))) 
                goto err;
            if (!(vitals->fs_options = dupblkopt(blkent->blk_opts, "options"))) 
                goto err;
            break;
        case DEV_TYPE_NONE:
            break;
    }

    return nash_bdev_vitals_dedupe(nc, vitals);
err:
    nash_vitals_decref(vitals);
    return NULL;
}

/*
 * this structure describes private probe data that relates to the probe
 * function rather than a device, so we only have to initialize probing once.
 */

struct probe_info {
    int id;
    char *name;
    void *priv;
    int (*alloc_priv)(struct probe_info *);
    void (*free_priv)(struct probe_info *);
    int (*do_probe)(nashContext *nc, struct probe_info *pi,
            struct nash_list *nodes, struct nash_bdev_vitals **vitalsp);
};

/* below this: probe functions */
/* PROBE_BDEVID prober */

static void probe_bdevid_destroy(struct probe_info *pi)
{
    struct bdevid *bdevid = pi->priv;
    if (!bdevid)
        return;

    bdevid_destroy(bdevid);
    pi->priv = NULL;
}

static int probe_bdevid_init(struct probe_info *pi)
{
    struct bdevid *bdevid;

    pi->priv = NULL;
    if (!(bdevid = bdevid_new("BDEVID_MODULE_PATH")))
        return -1;

    if (bdevid_module_load(bdevid, pi->name) < 0) {
        bdevid_destroy(bdevid);
        return -1;
    }

    pi->priv = bdevid;
    return 0;
}

struct bdevid_probe_priv {
    nashContext *nc;
    struct nash_dev_node *node;
    struct nash_bdev_vitals *vitals;
};

static int
bdevid_probe_visitor(struct bdevid_probe_result *result, void *privp)
{
    struct nash_bdev_vitals *vitals;
    struct bdevid_probe_priv *priv = (struct bdevid_probe_priv *)privp;
    char *attrs[] = {"module", "probe", "vendor", "model", "unique_id", NULL};
    int i, errnum;

    vitals = priv->vitals;
    vitals->type = DEV_TYPE_DISK;
    if (!(vitals->disk_device_node = strdup(priv->node->dev_path)))
        return -1;

    for (i = 0; attrs[i]; i++) {
        const char *key = attrs[i];
        const char *value = NULL;
        char *s = NULL;

        if (!(value = bdevid_pr_getattr(result, key)))
            continue;
        if (!(s = strdup(value)))
            goto err;
        if (!strcmp(key, "module"))
            vitals->disk_probe_module = s;
        else if (!strcmp(key, "probe"))
            vitals->disk_probe_name = s;
        else if (!strcmp(key, "vendor"))
            vitals->disk_vendor = s;
        else if (!strcmp(key, "model"))
            vitals->disk_model = s;
        else if (!strcmp(key, "unique_id"))
            vitals->unique_id = s;
        else if (s)
            free(s);
    }

    return 0;
err: 
    save_errno(errnum,
        xfree(vitals->disk_device_node);
        xfree(vitals->disk_probe_module);
        xfree(vitals->disk_probe_name);
        xfree(vitals->disk_vendor);
        xfree(vitals->disk_model);
        xfree(vitals->unique_id));

    return -1;
}

int probe_bdevid(nashContext *nc, struct probe_info *pi,
        struct nash_list *nodes, struct nash_bdev_vitals **vitalsp)
{
    struct bdevid_probe_priv priv = { .nc = nc };
    struct bdevid *bdevid;
    struct nash_bdev_vitals *vitals;
    struct nash_dev_node *node;
    int ret, errnum;

    if (!(bdevid = pi->priv))
        return -1;

    if (!(node = priv.node = nash_list_get(nodes, 0)))
        return -1;

    if (!(vitals = priv.vitals = nash_bdev_vitals_alloc()))
        return -1;

    if ((ret = bdevid_probe(bdevid, node->dev_path,
            bdevid_probe_visitor, &priv)) < 0) {
        save_errno(errnum, nash_bdev_vitals_free(vitals));
        return -1;
    }
    if (vitals->type == DEV_TYPE_NONE) {
        nash_vitals_decref(vitals);
        return -1;
    }
    *vitalsp = vitals;
    return ret;
}

/* end DEV_TYPE_DISK probe */

/* begin DEV_TYPE_DM_MPATH probe */
/* end DEV_TYPE_DM_MPATH probe */

/* begin DEV_TYPE_PARTITION probe */
/* end DEV_TYPE_PARTITION probe */

/*
 * this kindof sucks, but each probe has an ID (which can have only one bit
 * set), which are used for two purposes:
 * 1) to mark that we've done a probe we won't need to do again in
 *    node->probe_mask (not always set - dmraid for example can
 *    be used more than once, but there's still a 'final' time)
 * 2) to identify probe initialization data in probe_info[];
 */
#define PROBE_NONE          0x1 /* used for the end of the probe_info list */
#define PROBE_BDEVID_SCSI   0x2
#define PROBE_BDEVID_ATA    0x4
#define PROBE_BDEVID_USB    0x8
#define PROBE_PARTITION     0x10
#define PROBE_DM_MPATH      0x20 /* XXX might not exist... */
#define PROBE_DM_RAID       0x40
#define PROBE_MD_RAID       0x80
#define PROBE_LVM2_PV       0x100
#define PROBE_LVM2_VG       0x200
#define PROBE_LVM2_LV       0x400
#define PROBE_FS            0x800

static struct probe_info probe_info[] = {
    {
        .id = PROBE_BDEVID_SCSI,
        .name = "scsi",
        .alloc_priv = probe_bdevid_init,
        .free_priv = probe_bdevid_destroy,
        .do_probe = probe_bdevid,
    },
    {
        .id = PROBE_BDEVID_ATA,
        .name = "ata",
        .alloc_priv = probe_bdevid_init,
        .free_priv = probe_bdevid_destroy,
        .do_probe = probe_bdevid,
    },
    {
        .id = PROBE_BDEVID_USB,
        .name = "usb",
        .alloc_priv = probe_bdevid_init,
        .free_priv = probe_bdevid_destroy,
        .do_probe = probe_bdevid,
    },
#if 0
    {
        .id = PROBE_PARTITION,
        .name = "partition",
        .do_probe = probe_partitions,
    },
    /* XXX add probes for DM_MPATH, DM_RAID, MD_RAID,
     * LVM2_PV, LVM2_VG, and LVM2_LV
     */
    {
        .id = PROBE_FS,
        .name = "fs",
        .alloc_priv = probe_fs_init,
        .free_priv = probe_fs_destroy,
        .do_probe = probe_blkid,
    },
#endif
    { .id = PROBE_NONE, .name = "end of probe list" }
};

static struct probe_info *get_probe_info(int id)
{
    struct probe_info *pi = &probe_info[0];

    while (pi->id != PROBE_NONE && pi->id != id) 
        pi++;
    if (pi->id == PROBE_NONE)
        return NULL;
    return pi;
}

static int probes_initialized = 0;

int nash_vitals_initialize_probes(void)
{
    struct probe_info *pi;

    if (probes_initialized != 0)
        return probes_initialized;

    for (pi = &probe_info[0]; pi->id != PROBE_NONE; pi++) {
        /* we actually intentionally ignore failure here... maybe we shouldn't,
         * I can see both ways... */
        if (pi->alloc_priv)
            pi->alloc_priv(pi);
    }
    probes_initialized = 1;
    return 1;
}

void nash_vitals_destroy_probes(void)
{
    struct probe_info *pi;

    if (!probes_initialized)
        return;

    for (pi = &probe_info[0]; pi->id != PROBE_NONE; pi++) {
        if (pi->free_priv)
            pi->free_priv(pi);
    }
    probes_initialized = 0;
}

struct nash_list *nash_vitals_probe(nashContext *nc,
        struct nash_dev_node *node)
{
    struct probe_info *pi;
    struct nash_list *ret;
    struct nash_bdev_vitals *vitals = NULL;
    static struct nash_list *nodes;

    if (!nodes) {
        if (!(nodes = nash_ptr_list_new()))
            return NULL;
        while (nash_list_remove(nodes, 0) >= 0)
            ;
    }
    
    if (node->flags & DEV_FLAG_BANISHED)
        return NULL;

    switch (node->type) {
        case DEV_TYPE_TREE:
        case DEV_TYPE_NONE:
            return NULL;
        default:
            if (!(ret = nash_ptr_list_new()))
                return NULL;
            break;
    }

    switch (node->type) {
        case DEV_TYPE_TREE:
            /* this is here just for gcc's benefit. */
            break;
        /* this kindof sucks; it means people can't add modules themselves...*/
        case DEV_TYPE_DISK:
            nash_list_add(nodes, node);
            if (!(node->probe_mask & PROBE_BDEVID_SCSI)) {
                pi = get_probe_info(PROBE_BDEVID_SCSI);
                vitals = NULL;
                if (pi->do_probe(nc, pi, nodes, &vitals) >= 0) {
                    if ((vitals = nash_bdev_vitals_dedupe(nc, vitals)))
                        nash_list_add(ret, vitals);
                    node->probe_mask |= PROBE_BDEVID_SCSI;
                }
            }
            if (!(node->probe_mask & PROBE_BDEVID_ATA)) {
                pi = get_probe_info(PROBE_BDEVID_ATA);
                vitals = NULL;
                if (pi->do_probe(nc, pi, nodes, &vitals) >= 0) {
                    if ((vitals = nash_bdev_vitals_dedupe(nc, vitals)))
                        nash_list_add(ret, vitals);
                    node->probe_mask |= PROBE_BDEVID_ATA;
                }
            }
            if (!(node->probe_mask & PROBE_BDEVID_USB)) {
                pi = get_probe_info(PROBE_BDEVID_USB);
                vitals = NULL;
                if (pi->do_probe(nc, pi, nodes, &vitals) >= 0) {
                    if ((vitals = nash_bdev_vitals_dedupe(nc, vitals)))
                        nash_list_add(ret, vitals);
                    node->probe_mask |= PROBE_BDEVID_USB;
                }
            }
            break;
        default:
        case DEV_TYPE_NONE:
            /* this is here just for gcc's benefit. */
            break;
    }

    return ret;
}

int nash_dev_node_vitals_get(nashContext *nc,
    struct nash_dev_node *node, char *key, int i, char **value)
{
    int rc = -1;
    struct nash_bdev_vitals *vitals = nash_list_get(node->vitals, i);

    if (!vitals)
        return -1;

    if (!strcmp(key, "label")) {
        char *label = NULL;
        switch (vitals->type) {
            case DEV_TYPE_FS:
                label = vitals->fs_label;
                break;
            case DEV_TYPE_LVM2_LV:
                label = vitals->lv_name;
                break;
            case DEV_TYPE_LVM2_VG:
                label = vitals->vg_name;
                break;
            case DEV_TYPE_DM_MPATH:
            case DEV_TYPE_DM_RAID:
                label = vitals->dmname;
                break;
            default:
                rc = 0;
        }
        if (label) {
            *value = label;
            rc = 1;
        } else {
            rc = 0;
        }
    } else if (!strcmp(key, "unique_id")) {
        switch (vitals->type) {
            case DEV_TYPE_DISK:
            case DEV_TYPE_LVM2_PV:
            case DEV_TYPE_LVM2_VG:
            case DEV_TYPE_LVM2_LV:
            case DEV_TYPE_FS:
                *value = vitals->unique_id;
                rc = 1;
                break;
            default:
                rc = 0;
                break;
        }
    }
    return rc;
}

int nash_dev_node_vitals_has(nashContext *nc,
    struct nash_dev_node *node, char *key, char *value)
{
    char *name = NULL;
    int i = -1;
    int rc = 0;

    while (nash_dev_node_vitals_get(nc, node, key, ++i, &name) >= 0) {
        if (!name)
            continue;
        if (!strcmp(name, value)) {
            rc = 1;
            break;
        }
        name = NULL;
    }
    return rc;
}

/*
 * vim:ts=8:sw=4:sts=4:et
 */
Results 1 - 1
Help - FTP Sites List - Software Dir.
Searching half a billion files worldwide
© 1997-2009 MARUHN Internet Solutions