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

Reply via email to