/** * Created : Mar 30, 2012 * * @author pquiring */ import java.io.*; import java.util.*; import javaforce.*; import javaforce.utils.*; /** Monitors /dev for new devices and mounts them (such as USB drives). */ public class AutoMounter extends Thread implements monitordir.Listener { public boolean active = true; public static int paused = 0; private int monitor; public static class Mount { public String dev, media, fs; } private Vector<Mount> mounts = new Vector<Mount>(); private Object lock = new Object(); public void run() { cleanMedia(); bootMount(); monitor = monitordir.add("/dev"); monitordir.setListener(monitor, this); } //mounts any partitions that are not already mounted private void bootMount() { File dev = new File("/dev"); File devs[] = dev.listFiles(); for(int a=0;a<devs.length;a++) { String name = devs[a].getAbsolutePath(); if (name.startsWith("/dev/sd")) mountIf(name); if (name.startsWith("/dev/sr")) mountIf(name); } } //mount if not already mounted private void mountIf(String dev) { if (getMountPoint(dev) != null) return; mount(dev); } public Mount getMount(String mediaMointPoint) { synchronized(lock) { for(int a=0;a<mounts.size();a++) { if (mounts.get(a).media.equals(mediaMointPoint)) { return mounts.get(a); } } } return null; } public String getMountPoint(String dev) { ShellProcess sp = new ShellProcess(); String output = sp.run(new String[] {"mount"}, true); String lns[] = output.split("\n"); for(int a=0;a<lns.length;a++) { String f[] = lns[a].split(" "); //dev on path ... if (!f[0].equals(dev)) continue; return f[2]; } return null; } public synchronized void mount(String dev) { JFLog.log("AutoMount:Attempting to mount:" + dev); if (paused < 0) return; //mount in /media if (!dev.startsWith("/dev/sd") && !dev.startsWith("/dev/sr")) { //not a mountable volume (Storage Device/ROM) JFLog.log("AutoMount:Not a mountable device:" + dev); return; } if (dev.startsWith("/dev/sd")) { char lastChar = dev.charAt(dev.length()-1); if (!((lastChar >= '0') && (lastChar <= '9'))) { //not a partition JFLog.log("AutoMount:Not a mountable partition:" + dev); return; } } Mount mount = new Mount(); String volName = getVolumeName(dev, mount); JFLog.log("AutoMount:Volume Label:" + dev + "=" + volName); if (volName == null) { JFLog.log("AutoMount:No volume label found:" + dev); return; } volName = volName.replaceAll(" ", ""); if (volName.length() == 0) volName = "Unknown"; String volPath = "/media/" + volName; String fullPath = volPath; File file = new File(fullPath); int cnt = 1; while (file.exists()) { fullPath = volPath + "(" + cnt++ + ")"; file = new File(fullPath); } file.mkdir(); mount.dev = dev; mount.media = fullPath; if (dev.startsWith("/dev/sr")) { //do not automount cdda - user can use gvfs (gnome-disk-image-mounter) return; } String cmd[] = {"mount", dev, fullPath, "-o", "user"}; ShellProcess sp = new ShellProcess(); String output = sp.run(cmd, true); if (sp.getErrorLevel() != 0) { file.delete(); JFLog.log("AutoMount:Failed to mount:" + dev + ":error=" + output); } else { JFLog.log("AutoMount:Success:" + dev + " mounted to " + fullPath); synchronized(lock) { mounts.add(mount); } //broadcast /media change Startup.jbusClient.broadcast("org.jflinux.jfile", "rescanMedia", ""); } } public void umount(String dev) { if (paused < 0) return; //Normally user umount's from jfile - this should just clean up the /media folder boolean ok = false; Mount mount = null; synchronized(lock) { for(int a=0;a<mounts.size();a++) { mount = mounts.get(a); if (mount.dev.equals(dev)) { mounts.remove(a); ok = true; break; } } } if (ok) { umount(mount); } else { JFLog.log("AutoMount:umount unknown device:" + dev); } } public void umount(Mount mount) { if (mount.dev != null) { String cmd[] = {"umount", mount.dev}; try {Runtime.getRuntime().exec(cmd);} catch (Exception e) {JFLog.log(e);} } JF.sleep(500); //give kernel some time File folder = new File(mount.media); folder.delete(); //broadcast /media change Startup.jbusClient.broadcast("org.jflinux.jfile", "rescanMedia", ""); } public String getVolumeName(String dev, Mount mount) { //TODO : is there a better way to do this? if (dev.startsWith("/dev/sr")) { //CDROM - dosfslabel will not work mount.fs = "iso9660"; return "CDROM" + dev.substring(7); } ShellProcess sp = new ShellProcess(); //try dosfslabel String output = sp.run(new String[] {"dosfslabel", dev}, false); if (sp.getErrorLevel() == 0) { mount.fs = "dos"; return output.replaceAll("\n", ""); } //try ntfslabel output = sp.run(new String[] {"ntfslabel", dev}, false); if (sp.getErrorLevel() == 0) { mount.fs = "nt"; return output.replaceAll("\n", ""); } //try e2label output = sp.run(new String[] {"e2label", dev}, false); if (sp.getErrorLevel() == 0) { mount.fs = "e2"; return output.replaceAll("\n", ""); } //unknown filesystem return null; } public void folderChangeEvent(String event, String file) { if (event.equals("CREATED")) { mount("/dev/" + file); } if (event.equals("DELETED")) { //BUG : this doesn't make any sense - you should umount before it's deleted? umount("/dev/" + file); } } private void cleanMedia() { try { File files[] = new File("/media").listFiles(); if (files == null || files.length == 0) return; for(int a=0;a<files.length;a++) { if (files[a].isDirectory()) { files[a].delete(); } } } catch (Exception e) { JFLog.log(e); } } }