/* $Progeny$ */

/* scsi.c -- Scan the SCSI bus
 *
 * AUTHOR: John R. Daily <jdaily@progeny.com>
 *
 * Copyright 2002 Hewlett-Packard Company
 * Copyright 2001, 2002 Progeny Linux Systems, Inc.
 * Copyright (C) 1998-2000 MandrakeSoft
 *
 * This program 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 of the License, or
 * (at your option) any later version.
 *
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "config.h"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <discover/sysdep.h>
#include <discover/utils.h>

/*
 * The Linux kernel reports SCSI devices using human-readable names,
 * obliterating the original SCSI device type. We can undo some of
 * the damage, but not all of it.
 *
 * This list is taken from kernel 2.4.17, in drivers/scsi/scsi.c.
 */
char *scsi_kernel_mappings[] = {
    "Direct-Access",
    "Sequential-Access",
    "Printer",
    "Processor",
    "WORM",
    "CD-ROM",
    "Scanner",
    "Optical Device",
    "Medium Changer",
    "Communications",
    "Unknown",
    "Unknown",
    "Unknown",
    "Enclosure",
    NULL
};

/*
 * This function is specific to each sysdep.
 */
static void
_discover_sysdep_init(discover_sysdep_data_t *node)
{
    node->busclass = _discover_xmalloc(2);
    node->vendor = _discover_xmalloc(9);
    node->model = _discover_xmalloc(17);
}

discover_sysdep_data_t *
_discover_get_scsi_raw(void)
{
    FILE *file;
    char *line2, *line3;
    char *type;
    char *vendor, *model;
    int i, found_one = 0;
    discover_sysdep_data_t *head = NULL, *node, *last = NULL;

    line2 = (char *)_discover_xmalloc(1024);
    if (line2 == NULL) {
        return NULL;
    }

    line3 = (char *)_discover_xmalloc(1024);
    if (line3 == NULL) {
        return NULL;
    }

    /********************************************************************/
    /* Length of text fields in `/proc/scsi/scsi'                       */
    /*   - Type  17 chars                                               */
    /*   - Vendor 8 chars                                               */
    /*   - Model 16 chars                                               */
    /********************************************************************/

    if((file = fopen(PATH_PROC_SCSI, "r")) == NULL){
        free(line2);
        free(line3);
        return NULL;
    }

    fgets(line2, 500, file);
    if(strstr(line2, "Attached devices:") == NULL){
        fclose(file);
        free(line2);
        free(line3);
        return NULL;
    }
    while((fgets(line2, 500, file) != NULL) &&
          (fgets(line2, 500, file) != NULL) &&
          (fgets(line3, 500, file) != NULL)) {
        node = _discover_sysdep_data_new();
        _discover_sysdep_init(node);

        /*
         * We don't want trailing spaces to throw off the string
         * comparison.
         */
        line2[18]='\0';
        for(i = 17; line2[i] == ' '; i--) {
            line2[i] = '\0';
        }

        line2[42]='\0';
        for(i = 41; line2[i] == ' '; i--) {
            line2[i] = '\0';
        }

        line3[27]='\0';
        for(i = 26; line3[i] == ' '; i--) {
            line3[i] = '\0';
        }

        type = line3 + 10;
        vendor = line2 + 10;
        model = line2 + 26;

        for (i = 0; scsi_kernel_mappings[i]; i++) {
            if (strncmp(type, scsi_kernel_mappings[i],
                        strlen(scsi_kernel_mappings[i])) == 0) {
                sprintf(node->busclass, "%x", i);
                found_one = 1;
            }
        }
        if (!found_one) {
            /* One of the "unknown" classes */
            node->busclass[0] = 'a';
        }

        strcpy(node->vendor, vendor);
        strcpy(node->model, model);

        if (head == NULL) {
            head = node;
            last = head;
        } else {
            last->next = node;
            last = node;
        }
    }
    free(line2);
    free(line3);
    fclose(file);

    return head;
}

/*
 * Local variables:
 * c-file-style: "progeny"
 * indent-tabs-mode: nil
 * End:
 */
/* vim: set cin fo=tcroq sw=4 et sts=4 tw=75: */
