-
Notifications
You must be signed in to change notification settings - Fork 3
/
nex-bashrc.sh
2284 lines (1982 loc) · 117 KB
/
nex-bashrc.sh
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
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# This code asside from external tools and programs are covered under:
# Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
# https://creativecommons.org/licenses/by-sa/3.0/
## Block viewing motd
if [[ ! -f ~/.hushlogin ]]; then touch ~/.hushlogin; fi
## Source global definitions and Nexcess functions
if [ -f /etc/bashrc ]; then . /etc/bashrc; fi
if [ -f /etc/nexcess/bash_functions.sh ]; then . /etc/nexcess/bash_functions.sh; fi
if [[ -n "$PS1" ]]; then ## --> interactive shell
## Auto switch to root
if [[ $UID != "0" ]]; then r; fi;
NORMAL=$(tput sgr0); ## COLORS!
BLACK=$(tput setaf 0); RED=$(tput setaf 1); GREEN=$(tput setaf 2); YELLOW=$(tput setaf 3);
BLUE=$(tput setaf 4); PURPLE=$(tput setaf 5); CYAN=$(tput setaf 6); WHITE=$(tput setaf 7);
BRIGHT=$(tput bold); BLINK=$(tput blink); REVERSE=$(tput smso); UNDERLINE=$(tput smul);
## Once you switch to root, Lookup currently installed version of Iworx, and look to see who else is on the server
if [[ $UID == "0" ]]; then
IworxVersion=$(echo -n $(grep -A1 'user="iworx"' /home/interworx/iworx.ini | cut -d\" -f2 | sed 's/^\(.\)/\U\1/'));
echo -e "\n$IworxVersion\nCurrent Users\n-------------\n$(w | grep -Ev '[0-9]days')\n";
fi;
fi
export PATH=$PATH:/usr/local/sbin:/sbin:/usr/sbin:/var/qmail/bin/:/usr/nexkit/bin
export GREP_OPTIONS='--color=auto'
export PAGER=/usr/bin/less
# formatted at 2000-03-14 03:14:15
export HISTTIMEFORMAT="%F %T "
export EDITOR=/usr/bin/nano
export VISUAL=/usr/bin/nano
# lulz
alias rtfm=man
# protect myself from myself
alias rm='rm --preserve-root'
alias chown='chown --preserve-root'
alias chmod='chmod --preserve-root'
alias chgrp='chgrp --preserve-root'
# With -F, on listings append the following
# '*' for executable regular files
# '/' for directories
# '@' for symbolic links
# '|' for FIFOs
# '=' for sockets
alias ls='ls -F --color=auto'
alias la='ls -F --color=auto -lah'
alias lr='ls -F --color=auto -larth'
# only append to bash history to prevent it from overwriting it when you have multiple ssh windows open
shopt -s histappend
# save all lines of a multiple-line command in the same history entry
shopt -s cmdhist
# correct minor errors in the spelling of a directory component
shopt -s cdspell
# check the window size after each command and, if necessary, updates the values of LINES and COLUMNS
shopt -s checkwinsize
# add extended globing to bash to do regex pattern matching in file globs
shopt -s extglob
# RESET
txtrst='\[\e[0m\]' # Text Reset
# NORMAL
txtblk='\[\e[0;30m\]'; txtred='\[\e[0;31m\]'; txtgrn='\[\e[0;32m\]'
txtylw='\[\e[0;33m\]'; txtblu='\[\e[0;34m\]'; txtpur='\[\e[0;35m\]'
txtcyn='\[\e[0;36m\]'; txtwht='\[\e[0;37m\]';
# BOLD
bldblk='\[\e[1;30m\]'; bldred='\[\e[1;31m\]'; bldgrn='\[\e[1;32m\]'
bldylw='\[\e[1;33m\]'; bldblu='\[\e[1;34m\]'; bldpur='\[\e[1;35m\]'
bldcyn='\[\e[1;36m\]'; bldwht='\[\e[1;37m\]'
# UNDERLINE
unkblk='\[\e[4;30m\]'; undred='\[\e[4;31m\]'; undgrn='\[\e[4;32m\]'
undylw='\[\e[4;33m\]'; undblu='\[\e[4;34m\]'; undpur='\[\e[4;35m\]'
undcyn='\[\e[4;36m\]'; undwht='\[\e[4;37m\]'
if [ $UID = 0 ]; then
# nexkit bash completion
if [ -e '/etc/bash_completion.d/nexkit' ]; then
source /etc/bash_completion.d/nexkit
fi
PS1="[${txtcyn}\$(date +%H:%M)${txtrst}][${bldred}\u${txtrst}@${txtylw}\h${txtrst} ${txtcyn}\W${txtrst}]\$ "
else
PS1="[${txtcyn}\$(date +%H:%M)${txtrst}][\u@\h \W]\$ "
fi
## My Aliases
alias vi='vim -n'
alias less='less -R'
alias h='echo; serverName; echo'
alias os='echo; cat /etc/redhat-release; echo'
alias getrsync='wget updates.nexcess.net/scripts/rsync.sh; chmod +x rsync.sh'
alias omg='curl -s http://nanobots.robotzombies.net/aboutbashrc | less'
alias wtf="grep -B1 '^[a-z].*(){' /home/${SUDO_USER}/.bashrc | sed 's/(){.*$//' | less"
alias credits='curl -s http://nanobots.robotzombies.net/credits | less'
alias quotas='checkquota'
# Iworx DB
i(){ $(grep -B1 'dsn.orig=' ~iworx/iworx.ini | head -1 | sed 's|.*://\(.*\):\(.*\)@.*\(/usr.*.sock\)..\(.*\)"|mysql -u \1 -p\2 -S \3 \4|') "$@"; }
# Vpopmail
v(){ $(grep -A1 '\[vpopmail\]' ~iworx/iworx.ini | tail -1 | sed 's|.*://\(.*\):\(.*\)@.*\(/usr.*.sock\)..\(.*\)"|mysql -u \1 -p\2 -S \3 \4|') "$@"; }
# ProFTPd
f(){ $(grep -A1 '\[proftpd\]' ~iworx/iworx.ini | tail -1 | sed 's|.*://\(.*\):\(.*\)@.*\(/usr.*.sock\)..\(.*\)"|mysql -u \1 -p\2 -S \3 \4|') "$@"; }
## Lookup mail account password (http://www.qmailwiki.org/Vpopmail#vuserinfo)
emailpass(){ echo -e "\nUsername: $1\nPassword: $(~vpopmail/bin/vuserinfo -C $1)\n"; }
## Set my account to use someone else's .bashrc
# sourceme(){ if [[ -z "$1" ]]; then echo; read -p "Username: " U; else U="$1"; fi; source /home/$U/.bashrc; }
## Send a bug report to my email regarding a function in my bashrc
bugreport(){
echo -e "\nPlease include information regarding what you were trying to do, any files
you were working with, the command you ran, and the error you received. I will
try and get back to you with either an explaination or a fix, as soon as I can.\n
Once you save and exit this file, this message will be sent and this file removed.\n"
read -p "Script is paused, press [Enter] to begin editing the message ..."
echo -e "Bug Report (.bashrc): <Put the subject here>\n\nSERVER: $(serverName)\nUSER: $SUDO_USER\nPWD: $PWD\n\n$(cat /etc/redhat-release)\n$IworxVersion\n\nFiles:\n\nCommands:\n\nErrors:\n\n" > ~/tmp.file
vim ~/tmp.file && cat ~/tmp.file | mail -s "$(head -1 ~/tmp.file)" "[email protected]" && rm ~/tmp.file
}
## Function to print a number of dashes to the screen
dash(){ for ((i=1;i<=$1;i++)); do printf "-"; done; }
## Get the username from the PWD
getusr(){ pwd | sed 's:^/chroot::' | cut -d/ -f3; }
## Print the hostname if it resolves, otherwise print the main IP
serverName(){
if [[ -n $(dig +time=1 +tries=1 +short $(hostname)) ]]; then hostname;
else ip addr show | awk '/inet / {print $2}' | cut -d/ -f1 | grep -Ev '^127\.' | head -1; fi
}
## Print out most often accessed Nodeworx links
lworx(){
echo; if [[ -z "$1" ]]; then (for x in siteworx reseller dns/zone ip;
do echo "$x : https://$(serverName):2443/nodeworx/$x"; done; echo "webmail : https://$(serverName):2443/webmail") | column -t
else echo -e "Siteworx:\nLoginURL: https://$(serverName):2443/siteworx/?domain=$1"; fi; echo
}
## Download and execute global-dns-checker script
dnscheck(){
wget -q -O ~/dns-check.sh nanobots.robotzombies.net/dns-check.sh;
chmod +x ~/dns-check.sh; ~/./dns-check.sh "$@"; }
## Calculate the free slots on a server depending on the server type
freeslots(){
wget -q -O ~/freeslots.sh nanobots.robotzombies.net/freeslots.sh;
chmod +x ~/freeslots.sh; ~/./freeslots.sh "$@"; }
## Add date and time with username and open server_notes.txt for editing
srvnotes(){
echo -e "\n#$(date) - $(echo $SUDO_USER | sed 's/nex//g')" >> /etc/nexcess/server_notes.txt;
nano /etc/nexcess/server_notes.txt; }
## Update IonCube for CentOS 5/6
ioncubeupdate(){
if [[ $1 =~ [0-9]\.[0-9] ]]; then ver="$1";
else read -p "What is the running PHP version: " ver; fi
# Create Download Directory
if [[ ! -d ~/downloads ]]; then mkdir ~/downloads;
else rm -r ~/downloads; mkdir ~/downloads; fi
# Download archive into directory and unpack
cd ~/downloads/
wget -O ioncube_loaders_lin_x86-64.tar.gz http://downloads3.ioncube.com/loader_downloads/ioncube_loaders_lin_x86-64.tar.gz
tar -zxf ioncube_loaders_lin_x86-64.tar.gz; echo
# check for known configuration combinations
if [[ -f /etc/php.d/ioncube.ini && -f /usr/lib64/php5/ioncube.so ]]; then # CentOS 5
phpdir="/usr/lib64/php5/"; config="/etc/php.d/ioncube.ini"
elif [[ -d /usr/lib64/php/modules/ ]]; then # CentOS 6
phpdir="/usr/lib64/php/modules/"; config="/etc/php.d/ioncube-loader.ini"
fi
# Copy the correct .so driver file to the target directory
if [[ -f ${phpdir}ioncube.so ]]; then
echo -e "\n${phpdir}ioncube.so driver file exist, backing up before continuing\n"
cp ~/downloads/ioncube/ioncube_loader_lin_${ver}* ${phpdir}
gzip ${phpdir}ioncube.so && mv ${phpdir}ioncube_loader_lin_${ver}.so ${phpdir}ioncube.so
elif [[ -f ${phpdir}ioncube_loader_lin_${ver}.so ]]; then
echo -e "\n${phpdir}ioncube_loader_lin_${ver}.so driver file exists, backing up before updating.\n"
gzip ${phpdir}ioncube_loader_lin_${ver}* && cp ~/downloads/ioncube/ioncube_loader_lin_${ver}* ${phpdir}
fi
# Create correct config file for the service if necessary
if [[ -f ${config} ]]; then
echo -e "${config} file already exists!\n";
else
echo -e "Setting up new /etc/php.d/ioncube-loader.ini file\n"
echo -e "zend_extension=${phpdir}ioncube_loader_lin_${ver}.so" >> /etc/php.d/ioncube-loader.ini;
fi
# Check configs and restart php/httpd services
if [[ -d /etc/php-fpm.d/ ]]; then
php -v && service php-fpm restart
else
php -v && httpd -t && service httpd restart;
fi
}
## Install ZendGuard for CentOS 5/6
zendguardinstall(){
if [[ $1 =~ [0-9]\.[0-9] ]]; then ver="$1";
else read -p "What is the running PHP version: " ver; fi
# Create Download Directory
if [[ ! -d ~/downloads ]]; then mkdir ~/downloads; fi
# Download archive into directory and unpack
cd ~/downloads/
wget http://downloads.zend.com/guard/5.5.0/ZendGuardLoader-php-${ver}-linux-glibc23-x86_64.tar.gz
tar -zxvf ZendGuardLoader-php-${ver}-linux-glibc23-x86_64.tar.gz
# Copy driver the correct .so file to the target directory
if [[ ! -f /usr/lib64/php/modules/ZendGuardLoader.so ]]; then
cp ~/downloads/ZendGuardLoader-php-${ver}-linux-glibc23-x86_64/php-${ver}.x/ZendGuardLoader.so /usr/lib64/php/modules/
else echo "ZendGuardLoader.so already exists! Backing up current version before continuing.";
gzip /usr/lib64/php/modules/ZendGuardLoader.so && cp ~/downloads/ZendGuardLoader-php-${ver}-linux-glibc23-x86_64/php-${ver}.x/ZendGuardLoader.so /usr/lib64/php/modules/
fi
# Create correct config file for the service
if [[ ! -f /etc/php.d/ZendGuard.ini && ! -f /etc/php.d/ioncube.ini && ! -f /etc/php.d/ioncube-loader.ini ]]; then file="/etc/php.d/ZendGuard.ini"
elif [[ -f /etc/php.d/ioncube-loader.ini ]]; then file="/etc/php.d/ioncube-loader.ini";
elif [[ -f /etc/php.d/ioncube.ini ]]; then file="/etc/php.d/ioncube.ini"
elif [[ -f /etc/php.d/ZendGuard.ini ]]; then echo "ZendGuard.ini file already exists!"; file="/dev/null"; fi
echo "Adding Zend Guard config to $file"
echo -e "\n; Enable Zend Guard extension\nzend_extension=/usr/lib64/php/modules/ZendGuardLoader.so\nzend_loader.enable=1\n" >> $file
# Check configs and restart php/httpd services
if [[ -d /etc/php-fpm.d/ ]]; then php -v && service php-fpm restart
else httpd -t && service httpd restart; fi
}
## Rewrite of Ted Wells sinfo
sinfo(){
echo; FMT='%-14s: %s\n'
printf "$FMT" "Hostname" "$(serverName)"
printf "$FMT" "OS (Kernel)" "$(cat /etc/redhat-release | awk '{print $1,$3}') ($(uname -r))"
ssl="$(openssl version | awk '{print $2}')"
web="$(curl -s -I $(serverName) | awk '/Server:/ {print $2}')";
if [[ -z $web ]]; then web="$(curl -s -I $(serverName):8080 | awk '/Server:/ {print $2}')"; fi
if [[ $web =~ Apache ]]; then webver=$(httpd -v | head -1 | awk '{print $3}' | sed 's:/: :');
elif [[ $web =~ LiteSpeed ]]; then webver=$(/usr/local/lsws/bin/lshttpd -v | sed 's:/: :');
elif [[ $web =~ nginx ]]; then webver=$(nginx -v 2>&1 | head -1 | awk '{print $3}' | sed 's:/: :'); fi
printf "$FMT" "Web Server" "$webver; OpenSSL ($ssl)"
if [[ -f /etc/init.d/varnish ]]; then printf "$FMT" "Varnish" "$(varnishd -V 2>&1 | awk -F- 'NR<2 {print $2}' | tr -d \))"; fi
_phpversion(){
phpv=$($1 -v | awk '/^PHP/ {print $2}');
zend=$($1 -v | awk '/Engine/ {print "; "$1,$2" ("$3")"}' | sed 's/v//;s/,//');
ionc=$($1 -v | awk '/ionCube/ {print "; "$3" ("$6")"}' | sed 's/v//;s/,//');
eacc=$($1 -v | awk '/eAcc/ {print "; "$2" ("$3")"}' | sed 's/v//;s/,//');
guard=$($1 -v | awk '/Guard/ {print "; "$2,$3" ("$5")"}' | sed 's/v//;s/,//');
suhos=$($1 -v | awk '/Suhosin/ {print "; "$2" ("$3")"}' | sed 's/v//;s/,//');
opche=$($1 -v | awk '/OPcache/ {print "; "$2,$3" ("$4")"}' | sed 's/v//;s/,//')
if [[ -d /etc/php-fpm.d/ ]]; then phpt='php-fpm'; else
phpt=$(awk '/^LoadModule/ {print $2}' /etc/httpd/conf.d/php.conf /etc/httpd/conf.d/suphp.conf | sed 's/php[0-9]_module/mod_php/;s/_module//'); fi;
printf "$FMT" "PHP Version" "${phpt} (${phpv})${zend}${ionc}${guard}${opche}${eacc}${suhos}";
}
_phpversion /usr/bin/php; if [[ -f /opt/nexcess/php54u/root/usr/bin/php ]]; then for x in /opt/nexcess/*/root/usr/bin/php; do _phpversion $x; done; fi
modsecv=$(rpm -qi mod_security | awk '/Version/ {print $3}' 2> /dev/null)
modsecr=$(awk -F\" '/SecComp.*\"$/ {print "("$2")"}' /etc/httpd/modsecurity.d/*_crs_10_*.conf 2> /dev/null)
printf "$FMT" "ModSecurity" "${modsecv:-No ModSecurity} ${modsecr}"
printf "$FMT" "MySQL Version" "$(mysql --version | awk '{print $5}' | tr -d ,) $(mysqld --version 2> /dev/null | grep -io 'percona' 2> /dev/null)"
pstgrs="/usr/*/bin/postgres"; if [[ -f $(echo $pstgrs) ]]; then printf "$FMT" "PostgreSQL" "$($pstgrs -V | awk '{print $NF}')"; fi
printf "$FMT" "Interworx" "$(grep -A1 'user="iworx"' /home/interworx/iworx.ini | tail -1 | cut -d\" -f2)"
if [[ $1 =~ -v ]]; then
printf "$FMT" "Rev. Control" "Git ($(git --version | awk '{print $3}')); SVN ($(svn --version | awk 'NR<2 {print $3}')); $(hg --version | awk 'NR<2 {print $1" ("$NF}')"
perlv=$(perl -v | awk '/v[0-9]/ {print "Perl ("$4")"}' | sed 's/v//')
pythv=$(python -V 2>&1 | awk '{print $1" ("$2")"}')
rubyv=$(ruby -v | awk '{print "Ruby ("$2")"}')
railv=$(if [[ ! $(which rails 2>&1) =~ /which ]]; then rails -v | awk '{print $1" ("$2")"}'; fi)
printf "$FMT" "Script Langs" "${perlv}; ${pythv}; ${rubyv}; ${railv:-No Rails}"
printf "$FMT" "FTP/sFTP/SSH" "ProFTPD ($(proftpd --version | awk '{print $3}')); OpenSSH ($(ssh -V 2>&1 | cut -d, -f1 | awk -F_ '{print $2}'))"; fi
printf "\n$FMT" "CPUs (Type)" "$(awk '/model name/{print $4,$5,$7,$9,$10}' /proc/cpuinfo | uniq -c | awk '{print $1,"- "$2,$3" - "$4,$5,$6}')"
printf "$FMT" "Memory (RAM)" "$(free -m | awk '/Mem/ {print ($2/1000)"G / "($4/1000)"G ("($4/$2*100)"% Free)"}')"
printf "$FMT" "Memory (Swap)" "$(if [[ $(free -m | awk '/Swap/ {print $2}') != 0 ]]; then free -m | awk '/Swap/ {print ($2/1000)"G / "($4/1000)"G ("($4/$2*100)"% Free)"}'; else echo 'No Swap'; fi)"
printf "$FMT" "HDD (/home)" "$(df -h /home | tail -1 | awk '{print $2" / "$4" ("($4/$2*100)"% Free)"}')"
echo
}
## Generate xkcd / iworx style passwords
xkcd(){
if [[ $@ =~ -h ]]; then echo -e "\n Usage: xkcd [-l <length>] [-v]\n"; return 0; fi
if [[ $@ =~ -v ]]; then wordList='/usr/share/dict/words'; else wordList='/usr/local/interworx/lib/dict/words'; fi
if [[ $1 =~ -l ]]; then wordLength=$(( (${2} - 4) / 4 )); else wordLength="4,8"; fi
if [[ -x /usr/bin/shuf ]]; then
echo $(shuf -n1000 $wordList | grep -E ^[a-z]{$wordLength}$ | shuf -n4 )$(( ($RANDOM % 9000) + 1000 ))\
| sed 's/\b\([a-zA-Z]\)/\u\1/g' | sed 's/ //g'
else
n=0; word=(); len=$(wc -l < $wordList)
while [[ $n -lt 4 ]]; do
rnd=$(( ( $(od -vAn -N4 -tu4 < /dev/urandom) )%($len)+1 ));
word[$n]=$(sed -n "${rnd}p" $wordList | egrep "^[a-z]{4,8}$" | sed 's:\b\(.\):\u\1:');
if [[ -n ${word[$n]} ]]; then n=$n+1; fi;
done;
echo "${word[0]}${word[1]}${word[2]}${word[3]}$(( $RANDOM % 9000 + 1000 ))";
unset n word len
fi
}
## Find files in a directory that were modified a certain number of days ago
recmod(){
if [[ -z "$@" || "$1" == "-h" || "$1" == "--help" ]]; then
echo -e "\n Usage: recmod [-p <path>] [days|{sequence}]\n Note: Paths with * in them need to be quoted\n"; return 0;
elif [[ "$1" == "-p" ]]; then
DIR="$2"; shift; shift; else DIR="."; fi;
for x in "$@"; do
echo "Files modified within $x day(s) or $((${x}*24)) hours ago";
find $DIR -type f -mtime $((${x}-1)) -exec ls -lath {} \; | grep -Ev '(var|log|cache|media|tmp|jpg|png|gif)' | column -t; echo;
done
}
## Archive a particular target, adding time and date information
archive(){
echo; if [[ -z "$@" ]]; then echo -e " Usage: archive <target>\n"; return 0; fi
FILE=$(getusr).$(hostname | cut -d. -f1)--$(echo "$1" | sed s/"\/"/"-"/g)-$(date +%Y.%m.%d-%H.%M).tgz;
SIZE=$(du -sb "$1" | cut -f1); SIZEM=$(echo "scale=3;$SIZE/1024/1024" | bc); echo "Compressing ${SIZEM}M ... please be patient."
if [[ -f /usr/bin/pv && -f /usr/bin/pigz ]]; then
tar -cf - "$1" | pv -s ${SIZE} | pigz -c > $FILE;
elif [[ -f /usr/bin/pv ]]; then
tar -cf - "$1" | pv -s ${SIZE} | gzip -c > $FILE;
else
echo "Sorry, no idea how long this will take ..."; tar -zcf $FILE "$1";
fi && echo -e "\nArchive created successfully!\n\n$PWD/\n$FILE\n";
if [[ -f $FILE ]]; then
read -p "Chown file to [r]oot or [u]ser? [r/u]: " yn;
if [[ $yn = "r" ]]; then
U='root';
else U=$(getusr); fi;
chown $U. $FILE && echo -e "Archive owned to $U\n"; fi
}
## Update ownership to the username for the PWD
fixowner(){
U=$(getusr)
if [[ -z $2 ]]; then P='.'; else P=$2; fi
case $1 in
-u|--user) owner="$U:$U" ;;
-a|--apache) owner="apache:$U" ;;
-r|--root) owner="root:root" ;;
*|-h|--help) echo -e "\n Usage: fixowner [option] [path]\n -u | --user ..... Change ownership to $U:$U\n -a | --apache ... Change ownership to apache:$U\n -r | --root ..... Change ownership to root:root\n -h | --help ..... Show this help output\n"; return 0 ;;
esac
chown -R $owner $P && echo -e "\n Files owned to $owner\n"
}
## Set default permissions for files and directories
fixperms(){
if [[ $1 == '-h' || $1 == '--help' ]]; then echo -e "\n Usage: fixperms [path]\n Set file permissions to 644 and folder permissions to 2755\n"; return 0; fi
if [[ -n $1 ]]; then SITEPATH="$1"; else SITEPATH="."; fi
if [[ $(grep -i ^loadmodule.*php[0-9]_module /etc/httpd/conf.d/php.conf) ]]; then perms="664"; else perms="644"; fi
printf "\nFixing File Permissions ($perms) ... "; find $SITEPATH -type f -exec chmod $perms {} \;
if [[ $(grep -i ^loadmodule.*php[0-9]_module /etc/httpd/conf.d/php.conf) ]]; then perms="2775"; else perms="2755"; fi
printf "Fixing Directory Permissions ($perms) ... "; find $SITEPATH -type d -exec chmod $perms {} \;
printf "Operation Completed.\n\n";
}
## Generate .ftpaccess file to create read only FTP user
# http://www.proftpd.org/docs/howto/Limit.html
ftpreadonly(){
echo; if [[ -z "$1" ]]; then read -p "FTP Username: " U; else U="$1"; fi
sudo -u $(getusr) echo -e "\n<Limit WRITE>\n DenyUser $U\n</Limit>\n" >> .ftpaccess &&
echo -e "\n.ftpaccess file has been updated.\n"
}
complete -W '-h --help -u --user -p --pass -l' htpasswdauth
## Generate or update .htpasswd file to add username
htpasswdauth(){
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
echo -e "\n Usage: htpasswdauth [-u|--user username] [-p|--pass password] [-l length]\n Ex: htpasswdauth -u username -p passwod\n Ex: htpasswdauth -u username -l 5\n Ex: htpasswdauth -u username\n"; return 0; fi
if [[ -z $1 ]]; then echo; read -p "Username: " U; elif [[ $1 == '-u' || $1 == '--user' ]]; then U="$2"; fi;
if [[ -z $3 ]]; then P=$(xkcd); elif [[ $3 == '-p' || $3 == '--pass' ]]; then P="$4"; elif [[ $3 == '-l' ]]; then P=$(xkcd -l $4); fi
if [[ -f .htpasswd ]]; then sudo -u $(getusr) htpasswd -mb .htpasswd $U $P; else sudo -u $(getusr) htpasswd -cmb .htpasswd $U $P; fi;
echo -e "\nUsername: $U\nPassword: $P\n";
}
## Create or add http-auth section for given .htaccess file
htaccessauth(){
sudo -u $(getusr) echo -e "\n# ----- Password Protection Section -----
\nAuthUserFile $(pwd)/.htpasswd
AuthGroupFile /dev/null
AuthName \"Authorized Access Only\"
AuthType Basic
\nRequire valid-user
\n# ----- Password Protection Section -----\n" >> .htaccess
}
## Manage .htaccess black-lists, white-lists, and bot-lists.
htlist(){
# Parse through options/parameters
if [[ $1 =~ -p ]]; then SITEPATH=$2; shift; shift; else SITEPATH='.'; fi; opt=$1
# Run correct for-loop given list type
case $opt in
-b | --black)
if ! grep -Eq '.rder .llow,.eny' $SITEPATH/.htaccess &> /dev/null; then
sudo -u $(getusr) echo -e "Order Allow,Deny\nAllow From All" >> $SITEPATH/.htaccess &&
echo "$SITEPATH/.htaccess rules updated";
fi
shift; echo; for x in "$@"; do
sed -i "s/\b\(.rder .llow,.eny\)/\1\nDeny From $x/" $SITEPATH/.htaccess &&
echo "Deny From $x ... Added to $SITEPATH/.htaccess"
done; echo
;;
-w | --white)
if ! grep -Eq '.rder .eny,.llow' $SITEPATH/.htaccess &> /dev/null; then
sudo -u $(getusr) echo -e "Order Deny,Allow\nDeny From All" >> $SITEPATH/.htaccess &&
echo "$SITEPATH/.htaccess rules updated";
fi
shift; echo; for x in "$@"; do
sed -i "s/\b\(.rder .eny,.llow\)/\1\nAllow From $x/" $SITEPATH/.htaccess &&
echo "Allow From $x ... Added to $SITEPATH/.htaccess"
done; echo
;;
-r | --robot)
if grep -Eq '.rder .llow,.eny' $SITEPATH/.htaccess &> /dev/null; then
sed -i 's/\b\(.rder .llow,.eny\)/\1\nDeny from env=bad_bot/' $SITEPATH/.htaccess
else sudo -u $(getusr) echo -e "\nOrder Allow,Deny\nDeny from env=bad_bot\nAllow from All" >> $SITEPATH/.htaccess && echo "$SITEPATH/.htaccess rules updated."; fi
shift; echo
echo -e "\n# ----- Block Bad Bots Section -----\n" >> $SITEPATH/.htaccess
for x in "$@"; do echo "BrowserMatchNoCase $x bad_bot" | tee -a $SITEPATH/.htaccess; done
echo -e "\n# ----- Block Bad Bots Section -----\n" >> $SITEPATH/.htaccess; echo
;;
-h|--help|*)
echo -e "\n Usage: htlist [options] <listType> <IP1> <IP2> ...\n
Options:
-p | --path .... Path to .htaccess file
-h | --help .... Print this help and quit
List Types:
-b | --black ... Blacklist IPs
-w | --white ... Whitelist IPs
-r | --robot ... Block UserAgent\n";
return 0;
;;
esac
}
## Generate nexinfo.php to view php info in browser
nexinfo(){
sudo -u "$(getusr)" echo '<?php phpinfo(); ?>' > nexinfo.php
echo -e "\nhttp://$(pwd | sed 's:^/chroot::' | cut -d/ -f4-)/nexinfo.php created successfully.\n" | sed 's/html\///';
}
## System resource usage by account
sysusage(){
echo; colsort="4"; printf "%-10s %10s %10s %10s %10s\n" "User" "Mem (MB)" "Process" "CPU(%)" "MEM(%)"; echo "$(dash 54)"
ps aux | grep -v ^USER | awk '{ mem[$1]+=$6; procs[$1]+=1; pcpu[$1]+=$3; pmem[$1]+=$4; } END { for (i in mem) { printf "%-10s %10.2f %10d %9.1f%% %9.1f%%\n", i, mem[i]/(1024), procs[i], pcpu[i], pmem[i] } }' | sort -nrk$colsort | head; echo
}
# Lookup Siteworx account details
acctdetail(){
nodeworx -u -n -c Siteworx -a querySiteworxAccountDetails --domain $(~iworx/bin/listaccounts.pex | awk "/$(getusr)/"'{print $2}')\
| sed 's:\([a-zA-Z]\) \([a-zA-Z]\):\1_\2:g;s:\b1\b:YES:g;s:\b0\b:NO:g' | column -t
}
## Add an IP to a Siteworx account
addip(){ nodeworx -u -n -c Siteworx -a addIp --domain $(~iworx/bin/listaccounts.pex | awk "/$(getusr)/"'{print $2}') --ipv4 $1; }
## Enable Siteworx backups for an account
addbackups(){ nodeworx -u -n -c Siteworx -a edit --domain $(~iworx/bin/listaccounts.pex | awk "/$(getusr)/"'{print $2}') --OPT_BACKUP 1; }
## Adjust user quota on the fly using Nodeworx CLI
bumpquota(){
if [[ -z $@ || $1 =~ -h ]]; then echo -e "\n Usage: bumpquota <username> <newquota>\n Note: <username> can be '.' to get user from PWD\n"; return 0;
elif [[ $1 =~ ^[a-z].*$ ]]; then U=$1; shift;
elif [[ $1 == '.' ]]; then U=$(getusr); shift; fi
newQuota=$1; primaryDomain=$(~iworx/bin/listaccounts.pex | grep $U | awk '{print $2}')
nodeworx -u -n -c Siteworx -a edit --domain $primaryDomain --OPT_STORAGE $newQuota &&
echo -e "\nDisk Quota for $U has been set to $newQuota MB\n"; checkquota -u $U
}
complete -W '-h --help -a --all -l --large -u --user' checkquota
## Check users quota usage
checkquota(){
_quotaheader(){ echo; printf "%8s %12s %14s %14s\n" "Username" "Used(%)" "Used(G)" "Total(G)"; dash 51; }
_quotausage(){ printf "\n%-10s" "$1"; quota -g $1 2> /dev/null | tail -1 | awk '{printf "%10.3f%% %10.3f GB %10.3f GB",($2/$3*100),($2/1000/1024),($3/1000/1024)}' 2> /dev/null; }
case $1 in
-h|--help ) echo -e "\n Usage: checkquota [--user <username>|--all|--large]\n -u|--user user1 [user2..] .. Show quota usage for a user or list of users \n -a|--all ................... List quota usage for all users\n -l|--large ................. List all users at or above 80% of quota\n";;
-a|--all ) _quotaheader; for x in $(laccounts); do _quotausage $x; done | sort; echo ;;
-l|--large ) _quotaheader; echo; for x in $(laccounts); do _quotausage $x; done | sort | grep -E '[8,9][0-9]\..*%|1[0-9]{2}\..*%'; echo ;;
-u|--user|* ) _quotaheader; shift; if [[ -z "$@" ]]; then _quotausage $(getusr); else for x in "$@"; do _quotausage $x; done; fi; echo; echo ;;
esac
}
## Show backupserver and disk usage for current home directory
backupsvr(){
checkquota;
NEW_IPADDR=$(awk -F/ '/server.allow/ {print $NF}' /usr/sbin/r1soft/log/cdp.log | tail -1 | tr -d \' | sed 's/10\.17\./178\.17\./g; s/10\.1\./103\.1\./g; s/10\.240\./192\.240\./g');
ALL_IPADDR=$(awk -F/ '/server.allow/ {print $NF}' /usr/sbin/r1soft/log/cdp.log | sort | uniq | tr -d \' | sed 's/10\.17\./178\.17\./g; s/10\.1\./103\.1\./g; s/10\.240\./192\.240\./g');
if [[ $NEW_IPADDR =~ ^172\. ]]; then INTERNAL=$(curl -s http://mdsc.info/r1bs-internal); fi
_printbackupsvr(){
if [[ $1 =~ ^172\. ]]; then
for x in $INTERNAL; do echo -n $x | awk -F_ "/$1/"'{printf "R1Soft IP..: https://"$3":8001\n" "R1Soft rDNS: https://"$2":8001\n"}'; done
else
IP=$1; RDNS=$(dig +short -x $1 2> /dev/null);
echo "R1Soft IP..: https://${IP}:8001";
if [[ -n $RDNS ]]; then echo "R1Soft rDNS: https://$(echo $RDNS | sed 's/\.$//'):8001"; fi;
fi
echo
}
FIRSTSEEN=$(grep $(echo $NEW_IPADDR | cut -d. -f2-) /usr/sbin/r1soft/log/cdp.log | head -1 | awk '{print $1}');
echo "----- Current R1Soft Server ----- $FIRSTSEEN] $(dash 32)"; _printbackupsvr $NEW_IPADDR
for IPADDR in $ALL_IPADDR; do
if [[ $IPADDR != $NEW_IPADDR ]]; then
LASTSEEN=$(grep $(echo $IPADDR | cut -d. -f2-) /usr/sbin/r1soft/log/cdp.log | tail -1 | awk '{print $1}');
echo "----- Previous R1Soft Server ----- $LASTSEEN] $(dash 31)"; _printbackupsvr $IPADDR
fi;
done
}
## Lookup the DNS Nameservers on the host
nameserver(){ echo; for x in $(grep ns[1-2] ~iworx/iworx.ini | cut -d\" -f2;); do echo "$x ($(dig +short $x))"; done; echo; }
## Quick summary of domain DNS info
ddns(){
if [[ -z "$@" ]]; then read -p "Domain Name: " D; else D="$@"; fi
for x in $(echo $D | sed 's/\// /g'); do echo -e "\nDNS Summary: $x\n$(dash 79)";
for y in a aaaa ns mx txt soa; do dig +time=2 +tries=2 +short $y $x +noshort;
if [[ $y == 'ns' ]]; then dig +time=2 +tries=2 +short $(dig +short ns $x) +noshort | grep -v root; fi; done;
dig +short -x $(dig +time=2 +tries=2 +short $x) +noshort; echo; done
}
## List server IPs, and all domains configured on them.
domainips(){
echo; for I in $(ip addr show | awk '/inet / {print $2}' | cut -d/ -f1 | grep -Ev '^127\.'); do
printf " ${BRIGHT}${YELLOW}%-15s${NORMAL} " "$I";
D=$(grep -l $I /etc/httpd/conf.d/vhost_[^000_]*.conf | cut -d_ -f2 | sed 's/.conf$//');
for x in $D; do printf "$x "; done; echo;
done; echo
}
## Find IPs in use by a Siteowrx account
accountips(){ domaincheck -a $1; }
## Find IPs in use by a Reseller account
resellerips(){ domaincheck -r $1; }
## Match secondary domains to IPs on the server using vhost files
domaincheck(){
vhost="$(echo /etc/httpd/conf.d/vhost_[^000]*.conf)"; sub='';
case $1 in
-a) if [[ -n $2 ]]; then sub=$2; else sub=''; fi
vhost="$(grep -l $(getusr) /etc/httpd/conf.d/vhost_[^000]*.conf)" ;;
-r) if [[ -z $2 ]]; then read -p "ResellerID: " r_id; else r_id=$2; fi;
vhost=$(for r_user in $(nodeworx -unc Siteworx -a listAccounts | awk "(\$5 ~ /^$r_id$/)"'{print $2}'); do grep -l $r_user /etc/httpd/conf.d/vhost_[^000]*.conf; done | sort | uniq) ;;
-v) FMT=" %-15s %-15s %3s %3s %3s %s\n"
HLT="${BRIGHT}${RED} %-15s %-15s %3s %3s %3s %s${NORMAL}\n"
#printf "$FMT" " Server IP" " Live IP" "SSL" "FPM" "TMP" " Domain"
#printf "$FMT" "$(dash 15)" "$(dash 15)" "---" "---" "---" "$(dash 44)"
;;
esac; echo
FMT=" %-15s %-15s %3s %3s %s\n"
HLT="${BRIGHT}${RED} %-15s %-15s %3s %3s %s${NORMAL}\n"
printf "$FMT" " Server IP" " Live IP" "SSL" "FPM" " Domain"
printf "$FMT" "$(dash 15)" "$(dash 15)" "---" "---" "$(dash 44)"
for x in $vhost; do
D=$(basename $x .conf | cut -d_ -f2);
V=$(awk '/.irtual.ost/ {print $2}' $x | head -1 | cut -d: -f1);
I=$(dig +short +time=1 +tries=1 ${sub}$D | grep -E '^[0-9]{1,3}\.' | head -1);
S=$(if grep :443 $x &> /dev/null; then echo SSL; fi);
F=$(if grep MAGE_RUN $x &> /dev/null; then echo FIX; fi);
if [[ "$I" != "$V" ]];
then printf "$HLT" "$V" "$I" "${S:- - }" "${F:- - }" "${sub}$D";
else printf "$FMT" "$V" "$I" "${S:- - }" "${F:- - }" "${sub}$D"; fi
done; echo
}
## Find IPs that are not configured in any vhost files
freeips(){
echo; for x in $(ip addr show | awk '/inet / {print $2}' | cut -d/ -f1 | grep -Ev '^127\.|^10\.|^172\.'); do
printf "\n%-15s " "$x"; grep -l $x /etc/httpd/conf.d/vhost_[^000_]*.conf 2> /dev/null;
done | grep -v \.conf$ | column -t; echo
}
## Check if gzip is working for domain(s)
chkgzip(){
echo; if [[ -z "$@" ]]; then read -p "Domain name(s): " DNAME; else DNAME="$@"; fi
for x in "$DNAME"; do curl -I -H 'Accept-Encoding: gzip,deflate' $x; done; echo
}
## Check Time To First Byte with curl
ttfb(){
if [[ -z "$1" || "$1" == "-h" || "$1" == "--help" ]]; then echo -e "\n Usage: ttfb [mag] <domain>\n"; return 0; fi;
_timetofirstbyte(){ curl -so /dev/null -w "HTTP: %{http_code} Connect: %{time_connect} TTFB: %{time_starttransfer} Total time: %{time_total} Redirect URL: %{redirect_url}\n" "$1"; }
if [[ "$1" == "m" || "$1" == "mag" ]]; then if [[ -z "$2" ]]; then read -p "Domain: " D; else D="$2"; fi;
for x in index.php robots.txt; do echo -e "\n$D/$x"; _timetofirstbyte "$D/$x"; done;
else D="$1"; echo; _timetofirstbyte "$D"; fi; echo
}
## CD to document root in vhost containing the given domain
cdomain(){
if [[ -z "$@" ]]; then echo -e "\n Usage: cdomain <domain.tld>\n"; return 0; fi
vhost=$(grep -l " $(echo $1 | sed 's/\(.*\)/\L\1/g')" /etc/httpd/conf.d/vhost_[^000]*.conf)
if [[ -n $vhost ]]; then cd $(awk '/DocumentRoot/ {print $2}' $vhost | head -1); pwd;
else echo -e "\nCould not find $1 in the vhost files!\n"; fi
}
## Attempt to list Secondary Domains on an account
ldomains(){
DIR=$PWD; cd /home/$(getusr); for x in */html; do echo $x | sed 's/\/html//g'; done; cd $DIR
}
## Edit a list of vhosts in a loop for adding temp fixes
tempfix(){
for x in $(echo "$@" | sed 's/\// /g'); do nano /etc/httpd/conf.d/vhost_$x.conf; done; httpd -t && service httpd reload
}
## List the usernames for all accounts on the server
laccounts(){ ~iworx/bin/listaccounts.pex | awk '{print $1}'; }
## List Sitworx accouts sorted by Reseller
lreseller(){
( nodeworx -u -n -c Siteworx -a listAccounts | sed 's/ /_/g' | awk '{print $5,$2,$10}';
nodeworx -u -n -c Reseller -a listResellers | sed 's/ /_/g' | awk '{print $1,"0.Reseller",$3}' )\
| sort -n | column -t | sed 's/\(.*0\.Re.*\)/\n\1/' | grep -Ev '^1 '; echo
}
## List the daily snapshots for a database to see the dates/times on the snapshots
lsnapshots(){
echo; if [[ -z "$1" ]]; then read -p "Database Name: " DBNAME; else DBNAME="$1"; fi
ls -lah /home/.snapshots/daily.*/localhost/mysql/$DBNAME.sql.gz; echo
}
## Backup, and restore a database from a snapshot file
restoredb(){
echo; if [[ -z "$1" ]]; then read -p "Backup filename: " DBFILE; else DBFILE="$1"; fi;
DBNAME=$(echo $DBFILE | cut -d. -f1);
echo "Creating current $DBNAME backup ..."; mdz $DBNAME;
echo "Dropping current $DBNAME ..."; m -e"drop database $DBNAME";
echo "Creating empty $DBNAME ..."; m -e"create database $DBNAME";
echo "Importing backup $DBFILE ...";
if [[ $DBFILE =~ \.gz$ ]]; then SIZE=$(gzip -l $DBFILE | awk 'END {print $2}');
elif [[ $DBFILE =~ \.zip$ ]]; then SIZE=$(unzip -l $DBFILE | awk '{print $1}'); fi
if [[ -f /usr/bin/pv ]]; then zcat -f $DBFILE | pv -s $SIZE | m $DBNAME;
else zcat -f $DBFILE | m $DBNAME; fi;
if [[ -d /home/mysql/$DBNAME/ ]]; then echo "Fixing Ownership on new DB ..."; chown -R mysql:$(echo $DBNAME | cut -d_ -f1) /home/mysql/$DBNAME/; fi
echo
}
## Kill SELECT or Sleep queries on a server, potentialy for just one username
killqueries(){
_querieslog(){ filename="mytop-dump--$(date +%Y.%m.%d-%H.%M).dump";
mytop -b --nocolor > ~/"$filename"; echo -e "\n~/$filename created ...\nBegin killing queries ..."; }
case $1 in
sel|select) _querieslog; x=$(awk '/SELECT/ {print $1}' ~/"$filename");
for i in $x; do echo "Killing: $i"; m -e"kill $i"; done; echo -e "Operation completed.\n" ;;
sle|sleep) _querieslog; x=$(awk '/Sleep/ {print $1}' ~/"$filename");
for i in $x; do echo "Killing $i"; m -e"kill $i"; done; echo -e "Operation completed.\n" ;;
-h|--help|*) echo -e "\n Usage: killqueries [sleep|select]\n" ;;
esac
}
## Create user functions for memcached socket configured in local.xml
memcachedalias(){
if [[ -z $1 || $1 == '-h' || $1 == '--help' ]]; then
echo -e "\n Usage: memcachealias [sitepath] [name]\n"
elif [[ -f $1/app/etc/local.xml ]]; then
if [[ -n $2 ]]; then NAME="_$2"; else NAME='_memcached'; fi
U=$(getusr);
CACHE_SOCKET=$(grep -Eo '\/var.*_cache\.sock' $1/app/etc/local.xml | head -1)
SESSIONS_SOCKET=$(grep -Eo '\/var.*_sessions\.sock' $1/app/etc/local.xml | head -1)
echo; for x in flush_all stats; do
if [[ -n $SESSIONS_SOCKET ]]; then
echo "Adding ${x}${NAME}_cache to /home/$U/.bashrc ... ";
sudo -u $U echo "${x}${NAME}_cache(){ echo $x \$@ | nc -U $CACHE_SOCKET; }" >> /home/$U/.bashrc;
echo "Adding ${x}${NAME}_sessions to /home/$U/.bashrc ... ";
sudo -u $U echo "${x}${NAME}_sessions(){ echo $x \$@ | nc -U $SESSIONS_SOCKET; }" >> /home/$U/.bashrc;
else
echo "Adding ${x}${NAME}_cache to /home/$U/.bashrc ... ";
sudo -u $U echo "${x}${NAME}_cache(){ echo $x \$@ | nc -U $CACHE_SOCKET; }" >> /home/$U/.bashrc; fi;
done; echo;
echo "Adding bash completion for stats function"
sudo -u $U echo -e "\ncomplete -W 'items slabs detail sizes reset' stats${NAME}_cache" >> /home/$U/.bashrc
sudo -u $U echo -e "\ncomplete -W 'items slabs detail sizes reset' stats${NAME}_sessions" >> /home/$U/.bashrc
echo "Adding $U to the (nc) group"; usermod -a -G nc $U; echo;
else echo "\n Could not find local.xml file in $1\n"; fi;
}
## Add PHP-FPM fix for pointer method Magento Multistores
fpmfix(){
if [[ -z $1 || $1 == '.' ]]; then D=$(pwd | sed 's:^/chroot::' | cut -d/ -f4);
else D=$(echo $1 | sed 's:/::g'); fi
vhost="/etc/httpd/conf.d/vhost_${D}.conf"
if [[ -f $vhost ]]; then
sed -i 's/\(RewriteCond.*\.fcgi\)/\1\n # ----- PHP-FPM-Multistore-Fix -----\n SetEnvIf REDIRECT_MAGE_RUN_CODE (\.\+) MAGE_RUN_CODE=\$1\n SetEnvIf REDIRECT_MAGE_RUN_TYPE (\.\+) MAGE_RUN_TYPE=\$1\n # ----- PHP-FPM-Multistore-Fix -----/g' $vhost
httpd -t && service httpd reload && echo -e "\nFPM fix has been applied to $(basename $vhost)\n"
else echo -e "\n$(basename $vhost) not found!\n";
fi
}
## Set common and custom php-fpm configuration options
fpmconfig(){
if [[ -f $(echo /opt/nexcess/php5*/root/etc/php-fpm.d/$(getusr).conf) ]]; then
config="/opt/nexcess/php5*/root/etc/php-fpm.d/$(getusr).conf";
srv="$(echo $config | cut -d/ -f4)-php-fpm";
elif [[ -f /etc/php-fpm.d/$(getusr).conf ]]; then
config="/etc/php-fpm.d/$(getusr).conf";
srv="php-fpm"; fi;
_fpmconfig(){
if [[ $(grep $1 $config 2> /dev/null) ]]; then
echo -e "\n$1 is already configured in the PHP-FPM pool $config\n";
awk "/$1/"'{print}' $config; echo
elif [[ -f $(echo $config) ]]; then
echo "php_admin_value[$1] = $2" >> $config && service $srv reload && echo -e "\n$1 has been set to $2 in the PHP-FPM pool for $config\n";
else
echo -e "\n Could not find $config !\n Try running this from the user's /home/dir/\n"; fi;
}
case $1 in
-a) _fpmconfig apc.enabled Off ;;
-b) _fpmconfig open_basedir "$(php -i | awk '/open_basedir/ {print $NF}'):$2" ;;
-c) _fpmconfig $2 $3 ;;
-d) _fpmconfig display_errors On ;;
-e) _fpmconfig max_execution_time $2 ;;
-f) _fpmconfig allow_url_fopen On ;;
-g|-z) _fpmconfig zlib.output_compression On ;;
-m) _fpmconfig memory_limit $2 ;;
-s) _fpmconfig session.cookie_lifetime $2; _fpmconfig session.gc_maxlifetime $2 ;;
-u) _fpmconfig upload_max_filesize $2; _fpmconfig post_max_size $2 ;;
-h) echo -e "\n Usage: fpmconfig [option] [value]
Options:
-a ... Disable APC
-b ... Set open_basedir
-c ... Set a custom [parameter] to [value]
-d ... Enable display_errors
-e ... Set max_execution_time to [value]
-f ... Enable allow_url_fopen
-g ... Enable gzip (zlib.output_compression)
-m ... Set memory_limit to [value]
-s ... Set session timeouts (session.gc_maxlifetime, session.cookie_lifetime)
-u ... Set upload_max_filesize and post_max_size to [value]
-z ... Enable gzip (zlib.output_compression)
-h ... Print this help output and quit
Default behavior is to print the contents and location of config file.\n"
;;
*) echo; ls $config; echo; cat $config; echo;;
esac;
unset srv config;
}
## Enable zlib.output_compression for a user's PHP-FPM config pool
fpmgzip(){ fpmconfig -g; }
## Enable allow_url_fopen for a users PHP-FPM config pool
fpmfopen(){ fpmconfig -f; }
## Setup parallel downloads in vhost
magparallel(){
if [[ -z $@ || $1 == '-h' || $1 == '--help' ]]; then echo -e '\n Usage: parallel <domain> \n'; return 0;
elif [[ -f /etc/httpd/conf.d/vhost_$1.conf ]]; then D=$1;
elif [[ $1 == '.' && -f /etc/httpd/conf.d/vhost_$(pwd | sed 's:^/chroot::' | cut -d/ -f4).conf ]]; then D=$(pwd | sed 's:^/chroot::' | cut -d/ -f4)
else echo -e '\nCould not find requested vhost file!\n'; return 1; fi
domain=$(echo $D | sed 's:\.:\\\\\\.:g'); # Covert domain into Regex
# Place comment followed by a blank line, logic for parallel downloads, then another comment preceded by a blank line
sed -i "s:\(.*RewriteCond %{HTTP_HOST}...$domain.\[NC\]\):\1\n \# ----- Magento-Parallel-Downloads -----\n:g" /etc/httpd/conf.d/vhost_$D.conf
for x in skin media js; do sed -i "s:\(.*RewriteCond %{HTTP_HOST}...$domain.\[NC\]\):\1\n RewriteCond %{HTTP_HOST} \!\^$x\\\.$domain [NC]:g" /etc/httpd/conf.d/vhost_$D.conf; done
sed -i "s:\(.*RewriteCond %{HTTP_HOST}...$domain.\[NC\]\):\1\n\n \# ----- Magento-Parallel-Downloads -----:g" /etc/httpd/conf.d/vhost_$D.conf
httpd -t && service httpd reload && echo -e "\nParallel Downloads configure for $D\n" # Test and restart Apache, print success message
}
## Download scheduler.php and then list out the Magento Cron jobs
magcrons(){
if [[ -z "$1" ]]; then SITEPATH="."; else SITEPATH="$1"; fi
BASEURL=$(nkmagento info $SITEPATH | awk '/^Base/ {print $4}')
sudo -u $(getusr) wget -q -O $SITEPATH/scheduler.php nanobots.robotzombies.net/scheduler
curl -s "$BASEURL/scheduler.php" | less; echo
read -p "Remove scheduler.php? [y/n]: " yn; if [[ $yn == "n" ]]; then echo "Link: $BASEURL/scheduler.php";
else rm $SITEPATH/scheduler.php; echo "scheduler.php has been removed."; fi; echo
}
## Create Magento Multi-Store Symlinks
magsymlinks(){
echo; U=$(getusr); if [[ -z $1 ]]; then read -p "Domain Name: " D; else D=$1; fi
for X in app includes js lib media skin var; do sudo -u $U ln -s /home/$U/$D/html/$X/ $X; done;
echo; read -p "Copy .htaccess and index.php? [y/n]: " yn; if [[ $yn == "y" ]]; then
for Y in index.php .htaccess; do sudo -u $U cp /home/$U/$D/html/$Y .; done; fi
}
## Look up large tables of a given database to see what's taking up space
tablesize(){
if [[ -z $1 || $1 == '-h' || $1 = '--help' ]]; then
echo -e "\n Usage: tablesize [dbname] [option] [linecount]\n\n Options:\n -r ... Sort by most Rows\n -d ... Sort by largest Data_Size\n -i ... Sort by largest Index_Size\n"; return 0; fi
if [[ $1 == '.' ]]; then dbname=$(finddb); shift;
elif [[ $1 =~ ^[a-z]{1,}_.*$ ]]; then dbname="$1"; shift;
else read -p "Database: " dbname; fi
case $1 in
-r ) col='4'; shift;;
-d ) col='6'; shift;;
-i ) col='8'; shift;;
* ) col='6';;
esac
if [[ $1 =~ [0-9]{1,} ]]; then top="$1"; else top="20" ; fi
echo -e "\nDatabase: $dbname\n$(dash 93)"; printf "| %-50s | %8s | %11s | %11s |\n" "Name" "Rows" "Data_Size" "Index_Size"; echo "$(dash 93)";
echo "show table status" | m $dbname | awk 'NR>1 {printf "| %-50s | %8s | %10.2fM | %10.2fM |\n",$1,$5,($7/1024000),($9/1024000)}' | sort -rnk$col | head -n$top
echo -e "$(dash 93)\n"
}
## Find Magento database connection info, and run common queries
magdb(){
echo; runonce=0;
if [[ $1 =~ ^-.*$ ]]; then SITEPATH='.'; opt="$1"; shift; param="$@";
else SITEPATH="$1"; opt="$2"; shift; shift; param="$@"; fi;
tables="core_cache core_cache_option core_cache_tag core_session dataflow_batch_import dataflow_batch_export\
index_process_event log_customer log_quote log_summary log_summary_type\
log_url log_url_info log_visitor log_visitor_info log_visitor_online\
report_viewed_product_index report_compared_product_index report_event catalog_compare_item"
prefix="$(echo 'cat /config/global/resources/db/table_prefix/text()' | xmllint --nocdata --shell $SITEPATH/app/etc/local.xml | sed '1d;$d')"
adminurl="$(echo 'cat /config/admin/routers/adminhtml/args/frontName/text()' | xmllint --nocdata --shell $SITEPATH/app/etc/local.xml | sed '1d;$d')"
# if [[ -f $SITEPATH/app/etc/local.xml ]]; then continue=1; else echo -e "\n ${RED}Could not find Magento configuration file!${NORMAL}\n"; return 0; fi
_magdbusage(){ echo " Usage: magdb [<path>] <option> [<query>]
-a | --amazon .... Show Amazon errors from the exception log
-A | --admin ..... Add a new admin user into the database ${CYAN}(New)${NORMAL}
-b | --base ...... Show all configured Base Urls
-B | --backup .... Backup the Magento database as the user
-c | --cron ...... Show Cron Jobs and Their Statuses
-d | --dataflow .. Show size of dataflow batch tables
-e | --execute ... Execute a custom query (use '*' and \\\")
-i | --info ...... Display user credentials for database
-l | --login ..... Log into database using user credentials
-L | --logsize ... Show size of the log tables
-m | --multi ..... Show Multistore Information (Urls/Codes)
-o | --logclean .. Clean out (truncate) log tables
-O | --optimize .. Truncate and optimize log tables
-p | --parallel .. Show all parallel download base_urls
-P | --password .. Update or reset password for user
-r | --rewrite ... Show the count of Url Rewrites
-s | --swap ...... Temporarily swap out admin password ${RED}${BRIGHT}(BETA!)${NORMAL}
-u | --users ..... Show all Admin Users' information
-v | --visit ..... Show count of Visitors in the Log
-x | --index ..... Show Current Status of all Re-Index Processes
-X | --reindex ... Execute a reindex as the user (indexer.php)
-z | --zend ...... Clear user's Zend cache files in /tmp/
-h | --help ...... Display this help output and quit"
return 0; }
_magdbinfo(){ if [[ -f $SITEPATH/app/etc/local.xml ]]; then #Magento
dbhost="$(echo 'cat /config/global/resources/default_setup/connection/host/text()' | xmllint --nocdata --shell $SITEPATH/app/etc/local.xml | sed '1d;$d')"
dbuser="$(echo 'cat /config/global/resources/default_setup/connection/username/text()' | xmllint --nocdata --shell $SITEPATH/app/etc/local.xml | sed '1d;$d')"
dbpass="$(echo 'cat /config/global/resources/default_setup/connection/password/text()' | xmllint --nocdata --shell $SITEPATH/app/etc/local.xml | sed '1d;$d')"
dbname="$(echo 'cat /config/global/resources/default_setup/connection/dbname/text()' | xmllint --nocdata --shell $SITEPATH/app/etc/local.xml | sed '1d;$d')"
ver=($(grep 'function getVersionInfo' -A8 $SITEPATH/app/Mage.php | grep major -A4 | cut -d\' -f4)); version="${ver[0]}.${ver[1]}.${ver[2]}.${ver[3]}"
if grep -E 'Enterprise Edition|Commercial Edition' $SITEPATH/app/Mage.php > /dev/null; then edition="Enterprise Edition"; else edition="Community Edition"; fi
else echo "${RED}Could not find configuration file!${NORMAL}"; return 1; fi; }
_magdbsum(){ echo -e "${BRIGHT}$edition: ${RED}$version ${NORMAL}\n${BRIGHT}Connection Summary: ${RED}$dbuser:$dbname$(if [[ -n $prefix ]]; then echo .$prefix; fi)${NORMAL}\n"; }
_magdbconnect(){ _magdbinfo && if [[ $runonce -eq 0 ]]; then _magdbsum; runonce=1; fi && mysql -u"$dbuser" -p"$dbpass" -h $dbhost $dbname "$@"; }
_magdbbackup(){ _magdbinfo;
if [[ -x /usr/bin/pigz ]]; then COMPRESS="/usr/bin/pigz"; echo "Compressing with pigz";
else COMPRESS="/usr/bin/gzip"; echo "Compressing with gzip"; fi
echo "Using: mysqldump --opt --skip-lock-tables -u'$dbuser' -p'$dbpass' -h $dbhost $dbname";
if [[ -f /usr/bin/pv ]]; then sudo -u $(getusr) mysqldump --opt --skip-lock-tables -u"$dbuser" -p"$dbpass" -h $dbhost $dbname \
| pv -N 'MySQL-Dump' | $COMPRESS --fast | pv -N 'Compression' > ${dbname}-$(date +%Y.%m.%d-%H.%M).sql.gz;
else sudo -u $(getusr) mysqldump --opt --skip-lock-tables -u"$dbuser" -p"$dbpass" -h $dbhost $dbname \
| $COMPRESS --fast > ${dbname}-$(date +%Y.%m.%d-%H.%M).sql.gz; fi; }
case $opt in
-a|--amazon) _magdbconnect -e "SELECT * FROM ${prefix}amazon_log_exception ORDER BY log_id DESC LIMIT 1;";;
-A|--admin) read -p "Firstname: " firstname; read -p "Lastname: " lastname; read -p "Email: " emailaddr; read -p "Username: " username; password=$(xkcd);
_magdbconnect -e "INSERT INTO ${prefix}admin_user SELECT NULL \`user_id\`, \"$firstname\" \`firstname\`, \"$lastname\" \`lastname\`, \"$emailaddr\" \`email\`, \"$username\" \`username\`, MD5(\"$password\") \`password\`, NOW() \`created\`, NULL \`modified\`, NULL \`logdate\`, 0 \`lognum\`, 0 \`reload_acl_flag\`, 1 \`is_active\`, NULL \`extra\`, NULL \`rp_token\`, NOW() \`rp_token_created_at\`";
_magdbconnect -e "INSERT INTO ${prefix}admin_role SELECT NULL \`role_id\`, (SELECT \`role_id\` FROM ${prefix}admin_role WHERE \`role_name\` = 'Administrators') \`parent_id\`, 2 \`tree_level\`, 0 \`sort_order\`, 'U' \`role_type\`, (SELECT \`user_id\` FROM ${prefix}admin_user WHERE \`username\` = \"$username\") \`user_id\`, 'admin' \`role_name\`;";
echo -e "Username: $username\nPassword: $password" ;;
-b|--base) _magdbconnect -e "SELECT * FROM ${prefix}core_config_data WHERE path RLIKE \"base_url\";";;
-B|--backup) _magdbbackup ;;
-c|--cron) runonce=1; if [[ -z $param ]]; then
_magdbconnect -e "SELECT * FROM ${prefix}cron_schedule;"
elif [[ $param =~ ^clear$ ]]; then
_magdbconnect -e "DELETE FROM ${prefix}cron_schedule WHERE status RLIKE \"success|missed\";"
echo "Cron_Schedule table has been cleared of old crons"
elif [[ $param =~ ^clear.*-f$ ]]; then
_magdbconnect -e "TRUNCATE ${prefix}cron_schedule;"
echo "Cron_Schedule table has been truncated"
elif [[ $param == '-h' || $param == '--help' ]]; then
echo -e " Usage: magdb [<path>] <-c|--cron> [clear] [-f]\n clear : Remove completed or missed cron jobs\n clear -f : Truncate the cron_schedule table"
fi ;;
-e|--execute) _magdbconnect -e "${param};" ;;
-i|--info) _magdbinfo; echo "Database Connection Info:";
echo -e "\nLoc.Conn: mysql -u'$dbuser' -p'$dbpass' $dbname -h $dbhost \nRem.Conn: mysql -u'$dbuser' -p'$dbpass' $dbname -h $(hostname)\n";
echo -e "Username: $dbuser \nPassword: $dbpass \nDatabase: $dbname $(if [[ -n $prefix ]]; then echo \\nPrefix..: $prefix; fi) \nLoc.Host: $dbhost \nRem.Host: $(hostname)";;
-l|--login) _magdbconnect;;
-L|--logsize|-d|--dataflow|-v|--visit|-r|--rewrite) _magdbinfo; _magdbsum; datatotal=0; indextotal=0; rowtotal=0; freetotal=0;
if [[ $opt == '-d' || $opt == '--dataflow' ]]; then tables="dataflow_batch_import dataflow_batch_export";
elif [[ $opt == '-v' || $opt == '--visit' ]]; then tables="log_visitor log_visitor_info log_visitor_online";
elif [[ $opt == '-r' || $opt == '--rewrite' ]]; then tables="core_url_rewrite"; fi
div='+------------------------------------------+-----------------+----------------+----------------+'
LOGFMT="| %-40s | %15s | %12s M | %12s M |\n"
echo $div; printf "$LOGFMT" "Table Name" "Row Count" "Data Size" "Index Size"; echo $div
for x in $tables; do
datasize=$(_magdbconnect -e "SELECT data_length/1024000 FROM information_schema.TABLES WHERE table_name = \"${prefix}$x\";" | tail -1)
datatotal=$(echo "scale=3;$datatotal + $datasize" | bc)
indexsize=$(_magdbconnect -e "SELECT index_length/1024000 FROM information_schema.TABLES WHERE table_name = \"${prefix}$x\";" | tail -1)
indextotal=$(echo "scale=3;$indextotal+$indexsize" | bc)
rowcount=$(_magdbconnect -e "SELECT table_rows FROM information_schema.TABLES WHERE table_name = \"${prefix}$x\";" | tail -1)
rowtotal=$(($rowcount+$rowtotal))
printf "$LOGFMT" "$x" "$rowcount" "$datasize" "$indexsize"
done
echo $div; printf "$LOGFMT" "Totals" "$rowtotal" "$datatotal" "$indextotal"; echo $div ;;
-m|--multi) _magdbconnect -e "SELECT * FROM ${prefix}core_config_data WHERE path RLIKE \"base_url\"; SELECT * FROM ${prefix}core_website; SELECT * FROM ${prefix}core_store";;
-o|--logclean|-O|--optimize)
if [[ -z $param ]]; then tablename='-h'; else tablename="$param"; fi; runonce=1;
if [[ $tablename != *-h* ]]; then touch $SITEPATH/maintenance.flag && echo -e "Maintenance Flag set while cleaning tables\n"; fi
case $tablename in
all) if [[ $opt == '-o' || $opt == '--logclean' ]];
then for x in $tables; do echo "Truncating ${prefix}$x"; _magdbconnect -e "TRUNCATE ${prefix}$x;" >> /dev/null; done;
else for x in $tables; do echo; echo "Truncating/Optimizing ${prefix}$x"; _magdbconnect -e "TRUNCATE ${prefix}$x; OPTIMIZE TABLE ${prefix}$x;" >> /dev/null; done; fi ;;
-h|--help) echo -e " Usage: magdb $SITEPATH $opt [<option>]\n <option> can be a table_name, 'list of tables', or 'all'\n\n Individual Table Names\n $(dash 78)";
(for x in $tables; do echo " $x"; done) | column -x;;
*) if [[ $opt == '-o' || $opt == '--logclean' ]];
then for x in $tablename; do echo "Truncating ${prefix}$x"; _magdbconnect -e "TRUNCATE ${prefix}$x;" >> /dev/null; done;
else for x in $tablename; do echo; echo "Truncating/Optimizing ${prefix}$x"; _magdbconnect -e "TRUNCATE ${prefix}$x; OPTIMIZE TABLE ${prefix}$x;" >> /dev/null; done; fi ;;
esac
if [[ -f $SITEPATH/maintenance.flag ]]; then rm $SITEPATH/maintenance.flag && echo -e "\nTable cleaning complete, maintenance.flag removed"; fi ;;
-p|--parallel) _magdbconnect -e "SELECT * FROM ${prefix}core_config_data WHERE path RLIKE \"base.*url\";";;
-P|--password) runonce=1;
if [[ -n $param ]]; then
username=$(echo $param | awk '{print $1}'); password=$(echo $param | awk '{print $2}');
_magdbconnect -e "UPDATE ${prefix}admin_user SET password = MD5(\"$password\") WHERE ${prefix}admin_user.username = \"$username\";"
echo -e "New Magento Login Credentials:\nUsername: $username\nPassword: $password"
elif [[ -z $param || $param == '-h' || $param == '--help' ]]; then
echo -e " Usage: magdb [<path>] <-P|--password> <username> <password>"
fi ;;
-s|--swap )
username=$(_magdbconnect -e "SELECT username FROM ${prefix}admin_user WHERE is_active = 1 LIMIT 1;" | tail -1)
password=$(_magdbconnect -e "SELECT password FROM ${prefix}admin_user WHERE is_active = 1 LIMIT 1;" | tail -1 | sed 's/\$/\\\$/g')
_magdbconnect -e "UPDATE ${prefix}admin_user SET password=MD5('nexpassword') WHERE is_active = 1 LIMIT 1";
echo -e "You have 20 seconds to login using the following credentials\n"
echo -n "LoginURL: "; _magdbconnect -e "SELECT value FROM ${prefix}core_config_data WHERE path LIKE \"web/unsecure/base_url\" LIMIT 1;" | tail -1 | sed "s/\/$/\/$adminurl/"
echo -e "Username: $username\nPassword: nexpassword\n"
for x in {1..20}; do sleep 1; printf ". "; done; echo
_magdbconnect -e "UPDATE ${prefix}admin_user SET password=\"$password\" WHERE is_active = 1 LIMIT 1";
echo -e "\nPassword has been reverted." ;;
-u|--user|--users)
if [[ -z $param ]]; then _magdbconnect -e "select * from ${prefix}admin_user\G" | grep -v 'extra:';
elif [[ $param =~ -s ]]; then _magdbconnect -e "select username,CONCAT( firstname,\" \",lastname ) AS \"Full Name\",email,password from ${prefix}admin_user";
elif [[ $param == '-h' || $param == '--help' ]]; then echo -e " Usage: magdb [path] <-u|--user> [-s|--short]"; fi
;;
-x|--index) _magdbconnect -e "SELECT * FROM ${prefix}index_process";;
-X|--reindex) if [[ -z $param ]]; then index='help' ; else index="$param"; fi
_magdbinfo; _magdbsum; DIR=$PWD; cd $SITEPATH; sudo -u $(getusr) php -f shell/indexer.php -- $index; cd $DIR;;
-z|--zend)
if [[ -z $param ]]; then
echo "There are $(find /tmp/ -type f -name zend* -user $(getusr) -print | wc -l) Zend cache files for $(getusr) in /tmp/";
elif [[ $param =~ ^clear$ ]]; then
echo "Clearing Zend cache files for $(getusr) in /tmp/";
for x in $(find /tmp/ -type f -name zend* -user $(getusr) -print); do echo -n $x; rm $x && echo "... Removed"; done;
else
echo "$param is not a valid parameter for this option."
fi ;;
-h|--help|*) _magdbusage;;
esac; echo; dbhost=''; dbuser=''; dbpass=''; dbname=''; prefix='';
version=''; edition=''; adminurl=''; username=''; password='';
}
## Find Wordpress database configuration and run common queries
wpdb(){
echo; runonce=0;
if [[ $1 =~ ^-.*$ ]]; then SITEPATH='.'; opt="$1"; shift; param="$@";