On 2009-03-03 17:21 -0500, Antonio De Leon wrote: > On the question of detecting usb devices this tool can help on the > detection part.
Here's my ls-removable script too. It's in Lua, and needs both luafilesystem and posix packages for Lua. There are two versions. The suffix-1 version worked with the old 2.6.18 or whateveritwas Etch. Suffix-2 is a conversion to work the modified /sys layout in *buntu 8.10, but it fails to work because pmount doesn't seem to have been upgraded to to reflect that. It, however, shouldn't be too difficult to create a suid-root counterpart based on my code, that just calls mount -- this time with sane FAT and NTFS mounting arguments. (*sigh*, even the ntfs-3g in 8.10 ubuntu is old, and does not seem to support .NTFS-3G/UserMapping. A lot of shit in it is _old_, and yet it has just half-a-year release cycles.) -- "[Fashion] is usually a form of ugliness so intolerable that we have to alter it every six months." -- Oscar Wilde "The computer industry is the only industry that is more fashion-driven than women's fashion." -- RMS
#!/usr/local/bin/lua -- -- Copyright (c) Tuomo Valkonen 2008. -- require('lfs') require('posix') local function filtered_dir(d) local f, s_, v_ = lfs.dir(d) local function g(s, v) while true do local vn=f(s, v) if vn~='.' and vn~='..' then return vn end end end return g, s_, v_ end local function readfile(d) local f, err = io.open(d, 'r') if f then local s=f:read('*a') f:close() return s end end local function simplify_string(s) if s then return string.gsub(s, "\n$", "") end end local function readfile_simple(d) return simplify_string(readfile(d)) end local function removable(d) return readfile_simple(d.."/removable")=="1"; end local function removable_class(d) -- Super-dirty hack return d and string.match(d, "/usb%d+/") end local function simplify_path(p) local capts={} local start=string.match(p, "^(/)") string.gsub(p, "([^/]+)", function(e) if e==".." and #capts > 1 then capts[#capts]=nil elseif e~="." then table.insert(capts, e) end end) return (start or "")..table.concat(capts, "/") end local function get_device(d) l=posix.readlink(d.."/device") if not l then return nil end if string.match(l, "^.") then return simplify_path(d.."/"..l) else return simplify_path(l) end end local function get_info(dev) return { vendor=readfile_simple(dev.."/vendor"), model=readfile_simple(dev.."/model"), serial=readfile_simple(dev.."/serial") } end local function get_info_usb(dev) par=string.match(dev, "(.*)/[^/]+") if not par then return {} else local m=readfile_simple(par.."/manufacturer") if not m then return get_info_usb(par) else return { vendor=m, model=readfile_simple(par.."/product"), serial=readfile_simple(par.."/serial") } end end end local function scan_volumes(bd, d) local function g() local found=false for v in filtered_dir(bd..d) do if string.match(v, "^"..d.."%d+$") then coroutine.yield(v) found=true end end if not found then coroutine.yield(d) end end return coroutine.wrap(g) end local mounts={} --local mounts_=io.popen("mount"):read('*a') --string.gsub(mounts_, "[^\n]+", function(l) table.insert(mounts, l) end) local f=io.open("/etc/mtab") for l in f:lines() do table.insert(mounts, l) end f:close() local function mounted(v) for _, l in ipairs(mounts) do local mp=string.match(l, "^/dev/"..v.."%s+([^%s]+)") if mp then return mp end end return false end local bd='/sys/block/' local volumes={} for d in filtered_dir(bd) do local dev=get_device(bd..d) if removable(bd..d) or removable_class(dev) then local i1=get_info(dev) local i2=get_info_usb(dev) if i2 and i2.vendor then info=table.concat({i2.vendor, i2.model, i2.serial}, " ") else info=table.concat({i1.vendor, i1.model, i1.serial}, " ") end for v in scan_volumes(bd, d) do table.insert(volumes, { kernel=v, info=info, mountpoint=mounted(v), }) end end end table.sort(volumes, function(a, b) if a.mountpoint and not b.mountpoint then return false elseif not a.mountpoint and b.mountpoint then return true else return (a.kernel < b.kernel) end end) for k, v in ipairs(volumes) do if not v.mountpoint then io.write(string.format("%d) %s (%s)\n", k, v.kernel, v.info)) else io.write(string.format("[ %d) %s (%s) %s ]\n", k, v.kernel, v.info, v.mountpoint)) end end io.write("Choice (1): ") local a=io.read() local i=((not a or a=="") and 1) or tonumber(a) if i then if volumes[i].mountpoint then os.execute("pumount "..volumes[i].mountpoint) else os.execute("pmount /dev/"..volumes[i].kernel) end end
#!/usr/bin/lua -- -- Copyright (c) Tuomo Valkonen 2008. -- require('lfs') require('posix') local function filtered_dir(d) local f, s_, v_ = lfs.dir(d) local function g(s, v) while true do local vn=f(s, v) if vn~='.' and vn~='..' then return vn end end end return g, s_, v_ end local function readfile(d) local f, err = io.open(d, 'r') if f then local s=f:read('*a') f:close() return s end end local function basename(d) return string.gsub(d, "^(.*)/[^/]*$", "%1") end local function simplify_string(s) if s then return string.gsub(s, "\n$", "") end end local function readfile_simple(d) return simplify_string(readfile(d)) end local function removable(d) return readfile_simple(d.."/removable")=="1"; end local function removable_class(d) -- Super-dirty hack return d and string.match(d, "/usb%d+/") end local function simplify_path(p) local capts={} local start=string.match(p, "^(/)") string.gsub(p, "([^/]+)", function(e) if e==".." and #capts > 1 then capts[#capts]=nil elseif e~="." then table.insert(capts, e) end end) return (start or "")..table.concat(capts, "/") end local function get_device(d) --l=posix.readlink(d.."/device") l=posix.readlink(d) if not l then return nil end if string.match(l, "^.") then return simplify_path(basename(d).."/"..l.."/device") else return simplify_path(l.."/device") end end local function get_info(dev) return { vendor=readfile_simple(dev.."/vendor"), model=readfile_simple(dev.."/model"), serial=readfile_simple(dev.."/serial") } end local function get_info_usb(dev) par=string.match(dev, "(.*)/[^/]+") if not par then return {} else local m=readfile_simple(par.."/manufacturer") if not m then return get_info_usb(par) else return { vendor=m, model=readfile_simple(par.."/product"), serial=readfile_simple(par.."/serial") } end end end local function scan_volumes(bd, d) local function g() local found=false for v in filtered_dir(bd..d) do if string.match(v, "^"..d.."%d+$") then coroutine.yield(v) found=true end end if not found then coroutine.yield(d) end end return coroutine.wrap(g) end local mounts={} --local mounts_=io.popen("mount"):read('*a') --string.gsub(mounts_, "[^\n]+", function(l) table.insert(mounts, l) end) local f=io.open("/etc/mtab") for l in f:lines() do table.insert(mounts, l) end f:close() local function mounted(v) for _, l in ipairs(mounts) do local mp=string.match(l, "^/dev/"..v.."%s+([^%s]+)") if mp then return mp end end return false end local bd='/sys/block/' local volumes={} for d in filtered_dir(bd) do local dev=get_device(bd..d) if removable(bd..d) or removable_class(dev) then local i1=get_info(dev) local i2=get_info_usb(dev) if i2 and i2.vendor then info=table.concat({i2.vendor, i2.model, i2.serial}, " ") else info=table.concat({i1.vendor, i1.model, i1.serial}, " ") end for v in scan_volumes(bd, d) do table.insert(volumes, { kernel=v, info=info, mountpoint=mounted(v), }) end end end table.sort(volumes, function(a, b) if a.mountpoint and not b.mountpoint then return false elseif not a.mountpoint and b.mountpoint then return true else return (a.kernel < b.kernel) end end) for k, v in ipairs(volumes) do if not v.mountpoint then io.write(string.format("%d) %s (%s)\n", k, v.kernel, v.info)) else io.write(string.format("[ %d) %s (%s) %s ]\n", k, v.kernel, v.info, v.mountpoint)) end end io.write("Choice (1): ") local a=io.read() local i=((not a or a=="") and 1) or tonumber(a) if i then if volumes[i].mountpoint then os.execute("pumount "..volumes[i].mountpoint) else os.execute("pmount /dev/"..volumes[i].kernel) end end