Description:
merge
Commit status:
[Not Reviewed]
References:
merge algo
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r247:47c98faa5421 - - 9 files changed: 157 inserted, 31 deleted

@@ -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,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 1 #!/usr/bin/env ruby
2 2
3 3 require 'erb'
4 4 require 'fileutils'
5 5 require File.join(File.dirname(__FILE__),'lib/import_helper')
6 6
7 7 JUDGE_ENVIRONMENTS = [:grading, :exam]
8 8 ENV_INFO = {
9 9 :grading => {
10 10 :ev_dir => 'ev',
11 11 :raw_prefix => '',
12 12 },
13 13 :exam => {
14 14 :ev_dir => 'ev-exam',
15 15 :raw_prefix => 'ex.',
16 16 }
17 17 }
18 18
19 19 def input_filename(dir,i)
20 20 "#{dir}/input-#{i}.txt"
21 21 end
22 22
23 23 def answer_filename(dir,i)
24 24 "#{dir}/answer-#{i}.txt"
25 25 end
26 26
27 27 def build_testrun_info_from_dir(num_testruns, importing_test_dir, raw_prefix='')
28 28 filenames = Dir["#{importing_test_dir}/#{raw_prefix}*.in"].collect do |filename|
29 29 File.basename((/(.*)\.in/.match(filename))[1])
30 30 end
31 31 build_testrun_info(num_testruns,filenames,raw_prefix)
32 32 end
33 33
34 34 def copy_testcase(importing_test_dir,fname,dir,i)
35 35 FileUtils.cp("#{importing_test_dir}/#{fname}.in", "#{input_filename(dir,i)}")
36 36 FileUtils.cp("#{importing_test_dir}/#{fname}.sol", "#{answer_filename(dir,i)}")
37 37 end
38 38
39 39 def process_options(options)
40 40 i = 3
41 41 while i<ARGV.length
42 42 if ARGV[i]=='-t'
43 43 options[:time_limit] = ARGV[i+1].to_f if ARGV.length>i+1
44 44 i += 1
45 45 end
46 46 if ARGV[i]=='-m'
47 47 options[:mem_limit] = ARGV[i+1].to_i if ARGV.length>i+1
48 48 i += 1
49 49 end
50 50 i += 1
51 51 end
52 52 end
53 53
54 54 def print_usage
55 55 puts "using: import_problem_new name dir check [options]
56 56
57 57 where: name = problem_name (put '-' (dash) to use dir name)
58 58 dir = importing testcase directory
59 59 check = check script, which can be
60 60 'integer', 'text' (for standard script),
61 61 path_to_your_script, or
62 62 'wrapper:(path_to_your_wrapped_script)'
63 63 options: -t time-limit (in seconds)
64 64 -m memory-limit (in megabytes)
65 65
66 66 The script looks at test data files in the dir of the forms: *.in and
67 67 *.sol and import them to the evaluation dir for their environment,
68 68 based on their prefixes.
69 69
70 70 Currently supporting environments are:"
71 71
72 72 JUDGE_ENVIRONMENTS.each do |env|
73 73 prefix = ENV_INFO[env][:raw_prefix]
74 74 prefix = 'no prefix' if prefix==''
75 75 puts " * #{env}"
76 76 puts " import to: #{ENV_INFO[env][:ev_dir]}"
77 77 puts " prefix with: #{prefix} (e.g., #{ENV_INFO[env][:raw_prefix]}1.in, #{ENV_INFO[env][:raw_prefix]}5a.sol)"
78 78 end
79 79
80 80 puts"
81 81 For each environment, the script
82 82 * creates a directory for a problem in ev dir of that environment,
83 83 * copies testdata in the old format and create standard testcase config file
84 84 * copies a check script for grading
85 85 * creates a test_request template in the ev dir + '/test_request'
86 86
87 87 For wrapped checked script see comment in templates/check_wrapper for
88 88 information."
89 89 end
90 90
91 91 def count_testruns(testcase_dir, raw_prefix)
92 92 n = 0
93 93 begin
94 94 # check for test case n+1
95 95 if ((Dir["#{testcase_dir}/#{raw_prefix}#{n+1}.in"].length==0) and
96 96 (Dir["#{testcase_dir}/#{raw_prefix}#{n+1}[a-z].in"].length==0))
97 97 return n
98 98 end
99 99 n += 1
100 100 end while true
101 101 end
102 102
103 103 def create_dir_if_not_exists(dir)
104 104 if ! FileTest.exists? dir
105 105 FileUtils.mkdir(dir)
106 106 end
107 107 end
108 108
109 109 def import_problem(ev_dir, problem, testcase_dir, num_testruns, raw_prefix, check_script, options)
110 110 testrun_info = build_testrun_info_from_dir(num_testruns, testcase_dir, raw_prefix)
111 111
112 112 if !(FileTest.exists? ev_dir)
113 113 puts "Testdata dir (#{ev_dir}) not found."
114 114 return
115 115 end
116 116
117 117 problem_dir = "#{ev_dir}/#{problem}"
118 118
119 119 # start working
120 120 puts "creating directories"
121 121
122 122 create_dir_if_not_exists("#{problem_dir}")
123 123 create_dir_if_not_exists("#{problem_dir}/script")
124 124 create_dir_if_not_exists("#{problem_dir}/test_cases")
125 125
126 126 puts "copying testcases"
127 127
128 128 tr_num = 0
129 129
130 130 num_testcases = 0
131 131
132 132 testrun_info.each do |testrun|
133 133 tr_num += 1
134 134 puts "testrun: #{tr_num}"
135 -
135 +
136 136 testrun.each do |testcase_info|
137 137 testcase_num, testcase_fname = testcase_info
138 -
138 +
139 139 puts "copy #{testcase_fname} to #{testcase_num}"
140 -
140 +
141 141 create_dir_if_not_exists("#{problem_dir}/test_cases/#{testcase_num}")
142 142 copy_testcase("#{testcase_dir}",testcase_fname,"#{problem_dir}/test_cases/#{testcase_num}",testcase_num)
143 -
143 +
144 144 num_testcases += 1
145 145 end
146 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 154 # generating all_tests.cfg
149 155 puts "generating testcase config file"
150 -
156 +
151 157 template = File.open(SCRIPT_DIR + "/templates/all_tests.cfg.erb").read
152 158 all_test_cfg = ERB.new(template)
153 -
159 +
154 160 cfg_file = File.open("#{problem_dir}/test_cases/all_tests.cfg","w")
155 161 cfg_file.puts all_test_cfg.result binding
156 162 cfg_file.close
157 -
163 +
158 164 # copy check script
159 165 if res = /^wrapper:(.*)$/.match(check_script)
160 166 # wrapper script
161 167 check_script_fname = res[1]
162 168 script_name = File.basename(check_script_fname)
163 169 check_wrapper_template = File.open(SCRIPT_DIR + "/templates/check_wrapper").read
164 170 check_wrapper = ERB.new(check_wrapper_template)
165 -
171 +
166 172 check_file = File.open("#{problem_dir}/script/check","w")
167 173 check_file.puts check_wrapper.result binding
168 174 check_file.close
169 -
175 +
170 176 File.chmod(0755,"#{problem_dir}/script/check")
171 -
177 +
172 178 FileUtils.cp("#{check_script_fname}", "#{problem_dir}/script/#{script_name}")
173 179 else
174 180 if File.exists?(SCRIPT_DIR + "/templates/check.#{check_script}")
175 181 check_script_fname = SCRIPT_DIR + "/templates/check.#{check_script}"
176 182 else
177 183 check_script_fname = check_script
178 184 end
179 185 FileUtils.cp("#{check_script_fname}", "#{problem_dir}/script/check", :preserve => true)
180 186 end
181 -
187 +
182 188 # generating test_request directory
183 189 puts "generating test_request template"
184 190 FileUtils.mkdir_p("#{ev_dir}/test_request/#{problem}/script")
185 191 FileUtils.mkdir_p("#{ev_dir}/test_request/#{problem}/test_cases/1")
186 -
192 +
187 193 template = File.open(SCRIPT_DIR + "/templates/test_request_all_tests.cfg.erb").read
188 194 test_request_all_test_cfg = ERB.new(template)
189 -
195 +
190 196 cfg_file = File.open("#{ev_dir}/test_request/#{problem}/test_cases/all_tests.cfg","w")
191 197 cfg_file.puts test_request_all_test_cfg.result
192 198 cfg_file.close
193 -
199 +
194 200 FileUtils.cp("#{SCRIPT_DIR}/templates/check_empty",
195 201 "#{ev_dir}/test_request/#{problem}/script/check")
196 202 FileUtils.cp("#{SCRIPT_DIR}/templates/answer-1.txt",
197 203 "#{ev_dir}/test_request/#{problem}/test_cases/1")
198 -
204 +
199 205 puts "done"
200 206 end
201 207
202 208
203 209 SCRIPT_DIR = File.dirname(__FILE__)
204 210
205 211 # print usage
206 212 if (ARGV.length < 3) or (ARGV[2][0,1]=="-")
207 213 print_usage
208 214 exit(127)
209 215 end
210 216
211 217 # processing arguments
212 218 problem = ARGV[0]
213 219 testcase_dir = ARGV[1]
214 220 problem = File.basename(testcase_dir) if problem=="-"
215 221 check_script = ARGV[2]
216 222 options = {:time_limit => 1, :mem_limit => 16}
217 223 process_options(options)
218 224
219 225 JUDGE_ENVIRONMENTS.each do |env|
220 226 ev_dir = ENV_INFO[env][:ev_dir]
221 227 raw_prefix = ENV_INFO[env][:raw_prefix]
222 228
223 229 num_testruns = count_testruns(testcase_dir,raw_prefix)
224 230
225 231 puts ""
226 232 puts "*** Environment: #{env} (#{num_testruns} test runs) ***"
227 233 puts ""
228 234
229 235 import_problem(ev_dir,
230 236 problem,
231 237 testcase_dir,
232 238 num_testruns,
233 239 raw_prefix,
234 240 check_script,
235 241 options)
236 242 end
@@ -1,181 +1,181
1 1 #!/bin/sh
2 2
3 3 echo "This script will install and configure Cafe grader."
4 4
5 5 RUBY_VERSION=2.1.2
6 6 echo "This will install Ruby $RUBY_VERSION under RVM"
7 7
8 8 echo "Installing required apts"
9 9
10 10 sudo apt-get update
11 11 sudo apt-get install mysql-server mysql-client \
12 12 g++ gcc apache2 libmysqlclient20 build-essential \
13 13 git-core openssl libreadline6 libreadline6-dev \
14 14 zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-dev \
15 15 sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev \
16 16 ncurses-dev automake libtool bison subversion \
17 17 pkg-config curl nodejs unzip pyflakes ruby default-jdk \
18 - libmysqld-dev mercurial python-setuptools python-dev
18 + libmysqld-dev mercurial python-setuptools python-dev python3-numpy
19 19
20 20 echo "Installing RVM"
21 21 curl -k -L https://get.rvm.io | bash -s stable
22 22 source ~/.rvm/scripts/rvm
23 23
24 24 echo "Installing Ruby $RUBY_VERSION in RVM"
25 25
26 26 rvm install $RUBY_VERSION
27 27 rvm use $RUBY_VERSION
28 28
29 29 echo "Fetching Cafe Grader from Git repositories"
30 30
31 31 echo "Fetching web interface"
32 32
33 33 mkdir cafe_grader
34 34 cd cafe_grader
35 35 git clone -q git://github.com/jittat/cafe-grader-web.git web
36 36
37 37 echo "Configuring rails app"
38 38
39 39 cp web/config/application.rb.SAMPLE web/config/application.rb
40 40 cp web/config/initializers/cafe_grader_config.rb.SAMPLE web/config/initializers/cafe_grader_config.rb
41 41
42 42 #replace UTC in application.rb with the system timezone
43 43 timezone='UTC'
44 44 if [ -f '/etc/timezone' ]; then
45 45 timezone=\"`cat /etc/timezone`\"
46 46 else
47 47 if [ -f '/etc/sysconfig/clock' ]; then
48 48 timezone=`grep -e '^TIMEZONE' /etc/sysconfig/clock | grep -o -e '\".*\"'`
49 49 fi
50 50 fi
51 51 replace="s!'UTC'!$timezone!g"
52 52 sed -i $replace web/config/application.rb
53 53
54 54 echo "At this point we will need MySQL user and database."
55 55 echo "Have you created MySQL user and database for Cafe grader? (Y/N) "
56 56 read ch
57 57
58 58 if [ "$ch" = "n" -o "$ch" = "N" ]
59 59 then
60 60 echo "Please open another terminal and create the user and database for Cafe grader."
61 61 echo "Don't forget to grant access to that database for the user."
62 62 echo "Please have username, password, and database name ready before continue."
63 63 echo
64 64 echo "The following are instructions:"
65 65 echo "1. Run mysql:"
66 66 echo
67 67 echo " mysql -u root -p"
68 68 echo
69 69 echo " if you have just installed mysql, the root password is the one that you have just entered"
70 70 echo "2. Create a new database, a new user, and grant access to grader database:"
71 71 echo
72 72 echo " create user 'USERNAME'@'localhost' identified by 'PASSWORD';"
73 73 echo " create database \`DATABASENEME\`;"
74 74 echo " grant all on \`DATABASENAME\`.* to 'USERNAME'@'localhost';"
75 75 echo
76 76 echo " Replace USERNAME, PASSWORD, and DATABASENAME accordingly."
77 77 echo
78 78 echo "Hit enter when ready..."
79 79 read dummy
80 80 fi
81 81
82 82 CAFE_PATH=`pwd`
83 83
84 84 cd web
85 85
86 86 echo "Please provide grader database:"
87 87 read database
88 88
89 89 echo "Please provide grader username:"
90 90 read username
91 91
92 92 echo "Please provide $username password:"
93 93 read password
94 94
95 95 echo "development:" > config/database.yml
96 96 echo " adapter: mysql2" >> config/database.yml
97 97 echo " encoding: utf8" >> config/database.yml
98 98 echo " reconnect: false" >> config/database.yml
99 99 echo " database: $database" >> config/database.yml
100 100 echo " pool: 5" >> config/database.yml
101 101 echo " username: $username" >> config/database.yml
102 102 echo " password: $password" >> config/database.yml
103 103 echo " host: localhost" >> config/database.yml
104 104 echo " socket: /var/run/mysqld/mysqld.sock" >> config/database.yml
105 105 echo "" >> config/database.yml
106 106 echo "production:" >> config/database.yml
107 107 echo " adapter: mysql2" >> config/database.yml
108 108 echo " encoding: utf8" >> config/database.yml
109 109 echo " reconnect: false" >> config/database.yml
110 110 echo " database: $database" >> config/database.yml
111 111 echo " pool: 5" >> config/database.yml
112 112 echo " username: $username" >> config/database.yml
113 113 echo " password: $password" >> config/database.yml
114 114 echo " host: localhost" >> config/database.yml
115 115 echo " socket: /var/run/mysqld/mysqld.sock" >> config/database.yml
116 116
117 117 echo "Object.instance_eval{remove_const :GRADER_ROOT_DIR}" >> config/initializers/cafe_grader_config.rb
118 118 echo "Object.instance_eval{remove_const :GRADING_RESULT_DIR}" >> config/initializers/cafe_grader_config.rb
119 119 echo "GRADER_ROOT_DIR = '$CAFE_PATH/judge'" >> config/initializers/cafe_grader_config.rb
120 120 echo "GRADING_RESULT_DIR = '$CAFE_PATH/judge/result'" >> config/initializers/cafe_grader_config.rb
121 121
122 122 echo "Installing required gems"
123 123 gem install bundler
124 124 bundle install
125 125
126 126 echo "Running rake tasks to initialize database"
127 127
128 128 rake db:migrate
129 129 rake db:seed
130 130
131 131 echo "Running rake tasks to precompile the assets"
132 132
133 133 rake assets:precompile
134 134
135 135 echo "Intalling web interface complete..."
136 136 echo
137 137 echo "Fetching grader"
138 138
139 139 cd ..
140 140
141 141 mkdir judge
142 142 cd judge
143 143 git clone -q git://github.com/jittat/cafe-grader-judge-scripts.git scripts
144 144 mkdir raw
145 145 mkdir ev-exam
146 146 mkdir ev
147 147 mkdir result
148 148 mkdir log
149 149
150 150 echo "Configuring grader"
151 151
152 152 cp scripts/config/env_exam.rb.SAMPLE scripts/config/env_exam.rb
153 153 cp scripts/config/env_grading.rb.SAMPLE scripts/config/env_grading.rb
154 154
155 155 # create new environment.rb file
156 156 echo "RAILS_ROOT = '$CAFE_PATH/web'" > scripts/config/environment.rb
157 157 echo "GRADER_ROOT = '$CAFE_PATH/judge/scripts'" >> scripts/config/environment.rb
158 158 echo "require File.join(File.dirname(__FILE__),'../lib/boot')" >> scripts/config/environment.rb
159 159 echo "require File.dirname(__FILE__) + \"/env_#{GRADER_ENV}.rb\"" >> scripts/config/environment.rb
160 160
161 161 # compiling box
162 162 MACHINE_TYPE=`uname -m`
163 163 if [ ${MACHINE_TYPE} == 'x86_64' ]; then
164 164 gcc -std=c99 -o scripts/std-script/box scripts/std-script/box64-new.c
165 165 else
166 166 g++ -o scripts/std-script/box scripts/std-script/box.cc
167 167 fi
168 168
169 169
170 170 cd ..
171 171
172 172 echo "Now you are ready to run cafe grader...."
173 173 echo
174 174 echo "Try:"
175 175 echo
176 176 echo " cd web"
177 177 echo " rails s"
178 178 echo
179 179 echo "and access web at http://localhost:3000/"
180 180 echo "The root username is 'root', its password is 'ioionrails'."
181 181
@@ -1,100 +1,100
1 1 #!/usr/bin/env ruby
2 2
3 3 ENVIRONMENT_DIRS = ['ev', 'ev-exam']
4 4
5 5 def config
6 6 Grader::Configuration.get_instance
7 7 end
8 8
9 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 12 puts "Bad new problem name: #{new_problem_name}"
13 13 return
14 14 end
15 15
16 16 problem = Problem.find_by_name(old_problem_name)
17 17 if problem==nil
18 18 puts "Problem #{old_problem_name} does not exist."
19 19 return
20 20 end
21 21
22 22 puts "Problem: #{old_problem_name} -> #{new_problem_name}"
23 23
24 24 ENVIRONMENT_DIRS.each do |dir|
25 25 problem_dir = File.join(GRADER_ROOT,'..',dir,old_problem_name)
26 26 new_problem_dir = File.join(GRADER_ROOT,'..',dir,new_problem_name)
27 27
28 28 if FileTest.exists? problem_dir
29 29 puts "Moving #{problem_dir} to #{new_problem_dir}."
30 30 File.rename(problem_dir, new_problem_dir)
31 31
32 32 tr_problem_dir = File.join(GRADER_ROOT,'..',dir,
33 33 'test_request',old_problem_name)
34 34 new_tr_problem_dir = File.join(GRADER_ROOT,'..',dir,
35 35 'test_request',new_problem_name)
36 36 File.rename(tr_problem_dir, new_tr_problem_dir)
37 37 end
38 38 end
39 39
40 40 problem.name = new_problem_name
41 41 problem.save
42 42 end
43 43
44 44 def usage
45 45 puts <<USAGE
46 46 Usage:
47 47 rename_problem [old_name] [new_name]
48 48 or
49 49 rename_problem -f [filename]
50 50
51 51 When using with -f, that file should contain, for each line, the old
52 52 problem name and its new name.
53 53
54 54 This script should be called at the judge root dir where dirs 'ev' and
55 55 'ev-exam' are.
56 56 USAGE
57 57 end
58 58
59 59 def valid_problem_name(name)
60 60 if name.length==0:
61 61 return false
62 62 else
63 - return !(/^[a-zA-Z0-9_\-]+$/ === name)
63 + return (/^[a-zA-Z0-9_\-]+$/ === name)
64 64 end
65 65 end
66 66
67 67 if (ARGV.length!=2)
68 68 usage
69 69 exit(0)
70 70 end
71 71
72 72 if ARGV[0]=='-f' and !FileTest.exists?(ARGV[1])
73 73 puts "File #{ARGV[1]} does not exist."
74 74 usage
75 75 exit(0)
76 76 end
77 77
78 78 # load grader environment
79 79 GRADER_ENV = 'grading'
80 80 require File.join(File.dirname(__FILE__),'config/environment')
81 81
82 82 # boot rails, to be able to rename the problem
83 83 RAILS_ENV = config.rails_env
84 84 require RAILS_ROOT + '/config/environment'
85 85
86 86 if ARGV[0]!='-f'
87 87 old_problem_name = ARGV[0]
88 88 new_problem_name = ARGV[1]
89 89
90 90 rename_problem(old_problem_name, new_problem_name)
91 91 else
92 92 lines = IO.readlines(ARGV[1])
93 93 lines.each do |line|
94 94 items = line.split
95 95 if items.length==2
96 96 old_name, new_name = items
97 97 rename_problem(old_name, new_name)
98 98 end
99 99 end
100 100 end
@@ -414,384 +414,396
414 414 /* 122 */ [ __NR_setfsuid ] = "setfsuid",
415 415 /* 123 */ [ __NR_setfsgid ] = "setfsgid",
416 416 /* 124 */ [ __NR_getsid ] = "getsid",
417 417 /* 125 */ [ __NR_capget ] = "capget",
418 418 /* 126 */ [ __NR_capset ] = "capset",
419 419 /* 127 */ [ __NR_rt_sigpending ] = "rt_sigpending",
420 420 /* 128 */ [ __NR_rt_sigtimedwait ] = "rt_sigtimedwait",
421 421 /* 129 */ [ __NR_rt_sigqueueinfo ] = "rt_sigqueueinfo",
422 422 /* 130 */ [ __NR_rt_sigsuspend ] = "rt_sigsuspend",
423 423 /* 131 */ [ __NR_sigaltstack ] = "sigaltstack",
424 424 /* 132 */ [ __NR_utime ] = "utime",
425 425 /* 133 */ [ __NR_mknod ] = "mknod",
426 426 /* 134 */ [ __NR_uselib ] = "uselib",
427 427 /* 135 */ [ __NR_personality ] = "personality",
428 428 /* 136 */ [ __NR_ustat ] = "ustat",
429 429 /* 137 */ [ __NR_statfs ] = "statfs",
430 430 /* 138 */ [ __NR_fstatfs ] = "fstatfs",
431 431 /* 139 */ [ __NR_sysfs ] = "sysfs",
432 432 /* 140 */ [ __NR_getpriority ] = "getpriority",
433 433 /* 141 */ [ __NR_setpriority ] = "setpriority",
434 434 /* 142 */ [ __NR_sched_setparam ] = "sched_setparam",
435 435 /* 143 */ [ __NR_sched_getparam ] = "sched_getparam",
436 436 /* 144 */ [ __NR_sched_setscheduler ] = "sched_setscheduler",
437 437 /* 145 */ [ __NR_sched_getscheduler ] = "sched_getscheduler",
438 438 /* 146 */ [ __NR_sched_get_priority_max ] = "sched_get_priority_max",
439 439 /* 147 */ [ __NR_sched_get_priority_min ] = "sched_get_priority_min",
440 440 /* 148 */ [ __NR_sched_rr_get_interval ] = "sched_rr_get_interval",
441 441 /* 149 */ [ __NR_mlock ] = "mlock",
442 442 /* 150 */ [ __NR_munlock ] = "munlock",
443 443 /* 151 */ [ __NR_mlockall ] = "mlockall",
444 444 /* 152 */ [ __NR_munlockall ] = "munlockall",
445 445 /* 153 */ [ __NR_vhangup ] = "vhangup",
446 446 /* 154 */ [ __NR_modify_ldt ] = "modify_ldt",
447 447 /* 155 */ [ __NR_pivot_root ] = "pivot_root",
448 448 /* 156 */ [ __NR__sysctl ] = "_sysctl",
449 449 /* 157 */ [ __NR_prctl ] = "prctl",
450 450 /* 158 */ [ __NR_arch_prctl ] = "arch_prctl",
451 451 /* 159 */ [ __NR_adjtimex ] = "adjtimex",
452 452 /* 160 */ [ __NR_setrlimit ] = "setrlimit",
453 453 /* 161 */ [ __NR_chroot ] = "chroot",
454 454 /* 162 */ [ __NR_sync ] = "sync",
455 455 /* 163 */ [ __NR_acct ] = "acct",
456 456 /* 164 */ [ __NR_settimeofday ] = "settimeofday",
457 457 /* 165 */ [ __NR_mount ] = "mount",
458 458 /* 166 */ [ __NR_umount2 ] = "umount2",
459 459 /* 167 */ [ __NR_swapon ] = "swapon",
460 460 /* 168 */ [ __NR_swapoff ] = "swapoff",
461 461 /* 169 */ [ __NR_reboot ] = "reboot",
462 462 /* 170 */ [ __NR_sethostname ] = "sethostname",
463 463 /* 171 */ [ __NR_setdomainname ] = "setdomainname",
464 464 /* 172 */ [ __NR_iopl ] = "iopl",
465 465 /* 173 */ [ __NR_ioperm ] = "ioperm",
466 466 /* 174 */ [ __NR_create_module ] = "create_module",
467 467 /* 175 */ [ __NR_init_module ] = "init_module",
468 468 /* 176 */ [ __NR_delete_module ] = "delete_module",
469 469 /* 177 */ [ __NR_get_kernel_syms ] = "get_kernel_syms",
470 470 /* 178 */ [ __NR_query_module ] = "query_module",
471 471 /* 179 */ [ __NR_quotactl ] = "quotactl",
472 472 /* 180 */ [ __NR_nfsservctl ] = "nfsservctl",
473 473 /* 181 */ [ __NR_getpmsg ] = "getpmsg",
474 474 /* 182 */ [ __NR_putpmsg ] = "putpmsg",
475 475 /* 183 */ [ __NR_afs_syscall ] = "afs_syscall",
476 476 /* 184 */ [ __NR_tuxcall ] = "tuxcall",
477 477 /* 185 */ [ __NR_security ] = "security",
478 478 /* 186 */ [ __NR_gettid ] = "gettid",
479 479 /* 187 */ [ __NR_readahead ] = "readahead",
480 480 /* 188 */ [ __NR_setxattr ] = "setxattr",
481 481 /* 189 */ [ __NR_lsetxattr ] = "lsetxattr",
482 482 /* 190 */ [ __NR_fsetxattr ] = "fsetxattr",
483 483 /* 191 */ [ __NR_getxattr ] = "getxattr",
484 484 /* 192 */ [ __NR_lgetxattr ] = "lgetxattr",
485 485 /* 193 */ [ __NR_fgetxattr ] = "fgetxattr",
486 486 /* 194 */ [ __NR_listxattr ] = "listxattr",
487 487 /* 195 */ [ __NR_llistxattr ] = "llistxattr",
488 488 /* 196 */ [ __NR_flistxattr ] = "flistxattr",
489 489 /* 197 */ [ __NR_removexattr ] = "removexattr",
490 490 /* 198 */ [ __NR_lremovexattr ] = "lremovexattr",
491 491 /* 199 */ [ __NR_fremovexattr ] = "fremovexattr",
492 492 /* 200 */ [ __NR_tkill ] = "tkill",
493 493 /* 201 */ [ __NR_time ] = "time",
494 494 /* 202 */ [ __NR_futex ] = "futex",
495 495 /* 203 */ [ __NR_sched_setaffinity ] = "sched_setaffinity",
496 496 /* 204 */ [ __NR_sched_getaffinity ] = "sched_getaffinity",
497 497 /* 205 */ [ __NR_set_thread_area ] = "set_thread_area",
498 498 /* 206 */ [ __NR_io_setup ] = "io_setup",
499 499 /* 207 */ [ __NR_io_destroy ] = "io_destroy",
500 500 /* 208 */ [ __NR_io_getevents ] = "io_getevents",
501 501 /* 209 */ [ __NR_io_submit ] = "io_submit",
502 502 /* 210 */ [ __NR_io_cancel ] = "io_cancel",
503 503 /* 211 */ [ __NR_get_thread_area ] = "get_thread_area",
504 504 /* 212 */ [ __NR_lookup_dcookie ] = "lookup_dcookie",
505 505 /* 213 */ [ __NR_epoll_create ] = "epoll_create",
506 506 /* 214 */ [ __NR_epoll_ctl_old ] = "epoll_ctl_old",
507 507 /* 215 */ [ __NR_epoll_wait_old ] = "epoll_wait_old",
508 508 /* 216 */ [ __NR_remap_file_pages ] = "remap_file_pages",
509 509 /* 217 */ [ __NR_getdents64 ] = "getdents64",
510 510 /* 218 */ [ __NR_set_tid_address ] = "set_tid_address",
511 511 /* 219 */ [ __NR_restart_syscall ] = "restart_syscall",
512 512 /* 220 */ [ __NR_semtimedop ] = "semtimedop",
513 513 /* 221 */ [ __NR_fadvise64 ] = "fadvise64",
514 514 /* 222 */ [ __NR_timer_create ] = "timer_create",
515 515 /* 223 */ [ __NR_timer_settime ] = "timer_settime",
516 516 /* 224 */ [ __NR_timer_gettime ] = "timer_gettime",
517 517 /* 225 */ [ __NR_timer_getoverrun ] = "timer_getoverrun",
518 518 /* 226 */ [ __NR_timer_delete ] = "timer_delete",
519 519 /* 227 */ [ __NR_clock_settime ] = "clock_settime",
520 520 /* 228 */ [ __NR_clock_gettime ] = "clock_gettime",
521 521 /* 229 */ [ __NR_clock_getres ] = "clock_getres",
522 522 /* 230 */ [ __NR_clock_nanosleep ] = "clock_nanosleep",
523 523 /* 231 */ [ __NR_exit_group ] = "exit_group",
524 524 /* 232 */ [ __NR_epoll_wait ] = "epoll_wait",
525 525 /* 233 */ [ __NR_epoll_ctl ] = "epoll_ctl",
526 526 /* 234 */ [ __NR_tgkill ] = "tgkill",
527 527 /* 235 */ [ __NR_utimes ] = "utimes",
528 528 /* 236 */ [ __NR_vserver ] = "vserver",
529 529 /* 237 */ [ __NR_mbind ] = "mbind",
530 530 /* 238 */ [ __NR_set_mempolicy ] = "set_mempolicy",
531 531 /* 239 */ [ __NR_get_mempolicy ] = "get_mempolicy",
532 532 /* 240 */ [ __NR_mq_open ] = "mq_open",
533 533 /* 241 */ [ __NR_mq_unlink ] = "mq_unlink",
534 534 /* 242 */ [ __NR_mq_timedsend ] = "mq_timedsend",
535 535 /* 243 */ [ __NR_mq_timedreceive ] = "mq_timedreceive",
536 536 /* 244 */ [ __NR_mq_notify ] = "mq_notify",
537 537 /* 245 */ [ __NR_mq_getsetattr ] = "mq_getsetattr",
538 538 /* 246 */ [ __NR_kexec_load ] = "kexec_load",
539 539 /* 247 */ [ __NR_waitid ] = "waitid",
540 540 /* 248 */ [ __NR_add_key ] = "add_key",
541 541 /* 249 */ [ __NR_request_key ] = "request_key",
542 542 /* 250 */ [ __NR_keyctl ] = "keyctl",
543 543 /* 251 */ [ __NR_ioprio_set ] = "ioprio_set",
544 544 /* 252 */ [ __NR_ioprio_get ] = "ioprio_get",
545 545 /* 253 */ [ __NR_inotify_init ] = "inotify_init",
546 546 /* 254 */ [ __NR_inotify_add_watch ] = "inotify_add_watch",
547 547 /* 255 */ [ __NR_inotify_rm_watch ] = "inotify_rm_watch",
548 548 /* 256 */ [ __NR_migrate_pages ] = "migrate_pages",
549 549 /* 257 */ [ __NR_openat ] = "openat",
550 550 /* 258 */ [ __NR_mkdirat ] = "mkdirat",
551 551 /* 259 */ [ __NR_mknodat ] = "mknodat",
552 552 /* 260 */ [ __NR_fchownat ] = "fchownat",
553 553 /* 261 */ [ __NR_futimesat ] = "futimesat",
554 554 /* 262 */ [ __NR_newfstatat ] = "newfstatat",
555 555 /* 263 */ [ __NR_unlinkat ] = "unlinkat",
556 556 /* 264 */ [ __NR_renameat ] = "renameat",
557 557 /* 265 */ [ __NR_linkat ] = "linkat",
558 558 /* 266 */ [ __NR_symlinkat ] = "symlinkat",
559 559 /* 267 */ [ __NR_readlinkat ] = "readlinkat",
560 560 /* 268 */ [ __NR_fchmodat ] = "fchmodat",
561 561 /* 269 */ [ __NR_faccessat ] = "faccessat",
562 562 /* 270 */ [ __NR_pselect6 ] = "pselect6",
563 563 /* 271 */ [ __NR_ppoll ] = "ppoll",
564 564 /* 272 */ [ __NR_unshare ] = "unshare",
565 565 /* 273 */ [ __NR_set_robust_list ] = "set_robust_list",
566 566 /* 274 */ [ __NR_get_robust_list ] = "get_robust_list",
567 567 /* 275 */ [ __NR_splice ] = "splice",
568 568 /* 276 */ [ __NR_tee ] = "tee",
569 569 /* 277 */ [ __NR_sync_file_range ] = "sync_file_range",
570 570 /* 278 */ [ __NR_vmsplice ] = "vmsplice",
571 571 /* 279 */ [ __NR_move_pages ] = "move_pages",
572 572 /* 280 */ [ __NR_utimensat ] = "utimensat",
573 573 /* 281 */ [ __NR_epoll_pwait ] = "epoll_pwait",
574 574 /* 282 */ [ __NR_signalfd ] = "signalfd",
575 575 /* 283 */ [ __NR_timerfd_create ] = "timerfd_create",
576 576 /* 284 */ [ __NR_eventfd ] = "eventfd",
577 577 /* 285 */ [ __NR_fallocate ] = "fallocate",
578 578 /* 286 */ [ __NR_timerfd_settime ] = "timerfd_settime",
579 579 /* 287 */ [ __NR_timerfd_gettime ] = "timerfd_gettime",
580 580 /* 288 */ [ __NR_accept4 ] = "accept4",
581 581 /* 289 */ [ __NR_signalfd4 ] = "signalfd4",
582 582 /* 290 */ [ __NR_eventfd2 ] = "eventfd2",
583 583 /* 291 */ [ __NR_epoll_create1 ] = "epoll_create1",
584 584 /* 292 */ [ __NR_dup3 ] = "dup3",
585 585 /* 293 */ [ __NR_pipe2 ] = "pipe2",
586 586 /* 294 */ [ __NR_inotify_init1 ] = "inotify_init1",
587 587 /* 295 */ [ __NR_preadv ] = "preadv",
588 588 /* 296 */ [ __NR_pwritev ] = "pwritev",
589 589 /* 297 */ [ __NR_rt_tgsigqueueinfo ] = "rt_tgsigqueueinfo",
590 590 /* 298 */ [ __NR_perf_event_open ] = "perf_event_open",
591 591 /* 299 */ [ __NR_recvmmsg ] = "recvmmsg",
592 592 /* 300 */ [ __NR_fanotify_init ] = "fanotify_init",
593 593 /* 301 */ [ __NR_fanotify_mark ] = "fanotify_mark",
594 594 /* 302 */ [ __NR_prlimit64 ] = "prlimit64",
595 595 /* 303 */ [ __NR_name_to_handle_at ] = "name_to_handle_at",
596 596 /* 304 */ [ __NR_open_by_handle_at ] = "open_by_handle_at",
597 597 /* 305 */ [ __NR_clock_adjtime ] = "clock_adjtime",
598 598 /* 306 */ [ __NR_syncfs ] = "syncfs",
599 599 /* 307 */ [ __NR_sendmmsg ] = "sendmmsg",
600 600 /* 308 */ [ __NR_setns ] = "setns",
601 601 /* 309 */ [ __NR_getcpu ] = "getcpu",
602 602 /* 310 */ [ __NR_process_vm_readv ] = "process_vm_readv",
603 603 /* 311 */ [ __NR_process_vm_writev ] = "process_vm_writev",
604 604 /* 312 */ [ __NR_kcmp ] = "kcmp",
605 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 619 #define NUM_SYSCALLS ARRAY_SIZE(syscall_names)
608 620 #define NUM_ACTIONS (NUM_SYSCALLS+64)
609 621
610 622 enum action {
611 623 A_DEFAULT, // Use the default action
612 624 A_NO, // Always forbid
613 625 A_YES, // Always permit
614 626 A_FILENAME, // Permit if arg1 is a known filename
615 627 A_ACTION_MASK = 15,
616 628 A_NO_RETVAL = 32, // Does not return a value
617 629 A_SAMPLE_MEM = 64, // Sample memory usage before the syscall
618 630 A_LIBERAL = 128, // Valid only in liberal mode
619 631 // Must fit in a unsigned char
620 632 };
621 633
622 634 static unsigned char syscall_action[NUM_ACTIONS] = {
623 635 #define S(x) [__NR_##x]
624 636
625 637 // Syscalls permitted for specific file names
626 638 S(open) = A_FILENAME,
627 639 S(creat) = A_FILENAME,
628 640 S(unlink) = A_FILENAME,
629 641 S(access) = A_FILENAME,
630 642 S(truncate) = A_FILENAME,
631 643 S(stat) = A_FILENAME,
632 644 S(lstat) = A_FILENAME,
633 645 S(readlink) = A_FILENAME,
634 646 #ifndef CONFIG_BOX_USER_AMD64
635 647 S(oldstat) = A_FILENAME,
636 648 S(oldlstat) = A_FILENAME,
637 649 S(truncate64) = A_FILENAME,
638 650 S(stat64) = A_FILENAME,
639 651 S(lstat64) = A_FILENAME,
640 652 #endif
641 653
642 654 // Syscalls permitted always
643 655 S(exit) = A_YES | A_SAMPLE_MEM,
644 656 S(read) = A_YES,
645 657 S(write) = A_YES,
646 658 S(close) = A_YES,
647 659 S(lseek) = A_YES,
648 660 S(getpid) = A_YES,
649 661 S(getuid) = A_YES,
650 662 S(dup) = A_YES,
651 663 S(brk) = A_YES,
652 664 S(getgid) = A_YES,
653 665 S(geteuid) = A_YES,
654 666 S(getegid) = A_YES,
655 667 S(dup2) = A_YES,
656 668 S(ftruncate) = A_YES,
657 669 S(fstat) = A_YES,
658 670 S(personality) = A_YES,
659 671 S(readv) = A_YES,
660 672 S(writev) = A_YES,
661 673 S(getresuid) = A_YES,
662 674 #ifdef __NR_pread64
663 675 S(pread64) = A_YES,
664 676 S(pwrite64) = A_YES,
665 677 #else
666 678 S(pread) = A_YES,
667 679 S(pwrite) = A_YES,
668 680 #endif
669 681 S(fcntl) = A_YES,
670 682 S(mmap) = A_YES,
671 683 S(munmap) = A_YES,
672 684 S(ioctl) = A_YES,
673 685 S(uname) = A_YES,
674 686 S(gettid) = A_YES,
675 687 S(set_thread_area) = A_YES,
676 688 S(get_thread_area) = A_YES,
677 689 S(set_tid_address) = A_YES,
678 690 S(exit_group) = A_YES | A_SAMPLE_MEM,
679 691 #ifdef CONFIG_BOX_USER_AMD64
680 692 S(arch_prctl) = A_YES,
681 693 #else
682 694 S(oldfstat) = A_YES,
683 695 S(ftruncate64) = A_YES,
684 696 S(_llseek) = A_YES,
685 697 S(fstat64) = A_YES,
686 698 S(fcntl64) = A_YES,
687 699 S(mmap2) = A_YES,
688 700 #endif
689 701
690 702 // Syscalls permitted only in liberal mode
691 703 S(time) = A_YES | A_LIBERAL,
692 704 S(alarm) = A_YES | A_LIBERAL,
693 705 S(pause) = A_YES | A_LIBERAL,
694 706 S(fchmod) = A_YES | A_LIBERAL,
695 707 S(getrlimit) = A_YES | A_LIBERAL,
696 708 S(getrusage) = A_YES | A_LIBERAL,
697 709 S(gettimeofday) = A_YES | A_LIBERAL,
698 710 S(select) = A_YES | A_LIBERAL,
699 711 S(setitimer) = A_YES | A_LIBERAL,
700 712 S(getitimer) = A_YES | A_LIBERAL,
701 713 S(mprotect) = A_YES | A_LIBERAL,
702 714 S(getdents) = A_YES | A_LIBERAL,
703 715 S(getdents64) = A_YES | A_LIBERAL,
704 716 S(fdatasync) = A_YES | A_LIBERAL,
705 717 S(mremap) = A_YES | A_LIBERAL,
706 718 S(poll) = A_YES | A_LIBERAL,
707 719 S(getcwd) = A_YES | A_LIBERAL,
708 720 S(nanosleep) = A_YES | A_LIBERAL,
709 721 S(rt_sigreturn) = A_YES | A_LIBERAL | A_NO_RETVAL,
710 722 S(rt_sigaction) = A_YES | A_LIBERAL,
711 723 S(rt_sigprocmask) = A_YES | A_LIBERAL,
712 724 S(rt_sigpending) = A_YES | A_LIBERAL,
713 725 S(rt_sigtimedwait) = A_YES | A_LIBERAL,
714 726 S(rt_sigqueueinfo) = A_YES | A_LIBERAL,
715 727 S(rt_sigsuspend) = A_YES | A_LIBERAL,
716 728 S(_sysctl) = A_YES | A_LIBERAL,
717 729 #ifndef CONFIG_BOX_USER_AMD64
718 730 S(sigaction) = A_YES | A_LIBERAL,
719 731 S(sgetmask) = A_YES | A_LIBERAL,
720 732 S(ssetmask) = A_YES | A_LIBERAL,
721 733 S(sigsuspend) = A_YES | A_LIBERAL,
722 734 S(sigpending) = A_YES | A_LIBERAL,
723 735 S(sigreturn) = A_YES | A_LIBERAL | A_NO_RETVAL,
724 736 S(sigprocmask) = A_YES | A_LIBERAL,
725 737 S(ugetrlimit) = A_YES | A_LIBERAL,
726 738 S(readdir) = A_YES | A_LIBERAL,
727 739 S(signal) = A_YES | A_LIBERAL,
728 740 S(_newselect) = A_YES | A_LIBERAL,
729 741 #endif
730 742
731 743 #undef S
732 744 };
733 745
734 746 static const char *
735 747 syscall_name(unsigned int id, char *buf)
736 748 {
737 749 if (id < NUM_SYSCALLS && syscall_names[id])
738 750 return syscall_names[id];
739 751 else
740 752 {
741 753 sprintf(buf, "#%d", id);
742 754 return buf;
743 755 }
744 756 }
745 757
746 758 static int
747 759 syscall_by_name(char *name)
748 760 {
749 761 for (unsigned int i=0; i<NUM_SYSCALLS; i++)
750 762 if (syscall_names[i] && !strcmp(syscall_names[i], name))
751 763 return i;
752 764 if (name[0] == '#')
753 765 name++;
754 766 if (!*name)
755 767 return -1;
756 768 char *ep;
757 769 unsigned long l = strtoul(name, &ep, 0);
758 770 if (*ep)
759 771 return -1;
760 772 if (l >= NUM_ACTIONS)
761 773 return NUM_ACTIONS;
762 774 return l;
763 775 }
764 776
765 777 static int
766 778 set_syscall_action(char *a)
767 779 {
768 780 char *sep = strchr(a, '=');
769 781 enum action act = A_YES;
770 782 if (sep)
771 783 {
772 784 *sep++ = 0;
773 785 if (!strcmp(sep, "yes"))
774 786 act = A_YES;
775 787 else if (!strcmp(sep, "no"))
776 788 act = A_NO;
777 789 else if (!strcmp(sep, "file"))
778 790 act = A_FILENAME;
779 791 else
780 792 return 0;
781 793 }
782 794
783 795 int sys = syscall_by_name(a);
784 796 if (sys < 0)
785 797 die("Unknown syscall `%s'", a);
786 798 if (sys >= NUM_ACTIONS)
787 799 die("Syscall `%s' out of range", a);
788 800 syscall_action[sys] = act;
789 801 return 1;
790 802 }
791 803
792 804 /*** Path rules ***/
793 805
794 806 struct path_rule {
795 807 char *path;
796 808 enum action action;
797 809 struct path_rule *next;
@@ -1,188 +1,196
1 1 #!/usr/bin/env ruby
2 2
3 3 require 'fileutils'
4 4
5 5 ##############################
6 6 #
7 7 # Standard Compile Script
8 8 #
9 9 # Supported compilers:
10 10 # gcc, g++, and fpc.
11 11 #
12 12 ##############################
13 13
14 14 def talk(str='')
15 15 if ENV['TALKATIVE']!=nil
16 16 puts str
17 17 end
18 18 if ENV['GRADER_LOGGING']!=nil
19 19 log_fname = ENV['GRADER_LOGGING']
20 20 fp = File.open(log_fname,"a")
21 21 fp.puts("run: #{Time.new.strftime("%H:%M")} #{str}")
22 22 fp.close
23 23 end
24 24 end
25 25
26 26 C_COMPILER = "/usr/bin/gcc"
27 27 CPLUSPLUS_COMPILER = "/usr/bin/g++"
28 28 PASCAL_COMPILER = "/usr/bin/fpc"
29 29 JAVA_COMPILER = "/usr/bin/javac"
30 30 RUBY_INTERPRETER = "/usr/bin/ruby"
31 31 PYTHON_INTERPRETER = "/usr/bin/python3"
32 32 PYTHON_CHECKER = "/usr/bin/pyflakes"
33 33 PHP_INTERPRETER = "/usr/bin/php"
34 + HASKELL_COMPILER = "/usr/bin/ghc"
34 35
35 36 C_OPTIONS = "-O2 -s -static -std=c99 -DCONTEST -lm -Wall"
36 37 CPLUSPLUS_OPTIONS = "-O2 -s -std=c++11 -static -DCONTEST -lm -Wall"
37 38 PASCAL_OPTIONS = "-O1 -XS -dCONTEST"
38 39 JAVA_OPTIONS = ""
39 40 PYTHON_OPTIONS = ""
40 41 PHP_OPTIONS = "-l"
42 + HASKELL_OPTIONS = ""
41 43
42 44 # Check for the correct number of arguments. Otherwise, print usage.
43 45 if ARGV.length == 0 or ARGV.length > 4
44 46 puts "Usage: compile <language> [<source-file>] [<output-file>] [<message-file>]"
45 47 puts
46 48 puts "<source-file> is defaulted to \"source\"."
47 49 puts "<output-file> is defaulted to \"a.out\"."
48 50 puts "<message-file> is defaulted to \"compiler_message\"."
49 51 puts
50 52 exit(127)
51 53 end
52 54
53 55 PARAMS = {
54 56 :source_file => [1,'source'],
55 57 :output_file => [2,'a.out'],
56 58 :message_file => [3,'compiler_message']
57 59 }
58 60
59 61 params = {}
60 62 params[:prog_lang] = ARGV[0]
61 63 PARAMS.each_key do |param_name|
62 64 index, default = PARAMS[param_name]
63 65 if ARGV.length > index
64 66 params[param_name] = ARGV[index]
65 67 else
66 68 params[param_name] = default
67 69 end
68 70 talk "#{param_name}: #{params[param_name]}"
69 71 end
70 72
71 73 # Remove any remaining output files or message files.
72 74 if FileTest.exists? params[:output_file]
73 75 FileUtils.rm(params[:output_file])
74 76 end
75 77 if FileTest.exists? params[:message_file]
76 78 FileUtils.rm(params[:message_file])
77 79 end
78 80
79 81 # Check if the source file exists before attempt compiling.
80 82 if !FileTest.exists? params[:source_file]
81 83 talk("ERROR: The source file does not exist!")
82 84 open(params[:message_file],"w") do |f|
83 85 f.puts "ERROR: The source file did not exist."
84 86 end
85 87 exit(127)
86 88 end
87 89
88 90 if params[:prog_lang]=='cpp'
89 91 params[:prog_lang] = 'c++'
90 92 end
91 93
92 94 # Compile.
93 95 case params[:prog_lang]
94 96
95 97 when "c"
96 98 command = "#{C_COMPILER} #{params[:source_file]} -o #{params[:output_file]} #{C_OPTIONS}"
97 99 system(command, err: params[:message_file])
98 100
99 101 when "c++"
100 102 command = "#{CPLUSPLUS_COMPILER} #{params[:source_file]} -o #{params[:output_file]} #{CPLUSPLUS_OPTIONS}"
101 103 system(command, err: params[:message_file])
102 104
103 105 when "pas"
104 106 command = "#{PASCAL_COMPILER} #{params[:source_file]} -ooutpas #{PASCAL_OPTIONS}"
105 107 system(command,out: params[:message_file])
106 108 FileUtils.mv("output", params[:output_file])
107 109
108 110 when "java"
109 111 #rename the file to the public class name
110 112
111 113 #get the class name
112 114 classname = 'DUMMY'
113 115 source = Array.new
114 116 File.foreach(params[:source_file],'r:UTF-8') do |line|
115 117 line.encode!('UTF-8','UTF-8',invalid: :replace, replace: '')
116 118 md = /\s*public\s*class\s*(\w*)/.match(line)
117 119 classname=md[1] if md
118 120 source << line unless line =~ /\s*package\s*\w+\s*\;/
119 121 end
120 122 File.open("#{classname}.java","w") do |file|
121 123 source.each do |s|
122 124 file.puts s
123 125 end
124 126 end
125 127 #system("cp #{params[:source_file]} #{classname}.java")
126 128 command = "#{JAVA_COMPILER} -encoding utf8 #{classname}.java"
127 129 system(command, err: params[:message_file])
128 130 if File.exists?(classname + ".class")
129 131 File.open(params[:output_file],"w") {|file| file.write("#{classname}")}
130 132 end
131 133 if classname == 'DUMMY'
132 134 File.open(params[:message_file],"w") {|file| file.write("Cannot find any public class in the source code\n")}
133 135 end
134 136
135 137 when "ruby"
136 138 command = "#{RUBY_INTERPRETER} -c #{params[:source_file]}"
137 139 if system(command, err: params[:message_file])
138 140 File.open(params[:output_file],"w") do |out_file|
139 141 out_file.puts "#!#{RUBY_INTERPRETER}"
140 142 File.open(params[:source_file],"r").each do |line|
141 143 out_file.print line
142 144 end
143 145 end
144 146 File.chmod(0755, params[:output_file])
145 147 end
146 148
147 149 when "python"
148 - command = "#{PYTHON_CHECKER} #{params[:source_file]}"
149 - if system(command, out: params[:message_file])
150 + #command = "#{PYTHON_CHECKER} #{params[:source_file]}"
151 + #if system(command, out: params[:message_file])
150 152 #compile to python bytecode
151 153 command = "#{PYTHON_INTERPRETER} -c \"import py_compile; py_compile.compile('#{params[:source_file]}','#{params[:source_file]}c');\""
152 154 puts "compile: #{command}"
153 - system(command)
154 - puts "pwd: " + Dir.pwd
155 - Dir.new('.').each {|file| puts file}
156 - File.open(params[:output_file],"w") do |out_file|
157 - out_file.puts "#!#{PYTHON_INTERPRETER} #{params[:source_file]}c"
155 + system(command, err: params[:message_file])
156 + if FileTest.exists?("#{params[:source_file]}c")
157 + puts "pwd: " + Dir.pwd
158 + Dir.new('.').each {|file| puts file}
159 + File.open(params[:output_file],"w") do |out_file|
160 + out_file.puts "#!#{PYTHON_INTERPRETER} #{params[:source_file]}c"
161 + end
162 + File.chmod(0755, params[:output_file])
163 + FileUtils.cp("#{params[:source_file]}c",params[:output_file])
158 164 end
159 - File.chmod(0755, params[:output_file])
160 - FileUtils.cp("#{params[:source_file]}c",params[:output_file])
161 - end
165 + #end
162 166
163 167 when "php"
164 168 command = "#{PHP_INTERPRETER} #{PHP_OPTIONS} #{params[:source_file]}"
165 169 if system(command, err: params[:message_file])
166 170 File.open(params[:output_file],"w") do |out_file|
167 171 out_file.puts "#!#{PHP_INTERPRETER}"
168 172 File.open(params[:source_file],"r").each do |line|
169 173 out_file.print line
170 174 end
171 175 end
172 176 File.chmod(0755, params[:output_file])
173 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 183 else
176 184 talk("ERROR: Invalid language specified!")
177 185 open(params[:message_file],"w") do |f|
178 186 f.puts "ERROR: Invalid language specified!"
179 187 end
180 188 exit(127)
181 189 end
182 190
183 191 # Report success or failure.
184 192 if FileTest.exists? params[:output_file]
185 193 talk "Compilation was successful!"
186 194 else
187 195 talk "ERROR: Something was wrong during the compilation!"
188 196 end
@@ -1,180 +1,186
1 1 #!/usr/bin/env ruby
2 2
3 3 require 'fileutils'
4 4
5 5 def log(str='')
6 6 if ENV['TALKATIVE']!=nil
7 7 puts str
8 8 end
9 9 if ENV['GRADER_LOGGING']!=nil
10 10 log_fname = ENV['GRADER_LOGGING']
11 11 fp = File.open(log_fname,"a")
12 12 fp.puts("judge: #{Time.new.strftime("%H:%M")} #{str}")
13 13 fp.close
14 14 end
15 15 end
16 16
17 17 problem_home = ENV['PROBLEM_HOME']
18 18
19 19 def execute(command, error_message="")
20 20 if not system(command)
21 21 msg = "ERROR: #{error_message}"
22 22 log msg
23 23 raise(msg)
24 24 end
25 25 end
26 26
27 27 def call_and_log(error_message)
28 28 begin
29 29 yield
30 30 rescue
31 31 msg = "ERROR: #{error_message}"
32 32 log msg
33 33 raise msg
34 34 end
35 35 end
36 36
37 37 def clear_and_create_empty_dir(dir)
38 38 FileUtils.rm_rf(dir, :secure => true)
39 39 call_and_log("Cannot make directory #{dir}.") { FileUtils.mkdir(dir) }
40 40 end
41 41
42 42 # ARGV[0] --- language
43 43 # ARGV[1] --- program source file
44 44 # ARGV[2] --- test result directory
45 45 # ARGV[3] --- sandbox directory
46 46
47 47 if ARGV.length < 2 || ARGV.length > 4
48 48 puts "Usage: judge <language> <program-source> [<test-result-directory>] [<sandbox-directory>]"
49 49 puts " <sandbox-directory> is defaulted to ./sandbox"
50 50 puts " <test-result-directory> is defaulted to ./test-result"
51 51 puts "WARNING: The judge script will forcefully create the (implicitly and explicitly) specified directories and remove anything inside it."
52 52 exit(127)
53 53 end
54 54
55 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 57 log "You specified a language that is not supported: #{language}."
58 58 exit(127)
59 59 end
60 60
61 61 source_file = ARGV[1]
62 62 ENV['SOURCE_NAME'] = source_file
63 63 if File.exist?(source_file) == false
64 64 log "The source file does not exist."
65 65 exit(127)
66 66 end
67 67
68 68 log "Making test result and sandbox directories..."
69 69
70 70 current_dir = FileUtils.pwd
71 71 current_dir.strip!
72 72
73 73 if ARGV.length >= 3
74 74 test_result_dir = ARGV[2]
75 75 else
76 76 test_result_dir = "#{current_dir}/test-result"
77 77 end
78 78
79 79 log "Test result directory: #{test_result_dir}"
80 80 clear_and_create_empty_dir(test_result_dir)
81 81
82 82 if ARGV.length >= 4
83 83 sandbox_dir = ARGV[3]
84 84 else
85 85 sandbox_dir = "#{current_dir}/sandbox"
86 86 end
87 87 log "Sandbox directory: #{sandbox_dir}"
88 88 clear_and_create_empty_dir(sandbox_dir)
89 89
90 90 # Compile
91 91 log
92 92 log "Compiling..."
93 93 call_and_log("Cannot copy the source file to #{sandbox_dir}") {
94 94 FileUtils.cp(source_file, sandbox_dir)
95 95 }
96 96 begin
97 97 Dir.chdir sandbox_dir
98 98 rescue
99 99 log "ERROR: Cannot change directory to #{sandbox_dir}."
100 100 exit(127)
101 101 end
102 102 execute("#{problem_home}/script/compile #{language} #{source_file}", "Compilation error!")
103 103 compile_message = open("compiler_message").read
104 104 compile_message.strip!
105 105 call_and_log("Cannot move the compiler message to #{test_result_dir}.") {
106 106 FileUtils.mv("compiler_message", test_result_dir)
107 107 }
108 108 if !FileTest.exist?("a.out")
109 109 log "Cannot compile the source code. See message in #{test_result_dir}/compile_message"
110 110 exit(127)
111 111 else
112 112 call_and_log("Cannot move the compiled program to #{test_result_dir}") {
113 113 FileUtils.mv("a.out",test_result_dir)
114 114 if language == "java" then Dir["*.class"].each { |file| FileUtils.mv(file,test_result_dir)} end
115 115 if language == "python" then Dir["*.pyc"].each { |file| FileUtils.mv(file,test_result_dir)} end
116 116 }
117 117 FileUtils.rm_rf("#{sandbox_dir}/.")
118 118 end
119 119
120 120 require "#{problem_home}/script/test_dsl.rb"
121 121 load "#{problem_home}/test_cases/all_tests.cfg"
122 122 problem = Problem.get_instance
123 123
124 124 if problem.well_formed? == false
125 125 log "The problem specification is not well formed."
126 126 exit(127)
127 127 end
128 128
129 129 # Doing the testing.
130 130 (1..(problem.num_tests)).each do |test_num|
131 131
132 132 $stdout.print "[#{test_num}]"
133 133 $stdout.flush
134 134
135 135 log "Test number: #{test_num}"
136 136
137 137 call_and_log("Cannot copy the compiled program into #{sandbox_dir}") {
138 138 FileUtils.cp("#{test_result_dir}/a.out", sandbox_dir, :preserve => true)
139 139 if language == "java" then Dir["#{test_result_dir}/*.class"].each { |file| FileUtils.cp(file,sandbox_dir)} end
140 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 149 begin
144 150 execute("#{problem_home}/script/run #{language} #{test_num} ", "Error occured during execution of the run script")
145 151 rescue
146 152 # do nothing
147 153 end
148 154
149 155 call_and_log("Cannot create directory #{test_result_dir}/#{test_num}") {
150 156 FileUtils.mkdir "#{test_result_dir}/#{test_num}"
151 157 }
152 158 call_and_log("Cannot copy the result file into #{test_result_dir}/#{test_num}") {
153 159 FileUtils.mv "#{sandbox_dir}/result", "#{test_result_dir}/#{test_num}"
154 160 }
155 161 call_and_log("Cannot copy the comment file into #{test_result_dir}/#{test_num}") {
156 162 FileUtils.mv "#{sandbox_dir}/comment", "#{test_result_dir}/#{test_num}"
157 163 }
158 164 call_and_log("Cannot copy the output file into #{test_result_dir}/#{test_num}") {
159 165 FileUtils.mv "#{sandbox_dir}/output.txt", "#{test_result_dir}/#{test_num}"
160 166 }
161 167 call_and_log("Cannot clear #{sandbox_dir}") {
162 168 FileUtils.rm_rf(Dir.glob("#{sandbox_dir}/*"), :secure => true)
163 169 }
164 170 end
165 171
166 172 $stdout.print "[done]\n"
167 173
168 174 # Grade
169 175 log
170 176 log "Grading..."
171 177 begin
172 178 Dir.chdir test_result_dir
173 179 rescue
174 180 log "ERROR: Cannot change directory to #{test_result_dir}."
175 181 exit(127)
176 182 end
177 183 execute("#{problem_home}/script/grade", "An error occured during grading!")
178 184
179 185 log
180 186 log "All done!"
@@ -1,189 +1,192
1 1 #!/usr/bin/env ruby
2 2
3 3 require 'fileutils'
4 4
5 5 def log(str='')
6 6 if ENV['TALKATIVE']!=nil
7 7 puts str
8 8 end
9 9 if ENV['GRADER_LOGGING']!=nil
10 10 log_fname = ENV['GRADER_LOGGING']
11 11 fp = File.open(log_fname,"a")
12 12 fp.puts("run: #{Time.new.strftime("%H:%M")} #{str}")
13 13 fp.close
14 14 end
15 15 end
16 16
17 17 def extract_time(t)
18 18 # puts "TIME: #{t}"
19 19 if (result=/^(.*)r(.*)u(.*)s/.match(t))
20 20 {:real => result[1], :user => result[2], :sys => result[3]}
21 21 else
22 22 #{:real => 0, :user => 0, :sys => 0}
23 23 #puts "ERROR READING RUNNING TIME: #{t}"
24 24 raise "Error reading running time: #{t}"
25 25 end
26 26 end
27 27
28 28 def compile_box(source,bin)
29 29 system("g++ #{source} -o #{bin}")
30 30 end
31 31
32 32 if ARGV.length < 2 || ARGV.length > 3
33 33 puts "Usage: run <language> <test-num> [<program-name>]"
34 34 exit(127)
35 35 end
36 36
37 37 language = ARGV[0]
38 38 test_num = ARGV[1].to_i
39 39 if ARGV.length > 2
40 40 program_name = ARGV[2]
41 41 else
42 42 program_name = "a.out"
43 43 end
44 44
45 45 problem_home = ENV['PROBLEM_HOME']
46 46 source_name = ENV['SOURCE_NAME']
47 47 require "#{problem_home}/script/test_dsl.rb"
48 48 load "#{problem_home}/test_cases/all_tests.cfg"
49 49 problem = Problem.get_instance
50 50
51 51 sandbox_dir = Dir.getwd
52 52
53 53 if problem.well_formed? == false
54 54 log "The problem specification is not well formed."
55 55 exit(127)
56 56 end
57 57
58 58 # Check if the test number is okay.
59 59 if test_num <= 0 || test_num > problem.num_tests
60 60 log "You have specified a wrong test number."
61 61 exit(127)
62 62 end
63 63
64 64 #####################################
65 65 # Set the relavant file names here. #
66 66 #####################################
67 67
68 68 input_file_name = "#{problem_home}/test_cases/#{test_num}/input-#{test_num}.txt"
69 69
70 70 #####################################
71 71
72 72 time_limit = problem.get_time_limit test_num
73 73 mem_limit = problem.get_mem_limit(test_num) * 1024
74 74
75 75 # Copy the input file.
76 76 #`cp #{problem_home}/test_cases/#{test_num}/#{input_file_name} .`
77 77
78 78 # check if box is there, if not, compile it!
79 79 if !File.exists?("#{problem_home}/script/box")
80 80 log "WARNING: Compiling box: to increase efficiency, it should be compile manually"
81 81 compile_box("#{problem_home}/script/box.cc",
82 82 "#{problem_home}/script/box")
83 83 end
84 84
85 85 # Hide PROBLEM_HOME
86 86 ENV['PROBLEM_HOME'] = nil
87 87 ENV['SOURCE_NAME'] = nil
88 88
89 89 # Run the program.
90 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 93 JAVA_OPTION = "-s set_robust_list -s futex -s clone -s getppid -s clone -s wait4 -p /usr/bin/ -p ./"
94 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 /dev/urandom -p /usr/ -p #{sandbox_dir}/#{program_name} -p ./#{program_name} -p #{sandbox_dir}/#{source_name} -p /proc/mounts -s statfs -s set_robust_list -s openat -s recvmsg -s connect -s socket -s sendto -s futex -s sigaltstack -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 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 99 case language
99 100 when "java"
100 101 # for java, extract the classname
101 102 # wne have to add additional systemcall and we don't check the mem limit (dunno how to fix...)
102 103 classname = 'DUMMY'
103 104 File.open(program_name,"r").each do |line|
104 105 classname = line
105 106 end
106 107 #for java, we cannot really check the memory limit...
107 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 109 when "ruby"
109 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 111 when "python"
111 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 115 when "php"
113 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 117 else # for c++, pascal, we do the normal checking
115 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 119 end
117 120
118 121
119 122 log "Running test #{test_num}..."
120 123 log run_command
121 124 log
122 125 system(run_command,err: 'run_result')
123 126
124 127 # Restore PROBLEM_HOME
125 128 ENV['PROBLEM_HOME'] = problem_home
126 129
127 130 # Create the result file.
128 131 result_file = File.new("result", "w")
129 132 comment_file = File.new("comment", "w")
130 133
131 134 # Check if the program actually produced any output.
132 135 run_result_file = File.new("run_result", "r")
133 136 run_result = run_result_file.readlines
134 137 run_result_file.close
135 138
136 139 run_stat = run_result[run_result.length-1]
137 140 running_time = extract_time(run_stat)
138 141
139 142 report = lambda{ |status, points, comment|
140 143 result_file.write status.strip
141 144 result_file.write "\n"
142 145 result_file.write points.to_s.strip
143 146 result_file.write "\n"
144 147 result_file.write run_stat.strip
145 148 result_file.write "\n"
146 149 result_file.close
147 150 FileUtils.rm "run_result"
148 151 # `rm output.txt` --- keep the output
149 152
150 153 comment_file.write comment
151 154
152 155 # added for debuggin --- jittat
153 156 comment_file.write "--run-result--\n"
154 157 run_result.each do |l|
155 158 comment_file.write l
156 159 end
157 160
158 161 comment_file.close
159 162
160 163 log "Done!"
161 164 exit(0)
162 165 }
163 166
164 167
165 168 if run_result[0][0,2] != "OK"
166 169 log "There was a runtime error."
167 170 report.call(run_result[0], 0, "No comment.\n")
168 171 end
169 172
170 173 if running_time[:user].to_f > time_limit
171 174 log "Time limit exceeded."
172 175 report.call("Time limit exceeded", 0, "No comment.\n")
173 176 end
174 177
175 178 # Run 'check' to evaluate the output.
176 179 #puts "There was no runtime error. Proceed to checking the output."
177 180 check_command = "#{problem_home}/script/check #{language} #{test_num}"
178 181 log "Checking the output..."
179 182 log check_command
180 183 if not system(check_command)
181 184 log "Problem with check script"
182 185 report.call("Incorrect",0,"Check script error.\n")
183 186 exit(127)
184 187 end
185 188
186 189 check_file = File.new("check_result", "r")
187 190 check_file_lines = check_file.readlines
188 191
189 192 report.call(check_file_lines[0], check_file_lines[1], "No comment.\n")
You need to be logged in to leave comments. Login now