-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlostshell.tcl
executable file
·350 lines (281 loc) · 9.72 KB
/
lostshell.tcl
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
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
#!/usr/bin/env tclsh
#//////////////////////////
#echo export PATH=\${PATH}:/home/user/Programare/Tcl/ >> ~/.bashrc
#chmod +x lostshell.tcl
#//////////////////////////
#:Author: Clinciu Andrei
#:Email: <[email protected]>
# == List Shell
package require nx
if {0} {
#read config file and write it with each change
bookmarks {
bookmark location
bookmark2 location2
}
commands {
name { what to run }
name2 { what to run 2 }
}
}
::nx::Slot method type=choice {name value arg} {
if {$value ni [split $arg |]} {
error "Value '$value' of parameter $name not in permissible values $arg"
}
}
nx::Class create LostShell {
:public method main {argv argc} {
#view if object method exists.. if not default, if yes run with functions..
#TODO use foreach..?
set firstWord [lindex $argv 0]
set secondToLastWord [lrange $argv 1 end]
if {[:info lookup method $firstWord] != "" } {
:$firstWord {*}$secondToLastWord
} else { puts "Sorry, the command $firstWord doesn't exist.. try using \"help\"" }
}
:public method bookmark {args} {
puts "bookmark-ing.. [pwd]"
}
:public method go {args} {
puts "Go-ing to bookmark $args"
cd $args
}
:public method deleteBookmark {args} {
puts "Deleting bookmark $args"
}
#.An Example Sidebar
#************************************************
#Any AsciiDoc SectionBody element (apart from
#SidebarBlocks) can be placed inside a sidebar.
#************************************************
:public method registerCommand {args} {
puts "Registering command $args"
}
:public method runCommand {args} {
puts "running command $args"
exec sudo /opt/ns/bin/nsd -c -u www-data -t /opt/ns/conf/ubp-config.tcl > stdin
}
# === makeDoc creating documentation
#
:public method makeDoc {{-tcl 1} file} {
puts "Making documentation $file [info script]"
puts [array get env ]
if {$tcl} {
exec >&@stdout source-doc-beautifier.tcl $file
exec >&@stdout asciidoc -f [file dir [info script]]/asciidoc.conf -b html5 -a tabsize=4 -a icons -a toc2 [regsub {\.tcl} $file .txt]
} else {
#don't forget to do apt-get install source-highlight
exec >&@stdout asciidoc -b html5 -a tabsize=4 -a icons -a toc2 [regsub {\.tcl} $file .txt]
}
# exec asciidoc [regsub {.tcl} $args .txt]
}
:public method makePdf {{-tcl 1} file} {
puts "Making documentation $file [info script]"
puts [array get env ]
if {$tcl} {
exec >&@stdout source-doc-beautifier.tcl $file
exec >&@stdout a2x -fpdf -dbook --no-xmllint --dblatex-opts "-P latex.output.revhistory=0" [regsub {\.tcl} $file .txt]
} else {
#don't forget to do apt-get install source-highlight
exec >&@stdout a2x -fpdf -dbook --no-xmllint --dblatex-opts "-P latex.output.revhistory=0" [regsub {\.tcl} $file .txt]
}
}
#TODO CPU watcher
# If cpu is 100% for longer than 60 seconds for a certain PID, kill it
# this means that the cpu is 100% at each interval
#ps aux --sort -%cpu | head -10
:public method cpuWatcher {{-count:integer 10} {-interval:integer 5} {-maxCpu 100} {-maxTime 60} } {
}
:public method startMemoryWatcher {{-count:integer 10} {-interval:integer 5} {-maxMemory 1GB} } {
puts -nonewline "([:getTimestamp]): MemoryWatcher (by LostOne) is running"
puts " in the background checking processes higher than $maxMemory \n every $interval seconds"
set :runs 0
:memoryWatcher -count $count -interval $interval -maxMemory $maxMemory
vwait forever
}
#Memory watcher
#TODO watch and kill only if it's in list watchProcesses
#{watchProcesses:optional}
:public method memoryWatcher {{-count:integer 10} {-interval:integer 5} {-maxMemory 1GB} } {
#{USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND}
#RSS (real memory size or resident set size in 1024 byte units)
set psData [exec ps aux --sort -rss | head -$count]
set processesData [lrange [split $psData \n] 1 end]
set permittedMaxMemory [:toBytes $maxMemory]
:showFreeMemoryAtIntervals
foreach process $processesData {
set pid [lindex $process 1]
set memory [expr {[lindex $process 5]*1024}]
set command [lindex $process 10]
if {[expr {$permittedMaxMemory*0.85}] < $memory} {
puts "([:getTimestamp]): $command [:humanBytes $memory] is nearing the 85% level of Max Memory allowed $maxMemory"
}
if {$permittedMaxMemory < $memory} {
puts "([:getTimestamp]): KILLING PID $pid $command uses [:humanBytes $memory] memory and currently exceeds the maximum memory ($maxMemory) "
#TODO permit app 15 seconds to redress itself before killing
exec kill -9 $pid
}
}
after [expr {int($interval*1000)}] [list lostshell memoryWatcher -count $count \
-interval $interval -maxMemory $maxMemory ]
#needed If using from commandline
}
:public method showFreeMemoryAtIntervals {} {
incr :runs
if {[expr {${:runs}%10}] == 0} {
set data [exec free -b]
set data [split $data \n]
lassign [lindex $data 2] a b used free
puts "([:getTimestamp]): Used memory: [:humanBytes $used] \t Free memory: [:humanBytes $free]"
}
}
#COnvertion to human readable number
:public method humanBytes {{-precision 1} number} {
set byteList [list 1 kB 2 MB 3 GB 4 TB]
set lastPower 0; set lastHumanReadable B
foreach {power humanReadable} $byteList {
if {![expr {int($number)/1024**$power}]} {
set human [format %.${precision}f%s [expr {$number/1024.**$lastPower}] $lastHumanReadable]
return $human
}
set lastPower $power
set lastHumanReadable $humanReadable
}
}
#Conversion from human readable to pc readable (bytes)
:public method toBytes {args} {
set byteList [list 1 kB 2 MB 3 GB 4 TB]
regexp {(\d+\.?\d*)\s*([a-zA-Z]{0,2})} $args -> digits extension
set listIndex [lsearch -nocase $byteList $extension]
set power [lindex $byteList $listIndex-1]
set bytes [expr {$digits*1024**$power}]
return $bytes
}
:public method getTimestampTz {{unixtime ""}} {
if {$unixtime == ""} { set unixtime [clock seconds] }
return [clock format $unixtime -format "%Y-%m-%d %H:%M:%S%z"]
}
:public method getTimestamp {{unixtime ""}} {
if {$unixtime == ""} { set unixtime [clock seconds] }
return [clock format $unixtime -format "%Y-%m-%d %H:%M:%S"]
}
:public method terminal:password:get {promptString} {
# Turn off echoing, but leave newlines on. That looks better.
# Note that the terminal is left in cooked mode, so people can still use backspace
exec stty -echo echonl <@stdin
# Print the prompt
puts stdout $promptString
flush stdout
# Read that password! :^)
gets stdin password
# Reset the terminal
exec stty echo -echonl <@stdin
return $password
}
:public method terminal:confirmPassword {promptString} {
set password "pass" ; set confirmPassword "pass2"
while {$password != $confirmPassword} {
set password [:terminal:password:get $promptString ]
set confirmPassword [:terminal:password:get "Confirm password"]
}
return $password
}
#DEFAULT is to return Y/N
#If you change options to other letters/numbers remember to catch the output
# Y/N are boolean values so you can treat them as such
:method terminal:confirm:continue {{-default y} {-options {y "confirm" n "cancel" } } message} {
set default [string toupper $default]
if {[info exists :acceptAllDefault]} {
if {${:acceptAllDefault}} {
return $default
}
}
set defaultmsg ""
foreach {nr optionText} $options {
append defaultmsg "\n\t${nr}. $optionText "
if {$default == [string toupper $nr]} { append defaultmsg (default) }
}
set confirm [:terminal:confirm:outputMsg $message $defaultmsg]
foreach {nr optionText} $options {
if {$confirm == [string toupper $nr]} {
return $confirm
}
}
return $default
}
:method terminal:confirm:outputMsg {message defaultmsg} {
foreground yellow
puts -nonewline stdout $message
flush stdout
foreground green
puts -nonewline stdout $defaultmsg
foreground white
puts -nonewline stdout "\nEnter your choice: "
flush stdout
gets stdin confirm
set confirm [string toupper $confirm]
return $confirm
}
:method terminal:confirm {message} {
foreground green
puts -nonewline stdout $defaultmsg
flush stdout
gets stdin confirm
return $confirm
}
:public method commandlineprogress {{-total 50} {-char "#"} {-iteration 10} } {
puts -nonewline stdout {[}
for {set var 0} {$var < $total} {incr var} {
puts -nonewline stdout $char
flush stdout
after $iteration
}
puts "\] \n Complete!"
}
:public method getUserAndPassword {} {
puts "Please enter your username"
gets stdin username
set password [:terminal:password:get "How about you give us your password?"]
puts "Registering $username with pw $password"
}
}
# Bash Color (Linux Only)
# Utility interfaces to the low-level command
proc capability cap {expr {![catch {exec tput -S << $cap}]}}
proc colorterm {} {expr {[capability setaf] && [capability setab]}}
proc tput args {exec tput -S << $args >/dev/tty}
array set color {black 0 red 1 green 2 yellow 3 blue 4 magenta 5 cyan 6 white 7 }
proc foreground x {exec tput -S << "setaf $::color($x)" > /dev/tty}
proc background x {exec tput -S << "setab $::color($x)" > /dev/tty}
proc reset {} {exec tput sgr0 > /dev/tty}
array set bashcolor {
bold \033\[1m
dim \033\[2m
underline \033\[4m
blink \033\[5m
inverted \033\[7m
hidden \033\[8m
reset \033\[0m
black \033\[30m
red \033\[31m
green \033\[32m
yellow \033\[33m
blue \033\[34m
magenta \033\[35m
cyan \033\[36m
lightgray \033\[37m
darkgray \033\[90m
lightred \033\[91m
lightgreen \033\[92m
lightyellow \033\[93m
lightblue \033\[94m
lightmagenta \033\[95m
lightcyan \033\[96m
white \033\[97m
}
if {[info exists argv0]} {
if { [info script] eq $::argv0 } {
LostShell create lostshell
lostshell main $argv $argc
}
}