#!/usr/bin/ruby
# Purpose:
# Allows to remap specified fs-tree to different place and let it
# be accessed & modified by specified user (uid)
#
# Example:
# Extremely handy to let others modify cgroup filesystem which can't
# be mounted under different uid...
#
# cd /dev
# mkdir cgroup cgroup.wfw
# mount cgroup cgroup -t cgroup -o devices
# ./fuse-rights-proxy.rb
# (elsewhere:) setuidgid wejn sh -c 'echo $$ > /dev/cgroup.wfw/tasks'
#
# Author: Wejn (wejn at box dot cz)
# License: MIT
require 'fusefs'
class FUSERightsProxy
# constructor {{{
def initialize(target, uid)
unless FileTest.directory?(target)
raise ArgumentError, "target: #{target} doesn't exist"
end
if uid.to_i.zero?
raise ArgumentError, "uid should be non-root"
end
@target, @uid = target, uid.to_i
end
# }}}
# dirlist {{{
def contents(path)
out = nil
Dir.chdir(File.join(@target, path)) do
out = Dir['*']
end
out
end
# }}}
# tests {{{
def directory?(path)
FileTest.directory?(File.join(@target, path))
end
def file?(path)
FileTest.file?(File.join(@target, path))
end
# }}}
# file read {{{
def read_file(path)
File.open(File.join(@target, path)).read
rescue Object
nil
end
# }}}
# file write {{{
def can_write?(path)
(FuseFS.uid.zero? || FuseFS.uid == @uid) && !directory?(path)
end
def write_to(path, str)
File.open(File.join(@target, path), 'w') { |f| f.write(str) }
true
rescue Object
nil
end
# }}}
# file deletion {{{
def can_delete?(path)
# also needed for open(path, 'w')
(FuseFS.uid.zero? || FuseFS.uid == @uid) && file?(path)
end
def delete(path)
file?(path) && File.unlink(File.join(@target, path))
rescue Object
nil
end
# }}}
# dir manipulation {{{
def can_mkdir?(path)
(FuseFS.uid.zero? || FuseFS.uid == @uid) && !directory?(path) && !file?(path)
end
def mkdir(path)
Dir.mkdir(File.join(@target, path))
true
rescue Object
nil
end
def can_rmdir?(path)
(FuseFS.uid.zero? || FuseFS.uid == @uid) && directory?(path)
end
def rmdir(path)
Dir.rmdir(File.join(@target, path))
true
rescue Object
nil
end
# }}}
end
if __FILE__ == $0
target = '/dev/cgroup'
mpoint = '/dev/cgroup.wfw'
uid = 1000
unless FileTest.directory?(mpoint)
STDERR.puts "mount point: #{mpoint} doesn't exist"
exit 1
end
unless Process.uid.zero?
STDERR.puts "must be run as root"
exit 1
end
if File.open('/proc/filesystems').grep(/\sfuse/).empty?
STDERR.puts "/proc/filesystems indicates lack of FUSE support;" +
" modprobe it perhaps?"
exit 1
end
unless File.open('/proc/mounts').grep(Regexp.new(mpoint)).empty?
STDERR.puts "/proc/mounts indicates #{mpoint} is already mounted"
exit 1
end
d = FUSERightsProxy.new(target, uid)
FuseFS.set_root(d)
FuseFS.mount_to(mpoint, "allow_other")
begin
FuseFS.run
rescue Interrupt
end
end