chiark / gitweb /
cdrom_id: request the drive profile features with a dynamic length
[elogind.git] / extras / cdrom_id / cdrom_id.c
index 1b43fe43ae8decf378d7969a96bac5c470f61172..ec001cde713a291f182844ec11453f08b66e24b0 100644 (file)
@@ -398,12 +398,12 @@ static int cd_profiles(struct udev *udev, int fd)
        unsigned int i;
        int err;
 
+       /* First query the current profile */
        scsi_cmd_init(udev, &sc, features, sizeof(features));
        scsi_cmd_set(udev, &sc, 0, 0x46);
-       scsi_cmd_set(udev, &sc, 7, (sizeof(features) >> 8) & 0xff);
-       scsi_cmd_set(udev, &sc, 8, sizeof(features) & 0xff);
+       scsi_cmd_set(udev, &sc, 8, 8);
        scsi_cmd_set(udev, &sc, 9, 0);
-       err = scsi_cmd_run(udev, &sc, fd, features, sizeof(features));
+       err = scsi_cmd_run(udev, &sc, fd, features, 8);
        if ((err != 0)) {
                info_scsi_cmd_err(udev, "GET CONFIGURATION", err);
                /* handle pre-MMC2 drives which do not support GET CONFIGURATION */
@@ -415,31 +415,6 @@ static int cd_profiles(struct udev *udev, int fd)
                return -1;
        }
 
-       len = features[0] << 24 | features[1] << 16 | features[2] << 8 | features[3];
-       info(udev, "GET CONFIGURATION: size of features buffer 0x%04x\n", len);
-
-       if (len > sizeof(features)) {
-               info(udev, "can not get features in a single query, truncating\n");
-               len = sizeof(features);
-       }
-
-       /* device features */
-       for (i = 8; i+4 < len; i += (4 + features[i+3])) {
-               unsigned int feature;
-
-               feature = features[i] << 8 | features[i+1];
-
-               switch (feature) {
-               case 0x00:
-                       info(udev, "GET CONFIGURATION: feature 'profiles', with %i entries\n", features[i+3] / 4);
-                       feature_profiles(udev, &features[i]+4, features[i+3]);
-                       break;
-               default:
-                       info(udev, "GET CONFIGURATION: feature 0x%04x <ignored>, with 0x%02x bytes\n", feature, features[i+3]);
-                       break;
-               }
-       }
-
        cur_profile = features[6] << 8 | features[7];
        if (cur_profile > 0) {
                info(udev, "current profile 0x%02x\n", cur_profile);
@@ -553,6 +528,56 @@ static int cd_profiles(struct udev *udev, int fd)
                info(udev, "profile 0x%02x <ignored>\n", cur_profile);
                break;
        }
+
+
+       len = features[0] << 24 | features[1] << 16 | features[2] << 8 | features[3];
+       info(udev, "GET CONFIGURATION: size of features buffer 0x%04x\n", len);
+
+       if (len > sizeof(features)) {
+               info(udev, "can not get features in a single query, truncating\n");
+               len = sizeof(features);
+       } else if (len <= 8) {
+               len = sizeof(features);
+       }
+
+       /* Now get the full feature buffer */
+       scsi_cmd_init(udev, &sc, features,  len);
+       scsi_cmd_set(udev, &sc, 0, 0x46);
+       scsi_cmd_set(udev, &sc, 7, ( len >> 8 ) & 0xff);
+       scsi_cmd_set(udev, &sc, 8, len & 0xff);
+       scsi_cmd_set(udev, &sc, 9, 0);
+       err = scsi_cmd_run(udev, &sc, fd, features, len);
+       if ((err != 0)) {
+               info_scsi_cmd_err(udev, "GET CONFIGURATION", err);
+               return -1;
+       }
+
+       /* parse the length once more, in case the drive decided to have other features suddenly :) */
+       len = features[0] << 24 | features[1] << 16 | features[2] << 8 | features[3];
+       info(udev, "GET CONFIGURATION: size of features buffer 0x%04x\n", len);
+
+       if (len > sizeof(features)) {
+               info(udev, "can not get features in a single query, truncating\n");
+               len = sizeof(features);
+       }
+
+       /* device features */
+       for (i = 8; i+4 < len; i += (4 + features[i+3])) {
+               unsigned int feature;
+
+               feature = features[i] << 8 | features[i+1];
+
+               switch (feature) {
+               case 0x00:
+                       info(udev, "GET CONFIGURATION: feature 'profiles', with %i entries\n", features[i+3] / 4);
+                       feature_profiles(udev, &features[i]+4, features[i+3]);
+                       break;
+               default:
+                       info(udev, "GET CONFIGURATION: feature 0x%04x <ignored>, with 0x%02x bytes\n", feature, features[i+3]);
+                       break;
+               }
+       }
+
        return 0;
 }