📄 os_linux.cpp
字号:
/* * os_linux.c * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2003-8 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2003-8 Doug Gilbert <dougg@torque.net> * * Parts of this file are derived from code that was * * Written By: Adam Radford <linux@3ware.com> * Modifications By: Joel Jacobson <linux@3ware.com> * Arnaldo Carvalho de Melo <acme@conectiva.com.br> * Brad Strand <linux@3ware.com> * * Copyright (C) 1999-2003 3ware Inc. * * Kernel compatablity By: Andre Hedrick <andre@suse.com> * Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com> * * Other ars of this file are derived from code that was * * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org> * Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org> * * 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, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * This code was originally developed as a Senior Thesis by Michael Cornwell * at the Concurrent Systems Laboratory (now part of the Storage Systems * Research Center), Jack Baskin School of Engineering, University of * California, Santa Cruz. http://ssrc.soe.ucsc.edu/ * */// This file contains the linux-specific IOCTL parts of// smartmontools. It includes one interface routine for ATA devices,// one for SCSI devices, and one for ATA devices behind escalade// controllers.#include "config.h"#include <errno.h>#include <fcntl.h>#include <glob.h>#include <scsi/scsi_ioctl.h>#include <scsi/sg.h>#include <stdlib.h>#include <string.h>#include <sys/ioctl.h>#include <sys/stat.h>#include <unistd.h>#ifndef makedev // old versions of types.h do not include sysmacros.h#include <sys/sysmacros.h>#endif#include "int64.h"#include "atacmds.h"#include "extern.h"extern smartmonctrl * con;#include "os_linux.h"#include "scsicmds.h"#include "utility.h"#include "extern.h"#include "cciss.h"#ifndef ENOTSUP#define ENOTSUP ENOSYS#endiftypedef unsigned long long u8;#define ARGUSED(x) ((void)(x))static const char *filenameandversion="$Id: os_linux.cpp,v 1.100 2008/03/04 22:09:47 ballen4705 Exp $";const char *os_XXXX_c_cvsid="$Id: os_linux.cpp,v 1.100 2008/03/04 22:09:47 ballen4705 Exp $" \ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_LINUX_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;// to hold onto exit code for atexit routineextern int exitstatus;// global variable holding byte count of allocated memoryextern long long bytes;/* for passing global control variables */extern smartmonctrl *con;/* This function will setup and fix device nodes for a 3ware controller. */#define MAJOR_STRING_LENGTH 3#define DEVICE_STRING_LENGTH 32#define NODE_STRING_LENGTH 16int setup_3ware_nodes(char *nodename, char *driver_name) { int tw_major = 0; int index = 0; char majorstring[MAJOR_STRING_LENGTH+1]; char device_name[DEVICE_STRING_LENGTH+1]; char nodestring[NODE_STRING_LENGTH]; struct stat stat_buf; FILE *file; /* First try to open up /proc/devices */ if (!(file = fopen("/proc/devices", "r"))) { pout("Error opening /proc/devices to check/create 3ware device nodes\n"); syserror("fopen"); return 0; // don't fail here: user might not have /proc ! } /* Attempt to get device major number */ while (EOF != fscanf(file, "%3s %32s", majorstring, device_name)) { majorstring[MAJOR_STRING_LENGTH]='\0'; device_name[DEVICE_STRING_LENGTH]='\0'; if (!strncmp(device_name, nodename, DEVICE_STRING_LENGTH)) { tw_major = atoi(majorstring); break; } } fclose(file); /* See if we found a major device number */ if (!tw_major) { pout("No major number for /dev/%s listed in /proc/devices. Is the %s driver loaded?\n", nodename, driver_name); return 2; } /* Now check if nodes are correct */ for (index=0; index<16; index++) { sprintf(nodestring, "/dev/%s%d", nodename, index); /* Try to stat the node */ if ((stat(nodestring, &stat_buf))) { /* Create a new node if it doesn't exist */ if (mknod(nodestring, S_IFCHR|0600, makedev(tw_major, index))) { pout("problem creating 3ware device nodes %s", nodestring); syserror("mknod"); return 3; } } /* See if nodes major and minor numbers are correct */ if ((tw_major != (int)(major(stat_buf.st_rdev))) || (index != (int)(minor(stat_buf.st_rdev))) || (!S_ISCHR(stat_buf.st_mode))) { /* Delete the old node */ if (unlink(nodestring)) { pout("problem unlinking stale 3ware device node %s", nodestring); syserror("unlink"); return 4; } /* Make a new node */ if (mknod(nodestring, S_IFCHR|0600, makedev(tw_major, index))) { pout("problem creating 3ware device nodes %s", nodestring); syserror("mknod"); return 5; } } } return 0;}static char prev_scsi_dev[128];// equivalent to open(path, flags)int deviceopen(const char *pathname, char *type){ int fd; if (0 == strcmp(type,"SCSI")) { strncpy(prev_scsi_dev, pathname, sizeof(prev_scsi_dev) - 1); fd = open(pathname, O_RDWR | O_NONBLOCK); if (fd < 0 && errno == EROFS) fd = open(pathname, O_RDONLY | O_NONBLOCK); return fd; } else if (0 == strcmp(type,"ATA")) { // smartd re-opens SCSI devices with "type"==ATA for some reason. // If that was a SCSI generic device (e.g. /dev/sg0) then the // sg driver wants O_RDWR to allow through ATA PASS-THROUGH commands. // The purpose of the next code line is to limit the scope of // this change as a release is pending (and smartd needs a rewrite). if (0 == strncmp(pathname, prev_scsi_dev, sizeof(prev_scsi_dev))) return open(pathname, O_RDWR | O_NONBLOCK); else return open(pathname, O_RDONLY | O_NONBLOCK); } else if (0 == strcmp(type,"ATA_3WARE_9000")) { // the device nodes for this controller are dynamically assigned, // so we need to check that they exist with the correct major // numbers and if not, create them if (setup_3ware_nodes("twa", "3w-9xxx")) { if (!errno) errno=ENXIO; return -1; } return open(pathname, O_RDONLY | O_NONBLOCK); } else if (0 == strcmp(type,"ATA_3WARE_678K")) { // the device nodes for this controller are dynamically assigned, // so we need to check that they exist with the correct major // numbers and if not, create them if (setup_3ware_nodes("twe", "3w-xxxx")) { if (!errno) errno=ENXIO; return -1; } return open(pathname, O_RDONLY | O_NONBLOCK); } else if(0 == strcmp(type, "CCISS")) { // the device is a cciss smart array device. return open(pathname, O_RDWR | O_NONBLOCK); } else return -1;}// equivalent to close(file descriptor)int deviceclose(int fd){ return close(fd);}// print examples for smartctlvoid print_smartctl_examples(){ printf("=================================================== SMARTCTL EXAMPLES =====\n\n");#ifdef HAVE_GETOPT_LONG printf( " smartctl --all /dev/hda (Prints all SMART information)\n\n" " smartctl --smart=on --offlineauto=on --saveauto=on /dev/hda\n" " (Enables SMART on first disk)\n\n" " smartctl --test=long /dev/hda (Executes extended disk self-test)\n\n" " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/hda\n" " (Prints Self-Test & Attribute errors)\n" " smartctl --all --device=3ware,2 /dev/sda\n" " smartctl --all --device=3ware,2 /dev/twe0\n" " smartctl --all --device=3ware,2 /dev/twa0\n" " (Prints all SMART info for 3rd ATA disk on 3ware RAID controller)\n" " smartctl --all --device=hpt,1/1/3 /dev/sda\n" " (Prints all SMART info for the SATA disk attached to the 3rd PMPort\n" " of the 1st channel on the 1st HighPoint RAID controller)\n" );#else printf( " smartctl -a /dev/hda (Prints all SMART information)\n" " smartctl -s on -o on -S on /dev/hda (Enables SMART on first disk)\n" " smartctl -t long /dev/hda (Executes extended disk self-test)\n" " smartctl -A -l selftest -q errorsonly /dev/hda\n" " (Prints Self-Test & Attribute errors)\n" " smartctl -a -d 3ware,2 /dev/sda\n" " smartctl -a -d 3ware,2 /dev/twa0\n" " smartctl -a -d 3ware,2 /dev/twe0\n" " (Prints all SMART info for 3rd ATA disk on 3ware RAID controller)\n" " smartctl -a -d hpt,1/1/3 /dev/sda\n" " (Prints all SMART info for the SATA disk attached to the 3rd PMPort\n" " of the 1st channel on the 1st HighPoint RAID controller)\n" );#endif return;}// we are going to take advantage of the fact that Linux's devfs will only// have device entries for devices that exist. So if we get the equivalent of// ls /dev/hd[a-t], we have all the ATA devices on the system//// If any errors occur, leave errno set as it was returned by the// system call, and return <0.int get_dev_names(char*** names, const char* pattern, const char* name, int max) { int n = 0, retglob, i, lim; char** mp; glob_t globbuf; memset(&globbuf, 0, sizeof(globbuf)); // in case of non-clean exit *names=NULL; // Use glob to look for any directory entries matching the pattern if ((retglob=glob(pattern, GLOB_ERR, NULL, &globbuf))) { // glob failed: free memory and return globfree(&globbuf); if (retglob==GLOB_NOMATCH){ pout("glob(3) found no matches for pattern %s\n", pattern); return 0; } if (retglob==GLOB_NOSPACE) pout("glob(3) ran out of memory matching pattern %s\n", pattern);#ifdef GLOB_ABORTED // missing in old versions of glob.h else if (retglob==GLOB_ABORTED) pout("glob(3) aborted matching pattern %s\n", pattern);#endif else pout("Unexplained error in glob(3) of pattern %s\n", pattern); return -1; } // did we find too many paths? lim = ((int)globbuf.gl_pathc < max) ? (int)globbuf.gl_pathc : max; if (lim < (int)globbuf.gl_pathc) pout("glob(3) found %d > MAX=%d devices matching pattern %s: ignoring %d paths\n", (int)globbuf.gl_pathc, max, pattern, (int)(globbuf.gl_pathc-max)); // allocate space for up to lim number of ATA devices if (!(mp = (char **)calloc(lim, sizeof(char*)))){ pout("Out of memory constructing scan device list\n"); return -1; } // now step through the list returned by glob. If not a link, copy // to list. If it is a link, evaluate it and see if the path ends // in "disc". for (i=0; i<lim; i++){ int retlink; // prepare a buffer for storing the link char linkbuf[1024]; // see if path is a link retlink=readlink(globbuf.gl_pathv[i], linkbuf, 1023); // if not a link (or a strange link), keep it if (retlink<=0 || retlink>1023) mp[n++] = CustomStrDup(globbuf.gl_pathv[i], 1, __LINE__, filenameandversion); else { // or if it's a link that points to a disc, follow it char *p; linkbuf[retlink]='\0'; if ((p=strrchr(linkbuf,'/')) && !strcmp(p+1, "disc")) // This is the branch of the code that gets followed if we are // using devfs WITH traditional compatibility links. In this // case, we add the traditional device name to the list that // is returned. mp[n++] = CustomStrDup(globbuf.gl_pathv[i], 1, __LINE__, filenameandversion); else { // This is the branch of the code that gets followed if we are // using devfs WITHOUT traditional compatibility links. In // this case, we check that the link to the directory is of // the correct type, and then append "disc" to it. char tmpname[1024]={0}; const char * type = (strcmp(name,"ATA") ? "scsi" : "ide"); if (strstr(linkbuf, type)){ snprintf(tmpname, 1024, "%s/disc", globbuf.gl_pathv[i]); mp[n++] = CustomStrDup(tmpname, 1, __LINE__, filenameandversion); } } } } // free memory, track memory usage globfree(&globbuf); mp = static_cast<char **>(realloc(mp,n*(sizeof(char*)))); bytes += n*(sizeof(char*));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -