-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathrun-nasm
executable file
·195 lines (164 loc) · 6.58 KB
/
run-nasm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
#!/usr/bin/env python
# pylint: disable=C0103
"""
run-nasm is a CLI utility to assembly code with help of nasm (32-bit)
and run executables in isolated Docker environment
2015, Vlad Slepukhin
"""
import argparse
import logging
import sys
import getpass
import grp
import os
import shutil
import subprocess
import platform
import tempfile
## logging
logger_format = '[%(levelname)s] %(message)s'
logger = logging.getLogger()
logger.setLevel(logging.INFO)
logging.basicConfig(stream=sys.stdout,
format=logger_format,
datefmt='%Y-%m-%d %H:%M:%S')
## Args parsing
parser = argparse.ArgumentParser(description='''This command copies
files you passed, creates makefile,
assembles it and runs in docker.
Default assembly command is:
nasm -f elf -l file.lst file.asm &&
gcc -m32 -o file file.o ''',
epilog='''Created by Vlad Slepukhin, 2015\n
https://github.com/ka2m/ssu-open-nasm32'''
)
parser.add_argument('files', type=str,
help='files to assembly',
nargs='*',
metavar='file.nasm')
parser.add_argument('-p', '--pargs', type=str,
help='args to pass to compiled exeuctable',
action='append')
parser.add_argument('-v', '--verbose',
help='verbose ouput',
action='store_true')
parser.add_argument('-S', '--save',
help='save compiled executable to current directory',
action='store_true')
parser.add_argument('-s', '--sudo',
help='run docker with sudo (default is true)',
action='store_true')
parser.add_argument('-l', '--ld',
help='create executable with ld, do NOT link with gcc',
action='store_true')
parser.add_argument('-m', '--makefile',
help='path to custom makefile (incompatible with -l)')
parser.add_argument('-M', '--make',
help='custom make command (must be quoted with "), '\
'(incompatible with -l)',
metavar='"make this"')
args = parser.parse_args()
## Checking arguments
if args.verbose:
logger.info('Setting logging to DEBUG mode')
logger.setLevel(logging.DEBUG)
logger.debug('Now we are in verbose mode')
logger.info('Checking arguments')
logger.debug('SUDO: %s', args.sudo)
logger.debug('SAVE: %s', args.save)
logger.debug('LD: %s', args.ld)
logger.debug('Program ARGS: %s',
'none' if args.pargs is None else ' '.join(args.pargs))
logger.debug('Makefile: %s',
'auto' if args.makefile is None else args.makefile)
logger.debug('Sources: %s', ', '.join(args.files))
logger.debug('Check permissions to run docker (Linux-only)')
if not args.sudo and platform.system() == 'Linux':
user = getpass.getuser()
logger.debug('User: %s', user)
try:
members = grp.getgrnam('docker').gr_mem
if user not in members and user != 'root':
logger.critical('Your user %s not in docker group. ' \
'You cannot execute docker commands', user)
sys.exit(-3)
except KeyError:
logger.warning('Docker group not found. Cannot check docker '\
'execution avialiability')
if args.ld and args.make is not None:
logger.critical('--ld (-l) and --make (-M) cannot be used at one time')
sys.exit(-5)
if args.ld and args.makefile is not None:
logger.critical('--ld (-l) and --makefile (-m) cannot be used at one time')
sys.exit(-1)
if args.makefile and not os.path.isfile(args.makefile):
logger.critical('Custom makefile passed, but this file does not exists')
sys.exit(-2)
if args.make and (args.make[0] != '"' or args.make[-1] != '"'):
logger.critical('Make command passed, but not quoted with "')
sys.exit(-6)
if not args.makefile:
args.makefile = os.path.join(os.path.abspath(os.path.dirname(__file__)),
'Makefile')
logger.debug('Check passed files')
check_files = [os.path.isfile(x) for x in args.files]
if False in check_files:
logger.critical('File(s) not found: %s',
' '.join([x for x in args.files
if not check_files[args.files.index(x)]]))
sys.exit(-3)
check_files = [x.endswith('.asm') for x in args.files]
if False in check_files:
logger.critical('File(s) not ending with ".asm": %s',
' '.join([x for x in args.files
if not check_files[args.files.index(x)]]))
sys.exit(-4)
logger.info('Copying sources and Makefile to temporary directories')
## Sources and Makefile are being copied to platform default temporary dir...
temp_dir = tempfile.gettempdir()
if len(args.files) > 1:
logger.warning('Compiling separate programs for each source'\
' as no custom Makefile passed, but multiple'\
' sources did')
logger.warning('Selecting last passed file as main executable')
wd = tempfile.mkdtemp(prefix='.nasm32-', dir=tempfile.gettempdir())
for wf in args.files:
shutil.copy(wf, wd)
logger.debug('COPY: %s -> %s', wf, wd)
shutil.copy(args.makefile, wd)
## Running docker
# add sudo if required
use_sudo = 'sudo ' if args.sudo else ''
# add arguments to executable if any
pargs = ' '.join(args.pargs) if args.pargs else ''
if args.pargs:
pargs = ' ' + pargs
# linking mode
lm = ''
if not args.make:
lm = 'ld' if args.ld else 'gcc'
# select main file as resulting executable
_, src = os.path.split(args.files[-1])
src = src.split('.asm')[0]
# actual command
cmd = str('%sdocker run -it -v %s:/tmp '\
'-w /tmp vladfau/nasm32 /bin/sh -c'
% (use_sudo, wd)).split(' ')
make = args.make[1:-1] if args.make else 'make src=%s mode=%s' % (src, lm)
cmd.append('""%s; echo \'Running program:\'; ./%s%s""' %
(make, src, pargs))
try:
logger.info('Running Docker')
logger.debug('CMD: %s', ' '.join(cmd))
_ = subprocess.Popen(cmd).communicate()[0]
# this except is intended to catch ctrl-c signal during docker execution
except KeyboardInterrupt:
pass
finally:
if args.save:
logger.info('Saving resulting file to: %s',
os.path.abspath(os.path.dirname(src)))
shutil.copy(os.path.join(wd, src),
os.path.abspath(os.path.dirname(src)))
logger.info('Cleaning up')
shutil.rmtree(wd)