module/removables: audio CD support

Audio CDs are special, in that they don’t (usually) have any data
partitions. They also don’t have a volume label. They just have
tracks.

Before this patch, we ignored all optical mediums that did *not* have
a filesystem (that includes audio CDs).

Now, instead of using the ID_FS_USAGE property to determine whether
there’s media present in the CD-ROM or not, we use the
ID_CDROM_MEDIA. This property is set to ‘1’ for both audio CDs and
data CDs.

Then, we read the ID_CDROM_MEDIA_TRACK_COUNT_AUDIO property to
determine how many audio tracks there are.

If the CD has a filesystem, we treat it as a data CD, and use the
already existing add_partition() function to track it.

If the CD does _not_ have a filesystem, but it _does_ have at least
one audio track, we treat it as an audio CD and use the new
add_audio_cd() function to track it.

This function is almost identical to add_partition(), but instead of
reading the ID_FS_LABEL property, it reads the
ID_CDROM_MEDIA_TRACK_COUNT_AUDIO property and synthesizes a label on
the form “Audio CD - N tracks”.

Finally, a new boolean tag, “audio”, has been added. It is set to true
for audio CD “partitions”, and to false in all other cases.
This commit is contained in:
Daniel Eklöf 2021-12-26 12:17:49 +01:00
parent 4ff1c43669
commit d9316a202d
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F

View file

@ -36,8 +36,8 @@ struct partition {
char *label;
uint64_t size;
bool audio_cd;
/*tll(char *) mount_points;*/
mount_point_list_t mount_points;
};
@ -142,13 +142,14 @@ content(struct module *mod)
tag_new_string(mod, "vendor", p->block->vendor),
tag_new_string(mod, "model", p->block->model),
tag_new_bool(mod, "optical", p->block->optical),
tag_new_bool(mod, "audio", p->audio_cd),
tag_new_string(mod, "device", p->dev_path),
tag_new_int_range(mod, "size", p->size, 0, p->block->size),
tag_new_string(mod, "label", label),
tag_new_bool(mod, "mounted", is_mounted),
tag_new_string(mod, "mount_point", mount_point),
},
.count = 8,
.count = 9,
};
exposables[idx++] = m->label->instantiate(m->label, &tags);
@ -278,6 +279,64 @@ add_partition(struct module *mod, struct block_device *block,
.dev_path = strdup(udev_device_get_devnode(dev)),
.label = label != NULL ? strdup(label) : NULL,
.size = size,
.audio_cd = false,
.mount_points = tll_init()}));
struct partition *p = &tll_back(block->partitions);
update_mount_points(p);
mtx_unlock(&mod->lock);
return p;
}
static struct partition *
add_audio_cd(struct module *mod, struct block_device *block,
struct udev_device *dev)
{
struct private *m = mod->private;
const char *_size = udev_device_get_sysattr_value(dev, "size");
uint64_t size = 0;
if (_size != NULL)
sscanf(_size, "%"SCNu64, &size);
#if 0
struct udev_list_entry *e = NULL;
udev_list_entry_foreach(e, udev_device_get_properties_list_entry(dev)) {
LOG_DBG("%s -> %s", udev_list_entry_get_name(e), udev_list_entry_get_value(e));
}
#endif
const char *devname = udev_device_get_property_value(dev, "DEVNAME");
if (devname != NULL) {
tll_foreach(m->ignore, it) {
if (strcmp(it->item, devname) == 0) {
LOG_DBG("ignoring %s because it is on the ignore list", devname);
return NULL;
}
}
}
const char *_track_count = udev_device_get_property_value(
dev, "ID_CDROM_MEDIA_TRACK_COUNT_AUDIO");
unsigned long track_count = strtoul(_track_count, NULL, 10);
char label[64];
snprintf(label, sizeof(label), "Audio CD - %lu tracks", track_count);
LOG_INFO("audio CD: add: %s: tracks=%lu, label=%s, size=%"PRIu64,
udev_device_get_devnode(dev), track_count, label, size);
mtx_lock(&mod->lock);
tll_push_back(
block->partitions,
((struct partition){
.block = block,
.sys_path = strdup(udev_device_get_devpath(dev)),
.dev_path = strdup(udev_device_get_devnode(dev)),
.label = label != NULL ? strdup(label) : NULL,
.size = size,
.audio_cd = true,
.mount_points = tll_init()}));
struct partition *p = &tll_back(block->partitions);
@ -296,7 +355,9 @@ del_partition(struct module *mod, struct block_device *block,
tll_foreach(block->partitions, it) {
if (strcmp(it->item.sys_path, sys_path) == 0) {
LOG_INFO("partition: del: %s", it->item.dev_path);
LOG_INFO("%s: del: %s",
it->item.audio_cd ? "audio CD" : "partition",
it->item.dev_path);
free_partition(&it->item);
tll_remove(block->partitions, it);
@ -351,8 +412,16 @@ add_device(struct module *mod, struct udev_device *dev)
const char *_optical = udev_device_get_property_value(dev, "ID_CDROM");
bool optical = _optical != NULL && strcmp(_optical, "1") == 0;
const char *_media = udev_device_get_property_value(dev, "ID_CDROM_MEDIA");
bool media = _media != NULL && strcmp(_media, "1") == 0;
const char *_fs_usage = udev_device_get_property_value(dev, "ID_FS_USAGE");
bool media = _fs_usage != NULL && strcmp(_fs_usage, "filesystem") == 0;
bool have_fs = _fs_usage != NULL && strcmp(_fs_usage, "filesystem") == 0;
const char *_audio_track_count = udev_device_get_property_value(
dev, "ID_CDROM_MEDIA_TRACK_COUNT_AUDIO");
unsigned long audio_track_count =
_audio_track_count != NULL ? strtoul(_audio_track_count, NULL, 10) : 0;
LOG_DBG("device: add: %s: vendor=%s, model=%s, optical=%d, size=%"PRIu64,
udev_device_get_devnode(dev), vendor, model, optical, size);
@ -374,8 +443,12 @@ add_device(struct module *mod, struct udev_device *dev)
mtx_unlock(&mod->lock);
struct block_device *block = &tll_back(m->devices);
if (optical && media)
if (optical) {
if (have_fs)
add_partition(mod, block, dev);
else if (audio_track_count > 0)
add_audio_cd(mod, block, dev);
}
return &tll_back(m->devices);
}
@ -409,31 +482,53 @@ change_device(struct module *mod, struct udev_device *dev)
const char *sys_path = udev_device_get_devpath(dev);
mtx_lock(&mod->lock);
struct block_device *block = NULL;
tll_foreach(m->devices, it) {
if (strcmp(it->item.sys_path, sys_path) == 0) {
LOG_DBG("device: change: %s", it->item.dev_path);
block = &it->item;
break;
}
}
if (it->item.optical) {
const char *_media = udev_device_get_property_value(dev, "ID_FS_USAGE");
bool media = _media != NULL && strcmp(_media, "filesystem") == 0;
bool media_change = media != it->item.media;
if (block == NULL)
goto out;
it->item.media = media;
LOG_DBG("device: change: %s", block->dev_path);
if (!block->optical)
goto out;
const char *_media = udev_device_get_property_value(dev, "ID_CDROM_MEDIA");
bool media = _media != NULL && strcmp(_media, "1") == 0;
const char *_fs_usage = udev_device_get_property_value(dev, "ID_FS_USAGE");
bool have_fs = _fs_usage != NULL && strcmp(_fs_usage, "filesystem") == 0;
const char *_audio_track_count = udev_device_get_property_value(
dev, "ID_CDROM_MEDIA_TRACK_COUNT_AUDIO");
unsigned long audio_track_count =
_audio_track_count != NULL ? strtoul(_audio_track_count, NULL, 10) : 0;
bool media_change = media != block->media;
block->media = media;
mtx_unlock(&mod->lock);
if (media_change) {
LOG_INFO("device: change: %s: media %s",
it->item.dev_path, media ? "inserted" : "removed");
block->dev_path, media ? "inserted" : "removed");
if (media)
return add_partition(mod, &it->item, dev) != NULL;
else
return del_partition(mod, &it->item, dev);
}
}
}
if (media) {
if (have_fs)
return add_partition(mod, block, dev) != NULL;
else if (audio_track_count > 0)
return add_audio_cd(mod, block, dev) != NULL;
} else
return del_partition(mod, block, dev);
}
out:
mtx_unlock(&mod->lock);
return false;
}