Message ID | 1432115859-11413-6-git-send-email-dimara@arrikto.com |
---|---|
State | New |
Headers | show |
On 05/20/2015 03:57 AM, Dimitris Aragiorgis wrote: > Until now, an SG device was identified only by checking if its path > started with "/dev/sg". Then, hdev_open() set bs->sg accordingly. > This is very fragile, e.g. it fails with symlinks or relative paths. > We should rely on the actual properties of the device instead of the > specified file path. > > Test for an SG device (e.g. /dev/sg0) by ensuring that all of the > following holds: > > - The device supports the SG_GET_VERSION_NUM ioctl > - The device supports the SG_GET_SCSI_ID ioctl > - The specified file name corresponds to a character device I'd check stat first. ioctl's on the wrong device type might have unexpected side effects. > +static int hdev_is_sg(BlockDriverState *bs) > +{ > + > +#if defined(__linux__) > + > + struct stat st; > + struct sg_scsi_id scsiid; > + int sg_version; > + > + if (!bdrv_ioctl(bs, SG_GET_VERSION_NUM, &sg_version) && > + !bdrv_ioctl(bs, SG_GET_SCSI_ID, &scsiid) && > + stat(bs->filename, &st) >= 0 && S_ISCHR(st.st_mode)) { > + DPRINTF("SG device found: type=%d, version=%d\n", > + scsiid.scsi_type, sg_version); > + return 1; > + } > + > +#endif > + > + return 0; Make this return 'bool', using 'true' and 'false'. We require a C99 compiler, after all.
On Wed, May 20, 2015 at 12:57:39PM +0300, Dimitris Aragiorgis wrote:
> This is very fragile, e.g. it fails with symlinks or relative paths.
This is not true since realpath(3) is used to resolve symlinks and
product an absolute path.
Is this patch really necessary?
Hello Stefan, Yes, you are right. Using realpath() is a workaround for supporting symlinks, as long as they point to a path starting with "/dev/sg". I will remove this reference in the revised version of this patch. However, it still holds that determining whether a filename is an SG device or not is based on textual (and hardcoded) examination, i.e., whether it starts with "/dev/sg". The point is that a device node is a device node no matter what its filename or its location in the fs tree is. A device node with major 1, minor 3 is the null device whether it's called /dev/null or not. The proposed patch allows the use of any device node which is capable of acting as a scsi-generic device; it checks for the required intrinsic property ("does this device support the SG ioctl?") versus trying to second-guess the nature of the device node by checking its filename. Similarly, the programming example from SG's documentation does not check the node of the device node at all: http://sg.danny.cz/sg/p/sg_v3_ho.html#pexample /* It is prudent to check we have a sg device by trying an ioctl */ if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) { printf("%s is not an sg device, or old sg driver\n", argv[1]); return 1; The above has the advantage that it works with device nodes of any name, and in any directory. So I suggest we go with the submitted patch taking into account Eric's proposal: The code first stat()s the given filename to ensure it is a character device node, and then it issues the SG_GET_VERSION_NUM and SG_GET_SCSI_ID ioctl()s. Thanks, dimara * Stefan Hajnoczi <stefanha@redhat.com> [2015-06-19 13:33:02 +0100]: > On Wed, May 20, 2015 at 12:57:39PM +0300, Dimitris Aragiorgis wrote: > > This is very fragile, e.g. it fails with symlinks or relative paths. > > This is not true since realpath(3) is used to resolve symlinks and > product an absolute path. > > Is this patch really necessary?
On Mon, Jun 22, 2015 at 01:18:43PM +0300, Dimitris Aragiorgis wrote: > So I suggest we go with the submitted patch taking into account Eric's > proposal: The code first stat()s the given filename to ensure it is a > character device node, and then it issues the SG_GET_VERSION_NUM and > SG_GET_SCSI_ID ioctl()s. That's fine. Regarding Eric's comment about ioctl number collisions, I've checked Linux Documentation/ioctl/ioctl-number.txt. At least under Linux there is no collision for SG_GET_VERSION_NUM/SG_GET_SCSI_ID. Stefan
diff --git a/block/raw-posix.c b/block/raw-posix.c index ace228f..d84e5a0 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -57,6 +57,7 @@ #include <linux/fd.h> #include <linux/fs.h> #include <linux/hdreg.h> +#include <scsi/sg.h> #ifdef __s390__ #include <asm/dasd.h> #endif @@ -2081,15 +2082,38 @@ static void hdev_parse_filename(const char *filename, QDict *options, qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename))); } +static int hdev_is_sg(BlockDriverState *bs) +{ + +#if defined(__linux__) + + struct stat st; + struct sg_scsi_id scsiid; + int sg_version; + + if (!bdrv_ioctl(bs, SG_GET_VERSION_NUM, &sg_version) && + !bdrv_ioctl(bs, SG_GET_SCSI_ID, &scsiid) && + stat(bs->filename, &st) >= 0 && S_ISCHR(st.st_mode)) { + DPRINTF("SG device found: type=%d, version=%d\n", + scsiid.scsi_type, sg_version); + return 1; + } + +#endif + + return 0; +} + static int hdev_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { BDRVRawState *s = bs->opaque; Error *local_err = NULL; int ret; - const char *filename = qdict_get_str(options, "filename"); #if defined(__APPLE__) && defined(__MACH__) + const char *filename = qdict_get_str(options, "filename"); + if (strstart(filename, "/dev/cdrom", NULL)) { kern_return_t kernResult; io_iterator_t mediaIterator; @@ -2118,16 +2142,6 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags, #endif s->type = FTYPE_FILE; -#if defined(__linux__) - { - char resolved_path[ MAXPATHLEN ], *temp; - - temp = realpath(filename, resolved_path); - if (temp && strstart(temp, "/dev/sg", NULL)) { - bs->sg = 1; - } - } -#endif ret = raw_open_common(bs, options, flags, 0, &local_err); if (ret < 0) { @@ -2137,6 +2151,9 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags, return ret; } + /* Since this does ioctl the device must be already opened */ + bs->sg = hdev_is_sg(bs); + if (flags & BDRV_O_RDWR) { ret = check_hdev_writable(s); if (ret < 0) {
Until now, an SG device was identified only by checking if its path started with "/dev/sg". Then, hdev_open() set bs->sg accordingly. This is very fragile, e.g. it fails with symlinks or relative paths. We should rely on the actual properties of the device instead of the specified file path. Test for an SG device (e.g. /dev/sg0) by ensuring that all of the following holds: - The device supports the SG_GET_VERSION_NUM ioctl - The device supports the SG_GET_SCSI_ID ioctl - The specified file name corresponds to a character device Signed-off-by: Dimitris Aragiorgis <dimara@arrikto.com> --- block/raw-posix.c | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-)