-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmy_shell.py
318 lines (269 loc) · 8.85 KB
/
my_shell.py
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
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
import subprocess
import os, sys
import grp
import pwd
import shutil
import signal
from datetime import datetime
class bcolors:
FAIL = '\033[91m'
ENDC = '\033[0m'
# Simple shell
# COMMANDS
# 1. info XX - Checks file/dir exists
# 2. files - Shows files in directory
# 3. delete XX - Checks directory/ file exists and delete it
# 4. copy XX YY - Copies XX in YY
# 5. where - Shows current directory
# 6. down DD - Checks directory exists and enters
# 7. up - Check you're not in the root and goes up in the directory tree
# 8. finish - terminate program
# 9. program name to run external program
# Type any linux command - It will work! :)
# column headers
header_filescmd = ["File Name", "Type"]
global dirpath
header_infocmd = ["File Name", "Type", "Owner User", "Owner Group", "Last modified time", "Size", "Executable" ]
width= [25, 11 , 20, 20, 26, 11, 11]
path = os.environ['PATH']
THE_PATH = path.split(':')
# ========================
# Run command
# Run an executable somewhere on the path
# Any number of arguments
# ========================
def runCmd(fields):
global PID, THE_PATH
cmd = fields[0]
cnt = 0
args = []
while cnt < len(fields):
args.append(fields[cnt])
cnt += 1
execname = add_path(cmd, THE_PATH)
# run the executable
if not execname:
print ('Executable file ' + str(cmd) +' not found')
else:
# execute the command
print(execname)
# execv executes a new program, replacing the current process; on success, it does not return.
# On Unix, the new executable is loaded into the current process, and will have the same process id as the caller.
try:
pid = os.fork()
if pid == 0:
os.execv(execname, args)
os.exit(0)
else:
# wait for the child process to exit
# the 'status' variable is updated with the exit status
# If we pass 0 to os.waitpid, the request is for the status of
# any child in the process group of the current process.
# If we pass -1, the request pertains to any child of the current process.
_, status = os.waitpid(0, 0)
# this function gets the exit code from the status
#if os.WIFSIGNALED(status):
#returnedsig = os.WTERMSIG(status)
#signal.signal(signal.SIGINT, sigint_handler)
exitCode = os.WEXITSTATUS(status)
if exitCode == 0:
print ("Complete with return code %d" % (exitCode))
except :
print ('Something went wrong there >_<')
os._exit(0)
# ========================
# Constructs the full path used to run the external command
# Checks to see if the file is executable
# ========================
def add_path(cmd, path):
if cmd[0] not in ['/', '.']:
for d in path:
execname = d + "/" +cmd
if os.path.isfile(execname) and os.access(execname, os.X_OK):
return execname
return False
else:
return cmd
# ========================
# FILES COMMAND
# List file and directory names
# No arguments
# ========================
def files_cmd(fields, filename):
global info
info = []
if checkArgs(fields, 0):
info.append(filename)
info.append(get_file_type(filename))
# ========================
# INFO COMMAND
# List file information
# 1 argument: file name
# ========================
def info_cmd(fields):
global info
info = []
if checkArgs(fields, 1):
argument = fields[1]
if os.access(argument, os.F_OK):
print_header("info")
info.append(argument)
info.append(get_file_type(argument))
stat_info = os.stat(argument)
uid = stat_info.st_uid
gid = stat_info.st_gid
user = pwd.getpwuid(uid)[0]
group = grp.getgrgid(gid)[0]
info.append(user)
info.append(group)
info.append(datetime.fromtimestamp(os.stat(argument).st_mtime).strftime('%b %d %Y %H:%M:%S'))
info.append(os.path.getsize(argument))
if os.access(argument, os.X_OK):
info.append("No")
else:
info.append("Yes")
else:
print("I'm sorry but the file/dir doesn't exists :(")
# ========================
# DELETE COMMAND
# Delete the file
# 1 argument: file name
# ========================
def delete_cmd(fields):
if checkArgs(fields, 1):
argument = fields[1]
if os.access(argument, os.F_OK):
try:
os.remove(argument)
print ("File deleted :)")
except OSError:
print("I'm sorry you cannot delete this file >_<")
else:
print("I'm sorry but the file/dir doesn't exists :(")
# ========================
# COPY COMMAND
# Copy the 'from' file to the 'to' file
# 2 arguments: 'from' file and 'to' file
# ========================
def copy_cmd(fields):
if checkArgs(fields, 2):
argument_1 = fields[1]
argument_2 = fields[2]
if os.access(argument_1, os.F_OK) and not os.access(argument_2, os.F_OK):
shutil.copyfile(argument_1, argument_2)
else:
print("I'm sorry but the source file doesn't exists or the destination file exists :(")
# ========================
# WHERE COMMAND
# Show the current directory
# No arguments
# ========================
def where_cmd(fields):
if checkArgs(fields, 0):
dirpath = os.getcwd()
print(dirpath)
# ========================
# DOWN COMMAND
# Change to the specified directory, inside the current directory
# 1 argument: directory name
# ========================
def down_cmd(fields):
if checkArgs(fields, 1):
argument = fields[1]
if os.access(argument, os.F_OK):
os.chdir(argument)
else:
print("I'm sorry but the directory doesn't exists :(")
# ========================
# UP COMMAND
# Change to the parent of the current directory
# No arguments
# ========================
def up_cmd(fields):
if checkArgs(fields, 0):
if os.path.realpath(dirpath) == os.path.realpath("/"):
print("Hey! You can't go up, you're in the root!")
else:
os.chdir("../")
# ========================
# FINISH COMMAND
# Exits the shell
# No arguments
# ========================
def finish_cmd(fields):
if checkArgs(fields, 0):
exit()
# ----------------------
# Other functions
# ----------------------
def checkArgs(fields, num):
numArgs = len(fields) - 1
if numArgs == num:
return True
if numArgs > num:
print (" Unexpected argument " + fields[num+1] + "for command " + fields[0])
else:
print (" Missing argument for command " + fields[0])
return False
def print_file_info():
fieldNum = 0
output = ''
while fieldNum < len(info):
output += '{field:{fill}<{width}}'.format(field=info[fieldNum], fill=' ', width=width[fieldNum])
fieldNum += 1
print (output)
# Print a header.
# Print the header entries, using the corresponding width entries.
def print_header(type_header):
field_num = 0
output = ''
if type_header == "files":
while field_num < 2:
output += '{field:{fill}<{width}}'.format(field=header_infocmd[field_num], fill=' ', width=width[field_num])
field_num += 1
print (output)
print ('-' * 36)
elif type_header == "info":
while field_num < len(header_infocmd):
output += '{field:{fill}<{width}}'.format(field=header_infocmd[field_num], fill=' ', width=width[field_num])
field_num += 1
print (output)
length = sum(width)
print ('-' * length)
def get_file_type(filename):
if os.path.isdir(filename):
return "Dir"
elif os.path.isfile(filename):
return "File"
elif os.path.islink(filename):
return "Link"
# ----------------------------------------------------------------------------------------------------------------------
while True:
dirpath = os.getcwd()
base = os.path.basename(dirpath)
line = input(bcolors.FAIL + base + " SantiagoShell>" +bcolors.ENDC)
fields = line.split()
# split the command into fields stored in the fields list
# fields[0] is the command name and anything that follows (if it follows) is an argument to the command
if fields[0] == "files":
print_header("files")
for filename in os.listdir('.'):
files_cmd(fields, filename)
print_file_info()
elif fields[0] == "info":
info_cmd(fields)
print_file_info()
elif fields[0] == "delete":
delete_cmd(fields)
elif fields[0] == "copy":
copy_cmd(fields)
elif fields[0] == "where":
where_cmd(fields)
elif fields[0] == "down":
down_cmd(fields)
elif fields[0] == "up":
up_cmd(fields)
elif fields[0] == "finish":
finish_cmd(fields)
else:
runCmd(fields)