/*
 * Copyright (C) 2017 ~ 2017 Deepin Technology Co., Ltd.
 *
 * Author:     Iceyer <me@iceyer.net>
 *
 * Maintainer: Iceyer <me@iceyer.net>
 *
 * 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 3 of the License, or
 * 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, see <http://www.gnu.org/licenses/>.
 */

#include "diskid.h"

#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <linux/hdreg.h>

#include <QDebug>

DiskInfo getDiskInfo(const QString &diskpath)
{
    DiskInfo info;
    const size_t BufferSize = 1024;
    char buffer[BufferSize] = {0};
    int fd;
    static struct hd_driveid hd;

    if (geteuid() >  0) {
        qWarning() << "Must be root to use\n";
        return info;
    }
    if ((fd = open(diskpath.toStdString().c_str(), O_RDONLY | O_NONBLOCK)) < 0) {
        qWarning() << "Cannot open device" << diskpath;
        return info;
    }
    if (!ioctl(fd, HDIO_GET_IDENTITY, &hd)) {
        size_t modlelen = sizeof(hd.model) / sizeof(hd.model[0]);
        modlelen = qMin(modlelen, BufferSize);
        memset(buffer, 0, 1024);
        strncpy(buffer, reinterpret_cast<char *>(hd.model), modlelen);
        info.model = QString::fromStdString(std::string(buffer, modlelen)).trimmed();

        size_t seriallen = sizeof(hd.serial_no) / sizeof(hd.serial_no[0]);
        seriallen = qMin(seriallen, BufferSize);
        memset(buffer, 0, 1024);
        strncpy(buffer, reinterpret_cast<char *>(hd.serial_no), seriallen);
        info.serial_no = QString::fromStdString(std::string(buffer, seriallen)).trimmed();
        qDebug() << "Get hard disk info"
                 << diskpath << info.serial_no
                 <<  QString::fromStdString(std::string(buffer)).trimmed();
        info.name = diskpath;
    } else if (errno == -ENOMSG) {
        qDebug() << "No hard disk identification information available";
        return info;
    } else {
        qDebug() << "Call ioctl HDIO_GET_IDENTITY failed:" << diskpath << errno << strerror(errno);
        return info;
    }
    return info;
}
