summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimotej Lazar <timotej.lazar@fri.uni-lj.si>2019-03-02 13:25:35 +0100
committerTimotej Lazar <timotej.lazar@fri.uni-lj.si>2019-03-02 13:25:35 +0100
commit5c1efef4551e48edaee6b0ae2da00a9f85fd3ae4 (patch)
treed00927a4e5877f323ff09e787c145b27fea7ab5e
parent7efdc4d945855b6fe17efa16c4cbac9a94a4108e (diff)
Add task compile-run
Edit a file, compile it, write a script to run it and store stdout and stderr.
-rw-r--r--tasks/compile-run/task.py252
1 files changed, 252 insertions, 0 deletions
diff --git a/tasks/compile-run/task.py b/tasks/compile-run/task.py
new file mode 100644
index 0000000..0f8edee
--- /dev/null
+++ b/tasks/compile-run/task.py
@@ -0,0 +1,252 @@
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+# TODO:
+# - check if everything is filled in (computers, params, preparation)
+# - improve scoring
+# - test
+# - switch to a real SSH/SFTP client to properly handle filenames
+
+instructions = {
+ 'si': '''\
+<p>
+Postavite dva navidezna računalnika - <em>arbiter</em> in <em>student</em>. Drugi mrežni vmesnik na <em>arbiterju</em> in edini vmesnik na <em>studentu</em> naj bosta povezana v isto lokalno omrežje.
+
+<p>
+Na računalnik <em>student</em> se prijavite z uporabniškim imenom <code>student</code> in geslom <code>vaje</code>.
+
+<p>
+Obstoječi datoteko <code>{{P_c}}</code> v programskem jeziku C prevedite v program z imenom <code>{{P_executable}}</code>. Izvorna koda je namenoma pokvarjena tako, da so vanjo vrinjeni nepotrebni znaki. Pred prevajanjem jo morate popraviti.
+
+<p>
+Napišite skripto <code>{{P_script}}</code>, ki požene <code>{{P_executable}}</code> z argumentom
+
+<pre><code>"{{arg_c}}"</code></pre>
+
+<p>
+ in
+
+<ul>
+<li>mu na standardni vhod zapiše vrednost okoljske spremenljivke <code>{{env_c}}</code>;
+<li>v datoteko <code>{{out_stderr_c}}</code> zapiše napake (<em>stderr</em>); in
+<li>v datoteko <code>{{out_stdout_c}}</code> zapiše tiste vrstice na standardnem izhodu (<em>stdout</em>), ki vsebujejo niz <code>XYZZY</code>.
+</ul>
+
+<p>
+Poskrbite, da se bo dalo skripto pognati neposredno, torej z ukazom <code>./{{P_script}}</code>. Vse datoteke naj so v domačem imeniku uporabnika <code>student</code>, ki naj bo tudi njihov lastnik.
+''',
+ 'en': '''\
+<p>
+Set up two virtual machines - <em>arbiter</em> and <em>student</em>. Connect <em>arbiter’s</em> second network interface and <em>student’s</em> first interface to the same local network.
+
+<p>Log in to <em>student</em> as the user <code>student</code> with password <code>vaje</code>.
+
+<p>Compile the existing C file <code>{{P_c}}</code> into a program named <code>{{P_executable}}</code>. The source code was intentionally corrupted by inserting extraneous characters. Before compiling you have to fix it.
+
+<p>
+Write a script called <code>{{P_script}}</code> that runs <code>{{P_executable}}</code> with the argument
+
+<pre><code>"{{arg_c}}"</code></pre>
+
+and
+
+<ul>
+<li>pipes the value of the environment variable <code>{{env_c}}</code> into <code>{{P_executable}}</code>’s standard input;
+<li>redirects its <code>stderr</code> into a file called <code>{{out_stderr_c}}</code>; and
+<li>saves each line from the standard output that contains the string <code>XYZZY</code> into <code>{{out_stdout_c}}</code>.
+</ul>
+
+<p>
+Ensure that the script can be run directly, ie. <code>./{{P_script}}</code>. All files should be owned by <code>student</code> and placed in that user’s home directory.
+''',
+}
+
+computers = {
+ 'arbiter': {
+ 'disks': [{'name': 'dhcp-gw'}],
+ 'flavor': 'm1.tiny',
+ 'network_interfaces': [{'network': 'test-net'}, {'network': 'net1'}],
+ 'config_drive': True,
+ 'userdata': {'string': "#!/bin/bash\nsed -i '/cloud/d' /etc/fstab\npoweroff &\n"}
+ },
+ 'student': {
+ 'disks': [{ 'name': 'console-big'}],
+ 'flavor': 'm1.tiny',
+ 'network_interfaces': [{'network': 'net1'}],
+ 'config_drive': True,
+ 'userdata': {'string': "#!/bin/bash\nsed -i '/cloud/d' /etc/fstab\npoweroff &\n"}
+ }
+}
+
+networks = { 'test-net': {'public': True}, 'net1': {'public': False} }
+
+params_meta = {
+ 'student_IP': {
+ 'descriptions': { 'si': 'IP naslov računalnika student', 'en': 'IP address of student',
+ }, 'w': True, 'public': True, 'type': 'IP', 'generated': False,
+ },
+ 'P_c': {
+ 'descriptions': { 'si': 'Datoteka s programom v C', 'en': 'Filename of the program in C',
+ }, 'w': False, 'public': True, 'type': 'filename', 'generated': True,
+ },
+ 'P_executable': { 'descriptions': { 'si': 'Ime prevedenega programa v C', 'en': 'Filename of the compiled C program'
+ }, 'w': False, 'public': True, 'type': 'filename', 'generated': True,
+ },
+ 'arg_c': {
+ 'descriptions': { 'si': 'Vrednost argumenta', 'en': 'Argument value',
+ }, 'w': False, 'public': True, 'type': 'short_text', 'generated': True,
+ },
+ 'env_c': {
+ 'descriptions': { 'si': 'Ime okoljske spremenljivke', 'en': 'The name of the environment environment',
+ }, 'w': False, 'public': True, 'type': 'short_text', 'generated': True,
+ },
+ 'out_stderr_c': {
+ 'descriptions': { 'si': 'Datoteka z napakami', 'en': 'File to store errors',
+ }, 'w': False, 'public': True, 'type': 'filename', 'generated': True,
+ },
+ 'P_script': {
+ 'descriptions': { 'si': 'Ime skripte', 'en': 'Filename of the script',
+ }, 'w': False, 'public': True, 'type': 'filename', 'generated': True,
+ },
+ 'out_stdout_c': {
+ 'descriptions': { 'si': 'Datoteka z izhodom', 'en': 'File to store the output',
+ }, 'w': False, 'public': True, 'type': 'filename', 'generated': True,
+ },
+ 'param_gen_seed': {
+ 'descriptions': { 'si': 'Nakljucno seme', 'en': 'Random seed',
+ }, 'w': False, 'public': True, 'type': None, 'generated': True,
+ },
+ 'c_destroy_gen_seed': {
+ 'descriptions': { 'si': 'Nakljucno seme za kvarjenje kode v C', 'en': 'Random seed for destroying the C code',
+ }, 'w': False, 'public': False, 'type': None, 'generated': True,
+ }
+
+}
+
+def task(student_IP,
+ P_c, P_executable, arg_c, env_c, out_stderr_c, out_stdout_c, P_script,
+ param_gen_seed):
+ import random
+
+ r = random.Random(int(param_gen_seed))
+ env_val = "".join([r.choice('ABCDEFGHJKLMNPRSTUVZ012345') for i in range(11)])
+ arg_val = "".join([r.choice('ABCDEFGHJKLMNPRSTUVZ012345') for i in range(13)])
+ stdin_val = "".join([r.choice('ABCDEFGHJKLMNPRSTUVZ012345') for i in range(17)])
+
+ return kpov_util.ssh_test(student_IP, 'student', 'vaje', (
+ ('script_ls', 'ls -l ./{}'.format(P_script)),
+ ('executable_ls', 'ls -l ./{}'.format(P_executable)),
+ ('script_run', 'export {}={}; ./{}'.format(env_c, env_val, P_script)),
+ ('script_stderr', 'cat {}'.format(out_stderr_c)),
+ ('script_stdout', 'cat {}'.format(out_stdout_c)),
+ ('prog_stdout', 'echo "{}" | ./{} "{}" 2> /dev/null'.format(stdin_val, P_executable, arg_val)),
+ ('prog_stderr', 'echo "{}" | ./{} "{}" > /dev/null'.format(stdin_val, P_executable, arg_val)),
+ ))
+
+def gen_params(user_id, params_meta):
+ import random
+ r = random.Random(user_id+'evil cornholio')
+ params = kpov_util.default_gen(user_id, params_meta)
+ params['env_c'] = "".join([r.choice('ABCDEFGHIJKLMNPRSTUVZ') for i in range(5)])
+ params['P_c'] = "".join([r.choice('abcdefghijklmnoprst') for i in range(5)]) + ".c"
+ params['param_gen_seed'] = str(r.randint(0, 2**24))
+ params['c_destroy_gen_seed'] = str(r.randint(0, 2**24))
+ return params
+
+def task_check(results, params):
+ def test_out_gen(arg, env):
+ s_out = ""
+ s_err = ""
+ for i in range(30):
+ s = '{}{}\n'.format(
+ ('XYZZY' if i%5 == 0 else ''),
+ (env if i%2 == 0 else arg))
+ if i%3 == 0:
+ s_err += s
+ else:
+ s_out += s
+ return (s_out.strip(), s_err.strip(), len(env))
+
+ score = 0
+ hints = []
+ if results['ssh'] is not True:
+ hints += ['ssh failed: ' + results['ssh']]
+ return score, hints
+
+ r = random.Random(int(params['param_gen_seed']))
+ env_val = "".join([r.choice('ABCDEFGHJKLMNPRSTUVZ012345') for i in range(11)])
+ arg_val = "".join([r.choice('ABCDEFGHJKLMNPRSTUVZ012345') for i in range(13)])
+ stdin_val = "".join([r.choice('ABCDEFGHJKLMNPRSTUVZ012345') for i in range(17)])
+ expected_script_stdout, expected_script_stderr, rval = test_out_gen(
+ params['arg_c'], env_val)
+ if expected_script_stderr != results['script_stderr']:
+ hints += ['wrong script stderr']
+ else:
+ score += 2
+ split_stdout = expected_script_stdout.split('\n')
+ expected_script_stdout = '\n'.join([ i for i in split_stdout if i.find('XYZZY') >= 0])
+ if expected_script_stdout != results['script_stdout']:
+ hints += ['wrong script stdout']
+ else:
+ score += 2
+
+ expected_prog_stdout, expected_prog_stderr, rval = test_out_gen(arg_val, stdin_val)
+ if expected_prog_stderr != results['prog_stderr']:
+ hints += ['wrong program stderr']
+ else:
+ score += 2
+ if expected_prog_stdout != results['prog_stdout']:
+ hints += ['wrong program stdout']
+ else:
+ score += 2
+ if results['script_ls'].find('-r') < 0:
+ hints += ['script not found']
+ else:
+ score += 1
+ if results['executable_ls'].find('xr') < 0:
+ hints += ['C executable not found']
+ else:
+ score += 1
+ return score, hints
+
+def prepare_disks(templates, task_params, global_params):
+ c_source = '''#include<stdio.h>
+#include<stdlib.h>
+#include<string.h>
+
+/* Odstranite vse crke Q, W, R in program se bo prevedel. */
+/* Remove all letters Q, W, R and the program will compile. */
+
+int main(int argc, char **argv){
+ unsigned char *arg = argv[1];
+ unsigned char env[255];
+ scanf("%s", env);
+ size_t env_len = strlen(env);
+
+ for (int i = 0; i < 30; i++) {
+ fprintf(i%3 == 0 ? stderr : stdout, "%s%s\\n",
+ i%5 == 0 ? "XYZZY" : "",
+ i%2 == 0 ? env : arg);
+ }
+ return env_len;
+}
+'''
+
+ import random
+ d = templates['console-big']
+ r = random.Random(task_params['c_destroy_gen_seed'])
+ destroyed_c_source = c_source[:110]
+ for c in c_source[110:]:
+ i = r.randint(0, 5)
+ if i == 1:
+ destroyed_c_source += 'QW'
+ if i == 2:
+ destroyed_c_source += 'RW'
+ if i == 3:
+ destroyed_c_source += 'QR'
+ destroyed_c_source += c
+
+ path_c = '/home/student/{}'.format(task_params['P_c'])
+ d.write(path_c, destroyed_c_source)
+ d.chown(1000, 1000, path_c)
+
+ write_default_config(templates['dhcp-gw'], global_params)