Description:
Merge pull request #14 from nattee/master upgrade to current working snapshot
Commit status:
[Not Reviewed]
References:
merge default
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r263:7950cf0bb006 - - 12 files changed: 420 inserted, 12 deleted

@@ -0,0 +1,93
1 + #!/usr/bin/env ruby
2 +
3 + def config
4 + Grader::Configuration.get_instance
5 + end
6 +
7 + def display_manual
8 + puts <<USAGE
9 + Check similarity between submission
10 + using: check_similar sub1 sub2
11 + -- or --
12 + check_similar problem_name
13 + sub1 and sub2 are submission IDs to be checked
14 + problem_name will check all submissions of the problem wit problem short name is 'problem_name'
15 +
16 + The output are given as
17 + sub1.login, sub1.id, sub1.point, sub2.login, sub2.id, sub2.point, similarity
18 +
19 + USAGE
20 + end
21 +
22 + def process_options_and_stop_file
23 +
24 + # Process 'help' option
25 + if (ARGV.length == 0) or ((ARGV.length==1) and (/help/.match(ARGV[0])))
26 + display_manual
27 + exit(0)
28 + end
29 +
30 + #default options
31 + options = {
32 + :dry_run => false,
33 + }
34 +
35 +
36 + if ARGV.length == 2
37 + options[:sub1] = ARGV[0].to_i
38 + options[:sub2] = ARGV[1].to_i
39 + elsif ARGV.length == 1
40 + options[:problem] = ARGV[0]
41 + end
42 +
43 +
44 + return options
45 + end
46 +
47 + def compare(sub1,sub2,full = sub1.problem.full_score)
48 + dis = @jarow.getDistance(sub1.source, sub2.source)
49 + puts [sub1.user.login,"##{sub1.id}",(sub1.points * 100.0 / full).to_i,
50 + sub2.user.login,"##{sub2.id}",(sub2.points * 100.0 / full).to_i,
51 + "#{dis * 100}%"].join(',')
52 + end
53 +
54 + #########################################
55 + # main program
56 + #########################################
57 +
58 + options = process_options_and_stop_file
59 +
60 + # load grader environment
61 + GRADER_ENV = 'grading'
62 + require File.join(File.dirname(__FILE__),'config/environment')
63 +
64 + # boot rails, to be able to use the active record
65 + RAILS_ENV = config.rails_env
66 + require RAILS_ROOT + '/config/environment'
67 +
68 + # load comparator
69 + require 'fuzzystringmatch'
70 + @jarow = FuzzyStringMatch::JaroWinkler.create( :native )
71 +
72 + if options[:problem]
73 + p = Problem.where(name: options[:problem]).first
74 + unless p
75 + puts "cannot find problem #{options[:problem]}"
76 + exit(0)
77 + end
78 + subs = Submission.where(problem: p)
79 + full_score = p.full_score.to_i
80 + subs.each.with_index do |s1,i|
81 + puts "processing #{i+1} out of #{subs.length}"
82 + subs.each do |s2|
83 + if s1.user != s2.user
84 + compare(s1,s2,full_score)
85 + end
86 + end
87 + end
88 + else
89 + sub1 = Submission.find(options[:sub1])
90 + sub2 = Submission.find(options[:sub2])
91 + compare(sub1,sub2)
92 + end
93 +
@@ -0,0 +1,6
1 + #!/bin/bash
2 + count=`ps aux | grep "cafe_grader" | grep "grader grading queue" | wc -l`
3 + if [ $count -lt 1 ]; then
4 + cd /home/dae/cafe_grader/judge
5 + /home/dae/.rvm/wrappers/ruby-2.3.0/ruby /home/dae/cafe_grader/judge/scripts/grader grading queue > /home/dae/grading.log &
6 + fi
@@ -0,0 +1,179
1 + #!/bin/sh
2 +
3 + echo "This script will install and configure Cafe grader."
4 +
5 + RUBY_VERSION=2.1.2
6 + echo "This will install Ruby $RUBY_VERSION under RVM"
7 +
8 + echo "Installing required apts"
9 +
10 + sudo zypper install \
11 + g++ gcc libmysqlclient18 build-essential \
12 + git-core openssl libreadline6 libreadline6-devel \
13 + zlib1g zlib1g-devel libssl37 libyaml-devel sqlite3-devel \
14 + sqlite3 libxml2-devel libxslt-devel autoconf libc6-devel \
15 + ncurses-devel automake libtool bison subversion \
16 + pkg-config curl nodejs unzip pyflakes java-1_8_0-openjdk \
17 + libmysqld-devel mercurial python-setuptools python-devel
18 +
19 +
20 + echo "Installing Ruby $RUBY_VERSION in RVM"
21 +
22 + rvm install $RUBY_VERSION
23 + rvm use $RUBY_VERSION
24 +
25 + echo "Fetching Cafe Grader from Git repositories"
26 +
27 + echo "Fetching web interface"
28 +
29 + mkdir cafe_grader
30 + cd cafe_grader
31 + #git clone -q git://github.com/jittat/cafe-grader-web.git web
32 + hg clone git+ssh://git@github.com/nattee/cafe-grader-web.git web
33 +
34 + echo "Configuring rails app"
35 +
36 + cp web/config/application.rb.SAMPLE web/config/application.rb
37 + cp web/config/initializers/cafe_grader_config.rb.SAMPLE web/config/initializers/cafe_grader_config.rb
38 +
39 + #replace UTC in application.rb with the system timezone
40 + timezone='UTC'
41 + if [ -f '/etc/timezone' ]; then
42 + timezone=\"`cat /etc/timezone`\"
43 + else
44 + if [ -f '/etc/sysconfig/clock' ]; then
45 + timezone=`grep -e '^TIMEZONE' /etc/sysconfig/clock | grep -o -e '\".*\"'`
46 + fi
47 + fi
48 + replace="s!'UTC'!$timezone!g"
49 + sed -i $replace web/config/application.rb
50 +
51 + echo "At this point we will need MySQL user and database."
52 + echo "Have you created MySQL user and database for Cafe grader? (Y/N) "
53 + read ch
54 +
55 + if [ "$ch" = "n" -o "$ch" = "N" ]
56 + then
57 + echo "Please open another terminal and create the user and database for Cafe grader."
58 + echo "Don't forget to grant access to that database for the user."
59 + echo "Please have username, password, and database name ready before continue."
60 + echo
61 + echo "The following are instructions:"
62 + echo "1. Run mysql:"
63 + echo
64 + echo " mysql -u root -p"
65 + echo
66 + echo " if you have just installed mysql, the root password is the one that you have just entered"
67 + echo "2. Create a new database, a new user, and grant access to grader database:"
68 + echo
69 + echo " create user 'USERNAME'@'localhost' identified by 'PASSWORD';"
70 + echo " create database \`DATABASENEME\`;"
71 + echo " grant all on \`DATABASENAME\`.* to 'USERNAME'@'localhost';"
72 + echo
73 + echo " Replace USERNAME, PASSWORD, and DATABASENAME accordingly."
74 + echo
75 + echo "Hit enter when ready..."
76 + read dummy
77 + fi
78 +
79 + CAFE_PATH=`pwd`
80 +
81 + cd web
82 +
83 + echo "Please provide grader database:"
84 + read database
85 +
86 + echo "Please provide grader username:"
87 + read username
88 +
89 + echo "Please provide $username password:"
90 + read password
91 +
92 + echo "development:" > config/database.yml
93 + echo " adapter: mysql2" >> config/database.yml
94 + echo " encoding: utf8" >> config/database.yml
95 + echo " reconnect: false" >> config/database.yml
96 + echo " database: $database" >> config/database.yml
97 + echo " pool: 5" >> config/database.yml
98 + echo " username: $username" >> config/database.yml
99 + echo " password: $password" >> config/database.yml
100 + echo " host: localhost" >> config/database.yml
101 + echo " socket: /run/mysql/mysql.sock" >> config/database.yml
102 + echo "" >> config/database.yml
103 + echo "production:" >> config/database.yml
104 + echo " adapter: mysql2" >> config/database.yml
105 + echo " encoding: utf8" >> config/database.yml
106 + echo " reconnect: false" >> config/database.yml
107 + echo " database: $database" >> config/database.yml
108 + echo " pool: 5" >> config/database.yml
109 + echo " username: $username" >> config/database.yml
110 + echo " password: $password" >> config/database.yml
111 + echo " host: localhost" >> config/database.yml
112 + echo " socket: /run/mysql/mysql.sock" >> config/database.yml
113 +
114 + echo "Object.instance_eval{remove_const :GRADER_ROOT_DIR}" >> config/initializers/cafe_grader_config.rb
115 + echo "Object.instance_eval{remove_const :GRADING_RESULT_DIR}" >> config/initializers/cafe_grader_config.rb
116 + echo "GRADER_ROOT_DIR = '$CAFE_PATH/judge'" >> config/initializers/cafe_grader_config.rb
117 + echo "GRADING_RESULT_DIR = '$CAFE_PATH/judge/result'" >> config/initializers/cafe_grader_config.rb
118 +
119 + echo "Installing required gems"
120 + gem install bundler
121 + bundle install
122 +
123 + echo "Running rake tasks to initialize database"
124 +
125 + rake db:migrate
126 + rake db:seed
127 +
128 + echo "Running rake tasks to precompile the assets"
129 +
130 + rake assets:precompile
131 +
132 + echo "Intalling web interface complete..."
133 + echo
134 + echo "Fetching grader"
135 +
136 + cd ..
137 +
138 + mkdir judge
139 + cd judge
140 + #git clone -q git://github.com/jittat/cafe-grader-judge-scripts.git scripts
141 + hg clone git+ssh://git@github.com/nattee/cafe-grader-judge-scripts.git scripts
142 + mkdir raw
143 + mkdir ev-exam
144 + mkdir ev
145 + mkdir result
146 + mkdir log
147 +
148 + echo "Configuring grader"
149 +
150 + cp scripts/config/env_exam.rb.SAMPLE scripts/config/env_exam.rb
151 + cp scripts/config/env_grading.rb.SAMPLE scripts/config/env_grading.rb
152 +
153 + # create new environment.rb file
154 + echo "RAILS_ROOT = '$CAFE_PATH/web'" > scripts/config/environment.rb
155 + echo "GRADER_ROOT = '$CAFE_PATH/judge/scripts'" >> scripts/config/environment.rb
156 + echo "require File.join(File.dirname(__FILE__),'../lib/boot')" >> scripts/config/environment.rb
157 + echo "require File.dirname(__FILE__) + \"/env_#{GRADER_ENV}.rb\"" >> scripts/config/environment.rb
158 +
159 + # compiling box
160 + MACHINE_TYPE=`uname -m`
161 + if [ ${MACHINE_TYPE} == 'x86_64' ]; then
162 + gcc -std=c99 -o scripts/std-script/box scripts/std-script/box64-new.c
163 + else
164 + g++ -o scripts/std-script/box scripts/std-script/box.cc
165 + fi
166 +
167 +
168 + cd ..
169 +
170 + echo "Now you are ready to run cafe grader...."
171 + echo
172 + echo "Try:"
173 + echo
174 + echo " cd web"
175 + echo " rails s"
176 + echo
177 + echo "and access web at http://localhost:3000/"
178 + echo "The root username is 'root', its password is 'ioionrails'."
179 +
@@ -0,0 +1,85
1 + #!/usr/bin/env ruby
2 +
3 + def config
4 + Grader::Configuration.get_instance
5 + end
6 +
7 + def display_manual
8 + puts <<USAGE
9 + load_testcases
10 + using: load_testcases [problem_name ...]
11 + problem_name are list of "short name" of the problems
12 +
13 + options:
14 + --dry-run do nothing, just simulate the run
15 + --all import all problem. This might take several minutes
16 +
17 + USAGE
18 + end
19 +
20 + def process_options_and_stop_file
21 +
22 + # Process 'help' option
23 + if (ARGV.length == 0) or ((ARGV.length==1) and (/help/.match(ARGV[0])))
24 + display_manual
25 + exit(0)
26 + end
27 +
28 + #default options
29 + options = {
30 + :dry_run => false,
31 + }
32 +
33 + options[:dry_run] = (ARGV.delete('--dry') != nil)
34 + options[:all] = (ARGV.delete('--all') != nil)
35 +
36 + return options
37 + end
38 +
39 + def process_problem(prob,dry_run = false)
40 + prob.testcases.destroy_all
41 + testcases_root = File.expand_path(GRADER_ROOT+"/../ev/#{prob.name}/test_cases/")
42 + num = 1
43 + puts "Processing problem #{prob.name}"
44 + loop do
45 + file_root = testcases_root + "/#{num}/"
46 + puts " checking file #{file_root}"
47 + break unless File.exists? file_root
48 + input = File.read(file_root + "/input-#{num}.txt")
49 + answer = File.read(file_root + "/answer-#{num}.txt")
50 + puts " got test case ##{num} of size #{input.size} and #{answer.size}"
51 +
52 + #THIS IS JUST A PLACE HOLDER
53 + group = num #this is wrong!!! fix it!!
54 + score = 10
55 + #BEWARE
56 +
57 + prob.testcases.create(input: input,sol: answer, num: num, score:score,group: group) unless dry_run
58 + num += 1
59 + end
60 + end
61 +
62 + #########################################
63 + # main program
64 + #########################################
65 +
66 + options = process_options_and_stop_file
67 +
68 + # load grader environment
69 + GRADER_ENV = 'grading'
70 + require File.join(File.dirname(__FILE__),'config/environment')
71 +
72 + # boot rails, to be able to use the active record
73 + RAILS_ENV = config.rails_env
74 + require RAILS_ROOT + '/config/environment'
75 +
76 + if options[:all]
77 + Problem.all.each { |prob| process_problem(prob,options[:dry_run]) }
78 + else
79 + ARGV.each do |name|
80 + prob = Problem.find_by(name: name)
81 + process_problem(prob,options[:dry_run]) if prob
82 + puts "Cannot find the problem #{name}" unless prob
83 + end
84 + end
85 +
@@ -1,236 +1,242
1 #!/usr/bin/env ruby
1 #!/usr/bin/env ruby
2
2
3 require 'erb'
3 require 'erb'
4 require 'fileutils'
4 require 'fileutils'
5 require File.join(File.dirname(__FILE__),'lib/import_helper')
5 require File.join(File.dirname(__FILE__),'lib/import_helper')
6
6
7 JUDGE_ENVIRONMENTS = [:grading, :exam]
7 JUDGE_ENVIRONMENTS = [:grading, :exam]
8 ENV_INFO = {
8 ENV_INFO = {
9 :grading => {
9 :grading => {
10 :ev_dir => 'ev',
10 :ev_dir => 'ev',
11 :raw_prefix => '',
11 :raw_prefix => '',
12 },
12 },
13 :exam => {
13 :exam => {
14 :ev_dir => 'ev-exam',
14 :ev_dir => 'ev-exam',
15 :raw_prefix => 'ex.',
15 :raw_prefix => 'ex.',
16 }
16 }
17 }
17 }
18
18
19 def input_filename(dir,i)
19 def input_filename(dir,i)
20 "#{dir}/input-#{i}.txt"
20 "#{dir}/input-#{i}.txt"
21 end
21 end
22
22
23 def answer_filename(dir,i)
23 def answer_filename(dir,i)
24 "#{dir}/answer-#{i}.txt"
24 "#{dir}/answer-#{i}.txt"
25 end
25 end
26
26
27 def build_testrun_info_from_dir(num_testruns, importing_test_dir, raw_prefix='')
27 def build_testrun_info_from_dir(num_testruns, importing_test_dir, raw_prefix='')
28 filenames = Dir["#{importing_test_dir}/#{raw_prefix}*.in"].collect do |filename|
28 filenames = Dir["#{importing_test_dir}/#{raw_prefix}*.in"].collect do |filename|
29 File.basename((/(.*)\.in/.match(filename))[1])
29 File.basename((/(.*)\.in/.match(filename))[1])
30 end
30 end
31 build_testrun_info(num_testruns,filenames,raw_prefix)
31 build_testrun_info(num_testruns,filenames,raw_prefix)
32 end
32 end
33
33
34 def copy_testcase(importing_test_dir,fname,dir,i)
34 def copy_testcase(importing_test_dir,fname,dir,i)
35 FileUtils.cp("#{importing_test_dir}/#{fname}.in", "#{input_filename(dir,i)}")
35 FileUtils.cp("#{importing_test_dir}/#{fname}.in", "#{input_filename(dir,i)}")
36 FileUtils.cp("#{importing_test_dir}/#{fname}.sol", "#{answer_filename(dir,i)}")
36 FileUtils.cp("#{importing_test_dir}/#{fname}.sol", "#{answer_filename(dir,i)}")
37 end
37 end
38
38
39 def process_options(options)
39 def process_options(options)
40 i = 3
40 i = 3
41 while i<ARGV.length
41 while i<ARGV.length
42 if ARGV[i]=='-t'
42 if ARGV[i]=='-t'
43 options[:time_limit] = ARGV[i+1].to_f if ARGV.length>i+1
43 options[:time_limit] = ARGV[i+1].to_f if ARGV.length>i+1
44 i += 1
44 i += 1
45 end
45 end
46 if ARGV[i]=='-m'
46 if ARGV[i]=='-m'
47 options[:mem_limit] = ARGV[i+1].to_i if ARGV.length>i+1
47 options[:mem_limit] = ARGV[i+1].to_i if ARGV.length>i+1
48 i += 1
48 i += 1
49 end
49 end
50 i += 1
50 i += 1
51 end
51 end
52 end
52 end
53
53
54 def print_usage
54 def print_usage
55 puts "using: import_problem_new name dir check [options]
55 puts "using: import_problem_new name dir check [options]
56
56
57 where: name = problem_name (put '-' (dash) to use dir name)
57 where: name = problem_name (put '-' (dash) to use dir name)
58 dir = importing testcase directory
58 dir = importing testcase directory
59 check = check script, which can be
59 check = check script, which can be
60 'integer', 'text' (for standard script),
60 'integer', 'text' (for standard script),
61 path_to_your_script, or
61 path_to_your_script, or
62 'wrapper:(path_to_your_wrapped_script)'
62 'wrapper:(path_to_your_wrapped_script)'
63 options: -t time-limit (in seconds)
63 options: -t time-limit (in seconds)
64 -m memory-limit (in megabytes)
64 -m memory-limit (in megabytes)
65
65
66 The script looks at test data files in the dir of the forms: *.in and
66 The script looks at test data files in the dir of the forms: *.in and
67 *.sol and import them to the evaluation dir for their environment,
67 *.sol and import them to the evaluation dir for their environment,
68 based on their prefixes.
68 based on their prefixes.
69
69
70 Currently supporting environments are:"
70 Currently supporting environments are:"
71
71
72 JUDGE_ENVIRONMENTS.each do |env|
72 JUDGE_ENVIRONMENTS.each do |env|
73 prefix = ENV_INFO[env][:raw_prefix]
73 prefix = ENV_INFO[env][:raw_prefix]
74 prefix = 'no prefix' if prefix==''
74 prefix = 'no prefix' if prefix==''
75 puts " * #{env}"
75 puts " * #{env}"
76 puts " import to: #{ENV_INFO[env][:ev_dir]}"
76 puts " import to: #{ENV_INFO[env][:ev_dir]}"
77 puts " prefix with: #{prefix} (e.g., #{ENV_INFO[env][:raw_prefix]}1.in, #{ENV_INFO[env][:raw_prefix]}5a.sol)"
77 puts " prefix with: #{prefix} (e.g., #{ENV_INFO[env][:raw_prefix]}1.in, #{ENV_INFO[env][:raw_prefix]}5a.sol)"
78 end
78 end
79
79
80 puts"
80 puts"
81 For each environment, the script
81 For each environment, the script
82 * creates a directory for a problem in ev dir of that environment,
82 * creates a directory for a problem in ev dir of that environment,
83 * copies testdata in the old format and create standard testcase config file
83 * copies testdata in the old format and create standard testcase config file
84 * copies a check script for grading
84 * copies a check script for grading
85 * creates a test_request template in the ev dir + '/test_request'
85 * creates a test_request template in the ev dir + '/test_request'
86
86
87 For wrapped checked script see comment in templates/check_wrapper for
87 For wrapped checked script see comment in templates/check_wrapper for
88 information."
88 information."
89 end
89 end
90
90
91 def count_testruns(testcase_dir, raw_prefix)
91 def count_testruns(testcase_dir, raw_prefix)
92 n = 0
92 n = 0
93 begin
93 begin
94 # check for test case n+1
94 # check for test case n+1
95 if ((Dir["#{testcase_dir}/#{raw_prefix}#{n+1}.in"].length==0) and
95 if ((Dir["#{testcase_dir}/#{raw_prefix}#{n+1}.in"].length==0) and
96 (Dir["#{testcase_dir}/#{raw_prefix}#{n+1}[a-z].in"].length==0))
96 (Dir["#{testcase_dir}/#{raw_prefix}#{n+1}[a-z].in"].length==0))
97 return n
97 return n
98 end
98 end
99 n += 1
99 n += 1
100 end while true
100 end while true
101 end
101 end
102
102
103 def create_dir_if_not_exists(dir)
103 def create_dir_if_not_exists(dir)
104 if ! FileTest.exists? dir
104 if ! FileTest.exists? dir
105 FileUtils.mkdir(dir)
105 FileUtils.mkdir(dir)
106 end
106 end
107 end
107 end
108
108
109 def import_problem(ev_dir, problem, testcase_dir, num_testruns, raw_prefix, check_script, options)
109 def import_problem(ev_dir, problem, testcase_dir, num_testruns, raw_prefix, check_script, options)
110 testrun_info = build_testrun_info_from_dir(num_testruns, testcase_dir, raw_prefix)
110 testrun_info = build_testrun_info_from_dir(num_testruns, testcase_dir, raw_prefix)
111
111
112 if !(FileTest.exists? ev_dir)
112 if !(FileTest.exists? ev_dir)
113 puts "Testdata dir (#{ev_dir}) not found."
113 puts "Testdata dir (#{ev_dir}) not found."
114 return
114 return
115 end
115 end
116
116
117 problem_dir = "#{ev_dir}/#{problem}"
117 problem_dir = "#{ev_dir}/#{problem}"
118
118
119 # start working
119 # start working
120 puts "creating directories"
120 puts "creating directories"
121
121
122 create_dir_if_not_exists("#{problem_dir}")
122 create_dir_if_not_exists("#{problem_dir}")
123 create_dir_if_not_exists("#{problem_dir}/script")
123 create_dir_if_not_exists("#{problem_dir}/script")
124 create_dir_if_not_exists("#{problem_dir}/test_cases")
124 create_dir_if_not_exists("#{problem_dir}/test_cases")
125
125
126 puts "copying testcases"
126 puts "copying testcases"
127
127
128 tr_num = 0
128 tr_num = 0
129
129
130 num_testcases = 0
130 num_testcases = 0
131
131
132 testrun_info.each do |testrun|
132 testrun_info.each do |testrun|
133 tr_num += 1
133 tr_num += 1
134 puts "testrun: #{tr_num}"
134 puts "testrun: #{tr_num}"
135
135
136 testrun.each do |testcase_info|
136 testrun.each do |testcase_info|
137 testcase_num, testcase_fname = testcase_info
137 testcase_num, testcase_fname = testcase_info
138
138
139 puts "copy #{testcase_fname} to #{testcase_num}"
139 puts "copy #{testcase_fname} to #{testcase_num}"
140
140
141 create_dir_if_not_exists("#{problem_dir}/test_cases/#{testcase_num}")
141 create_dir_if_not_exists("#{problem_dir}/test_cases/#{testcase_num}")
142 copy_testcase("#{testcase_dir}",testcase_fname,"#{problem_dir}/test_cases/#{testcase_num}",testcase_num)
142 copy_testcase("#{testcase_dir}",testcase_fname,"#{problem_dir}/test_cases/#{testcase_num}",testcase_num)
143
143
144 num_testcases += 1
144 num_testcases += 1
145 end
145 end
146 end
146 end
147
147
148 + #also include any .txt files
149 + Dir.glob("#{testcase_dir}/*.txt") do |file|
150 + puts "copy data file #{file}"
151 + FileUtils.cp(file,"#{problem_dir}")
152 + end
153 +
148 # generating all_tests.cfg
154 # generating all_tests.cfg
149 puts "generating testcase config file"
155 puts "generating testcase config file"
150
156
151 template = File.open(SCRIPT_DIR + "/templates/all_tests.cfg.erb").read
157 template = File.open(SCRIPT_DIR + "/templates/all_tests.cfg.erb").read
152 all_test_cfg = ERB.new(template)
158 all_test_cfg = ERB.new(template)
153
159
154 cfg_file = File.open("#{problem_dir}/test_cases/all_tests.cfg","w")
160 cfg_file = File.open("#{problem_dir}/test_cases/all_tests.cfg","w")
155 cfg_file.puts all_test_cfg.result binding
161 cfg_file.puts all_test_cfg.result binding
156 cfg_file.close
162 cfg_file.close
157
163
158 # copy check script
164 # copy check script
159 if res = /^wrapper:(.*)$/.match(check_script)
165 if res = /^wrapper:(.*)$/.match(check_script)
160 # wrapper script
166 # wrapper script
161 check_script_fname = res[1]
167 check_script_fname = res[1]
162 script_name = File.basename(check_script_fname)
168 script_name = File.basename(check_script_fname)
163 check_wrapper_template = File.open(SCRIPT_DIR + "/templates/check_wrapper").read
169 check_wrapper_template = File.open(SCRIPT_DIR + "/templates/check_wrapper").read
164 check_wrapper = ERB.new(check_wrapper_template)
170 check_wrapper = ERB.new(check_wrapper_template)
165
171
166 check_file = File.open("#{problem_dir}/script/check","w")
172 check_file = File.open("#{problem_dir}/script/check","w")
167 check_file.puts check_wrapper.result binding
173 check_file.puts check_wrapper.result binding
168 check_file.close
174 check_file.close
169
175
170 File.chmod(0755,"#{problem_dir}/script/check")
176 File.chmod(0755,"#{problem_dir}/script/check")
171
177
172 FileUtils.cp("#{check_script_fname}", "#{problem_dir}/script/#{script_name}")
178 FileUtils.cp("#{check_script_fname}", "#{problem_dir}/script/#{script_name}")
173 else
179 else
174 if File.exists?(SCRIPT_DIR + "/templates/check.#{check_script}")
180 if File.exists?(SCRIPT_DIR + "/templates/check.#{check_script}")
175 check_script_fname = SCRIPT_DIR + "/templates/check.#{check_script}"
181 check_script_fname = SCRIPT_DIR + "/templates/check.#{check_script}"
176 else
182 else
177 check_script_fname = check_script
183 check_script_fname = check_script
178 end
184 end
179 FileUtils.cp("#{check_script_fname}", "#{problem_dir}/script/check", :preserve => true)
185 FileUtils.cp("#{check_script_fname}", "#{problem_dir}/script/check", :preserve => true)
180 end
186 end
181
187
182 # generating test_request directory
188 # generating test_request directory
183 puts "generating test_request template"
189 puts "generating test_request template"
184 FileUtils.mkdir_p("#{ev_dir}/test_request/#{problem}/script")
190 FileUtils.mkdir_p("#{ev_dir}/test_request/#{problem}/script")
185 FileUtils.mkdir_p("#{ev_dir}/test_request/#{problem}/test_cases/1")
191 FileUtils.mkdir_p("#{ev_dir}/test_request/#{problem}/test_cases/1")
186
192
187 template = File.open(SCRIPT_DIR + "/templates/test_request_all_tests.cfg.erb").read
193 template = File.open(SCRIPT_DIR + "/templates/test_request_all_tests.cfg.erb").read
188 test_request_all_test_cfg = ERB.new(template)
194 test_request_all_test_cfg = ERB.new(template)
189
195
190 cfg_file = File.open("#{ev_dir}/test_request/#{problem}/test_cases/all_tests.cfg","w")
196 cfg_file = File.open("#{ev_dir}/test_request/#{problem}/test_cases/all_tests.cfg","w")
191 cfg_file.puts test_request_all_test_cfg.result
197 cfg_file.puts test_request_all_test_cfg.result
192 cfg_file.close
198 cfg_file.close
193
199
194 FileUtils.cp("#{SCRIPT_DIR}/templates/check_empty",
200 FileUtils.cp("#{SCRIPT_DIR}/templates/check_empty",
195 "#{ev_dir}/test_request/#{problem}/script/check")
201 "#{ev_dir}/test_request/#{problem}/script/check")
196 FileUtils.cp("#{SCRIPT_DIR}/templates/answer-1.txt",
202 FileUtils.cp("#{SCRIPT_DIR}/templates/answer-1.txt",
197 "#{ev_dir}/test_request/#{problem}/test_cases/1")
203 "#{ev_dir}/test_request/#{problem}/test_cases/1")
198
204
199 puts "done"
205 puts "done"
200 end
206 end
201
207
202
208
203 SCRIPT_DIR = File.dirname(__FILE__)
209 SCRIPT_DIR = File.dirname(__FILE__)
204
210
205 # print usage
211 # print usage
206 if (ARGV.length < 3) or (ARGV[2][0,1]=="-")
212 if (ARGV.length < 3) or (ARGV[2][0,1]=="-")
207 print_usage
213 print_usage
208 exit(127)
214 exit(127)
209 end
215 end
210
216
211 # processing arguments
217 # processing arguments
212 problem = ARGV[0]
218 problem = ARGV[0]
213 testcase_dir = ARGV[1]
219 testcase_dir = ARGV[1]
214 problem = File.basename(testcase_dir) if problem=="-"
220 problem = File.basename(testcase_dir) if problem=="-"
215 check_script = ARGV[2]
221 check_script = ARGV[2]
216 options = {:time_limit => 1, :mem_limit => 16}
222 options = {:time_limit => 1, :mem_limit => 16}
217 process_options(options)
223 process_options(options)
218
224
219 JUDGE_ENVIRONMENTS.each do |env|
225 JUDGE_ENVIRONMENTS.each do |env|
220 ev_dir = ENV_INFO[env][:ev_dir]
226 ev_dir = ENV_INFO[env][:ev_dir]
221 raw_prefix = ENV_INFO[env][:raw_prefix]
227 raw_prefix = ENV_INFO[env][:raw_prefix]
222
228
223 num_testruns = count_testruns(testcase_dir,raw_prefix)
229 num_testruns = count_testruns(testcase_dir,raw_prefix)
224
230
225 puts ""
231 puts ""
226 puts "*** Environment: #{env} (#{num_testruns} test runs) ***"
232 puts "*** Environment: #{env} (#{num_testruns} test runs) ***"
227 puts ""
233 puts ""
228
234
229 import_problem(ev_dir,
235 import_problem(ev_dir,
230 problem,
236 problem,
231 testcase_dir,
237 testcase_dir,
232 num_testruns,
238 num_testruns,
233 raw_prefix,
239 raw_prefix,
234 check_script,
240 check_script,
235 options)
241 options)
236 end
242 end
@@ -1,180 +1,181
1 #!/bin/sh
1 #!/bin/sh
2
2
3 echo "This script will install and configure Cafe grader."
3 echo "This script will install and configure Cafe grader."
4
4
5 RUBY_VERSION=2.1.2
5 RUBY_VERSION=2.1.2
6 echo "This will install Ruby $RUBY_VERSION under RVM"
6 echo "This will install Ruby $RUBY_VERSION under RVM"
7
7
8 echo "Installing required apts"
8 echo "Installing required apts"
9
9
10 sudo apt-get update
10 sudo apt-get update
11 sudo apt-get install mysql-server mysql-client \
11 sudo apt-get install mysql-server mysql-client \
12 - g++ gcc apache2 libmysqlclient15-dev build-essential \
12 + g++ gcc apache2 libmysqlclient20 build-essential \
13 git-core openssl libreadline6 libreadline6-dev \
13 git-core openssl libreadline6 libreadline6-dev \
14 zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-dev \
14 zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-dev \
15 sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev \
15 sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev \
16 ncurses-dev automake libtool bison subversion \
16 ncurses-dev automake libtool bison subversion \
17 - pkg-config curl nodejs unzip pyflakes ruby default-jdk
17 + pkg-config curl nodejs unzip pyflakes ruby default-jdk \
18 + libmysqld-dev mercurial python-setuptools python-dev python3-numpy
18
19
19 echo "Installing RVM"
20 echo "Installing RVM"
20 curl -k -L https://get.rvm.io | bash -s stable
21 curl -k -L https://get.rvm.io | bash -s stable
21 source ~/.rvm/scripts/rvm
22 source ~/.rvm/scripts/rvm
22
23
23 echo "Installing Ruby $RUBY_VERSION in RVM"
24 echo "Installing Ruby $RUBY_VERSION in RVM"
24
25
25 rvm install $RUBY_VERSION
26 rvm install $RUBY_VERSION
26 rvm use $RUBY_VERSION
27 rvm use $RUBY_VERSION
27
28
28 echo "Fetching Cafe Grader from Git repositories"
29 echo "Fetching Cafe Grader from Git repositories"
29
30
30 echo "Fetching web interface"
31 echo "Fetching web interface"
31
32
32 mkdir cafe_grader
33 mkdir cafe_grader
33 cd cafe_grader
34 cd cafe_grader
34 git clone -q git://github.com/jittat/cafe-grader-web.git web
35 git clone -q git://github.com/jittat/cafe-grader-web.git web
35
36
36 echo "Configuring rails app"
37 echo "Configuring rails app"
37
38
38 cp web/config/application.rb.SAMPLE web/config/application.rb
39 cp web/config/application.rb.SAMPLE web/config/application.rb
39 cp web/config/initializers/cafe_grader_config.rb.SAMPLE web/config/initializers/cafe_grader_config.rb
40 cp web/config/initializers/cafe_grader_config.rb.SAMPLE web/config/initializers/cafe_grader_config.rb
40
41
41 #replace UTC in application.rb with the system timezone
42 #replace UTC in application.rb with the system timezone
42 timezone='UTC'
43 timezone='UTC'
43 if [ -f '/etc/timezone' ]; then
44 if [ -f '/etc/timezone' ]; then
44 timezone=\"`cat /etc/timezone`\"
45 timezone=\"`cat /etc/timezone`\"
45 else
46 else
46 if [ -f '/etc/sysconfig/clock' ]; then
47 if [ -f '/etc/sysconfig/clock' ]; then
47 timezone=`grep -e '^TIMEZONE' /etc/sysconfig/clock | grep -o -e '\".*\"'`
48 timezone=`grep -e '^TIMEZONE' /etc/sysconfig/clock | grep -o -e '\".*\"'`
48 fi
49 fi
49 fi
50 fi
50 replace="s!'UTC'!$timezone!g"
51 replace="s!'UTC'!$timezone!g"
51 sed -i $replace web/config/application.rb
52 sed -i $replace web/config/application.rb
52
53
53 echo "At this point we will need MySQL user and database."
54 echo "At this point we will need MySQL user and database."
54 echo "Have you created MySQL user and database for Cafe grader? (Y/N) "
55 echo "Have you created MySQL user and database for Cafe grader? (Y/N) "
55 read ch
56 read ch
56
57
57 if [ "$ch" = "n" -o "$ch" = "N" ]
58 if [ "$ch" = "n" -o "$ch" = "N" ]
58 then
59 then
59 echo "Please open another terminal and create the user and database for Cafe grader."
60 echo "Please open another terminal and create the user and database for Cafe grader."
60 echo "Don't forget to grant access to that database for the user."
61 echo "Don't forget to grant access to that database for the user."
61 echo "Please have username, password, and database name ready before continue."
62 echo "Please have username, password, and database name ready before continue."
62 echo
63 echo
63 echo "The following are instructions:"
64 echo "The following are instructions:"
64 echo "1. Run mysql:"
65 echo "1. Run mysql:"
65 echo
66 echo
66 echo " mysql -u root -p"
67 echo " mysql -u root -p"
67 echo
68 echo
68 echo " if you have just installed mysql, the root password is the one that you have just entered"
69 echo " if you have just installed mysql, the root password is the one that you have just entered"
69 echo "2. Create a new database, a new user, and grant access to grader database:"
70 echo "2. Create a new database, a new user, and grant access to grader database:"
70 echo
71 echo
71 echo " create user 'USERNAME'@'localhost' identified by 'PASSWORD';"
72 echo " create user 'USERNAME'@'localhost' identified by 'PASSWORD';"
72 echo " create database \`DATABASENEME\`;"
73 echo " create database \`DATABASENEME\`;"
73 echo " grant all on \`DATABASENAME\`.* to 'USERNAME'@'localhost';"
74 echo " grant all on \`DATABASENAME\`.* to 'USERNAME'@'localhost';"
74 echo
75 echo
75 echo " Replace USERNAME, PASSWORD, and DATABASENAME accordingly."
76 echo " Replace USERNAME, PASSWORD, and DATABASENAME accordingly."
76 echo
77 echo
77 echo "Hit enter when ready..."
78 echo "Hit enter when ready..."
78 read dummy
79 read dummy
79 fi
80 fi
80
81
81 CAFE_PATH=`pwd`
82 CAFE_PATH=`pwd`
82
83
83 cd web
84 cd web
84
85
85 echo "Please provide grader database:"
86 echo "Please provide grader database:"
86 read database
87 read database
87
88
88 echo "Please provide grader username:"
89 echo "Please provide grader username:"
89 read username
90 read username
90
91
91 echo "Please provide $username password:"
92 echo "Please provide $username password:"
92 read password
93 read password
93
94
94 echo "development:" > config/database.yml
95 echo "development:" > config/database.yml
95 echo " adapter: mysql2" >> config/database.yml
96 echo " adapter: mysql2" >> config/database.yml
96 echo " encoding: utf8" >> config/database.yml
97 echo " encoding: utf8" >> config/database.yml
97 echo " reconnect: false" >> config/database.yml
98 echo " reconnect: false" >> config/database.yml
98 echo " database: $database" >> config/database.yml
99 echo " database: $database" >> config/database.yml
99 echo " pool: 5" >> config/database.yml
100 echo " pool: 5" >> config/database.yml
100 echo " username: $username" >> config/database.yml
101 echo " username: $username" >> config/database.yml
101 echo " password: $password" >> config/database.yml
102 echo " password: $password" >> config/database.yml
102 echo " host: localhost" >> config/database.yml
103 echo " host: localhost" >> config/database.yml
103 echo " socket: /var/run/mysqld/mysqld.sock" >> config/database.yml
104 echo " socket: /var/run/mysqld/mysqld.sock" >> config/database.yml
104 echo "" >> config/database.yml
105 echo "" >> config/database.yml
105 echo "production:" >> config/database.yml
106 echo "production:" >> config/database.yml
106 echo " adapter: mysql2" >> config/database.yml
107 echo " adapter: mysql2" >> config/database.yml
107 echo " encoding: utf8" >> config/database.yml
108 echo " encoding: utf8" >> config/database.yml
108 echo " reconnect: false" >> config/database.yml
109 echo " reconnect: false" >> config/database.yml
109 echo " database: $database" >> config/database.yml
110 echo " database: $database" >> config/database.yml
110 echo " pool: 5" >> config/database.yml
111 echo " pool: 5" >> config/database.yml
111 echo " username: $username" >> config/database.yml
112 echo " username: $username" >> config/database.yml
112 echo " password: $password" >> config/database.yml
113 echo " password: $password" >> config/database.yml
113 echo " host: localhost" >> config/database.yml
114 echo " host: localhost" >> config/database.yml
114 echo " socket: /var/run/mysqld/mysqld.sock" >> config/database.yml
115 echo " socket: /var/run/mysqld/mysqld.sock" >> config/database.yml
115
116
116 echo "Object.instance_eval{remove_const :GRADER_ROOT_DIR}" >> config/initializers/cafe_grader_config.rb
117 echo "Object.instance_eval{remove_const :GRADER_ROOT_DIR}" >> config/initializers/cafe_grader_config.rb
117 echo "Object.instance_eval{remove_const :GRADING_RESULT_DIR}" >> config/initializers/cafe_grader_config.rb
118 echo "Object.instance_eval{remove_const :GRADING_RESULT_DIR}" >> config/initializers/cafe_grader_config.rb
118 echo "GRADER_ROOT_DIR = '$CAFE_PATH/judge'" >> config/initializers/cafe_grader_config.rb
119 echo "GRADER_ROOT_DIR = '$CAFE_PATH/judge'" >> config/initializers/cafe_grader_config.rb
119 echo "GRADING_RESULT_DIR = '$CAFE_PATH/judge/result'" >> config/initializers/cafe_grader_config.rb
120 echo "GRADING_RESULT_DIR = '$CAFE_PATH/judge/result'" >> config/initializers/cafe_grader_config.rb
120
121
121 echo "Installing required gems"
122 echo "Installing required gems"
122 gem install bundler
123 gem install bundler
123 bundle install
124 bundle install
124
125
125 echo "Running rake tasks to initialize database"
126 echo "Running rake tasks to initialize database"
126
127
127 rake db:migrate
128 rake db:migrate
128 rake db:seed
129 rake db:seed
129
130
130 echo "Running rake tasks to precompile the assets"
131 echo "Running rake tasks to precompile the assets"
131
132
132 rake assets:precompile
133 rake assets:precompile
133
134
134 echo "Intalling web interface complete..."
135 echo "Intalling web interface complete..."
135 echo
136 echo
136 echo "Fetching grader"
137 echo "Fetching grader"
137
138
138 cd ..
139 cd ..
139
140
140 mkdir judge
141 mkdir judge
141 cd judge
142 cd judge
142 git clone -q git://github.com/jittat/cafe-grader-judge-scripts.git scripts
143 git clone -q git://github.com/jittat/cafe-grader-judge-scripts.git scripts
143 mkdir raw
144 mkdir raw
144 mkdir ev-exam
145 mkdir ev-exam
145 mkdir ev
146 mkdir ev
146 mkdir result
147 mkdir result
147 mkdir log
148 mkdir log
148
149
149 echo "Configuring grader"
150 echo "Configuring grader"
150
151
151 cp scripts/config/env_exam.rb.SAMPLE scripts/config/env_exam.rb
152 cp scripts/config/env_exam.rb.SAMPLE scripts/config/env_exam.rb
152 cp scripts/config/env_grading.rb.SAMPLE scripts/config/env_grading.rb
153 cp scripts/config/env_grading.rb.SAMPLE scripts/config/env_grading.rb
153
154
154 # create new environment.rb file
155 # create new environment.rb file
155 echo "RAILS_ROOT = '$CAFE_PATH/web'" > scripts/config/environment.rb
156 echo "RAILS_ROOT = '$CAFE_PATH/web'" > scripts/config/environment.rb
156 echo "GRADER_ROOT = '$CAFE_PATH/judge/scripts'" >> scripts/config/environment.rb
157 echo "GRADER_ROOT = '$CAFE_PATH/judge/scripts'" >> scripts/config/environment.rb
157 echo "require File.join(File.dirname(__FILE__),'../lib/boot')" >> scripts/config/environment.rb
158 echo "require File.join(File.dirname(__FILE__),'../lib/boot')" >> scripts/config/environment.rb
158 echo "require File.dirname(__FILE__) + \"/env_#{GRADER_ENV}.rb\"" >> scripts/config/environment.rb
159 echo "require File.dirname(__FILE__) + \"/env_#{GRADER_ENV}.rb\"" >> scripts/config/environment.rb
159
160
160 # compiling box
161 # compiling box
161 MACHINE_TYPE=`uname -m`
162 MACHINE_TYPE=`uname -m`
162 if [ ${MACHINE_TYPE} == 'x86_64' ]; then
163 if [ ${MACHINE_TYPE} == 'x86_64' ]; then
163 gcc -std=c99 -o scripts/std-script/box scripts/std-script/box64-new.c
164 gcc -std=c99 -o scripts/std-script/box scripts/std-script/box64-new.c
164 else
165 else
165 g++ -o scripts/std-script/box scripts/std-script/box.cc
166 g++ -o scripts/std-script/box scripts/std-script/box.cc
166 fi
167 fi
167
168
168
169
169 cd ..
170 cd ..
170
171
171 echo "Now you are ready to run cafe grader...."
172 echo "Now you are ready to run cafe grader...."
172 echo
173 echo
173 echo "Try:"
174 echo "Try:"
174 echo
175 echo
175 echo " cd web"
176 echo " cd web"
176 echo " rails s"
177 echo " rails s"
177 echo
178 echo
178 echo "and access web at http://localhost:3000/"
179 echo "and access web at http://localhost:3000/"
179 echo "The root username is 'root', its password is 'ioionrails'."
180 echo "The root username is 'root', its password is 'ioionrails'."
180
181
@@ -1,100 +1,100
1 #!/usr/bin/env ruby
1 #!/usr/bin/env ruby
2
2
3 ENVIRONMENT_DIRS = ['ev', 'ev-exam']
3 ENVIRONMENT_DIRS = ['ev', 'ev-exam']
4
4
5 def config
5 def config
6 Grader::Configuration.get_instance
6 Grader::Configuration.get_instance
7 end
7 end
8
8
9 def rename_problem(old_problem_name, new_problem_name)
9 def rename_problem(old_problem_name, new_problem_name)
10
10
11 - if valid_problem_name(new_problem_name)
11 + unless valid_problem_name(new_problem_name)
12 puts "Bad new problem name: #{new_problem_name}"
12 puts "Bad new problem name: #{new_problem_name}"
13 return
13 return
14 end
14 end
15
15
16 problem = Problem.find_by_name(old_problem_name)
16 problem = Problem.find_by_name(old_problem_name)
17 if problem==nil
17 if problem==nil
18 puts "Problem #{old_problem_name} does not exist."
18 puts "Problem #{old_problem_name} does not exist."
19 return
19 return
20 end
20 end
21
21
22 puts "Problem: #{old_problem_name} -> #{new_problem_name}"
22 puts "Problem: #{old_problem_name} -> #{new_problem_name}"
23
23
24 ENVIRONMENT_DIRS.each do |dir|
24 ENVIRONMENT_DIRS.each do |dir|
25 problem_dir = File.join(GRADER_ROOT,'..',dir,old_problem_name)
25 problem_dir = File.join(GRADER_ROOT,'..',dir,old_problem_name)
26 new_problem_dir = File.join(GRADER_ROOT,'..',dir,new_problem_name)
26 new_problem_dir = File.join(GRADER_ROOT,'..',dir,new_problem_name)
27
27
28 if FileTest.exists? problem_dir
28 if FileTest.exists? problem_dir
29 puts "Moving #{problem_dir} to #{new_problem_dir}."
29 puts "Moving #{problem_dir} to #{new_problem_dir}."
30 File.rename(problem_dir, new_problem_dir)
30 File.rename(problem_dir, new_problem_dir)
31
31
32 tr_problem_dir = File.join(GRADER_ROOT,'..',dir,
32 tr_problem_dir = File.join(GRADER_ROOT,'..',dir,
33 'test_request',old_problem_name)
33 'test_request',old_problem_name)
34 new_tr_problem_dir = File.join(GRADER_ROOT,'..',dir,
34 new_tr_problem_dir = File.join(GRADER_ROOT,'..',dir,
35 'test_request',new_problem_name)
35 'test_request',new_problem_name)
36 File.rename(tr_problem_dir, new_tr_problem_dir)
36 File.rename(tr_problem_dir, new_tr_problem_dir)
37 end
37 end
38 end
38 end
39
39
40 problem.name = new_problem_name
40 problem.name = new_problem_name
41 problem.save
41 problem.save
42 end
42 end
43
43
44 def usage
44 def usage
45 puts <<USAGE
45 puts <<USAGE
46 Usage:
46 Usage:
47 rename_problem [old_name] [new_name]
47 rename_problem [old_name] [new_name]
48 or
48 or
49 rename_problem -f [filename]
49 rename_problem -f [filename]
50
50
51 When using with -f, that file should contain, for each line, the old
51 When using with -f, that file should contain, for each line, the old
52 problem name and its new name.
52 problem name and its new name.
53
53
54 This script should be called at the judge root dir where dirs 'ev' and
54 This script should be called at the judge root dir where dirs 'ev' and
55 'ev-exam' are.
55 'ev-exam' are.
56 USAGE
56 USAGE
57 end
57 end
58
58
59 def valid_problem_name(name)
59 def valid_problem_name(name)
60 if name.length==0:
60 if name.length==0:
61 return false
61 return false
62 else
62 else
63 - return !(/^[a-zA-Z0-9_\-]+$/ === name)
63 + return (/^[a-zA-Z0-9_\-]+$/ === name)
64 end
64 end
65 end
65 end
66
66
67 if (ARGV.length!=2)
67 if (ARGV.length!=2)
68 usage
68 usage
69 exit(0)
69 exit(0)
70 end
70 end
71
71
72 if ARGV[0]=='-f' and !FileTest.exists?(ARGV[1])
72 if ARGV[0]=='-f' and !FileTest.exists?(ARGV[1])
73 puts "File #{ARGV[1]} does not exist."
73 puts "File #{ARGV[1]} does not exist."
74 usage
74 usage
75 exit(0)
75 exit(0)
76 end
76 end
77
77
78 # load grader environment
78 # load grader environment
79 GRADER_ENV = 'grading'
79 GRADER_ENV = 'grading'
80 require File.join(File.dirname(__FILE__),'config/environment')
80 require File.join(File.dirname(__FILE__),'config/environment')
81
81
82 # boot rails, to be able to rename the problem
82 # boot rails, to be able to rename the problem
83 RAILS_ENV = config.rails_env
83 RAILS_ENV = config.rails_env
84 require RAILS_ROOT + '/config/environment'
84 require RAILS_ROOT + '/config/environment'
85
85
86 if ARGV[0]!='-f'
86 if ARGV[0]!='-f'
87 old_problem_name = ARGV[0]
87 old_problem_name = ARGV[0]
88 new_problem_name = ARGV[1]
88 new_problem_name = ARGV[1]
89
89
90 rename_problem(old_problem_name, new_problem_name)
90 rename_problem(old_problem_name, new_problem_name)
91 else
91 else
92 lines = IO.readlines(ARGV[1])
92 lines = IO.readlines(ARGV[1])
93 lines.each do |line|
93 lines.each do |line|
94 items = line.split
94 items = line.split
95 if items.length==2
95 if items.length==2
96 old_name, new_name = items
96 old_name, new_name = items
97 rename_problem(old_name, new_name)
97 rename_problem(old_name, new_name)
98 end
98 end
99 end
99 end
100 end
100 end
@@ -1,1760 +1,1772
1 /*
1 /*
2 * A Simple Sandbox for Moe
2 * A Simple Sandbox for Moe
3 *
3 *
4 * (c) 2001--2010 Martin Mares <mj@ucw.cz>
4 * (c) 2001--2010 Martin Mares <mj@ucw.cz>
5 */
5 */
6
6
7 #define _LARGEFILE64_SOURCE
7 #define _LARGEFILE64_SOURCE
8 #define _GNU_SOURCE
8 #define _GNU_SOURCE
9
9
10 /* Generated automatically by ./configure, please don't touch manually. */
10 /* Generated automatically by ./configure, please don't touch manually. */
11 #define CONFIG_BOX_KERNEL_AMD64 1
11 #define CONFIG_BOX_KERNEL_AMD64 1
12 #define CONFIG_BOX_USER_AMD64 1
12 #define CONFIG_BOX_USER_AMD64 1
13 #define CONFIG_DIR "cf"
13 #define CONFIG_DIR "cf"
14 #define CONFIG_DIRECT_IO 1
14 #define CONFIG_DIRECT_IO 1
15 #define CONFIG_ISOLATE_BOX_DIR "/tmp/box"
15 #define CONFIG_ISOLATE_BOX_DIR "/tmp/box"
16 #define CONFIG_ISOLATE_CGROUP_ROOT "/sys/fs/cgroup"
16 #define CONFIG_ISOLATE_CGROUP_ROOT "/sys/fs/cgroup"
17 #define CONFIG_ISOLATE_FIRST_GID 60000
17 #define CONFIG_ISOLATE_FIRST_GID 60000
18 #define CONFIG_ISOLATE_FIRST_UID 60000
18 #define CONFIG_ISOLATE_FIRST_UID 60000
19 #define CONFIG_ISOLATE_NUM_BOXES 100
19 #define CONFIG_ISOLATE_NUM_BOXES 100
20 #define CONFIG_LARGE_FILES 1
20 #define CONFIG_LARGE_FILES 1
21 #define CONFIG_LFS 1
21 #define CONFIG_LFS 1
22 #define CONFIG_LINUX 1
22 #define CONFIG_LINUX 1
23 #define CONFIG_LOCAL 1
23 #define CONFIG_LOCAL 1
24 #define CONFIG_UCW_PARTMAP_IS_MMAP 1
24 #define CONFIG_UCW_PARTMAP_IS_MMAP 1
25 #define CONFIG_UCW_PERL 1
25 #define CONFIG_UCW_PERL 1
26 #define CONFIG_UCW_POOL_IS_MMAP 1
26 #define CONFIG_UCW_POOL_IS_MMAP 1
27 #define CONFIG_UCW_RADIX_SORTER_BITS 10
27 #define CONFIG_UCW_RADIX_SORTER_BITS 10
28 #define CONFIG_UCW_SHELL_UTILS 1
28 #define CONFIG_UCW_SHELL_UTILS 1
29 #define CPU_64BIT_POINTERS 1
29 #define CPU_64BIT_POINTERS 1
30 #define CPU_ALLOW_UNALIGNED 1
30 #define CPU_ALLOW_UNALIGNED 1
31 #define CPU_AMD64 1
31 #define CPU_AMD64 1
32 #define CPU_ARCH "default"
32 #define CPU_ARCH "default"
33 #define CPU_LITTLE_ENDIAN 1
33 #define CPU_LITTLE_ENDIAN 1
34 #define CPU_PAGE_SIZE 4096
34 #define CPU_PAGE_SIZE 4096
35 #define CPU_STRUCT_ALIGN 8
35 #define CPU_STRUCT_ALIGN 8
36 #define CWARNS_OFF " -Wno-pointer-sign"
36 #define CWARNS_OFF " -Wno-pointer-sign"
37 #define HAVE_ASCII_DOC "none"
37 #define HAVE_ASCII_DOC "none"
38 #define INSTALL_BIN_DIR "bin"
38 #define INSTALL_BIN_DIR "bin"
39 #define INSTALL_CONFIG_DIR "cf"
39 #define INSTALL_CONFIG_DIR "cf"
40 #define INSTALL_DOC_DIR "share/doc"
40 #define INSTALL_DOC_DIR "share/doc"
41 #define INSTALL_INCLUDE_DIR "include"
41 #define INSTALL_INCLUDE_DIR "include"
42 #define INSTALL_LIB_DIR "lib"
42 #define INSTALL_LIB_DIR "lib"
43 #define INSTALL_LOG_DIR "log"
43 #define INSTALL_LOG_DIR "log"
44 #define INSTALL_MAN_DIR "share/man"
44 #define INSTALL_MAN_DIR "share/man"
45 #define INSTALL_PERL_DIR "lib/perl5"
45 #define INSTALL_PERL_DIR "lib/perl5"
46 #define INSTALL_PKGCONFIG_DIR "lib/pkgconfig"
46 #define INSTALL_PKGCONFIG_DIR "lib/pkgconfig"
47 #define INSTALL_PREFIX
47 #define INSTALL_PREFIX
48 #define INSTALL_RUN_DIR "run"
48 #define INSTALL_RUN_DIR "run"
49 #define INSTALL_SBIN_DIR "sbin"
49 #define INSTALL_SBIN_DIR "sbin"
50 #define INSTALL_SHARE_DIR "share"
50 #define INSTALL_SHARE_DIR "share"
51 #define INSTALL_STATE_DIR "lib"
51 #define INSTALL_STATE_DIR "lib"
52 #define INSTALL_USR_PREFIX
52 #define INSTALL_USR_PREFIX
53 #define INSTALL_VAR_PREFIX
53 #define INSTALL_VAR_PREFIX
54 #define SHERLOCK_VERSION "3.99.2"
54 #define SHERLOCK_VERSION "3.99.2"
55 #define SHERLOCK_VERSION_CODE 3099002
55 #define SHERLOCK_VERSION_CODE 3099002
56 #define SONAME_PREFIX "lib/"
56 #define SONAME_PREFIX "lib/"
57 #define UCW_VERSION "3.99.2"
57 #define UCW_VERSION "3.99.2"
58 #define UCW_VERSION_CODE 3099002
58 #define UCW_VERSION_CODE 3099002
59
59
60 #include <errno.h>
60 #include <errno.h>
61 #include <stdio.h>
61 #include <stdio.h>
62 #include <fcntl.h>
62 #include <fcntl.h>
63 #include <stdlib.h>
63 #include <stdlib.h>
64 #include <string.h>
64 #include <string.h>
65 #include <stdarg.h>
65 #include <stdarg.h>
66 #include <stdint.h>
66 #include <stdint.h>
67 #include <unistd.h>
67 #include <unistd.h>
68 #include <getopt.h>
68 #include <getopt.h>
69 #include <time.h>
69 #include <time.h>
70 #include <sys/wait.h>
70 #include <sys/wait.h>
71 #include <sys/user.h>
71 #include <sys/user.h>
72 #include <sys/time.h>
72 #include <sys/time.h>
73 #include <sys/ptrace.h>
73 #include <sys/ptrace.h>
74 #include <sys/signal.h>
74 #include <sys/signal.h>
75 #include <sys/sysinfo.h>
75 #include <sys/sysinfo.h>
76 #include <sys/resource.h>
76 #include <sys/resource.h>
77 #include <sys/utsname.h>
77 #include <sys/utsname.h>
78 //#include <linux/ptrace.h>
78 //#include <linux/ptrace.h>
79
79
80 #if defined(CONFIG_BOX_KERNEL_AMD64) && !defined(CONFIG_BOX_USER_AMD64)
80 #if defined(CONFIG_BOX_KERNEL_AMD64) && !defined(CONFIG_BOX_USER_AMD64)
81 #include <asm/unistd_32.h>
81 #include <asm/unistd_32.h>
82 #define NATIVE_NR_execve 59 /* 64-bit execve */
82 #define NATIVE_NR_execve 59 /* 64-bit execve */
83 #else
83 #else
84 #include <asm/unistd.h>
84 #include <asm/unistd.h>
85 #define NATIVE_NR_execve __NR_execve
85 #define NATIVE_NR_execve __NR_execve
86 #endif
86 #endif
87
87
88 #define NONRET __attribute__((noreturn))
88 #define NONRET __attribute__((noreturn))
89 #define UNUSED __attribute__((unused))
89 #define UNUSED __attribute__((unused))
90 #define ARRAY_SIZE(a) (int)(sizeof(a)/sizeof(a[0]))
90 #define ARRAY_SIZE(a) (int)(sizeof(a)/sizeof(a[0]))
91
91
92 static int filter_syscalls; /* 0=off, 1=liberal, 2=totalitarian */
92 static int filter_syscalls; /* 0=off, 1=liberal, 2=totalitarian */
93 static int timeout; /* milliseconds */
93 static int timeout; /* milliseconds */
94 static int wall_timeout;
94 static int wall_timeout;
95 static int extra_timeout;
95 static int extra_timeout;
96 static int pass_environ;
96 static int pass_environ;
97 static int file_access;
97 static int file_access;
98 static int verbose;
98 static int verbose;
99 static int memory_limit;
99 static int memory_limit;
100 static int stack_limit;
100 static int stack_limit;
101 static char *redir_stdin, *redir_stdout, *redir_stderr;
101 static char *redir_stdin, *redir_stdout, *redir_stderr;
102 static char *set_cwd;
102 static char *set_cwd;
103
103
104 static pid_t box_pid;
104 static pid_t box_pid;
105 static int is_ptraced;
105 static int is_ptraced;
106 static volatile int timer_tick;
106 static volatile int timer_tick;
107 static struct timeval start_time;
107 static struct timeval start_time;
108 static int ticks_per_sec;
108 static int ticks_per_sec;
109 static int exec_seen;
109 static int exec_seen;
110 static int partial_line;
110 static int partial_line;
111
111
112 static int mem_peak_kb;
112 static int mem_peak_kb;
113 static int total_ms, wall_ms, sys_ms;
113 static int total_ms, wall_ms, sys_ms;
114
114
115 static void die(char *msg, ...) NONRET;
115 static void die(char *msg, ...) NONRET;
116 static void sample_mem_peak(void);
116 static void sample_mem_peak(void);
117
117
118 /*** Meta-files ***/
118 /*** Meta-files ***/
119
119
120 static FILE *metafile;
120 static FILE *metafile;
121
121
122 static void
122 static void
123 meta_open(const char *name)
123 meta_open(const char *name)
124 {
124 {
125 if (!strcmp(name, "-"))
125 if (!strcmp(name, "-"))
126 {
126 {
127 metafile = stdout;
127 metafile = stdout;
128 return;
128 return;
129 }
129 }
130 metafile = fopen(name, "w");
130 metafile = fopen(name, "w");
131 if (!metafile)
131 if (!metafile)
132 die("Failed to open metafile '%s'",name);
132 die("Failed to open metafile '%s'",name);
133 }
133 }
134
134
135 static void
135 static void
136 meta_close(void)
136 meta_close(void)
137 {
137 {
138 if (metafile && metafile != stdout)
138 if (metafile && metafile != stdout)
139 fclose(metafile);
139 fclose(metafile);
140 }
140 }
141
141
142 static void __attribute__((format(printf,1,2)))
142 static void __attribute__((format(printf,1,2)))
143 meta_printf(const char *fmt, ...)
143 meta_printf(const char *fmt, ...)
144 {
144 {
145 if (!metafile)
145 if (!metafile)
146 return;
146 return;
147
147
148 va_list args;
148 va_list args;
149 va_start(args, fmt);
149 va_start(args, fmt);
150 vfprintf(metafile, fmt, args);
150 vfprintf(metafile, fmt, args);
151 va_end(args);
151 va_end(args);
152 }
152 }
153
153
154
154
155 static void print_running_stat(double wall_time,
155 static void print_running_stat(double wall_time,
156 double user_time,
156 double user_time,
157 double system_time,
157 double system_time,
158 int mem_usage)
158 int mem_usage)
159 {
159 {
160 //total is user
160 //total is user
161 //wall is wall
161 //wall is wall
162 //
162 //
163 fprintf(stderr,"%.4lfr%.4lfu%.4lfs%dkbytes\n",
163 fprintf(stderr,"%.4lfr%.4lfu%.4lfs%dkbytes\n",
164 wall_time, user_time, system_time, mem_usage);
164 wall_time, user_time, system_time, mem_usage);
165 }
165 }
166
166
167 static void
167 static void
168 final_stats(struct rusage *rus)
168 final_stats(struct rusage *rus)
169 {
169 {
170 struct timeval total, now, wall;
170 struct timeval total, now, wall;
171 timeradd(&rus->ru_utime, &rus->ru_stime, &total);
171 timeradd(&rus->ru_utime, &rus->ru_stime, &total);
172 total_ms = total.tv_sec*1000 + total.tv_usec/1000;
172 total_ms = total.tv_sec*1000 + total.tv_usec/1000;
173 gettimeofday(&now, NULL);
173 gettimeofday(&now, NULL);
174 timersub(&now, &start_time, &wall);
174 timersub(&now, &start_time, &wall);
175 wall_ms = wall.tv_sec*1000 + wall.tv_usec/1000;
175 wall_ms = wall.tv_sec*1000 + wall.tv_usec/1000;
176 sys_ms = rus->ru_stime.tv_sec * 1000 + rus->ru_stime.tv_usec / 1000;
176 sys_ms = rus->ru_stime.tv_sec * 1000 + rus->ru_stime.tv_usec / 1000;
177
177
178 meta_printf("time:%d.%03d\n", total_ms/1000, total_ms%1000);
178 meta_printf("time:%d.%03d\n", total_ms/1000, total_ms%1000);
179 meta_printf("time-wall:%d.%03d\n", wall_ms/1000, wall_ms%1000);
179 meta_printf("time-wall:%d.%03d\n", wall_ms/1000, wall_ms%1000);
180 meta_printf("mem:%llu\n", (unsigned long long) mem_peak_kb * 1024);
180 meta_printf("mem:%llu\n", (unsigned long long) mem_peak_kb * 1024);
181 }
181 }
182
182
183 /*** Messages and exits ***/
183 /*** Messages and exits ***/
184
184
185 static void NONRET
185 static void NONRET
186 box_exit(int rc)
186 box_exit(int rc)
187 {
187 {
188 if (box_pid > 0)
188 if (box_pid > 0)
189 {
189 {
190 sample_mem_peak();
190 sample_mem_peak();
191 if (is_ptraced)
191 if (is_ptraced)
192 ptrace(PTRACE_KILL, box_pid);
192 ptrace(PTRACE_KILL, box_pid);
193 kill(-box_pid, SIGKILL);
193 kill(-box_pid, SIGKILL);
194 kill(box_pid, SIGKILL);
194 kill(box_pid, SIGKILL);
195 meta_printf("killed:1\n");
195 meta_printf("killed:1\n");
196
196
197 struct rusage rus;
197 struct rusage rus;
198 int p, stat;
198 int p, stat;
199 do
199 do
200 p = wait4(box_pid, &stat, 0, &rus);
200 p = wait4(box_pid, &stat, 0, &rus);
201 while (p < 0 && errno == EINTR);
201 while (p < 0 && errno == EINTR);
202 if (p < 0)
202 if (p < 0)
203 fprintf(stderr, "UGH: Lost track of the process (%m)\n");
203 fprintf(stderr, "UGH: Lost track of the process (%m)\n");
204 else {
204 else {
205 final_stats(&rus);
205 final_stats(&rus);
206 }
206 }
207 }
207 }
208 print_running_stat(
208 print_running_stat(
209 (double)wall_ms/1000,
209 (double)wall_ms/1000,
210 (double)total_ms/1000,
210 (double)total_ms/1000,
211 (double)sys_ms/1000,
211 (double)sys_ms/1000,
212 mem_peak_kb);
212 mem_peak_kb);
213 meta_close();
213 meta_close();
214 exit(rc);
214 exit(rc);
215 }
215 }
216
216
217 static void
217 static void
218 flush_line(void)
218 flush_line(void)
219 {
219 {
220 if (partial_line)
220 if (partial_line)
221 fputc('\n', stderr);
221 fputc('\n', stderr);
222 partial_line = 0;
222 partial_line = 0;
223 }
223 }
224
224
225 /* Report an error of the sandbox itself */
225 /* Report an error of the sandbox itself */
226 static void NONRET __attribute__((format(printf,1,2)))
226 static void NONRET __attribute__((format(printf,1,2)))
227 die(char *msg, ...)
227 die(char *msg, ...)
228 {
228 {
229 va_list args;
229 va_list args;
230 va_start(args, msg);
230 va_start(args, msg);
231 flush_line();
231 flush_line();
232 char buf[1024];
232 char buf[1024];
233 vsnprintf(buf, sizeof(buf), msg, args);
233 vsnprintf(buf, sizeof(buf), msg, args);
234 meta_printf("status:XX\nmessage:%s\n", buf);
234 meta_printf("status:XX\nmessage:%s\n", buf);
235 fputs(buf, stderr);
235 fputs(buf, stderr);
236 fputc('\n', stderr);
236 fputc('\n', stderr);
237 box_exit(2);
237 box_exit(2);
238 }
238 }
239
239
240 /* Report an error of the program inside the sandbox */
240 /* Report an error of the program inside the sandbox */
241 static void NONRET __attribute__((format(printf,1,2)))
241 static void NONRET __attribute__((format(printf,1,2)))
242 err(char *msg, ...)
242 err(char *msg, ...)
243 {
243 {
244 va_list args;
244 va_list args;
245 va_start(args, msg);
245 va_start(args, msg);
246 flush_line();
246 flush_line();
247 if (msg[0] && msg[1] && msg[2] == ':' && msg[3] == ' ')
247 if (msg[0] && msg[1] && msg[2] == ':' && msg[3] == ' ')
248 {
248 {
249 meta_printf("status:%c%c\n", msg[0], msg[1]);
249 meta_printf("status:%c%c\n", msg[0], msg[1]);
250 msg += 4;
250 msg += 4;
251 }
251 }
252 char buf[1024];
252 char buf[1024];
253 vsnprintf(buf, sizeof(buf), msg, args);
253 vsnprintf(buf, sizeof(buf), msg, args);
254 meta_printf("message:%s\n", buf);
254 meta_printf("message:%s\n", buf);
255 fputs(buf, stderr);
255 fputs(buf, stderr);
256 fputc('\n', stderr);
256 fputc('\n', stderr);
257 box_exit(1);
257 box_exit(1);
258 }
258 }
259
259
260 /* Write a message, but only if in verbose mode */
260 /* Write a message, but only if in verbose mode */
261 static void __attribute__((format(printf,1,2)))
261 static void __attribute__((format(printf,1,2)))
262 msg(char *msg, ...)
262 msg(char *msg, ...)
263 {
263 {
264 va_list args;
264 va_list args;
265 va_start(args, msg);
265 va_start(args, msg);
266 if (verbose)
266 if (verbose)
267 {
267 {
268 int len = strlen(msg);
268 int len = strlen(msg);
269 if (len > 0)
269 if (len > 0)
270 partial_line = (msg[len-1] != '\n');
270 partial_line = (msg[len-1] != '\n');
271 vfprintf(stderr, msg, args);
271 vfprintf(stderr, msg, args);
272 fflush(stderr);
272 fflush(stderr);
273 }
273 }
274 va_end(args);
274 va_end(args);
275 }
275 }
276
276
277 static void *
277 static void *
278 xmalloc(size_t size)
278 xmalloc(size_t size)
279 {
279 {
280 void *p = malloc(size);
280 void *p = malloc(size);
281 if (!p)
281 if (!p)
282 die("Out of memory");
282 die("Out of memory");
283 return p;
283 return p;
284 }
284 }
285
285
286 /*** Syscall rules ***/
286 /*** Syscall rules ***/
287
287
288 static const char * const syscall_names[] = {
288 static const char * const syscall_names[] = {
289
289
290 /* Syscall table automatically generated by mk-syscall-table */
290 /* Syscall table automatically generated by mk-syscall-table */
291
291
292 /* 0 */ [ __NR_read ] = "read",
292 /* 0 */ [ __NR_read ] = "read",
293 /* 1 */ [ __NR_write ] = "write",
293 /* 1 */ [ __NR_write ] = "write",
294 /* 2 */ [ __NR_open ] = "open",
294 /* 2 */ [ __NR_open ] = "open",
295 /* 3 */ [ __NR_close ] = "close",
295 /* 3 */ [ __NR_close ] = "close",
296 /* 4 */ [ __NR_stat ] = "stat",
296 /* 4 */ [ __NR_stat ] = "stat",
297 /* 5 */ [ __NR_fstat ] = "fstat",
297 /* 5 */ [ __NR_fstat ] = "fstat",
298 /* 6 */ [ __NR_lstat ] = "lstat",
298 /* 6 */ [ __NR_lstat ] = "lstat",
299 /* 7 */ [ __NR_poll ] = "poll",
299 /* 7 */ [ __NR_poll ] = "poll",
300 /* 8 */ [ __NR_lseek ] = "lseek",
300 /* 8 */ [ __NR_lseek ] = "lseek",
301 /* 9 */ [ __NR_mmap ] = "mmap",
301 /* 9 */ [ __NR_mmap ] = "mmap",
302 /* 10 */ [ __NR_mprotect ] = "mprotect",
302 /* 10 */ [ __NR_mprotect ] = "mprotect",
303 /* 11 */ [ __NR_munmap ] = "munmap",
303 /* 11 */ [ __NR_munmap ] = "munmap",
304 /* 12 */ [ __NR_brk ] = "brk",
304 /* 12 */ [ __NR_brk ] = "brk",
305 /* 13 */ [ __NR_rt_sigaction ] = "rt_sigaction",
305 /* 13 */ [ __NR_rt_sigaction ] = "rt_sigaction",
306 /* 14 */ [ __NR_rt_sigprocmask ] = "rt_sigprocmask",
306 /* 14 */ [ __NR_rt_sigprocmask ] = "rt_sigprocmask",
307 /* 15 */ [ __NR_rt_sigreturn ] = "rt_sigreturn",
307 /* 15 */ [ __NR_rt_sigreturn ] = "rt_sigreturn",
308 /* 16 */ [ __NR_ioctl ] = "ioctl",
308 /* 16 */ [ __NR_ioctl ] = "ioctl",
309 /* 17 */ [ __NR_pread64 ] = "pread64",
309 /* 17 */ [ __NR_pread64 ] = "pread64",
310 /* 18 */ [ __NR_pwrite64 ] = "pwrite64",
310 /* 18 */ [ __NR_pwrite64 ] = "pwrite64",
311 /* 19 */ [ __NR_readv ] = "readv",
311 /* 19 */ [ __NR_readv ] = "readv",
312 /* 20 */ [ __NR_writev ] = "writev",
312 /* 20 */ [ __NR_writev ] = "writev",
313 /* 21 */ [ __NR_access ] = "access",
313 /* 21 */ [ __NR_access ] = "access",
314 /* 22 */ [ __NR_pipe ] = "pipe",
314 /* 22 */ [ __NR_pipe ] = "pipe",
315 /* 23 */ [ __NR_select ] = "select",
315 /* 23 */ [ __NR_select ] = "select",
316 /* 24 */ [ __NR_sched_yield ] = "sched_yield",
316 /* 24 */ [ __NR_sched_yield ] = "sched_yield",
317 /* 25 */ [ __NR_mremap ] = "mremap",
317 /* 25 */ [ __NR_mremap ] = "mremap",
318 /* 26 */ [ __NR_msync ] = "msync",
318 /* 26 */ [ __NR_msync ] = "msync",
319 /* 27 */ [ __NR_mincore ] = "mincore",
319 /* 27 */ [ __NR_mincore ] = "mincore",
320 /* 28 */ [ __NR_madvise ] = "madvise",
320 /* 28 */ [ __NR_madvise ] = "madvise",
321 /* 29 */ [ __NR_shmget ] = "shmget",
321 /* 29 */ [ __NR_shmget ] = "shmget",
322 /* 30 */ [ __NR_shmat ] = "shmat",
322 /* 30 */ [ __NR_shmat ] = "shmat",
323 /* 31 */ [ __NR_shmctl ] = "shmctl",
323 /* 31 */ [ __NR_shmctl ] = "shmctl",
324 /* 32 */ [ __NR_dup ] = "dup",
324 /* 32 */ [ __NR_dup ] = "dup",
325 /* 33 */ [ __NR_dup2 ] = "dup2",
325 /* 33 */ [ __NR_dup2 ] = "dup2",
326 /* 34 */ [ __NR_pause ] = "pause",
326 /* 34 */ [ __NR_pause ] = "pause",
327 /* 35 */ [ __NR_nanosleep ] = "nanosleep",
327 /* 35 */ [ __NR_nanosleep ] = "nanosleep",
328 /* 36 */ [ __NR_getitimer ] = "getitimer",
328 /* 36 */ [ __NR_getitimer ] = "getitimer",
329 /* 37 */ [ __NR_alarm ] = "alarm",
329 /* 37 */ [ __NR_alarm ] = "alarm",
330 /* 38 */ [ __NR_setitimer ] = "setitimer",
330 /* 38 */ [ __NR_setitimer ] = "setitimer",
331 /* 39 */ [ __NR_getpid ] = "getpid",
331 /* 39 */ [ __NR_getpid ] = "getpid",
332 /* 40 */ [ __NR_sendfile ] = "sendfile",
332 /* 40 */ [ __NR_sendfile ] = "sendfile",
333 /* 41 */ [ __NR_socket ] = "socket",
333 /* 41 */ [ __NR_socket ] = "socket",
334 /* 42 */ [ __NR_connect ] = "connect",
334 /* 42 */ [ __NR_connect ] = "connect",
335 /* 43 */ [ __NR_accept ] = "accept",
335 /* 43 */ [ __NR_accept ] = "accept",
336 /* 44 */ [ __NR_sendto ] = "sendto",
336 /* 44 */ [ __NR_sendto ] = "sendto",
337 /* 45 */ [ __NR_recvfrom ] = "recvfrom",
337 /* 45 */ [ __NR_recvfrom ] = "recvfrom",
338 /* 46 */ [ __NR_sendmsg ] = "sendmsg",
338 /* 46 */ [ __NR_sendmsg ] = "sendmsg",
339 /* 47 */ [ __NR_recvmsg ] = "recvmsg",
339 /* 47 */ [ __NR_recvmsg ] = "recvmsg",
340 /* 48 */ [ __NR_shutdown ] = "shutdown",
340 /* 48 */ [ __NR_shutdown ] = "shutdown",
341 /* 49 */ [ __NR_bind ] = "bind",
341 /* 49 */ [ __NR_bind ] = "bind",
342 /* 50 */ [ __NR_listen ] = "listen",
342 /* 50 */ [ __NR_listen ] = "listen",
343 /* 51 */ [ __NR_getsockname ] = "getsockname",
343 /* 51 */ [ __NR_getsockname ] = "getsockname",
344 /* 52 */ [ __NR_getpeername ] = "getpeername",
344 /* 52 */ [ __NR_getpeername ] = "getpeername",
345 /* 53 */ [ __NR_socketpair ] = "socketpair",
345 /* 53 */ [ __NR_socketpair ] = "socketpair",
346 /* 54 */ [ __NR_setsockopt ] = "setsockopt",
346 /* 54 */ [ __NR_setsockopt ] = "setsockopt",
347 /* 55 */ [ __NR_getsockopt ] = "getsockopt",
347 /* 55 */ [ __NR_getsockopt ] = "getsockopt",
348 /* 56 */ [ __NR_clone ] = "clone",
348 /* 56 */ [ __NR_clone ] = "clone",
349 /* 57 */ [ __NR_fork ] = "fork",
349 /* 57 */ [ __NR_fork ] = "fork",
350 /* 58 */ [ __NR_vfork ] = "vfork",
350 /* 58 */ [ __NR_vfork ] = "vfork",
351 /* 59 */ [ __NR_execve ] = "execve",
351 /* 59 */ [ __NR_execve ] = "execve",
352 /* 60 */ [ __NR_exit ] = "exit",
352 /* 60 */ [ __NR_exit ] = "exit",
353 /* 61 */ [ __NR_wait4 ] = "wait4",
353 /* 61 */ [ __NR_wait4 ] = "wait4",
354 /* 62 */ [ __NR_kill ] = "kill",
354 /* 62 */ [ __NR_kill ] = "kill",
355 /* 63 */ [ __NR_uname ] = "uname",
355 /* 63 */ [ __NR_uname ] = "uname",
356 /* 64 */ [ __NR_semget ] = "semget",
356 /* 64 */ [ __NR_semget ] = "semget",
357 /* 65 */ [ __NR_semop ] = "semop",
357 /* 65 */ [ __NR_semop ] = "semop",
358 /* 66 */ [ __NR_semctl ] = "semctl",
358 /* 66 */ [ __NR_semctl ] = "semctl",
359 /* 67 */ [ __NR_shmdt ] = "shmdt",
359 /* 67 */ [ __NR_shmdt ] = "shmdt",
360 /* 68 */ [ __NR_msgget ] = "msgget",
360 /* 68 */ [ __NR_msgget ] = "msgget",
361 /* 69 */ [ __NR_msgsnd ] = "msgsnd",
361 /* 69 */ [ __NR_msgsnd ] = "msgsnd",
362 /* 70 */ [ __NR_msgrcv ] = "msgrcv",
362 /* 70 */ [ __NR_msgrcv ] = "msgrcv",
363 /* 71 */ [ __NR_msgctl ] = "msgctl",
363 /* 71 */ [ __NR_msgctl ] = "msgctl",
364 /* 72 */ [ __NR_fcntl ] = "fcntl",
364 /* 72 */ [ __NR_fcntl ] = "fcntl",
365 /* 73 */ [ __NR_flock ] = "flock",
365 /* 73 */ [ __NR_flock ] = "flock",
366 /* 74 */ [ __NR_fsync ] = "fsync",
366 /* 74 */ [ __NR_fsync ] = "fsync",
367 /* 75 */ [ __NR_fdatasync ] = "fdatasync",
367 /* 75 */ [ __NR_fdatasync ] = "fdatasync",
368 /* 76 */ [ __NR_truncate ] = "truncate",
368 /* 76 */ [ __NR_truncate ] = "truncate",
369 /* 77 */ [ __NR_ftruncate ] = "ftruncate",
369 /* 77 */ [ __NR_ftruncate ] = "ftruncate",
370 /* 78 */ [ __NR_getdents ] = "getdents",
370 /* 78 */ [ __NR_getdents ] = "getdents",
371 /* 79 */ [ __NR_getcwd ] = "getcwd",
371 /* 79 */ [ __NR_getcwd ] = "getcwd",
372 /* 80 */ [ __NR_chdir ] = "chdir",
372 /* 80 */ [ __NR_chdir ] = "chdir",
373 /* 81 */ [ __NR_fchdir ] = "fchdir",
373 /* 81 */ [ __NR_fchdir ] = "fchdir",
374 /* 82 */ [ __NR_rename ] = "rename",
374 /* 82 */ [ __NR_rename ] = "rename",
375 /* 83 */ [ __NR_mkdir ] = "mkdir",
375 /* 83 */ [ __NR_mkdir ] = "mkdir",
376 /* 84 */ [ __NR_rmdir ] = "rmdir",
376 /* 84 */ [ __NR_rmdir ] = "rmdir",
377 /* 85 */ [ __NR_creat ] = "creat",
377 /* 85 */ [ __NR_creat ] = "creat",
378 /* 86 */ [ __NR_link ] = "link",
378 /* 86 */ [ __NR_link ] = "link",
379 /* 87 */ [ __NR_unlink ] = "unlink",
379 /* 87 */ [ __NR_unlink ] = "unlink",
380 /* 88 */ [ __NR_symlink ] = "symlink",
380 /* 88 */ [ __NR_symlink ] = "symlink",
381 /* 89 */ [ __NR_readlink ] = "readlink",
381 /* 89 */ [ __NR_readlink ] = "readlink",
382 /* 90 */ [ __NR_chmod ] = "chmod",
382 /* 90 */ [ __NR_chmod ] = "chmod",
383 /* 91 */ [ __NR_fchmod ] = "fchmod",
383 /* 91 */ [ __NR_fchmod ] = "fchmod",
384 /* 92 */ [ __NR_chown ] = "chown",
384 /* 92 */ [ __NR_chown ] = "chown",
385 /* 93 */ [ __NR_fchown ] = "fchown",
385 /* 93 */ [ __NR_fchown ] = "fchown",
386 /* 94 */ [ __NR_lchown ] = "lchown",
386 /* 94 */ [ __NR_lchown ] = "lchown",
387 /* 95 */ [ __NR_umask ] = "umask",
387 /* 95 */ [ __NR_umask ] = "umask",
388 /* 96 */ [ __NR_gettimeofday ] = "gettimeofday",
388 /* 96 */ [ __NR_gettimeofday ] = "gettimeofday",
389 /* 97 */ [ __NR_getrlimit ] = "getrlimit",
389 /* 97 */ [ __NR_getrlimit ] = "getrlimit",
390 /* 98 */ [ __NR_getrusage ] = "getrusage",
390 /* 98 */ [ __NR_getrusage ] = "getrusage",
391 /* 99 */ [ __NR_sysinfo ] = "sysinfo",
391 /* 99 */ [ __NR_sysinfo ] = "sysinfo",
392 /* 100 */ [ __NR_times ] = "times",
392 /* 100 */ [ __NR_times ] = "times",
393 /* 101 */ [ __NR_ptrace ] = "ptrace",
393 /* 101 */ [ __NR_ptrace ] = "ptrace",
394 /* 102 */ [ __NR_getuid ] = "getuid",
394 /* 102 */ [ __NR_getuid ] = "getuid",
395 /* 103 */ [ __NR_syslog ] = "syslog",
395 /* 103 */ [ __NR_syslog ] = "syslog",
396 /* 104 */ [ __NR_getgid ] = "getgid",
396 /* 104 */ [ __NR_getgid ] = "getgid",
397 /* 105 */ [ __NR_setuid ] = "setuid",
397 /* 105 */ [ __NR_setuid ] = "setuid",
398 /* 106 */ [ __NR_setgid ] = "setgid",
398 /* 106 */ [ __NR_setgid ] = "setgid",
399 /* 107 */ [ __NR_geteuid ] = "geteuid",
399 /* 107 */ [ __NR_geteuid ] = "geteuid",
400 /* 108 */ [ __NR_getegid ] = "getegid",
400 /* 108 */ [ __NR_getegid ] = "getegid",
401 /* 109 */ [ __NR_setpgid ] = "setpgid",
401 /* 109 */ [ __NR_setpgid ] = "setpgid",
402 /* 110 */ [ __NR_getppid ] = "getppid",
402 /* 110 */ [ __NR_getppid ] = "getppid",
403 /* 111 */ [ __NR_getpgrp ] = "getpgrp",
403 /* 111 */ [ __NR_getpgrp ] = "getpgrp",
404 /* 112 */ [ __NR_setsid ] = "setsid",
404 /* 112 */ [ __NR_setsid ] = "setsid",
405 /* 113 */ [ __NR_setreuid ] = "setreuid",
405 /* 113 */ [ __NR_setreuid ] = "setreuid",
406 /* 114 */ [ __NR_setregid ] = "setregid",
406 /* 114 */ [ __NR_setregid ] = "setregid",
407 /* 115 */ [ __NR_getgroups ] = "getgroups",
407 /* 115 */ [ __NR_getgroups ] = "getgroups",
408 /* 116 */ [ __NR_setgroups ] = "setgroups",
408 /* 116 */ [ __NR_setgroups ] = "setgroups",
409 /* 117 */ [ __NR_setresuid ] = "setresuid",
409 /* 117 */ [ __NR_setresuid ] = "setresuid",
410 /* 118 */ [ __NR_getresuid ] = "getresuid",
410 /* 118 */ [ __NR_getresuid ] = "getresuid",
411 /* 119 */ [ __NR_setresgid ] = "setresgid",
411 /* 119 */ [ __NR_setresgid ] = "setresgid",
412 /* 120 */ [ __NR_getresgid ] = "getresgid",
412 /* 120 */ [ __NR_getresgid ] = "getresgid",
413 /* 121 */ [ __NR_getpgid ] = "getpgid",
413 /* 121 */ [ __NR_getpgid ] = "getpgid",
414 /* 122 */ [ __NR_setfsuid ] = "setfsuid",
414 /* 122 */ [ __NR_setfsuid ] = "setfsuid",
415 /* 123 */ [ __NR_setfsgid ] = "setfsgid",
415 /* 123 */ [ __NR_setfsgid ] = "setfsgid",
416 /* 124 */ [ __NR_getsid ] = "getsid",
416 /* 124 */ [ __NR_getsid ] = "getsid",
417 /* 125 */ [ __NR_capget ] = "capget",
417 /* 125 */ [ __NR_capget ] = "capget",
418 /* 126 */ [ __NR_capset ] = "capset",
418 /* 126 */ [ __NR_capset ] = "capset",
419 /* 127 */ [ __NR_rt_sigpending ] = "rt_sigpending",
419 /* 127 */ [ __NR_rt_sigpending ] = "rt_sigpending",
420 /* 128 */ [ __NR_rt_sigtimedwait ] = "rt_sigtimedwait",
420 /* 128 */ [ __NR_rt_sigtimedwait ] = "rt_sigtimedwait",
421 /* 129 */ [ __NR_rt_sigqueueinfo ] = "rt_sigqueueinfo",
421 /* 129 */ [ __NR_rt_sigqueueinfo ] = "rt_sigqueueinfo",
422 /* 130 */ [ __NR_rt_sigsuspend ] = "rt_sigsuspend",
422 /* 130 */ [ __NR_rt_sigsuspend ] = "rt_sigsuspend",
423 /* 131 */ [ __NR_sigaltstack ] = "sigaltstack",
423 /* 131 */ [ __NR_sigaltstack ] = "sigaltstack",
424 /* 132 */ [ __NR_utime ] = "utime",
424 /* 132 */ [ __NR_utime ] = "utime",
425 /* 133 */ [ __NR_mknod ] = "mknod",
425 /* 133 */ [ __NR_mknod ] = "mknod",
426 /* 134 */ [ __NR_uselib ] = "uselib",
426 /* 134 */ [ __NR_uselib ] = "uselib",
427 /* 135 */ [ __NR_personality ] = "personality",
427 /* 135 */ [ __NR_personality ] = "personality",
428 /* 136 */ [ __NR_ustat ] = "ustat",
428 /* 136 */ [ __NR_ustat ] = "ustat",
429 /* 137 */ [ __NR_statfs ] = "statfs",
429 /* 137 */ [ __NR_statfs ] = "statfs",
430 /* 138 */ [ __NR_fstatfs ] = "fstatfs",
430 /* 138 */ [ __NR_fstatfs ] = "fstatfs",
431 /* 139 */ [ __NR_sysfs ] = "sysfs",
431 /* 139 */ [ __NR_sysfs ] = "sysfs",
432 /* 140 */ [ __NR_getpriority ] = "getpriority",
432 /* 140 */ [ __NR_getpriority ] = "getpriority",
433 /* 141 */ [ __NR_setpriority ] = "setpriority",
433 /* 141 */ [ __NR_setpriority ] = "setpriority",
434 /* 142 */ [ __NR_sched_setparam ] = "sched_setparam",
434 /* 142 */ [ __NR_sched_setparam ] = "sched_setparam",
435 /* 143 */ [ __NR_sched_getparam ] = "sched_getparam",
435 /* 143 */ [ __NR_sched_getparam ] = "sched_getparam",
436 /* 144 */ [ __NR_sched_setscheduler ] = "sched_setscheduler",
436 /* 144 */ [ __NR_sched_setscheduler ] = "sched_setscheduler",
437 /* 145 */ [ __NR_sched_getscheduler ] = "sched_getscheduler",
437 /* 145 */ [ __NR_sched_getscheduler ] = "sched_getscheduler",
438 /* 146 */ [ __NR_sched_get_priority_max ] = "sched_get_priority_max",
438 /* 146 */ [ __NR_sched_get_priority_max ] = "sched_get_priority_max",
439 /* 147 */ [ __NR_sched_get_priority_min ] = "sched_get_priority_min",
439 /* 147 */ [ __NR_sched_get_priority_min ] = "sched_get_priority_min",
440 /* 148 */ [ __NR_sched_rr_get_interval ] = "sched_rr_get_interval",
440 /* 148 */ [ __NR_sched_rr_get_interval ] = "sched_rr_get_interval",
441 /* 149 */ [ __NR_mlock ] = "mlock",
441 /* 149 */ [ __NR_mlock ] = "mlock",
442 /* 150 */ [ __NR_munlock ] = "munlock",
442 /* 150 */ [ __NR_munlock ] = "munlock",
443 /* 151 */ [ __NR_mlockall ] = "mlockall",
443 /* 151 */ [ __NR_mlockall ] = "mlockall",
444 /* 152 */ [ __NR_munlockall ] = "munlockall",
444 /* 152 */ [ __NR_munlockall ] = "munlockall",
445 /* 153 */ [ __NR_vhangup ] = "vhangup",
445 /* 153 */ [ __NR_vhangup ] = "vhangup",
446 /* 154 */ [ __NR_modify_ldt ] = "modify_ldt",
446 /* 154 */ [ __NR_modify_ldt ] = "modify_ldt",
447 /* 155 */ [ __NR_pivot_root ] = "pivot_root",
447 /* 155 */ [ __NR_pivot_root ] = "pivot_root",
448 /* 156 */ [ __NR__sysctl ] = "_sysctl",
448 /* 156 */ [ __NR__sysctl ] = "_sysctl",
449 /* 157 */ [ __NR_prctl ] = "prctl",
449 /* 157 */ [ __NR_prctl ] = "prctl",
450 /* 158 */ [ __NR_arch_prctl ] = "arch_prctl",
450 /* 158 */ [ __NR_arch_prctl ] = "arch_prctl",
451 /* 159 */ [ __NR_adjtimex ] = "adjtimex",
451 /* 159 */ [ __NR_adjtimex ] = "adjtimex",
452 /* 160 */ [ __NR_setrlimit ] = "setrlimit",
452 /* 160 */ [ __NR_setrlimit ] = "setrlimit",
453 /* 161 */ [ __NR_chroot ] = "chroot",
453 /* 161 */ [ __NR_chroot ] = "chroot",
454 /* 162 */ [ __NR_sync ] = "sync",
454 /* 162 */ [ __NR_sync ] = "sync",
455 /* 163 */ [ __NR_acct ] = "acct",
455 /* 163 */ [ __NR_acct ] = "acct",
456 /* 164 */ [ __NR_settimeofday ] = "settimeofday",
456 /* 164 */ [ __NR_settimeofday ] = "settimeofday",
457 /* 165 */ [ __NR_mount ] = "mount",
457 /* 165 */ [ __NR_mount ] = "mount",
458 /* 166 */ [ __NR_umount2 ] = "umount2",
458 /* 166 */ [ __NR_umount2 ] = "umount2",
459 /* 167 */ [ __NR_swapon ] = "swapon",
459 /* 167 */ [ __NR_swapon ] = "swapon",
460 /* 168 */ [ __NR_swapoff ] = "swapoff",
460 /* 168 */ [ __NR_swapoff ] = "swapoff",
461 /* 169 */ [ __NR_reboot ] = "reboot",
461 /* 169 */ [ __NR_reboot ] = "reboot",
462 /* 170 */ [ __NR_sethostname ] = "sethostname",
462 /* 170 */ [ __NR_sethostname ] = "sethostname",
463 /* 171 */ [ __NR_setdomainname ] = "setdomainname",
463 /* 171 */ [ __NR_setdomainname ] = "setdomainname",
464 /* 172 */ [ __NR_iopl ] = "iopl",
464 /* 172 */ [ __NR_iopl ] = "iopl",
465 /* 173 */ [ __NR_ioperm ] = "ioperm",
465 /* 173 */ [ __NR_ioperm ] = "ioperm",
466 /* 174 */ [ __NR_create_module ] = "create_module",
466 /* 174 */ [ __NR_create_module ] = "create_module",
467 /* 175 */ [ __NR_init_module ] = "init_module",
467 /* 175 */ [ __NR_init_module ] = "init_module",
468 /* 176 */ [ __NR_delete_module ] = "delete_module",
468 /* 176 */ [ __NR_delete_module ] = "delete_module",
469 /* 177 */ [ __NR_get_kernel_syms ] = "get_kernel_syms",
469 /* 177 */ [ __NR_get_kernel_syms ] = "get_kernel_syms",
470 /* 178 */ [ __NR_query_module ] = "query_module",
470 /* 178 */ [ __NR_query_module ] = "query_module",
471 /* 179 */ [ __NR_quotactl ] = "quotactl",
471 /* 179 */ [ __NR_quotactl ] = "quotactl",
472 /* 180 */ [ __NR_nfsservctl ] = "nfsservctl",
472 /* 180 */ [ __NR_nfsservctl ] = "nfsservctl",
473 /* 181 */ [ __NR_getpmsg ] = "getpmsg",
473 /* 181 */ [ __NR_getpmsg ] = "getpmsg",
474 /* 182 */ [ __NR_putpmsg ] = "putpmsg",
474 /* 182 */ [ __NR_putpmsg ] = "putpmsg",
475 /* 183 */ [ __NR_afs_syscall ] = "afs_syscall",
475 /* 183 */ [ __NR_afs_syscall ] = "afs_syscall",
476 /* 184 */ [ __NR_tuxcall ] = "tuxcall",
476 /* 184 */ [ __NR_tuxcall ] = "tuxcall",
477 /* 185 */ [ __NR_security ] = "security",
477 /* 185 */ [ __NR_security ] = "security",
478 /* 186 */ [ __NR_gettid ] = "gettid",
478 /* 186 */ [ __NR_gettid ] = "gettid",
479 /* 187 */ [ __NR_readahead ] = "readahead",
479 /* 187 */ [ __NR_readahead ] = "readahead",
480 /* 188 */ [ __NR_setxattr ] = "setxattr",
480 /* 188 */ [ __NR_setxattr ] = "setxattr",
481 /* 189 */ [ __NR_lsetxattr ] = "lsetxattr",
481 /* 189 */ [ __NR_lsetxattr ] = "lsetxattr",
482 /* 190 */ [ __NR_fsetxattr ] = "fsetxattr",
482 /* 190 */ [ __NR_fsetxattr ] = "fsetxattr",
483 /* 191 */ [ __NR_getxattr ] = "getxattr",
483 /* 191 */ [ __NR_getxattr ] = "getxattr",
484 /* 192 */ [ __NR_lgetxattr ] = "lgetxattr",
484 /* 192 */ [ __NR_lgetxattr ] = "lgetxattr",
485 /* 193 */ [ __NR_fgetxattr ] = "fgetxattr",
485 /* 193 */ [ __NR_fgetxattr ] = "fgetxattr",
486 /* 194 */ [ __NR_listxattr ] = "listxattr",
486 /* 194 */ [ __NR_listxattr ] = "listxattr",
487 /* 195 */ [ __NR_llistxattr ] = "llistxattr",
487 /* 195 */ [ __NR_llistxattr ] = "llistxattr",
488 /* 196 */ [ __NR_flistxattr ] = "flistxattr",
488 /* 196 */ [ __NR_flistxattr ] = "flistxattr",
489 /* 197 */ [ __NR_removexattr ] = "removexattr",
489 /* 197 */ [ __NR_removexattr ] = "removexattr",
490 /* 198 */ [ __NR_lremovexattr ] = "lremovexattr",
490 /* 198 */ [ __NR_lremovexattr ] = "lremovexattr",
491 /* 199 */ [ __NR_fremovexattr ] = "fremovexattr",
491 /* 199 */ [ __NR_fremovexattr ] = "fremovexattr",
492 /* 200 */ [ __NR_tkill ] = "tkill",
492 /* 200 */ [ __NR_tkill ] = "tkill",
493 /* 201 */ [ __NR_time ] = "time",
493 /* 201 */ [ __NR_time ] = "time",
494 /* 202 */ [ __NR_futex ] = "futex",
494 /* 202 */ [ __NR_futex ] = "futex",
495 /* 203 */ [ __NR_sched_setaffinity ] = "sched_setaffinity",
495 /* 203 */ [ __NR_sched_setaffinity ] = "sched_setaffinity",
496 /* 204 */ [ __NR_sched_getaffinity ] = "sched_getaffinity",
496 /* 204 */ [ __NR_sched_getaffinity ] = "sched_getaffinity",
497 /* 205 */ [ __NR_set_thread_area ] = "set_thread_area",
497 /* 205 */ [ __NR_set_thread_area ] = "set_thread_area",
498 /* 206 */ [ __NR_io_setup ] = "io_setup",
498 /* 206 */ [ __NR_io_setup ] = "io_setup",
499 /* 207 */ [ __NR_io_destroy ] = "io_destroy",
499 /* 207 */ [ __NR_io_destroy ] = "io_destroy",
500 /* 208 */ [ __NR_io_getevents ] = "io_getevents",
500 /* 208 */ [ __NR_io_getevents ] = "io_getevents",
501 /* 209 */ [ __NR_io_submit ] = "io_submit",
501 /* 209 */ [ __NR_io_submit ] = "io_submit",
502 /* 210 */ [ __NR_io_cancel ] = "io_cancel",
502 /* 210 */ [ __NR_io_cancel ] = "io_cancel",
503 /* 211 */ [ __NR_get_thread_area ] = "get_thread_area",
503 /* 211 */ [ __NR_get_thread_area ] = "get_thread_area",
504 /* 212 */ [ __NR_lookup_dcookie ] = "lookup_dcookie",
504 /* 212 */ [ __NR_lookup_dcookie ] = "lookup_dcookie",
505 /* 213 */ [ __NR_epoll_create ] = "epoll_create",
505 /* 213 */ [ __NR_epoll_create ] = "epoll_create",
506 /* 214 */ [ __NR_epoll_ctl_old ] = "epoll_ctl_old",
506 /* 214 */ [ __NR_epoll_ctl_old ] = "epoll_ctl_old",
507 /* 215 */ [ __NR_epoll_wait_old ] = "epoll_wait_old",
507 /* 215 */ [ __NR_epoll_wait_old ] = "epoll_wait_old",
508 /* 216 */ [ __NR_remap_file_pages ] = "remap_file_pages",
508 /* 216 */ [ __NR_remap_file_pages ] = "remap_file_pages",
509 /* 217 */ [ __NR_getdents64 ] = "getdents64",
509 /* 217 */ [ __NR_getdents64 ] = "getdents64",
510 /* 218 */ [ __NR_set_tid_address ] = "set_tid_address",
510 /* 218 */ [ __NR_set_tid_address ] = "set_tid_address",
511 /* 219 */ [ __NR_restart_syscall ] = "restart_syscall",
511 /* 219 */ [ __NR_restart_syscall ] = "restart_syscall",
512 /* 220 */ [ __NR_semtimedop ] = "semtimedop",
512 /* 220 */ [ __NR_semtimedop ] = "semtimedop",
513 /* 221 */ [ __NR_fadvise64 ] = "fadvise64",
513 /* 221 */ [ __NR_fadvise64 ] = "fadvise64",
514 /* 222 */ [ __NR_timer_create ] = "timer_create",
514 /* 222 */ [ __NR_timer_create ] = "timer_create",
515 /* 223 */ [ __NR_timer_settime ] = "timer_settime",
515 /* 223 */ [ __NR_timer_settime ] = "timer_settime",
516 /* 224 */ [ __NR_timer_gettime ] = "timer_gettime",
516 /* 224 */ [ __NR_timer_gettime ] = "timer_gettime",
517 /* 225 */ [ __NR_timer_getoverrun ] = "timer_getoverrun",
517 /* 225 */ [ __NR_timer_getoverrun ] = "timer_getoverrun",
518 /* 226 */ [ __NR_timer_delete ] = "timer_delete",
518 /* 226 */ [ __NR_timer_delete ] = "timer_delete",
519 /* 227 */ [ __NR_clock_settime ] = "clock_settime",
519 /* 227 */ [ __NR_clock_settime ] = "clock_settime",
520 /* 228 */ [ __NR_clock_gettime ] = "clock_gettime",
520 /* 228 */ [ __NR_clock_gettime ] = "clock_gettime",
521 /* 229 */ [ __NR_clock_getres ] = "clock_getres",
521 /* 229 */ [ __NR_clock_getres ] = "clock_getres",
522 /* 230 */ [ __NR_clock_nanosleep ] = "clock_nanosleep",
522 /* 230 */ [ __NR_clock_nanosleep ] = "clock_nanosleep",
523 /* 231 */ [ __NR_exit_group ] = "exit_group",
523 /* 231 */ [ __NR_exit_group ] = "exit_group",
524 /* 232 */ [ __NR_epoll_wait ] = "epoll_wait",
524 /* 232 */ [ __NR_epoll_wait ] = "epoll_wait",
525 /* 233 */ [ __NR_epoll_ctl ] = "epoll_ctl",
525 /* 233 */ [ __NR_epoll_ctl ] = "epoll_ctl",
526 /* 234 */ [ __NR_tgkill ] = "tgkill",
526 /* 234 */ [ __NR_tgkill ] = "tgkill",
527 /* 235 */ [ __NR_utimes ] = "utimes",
527 /* 235 */ [ __NR_utimes ] = "utimes",
528 /* 236 */ [ __NR_vserver ] = "vserver",
528 /* 236 */ [ __NR_vserver ] = "vserver",
529 /* 237 */ [ __NR_mbind ] = "mbind",
529 /* 237 */ [ __NR_mbind ] = "mbind",
530 /* 238 */ [ __NR_set_mempolicy ] = "set_mempolicy",
530 /* 238 */ [ __NR_set_mempolicy ] = "set_mempolicy",
531 /* 239 */ [ __NR_get_mempolicy ] = "get_mempolicy",
531 /* 239 */ [ __NR_get_mempolicy ] = "get_mempolicy",
532 /* 240 */ [ __NR_mq_open ] = "mq_open",
532 /* 240 */ [ __NR_mq_open ] = "mq_open",
533 /* 241 */ [ __NR_mq_unlink ] = "mq_unlink",
533 /* 241 */ [ __NR_mq_unlink ] = "mq_unlink",
534 /* 242 */ [ __NR_mq_timedsend ] = "mq_timedsend",
534 /* 242 */ [ __NR_mq_timedsend ] = "mq_timedsend",
535 /* 243 */ [ __NR_mq_timedreceive ] = "mq_timedreceive",
535 /* 243 */ [ __NR_mq_timedreceive ] = "mq_timedreceive",
536 /* 244 */ [ __NR_mq_notify ] = "mq_notify",
536 /* 244 */ [ __NR_mq_notify ] = "mq_notify",
537 /* 245 */ [ __NR_mq_getsetattr ] = "mq_getsetattr",
537 /* 245 */ [ __NR_mq_getsetattr ] = "mq_getsetattr",
538 /* 246 */ [ __NR_kexec_load ] = "kexec_load",
538 /* 246 */ [ __NR_kexec_load ] = "kexec_load",
539 /* 247 */ [ __NR_waitid ] = "waitid",
539 /* 247 */ [ __NR_waitid ] = "waitid",
540 /* 248 */ [ __NR_add_key ] = "add_key",
540 /* 248 */ [ __NR_add_key ] = "add_key",
541 /* 249 */ [ __NR_request_key ] = "request_key",
541 /* 249 */ [ __NR_request_key ] = "request_key",
542 /* 250 */ [ __NR_keyctl ] = "keyctl",
542 /* 250 */ [ __NR_keyctl ] = "keyctl",
543 /* 251 */ [ __NR_ioprio_set ] = "ioprio_set",
543 /* 251 */ [ __NR_ioprio_set ] = "ioprio_set",
544 /* 252 */ [ __NR_ioprio_get ] = "ioprio_get",
544 /* 252 */ [ __NR_ioprio_get ] = "ioprio_get",
545 /* 253 */ [ __NR_inotify_init ] = "inotify_init",
545 /* 253 */ [ __NR_inotify_init ] = "inotify_init",
546 /* 254 */ [ __NR_inotify_add_watch ] = "inotify_add_watch",
546 /* 254 */ [ __NR_inotify_add_watch ] = "inotify_add_watch",
547 /* 255 */ [ __NR_inotify_rm_watch ] = "inotify_rm_watch",
547 /* 255 */ [ __NR_inotify_rm_watch ] = "inotify_rm_watch",
548 /* 256 */ [ __NR_migrate_pages ] = "migrate_pages",
548 /* 256 */ [ __NR_migrate_pages ] = "migrate_pages",
549 /* 257 */ [ __NR_openat ] = "openat",
549 /* 257 */ [ __NR_openat ] = "openat",
550 /* 258 */ [ __NR_mkdirat ] = "mkdirat",
550 /* 258 */ [ __NR_mkdirat ] = "mkdirat",
551 /* 259 */ [ __NR_mknodat ] = "mknodat",
551 /* 259 */ [ __NR_mknodat ] = "mknodat",
552 /* 260 */ [ __NR_fchownat ] = "fchownat",
552 /* 260 */ [ __NR_fchownat ] = "fchownat",
553 /* 261 */ [ __NR_futimesat ] = "futimesat",
553 /* 261 */ [ __NR_futimesat ] = "futimesat",
554 /* 262 */ [ __NR_newfstatat ] = "newfstatat",
554 /* 262 */ [ __NR_newfstatat ] = "newfstatat",
555 /* 263 */ [ __NR_unlinkat ] = "unlinkat",
555 /* 263 */ [ __NR_unlinkat ] = "unlinkat",
556 /* 264 */ [ __NR_renameat ] = "renameat",
556 /* 264 */ [ __NR_renameat ] = "renameat",
557 /* 265 */ [ __NR_linkat ] = "linkat",
557 /* 265 */ [ __NR_linkat ] = "linkat",
558 /* 266 */ [ __NR_symlinkat ] = "symlinkat",
558 /* 266 */ [ __NR_symlinkat ] = "symlinkat",
559 /* 267 */ [ __NR_readlinkat ] = "readlinkat",
559 /* 267 */ [ __NR_readlinkat ] = "readlinkat",
560 /* 268 */ [ __NR_fchmodat ] = "fchmodat",
560 /* 268 */ [ __NR_fchmodat ] = "fchmodat",
561 /* 269 */ [ __NR_faccessat ] = "faccessat",
561 /* 269 */ [ __NR_faccessat ] = "faccessat",
562 /* 270 */ [ __NR_pselect6 ] = "pselect6",
562 /* 270 */ [ __NR_pselect6 ] = "pselect6",
563 /* 271 */ [ __NR_ppoll ] = "ppoll",
563 /* 271 */ [ __NR_ppoll ] = "ppoll",
564 /* 272 */ [ __NR_unshare ] = "unshare",
564 /* 272 */ [ __NR_unshare ] = "unshare",
565 /* 273 */ [ __NR_set_robust_list ] = "set_robust_list",
565 /* 273 */ [ __NR_set_robust_list ] = "set_robust_list",
566 /* 274 */ [ __NR_get_robust_list ] = "get_robust_list",
566 /* 274 */ [ __NR_get_robust_list ] = "get_robust_list",
567 /* 275 */ [ __NR_splice ] = "splice",
567 /* 275 */ [ __NR_splice ] = "splice",
568 /* 276 */ [ __NR_tee ] = "tee",
568 /* 276 */ [ __NR_tee ] = "tee",
569 /* 277 */ [ __NR_sync_file_range ] = "sync_file_range",
569 /* 277 */ [ __NR_sync_file_range ] = "sync_file_range",
570 /* 278 */ [ __NR_vmsplice ] = "vmsplice",
570 /* 278 */ [ __NR_vmsplice ] = "vmsplice",
571 /* 279 */ [ __NR_move_pages ] = "move_pages",
571 /* 279 */ [ __NR_move_pages ] = "move_pages",
572 /* 280 */ [ __NR_utimensat ] = "utimensat",
572 /* 280 */ [ __NR_utimensat ] = "utimensat",
573 /* 281 */ [ __NR_epoll_pwait ] = "epoll_pwait",
573 /* 281 */ [ __NR_epoll_pwait ] = "epoll_pwait",
574 /* 282 */ [ __NR_signalfd ] = "signalfd",
574 /* 282 */ [ __NR_signalfd ] = "signalfd",
575 /* 283 */ [ __NR_timerfd_create ] = "timerfd_create",
575 /* 283 */ [ __NR_timerfd_create ] = "timerfd_create",
576 /* 284 */ [ __NR_eventfd ] = "eventfd",
576 /* 284 */ [ __NR_eventfd ] = "eventfd",
577 /* 285 */ [ __NR_fallocate ] = "fallocate",
577 /* 285 */ [ __NR_fallocate ] = "fallocate",
578 /* 286 */ [ __NR_timerfd_settime ] = "timerfd_settime",
578 /* 286 */ [ __NR_timerfd_settime ] = "timerfd_settime",
579 /* 287 */ [ __NR_timerfd_gettime ] = "timerfd_gettime",
579 /* 287 */ [ __NR_timerfd_gettime ] = "timerfd_gettime",
580 /* 288 */ [ __NR_accept4 ] = "accept4",
580 /* 288 */ [ __NR_accept4 ] = "accept4",
581 /* 289 */ [ __NR_signalfd4 ] = "signalfd4",
581 /* 289 */ [ __NR_signalfd4 ] = "signalfd4",
582 /* 290 */ [ __NR_eventfd2 ] = "eventfd2",
582 /* 290 */ [ __NR_eventfd2 ] = "eventfd2",
583 /* 291 */ [ __NR_epoll_create1 ] = "epoll_create1",
583 /* 291 */ [ __NR_epoll_create1 ] = "epoll_create1",
584 /* 292 */ [ __NR_dup3 ] = "dup3",
584 /* 292 */ [ __NR_dup3 ] = "dup3",
585 /* 293 */ [ __NR_pipe2 ] = "pipe2",
585 /* 293 */ [ __NR_pipe2 ] = "pipe2",
586 /* 294 */ [ __NR_inotify_init1 ] = "inotify_init1",
586 /* 294 */ [ __NR_inotify_init1 ] = "inotify_init1",
587 /* 295 */ [ __NR_preadv ] = "preadv",
587 /* 295 */ [ __NR_preadv ] = "preadv",
588 /* 296 */ [ __NR_pwritev ] = "pwritev",
588 /* 296 */ [ __NR_pwritev ] = "pwritev",
589 /* 297 */ [ __NR_rt_tgsigqueueinfo ] = "rt_tgsigqueueinfo",
589 /* 297 */ [ __NR_rt_tgsigqueueinfo ] = "rt_tgsigqueueinfo",
590 /* 298 */ [ __NR_perf_event_open ] = "perf_event_open",
590 /* 298 */ [ __NR_perf_event_open ] = "perf_event_open",
591 /* 299 */ [ __NR_recvmmsg ] = "recvmmsg",
591 /* 299 */ [ __NR_recvmmsg ] = "recvmmsg",
592 /* 300 */ [ __NR_fanotify_init ] = "fanotify_init",
592 /* 300 */ [ __NR_fanotify_init ] = "fanotify_init",
593 /* 301 */ [ __NR_fanotify_mark ] = "fanotify_mark",
593 /* 301 */ [ __NR_fanotify_mark ] = "fanotify_mark",
594 /* 302 */ [ __NR_prlimit64 ] = "prlimit64",
594 /* 302 */ [ __NR_prlimit64 ] = "prlimit64",
595 /* 303 */ [ __NR_name_to_handle_at ] = "name_to_handle_at",
595 /* 303 */ [ __NR_name_to_handle_at ] = "name_to_handle_at",
596 /* 304 */ [ __NR_open_by_handle_at ] = "open_by_handle_at",
596 /* 304 */ [ __NR_open_by_handle_at ] = "open_by_handle_at",
597 /* 305 */ [ __NR_clock_adjtime ] = "clock_adjtime",
597 /* 305 */ [ __NR_clock_adjtime ] = "clock_adjtime",
598 /* 306 */ [ __NR_syncfs ] = "syncfs",
598 /* 306 */ [ __NR_syncfs ] = "syncfs",
599 /* 307 */ [ __NR_sendmmsg ] = "sendmmsg",
599 /* 307 */ [ __NR_sendmmsg ] = "sendmmsg",
600 /* 308 */ [ __NR_setns ] = "setns",
600 /* 308 */ [ __NR_setns ] = "setns",
601 /* 309 */ [ __NR_getcpu ] = "getcpu",
601 /* 309 */ [ __NR_getcpu ] = "getcpu",
602 /* 310 */ [ __NR_process_vm_readv ] = "process_vm_readv",
602 /* 310 */ [ __NR_process_vm_readv ] = "process_vm_readv",
603 /* 311 */ [ __NR_process_vm_writev ] = "process_vm_writev",
603 /* 311 */ [ __NR_process_vm_writev ] = "process_vm_writev",
604 /* 312 */ [ __NR_kcmp ] = "kcmp",
604 /* 312 */ [ __NR_kcmp ] = "kcmp",
605 /* 313 */ [ __NR_finit_module ] = "finit_module",
605 /* 313 */ [ __NR_finit_module ] = "finit_module",
606 + /* 314 */ [ __NR_sched_setattr ] = "sched_setattr",
607 + /* 315 */ [ __NR_sched_getattr ] = "sched_getattr",
608 + /* 316 */ [ __NR_renameat2 ] = "renameat2",
609 + /* 317 */ [ __NR_seccomp ] = "seccomp",
610 + /* 318 */ [ __NR_getrandom ] = "getrandom",
611 + /* 319 */ [ __NR_memfd_create ] = "memfd_create",
612 + /* 320 */ [ __NR_kexec_file_load ] = "kexec_file_load",
613 + /* 321 */ [ __NR_bpf ] = "bpf",
614 + /* 322 */ [ __NR_execveat ] = "execveat",
615 + /* 323 */ [ __NR_userfaultfd ] = "userfaultfd",
616 + /* 324 */ [ __NR_membarrier ] = "membarrier",
617 + /* 325 */ [ __NR_mlock2 ] = "mlock2",
606 };
618 };
607 #define NUM_SYSCALLS ARRAY_SIZE(syscall_names)
619 #define NUM_SYSCALLS ARRAY_SIZE(syscall_names)
608 #define NUM_ACTIONS (NUM_SYSCALLS+64)
620 #define NUM_ACTIONS (NUM_SYSCALLS+64)
609
621
610 enum action {
622 enum action {
611 A_DEFAULT, // Use the default action
623 A_DEFAULT, // Use the default action
612 A_NO, // Always forbid
624 A_NO, // Always forbid
613 A_YES, // Always permit
625 A_YES, // Always permit
614 A_FILENAME, // Permit if arg1 is a known filename
626 A_FILENAME, // Permit if arg1 is a known filename
615 A_ACTION_MASK = 15,
627 A_ACTION_MASK = 15,
616 A_NO_RETVAL = 32, // Does not return a value
628 A_NO_RETVAL = 32, // Does not return a value
617 A_SAMPLE_MEM = 64, // Sample memory usage before the syscall
629 A_SAMPLE_MEM = 64, // Sample memory usage before the syscall
618 A_LIBERAL = 128, // Valid only in liberal mode
630 A_LIBERAL = 128, // Valid only in liberal mode
619 // Must fit in a unsigned char
631 // Must fit in a unsigned char
620 };
632 };
621
633
622 static unsigned char syscall_action[NUM_ACTIONS] = {
634 static unsigned char syscall_action[NUM_ACTIONS] = {
623 #define S(x) [__NR_##x]
635 #define S(x) [__NR_##x]
624
636
625 // Syscalls permitted for specific file names
637 // Syscalls permitted for specific file names
626 S(open) = A_FILENAME,
638 S(open) = A_FILENAME,
627 S(creat) = A_FILENAME,
639 S(creat) = A_FILENAME,
628 S(unlink) = A_FILENAME,
640 S(unlink) = A_FILENAME,
629 S(access) = A_FILENAME,
641 S(access) = A_FILENAME,
630 S(truncate) = A_FILENAME,
642 S(truncate) = A_FILENAME,
631 S(stat) = A_FILENAME,
643 S(stat) = A_FILENAME,
632 S(lstat) = A_FILENAME,
644 S(lstat) = A_FILENAME,
633 S(readlink) = A_FILENAME,
645 S(readlink) = A_FILENAME,
634 #ifndef CONFIG_BOX_USER_AMD64
646 #ifndef CONFIG_BOX_USER_AMD64
635 S(oldstat) = A_FILENAME,
647 S(oldstat) = A_FILENAME,
636 S(oldlstat) = A_FILENAME,
648 S(oldlstat) = A_FILENAME,
637 S(truncate64) = A_FILENAME,
649 S(truncate64) = A_FILENAME,
638 S(stat64) = A_FILENAME,
650 S(stat64) = A_FILENAME,
639 S(lstat64) = A_FILENAME,
651 S(lstat64) = A_FILENAME,
640 #endif
652 #endif
641
653
642 // Syscalls permitted always
654 // Syscalls permitted always
643 S(exit) = A_YES | A_SAMPLE_MEM,
655 S(exit) = A_YES | A_SAMPLE_MEM,
644 S(read) = A_YES,
656 S(read) = A_YES,
645 S(write) = A_YES,
657 S(write) = A_YES,
646 S(close) = A_YES,
658 S(close) = A_YES,
647 S(lseek) = A_YES,
659 S(lseek) = A_YES,
648 S(getpid) = A_YES,
660 S(getpid) = A_YES,
649 S(getuid) = A_YES,
661 S(getuid) = A_YES,
650 S(dup) = A_YES,
662 S(dup) = A_YES,
651 S(brk) = A_YES,
663 S(brk) = A_YES,
652 S(getgid) = A_YES,
664 S(getgid) = A_YES,
653 S(geteuid) = A_YES,
665 S(geteuid) = A_YES,
654 S(getegid) = A_YES,
666 S(getegid) = A_YES,
655 S(dup2) = A_YES,
667 S(dup2) = A_YES,
656 S(ftruncate) = A_YES,
668 S(ftruncate) = A_YES,
657 S(fstat) = A_YES,
669 S(fstat) = A_YES,
658 S(personality) = A_YES,
670 S(personality) = A_YES,
659 S(readv) = A_YES,
671 S(readv) = A_YES,
660 S(writev) = A_YES,
672 S(writev) = A_YES,
661 S(getresuid) = A_YES,
673 S(getresuid) = A_YES,
662 #ifdef __NR_pread64
674 #ifdef __NR_pread64
663 S(pread64) = A_YES,
675 S(pread64) = A_YES,
664 S(pwrite64) = A_YES,
676 S(pwrite64) = A_YES,
665 #else
677 #else
666 S(pread) = A_YES,
678 S(pread) = A_YES,
667 S(pwrite) = A_YES,
679 S(pwrite) = A_YES,
668 #endif
680 #endif
669 S(fcntl) = A_YES,
681 S(fcntl) = A_YES,
670 S(mmap) = A_YES,
682 S(mmap) = A_YES,
671 S(munmap) = A_YES,
683 S(munmap) = A_YES,
672 S(ioctl) = A_YES,
684 S(ioctl) = A_YES,
673 S(uname) = A_YES,
685 S(uname) = A_YES,
674 S(gettid) = A_YES,
686 S(gettid) = A_YES,
675 S(set_thread_area) = A_YES,
687 S(set_thread_area) = A_YES,
676 S(get_thread_area) = A_YES,
688 S(get_thread_area) = A_YES,
677 S(set_tid_address) = A_YES,
689 S(set_tid_address) = A_YES,
678 S(exit_group) = A_YES | A_SAMPLE_MEM,
690 S(exit_group) = A_YES | A_SAMPLE_MEM,
679 #ifdef CONFIG_BOX_USER_AMD64
691 #ifdef CONFIG_BOX_USER_AMD64
680 S(arch_prctl) = A_YES,
692 S(arch_prctl) = A_YES,
681 #else
693 #else
682 S(oldfstat) = A_YES,
694 S(oldfstat) = A_YES,
683 S(ftruncate64) = A_YES,
695 S(ftruncate64) = A_YES,
684 S(_llseek) = A_YES,
696 S(_llseek) = A_YES,
685 S(fstat64) = A_YES,
697 S(fstat64) = A_YES,
686 S(fcntl64) = A_YES,
698 S(fcntl64) = A_YES,
687 S(mmap2) = A_YES,
699 S(mmap2) = A_YES,
688 #endif
700 #endif
689
701
690 // Syscalls permitted only in liberal mode
702 // Syscalls permitted only in liberal mode
691 S(time) = A_YES | A_LIBERAL,
703 S(time) = A_YES | A_LIBERAL,
692 S(alarm) = A_YES | A_LIBERAL,
704 S(alarm) = A_YES | A_LIBERAL,
693 S(pause) = A_YES | A_LIBERAL,
705 S(pause) = A_YES | A_LIBERAL,
694 S(fchmod) = A_YES | A_LIBERAL,
706 S(fchmod) = A_YES | A_LIBERAL,
695 S(getrlimit) = A_YES | A_LIBERAL,
707 S(getrlimit) = A_YES | A_LIBERAL,
696 S(getrusage) = A_YES | A_LIBERAL,
708 S(getrusage) = A_YES | A_LIBERAL,
697 S(gettimeofday) = A_YES | A_LIBERAL,
709 S(gettimeofday) = A_YES | A_LIBERAL,
698 S(select) = A_YES | A_LIBERAL,
710 S(select) = A_YES | A_LIBERAL,
699 S(setitimer) = A_YES | A_LIBERAL,
711 S(setitimer) = A_YES | A_LIBERAL,
700 S(getitimer) = A_YES | A_LIBERAL,
712 S(getitimer) = A_YES | A_LIBERAL,
701 S(mprotect) = A_YES | A_LIBERAL,
713 S(mprotect) = A_YES | A_LIBERAL,
702 S(getdents) = A_YES | A_LIBERAL,
714 S(getdents) = A_YES | A_LIBERAL,
703 S(getdents64) = A_YES | A_LIBERAL,
715 S(getdents64) = A_YES | A_LIBERAL,
704 S(fdatasync) = A_YES | A_LIBERAL,
716 S(fdatasync) = A_YES | A_LIBERAL,
705 S(mremap) = A_YES | A_LIBERAL,
717 S(mremap) = A_YES | A_LIBERAL,
706 S(poll) = A_YES | A_LIBERAL,
718 S(poll) = A_YES | A_LIBERAL,
707 S(getcwd) = A_YES | A_LIBERAL,
719 S(getcwd) = A_YES | A_LIBERAL,
708 S(nanosleep) = A_YES | A_LIBERAL,
720 S(nanosleep) = A_YES | A_LIBERAL,
709 S(rt_sigreturn) = A_YES | A_LIBERAL | A_NO_RETVAL,
721 S(rt_sigreturn) = A_YES | A_LIBERAL | A_NO_RETVAL,
710 S(rt_sigaction) = A_YES | A_LIBERAL,
722 S(rt_sigaction) = A_YES | A_LIBERAL,
711 S(rt_sigprocmask) = A_YES | A_LIBERAL,
723 S(rt_sigprocmask) = A_YES | A_LIBERAL,
712 S(rt_sigpending) = A_YES | A_LIBERAL,
724 S(rt_sigpending) = A_YES | A_LIBERAL,
713 S(rt_sigtimedwait) = A_YES | A_LIBERAL,
725 S(rt_sigtimedwait) = A_YES | A_LIBERAL,
714 S(rt_sigqueueinfo) = A_YES | A_LIBERAL,
726 S(rt_sigqueueinfo) = A_YES | A_LIBERAL,
715 S(rt_sigsuspend) = A_YES | A_LIBERAL,
727 S(rt_sigsuspend) = A_YES | A_LIBERAL,
716 S(_sysctl) = A_YES | A_LIBERAL,
728 S(_sysctl) = A_YES | A_LIBERAL,
717 #ifndef CONFIG_BOX_USER_AMD64
729 #ifndef CONFIG_BOX_USER_AMD64
718 S(sigaction) = A_YES | A_LIBERAL,
730 S(sigaction) = A_YES | A_LIBERAL,
719 S(sgetmask) = A_YES | A_LIBERAL,
731 S(sgetmask) = A_YES | A_LIBERAL,
720 S(ssetmask) = A_YES | A_LIBERAL,
732 S(ssetmask) = A_YES | A_LIBERAL,
721 S(sigsuspend) = A_YES | A_LIBERAL,
733 S(sigsuspend) = A_YES | A_LIBERAL,
722 S(sigpending) = A_YES | A_LIBERAL,
734 S(sigpending) = A_YES | A_LIBERAL,
723 S(sigreturn) = A_YES | A_LIBERAL | A_NO_RETVAL,
735 S(sigreturn) = A_YES | A_LIBERAL | A_NO_RETVAL,
724 S(sigprocmask) = A_YES | A_LIBERAL,
736 S(sigprocmask) = A_YES | A_LIBERAL,
725 S(ugetrlimit) = A_YES | A_LIBERAL,
737 S(ugetrlimit) = A_YES | A_LIBERAL,
726 S(readdir) = A_YES | A_LIBERAL,
738 S(readdir) = A_YES | A_LIBERAL,
727 S(signal) = A_YES | A_LIBERAL,
739 S(signal) = A_YES | A_LIBERAL,
728 S(_newselect) = A_YES | A_LIBERAL,
740 S(_newselect) = A_YES | A_LIBERAL,
729 #endif
741 #endif
730
742
731 #undef S
743 #undef S
732 };
744 };
733
745
734 static const char *
746 static const char *
735 syscall_name(unsigned int id, char *buf)
747 syscall_name(unsigned int id, char *buf)
736 {
748 {
737 if (id < NUM_SYSCALLS && syscall_names[id])
749 if (id < NUM_SYSCALLS && syscall_names[id])
738 return syscall_names[id];
750 return syscall_names[id];
739 else
751 else
740 {
752 {
741 sprintf(buf, "#%d", id);
753 sprintf(buf, "#%d", id);
742 return buf;
754 return buf;
743 }
755 }
744 }
756 }
745
757
746 static int
758 static int
747 syscall_by_name(char *name)
759 syscall_by_name(char *name)
748 {
760 {
749 for (unsigned int i=0; i<NUM_SYSCALLS; i++)
761 for (unsigned int i=0; i<NUM_SYSCALLS; i++)
750 if (syscall_names[i] && !strcmp(syscall_names[i], name))
762 if (syscall_names[i] && !strcmp(syscall_names[i], name))
751 return i;
763 return i;
752 if (name[0] == '#')
764 if (name[0] == '#')
753 name++;
765 name++;
754 if (!*name)
766 if (!*name)
755 return -1;
767 return -1;
756 char *ep;
768 char *ep;
757 unsigned long l = strtoul(name, &ep, 0);
769 unsigned long l = strtoul(name, &ep, 0);
758 if (*ep)
770 if (*ep)
759 return -1;
771 return -1;
760 if (l >= NUM_ACTIONS)
772 if (l >= NUM_ACTIONS)
761 return NUM_ACTIONS;
773 return NUM_ACTIONS;
762 return l;
774 return l;
763 }
775 }
764
776
765 static int
777 static int
766 set_syscall_action(char *a)
778 set_syscall_action(char *a)
767 {
779 {
768 char *sep = strchr(a, '=');
780 char *sep = strchr(a, '=');
769 enum action act = A_YES;
781 enum action act = A_YES;
770 if (sep)
782 if (sep)
771 {
783 {
772 *sep++ = 0;
784 *sep++ = 0;
773 if (!strcmp(sep, "yes"))
785 if (!strcmp(sep, "yes"))
774 act = A_YES;
786 act = A_YES;
775 else if (!strcmp(sep, "no"))
787 else if (!strcmp(sep, "no"))
776 act = A_NO;
788 act = A_NO;
777 else if (!strcmp(sep, "file"))
789 else if (!strcmp(sep, "file"))
778 act = A_FILENAME;
790 act = A_FILENAME;
779 else
791 else
780 return 0;
792 return 0;
781 }
793 }
782
794
783 int sys = syscall_by_name(a);
795 int sys = syscall_by_name(a);
784 if (sys < 0)
796 if (sys < 0)
785 die("Unknown syscall `%s'", a);
797 die("Unknown syscall `%s'", a);
786 if (sys >= NUM_ACTIONS)
798 if (sys >= NUM_ACTIONS)
787 die("Syscall `%s' out of range", a);
799 die("Syscall `%s' out of range", a);
788 syscall_action[sys] = act;
800 syscall_action[sys] = act;
789 return 1;
801 return 1;
790 }
802 }
791
803
792 /*** Path rules ***/
804 /*** Path rules ***/
793
805
794 struct path_rule {
806 struct path_rule {
795 char *path;
807 char *path;
796 enum action action;
808 enum action action;
797 struct path_rule *next;
809 struct path_rule *next;
798 };
810 };
799
811
800 static struct path_rule default_path_rules[] = {
812 static struct path_rule default_path_rules[] = {
801 { "/etc/", A_YES },
813 { "/etc/", A_YES },
802 { "/lib/", A_YES },
814 { "/lib/", A_YES },
803 { "/usr/lib/", A_YES },
815 { "/usr/lib/", A_YES },
804 { "/opt/lib/", A_YES },
816 { "/opt/lib/", A_YES },
805 { "/usr/share/zoneinfo/", A_YES },
817 { "/usr/share/zoneinfo/", A_YES },
806 { "/usr/share/locale/", A_YES },
818 { "/usr/share/locale/", A_YES },
807 { "/dev/null", A_YES },
819 { "/dev/null", A_YES },
808 { "/dev/zero", A_YES },
820 { "/dev/zero", A_YES },
809 { "/proc/meminfo", A_YES },
821 { "/proc/meminfo", A_YES },
810 { "/proc/self/stat", A_YES },
822 { "/proc/self/stat", A_YES },
811 { "/proc/self/exe", A_YES }, // Needed by FPC 2.0.x runtime
823 { "/proc/self/exe", A_YES }, // Needed by FPC 2.0.x runtime
812 { "/proc/self/maps", A_YES }, // Needed by glibc when it reports arena corruption
824 { "/proc/self/maps", A_YES }, // Needed by glibc when it reports arena corruption
813 };
825 };
814
826
815 static struct path_rule *user_path_rules;
827 static struct path_rule *user_path_rules;
816 static struct path_rule **last_path_rule = &user_path_rules;
828 static struct path_rule **last_path_rule = &user_path_rules;
817
829
818 static int
830 static int
819 set_path_action(char *a)
831 set_path_action(char *a)
820 {
832 {
821 char *sep = strchr(a, '=');
833 char *sep = strchr(a, '=');
822 enum action act = A_YES;
834 enum action act = A_YES;
823 if (sep)
835 if (sep)
824 {
836 {
825 *sep++ = 0;
837 *sep++ = 0;
826 if (!strcmp(sep, "yes"))
838 if (!strcmp(sep, "yes"))
827 act = A_YES;
839 act = A_YES;
828 else if (!strcmp(sep, "no"))
840 else if (!strcmp(sep, "no"))
829 act = A_NO;
841 act = A_NO;
830 else
842 else
831 return 0;
843 return 0;
832 }
844 }
833
845
834 struct path_rule *r = xmalloc(sizeof(*r) + strlen(a) + 1);
846 struct path_rule *r = xmalloc(sizeof(*r) + strlen(a) + 1);
835 r->path = (char *)(r+1);
847 r->path = (char *)(r+1);
836 strcpy(r->path, a);
848 strcpy(r->path, a);
837 r->action = act;
849 r->action = act;
838 r->next = NULL;
850 r->next = NULL;
839 *last_path_rule = r;
851 *last_path_rule = r;
840 last_path_rule = &r->next;
852 last_path_rule = &r->next;
841 return 1;
853 return 1;
842 }
854 }
843
855
844 static enum action
856 static enum action
845 match_path_rule(struct path_rule *r, char *path)
857 match_path_rule(struct path_rule *r, char *path)
846 {
858 {
847 char *rr = r->path;
859 char *rr = r->path;
848 while (*rr)
860 while (*rr)
849 if (*rr++ != *path++)
861 if (*rr++ != *path++)
850 {
862 {
851 if (rr[-1] == '/' && !path[-1])
863 if (rr[-1] == '/' && !path[-1])
852 break;
864 break;
853 return A_DEFAULT;
865 return A_DEFAULT;
854 }
866 }
855 if (rr > r->path && rr[-1] != '/' && *path)
867 if (rr > r->path && rr[-1] != '/' && *path)
856 return A_DEFAULT;
868 return A_DEFAULT;
857 return r->action;
869 return r->action;
858 }
870 }
859
871
860 /*** Environment rules ***/
872 /*** Environment rules ***/
861
873
862 struct env_rule {
874 struct env_rule {
863 char *var; // Variable to match
875 char *var; // Variable to match
864 char *val; // ""=clear, NULL=inherit
876 char *val; // ""=clear, NULL=inherit
865 int var_len;
877 int var_len;
866 struct env_rule *next;
878 struct env_rule *next;
867 };
879 };
868
880
869 static struct env_rule *first_env_rule;
881 static struct env_rule *first_env_rule;
870 static struct env_rule **last_env_rule = &first_env_rule;
882 static struct env_rule **last_env_rule = &first_env_rule;
871
883
872 static struct env_rule default_env_rules[] = {
884 static struct env_rule default_env_rules[] = {
873 { "LIBC_FATAL_STDERR_", "1" }
885 { "LIBC_FATAL_STDERR_", "1" }
874 };
886 };
875
887
876 static int
888 static int
877 set_env_action(char *a0)
889 set_env_action(char *a0)
878 {
890 {
879 struct env_rule *r = xmalloc(sizeof(*r) + strlen(a0) + 1);
891 struct env_rule *r = xmalloc(sizeof(*r) + strlen(a0) + 1);
880 char *a = (char *)(r+1);
892 char *a = (char *)(r+1);
881 strcpy(a, a0);
893 strcpy(a, a0);
882
894
883 char *sep = strchr(a, '=');
895 char *sep = strchr(a, '=');
884 if (sep == a)
896 if (sep == a)
885 return 0;
897 return 0;
886 r->var = a;
898 r->var = a;
887 if (sep)
899 if (sep)
888 {
900 {
889 *sep++ = 0;
901 *sep++ = 0;
890 r->val = sep;
902 r->val = sep;
891 }
903 }
892 else
904 else
893 r->val = NULL;
905 r->val = NULL;
894 *last_env_rule = r;
906 *last_env_rule = r;
895 last_env_rule = &r->next;
907 last_env_rule = &r->next;
896 r->next = NULL;
908 r->next = NULL;
897 return 1;
909 return 1;
898 }
910 }
899
911
900 static int
912 static int
901 match_env_var(char *env_entry, struct env_rule *r)
913 match_env_var(char *env_entry, struct env_rule *r)
902 {
914 {
903 if (strncmp(env_entry, r->var, r->var_len))
915 if (strncmp(env_entry, r->var, r->var_len))
904 return 0;
916 return 0;
905 return (env_entry[r->var_len] == '=');
917 return (env_entry[r->var_len] == '=');
906 }
918 }
907
919
908 static void
920 static void
909 apply_env_rule(char **env, int *env_sizep, struct env_rule *r)
921 apply_env_rule(char **env, int *env_sizep, struct env_rule *r)
910 {
922 {
911 // First remove the variable if already set
923 // First remove the variable if already set
912 int pos = 0;
924 int pos = 0;
913 while (pos < *env_sizep && !match_env_var(env[pos], r))
925 while (pos < *env_sizep && !match_env_var(env[pos], r))
914 pos++;
926 pos++;
915 if (pos < *env_sizep)
927 if (pos < *env_sizep)
916 {
928 {
917 (*env_sizep)--;
929 (*env_sizep)--;
918 env[pos] = env[*env_sizep];
930 env[pos] = env[*env_sizep];
919 env[*env_sizep] = NULL;
931 env[*env_sizep] = NULL;
920 }
932 }
921
933
922 // What is the new value?
934 // What is the new value?
923 char *new;
935 char *new;
924 if (r->val)
936 if (r->val)
925 {
937 {
926 if (!r->val[0])
938 if (!r->val[0])
927 return;
939 return;
928 new = xmalloc(r->var_len + 1 + strlen(r->val) + 1);
940 new = xmalloc(r->var_len + 1 + strlen(r->val) + 1);
929 sprintf(new, "%s=%s", r->var, r->val);
941 sprintf(new, "%s=%s", r->var, r->val);
930 }
942 }
931 else
943 else
932 {
944 {
933 pos = 0;
945 pos = 0;
934 while (environ[pos] && !match_env_var(environ[pos], r))
946 while (environ[pos] && !match_env_var(environ[pos], r))
935 pos++;
947 pos++;
936 if (!(new = environ[pos]))
948 if (!(new = environ[pos]))
937 return;
949 return;
938 }
950 }
939
951
940 // Add it at the end of the array
952 // Add it at the end of the array
941 env[(*env_sizep)++] = new;
953 env[(*env_sizep)++] = new;
942 env[*env_sizep] = NULL;
954 env[*env_sizep] = NULL;
943 }
955 }
944
956
945 static char **
957 static char **
946 setup_environment(void)
958 setup_environment(void)
947 {
959 {
948 // Link built-in rules with user rules
960 // Link built-in rules with user rules
949 for (int i=ARRAY_SIZE(default_env_rules)-1; i >= 0; i--)
961 for (int i=ARRAY_SIZE(default_env_rules)-1; i >= 0; i--)
950 {
962 {
951 default_env_rules[i].next = first_env_rule;
963 default_env_rules[i].next = first_env_rule;
952 first_env_rule = &default_env_rules[i];
964 first_env_rule = &default_env_rules[i];
953 }
965 }
954
966
955 // Scan the original environment
967 // Scan the original environment
956 char **orig_env = environ;
968 char **orig_env = environ;
957 int orig_size = 0;
969 int orig_size = 0;
958 while (orig_env[orig_size])
970 while (orig_env[orig_size])
959 orig_size++;
971 orig_size++;
960
972
961 // For each rule, reserve one more slot and calculate length
973 // For each rule, reserve one more slot and calculate length
962 int num_rules = 0;
974 int num_rules = 0;
963 for (struct env_rule *r = first_env_rule; r; r=r->next)
975 for (struct env_rule *r = first_env_rule; r; r=r->next)
964 {
976 {
965 num_rules++;
977 num_rules++;
966 r->var_len = strlen(r->var);
978 r->var_len = strlen(r->var);
967 }
979 }
968
980
969 // Create a new environment
981 // Create a new environment
970 char **env = xmalloc((orig_size + num_rules + 1) * sizeof(char *));
982 char **env = xmalloc((orig_size + num_rules + 1) * sizeof(char *));
971 int size;
983 int size;
972 if (pass_environ)
984 if (pass_environ)
973 {
985 {
974 memcpy(env, environ, orig_size * sizeof(char *));
986 memcpy(env, environ, orig_size * sizeof(char *));
975 size = orig_size;
987 size = orig_size;
976 }
988 }
977 else
989 else
978 size = 0;
990 size = 0;
979 env[size] = NULL;
991 env[size] = NULL;
980
992
981 // Apply the rules one by one
993 // Apply the rules one by one
982 for (struct env_rule *r = first_env_rule; r; r=r->next)
994 for (struct env_rule *r = first_env_rule; r; r=r->next)
983 apply_env_rule(env, &size, r);
995 apply_env_rule(env, &size, r);
984
996
985 // Return the new env and pass some gossip
997 // Return the new env and pass some gossip
986 if (verbose > 1)
998 if (verbose > 1)
987 {
999 {
988 fprintf(stderr, "Passing environment:\n");
1000 fprintf(stderr, "Passing environment:\n");
989 for (int i=0; env[i]; i++)
1001 for (int i=0; env[i]; i++)
990 fprintf(stderr, "\t%s\n", env[i]);
1002 fprintf(stderr, "\t%s\n", env[i]);
991 }
1003 }
992 return env;
1004 return env;
993 }
1005 }
994
1006
995 /*** Low-level parsing of syscalls ***/
1007 /*** Low-level parsing of syscalls ***/
996
1008
997 #ifdef CONFIG_BOX_KERNEL_AMD64
1009 #ifdef CONFIG_BOX_KERNEL_AMD64
998 typedef uint64_t arg_t;
1010 typedef uint64_t arg_t;
999 #else
1011 #else
1000 typedef uint32_t arg_t;
1012 typedef uint32_t arg_t;
1001 #endif
1013 #endif
1002
1014
1003 struct syscall_args {
1015 struct syscall_args {
1004 arg_t sys;
1016 arg_t sys;
1005 arg_t arg1, arg2, arg3;
1017 arg_t arg1, arg2, arg3;
1006 arg_t result;
1018 arg_t result;
1007 struct user user;
1019 struct user user;
1008 };
1020 };
1009
1021
1010 static int user_mem_fd;
1022 static int user_mem_fd;
1011
1023
1012 static int read_user_mem(arg_t addr, char *buf, int len)
1024 static int read_user_mem(arg_t addr, char *buf, int len)
1013 {
1025 {
1014 if (!user_mem_fd)
1026 if (!user_mem_fd)
1015 {
1027 {
1016 char memname[64];
1028 char memname[64];
1017 sprintf(memname, "/proc/%d/mem", (int) box_pid);
1029 sprintf(memname, "/proc/%d/mem", (int) box_pid);
1018 user_mem_fd = open(memname, O_RDONLY);
1030 user_mem_fd = open(memname, O_RDONLY);
1019 if (user_mem_fd < 0)
1031 if (user_mem_fd < 0)
1020 die("open(%s): %m", memname);
1032 die("open(%s): %m", memname);
1021 }
1033 }
1022 if (lseek64(user_mem_fd, addr, SEEK_SET) < 0)
1034 if (lseek64(user_mem_fd, addr, SEEK_SET) < 0)
1023 die("lseek64(mem): %m");
1035 die("lseek64(mem): %m");
1024 return read(user_mem_fd, buf, len);
1036 return read(user_mem_fd, buf, len);
1025 }
1037 }
1026
1038
1027 static void close_user_mem(void)
1039 static void close_user_mem(void)
1028 {
1040 {
1029 if (user_mem_fd)
1041 if (user_mem_fd)
1030 {
1042 {
1031 close(user_mem_fd);
1043 close(user_mem_fd);
1032 user_mem_fd = 0;
1044 user_mem_fd = 0;
1033 }
1045 }
1034 }
1046 }
1035
1047
1036 #ifdef CONFIG_BOX_KERNEL_AMD64
1048 #ifdef CONFIG_BOX_KERNEL_AMD64
1037
1049
1038 static void
1050 static void
1039 get_syscall_args(struct syscall_args *a, int is_exit)
1051 get_syscall_args(struct syscall_args *a, int is_exit)
1040 {
1052 {
1041 if (ptrace(PTRACE_GETREGS, box_pid, NULL, &a->user) < 0)
1053 if (ptrace(PTRACE_GETREGS, box_pid, NULL, &a->user) < 0)
1042 die("ptrace(PTRACE_GETREGS): %m");
1054 die("ptrace(PTRACE_GETREGS): %m");
1043 a->sys = a->user.regs.orig_rax;
1055 a->sys = a->user.regs.orig_rax;
1044 a->result = a->user.regs.rax;
1056 a->result = a->user.regs.rax;
1045
1057
1046 /*
1058 /*
1047 * CAVEAT: We have to check carefully that this is a real 64-bit syscall.
1059 * CAVEAT: We have to check carefully that this is a real 64-bit syscall.
1048 * We test whether the process runs in 64-bit mode, but surprisingly this
1060 * We test whether the process runs in 64-bit mode, but surprisingly this
1049 * is not enough: a 64-bit process can still issue the INT 0x80 instruction
1061 * is not enough: a 64-bit process can still issue the INT 0x80 instruction
1050 * which performs a 32-bit syscall. Currently, the only known way how to
1062 * which performs a 32-bit syscall. Currently, the only known way how to
1051 * detect this situation is to inspect the instruction code (the kernel
1063 * detect this situation is to inspect the instruction code (the kernel
1052 * keeps a syscall type flag internally, but it is not accessible from
1064 * keeps a syscall type flag internally, but it is not accessible from
1053 * user space). Hopefully, there is no instruction whose suffix is the
1065 * user space). Hopefully, there is no instruction whose suffix is the
1054 * code of the SYSCALL instruction. Sometimes, one would wish the
1066 * code of the SYSCALL instruction. Sometimes, one would wish the
1055 * instruction codes to be unique even when read backwards :)
1067 * instruction codes to be unique even when read backwards :)
1056 */
1068 */
1057
1069
1058 if (is_exit)
1070 if (is_exit)
1059 return;
1071 return;
1060
1072
1061 int sys_type;
1073 int sys_type;
1062 uint16_t instr;
1074 uint16_t instr;
1063
1075
1064 switch (a->user.regs.cs)
1076 switch (a->user.regs.cs)
1065 {
1077 {
1066 case 0x23:
1078 case 0x23:
1067 // 32-bit CPU mode => only 32-bit syscalls can be issued
1079 // 32-bit CPU mode => only 32-bit syscalls can be issued
1068 sys_type = 32;
1080 sys_type = 32;
1069 break;
1081 break;
1070 case 0x33:
1082 case 0x33:
1071 // 64-bit CPU mode
1083 // 64-bit CPU mode
1072 if (read_user_mem(a->user.regs.rip-2, (char *) &instr, 2) != 2)
1084 if (read_user_mem(a->user.regs.rip-2, (char *) &instr, 2) != 2)
1073 err("FO: Cannot read syscall instruction");
1085 err("FO: Cannot read syscall instruction");
1074 switch (instr)
1086 switch (instr)
1075 {
1087 {
1076 case 0x050f:
1088 case 0x050f:
1077 break;
1089 break;
1078 case 0x80cd:
1090 case 0x80cd:
1079 err("FO: Forbidden 32-bit syscall in 64-bit mode");
1091 err("FO: Forbidden 32-bit syscall in 64-bit mode");
1080 default:
1092 default:
1081 err("XX: Unknown syscall instruction %04x", instr);
1093 err("XX: Unknown syscall instruction %04x", instr);
1082 }
1094 }
1083 sys_type = 64;
1095 sys_type = 64;
1084 break;
1096 break;
1085 default:
1097 default:
1086 err("XX: Unknown code segment %04jx", (intmax_t) a->user.regs.cs);
1098 err("XX: Unknown code segment %04jx", (intmax_t) a->user.regs.cs);
1087 }
1099 }
1088
1100
1089 #ifdef CONFIG_BOX_USER_AMD64
1101 #ifdef CONFIG_BOX_USER_AMD64
1090 if (sys_type != 64)
1102 if (sys_type != 64)
1091 err("FO: Forbidden %d-bit mode syscall", sys_type);
1103 err("FO: Forbidden %d-bit mode syscall", sys_type);
1092 #else
1104 #else
1093 if (sys_type != (exec_seen ? 32 : 64))
1105 if (sys_type != (exec_seen ? 32 : 64))
1094 err("FO: Forbidden %d-bit mode syscall", sys_type);
1106 err("FO: Forbidden %d-bit mode syscall", sys_type);
1095 #endif
1107 #endif
1096
1108
1097 if (sys_type == 32)
1109 if (sys_type == 32)
1098 {
1110 {
1099 a->arg1 = a->user.regs.rbx;
1111 a->arg1 = a->user.regs.rbx;
1100 a->arg2 = a->user.regs.rcx;
1112 a->arg2 = a->user.regs.rcx;
1101 a->arg3 = a->user.regs.rdx;
1113 a->arg3 = a->user.regs.rdx;
1102 }
1114 }
1103 else
1115 else
1104 {
1116 {
1105 a->arg1 = a->user.regs.rdi;
1117 a->arg1 = a->user.regs.rdi;
1106 a->arg2 = a->user.regs.rsi;
1118 a->arg2 = a->user.regs.rsi;
1107 a->arg3 = a->user.regs.rdx;
1119 a->arg3 = a->user.regs.rdx;
1108 }
1120 }
1109 }
1121 }
1110
1122
1111 static void
1123 static void
1112 set_syscall_nr(struct syscall_args *a, arg_t sys)
1124 set_syscall_nr(struct syscall_args *a, arg_t sys)
1113 {
1125 {
1114 a->sys = sys;
1126 a->sys = sys;
1115 a->user.regs.orig_rax = sys;
1127 a->user.regs.orig_rax = sys;
1116 if (ptrace(PTRACE_SETREGS, box_pid, NULL, &a->user) < 0)
1128 if (ptrace(PTRACE_SETREGS, box_pid, NULL, &a->user) < 0)
1117 die("ptrace(PTRACE_SETREGS): %m");
1129 die("ptrace(PTRACE_SETREGS): %m");
1118 }
1130 }
1119
1131
1120 static void
1132 static void
1121 sanity_check(void)
1133 sanity_check(void)
1122 {
1134 {
1123 }
1135 }
1124
1136
1125 #else
1137 #else
1126
1138
1127 static void
1139 static void
1128 get_syscall_args(struct syscall_args *a, int is_exit UNUSED)
1140 get_syscall_args(struct syscall_args *a, int is_exit UNUSED)
1129 {
1141 {
1130 if (ptrace(PTRACE_GETREGS, box_pid, NULL, &a->user) < 0)
1142 if (ptrace(PTRACE_GETREGS, box_pid, NULL, &a->user) < 0)
1131 die("ptrace(PTRACE_GETREGS): %m");
1143 die("ptrace(PTRACE_GETREGS): %m");
1132 a->sys = a->user.regs.orig_eax;
1144 a->sys = a->user.regs.orig_eax;
1133 a->arg1 = a->user.regs.ebx;
1145 a->arg1 = a->user.regs.ebx;
1134 a->arg2 = a->user.regs.ecx;
1146 a->arg2 = a->user.regs.ecx;
1135 a->arg3 = a->user.regs.edx;
1147 a->arg3 = a->user.regs.edx;
1136 a->result = a->user.regs.eax;
1148 a->result = a->user.regs.eax;
1137 }
1149 }
1138
1150
1139 static void
1151 static void
1140 set_syscall_nr(struct syscall_args *a, arg_t sys)
1152 set_syscall_nr(struct syscall_args *a, arg_t sys)
1141 {
1153 {
1142 a->sys = sys;
1154 a->sys = sys;
1143 a->user.regs.orig_eax = sys;
1155 a->user.regs.orig_eax = sys;
1144 if (ptrace(PTRACE_SETREGS, box_pid, NULL, &a->user) < 0)
1156 if (ptrace(PTRACE_SETREGS, box_pid, NULL, &a->user) < 0)
1145 die("ptrace(PTRACE_SETREGS): %m");
1157 die("ptrace(PTRACE_SETREGS): %m");
1146 }
1158 }
1147
1159
1148 static void
1160 static void
1149 sanity_check(void)
1161 sanity_check(void)
1150 {
1162 {
1151 #if !defined(CONFIG_BOX_ALLOW_INSECURE)
1163 #if !defined(CONFIG_BOX_ALLOW_INSECURE)
1152 struct utsname uts;
1164 struct utsname uts;
1153 if (uname(&uts) < 0)
1165 if (uname(&uts) < 0)
1154 die("uname() failed: %m");
1166 die("uname() failed: %m");
1155
1167
1156 if (!strcmp(uts.machine, "x86_64"))
1168 if (!strcmp(uts.machine, "x86_64"))
1157 die("Running 32-bit sandbox on 64-bit kernels is inherently unsafe. Please get a 64-bit version.");
1169 die("Running 32-bit sandbox on 64-bit kernels is inherently unsafe. Please get a 64-bit version.");
1158 #endif
1170 #endif
1159 }
1171 }
1160
1172
1161 #endif
1173 #endif
1162
1174
1163 /*** Syscall checks ***/
1175 /*** Syscall checks ***/
1164
1176
1165 static void
1177 static void
1166 valid_filename(arg_t addr)
1178 valid_filename(arg_t addr)
1167 {
1179 {
1168 char namebuf[4096], *p, *end;
1180 char namebuf[4096], *p, *end;
1169
1181
1170 if (!file_access)
1182 if (!file_access)
1171 err("FA: File access forbidden");
1183 err("FA: File access forbidden");
1172 if (file_access >= 9)
1184 if (file_access >= 9)
1173 return;
1185 return;
1174
1186
1175 p = end = namebuf;
1187 p = end = namebuf;
1176 do
1188 do
1177 {
1189 {
1178 if (p >= end)
1190 if (p >= end)
1179 {
1191 {
1180 int remains = PAGE_SIZE - (addr & (PAGE_SIZE-1));
1192 int remains = PAGE_SIZE - (addr & (PAGE_SIZE-1));
1181 int l = namebuf + sizeof(namebuf) - end;
1193 int l = namebuf + sizeof(namebuf) - end;
1182 if (l > remains)
1194 if (l > remains)
1183 l = remains;
1195 l = remains;
1184 if (!l)
1196 if (!l)
1185 err("FA: Access to file with name too long");
1197 err("FA: Access to file with name too long");
1186 remains = read_user_mem(addr, end, l);
1198 remains = read_user_mem(addr, end, l);
1187 if (remains < 0)
1199 if (remains < 0)
1188 die("read(mem): %m");
1200 die("read(mem): %m");
1189 if (!remains)
1201 if (!remains)
1190 err("FA: Access to file with name out of memory");
1202 err("FA: Access to file with name out of memory");
1191 end += remains;
1203 end += remains;
1192 addr += remains;
1204 addr += remains;
1193 }
1205 }
1194 }
1206 }
1195 while (*p++);
1207 while (*p++);
1196
1208
1197 msg("[%s] ", namebuf);
1209 msg("[%s] ", namebuf);
1198 if (file_access >= 3)
1210 if (file_access >= 3)
1199 return;
1211 return;
1200
1212
1201 // Everything in current directory is permitted
1213 // Everything in current directory is permitted
1202 if (!strchr(namebuf, '/') && strcmp(namebuf, ".."))
1214 if (!strchr(namebuf, '/') && strcmp(namebuf, ".."))
1203 return;
1215 return;
1204
1216
1205 // ".." anywhere in the path is forbidden
1217 // ".." anywhere in the path is forbidden
1206 enum action act = A_DEFAULT;
1218 enum action act = A_DEFAULT;
1207 if (strstr(namebuf, ".."))
1219 if (strstr(namebuf, ".."))
1208 act = A_NO;
1220 act = A_NO;
1209
1221
1210 // Scan user rules
1222 // Scan user rules
1211 for (struct path_rule *r = user_path_rules; r && !act; r=r->next)
1223 for (struct path_rule *r = user_path_rules; r && !act; r=r->next)
1212 act = match_path_rule(r, namebuf);
1224 act = match_path_rule(r, namebuf);
1213
1225
1214 // Scan built-in rules
1226 // Scan built-in rules
1215 if (file_access >= 2)
1227 if (file_access >= 2)
1216 for (int i=0; i<ARRAY_SIZE(default_path_rules) && !act; i++)
1228 for (int i=0; i<ARRAY_SIZE(default_path_rules) && !act; i++)
1217 act = match_path_rule(&default_path_rules[i], namebuf);
1229 act = match_path_rule(&default_path_rules[i], namebuf);
1218
1230
1219 if (act != A_YES)
1231 if (act != A_YES)
1220 err("FA: Forbidden access to file `%s'", namebuf);
1232 err("FA: Forbidden access to file `%s'", namebuf);
1221 }
1233 }
1222
1234
1223 // Check syscall. If invalid, return -1, otherwise return the action mask.
1235 // Check syscall. If invalid, return -1, otherwise return the action mask.
1224 static int
1236 static int
1225 valid_syscall(struct syscall_args *a)
1237 valid_syscall(struct syscall_args *a)
1226 {
1238 {
1227 unsigned int sys = a->sys;
1239 unsigned int sys = a->sys;
1228 unsigned int act = (sys < NUM_ACTIONS) ? syscall_action[sys] : A_DEFAULT;
1240 unsigned int act = (sys < NUM_ACTIONS) ? syscall_action[sys] : A_DEFAULT;
1229
1241
1230 if (act & A_LIBERAL)
1242 if (act & A_LIBERAL)
1231 {
1243 {
1232 if (filter_syscalls != 1)
1244 if (filter_syscalls != 1)
1233 act = A_DEFAULT;
1245 act = A_DEFAULT;
1234 }
1246 }
1235
1247
1236 switch (act & A_ACTION_MASK)
1248 switch (act & A_ACTION_MASK)
1237 {
1249 {
1238 case A_YES:
1250 case A_YES:
1239 return act;
1251 return act;
1240 case A_NO:
1252 case A_NO:
1241 return -1;
1253 return -1;
1242 case A_FILENAME:
1254 case A_FILENAME:
1243 valid_filename(a->arg1);
1255 valid_filename(a->arg1);
1244 return act;
1256 return act;
1245 default: ;
1257 default: ;
1246 }
1258 }
1247
1259
1248 switch (sys)
1260 switch (sys)
1249 {
1261 {
1250 case __NR_kill:
1262 case __NR_kill:
1251 if (a->arg1 == (arg_t) box_pid)
1263 if (a->arg1 == (arg_t) box_pid)
1252 {
1264 {
1253 meta_printf("exitsig:%d\n", (int) a->arg2);
1265 meta_printf("exitsig:%d\n", (int) a->arg2);
1254 err("SG: Committed suicide by signal %d", (int) a->arg2);
1266 err("SG: Committed suicide by signal %d", (int) a->arg2);
1255 }
1267 }
1256 return -1;
1268 return -1;
1257 case __NR_tgkill:
1269 case __NR_tgkill:
1258 if (a->arg1 == (arg_t) box_pid && a->arg2 == (arg_t) box_pid)
1270 if (a->arg1 == (arg_t) box_pid && a->arg2 == (arg_t) box_pid)
1259 {
1271 {
1260 meta_printf("exitsig:%d\n", (int) a->arg3);
1272 meta_printf("exitsig:%d\n", (int) a->arg3);
1261 err("SG: Committed suicide by signal %d", (int) a->arg3);
1273 err("SG: Committed suicide by signal %d", (int) a->arg3);
1262 }
1274 }
1263 return -1;
1275 return -1;
1264 default:
1276 default:
1265 return -1;
1277 return -1;
1266 }
1278 }
1267 }
1279 }
1268
1280
1269 static void
1281 static void
1270 signal_alarm(int unused UNUSED)
1282 signal_alarm(int unused UNUSED)
1271 {
1283 {
1272 /* Time limit checks are synchronous, so we only schedule them there. */
1284 /* Time limit checks are synchronous, so we only schedule them there. */
1273 timer_tick = 1;
1285 timer_tick = 1;
1274 alarm(1);
1286 alarm(1);
1275 }
1287 }
1276
1288
1277 static void
1289 static void
1278 signal_int(int unused UNUSED)
1290 signal_int(int unused UNUSED)
1279 {
1291 {
1280 /* Interrupts are fatal, so no synchronization requirements. */
1292 /* Interrupts are fatal, so no synchronization requirements. */
1281 meta_printf("exitsig:%d\n", SIGINT);
1293 meta_printf("exitsig:%d\n", SIGINT);
1282 err("SG: Interrupted");
1294 err("SG: Interrupted");
1283 }
1295 }
1284
1296
1285 #define PROC_BUF_SIZE 4096
1297 #define PROC_BUF_SIZE 4096
1286 static void
1298 static void
1287 read_proc_file(char *buf, char *name, int *fdp)
1299 read_proc_file(char *buf, char *name, int *fdp)
1288 {
1300 {
1289 int c;
1301 int c;
1290
1302
1291 if (!*fdp)
1303 if (!*fdp)
1292 {
1304 {
1293 sprintf(buf, "/proc/%d/%s", (int) box_pid, name);
1305 sprintf(buf, "/proc/%d/%s", (int) box_pid, name);
1294 *fdp = open(buf, O_RDONLY);
1306 *fdp = open(buf, O_RDONLY);
1295 if (*fdp < 0)
1307 if (*fdp < 0)
1296 die("open(%s): %m", buf);
1308 die("open(%s): %m", buf);
1297 }
1309 }
1298 lseek(*fdp, 0, SEEK_SET);
1310 lseek(*fdp, 0, SEEK_SET);
1299 if ((c = read(*fdp, buf, PROC_BUF_SIZE-1)) < 0)
1311 if ((c = read(*fdp, buf, PROC_BUF_SIZE-1)) < 0)
1300 die("read on /proc/$pid/%s: %m", name);
1312 die("read on /proc/$pid/%s: %m", name);
1301 if (c >= PROC_BUF_SIZE-1)
1313 if (c >= PROC_BUF_SIZE-1)
1302 die("/proc/$pid/%s too long", name);
1314 die("/proc/$pid/%s too long", name);
1303 buf[c] = 0;
1315 buf[c] = 0;
1304 }
1316 }
1305
1317
1306 static void
1318 static void
1307 check_timeout(void)
1319 check_timeout(void)
1308 {
1320 {
1309 if (wall_timeout)
1321 if (wall_timeout)
1310 {
1322 {
1311 struct timeval now, wall;
1323 struct timeval now, wall;
1312 int wall_ms;
1324 int wall_ms;
1313 gettimeofday(&now, NULL);
1325 gettimeofday(&now, NULL);
1314 timersub(&now, &start_time, &wall);
1326 timersub(&now, &start_time, &wall);
1315 wall_ms = wall.tv_sec*1000 + wall.tv_usec/1000;
1327 wall_ms = wall.tv_sec*1000 + wall.tv_usec/1000;
1316 if (wall_ms > wall_timeout)
1328 if (wall_ms > wall_timeout)
1317 err("TO: Time limit exceeded (wall clock)");
1329 err("TO: Time limit exceeded (wall clock)");
1318 if (verbose > 1)
1330 if (verbose > 1)
1319 fprintf(stderr, "[wall time check: %d msec]\n", wall_ms);
1331 fprintf(stderr, "[wall time check: %d msec]\n", wall_ms);
1320 }
1332 }
1321 if (timeout)
1333 if (timeout)
1322 {
1334 {
1323 char buf[PROC_BUF_SIZE], *x;
1335 char buf[PROC_BUF_SIZE], *x;
1324 int utime, stime, ms;
1336 int utime, stime, ms;
1325 static int proc_stat_fd;
1337 static int proc_stat_fd;
1326 read_proc_file(buf, "stat", &proc_stat_fd);
1338 read_proc_file(buf, "stat", &proc_stat_fd);
1327 x = buf;
1339 x = buf;
1328 while (*x && *x != ' ')
1340 while (*x && *x != ' ')
1329 x++;
1341 x++;
1330 while (*x == ' ')
1342 while (*x == ' ')
1331 x++;
1343 x++;
1332 if (*x++ != '(')
1344 if (*x++ != '(')
1333 die("proc stat syntax error 1");
1345 die("proc stat syntax error 1");
1334 while (*x && (*x != ')' || x[1] != ' '))
1346 while (*x && (*x != ')' || x[1] != ' '))
1335 x++;
1347 x++;
1336 while (*x == ')' || *x == ' ')
1348 while (*x == ')' || *x == ' ')
1337 x++;
1349 x++;
1338 if (sscanf(x, "%*c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d", &utime, &stime) != 2)
1350 if (sscanf(x, "%*c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d", &utime, &stime) != 2)
1339 die("proc stat syntax error 2");
1351 die("proc stat syntax error 2");
1340 ms = (utime + stime) * 1000 / ticks_per_sec;
1352 ms = (utime + stime) * 1000 / ticks_per_sec;
1341 if (verbose > 1)
1353 if (verbose > 1)
1342 fprintf(stderr, "[time check: %d msec]\n", ms);
1354 fprintf(stderr, "[time check: %d msec]\n", ms);
1343 if (ms > timeout && ms > extra_timeout)
1355 if (ms > timeout && ms > extra_timeout)
1344 err("TO: Time limit exceeded");
1356 err("TO: Time limit exceeded");
1345 }
1357 }
1346 }
1358 }
1347
1359
1348 static void
1360 static void
1349 sample_mem_peak(void)
1361 sample_mem_peak(void)
1350 {
1362 {
1351 /*
1363 /*
1352 * We want to find out the peak memory usage of the process, which is
1364 * We want to find out the peak memory usage of the process, which is
1353 * maintained by the kernel, but unforunately it gets lost when the
1365 * maintained by the kernel, but unforunately it gets lost when the
1354 * process exits (it is not reported in struct rusage). Therefore we
1366 * process exits (it is not reported in struct rusage). Therefore we
1355 * have to sample it whenever we suspect that the process is about
1367 * have to sample it whenever we suspect that the process is about
1356 * to exit.
1368 * to exit.
1357 */
1369 */
1358 char buf[PROC_BUF_SIZE], *x;
1370 char buf[PROC_BUF_SIZE], *x;
1359 static int proc_status_fd;
1371 static int proc_status_fd;
1360 read_proc_file(buf, "status", &proc_status_fd);
1372 read_proc_file(buf, "status", &proc_status_fd);
1361
1373
1362 x = buf;
1374 x = buf;
1363 while (*x)
1375 while (*x)
1364 {
1376 {
1365 char *key = x;
1377 char *key = x;
1366 while (*x && *x != ':' && *x != '\n')
1378 while (*x && *x != ':' && *x != '\n')
1367 x++;
1379 x++;
1368 if (!*x || *x == '\n')
1380 if (!*x || *x == '\n')
1369 break;
1381 break;
1370 *x++ = 0;
1382 *x++ = 0;
1371 while (*x == ' ' || *x == '\t')
1383 while (*x == ' ' || *x == '\t')
1372 x++;
1384 x++;
1373
1385
1374 char *val = x;
1386 char *val = x;
1375 while (*x && *x != '\n')
1387 while (*x && *x != '\n')
1376 x++;
1388 x++;
1377 if (!*x)
1389 if (!*x)
1378 break;
1390 break;
1379 *x++ = 0;
1391 *x++ = 0;
1380
1392
1381 if (!strcmp(key, "VmPeak"))
1393 if (!strcmp(key, "VmPeak"))
1382 {
1394 {
1383 int peak = atoi(val);
1395 int peak = atoi(val);
1384 if (peak > mem_peak_kb)
1396 if (peak > mem_peak_kb)
1385 mem_peak_kb = peak;
1397 mem_peak_kb = peak;
1386 }
1398 }
1387 }
1399 }
1388
1400
1389 if (verbose > 1)
1401 if (verbose > 1)
1390 msg("[mem-peak: %u KB]\n", mem_peak_kb);
1402 msg("[mem-peak: %u KB]\n", mem_peak_kb);
1391 }
1403 }
1392
1404
1393 static void
1405 static void
1394 boxkeeper(void)
1406 boxkeeper(void)
1395 {
1407 {
1396 int syscall_count = (filter_syscalls ? 0 : 1);
1408 int syscall_count = (filter_syscalls ? 0 : 1);
1397 struct sigaction sa;
1409 struct sigaction sa;
1398
1410
1399 is_ptraced = 1;
1411 is_ptraced = 1;
1400
1412
1401 bzero(&sa, sizeof(sa));
1413 bzero(&sa, sizeof(sa));
1402 sa.sa_handler = signal_int;
1414 sa.sa_handler = signal_int;
1403 sigaction(SIGINT, &sa, NULL);
1415 sigaction(SIGINT, &sa, NULL);
1404
1416
1405 gettimeofday(&start_time, NULL);
1417 gettimeofday(&start_time, NULL);
1406 ticks_per_sec = sysconf(_SC_CLK_TCK);
1418 ticks_per_sec = sysconf(_SC_CLK_TCK);
1407 if (ticks_per_sec <= 0)
1419 if (ticks_per_sec <= 0)
1408 die("Invalid ticks_per_sec!");
1420 die("Invalid ticks_per_sec!");
1409
1421
1410 if (timeout || wall_timeout)
1422 if (timeout || wall_timeout)
1411 {
1423 {
1412 sa.sa_handler = signal_alarm;
1424 sa.sa_handler = signal_alarm;
1413 sigaction(SIGALRM, &sa, NULL);
1425 sigaction(SIGALRM, &sa, NULL);
1414 alarm(1);
1426 alarm(1);
1415 }
1427 }
1416
1428
1417 for(;;)
1429 for(;;)
1418 {
1430 {
1419 struct rusage rus;
1431 struct rusage rus;
1420 int stat;
1432 int stat;
1421 pid_t p;
1433 pid_t p;
1422 if (timer_tick)
1434 if (timer_tick)
1423 {
1435 {
1424 check_timeout();
1436 check_timeout();
1425 timer_tick = 0;
1437 timer_tick = 0;
1426 }
1438 }
1427 p = wait4(box_pid, &stat, WUNTRACED, &rus);
1439 p = wait4(box_pid, &stat, WUNTRACED, &rus);
1428 if (p < 0)
1440 if (p < 0)
1429 {
1441 {
1430 if (errno == EINTR)
1442 if (errno == EINTR)
1431 continue;
1443 continue;
1432 die("wait4: %m");
1444 die("wait4: %m");
1433 }
1445 }
1434 if (p != box_pid)
1446 if (p != box_pid)
1435 die("wait4: unknown pid %d exited!", p);
1447 die("wait4: unknown pid %d exited!", p);
1436 if (WIFEXITED(stat))
1448 if (WIFEXITED(stat))
1437 {
1449 {
1438 box_pid = 0;
1450 box_pid = 0;
1439 final_stats(&rus);
1451 final_stats(&rus);
1440 if (WEXITSTATUS(stat))
1452 if (WEXITSTATUS(stat))
1441 {
1453 {
1442 if (syscall_count)
1454 if (syscall_count)
1443 {
1455 {
1444 meta_printf("exitcode:%d\n", WEXITSTATUS(stat));
1456 meta_printf("exitcode:%d\n", WEXITSTATUS(stat));
1445 err("RE: Exited with error status %d", WEXITSTATUS(stat));
1457 err("RE: Exited with error status %d", WEXITSTATUS(stat));
1446 }
1458 }
1447 else
1459 else
1448 {
1460 {
1449 // Internal error happened inside the child process and it has been already reported.
1461 // Internal error happened inside the child process and it has been already reported.
1450 box_exit(2);
1462 box_exit(2);
1451 }
1463 }
1452 }
1464 }
1453 if (timeout && total_ms > timeout)
1465 if (timeout && total_ms > timeout)
1454 err("TO: Time limit exceeded");
1466 err("TO: Time limit exceeded");
1455 if (wall_timeout && wall_ms > wall_timeout)
1467 if (wall_timeout && wall_ms > wall_timeout)
1456 err("TO: Time limit exceeded (wall clock)");
1468 err("TO: Time limit exceeded (wall clock)");
1457 flush_line();
1469 flush_line();
1458 fprintf(stderr,"OK\n");
1470 fprintf(stderr,"OK\n");
1459 box_exit(0);
1471 box_exit(0);
1460 }
1472 }
1461 if (WIFSIGNALED(stat))
1473 if (WIFSIGNALED(stat))
1462 {
1474 {
1463 box_pid = 0;
1475 box_pid = 0;
1464 meta_printf("exitsig:%d\n", WTERMSIG(stat));
1476 meta_printf("exitsig:%d\n", WTERMSIG(stat));
1465 final_stats(&rus);
1477 final_stats(&rus);
1466 err("SG: Caught fatal signal %d%s", WTERMSIG(stat), (syscall_count ? "" : " during startup"));
1478 err("SG: Caught fatal signal %d%s", WTERMSIG(stat), (syscall_count ? "" : " during startup"));
1467 }
1479 }
1468 if (WIFSTOPPED(stat))
1480 if (WIFSTOPPED(stat))
1469 {
1481 {
1470 int sig = WSTOPSIG(stat);
1482 int sig = WSTOPSIG(stat);
1471 if (sig == SIGTRAP)
1483 if (sig == SIGTRAP)
1472 {
1484 {
1473 if (verbose > 2)
1485 if (verbose > 2)
1474 msg("[ptrace status %08x] ", stat);
1486 msg("[ptrace status %08x] ", stat);
1475 static int stop_count;
1487 static int stop_count;
1476 if (!stop_count++) /* Traceme request */
1488 if (!stop_count++) /* Traceme request */
1477 msg(">> Traceme request caught\n");
1489 msg(">> Traceme request caught\n");
1478 else
1490 else
1479 err("SG: Breakpoint");
1491 err("SG: Breakpoint");
1480 ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
1492 ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
1481 }
1493 }
1482 else if (sig == (SIGTRAP | 0x80))
1494 else if (sig == (SIGTRAP | 0x80))
1483 {
1495 {
1484 if (verbose > 2)
1496 if (verbose > 2)
1485 msg("[ptrace status %08x] ", stat);
1497 msg("[ptrace status %08x] ", stat);
1486 struct syscall_args a;
1498 struct syscall_args a;
1487 static unsigned int sys_tick, last_act;
1499 static unsigned int sys_tick, last_act;
1488 static arg_t last_sys;
1500 static arg_t last_sys;
1489 if (++sys_tick & 1) /* Syscall entry */
1501 if (++sys_tick & 1) /* Syscall entry */
1490 {
1502 {
1491 char namebuf[32];
1503 char namebuf[32];
1492 int act;
1504 int act;
1493
1505
1494 get_syscall_args(&a, 0);
1506 get_syscall_args(&a, 0);
1495 arg_t sys = a.sys;
1507 arg_t sys = a.sys;
1496 msg(">> Syscall %-12s (%08jx,%08jx,%08jx) ", syscall_name(sys, namebuf), (intmax_t) a.arg1, (intmax_t) a.arg2, (intmax_t) a.arg3);
1508 msg(">> Syscall %-12s (%08jx,%08jx,%08jx) ", syscall_name(sys, namebuf), (intmax_t) a.arg1, (intmax_t) a.arg2, (intmax_t) a.arg3);
1497 if (!exec_seen)
1509 if (!exec_seen)
1498 {
1510 {
1499 msg("[master] ");
1511 msg("[master] ");
1500 if (sys == NATIVE_NR_execve)
1512 if (sys == NATIVE_NR_execve)
1501 {
1513 {
1502 exec_seen = 1;
1514 exec_seen = 1;
1503 close_user_mem();
1515 close_user_mem();
1504 }
1516 }
1505 }
1517 }
1506 else if ((act = valid_syscall(&a)) >= 0)
1518 else if ((act = valid_syscall(&a)) >= 0)
1507 {
1519 {
1508 last_act = act;
1520 last_act = act;
1509 syscall_count++;
1521 syscall_count++;
1510 if (act & A_SAMPLE_MEM)
1522 if (act & A_SAMPLE_MEM)
1511 sample_mem_peak();
1523 sample_mem_peak();
1512 }
1524 }
1513 else
1525 else
1514 {
1526 {
1515 /*
1527 /*
1516 * Unfortunately, PTRACE_KILL kills _after_ the syscall completes,
1528 * Unfortunately, PTRACE_KILL kills _after_ the syscall completes,
1517 * so we have to change it to something harmless (e.g., an undefined
1529 * so we have to change it to something harmless (e.g., an undefined
1518 * syscall) and make the program continue.
1530 * syscall) and make the program continue.
1519 */
1531 */
1520 set_syscall_nr(&a, ~(arg_t)0);
1532 set_syscall_nr(&a, ~(arg_t)0);
1521 err("FO: Forbidden syscall %s", syscall_name(sys, namebuf));
1533 err("FO: Forbidden syscall %s", syscall_name(sys, namebuf));
1522 }
1534 }
1523 last_sys = sys;
1535 last_sys = sys;
1524 }
1536 }
1525 else /* Syscall return */
1537 else /* Syscall return */
1526 {
1538 {
1527 get_syscall_args(&a, 1);
1539 get_syscall_args(&a, 1);
1528 if (a.sys == ~(arg_t)0)
1540 if (a.sys == ~(arg_t)0)
1529 {
1541 {
1530 /* Some syscalls (sigreturn et al.) do not return a value */
1542 /* Some syscalls (sigreturn et al.) do not return a value */
1531 if (!(last_act & A_NO_RETVAL))
1543 if (!(last_act & A_NO_RETVAL))
1532 err("XX: Syscall does not return, but it should");
1544 err("XX: Syscall does not return, but it should");
1533 }
1545 }
1534 else
1546 else
1535 {
1547 {
1536 if (a.sys != last_sys)
1548 if (a.sys != last_sys)
1537 err("XX: Mismatched syscall entry/exit");
1549 err("XX: Mismatched syscall entry/exit");
1538 }
1550 }
1539 if (last_act & A_NO_RETVAL)
1551 if (last_act & A_NO_RETVAL)
1540 msg("= ?\n");
1552 msg("= ?\n");
1541 else
1553 else
1542 msg("= %jd\n", (intmax_t) a.result);
1554 msg("= %jd\n", (intmax_t) a.result);
1543 }
1555 }
1544 ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
1556 ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
1545 }
1557 }
1546 else if (sig == SIGSTOP)
1558 else if (sig == SIGSTOP)
1547 {
1559 {
1548 msg(">> SIGSTOP\n");
1560 msg(">> SIGSTOP\n");
1549 if (ptrace(PTRACE_SETOPTIONS, box_pid, NULL, (void *) PTRACE_O_TRACESYSGOOD) < 0)
1561 if (ptrace(PTRACE_SETOPTIONS, box_pid, NULL, (void *) PTRACE_O_TRACESYSGOOD) < 0)
1550 die("ptrace(PTRACE_SETOPTIONS): %m");
1562 die("ptrace(PTRACE_SETOPTIONS): %m");
1551 ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
1563 ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
1552 }
1564 }
1553 else if (sig != SIGXCPU && sig != SIGXFSZ)
1565 else if (sig != SIGXCPU && sig != SIGXFSZ)
1554 {
1566 {
1555 msg(">> Signal %d\n", sig);
1567 msg(">> Signal %d\n", sig);
1556 sample_mem_peak(); /* Signal might be fatal, so update mem-peak */
1568 sample_mem_peak(); /* Signal might be fatal, so update mem-peak */
1557 ptrace(PTRACE_SYSCALL, box_pid, 0, sig);
1569 ptrace(PTRACE_SYSCALL, box_pid, 0, sig);
1558 }
1570 }
1559 else
1571 else
1560 {
1572 {
1561 meta_printf("exitsig:%d", sig);
1573 meta_printf("exitsig:%d", sig);
1562 err("SG: Received signal %d", sig);
1574 err("SG: Received signal %d", sig);
1563 }
1575 }
1564 }
1576 }
1565 else
1577 else
1566 die("wait4: unknown status %x, giving up!", stat);
1578 die("wait4: unknown status %x, giving up!", stat);
1567 }
1579 }
1568 }
1580 }
1569
1581
1570 static void
1582 static void
1571 box_inside(int argc, char **argv)
1583 box_inside(int argc, char **argv)
1572 {
1584 {
1573 struct rlimit rl;
1585 struct rlimit rl;
1574 char *args[argc+1];
1586 char *args[argc+1];
1575
1587
1576 memcpy(args, argv, argc * sizeof(char *));
1588 memcpy(args, argv, argc * sizeof(char *));
1577 args[argc] = NULL;
1589 args[argc] = NULL;
1578 if (set_cwd && chdir(set_cwd))
1590 if (set_cwd && chdir(set_cwd))
1579 die("chdir: %m");
1591 die("chdir: %m");
1580 if (redir_stdin)
1592 if (redir_stdin)
1581 {
1593 {
1582 close(0);
1594 close(0);
1583 if (open(redir_stdin, O_RDONLY) != 0)
1595 if (open(redir_stdin, O_RDONLY) != 0)
1584 die("open(\"%s\"): %m", redir_stdin);
1596 die("open(\"%s\"): %m", redir_stdin);
1585 }
1597 }
1586 if (redir_stdout)
1598 if (redir_stdout)
1587 {
1599 {
1588 close(1);
1600 close(1);
1589 if (open(redir_stdout, O_WRONLY | O_CREAT | O_TRUNC, 0666) != 1)
1601 if (open(redir_stdout, O_WRONLY | O_CREAT | O_TRUNC, 0666) != 1)
1590 die("open(\"%s\"): %m", redir_stdout);
1602 die("open(\"%s\"): %m", redir_stdout);
1591 }
1603 }
1592 if (redir_stderr)
1604 if (redir_stderr)
1593 {
1605 {
1594 close(2);
1606 close(2);
1595 if (open(redir_stderr, O_WRONLY | O_CREAT | O_TRUNC, 0666) != 2)
1607 if (open(redir_stderr, O_WRONLY | O_CREAT | O_TRUNC, 0666) != 2)
1596 die("open(\"%s\"): %m", redir_stderr);
1608 die("open(\"%s\"): %m", redir_stderr);
1597 }
1609 }
1598 else
1610 else
1599 dup2(1, 2);
1611 dup2(1, 2);
1600 setpgrp();
1612 setpgrp();
1601
1613
1602 if (memory_limit)
1614 if (memory_limit)
1603 {
1615 {
1604 rl.rlim_cur = rl.rlim_max = memory_limit * 1024;
1616 rl.rlim_cur = rl.rlim_max = memory_limit * 1024;
1605 if (setrlimit(RLIMIT_AS, &rl) < 0)
1617 if (setrlimit(RLIMIT_AS, &rl) < 0)
1606 die("setrlimit(RLIMIT_AS): %m");
1618 die("setrlimit(RLIMIT_AS): %m");
1607 }
1619 }
1608
1620
1609 rl.rlim_cur = rl.rlim_max = (stack_limit ? (rlim_t)stack_limit * 1024 : RLIM_INFINITY);
1621 rl.rlim_cur = rl.rlim_max = (stack_limit ? (rlim_t)stack_limit * 1024 : RLIM_INFINITY);
1610 if (setrlimit(RLIMIT_STACK, &rl) < 0)
1622 if (setrlimit(RLIMIT_STACK, &rl) < 0)
1611 die("setrlimit(RLIMIT_STACK): %m");
1623 die("setrlimit(RLIMIT_STACK): %m");
1612
1624
1613 rl.rlim_cur = rl.rlim_max = 64;
1625 rl.rlim_cur = rl.rlim_max = 64;
1614 if (setrlimit(RLIMIT_NOFILE, &rl) < 0)
1626 if (setrlimit(RLIMIT_NOFILE, &rl) < 0)
1615 die("setrlimit(RLIMIT_NOFILE): %m");
1627 die("setrlimit(RLIMIT_NOFILE): %m");
1616
1628
1617 char **env = setup_environment();
1629 char **env = setup_environment();
1618 if (filter_syscalls)
1630 if (filter_syscalls)
1619 {
1631 {
1620 if (ptrace(PTRACE_TRACEME) < 0)
1632 if (ptrace(PTRACE_TRACEME) < 0)
1621 die("ptrace(PTRACE_TRACEME): %m");
1633 die("ptrace(PTRACE_TRACEME): %m");
1622 /* Trick: Make sure that we are stopped until the boxkeeper wakes up. */
1634 /* Trick: Make sure that we are stopped until the boxkeeper wakes up. */
1623 raise(SIGSTOP);
1635 raise(SIGSTOP);
1624 }
1636 }
1625 execve(args[0], args, env);
1637 execve(args[0], args, env);
1626 die("execve(\"%s\"): %m", args[0]);
1638 die("execve(\"%s\"): %m", args[0]);
1627 }
1639 }
1628
1640
1629 static void
1641 static void
1630 usage(void)
1642 usage(void)
1631 {
1643 {
1632 fprintf(stderr, "Invalid arguments!\n");
1644 fprintf(stderr, "Invalid arguments!\n");
1633 printf("\
1645 printf("\
1634 Usage: box [<options>] -- <command> <arguments>\n\
1646 Usage: box [<options>] -- <command> <arguments>\n\
1635 \n\
1647 \n\
1636 Options:\n\
1648 Options:\n\
1637 -a <level>\tSet file access level (0=none, 1=cwd, 2=/etc,/lib,..., 3=whole fs, 9=no checks; needs -f)\n\
1649 -a <level>\tSet file access level (0=none, 1=cwd, 2=/etc,/lib,..., 3=whole fs, 9=no checks; needs -f)\n\
1638 -c <dir>\tChange directory to <dir> first\n\
1650 -c <dir>\tChange directory to <dir> first\n\
1639 -e\t\tInherit full environment of the parent process\n\
1651 -e\t\tInherit full environment of the parent process\n\
1640 -E <var>\tInherit the environment variable <var> from the parent process\n\
1652 -E <var>\tInherit the environment variable <var> from the parent process\n\
1641 -E <var>=<val>\tSet the environment variable <var> to <val>; unset it if <var> is empty\n\
1653 -E <var>=<val>\tSet the environment variable <var> to <val>; unset it if <var> is empty\n\
1642 -f\t\tFilter system calls (-ff=very restricted)\n\
1654 -f\t\tFilter system calls (-ff=very restricted)\n\
1643 -i <file>\tRedirect stdin from <file>\n\
1655 -i <file>\tRedirect stdin from <file>\n\
1644 -k <size>\tLimit stack size to <size> KB (default: 0=unlimited)\n\
1656 -k <size>\tLimit stack size to <size> KB (default: 0=unlimited)\n\
1645 -m <size>\tLimit address space to <size> KB\n\
1657 -m <size>\tLimit address space to <size> KB\n\
1646 -M <file>\tOutput process information to <file> (name:value)\n\
1658 -M <file>\tOutput process information to <file> (name:value)\n\
1647 -o <file>\tRedirect stdout to <file>\n\
1659 -o <file>\tRedirect stdout to <file>\n\
1648 -p <path>\tPermit access to the specified path (or subtree if it ends with a `/')\n\
1660 -p <path>\tPermit access to the specified path (or subtree if it ends with a `/')\n\
1649 -p <path>=<act>\tDefine action for the specified path (<act>=yes/no)\n\
1661 -p <path>=<act>\tDefine action for the specified path (<act>=yes/no)\n\
1650 -r <file>\tRedirect stderr to <file>\n\
1662 -r <file>\tRedirect stderr to <file>\n\
1651 -s <sys>\tPermit the specified syscall (be careful)\n\
1663 -s <sys>\tPermit the specified syscall (be careful)\n\
1652 -s <sys>=<act>\tDefine action for the specified syscall (<act>=yes/no/file)\n\
1664 -s <sys>=<act>\tDefine action for the specified syscall (<act>=yes/no/file)\n\
1653 -t <time>\tSet run time limit (seconds, fractions allowed)\n\
1665 -t <time>\tSet run time limit (seconds, fractions allowed)\n\
1654 -T\t\tAllow syscalls for measuring run time\n\
1666 -T\t\tAllow syscalls for measuring run time\n\
1655 -v\t\tBe verbose (use multiple times for even more verbosity)\n\
1667 -v\t\tBe verbose (use multiple times for even more verbosity)\n\
1656 -w <time>\tSet wall clock time limit (seconds, fractions allowed)\n\
1668 -w <time>\tSet wall clock time limit (seconds, fractions allowed)\n\
1657 -x <time>\tSet extra timeout, before which a timing-out program is not yet killed,\n\
1669 -x <time>\tSet extra timeout, before which a timing-out program is not yet killed,\n\
1658 \t\tso that its real execution time is reported (seconds, fractions allowed)\n\
1670 \t\tso that its real execution time is reported (seconds, fractions allowed)\n\
1659 -A <opt>\tPass <opt> as additional argument to the <command>\n\
1671 -A <opt>\tPass <opt> as additional argument to the <command>\n\
1660 \t\tBe noted that this option will be appended after <arguments> respectively\n\
1672 \t\tBe noted that this option will be appended after <arguments> respectively\n\
1661 ");
1673 ");
1662 exit(2);
1674 exit(2);
1663 }
1675 }
1664
1676
1665 int
1677 int
1666 main(int argc, char **argv)
1678 main(int argc, char **argv)
1667 {
1679 {
1668 int c;
1680 int c;
1669 uid_t uid;
1681 uid_t uid;
1670 char **prog_argv = xmalloc(sizeof(char*) * argc);
1682 char **prog_argv = xmalloc(sizeof(char*) * argc);
1671 int prog_argc = 0;
1683 int prog_argc = 0;
1672
1684
1673 while ((c = getopt(argc, argv, "a:c:eE:fi:k:m:M:o:p:r:s:t:Tvw:x:A:")) >= 0)
1685 while ((c = getopt(argc, argv, "a:c:eE:fi:k:m:M:o:p:r:s:t:Tvw:x:A:")) >= 0)
1674 switch (c)
1686 switch (c)
1675 {
1687 {
1676 case 'a':
1688 case 'a':
1677 file_access = atol(optarg);
1689 file_access = atol(optarg);
1678 break;
1690 break;
1679 case 'c':
1691 case 'c':
1680 set_cwd = optarg;
1692 set_cwd = optarg;
1681 break;
1693 break;
1682 case 'e':
1694 case 'e':
1683 pass_environ = 1;
1695 pass_environ = 1;
1684 break;
1696 break;
1685 case 'E':
1697 case 'E':
1686 if (!set_env_action(optarg))
1698 if (!set_env_action(optarg))
1687 usage();
1699 usage();
1688 break;
1700 break;
1689 case 'f':
1701 case 'f':
1690 filter_syscalls++;
1702 filter_syscalls++;
1691 break;
1703 break;
1692 case 'k':
1704 case 'k':
1693 stack_limit = atol(optarg);
1705 stack_limit = atol(optarg);
1694 break;
1706 break;
1695 case 'i':
1707 case 'i':
1696 redir_stdin = optarg;
1708 redir_stdin = optarg;
1697 break;
1709 break;
1698 case 'm':
1710 case 'm':
1699 memory_limit = atol(optarg);
1711 memory_limit = atol(optarg);
1700 break;
1712 break;
1701 case 'M':
1713 case 'M':
1702 meta_open(optarg);
1714 meta_open(optarg);
1703 break;
1715 break;
1704 case 'o':
1716 case 'o':
1705 redir_stdout = optarg;
1717 redir_stdout = optarg;
1706 break;
1718 break;
1707 case 'p':
1719 case 'p':
1708 if (!set_path_action(optarg))
1720 if (!set_path_action(optarg))
1709 usage();
1721 usage();
1710 break;
1722 break;
1711 case 'r':
1723 case 'r':
1712 redir_stderr = optarg;
1724 redir_stderr = optarg;
1713 break;
1725 break;
1714 case 's':
1726 case 's':
1715 if (!set_syscall_action(optarg))
1727 if (!set_syscall_action(optarg))
1716 usage();
1728 usage();
1717 break;
1729 break;
1718 case 't':
1730 case 't':
1719 timeout = 1000*atof(optarg);
1731 timeout = 1000*atof(optarg);
1720 break;
1732 break;
1721 case 'T':
1733 case 'T':
1722 syscall_action[__NR_times] = A_YES;
1734 syscall_action[__NR_times] = A_YES;
1723 break;
1735 break;
1724 case 'v':
1736 case 'v':
1725 verbose++;
1737 verbose++;
1726 break;
1738 break;
1727 case 'w':
1739 case 'w':
1728 wall_timeout = 1000*atof(optarg);
1740 wall_timeout = 1000*atof(optarg);
1729 break;
1741 break;
1730 case 'x':
1742 case 'x':
1731 extra_timeout = 1000*atof(optarg);
1743 extra_timeout = 1000*atof(optarg);
1732 case 'A':
1744 case 'A':
1733 prog_argv[prog_argc++] = strdup(optarg);
1745 prog_argv[prog_argc++] = strdup(optarg);
1734 break;
1746 break;
1735 break;
1747 break;
1736 default:
1748 default:
1737 usage();
1749 usage();
1738 }
1750 }
1739 if (optind >= argc)
1751 if (optind >= argc)
1740 usage();
1752 usage();
1741
1753
1742 sanity_check();
1754 sanity_check();
1743 uid = geteuid();
1755 uid = geteuid();
1744 if (setreuid(uid, uid) < 0)
1756 if (setreuid(uid, uid) < 0)
1745 die("setreuid: %m");
1757 die("setreuid: %m");
1746 box_pid = fork();
1758 box_pid = fork();
1747 if (box_pid < 0)
1759 if (box_pid < 0)
1748 die("fork: %m");
1760 die("fork: %m");
1749 if (!box_pid) {
1761 if (!box_pid) {
1750 int real_argc = prog_argc + argc - optind;
1762 int real_argc = prog_argc + argc - optind;
1751 char **real_argv = xmalloc(sizeof(char*) * (real_argc));
1763 char **real_argv = xmalloc(sizeof(char*) * (real_argc));
1752 for (int i = 0;i < argc-optind;i++)
1764 for (int i = 0;i < argc-optind;i++)
1753 real_argv[i] = strdup(argv[i+optind]);
1765 real_argv[i] = strdup(argv[i+optind]);
1754 for (int i = 0;i < prog_argc;i++)
1766 for (int i = 0;i < prog_argc;i++)
1755 real_argv[argc - optind + i] = strdup(prog_argv[i]);
1767 real_argv[argc - optind + i] = strdup(prog_argv[i]);
1756 box_inside(real_argc, real_argv);
1768 box_inside(real_argc, real_argv);
1757 } else
1769 } else
1758 boxkeeper();
1770 boxkeeper();
1759 die("Internal error: fell over edge of the world");
1771 die("Internal error: fell over edge of the world");
1760 }
1772 }
@@ -1,188 +1,196
1 #!/usr/bin/env ruby
1 #!/usr/bin/env ruby
2
2
3 require 'fileutils'
3 require 'fileutils'
4
4
5 ##############################
5 ##############################
6 #
6 #
7 # Standard Compile Script
7 # Standard Compile Script
8 #
8 #
9 # Supported compilers:
9 # Supported compilers:
10 # gcc, g++, and fpc.
10 # gcc, g++, and fpc.
11 #
11 #
12 ##############################
12 ##############################
13
13
14 def talk(str='')
14 def talk(str='')
15 if ENV['TALKATIVE']!=nil
15 if ENV['TALKATIVE']!=nil
16 puts str
16 puts str
17 end
17 end
18 if ENV['GRADER_LOGGING']!=nil
18 if ENV['GRADER_LOGGING']!=nil
19 log_fname = ENV['GRADER_LOGGING']
19 log_fname = ENV['GRADER_LOGGING']
20 fp = File.open(log_fname,"a")
20 fp = File.open(log_fname,"a")
21 fp.puts("run: #{Time.new.strftime("%H:%M")} #{str}")
21 fp.puts("run: #{Time.new.strftime("%H:%M")} #{str}")
22 fp.close
22 fp.close
23 end
23 end
24 end
24 end
25
25
26 C_COMPILER = "/usr/bin/gcc"
26 C_COMPILER = "/usr/bin/gcc"
27 CPLUSPLUS_COMPILER = "/usr/bin/g++"
27 CPLUSPLUS_COMPILER = "/usr/bin/g++"
28 PASCAL_COMPILER = "/usr/bin/fpc"
28 PASCAL_COMPILER = "/usr/bin/fpc"
29 JAVA_COMPILER = "/usr/bin/javac"
29 JAVA_COMPILER = "/usr/bin/javac"
30 RUBY_INTERPRETER = "/usr/bin/ruby"
30 RUBY_INTERPRETER = "/usr/bin/ruby"
31 - PYTHON_INTERPRETER = "/usr/bin/python"
31 + PYTHON_INTERPRETER = "/usr/bin/python3"
32 PYTHON_CHECKER = "/usr/bin/pyflakes"
32 PYTHON_CHECKER = "/usr/bin/pyflakes"
33 PHP_INTERPRETER = "/usr/bin/php"
33 PHP_INTERPRETER = "/usr/bin/php"
34 + HASKELL_COMPILER = "/usr/bin/ghc"
34
35
35 C_OPTIONS = "-O2 -s -static -std=c99 -DCONTEST -lm -Wall"
36 C_OPTIONS = "-O2 -s -static -std=c99 -DCONTEST -lm -Wall"
36 CPLUSPLUS_OPTIONS = "-O2 -s -std=c++11 -static -DCONTEST -lm -Wall"
37 CPLUSPLUS_OPTIONS = "-O2 -s -std=c++11 -static -DCONTEST -lm -Wall"
37 PASCAL_OPTIONS = "-O1 -XS -dCONTEST"
38 PASCAL_OPTIONS = "-O1 -XS -dCONTEST"
38 JAVA_OPTIONS = ""
39 JAVA_OPTIONS = ""
39 PYTHON_OPTIONS = ""
40 PYTHON_OPTIONS = ""
40 PHP_OPTIONS = "-l"
41 PHP_OPTIONS = "-l"
42 + HASKELL_OPTIONS = ""
41
43
42 # Check for the correct number of arguments. Otherwise, print usage.
44 # Check for the correct number of arguments. Otherwise, print usage.
43 if ARGV.length == 0 or ARGV.length > 4
45 if ARGV.length == 0 or ARGV.length > 4
44 puts "Usage: compile <language> [<source-file>] [<output-file>] [<message-file>]"
46 puts "Usage: compile <language> [<source-file>] [<output-file>] [<message-file>]"
45 puts
47 puts
46 puts "<source-file> is defaulted to \"source\"."
48 puts "<source-file> is defaulted to \"source\"."
47 puts "<output-file> is defaulted to \"a.out\"."
49 puts "<output-file> is defaulted to \"a.out\"."
48 puts "<message-file> is defaulted to \"compiler_message\"."
50 puts "<message-file> is defaulted to \"compiler_message\"."
49 puts
51 puts
50 exit(127)
52 exit(127)
51 end
53 end
52
54
53 PARAMS = {
55 PARAMS = {
54 :source_file => [1,'source'],
56 :source_file => [1,'source'],
55 :output_file => [2,'a.out'],
57 :output_file => [2,'a.out'],
56 :message_file => [3,'compiler_message']
58 :message_file => [3,'compiler_message']
57 }
59 }
58
60
59 params = {}
61 params = {}
60 params[:prog_lang] = ARGV[0]
62 params[:prog_lang] = ARGV[0]
61 PARAMS.each_key do |param_name|
63 PARAMS.each_key do |param_name|
62 index, default = PARAMS[param_name]
64 index, default = PARAMS[param_name]
63 if ARGV.length > index
65 if ARGV.length > index
64 params[param_name] = ARGV[index]
66 params[param_name] = ARGV[index]
65 else
67 else
66 params[param_name] = default
68 params[param_name] = default
67 end
69 end
68 talk "#{param_name}: #{params[param_name]}"
70 talk "#{param_name}: #{params[param_name]}"
69 end
71 end
70
72
71 # Remove any remaining output files or message files.
73 # Remove any remaining output files or message files.
72 if FileTest.exists? params[:output_file]
74 if FileTest.exists? params[:output_file]
73 FileUtils.rm(params[:output_file])
75 FileUtils.rm(params[:output_file])
74 end
76 end
75 if FileTest.exists? params[:message_file]
77 if FileTest.exists? params[:message_file]
76 FileUtils.rm(params[:message_file])
78 FileUtils.rm(params[:message_file])
77 end
79 end
78
80
79 # Check if the source file exists before attempt compiling.
81 # Check if the source file exists before attempt compiling.
80 if !FileTest.exists? params[:source_file]
82 if !FileTest.exists? params[:source_file]
81 talk("ERROR: The source file does not exist!")
83 talk("ERROR: The source file does not exist!")
82 open(params[:message_file],"w") do |f|
84 open(params[:message_file],"w") do |f|
83 f.puts "ERROR: The source file did not exist."
85 f.puts "ERROR: The source file did not exist."
84 end
86 end
85 exit(127)
87 exit(127)
86 end
88 end
87
89
88 if params[:prog_lang]=='cpp'
90 if params[:prog_lang]=='cpp'
89 params[:prog_lang] = 'c++'
91 params[:prog_lang] = 'c++'
90 end
92 end
91
93
92 # Compile.
94 # Compile.
93 case params[:prog_lang]
95 case params[:prog_lang]
94
96
95 when "c"
97 when "c"
96 command = "#{C_COMPILER} #{params[:source_file]} -o #{params[:output_file]} #{C_OPTIONS}"
98 command = "#{C_COMPILER} #{params[:source_file]} -o #{params[:output_file]} #{C_OPTIONS}"
97 system(command, err: params[:message_file])
99 system(command, err: params[:message_file])
98
100
99 when "c++"
101 when "c++"
100 command = "#{CPLUSPLUS_COMPILER} #{params[:source_file]} -o #{params[:output_file]} #{CPLUSPLUS_OPTIONS}"
102 command = "#{CPLUSPLUS_COMPILER} #{params[:source_file]} -o #{params[:output_file]} #{CPLUSPLUS_OPTIONS}"
101 system(command, err: params[:message_file])
103 system(command, err: params[:message_file])
102
104
103 when "pas"
105 when "pas"
104 command = "#{PASCAL_COMPILER} #{params[:source_file]} -ooutpas #{PASCAL_OPTIONS}"
106 command = "#{PASCAL_COMPILER} #{params[:source_file]} -ooutpas #{PASCAL_OPTIONS}"
105 system(command,out: params[:message_file])
107 system(command,out: params[:message_file])
106 FileUtils.mv("output", params[:output_file])
108 FileUtils.mv("output", params[:output_file])
107
109
108 when "java"
110 when "java"
109 #rename the file to the public class name
111 #rename the file to the public class name
110
112
111 #get the class name
113 #get the class name
112 classname = 'DUMMY'
114 classname = 'DUMMY'
113 source = Array.new
115 source = Array.new
114 File.foreach(params[:source_file],'r:UTF-8') do |line|
116 File.foreach(params[:source_file],'r:UTF-8') do |line|
115 line.encode!('UTF-8','UTF-8',invalid: :replace, replace: '')
117 line.encode!('UTF-8','UTF-8',invalid: :replace, replace: '')
116 md = /\s*public\s*class\s*(\w*)/.match(line)
118 md = /\s*public\s*class\s*(\w*)/.match(line)
117 classname=md[1] if md
119 classname=md[1] if md
118 source << line unless line =~ /\s*package\s*\w+\s*\;/
120 source << line unless line =~ /\s*package\s*\w+\s*\;/
119 end
121 end
120 File.open("#{classname}.java","w") do |file|
122 File.open("#{classname}.java","w") do |file|
121 source.each do |s|
123 source.each do |s|
122 file.puts s
124 file.puts s
123 end
125 end
124 end
126 end
125 #system("cp #{params[:source_file]} #{classname}.java")
127 #system("cp #{params[:source_file]} #{classname}.java")
126 command = "#{JAVA_COMPILER} -encoding utf8 #{classname}.java"
128 command = "#{JAVA_COMPILER} -encoding utf8 #{classname}.java"
127 system(command, err: params[:message_file])
129 system(command, err: params[:message_file])
128 if File.exists?(classname + ".class")
130 if File.exists?(classname + ".class")
129 File.open(params[:output_file],"w") {|file| file.write("#{classname}")}
131 File.open(params[:output_file],"w") {|file| file.write("#{classname}")}
130 end
132 end
131 if classname == 'DUMMY'
133 if classname == 'DUMMY'
132 File.open(params[:message_file],"w") {|file| file.write("Cannot find any public class in the source code\n")}
134 File.open(params[:message_file],"w") {|file| file.write("Cannot find any public class in the source code\n")}
133 end
135 end
134
136
135 when "ruby"
137 when "ruby"
136 command = "#{RUBY_INTERPRETER} -c #{params[:source_file]}"
138 command = "#{RUBY_INTERPRETER} -c #{params[:source_file]}"
137 if system(command, err: params[:message_file])
139 if system(command, err: params[:message_file])
138 File.open(params[:output_file],"w") do |out_file|
140 File.open(params[:output_file],"w") do |out_file|
139 out_file.puts "#!#{RUBY_INTERPRETER}"
141 out_file.puts "#!#{RUBY_INTERPRETER}"
140 File.open(params[:source_file],"r").each do |line|
142 File.open(params[:source_file],"r").each do |line|
141 out_file.print line
143 out_file.print line
142 end
144 end
143 end
145 end
144 File.chmod(0755, params[:output_file])
146 File.chmod(0755, params[:output_file])
145 end
147 end
146
148
147 when "python"
149 when "python"
148 - command = "#{PYTHON_CHECKER} #{params[:source_file]}"
150 + #command = "#{PYTHON_CHECKER} #{params[:source_file]}"
149 - if system(command, out: params[:message_file])
151 + #if system(command, out: params[:message_file])
150 #compile to python bytecode
152 #compile to python bytecode
151 - command = "#{PYTHON_INTERPRETER} -m py_compile #{params[:source_file]}"
153 + command = "#{PYTHON_INTERPRETER} -c \"import py_compile; py_compile.compile('#{params[:source_file]}','#{params[:source_file]}c');\""
152 puts "compile: #{command}"
154 puts "compile: #{command}"
153 - system(command)
155 + system(command, err: params[:message_file])
156 + if FileTest.exists?("#{params[:source_file]}c")
154 puts "pwd: " + Dir.pwd
157 puts "pwd: " + Dir.pwd
155 Dir.new('.').each {|file| puts file}
158 Dir.new('.').each {|file| puts file}
156 File.open(params[:output_file],"w") do |out_file|
159 File.open(params[:output_file],"w") do |out_file|
157 out_file.puts "#!#{PYTHON_INTERPRETER} #{params[:source_file]}c"
160 out_file.puts "#!#{PYTHON_INTERPRETER} #{params[:source_file]}c"
158 end
161 end
159 File.chmod(0755, params[:output_file])
162 File.chmod(0755, params[:output_file])
160 FileUtils.cp("#{params[:source_file]}c",params[:output_file])
163 FileUtils.cp("#{params[:source_file]}c",params[:output_file])
161 end
164 end
165 + #end
162
166
163 when "php"
167 when "php"
164 command = "#{PHP_INTERPRETER} #{PHP_OPTIONS} #{params[:source_file]}"
168 command = "#{PHP_INTERPRETER} #{PHP_OPTIONS} #{params[:source_file]}"
165 if system(command, err: params[:message_file])
169 if system(command, err: params[:message_file])
166 File.open(params[:output_file],"w") do |out_file|
170 File.open(params[:output_file],"w") do |out_file|
167 out_file.puts "#!#{PHP_INTERPRETER}"
171 out_file.puts "#!#{PHP_INTERPRETER}"
168 File.open(params[:source_file],"r").each do |line|
172 File.open(params[:source_file],"r").each do |line|
169 out_file.print line
173 out_file.print line
170 end
174 end
171 end
175 end
172 File.chmod(0755, params[:output_file])
176 File.chmod(0755, params[:output_file])
173 end
177 end
174
178
179 + when "haskell"
180 + command = "#{HASKELL_COMPILER} #{params[:source_file]} -o #{params[:output_file]} #{HASKELL_OPTIONS}"
181 + system(command, err: params[:message_file])
182 +
175 else
183 else
176 talk("ERROR: Invalid language specified!")
184 talk("ERROR: Invalid language specified!")
177 open(params[:message_file],"w") do |f|
185 open(params[:message_file],"w") do |f|
178 f.puts "ERROR: Invalid language specified!"
186 f.puts "ERROR: Invalid language specified!"
179 end
187 end
180 exit(127)
188 exit(127)
181 end
189 end
182
190
183 # Report success or failure.
191 # Report success or failure.
184 if FileTest.exists? params[:output_file]
192 if FileTest.exists? params[:output_file]
185 talk "Compilation was successful!"
193 talk "Compilation was successful!"
186 else
194 else
187 talk "ERROR: Something was wrong during the compilation!"
195 talk "ERROR: Something was wrong during the compilation!"
188 end
196 end
@@ -1,180 +1,186
1 #!/usr/bin/env ruby
1 #!/usr/bin/env ruby
2
2
3 require 'fileutils'
3 require 'fileutils'
4
4
5 def log(str='')
5 def log(str='')
6 if ENV['TALKATIVE']!=nil
6 if ENV['TALKATIVE']!=nil
7 puts str
7 puts str
8 end
8 end
9 if ENV['GRADER_LOGGING']!=nil
9 if ENV['GRADER_LOGGING']!=nil
10 log_fname = ENV['GRADER_LOGGING']
10 log_fname = ENV['GRADER_LOGGING']
11 fp = File.open(log_fname,"a")
11 fp = File.open(log_fname,"a")
12 fp.puts("judge: #{Time.new.strftime("%H:%M")} #{str}")
12 fp.puts("judge: #{Time.new.strftime("%H:%M")} #{str}")
13 fp.close
13 fp.close
14 end
14 end
15 end
15 end
16
16
17 problem_home = ENV['PROBLEM_HOME']
17 problem_home = ENV['PROBLEM_HOME']
18
18
19 def execute(command, error_message="")
19 def execute(command, error_message="")
20 if not system(command)
20 if not system(command)
21 msg = "ERROR: #{error_message}"
21 msg = "ERROR: #{error_message}"
22 log msg
22 log msg
23 raise(msg)
23 raise(msg)
24 end
24 end
25 end
25 end
26
26
27 def call_and_log(error_message)
27 def call_and_log(error_message)
28 begin
28 begin
29 yield
29 yield
30 rescue
30 rescue
31 msg = "ERROR: #{error_message}"
31 msg = "ERROR: #{error_message}"
32 log msg
32 log msg
33 raise msg
33 raise msg
34 end
34 end
35 end
35 end
36
36
37 def clear_and_create_empty_dir(dir)
37 def clear_and_create_empty_dir(dir)
38 FileUtils.rm_rf(dir, :secure => true)
38 FileUtils.rm_rf(dir, :secure => true)
39 call_and_log("Cannot make directory #{dir}.") { FileUtils.mkdir(dir) }
39 call_and_log("Cannot make directory #{dir}.") { FileUtils.mkdir(dir) }
40 end
40 end
41
41
42 # ARGV[0] --- language
42 # ARGV[0] --- language
43 # ARGV[1] --- program source file
43 # ARGV[1] --- program source file
44 # ARGV[2] --- test result directory
44 # ARGV[2] --- test result directory
45 # ARGV[3] --- sandbox directory
45 # ARGV[3] --- sandbox directory
46
46
47 if ARGV.length < 2 || ARGV.length > 4
47 if ARGV.length < 2 || ARGV.length > 4
48 puts "Usage: judge <language> <program-source> [<test-result-directory>] [<sandbox-directory>]"
48 puts "Usage: judge <language> <program-source> [<test-result-directory>] [<sandbox-directory>]"
49 puts " <sandbox-directory> is defaulted to ./sandbox"
49 puts " <sandbox-directory> is defaulted to ./sandbox"
50 puts " <test-result-directory> is defaulted to ./test-result"
50 puts " <test-result-directory> is defaulted to ./test-result"
51 puts "WARNING: The judge script will forcefully create the (implicitly and explicitly) specified directories and remove anything inside it."
51 puts "WARNING: The judge script will forcefully create the (implicitly and explicitly) specified directories and remove anything inside it."
52 exit(127)
52 exit(127)
53 end
53 end
54
54
55 language = ARGV[0]
55 language = ARGV[0]
56 - if language != "c" && language != "c++" && language != "pas" && language != "java" && language != "ruby" && language != "python" && language != "php"
56 + if language != "c" && language != "c++" && language != "pas" && language != "java" && language != "ruby" && language != "python" && language != "php" && language != "haskell"
57 log "You specified a language that is not supported: #{language}."
57 log "You specified a language that is not supported: #{language}."
58 exit(127)
58 exit(127)
59 end
59 end
60
60
61 source_file = ARGV[1]
61 source_file = ARGV[1]
62 ENV['SOURCE_NAME'] = source_file
62 ENV['SOURCE_NAME'] = source_file
63 if File.exist?(source_file) == false
63 if File.exist?(source_file) == false
64 log "The source file does not exist."
64 log "The source file does not exist."
65 exit(127)
65 exit(127)
66 end
66 end
67
67
68 log "Making test result and sandbox directories..."
68 log "Making test result and sandbox directories..."
69
69
70 current_dir = FileUtils.pwd
70 current_dir = FileUtils.pwd
71 current_dir.strip!
71 current_dir.strip!
72
72
73 if ARGV.length >= 3
73 if ARGV.length >= 3
74 test_result_dir = ARGV[2]
74 test_result_dir = ARGV[2]
75 else
75 else
76 test_result_dir = "#{current_dir}/test-result"
76 test_result_dir = "#{current_dir}/test-result"
77 end
77 end
78
78
79 log "Test result directory: #{test_result_dir}"
79 log "Test result directory: #{test_result_dir}"
80 clear_and_create_empty_dir(test_result_dir)
80 clear_and_create_empty_dir(test_result_dir)
81
81
82 if ARGV.length >= 4
82 if ARGV.length >= 4
83 sandbox_dir = ARGV[3]
83 sandbox_dir = ARGV[3]
84 else
84 else
85 sandbox_dir = "#{current_dir}/sandbox"
85 sandbox_dir = "#{current_dir}/sandbox"
86 end
86 end
87 log "Sandbox directory: #{sandbox_dir}"
87 log "Sandbox directory: #{sandbox_dir}"
88 clear_and_create_empty_dir(sandbox_dir)
88 clear_and_create_empty_dir(sandbox_dir)
89
89
90 # Compile
90 # Compile
91 log
91 log
92 log "Compiling..."
92 log "Compiling..."
93 call_and_log("Cannot copy the source file to #{sandbox_dir}") {
93 call_and_log("Cannot copy the source file to #{sandbox_dir}") {
94 FileUtils.cp(source_file, sandbox_dir)
94 FileUtils.cp(source_file, sandbox_dir)
95 }
95 }
96 begin
96 begin
97 Dir.chdir sandbox_dir
97 Dir.chdir sandbox_dir
98 rescue
98 rescue
99 log "ERROR: Cannot change directory to #{sandbox_dir}."
99 log "ERROR: Cannot change directory to #{sandbox_dir}."
100 exit(127)
100 exit(127)
101 end
101 end
102 execute("#{problem_home}/script/compile #{language} #{source_file}", "Compilation error!")
102 execute("#{problem_home}/script/compile #{language} #{source_file}", "Compilation error!")
103 compile_message = open("compiler_message").read
103 compile_message = open("compiler_message").read
104 compile_message.strip!
104 compile_message.strip!
105 call_and_log("Cannot move the compiler message to #{test_result_dir}.") {
105 call_and_log("Cannot move the compiler message to #{test_result_dir}.") {
106 FileUtils.mv("compiler_message", test_result_dir)
106 FileUtils.mv("compiler_message", test_result_dir)
107 }
107 }
108 if !FileTest.exist?("a.out")
108 if !FileTest.exist?("a.out")
109 log "Cannot compile the source code. See message in #{test_result_dir}/compile_message"
109 log "Cannot compile the source code. See message in #{test_result_dir}/compile_message"
110 exit(127)
110 exit(127)
111 else
111 else
112 call_and_log("Cannot move the compiled program to #{test_result_dir}") {
112 call_and_log("Cannot move the compiled program to #{test_result_dir}") {
113 FileUtils.mv("a.out",test_result_dir)
113 FileUtils.mv("a.out",test_result_dir)
114 if language == "java" then Dir["*.class"].each { |file| FileUtils.mv(file,test_result_dir)} end
114 if language == "java" then Dir["*.class"].each { |file| FileUtils.mv(file,test_result_dir)} end
115 if language == "python" then Dir["*.pyc"].each { |file| FileUtils.mv(file,test_result_dir)} end
115 if language == "python" then Dir["*.pyc"].each { |file| FileUtils.mv(file,test_result_dir)} end
116 }
116 }
117 FileUtils.rm_rf("#{sandbox_dir}/.")
117 FileUtils.rm_rf("#{sandbox_dir}/.")
118 end
118 end
119
119
120 require "#{problem_home}/script/test_dsl.rb"
120 require "#{problem_home}/script/test_dsl.rb"
121 load "#{problem_home}/test_cases/all_tests.cfg"
121 load "#{problem_home}/test_cases/all_tests.cfg"
122 problem = Problem.get_instance
122 problem = Problem.get_instance
123
123
124 if problem.well_formed? == false
124 if problem.well_formed? == false
125 log "The problem specification is not well formed."
125 log "The problem specification is not well formed."
126 exit(127)
126 exit(127)
127 end
127 end
128
128
129 # Doing the testing.
129 # Doing the testing.
130 (1..(problem.num_tests)).each do |test_num|
130 (1..(problem.num_tests)).each do |test_num|
131
131
132 $stdout.print "[#{test_num}]"
132 $stdout.print "[#{test_num}]"
133 $stdout.flush
133 $stdout.flush
134
134
135 log "Test number: #{test_num}"
135 log "Test number: #{test_num}"
136
136
137 call_and_log("Cannot copy the compiled program into #{sandbox_dir}") {
137 call_and_log("Cannot copy the compiled program into #{sandbox_dir}") {
138 FileUtils.cp("#{test_result_dir}/a.out", sandbox_dir, :preserve => true)
138 FileUtils.cp("#{test_result_dir}/a.out", sandbox_dir, :preserve => true)
139 if language == "java" then Dir["#{test_result_dir}/*.class"].each { |file| FileUtils.cp(file,sandbox_dir)} end
139 if language == "java" then Dir["#{test_result_dir}/*.class"].each { |file| FileUtils.cp(file,sandbox_dir)} end
140 if language == "python" then Dir["#{test_result_dir}/*.pyc"].each { |file| FileUtils.cp(file,sandbox_dir)} end
140 if language == "python" then Dir["#{test_result_dir}/*.pyc"].each { |file| FileUtils.cp(file,sandbox_dir)} end
141 }
141 }
142
142
143 + #additionally copy any extra .txt file
144 + data_files = Dir[problem_home + '/*.txt']
145 + data_files.each do |file|
146 + FileUtils.cp(file,sandbox_dir)
147 + end
148 +
143 begin
149 begin
144 execute("#{problem_home}/script/run #{language} #{test_num} ", "Error occured during execution of the run script")
150 execute("#{problem_home}/script/run #{language} #{test_num} ", "Error occured during execution of the run script")
145 rescue
151 rescue
146 # do nothing
152 # do nothing
147 end
153 end
148
154
149 call_and_log("Cannot create directory #{test_result_dir}/#{test_num}") {
155 call_and_log("Cannot create directory #{test_result_dir}/#{test_num}") {
150 FileUtils.mkdir "#{test_result_dir}/#{test_num}"
156 FileUtils.mkdir "#{test_result_dir}/#{test_num}"
151 }
157 }
152 call_and_log("Cannot copy the result file into #{test_result_dir}/#{test_num}") {
158 call_and_log("Cannot copy the result file into #{test_result_dir}/#{test_num}") {
153 FileUtils.mv "#{sandbox_dir}/result", "#{test_result_dir}/#{test_num}"
159 FileUtils.mv "#{sandbox_dir}/result", "#{test_result_dir}/#{test_num}"
154 }
160 }
155 call_and_log("Cannot copy the comment file into #{test_result_dir}/#{test_num}") {
161 call_and_log("Cannot copy the comment file into #{test_result_dir}/#{test_num}") {
156 FileUtils.mv "#{sandbox_dir}/comment", "#{test_result_dir}/#{test_num}"
162 FileUtils.mv "#{sandbox_dir}/comment", "#{test_result_dir}/#{test_num}"
157 }
163 }
158 call_and_log("Cannot copy the output file into #{test_result_dir}/#{test_num}") {
164 call_and_log("Cannot copy the output file into #{test_result_dir}/#{test_num}") {
159 FileUtils.mv "#{sandbox_dir}/output.txt", "#{test_result_dir}/#{test_num}"
165 FileUtils.mv "#{sandbox_dir}/output.txt", "#{test_result_dir}/#{test_num}"
160 }
166 }
161 call_and_log("Cannot clear #{sandbox_dir}") {
167 call_and_log("Cannot clear #{sandbox_dir}") {
162 FileUtils.rm_rf(Dir.glob("#{sandbox_dir}/*"), :secure => true)
168 FileUtils.rm_rf(Dir.glob("#{sandbox_dir}/*"), :secure => true)
163 }
169 }
164 end
170 end
165
171
166 $stdout.print "[done]\n"
172 $stdout.print "[done]\n"
167
173
168 # Grade
174 # Grade
169 log
175 log
170 log "Grading..."
176 log "Grading..."
171 begin
177 begin
172 Dir.chdir test_result_dir
178 Dir.chdir test_result_dir
173 rescue
179 rescue
174 log "ERROR: Cannot change directory to #{test_result_dir}."
180 log "ERROR: Cannot change directory to #{test_result_dir}."
175 exit(127)
181 exit(127)
176 end
182 end
177 execute("#{problem_home}/script/grade", "An error occured during grading!")
183 execute("#{problem_home}/script/grade", "An error occured during grading!")
178
184
179 log
185 log
180 log "All done!"
186 log "All done!"
@@ -1,189 +1,192
1 #!/usr/bin/env ruby
1 #!/usr/bin/env ruby
2
2
3 require 'fileutils'
3 require 'fileutils'
4
4
5 def log(str='')
5 def log(str='')
6 if ENV['TALKATIVE']!=nil
6 if ENV['TALKATIVE']!=nil
7 puts str
7 puts str
8 end
8 end
9 if ENV['GRADER_LOGGING']!=nil
9 if ENV['GRADER_LOGGING']!=nil
10 log_fname = ENV['GRADER_LOGGING']
10 log_fname = ENV['GRADER_LOGGING']
11 fp = File.open(log_fname,"a")
11 fp = File.open(log_fname,"a")
12 fp.puts("run: #{Time.new.strftime("%H:%M")} #{str}")
12 fp.puts("run: #{Time.new.strftime("%H:%M")} #{str}")
13 fp.close
13 fp.close
14 end
14 end
15 end
15 end
16
16
17 def extract_time(t)
17 def extract_time(t)
18 # puts "TIME: #{t}"
18 # puts "TIME: #{t}"
19 if (result=/^(.*)r(.*)u(.*)s/.match(t))
19 if (result=/^(.*)r(.*)u(.*)s/.match(t))
20 {:real => result[1], :user => result[2], :sys => result[3]}
20 {:real => result[1], :user => result[2], :sys => result[3]}
21 else
21 else
22 #{:real => 0, :user => 0, :sys => 0}
22 #{:real => 0, :user => 0, :sys => 0}
23 #puts "ERROR READING RUNNING TIME: #{t}"
23 #puts "ERROR READING RUNNING TIME: #{t}"
24 raise "Error reading running time: #{t}"
24 raise "Error reading running time: #{t}"
25 end
25 end
26 end
26 end
27
27
28 def compile_box(source,bin)
28 def compile_box(source,bin)
29 system("g++ #{source} -o #{bin}")
29 system("g++ #{source} -o #{bin}")
30 end
30 end
31
31
32 if ARGV.length < 2 || ARGV.length > 3
32 if ARGV.length < 2 || ARGV.length > 3
33 puts "Usage: run <language> <test-num> [<program-name>]"
33 puts "Usage: run <language> <test-num> [<program-name>]"
34 exit(127)
34 exit(127)
35 end
35 end
36
36
37 language = ARGV[0]
37 language = ARGV[0]
38 test_num = ARGV[1].to_i
38 test_num = ARGV[1].to_i
39 if ARGV.length > 2
39 if ARGV.length > 2
40 program_name = ARGV[2]
40 program_name = ARGV[2]
41 else
41 else
42 program_name = "a.out"
42 program_name = "a.out"
43 end
43 end
44
44
45 problem_home = ENV['PROBLEM_HOME']
45 problem_home = ENV['PROBLEM_HOME']
46 source_name = ENV['SOURCE_NAME']
46 source_name = ENV['SOURCE_NAME']
47 require "#{problem_home}/script/test_dsl.rb"
47 require "#{problem_home}/script/test_dsl.rb"
48 load "#{problem_home}/test_cases/all_tests.cfg"
48 load "#{problem_home}/test_cases/all_tests.cfg"
49 problem = Problem.get_instance
49 problem = Problem.get_instance
50
50
51 sandbox_dir = Dir.getwd
51 sandbox_dir = Dir.getwd
52
52
53 if problem.well_formed? == false
53 if problem.well_formed? == false
54 log "The problem specification is not well formed."
54 log "The problem specification is not well formed."
55 exit(127)
55 exit(127)
56 end
56 end
57
57
58 # Check if the test number is okay.
58 # Check if the test number is okay.
59 if test_num <= 0 || test_num > problem.num_tests
59 if test_num <= 0 || test_num > problem.num_tests
60 log "You have specified a wrong test number."
60 log "You have specified a wrong test number."
61 exit(127)
61 exit(127)
62 end
62 end
63
63
64 #####################################
64 #####################################
65 # Set the relavant file names here. #
65 # Set the relavant file names here. #
66 #####################################
66 #####################################
67
67
68 input_file_name = "#{problem_home}/test_cases/#{test_num}/input-#{test_num}.txt"
68 input_file_name = "#{problem_home}/test_cases/#{test_num}/input-#{test_num}.txt"
69
69
70 #####################################
70 #####################################
71
71
72 time_limit = problem.get_time_limit test_num
72 time_limit = problem.get_time_limit test_num
73 mem_limit = problem.get_mem_limit(test_num) * 1024
73 mem_limit = problem.get_mem_limit(test_num) * 1024
74
74
75 # Copy the input file.
75 # Copy the input file.
76 #`cp #{problem_home}/test_cases/#{test_num}/#{input_file_name} .`
76 #`cp #{problem_home}/test_cases/#{test_num}/#{input_file_name} .`
77
77
78 # check if box is there, if not, compile it!
78 # check if box is there, if not, compile it!
79 if !File.exists?("#{problem_home}/script/box")
79 if !File.exists?("#{problem_home}/script/box")
80 log "WARNING: Compiling box: to increase efficiency, it should be compile manually"
80 log "WARNING: Compiling box: to increase efficiency, it should be compile manually"
81 compile_box("#{problem_home}/script/box.cc",
81 compile_box("#{problem_home}/script/box.cc",
82 "#{problem_home}/script/box")
82 "#{problem_home}/script/box")
83 end
83 end
84
84
85 # Hide PROBLEM_HOME
85 # Hide PROBLEM_HOME
86 ENV['PROBLEM_HOME'] = nil
86 ENV['PROBLEM_HOME'] = nil
87 ENV['SOURCE_NAME'] = nil
87 ENV['SOURCE_NAME'] = nil
88
88
89 # Run the program.
89 # Run the program.
90 #run_command = "/usr/bin/time -f \"#{time_output_format}\" 2>run_result #{problem_home}/script/box_new -a 2 -f -t #{time_limit} -m #{mem_limit} -i #{input_file_name} -o output.txt #{program_name}"
90 #run_command = "/usr/bin/time -f \"#{time_output_format}\" 2>run_result #{problem_home}/script/box_new -a 2 -f -t #{time_limit} -m #{mem_limit} -i #{input_file_name} -o output.txt #{program_name}"
91 #
91 #
92
92
93 JAVA_OPTION = "-s set_robust_list -s futex -s clone -s getppid -s clone -s wait4 -p /usr/bin/ -p ./"
93 JAVA_OPTION = "-s set_robust_list -s futex -s clone -s getppid -s clone -s wait4 -p /usr/bin/ -p ./"
94 RUBY_OPTION = "-p /usr/lib64/ -p /usr/local/lib64/ -p /usr/local/lib/ -p /lib64/ -p /dev/urandom -p #{sandbox_dir}/#{program_name} -p #{sandbox_dir}/ -s set_robust_list -s sched_getaffinity -s clock_gettime -s sigaltstack -s pipe2 -s clone -s futex -s openat -s pipe"
94 RUBY_OPTION = "-p /usr/lib64/ -p /usr/local/lib64/ -p /usr/local/lib/ -p /lib64/ -p /dev/urandom -p #{sandbox_dir}/#{program_name} -p #{sandbox_dir}/ -s set_robust_list -s sched_getaffinity -s clock_gettime -s sigaltstack -s pipe2 -s clone -s futex -s openat -s pipe"
95 - PYTHON_OPTION = "-p /usr/lib64/ -p /usr/local/lib64/ -p /usr/local/lib/ -p /usr/bin/ -p /lib64/ -p #{sandbox_dir}/#{program_name} -p ./#{program_name} -p #{sandbox_dir}/#{source_name} -s set_robust_list -s openat -s recvmsg -s connect -s socket -s sendto -s futex -E PYTHONNOUSERSITE=yes"
95 + PYTHON_OPTION = "-p /usr/lib64/ -p /usr/local/lib64/ -p /usr/local/lib/ -p /usr/bin/ -p /lib64/ -p /dev/urandom -p /usr/ -p #{sandbox_dir}/#{program_name} -p ./#{program_name} -p #{sandbox_dir}/#{source_name} -p /proc/sys/crypto/fips_enabled -p /proc/self/status -p /proc/mounts -p /var/lib/dpkg/status -s statfs -s set_robust_list -s openat -s sysinfo -s recvmsg -s connect -s socket -s sendto -s futex -s sigaltstack -s getrandom -E PYTHONNOUSERSITE=yes"
96 PHP_OPTION = "-p /usr/lib64/ -p/lib64/ -p /usr/bin/ -p #{sandbox_dir}/#{program_name} -p ./#{program_name} -p /usr/share/ -s setfsuid -s setfsgid -s openat -s set_robust_list -s futex -s clone -s socket -s connect"
96 PHP_OPTION = "-p /usr/lib64/ -p/lib64/ -p /usr/bin/ -p #{sandbox_dir}/#{program_name} -p ./#{program_name} -p /usr/share/ -s setfsuid -s setfsgid -s openat -s set_robust_list -s futex -s clone -s socket -s connect"
97 + HASKELL_OPTION = "-s set_robust_list -s clock_gettime -s sysinfo -s timer_create -s timer_settime -s futex -s timer_delete"
97
98
98 case language
99 case language
99 when "java"
100 when "java"
100 # for java, extract the classname
101 # for java, extract the classname
101 # wne have to add additional systemcall and we don't check the mem limit (dunno how to fix...)
102 # wne have to add additional systemcall and we don't check the mem limit (dunno how to fix...)
102 classname = 'DUMMY'
103 classname = 'DUMMY'
103 File.open(program_name,"r").each do |line|
104 File.open(program_name,"r").each do |line|
104 classname = line
105 classname = line
105 end
106 end
106 #for java, we cannot really check the memory limit...
107 #for java, we cannot really check the memory limit...
107 run_command = "#{problem_home}/script/box -a 3 -f -T -t #{time_limit} #{JAVA_OPTION} -i #{input_file_name} -o output.txt /usr/bin/java -A -Xmx#{mem_limit}k -A #{classname} "
108 run_command = "#{problem_home}/script/box -a 3 -f -T -t #{time_limit} #{JAVA_OPTION} -i #{input_file_name} -o output.txt /usr/bin/java -A -Xmx#{mem_limit}k -A #{classname} "
108 when "ruby"
109 when "ruby"
109 run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit*=2} -m #{mem_limit} #{RUBY_OPTION} -i #{input_file_name} -o output.txt /usr/bin/ruby #{program_name} "
110 run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit*=2} -m #{mem_limit} #{RUBY_OPTION} -i #{input_file_name} -o output.txt /usr/bin/ruby #{program_name} "
110 when "python"
111 when "python"
111 - run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit*=2} -m #{mem_limit} #{PYTHON_OPTION} -i #{input_file_name} -o output.txt /usr/bin/python #{program_name} "
112 + run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit*=2} -m #{[128 * 1024,mem_limit].max} #{PYTHON_OPTION} -i #{input_file_name} -o output.txt /usr/bin/python3 #{program_name} "
113 + when "haskell"
114 + run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit} -m #{[512 * 1024,mem_limit].max} #{HASKELL_OPTION} -i #{input_file_name} -o output.txt #{program_name} "
112 when "php"
115 when "php"
113 run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit*=2} -m #{[128*1024,mem_limit].max} #{PHP_OPTION} -i #{input_file_name} -o output.txt /usr/bin/php -A -d -A memory_limit=#{mem_limit}k -A #{program_name} "
116 run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit*=2} -m #{[128 * 1024,mem_limit].max} #{PHP_OPTION} -i #{input_file_name} -o output.txt /usr/bin/php -A -d -A memory_limit=#{mem_limit}k -A #{program_name} "
114 else # for c++, pascal, we do the normal checking
117 else # for c++, pascal, we do the normal checking
115 run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit} -m #{mem_limit} -i #{input_file_name} -o output.txt #{program_name} "
118 run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit} -m #{mem_limit} -i #{input_file_name} -o output.txt #{program_name} "
116 end
119 end
117
120
118
121
119 log "Running test #{test_num}..."
122 log "Running test #{test_num}..."
120 log run_command
123 log run_command
121 log
124 log
122 system(run_command,err: 'run_result')
125 system(run_command,err: 'run_result')
123
126
124 # Restore PROBLEM_HOME
127 # Restore PROBLEM_HOME
125 ENV['PROBLEM_HOME'] = problem_home
128 ENV['PROBLEM_HOME'] = problem_home
126
129
127 # Create the result file.
130 # Create the result file.
128 result_file = File.new("result", "w")
131 result_file = File.new("result", "w")
129 comment_file = File.new("comment", "w")
132 comment_file = File.new("comment", "w")
130
133
131 # Check if the program actually produced any output.
134 # Check if the program actually produced any output.
132 run_result_file = File.new("run_result", "r")
135 run_result_file = File.new("run_result", "r")
133 run_result = run_result_file.readlines
136 run_result = run_result_file.readlines
134 run_result_file.close
137 run_result_file.close
135
138
136 run_stat = run_result[run_result.length-1]
139 run_stat = run_result[run_result.length-1]
137 running_time = extract_time(run_stat)
140 running_time = extract_time(run_stat)
138
141
139 report = lambda{ |status, points, comment|
142 report = lambda{ |status, points, comment|
140 result_file.write status.strip
143 result_file.write status.strip
141 result_file.write "\n"
144 result_file.write "\n"
142 result_file.write points.to_s.strip
145 result_file.write points.to_s.strip
143 result_file.write "\n"
146 result_file.write "\n"
144 result_file.write run_stat.strip
147 result_file.write run_stat.strip
145 result_file.write "\n"
148 result_file.write "\n"
146 result_file.close
149 result_file.close
147 FileUtils.rm "run_result"
150 FileUtils.rm "run_result"
148 # `rm output.txt` --- keep the output
151 # `rm output.txt` --- keep the output
149
152
150 comment_file.write comment
153 comment_file.write comment
151
154
152 # added for debuggin --- jittat
155 # added for debuggin --- jittat
153 comment_file.write "--run-result--\n"
156 comment_file.write "--run-result--\n"
154 run_result.each do |l|
157 run_result.each do |l|
155 comment_file.write l
158 comment_file.write l
156 end
159 end
157
160
158 comment_file.close
161 comment_file.close
159
162
160 log "Done!"
163 log "Done!"
161 exit(0)
164 exit(0)
162 }
165 }
163
166
164
167
165 if run_result[0][0,2] != "OK"
168 if run_result[0][0,2] != "OK"
166 log "There was a runtime error."
169 log "There was a runtime error."
167 report.call(run_result[0], 0, "No comment.\n")
170 report.call(run_result[0], 0, "No comment.\n")
168 end
171 end
169
172
170 if running_time[:user].to_f > time_limit
173 if running_time[:user].to_f > time_limit
171 log "Time limit exceeded."
174 log "Time limit exceeded."
172 report.call("Time limit exceeded", 0, "No comment.\n")
175 report.call("Time limit exceeded", 0, "No comment.\n")
173 end
176 end
174
177
175 # Run 'check' to evaluate the output.
178 # Run 'check' to evaluate the output.
176 #puts "There was no runtime error. Proceed to checking the output."
179 #puts "There was no runtime error. Proceed to checking the output."
177 check_command = "#{problem_home}/script/check #{language} #{test_num}"
180 check_command = "#{problem_home}/script/check #{language} #{test_num}"
178 log "Checking the output..."
181 log "Checking the output..."
179 log check_command
182 log check_command
180 if not system(check_command)
183 if not system(check_command)
181 log "Problem with check script"
184 log "Problem with check script"
182 report.call("Incorrect",0,"Check script error.\n")
185 report.call("Incorrect",0,"Check script error.\n")
183 exit(127)
186 exit(127)
184 end
187 end
185
188
186 check_file = File.new("check_result", "r")
189 check_file = File.new("check_result", "r")
187 check_file_lines = check_file.readlines
190 check_file_lines = check_file.readlines
188
191
189 report.call(check_file_lines[0], check_file_lines[1], "No comment.\n")
192 report.call(check_file_lines[0], check_file_lines[1], "No comment.\n")
@@ -1,66 +1,75
1 #!/usr/bin/env ruby
1 #!/usr/bin/env ruby
2
2
3 problem_home = ENV['PROBLEM_HOME']
3 problem_home = ENV['PROBLEM_HOME']
4 require "#{problem_home}/script/test_dsl.rb"
4 require "#{problem_home}/script/test_dsl.rb"
5
5
6 if ARGV.length < 2
6 if ARGV.length < 2
7 puts "Usage: check <language> <test-number> [<output-file>]"
7 puts "Usage: check <language> <test-number> [<output-file>]"
8 exit(0)
8 exit(0)
9 end
9 end
10
10
11 language = ARGV[0]
11 language = ARGV[0]
12 test_num = ARGV[1].to_i
12 test_num = ARGV[1].to_i
13 if ARGV.length >= 3
13 if ARGV.length >= 3
14 output_file_name = ARGV[2]
14 output_file_name = ARGV[2]
15 else
15 else
16 output_file_name = "output.txt"
16 output_file_name = "output.txt"
17 end
17 end
18
18
19 load "#{problem_home}/test_cases/all_tests.cfg"
19 load "#{problem_home}/test_cases/all_tests.cfg"
20 problem = Problem.get_instance
20 problem = Problem.get_instance
21
21
22 output_file = File.new(output_file_name, "r")
22 output_file = File.new(output_file_name, "r")
23 answer_file = File.new("#{problem_home}/test_cases/#{test_num}/answer-#{test_num}.txt")
23 answer_file = File.new("#{problem_home}/test_cases/#{test_num}/answer-#{test_num}.txt")
24 result_file = File.new("check_result", "w")
24 result_file = File.new("check_result", "w")
25
25
26 output_file_content = output_file.read
26 output_file_content = output_file.read
27 answer_file_content = answer_file.read
27 answer_file_content = answer_file.read
28
28
29 report_correct = lambda {
29 report_correct = lambda {
30 result_file.write "Correct\n"
30 result_file.write "Correct\n"
31 result_file.write problem.get_score(test_num)
31 result_file.write problem.get_score(test_num)
32 result_file.write "\n"
32 result_file.write "\n"
33 result_file.close
33 result_file.close
34 exit(0)
34 exit(0)
35 }
35 }
36
36
37 report_wrong = lambda {
37 report_wrong = lambda {
38 result_file.write "Incorrect\n"
38 result_file.write "Incorrect\n"
39 result_file.write "0\n"
39 result_file.write "0\n"
40 result_file.close
40 result_file.close
41 exit(0)
41 exit(0)
42 }
42 }
43
43
44 ##################
44 ##################
45 # Your code here #
45 # Your code here #
46 ##################
46 ##################
47
47
48 ########### THIS IS FOR CHECKING FLOAT with EPSILON error ##########
48 ########### THIS IS FOR CHECKING FLOAT with EPSILON error ##########
49
49
50 +
51 + def is_float?(fl)
52 + !!Float(fl) rescue false
53 + end
54 +
50 EPSILON = 0.000001
55 EPSILON = 0.000001
51
56
52 out_items = output_file_content.split
57 out_items = output_file_content.split
53 ans_items = answer_file_content.split
58 ans_items = answer_file_content.split
54
59
55 if out_items.length != ans_items.length
60 if out_items.length != ans_items.length
56 report_wrong.call
61 report_wrong.call
57 else
62 else
58 out_items.length.times do |i|
63 out_items.length.times do |i|
64 + if is_float?(out_items[i]) && is_float?(ans_items[i])
59 out_value = out_items[i].to_f
65 out_value = out_items[i].to_f
60 ans_value = ans_items[i].to_f
66 ans_value = ans_items[i].to_f
61 if (out_value - ans_value).abs > EPSILON * [out_value.abs,ans_value.abs].max
67 if (out_value - ans_value).abs > EPSILON * [out_value.abs,ans_value.abs].max
62 report_wrong.call
68 report_wrong.call
63 end
69 end
70 + else
71 + report_wrong.call if out_items[i] != ans_items[i]
72 + end
64 end
73 end
65 report_correct.call
74 report_correct.call
66 end
75 end
You need to be logged in to leave comments. Login now