1
/***************************************************************************
4
* probe-volume.c : volume prober
6
* Copyright (C) 2006, 2007 Jean-Yves Lefort <jylefort@FreeBSD.org>
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22
**************************************************************************/
35
#include <sys/ioctl.h>
38
#include <sys/param.h>
39
#include <sys/mount.h>
40
#include <sys/types.h>
41
#include <ufs/ufs/ufsmount.h>
42
#include <ufs/ufs/dinode.h>
43
#include <ufs/ffs/fs.h>
45
#include <isofs/cd9660/iso.h>
47
#include <libvolume_id.h>
49
#include "libhal/libhal.h"
51
#include "../libprobe/hfp.h"
53
#include "freebsd_dvd_rw_utils.h"
55
#define ISO_VOLDESC_SEC 16
57
struct iso_path_table_entry
59
char name_len [ISODCL(1,1)];
60
char ext_attr_len [ISODCL(2,2)];
61
char extent [ISODCL(3,6)];
62
char parent_no [ISODCL(7,8)];
65
#define ISO_PATH_TABLE_ENTRY_SIZE 8
67
#if (__FreeBSD_version < 600101) && (__FreeBSD_kernel_version < 600101)
69
isonum_731(unsigned char *p)
71
return (p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24);
75
isonum_732(unsigned char *p)
77
return (p[3] | p[2] << 8 | p[1] << 16 | p[0] << 24);
82
hf_probe_volume_getenv_uintmax (const char *name)
86
g_return_val_if_fail(name != NULL, 0);
90
return str ? strtoumax(str, NULL, 10) : 0;
94
hf_probe_volume_getenv_int (const char *name)
98
g_return_val_if_fail(name != NULL, 0);
102
return str ? atoi(str) : 0;
106
hf_probe_volume_get_label (const struct volume_id *vid)
110
if (vid && *vid->label)
112
if (g_utf8_validate(vid->label, -1, NULL))
113
label = g_strdup(vid->label);
114
else /* assume ISO8859-1 */
115
label = g_convert(vid->label, -1, "UTF-8", "ISO8859-1", NULL, NULL, NULL);
122
hf_probe_volume_get_disc_info (int fd,
126
struct ioc_toc_header toc_header;
128
struct cd_toc_entry *buffer = NULL;
129
struct ioc_read_toc_entry read_toc_entry;
132
g_return_if_fail(has_audio != NULL);
133
g_return_if_fail(has_data != NULL);
138
if (ioctl(fd, CDIOREADTOCHEADER, &toc_header) < 0)
141
n_tracks = toc_header.ending_track - toc_header.starting_track + 1;
143
buffer = g_new(struct cd_toc_entry, n_tracks + 1);
145
read_toc_entry.address_format = CD_MSF_FORMAT;
146
read_toc_entry.starting_track = 0;
147
read_toc_entry.data_len = (n_tracks + 1) * sizeof(struct cd_toc_entry);
148
read_toc_entry.data = buffer;
150
if (ioctl(fd, CDIOREADTOCENTRYS, &read_toc_entry) < 0)
153
for (i = 0; i < n_tracks; i++)
155
if ((buffer[i].control & 4) != 0)
166
hf_probe_volume_advanced_disc_detect (int fd)
168
size_t secsz = ISO_DEFAULT_BLOCK_SIZE;
170
struct iso_primary_descriptor desc;
172
int ptbl_size, ptbl_bsize;
174
struct iso_path_table_entry *pte;
179
readoff = ISO_VOLDESC_SEC * secsz;
182
if (pread(fd, &desc, sizeof desc, readoff) != sizeof desc)
184
hfp_warning("volume descriptor read error");
187
if (isonum_711(desc.type) == ISO_VD_END)
191
while (isonum_711(desc.type) != ISO_VD_PRIMARY);
193
ptbl_size = isonum_733(desc.path_table_size);
194
#if BYTE_ORDER == LITTLE_ENDIAN
195
ptbl_lbn = isonum_731(desc.type_l_path_table);
197
ptbl_lbn = isonum_732(desc.type_m_path_table);
199
ptbl_bsize = (ptbl_size + secsz - 1) / secsz * secsz;
200
ptbl = g_malloc(ptbl_bsize);
203
hfp_warning("path table allocation failure");
206
readoff = ptbl_lbn * secsz;
207
if (pread(fd, ptbl, ptbl_bsize, readoff) != ptbl_bsize)
210
hfp_warning("path table read error");
212
for (off = 0; off < ptbl_size; off += pte_len)
214
pte = (struct iso_path_table_entry *)(ptbl + off);
215
name_len = *pte->name_len;
216
pte_len = ISO_PATH_TABLE_ENTRY_SIZE + name_len + (name_len % 2);
217
if (*(short *)pte->parent_no != 1)
219
if (name_len == 8 && strncmp(pte->name, "VIDEO_TS", 8) == 0)
221
libhal_device_set_property_bool(hfp_ctx, hfp_udi, "volume.disc.is_videodvd", TRUE, &hfp_error);
224
else if (name_len == 3 && strncmp(pte->name, "VCD", 8) == 0)
226
libhal_device_set_property_bool(hfp_ctx, hfp_udi, "volume.disc.is_vcd", TRUE, &hfp_error);
229
else if (name_len == 4 && strncmp(pte->name, "SVCD", 4) == 0)
231
libhal_device_set_property_bool(hfp_ctx, hfp_udi, "volume.disc.is_svcd", TRUE, &hfp_error);
239
hf_probe_volume_get_partition_info (const char *geom_class,
247
g_return_val_if_fail(geom_class != NULL, FALSE);
248
g_return_val_if_fail(devfile != NULL, FALSE);
249
g_return_val_if_fail(number != NULL, FALSE);
250
g_return_val_if_fail(type != NULL, FALSE);
251
g_return_val_if_fail(scheme != NULL, FALSE);
252
g_return_val_if_fail(mediasize != NULL, FALSE);
253
g_return_val_if_fail(offset != NULL, FALSE);
255
if (strcmp(geom_class, "MBR") &&
256
strcmp(geom_class, "MBREXT") &&
257
strcmp(geom_class, "GPT") &&
258
strcmp(geom_class, "SUN") &&
259
strcmp(geom_class, "APPLE"))
262
*mediasize = hf_probe_volume_getenv_uintmax("HF_VOLUME_SIZE");
266
*offset = hf_probe_volume_getenv_uintmax("HF_VOLUME_OFFSET");
268
*number = hf_probe_volume_getenv_int("HF_VOLUME_PART_INDEX");
274
partno = strrchr(devfile, 's');
278
len = strlen(partno) - 1;
279
if (len > 0 && strspn(partno + 1, "0123456789") == len)
280
*number = atoi(partno);
285
*scheme = g_ascii_strdown(geom_class, -1);
286
if (! strcmp(*scheme, "apple"))
289
*scheme = g_strdup("apm");
292
if (! strcmp(*scheme, "mbrext"))
295
*scheme = g_strdup("embr");
298
if (! strcmp(*scheme, "mbr") || ! strcmp(*scheme, "embr"))
299
*type = g_strdup_printf("0x%x",
300
hf_probe_volume_getenv_int("HF_VOLUME_PART_TYPE"));
305
parttype = getenv("HF_VOLUME_PART_TYPE");
308
*type = g_strdup(parttype);
310
*type = g_strdup("");
317
main (int argc, char **argv)
321
char *grandparent_udi;
322
char *parent_drive_type;
324
struct volume_id *vid = NULL;
326
gboolean has_children;
329
gboolean is_partition = FALSE;
330
gboolean has_audio = FALSE;
331
gboolean has_data = FALSE;
332
gboolean is_blank = FALSE;
335
unsigned int sector_size = 0;
336
off_t media_size = 0;
338
if (! hfp_init(argc, argv))
341
device_file = getenv("HAL_PROP_BLOCK_DEVICE");
345
parent_udi = getenv("HAL_PROP_INFO_PARENT");
349
/* give a meaningful process title for ps(1) */
351
setproctitle("%s", device_file);
354
has_children = hfp_getenv_bool("HF_HAS_CHILDREN");
355
is_swap = hfp_getenv_bool("HF_IS_SWAP");
357
fd = open(device_file, O_RDONLY);
361
parent_drive_type = libhal_device_get_property_string(hfp_ctx, parent_udi, "storage.drive_type", &hfp_error);
362
dbus_error_free(&hfp_error);
364
grandparent_udi = libhal_device_get_property_string(hfp_ctx, parent_udi, "info.parent", &hfp_error);
365
dbus_error_free(&hfp_error);
367
is_cdrom = parent_drive_type && ! strcmp(parent_drive_type, "cdrom");
368
g_free(parent_drive_type);
372
hf_probe_volume_get_disc_info(fd, &has_audio, &has_data);
373
is_blank = (! has_audio && ! has_data);
376
ioctl(fd, DIOCGMEDIASIZE, &media_size);
379
* We only check for filesystems if the volume has no children,
380
* otherwise volume_id might find a filesystem in what is actually
381
* the first child partition of the volume.
383
* If hald (which has looked at the partition type) reports that it
384
* is a swap partition, we probe it nevertheless in case the
385
* partition type is incorrect.
387
if (! has_children && ! (is_cdrom && ! has_data))
389
vid = volume_id_open_fd(fd);
392
if (volume_id_probe_all(vid, 0, media_size) == 0)
396
volume_id_close(vid);
402
if (! has_children && ! is_swap && ! has_audio && ! has_data && ! is_blank)
405
libhal_device_add_capability(hfp_ctx, hfp_udi, "volume", &hfp_error);
412
libhal_device_set_property_string(hfp_ctx, hfp_udi, "info.category", "volume.disc", &hfp_error);
413
libhal_device_add_capability(hfp_ctx, hfp_udi, "volume.disc", &hfp_error);
415
libhal_device_set_property_bool(hfp_ctx, hfp_udi, "volume.disc.has_audio", has_audio, &hfp_error);
416
libhal_device_set_property_bool(hfp_ctx, hfp_udi, "volume.disc.has_data", has_data, &hfp_error);
417
libhal_device_set_property_bool(hfp_ctx, hfp_udi, "volume.disc.is_vcd", FALSE, &hfp_error);
418
libhal_device_set_property_bool(hfp_ctx, hfp_udi, "volume.disc.is_svcd", FALSE, &hfp_error);
419
libhal_device_set_property_bool(hfp_ctx, hfp_udi, "volume.disc.is_videodvd", FALSE, &hfp_error);
420
libhal_device_set_property_bool(hfp_ctx, hfp_udi, "volume.disc.is_appendable", FALSE, &hfp_error);
421
libhal_device_set_property_bool(hfp_ctx, hfp_udi, "volume.disc.is_blank", is_blank, &hfp_error);
422
libhal_device_set_property_bool(hfp_ctx, hfp_udi, "volume.disc.is_rewritable", FALSE, &hfp_error);
423
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.disc.type", "unknown", &hfp_error);
425
/* the following code was adapted from linux's probe-volume.c */
427
cdrom = hfp_cdrom_new_from_fd(fd, device_file, grandparent_udi);
430
type = get_disc_type(cdrom);
434
case 0x08: /* CD-ROM */
435
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.disc.type", "cd_rom", &hfp_error);
437
case 0x09: /* CD-R */
438
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.disc.type", "cd_r", &hfp_error);
440
case 0x0a: /* CD-RW */
441
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.disc.type", "cd_rw", &hfp_error);
442
libhal_device_set_property_bool(hfp_ctx, hfp_udi, "volume.disc.is_rewritable", TRUE, &hfp_error);
444
case 0x10: /* DVD-ROM */
445
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.disc.type", "dvd_rom", &hfp_error);
447
case 0x11: /* DVD-R Sequential */
448
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.disc.type", "dvd_r", &hfp_error);
450
case 0x12: /* DVD-RAM */
451
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.disc.type", "dvd_ram", &hfp_error);
452
libhal_device_set_property_bool(hfp_ctx, hfp_udi, "volume.disc.is_rewritable", TRUE, &hfp_error);
454
case 0x13: /* DVD-RW Restricted Overwrite */
455
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.disc.type", "dvd_rw", &hfp_error);
456
libhal_device_set_property_bool(hfp_ctx, hfp_udi, "volume.disc.is_rewritable", TRUE, &hfp_error);
458
case 0x14: /* DVD-RW Sequential */
459
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.disc.type", "dvd_rw", &hfp_error);
460
libhal_device_set_property_bool(hfp_ctx, hfp_udi, "volume.disc.is_rewritable", TRUE, &hfp_error);
462
case 0x1A: /* DVD+RW */
463
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.disc.type", "dvd_plus_rw", &hfp_error);
464
libhal_device_set_property_bool(hfp_ctx, hfp_udi, "volume.disc.is_rewritable", TRUE, &hfp_error);
466
case 0x1B: /* DVD+R */
467
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.disc.type", "dvd_plus_r", &hfp_error);
469
case 0x2B: /* DVD+R Double Layer */
470
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.disc.type", "dvd_plus_r_dl", &hfp_error);
472
case 0x40: /* BD-ROM */
473
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.disc.type", "bd_rom", &hfp_error);
475
case 0x41: /* BD-R Sequential */
476
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.disc.type", "bd_r", &hfp_error);
478
case 0x42: /* BD-R Random */
479
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.disc.type", "bd_r", &hfp_error);
481
case 0x43: /* BD-RE */
482
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.disc.type", "bd_re", &hfp_error);
483
libhal_device_set_property_bool(hfp_ctx, hfp_udi, "volume.disc.is_rewritable", TRUE, &hfp_error);
485
case 0x50: /* HD DVD-ROM */
486
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.disc.type", "hddvd_rom", &hfp_error);
488
case 0x51: /* HD DVD-R */
489
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.disc.type", "hddvd_r", &hfp_error);
491
case 0x52: /* HD DVD-Rewritable */
492
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.disc.type", "hddvd_rw", &hfp_error);
493
libhal_device_set_property_bool(hfp_ctx, hfp_udi, "volume.disc.is_rewritable", TRUE, &hfp_error);
497
if (get_disc_capacity_for_type(cdrom, type, &capacity) == 0)
498
libhal_device_set_property_uint64(hfp_ctx, hfp_udi, "volume.disc.capacity", capacity, &hfp_error);
501
* linux's probe-volume.c: "on some hardware the get_disc_type
502
* call fails, so we use this as a backup".
504
if (disc_is_rewritable(cdrom))
505
libhal_device_set_property_bool(hfp_ctx, hfp_udi, "volume.disc.is_rewritable", TRUE, &hfp_error);
506
if (disc_is_appendable(cdrom))
507
libhal_device_set_property_bool (hfp_ctx, hfp_udi, "volume.disc.is_appendable", TRUE, &hfp_error);
509
hfp_cdrom_free(cdrom);
512
if (has_data && vid && (! strcmp(vid->type, "iso9660") ||
513
! strcmp(vid->type, "udf")))
514
hf_probe_volume_advanced_disc_detect(fd);
518
libhal_device_set_property_string(hfp_ctx, hfp_udi, "info.category", "volume", &hfp_error);
520
if (libhal_device_query_capability(hfp_ctx, parent_udi, "storage", &hfp_error))
529
geom_class = getenv("HF_VOLUME_GEOM_CLASS");
533
if (hf_probe_volume_get_partition_info(geom_class, device_file, &number, &type, &scheme, &mediasize, &offset))
537
libhal_device_set_property_int(hfp_ctx, hfp_udi, "volume.partition.number", number, &hfp_error);
538
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.partition.scheme", scheme, &hfp_error);
539
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.partition.type", type, &hfp_error);
541
/* FIXME We need to fill in the supported partition flags. */
543
libhal_device_set_property_uint64(hfp_ctx, hfp_udi, "volume.partition.media_size", mediasize, &hfp_error);
544
libhal_device_set_property_uint64(hfp_ctx, hfp_udi, "volume.partition.start", offset, &hfp_error);
546
if (! strcmp(scheme, "gpt"))
547
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.partition.uuid", type, &hfp_error);
549
if (! strcmp(scheme, "gpt") || ! strcmp(scheme, "apm"))
550
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.partition.label", "", &hfp_error);
558
dbus_error_free(&hfp_error);
561
libhal_device_set_property_bool(hfp_ctx, hfp_udi, "volume.is_disc", is_cdrom, &hfp_error);
562
libhal_device_set_property_bool(hfp_ctx, hfp_udi, "volume.is_partition", is_partition, &hfp_error);
564
libhal_device_set_property_bool(hfp_ctx, hfp_udi, "volume.ignore", has_children || is_swap, &hfp_error);
566
if (vid && ! strcmp (vid->type, "ufs"))
568
struct uufsd ufsdisk;
570
if (ufs_disk_fillout(&ufsdisk, device_file) == 0)
573
char **ufs_devs = NULL;
577
snprintf(ufsid, sizeof(ufsid), "%08x%08x", ufsdisk.d_fs.fs_id[0], ufsdisk.d_fs.fs_id[1]);
578
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.freebsd.ufsid", ufsid, &hfp_error);
579
ufs_devs = libhal_manager_find_device_string_match(hfp_ctx,
580
"volume.freebsd.ufsid",
584
dbus_error_free(&hfp_error);
585
for (i = 0; i < num_udis; i++)
587
if (ufs_devs[i] != NULL)
591
mounted = libhal_device_get_property_bool(hfp_ctx, ufs_devs[i], "volume.is_mounted", &hfp_error);
592
dbus_error_free(&hfp_error);
595
libhal_device_set_property_bool(hfp_ctx, hfp_udi, "volume.ignore", TRUE, &hfp_error);
596
dbus_error_free(&hfp_error);
601
libhal_free_string_array(ufs_devs);
602
ufs_disk_close(&ufsdisk);
607
usage = "partitiontable";
611
switch (vid ? vid->usage_id : (enum volume_id_usage) -1)
613
case VOLUME_ID_FILESYSTEM: usage = "filesystem"; break;
614
case VOLUME_ID_DISKLABEL: usage = "disklabel"; break;
615
case VOLUME_ID_OTHER: usage = "other"; break;
616
case VOLUME_ID_RAID: usage = "raid"; break;
617
case VOLUME_ID_CRYPTO: usage = "crypto"; break;
618
case VOLUME_ID_UNUSED: usage = "unused"; break;
619
default: usage = "unknown"; break;
622
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.fsusage", usage, &hfp_error);
623
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.fstype", vid ? vid->type: "", &hfp_error);
624
if (vid && *vid->type_version)
625
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.fsversion", vid->type_version, &hfp_error);
627
label = hf_probe_volume_get_label(vid);
628
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.label", label ? label : "", &hfp_error);
631
libhal_device_set_property_string(hfp_ctx, hfp_udi, "volume.uuid", vid ? vid->uuid : "", &hfp_error);
633
ioctl(fd, DIOCGSECTORSIZE, §or_size);
635
if (sector_size != 0)
636
libhal_device_set_property_uint64(hfp_ctx, hfp_udi, "volume.block_size", sector_size, &hfp_error);
638
libhal_device_set_property_uint64(hfp_ctx, hfp_udi, "volume.size", media_size, &hfp_error);
639
if (sector_size != 0 && media_size != 0)
640
libhal_device_set_property_uint64(hfp_ctx, hfp_udi, "volume.num_blocks", media_size / sector_size, &hfp_error);
642
ret = 0; /* is a volume */