tasks/sys_arg.rake
# frozen_string_literal: true
desc 'Generate syscall arguments from Linux:include/linux/syscalls.h'
task :sys_arg do
content = File.binread('tasks/syscalls.h') + File.binread('tasks/syscalls_complement.h')
def error(name, args, msg)
puts "[ERROR] #{msg}\n\t#{name}(#{args})"
end
def parse_args(args)
return [] if args == 'void'
args = args.gsub(/\s+/m, ' ')
args = args.split(', ').map { |c| c.scan(/ *?(\w+)$/).flatten.first }
return nil unless args.all?
return nil if %w[int long].any? { |t| args.include?(t) }
args
end
parse_failed = {}
proto = content.scan(/^asmlinkage long sys_(\w+)\(([^)]+)\);/m).each_with_object({}) do |(name, args), hash|
next if name == 'sigsuspend' # XXX: there are two implementations, don't know which one should be used
next error(name, args, 'dup') if hash.key?(name)
parse_args(args).tap do |res|
res.nil? ? parse_failed[name] = args : hash[name] = res
end
end
parse_failed.each do |name, args|
error(name, args, 'parse args faield') unless proto.key?(name)
end
File.binwrite(File.join('lib', 'seccomp-tools', 'consts', 'sys_arg.rb'), <<~RUBY)
# frozen_string_literal: true
# Generated by `bundle exec rake sys_arg`
{
#{proto.map { |key, value| " #{key}: %w[#{value.join(' ')}]" }.join(",\n")}
}
RUBY
end