]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
udev/cdrom: introduce Context
authorYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 24 Dec 2020 15:11:07 +0000 (00:11 +0900)
committerLuca Boccassi <luca.boccassi@gmail.com>
Fri, 8 Jan 2021 14:08:38 +0000 (14:08 +0000)
src/udev/cdrom_id/cdrom_id.c

index cb4a9cb3c3b8fdfdb70b0301e915fcd3d70e6b66..b4b0596a42960f83596b4a73616d425e6be23df4 100644 (file)
@@ -21,6 +21,7 @@
 #include <time.h>
 #include <unistd.h>
 
+#include "fd-util.h"
 #include "log.h"
 #include "memory-util.h"
 #include "random-util.h"
@@ -31,6 +32,10 @@ static bool arg_lock = false;
 static bool arg_unlock = false;
 static const char *arg_node = NULL;
 
+typedef struct Context {
+        int fd;
+} Context;
+
 /* device info */
 static unsigned cd_rw_nonremovable;
 static unsigned cd_rw_removable;
@@ -124,6 +129,21 @@ static unsigned cd_media_track_count_data;
 static unsigned cd_media_track_count_audio;
 static unsigned long long int cd_media_session_last_offset;
 
+static void context_clear(Context *c) {
+        if (!c)
+                return;
+
+        safe_close(c->fd);
+}
+
+static void context_init(Context *c) {
+        assert(c);
+
+        *c = (Context) {
+                .fd = -1,
+        };
+}
+
 #define ERRCODE(s)      ((((s)[2] & 0x0F) << 16) | ((s)[12] << 8) | ((s)[13]))
 #define SK(errcode)     (((errcode) >> 16) & 0xF)
 #define ASC(errcode)    (((errcode) >> 8) & 0xFF)
@@ -233,10 +253,12 @@ static int media_eject(int fd) {
         return scsi_cmd_run_and_log(&sc, fd, NULL, 0, "start/stop unit");
 }
 
-static int cd_capability_compat(int fd) {
+static int cd_capability_compat(Context *c) {
         int capability;
 
-        capability = ioctl(fd, CDROM_GET_CAPABILITY, NULL);
+        assert(c);
+
+        capability = ioctl(c->fd, CDROM_GET_CAPABILITY, NULL);
         if (capability < 0)
                 return log_debug_errno(errno, "CDROM_GET_CAPABILITY failed");
 
@@ -257,24 +279,28 @@ static int cd_capability_compat(int fd) {
         return 0;
 }
 
-static int cd_media_compat(int fd) {
-        if (ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT) != CDS_DISC_OK)
+static int cd_media_compat(Context *c) {
+        assert(c);
+
+        if (ioctl(c->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT) != CDS_DISC_OK)
                 return log_debug_errno(errno, "CDROM_DRIVE_STATUS != CDS_DISC_OK");
 
         cd_media = 1;
         return 0;
 }
 
-static int cd_inquiry(int fd) {
+static int cd_inquiry(Context *c) {
         struct scsi_cmd sc;
         unsigned char inq[36];
         int r;
 
+        assert(c);
+
         scsi_cmd_init(&sc);
         scsi_cmd_set(&sc, 0, GPCMD_INQUIRY);
         scsi_cmd_set(&sc, 4, sizeof(inq));
         scsi_cmd_set(&sc, 5, 0);
-        r = scsi_cmd_run_and_log(&sc, fd, inq, sizeof(inq), "inquire");
+        r = scsi_cmd_run_and_log(&sc, c->fd, inq, sizeof(inq), "inquire");
         if (r < 0)
                 return r;
 
@@ -635,18 +661,19 @@ static int feature_profiles(const unsigned char *profiles, size_t size) {
         return 0;
 }
 
-static int cd_profiles_old_mmc(int fd) {
+static int cd_profiles_old_mmc(Context *c) {
+        disc_information discinfo;
         struct scsi_cmd sc;
         size_t len;
         int r;
 
-        disc_information discinfo;
+        assert(c);
 
         scsi_cmd_init(&sc);
         scsi_cmd_set(&sc, 0, GPCMD_READ_DISC_INFO);
         scsi_cmd_set(&sc, 8, sizeof(discinfo.disc_information_length));
         scsi_cmd_set(&sc, 9, 0);
-        r = scsi_cmd_run_and_log(&sc, fd, (unsigned char *)&discinfo.disc_information_length, sizeof(discinfo.disc_information_length), "read disc information");
+        r = scsi_cmd_run_and_log(&sc, c->fd, (unsigned char *)&discinfo.disc_information_length, sizeof(discinfo.disc_information_length), "read disc information");
         if (r >= 0) {
                 /* Not all drives have the same disc_info length, so requeue
                  * packet with the length the drive tells us it can supply */
@@ -658,7 +685,7 @@ static int cd_profiles_old_mmc(int fd) {
                 scsi_cmd_set(&sc, 0, GPCMD_READ_DISC_INFO);
                 scsi_cmd_set(&sc, 8, len);
                 scsi_cmd_set(&sc, 9, 0);
-                r = scsi_cmd_run_and_log(&sc, fd, (unsigned char *)&discinfo, len, "read disc information");
+                r = scsi_cmd_run_and_log(&sc, c->fd, (unsigned char *)&discinfo, len, "read disc information");
         }
         if (r < 0) {
                 if (cd_media == 1) {
@@ -688,7 +715,7 @@ static int cd_profiles_old_mmc(int fd) {
         return 1;
 }
 
-static int cd_profiles(int fd) {
+static int cd_profiles(Context *c) {
         struct scsi_cmd sc;
         unsigned char features[65530];
         unsigned cur_profile = 0;
@@ -697,18 +724,20 @@ static int cd_profiles(int fd) {
         bool has_media = false;
         int r;
 
+        assert(c);
+
         /* First query the current profile */
         scsi_cmd_init(&sc);
         scsi_cmd_set(&sc, 0, GPCMD_GET_CONFIGURATION);
         scsi_cmd_set(&sc, 8, 8);
         scsi_cmd_set(&sc, 9, 0);
-        r = scsi_cmd_run(&sc, fd, features, 8);
+        r = scsi_cmd_run(&sc, c->fd, features, 8);
         if (r != 0) {
                 /* handle pre-MMC2 drives which do not support GET CONFIGURATION */
                 if (r > 0 && SK(r) == 0x5 && IN_SET(ASC(r), 0x20, 0x24)) {
                         log_debug("Drive is pre-MMC2 and does not support 46h get configuration command; "
                                   "trying to work around the problem.");
-                        return cd_profiles_old_mmc(fd);
+                        return cd_profiles_old_mmc(c);
                 }
 
                 return log_scsi_debug_errno(r, "get configuration");
@@ -737,7 +766,7 @@ static int cd_profiles(int fd) {
         scsi_cmd_set(&sc, 7, ( len >> 8 ) & 0xff);
         scsi_cmd_set(&sc, 8, len & 0xff);
         scsi_cmd_set(&sc, 9, 0);
-        r = scsi_cmd_run_and_log(&sc, fd, features, len, "get configuration");
+        r = scsi_cmd_run_and_log(&sc, c->fd, features, len, "get configuration");
         if (r < 0)
                 return r;
 
@@ -770,7 +799,7 @@ static int cd_profiles(int fd) {
         return has_media;
 }
 
-static int cd_media_info(int fd) {
+static int cd_media_info(Context *c) {
         struct scsi_cmd sc;
         unsigned char header[32];
         static const char *const media_status[] = {
@@ -781,11 +810,13 @@ static int cd_media_info(int fd) {
         };
         int r;
 
+        assert(c);
+
         scsi_cmd_init(&sc);
         scsi_cmd_set(&sc, 0, GPCMD_READ_DISC_INFO);
         scsi_cmd_set(&sc, 8, sizeof(header));
         scsi_cmd_set(&sc, 9, 0);
-        r = scsi_cmd_run_and_log(&sc, fd, header, sizeof(header), "read disc information");
+        r = scsi_cmd_run_and_log(&sc, c->fd, header, sizeof(header), "read disc information");
         if (r < 0)
                 return r;
 
@@ -822,7 +853,7 @@ static int cd_media_info(int fd) {
                         scsi_cmd_set(&sc, 7, 0xC0);
                         scsi_cmd_set(&sc, 9, sizeof(dvdstruct));
                         scsi_cmd_set(&sc, 11, 0);
-                        r = scsi_cmd_run_and_log(&sc, fd, dvdstruct, sizeof(dvdstruct), "read DVD structure");
+                        r = scsi_cmd_run_and_log(&sc, c->fd, dvdstruct, sizeof(dvdstruct), "read DVD structure");
                         if (r < 0)
                                 return r;
 
@@ -837,7 +868,7 @@ static int cd_media_info(int fd) {
                         scsi_cmd_set(&sc, 0, GPCMD_READ_FORMAT_CAPACITIES);
                         scsi_cmd_set(&sc, 8, sizeof(format));
                         scsi_cmd_set(&sc, 9, 0);
-                        r = scsi_cmd_run_and_log(&sc, fd, format, sizeof(format), "read DVD format capacities");
+                        r = scsi_cmd_run_and_log(&sc, c->fd, format, sizeof(format), "read DVD format capacities");
                         if (r < 0)
                                 return r;
 
@@ -876,7 +907,7 @@ static int cd_media_info(int fd) {
                 scsi_cmd_set(&sc, 5, 0);
                 scsi_cmd_set(&sc, 8, sizeof(buffer)/2048);
                 scsi_cmd_set(&sc, 9, 0);
-                r = scsi_cmd_run_and_log(&sc, fd, buffer, sizeof(buffer), "read first 32 blocks");
+                r = scsi_cmd_run_and_log(&sc, c->fd, buffer, sizeof(buffer), "read first 32 blocks");
                 if (r < 0) {
                         cd_media = 0;
                         return r;
@@ -915,7 +946,7 @@ determined:
         return 0;
 }
 
-static int cd_media_toc(int fd) {
+static int cd_media_toc(Context *c) {
         struct scsi_cmd sc;
         unsigned char header[12];
         unsigned char toc[65536];
@@ -923,12 +954,14 @@ static int cd_media_toc(int fd) {
         unsigned char *p;
         int r;
 
+        assert(c);
+
         scsi_cmd_init(&sc);
         scsi_cmd_set(&sc, 0, GPCMD_READ_TOC_PMA_ATIP);
         scsi_cmd_set(&sc, 6, 1);
         scsi_cmd_set(&sc, 8, sizeof(header));
         scsi_cmd_set(&sc, 9, 0);
-        r = scsi_cmd_run_and_log(&sc, fd, header, sizeof(header), "read TOC");
+        r = scsi_cmd_run_and_log(&sc, c->fd, header, sizeof(header), "read TOC");
         if (r < 0)
                 return r;
 
@@ -951,7 +984,7 @@ static int cd_media_toc(int fd) {
         scsi_cmd_set(&sc, 7, (len >> 8) & 0xff);
         scsi_cmd_set(&sc, 8, len & 0xff);
         scsi_cmd_set(&sc, 9, 0);
-        r = scsi_cmd_run_and_log(&sc, fd, toc, len, "read TOC (tracks)");
+        r = scsi_cmd_run_and_log(&sc, c->fd, toc, len, "read TOC (tracks)");
         if (r < 0)
                 return r;
 
@@ -979,7 +1012,7 @@ static int cd_media_toc(int fd) {
         scsi_cmd_set(&sc, 2, 1); /* Session Info */
         scsi_cmd_set(&sc, 8, sizeof(header));
         scsi_cmd_set(&sc, 9, 0);
-        r = scsi_cmd_run_and_log(&sc, fd, header, sizeof(header), "read TOC (multi session)");
+        r = scsi_cmd_run_and_log(&sc, c->fd, header, sizeof(header), "read TOC (multi session)");
         if (r < 0)
                 return r;
 
@@ -990,6 +1023,29 @@ static int cd_media_toc(int fd) {
         return 0;
 }
 
+static int open_drive(Context *c) {
+        _cleanup_close_ int fd = -1;
+
+        assert(c);
+        assert(c->fd < 0);
+
+        for (int cnt = 0; cnt < 20; cnt++) {
+                if (cnt != 0)
+                        (void) usleep(100 * USEC_PER_MSEC + random_u64() % (100 * USEC_PER_MSEC));
+
+                fd = open(arg_node, O_RDONLY|O_NONBLOCK|O_CLOEXEC);
+                if (fd >= 0 || errno != EBUSY)
+                        break;
+        }
+        if (fd < 0)
+                return log_debug_errno(errno, "Unable to open '%s'", arg_node);
+
+        log_debug("probing: '%s'", arg_node);
+
+        c->fd = TAKE_FD(fd);
+        return 0;
+}
+
 static int help(void) {
         printf("Usage: %s [options] <device>\n"
                "  -l --lock-media    lock the media (to enable eject request events)\n"
@@ -1044,79 +1100,70 @@ static int parse_argv(int argc, char *argv[]) {
 }
 
 int main(int argc, char *argv[]) {
-        int fd = -1;
-        int rc = 0;
-        int r;
+        _cleanup_(context_clear) Context c;
+        int r, rc = 0;
 
         log_set_target(LOG_TARGET_AUTO);
         udev_parse_config();
         log_parse_environment();
         log_open();
 
+        context_init(&c);
+
         r = parse_argv(argc, argv);
         if (r <= 0) {
                 rc = r < 0;
                 goto exit;
         }
 
-        for (int cnt = 0; cnt < 20; cnt++) {
-                if (cnt != 0)
-                        (void) usleep(100 * USEC_PER_MSEC + random_u64() % (100 * USEC_PER_MSEC));
-
-                fd = open(arg_node, O_RDONLY|O_NONBLOCK|O_CLOEXEC);
-                if (fd >= 0 || errno != EBUSY)
-                        break;
-        }
-        if (fd < 0) {
-                log_debug("unable to open '%s'", arg_node);
+        if (open_drive(&c) < 0) {
                 rc = 1;
                 goto exit;
         }
-        log_debug("probing: '%s'", arg_node);
 
         /* same data as original cdrom_id */
-        if (cd_capability_compat(fd) < 0) {
+        if (cd_capability_compat(&c) < 0) {
                 rc = 1;
                 goto exit;
         }
 
         /* check for media - don't bail if there's no media as we still need to
          * to read profiles */
-        cd_media_compat(fd);
+        cd_media_compat(&c);
 
         /* check if drive talks MMC */
-        if (cd_inquiry(fd) < 0)
+        if (cd_inquiry(&c) < 0)
                 goto work;
 
         /* read drive and possibly current profile */
-        r = cd_profiles(fd);
+        r = cd_profiles(&c);
         if (r > 0) {
                 /* at this point we are guaranteed to have media in the drive - find out more about it */
 
                 /* get session/track info */
-                cd_media_toc(fd);
+                cd_media_toc(&c);
 
                 /* get writable media state */
-                cd_media_info(fd);
+                cd_media_info(&c);
         }
 
 work:
         /* lock the media, so we enable eject button events */
         if (arg_lock && cd_media) {
                 log_debug("PREVENT_ALLOW_MEDIUM_REMOVAL (lock)");
-                media_lock(fd, true);
+                media_lock(c.fd, true);
         }
 
         if (arg_unlock && cd_media) {
                 log_debug("PREVENT_ALLOW_MEDIUM_REMOVAL (unlock)");
-                media_lock(fd, false);
+                media_lock(c.fd, false);
         }
 
         if (arg_eject) {
                 log_debug("PREVENT_ALLOW_MEDIUM_REMOVAL (unlock)");
-                media_lock(fd, false);
+                media_lock(c.fd, false);
                 log_debug("START_STOP_UNIT (eject)");
-                media_eject(fd);
+                media_eject(c.fd);
         }
 
         printf("ID_CDROM=1\n");
@@ -1295,8 +1342,6 @@ work:
         if (cd_media_track_count_data > 0)
                 printf("ID_CDROM_MEDIA_TRACK_COUNT_DATA=%u\n", cd_media_track_count_data);
 exit:
-        if (fd >= 0)
-                close(fd);
         log_close();
         return rc;
 }