From 6daa792eab1488d013fefc5eb7e4d01f40f38687 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Sun, 7 Feb 2010 20:03:20 +0100 Subject: change defaults for CONFIG/BUILD/INSTALL styles All packages need an update, so here is a very huge commit. Most of the 460 source packages use automatic style for configuration, building and installing. Make these styles default to "auto". If you have a package, which does not conform to this, just use manual style and add a do-$task make target. I added a new style named AUTOTOOL style, which is needed for some broken packages, which needs to be updated via autoconf or automake. I renamed CONFIGURE_STYLE to CONFIG_STYLE. Updates for some packages, which have newer upstream versions. Renaming of all package/*/extra directories. Use the directory src/ to provide overwrites of source files or to add the code, when no upstream package is available or used. src directory will be automatically used. --- package/scsi-spin/Makefile | 8 +- package/scsi-spin/files/scsi-spin.c | 420 ------------------------------------ package/scsi-spin/src/scsi-spin.c | 420 ++++++++++++++++++++++++++++++++++++ 3 files changed, 426 insertions(+), 422 deletions(-) delete mode 100644 package/scsi-spin/files/scsi-spin.c create mode 100644 package/scsi-spin/src/scsi-spin.c (limited to 'package/scsi-spin') diff --git a/package/scsi-spin/Makefile b/package/scsi-spin/Makefile index f8a551b9b..a7abd2b9a 100644 --- a/package/scsi-spin/Makefile +++ b/package/scsi-spin/Makefile @@ -11,14 +11,18 @@ PKG_DESCR:= Utility to spin down scsi disks PKG_SECTION:= misc NO_DISTFILES:= 1 -WRKDIST= ${WRKDIR}/scsi-spin include ${TOPDIR}/mk/package.mk $(eval $(call PKG_template,SCSI_SPIN,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION})) +CONFIG_STYLE:= manual +BUILD_STYLE:= manual +INSTALL_STYLE:= manual + do-build: - ${TARGET_CC} ${TARGET_CFLAGS} -o ${WRKBUILD}/scsi-spin files/scsi-spin.c + ${TARGET_CC} -Wall ${TCPPFLAGS} ${TCFLAGS} -o ${WRKBUILD}/scsi-spin \ + ${WRKBUILD}/scsi-spin.c do-install: ${INSTALL_DIR} ${IDIR_SCSI_SPIN}/usr/sbin diff --git a/package/scsi-spin/files/scsi-spin.c b/package/scsi-spin/files/scsi-spin.c deleted file mode 100644 index 443934c78..000000000 --- a/package/scsi-spin/files/scsi-spin.c +++ /dev/null @@ -1,420 +0,0 @@ -/* - File: scsi-spin.c - - A simple program to manually spin up and down a scsi device. - - Copyright 1998 Rob Browning - Copyright 2001 Eric Delaunay - - This source is covered by the terms the GNU Public License. - - Some of the original code came from - The Linux SCSI programming HOWTO - Heiko Eifeldt heiko@colossus.escape.de - v1.5, 7 May 1996 - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \ - ((M) >= SCSI_DISK1_MAJOR && \ - (M) <= SCSI_DISK7_MAJOR) || \ - ((M) >= SCSI_DISK8_MAJOR && \ - (M) <= SCSI_DISK15_MAJOR)) - -#define SCSI_BLK_MAJOR(M) \ - (SCSI_DISK_MAJOR(M) || \ - (M) == SCSI_CDROM_MAJOR) - -/* define USE_SG_IO to send commands using scsi generic interface - */ -#define USE_SG_IO - -#ifdef USE_SG_IO -int opt_oldioctl = 0; -int opt_verbose = 0; - -const char* SENSE_KEY_STR[16] = { - "NO SENSE", - "RECOVERED ERROR", - "NOT READY", - "MEDIUM ERROR", - "HARDWARE ERROR", - "ILLEGAL REQUEST", - "UNIT ATTENTION", - "DATA PROJECT", - "BLANK CHECK", - "VENDOR-SPECIFIC", - "COPY ARBORTED", - "ABORTED COMMAND", - "EQUAL", - "VOLUME OVERFLOW", - "MISCOMPARED", - "RESERVED" -}; - -/* process a complete SCSI cmd. Use the generic SCSI interface. */ -static int handle_SCSI_cmd(const int fd, - const unsigned cmd_len, /* command length */ - unsigned char *cmd, /* command buffer */ - const unsigned in_size, /* input data size */ - const unsigned out_size, /* output data size */ - unsigned char *io_buff, /* i/o buffer */ - unsigned sense_size, /* sense buf length */ - unsigned char* sense_buff, /* sense buffer */ - const unsigned timeout /* timeout in s */ - ) { - ssize_t status = 0; - int k, err; - sg_io_hdr_t sg_hdr; - unsigned char sense[16]; - - /* safety checks */ - if (!cmd_len) return -1; /* need a cmd_len != 0 */ - if (in_size > 0 && io_buff == NULL) return -1; /* need an input buffer != NULL */ - /* generic SCSI device header construction */ - memset(&sg_hdr, 0, sizeof(sg_hdr)); - sg_hdr.interface_id = 'S'; - sg_hdr.dxfer_direction = SG_DXFER_NONE; - sg_hdr.cmd_len = cmd_len; - sg_hdr.cmdp = cmd; - sg_hdr.dxfer_len = in_size; - sg_hdr.dxferp = io_buff; - sg_hdr.timeout = (timeout ? timeout : 2)*1000; /* timeout in ms */ - if (sense_buff == NULL) { - sense_buff = sense; - sense_size = sizeof(sense); - } - sg_hdr.mx_sb_len = sense_size; - sg_hdr.sbp = sense_buff; - - if (opt_verbose > 1) { - fprintf( stderr, " cmd = " ); - for( k = 0 ; k < cmd_len ; k++ ) - fprintf( stderr, " %02x", cmd[k] ); - fputc( '\n', stderr ); - } - /* send command */ - status = ioctl( fd, SG_IO, &sg_hdr ); - if (status < 0 || sg_hdr.masked_status == CHECK_CONDITION) { - /* some error happened */ - fprintf( stderr, "SG_IO: status = 0x%x cmd = 0x%x\n", - sg_hdr.status, cmd[0] ); - if (opt_verbose > 0) { - fprintf( stderr, " sense = " ); - for( k = 0 ; k < sg_hdr.sb_len_wr ; k++ ) - fprintf( stderr, " %02x", sense_buff[k] ); - fputc( '\n', stderr ); - err = sense_buff[0] & 0x7f; - if (err == 0x70 || err == 0x71) { - fprintf( stderr, " (%s)\n", SENSE_KEY_STR[sense_buff[2] & 0xf] ); - } - } - perror(""); - } - return status; /* 0 means no error */ -} -#endif - -static void -scsi_spin(const int fd, const int desired_state, const int load_eject, const int wait) { -#ifdef USE_SG_IO - if (! opt_oldioctl) { - unsigned char cmdblk [6] = - { START_STOP, /* command */ - (wait ? 0 : 1), /* lun(3 bits)/reserved(4 bits)/immed(1 bit) */ - 0, /* reserved */ - 0, /* reserved */ - (load_eject ? 2 : 0) - | (desired_state ? 1 : 0), /* reserved(6)/LoEj(1)/Start(1)*/ - 0 };/* reserved/flag/link */ - - if (handle_SCSI_cmd(fd, sizeof(cmdblk), cmdblk, 0, 0, NULL, 0, NULL, wait)) { - fprintf( stderr, "start/stop failed\n" ); - exit(2); - } - return; - } -#endif - int ret; - if (desired_state != 0) - ret = ioctl( fd, SCSI_IOCTL_START_UNIT ); - else - ret = ioctl( fd, SCSI_IOCTL_STOP_UNIT ); - if (ret < 0) - perror( "scsi_spin: ioctl" ); -} - -static void -scsi_lock(const int fd, const int door_lock) { -#ifdef USE_SG_IO - if (! opt_oldioctl) { - unsigned char cmdblk [6] = - { ALLOW_MEDIUM_REMOVAL, /* command */ - 0, /* lun(3 bits)/reserved(5 bits) */ - 0, /* reserved */ - 0, /* reserved */ - (door_lock ? 1 : 0), /* reserved(7)/Prevent(1)*/ - 0 };/* control */ - - if (handle_SCSI_cmd(fd, sizeof(cmdblk), cmdblk, 0, 0, NULL, 0, NULL, 2)) { - fprintf( stderr, "lock/unlock failed\n" ); - exit(2); - } - return; - } -#endif - int ret; - if (door_lock != 0) - ret = ioctl( fd, SCSI_IOCTL_DOORLOCK ); - else - ret = ioctl( fd, SCSI_IOCTL_DOORUNLOCK ); - if (ret < 0) - perror( "scsi_lock: ioctl" ); -} - -/* -- [ED] -- - * Check if the device has some of its partitions mounted. - * The check is done by comparison between device major and minor numbers so it - * even works when the device name of the mount point is not the same of the - * one passed to scsi-spin (for example, scsidev creates device aliases under - * /dev/scsi). - */ -static int -is_mounted( const char* device, int use_proc, int devmaj, int devmin ) -{ - struct mntent *mnt; - struct stat devstat; - int mounted = 0; - struct { - __uint32_t dev_id; - __uint32_t host_unique_id; - } scsi_dev_id, scsi_id; - FILE *mtab; - char *mtabfile = use_proc ? "/proc/mounts" : "/etc/mtab"; - - if (devmaj == SCSI_GENERIC_MAJOR) { - /* scsi-spin device arg is /dev/sgN */ - int fd = open( device, O_RDONLY ); - if (fd >= 0) { - int ret = ioctl( fd, SCSI_IOCTL_GET_IDLUN, &scsi_dev_id ); - close( fd ); - if (ret < 0) - return -1; - } - } - /*printf("devid=%x\n",scsi_dev_id.dev_id);*/ - - mtab = setmntent( mtabfile, "r" ); - if (mtab == NULL) - return -1; - - while ((mnt = getmntent( mtab )) != 0) { - char * mdev = mnt->mnt_fsname; - if (stat( mdev, &devstat ) == 0) { - int maj = major(devstat.st_rdev); - int min = minor(devstat.st_rdev); - if (SCSI_DISK_MAJOR(maj) && SCSI_DISK_MAJOR(devmaj)) { - if (maj == devmaj && (min & ~15) == (devmin & ~15)) { - mounted = 1; - break; - } - } - else if (devmaj == SCSI_GENERIC_MAJOR && SCSI_BLK_MAJOR(maj)) { - /* scsi-spin device arg is /dev/sgN */ - int fd = open( mdev, O_RDONLY ); - if (fd >= 0) { - int ret = ioctl( fd, SCSI_IOCTL_GET_IDLUN, &scsi_id ); - close( fd ); - /*printf("id=%x\n",scsi_id.dev_id);*/ - if (ret == 0 && scsi_id.dev_id == scsi_dev_id.dev_id) { - /* same SCSI ID => same device */ - mounted = 1; - break; - } - } - } - else if (maj == SCSI_CDROM_MAJOR && maj == devmaj && min == devmin) { - mounted = 1; - break; - } - } - } - - endmntent( mtab ); - return mounted; -} - -static void -usage() -{ - static char usage_string[] = - "usage: scsi-spin {-u,-d} [-nfpe] device\n" - " -u, --up spin up device.\n" - " -d, --down spin down device.\n" - " -v, --verbose[=n] verbose mode (1: normal, 2: debug).\n" -#ifdef SG_IO - " -e, --loej load (-u) or eject (-d) removable medium.\n" - " -w, --wait=[n] wait the spin up/down operation to be completed\n" - " (n is the number of seconds to timeout).\n" - " -I, --oldioctl use legacy ioctl instead of SG I/O (-e,-w ignored).\n" -#endif - " -l, --lock prevent medium removal.\n" - " -L, --unlock allow medium removal.\n" - " -n, --noact do nothing but check if the device is in use.\n" - " -f, --force force spinning up/down even if the device is in use.\n" - " -p, --proc use /proc/mounts instead of /etc/mtab to do the check.\n" - " device is one of /dev/sd[a-z], /dev/scd[0-9]* or /dev/sg[0-9]*.\n"; - - fputs(usage_string, stderr); -} - -int -main(int argc, char *argv[]) -{ - int result = 0; - int fd; - int opt_up = 0; - int opt_down = 0; - int opt_loej = 0; - int opt_wait = 0; - int opt_force = 0; - int opt_noact = 0; - int opt_proc = 0; - int opt_lock = 0; - int opt_unlock = 0; - struct option cmd_line_opts[] = { - {"verbose", 2, NULL, 'v'}, - {"up", 0, NULL, 'u'}, - {"down", 0, NULL, 'd'}, -#ifdef SG_IO - {"loej", 0, NULL, 'e'}, - {"wait", 2, NULL, 'w'}, - {"oldioctl", 0, NULL, 'I'}, -#endif - {"lock", 0, NULL, 'l'}, - {"unlock", 0, NULL, 'L'}, - {"force", 0, NULL, 'f'}, - {"noact", 0, NULL, 'n'}, - {"proc", 0, NULL, 'p'}, - {0, 0, 0, 0}, - }; - char* endptr = ""; - char* device; - struct stat devstat; - - char c; - while((c = getopt_long(argc, argv, "vudewlLfnp", cmd_line_opts, NULL)) != EOF) { - switch (c) { - case 'v': opt_verbose = optarg ? strtol(optarg, &endptr, 10) : opt_verbose+1; - if (*endptr) goto error; - break; - case 'u': opt_up = 1; break; - case 'd': opt_down = 1; break; -#ifdef SG_IO - case 'e': opt_loej = 1; break; - case 'w': opt_wait = optarg ? strtol(optarg, &endptr, 10) : opt_wait+1; - if (*endptr) goto error; - break; - case 'I': opt_oldioctl = 1; break; -#endif - case 'f': opt_force = 1; break; - case 'l': opt_lock = 1; break; - case 'L': opt_unlock = 1; break; - case 'n': opt_noact = 1; break; - case 'p': opt_proc = 1; break; - default: -error: - usage(); - exit(1); - } - } - - if(opt_up && opt_down) { - fputs("scsi-spin: specified both --up and --down. " - "Is this some kind of test?\n", stderr); - exit(1); - } - if(opt_lock && opt_unlock) { - fputs("scsi-spin: specified both --lock and --unlock. " - "Is this some kind of test?\n", stderr); - exit(1); - } - if (opt_oldioctl && (opt_wait || opt_loej)) { - fputs("scsi-spin: -e or -w not working in old ioctl mode.\n", stderr); - exit(1); - } - if(!(opt_up || opt_down || opt_lock || opt_unlock)) { - fputs("scsi-spin: must specify --up, --down, --lock or --unlock at least.\n", stderr); - exit(1); - } - - if(optind != (argc - 1)) { - usage(); - exit(1); - } - - device = argv[optind]; - - if(stat(device, &devstat) == -1) { - fprintf(stderr, "scsi-spin [stat]: %s: %s\n", device, strerror(errno)); - result = 1; - } - - if (is_mounted( device, opt_proc, major(devstat.st_rdev), minor(devstat.st_rdev) )) { - if (! opt_force) { - fprintf( stderr, "scsi-spin: device already in use (mounted partition)\n" ); - exit(1); - } - else { - fprintf( stderr, "scsi-spin [warning]: device is mounted but --force is passed\n" ); - } - } - - /* first try to open the device r/w */ - fd = open(device, O_RDWR); - if (fd < 0) { - /* if it's fail, then try ro */ - fd = open(device, O_RDONLY); - if (fd < 0) { - fprintf(stderr, "scsi-spin [open]: %s: %s\n", device, strerror(errno)); - exit(1); - } - } - - if ((S_ISBLK(devstat.st_mode) && - SCSI_BLK_MAJOR(major(devstat.st_rdev))) || - (S_ISCHR(devstat.st_mode) && - major(devstat.st_rdev) == SCSI_GENERIC_MAJOR)) - { - if (! opt_noact) { - if (opt_lock || opt_unlock) - scsi_lock(fd, opt_lock); - if (opt_up || opt_down) - scsi_spin(fd, opt_up, opt_loej, opt_wait); - } - } - else { - fprintf(stderr, "scsi-spin: %s is not a disk or generic SCSI device.\n", device); - result = 1; - } - - close(fd); - return result; -} diff --git a/package/scsi-spin/src/scsi-spin.c b/package/scsi-spin/src/scsi-spin.c new file mode 100644 index 000000000..443934c78 --- /dev/null +++ b/package/scsi-spin/src/scsi-spin.c @@ -0,0 +1,420 @@ +/* + File: scsi-spin.c + + A simple program to manually spin up and down a scsi device. + + Copyright 1998 Rob Browning + Copyright 2001 Eric Delaunay + + This source is covered by the terms the GNU Public License. + + Some of the original code came from + The Linux SCSI programming HOWTO + Heiko Eifeldt heiko@colossus.escape.de + v1.5, 7 May 1996 + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \ + ((M) >= SCSI_DISK1_MAJOR && \ + (M) <= SCSI_DISK7_MAJOR) || \ + ((M) >= SCSI_DISK8_MAJOR && \ + (M) <= SCSI_DISK15_MAJOR)) + +#define SCSI_BLK_MAJOR(M) \ + (SCSI_DISK_MAJOR(M) || \ + (M) == SCSI_CDROM_MAJOR) + +/* define USE_SG_IO to send commands using scsi generic interface + */ +#define USE_SG_IO + +#ifdef USE_SG_IO +int opt_oldioctl = 0; +int opt_verbose = 0; + +const char* SENSE_KEY_STR[16] = { + "NO SENSE", + "RECOVERED ERROR", + "NOT READY", + "MEDIUM ERROR", + "HARDWARE ERROR", + "ILLEGAL REQUEST", + "UNIT ATTENTION", + "DATA PROJECT", + "BLANK CHECK", + "VENDOR-SPECIFIC", + "COPY ARBORTED", + "ABORTED COMMAND", + "EQUAL", + "VOLUME OVERFLOW", + "MISCOMPARED", + "RESERVED" +}; + +/* process a complete SCSI cmd. Use the generic SCSI interface. */ +static int handle_SCSI_cmd(const int fd, + const unsigned cmd_len, /* command length */ + unsigned char *cmd, /* command buffer */ + const unsigned in_size, /* input data size */ + const unsigned out_size, /* output data size */ + unsigned char *io_buff, /* i/o buffer */ + unsigned sense_size, /* sense buf length */ + unsigned char* sense_buff, /* sense buffer */ + const unsigned timeout /* timeout in s */ + ) { + ssize_t status = 0; + int k, err; + sg_io_hdr_t sg_hdr; + unsigned char sense[16]; + + /* safety checks */ + if (!cmd_len) return -1; /* need a cmd_len != 0 */ + if (in_size > 0 && io_buff == NULL) return -1; /* need an input buffer != NULL */ + /* generic SCSI device header construction */ + memset(&sg_hdr, 0, sizeof(sg_hdr)); + sg_hdr.interface_id = 'S'; + sg_hdr.dxfer_direction = SG_DXFER_NONE; + sg_hdr.cmd_len = cmd_len; + sg_hdr.cmdp = cmd; + sg_hdr.dxfer_len = in_size; + sg_hdr.dxferp = io_buff; + sg_hdr.timeout = (timeout ? timeout : 2)*1000; /* timeout in ms */ + if (sense_buff == NULL) { + sense_buff = sense; + sense_size = sizeof(sense); + } + sg_hdr.mx_sb_len = sense_size; + sg_hdr.sbp = sense_buff; + + if (opt_verbose > 1) { + fprintf( stderr, " cmd = " ); + for( k = 0 ; k < cmd_len ; k++ ) + fprintf( stderr, " %02x", cmd[k] ); + fputc( '\n', stderr ); + } + /* send command */ + status = ioctl( fd, SG_IO, &sg_hdr ); + if (status < 0 || sg_hdr.masked_status == CHECK_CONDITION) { + /* some error happened */ + fprintf( stderr, "SG_IO: status = 0x%x cmd = 0x%x\n", + sg_hdr.status, cmd[0] ); + if (opt_verbose > 0) { + fprintf( stderr, " sense = " ); + for( k = 0 ; k < sg_hdr.sb_len_wr ; k++ ) + fprintf( stderr, " %02x", sense_buff[k] ); + fputc( '\n', stderr ); + err = sense_buff[0] & 0x7f; + if (err == 0x70 || err == 0x71) { + fprintf( stderr, " (%s)\n", SENSE_KEY_STR[sense_buff[2] & 0xf] ); + } + } + perror(""); + } + return status; /* 0 means no error */ +} +#endif + +static void +scsi_spin(const int fd, const int desired_state, const int load_eject, const int wait) { +#ifdef USE_SG_IO + if (! opt_oldioctl) { + unsigned char cmdblk [6] = + { START_STOP, /* command */ + (wait ? 0 : 1), /* lun(3 bits)/reserved(4 bits)/immed(1 bit) */ + 0, /* reserved */ + 0, /* reserved */ + (load_eject ? 2 : 0) + | (desired_state ? 1 : 0), /* reserved(6)/LoEj(1)/Start(1)*/ + 0 };/* reserved/flag/link */ + + if (handle_SCSI_cmd(fd, sizeof(cmdblk), cmdblk, 0, 0, NULL, 0, NULL, wait)) { + fprintf( stderr, "start/stop failed\n" ); + exit(2); + } + return; + } +#endif + int ret; + if (desired_state != 0) + ret = ioctl( fd, SCSI_IOCTL_START_UNIT ); + else + ret = ioctl( fd, SCSI_IOCTL_STOP_UNIT ); + if (ret < 0) + perror( "scsi_spin: ioctl" ); +} + +static void +scsi_lock(const int fd, const int door_lock) { +#ifdef USE_SG_IO + if (! opt_oldioctl) { + unsigned char cmdblk [6] = + { ALLOW_MEDIUM_REMOVAL, /* command */ + 0, /* lun(3 bits)/reserved(5 bits) */ + 0, /* reserved */ + 0, /* reserved */ + (door_lock ? 1 : 0), /* reserved(7)/Prevent(1)*/ + 0 };/* control */ + + if (handle_SCSI_cmd(fd, sizeof(cmdblk), cmdblk, 0, 0, NULL, 0, NULL, 2)) { + fprintf( stderr, "lock/unlock failed\n" ); + exit(2); + } + return; + } +#endif + int ret; + if (door_lock != 0) + ret = ioctl( fd, SCSI_IOCTL_DOORLOCK ); + else + ret = ioctl( fd, SCSI_IOCTL_DOORUNLOCK ); + if (ret < 0) + perror( "scsi_lock: ioctl" ); +} + +/* -- [ED] -- + * Check if the device has some of its partitions mounted. + * The check is done by comparison between device major and minor numbers so it + * even works when the device name of the mount point is not the same of the + * one passed to scsi-spin (for example, scsidev creates device aliases under + * /dev/scsi). + */ +static int +is_mounted( const char* device, int use_proc, int devmaj, int devmin ) +{ + struct mntent *mnt; + struct stat devstat; + int mounted = 0; + struct { + __uint32_t dev_id; + __uint32_t host_unique_id; + } scsi_dev_id, scsi_id; + FILE *mtab; + char *mtabfile = use_proc ? "/proc/mounts" : "/etc/mtab"; + + if (devmaj == SCSI_GENERIC_MAJOR) { + /* scsi-spin device arg is /dev/sgN */ + int fd = open( device, O_RDONLY ); + if (fd >= 0) { + int ret = ioctl( fd, SCSI_IOCTL_GET_IDLUN, &scsi_dev_id ); + close( fd ); + if (ret < 0) + return -1; + } + } + /*printf("devid=%x\n",scsi_dev_id.dev_id);*/ + + mtab = setmntent( mtabfile, "r" ); + if (mtab == NULL) + return -1; + + while ((mnt = getmntent( mtab )) != 0) { + char * mdev = mnt->mnt_fsname; + if (stat( mdev, &devstat ) == 0) { + int maj = major(devstat.st_rdev); + int min = minor(devstat.st_rdev); + if (SCSI_DISK_MAJOR(maj) && SCSI_DISK_MAJOR(devmaj)) { + if (maj == devmaj && (min & ~15) == (devmin & ~15)) { + mounted = 1; + break; + } + } + else if (devmaj == SCSI_GENERIC_MAJOR && SCSI_BLK_MAJOR(maj)) { + /* scsi-spin device arg is /dev/sgN */ + int fd = open( mdev, O_RDONLY ); + if (fd >= 0) { + int ret = ioctl( fd, SCSI_IOCTL_GET_IDLUN, &scsi_id ); + close( fd ); + /*printf("id=%x\n",scsi_id.dev_id);*/ + if (ret == 0 && scsi_id.dev_id == scsi_dev_id.dev_id) { + /* same SCSI ID => same device */ + mounted = 1; + break; + } + } + } + else if (maj == SCSI_CDROM_MAJOR && maj == devmaj && min == devmin) { + mounted = 1; + break; + } + } + } + + endmntent( mtab ); + return mounted; +} + +static void +usage() +{ + static char usage_string[] = + "usage: scsi-spin {-u,-d} [-nfpe] device\n" + " -u, --up spin up device.\n" + " -d, --down spin down device.\n" + " -v, --verbose[=n] verbose mode (1: normal, 2: debug).\n" +#ifdef SG_IO + " -e, --loej load (-u) or eject (-d) removable medium.\n" + " -w, --wait=[n] wait the spin up/down operation to be completed\n" + " (n is the number of seconds to timeout).\n" + " -I, --oldioctl use legacy ioctl instead of SG I/O (-e,-w ignored).\n" +#endif + " -l, --lock prevent medium removal.\n" + " -L, --unlock allow medium removal.\n" + " -n, --noact do nothing but check if the device is in use.\n" + " -f, --force force spinning up/down even if the device is in use.\n" + " -p, --proc use /proc/mounts instead of /etc/mtab to do the check.\n" + " device is one of /dev/sd[a-z], /dev/scd[0-9]* or /dev/sg[0-9]*.\n"; + + fputs(usage_string, stderr); +} + +int +main(int argc, char *argv[]) +{ + int result = 0; + int fd; + int opt_up = 0; + int opt_down = 0; + int opt_loej = 0; + int opt_wait = 0; + int opt_force = 0; + int opt_noact = 0; + int opt_proc = 0; + int opt_lock = 0; + int opt_unlock = 0; + struct option cmd_line_opts[] = { + {"verbose", 2, NULL, 'v'}, + {"up", 0, NULL, 'u'}, + {"down", 0, NULL, 'd'}, +#ifdef SG_IO + {"loej", 0, NULL, 'e'}, + {"wait", 2, NULL, 'w'}, + {"oldioctl", 0, NULL, 'I'}, +#endif + {"lock", 0, NULL, 'l'}, + {"unlock", 0, NULL, 'L'}, + {"force", 0, NULL, 'f'}, + {"noact", 0, NULL, 'n'}, + {"proc", 0, NULL, 'p'}, + {0, 0, 0, 0}, + }; + char* endptr = ""; + char* device; + struct stat devstat; + + char c; + while((c = getopt_long(argc, argv, "vudewlLfnp", cmd_line_opts, NULL)) != EOF) { + switch (c) { + case 'v': opt_verbose = optarg ? strtol(optarg, &endptr, 10) : opt_verbose+1; + if (*endptr) goto error; + break; + case 'u': opt_up = 1; break; + case 'd': opt_down = 1; break; +#ifdef SG_IO + case 'e': opt_loej = 1; break; + case 'w': opt_wait = optarg ? strtol(optarg, &endptr, 10) : opt_wait+1; + if (*endptr) goto error; + break; + case 'I': opt_oldioctl = 1; break; +#endif + case 'f': opt_force = 1; break; + case 'l': opt_lock = 1; break; + case 'L': opt_unlock = 1; break; + case 'n': opt_noact = 1; break; + case 'p': opt_proc = 1; break; + default: +error: + usage(); + exit(1); + } + } + + if(opt_up && opt_down) { + fputs("scsi-spin: specified both --up and --down. " + "Is this some kind of test?\n", stderr); + exit(1); + } + if(opt_lock && opt_unlock) { + fputs("scsi-spin: specified both --lock and --unlock. " + "Is this some kind of test?\n", stderr); + exit(1); + } + if (opt_oldioctl && (opt_wait || opt_loej)) { + fputs("scsi-spin: -e or -w not working in old ioctl mode.\n", stderr); + exit(1); + } + if(!(opt_up || opt_down || opt_lock || opt_unlock)) { + fputs("scsi-spin: must specify --up, --down, --lock or --unlock at least.\n", stderr); + exit(1); + } + + if(optind != (argc - 1)) { + usage(); + exit(1); + } + + device = argv[optind]; + + if(stat(device, &devstat) == -1) { + fprintf(stderr, "scsi-spin [stat]: %s: %s\n", device, strerror(errno)); + result = 1; + } + + if (is_mounted( device, opt_proc, major(devstat.st_rdev), minor(devstat.st_rdev) )) { + if (! opt_force) { + fprintf( stderr, "scsi-spin: device already in use (mounted partition)\n" ); + exit(1); + } + else { + fprintf( stderr, "scsi-spin [warning]: device is mounted but --force is passed\n" ); + } + } + + /* first try to open the device r/w */ + fd = open(device, O_RDWR); + if (fd < 0) { + /* if it's fail, then try ro */ + fd = open(device, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "scsi-spin [open]: %s: %s\n", device, strerror(errno)); + exit(1); + } + } + + if ((S_ISBLK(devstat.st_mode) && + SCSI_BLK_MAJOR(major(devstat.st_rdev))) || + (S_ISCHR(devstat.st_mode) && + major(devstat.st_rdev) == SCSI_GENERIC_MAJOR)) + { + if (! opt_noact) { + if (opt_lock || opt_unlock) + scsi_lock(fd, opt_lock); + if (opt_up || opt_down) + scsi_spin(fd, opt_up, opt_loej, opt_wait); + } + } + else { + fprintf(stderr, "scsi-spin: %s is not a disk or generic SCSI device.\n", device); + result = 1; + } + + close(fd); + return result; +} -- cgit v1.2.3