📄 vold.c
字号:
#include "vold.h"#include <sys/types.h> /* open, fork, mkdir, stat, geteuid */#include <sys/stat.h> /* open, mkdir, stat */#include <fcntl.h> /* open */#include <unistd.h> /* geteuid */#include <unistd.h> /* fork, stat, rmdir */#include <signal.h> /* signal handlers */#include <stdlib.h> /* exit */#include <sys/mount.h> /* mount */#include <mntent.h> /* getmntent */#include <stdio.h> /* printf, getmntent */#include <string.h>#include <getopt.h>/* config variables */
int check_delay = 5; //delay between new partitions check in seconds
int background = 0; //fork to background?
char pidfile[MAX_STRLEN + 1]; //pidfile of iMount
char configfilename[MAX_STRLEN + 1]; //config filename (defaults to vold.conf)
char volumeroot[MAX_STRLEN + 1]; //Volume root (defaults to /Volumes)
unsigned long defaultmountflags = 0;
int uuid_filecheck = 0;
/* internal variables */int done = 0; //program quits if trueint debug = 0;extern scan_item* scan_list;extern vold_mount* mount_list;/* Tests if a specific device is available (i.e. "/dev/hda1") returns 1 if the device exists, 0 else. PROBLEM: returns true on /dev/hda3 even if you only have one partition /dev/hda1 */int device_exists(char* device) { int ret = 0; if(device != NULL) { ret = open(device, O_RDONLY); if(ret == -1) { ret = 0; } else { /* the device exists, now close it */ close(ret); ret = 1; } } return ret;}/* Structure describing a mount table entry. */
/* struct mntent */
/* {
/* char *mnt_fsname; Device or server for filesystem. */
/* char *mnt_dir; Directory mounted on. */
/* char *mnt_type; Type of filesystem: ufs, nfs, etc. */
/* char *mnt_opts; Comma-separated options for fs. */
/* int mnt_freq; Dump frequency (in days). */
/* int mnt_passno; Pass number for `fsck'. */
/* };*/
/* Loads /proc/mounts and adds the entries to the mount_list and updates the scan_list */void load_mounts() { FILE* fd; struct mntent* m; vold_mount* tmp; scan_item* sdevice; uuid_t uuid; uuid_clear(uuid); fd = fopen("/proc/mounts", "r+"); if(fd == NULL) { errormsg("Cannot open /proc/mounts: %s", strerror(errno)); return; } debugmsg("Reading /proc/mounts"); debugmsg("%-30s %-30s %-8s %-30s %4s %4s", "<file system>", "<mount point>", "<type>", "<options>", "<dump>", "<pass>"); for(m = getmntent(fd); m != NULL; m = getmntent(fd)) { /* ignore the "rootfs" entry */ if(strncmp("rootfs", m->mnt_fsname, 6) == 0) continue; /* mark the device_item from the scan_list as mounted */ sdevice = sdevice_find(m->mnt_fsname); if(sdevice == NULL) continue; /* We do not scan for this device. Ignore and continue. */ sdevice->status = VOLD_MOUNTED; /* now add the device if it doesn't already exist. */ if(vmount_find(m->mnt_fsname, NULL, NULL) == NULL) { debugmsg("%-30s %-30s %-8s %-30s %2i %2i", m->mnt_fsname, m->mnt_dir, m->mnt_type, m->mnt_opts, m->mnt_freq, m->mnt_passno); tmp = vmount_new(); if(tmp != NULL) { tmp->fixed = 0; SDUP(tmp->device, m->mnt_fsname); SDUP(tmp->mountpoint, m->mnt_dir); SDUP(tmp->fstype, m->mnt_type); tmp->mountflags = 0; SDUP(tmp->data, m->mnt_opts); tmp->volumename = NULL; uuid_clear(tmp->uuid); tmp->next = NULL; vmount_add(tmp); } else { errormsg("Not enough memory creating vmount struct"); } } } if(m) free(m); fclose(fd);}/* Loads /etc/fstab and add the single entries to the mount_list (vmount structure) */void load_fstab() { FILE* fd; struct mntent* m; vold_mount* tmp; char* device = NULL; char* label = NULL; uuid_t uuid; uuid_clear(uuid); fd = fopen("/etc/fstab", "r+"); if(fd == NULL) { errormsg("Cannot open /etc/fstab: %s", strerror(errno)); return; } debugmsg("Reading /etc/fstab"); debugmsg("%-30s %-30s %-8s %-30s %4s %4s", "<file system>", "<mount point>", "<type>", "<options>", "<dump>", "<pass>"); for(m = getmntent(fd); m != NULL; m = getmntent(fd)) { /* test if device string contains "LABEL=" or "UUID=" and set vars... */ if(strncmp("LABEL=", m->mnt_fsname, MAX_STRLEN) == 0) { SDUP(label, &m->mnt_fsname[5]); } else if(strncmp("UUID=", m->mnt_fsname, MAX_STRLEN) == 0) { uuid_parse( &m->mnt_fsname[4], uuid); } else { SDUP(device, m->mnt_fsname); } /* now add the device if it doesn't have the noauto flag and if it doesn't already exist */ tmp = vmount_find(device, uuid, label); if(tmp != NULL) { debugmsg("Device, UUID or Label conflicts with previously added vmount. Skipping the following entry"); debugmsg("%-30s %-30s %-8s %-30s %4i %4i", m->mnt_fsname, m->mnt_dir, m->mnt_type, m->mnt_opts, m->mnt_freq, m->mnt_passno); debugmsg("-----"); tmp->fixed = 1; } else { /* TODO: how to deal with the noauto flag?? */ /* if(hasmntopt(m, "noauto") == NULL && vmount_find(device, uuid, label) == NULL) { */ debugmsg("%-30s %-30s %-8s %-30s %4i %4i", m->mnt_fsname, m->mnt_dir, m->mnt_type, m->mnt_opts, m->mnt_freq, m->mnt_passno); tmp = vmount_new(); if(tmp != NULL) { tmp->fixed = 1; SDUP(tmp->device, device); SDUP(tmp->mountpoint, m->mnt_dir); SDUP(tmp->fstype, m->mnt_type); tmp->mountflags = 0; SDUP(tmp->data, m->mnt_opts); SDUP(tmp->volumename, label); uuid_copy(tmp->uuid, uuid); tmp->next = NULL; vmount_add(tmp); } else { errormsg("Not enough memory creating vmount struct"); } } /* cleanup */ if(label != NULL) free(label); label = NULL; if(device != NULL) free(device); device = NULL; uuid_clear(uuid); } if(m) free(m); fclose(fd);}/* Checks all devices for new (or lost) partitions and passes them over to handle_device. either check all periodic or the others */int scan_devices(int periodic) { scan_item* tmp = scan_list; hotplug_msg msg; debugmsg("Checking for new %sdevices....", periodic?"periodic ":""); while(tmp) { if(tmp->periodic == periodic) { if(device_exists(tmp->device)) { /* device exists, test if it has appeared just now */ if(tmp->status == VOLD_UNKNOWN) { msg.action = VOLD_ADD; msg.vendor = NULL; msg.model = NULL; msg.device = tmp->device; handle_device(&msg, tmp); } else if(tmp->status == VOLD_MOUNTED) { //logmsg("Not touching device '%s': Already mounted", tmp->device); if( dir_mounted(tmp->device) == 0) { /* device was unmounted by user */ debugmsg("Device was manually unmounted."); msg.action = VOLD_REMOVE; msg.vendor = NULL; msg.model = NULL; msg.device = tmp->device; handle_device(&msg, tmp); } } } else { if(tmp->status == VOLD_MOUNTED) { /* device disappeared illegally */ errormsg("POSSIBLE DATA LOSS! Device %s removed without umounting.", tmp->device); msg.action = VOLD_REMOVE; msg.vendor = NULL; msg.model = NULL; msg.device = tmp->device; handle_device(&msg, tmp); } else if(tmp->status == VOLD_IGNORED || tmp->status == VOLD_UNMOUNTED) { /* device no more here, mark state unknown */ tmp->status = VOLD_UNKNOWN; } } } tmp = tmp->next; } return 0;}/* Receives a hotplug message ADD: detects filesystem using Disktype and scans for uuid's from the filesystem, then calls mount_device with the corresponding vmount struct. If mount is succesful adds/appends the information to the mount_list (using vmount_find() vmount_add()). REMOVE: calls unmount_device and removes the vmount entry */void handle_device(hotplug_msg* msg, scan_item* dev) { int ret = 0; vold_mount* vm = NULL; DT_Info* info; uuid_t uuid; /* sanity */ if(msg == NULL || dev == NULL) return; uuid_clear(uuid); switch(msg->action) { case VOLD_ADD: debugmsg("---- New device '%s' found ------", msg->device); info = DT_detect(msg->device, DFLAG_ALL); if(info == NULL) { errormsg("could not detect filesystem type. NOT mounting %s", msg->device); errormsg("Disktype should be able to detect everything!! Mail me if you can read this."); errormsg("---Device will be ignored until it is unplugged---"); dev->status = VOLD_IGNORED; return; } if(info->type == DT_PARTMAP) { /* partition map handling */ debugmsg("PARTITION:Detected fstype for device %s: '%s'", msg->device, info->fs.type_name); debugmsg("TODO: implement Partition handling :-)"); /* TODO */ } else if(info->type == DT_FS && info->fs.type_name != NULL) { /* single filesystem handling (for linux mountable devices) */ debugmsg("Detected fstype for device %s: '%s'", msg->device, info->fs.type_name); /* check if we have a uuid (either direct or from disk) */ if(uuid_is_null(info->fs.uuid)) { /* no uuid, check if fs has a uuid_file */ get_uuid_from_fs(info->fs.type_name, msg->device, uuid); } else uuid_copy(uuid, info->fs.uuid); /* if there is a uuid we now have it in 'uuid' */ /* add or append? */ vm = vmount_find(msg->device, uuid, info->fs.volume_name); if(vm != NULL) { /* append */ debugmsg("vold_mount already exists, updating information"); //vm->fixed = 0; SADD(vm->device, msg->device); SADD(vm->fstype, info->fs.type_name); SDUP(vm->volumename, info->fs.volume_name); uuid_copy(vm->uuid, uuid); } else { /* add */ vm = vmount_new(); if(vm == NULL) { errormsg("Not enough memory creating new vold_mount struct"); return; } debugmsg("vold_mount not found. This is a new partition not found in fstab"); vm->fixed = 0; SDUP(vm->device, msg->device); vm->mountpoint = NULL; SDUP(vm->fstype, info->fs.type_name); vm->mountflags = 0; vm->data = NULL; SDUP(vm->volumename, info->fs.volume_name); SADD(vm->volumename, msg->model) uuid_copy(vm->uuid, uuid); vm->next = NULL; vmount_add(vm); } ret = mount_device(vm); switch(ret) { case 0: debugmsg("Mount succesful"); dev->status = VOLD_MOUNTED; break; default: vmount_remove(vm); logmsg("mount failed. Device ignored! (Error: %i)", ret); dev->status = VOLD_IGNORED; } } else { /* nothing to do */ errormsg("Device does not contain a partition table or a filesystem mountable by linux"); errormsg("infotype: %i fstype: %i, type_version_name: %s, volume_name: %s", info->type, info->fs.type, info->fs.type_version_name, info->fs.volume_name); } /* cleanup! */ remove_DT_Info(info); debugmsg("-------------------------------------------"); break; case VOLD_REMOVE: debugmsg("---- Removing device '%s' ------", msg->device); vm = vmount_find(msg->device, NULL, NULL); ret = unmount_device(vm); switch(ret) { case 0: debugmsg("Unmount succesful"); dev->status = VOLD_UNMOUNTED; vmount_remove(vm); break; default: logmsg("unmount failed. unmount_device returned error: %i", ret); break; } debugmsg("-------------------------------------------"); break; default: break; }}/* Receives a vmount that contains all essential information to complete the other fields (device, fstype, and either mountpoint or volumename have to be present). Checks if device is already mounted. Uses get_mountpoint to find a suitable mountpoint. Mountpoint: defined in fstab or "/VOLUMES/[volumelabel]" */ int mount_device(vold_mount* vm) { int ret; if(vm == NULL) return -3; /* check if vmount has all its essential fields filled */ if(vm->device == NULL || vm->fstype == NULL) return -1; /* check if its a swap device */ if(strcmp(vm->fstype, "swap") == 0) { /* TODO: implement Swapon */ errormsg("SWAP detected: **** NOT IMPLEMENTED ****"); return -1; } /* check if it is already mounted */ if(dir_mounted(vm->device)) return -1; get_mountpoint(vm); if(vm->mountpoint == NULL) { errormsg("Could not find a valid mountpoint for %s (%s)", vm->device, vm->fstype); return -1; } logmsg("Mounting %s (%s) at %s, (mountflags: %i, data: %s)", vm->device, vm->fstype, vm->mountpoint, vm->mountflags, vm->data); ret = mount(vm->device, vm->mountpoint, vm->fstype, vm->mountflags, vm->data); if(ret == -1) { errormsg("Could not mount %s under %s.", vm->device, vm->mountpoint); errormsg("Reason: %s", strerror(errno)); } return ret;}/* Unmounts the device */int unmount_device(vold_mount* vm) { int ret = 0; if(vm == NULL) return -3; logmsg("Unmounting device %s at %s", vm->device, vm->mountpoint); ret = umount(vm->mountpoint); /* just for testing.. remove this, if every thing works. */ if(ret != 0) { /* this can happen if the user has ummounted the device manually!!! */ debugmsg("unmount returned error: %s", strerror(errno)); } if( dir_mounted(vm->mountpoint) == 0) { /* device no more mounted, this is the really important point :-) */ ret = 0; if(vm->fixed == 0) { /* dont remove dir if we have a fixed mount */ if(rmdir(vm->mountpoint) != 0) { errormsg("Cannot remove dir '%s' after unmounting: %s", vm->mountpoint, strerror(errno)); } else { debugmsg("directory removed");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -