📄 transport.hxx
字号:
//// This is part of dvd+rw-tools by Andy Polyakov <appro@fy.chalmers.se>//// Use-it-on-your-own-risk, GPL bless...//// For further details see http://fy.chalmers.se/~appro/linux/DVD+RW///#if defined(__unix) || defined(__unix__)#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <poll.h>#include <sys/time.h>inline long getmsecs(){ struct timeval tv; gettimeofday (&tv,NULL); return tv.tv_sec*1000+tv.tv_usec/1000;}#include <errno.h>#ifndef EMEDIUMTYPE#define EMEDIUMTYPE EINVAL#endif#ifndef ENOMEDIUM#define ENOMEDIUM ENODEV#endif#elif defined(_WIN32)#include <windows.h>#include <stdio.h>#define EINVAL ERROR_BAD_ARGUMENTS#define ENOMEM ERROR_OUTOFMEMORY#define EMEDIUMTYPE ERROR_MEDIA_INCOMPATIBLE#define ENOMEDIUM ERROR_MEDIA_OFFLINE#define ENODEV ERROR_BAD_COMMAND#define EAGAIN ERROR_NOT_READY#define ENOSPC ERROR_DISK_FULL#define EIO ERROR_NOT_SUPPORTED#define ENXIO ERROR_GEN_FAILUREstatic class _win32_errno { public: operator int() { return GetLastError(); } int operator=(int e) { SetLastError(e); return e; }} _sys_errno;#ifdef errno#undef errno#endif#define errno _sys_errnoinline void perror (const char *str){ LPVOID lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), 0, // Default language (LPTSTR) &lpMsgBuf, 0, NULL ); if (str) fprintf (stderr,"%s: %s",str,lpMsgBuf); else fprintf (stderr,"%s",lpMsgBuf); LocalFree(lpMsgBuf);}#define poll(a,b,t) Sleep(t)#define getmsecs() GetTickCount()#define exit(e) ExitProcess(e)#endif#define CREAM_ON_ERRNO_NAKED(s) \ switch ((s)[12]) \ { case 0x04: errno=EAGAIN; break; \ case 0x20: errno=ENODEV; break; \ case 0x21: if ((s)[13]==0) errno=ENOSPC; \ else errno=EINVAL; \ break; \ case 0x30: errno=EMEDIUMTYPE; break; \ case 0x3A: errno=ENOMEDIUM; break; \ }#define CREAM_ON_ERRNO(s) do { CREAM_ON_ERRNO_NAKED(s) } while(0)#define FATAL_START(er) (0x80|(er))#define ERRCODE(s) ((((s)[2]&0x0F)<<16)|((s)[12]<<8)|((s)[13]))#define SK(errcode) (((errcode)>>16)&0xF)#define ASC(errcode) (((errcode)>>8)&0xFF)#define ASCQ(errcode) ((errcode)&0xFF)static void sperror (const char *cmd,int err){ int saved_errno=errno; if (err==-1) fprintf (stderr,":-( unable to %s: ",cmd); else fprintf (stderr,":-[ %s failed with SK=%Xh/ASC=%02Xh/ACQ=%02Xh]: ", cmd,SK(err),ASC(err),ASCQ(err)); errno=saved_errno, perror (NULL);}class autofree { private: unsigned char *ptr; public: autofree() { ptr=NULL; } ~autofree() { if (ptr) free(ptr); } unsigned char *operator=(unsigned char *str) { return ptr=str; } operator unsigned char *() { return ptr; }};#if defined(__linux)#include <sys/ioctl.h>#include <linux/cdrom.h>#include <mntent.h>#include <sys/wait.h>#include <sys/utsname.h>#include <scsi/sg.h>#if !defined(SG_FLAG_LUN_INHIBIT)# if defined(SG_FLAG_UNUSED_LUN_INHIBIT)# define SG_FLAG_LUN_INHIBIT SG_FLAG_UNUSED_LUN_INHIBIT# else# define SG_FLAG_LUN_INHIBIT 0# endif#endif#ifndef CHECK_CONDITION#define CHECK_CONDITION 0x01#endiftypedef enum { NONE=CGC_DATA_NONE, // 3 READ=CGC_DATA_READ, // 2 WRITE=CGC_DATA_WRITE // 1 } Direction;#ifdef SG_IOstatic const int Dir_xlate [4] = { // should have been defined // private in USE_SG_IO scope, // but it appears to be too 0, // implementation-dependent... SG_DXFER_TO_DEV, // 1,CGC_DATA_WRITE SG_DXFER_FROM_DEV, // 2,CGC_DATA_READ SG_DXFER_NONE }; // 3,CGC_DATA_NONEstatic const class USE_SG_IO {private: int yes_or_no;public: USE_SG_IO() { struct utsname buf; uname (&buf); // was CDROM_SEND_PACKET declared dead in 2.5? yes_or_no=(strcmp(buf.release,"2.5.43")>=0); } ~USE_SG_IO(){} operator int() const { return yes_or_no; } int operator[] (Direction dir) const { return Dir_xlate[dir]; }} use_sg_io;#endifclass Scsi_Command {private: int fd,autoclose; char *filename; struct cdrom_generic_command cgc; union { struct request_sense s; unsigned char u[18]; } _sense;#ifdef SG_IO struct sg_io_hdr sg_io;#else struct { int cmd_len,timeout; } sg_io;#endifpublic: Scsi_Command() { fd=-1, autoclose=1; filename=NULL; } Scsi_Command(int f) { fd=f, autoclose=0; filename=NULL; } Scsi_Command(void*f){ fd=(long)f, autoclose=0; filename=NULL; } ~Scsi_Command() { if (fd>=0 && autoclose) close(fd),fd=-1; if (filename) free(filename),filename=NULL; } int associate (const char *file,const struct stat *ref=NULL) { struct stat sb; /* * O_RDWR is expected to provide for none set-root-uid * execution under Linux kernel 2.6[.8]. Under 2.4 it * falls down to O_RDONLY... */ if ((fd=open (file,O_RDWR|O_NONBLOCK)) < 0 && (fd=open (file,O_RDONLY|O_NONBLOCK)) < 0) return 0; if (fstat(fd,&sb) < 0) return 0; if (!S_ISBLK(sb.st_mode)) { errno=ENOTBLK;return 0; } if (ref && (!S_ISBLK(ref->st_mode) || ref->st_rdev!=sb.st_rdev)) { errno=ENXIO; return 0; } filename=strdup(file); return 1; } unsigned char &operator[] (size_t i) { if (i==0) { memset(&cgc,0,sizeof(cgc)), memset(&_sense,0,sizeof(_sense)); cgc.quiet = 1; cgc.sense = &_sense.s;#ifdef SG_IO if (use_sg_io) { memset(&sg_io,0,sizeof(sg_io)); sg_io.interface_id= 'S'; sg_io.mx_sb_len = sizeof(_sense); sg_io.cmdp = cgc.cmd; sg_io.sbp = _sense.u; sg_io.flags = SG_FLAG_LUN_INHIBIT|SG_FLAG_DIRECT_IO; }#endif } sg_io.cmd_len = i+1; return cgc.cmd[i]; } unsigned char &operator()(size_t i) { return _sense.u[i]; } unsigned char *sense() { return _sense.u; } void timeout(int i) { cgc.timeout=sg_io.timeout=i*1000; }#ifdef SG_IO size_t residue() { return use_sg_io?sg_io.resid:0; }#else size_t residue() { return 0; }#endif int transport(Direction dir=NONE,void *buf=NULL,size_t sz=0) { int ret = 0;#ifdef SG_IO#define KERNEL_BROKEN 0 if (use_sg_io) { sg_io.dxferp = buf; sg_io.dxfer_len = sz; sg_io.dxfer_direction = use_sg_io[dir]; if (ioctl (fd,SG_IO,&sg_io)) return -1;#if !KERNEL_BROKEN if ((sg_io.info&SG_INFO_OK_MASK) != SG_INFO_OK)#else if (sg_io.status)#endif { errno=EIO; ret=-1;#if !KERNEL_BROKEN if (sg_io.masked_status&CHECK_CONDITION)#endif { ret = ERRCODE(sg_io.sbp); if (ret==0) ret=-1; else CREAM_ON_ERRNO(sg_io.sbp); } } return ret; } else#undef KERNEL_BROKEN#endif { cgc.buffer = (unsigned char *)buf; cgc.buflen = sz; cgc.data_direction = dir; if (ioctl (fd,CDROM_SEND_PACKET,&cgc)) { ret = ERRCODE(_sense.u); if (ret==0) ret=-1; } } return ret; } int umount(int f=-1) { struct stat fsb,msb; struct mntent *mb; FILE *fp; pid_t pid,rpid; int ret=0,rval; if (f==-1) f=fd; if (fstat (f,&fsb) < 0) return -1; if ((fp=setmntent ("/proc/mounts","r"))==NULL) return -1; while ((mb=getmntent (fp))!=NULL) { if (stat (mb->mnt_fsname,&msb) < 0) continue; // corrupted line? if (msb.st_rdev == fsb.st_rdev) { ret = -1; if ((pid = fork()) == (pid_t)-1) break; if (pid == 0) execl ("/bin/umount","umount",mb->mnt_dir,NULL); while (1) { rpid = waitpid (pid,&rval,0); if (rpid == (pid_t)-1) { if (errno==EINTR) continue; else break; } else if (rpid != pid) { errno = ECHILD; break; } if (WIFEXITED(rval)) { if (WEXITSTATUS(rval) == 0) ret=0; else errno=EBUSY; // most likely break; } else { errno = ENOLINK; // some phony errno break; } } break; } } endmntent (fp); return ret; } int is_reload_needed () { return ioctl (fd,CDROM_MEDIA_CHANGED,CDSL_CURRENT) == 0; }};#elif defined(__OpenBSD__) || defined(__NetBSD__)#include <sys/ioctl.h>#include <sys/scsiio.h>#include <sys/wait.h>#include <sys/param.h>#include <sys/mount.h>typedef off_t off64_t;#define stat64 stat#define fstat64 fstat#define open64 open#define pread64 pread#define pwrite64 pwrite#define lseek64 lseektypedef enum { NONE=0, READ=SCCMD_READ, WRITE=SCCMD_WRITE } Direction;class Scsi_Command {private: int fd,autoclose; char *filename; scsireq_t req;public: Scsi_Command() { fd=-1, autoclose=1; filename=NULL; } Scsi_Command(int f) { fd=f, autoclose=0; filename=NULL; } Scsi_Command(void*f){ fd=(long)f, autoclose=0; filename=NULL; } ~Scsi_Command() { if (fd>=0 && autoclose) close(fd),fd=-1; if (filename) free(filename),filename=NULL; } int associate (const char *file,const struct stat *ref=NULL) { struct stat sb; fd=open(file,O_RDWR|O_NONBLOCK); // this is --^^^^^^-- why we have to run set-root-uid... if (fd < 0) return 0; if (fstat(fd,&sb) < 0) return 0; if (!S_ISCHR(sb.st_mode)) { errno=EINVAL; return 0; } if (ref && (!S_ISCHR(ref->st_mode) || ref->st_rdev!=sb.st_rdev)) { errno=ENXIO; return 0; } filename=strdup(file); return 1; } unsigned char &operator[] (size_t i) { if (i==0) { memset(&req,0,sizeof(req)); req.flags = SCCMD_ESCAPE; req.timeout = 30000; req.senselen = 18; //sizeof(req.sense); } req.cmdlen = i+1; return req.cmd[i]; } unsigned char &operator()(size_t i) { return req.sense[i]; } unsigned char *sense() { return req.sense; } void timeout(int i) { req.timeout=i*1000; } size_t residue() { return req.datalen-req.datalen_used; } int transport(Direction dir=NONE,void *buf=NULL,size_t sz=0) { int ret=0; req.databuf = (caddr_t)buf; req.datalen = sz; req.flags |= dir; if (ioctl (fd,SCIOCCOMMAND,&req) < 0) return -1; if (req.retsts==SCCMD_OK) return 0; errno=EIO; ret=-1; if (req.retsts==SCCMD_SENSE) { ret = ERRCODE(req.sense); if (ret==0) ret=-1; else CREAM_ON_ERRNO(req.sense); } return ret; } // this code is basically redundant... indeed, we normally want to // open device O_RDWR, but we can't do that as long as it's mounted. // in other words, whenever this routine is invoked, device is not // mounted, so that it could as well just return 0; int umount(int f=-1) { struct stat fsb,msb; struct statfs *mntbuf; int ret=0,mntsize,i; if (f==-1) f=fd; if (fstat (f,&fsb) < 0) return -1; if ((mntsize=getmntinfo(&mntbuf,MNT_NOWAIT))==0)return -1; for (i=0;i<mntsize;i++) { char rdev[MNAMELEN+1],*slash,*rslash; mntbuf[i].f_mntfromname[MNAMELEN-1]='\0'; // paranoia if ((slash=strrchr (mntbuf[i].f_mntfromname,'/'))==NULL) continue; strcpy (rdev,mntbuf[i].f_mntfromname); // rdev is 1 byte larger! rslash = strrchr (rdev,'/'); *(rslash+1) = 'r', strcpy (rslash+2,slash+1); if (stat (rdev,&msb) < 0) continue; if (msb.st_rdev == fsb.st_rdev) { ret=unmount (mntbuf[i].f_mntonname,0); break; } } return ret; } int is_reload_needed () { return 1; }};#elif defined(__FreeBSD__)#include <sys/ioctl.h>#include <camlib.h>#include <cam/scsi/scsi_message.h>#include <cam/scsi/scsi_pass.h>#include <sys/wait.h>#include <sys/param.h>#include <sys/mount.h>#include <dirent.h>typedef off_t off64_t;#define stat64 stat#define fstat64 fstat#define open64 open#define pread64 pread#define pwrite64 pwrite#define lseek64 lseek#define ioctl_fd (((struct cam_device *)ioctl_handle)->fd)typedef enum { NONE=CAM_DIR_NONE, READ=CAM_DIR_IN, WRITE=CAM_DIR_OUT } Direction;class Scsi_Command {private: int fd,autoclose; char *filename; struct cam_device *cam; union ccb ccb;public: Scsi_Command() { cam=NULL, fd=-1, autoclose=1; filename=NULL; } Scsi_Command(int f) { char pass[32]; // periph_name is 16 chars long cam=NULL, fd=-1, autoclose=1, filename=NULL; memset (&ccb,0,sizeof(ccb)); ccb.ccb_h.func_code = XPT_GDEVLIST; if (ioctl (f,CAMGETPASSTHRU,&ccb) < 0) return; sprintf (pass,"/dev/%.15s%u",ccb.cgdl.periph_name,ccb.cgdl.unit_number); cam=cam_open_pass (pass,O_RDWR,NULL); } Scsi_Command(void *f) { cam=(struct cam_device *)f, autoclose=0; fd=-1; filename=NULL; } ~Scsi_Command() { if (cam && autoclose) cam_close_device(cam), cam=NULL; if (fd>=0) close(fd); if (filename) free(filename), filename=NULL; } int associate (const char *file,const struct stat *ref=NULL) { struct stat sb; char pass[32]; // periph_name is 16 chars long fd=open(file,O_RDONLY|O_NONBLOCK); // all if (ref) code is actually redundant, it never runs // as long as RELOAD_NEVER_NEEDED... if (ref && fd<0 && errno==EPERM) { // expectedly we would get here if file is /dev/passN if (stat(file,&sb) < 0) return 0; if (!S_ISCHR(ref->st_mode) || ref->st_rdev!=sb.st_rdev) return (errno=ENXIO,0); fd=open(file,O_RDWR); } if (fd < 0) return 0; if (fstat(fd,&sb) < 0) return 0; if (!S_ISCHR(sb.st_mode)) return (errno=EINVAL,0); if (ref && (!S_ISCHR(ref->st_mode) || ref->st_rdev!=sb.st_rdev)) return (errno=ENXIO,0); memset (&ccb,0,sizeof(ccb)); ccb.ccb_h.func_code = XPT_GDEVLIST; if (ioctl(fd,CAMGETPASSTHRU,&ccb)<0) return (close(fd),fd=-1,0); sprintf (pass,"/dev/%.15s%u",ccb.cgdl.periph_name,ccb.cgdl.unit_number); cam=cam_open_pass (pass,O_RDWR,NULL); if (cam==NULL) return (close(fd),fd=-1,0); filename=strdup(file); return 1; } unsigned char &operator[] (size_t i)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -