+#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/wait.h>
#include <sys/inotify.h>
-#include <sys/stat.h>
-#include <sys/types.h>
+#include <sys/mount.h>
#include <glob.h>
#include <libgen.h>
#include <poll.h>
-#include <dirent.h>
#include <syslog.h>
#include "include/log.h"
static struct list_head mounts;
+/**
+ * enum status - status of mount entry
+ *
+ * @STATUS_UNMOUNTED: currently not mounted
+ * @STATUS_MOUNTED: mounted & ready for usage
+ * @STATUS_EXPIRED: mount expired & *temporary* unmounted
+ * @STATUS_IGNORE: entry should be ignored and never mounted
+ */
+enum status {
+ STATUS_UNMOUNTED = 0,
+ STATUS_MOUNTED,
+ STATUS_EXPIRED,
+ STATUS_IGNORE,
+};
+
struct mount {
struct list_head list;
char name[64];
char vendor[64];
char model[64];
char rev[64];
- int mounted;
- int ignore;
+ enum status status;
char size[64];
char sector_size[64];
int fs;
ucix_add_option(ctx, mountd, q->serial, "disc", t);
ucix_add_option(ctx, mountd, q->serial, "sector_size", q->sector_size);
snprintf(t, 64, "part%dmounted", atoi(&q->dev[3]));
- ucix_add_option(ctx, mountd, q->serial, t, (q->mounted)?("1"):("0"));
+ ucix_add_option(ctx, mountd, q->serial, t, q->status == STATUS_MOUNTED ? "1" : "0");
ucix_add_option(ctx, mountd, q->serial, "vendor", q->vendor);
ucix_add_option(ctx, mountd, q->serial, "model", q->model);
ucix_add_option(ctx, mountd, q->serial, "rev", q->rev);
snprintf(t, 64, "fs%d", atoi(&q->dev[3]));
ucix_add_option(ctx, mountd, q->serial, t, fs_names[q->fs]);
}
- if(q->mounted)
+ if (q->status == STATUS_MOUNTED)
mounted++;
- if((!q->ignore) && q->size && q->sector_size)
+ if ((q->status != STATUS_IGNORE) && q->size && q->sector_size)
size = size + (((unsigned long long int)atoi(q->size)) * ((unsigned long long int)atoi(q->sector_size)));
}
ucix_add_option_int(ctx, mountd, mountd, "mounted", mounted);
char *vendor, char *model, char *rev, int ignore, char *size, char *sector_size, int fs)
{
struct mount *mount;
- char tmp[64], tmp2[64];
- if(fs <= MBR || fs > LASTFS)
- return;
+ char dev_path[64], dev_link[64], tmp[64];
+
mount = malloc(sizeof(struct mount));
INIT_LIST_HEAD(&mount->list);
strncpy(mount->vendor, vendor, 64);
strncpy(mount->serial, serial, 64);
strncpy(mount->size, size, 64);
strncpy(mount->sector_size, sector_size, 64);
- mount->ignore = ignore;
- mount->mounted = 0;
+ mount->status = STATUS_UNMOUNTED;
mount->fs = fs;
list_add(&mount->list, &mounts);
- if((!mount->ignore) && (mount->fs > MBR) && (mount->fs <= LASTFS))
- {
+
+ if (ignore) {
+ mount->status = STATUS_IGNORE;
+ } else {
+ struct stat st;
+
log_printf("new mount : %s -> %s (%s)\n", name, dev, fs_names[mount->fs]);
- snprintf(tmp, 64, "%s%s", uci_path, name);
- snprintf(tmp2, 64, "/tmp/run/mountd/%s", dev);
- symlink(tmp2, tmp);
- mount_new("/tmp/run/mountd/", dev);
- system_printf("ACTION=add DEVICE=%s NAME=%s /sbin/hotplug-call mount", dev, name);
+
+ snprintf(dev_link, sizeof(dev_link), "%s%s", uci_path, name);
+ snprintf(dev_path, sizeof(dev_path), "%s%s", "/tmp/run/mountd/", dev);
+ /* If link aleady exists - replace it */
+ if (lstat(dev_link, &st) == 0 && S_ISLNK(st.st_mode)) {
+ snprintf(tmp, sizeof(tmp), "%s%s", uci_path, "tmp");
+ symlink(dev_path, tmp);
+ rename(tmp, dev_link);
+ } else {
+ symlink(dev_path, dev_link);
+ }
+ if (!mount_new("/tmp/run/mountd/", dev))
+ system_printf("ACTION=add DEVICE=%s NAME=%s /sbin/hotplug-call mount", dev, name);
}
}
log_printf("request for invalid path %s%s\n", path, dev);
return -1;
}
- if(mount->ignore || mount->mounted || mount->fs == EXTENDED)
+ if (mount->status == STATUS_IGNORE || mount->status == STATUS_MOUNTED || mount->fs == EXTENDED)
return -1;
snprintf(tmp, 256, "%s%s", path, mount->dev);
log_printf("mounting %s\n", tmp);
pid = waitpid(pid, &ret, 0);
ret = WEXITSTATUS(ret);
log_printf("----------> mount ret = %d\n", ret);
- if(ret && (ret != 0xff))
+ if (ret && ret != 0xff) {
+ rmdir(tmp);
return -1;
+ }
if(mount_wait_for_disc(mount->dev) == 0)
{
- mount->mounted = 1;
+ mount->status = STATUS_MOUNTED;
mount_dump_uci_state();
} else return -1;
return 0;
char tmp[256];
int ret;
snprintf(tmp, 256, "%s%s", path, dev);
- log_printf("%s has expired... unmounting\n", tmp);
+ log_printf("device %s has expired... unmounting %s\n", dev, tmp);
ret = system_printf("/bin/umount %s", tmp);
if(ret != 0)
return 0;
rmdir(tmp);
mount = mount_find(0, dev);
if(mount)
- mount->mounted = 0;
+ mount->status = STATUS_EXPIRED;
log_printf("finished unmounting\n");
mount_dump_uci_state();
return 0;
{
int id;
struct stat buf;
- char tmp3[64];
+ char tmp3[strlen(namelist[n]->d_name) + strlen(dev) + 31];
int ret;
*t = 0;
id = atoi(namelist[n]->d_name);
*t = ':';
+
sprintf(tmp3, "/sys/bus/scsi/devices/%s/block:%s/", namelist[n]->d_name, dev);
ret = stat(tmp3, &buf);
if(ret)
char sector_size[64];
FILE *fp;
int offset = 3;
+ int fs;
strcpy(name, dev);
if (!strncmp(name, "mmcblk", 6))
fclose(fp);
}
snprintf(tmp, 64, "/dev/%s", dev);
- mount_add_list(node, dev, s, vendor, model, rev, ignore, size, sector_size, detect_fs(tmp));
+ fs = detect_fs(tmp);
+ if (fs <= MBR || fs > LASTFS) {
+ ignore = 1;
+ }
+ mount_add_list(node, dev, s, vendor, model, rev, ignore, size, sector_size, fs);
mount_dump_uci_state();
}
}
-static void mount_dev_del(char *dev)
+static int mount_dev_del(struct mount *mount)
{
- struct mount *mount = mount_find(0, dev);
char tmp[256];
- if(mount)
- {
- if(mount->mounted)
- {
- snprintf(tmp, 256, "%s%s", "/tmp/run/mountd/", mount->name);
- log_printf("%s has dissappeared ... unmounting\n", tmp);
- snprintf(tmp, 256, "%s%s", "/tmp/run/mountd/", mount->dev);
- system_printf("/bin/umount %s", tmp);
- rmdir(tmp);
- snprintf(tmp, 64, "%s%s", uci_path, mount->name);
- unlink(tmp);
- mount_dump_uci_state();
+ int err = 0;
+
+ if (mount->status == STATUS_MOUNTED) {
+ snprintf(tmp, 256, "%s%s", "/tmp/run/mountd/", mount->dev);
+ log_printf("device %s has disappeared ... unmounting %s\n", mount->dev, tmp);
+ if (umount(tmp)) {
+ err = -errno;
+ umount2(tmp, MNT_DETACH);
}
+ rmdir(tmp);
+ mount_dump_uci_state();
}
+
+ return err;
}
void mount_dump_list(void)
list_for_each(p, &mounts)
{
struct mount *q = container_of(p, struct mount, list);
- log_printf("* %s %s %d\n", q->name, q->dev, q->mounted);
+ log_printf("* %s %s %d\n", q->name, q->dev, q->status == STATUS_MOUNTED);
}
}
return 0;
}
-static void mount_check_mount_list(void)
+static void mount_update_mount_list(void)
{
FILE *fp = fopen("/proc/mounts", "r");
char tmp[256];
while(fgets(tmp, 256, fp) != NULL)
{
char *t, *t2;
+
+ if (mounted_count + 1 > MAX_MOUNTED) {
+ log_printf("found more than %d mounts \n", MAX_MOUNTED);
+ break;
+ }
+
t = strstr(tmp, " ");
if(t)
{
mounted[mounted_count][0],
mounted[mounted_count][1],
mounted[mounted_count][2]);*/
- if(mounted_count < MAX_MOUNTED - 1)
- mounted_count++;
- else
- log_printf("found more than %d mounts \n", MAX_MOUNTED);
+
+ mounted_count++;
}
fclose(fp);
}
ctx = ucix_init("mountd");
t = ucix_get_option(ctx, "mountd", q->serial, tmp);
ucix_cleanup(ctx);
- if(t && !q->mounted)
+ if (t && q->status != STATUS_MOUNTED)
{
if(!strcmp(t, "0"))
{
- if(!q->ignore)
+ if (q->status != STATUS_IGNORE)
del = 1;
} else if(!strcmp(t, "1"))
{
}
if(!check_block(q->dev)||del)
{
- mount_dev_del(q->dev);
+ if (q->status == STATUS_MOUNTED || q->status == STATUS_EXPIRED) {
+ char dev_link[64];
+ int err;
+
+ system_printf("ACTION=remove DEVICE=%s NAME=%s /sbin/hotplug-call mount", q->dev, q->name);
+
+ err = mount_dev_del(q);
+
+ snprintf(dev_link, sizeof(dev_link), "%s%s", uci_path, q->name);
+ if (err == -EBUSY) {
+ /* Create "tmp" symlink to non-existing path */
+ snprintf(tmp, sizeof(tmp), "%s%s", uci_path, "tmp");
+ symlink("## DEVICE MISSING ##", tmp);
+
+ /* Replace old symlink with the not working one */
+ rename(tmp, dev_link);
+ } else {
+ log_printf("unlinking %s\n", dev_link);
+ unlink(dev_link);
+ }
+ }
+
p->prev->next = p->next;
p->next->prev = p->prev;
p = p->next;
- log_printf("removing %s\n", q->dev);
- snprintf(tmp, 64, "%s%s", "/tmp/run/mountd/", q->dev);
- rmdir(tmp);
- snprintf(tmp, 64, "%s%s", uci_path, q->name);
- unlink(tmp);
- system_printf("ACTION=remove DEVICE=%s NAME=%s /sbin/hotplug-call mount", q->dev, q->name);
free(q);
+
mount_dump_uci_state();
system_printf("/etc/fonstated/ReloadSamba");
} else p = p->next;
void mount_init(void)
{
INIT_LIST_HEAD(&mounts);
- timer_add(mount_check_mount_list, 2);
+ timer_add(mount_update_mount_list, 2);
timer_add(mount_check_enum, 1);
- mount_check_mount_list();
+ mount_update_mount_list();
}