Linux server.kiran-academy.com 3.10.0-1160.108.1.el7.x86_64 #1 SMP Thu Jan 25 16:17:31 UTC 2024 x86_64
Apache/2.4.57 (Unix) OpenSSL/1.0.2k-fips
: 194.233.91.196 | : 216.73.216.172
Cant Read [ /etc/named.conf ]
7.4.32
finalho
www.github.com/MadExploits
Terminal
AUTO ROOT
Adminer
Backdoor Destroyer
Linux Exploit
Lock Shell
Lock File
Create User
CREATE RDP
PHP Mailer
BACKCONNECT
UNLOCK SHELL
HASH IDENTIFIER
CPANEL RESET
CREATE WP USER
README
+ Create Folder
+ Create File
/
usr /
bin /
[ HOME SHELL ]
Name
Size
Permission
Action
7z
40
B
-rwxr-xr-x
7za
41
B
-rwxr-xr-x
GET
14.71
KB
-rwxr-xr-x
HEAD
14.71
KB
-rwxr-xr-x
Magick-config
1.23
KB
-rwxr-xr-x
MagickCore-config
1.24
KB
-rwxr-xr-x
MagickWand-config
1.25
KB
-rwxr-xr-x
Mail
383.67
KB
-rwxr-xr-x
POST
14.71
KB
-rwxr-xr-x
Wand-config
1.23
KB
-rwxr-xr-x
[
40.52
KB
-rwxr-xr-x
a2p
105.32
KB
-rwxr-xr-x
aclocal
35.87
KB
-rwxr-xr-x
aclocal-1.13
35.87
KB
-rwxr-xr-x
addr2line
28.42
KB
-rwxr-xr-x
agentxtrap
19.16
KB
-rwxr-xr-x
alias
29
B
-rwxr-xr-x
altermime
108.35
KB
-rwxr-xr-x
amavisd-agent
13.12
KB
-rwxr-xr-x
amavisd-nanny
11.72
KB
-rwxr-xr-x
amavisd-release
12.35
KB
-rwxr-xr-x
amavisd-signer
36.85
KB
-rwxr-xr-x
amavisd-submit
9.09
KB
-rwxr-xr-x
animate
7.04
KB
-rwxr-xr-x
apr-1-config
6.76
KB
-rwxr-xr-x
apropos
45.49
KB
-rwxr-xr-x
apu-1-config
5.97
KB
-rwxr-xr-x
ar
61.22
KB
-rwxr-xr-x
arch
32.3
KB
-rwxr-xr-x
aria_chk
4.56
MB
-rwxr-xr-x
aria_dump_log
4.36
MB
-rwxr-xr-x
aria_ftdump
4.37
MB
-rwxr-xr-x
aria_pack
4.4
MB
-rwxr-xr-x
aria_read_log
4.52
MB
-rwxr-xr-x
arj
199.56
KB
-rwxr-xr-x
arjdisp
12.55
KB
-rwxr-xr-x
arpaname
7.03
KB
-rwxr-xr-x
as
377.36
KB
-rwxr-xr-x
aserver
28.21
KB
-rwxr-xr-x
aspell
163.35
KB
-rwxr-xr-x
at
51.73
KB
-rwsr-xr-x
atq
51.73
KB
-rwsr-xr-x
atrm
51.73
KB
-rwsr-xr-x
audit2allow
14.21
KB
-rwxr-xr-x
audit2why
14.21
KB
-rwxr-xr-x
aulast
15.48
KB
-rwxr-xr-x
aulastlog
11.35
KB
-rwxr-xr-x
ausyscall
11.18
KB
-rwxr-xr-x
autoconf
14.42
KB
-rwxr-xr-x
autoheader
8.33
KB
-rwxr-xr-x
autom4te
31.43
KB
-rwxr-xr-x
automake
246.44
KB
-rwxr-xr-x
automake-1.13
246.44
KB
-rwxr-xr-x
autoreconf
20.57
KB
-rwxr-xr-x
autoscan
16.72
KB
-rwxr-xr-x
autoupdate
33.08
KB
-rwxr-xr-x
auvirt
31.93
KB
-rwxr-xr-x
awk
418.54
KB
-rwxr-xr-x
base64
36.48
KB
-rwxr-xr-x
basename
28.35
KB
-rwxr-xr-x
bash
941.93
KB
-rwxr-xr-x
bashbug
6.8
KB
-rwxr-xr-x
bashbug-64
6.8
KB
-rwxr-xr-x
batch
137
B
-rwxr-xr-x
bc
81.47
KB
-rwxr-xr-x
bdftopcf
44.19
KB
-rwxr-xr-x
bdftruncate
11.2
KB
-rwxr-xr-x
bg
26
B
-rwxr-xr-x
bison
393.34
KB
-rwxr-xr-x
bond2team
22.74
KB
-rwxr-xr-x
bootctl
68.99
KB
-rwxr-xr-x
bunzip2
31.89
KB
-rwxr-xr-x
busctl
403.2
KB
-rwxr-xr-x
bzcat
31.89
KB
-rwxr-xr-x
bzcmp
2.08
KB
-rwxr-xr-x
bzdiff
2.08
KB
-rwxr-xr-x
bzgrep
1.64
KB
-rwxr-xr-x
bzip2
31.89
KB
-rwxr-xr-x
bzip2recover
15.24
KB
-rwxr-xr-x
bzless
1.23
KB
-rwxr-xr-x
bzmore
1.23
KB
-rwxr-xr-x
c++
754.59
KB
-rwxr-xr-x
c++filt
27.92
KB
-rwxr-xr-x
c2ph
35.75
KB
-rwxr-xr-x
c89
224
B
-rwxr-xr-x
c99
215
B
-rwxr-xr-x
ca-legacy
1.6
KB
-rwxr-xr-x
cabextract
68.7
KB
-rwxr-xr-x
cairo-sphinx
69.99
KB
-rwxr-xr-x
cal
36.8
KB
-rwxr-xr-x
captoinfo
64.26
KB
-rwxr-xr-x
cat
52.81
KB
-rwxr-xr-x
catchsegv
3.26
KB
-rwxr-xr-x
catman
36.75
KB
-rwxr-xr-x
cc
750.59
KB
-rwxr-xr-x
ccmake
3.95
MB
-rwxr-xr-x
ccmake3
5.83
MB
-rwxr-xr-x
cd
26
B
-rwxr-xr-x
centrino-decode
6.13
KB
-rwxr-xr-x
certutil
179.75
KB
-rwxr-xr-x
certwatch
15.38
KB
-rwxr-xr-x
chacl
15.27
KB
-rwxr-xr-x
chage
72.16
KB
-rwsr-xr-x
chardetect
307
B
-rwxr-xr-x
chattr
11.27
KB
-rwxr-xr-x
chcat
13.12
KB
-rwxr-xr-x
chcon
61.46
KB
-rwxr-xr-x
checkmodule
400.48
KB
-rwxr-xr-x
checkpolicy
412.46
KB
-rwxr-xr-x
chfn
23.41
KB
-rws--x--x
chgrp
61.32
KB
-rwxr-xr-x
chmem
40.43
KB
-rwxr-xr-x
chmod
57.21
KB
-rwxr-xr-x
chown
61.36
KB
-rwxr-xr-x
chronyc
85.03
KB
-rwxr-xr-x
chrt
32.17
KB
-rwxr-xr-x
chsh
23.32
KB
-rws--x--x
chvt
11.14
KB
-rwxr-xr-x
cifsiostat
48.5
KB
-rwxr-xr-x
cksum
32.38
KB
-rwxr-xr-x
clambc
139.76
KB
-rwxr-xr-x
clamconf
139.43
KB
-rwxr-xr-x
clamdscan
155.77
KB
-rwxr-xr-x
clamdtop
155.74
KB
-rwxr-xr-x
clamscan
163.64
KB
-rwxr-xr-x
clamsubmit
147.73
KB
-rwxr-xr-x
clear
7.02
KB
-rwxr-xr-x
clusterdb
53.22
KB
-rwxr-xr-x
cmake
3.9
MB
-rwxr-xr-x
cmake3
6.21
MB
-rwxr-xr-x
cmp
44.14
KB
-rwxr-xr-x
cmsutil
110.59
KB
-rwxr-xr-x
col
23.88
KB
-rwxr-xr-x
colcrt
11.29
KB
-rwxr-xr-x
colrm
23.77
KB
-rwxr-xr-x
column
27.99
KB
-rwxr-xr-x
comm
36.55
KB
-rwxr-xr-x
command
31
B
-rwxr-xr-x
compare
11.09
KB
-rwxr-xr-x
compile_et
1.45
KB
-rwxr-xr-x
composite
7.04
KB
-rwxr-xr-x
conjure
7.04
KB
-rwxr-xr-x
consolehelper
6.95
KB
-rwxr-xr-x
convert
7.04
KB
-rwxr-xr-x
coredumpctl
154.52
KB
-rwxr-xr-x
cp
151.55
KB
-rwxr-xr-x
cpack
4.16
MB
-rwxr-xr-x
cpack3
6.31
MB
-rwxr-xr-x
cpio
142.55
KB
-rwxr-xr-x
cpp
754.58
KB
-rwxr-xr-x
cpulimit
23.78
KB
-rwxr-xr-x
cpupower
66.34
KB
-rwxr-xr-x
crc32
794
B
-rwxr-xr-x
createdb
53.27
KB
-rwxr-xr-x
createlang
57.09
KB
-rwxr-xr-x
createuser
57.63
KB
-rwxr-xr-x
crlutil
127
KB
-rwxr-xr-x
crontab
56.23
KB
-rwsr-xr-x
csplit
48.82
KB
-rwxr-xr-x
csslint-0.6
19.55
KB
-rwxr-xr-x
ctest
4.96
MB
-rwxr-xr-x
ctest3
7.14
MB
-rwxr-xr-x
curl
152.99
KB
-rwxr-xr-x
curl-config
4.08
KB
-rwxr-xr-x
cut
40.61
KB
-rwxr-xr-x
cvtsudoers
241.7
KB
-rwxr-xr-x
cxpm
28.05
KB
-rwxr-xr-x
date
60.74
KB
-rwxr-xr-x
db_archive
11.23
KB
-rwxr-xr-x
db_checkpoint
11.3
KB
-rwxr-xr-x
db_deadlock
11.31
KB
-rwxr-xr-x
db_dump
15.33
KB
-rwxr-xr-x
db_dump185
64.45
KB
-rwxr-xr-x
db_hotbackup
15.34
KB
-rwxr-xr-x
db_load
27.51
KB
-rwxr-xr-x
db_log_verify
15.34
KB
-rwxr-xr-x
db_printlog
32.26
KB
-rwxr-xr-x
db_recover
11.33
KB
-rwxr-xr-x
db_replicate
15.34
KB
-rwxr-xr-x
db_stat
15.26
KB
-rwxr-xr-x
db_tuner
19.33
KB
-rwxr-xr-x
db_upgrade
11.23
KB
-rwxr-xr-x
db_verify
11.25
KB
-rwxr-xr-x
dbilogstrip
1.43
KB
-rwxr-xr-x
dbinfo
3.29
KB
-rwxr-xr-x
dbiprof
6.15
KB
-rwxr-xr-x
dbiproxy
5.35
KB
-rwxr-xr-x
dbus-binding-tool
94.49
KB
-rwxr-xr-x
dbus-cleanup-sockets
11
KB
-rwxr-xr-x
dbus-daemon
218
KB
-rwxr-xr-x
dbus-monitor
23.13
KB
-rwxr-xr-x
dbus-run-session
14.97
KB
-rwxr-xr-x
dbus-send
27.07
KB
-rwxr-xr-x
dbus-test-tool
23.13
KB
-rwxr-xr-x
dbus-update-activation-environ...
15.02
KB
-rwxr-xr-x
dbus-uuidgen
10.98
KB
-rwxr-xr-x
dc
44.33
KB
-rwxr-xr-x
dd
73.14
KB
-rwxr-xr-x
deallocvt
11.16
KB
-rwxr-xr-x
debuginfo-install
7.88
KB
-rwxr-xr-x
delv
39.98
KB
-rwxr-xr-x
derb
19.95
KB
-rwxr-xr-x
df
102.55
KB
-rwxr-xr-x
dgawk
502.12
KB
-rwxr-xr-x
diff
195.46
KB
-rwxr-xr-x
diff3
60.65
KB
-rwxr-xr-x
dig
146.96
KB
-rwxr-xr-x
dir
114.85
KB
-rwxr-xr-x
dircolors
40.44
KB
-rwxr-xr-x
dirname
28.31
KB
-rwxr-xr-x
display
7.04
KB
-rwxr-xr-x
dm_date
5.47
KB
-rwxr-xr-x
dm_zdump
4.95
KB
-rwxr-xr-x
dmesg
48.52
KB
-rwxr-xr-x
dnsdomainname
15.41
KB
-rwxr-xr-x
domainname
15.41
KB
-rwxr-xr-x
doveadm
596.59
KB
-rwxr-xr-x
doveconf
161.41
KB
-rwxr-xr-x
dracut
55.83
KB
-rwxr-xr-x
dropdb
53.08
KB
-rwxr-xr-x
droplang
57.08
KB
-rwxr-xr-x
dropuser
53.05
KB
-rwxr-xr-x
dsync
596.59
KB
-rwxr-xr-x
dtrace
16.66
KB
-rwxr-xr-x
du
110.34
KB
-rwxr-xr-x
dumpkeys
77.51
KB
-rwxr-xr-x
dumpsexp
15.18
KB
-rwxr-xr-x
dwp
3.03
MB
-rwxr-xr-x
easy_install-3.6
234
B
-rwxr-xr-x
echo
32.31
KB
-rwxr-xr-x
ecpg
737.83
KB
-rwxr-xr-x
ed2k-link
71.57
KB
-rwxr-xr-x
egrep
290
B
-rwxr-xr-x
eject
48.81
KB
-rwxr-xr-x
elfedit
32.18
KB
-rwxr-xr-x
enchant
15.29
KB
-rwxr-xr-x
enchant-lsmod
11.13
KB
-rwxr-xr-x
env
28.33
KB
-rwxr-xr-x
envsubst
36.01
KB
-rwxr-xr-x
eqn
144.41
KB
-rwxr-xr-x
ex
906.45
KB
-rwxr-xr-x
expand
32.48
KB
-rwxr-xr-x
expr
36.53
KB
-rwxr-xr-x
factor
93.29
KB
-rwxr-xr-x
fallocate
27.84
KB
-rwxr-xr-x
false
28.25
KB
-rwxr-xr-x
fc
26
B
-rwxr-xr-x
fc-cache
132
B
-rwxr-xr-x
fc-cache-64
15.45
KB
-rwxr-xr-x
fc-cat
15.4
KB
-rwxr-xr-x
fc-conflist
11.2
KB
-rwxr-xr-x
fc-list
11.26
KB
-rwxr-xr-x
fc-match
11.32
KB
-rwxr-xr-x
fc-pattern
11.26
KB
-rwxr-xr-x
fc-query
11.23
KB
-rwxr-xr-x
fc-scan
11.27
KB
-rwxr-xr-x
fc-validate
11.27
KB
-rwxr-xr-x
fcat
23.82
KB
-rwxr-xr-x
fg
26
B
-rwxr-xr-x
fgconsole
11.16
KB
-rwxr-xr-x
fgrep
290
B
-rwxr-xr-x
filan
89.13
KB
-rwxr-xr-x
file
19.3
KB
-rwxr-xr-x
find
194.63
KB
-rwxr-xr-x
find-repos-of-install
4.27
KB
-rwxr-xr-x
find2perl
23.06
KB
-rwxr-xr-x
findmnt
58.38
KB
-rwxr-xr-x
fipscheck
15.37
KB
-rwxr-xr-x
fipshmac
11.3
KB
-rwxr-xr-x
firewall-cmd
113.48
KB
-rwxr-xr-x
firewall-offline-cmd
101.18
KB
-rwxr-xr-x
flex
318.07
KB
-rwxr-xr-x
flex++
318.07
KB
-rwxr-xr-x
flock
23.88
KB
-rwxr-xr-x
fmt
36.48
KB
-rwxr-xr-x
fold
36.46
KB
-rwxr-xr-x
fonttosfnt
35.99
KB
-rwxr-xr-x
formail
43.68
KB
-rwxr-xr-x
free
19.33
KB
-rwxr-xr-x
freetype-config
4.39
KB
-rwxr-xr-x
freeze
23.82
KB
-rwxr-xr-x
freshclam
39.23
KB
-rwxr-xr-x
fribidi
16.09
KB
-rwxr-xr-x
funzip
31.38
KB
-rwxr-xr-x
g++
754.59
KB
-rwxr-xr-x
galera_new_cluster
917
B
-rwxr-xr-x
galera_recovery
3.28
KB
-rwxr-xr-x
gapplication
19.48
KB
-rwxr-xr-x
garb-systemd
1.2
KB
-rwxr-xr-x
garbd
2.2
MB
-rwxr-xr-x
gawk
418.54
KB
-rwxr-xr-x
gcc
750.59
KB
-rwxr-xr-x
gcc-ar
26.45
KB
-rwxr-xr-x
gcc-nm
26.45
KB
-rwxr-xr-x
gcc-ranlib
26.45
KB
-rwxr-xr-x
gcov
307.45
KB
-rwxr-xr-x
gdbus
40.17
KB
-rwxr-xr-x
gdbus-codegen
2
KB
-rwxr-xr-x
gdk-pixbuf-query-loaders-64
15.38
KB
-rwxr-xr-x
gdk-pixbuf-thumbnailer
15.59
KB
-rwxr-xr-x
genbrk
15.75
KB
-rwxr-xr-x
gencat
22.11
KB
-rwxr-xr-x
gencfu
11.64
KB
-rwxr-xr-x
gencnval
19.71
KB
-rwxr-xr-x
gendict
24.01
KB
-rwxr-xr-x
genkey
43.13
KB
-rwxr-xr-x
genl-ctrl-list
11.27
KB
-rwxr-xr-x
genrb
95.2
KB
-rwxr-xr-x
geoiplookup
15.28
KB
-rwxr-xr-x
geoiplookup6
11.16
KB
-rwxr-xr-x
geoipupdate
31.28
KB
-rwxr-xr-x
geqn
144.41
KB
-rwxr-xr-x
getconf
22.02
KB
-rwxr-xr-x
getent
26.39
KB
-rwxr-xr-x
getfacl
24.29
KB
-rwxr-xr-x
getkeycodes
11.16
KB
-rwxr-xr-x
getopt
15.38
KB
-rwxr-xr-x
getopts
31
B
-rwxr-xr-x
gettext
35.94
KB
-rwxr-xr-x
gettext.sh
4.52
KB
-rwxr-xr-x
gio
73.41
KB
-rwxr-xr-x
gio-querymodules-64
11.31
KB
-rwxr-xr-x
git
1.46
MB
-rwxr-xr-x
git-receive-pack
1.46
MB
-rwxr-xr-x
git-shell
717.98
KB
-rwxr-xr-x
git-upload-archive
1.46
MB
-rwxr-xr-x
git-upload-pack
791.45
KB
-rwxr-xr-x
glib-compile-resources
40.25
KB
-rwxr-xr-x
glib-compile-schemas
44.38
KB
-rwxr-xr-x
glib-genmarshal
39.97
KB
-rwxr-xr-x
glib-gettextize
5.25
KB
-rwxr-xr-x
glib-mkenums
27.15
KB
-rwxr-xr-x
gmake
178.47
KB
-rwxr-xr-x
gneqn
271
B
-rwxr-xr-x
gnroff
3.31
KB
-rwxr-xr-x
goaccess
610.99
KB
-rwxr-xr-x
gobject-query
11.13
KB
-rwxr-xr-x
gost-hash
71.57
KB
-rwxr-xr-x
gpasswd
76.57
KB
-rwsr-xr-x
gpg
732.4
KB
-rwxr-xr-x
gpg-agent
289.74
KB
-rwxr-xr-x
gpg-connect-agent
152.69
KB
-rwxr-xr-x
gpg-error
23.18
KB
-rwxr-xr-x
gpg-error-config
1.83
KB
-rwxr-xr-x
gpg-zip
3.23
KB
-rwxr-xr-x
gpg2
732.4
KB
-rwxr-xr-x
gpgconf
140.31
KB
-rwxr-xr-x
gpgparsemail
23.7
KB
-rwxr-xr-x
gpgsplit
48.88
KB
-rwxr-xr-x
gpgv
345.38
KB
-rwxr-xr-x
gpgv2
345.38
KB
-rwxr-xr-x
gpic
180.41
KB
-rwxr-xr-x
gprof
98.41
KB
-rwxr-xr-x
gr2fonttest
23.66
KB
-rwxr-xr-x
grep
155.3
KB
-rwxr-xr-x
gresource
19.55
KB
-rwxr-xr-x
groff
81.63
KB
-rwxr-xr-x
grops
140.85
KB
-rwxr-xr-x
grotty
98.59
KB
-rwxr-xr-x
groups
32.41
KB
-rwxr-xr-x
grub2-editenv
396.07
KB
-rwxr-xr-x
grub2-file
830.36
KB
-rwxr-xr-x
grub2-fstest
1.03
MB
-rwxr-xr-x
grub2-glue-efi
258.85
KB
-rwxr-xr-x
grub2-kbdcomp
1.63
KB
-rwxr-xr-x
grub2-menulst2cfg
241.82
KB
-rwxr-xr-x
grub2-mkfont
287.6
KB
-rwxr-xr-x
grub2-mkimage
379.25
KB
-rwxr-xr-x
grub2-mklayout
264.91
KB
-rwxr-xr-x
grub2-mknetdir
429.8
KB
-rwxr-xr-x
grub2-mkpasswd-pbkdf2
271.29
KB
-rwxr-xr-x
grub2-mkrelpath
258.48
KB
-rwxr-xr-x
grub2-mkrescue
1017.84
KB
-rwxr-xr-x
grub2-mkstandalone
534.32
KB
-rwxr-xr-x
grub2-render-label
835.16
KB
-rwxr-xr-x
grub2-script-check
295.43
KB
-rwxr-xr-x
grub2-syslinux2cfg
763.7
KB
-rwxr-xr-x
gsettings
23.8
KB
-rwxr-xr-x
gsoelim
32.59
KB
-rwxr-xr-x
gss-client
23.17
KB
-rwxr-xr-x
gtar
338.02
KB
-rwxr-xr-x
gtbl
115.96
KB
-rwxr-xr-x
gtester
23.64
KB
-rwxr-xr-x
gtester-report
18.39
KB
-rwxr-xr-x
gtroff
512.96
KB
-rwxr-xr-x
gunzip
2.2
KB
-rwxr-xr-x
gzexe
5.79
KB
-rwxr-xr-x
gzip
98.43
KB
-rwxr-xr-x
h2ph
27.65
KB
-rwxr-xr-x
h2xs
59.15
KB
-rwxr-xr-x
has160-hash
71.57
KB
-rwxr-xr-x
hdsploader
11.18
KB
-rwxr-xr-x
head
40.51
KB
-rwxr-xr-x
hexdump
32.02
KB
-rwxr-xr-x
hmac256
15.67
KB
-rwxr-xr-x
host
127.02
KB
-rwxr-xr-x
hostid
28.32
KB
-rwxr-xr-x
hostname
15.41
KB
-rwxr-xr-x
hostnamectl
318.07
KB
-rwxr-xr-x
hunspell
53.11
KB
-rwxr-xr-x
i386
15.27
KB
-rwxr-xr-x
iceauth
31.73
KB
-rwxr-xr-x
iconv
58.14
KB
-rwxr-xr-x
icu-config
172
B
-rwxr-xr-x
icu-config-64
21.49
KB
-rwxr-xr-x
icuinfo
15.6
KB
-rwxr-xr-x
id
36.52
KB
-rwxr-xr-x
identify
7.06
KB
-rwxr-xr-x
idiag-socket-details
11.34
KB
-rwxr-xr-x
idn
32.45
KB
-rwxr-xr-x
ifnames
4.03
KB
-rwxr-xr-x
igawk
3.11
KB
-rwxr-xr-x
imapsync
338.75
KB
-rwxr-xr-x
import
7.04
KB
-rwxr-xr-x
info
265.19
KB
-rwxr-xr-x
infocmp
56.07
KB
-rwxr-xr-x
infokey
21.47
KB
-rwxr-xr-x
infotocap
64.26
KB
-rwxr-xr-x
innochecksum
3.64
MB
-rwxr-xr-x
install
139.59
KB
-rwxr-xr-x
instmodsh
4.15
KB
-rwxr-xr-x
ionice
23.86
KB
-rwxr-xr-x
iostat
60.77
KB
-rwxr-xr-x
ipcalc
15.05
KB
-rwxr-xr-x
ipcmk
24
KB
-rwxr-xr-x
ipcrm
27.85
KB
-rwxr-xr-x
ipcs
48.37
KB
-rwxr-xr-x
iptables-xml
91.52
KB
-rwxr-xr-x
isosize
23.83
KB
-rwxr-xr-x
ispell
988
B
-rwxr-xr-x
jemalloc.sh
125
B
-rwxr-xr-x
jobs
28
B
-rwxr-xr-x
join
48.75
KB
-rwxr-xr-x
journalctl
537.88
KB
-rwxr-xr-x
kbd_mode
11.16
KB
-rwxr-xr-x
kbdinfo
11.19
KB
-rwxr-xr-x
kbdrate
11.22
KB
-rwxr-xr-x
kdumpctl
33.18
KB
-rwxr-xr-x
kernel-install
4.7
KB
-rwxr-xr-x
keyrand
11.25
KB
-rwxr-xr-x
keyutil
60.84
KB
-rwxr-xr-x
kill
32.82
KB
-rwxr-xr-x
kmod
143.24
KB
-rwxr-xr-x
krb5-config
6.96
KB
-rwxr-xr-x
l4p-tmpl
1.89
KB
-rwxr-xr-x
last
19.11
KB
-rwxr-xr-x
lastb
19.11
KB
-rwxr-xr-x
lastlog
19.15
KB
-rwxr-xr-x
lchfn
15.52
KB
-rwxr-xr-x
lchsh
15.49
KB
-rwxr-xr-x
ld
982.61
KB
-rwxr-xr-x
ld.bfd
982.61
KB
-rwxr-xr-x
ld.gold
5.11
MB
-rwxr-xr-x
ldd
5.18
KB
-rwxr-xr-x
less
154.53
KB
-rwxr-xr-x
lessecho
11.11
KB
-rwxr-xr-x
lesskey
16.66
KB
-rwxr-xr-x
lesspipe.sh
2.24
KB
-rwxr-xr-x
lex
318.07
KB
-rwxr-xr-x
lexgrog
85.09
KB
-rwxr-xr-x
libgcrypt-config
3.78
KB
-rwxr-xr-x
libmcrypt-config
1.38
KB
-rwxr-xr-x
libnetcfg
15.36
KB
-rwxr-xr-x
libpng-config
2.38
KB
-rwxr-xr-x
libpng15-config
2.38
KB
-rwxr-xr-x
link
28.3
KB
-rwxr-xr-x
links
4.37
MB
-rwxr-xr-x
links2
4.37
MB
-rwxr-xr-x
linux-boot-prober
5.85
KB
-rwxr-xr-x
linux32
15.27
KB
-rwxr-xr-x
linux64
15.27
KB
-rwxr-xr-x
ln
57.22
KB
-rwxr-xr-x
loadkeys
110.48
KB
-rwxr-xr-x
loadunimap
23.88
KB
-rwxr-xr-x
locale
37.11
KB
-rwxr-xr-x
localectl
326.16
KB
-rwxr-xr-x
localedef
318.31
KB
-rwxr-xr-x
locate
39.57
KB
-rwx--s--x
lockfile
19.36
KB
-rwxr-sr-x
logger
28.62
KB
-rwxr-xr-x
login
36.38
KB
-rwxr-xr-x
loginctl
489.62
KB
-rwxr-xr-x
logname
28.31
KB
-rwxr-xr-x
look
11.27
KB
-rwxr-xr-x
ls
114.85
KB
-rwxr-xr-x
lsattr
11.25
KB
-rwxr-xr-x
lsblk
79.17
KB
-rwxr-xr-x
lscpu
60.75
KB
-rwxr-xr-x
lsinitrd
6.26
KB
-rwxr-xr-x
lsipc
60.95
KB
-rwxr-xr-x
lslocks
41.01
KB
-rwxr-xr-x
lslogins
52.88
KB
-rwxr-xr-x
lsmem
40.78
KB
-rwxr-xr-x
lsns
36.43
KB
-rwxr-xr-x
lsscsi
56.48
KB
-rwxr-xr-x
lua
15.47
KB
-rwxr-xr-x
luac
119.03
KB
-rwxr-xr-x
lwp-download
8.43
KB
-rwxr-xr-x
lwp-dump
2.73
KB
-rwxr-xr-x
lwp-mirror
2.42
KB
-rwxr-xr-x
lwp-request
14.71
KB
-rwxr-xr-x
lynis
50.57
KB
-rwxr-xr-x
lz4
105.84
KB
-rwxr-xr-x
lz4c
105.84
KB
-rwxr-xr-x
lz4cat
105.84
KB
-rwxr-xr-x
lzop
69.32
KB
-rwxr-xr-x
m4
151.17
KB
-rwxr-xr-x
machinectl
533.95
KB
-rwxr-xr-x
magnet-link
71.57
KB
-rwxr-xr-x
mail
383.67
KB
-rwxr-xr-x
mailq
322.16
KB
-rwxr-xr-x
mailq.postfix
322.16
KB
-rwxr-xr-x
mailstat
5.72
KB
-rwxr-xr-x
mailx
383.67
KB
-rwxr-xr-x
make
178.47
KB
-rwxr-xr-x
makeconv
40.51
KB
-rwxr-xr-x
makedb
18.11
KB
-rwxr-xr-x
man
100.44
KB
-rwxr-xr-x
mandb
122.25
KB
-rwxr-xr-x
manpath
32.55
KB
-rwxr-xr-x
mapscrn
19.78
KB
-rwxr-xr-x
mariadb
4.33
MB
-rwxr-xr-x
mariadb-access
109.33
KB
-rwxr-xr-x
mariadb-admin
3.85
MB
-rwxr-xr-x
mariadb-binlog
4.11
MB
-rwxr-xr-x
mariadb-check
3.85
MB
-rwxr-xr-x
mariadb-convert-table-format
4.12
KB
-rwxr-xr-x
mariadb-dump
3.94
MB
-rwxr-xr-x
mariadb-dumpslow
8.05
KB
-rwxr-xr-x
mariadb-embedded
21.82
MB
-rwxr-xr-x
mariadb-find-rows
3.21
KB
-rwxr-xr-x
mariadb-fix-extensions
1.22
KB
-rwxr-xr-x
mariadb-hotcopy
34.14
KB
-rwxr-xr-x
mariadb-import
3.84
MB
-rwxr-xr-x
mariadb-install-db
21.57
KB
-rwxr-xr-x
mariadb-plugin
3.54
MB
-rwxr-xr-x
mariadb-secure-installation
13.37
KB
-rwxr-xr-x
mariadb-service-convert
2.45
KB
-rwxr-xr-x
mariadb-setpermission
17.13
KB
-rwxr-xr-x
mariadb-show
3.84
MB
-rwxr-xr-x
mariadb-slap
3.86
MB
-rwxr-xr-x
mariadb-tzinfo-to-sql
3.54
MB
-rwxr-xr-x
mariadb-upgrade
3.63
MB
-rwxr-xr-x
mariadb-waitpid
3.53
MB
-rwxr-xr-x
mariadb_config
11.57
KB
-rwxr-xr-x
mariadbd-multi
26.69
KB
-rwxr-xr-x
mariadbd-safe
30.39
KB
-rwxr-xr-x
mariadbd-safe-helper
3.5
MB
-rwxr-xr-x
mcookie
15.44
KB
-rwxr-xr-x
md5sum
40.53
KB
-rwxr-xr-x
mdig
44.2
KB
-rwxr-xr-x
melt
23.82
KB
-rwxr-xr-x
memaslap
65.37
KB
-rwxr-xr-x
memcached
108.77
KB
-rwxr-xr-x
memcached-tool
4.18
KB
-rwxr-xr-x
memcapable
57.71
KB
-rwxr-xr-x
memcat
19.99
KB
-rwxr-xr-x
memcp
20.19
KB
-rwxr-xr-x
memdump
15.81
KB
-rwxr-xr-x
memerror
15.46
KB
-rwxr-xr-x
memexist
15.72
KB
-rwxr-xr-x
memflush
15.73
KB
-rwxr-xr-x
memparse
11.06
KB
-rwxr-xr-x
memping
15.84
KB
-rwxr-xr-x
memrm
15.78
KB
-rwxr-xr-x
memslap
24.55
KB
-rwxr-xr-x
memstat
20.17
KB
-rwxr-xr-x
memtouch
15.8
KB
-rwxr-xr-x
mesg
10.98
KB
-rwxr-xr-x
mimedump
2.29
KB
-rwxr-xr-x
mimeencode
849
B
-rwxr-xr-x
mimeexplode
3.28
KB
-rwxr-xr-x
mimepostcard
2.68
KB
-rwxr-xr-x
mimesend
3.06
KB
-rwxr-xr-x
mixartloader
15.38
KB
-rwxr-xr-x
mkdir
77.9
KB
-rwxr-xr-x
mkfifo
61.59
KB
-rwxr-xr-x
mkfontdir
65
B
-rwxr-xr-x
mkfontscale
32.48
KB
-rwxr-xr-x
mkinitrd
2.94
KB
-rwxr-xr-x
mknod
65.61
KB
-rwxr-xr-x
mktemp
40.66
KB
-rwxr-xr-x
modutil
165.78
KB
-rwxr-xr-x
mogrify
7.04
KB
-rwxr-xr-x
montage
7.04
KB
-rwxr-xr-x
more
40.15
KB
-rwxr-xr-x
mount
43.23
KB
-rwsr-xr-x
mountpoint
15.32
KB
-rwxr-xr-x
mpstat
52.53
KB
-rwxr-xr-x
msgattrib
23.36
KB
-rwxr-xr-x
msgcat
23.34
KB
-rwxr-xr-x
msgcmp
23.59
KB
-rwxr-xr-x
msgcomm
19.31
KB
-rwxr-xr-x
msgconv
19.3
KB
-rwxr-xr-x
msgen
19.3
KB
-rwxr-xr-x
msgexec
15.33
KB
-rwxr-xr-x
msgfilter
27.56
KB
-rwxr-xr-x
msgfmt
77.05
KB
-rwxr-xr-x
msggrep
35.97
KB
-rwxr-xr-x
msghack
12.45
KB
-rwxr-xr-x
msginit
44.38
KB
-rwxr-xr-x
msgmerge
52.6
KB
-rwxr-xr-x
msgunfmt
31.7
KB
-rwxr-xr-x
msguniq
19.31
KB
-rwxr-xr-x
msql2mysql
1.41
KB
-rwxr-xr-x
mv
127.3
KB
-rwxr-xr-x
my_print_defaults
3.53
MB
-rwxr-xr-x
myisam_ftdump
3.89
MB
-rwxr-xr-x
myisamchk
4.01
MB
-rwxr-xr-x
myisamlog
3.87
MB
-rwxr-xr-x
myisampack
3.91
MB
-rwxr-xr-x
mysql
4.33
MB
-rwxr-xr-x
mysql_config
4.58
KB
-rwxr-xr-x
mysql_convert_table_format
4.12
KB
-rwxr-xr-x
mysql_embedded
21.82
MB
-rwxr-xr-x
mysql_find_rows
3.21
KB
-rwxr-xr-x
mysql_fix_extensions
1.22
KB
-rwxr-xr-x
mysql_install_db
21.57
KB
-rwxr-xr-x
mysql_plugin
3.54
MB
-rwxr-xr-x
mysql_secure_installation
13.37
KB
-rwxr-xr-x
mysql_setpermission
17.13
KB
-rwxr-xr-x
mysql_tzinfo_to_sql
3.54
MB
-rwxr-xr-x
mysql_upgrade
3.63
MB
-rwxr-xr-x
mysql_waitpid
3.53
MB
-rwxr-xr-x
mysqlaccess
109.33
KB
-rwxr-xr-x
mysqladmin
3.85
MB
-rwxr-xr-x
mysqlbinlog
4.11
MB
-rwxr-xr-x
mysqlcheck
3.85
MB
-rwxr-xr-x
mysqld_multi
26.69
KB
-rwxr-xr-x
mysqld_safe
30.39
KB
-rwxr-xr-x
mysqld_safe_helper
3.5
MB
-rwxr-xr-x
mysqldump
3.94
MB
-rwxr-xr-x
mysqldumpslow
8.05
KB
-rwxr-xr-x
mysqlhotcopy
34.14
KB
-rwxr-xr-x
mysqlimport
3.84
MB
-rwxr-xr-x
mysqlshow
3.84
MB
-rwxr-xr-x
mysqlslap
3.86
MB
-rwxr-xr-x
nail
383.67
KB
-rwxr-xr-x
named-rrchecker
15.32
KB
-rwxr-xr-x
namei
27.95
KB
-rwxr-xr-x
nano
201.08
KB
-rwxr-xr-x
ncurses5-config
5.68
KB
-rwxr-xr-x
ncursesw5-config
5.68
KB
-rwxr-xr-x
ndptool
23.63
KB
-rwxr-xr-x
needs-restarting
8.17
KB
-rwxr-xr-x
neqn
271
B
-rwxr-xr-x
net-server
3.34
KB
-rwxr-xr-x
net-snmp-config
1.3
KB
-rwxr-xr-x
net-snmp-config-x86_64
29.46
KB
-rwxr-xr-x
net-snmp-create-v3-user
2.98
KB
-rwxr-xr-x
netstat
151.38
KB
-rwxr-xr-x
nettle-hash
11.33
KB
-rwxr-xr-x
nettle-lfib-stream
7.05
KB
-rwxr-xr-x
newaliases
322.16
KB
-rwxr-xr-x
newaliases.postfix
322.16
KB
-rwxr-xr-x
newgidmap
38.09
KB
-rwxr-xr-x
newgrp
40.95
KB
-rwsr-xr-x
newuidmap
38.06
KB
-rwxr-xr-x
nf-ct-add
11.8
KB
-rwxr-xr-x
nf-ct-list
15.84
KB
-rwxr-xr-x
nf-exp-add
16.21
KB
-rwxr-xr-x
nf-exp-delete
15.99
KB
-rwxr-xr-x
nf-exp-list
11.8
KB
-rwxr-xr-x
nf-log
11.23
KB
-rwxr-xr-x
nf-monitor
11.18
KB
-rwxr-xr-x
nf-queue
11.27
KB
-rwxr-xr-x
nfsiostat-sysstat
52.52
KB
-rwxr-xr-x
ngettext
35.95
KB
-rwxr-xr-x
nice
32.32
KB
-rwxr-xr-x
nisdomainname
15.41
KB
-rwxr-xr-x
nl
40.6
KB
-rwxr-xr-x
nl-addr-add
11.65
KB
-rwxr-xr-x
nl-addr-delete
11.73
KB
-rwxr-xr-x
nl-addr-list
15.88
KB
-rwxr-xr-x
nl-class-add
11.7
KB
-rwxr-xr-x
nl-class-delete
11.55
KB
-rwxr-xr-x
nl-class-list
11.48
KB
-rwxr-xr-x
nl-classid-lookup
11.29
KB
-rwxr-xr-x
nl-cls-add
11.76
KB
-rwxr-xr-x
nl-cls-delete
11.68
KB
-rwxr-xr-x
nl-cls-list
11.58
KB
-rwxr-xr-x
nl-fib-lookup
11.41
KB
-rwxr-xr-x
nl-link-enslave
7.05
KB
-rwxr-xr-x
nl-link-ifindex2name
7.06
KB
-rwxr-xr-x
nl-link-list
11.52
KB
-rwxr-xr-x
nl-link-name2ifindex
7.05
KB
-rwxr-xr-x
nl-link-release
7.05
KB
-rwxr-xr-x
nl-link-set
11.64
KB
-rwxr-xr-x
nl-link-stats
11.39
KB
-rwxr-xr-x
nl-list-caches
11.08
KB
-rwxr-xr-x
nl-list-sockets
7.06
KB
-rwxr-xr-x
nl-monitor
11.2
KB
-rwxr-xr-x
nl-neigh-add
11.51
KB
-rwxr-xr-x
nl-neigh-delete
11.57
KB
-rwxr-xr-x
nl-neigh-list
11.46
KB
-rwxr-xr-x
nl-neightbl-list
11.27
KB
-rwxr-xr-x
nl-pktloc-lookup
11.36
KB
-rwxr-xr-x
nl-qdisc-add
11.6
KB
-rwxr-xr-x
nl-qdisc-delete
11.54
KB
-rwxr-xr-x
nl-qdisc-list
11.63
KB
-rwxr-xr-x
nl-route-add
11.73
KB
-rwxr-xr-x
nl-route-delete
15.86
KB
-rwxr-xr-x
nl-route-get
11.18
KB
-rwxr-xr-x
nl-route-list
11.77
KB
-rwxr-xr-x
nl-rule-list
11.3
KB
-rwxr-xr-x
nl-tctree-list
11.53
KB
-rwxr-xr-x
nl-util-addr
7.03
KB
-rwxr-xr-x
nm
45.43
KB
-rwxr-xr-x
nm-online
15.16
KB
-rwxr-xr-x
nmcli
809.16
KB
-rwxr-xr-x
nmtui
646.77
KB
-rwxr-xr-x
nmtui-connect
646.77
KB
-rwxr-xr-x
nmtui-edit
646.77
KB
-rwxr-xr-x
nmtui-hostname
646.77
KB
-rwxr-xr-x
nohup
32.42
KB
-rwxr-xr-x
nomarch
19.6
KB
-rwxr-xr-x
nproc
32.37
KB
-rwxr-xr-x
nroff
3.31
KB
-rwxr-xr-x
nsenter
28.22
KB
-rwxr-xr-x
nslookup
130.93
KB
-rwxr-xr-x
nss-policy-check
15.26
KB
-rwxr-xr-x
nsupdate
65.2
KB
-rwxr-xr-x
numfmt
64.71
KB
-rwxr-xr-x
objcopy
227.34
KB
-rwxr-xr-x
objdump
357.74
KB
-rwxr-xr-x
od
64.81
KB
-rwxr-xr-x
offlineimap
926
B
-rwxr-xr-x
oldfind
186.41
KB
-rwxr-xr-x
onig-config
1.31
KB
-rwxr-xr-x
opax
110.53
KB
-rwxr-xr-x
open
19.48
KB
-rwxr-xr-x
openssl
542.27
KB
-rwxr-xr-x
openvt
19.48
KB
-rwxr-xr-x
os-prober
5.51
KB
-rwxr-xr-x
p11-kit
32.18
KB
-rwxr-xr-x
package-cleanup
17.39
KB
-rwxr-xr-x
package-stash-conflicts
487
B
-rwxr-xr-x
page_owner_sort
10.2
KB
-rwxr-xr-x
pango-list
11.1
KB
-rwxr-xr-x
pango-querymodules-64
28.26
KB
-rwxr-xr-x
pango-view
49.47
KB
-rwxr-xr-x
paperconf
11.23
KB
-rwxr-xr-x
passwd
27.2
KB
-rwsr-xr-x
paste
32.34
KB
-rwxr-xr-x
pathchk
32.31
KB
-rwxr-xr-x
pax
110.53
KB
-rwxr-xr-x
pchrt
3.93
KB
-rwxr-xr-x
pcre-config
2.09
KB
-rwxr-xr-x
perl
11.14
KB
-rwxr-xr-x
perl5.16.3
11.14
KB
-rwxr-xr-x
perlbug
43.61
KB
-rwxr-xr-x
perldoc
203
B
-rwxr-xr-x
perlivp
10.52
KB
-rwxr-xr-x
perlthanks
43.61
KB
-rwxr-xr-x
perror
3.72
MB
-rwxr-xr-x
pflags
2.06
KB
-rwxr-xr-x
pg_config
28
KB
-rwxr-xr-x
pg_dump
305.78
KB
-rwxr-xr-x
pg_dumpall
73.89
KB
-rwxr-xr-x
pg_restore
126.79
KB
-rwxr-xr-x
pgawk
418.63
KB
-rwxr-xr-x
pgrep
27.67
KB
-rwxr-xr-x
php
41.44
MB
-rwxr-xr-x
pic
180.41
KB
-rwxr-xr-x
piconv
7.99
KB
-rwxr-xr-x
pidstat
68.89
KB
-rwxr-xr-x
pinentry
2.54
KB
-rwxr-xr-x
pinentry-curses
49.19
KB
-rwxr-xr-x
ping
64.63
KB
-rwxr-xr-x
ping6
64.63
KB
-rwxr-xr-x
pinky
36.57
KB
-rwxr-xr-x
pip-3
407
B
-rwxr-xr-x
pip-3.6
407
B
-rwxr-xr-x
pip3
407
B
-rwxr-xr-x
pip3.6
407
B
-rwxr-xr-x
pk12util
103.22
KB
-rwxr-xr-x
pkaction
15
KB
-rwxr-xr-x
pkcheck
23.03
KB
-rwxr-xr-x
pkcs1-conv
15.52
KB
-rwxr-xr-x
pkexec
27.02
KB
-rwsr-xr-x
pkg-config
44.38
KB
-rwxr-xr-x
pkgdata
36.7
KB
-rwxr-xr-x
pkill
27.67
KB
-rwxr-xr-x
pkla-admin-identities
19.23
KB
-rwxr-xr-x
pkla-check-authorization
27.3
KB
-rwxr-xr-x
pkttyagent
18.98
KB
-rwxr-xr-x
pl2pm
4.42
KB
-rwxr-xr-x
pldd
14.11
KB
-rwxr-xr-x
plymouth
39.77
KB
-rwxr-xr-x
pmap
27.61
KB
-rwxr-xr-x
pod2html
4
KB
-rwxr-xr-x
pod2man
13.26
KB
-rwxr-xr-x
pod2text
10.75
KB
-rwxr-xr-x
pod2usage
3.67
KB
-rwxr-xr-x
post-grohtml
187.55
KB
-rwxr-xr-x
powernow-k8-decode
6.15
KB
-rwxr-xr-x
pr
65.11
KB
-rwxr-xr-x
pre-grohtml
86.24
KB
-rwxr-xr-x
precat
5.52
KB
-rwxr-xr-x
preconv
40.88
KB
-rwxr-xr-x
preunzip
5.52
KB
-rwxr-xr-x
prezip
5.52
KB
-rwxr-xr-x
prezip-bin
11.05
KB
-rwxr-xr-x
printenv
28.28
KB
-rwxr-xr-x
printf
48.61
KB
-rwxr-xr-x
prlimit
41.2
KB
-rwxr-xr-x
procan
76.99
KB
-rwxr-xr-x
procmail
105.45
KB
-rwxr-xr-x
prove
13.13
KB
-rwxr-xr-x
ps
97.77
KB
-rwxr-xr-x
psed
52.08
KB
-rwxr-xr-x
psfaddtable
19.48
KB
-rwxr-xr-x
psfgettable
19.48
KB
-rwxr-xr-x
psfstriptable
19.48
KB
-rwxr-xr-x
psfxtable
19.48
KB
-rwxr-xr-x
pspell-config
384
B
-rwxr-xr-x
psql
438.74
KB
-rwxr-xr-x
pstruct
35.75
KB
-rwxr-xr-x
pt-align
39.89
KB
-rwxr-xr-x
pt-archiver
255.74
KB
-rwxr-xr-x
pt-config-diff
164.27
KB
-rwxr-xr-x
pt-deadlock-logger
161.56
KB
-rwxr-xr-x
pt-diskstats
160.3
KB
-rwxr-xr-x
pt-duplicate-key-checker
164.22
KB
-rwxr-xr-x
pt-fifo-split
48.11
KB
-rwxr-xr-x
pt-find
145.46
KB
-rwxr-xr-x
pt-fingerprint
64.85
KB
-rwxr-xr-x
pt-fk-error-logger
129.3
KB
-rwxr-xr-x
pt-heartbeat
186.97
KB
-rwxr-xr-x
pt-index-usage
219.97
KB
-rwxr-xr-x
pt-ioprofile
31.59
KB
-rwxr-xr-x
pt-kill
242.13
KB
-rwxr-xr-x
pt-mext
21.24
KB
-rwxr-xr-x
pt-mysql-summary
98.62
KB
-rwxr-xr-x
pt-online-schema-change
374.96
KB
-rwxr-xr-x
pt-pmp
24.02
KB
-rwxr-xr-x
pt-query-digest
505.41
KB
-rwxr-xr-x
pt-show-grants
70.84
KB
-rwxr-xr-x
pt-sift
36.84
KB
-rwxr-xr-x
pt-slave-delay
141.38
KB
-rwxr-xr-x
pt-slave-find
124
KB
-rwxr-xr-x
pt-slave-restart
174.58
KB
-rwxr-xr-x
pt-stalk
67.93
KB
-rwxr-xr-x
pt-summary
87.76
KB
-rwxr-xr-x
pt-table-checksum
408.52
KB
-rwxr-xr-x
pt-table-sync
386.36
KB
-rwxr-xr-x
pt-table-usage
217.38
KB
-rwxr-xr-x
pt-upgrade
322.26
KB
-rwxr-xr-x
pt-variable-advisor
172.12
KB
-rwxr-xr-x
pt-visual-explain
99.27
KB
-rwxr-xr-x
ptar
3.43
KB
-rwxr-xr-x
ptardiff
2.41
KB
-rwxr-xr-x
ptargrep
4.13
KB
-rwxr-xr-x
ptaskset
3.8
KB
-rwxr-xr-x
ptx
65.08
KB
-rwxr-xr-x
pure-ftpwho
6.95
KB
-rwxr-xr-x
pure-pw
39.5
KB
-rwxr-xr-x
pure-pwconvert
10.95
KB
-rwxr-xr-x
pure-statsdecode
10.95
KB
-rwxr-xr-x
pwd
32.45
KB
-rwxr-xr-x
pwdx
11.27
KB
-rwxr-xr-x
pwmake
11.13
KB
-rwxr-xr-x
pwscore
11.13
KB
-rwxr-xr-x
pydoc
78
B
-rwxr-xr-x
pydoc3
78
B
-rwxr-xr-x
pydoc3.6
78
B
-rwxr-xr-x
python
6.98
KB
-rwxr-xr-x
python2
6.98
KB
-rwxr-xr-x
python2.7
6.98
KB
-rwxr-xr-x
python3
11.07
KB
-rwxr-xr-x
python3.6
11.07
KB
-rwxr-xr-x
python3.6m
11.07
KB
-rwxr-xr-x
pyvenv
435
B
-rwxr-xr-x
pyvenv-3.6
435
B
-rwxr-xr-x
qemu-ga
267.8
KB
-rwxr-xr-x
quota
83.31
KB
-rwxr-xr-x
quotasync
70.84
KB
-rwxr-xr-x
ranlib
61.22
KB
-rwxr-xr-x
raw
15.27
KB
-rwxr-xr-x
razor-admin
905
B
-rwxr-xr-x
razor-check
907
B
-rwxr-xr-x
razor-client
624
B
-rwxr-xr-x
razor-report
911
B
-rwxr-xr-x
razor-revoke
911
B
-rwxr-xr-x
read
28
B
-rwxr-xr-x
readelf
509.83
KB
-rwxr-xr-x
readlink
40.82
KB
-rwxr-xr-x
realpath
61.23
KB
-rwxr-xr-x
rearj
60.17
KB
-rwxr-xr-x
recode
39.87
KB
-rwxr-xr-x
recode-sr-latin
15.29
KB
-rwxr-xr-x
redis-benchmark
1.28
MB
-rwxr-xr-x
redis-check-aof
2.79
MB
-rwxr-xr-x
redis-check-rdb
2.79
MB
-rwxr-xr-x
redis-cli
926.3
KB
-rwxr-xr-x
redis-sentinel
2.79
MB
-rwxr-xr-x
redis-server
2.79
MB
-rwxr-xr-x
reindexdb
57.27
KB
-rwxr-xr-x
rename
11.26
KB
-rwxr-xr-x
renice
11.21
KB
-rwxr-xr-x
replace
3.51
MB
-rwxr-xr-x
repo-graph
4.09
KB
-rwxr-xr-x
repo-rss
10.07
KB
-rwxr-xr-x
repoclosure
11.42
KB
-rwxr-xr-x
repodiff
13.97
KB
-rwxr-xr-x
repomanage
6.88
KB
-rwxr-xr-x
repoquery
55.68
KB
-rwxr-xr-x
reposync
14.14
KB
-rwxr-xr-x
repotrack
9.86
KB
-rwxr-xr-x
rescan-scsi-bus.sh
33.81
KB
-rwxr-xr-x
reset
19.6
KB
-rwxr-xr-x
resizecons
19.63
KB
-rwxr-xr-x
resolve_stack_dump
3.53
MB
-rwxr-xr-x
resolveip
3.53
MB
-rwxr-xr-x
rev
11.26
KB
-rwxr-xr-x
rhash
71.57
KB
-rwxr-xr-x
rkhunter
562.04
KB
-rwxr-xr-x
rm
61.4
KB
-rwxr-xr-x
rmail
262
B
-rwxr-xr-x
rmail.postfix
262
B
-rwxr-xr-x
rmdir
44.46
KB
-rwxr-xr-x
rnano
201.08
KB
-rwxr-xr-x
rpcgen
90.45
KB
-rwxr-xr-x
rpm
15.75
KB
-rwxr-xr-x
rpm2cpio
11.16
KB
-rwxr-xr-x
rpmdb
11.73
KB
-rwxr-xr-x
rpmgraph
15.63
KB
-rwxr-xr-x
rpmkeys
11.73
KB
-rwxr-xr-x
rpmquery
15.75
KB
-rwxr-xr-x
rpmverify
15.75
KB
-rwxr-xr-x
rrdcached
52.98
KB
-rwxr-xr-x
rrdcgi
27.81
KB
-rwxr-xr-x
rrdcreate
89.35
KB
-rwxr-xr-x
rrdinfo
89.35
KB
-rwxr-xr-x
rrdtool
27.49
KB
-rwxr-xr-x
rrdupdate
89.35
KB
-rwxr-xr-x
rsync
488.38
KB
-rwxr-xr-x
rsyslog-recover-qi.pl
5.96
KB
-rwxr-xr-x
run-parts
2.04
KB
-rwxr-xr-x
run-with-aspell
85
B
-rwxr-xr-x
runcon
32.47
KB
-rwxr-xr-x
rvi
906.45
KB
-rwxr-xr-x
rview
906.45
KB
-rwxr-xr-x
s2p
52.08
KB
-rwxr-xr-x
sa-awl
4.91
KB
-rwxr-xr-x
sa-check_spamd
14.45
KB
-rwxr-xr-x
sa-compile
21.62
KB
-rwxr-xr-x
sa-learn
44.5
KB
-rwxr-xr-x
sa-update
68.06
KB
-rwxr-xr-x
sadf
168.45
KB
-rwxr-xr-x
sandbox
17.52
KB
-rwxr-xr-x
sar
95.38
KB
-rwxr-xr-x
sasl2-sample-client
19.27
KB
-rwxr-xr-x
sasl2-sample-server
19.1
KB
-rwxr-xr-x
scp
89.23
KB
-rwxr-xr-x
screen
464.1
KB
-rwxr-sr-x
script
19.61
KB
-rwxr-xr-x
scriptreplay
15.29
KB
-rwxr-xr-x
scsi-rescan
33.81
KB
-rwxr-xr-x
scsi_logging_level
7.72
KB
-rwxr-xr-x
scsi_mandat
3.55
KB
-rwxr-xr-x
scsi_readcap
1.3
KB
-rwxr-xr-x
scsi_ready
1.09
KB
-rwxr-xr-x
scsi_satl
3.76
KB
-rwxr-xr-x
scsi_start
1.25
KB
-rwxr-xr-x
scsi_stop
1.44
KB
-rwxr-xr-x
scsi_temperature
936
B
-rwxr-xr-x
sdiff
48.41
KB
-rwxr-xr-x
secon
24.06
KB
-rwxr-xr-x
sed
74.29
KB
-rwxr-xr-x
sedismod
249.42
KB
-rwxr-xr-x
sedispol
176.32
KB
-rwxr-xr-x
semodule_package
15.3
KB
-rwxr-xr-x
seq
48.48
KB
-rwxr-xr-x
sessreg
11.24
KB
-rwxr-xr-x
setarch
15.27
KB
-rwxr-xr-x
setfacl
36.73
KB
-rwxr-xr-x
setfont
40.38
KB
-rwxr-xr-x
setkeycodes
11.16
KB
-rwxr-xr-x
setleds
11.16
KB
-rwxr-xr-x
setmetamode
11.21
KB
-rwxr-xr-x
setpriv
36.06
KB
-rwxr-xr-x
setsid
11.23
KB
-rwxr-xr-x
setterm
27.48
KB
-rwxr-xr-x
setup-nsssysinit
1.5
KB
-rwxr-xr-x
setup-nsssysinit.sh
1.5
KB
-rwxr-xr-x
setvtrgb
11.34
KB
-rwxr-xr-x
sexp-conv
23.63
KB
-rwxr-xr-x
sftp
142.01
KB
-rwxr-xr-x
sfv-hash
71.57
KB
-rwxr-xr-x
sg
40.95
KB
-rwsr-xr-x
sg_compare_and_write
15.82
KB
-rwxr-xr-x
sg_copy_results
20.02
KB
-rwxr-xr-x
sg_dd
43.63
KB
-rwxr-xr-x
sg_decode_sense
15.49
KB
-rwxr-xr-x
sg_emc_trespass
11.09
KB
-rwxr-xr-x
sg_format
24.05
KB
-rwxr-xr-x
sg_get_config
28.22
KB
-rwxr-xr-x
sg_get_lba_status
15.5
KB
-rwxr-xr-x
sg_ident
15.46
KB
-rwxr-xr-x
sg_inq
83.68
KB
-rwxr-xr-x
sg_logs
92.48
KB
-rwxr-xr-x
sg_luns
19.65
KB
-rwxr-xr-x
sg_map
15.23
KB
-rwxr-xr-x
sg_map26
23.77
KB
-rwxr-xr-x
sg_modes
29.3
KB
-rwxr-xr-x
sg_opcodes
23.88
KB
-rwxr-xr-x
sg_persist
28.34
KB
-rwxr-xr-x
sg_prevent
11.29
KB
-rwxr-xr-x
sg_raw
19.78
KB
-rwxr-xr-x
sg_rbuf
19.66
KB
-rwxr-xr-x
sg_rdac
15.13
KB
-rwxr-xr-x
sg_read
23.33
KB
-rwxr-xr-x
sg_read_block_limits
11.31
KB
-rwxr-xr-x
sg_read_buffer
15.53
KB
-rwxr-xr-x
sg_read_long
15.55
KB
-rwxr-xr-x
sg_readcap
19.66
KB
-rwxr-xr-x
sg_reassign
15.54
KB
-rwxr-xr-x
sg_referrals
15.48
KB
-rwxr-xr-x
sg_requests
15.58
KB
-rwxr-xr-x
sg_reset
11.46
KB
-rwxr-xr-x
sg_rmsn
11.32
KB
-rwxr-xr-x
sg_rtpg
15.39
KB
-rwxr-xr-x
sg_safte
19.59
KB
-rwxr-xr-x
sg_sanitize
19.88
KB
-rwxr-xr-x
sg_sat_identify
15.55
KB
-rwxr-xr-x
sg_sat_phy_event
15.87
KB
-rwxr-xr-x
sg_sat_set_features
15.41
KB
-rwxr-xr-x
sg_scan
15.34
KB
-rwxr-xr-x
sg_senddiag
20.02
KB
-rwxr-xr-x
sg_ses
67.55
KB
-rwxr-xr-x
sg_start
19.7
KB
-rwxr-xr-x
sg_stpg
19.61
KB
-rwxr-xr-x
sg_sync
15.52
KB
-rwxr-xr-x
sg_test_rwbuf
15.6
KB
-rwxr-xr-x
sg_turs
15.48
KB
-rwxr-xr-x
sg_unmap
15.5
KB
-rwxr-xr-x
sg_verify
15.7
KB
-rwxr-xr-x
sg_vpd
77.67
KB
-rwxr-xr-x
sg_wr_mode
19.55
KB
-rwxr-xr-x
sg_write_buffer
15.66
KB
-rwxr-xr-x
sg_write_long
15.55
KB
-rwxr-xr-x
sg_write_same
19.9
KB
-rwxr-xr-x
sg_xcopy
35.61
KB
-rwxr-xr-x
sginfo
65.8
KB
-rwxr-xr-x
sgm_dd
31.52
KB
-rwxr-xr-x
sgp_dd
35.83
KB
-rwxr-xr-x
sh
941.93
KB
-rwxr-xr-x
sha1sum
36.57
KB
-rwxr-xr-x
sha224sum
40.63
KB
-rwxr-xr-x
sha256sum
40.63
KB
-rwxr-xr-x
sha384sum
40.65
KB
-rwxr-xr-x
sha512sum
40.65
KB
-rwxr-xr-x
shasum
8.4
KB
-rwxr-xr-x
show-changed-rco
10.13
KB
-rwxr-xr-x
show-installed
16.18
KB
-rwxr-xr-x
showconsolefont
15.47
KB
-rwxr-xr-x
showkey
15.23
KB
-rwxr-xr-x
showrgb
7.08
KB
-rwxr-xr-x
shred
52.94
KB
-rwxr-xr-x
shuf
49.13
KB
-rwxr-xr-x
sieve-dump
23.05
KB
-rwxr-xr-x
sieve-filter
27.06
KB
-rwxr-xr-x
sieve-test
27.13
KB
-rwxr-xr-x
sievec
23.06
KB
-rwxr-xr-x
signver
102.6
KB
-rwxr-xr-x
sigtool
207.89
KB
-rwxr-xr-x
sim_client
14.97
KB
-rwxr-xr-x
size
32.35
KB
-rwxr-xr-x
skill
23.62
KB
-rwxr-xr-x
slabinfo
34.96
KB
-rwxr-xr-x
slabtop
19.52
KB
-rwxr-xr-x
sleep
32.35
KB
-rwxr-xr-x
slogin
756.4
KB
-rwxr-xr-x
snice
23.62
KB
-rwxr-xr-x
snmpconf
25.52
KB
-rwxr-xr-x
socat
380.43
KB
-rwxr-xr-x
soelim
32.59
KB
-rwxr-xr-x
sort
114.94
KB
-rwxr-xr-x
sotruss
4.24
KB
-rwxr-xr-x
spamassassin
29.22
KB
-rwxr-xr-x
spamc
45.19
KB
-rwxr-xr-x
spamd
125.25
KB
-rwxr-xr-x
spell
122
B
-rwxr-xr-x
spfquery
4.49
KB
-rwxr-xr-x
splain
18.03
KB
-rwxr-xr-x
split
69.47
KB
-rwxr-xr-x
sprof
22.1
KB
-rwxr-xr-x
sqlite3
54.95
KB
-rwxr-xr-x
ssh
756.4
KB
-rwxr-xr-x
ssh-add
352.46
KB
-rwxr-xr-x
ssh-agent
373.25
KB
---x--s--x
ssh-copy-id
10.22
KB
-rwxr-xr-x
ssh-keygen
409.38
KB
-rwxr-xr-x
ssh-keyscan
430.7
KB
-rwxr-xr-x
sshpass
15.37
KB
-rwxr-xr-x
ssltap
118.41
KB
-rwxr-xr-x
stat
77.19
KB
-rwxr-xr-x
statist
11.18
KB
-rwxr-xr-x
stdbuf
64.88
KB
-rwxr-xr-x
stream
7.04
KB
-rwxr-xr-x
strings
32.55
KB
-rwxr-xr-x
strip
227.34
KB
-rwxr-xr-x
stty
68.61
KB
-rwxr-xr-x
su
31.38
KB
-rwsr-xr-x
sudo
147.88
KB
---s--x--x
sudoedit
147.88
KB
---s--x--x
sudoreplay
56.11
KB
---x--x--x
sum
36.55
KB
-rwxr-xr-x
svn
232.45
KB
-rwxr-xr-x
svnadmin
67.4
KB
-rwxr-xr-x
svndumpfilter
35.32
KB
-rwxr-xr-x
svnlook
67.45
KB
-rwxr-xr-x
svnrdump
51.54
KB
-rwxr-xr-x
svnserve
83.95
KB
-rwxr-xr-x
svnsync
51.59
KB
-rwxr-xr-x
svnversion
15.15
KB
-rwxr-xr-x
sxpm
19.83
KB
-rwxr-xr-x
sync
28.33
KB
-rwxr-xr-x
systemctl
704.8
KB
-rwxr-xr-x
systemd-analyze
1.49
MB
-rwxr-xr-x
systemd-ask-password
60.38
KB
-rwxr-xr-x
systemd-cat
39.98
KB
-rwxr-xr-x
systemd-cgls
326.29
KB
-rwxr-xr-x
systemd-cgtop
85.09
KB
-rwxr-xr-x
systemd-coredumpctl
154.52
KB
-rwxr-xr-x
systemd-delta
76.84
KB
-rwxr-xr-x
systemd-detect-virt
39.97
KB
-rwxr-xr-x
systemd-escape
48.2
KB
-rwxr-xr-x
systemd-firstboot
101.52
KB
-rwxr-xr-x
systemd-hwdb
85.31
KB
-rwxr-xr-x
systemd-inhibit
309.83
KB
-rwxr-xr-x
systemd-loginctl
489.62
KB
-rwxr-xr-x
systemd-machine-id-setup
52.23
KB
-rwxr-xr-x
systemd-notify
48.13
KB
-rwxr-xr-x
systemd-nspawn
545.88
KB
-rwxr-xr-x
systemd-path
52.16
KB
-rwxr-xr-x
systemd-run
387.05
KB
-rwxr-xr-x
systemd-stdio-bridge
305.77
KB
-rwxr-xr-x
systemd-sysv-convert
3.89
KB
-rwxr-xr-x
systemd-tmpfiles
146.13
KB
-rwxr-xr-x
systemd-tty-ask-password-agent
84.75
KB
-rwxr-xr-x
tabs
15.31
KB
-rwxr-xr-x
tac
32.48
KB
-rwxr-xr-x
tail
65.25
KB
-rwxr-xr-x
tailf
23.88
KB
-rwxr-xr-x
tapestat
52.55
KB
-rwxr-xr-x
tar
338.02
KB
-rwxr-xr-x
taskset
32.22
KB
-rwxr-xr-x
tbl
115.96
KB
-rwxr-xr-x
tcamgr
23.47
KB
-rwxr-xr-x
tcamttest
19.37
KB
-rwxr-xr-x
tcatest
52.78
KB
-rwxr-xr-x
tcbmgr
27.66
KB
-rwxr-xr-x
tcbmttest
47.96
KB
-rwxr-xr-x
tcbtest
64.47
KB
-rwxr-xr-x
tcfmgr
19.5
KB
-rwxr-xr-x
tcfmttest
31.79
KB
-rwxr-xr-x
tcftest
43.86
KB
-rwxr-xr-x
tchmgr
23.52
KB
-rwxr-xr-x
tchmttest
43.87
KB
-rwxr-xr-x
tchtest
52.29
KB
-rwxr-xr-x
tctmgr
31.82
KB
-rwxr-xr-x
tctmttest
39.72
KB
-rwxr-xr-x
tcttest
51.9
KB
-rwxr-xr-x
tcucodec
31.75
KB
-rwxr-xr-x
tcumttest
19.52
KB
-rwxr-xr-x
tcutest
65.61
KB
-rwxr-xr-x
teamd
155.09
KB
-rwxr-xr-x
teamdctl
28.98
KB
-rwxr-xr-x
teamnl
19.09
KB
-rwxr-xr-x
tee
32.38
KB
-rwxr-xr-x
test
36.46
KB
-rwxr-xr-x
testgdbm
29.77
KB
-rwxr-xr-x
tic
64.26
KB
-rwxr-xr-x
tiger-hash
71.57
KB
-rwxr-xr-x
timedatectl
330.22
KB
-rwxr-xr-x
timeout
53.31
KB
-rwxr-xr-x
tload
15.38
KB
-rwxr-xr-x
tmon
31.11
KB
-rwxr-xr-x
toe
15.43
KB
-rwxr-xr-x
top
104.38
KB
-rwxr-xr-x
touch
61.02
KB
-rwxr-xr-x
tput
15.41
KB
-rwxr-xr-x
tr
44.61
KB
-rwxr-xr-x
tracepath
15.05
KB
-rwxr-xr-x
tracepath6
15.05
KB
-rwxr-xr-x
troff
512.96
KB
-rwxr-xr-x
true
28.26
KB
-rwxr-xr-x
truncate
52.68
KB
-rwxr-xr-x
trust
179.08
KB
-rwxr-xr-x
tset
19.6
KB
-rwxr-xr-x
tsort
36.47
KB
-rwxr-xr-x
tth-hash
71.57
KB
-rwxr-xr-x
tty
28.29
KB
-rwxr-xr-x
turbostat
113.15
KB
-rwxr-xr-x
type99
4.57
KB
-rwxr-xr-x
tzselect
7.17
KB
-rwxr-xr-x
uconv
52.57
KB
-rwxr-xr-x
ucs2any
19.47
KB
-rwxr-xr-x
udevadm
414.27
KB
-rwxr-xr-x
ul
19.47
KB
-rwxr-xr-x
umask
29
B
-rwxr-xr-x
umount
31.23
KB
-rwsr-xr-x
unalias
31
B
-rwxr-xr-x
uname
32.3
KB
-rwxr-xr-x
unarj
74
B
-rwxr-xr-x
unexpand
32.45
KB
-rwxr-xr-x
unfreeze
23.82
KB
-rwxr-xr-x
unicode_start
2.5
KB
-rwxr-xr-x
unicode_stop
363
B
-rwxr-xr-x
uniq
44.71
KB
-rwxr-xr-x
unlink
28.3
KB
-rwxr-xr-x
unlz4
105.84
KB
-rwxr-xr-x
unshare
15.45
KB
-rwxr-xr-x
unxz
73.52
KB
-rwxr-xr-x
unzip
185.16
KB
-rwxr-xr-x
unzipsfx
88.66
KB
-rwxr-xr-x
unzoo
27.67
KB
-rwxr-xr-x
update-ca-trust
1.03
KB
-rwxr-xr-x
update-mime-database
52.82
KB
-rwxr-xr-x
updatedb
47.65
KB
-rwxr-xr-x
uptime
11.22
KB
-rwxr-xr-x
urlgrabber
12.17
KB
-rwxr-xr-x
users
32.42
KB
-rwxr-xr-x
usleep
10.95
KB
-rwxr-xr-x
usx2yloader
15.41
KB
-rwxr-xr-x
utmpdump
15.45
KB
-rwxr-xr-x
uuclient
14.97
KB
-rwxr-xr-x
uuidgen
11.21
KB
-rwxr-xr-x
vacuumdb
57.35
KB
-rwxr-xr-x
varnishadm
124.63
KB
-rwxr-xr-x
varnishhist
55.02
KB
-rwxr-xr-x
varnishlog
30.09
KB
-rwxr-xr-x
varnishncsa
98.75
KB
-rwxr-xr-x
varnishstat
88.88
KB
-rwxr-xr-x
varnishtest
1.19
MB
-rwxr-xr-x
varnishtop
61.65
KB
-rwxr-xr-x
vdir
114.85
KB
-rwxr-xr-x
verifytree
10.79
KB
-rwxr-xr-x
vi
906.45
KB
-rwxr-xr-x
view
906.45
KB
-rwxr-xr-x
vlock
15.73
KB
-rwxr-xr-x
vmstat
31.48
KB
-rwxr-xr-x
vxloader
15.38
KB
-rwxr-xr-x
w
19.45
KB
-rwxr-xr-x
wait
28
B
-rwxr-xr-x
wall
14.98
KB
-r-xr-sr-x
watch
24.14
KB
-rwxr-xr-x
watchgnupg
15.35
KB
-rwxr-xr-x
wc
40.67
KB
-rwxr-xr-x
wdctl
40.7
KB
-rwxr-xr-x
wget
408.96
KB
-rwxr-xr-x
whatis
45.49
KB
-rwxr-xr-x
whereis
20.2
KB
-rwxr-xr-x
which
23.77
KB
-rwxr-xr-x
whiptail
27.84
KB
-rwxr-xr-x
whirlpool-hash
71.57
KB
-rwxr-xr-x
who
48.7
KB
-rwxr-xr-x
whoami
28.3
KB
-rwxr-xr-x
word-list-compress
11.03
KB
-rwxr-xr-x
write
19.09
KB
-rwxr-sr-x
wsrep_sst_backup
2.95
KB
-rwxr-xr-x
wsrep_sst_common
54.08
KB
-rw-r--r--
wsrep_sst_mariabackup
50.86
KB
-rwxr-xr-x
wsrep_sst_mysqldump
7.7
KB
-rwxr-xr-x
wsrep_sst_rsync
32.2
KB
-rwxr-xr-x
wsrep_sst_rsync_wan
32.2
KB
-rwxr-xr-x
x86_64
15.27
KB
-rwxr-xr-x
x86_64-redhat-linux-c++
754.59
KB
-rwxr-xr-x
x86_64-redhat-linux-g++
754.59
KB
-rwxr-xr-x
x86_64-redhat-linux-gcc
750.59
KB
-rwxr-xr-x
x86_energy_perf_policy
10.23
KB
-rwxr-xr-x
xargs
60.91
KB
-rwxr-xr-x
xgamma
11.15
KB
-rwxr-xr-x
xgettext
265.35
KB
-rwxr-xr-x
xhost
15.38
KB
-rwxr-xr-x
xinput
52.81
KB
-rwxr-xr-x
xkill
15.27
KB
-rwxr-xr-x
xml2-config
1.68
KB
-rwxr-xr-x
xmlcatalog
15.3
KB
-rwxr-xr-x
xmllint
61.94
KB
-rwxr-xr-x
xmlwf
24
KB
-rwxr-xr-x
xmodmap
32.28
KB
-rwxr-xr-x
xorg-x11-fonts-update-dirs
1.29
KB
-rwxr--r--
xrandr
60.06
KB
-rwxr-xr-x
xrdb
27.78
KB
-rwxr-xr-x
xrefresh
11.16
KB
-rwxr-xr-x
xset
31.72
KB
-rwxr-xr-x
xsetmode
11.1
KB
-rwxr-xr-x
xsetpointer
11.13
KB
-rwxr-xr-x
xsetroot
19.38
KB
-rwxr-xr-x
xslt-config
2.36
KB
-rwxr-xr-x
xsltproc
23.51
KB
-rwxr-xr-x
xstdcmap
15.77
KB
-rwxr-xr-x
xsubpp
4.45
KB
-rwxr-xr-x
xz
73.52
KB
-rwxr-xr-x
xzcat
73.52
KB
-rwxr-xr-x
xzcmp
6.48
KB
-rwxr-xr-x
xzdec
11.21
KB
-rwxr-xr-x
xzdiff
6.48
KB
-rwxr-xr-x
xzegrep
5.76
KB
-rwxr-xr-x
xzfgrep
5.76
KB
-rwxr-xr-x
xzgrep
5.76
KB
-rwxr-xr-x
xzless
1.76
KB
-rwxr-xr-x
xzmore
2.11
KB
-rwxr-xr-x
yes
28.3
KB
-rwxr-xr-x
ypdomainname
15.41
KB
-rwxr-xr-x
yum
801
B
-rwxr-xr-x
yum-builddep
9.95
KB
-rwxr-xr-x
yum-config-manager
9.35
KB
-rwxr-xr-x
yum-debug-dump
8.34
KB
-rwxr-xr-x
yum-debug-restore
7.72
KB
-rwxr-xr-x
yum-groups-manager
10.77
KB
-rwxr-xr-x
yumdownloader
10.85
KB
-rwxr-xr-x
zcat
1.9
KB
-rwxr-xr-x
zcmp
1.72
KB
-rwxr-xr-x
zdiff
5.63
KB
-rwxr-xr-x
zegrep
123
B
-rwxr-xr-x
zfgrep
123
B
-rwxr-xr-x
zforce
2.09
KB
-rwxr-xr-x
zgrep
5.98
KB
-rwxr-xr-x
zip
210.78
KB
-rwxr-xr-x
zipcloak
98.1
KB
-rwxr-xr-x
zipdetails
47.32
KB
-rwxr-xr-x
zipgrep
2.88
KB
-rwxr-xr-x
zipinfo
185.16
KB
-rwxr-xr-x
zipnote
93.73
KB
-rwxr-xr-x
zipsplit
97.75
KB
-rwxr-xr-x
zless
1.99
KB
-rwxr-xr-x
zmore
2.79
KB
-rwxr-xr-x
znew
5.22
KB
-rwxr-xr-x
zsoelim
32.59
KB
-rwxr-xr-x
Delete
Unzip
Zip
${this.title}
Close
Code Editor : pt-variable-advisor
#!/usr/bin/env perl # This program is part of Percona Toolkit: http://www.percona.com/software/ # See "COPYRIGHT, LICENSE, AND WARRANTY" at the end of this file for legal # notices and disclaimers. use strict; use warnings FATAL => 'all'; # This tool is "fat-packed": most of its dependent modules are embedded # in this file. Setting %INC to this file for each module makes Perl aware # of this so it will not try to load the module from @INC. See the tool's # documentation for a full list of dependencies. BEGIN { $INC{$_} = __FILE__ for map { (my $pkg = "$_.pm") =~ s!::!/!g; $pkg } (qw( Percona::Toolkit OptionParser Lmo::Utils Lmo::Meta Lmo::Object Lmo::Types Lmo DSNParser VersionParser Daemon PodParser TextResultSetParser Advisor AdvisorRules VariableAdvisorRules HTTP::Micro VersionCheck )); } # ########################################################################### # Percona::Toolkit package # This package is a copy without comments from the original. The original # with comments and its test file can be found in the Bazaar repository at, # lib/Percona/Toolkit.pm # t/lib/Percona/Toolkit.t # See https://launchpad.net/percona-toolkit for more information. # ########################################################################### { package Percona::Toolkit; our $VERSION = '2.2.15'; use strict; use warnings FATAL => 'all'; use English qw(-no_match_vars); use constant PTDEBUG => $ENV{PTDEBUG} || 0; use Carp qw(carp cluck); use Data::Dumper qw(); require Exporter; our @ISA = qw(Exporter); our @EXPORT_OK = qw( have_required_args Dumper _d ); sub have_required_args { my ($args, @required_args) = @_; my $have_required_args = 1; foreach my $arg ( @required_args ) { if ( !defined $args->{$arg} ) { $have_required_args = 0; carp "Argument $arg is not defined"; } } cluck unless $have_required_args; # print backtrace return $have_required_args; } sub Dumper { local $Data::Dumper::Indent = 1; local $Data::Dumper::Sortkeys = 1; local $Data::Dumper::Quotekeys = 0; Data::Dumper::Dumper(@_); } sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } map { defined $_ ? $_ : 'undef' } @_; print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; } 1; } # ########################################################################### # End Percona::Toolkit package # ########################################################################### # ########################################################################### # OptionParser package # This package is a copy without comments from the original. The original # with comments and its test file can be found in the Bazaar repository at, # lib/OptionParser.pm # t/lib/OptionParser.t # See https://launchpad.net/percona-toolkit for more information. # ########################################################################### { package OptionParser; use strict; use warnings FATAL => 'all'; use English qw(-no_match_vars); use constant PTDEBUG => $ENV{PTDEBUG} || 0; use List::Util qw(max); use Getopt::Long; use Data::Dumper; my $POD_link_re = '[LC]<"?([^">]+)"?>'; sub new { my ( $class, %args ) = @_; my @required_args = qw(); foreach my $arg ( @required_args ) { die "I need a $arg argument" unless $args{$arg}; } my ($program_name) = $PROGRAM_NAME =~ m/([.A-Za-z-]+)$/; $program_name ||= $PROGRAM_NAME; my $home = $ENV{HOME} || $ENV{HOMEPATH} || $ENV{USERPROFILE} || '.'; my %attributes = ( 'type' => 1, 'short form' => 1, 'group' => 1, 'default' => 1, 'cumulative' => 1, 'negatable' => 1, ); my $self = { head1 => 'OPTIONS', # These args are used internally skip_rules => 0, # to instantiate another Option- item => '--(.*)', # Parser obj that parses the attributes => \%attributes, # DSN OPTIONS section. Tools parse_attributes => \&_parse_attribs, # don't tinker with these args. %args, strict => 1, # disabled by a special rule program_name => $program_name, opts => {}, got_opts => 0, short_opts => {}, defaults => {}, groups => {}, allowed_groups => {}, errors => [], rules => [], # desc of rules for --help mutex => [], # rule: opts are mutually exclusive atleast1 => [], # rule: at least one opt is required disables => {}, # rule: opt disables other opts defaults_to => {}, # rule: opt defaults to value of other opt DSNParser => undef, default_files => [ "/etc/percona-toolkit/percona-toolkit.conf", "/etc/percona-toolkit/$program_name.conf", "$home/.percona-toolkit.conf", "$home/.$program_name.conf", ], types => { string => 's', # standard Getopt type int => 'i', # standard Getopt type float => 'f', # standard Getopt type Hash => 'H', # hash, formed from a comma-separated list hash => 'h', # hash as above, but only if a value is given Array => 'A', # array, similar to Hash array => 'a', # array, similar to hash DSN => 'd', # DSN size => 'z', # size with kMG suffix (powers of 2^10) time => 'm', # time, with an optional suffix of s/h/m/d }, }; return bless $self, $class; } sub get_specs { my ( $self, $file ) = @_; $file ||= $self->{file} || __FILE__; my @specs = $self->_pod_to_specs($file); $self->_parse_specs(@specs); open my $fh, "<", $file or die "Cannot open $file: $OS_ERROR"; my $contents = do { local $/ = undef; <$fh> }; close $fh; if ( $contents =~ m/^=head1 DSN OPTIONS/m ) { PTDEBUG && _d('Parsing DSN OPTIONS'); my $dsn_attribs = { dsn => 1, copy => 1, }; my $parse_dsn_attribs = sub { my ( $self, $option, $attribs ) = @_; map { my $val = $attribs->{$_}; if ( $val ) { $val = $val eq 'yes' ? 1 : $val eq 'no' ? 0 : $val; $attribs->{$_} = $val; } } keys %$attribs; return { key => $option, %$attribs, }; }; my $dsn_o = new OptionParser( description => 'DSN OPTIONS', head1 => 'DSN OPTIONS', dsn => 0, # XXX don't infinitely recurse! item => '\* (.)', # key opts are a single character skip_rules => 1, # no rules before opts attributes => $dsn_attribs, parse_attributes => $parse_dsn_attribs, ); my @dsn_opts = map { my $opts = { key => $_->{spec}->{key}, dsn => $_->{spec}->{dsn}, copy => $_->{spec}->{copy}, desc => $_->{desc}, }; $opts; } $dsn_o->_pod_to_specs($file); $self->{DSNParser} = DSNParser->new(opts => \@dsn_opts); } if ( $contents =~ m/^=head1 VERSION\n\n^(.+)$/m ) { $self->{version} = $1; PTDEBUG && _d($self->{version}); } return; } sub DSNParser { my ( $self ) = @_; return $self->{DSNParser}; }; sub get_defaults_files { my ( $self ) = @_; return @{$self->{default_files}}; } sub _pod_to_specs { my ( $self, $file ) = @_; $file ||= $self->{file} || __FILE__; open my $fh, '<', $file or die "Cannot open $file: $OS_ERROR"; my @specs = (); my @rules = (); my $para; local $INPUT_RECORD_SEPARATOR = ''; while ( $para = <$fh> ) { next unless $para =~ m/^=head1 $self->{head1}/; last; } while ( $para = <$fh> ) { last if $para =~ m/^=over/; next if $self->{skip_rules}; chomp $para; $para =~ s/\s+/ /g; $para =~ s/$POD_link_re/$1/go; PTDEBUG && _d('Option rule:', $para); push @rules, $para; } die "POD has no $self->{head1} section" unless $para; do { if ( my ($option) = $para =~ m/^=item $self->{item}/ ) { chomp $para; PTDEBUG && _d($para); my %attribs; $para = <$fh>; # read next paragraph, possibly attributes if ( $para =~ m/: / ) { # attributes $para =~ s/\s+\Z//g; %attribs = map { my ( $attrib, $val) = split(/: /, $_); die "Unrecognized attribute for --$option: $attrib" unless $self->{attributes}->{$attrib}; ($attrib, $val); } split(/; /, $para); if ( $attribs{'short form'} ) { $attribs{'short form'} =~ s/-//; } $para = <$fh>; # read next paragraph, probably short help desc } else { PTDEBUG && _d('Option has no attributes'); } $para =~ s/\s+\Z//g; $para =~ s/\s+/ /g; $para =~ s/$POD_link_re/$1/go; $para =~ s/\.(?:\n.*| [A-Z].*|\Z)//s; PTDEBUG && _d('Short help:', $para); die "No description after option spec $option" if $para =~ m/^=item/; if ( my ($base_option) = $option =~ m/^\[no\](.*)/ ) { $option = $base_option; $attribs{'negatable'} = 1; } push @specs, { spec => $self->{parse_attributes}->($self, $option, \%attribs), desc => $para . (defined $attribs{default} ? " (default $attribs{default})" : ''), group => ($attribs{'group'} ? $attribs{'group'} : 'default'), }; } while ( $para = <$fh> ) { last unless $para; if ( $para =~ m/^=head1/ ) { $para = undef; # Can't 'last' out of a do {} block. last; } last if $para =~ m/^=item /; } } while ( $para ); die "No valid specs in $self->{head1}" unless @specs; close $fh; return @specs, @rules; } sub _parse_specs { my ( $self, @specs ) = @_; my %disables; # special rule that requires deferred checking foreach my $opt ( @specs ) { if ( ref $opt ) { # It's an option spec, not a rule. PTDEBUG && _d('Parsing opt spec:', map { ($_, '=>', $opt->{$_}) } keys %$opt); my ( $long, $short ) = $opt->{spec} =~ m/^([\w-]+)(?:\|([^!+=]*))?/; if ( !$long ) { die "Cannot parse long option from spec $opt->{spec}"; } $opt->{long} = $long; die "Duplicate long option --$long" if exists $self->{opts}->{$long}; $self->{opts}->{$long} = $opt; if ( length $long == 1 ) { PTDEBUG && _d('Long opt', $long, 'looks like short opt'); $self->{short_opts}->{$long} = $long; } if ( $short ) { die "Duplicate short option -$short" if exists $self->{short_opts}->{$short}; $self->{short_opts}->{$short} = $long; $opt->{short} = $short; } else { $opt->{short} = undef; } $opt->{is_negatable} = $opt->{spec} =~ m/!/ ? 1 : 0; $opt->{is_cumulative} = $opt->{spec} =~ m/\+/ ? 1 : 0; $opt->{is_required} = $opt->{desc} =~ m/required/ ? 1 : 0; $opt->{group} ||= 'default'; $self->{groups}->{ $opt->{group} }->{$long} = 1; $opt->{value} = undef; $opt->{got} = 0; my ( $type ) = $opt->{spec} =~ m/=(.)/; $opt->{type} = $type; PTDEBUG && _d($long, 'type:', $type); $opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ ); if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) { $self->{defaults}->{$long} = defined $def ? $def : 1; PTDEBUG && _d($long, 'default:', $def); } if ( $long eq 'config' ) { $self->{defaults}->{$long} = join(',', $self->get_defaults_files()); } if ( (my ($dis) = $opt->{desc} =~ m/(disables .*)/) ) { $disables{$long} = $dis; PTDEBUG && _d('Deferring check of disables rule for', $opt, $dis); } $self->{opts}->{$long} = $opt; } else { # It's an option rule, not a spec. PTDEBUG && _d('Parsing rule:', $opt); push @{$self->{rules}}, $opt; my @participants = $self->_get_participants($opt); my $rule_ok = 0; if ( $opt =~ m/mutually exclusive|one and only one/ ) { $rule_ok = 1; push @{$self->{mutex}}, \@participants; PTDEBUG && _d(@participants, 'are mutually exclusive'); } if ( $opt =~ m/at least one|one and only one/ ) { $rule_ok = 1; push @{$self->{atleast1}}, \@participants; PTDEBUG && _d(@participants, 'require at least one'); } if ( $opt =~ m/default to/ ) { $rule_ok = 1; $self->{defaults_to}->{$participants[0]} = $participants[1]; PTDEBUG && _d($participants[0], 'defaults to', $participants[1]); } if ( $opt =~ m/restricted to option groups/ ) { $rule_ok = 1; my ($groups) = $opt =~ m/groups ([\w\s\,]+)/; my @groups = split(',', $groups); %{$self->{allowed_groups}->{$participants[0]}} = map { s/\s+//; $_ => 1; } @groups; } if( $opt =~ m/accepts additional command-line arguments/ ) { $rule_ok = 1; $self->{strict} = 0; PTDEBUG && _d("Strict mode disabled by rule"); } die "Unrecognized option rule: $opt" unless $rule_ok; } } foreach my $long ( keys %disables ) { my @participants = $self->_get_participants($disables{$long}); $self->{disables}->{$long} = \@participants; PTDEBUG && _d('Option', $long, 'disables', @participants); } return; } sub _get_participants { my ( $self, $str ) = @_; my @participants; foreach my $long ( $str =~ m/--(?:\[no\])?([\w-]+)/g ) { die "Option --$long does not exist while processing rule $str" unless exists $self->{opts}->{$long}; push @participants, $long; } PTDEBUG && _d('Participants for', $str, ':', @participants); return @participants; } sub opts { my ( $self ) = @_; my %opts = %{$self->{opts}}; return %opts; } sub short_opts { my ( $self ) = @_; my %short_opts = %{$self->{short_opts}}; return %short_opts; } sub set_defaults { my ( $self, %defaults ) = @_; $self->{defaults} = {}; foreach my $long ( keys %defaults ) { die "Cannot set default for nonexistent option $long" unless exists $self->{opts}->{$long}; $self->{defaults}->{$long} = $defaults{$long}; PTDEBUG && _d('Default val for', $long, ':', $defaults{$long}); } return; } sub get_defaults { my ( $self ) = @_; return $self->{defaults}; } sub get_groups { my ( $self ) = @_; return $self->{groups}; } sub _set_option { my ( $self, $opt, $val ) = @_; my $long = exists $self->{opts}->{$opt} ? $opt : exists $self->{short_opts}->{$opt} ? $self->{short_opts}->{$opt} : die "Getopt::Long gave a nonexistent option: $opt"; $opt = $self->{opts}->{$long}; if ( $opt->{is_cumulative} ) { $opt->{value}++; } elsif ( ($opt->{type} || '') eq 's' && $val =~ m/^--?(.+)/ ) { my $next_opt = $1; if ( exists $self->{opts}->{$next_opt} || exists $self->{short_opts}->{$next_opt} ) { $self->save_error("--$long requires a string value"); return; } else { $opt->{value} = $val; } } else { $opt->{value} = $val; } $opt->{got} = 1; PTDEBUG && _d('Got option', $long, '=', $val); } sub get_opts { my ( $self ) = @_; foreach my $long ( keys %{$self->{opts}} ) { $self->{opts}->{$long}->{got} = 0; $self->{opts}->{$long}->{value} = exists $self->{defaults}->{$long} ? $self->{defaults}->{$long} : $self->{opts}->{$long}->{is_cumulative} ? 0 : undef; } $self->{got_opts} = 0; $self->{errors} = []; if ( @ARGV && $ARGV[0] eq "--config" ) { shift @ARGV; $self->_set_option('config', shift @ARGV); } if ( $self->has('config') ) { my @extra_args; foreach my $filename ( split(',', $self->get('config')) ) { eval { push @extra_args, $self->_read_config_file($filename); }; if ( $EVAL_ERROR ) { if ( $self->got('config') ) { die $EVAL_ERROR; } elsif ( PTDEBUG ) { _d($EVAL_ERROR); } } } unshift @ARGV, @extra_args; } Getopt::Long::Configure('no_ignore_case', 'bundling'); GetOptions( map { $_->{spec} => sub { $self->_set_option(@_); } } grep { $_->{long} ne 'config' } # --config is handled specially above. values %{$self->{opts}} ) or $self->save_error('Error parsing options'); if ( exists $self->{opts}->{version} && $self->{opts}->{version}->{got} ) { if ( $self->{version} ) { print $self->{version}, "\n"; } else { print "Error parsing version. See the VERSION section of the tool's documentation.\n"; } exit 1; } if ( @ARGV && $self->{strict} ) { $self->save_error("Unrecognized command-line options @ARGV"); } foreach my $mutex ( @{$self->{mutex}} ) { my @set = grep { $self->{opts}->{$_}->{got} } @$mutex; if ( @set > 1 ) { my $err = join(', ', map { "--$self->{opts}->{$_}->{long}" } @{$mutex}[ 0 .. scalar(@$mutex) - 2] ) . ' and --'.$self->{opts}->{$mutex->[-1]}->{long} . ' are mutually exclusive.'; $self->save_error($err); } } foreach my $required ( @{$self->{atleast1}} ) { my @set = grep { $self->{opts}->{$_}->{got} } @$required; if ( @set == 0 ) { my $err = join(', ', map { "--$self->{opts}->{$_}->{long}" } @{$required}[ 0 .. scalar(@$required) - 2] ) .' or --'.$self->{opts}->{$required->[-1]}->{long}; $self->save_error("Specify at least one of $err"); } } $self->_check_opts( keys %{$self->{opts}} ); $self->{got_opts} = 1; return; } sub _check_opts { my ( $self, @long ) = @_; my $long_last = scalar @long; while ( @long ) { foreach my $i ( 0..$#long ) { my $long = $long[$i]; next unless $long; my $opt = $self->{opts}->{$long}; if ( $opt->{got} ) { if ( exists $self->{disables}->{$long} ) { my @disable_opts = @{$self->{disables}->{$long}}; map { $self->{opts}->{$_}->{value} = undef; } @disable_opts; PTDEBUG && _d('Unset options', @disable_opts, 'because', $long,'disables them'); } if ( exists $self->{allowed_groups}->{$long} ) { my @restricted_groups = grep { !exists $self->{allowed_groups}->{$long}->{$_} } keys %{$self->{groups}}; my @restricted_opts; foreach my $restricted_group ( @restricted_groups ) { RESTRICTED_OPT: foreach my $restricted_opt ( keys %{$self->{groups}->{$restricted_group}} ) { next RESTRICTED_OPT if $restricted_opt eq $long; push @restricted_opts, $restricted_opt if $self->{opts}->{$restricted_opt}->{got}; } } if ( @restricted_opts ) { my $err; if ( @restricted_opts == 1 ) { $err = "--$restricted_opts[0]"; } else { $err = join(', ', map { "--$self->{opts}->{$_}->{long}" } grep { $_ } @restricted_opts[0..scalar(@restricted_opts) - 2] ) . ' or --'.$self->{opts}->{$restricted_opts[-1]}->{long}; } $self->save_error("--$long is not allowed with $err"); } } } elsif ( $opt->{is_required} ) { $self->save_error("Required option --$long must be specified"); } $self->_validate_type($opt); if ( $opt->{parsed} ) { delete $long[$i]; } else { PTDEBUG && _d('Temporarily failed to parse', $long); } } die "Failed to parse options, possibly due to circular dependencies" if @long == $long_last; $long_last = @long; } return; } sub _validate_type { my ( $self, $opt ) = @_; return unless $opt; if ( !$opt->{type} ) { $opt->{parsed} = 1; return; } my $val = $opt->{value}; if ( $val && $opt->{type} eq 'm' ) { # type time PTDEBUG && _d('Parsing option', $opt->{long}, 'as a time value'); my ( $prefix, $num, $suffix ) = $val =~ m/([+-]?)(\d+)([a-z])?$/; if ( !$suffix ) { my ( $s ) = $opt->{desc} =~ m/\(suffix (.)\)/; $suffix = $s || 's'; PTDEBUG && _d('No suffix given; using', $suffix, 'for', $opt->{long}, '(value:', $val, ')'); } if ( $suffix =~ m/[smhd]/ ) { $val = $suffix eq 's' ? $num # Seconds : $suffix eq 'm' ? $num * 60 # Minutes : $suffix eq 'h' ? $num * 3600 # Hours : $num * 86400; # Days $opt->{value} = ($prefix || '') . $val; PTDEBUG && _d('Setting option', $opt->{long}, 'to', $val); } else { $self->save_error("Invalid time suffix for --$opt->{long}"); } } elsif ( $val && $opt->{type} eq 'd' ) { # type DSN PTDEBUG && _d('Parsing option', $opt->{long}, 'as a DSN'); my $prev = {}; my $from_key = $self->{defaults_to}->{ $opt->{long} }; if ( $from_key ) { PTDEBUG && _d($opt->{long}, 'DSN copies from', $from_key, 'DSN'); if ( $self->{opts}->{$from_key}->{parsed} ) { $prev = $self->{opts}->{$from_key}->{value}; } else { PTDEBUG && _d('Cannot parse', $opt->{long}, 'until', $from_key, 'parsed'); return; } } my $defaults = $self->{DSNParser}->parse_options($self); $opt->{value} = $self->{DSNParser}->parse($val, $prev, $defaults); } elsif ( $val && $opt->{type} eq 'z' ) { # type size PTDEBUG && _d('Parsing option', $opt->{long}, 'as a size value'); $self->_parse_size($opt, $val); } elsif ( $opt->{type} eq 'H' || (defined $val && $opt->{type} eq 'h') ) { $opt->{value} = { map { $_ => 1 } split(/(?<!\\),\s*/, ($val || '')) }; } elsif ( $opt->{type} eq 'A' || (defined $val && $opt->{type} eq 'a') ) { $opt->{value} = [ split(/(?<!\\),\s*/, ($val || '')) ]; } else { PTDEBUG && _d('Nothing to validate for option', $opt->{long}, 'type', $opt->{type}, 'value', $val); } $opt->{parsed} = 1; return; } sub get { my ( $self, $opt ) = @_; my $long = (length $opt == 1 ? $self->{short_opts}->{$opt} : $opt); die "Option $opt does not exist" unless $long && exists $self->{opts}->{$long}; return $self->{opts}->{$long}->{value}; } sub got { my ( $self, $opt ) = @_; my $long = (length $opt == 1 ? $self->{short_opts}->{$opt} : $opt); die "Option $opt does not exist" unless $long && exists $self->{opts}->{$long}; return $self->{opts}->{$long}->{got}; } sub has { my ( $self, $opt ) = @_; my $long = (length $opt == 1 ? $self->{short_opts}->{$opt} : $opt); return defined $long ? exists $self->{opts}->{$long} : 0; } sub set { my ( $self, $opt, $val ) = @_; my $long = (length $opt == 1 ? $self->{short_opts}->{$opt} : $opt); die "Option $opt does not exist" unless $long && exists $self->{opts}->{$long}; $self->{opts}->{$long}->{value} = $val; return; } sub save_error { my ( $self, $error ) = @_; push @{$self->{errors}}, $error; return; } sub errors { my ( $self ) = @_; return $self->{errors}; } sub usage { my ( $self ) = @_; warn "No usage string is set" unless $self->{usage}; # XXX return "Usage: " . ($self->{usage} || '') . "\n"; } sub descr { my ( $self ) = @_; warn "No description string is set" unless $self->{description}; # XXX my $descr = ($self->{description} || $self->{program_name} || '') . " For more details, please use the --help option, " . "or try 'perldoc $PROGRAM_NAME' " . "for complete documentation."; $descr = join("\n", $descr =~ m/(.{0,80})(?:\s+|$)/g) unless $ENV{DONT_BREAK_LINES}; $descr =~ s/ +$//mg; return $descr; } sub usage_or_errors { my ( $self, $file, $return ) = @_; $file ||= $self->{file} || __FILE__; if ( !$self->{description} || !$self->{usage} ) { PTDEBUG && _d("Getting description and usage from SYNOPSIS in", $file); my %synop = $self->_parse_synopsis($file); $self->{description} ||= $synop{description}; $self->{usage} ||= $synop{usage}; PTDEBUG && _d("Description:", $self->{description}, "\nUsage:", $self->{usage}); } if ( $self->{opts}->{help}->{got} ) { print $self->print_usage() or die "Cannot print usage: $OS_ERROR"; exit 0 unless $return; } elsif ( scalar @{$self->{errors}} ) { print $self->print_errors() or die "Cannot print errors: $OS_ERROR"; exit 1 unless $return; } return; } sub print_errors { my ( $self ) = @_; my $usage = $self->usage() . "\n"; if ( (my @errors = @{$self->{errors}}) ) { $usage .= join("\n * ", 'Errors in command-line arguments:', @errors) . "\n"; } return $usage . "\n" . $self->descr(); } sub print_usage { my ( $self ) = @_; die "Run get_opts() before print_usage()" unless $self->{got_opts}; my @opts = values %{$self->{opts}}; my $maxl = max( map { length($_->{long}) # option long name + ($_->{is_negatable} ? 4 : 0) # "[no]" if opt is negatable + ($_->{type} ? 2 : 0) # "=x" where x is the opt type } @opts); my $maxs = max(0, map { length($_) + ($self->{opts}->{$_}->{is_negatable} ? 4 : 0) + ($self->{opts}->{$_}->{type} ? 2 : 0) } values %{$self->{short_opts}}); my $lcol = max($maxl, ($maxs + 3)); my $rcol = 80 - $lcol - 6; my $rpad = ' ' x ( 80 - $rcol ); $maxs = max($lcol - 3, $maxs); my $usage = $self->descr() . "\n" . $self->usage(); my @groups = reverse sort grep { $_ ne 'default'; } keys %{$self->{groups}}; push @groups, 'default'; foreach my $group ( reverse @groups ) { $usage .= "\n".($group eq 'default' ? 'Options' : $group).":\n\n"; foreach my $opt ( sort { $a->{long} cmp $b->{long} } grep { $_->{group} eq $group } @opts ) { my $long = $opt->{is_negatable} ? "[no]$opt->{long}" : $opt->{long}; my $short = $opt->{short}; my $desc = $opt->{desc}; $long .= $opt->{type} ? "=$opt->{type}" : ""; if ( $opt->{type} && $opt->{type} eq 'm' ) { my ($s) = $desc =~ m/\(suffix (.)\)/; $s ||= 's'; $desc =~ s/\s+\(suffix .\)//; $desc .= ". Optional suffix s=seconds, m=minutes, h=hours, " . "d=days; if no suffix, $s is used."; } $desc = join("\n$rpad", grep { $_ } $desc =~ m/(.{0,$rcol}(?!\W))(?:\s+|(?<=\W)|$)/g); $desc =~ s/ +$//mg; if ( $short ) { $usage .= sprintf(" --%-${maxs}s -%s %s\n", $long, $short, $desc); } else { $usage .= sprintf(" --%-${lcol}s %s\n", $long, $desc); } } } $usage .= "\nOption types: s=string, i=integer, f=float, h/H/a/A=comma-separated list, d=DSN, z=size, m=time\n"; if ( (my @rules = @{$self->{rules}}) ) { $usage .= "\nRules:\n\n"; $usage .= join("\n", map { " $_" } @rules) . "\n"; } if ( $self->{DSNParser} ) { $usage .= "\n" . $self->{DSNParser}->usage(); } $usage .= "\nOptions and values after processing arguments:\n\n"; foreach my $opt ( sort { $a->{long} cmp $b->{long} } @opts ) { my $val = $opt->{value}; my $type = $opt->{type} || ''; my $bool = $opt->{spec} =~ m/^[\w-]+(?:\|[\w-])?!?$/; $val = $bool ? ( $val ? 'TRUE' : 'FALSE' ) : !defined $val ? '(No value)' : $type eq 'd' ? $self->{DSNParser}->as_string($val) : $type =~ m/H|h/ ? join(',', sort keys %$val) : $type =~ m/A|a/ ? join(',', @$val) : $val; $usage .= sprintf(" --%-${lcol}s %s\n", $opt->{long}, $val); } return $usage; } sub prompt_noecho { shift @_ if ref $_[0] eq __PACKAGE__; my ( $prompt ) = @_; local $OUTPUT_AUTOFLUSH = 1; print STDERR $prompt or die "Cannot print: $OS_ERROR"; my $response; eval { require Term::ReadKey; Term::ReadKey::ReadMode('noecho'); chomp($response = <STDIN>); Term::ReadKey::ReadMode('normal'); print "\n" or die "Cannot print: $OS_ERROR"; }; if ( $EVAL_ERROR ) { die "Cannot read response; is Term::ReadKey installed? $EVAL_ERROR"; } return $response; } sub _read_config_file { my ( $self, $filename ) = @_; open my $fh, "<", $filename or die "Cannot open $filename: $OS_ERROR\n"; my @args; my $prefix = '--'; my $parse = 1; LINE: while ( my $line = <$fh> ) { chomp $line; next LINE if $line =~ m/^\s*(?:\#|\;|$)/; $line =~ s/\s+#.*$//g; $line =~ s/^\s+|\s+$//g; if ( $line eq '--' ) { $prefix = ''; $parse = 0; next LINE; } if ( $parse && (my($opt, $arg) = $line =~ m/^\s*([^=\s]+?)(?:\s*=\s*(.*?)\s*)?$/) ) { push @args, grep { defined $_ } ("$prefix$opt", $arg); } elsif ( $line =~ m/./ ) { push @args, $line; } else { die "Syntax error in file $filename at line $INPUT_LINE_NUMBER"; } } close $fh; return @args; } sub read_para_after { my ( $self, $file, $regex ) = @_; open my $fh, "<", $file or die "Can't open $file: $OS_ERROR"; local $INPUT_RECORD_SEPARATOR = ''; my $para; while ( $para = <$fh> ) { next unless $para =~ m/^=pod$/m; last; } while ( $para = <$fh> ) { next unless $para =~ m/$regex/; last; } $para = <$fh>; chomp($para); close $fh or die "Can't close $file: $OS_ERROR"; return $para; } sub clone { my ( $self ) = @_; my %clone = map { my $hashref = $self->{$_}; my $val_copy = {}; foreach my $key ( keys %$hashref ) { my $ref = ref $hashref->{$key}; $val_copy->{$key} = !$ref ? $hashref->{$key} : $ref eq 'HASH' ? { %{$hashref->{$key}} } : $ref eq 'ARRAY' ? [ @{$hashref->{$key}} ] : $hashref->{$key}; } $_ => $val_copy; } qw(opts short_opts defaults); foreach my $scalar ( qw(got_opts) ) { $clone{$scalar} = $self->{$scalar}; } return bless \%clone; } sub _parse_size { my ( $self, $opt, $val ) = @_; if ( lc($val || '') eq 'null' ) { PTDEBUG && _d('NULL size for', $opt->{long}); $opt->{value} = 'null'; return; } my %factor_for = (k => 1_024, M => 1_048_576, G => 1_073_741_824); my ($pre, $num, $factor) = $val =~ m/^([+-])?(\d+)([kMG])?$/; if ( defined $num ) { if ( $factor ) { $num *= $factor_for{$factor}; PTDEBUG && _d('Setting option', $opt->{y}, 'to num', $num, '* factor', $factor); } $opt->{value} = ($pre || '') . $num; } else { $self->save_error("Invalid size for --$opt->{long}: $val"); } return; } sub _parse_attribs { my ( $self, $option, $attribs ) = @_; my $types = $self->{types}; return $option . ($attribs->{'short form'} ? '|' . $attribs->{'short form'} : '' ) . ($attribs->{'negatable'} ? '!' : '' ) . ($attribs->{'cumulative'} ? '+' : '' ) . ($attribs->{'type'} ? '=' . $types->{$attribs->{type}} : '' ); } sub _parse_synopsis { my ( $self, $file ) = @_; $file ||= $self->{file} || __FILE__; PTDEBUG && _d("Parsing SYNOPSIS in", $file); local $INPUT_RECORD_SEPARATOR = ''; # read paragraphs open my $fh, "<", $file or die "Cannot open $file: $OS_ERROR"; my $para; 1 while defined($para = <$fh>) && $para !~ m/^=head1 SYNOPSIS/; die "$file does not contain a SYNOPSIS section" unless $para; my @synop; for ( 1..2 ) { # 1 for the usage, 2 for the description my $para = <$fh>; push @synop, $para; } close $fh; PTDEBUG && _d("Raw SYNOPSIS text:", @synop); my ($usage, $desc) = @synop; die "The SYNOPSIS section in $file is not formatted properly" unless $usage && $desc; $usage =~ s/^\s*Usage:\s+(.+)/$1/; chomp $usage; $desc =~ s/\n/ /g; $desc =~ s/\s{2,}/ /g; $desc =~ s/\. ([A-Z][a-z])/. $1/g; $desc =~ s/\s+$//; return ( description => $desc, usage => $usage, ); }; sub set_vars { my ($self, $file) = @_; $file ||= $self->{file} || __FILE__; my %user_vars; my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef; if ( $user_vars ) { foreach my $var_val ( @$user_vars ) { my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/; die "Invalid --set-vars value: $var_val\n" unless $var && defined $val; $user_vars{$var} = { val => $val, default => 0, }; } } my %default_vars; my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/); if ( $default_vars ) { %default_vars = map { my $var_val = $_; my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/; die "Invalid --set-vars value: $var_val\n" unless $var && defined $val; $var => { val => $val, default => 1, }; } split("\n", $default_vars); } my %vars = ( %default_vars, # first the tool's defaults %user_vars, # then the user's which overwrite the defaults ); PTDEBUG && _d('--set-vars:', Dumper(\%vars)); return \%vars; } sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } map { defined $_ ? $_ : 'undef' } @_; print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; } if ( PTDEBUG ) { print STDERR '# ', $^X, ' ', $], "\n"; if ( my $uname = `uname -a` ) { $uname =~ s/\s+/ /g; print STDERR "# $uname\n"; } print STDERR '# Arguments: ', join(' ', map { my $a = "_[$_]_"; $a =~ s/\n/\n# /g; $a; } @ARGV), "\n"; } 1; } # ########################################################################### # End OptionParser package # ########################################################################### # ########################################################################### # Lmo::Utils package # This package is a copy without comments from the original. The original # with comments and its test file can be found in the Bazaar repository at, # lib/Lmo/Utils.pm # t/lib/Lmo/Utils.t # See https://launchpad.net/percona-toolkit for more information. # ########################################################################### { package Lmo::Utils; use strict; use warnings qw( FATAL all ); require Exporter; our (@ISA, @EXPORT, @EXPORT_OK); BEGIN { @ISA = qw(Exporter); @EXPORT = @EXPORT_OK = qw( _install_coderef _unimport_coderefs _glob_for _stash_for ); } { no strict 'refs'; sub _glob_for { return \*{shift()} } sub _stash_for { return \%{ shift() . "::" }; } } sub _install_coderef { my ($to, $code) = @_; return *{ _glob_for $to } = $code; } sub _unimport_coderefs { my ($target, @names) = @_; return unless @names; my $stash = _stash_for($target); foreach my $name (@names) { if ($stash->{$name} and defined(&{$stash->{$name}})) { delete $stash->{$name}; } } } 1; } # ########################################################################### # End Lmo::Utils package # ########################################################################### # ########################################################################### # Lmo::Meta package # This package is a copy without comments from the original. The original # with comments and its test file can be found in the Bazaar repository at, # lib/Lmo/Meta.pm # t/lib/Lmo/Meta.t # See https://launchpad.net/percona-toolkit for more information. # ########################################################################### { package Lmo::Meta; use strict; use warnings qw( FATAL all ); my %metadata_for; sub new { my $class = shift; return bless { @_ }, $class } sub metadata_for { my $self = shift; my ($class) = @_; return $metadata_for{$class} ||= {}; } sub class { shift->{class} } sub attributes { my $self = shift; return keys %{$self->metadata_for($self->class)} } sub attributes_for_new { my $self = shift; my @attributes; my $class_metadata = $self->metadata_for($self->class); while ( my ($attr, $meta) = each %$class_metadata ) { if ( exists $meta->{init_arg} ) { push @attributes, $meta->{init_arg} if defined $meta->{init_arg}; } else { push @attributes, $attr; } } return @attributes; } 1; } # ########################################################################### # End Lmo::Meta package # ########################################################################### # ########################################################################### # Lmo::Object package # This package is a copy without comments from the original. The original # with comments and its test file can be found in the Bazaar repository at, # lib/Lmo/Object.pm # t/lib/Lmo/Object.t # See https://launchpad.net/percona-toolkit for more information. # ########################################################################### { package Lmo::Object; use strict; use warnings qw( FATAL all ); use Carp (); use Scalar::Util qw(blessed); use Lmo::Meta; use Lmo::Utils qw(_glob_for); sub new { my $class = shift; my $args = $class->BUILDARGS(@_); my $class_metadata = Lmo::Meta->metadata_for($class); my @args_to_delete; while ( my ($attr, $meta) = each %$class_metadata ) { next unless exists $meta->{init_arg}; my $init_arg = $meta->{init_arg}; if ( defined $init_arg ) { $args->{$attr} = delete $args->{$init_arg}; } else { push @args_to_delete, $attr; } } delete $args->{$_} for @args_to_delete; for my $attribute ( keys %$args ) { if ( my $coerce = $class_metadata->{$attribute}{coerce} ) { $args->{$attribute} = $coerce->($args->{$attribute}); } if ( my $isa_check = $class_metadata->{$attribute}{isa} ) { my ($check_name, $check_sub) = @$isa_check; $check_sub->($args->{$attribute}); } } while ( my ($attribute, $meta) = each %$class_metadata ) { next unless $meta->{required}; Carp::confess("Attribute ($attribute) is required for $class") if ! exists $args->{$attribute} } my $self = bless $args, $class; my @build_subs; my $linearized_isa = mro::get_linear_isa($class); for my $isa_class ( @$linearized_isa ) { unshift @build_subs, *{ _glob_for "${isa_class}::BUILD" }{CODE}; } my @args = %$args; for my $sub (grep { defined($_) && exists &$_ } @build_subs) { $sub->( $self, @args); } return $self; } sub BUILDARGS { shift; # No need for the classname if ( @_ == 1 && ref($_[0]) ) { Carp::confess("Single parameters to new() must be a HASH ref, not $_[0]") unless ref($_[0]) eq ref({}); return {%{$_[0]}} # We want a new reference, always } else { return { @_ }; } } sub meta { my $class = shift; $class = Scalar::Util::blessed($class) || $class; return Lmo::Meta->new(class => $class); } 1; } # ########################################################################### # End Lmo::Object package # ########################################################################### # ########################################################################### # Lmo::Types package # This package is a copy without comments from the original. The original # with comments and its test file can be found in the Bazaar repository at, # lib/Lmo/Types.pm # t/lib/Lmo/Types.t # See https://launchpad.net/percona-toolkit for more information. # ########################################################################### { package Lmo::Types; use strict; use warnings qw( FATAL all ); use Carp (); use Scalar::Util qw(looks_like_number blessed); our %TYPES = ( Bool => sub { !$_[0] || (defined $_[0] && looks_like_number($_[0]) && $_[0] == 1) }, Num => sub { defined $_[0] && looks_like_number($_[0]) }, Int => sub { defined $_[0] && looks_like_number($_[0]) && $_[0] == int($_[0]) }, Str => sub { defined $_[0] }, Object => sub { defined $_[0] && blessed($_[0]) }, FileHandle => sub { local $@; require IO::Handle; fileno($_[0]) && $_[0]->opened }, map { my $type = /R/ ? $_ : uc $_; $_ . "Ref" => sub { ref $_[0] eq $type } } qw(Array Code Hash Regexp Glob Scalar) ); sub check_type_constaints { my ($attribute, $type_check, $check_name, $val) = @_; ( ref($type_check) eq 'CODE' ? $type_check->($val) : (ref $val eq $type_check || ($val && $val eq $type_check) || (exists $TYPES{$type_check} && $TYPES{$type_check}->($val))) ) || Carp::confess( qq<Attribute ($attribute) does not pass the type constraint because: > . qq<Validation failed for '$check_name' with value > . (defined $val ? Lmo::Dumper($val) : 'undef') ) } sub _nested_constraints { my ($attribute, $aggregate_type, $type) = @_; my $inner_types; if ( $type =~ /\A(ArrayRef|Maybe)\[(.*)\]\z/ ) { $inner_types = _nested_constraints($1, $2); } else { $inner_types = $TYPES{$type}; } if ( $aggregate_type eq 'ArrayRef' ) { return sub { my ($val) = @_; return unless ref($val) eq ref([]); if ($inner_types) { for my $value ( @{$val} ) { return unless $inner_types->($value) } } else { for my $value ( @{$val} ) { return unless $value && ($value eq $type || (Scalar::Util::blessed($value) && $value->isa($type))); } } return 1; }; } elsif ( $aggregate_type eq 'Maybe' ) { return sub { my ($value) = @_; return 1 if ! defined($value); if ($inner_types) { return unless $inner_types->($value) } else { return unless $value eq $type || (Scalar::Util::blessed($value) && $value->isa($type)); } return 1; } } else { Carp::confess("Nested aggregate types are only implemented for ArrayRefs and Maybe"); } } 1; } # ########################################################################### # End Lmo::Types package # ########################################################################### # ########################################################################### # Lmo package # This package is a copy without comments from the original. The original # with comments and its test file can be found in the Bazaar repository at, # lib/Lmo.pm # t/lib/Lmo.t # See https://launchpad.net/percona-toolkit for more information. # ########################################################################### { BEGIN { $INC{"Lmo.pm"} = __FILE__; package Lmo; our $VERSION = '0.30_Percona'; # Forked from 0.30 of Mo. use strict; use warnings qw( FATAL all ); use Carp (); use Scalar::Util qw(looks_like_number blessed); use Lmo::Meta; use Lmo::Object; use Lmo::Types; use Lmo::Utils; my %export_for; sub import { warnings->import(qw(FATAL all)); strict->import(); my $caller = scalar caller(); # Caller's package my %exports = ( extends => \&extends, has => \&has, with => \&with, override => \&override, confess => \&Carp::confess, ); $export_for{$caller} = \%exports; for my $keyword ( keys %exports ) { _install_coderef "${caller}::$keyword" => $exports{$keyword}; } if ( !@{ *{ _glob_for "${caller}::ISA" }{ARRAY} || [] } ) { @_ = "Lmo::Object"; goto *{ _glob_for "${caller}::extends" }{CODE}; } } sub extends { my $caller = scalar caller(); for my $class ( @_ ) { _load_module($class); } _set_package_isa($caller, @_); _set_inherited_metadata($caller); } sub _load_module { my ($class) = @_; (my $file = $class) =~ s{::|'}{/}g; $file .= '.pm'; { local $@; eval { require "$file" } } # or warn $@; return; } sub with { my $package = scalar caller(); require Role::Tiny; for my $role ( @_ ) { _load_module($role); _role_attribute_metadata($package, $role); } Role::Tiny->apply_roles_to_package($package, @_); } sub _role_attribute_metadata { my ($package, $role) = @_; my $package_meta = Lmo::Meta->metadata_for($package); my $role_meta = Lmo::Meta->metadata_for($role); %$package_meta = (%$role_meta, %$package_meta); } sub has { my $names = shift; my $caller = scalar caller(); my $class_metadata = Lmo::Meta->metadata_for($caller); for my $attribute ( ref $names ? @$names : $names ) { my %args = @_; my $method = ($args{is} || '') eq 'ro' ? sub { Carp::confess("Cannot assign a value to a read-only accessor at reader ${caller}::${attribute}") if $#_; return $_[0]{$attribute}; } : sub { return $#_ ? $_[0]{$attribute} = $_[1] : $_[0]{$attribute}; }; $class_metadata->{$attribute} = (); if ( my $type_check = $args{isa} ) { my $check_name = $type_check; if ( my ($aggregate_type, $inner_type) = $type_check =~ /\A(ArrayRef|Maybe)\[(.*)\]\z/ ) { $type_check = Lmo::Types::_nested_constraints($attribute, $aggregate_type, $inner_type); } my $check_sub = sub { my ($new_val) = @_; Lmo::Types::check_type_constaints($attribute, $type_check, $check_name, $new_val); }; $class_metadata->{$attribute}{isa} = [$check_name, $check_sub]; my $orig_method = $method; $method = sub { $check_sub->($_[1]) if $#_; goto &$orig_method; }; } if ( my $builder = $args{builder} ) { my $original_method = $method; $method = sub { $#_ ? goto &$original_method : ! exists $_[0]{$attribute} ? $_[0]{$attribute} = $_[0]->$builder : goto &$original_method }; } if ( my $code = $args{default} ) { Carp::confess("${caller}::${attribute}'s default is $code, but should be a coderef") unless ref($code) eq 'CODE'; my $original_method = $method; $method = sub { $#_ ? goto &$original_method : ! exists $_[0]{$attribute} ? $_[0]{$attribute} = $_[0]->$code : goto &$original_method }; } if ( my $role = $args{does} ) { my $original_method = $method; $method = sub { if ( $#_ ) { Carp::confess(qq<Attribute ($attribute) doesn't consume a '$role' role">) unless Scalar::Util::blessed($_[1]) && eval { $_[1]->does($role) } } goto &$original_method }; } if ( my $coercion = $args{coerce} ) { $class_metadata->{$attribute}{coerce} = $coercion; my $original_method = $method; $method = sub { if ( $#_ ) { return $original_method->($_[0], $coercion->($_[1])) } goto &$original_method; } } _install_coderef "${caller}::$attribute" => $method; if ( $args{required} ) { $class_metadata->{$attribute}{required} = 1; } if ($args{clearer}) { _install_coderef "${caller}::$args{clearer}" => sub { delete shift->{$attribute} } } if ($args{predicate}) { _install_coderef "${caller}::$args{predicate}" => sub { exists shift->{$attribute} } } if ($args{handles}) { _has_handles($caller, $attribute, \%args); } if (exists $args{init_arg}) { $class_metadata->{$attribute}{init_arg} = $args{init_arg}; } } } sub _has_handles { my ($caller, $attribute, $args) = @_; my $handles = $args->{handles}; my $ref = ref $handles; my $kv; if ( $ref eq ref [] ) { $kv = { map { $_,$_ } @{$handles} }; } elsif ( $ref eq ref {} ) { $kv = $handles; } elsif ( $ref eq ref qr// ) { Carp::confess("Cannot delegate methods based on a Regexp without a type constraint (isa)") unless $args->{isa}; my $target_class = $args->{isa}; $kv = { map { $_, $_ } grep { $_ =~ $handles } grep { !exists $Lmo::Object::{$_} && $target_class->can($_) } grep { !$export_for{$target_class}->{$_} } keys %{ _stash_for $target_class } }; } else { Carp::confess("handles for $ref not yet implemented"); } while ( my ($method, $target) = each %{$kv} ) { my $name = _glob_for "${caller}::$method"; Carp::confess("You cannot overwrite a locally defined method ($method) with a delegation") if defined &$name; my ($target, @curried_args) = ref($target) ? @$target : $target; *$name = sub { my $self = shift; my $delegate_to = $self->$attribute(); my $error = "Cannot delegate $method to $target because the value of $attribute"; Carp::confess("$error is not defined") unless $delegate_to; Carp::confess("$error is not an object (got '$delegate_to')") unless Scalar::Util::blessed($delegate_to) || (!ref($delegate_to) && $delegate_to->can($target)); return $delegate_to->$target(@curried_args, @_); } } } sub _set_package_isa { my ($package, @new_isa) = @_; my $package_isa = \*{ _glob_for "${package}::ISA" }; @{*$package_isa} = @new_isa; } sub _set_inherited_metadata { my $class = shift; my $class_metadata = Lmo::Meta->metadata_for($class); my $linearized_isa = mro::get_linear_isa($class); my %new_metadata; for my $isa_class (reverse @$linearized_isa) { my $isa_metadata = Lmo::Meta->metadata_for($isa_class); %new_metadata = ( %new_metadata, %$isa_metadata, ); } %$class_metadata = %new_metadata; } sub unimport { my $caller = scalar caller(); my $target = caller; _unimport_coderefs($target, keys %{$export_for{$caller}}); } sub Dumper { require Data::Dumper; local $Data::Dumper::Indent = 0; local $Data::Dumper::Sortkeys = 0; local $Data::Dumper::Quotekeys = 0; local $Data::Dumper::Terse = 1; Data::Dumper::Dumper(@_) } BEGIN { if ($] >= 5.010) { { local $@; require mro; } } else { local $@; eval { require MRO::Compat; } or do { *mro::get_linear_isa = *mro::get_linear_isa_dfs = sub { no strict 'refs'; my $classname = shift; my @lin = ($classname); my %stored; foreach my $parent (@{"$classname\::ISA"}) { my $plin = mro::get_linear_isa_dfs($parent); foreach (@$plin) { next if exists $stored{$_}; push(@lin, $_); $stored{$_} = 1; } } return \@lin; }; } } } sub override { my ($methods, $code) = @_; my $caller = scalar caller; for my $method ( ref($methods) ? @$methods : $methods ) { my $full_method = "${caller}::${method}"; *{_glob_for $full_method} = $code; } } } 1; } # ########################################################################### # End Lmo package # ########################################################################### # ########################################################################### # DSNParser package # This package is a copy without comments from the original. The original # with comments and its test file can be found in the Bazaar repository at, # lib/DSNParser.pm # t/lib/DSNParser.t # See https://launchpad.net/percona-toolkit for more information. # ########################################################################### { package DSNParser; use strict; use warnings FATAL => 'all'; use English qw(-no_match_vars); use constant PTDEBUG => $ENV{PTDEBUG} || 0; use Data::Dumper; $Data::Dumper::Indent = 0; $Data::Dumper::Quotekeys = 0; my $dsn_sep = qr/(?<!\\),/; eval { require DBI; }; my $have_dbi = $EVAL_ERROR ? 0 : 1; sub new { my ( $class, %args ) = @_; foreach my $arg ( qw(opts) ) { die "I need a $arg argument" unless $args{$arg}; } my $self = { opts => {} # h, P, u, etc. Should come from DSN OPTIONS section in POD. }; foreach my $opt ( @{$args{opts}} ) { if ( !$opt->{key} || !$opt->{desc} ) { die "Invalid DSN option: ", Dumper($opt); } PTDEBUG && _d('DSN option:', join(', ', map { "$_=" . (defined $opt->{$_} ? ($opt->{$_} || '') : 'undef') } keys %$opt ) ); $self->{opts}->{$opt->{key}} = { dsn => $opt->{dsn}, desc => $opt->{desc}, copy => $opt->{copy} || 0, }; } return bless $self, $class; } sub prop { my ( $self, $prop, $value ) = @_; if ( @_ > 2 ) { PTDEBUG && _d('Setting', $prop, 'property'); $self->{$prop} = $value; } return $self->{$prop}; } sub parse { my ( $self, $dsn, $prev, $defaults ) = @_; if ( !$dsn ) { PTDEBUG && _d('No DSN to parse'); return; } PTDEBUG && _d('Parsing', $dsn); $prev ||= {}; $defaults ||= {}; my %given_props; my %final_props; my $opts = $self->{opts}; foreach my $dsn_part ( split($dsn_sep, $dsn) ) { $dsn_part =~ s/\\,/,/g; if ( my ($prop_key, $prop_val) = $dsn_part =~ m/^(.)=(.*)$/ ) { $given_props{$prop_key} = $prop_val; } else { PTDEBUG && _d('Interpreting', $dsn_part, 'as h=', $dsn_part); $given_props{h} = $dsn_part; } } foreach my $key ( keys %$opts ) { PTDEBUG && _d('Finding value for', $key); $final_props{$key} = $given_props{$key}; if ( !defined $final_props{$key} && defined $prev->{$key} && $opts->{$key}->{copy} ) { $final_props{$key} = $prev->{$key}; PTDEBUG && _d('Copying value for', $key, 'from previous DSN'); } if ( !defined $final_props{$key} ) { $final_props{$key} = $defaults->{$key}; PTDEBUG && _d('Copying value for', $key, 'from defaults'); } } foreach my $key ( keys %given_props ) { die "Unknown DSN option '$key' in '$dsn'. For more details, " . "please use the --help option, or try 'perldoc $PROGRAM_NAME' " . "for complete documentation." unless exists $opts->{$key}; } if ( (my $required = $self->prop('required')) ) { foreach my $key ( keys %$required ) { die "Missing required DSN option '$key' in '$dsn'. For more details, " . "please use the --help option, or try 'perldoc $PROGRAM_NAME' " . "for complete documentation." unless $final_props{$key}; } } return \%final_props; } sub parse_options { my ( $self, $o ) = @_; die 'I need an OptionParser object' unless ref $o eq 'OptionParser'; my $dsn_string = join(',', map { "$_=".$o->get($_); } grep { $o->has($_) && $o->get($_) } keys %{$self->{opts}} ); PTDEBUG && _d('DSN string made from options:', $dsn_string); return $self->parse($dsn_string); } sub as_string { my ( $self, $dsn, $props ) = @_; return $dsn unless ref $dsn; my @keys = $props ? @$props : sort keys %$dsn; return join(',', map { "$_=" . ($_ eq 'p' ? '...' : $dsn->{$_}) } grep { exists $self->{opts}->{$_} && exists $dsn->{$_} && defined $dsn->{$_} } @keys); } sub usage { my ( $self ) = @_; my $usage = "DSN syntax is key=value[,key=value...] Allowable DSN keys:\n\n" . " KEY COPY MEANING\n" . " === ==== =============================================\n"; my %opts = %{$self->{opts}}; foreach my $key ( sort keys %opts ) { $usage .= " $key " . ($opts{$key}->{copy} ? 'yes ' : 'no ') . ($opts{$key}->{desc} || '[No description]') . "\n"; } $usage .= "\n If the DSN is a bareword, the word is treated as the 'h' key.\n"; return $usage; } sub get_cxn_params { my ( $self, $info ) = @_; my $dsn; my %opts = %{$self->{opts}}; my $driver = $self->prop('dbidriver') || ''; if ( $driver eq 'Pg' ) { $dsn = 'DBI:Pg:dbname=' . ( $info->{D} || '' ) . ';' . join(';', map { "$opts{$_}->{dsn}=$info->{$_}" } grep { defined $info->{$_} } qw(h P)); } else { $dsn = 'DBI:mysql:' . ( $info->{D} || '' ) . ';' . join(';', map { "$opts{$_}->{dsn}=$info->{$_}" } grep { defined $info->{$_} } qw(F h P S A)) . ';mysql_read_default_group=client' . ($info->{L} ? ';mysql_local_infile=1' : ''); } PTDEBUG && _d($dsn); return ($dsn, $info->{u}, $info->{p}); } sub fill_in_dsn { my ( $self, $dbh, $dsn ) = @_; my $vars = $dbh->selectall_hashref('SHOW VARIABLES', 'Variable_name'); my ($user, $db) = $dbh->selectrow_array('SELECT USER(), DATABASE()'); $user =~ s/@.*//; $dsn->{h} ||= $vars->{hostname}->{Value}; $dsn->{S} ||= $vars->{'socket'}->{Value}; $dsn->{P} ||= $vars->{port}->{Value}; $dsn->{u} ||= $user; $dsn->{D} ||= $db; } sub get_dbh { my ( $self, $cxn_string, $user, $pass, $opts ) = @_; $opts ||= {}; my $defaults = { AutoCommit => 0, RaiseError => 1, PrintError => 0, ShowErrorStatement => 1, mysql_enable_utf8 => ($cxn_string =~ m/charset=utf8/i ? 1 : 0), }; @{$defaults}{ keys %$opts } = values %$opts; if (delete $defaults->{L}) { # L for LOAD DATA LOCAL INFILE, our own extension $defaults->{mysql_local_infile} = 1; } if ( $opts->{mysql_use_result} ) { $defaults->{mysql_use_result} = 1; } if ( !$have_dbi ) { die "Cannot connect to MySQL because the Perl DBI module is not " . "installed or not found. Run 'perl -MDBI' to see the directories " . "that Perl searches for DBI. If DBI is not installed, try:\n" . " Debian/Ubuntu apt-get install libdbi-perl\n" . " RHEL/CentOS yum install perl-DBI\n" . " OpenSolaris pkg install pkg:/SUNWpmdbi\n"; } my $dbh; my $tries = 2; while ( !$dbh && $tries-- ) { PTDEBUG && _d($cxn_string, ' ', $user, ' ', $pass, join(', ', map { "$_=>$defaults->{$_}" } keys %$defaults )); $dbh = eval { DBI->connect($cxn_string, $user, $pass, $defaults) }; if ( !$dbh && $EVAL_ERROR ) { if ( $EVAL_ERROR =~ m/locate DBD\/mysql/i ) { die "Cannot connect to MySQL because the Perl DBD::mysql module is " . "not installed or not found. Run 'perl -MDBD::mysql' to see " . "the directories that Perl searches for DBD::mysql. If " . "DBD::mysql is not installed, try:\n" . " Debian/Ubuntu apt-get install libdbd-mysql-perl\n" . " RHEL/CentOS yum install perl-DBD-MySQL\n" . " OpenSolaris pgk install pkg:/SUNWapu13dbd-mysql\n"; } elsif ( $EVAL_ERROR =~ m/not a compiled character set|character set utf8/ ) { PTDEBUG && _d('Going to try again without utf8 support'); delete $defaults->{mysql_enable_utf8}; } if ( !$tries ) { die $EVAL_ERROR; } } } if ( $cxn_string =~ m/mysql/i ) { my $sql; $sql = 'SELECT @@SQL_MODE'; PTDEBUG && _d($dbh, $sql); my ($sql_mode) = eval { $dbh->selectrow_array($sql) }; if ( $EVAL_ERROR ) { die "Error getting the current SQL_MODE: $EVAL_ERROR"; } if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) { $sql = qq{/*!40101 SET NAMES "$charset"*/}; PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( $EVAL_ERROR ) { die "Error setting NAMES to $charset: $EVAL_ERROR"; } PTDEBUG && _d('Enabling charset for STDOUT'); if ( $charset eq 'utf8' ) { binmode(STDOUT, ':utf8') or die "Can't binmode(STDOUT, ':utf8'): $OS_ERROR"; } else { binmode(STDOUT) or die "Can't binmode(STDOUT): $OS_ERROR"; } } if ( my $vars = $self->prop('set-vars') ) { $self->set_vars($dbh, $vars); } $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1' . '/*!40101, @@SQL_MODE=\'NO_AUTO_VALUE_ON_ZERO' . ($sql_mode ? ",$sql_mode" : '') . '\'*/'; PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( $EVAL_ERROR ) { die "Error setting SQL_QUOTE_SHOW_CREATE, SQL_MODE" . ($sql_mode ? " and $sql_mode" : '') . ": $EVAL_ERROR"; } } PTDEBUG && _d('DBH info: ', $dbh, Dumper($dbh->selectrow_hashref( 'SELECT DATABASE(), CONNECTION_ID(), VERSION()/*!50038 , @@hostname*/')), 'Connection info:', $dbh->{mysql_hostinfo}, 'Character set info:', Dumper($dbh->selectall_arrayref( "SHOW VARIABLES LIKE 'character_set%'", { Slice => {}})), '$DBD::mysql::VERSION:', $DBD::mysql::VERSION, '$DBI::VERSION:', $DBI::VERSION, ); return $dbh; } sub get_hostname { my ( $self, $dbh ) = @_; if ( my ($host) = ($dbh->{mysql_hostinfo} || '') =~ m/^(\w+) via/ ) { return $host; } my ( $hostname, $one ) = $dbh->selectrow_array( 'SELECT /*!50038 @@hostname, */ 1'); return $hostname; } sub disconnect { my ( $self, $dbh ) = @_; PTDEBUG && $self->print_active_handles($dbh); $dbh->disconnect; } sub print_active_handles { my ( $self, $thing, $level ) = @_; $level ||= 0; printf("# Active %sh: %s %s %s\n", ($thing->{Type} || 'undef'), "\t" x $level, $thing, (($thing->{Type} || '') eq 'st' ? $thing->{Statement} || '' : '')) or die "Cannot print: $OS_ERROR"; foreach my $handle ( grep {defined} @{ $thing->{ChildHandles} } ) { $self->print_active_handles( $handle, $level + 1 ); } } sub copy { my ( $self, $dsn_1, $dsn_2, %args ) = @_; die 'I need a dsn_1 argument' unless $dsn_1; die 'I need a dsn_2 argument' unless $dsn_2; my %new_dsn = map { my $key = $_; my $val; if ( $args{overwrite} ) { $val = defined $dsn_1->{$key} ? $dsn_1->{$key} : $dsn_2->{$key}; } else { $val = defined $dsn_2->{$key} ? $dsn_2->{$key} : $dsn_1->{$key}; } $key => $val; } keys %{$self->{opts}}; return \%new_dsn; } sub set_vars { my ($self, $dbh, $vars) = @_; return unless $vars; foreach my $var ( sort keys %$vars ) { my $val = $vars->{$var}->{val}; (my $quoted_var = $var) =~ s/_/\\_/; my ($var_exists, $current_val); eval { ($var_exists, $current_val) = $dbh->selectrow_array( "SHOW VARIABLES LIKE '$quoted_var'"); }; my $e = $EVAL_ERROR; if ( $e ) { PTDEBUG && _d($e); } if ( $vars->{$var}->{default} && !$var_exists ) { PTDEBUG && _d('Not setting default var', $var, 'because it does not exist'); next; } if ( $current_val && $current_val eq $val ) { PTDEBUG && _d('Not setting var', $var, 'because its value', 'is already', $val); next; } my $sql = "SET SESSION $var=$val"; PTDEBUG && _d($dbh, $sql); eval { $dbh->do($sql) }; if ( my $set_error = $EVAL_ERROR ) { chomp($set_error); $set_error =~ s/ at \S+ line \d+//; my $msg = "Error setting $var: $set_error"; if ( $current_val ) { $msg .= " The current value for $var is $current_val. " . "If the variable is read only (not dynamic), specify " . "--set-vars $var=$current_val to avoid this warning, " . "else manually set the variable and restart MySQL."; } warn $msg . "\n\n"; } } return; } sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } map { defined $_ ? $_ : 'undef' } @_; print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; } 1; } # ########################################################################### # End DSNParser package # ########################################################################### # ########################################################################### # VersionParser package # This package is a copy without comments from the original. The original # with comments and its test file can be found in the Bazaar repository at, # lib/VersionParser.pm # t/lib/VersionParser.t # See https://launchpad.net/percona-toolkit for more information. # ########################################################################### { package VersionParser; use Lmo; use Scalar::Util qw(blessed); use English qw(-no_match_vars); use constant PTDEBUG => $ENV{PTDEBUG} || 0; use overload ( '""' => "version", '<=>' => "cmp", 'cmp' => "cmp", fallback => 1, ); use Carp (); our $VERSION = 0.01; has major => ( is => 'ro', isa => 'Int', required => 1, ); has [qw( minor revision )] => ( is => 'ro', isa => 'Num', ); has flavor => ( is => 'ro', isa => 'Str', default => sub { 'Unknown' }, ); has innodb_version => ( is => 'ro', isa => 'Str', default => sub { 'NO' }, ); sub series { my $self = shift; return $self->_join_version($self->major, $self->minor); } sub version { my $self = shift; return $self->_join_version($self->major, $self->minor, $self->revision); } sub is_in { my ($self, $target) = @_; return $self eq $target; } sub _join_version { my ($self, @parts) = @_; return join ".", map { my $c = $_; $c =~ s/^0\./0/; $c } grep defined, @parts; } sub _split_version { my ($self, $str) = @_; my @version_parts = map { s/^0(?=\d)/0./; $_ } $str =~ m/(\d+)/g; return @version_parts[0..2]; } sub normalized_version { my ( $self ) = @_; my $result = sprintf('%d%02d%02d', map { $_ || 0 } $self->major, $self->minor, $self->revision); PTDEBUG && _d($self->version, 'normalizes to', $result); return $result; } sub comment { my ( $self, $cmd ) = @_; my $v = $self->normalized_version(); return "/*!$v $cmd */" } my @methods = qw(major minor revision); sub cmp { my ($left, $right) = @_; my $right_obj = (blessed($right) && $right->isa(ref($left))) ? $right : ref($left)->new($right); my $retval = 0; for my $m ( @methods ) { last unless defined($left->$m) && defined($right_obj->$m); $retval = $left->$m <=> $right_obj->$m; last if $retval; } return $retval; } sub BUILDARGS { my $self = shift; if ( @_ == 1 ) { my %args; if ( blessed($_[0]) && $_[0]->can("selectrow_hashref") ) { PTDEBUG && _d("VersionParser got a dbh, trying to get the version"); my $dbh = $_[0]; local $dbh->{FetchHashKeyName} = 'NAME_lc'; my $query = eval { $dbh->selectall_arrayref(q/SHOW VARIABLES LIKE 'version%'/, { Slice => {} }) }; if ( $query ) { $query = { map { $_->{variable_name} => $_->{value} } @$query }; @args{@methods} = $self->_split_version($query->{version}); $args{flavor} = delete $query->{version_comment} if $query->{version_comment}; } elsif ( eval { ($query) = $dbh->selectrow_array(q/SELECT VERSION()/) } ) { @args{@methods} = $self->_split_version($query); } else { Carp::confess("Couldn't get the version from the dbh while " . "creating a VersionParser object: $@"); } $args{innodb_version} = eval { $self->_innodb_version($dbh) }; } elsif ( !ref($_[0]) ) { @args{@methods} = $self->_split_version($_[0]); } for my $method (@methods) { delete $args{$method} unless defined $args{$method}; } @_ = %args if %args; } return $self->SUPER::BUILDARGS(@_); } sub _innodb_version { my ( $self, $dbh ) = @_; return unless $dbh; my $innodb_version = "NO"; my ($innodb) = grep { $_->{engine} =~ m/InnoDB/i } map { my %hash; @hash{ map { lc $_ } keys %$_ } = values %$_; \%hash; } @{ $dbh->selectall_arrayref("SHOW ENGINES", {Slice=>{}}) }; if ( $innodb ) { PTDEBUG && _d("InnoDB support:", $innodb->{support}); if ( $innodb->{support} =~ m/YES|DEFAULT/i ) { my $vars = $dbh->selectrow_hashref( "SHOW VARIABLES LIKE 'innodb_version'"); $innodb_version = !$vars ? "BUILTIN" : ($vars->{Value} || $vars->{value}); } else { $innodb_version = $innodb->{support}; # probably DISABLED or NO } } PTDEBUG && _d("InnoDB version:", $innodb_version); return $innodb_version; } sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } map { defined $_ ? $_ : 'undef' } @_; print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; } no Lmo; 1; } # ########################################################################### # End VersionParser package # ########################################################################### # ########################################################################### # Daemon package # This package is a copy without comments from the original. The original # with comments and its test file can be found in the Bazaar repository at, # lib/Daemon.pm # t/lib/Daemon.t # See https://launchpad.net/percona-toolkit for more information. # ########################################################################### { package Daemon; use strict; use warnings FATAL => 'all'; use English qw(-no_match_vars); use constant PTDEBUG => $ENV{PTDEBUG} || 0; use POSIX qw(setsid); sub new { my ( $class, %args ) = @_; foreach my $arg ( qw(o) ) { die "I need a $arg argument" unless $args{$arg}; } my $o = $args{o}; my $self = { o => $o, log_file => $o->has('log') ? $o->get('log') : undef, PID_file => $o->has('pid') ? $o->get('pid') : undef, }; check_PID_file(undef, $self->{PID_file}); PTDEBUG && _d('Daemonized child will log to', $self->{log_file}); return bless $self, $class; } sub daemonize { my ( $self ) = @_; PTDEBUG && _d('About to fork and daemonize'); defined (my $pid = fork()) or die "Cannot fork: $OS_ERROR"; if ( $pid ) { PTDEBUG && _d('Parent PID', $PID, 'exiting after forking child PID',$pid); exit; } PTDEBUG && _d('Daemonizing child PID', $PID); $self->{PID_owner} = $PID; $self->{child} = 1; POSIX::setsid() or die "Cannot start a new session: $OS_ERROR"; chdir '/' or die "Cannot chdir to /: $OS_ERROR"; $self->_make_PID_file(); $OUTPUT_AUTOFLUSH = 1; PTDEBUG && _d('Redirecting STDIN to /dev/null'); close STDIN; open STDIN, '/dev/null' or die "Cannot reopen STDIN to /dev/null: $OS_ERROR"; if ( $self->{log_file} ) { PTDEBUG && _d('Redirecting STDOUT and STDERR to', $self->{log_file}); close STDOUT; open STDOUT, '>>', $self->{log_file} or die "Cannot open log file $self->{log_file}: $OS_ERROR"; close STDERR; open STDERR, ">&STDOUT" or die "Cannot dupe STDERR to STDOUT: $OS_ERROR"; } else { if ( -t STDOUT ) { PTDEBUG && _d('No log file and STDOUT is a terminal;', 'redirecting to /dev/null'); close STDOUT; open STDOUT, '>', '/dev/null' or die "Cannot reopen STDOUT to /dev/null: $OS_ERROR"; } if ( -t STDERR ) { PTDEBUG && _d('No log file and STDERR is a terminal;', 'redirecting to /dev/null'); close STDERR; open STDERR, '>', '/dev/null' or die "Cannot reopen STDERR to /dev/null: $OS_ERROR"; } } return; } sub check_PID_file { my ( $self, $file ) = @_; my $PID_file = $self ? $self->{PID_file} : $file; PTDEBUG && _d('Checking PID file', $PID_file); if ( $PID_file && -f $PID_file ) { my $pid; eval { chomp($pid = (slurp_file($PID_file) || '')); }; if ( $EVAL_ERROR ) { die "The PID file $PID_file already exists but it cannot be read: " . $EVAL_ERROR; } PTDEBUG && _d('PID file exists; it contains PID', $pid); if ( $pid ) { my $pid_is_alive = kill 0, $pid; if ( $pid_is_alive ) { die "The PID file $PID_file already exists " . " and the PID that it contains, $pid, is running"; } else { warn "Overwriting PID file $PID_file because the PID that it " . "contains, $pid, is not running"; } } else { die "The PID file $PID_file already exists but it does not " . "contain a PID"; } } else { PTDEBUG && _d('No PID file'); } return; } sub make_PID_file { my ( $self ) = @_; if ( exists $self->{child} ) { die "Do not call Daemon::make_PID_file() for daemonized scripts"; } $self->_make_PID_file(); $self->{PID_owner} = $PID; return; } sub _make_PID_file { my ( $self ) = @_; my $PID_file = $self->{PID_file}; if ( !$PID_file ) { PTDEBUG && _d('No PID file to create'); return; } $self->check_PID_file(); open my $PID_FH, '>', $PID_file or die "Cannot open PID file $PID_file: $OS_ERROR"; print $PID_FH $PID or die "Cannot print to PID file $PID_file: $OS_ERROR"; close $PID_FH or die "Cannot close PID file $PID_file: $OS_ERROR"; PTDEBUG && _d('Created PID file:', $self->{PID_file}); return; } sub _remove_PID_file { my ( $self ) = @_; if ( $self->{PID_file} && -f $self->{PID_file} ) { unlink $self->{PID_file} or warn "Cannot remove PID file $self->{PID_file}: $OS_ERROR"; PTDEBUG && _d('Removed PID file'); } else { PTDEBUG && _d('No PID to remove'); } return; } sub DESTROY { my ( $self ) = @_; $self->_remove_PID_file() if ($self->{PID_owner} || 0) == $PID; return; } sub slurp_file { my ($file) = @_; return unless $file; open my $fh, "<", $file or die "Cannot open $file: $OS_ERROR"; return do { local $/; <$fh> }; } sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } map { defined $_ ? $_ : 'undef' } @_; print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; } 1; } # ########################################################################### # End Daemon package # ########################################################################### # ########################################################################### # PodParser package # This package is a copy without comments from the original. The original # with comments and its test file can be found in the Bazaar repository at, # lib/PodParser.pm # t/lib/PodParser.t # See https://launchpad.net/percona-toolkit for more information. # ########################################################################### { package PodParser; use strict; use warnings FATAL => 'all'; use English qw(-no_match_vars); use constant PTDEBUG => $ENV{PTDEBUG} || 0; my %parse_items_from = ( 'OPTIONS' => 1, 'DSN OPTIONS' => 1, 'RULES' => 1, ); my %item_pattern_for = ( 'OPTIONS' => qr/--(.*)/, 'DSN OPTIONS' => qr/\* (.)/, 'RULES' => qr/(.*)/, ); my %section_has_rules = ( 'OPTIONS' => 1, 'DSN OPTIONS' => 0, 'RULES' => 0, ); sub new { my ( $class, %args ) = @_; my $self = { current_section => '', current_item => '', items => {}, # keyed off SECTION magic => {}, # keyed off SECTION->magic ident (without MAGIC_) magic_ident => '', # set when next para is a magic para }; return bless $self, $class; } sub get_items { my ( $self, $section ) = @_; return $section ? $self->{items}->{$section} : $self->{items}; } sub get_magic { my ( $self, $section ) = @_; return $section ? $self->{magic}->{$section} : $self->{magic}; } sub parse_from_file { my ( $self, $file ) = @_; return unless $file; PTDEBUG && _d('Parsing POD in', $file); open my $fh, "<", $file or die "Cannot open $file: $OS_ERROR"; local $INPUT_RECORD_SEPARATOR = ''; # read paragraphs my $para; 1 while defined($para = <$fh>) && $para !~ m/^=pod/; die "$file does not contain =pod" unless $para; while ( defined($para = <$fh>) && $para !~ m/^=cut/ ) { if ( $para =~ m/^=(head|item|over|back)/ ) { my ($cmd, $name) = $para =~ m/^=(\w+)(?:\s+(.+))?/; $name ||= ''; PTDEBUG && _d('cmd:', $cmd, 'name:', $name); $self->command($cmd, $name); } elsif ( $parse_items_from{$self->{current_section}} ) { $self->textblock($para); } } close $fh; } sub command { my ( $self, $cmd, $name ) = @_; $name =~ s/\s+\Z//m; # Remove \n and blank line after name. if ( $cmd eq 'head1' ) { PTDEBUG && _d('In section', $name); $self->{current_section} = $name; } elsif ( $cmd eq 'over' ) { if ( $parse_items_from{$name} ) { PTDEBUG && _d('Start items in', $self->{current_section}); $self->{items}->{$self->{current_section}} = {}; } } elsif ( $cmd eq 'item' && $parse_items_from{$self->{current_section}} ) { my $pat = $item_pattern_for{ $self->{current_section} }; my ($item) = $name =~ m/$pat/; if ( $item ) { PTDEBUG && _d($self->{current_section}, 'item:', $item); $self->{items}->{ $self->{current_section} }->{$item} = { desc => '', # every item should have a desc }; $self->{current_item} = $item; } else { warn "Item $name does not match $pat"; } } elsif ( $cmd eq 'back' ) { if ( $parse_items_from{$self->{current_section}} ) { PTDEBUG && _d('End items in', $self->{current_section}); } } else { $self->{current_section} = ''; } return; } sub textblock { my ( $self, $para ) = @_; return unless $self->{current_section} && $self->{current_item}; my $section = $self->{current_section}; my $item = $self->{items}->{$section}->{ $self->{current_item} }; $para =~ s/\s+\Z//; if ( $para =~ m/^[a-z]\w+[:;] / ) { PTDEBUG && _d('Item attributes:', $para); map { my ($attrib, $val) = split(/: /, $_); $item->{$attrib} = defined $val ? $val : 1; } split(/; /, $para); } else { if ( $self->{magic_ident} ) { my ($leading_space) = $para =~ m/^(\s+)/; my $indent = length($leading_space || ''); if ( $indent ) { $para =~ s/^\s{$indent}//mg; $para =~ s/\s+$//; PTDEBUG && _d("MAGIC", $self->{magic_ident}, "para:", $para); $self->{magic}->{$self->{current_section}}->{$self->{magic_ident}} = $para; } else { PTDEBUG && _d("MAGIC", $self->{magic_ident}, "para is not indented; treating as normal para"); } $self->{magic_ident} = ''; # must unset this! } PTDEBUG && _d('Item desc:', substr($para, 0, 40), length($para) > 40 ? '...' : ''); $para =~ s/\n+/ /g; $item->{desc} .= $para; if ( $para =~ m/MAGIC_(\w+)/ ) { $self->{magic_ident} = $1; # XXX PTDEBUG && _d("MAGIC", $self->{magic_ident}, "follows"); } } return; } sub verbatim { my ( $self, $para ) = @_; return; } sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } map { defined $_ ? $_ : 'undef' } @_; print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; } 1; } # ########################################################################### # End PodParser package # ########################################################################### # ########################################################################### # TextResultSetParser package # This package is a copy without comments from the original. The original # with comments and its test file can be found in the Bazaar repository at, # lib/TextResultSetParser.pm # t/lib/TextResultSetParser.t # See https://launchpad.net/percona-toolkit for more information. # ########################################################################### { package TextResultSetParser; use strict; use warnings FATAL => 'all'; use English qw(-no_match_vars); use constant PTDEBUG => $ENV{PTDEBUG} || 0; sub new { my ( $class, %args ) = @_; my %value_for = ( 'NULL' => undef, # DBI::selectall_arrayref() does this ($args{value_for} ? %{$args{value_for}} : ()), ); my $self = { %args, value_for => \%value_for, }; return bless $self, $class; } sub _parse_tabular { my ( $text, @cols ) = @_; my %row; my @vals = $text =~ m/\| +([^\|]*?)(?= +\|)/msg; return (undef, \@vals) unless @cols; @row{@cols} = @vals; return (\%row, undef); } sub _parse_tab_sep { my ( $text, @cols ) = @_; my %row; my @vals = split(/\t/, $text); return (undef, \@vals) unless @cols; @row{@cols} = @vals; return (\%row, undef); } sub parse_vertical_row { my ( $self, $text ) = @_; my %row = $text =~ m/^\s*(\w+):(?: ([^\n]*))?/msg; if ( $self->{NAME_lc} ) { my %lc_row = map { my $key = lc $_; $key => $row{$_}; } keys %row; return \%lc_row; } else { return \%row; } } sub parse { my ( $self, $text ) = @_; my $result_set; if ( $text =~ m/^\+---/m ) { # standard "tabular" output PTDEBUG && _d('Result set text is standard tabular'); my $line_pattern = qr/^(\| .*)[\r\n]+/m; $result_set = $self->parse_horizontal_row($text, $line_pattern, \&_parse_tabular); } elsif ( $text =~ m/^\w+\t\w+/m ) { # tab-separated PTDEBUG && _d('Result set text is tab-separated'); my $line_pattern = qr/^(.*?\t.*)[\r\n]+/m; $result_set = $self->parse_horizontal_row($text, $line_pattern, \&_parse_tab_sep); } elsif ( $text =~ m/\*\*\* \d+\. row/ ) { # "vertical" output PTDEBUG && _d('Result set text is vertical (\G)'); foreach my $row ( split_vertical_rows($text) ) { push @$result_set, $self->parse_vertical_row($row); } } else { my $text_sample = substr $text, 0, 300; my $remaining = length $text > 300 ? (length $text) - 300 : 0; chomp $text_sample; die "Cannot determine if text is tabular, tab-separated or vertical:\n" . "$text_sample\n" . ($remaining ? "(not showing last $remaining bytes of text)\n" : ""); } if ( $self->{value_for} ) { foreach my $result_set ( @$result_set ) { foreach my $key ( keys %$result_set ) { next unless defined $result_set->{$key}; $result_set->{$key} = $self->{value_for}->{ $result_set->{$key} } if exists $self->{value_for}->{ $result_set->{$key} }; } } } return $result_set; } sub parse_horizontal_row { my ( $self, $text, $line_pattern, $sub ) = @_; my @result_sets = (); my @cols = (); foreach my $line ( $text =~ m/$line_pattern/g ) { my ( $row, $cols ) = $sub->($line, @cols); if ( $row ) { push @result_sets, $row; } else { @cols = map { $self->{NAME_lc} ? lc $_ : $_ } @$cols; } } return \@result_sets; } sub split_vertical_rows { my ( $text ) = @_; my $ROW_HEADER = '\*{3,} \d+\. row \*{3,}'; my @rows = $text =~ m/($ROW_HEADER.*?)(?=$ROW_HEADER|\z)/omgs; return @rows; } sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } map { defined $_ ? $_ : 'undef' } @_; print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; } 1; } # ########################################################################### # End TextResultSetParser package # ########################################################################### # ########################################################################### # Advisor package # This package is a copy without comments from the original. The original # with comments and its test file can be found in the Bazaar repository at, # lib/Advisor.pm # t/lib/Advisor.t # See https://launchpad.net/percona-toolkit for more information. # ########################################################################### { package Advisor; use strict; use warnings FATAL => 'all'; use English qw(-no_match_vars); use constant PTDEBUG => $ENV{PTDEBUG} || 0; sub new { my ( $class, %args ) = @_; foreach my $arg ( qw(match_type) ) { die "I need a $arg argument" unless $args{$arg}; } my $self = { %args, rules => [], # Rules from all advisor modules. rule_index_for => {}, # Maps rules by ID to their array index in $rules. rule_info => {}, # ID, severity, description, etc. for each rule. }; return bless $self, $class; } sub load_rules { my ( $self, $advisor ) = @_; return unless $advisor; PTDEBUG && _d('Loading rules from', ref $advisor); my $i = scalar @{$self->{rules}}; RULE: foreach my $rule ( $advisor->get_rules() ) { my $id = $rule->{id}; if ( $self->{ignore_rules}->{"$id"} ) { PTDEBUG && _d("Ignoring rule", $id); next RULE; } die "Rule $id already exists and cannot be redefined" if defined $self->{rule_index_for}->{$id}; push @{$self->{rules}}, $rule; $self->{rule_index_for}->{$id} = $i++; } return; } sub load_rule_info { my ( $self, $advisor ) = @_; return unless $advisor; PTDEBUG && _d('Loading rule info from', ref $advisor); my $rules = $self->{rules}; foreach my $rule ( @$rules ) { my $id = $rule->{id}; if ( $self->{ignore_rules}->{"$id"} ) { die "Rule $id was loaded but should be ignored"; } my $rule_info = $advisor->get_rule_info($id); next unless $rule_info; die "Info for rule $id already exists and cannot be redefined" if $self->{rule_info}->{$id}; $self->{rule_info}->{$id} = $rule_info; } return; } sub run_rules { my ( $self, %args ) = @_; my @matched_rules; my @matched_pos; my $rules = $self->{rules}; my $match_type = lc $self->{match_type}; foreach my $rule ( @$rules ) { eval { my $match = $rule->{code}->(%args); if ( $match_type eq 'pos' ) { if ( defined $match ) { PTDEBUG && _d('Matches rule', $rule->{id}, 'near pos', $match); push @matched_rules, $rule->{id}; push @matched_pos, $match; } } elsif ( $match_type eq 'bool' ) { if ( $match ) { PTDEBUG && _d("Matches rule", $rule->{id}); push @matched_rules, $rule->{id}; } } }; if ( $EVAL_ERROR ) { warn "Code for rule $rule->{id} caused an error: $EVAL_ERROR"; } } return \@matched_rules, \@matched_pos; }; sub get_rule_info { my ( $self, $id ) = @_; return unless $id; return $self->{rule_info}->{$id}; } sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } map { defined $_ ? $_ : 'undef' } @_; print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; } 1; } # ########################################################################### # End Advisor package # ########################################################################### # ########################################################################### # AdvisorRules package # This package is a copy without comments from the original. The original # with comments and its test file can be found in the Bazaar repository at, # lib/AdvisorRules.pm # t/lib/AdvisorRules.t # See https://launchpad.net/percona-toolkit for more information. # ########################################################################### { package AdvisorRules; use strict; use warnings FATAL => 'all'; use English qw(-no_match_vars); use constant PTDEBUG => $ENV{PTDEBUG} || 0; sub new { my ( $class, %args ) = @_; foreach my $arg ( qw(PodParser) ) { die "I need a $arg argument" unless $args{$arg}; } my $self = { %args, rules => [], rule_info => {}, }; return bless $self, $class; } sub load_rule_info { my ( $self, %args ) = @_; foreach my $arg ( qw(file section ) ) { die "I need a $arg argument" unless $args{$arg}; } my $rules = $args{rules} || $self->{rules}; my $p = $self->{PodParser}; $p->parse_from_file($args{file}); my $rule_items = $p->get_items($args{section}); my %seen; foreach my $rule_id ( keys %$rule_items ) { my $rule = $rule_items->{$rule_id}; die "Rule $rule_id has no description" unless $rule->{desc}; die "Rule $rule_id has no severity" unless $rule->{severity}; die "Rule $rule_id is already defined" if exists $self->{rule_info}->{$rule_id}; $self->{rule_info}->{$rule_id} = { id => $rule_id, severity => $rule->{severity}, description => $rule->{desc}, }; } foreach my $rule ( @$rules ) { die "There is no info for rule $rule->{id} in $args{file}" unless $self->{rule_info}->{ $rule->{id} }; } return; } sub get_rule_info { my ( $self, $id ) = @_; return unless $id; return $self->{rule_info}->{$id}; } sub _reset_rule_info { my ( $self ) = @_; $self->{rule_info} = {}; return; } sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } map { defined $_ ? $_ : 'undef' } @_; print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; } 1; } # ########################################################################### # End AdvisorRules package # ########################################################################### # ########################################################################### # VariableAdvisorRules package # This package is a copy without comments from the original. The original # with comments and its test file can be found in the Bazaar repository at, # lib/VariableAdvisorRules.pm # t/lib/VariableAdvisorRules.t # See https://launchpad.net/percona-toolkit for more information. # ########################################################################### { package VariableAdvisorRules; use base 'AdvisorRules'; use strict; use warnings FATAL => 'all'; use English qw(-no_match_vars); use constant PTDEBUG => $ENV{PTDEBUG} || 0; sub new { my ( $class, %args ) = @_; my $self = $class->SUPER::new(%args); @{$self->{rules}} = $self->get_rules(); PTDEBUG && _d(scalar @{$self->{rules}}, "rules"); return $self; } sub get_rules { return { id => 'auto_increment', code => sub { my ( %args ) = @_; my $vars = $args{variables}; return unless defined $vars->{auto_increment_increment} && defined $vars->{auto_increment_offset}; return $vars->{auto_increment_increment} != 1 || $vars->{auto_increment_offset} != 1 ? 1 : 0; }, }, { id => 'concurrent_insert', code => sub { my ( %args ) = @_; if ( $args{variables}->{concurrent_insert} && $args{variables}->{concurrent_insert} =~ m/[^\d]/ ) { return $args{variables}->{concurrent_insert} eq 'ALWAYS' ? 1 : 0; } return _var_gt($args{variables}->{concurrent_insert}, 1); }, }, { id => 'connect_timeout', code => sub { my ( %args ) = @_; return _var_gt($args{variables}->{connect_timeout}, 10); }, }, { id => 'debug', code => sub { my ( %args ) = @_; return $args{variables}->{debug} ? 1 : 0; }, }, { id => 'delay_key_write', code => sub { my ( %args ) = @_; return _var_seq($args{variables}->{delay_key_write}, "ON"); }, }, { id => 'flush', code => sub { my ( %args ) = @_; return _var_seq($args{variables}->{flush}, "ON"); }, }, { id => 'flush_time', code => sub { my ( %args ) = @_; return _var_gt($args{variables}->{flush_time}, 0); }, }, { id => 'have_bdb', code => sub { my ( %args ) = @_; return _var_seq($args{variables}->{have_bdb}, 'YES'); }, }, { id => 'init_connect', code => sub { my ( %args ) = @_; return $args{variables}->{init_connect} ? 1 : 0; }, }, { id => 'init_file', code => sub { my ( %args ) = @_; return $args{variables}->{init_file} ? 1 : 0; }, }, { id => 'init_slave', code => sub { my ( %args ) = @_; return $args{variables}->{init_slave} ? 1 : 0; }, }, { id => 'innodb_additional_mem_pool_size', code => sub { my ( %args ) = @_; return _var_gt($args{variables}->{innodb_additional_mem_pool_size}, 20 * 1_048_576); # 20M }, }, { id => 'innodb_buffer_pool_size', code => sub { my ( %args ) = @_; return _var_eq($args{variables}->{innodb_buffer_pool_size}, 10 * 1_048_576); # 10M }, }, { id => 'innodb_checksums', code => sub { my ( %args ) = @_; return _var_sneq($args{variables}->{innodb_checksums}, "ON"); }, }, { id => 'innodb_doublewrite', code => sub { my ( %args ) = @_; return _var_sneq($args{variables}->{innodb_doublewrite}, "ON"); }, }, { id => 'innodb_fast_shutdown', code => sub { my ( %args ) = @_; return _var_neq($args{variables}->{innodb_fast_shutdown}, 1); }, }, { id => 'innodb_flush_log_at_trx_commit-1', code => sub { my ( %args ) = @_; return _var_neq($args{variables}->{innodb_flush_log_at_trx_commit}, 1); }, }, { id => 'innodb_flush_log_at_trx_commit-2', code => sub { my ( %args ) = @_; return _var_eq($args{variables}->{innodb_flush_log_at_trx_commit}, 0); }, }, { id => 'innodb_force_recovery', code => sub { my ( %args ) = @_; return _var_gt($args{variables}->{innodb_force_recovery}, 0); }, }, { id => 'innodb_lock_wait_timeout', code => sub { my ( %args ) = @_; return _var_gt($args{variables}->{innodb_lock_wait_timeout}, 50); }, }, { id => 'innodb_log_buffer_size', code => sub { my ( %args ) = @_; return _var_gt($args{variables}->{innodb_log_buffer_size}, 16 * 1_048_576); # 16M }, }, { id => 'innodb_log_file_size', code => sub { my ( %args ) = @_; return _var_eq($args{variables}->{innodb_log_file_size}, 5 * 1_048_576); # 5M }, }, { id => 'innodb_max_dirty_pages_pct', code => sub { my ( %args ) = @_; my $mysql_version = $args{mysql_version}; return _var_lt($args{variables}->{innodb_max_dirty_pages_pct}, ($mysql_version < '5.5' ? 90 : 75)); }, }, { id => 'key_buffer_size', code => sub { my ( %args ) = @_; return _var_eq($args{variables}->{key_buffer_size}, 8 * 1_048_576); # 8M }, }, { id => 'large_pages', code => sub { my ( %args ) = @_; return _var_seq($args{variables}->{large_pages}, "ON"); }, }, { id => 'locked_in_memory', code => sub { my ( %args ) = @_; return _var_seq($args{variables}->{locked_in_memory}, "ON"); }, }, { id => 'log_warnings-1', code => sub { my ( %args ) = @_; return _var_eq($args{variables}->{log_warnings}, 0); }, }, { id => 'log_warnings-2', code => sub { my ( %args ) = @_; return _var_eq($args{variables}->{log_warnings}, 1); }, }, { id => 'low_priority_updates', code => sub { my ( %args ) = @_; return _var_seq($args{variables}->{low_priority_updates}, "ON"); }, }, { id => 'max_binlog_size', code => sub { my ( %args ) = @_; return _var_lt($args{variables}->{max_binlog_size}, 1 * 1_073_741_824); # 1G }, }, { id => 'max_connect_errors', code => sub { my ( %args ) = @_; return _var_eq($args{variables}->{max_connect_errors}, 10); }, }, { id => 'max_connections', code => sub { my ( %args ) = @_; return _var_gt($args{variables}->{max_connections}, 1_000); }, }, { id => 'myisam_repair_threads', code => sub { my ( %args ) = @_; return _var_gt($args{variables}->{myisam_repair_threads}, 1); }, }, { id => 'old_passwords', code => sub { my ( %args ) = @_; return _var_seq($args{variables}->{old_passwords}, "ON"); }, }, { id => 'optimizer_prune_level', code => sub { my ( %args ) = @_; return _var_lt($args{variables}->{optimizer_prune_level}, 1); }, }, { id => 'port', code => sub { my ( %args ) = @_; return _var_neq($args{variables}->{port}, 3306); }, }, { id => 'query_cache_size-1', code => sub { my ( %args ) = @_; return _var_gt($args{variables}->{query_cache_size}, 128 * 1_048_576); # 128M }, }, { id => 'query_cache_size-2', code => sub { my ( %args ) = @_; return _var_gt($args{variables}->{query_cache_size}, 512 * 1_048_576); # 512M }, }, { id => 'read_buffer_size-1', code => sub { my ( %args ) = @_; return _var_neq($args{variables}->{read_buffer_size}, 131_072); }, }, { id => 'read_buffer_size-2', code => sub { my ( %args ) = @_; return _var_gt($args{variables}->{read_buffer_size}, 8 * 1_048_576); # 8M }, }, { id => 'read_rnd_buffer_size-1', code => sub { my ( %args ) = @_; return _var_neq($args{variables}->{read_rnd_buffer_size}, 262_144); }, }, { id => 'read_rnd_buffer_size-2', code => sub { my ( %args ) = @_; return _var_gt($args{variables}->{read_rnd_buffer_size}, 4 * 1_048_576); # 4M }, }, { id => 'relay_log_space_limit', code => sub { my ( %args ) = @_; return _var_gt($args{variables}->{relay_log_space_limit}, 0); }, }, { id => 'slave_net_timeout', code => sub { my ( %args ) = @_; return _var_gt($args{variables}->{slave_net_timeout}, 60); }, }, { id => 'slave_skip_errors', code => sub { my ( %args ) = @_; return $args{variables}->{slave_skip_errors} && $args{variables}->{slave_skip_errors} ne 'OFF' ? 1 : 0; }, }, { id => 'sort_buffer_size-1', code => sub { my ( %args ) = @_; return _var_neq($args{variables}->{sort_buffer_size}, 2_097_144); }, }, { id => 'sort_buffer_size-2', code => sub { my ( %args ) = @_; return _var_gt($args{variables}->{sort_buffer_size}, 4 * 1_048_576); # 4M }, }, { id => 'sql_notes', code => sub { my ( %args ) = @_; return _var_seq($args{variables}->{sql_notes}, "OFF"); }, }, { id => 'sync_frm', code => sub { my ( %args ) = @_; return _var_sneq($args{variables}->{sync_frm}, "ON"); }, }, { id => 'tx_isolation-1', code => sub { my ( %args ) = @_; return _var_sneq($args{variables}->{tx_isolation}, "REPEATABLE-READ"); }, }, { id => 'tx_isolation-2', code => sub { my ( %args ) = @_; return _var_sneq($args{variables}->{tx_isolation}, "REPEATABLE-READ") && _var_sneq($args{variables}->{tx_isolation}, "READ-COMMITTED") ? 1 : 0; }, }, { id => 'expire_logs_days', code => sub { my ( %args ) = @_; return _var_eq($args{variables}->{expire_logs_days}, 0) && _var_seq($args{variables}->{log_bin}, "ON"); }, }, { id => 'innodb_file_io_threads', code => sub { my ( %args ) = @_; return _var_neq($args{variables}->{innodb_file_io_threads}, 4) && $OSNAME ne 'MSWin32' ? 1 : 0; }, }, { id => 'innodb_data_file_path', code => sub { my ( %args ) = @_; return ($args{variables}->{innodb_data_file_path} || '') =~ m/autoextend/ ? 1 : 0; }, }, { id => 'innodb_flush_method', code => sub { my ( %args ) = @_; return _var_sneq($args{variables}->{innodb_flush_method}, 'O_DIRECT') && $OSNAME ne 'MSWin32' ? 1 : 0; }, }, { id => 'innodb_locks_unsafe_for_binlog', code => sub { my ( %args ) = @_; return _var_seq($args{variables}->{innodb_locks_unsafe_for_binlog}, "ON") && _var_seq($args{variables}->{log_bin}, "ON"); }, }, { id => 'innodb_support_xa', code => sub { my ( %args ) = @_; return _var_sneq($args{variables}->{innodb_support_xa}, "ON") && _var_seq($args{variables}->{log_bin}, "ON"); }, }, { id => 'log_bin', code => sub { my ( %args ) = @_; return _var_sneq($args{variables}->{log_bin}, "ON"); }, }, { id => 'log_output', code => sub { my ( %args ) = @_; return ($args{variables}->{log_output} || '') =~ m/TABLE/i ? 1 : 0; }, }, { id => 'max_relay_log_size', code => sub { my ( %args ) = @_; return _var_gt($args{variables}->{max_relay_log_size}, 0) && _var_lt($args{variables}->{max_relay_log_size}, 1 * 1_073_741_824) ? 1 : 0; }, }, { id => 'myisam_recover_options', code => sub { my ( %args ) = @_; return _var_seq($args{variables}->{myisam_recover_options}, "OFF") || _var_seq($args{variables}->{myisam_recover_options}, "DEFAULT") ? 1 : 0; }, }, { id => 'storage_engine', code => sub { my ( %args ) = @_; return 0 unless $args{variables}->{storage_engine}; return $args{variables}->{storage_engine} !~ m/InnoDB|MyISAM/i ? 1 : 0; }, }, { id => 'sync_binlog', code => sub { my ( %args ) = @_; return _var_seq($args{variables}->{log_bin}, "ON") && ( _var_eq($args{variables}->{sync_binlog}, 0) || _var_gt($args{variables}->{sync_binlog}, 1)) ? 1 : 0; }, }, { id => 'tmp_table_size', code => sub { my ( %args ) = @_; return ($args{variables}->{tmp_table_size} || 0) > ($args{variables}->{max_heap_table_size} || 0) ? 1 : 0; }, }, { id => 'old mysql version', code => sub { my ( %args ) = @_; my $mysql_version = $args{mysql_version}; return 0 unless $mysql_version; return 1 if ($mysql_version == '3' && $mysql_version < '3.23' ) || ($mysql_version == '4' && $mysql_version < '4.1.20') || ($mysql_version == '5.0' && $mysql_version < '5.0.37') || ($mysql_version == '5.1' && $mysql_version < '5.1.30'); return 0; }, }, { id => 'end-of-life mysql version', code => sub { my ( %args ) = @_; my $mysql_version = $args{mysql_version}; return 0 unless $mysql_version; return $mysql_version < '5.1' ? 1 : 0; # 5.1.x }, }, }; sub _var_gt { my ($var, $val) = @_; return 0 unless defined $var; return $var > $val ? 1 : 0; } sub _var_lt { my ($var, $val) = @_; return 0 unless defined $var; return $var < $val ? 1 : 0; } sub _var_eq { my ($var, $val) = @_; return 0 unless defined $var; return $var == $val ? 1 : 0; } sub _var_neq { my ($var, $val) = @_; return 0 unless defined $var; return _var_eq($var, $val) ? 0 : 1; } sub _var_seq { my ($var, $val) = @_; return 0 unless defined $var; return $var eq $val ? 1 : 0; } sub _var_sneq { my ($var, $val) = @_; return 0 unless defined $var; return _var_seq($var, $val) ? 0 : 1; } sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } map { defined $_ ? $_ : 'undef' } @_; print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; } 1; } # ########################################################################### # End VariableAdvisorRules package # ########################################################################### # ########################################################################### # HTTP::Micro package # This package is a copy without comments from the original. The original # with comments and its test file can be found in the Bazaar repository at, # lib/HTTP/Micro.pm # t/lib/HTTP/Micro.t # See https://launchpad.net/percona-toolkit for more information. # ########################################################################### { package HTTP::Micro; our $VERSION = '0.01'; use strict; use warnings FATAL => 'all'; use English qw(-no_match_vars); use Carp (); my @attributes; BEGIN { @attributes = qw(agent timeout); no strict 'refs'; for my $accessor ( @attributes ) { *{$accessor} = sub { @_ > 1 ? $_[0]->{$accessor} = $_[1] : $_[0]->{$accessor}; }; } } sub new { my($class, %args) = @_; (my $agent = $class) =~ s{::}{-}g; my $self = { agent => $agent . "/" . ($class->VERSION || 0), timeout => 60, }; for my $key ( @attributes ) { $self->{$key} = $args{$key} if exists $args{$key} } return bless $self, $class; } my %DefaultPort = ( http => 80, https => 443, ); sub request { my ($self, $method, $url, $args) = @_; @_ == 3 || (@_ == 4 && ref $args eq 'HASH') or Carp::croak(q/Usage: $http->request(METHOD, URL, [HASHREF])/); $args ||= {}; # we keep some state in this during _request my $response; for ( 0 .. 1 ) { $response = eval { $self->_request($method, $url, $args) }; last unless $@ && $method eq 'GET' && $@ =~ m{^(?:Socket closed|Unexpected end)}; } if (my $e = "$@") { $response = { success => q{}, status => 599, reason => 'Internal Exception', content => $e, headers => { 'content-type' => 'text/plain', 'content-length' => length $e, } }; } return $response; } sub _request { my ($self, $method, $url, $args) = @_; my ($scheme, $host, $port, $path_query) = $self->_split_url($url); my $request = { method => $method, scheme => $scheme, host_port => ($port == $DefaultPort{$scheme} ? $host : "$host:$port"), uri => $path_query, headers => {}, }; my $handle = HTTP::Micro::Handle->new(timeout => $self->{timeout}); $handle->connect($scheme, $host, $port); $self->_prepare_headers_and_cb($request, $args); $handle->write_request_header(@{$request}{qw/method uri headers/}); $handle->write_content_body($request) if $request->{content}; my $response; do { $response = $handle->read_response_header } until (substr($response->{status},0,1) ne '1'); if (!($method eq 'HEAD' || $response->{status} =~ /^[23]04/)) { $response->{content} = ''; $handle->read_content_body(sub { $_[1]->{content} .= $_[0] }, $response); } $handle->close; $response->{success} = substr($response->{status},0,1) eq '2'; return $response; } sub _prepare_headers_and_cb { my ($self, $request, $args) = @_; for ($args->{headers}) { next unless defined; while (my ($k, $v) = each %$_) { $request->{headers}{lc $k} = $v; } } $request->{headers}{'host'} = $request->{host_port}; $request->{headers}{'connection'} = "close"; $request->{headers}{'user-agent'} ||= $self->{agent}; if (defined $args->{content}) { $request->{headers}{'content-type'} ||= "application/octet-stream"; utf8::downgrade($args->{content}, 1) or Carp::croak(q/Wide character in request message body/); $request->{headers}{'content-length'} = length $args->{content}; $request->{content} = $args->{content}; } return; } sub _split_url { my $url = pop; my ($scheme, $authority, $path_query) = $url =~ m<\A([^:/?#]+)://([^/?#]*)([^#]*)> or Carp::croak(qq/Cannot parse URL: '$url'/); $scheme = lc $scheme; $path_query = "/$path_query" unless $path_query =~ m<\A/>; my $host = (length($authority)) ? lc $authority : 'localhost'; $host =~ s/\A[^@]*@//; # userinfo my $port = do { $host =~ s/:([0-9]*)\z// && length $1 ? $1 : $DefaultPort{$scheme} }; return ($scheme, $host, $port, $path_query); } } # HTTP::Micro { package HTTP::Micro::Handle; use strict; use warnings FATAL => 'all'; use English qw(-no_match_vars); use Carp qw(croak); use Errno qw(EINTR EPIPE); use IO::Socket qw(SOCK_STREAM); sub BUFSIZE () { 32768 } my $Printable = sub { local $_ = shift; s/\r/\\r/g; s/\n/\\n/g; s/\t/\\t/g; s/([^\x20-\x7E])/sprintf('\\x%.2X', ord($1))/ge; $_; }; sub new { my ($class, %args) = @_; return bless { rbuf => '', timeout => 60, max_line_size => 16384, %args }, $class; } my $ssl_verify_args = { check_cn => "when_only", wildcards_in_alt => "anywhere", wildcards_in_cn => "anywhere" }; sub connect { @_ == 4 || croak(q/Usage: $handle->connect(scheme, host, port)/); my ($self, $scheme, $host, $port) = @_; if ( $scheme eq 'https' ) { eval "require IO::Socket::SSL" unless exists $INC{'IO/Socket/SSL.pm'}; croak(qq/IO::Socket::SSL must be installed for https support\n/) unless $INC{'IO/Socket/SSL.pm'}; } elsif ( $scheme ne 'http' ) { croak(qq/Unsupported URL scheme '$scheme'\n/); } $self->{fh} = IO::Socket::INET->new( PeerHost => $host, PeerPort => $port, Proto => 'tcp', Type => SOCK_STREAM, Timeout => $self->{timeout} ) or croak(qq/Could not connect to '$host:$port': $@/); binmode($self->{fh}) or croak(qq/Could not binmode() socket: '$!'/); if ( $scheme eq 'https') { IO::Socket::SSL->start_SSL($self->{fh}); ref($self->{fh}) eq 'IO::Socket::SSL' or die(qq/SSL connection failed for $host\n/); if ( $self->{fh}->can("verify_hostname") ) { $self->{fh}->verify_hostname( $host, $ssl_verify_args ) or die(qq/SSL certificate not valid for $host\n/); } else { my $fh = $self->{fh}; _verify_hostname_of_cert($host, _peer_certificate($fh), $ssl_verify_args) or die(qq/SSL certificate not valid for $host\n/); } } $self->{host} = $host; $self->{port} = $port; return $self; } sub close { @_ == 1 || croak(q/Usage: $handle->close()/); my ($self) = @_; CORE::close($self->{fh}) or croak(qq/Could not close socket: '$!'/); } sub write { @_ == 2 || croak(q/Usage: $handle->write(buf)/); my ($self, $buf) = @_; my $len = length $buf; my $off = 0; local $SIG{PIPE} = 'IGNORE'; while () { $self->can_write or croak(q/Timed out while waiting for socket to become ready for writing/); my $r = syswrite($self->{fh}, $buf, $len, $off); if (defined $r) { $len -= $r; $off += $r; last unless $len > 0; } elsif ($! == EPIPE) { croak(qq/Socket closed by remote server: $!/); } elsif ($! != EINTR) { croak(qq/Could not write to socket: '$!'/); } } return $off; } sub read { @_ == 2 || @_ == 3 || croak(q/Usage: $handle->read(len)/); my ($self, $len) = @_; my $buf = ''; my $got = length $self->{rbuf}; if ($got) { my $take = ($got < $len) ? $got : $len; $buf = substr($self->{rbuf}, 0, $take, ''); $len -= $take; } while ($len > 0) { $self->can_read or croak(q/Timed out while waiting for socket to become ready for reading/); my $r = sysread($self->{fh}, $buf, $len, length $buf); if (defined $r) { last unless $r; $len -= $r; } elsif ($! != EINTR) { croak(qq/Could not read from socket: '$!'/); } } if ($len) { croak(q/Unexpected end of stream/); } return $buf; } sub readline { @_ == 1 || croak(q/Usage: $handle->readline()/); my ($self) = @_; while () { if ($self->{rbuf} =~ s/\A ([^\x0D\x0A]* \x0D?\x0A)//x) { return $1; } $self->can_read or croak(q/Timed out while waiting for socket to become ready for reading/); my $r = sysread($self->{fh}, $self->{rbuf}, BUFSIZE, length $self->{rbuf}); if (defined $r) { last unless $r; } elsif ($! != EINTR) { croak(qq/Could not read from socket: '$!'/); } } croak(q/Unexpected end of stream while looking for line/); } sub read_header_lines { @_ == 1 || @_ == 2 || croak(q/Usage: $handle->read_header_lines([headers])/); my ($self, $headers) = @_; $headers ||= {}; my $lines = 0; my $val; while () { my $line = $self->readline; if ($line =~ /\A ([^\x00-\x1F\x7F:]+) : [\x09\x20]* ([^\x0D\x0A]*)/x) { my ($field_name) = lc $1; $val = \($headers->{$field_name} = $2); } elsif ($line =~ /\A [\x09\x20]+ ([^\x0D\x0A]*)/x) { $val or croak(q/Unexpected header continuation line/); next unless length $1; $$val .= ' ' if length $$val; $$val .= $1; } elsif ($line =~ /\A \x0D?\x0A \z/x) { last; } else { croak(q/Malformed header line: / . $Printable->($line)); } } return $headers; } sub write_header_lines { (@_ == 2 && ref $_[1] eq 'HASH') || croak(q/Usage: $handle->write_header_lines(headers)/); my($self, $headers) = @_; my $buf = ''; while (my ($k, $v) = each %$headers) { my $field_name = lc $k; $field_name =~ /\A [\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7A\x7C\x7E]+ \z/x or croak(q/Invalid HTTP header field name: / . $Printable->($field_name)); $field_name =~ s/\b(\w)/\u$1/g; $buf .= "$field_name: $v\x0D\x0A"; } $buf .= "\x0D\x0A"; return $self->write($buf); } sub read_content_body { @_ == 3 || @_ == 4 || croak(q/Usage: $handle->read_content_body(callback, response, [read_length])/); my ($self, $cb, $response, $len) = @_; $len ||= $response->{headers}{'content-length'}; croak("No content-length in the returned response, and this " . "UA doesn't implement chunking") unless defined $len; while ($len > 0) { my $read = ($len > BUFSIZE) ? BUFSIZE : $len; $cb->($self->read($read), $response); $len -= $read; } return; } sub write_content_body { @_ == 2 || croak(q/Usage: $handle->write_content_body(request)/); my ($self, $request) = @_; my ($len, $content_length) = (0, $request->{headers}{'content-length'}); $len += $self->write($request->{content}); $len == $content_length or croak(qq/Content-Length missmatch (got: $len expected: $content_length)/); return $len; } sub read_response_header { @_ == 1 || croak(q/Usage: $handle->read_response_header()/); my ($self) = @_; my $line = $self->readline; $line =~ /\A (HTTP\/(0*\d+\.0*\d+)) [\x09\x20]+ ([0-9]{3}) [\x09\x20]+ ([^\x0D\x0A]*) \x0D?\x0A/x or croak(q/Malformed Status-Line: / . $Printable->($line)); my ($protocol, $version, $status, $reason) = ($1, $2, $3, $4); return { status => $status, reason => $reason, headers => $self->read_header_lines, protocol => $protocol, }; } sub write_request_header { @_ == 4 || croak(q/Usage: $handle->write_request_header(method, request_uri, headers)/); my ($self, $method, $request_uri, $headers) = @_; return $self->write("$method $request_uri HTTP/1.1\x0D\x0A") + $self->write_header_lines($headers); } sub _do_timeout { my ($self, $type, $timeout) = @_; $timeout = $self->{timeout} unless defined $timeout && $timeout >= 0; my $fd = fileno $self->{fh}; defined $fd && $fd >= 0 or croak(q/select(2): 'Bad file descriptor'/); my $initial = time; my $pending = $timeout; my $nfound; vec(my $fdset = '', $fd, 1) = 1; while () { $nfound = ($type eq 'read') ? select($fdset, undef, undef, $pending) : select(undef, $fdset, undef, $pending) ; if ($nfound == -1) { $! == EINTR or croak(qq/select(2): '$!'/); redo if !$timeout || ($pending = $timeout - (time - $initial)) > 0; $nfound = 0; } last; } $! = 0; return $nfound; } sub can_read { @_ == 1 || @_ == 2 || croak(q/Usage: $handle->can_read([timeout])/); my $self = shift; return $self->_do_timeout('read', @_) } sub can_write { @_ == 1 || @_ == 2 || croak(q/Usage: $handle->can_write([timeout])/); my $self = shift; return $self->_do_timeout('write', @_) } } # HTTP::Micro::Handle my $prog = <<'EOP'; BEGIN { if ( defined &IO::Socket::SSL::CAN_IPV6 ) { *CAN_IPV6 = \*IO::Socket::SSL::CAN_IPV6; } else { constant->import( CAN_IPV6 => '' ); } my %const = ( NID_CommonName => 13, GEN_DNS => 2, GEN_IPADD => 7, ); while ( my ($name,$value) = each %const ) { no strict 'refs'; *{$name} = UNIVERSAL::can( 'Net::SSLeay', $name ) || sub { $value }; } } { use Carp qw(croak); my %dispatcher = ( issuer => sub { Net::SSLeay::X509_NAME_oneline( Net::SSLeay::X509_get_issuer_name( shift )) }, subject => sub { Net::SSLeay::X509_NAME_oneline( Net::SSLeay::X509_get_subject_name( shift )) }, ); if ( $Net::SSLeay::VERSION >= 1.30 ) { $dispatcher{commonName} = sub { my $cn = Net::SSLeay::X509_NAME_get_text_by_NID( Net::SSLeay::X509_get_subject_name( shift ), NID_CommonName); $cn =~s{\0$}{}; # work around Bug in Net::SSLeay <1.33 $cn; } } else { $dispatcher{commonName} = sub { croak "you need at least Net::SSLeay version 1.30 for getting commonName" } } if ( $Net::SSLeay::VERSION >= 1.33 ) { $dispatcher{subjectAltNames} = sub { Net::SSLeay::X509_get_subjectAltNames( shift ) }; } else { $dispatcher{subjectAltNames} = sub { return; }; } $dispatcher{authority} = $dispatcher{issuer}; $dispatcher{owner} = $dispatcher{subject}; $dispatcher{cn} = $dispatcher{commonName}; sub _peer_certificate { my ($self, $field) = @_; my $ssl = $self->_get_ssl_object or return; my $cert = ${*$self}{_SSL_certificate} ||= Net::SSLeay::get_peer_certificate($ssl) or return $self->error("Could not retrieve peer certificate"); if ($field) { my $sub = $dispatcher{$field} or croak "invalid argument for peer_certificate, valid are: ".join( " ",keys %dispatcher ). "\nMaybe you need to upgrade your Net::SSLeay"; return $sub->($cert); } else { return $cert } } my %scheme = ( ldap => { wildcards_in_cn => 0, wildcards_in_alt => 'leftmost', check_cn => 'always', }, http => { wildcards_in_cn => 'anywhere', wildcards_in_alt => 'anywhere', check_cn => 'when_only', }, smtp => { wildcards_in_cn => 0, wildcards_in_alt => 0, check_cn => 'always' }, none => {}, # do not check ); $scheme{www} = $scheme{http}; # alias $scheme{xmpp} = $scheme{http}; # rfc 3920 $scheme{pop3} = $scheme{ldap}; # rfc 2595 $scheme{imap} = $scheme{ldap}; # rfc 2595 $scheme{acap} = $scheme{ldap}; # rfc 2595 $scheme{nntp} = $scheme{ldap}; # rfc 4642 $scheme{ftp} = $scheme{http}; # rfc 4217 sub _verify_hostname_of_cert { my $identity = shift; my $cert = shift; my $scheme = shift || 'none'; if ( ! ref($scheme) ) { $scheme = $scheme{$scheme} or croak "scheme $scheme not defined"; } return 1 if ! %$scheme; # 'none' my $commonName = $dispatcher{cn}->($cert); my @altNames = $dispatcher{subjectAltNames}->($cert); if ( my $sub = $scheme->{callback} ) { return $sub->($identity,$commonName,@altNames); } my $ipn; if ( CAN_IPV6 and $identity =~m{:} ) { $ipn = IO::Socket::SSL::inet_pton(IO::Socket::SSL::AF_INET6,$identity) or croak "'$identity' is not IPv6, but neither IPv4 nor hostname"; } elsif ( $identity =~m{^\d+\.\d+\.\d+\.\d+$} ) { $ipn = IO::Socket::SSL::inet_aton( $identity ) or croak "'$identity' is not IPv4, but neither IPv6 nor hostname"; } else { if ( $identity =~m{[^a-zA-Z0-9_.\-]} ) { $identity =~m{\0} and croak("name '$identity' has \\0 byte"); $identity = IO::Socket::SSL::idn_to_ascii($identity) or croak "Warning: Given name '$identity' could not be converted to IDNA!"; } } my $check_name = sub { my ($name,$identity,$wtyp) = @_; $wtyp ||= ''; my $pattern; if ( $wtyp eq 'anywhere' and $name =~m{^([a-zA-Z0-9_\-]*)\*(.+)} ) { $pattern = qr{^\Q$1\E[a-zA-Z0-9_\-]*\Q$2\E$}i; } elsif ( $wtyp eq 'leftmost' and $name =~m{^\*(\..+)$} ) { $pattern = qr{^[a-zA-Z0-9_\-]*\Q$1\E$}i; } else { $pattern = qr{^\Q$name\E$}i; } return $identity =~ $pattern; }; my $alt_dnsNames = 0; while (@altNames) { my ($type, $name) = splice (@altNames, 0, 2); if ( $ipn and $type == GEN_IPADD ) { return 1 if $ipn eq $name; } elsif ( ! $ipn and $type == GEN_DNS ) { $name =~s/\s+$//; $name =~s/^\s+//; $alt_dnsNames++; $check_name->($name,$identity,$scheme->{wildcards_in_alt}) and return 1; } } if ( ! $ipn and ( $scheme->{check_cn} eq 'always' or $scheme->{check_cn} eq 'when_only' and !$alt_dnsNames)) { $check_name->($commonName,$identity,$scheme->{wildcards_in_cn}) and return 1; } return 0; # no match } } EOP eval { require IO::Socket::SSL }; if ( $INC{"IO/Socket/SSL.pm"} ) { eval $prog; die $@ if $@; } 1; # ########################################################################### # End HTTP::Micro package # ########################################################################### # ########################################################################### # VersionCheck package # This package is a copy without comments from the original. The original # with comments and its test file can be found in the Bazaar repository at, # lib/VersionCheck.pm # t/lib/VersionCheck.t # See https://launchpad.net/percona-toolkit for more information. # ########################################################################### { package VersionCheck; use strict; use warnings FATAL => 'all'; use English qw(-no_match_vars); use constant PTDEBUG => $ENV{PTDEBUG} || 0; use Data::Dumper; local $Data::Dumper::Indent = 1; local $Data::Dumper::Sortkeys = 1; local $Data::Dumper::Quotekeys = 0; use Digest::MD5 qw(md5_hex); use Sys::Hostname qw(hostname); use File::Basename qw(); use File::Spec; use FindBin qw(); eval { require Percona::Toolkit; require HTTP::Micro; }; { my $file = 'percona-version-check'; my $home = $ENV{HOME} || $ENV{HOMEPATH} || $ENV{USERPROFILE} || '.'; my @vc_dirs = ( '/etc/percona', '/etc/percona-toolkit', '/tmp', "$home", ); sub version_check_file { foreach my $dir ( @vc_dirs ) { if ( -d $dir && -w $dir ) { PTDEBUG && _d('Version check file', $file, 'in', $dir); return $dir . '/' . $file; } } PTDEBUG && _d('Version check file', $file, 'in', $ENV{PWD}); return $file; # in the CWD } } sub version_check_time_limit { return 60 * 60 * 24; # one day } sub version_check { my (%args) = @_; my $instances = $args{instances} || []; my $instances_to_check; PTDEBUG && _d('FindBin::Bin:', $FindBin::Bin); if ( !$args{force} ) { if ( $FindBin::Bin && (-d "$FindBin::Bin/../.bzr" || -d "$FindBin::Bin/../../.bzr" || -d "$FindBin::Bin/../.git" || -d "$FindBin::Bin/../../.git" ) ) { PTDEBUG && _d("$FindBin::Bin/../.bzr disables --version-check"); return; } } eval { foreach my $instance ( @$instances ) { my ($name, $id) = get_instance_id($instance); $instance->{name} = $name; $instance->{id} = $id; } push @$instances, { name => 'system', id => 0 }; $instances_to_check = get_instances_to_check( instances => $instances, vc_file => $args{vc_file}, # testing now => $args{now}, # testing ); PTDEBUG && _d(scalar @$instances_to_check, 'instances to check'); return unless @$instances_to_check; my $protocol = 'https'; eval { require IO::Socket::SSL; }; if ( $EVAL_ERROR ) { PTDEBUG && _d($EVAL_ERROR); PTDEBUG && _d("SSL not available, won't run version_check"); return; } PTDEBUG && _d('Using', $protocol); my $advice = pingback( instances => $instances_to_check, protocol => $protocol, url => $args{url} # testing || $ENV{PERCONA_VERSION_CHECK_URL} # testing || "$protocol://v.percona.com", ); if ( $advice ) { PTDEBUG && _d('Advice:', Dumper($advice)); if ( scalar @$advice > 1) { print "\n# " . scalar @$advice . " software updates are " . "available:\n"; } else { print "\n# A software update is available:\n"; } print join("\n", map { "# * $_" } @$advice), "\n\n"; } }; if ( $EVAL_ERROR ) { PTDEBUG && _d('Version check failed:', $EVAL_ERROR); } if ( @$instances_to_check ) { eval { update_check_times( instances => $instances_to_check, vc_file => $args{vc_file}, # testing now => $args{now}, # testing ); }; if ( $EVAL_ERROR ) { PTDEBUG && _d('Error updating version check file:', $EVAL_ERROR); } } if ( $ENV{PTDEBUG_VERSION_CHECK} ) { warn "Exiting because the PTDEBUG_VERSION_CHECK " . "environment variable is defined.\n"; exit 255; } return; } sub get_instances_to_check { my (%args) = @_; my $instances = $args{instances}; my $now = $args{now} || int(time); my $vc_file = $args{vc_file} || version_check_file(); if ( !-f $vc_file ) { PTDEBUG && _d('Version check file', $vc_file, 'does not exist;', 'version checking all instances'); return $instances; } open my $fh, '<', $vc_file or die "Cannot open $vc_file: $OS_ERROR"; chomp(my $file_contents = do { local $/ = undef; <$fh> }); PTDEBUG && _d('Version check file', $vc_file, 'contents:', $file_contents); close $fh; my %last_check_time_for = $file_contents =~ /^([^,]+),(.+)$/mg; my $check_time_limit = version_check_time_limit(); my @instances_to_check; foreach my $instance ( @$instances ) { my $last_check_time = $last_check_time_for{ $instance->{id} }; PTDEBUG && _d('Intsance', $instance->{id}, 'last checked', $last_check_time, 'now', $now, 'diff', $now - ($last_check_time || 0), 'hours until next check', sprintf '%.2f', ($check_time_limit - ($now - ($last_check_time || 0))) / 3600); if ( !defined $last_check_time || ($now - $last_check_time) >= $check_time_limit ) { PTDEBUG && _d('Time to check', Dumper($instance)); push @instances_to_check, $instance; } } return \@instances_to_check; } sub update_check_times { my (%args) = @_; my $instances = $args{instances}; my $now = $args{now} || int(time); my $vc_file = $args{vc_file} || version_check_file(); PTDEBUG && _d('Updating last check time:', $now); my %all_instances = map { $_->{id} => { name => $_->{name}, ts => $now } } @$instances; if ( -f $vc_file ) { open my $fh, '<', $vc_file or die "Cannot read $vc_file: $OS_ERROR"; my $contents = do { local $/ = undef; <$fh> }; close $fh; foreach my $line ( split("\n", ($contents || '')) ) { my ($id, $ts) = split(',', $line); if ( !exists $all_instances{$id} ) { $all_instances{$id} = { ts => $ts }; # original ts, not updated } } } open my $fh, '>', $vc_file or die "Cannot write to $vc_file: $OS_ERROR"; foreach my $id ( sort keys %all_instances ) { PTDEBUG && _d('Updated:', $id, Dumper($all_instances{$id})); print { $fh } $id . ',' . $all_instances{$id}->{ts} . "\n"; } close $fh; return; } sub get_instance_id { my ($instance) = @_; my $dbh = $instance->{dbh}; my $dsn = $instance->{dsn}; my $sql = q{SELECT CONCAT(@@hostname, @@port)}; PTDEBUG && _d($sql); my ($name) = eval { $dbh->selectrow_array($sql) }; if ( $EVAL_ERROR ) { PTDEBUG && _d($EVAL_ERROR); $sql = q{SELECT @@hostname}; PTDEBUG && _d($sql); ($name) = eval { $dbh->selectrow_array($sql) }; if ( $EVAL_ERROR ) { PTDEBUG && _d($EVAL_ERROR); $name = ($dsn->{h} || 'localhost') . ($dsn->{P} || 3306); } else { $sql = q{SHOW VARIABLES LIKE 'port'}; PTDEBUG && _d($sql); my (undef, $port) = eval { $dbh->selectrow_array($sql) }; PTDEBUG && _d('port:', $port); $name .= $port || ''; } } my $id = md5_hex($name); PTDEBUG && _d('MySQL instance:', $id, $name, Dumper($dsn)); return $name, $id; } sub pingback { my (%args) = @_; my @required_args = qw(url instances); foreach my $arg ( @required_args ) { die "I need a $arg arugment" unless $args{$arg}; } my $url = $args{url}; my $instances = $args{instances}; my $ua = $args{ua} || HTTP::Micro->new( timeout => 3 ); my $response = $ua->request('GET', $url); PTDEBUG && _d('Server response:', Dumper($response)); die "No response from GET $url" if !$response; die("GET on $url returned HTTP status $response->{status}; expected 200\n", ($response->{content} || '')) if $response->{status} != 200; die("GET on $url did not return any programs to check") if !$response->{content}; my $items = parse_server_response( response => $response->{content} ); die "Failed to parse server requested programs: $response->{content}" if !scalar keys %$items; my $versions = get_versions( items => $items, instances => $instances, ); die "Failed to get any program versions; should have at least gotten Perl" if !scalar keys %$versions; my $client_content = encode_client_response( items => $items, versions => $versions, general_id => md5_hex( hostname() ), ); my $client_response = { headers => { "X-Percona-Toolkit-Tool" => File::Basename::basename($0) }, content => $client_content, }; PTDEBUG && _d('Client response:', Dumper($client_response)); $response = $ua->request('POST', $url, $client_response); PTDEBUG && _d('Server suggestions:', Dumper($response)); die "No response from POST $url $client_response" if !$response; die "POST $url returned HTTP status $response->{status}; expected 200" if $response->{status} != 200; return unless $response->{content}; $items = parse_server_response( response => $response->{content}, split_vars => 0, ); die "Failed to parse server suggestions: $response->{content}" if !scalar keys %$items; my @suggestions = map { $_->{vars} } sort { $a->{item} cmp $b->{item} } values %$items; return \@suggestions; } sub encode_client_response { my (%args) = @_; my @required_args = qw(items versions general_id); foreach my $arg ( @required_args ) { die "I need a $arg arugment" unless $args{$arg}; } my ($items, $versions, $general_id) = @args{@required_args}; my @lines; foreach my $item ( sort keys %$items ) { next unless exists $versions->{$item}; if ( ref($versions->{$item}) eq 'HASH' ) { my $mysql_versions = $versions->{$item}; for my $id ( sort keys %$mysql_versions ) { push @lines, join(';', $id, $item, $mysql_versions->{$id}); } } else { push @lines, join(';', $general_id, $item, $versions->{$item}); } } my $client_response = join("\n", @lines) . "\n"; return $client_response; } sub parse_server_response { my (%args) = @_; my @required_args = qw(response); foreach my $arg ( @required_args ) { die "I need a $arg arugment" unless $args{$arg}; } my ($response) = @args{@required_args}; my %items = map { my ($item, $type, $vars) = split(";", $_); if ( !defined $args{split_vars} || $args{split_vars} ) { $vars = [ split(",", ($vars || '')) ]; } $item => { item => $item, type => $type, vars => $vars, }; } split("\n", $response); PTDEBUG && _d('Items:', Dumper(\%items)); return \%items; } my %sub_for_type = ( os_version => \&get_os_version, perl_version => \&get_perl_version, perl_module_version => \&get_perl_module_version, mysql_variable => \&get_mysql_variable, ); sub valid_item { my ($item) = @_; return unless $item; if ( !exists $sub_for_type{ $item->{type} } ) { PTDEBUG && _d('Invalid type:', $item->{type}); return 0; } return 1; } sub get_versions { my (%args) = @_; my @required_args = qw(items); foreach my $arg ( @required_args ) { die "I need a $arg arugment" unless $args{$arg}; } my ($items) = @args{@required_args}; my %versions; foreach my $item ( values %$items ) { next unless valid_item($item); eval { my $version = $sub_for_type{ $item->{type} }->( item => $item, instances => $args{instances}, ); if ( $version ) { chomp $version unless ref($version); $versions{$item->{item}} = $version; } }; if ( $EVAL_ERROR ) { PTDEBUG && _d('Error getting version for', Dumper($item), $EVAL_ERROR); } } return \%versions; } sub get_os_version { if ( $OSNAME eq 'MSWin32' ) { require Win32; return Win32::GetOSDisplayName(); } chomp(my $platform = `uname -s`); PTDEBUG && _d('platform:', $platform); return $OSNAME unless $platform; chomp(my $lsb_release = `which lsb_release 2>/dev/null | awk '{print \$1}'` || ''); PTDEBUG && _d('lsb_release:', $lsb_release); my $release = ""; if ( $platform eq 'Linux' ) { if ( -f "/etc/fedora-release" ) { $release = `cat /etc/fedora-release`; } elsif ( -f "/etc/redhat-release" ) { $release = `cat /etc/redhat-release`; } elsif ( -f "/etc/system-release" ) { $release = `cat /etc/system-release`; } elsif ( $lsb_release ) { $release = `$lsb_release -ds`; } elsif ( -f "/etc/lsb-release" ) { $release = `grep DISTRIB_DESCRIPTION /etc/lsb-release`; $release =~ s/^\w+="([^"]+)".+/$1/; } elsif ( -f "/etc/debian_version" ) { chomp(my $rel = `cat /etc/debian_version`); $release = "Debian $rel"; if ( -f "/etc/apt/sources.list" ) { chomp(my $code_name = `awk '/^deb/ {print \$3}' /etc/apt/sources.list | awk -F/ '{print \$1}'| awk 'BEGIN {FS="|"} {print \$1}' | sort | uniq -c | sort -rn | head -n1 | awk '{print \$2}'`); $release .= " ($code_name)" if $code_name; } } elsif ( -f "/etc/os-release" ) { # openSUSE chomp($release = `grep PRETTY_NAME /etc/os-release`); $release =~ s/^PRETTY_NAME="(.+)"$/$1/; } elsif ( `ls /etc/*release 2>/dev/null` ) { if ( `grep DISTRIB_DESCRIPTION /etc/*release 2>/dev/null` ) { $release = `grep DISTRIB_DESCRIPTION /etc/*release | head -n1`; } else { $release = `cat /etc/*release | head -n1`; } } } elsif ( $platform =~ m/(?:BSD|^Darwin)$/ ) { my $rel = `uname -r`; $release = "$platform $rel"; } elsif ( $platform eq "SunOS" ) { my $rel = `head -n1 /etc/release` || `uname -r`; $release = "$platform $rel"; } if ( !$release ) { PTDEBUG && _d('Failed to get the release, using platform'); $release = $platform; } chomp($release); $release =~ s/^"|"$//g; PTDEBUG && _d('OS version =', $release); return $release; } sub get_perl_version { my (%args) = @_; my $item = $args{item}; return unless $item; my $version = sprintf '%vd', $PERL_VERSION; PTDEBUG && _d('Perl version', $version); return $version; } sub get_perl_module_version { my (%args) = @_; my $item = $args{item}; return unless $item; my $var = '$' . $item->{item} . '::VERSION'; my $version = eval "use $item->{item}; $var;"; PTDEBUG && _d('Perl version for', $var, '=', $version); return $version; } sub get_mysql_variable { return get_from_mysql( show => 'VARIABLES', @_, ); } sub get_from_mysql { my (%args) = @_; my $show = $args{show}; my $item = $args{item}; my $instances = $args{instances}; return unless $show && $item; if ( !$instances || !@$instances ) { PTDEBUG && _d('Cannot check', $item, 'because there are no MySQL instances'); return; } if ($item->{item} eq 'MySQL' && $item->{type} eq 'mysql_variable') { @{$item->{vars}} = grep { $_ eq 'version' || $_ eq 'version_comment' } @{$item->{vars}}; } my @versions; my %version_for; foreach my $instance ( @$instances ) { next unless $instance->{id}; # special system instance has id=0 my $dbh = $instance->{dbh}; local $dbh->{FetchHashKeyName} = 'NAME_lc'; my $sql = qq/SHOW $show/; PTDEBUG && _d($sql); my $rows = $dbh->selectall_hashref($sql, 'variable_name'); my @versions; foreach my $var ( @{$item->{vars}} ) { $var = lc($var); my $version = $rows->{$var}->{value}; PTDEBUG && _d('MySQL version for', $item->{item}, '=', $version, 'on', $instance->{name}); push @versions, $version; } $version_for{ $instance->{id} } = join(' ', @versions); } return \%version_for; } sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } map { defined $_ ? $_ : 'undef' } @_; print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; } 1; } # ########################################################################### # End VersionCheck package # ########################################################################### # ########################################################################### # This is a combination of modules and programs in one -- a runnable module. # http://www.perl.com/pub/a/2006/07/13/lightning-articles.html?page=last # Or, look it up in the Camel book on pages 642 and 643 in the 3rd edition. # # Check at the end of this package for the call to main() which actually runs # the program. # ########################################################################### package pt_variable_advisor; use strict; use warnings FATAL => 'all'; use English qw(-no_match_vars); use Percona::Toolkit; use constant PTDEBUG => $ENV{PTDEBUG} || 0; sub main { local @ARGV = @_; # set global ARGV for this package # ######################################################################## # Get configuration information. # ######################################################################## my $o = new OptionParser(); $o->get_specs(); $o->get_opts(); my $dp = $o->DSNParser(); $dp->prop('set-vars', $o->set_vars()); my $vars_from = $o->get('source-of-variables'); # my $status_from = lc $o->get('source-of-status'); # my $slave_status_from = lc $o->get('source-of-slave-status'); my $need_dbh = $vars_from =~ m/^mysql$/i; # || $status_from eq 'mysql' etc. if ( !$o->get('help') ) { if ( $vars_from =~ m/^mysql$/i && @ARGV == 0 ) { $o->save_error("A DSN must be specified when --source-of-variables=mysql"); } } $o->usage_or_errors(); # ######################################################################### # Check that any files given exit. # ######################################################################### if ( $vars_from !~ m/^mysql|none^/i ) { die "The --source-of-variables file $vars_from does not exist" unless -f $vars_from; } # ######################################################################### # Load rules from POD and plugins. # ######################################################################### my $p = new PodParser(); my $var = new VariableAdvisorRules(PodParser => $p); my $adv = new Advisor( match_type => "bool", ignore_rules => $o->get('ignore-rules'), ); $var->load_rule_info( file => __FILE__, section => 'RULES', ); $adv->load_rules($var); $adv->load_rule_info($var); # TODO: load rules from plugins # ######################################################################### # Make common modules. # ######################################################################### my $trp = new TextResultSetParser(); my %common_modules = ( OptionParser => $o, DSNParser => $dp, TextResultSetParser => $trp, ); # ########################################################################## # Connect to MySQL if any of the input sources is mysql. # ########################################################################## my ($dbh, $dsn); if ( $need_dbh ) { my $dsn_defaults = $dp->parse_options($o); $dsn = $dp->parse(shift @ARGV, $dsn_defaults); if ( $o->get('ask-pass') ) { $dsn->{p} = OptionParser::prompt_noecho("Enter password: "); } $dbh = $dp->get_dbh($dp->get_cxn_params($dsn), {AutoCommit => 1}); $dbh->{FetchHashKeyName} = 'NAME_lc'; PTDEBUG && _d('Connected dbh', $dbh); } # ######################################################################## # Daemonize now that everything is setup and ready to work. # ######################################################################## my $daemon; if ( $o->get('daemonize') ) { $daemon = new Daemon(o=>$o); $daemon->daemonize(); PTDEBUG && _d('I am a daemon now'); } elsif ( $o->get('pid') ) { # We're not daemoninzing, it just handles PID stuff. $daemon = new Daemon(o=>$o); $daemon->make_PID_file(); } # ######################################################################## # Do the version-check # ######################################################################## if ( $o->get('version-check') && (!$o->has('quiet') || !$o->get('quiet')) ) { VersionCheck::version_check( force => $o->got('version-check'), instances => [ ($dbh ? { dbh => $dbh, dsn => $dsn } : ()) ], ); } # ######################################################################### # Get the variables and other MySQL info to pass to rules. # ######################################################################### my $vars = get_variables( source => $vars_from, dbh => $dbh, %common_modules, ); my $mysql_version = VersionParser->new($vars->{version}); my $innodb_version = VersionParser->new($dbh)->innodb_version() if $dbh; PTDEBUG && _d("MySQL version", $mysql_version, "InnoDB version", $innodb_version); # ######################################################################### # Run rules, print advice. # ######################################################################### my ($advice) = $adv->run_rules( variables => $vars, mysql_version => $mysql_version, innodb_version => $innodb_version, %common_modules, ); print_advice( advice => $advice, Advisor => $adv, %common_modules, ); return 0; } # ########################################################################## # Subroutines # ########################################################################## # Sub: get_variables # Get SHOW VARIABLES from MySQL or a file. # # Parameters: # %args - Arguments # # Required Arguments: # source - "mysql" or a file name # # Optional Arguments: # dbh - dbh if source=="mysql" # TextResultSetParser - <TextResultSetParser> object if source==file # # Returns: # Hashref of SHOW /*40003 GLOBAL*/ VARIABLES values. sub get_variables { my ( %args ) = @_; my @required_args = qw(source); foreach my $arg ( @required_args ) { die "I need a $arg argument" unless $args{$arg}; } my ($source) = @args{@required_args}; my $vars; if ( ($source || '') =~ m/^mysql$/i ) { my $dbh = $args{dbh}; die "I need a dbh argument" unless $dbh; PTDEBUG && _d("Getting variables from dbh", $dbh); my $sql = "SHOW /*40003 GLOBAL*/ VARIABLES"; PTDEBUG && _d($dbh, $sql); map { $vars->{$_->{variable_name}} = $_->{value}; } @{ $dbh->selectall_arrayref($sql, {Slice=>{}}) }; } else { my $trp = $args{TextResultSetParser}; die "I need a TextResultSetParser arg" unless $trp; PTDEBUG && _d("Getting variables from", $source); open my $fh, "<", $source or die "Cannot open $source: $OS_ERROR"; my $contents = do { local $/ = undef; <$fh> }; close $fh; map { $vars->{$_->{Variable_name}} = $_->{Value} } @{ $trp->parse($contents) }; } return $vars; } # Sub: print_advice # Print information about rules that matched. # # Parameters: # %args - Arguments # # Required Arguments: # advice - Arrayref of rule IDs, returned by <Advisor::run_rules()> # Advisor - <Advisor> object # OptionParser - <OptionParser> object sub print_advice { my ( %args ) = @_; my @required_args = qw(advice Advisor OptionParser); foreach my $arg ( @required_args ) { die "I need a $arg argument" unless $args{$arg}; } my ($advice, $adv, $o) = @args{@required_args}; my $verbose = $o->get('verbose'); return unless scalar @$advice; foreach my $id ( @$advice ) { my $info = $adv->get_rule_info($id); my @desc = map { $_ .= '.' unless m/[.?]$/; $_; } split(/(?<=[.?])\s{1,2}/, $info->{description} || ''); $desc[1] ||= ""; # Some desc have only 1 sentence. my $desc = $verbose == 1 ? $desc[0] # terse : $verbose == 2 ? "$desc[0] $desc[1]" # fuller : $verbose > 2 ? $info->{description} # complete : ''; # none print "# ", uc $info->{severity}, " $id: $desc\n\n"; } return; } sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } map { defined $_ ? $_ : 'undef' } @_; print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; } # ############################################################################ # Run the program. # ############################################################################ if ( !caller ) { exit main(@ARGV); } 1; # Because this is a module as well as a script. # ############################################################################ # Documentation # ############################################################################ =pod =head1 NAME pt-variable-advisor - Analyze MySQL variables and advise on possible problems. =head1 SYNOPSIS Usage: pt-variable-advisor [OPTIONS] [DSN] pt-variable-advisor analyzes variables and advises on possible problems. Get SHOW VARIABLES from localhost: pt-variable-advisor localhost Get SHOW VARIABLES output saved in vars.txt: pt-variable-advisor --source-of-variables vars.txt =head1 RISKS Percona Toolkit is mature, proven in the real world, and well tested, but all database tools can pose a risk to the system and the database server. Before using this tool, please: =over =item * Read the tool's documentation =item * Review the tool's known L<"BUGS"> =item * Test the tool on a non-production server =item * Backup your production server and verify the backups =back =head1 DESCRIPTION pt-variable-advisor examines C<SHOW VARIABLES> for bad values and settings according to the L<"RULES"> described below. It reports on variables that match the rules, so you can find bad settings in your MySQL server. At the time of this release, pt-variable-advisor only examples C<SHOW VARIABLES>, but other input sources are planned like C<SHOW STATUS> and C<SHOW SLAVE STATUS>. =head1 RULES These are the rules that pt-variable-advisor will apply to SHOW VARIABLES. Each rule has three parts: an ID, a severity, and a description. The rule's ID is a short, unique name for the rule. It usually relates to the variable that the rule examines. If a variable is examined by several rules, then the rules' IDs are numbered like "-1", "-2", "-N". The rule's severity is an indication of how important it is that this rule matched a query. We use NOTE, WARN, and CRIT to denote these levels. The rule's description is a textual, human-readable explanation of what it means when a variable matches this rule. Depending on the verbosity of the report you generate, you will see more of the text in the description. By default, you'll see only the first sentence, which is sort of a terse synopsis of the rule's meaning. At a higher verbosity, you'll see subsequent sentences. =over =item auto_increment severity: note Are you trying to write to more than one server in a dual-master or ring replication configuration? This is potentially very dangerous and in most cases is a serious mistake. Most people's reasons for doing this are actually not valid at all. =item concurrent_insert severity: note Holes (spaces left by deletes) in MyISAM tables might never be reused. =item connect_timeout severity: note A large value of this setting can create a denial of service vulnerability. =item debug severity: crit Servers built with debugging capability should not be used in production because of the large performance impact. =item delay_key_write severity: warn MyISAM index blocks are never flushed until necessary. If there is a server crash, data corruption on MyISAM tables can be much worse than usual. =item flush severity: warn This option might decrease performance greatly. =item flush_time severity: warn This option might decrease performance greatly. =item have_bdb severity: note The BDB engine is deprecated. If you aren't using it, you should disable it with the skip_bdb option. =item init_connect severity: note The init_connect option is enabled on this server. =item init_file severity: note The init_file option is enabled on this server. =item init_slave severity: note The init_slave option is enabled on this server. =item innodb_additional_mem_pool_size severity: warn This variable generally doesn't need to be larger than 20MB. =item innodb_buffer_pool_size severity: warn The InnoDB buffer pool size is unconfigured. In a production environment it should always be configured explicitly, and the default 10MB size is not good. =item innodb_checksums severity: warn InnoDB checksums are disabled. Your data is not protected from hardware corruption or other errors! =item innodb_doublewrite severity: warn InnoDB doublewrite is disabled. Unless you use a filesystem that protects against partial page writes, your data is not safe! =item innodb_fast_shutdown severity: warn InnoDB's shutdown behavior is not the default. This can lead to poor performance, or the need to perform crash recovery upon startup. =item innodb_flush_log_at_trx_commit-1 severity: warn InnoDB is not configured in strictly ACID mode. If there is a crash, some transactions can be lost. =item innodb_flush_log_at_trx_commit-2 severity: warn Setting innodb_flush_log_at_trx_commit to 0 has no performance benefits over setting it to 2, and more types of data loss are possible. If you are trying to change it from 1 for performance reasons, you should set it to 2 instead of 0. =item innodb_force_recovery severity: warn InnoDB is in forced recovery mode! This should be used only temporarily when recovering from data corruption or other bugs, not for normal usage. =item innodb_lock_wait_timeout severity: warn This option has an unusually long value, which can cause system overload if locks are not being released. =item innodb_log_buffer_size severity: warn The InnoDB log buffer size generally should not be set larger than 16MB. If you are doing large BLOB operations, InnoDB is not really a good choice of engines anyway. =item innodb_log_file_size severity: warn The InnoDB log file size is set to its default value, which is not usable on production systems. =item innodb_max_dirty_pages_pct severity: note The innodb_max_dirty_pages_pct is lower than the default. This can cause overly aggressive flushing and add load to the I/O system. =item flush_time severity: warn This setting is likely to cause very bad performance every flush_time seconds. =item key_buffer_size severity: warn The key buffer size is set to its default value, which is not good for most production systems. In a production environment, key_buffer_size should be larger than the default 8MB size. =item large_pages severity: note Large pages are enabled. =item locked_in_memory severity: note The server is locked in memory with --memlock. =item log_warnings-1 severity: note Log_warnings is disabled, so unusual events such as statements unsafe for replication and aborted connections will not be logged to the error log. =item log_warnings-2 severity: note Log_warnings must be set greater than 1 to log unusual events such as aborted connections. =item low_priority_updates severity: note The server is running with non-default lock priority for updates. This could cause update queries to wait unexpectedly for read queries. =item max_binlog_size severity: note The max_binlog_size is smaller than the default of 1GB. =item max_connect_errors severity: note max_connect_errors should probably be set as large as your platform allows. =item max_connections severity: warn If the server ever really has more than a thousand threads running, then the system is likely to spend more time scheduling threads than really doing useful work. This variable's value should be considered in light of your workload. =item myisam_repair_threads severity: note myisam_repair_threads > 1 enables multi-threaded repair, which is relatively untested and is still listed as beta-quality code in the official documentation. =item old_passwords severity: warn Old-style passwords are insecure. They are sent in plain text across the wire. =item optimizer_prune_level severity: warn The optimizer will use an exhaustive search when planning complex queries, which can cause the planning process to take a long time. =item port severity: note The server is listening on a non-default port. =item query_cache_size-1 severity: note The query cache does not scale to large sizes and can cause unstable performance when larger than 128MB, especially on multi-core machines. =item query_cache_size-2 severity: warn The query cache can cause severe performance problems when it is larger than 256MB, especially on multi-core machines. =item read_buffer_size-1 severity: note The read_buffer_size variable should generally be left at its default unless an expert determines it is necessary to change it. =item read_buffer_size-2 severity: warn The read_buffer_size variable should not be larger than 8MB. It should generally be left at its default unless an expert determines it is necessary to change it. Making it larger than 2MB can hurt performance significantly, and can make the server crash, swap to death, or just become extremely unstable. =item read_rnd_buffer_size-1 severity: note The read_rnd_buffer_size variable should generally be left at its default unless an expert determines it is necessary to change it. =item read_rnd_buffer_size-2 severity: warn The read_rnd_buffer_size variable should not be larger than 4M. It should generally be left at its default unless an expert determines it is necessary to change it. =item relay_log_space_limit severity: warn Setting relay_log_space_limit can cause replicas to stop fetching binary logs from their master immediately. This could increase the risk that your data will be lost if the master crashes. If the replicas have encountered a limit on relay log space, then it is possible that the latest transactions exist only on the master and no replica has retrieved them. =item slave_net_timeout severity: warn This variable is set too high. This is too long to wait before noticing that the connection to the master has failed and retrying. This should probably be set to 60 seconds or less. It is also a good idea to use pt-heartbeat to ensure that the connection does not appear to time out when the master is simply idle. =item slave_skip_errors severity: crit You should not set this option. If replication is having errors, you need to find and resolve the cause of that; it is likely that your slave's data is different from the master. You can find out with pt-table-checksum. =item sort_buffer_size-1 severity: note The sort_buffer_size variable should generally be left at its default unless an expert determines it is necessary to change it. =item sort_buffer_size-2 severity: note The sort_buffer_size variable should generally be left at its default unless an expert determines it is necessary to change it. Making it larger than a few MB can hurt performance significantly, and can make the server crash, swap to death, or just become extremely unstable. =item sql_notes severity: note This server is configured not to log Note level warnings to the error log. =item sync_frm severity: warn It is best to set sync_frm so that .frm files are flushed safely to disk in case of a server crash. =item tx_isolation-1 severity: note This server's transaction isolation level is non-default. =item tx_isolation-2 severity: warn Most applications should use the default REPEATABLE-READ transaction isolation level, or in a few cases READ-COMMITTED. =item expire_logs_days severity: warn Binary logs are enabled, but automatic purging is not enabled. If you do not purge binary logs, your disk will fill up. If you delete binary logs externally to MySQL, you will cause unwanted behaviors. Always ask MySQL to purge obsolete logs, never delete them externally. =item innodb_file_io_threads severity: note This option is useless except on Windows. =item innodb_data_file_path severity: note Auto-extending InnoDB files can consume a lot of disk space that is very difficult to reclaim later. Some people prefer to set innodb_file_per_table and allocate a fixed-size file for ibdata1. =item innodb_flush_method severity: note Most production database servers that use InnoDB should set innodb_flush_method to O_DIRECT to avoid double-buffering, unless the I/O system is very low performance. =item innodb_locks_unsafe_for_binlog severity: warn This option makes point-in-time recovery from binary logs, and replication, untrustworthy if statement-based logging is used. =item innodb_support_xa severity: warn MySQL's internal XA transaction support between InnoDB and the binary log is disabled. The binary log might not match InnoDB's state after crash recovery, and replication might drift out of sync due to out-of-order statements in the binary log. =item log_bin severity: warn Binary logging is disabled, so point-in-time recovery and replication are not possible. =item log_output severity: warn Directing log output to tables has a high performance impact. =item max_relay_log_size severity: note A custom max_relay_log_size is defined. =item myisam_recover_options severity: warn myisam_recover_options should be set to some value such as BACKUP,FORCE to ensure that table corruption is noticed. =item storage_engine severity: note The server is using a non-standard storage engine as default. =item sync_binlog severity: warn Binary logging is enabled, but sync_binlog isn't configured so that every transaction is flushed to the binary log for durability. =item tmp_table_size severity: note The effective minimum size of in-memory implicit temporary tables used internally during query execution is min(tmp_table_size, max_heap_table_size), so max_heap_table_size should be at least as large as tmp_table_size. =item old mysql version severity: warn These are the recommended minimum version for each major release: 3.23, 4.1.20, 5.0.37, 5.1.30. =item end-of-life mysql version severity: note Every release older than 5.1 is now officially end-of-life. =back =head1 OPTIONS This tool accepts additional command-line arguments. Refer to the L<"SYNOPSIS"> and usage information for details. =over =item --ask-pass Prompt for a password when connecting to MySQL. =item --charset short form: -A; type: string Default character set. If the value is utf8, sets Perl's binmode on STDOUT to utf8, passes the mysql_enable_utf8 option to DBD::mysql, and runs SET NAMES UTF8 after connecting to MySQL. Any other value sets binmode on STDOUT without the utf8 layer, and runs SET NAMES after connecting to MySQL. =item --config type: Array Read this comma-separated list of config files; if specified, this must be the first option on the command line. =item --daemonize Fork to the background and detach from the shell. POSIX operating systems only. =item --database short form: -D; type: string Connect to this database. =item --defaults-file short form: -F; type: string Only read mysql options from the given file. You must give an absolute pathname. =item --help Show help and exit. =item --host short form: -h; type: string Connect to host. =item --ignore-rules type: hash Ignore these rule IDs. Specify a comma-separated list of rule IDs (e.g. LIT.001,RES.002,etc.) to ignore. =item --password short form: -p; type: string Password to use when connecting. If password contains commas they must be escaped with a backslash: "exam\,ple" =item --pid type: string Create the given PID file. The tool won't start if the PID file already exists and the PID it contains is different than the current PID. However, if the PID file exists and the PID it contains is no longer running, the tool will overwrite the PID file with the current PID. The PID file is removed automatically when the tool exits. =item --port short form: -P; type: int Port number to use for connection. =item --set-vars type: Array Set the MySQL variables in this comma-separated list of C<variable=value> pairs. By default, the tool sets: =for comment ignore-pt-internal-value MAGIC_set_vars wait_timeout=10000 Variables specified on the command line override these defaults. For example, specifying C<--set-vars wait_timeout=500> overrides the defaultvalue of C<10000>. The tool prints a warning and continues if a variable cannot be set. =item --socket short form: -S; type: string Socket file to use for connection. =item --source-of-variables type: string; default: mysql Read C<SHOW VARIABLES> from this source. Possible values are "mysql", "none" or a file name. If "mysql" is specified then you must also specify a DSN on the command line. =item --user short form: -u; type: string User for login if not current user. =item --verbose short form: -v; cumulative: yes; default: 1 Increase verbosity of output. At the default level of verbosity, the program prints only the first sentence of each rule's description. At higher levels, the program prints more of the description. =item --version Show version and exit. =item --[no]version-check default: yes Check for the latest version of Percona Toolkit, MySQL, and other programs. This is a standard "check for updates automatically" feature, with two additional features. First, the tool checks the version of other programs on the local system in addition to its own version. For example, it checks the version of every MySQL server it connects to, Perl, and the Perl module DBD::mysql. Second, it checks for and warns about versions with known problems. For example, MySQL 5.5.25 had a critical bug and was re-released as 5.5.25a. Any updates or known problems are printed to STDOUT before the tool's normal output. This feature should never interfere with the normal operation of the tool. For more information, visit L<https://www.percona.com/version-check>. =back =head1 DSN OPTIONS These DSN options are used to create a DSN. Each option is given like C<option=value>. The options are case-sensitive, so P and p are not the same option. There cannot be whitespace before or after the C<=> and if the value contains whitespace it must be quoted. DSN options are comma-separated. See the L<percona-toolkit> manpage for full details. =over =item * A dsn: charset; copy: yes Default character set. =item * D dsn: database; copy: yes Default database. =item * F dsn: mysql_read_default_file; copy: yes Only read default options from the given file =item * h dsn: host; copy: yes Connect to host. =item * p dsn: password; copy: yes Password to use when connecting. If password contains commas they must be escaped with a backslash: "exam\,ple" =item * P dsn: port; copy: yes Port number to use for connection. =item * S dsn: mysql_socket; copy: yes Socket file to use for connection. =item * u dsn: user; copy: yes User for login if not current user. =back =head1 ENVIRONMENT The environment variable C<PTDEBUG> enables verbose debugging output to STDERR. To enable debugging and capture all output to a file, run the tool like: PTDEBUG=1 pt-variable-advisor ... > FILE 2>&1 Be careful: debugging output is voluminous and can generate several megabytes of output. =head1 SYSTEM REQUIREMENTS You need Perl, DBI, DBD::mysql, and some core packages that ought to be installed in any reasonably new version of Perl. =head1 BUGS For a list of known bugs, see L<http://www.percona.com/bugs/pt-variable-advisor>. Please report bugs at L<https://bugs.launchpad.net/percona-toolkit>. Include the following information in your bug report: =over =item * Complete command-line used to run the tool =item * Tool L<"--version"> =item * MySQL version of all servers involved =item * Output from the tool including STDERR =item * Input files (log/dump/config files, etc.) =back If possible, include debugging output by running the tool with C<PTDEBUG>; see L<"ENVIRONMENT">. =head1 DOWNLOADING Visit L<http://www.percona.com/software/percona-toolkit/> to download the latest release of Percona Toolkit. Or, get the latest release from the command line: wget percona.com/get/percona-toolkit.tar.gz wget percona.com/get/percona-toolkit.rpm wget percona.com/get/percona-toolkit.deb You can also get individual tools from the latest release: wget percona.com/get/TOOL Replace C<TOOL> with the name of any tool. =head1 AUTHORS Baron Schwartz and Daniel Nichter =head1 ABOUT PERCONA TOOLKIT This tool is part of Percona Toolkit, a collection of advanced command-line tools for MySQL developed by Percona. Percona Toolkit was forked from two projects in June, 2011: Maatkit and Aspersa. Those projects were created by Baron Schwartz and primarily developed by him and Daniel Nichter. Visit L<http://www.percona.com/software/> to learn about other free, open-source software from Percona. =head1 COPYRIGHT, LICENSE, AND WARRANTY This program is copyright 2010-2015 Percona LLC and/or its affiliates. THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2; OR the Perl Artistic License. On UNIX and similar systems, you can issue `man perlgpl' or `man perlartistic' to read these licenses. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. =head1 VERSION pt-variable-advisor 2.2.16 =cut
Close