+/**
+Checks if a partition identified by a sysfs path is on a removable device.
+*/
+int is_removable(char *devpath)
+{
+ char fnbuf[256];
+ int len;
+ char *ptr;
+ int fd;
+
+ len = snprintf(fnbuf, sizeof(fnbuf), "/sys%s", devpath);
+ /* Default to not removable if the path was too long. */
+ if(len+10>=(int)sizeof(fnbuf))
+ return 0;
+
+ /* We got a partition as a parameter, but the removable property is on the
+ disk. Replace the last component with "removable". */
+ for(ptr=fnbuf+len; (ptr>fnbuf && *ptr!='/'); --ptr) ;
+ strcpy(ptr, "/removable");
+
+ fd = open(fnbuf, O_RDONLY);
+ if(fd!=-1)
+ {
+ char c;
+ read(fd, &c, 1);
+ close(fd);
+ if(c=='1')
+ {
+ if(verbosity>=2)
+ printf(" Removable\n");
+ return 1;
+ }
+ if(verbosity>=2)
+ printf(" Not removable\n");
+ }
+
+ return 0;
+}
+
+/**
+Checks if a partition's disk or any of its parent devices are connected to any
+of a set of buses. The device is identified by a sysfs path. The bus array
+must be terminated with a NULL entry.
+*/
+int check_buses(char *devpath, char **buses)
+{
+ char fnbuf[256];
+ char *ptr;
+ int len;
+
+ len = snprintf(fnbuf, sizeof(fnbuf), "/sys%s", devpath);
+ /* Default to no match if the path was too long. */
+ if(len+10>=(int)sizeof(fnbuf))
+ return 0;
+
+ for(ptr=fnbuf+len; ptr>fnbuf+12; --ptr)
+ if(*ptr=='/')
+ {
+ char linkbuf[256];
+ /* Replace the last component with "subsystem". */
+ strcpy(ptr, "/subsystem");
+ len = readlink(fnbuf, linkbuf, sizeof(linkbuf)-1);
+
+ if(len!=-1)
+ {
+ linkbuf[len] = 0;
+ /* Extract the last component of the subsystem symlink. */
+ for(; (len>0 && linkbuf[len-1]!='/'); --len) ;
+
+ if(verbosity>=2)
+ {
+ *ptr = 0;
+ printf(" Subsystem of %s is %s\n", fnbuf, linkbuf+len);
+ }
+
+ if(is_in_array(buses, linkbuf+len))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+Check if an array of properties describes a device that can be mounted. An
+array of explicitly allowed devices can be passed in as well. Both arrays must
+be terminated by a NULL entry.
+*/
+int can_mount(Property *props, char **allowed)
+{
+ static char *removable_buses[] = { "usb", "firewire", 0 };
+ char *devname;
+ char *devpath;
+ char *bus;
+
+ devname = get_property_value(props, "DEVNAME");
+ if(is_in_array(allowed, devname))
+ return 1;
+
+ /* Special case for CD devices, since they are not partitions. Only allow
+ mounting if media is inserted. */
+ if(match_property_value(props, "ID_TYPE", "cd") && match_property_value(props, "ID_CDROM_MEDIA", "1"))
+ return 1;
+
+ /* Only allow mounting partitions. */
+ if(!match_property_value(props, "DEVTYPE", "partition"))
+ return 0;
+
+ devpath = get_property_value(props, "DEVPATH");
+ if(is_removable(devpath))
+ return 1;
+
+ /* Certain buses are removable by nature, but devices only advertise
+ themselves as removable if they support removable media, e.g. memory card
+ readers. */
+ bus = get_property_value(props, "ID_BUS");
+ if(is_in_array(removable_buses, bus))
+ return 1;
+
+ return check_buses(devpath, removable_buses);
+}
+
+/**
+Returns an array of all device nodes in a directory. Symbolic links are
+dereferenced.
+*/