aboutsummaryrefslogtreecommitdiff
path: root/sbopkglint.d/05-basic-sanity.t.sh
blob: aa04cf9763245a61982d385fdadaac3d2e9b9e26 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
#!/bin/sh

# sbopkglint test, must be sourced by sbopkglint (not run standalone).

# PKG, PRGNAM, VERSION, ARCH are set by sbopkglint. also the current
# directory is the root of the installed package tree.

#######################################################################
# these directories are allowed to exist in the package, but they
# must be mode 0755 and owned by root:root. if a dir from this list
# exists but is empty, that's an error. if a top-level directory
# exists that's *not* in this list (such as /dev), that's an error.
topleveldirs="bin boot etc lib lib64 opt sbin srv usr var run"

# these directories are *required* to exist, and must be mode 0755, root:root.
# if a dir from this list exists but is empty, that's an error. note
# that the install/ dir no longer exists by the time we run (installpkg
# deleted it already); slack-desc is checked by the pre-doinst test.
requireddirs="usr/doc/$PRGNAM-$VERSION"

# these directories are the only ones allowed to exist directly under /usr.
# do not include X11R6 or local here, and do not include dirs which are
# symlinks on Slackware (X11 adm dict spool tmp).
# don't list (x86_64|i586|etc)-slackware-linux, it's checked separately.
usrdirs="bin doc games include info lib lib64 libexec man sbin share src x86_64-slackware-linux dict"

# these directories *must not* exist. no need to list top-level dirs here,
# the topleveldirs check already catches those. also, don't list stuff caught
# by the $usrdirs check (e.g. usr/local, usr/etc, usr/man1).
baddirs="etc/ld.so.conf.d usr/share/doc usr/share/man usr/share/info"

# these directories may only contain files with +x permissions. in
# other words, no non-executable files may live here. note that
# bindirs is a subset of fileonlydirs.
bindirs="bin usr/bin sbin usr/sbin usr/games"

# these directories may exist, but must contain only files or symlinks,
# and must be mode 0755, root:root. I thought usr/share/pixmaps
# belonged here, but quite a few packages create subdirs there for
# images required at runtime that aren't the app icon.
fileonlydirs="$bindirs usr/man/man1 usr/man/man2 usr/man/man3 usr/man/man4 usr/man/man5 usr/man/man6 usr/man/man7 usr/man/man8 usr/man/man9 usr/man/manl usr/man/mann usr/lib/pkgconfig usr/lib64/pkgconfig usr/share/pkgconfig"

# these directories may exist, but must contain only subdirectories
# (no files, symlinks, devices, etc). "." (the top-level package dir)
# doesn't need to be included here; it's checked separately.
nofiledirs="usr usr/doc usr/share usr/man usr/doc/HTML usr/share/terminfo"

# these directories may exist but must not have executable files
# anywhere under them. I would put usr/doc and etc here, but too many
# packages break that rule. usr/share/applications is listed here,
# even though Slackware's KDE packages (erroneously) install .desktop
# files +x.
noexecdirs="usr/include usr/man usr/share/pixmaps usr/share/icons usr/share/applications usr/share/appdata usr/share/mime usr/share/mime-info usr/share/glib-2.0 usr/doc/HTML usr/share/terminfo usr/lib/pkgconfig usr/lib64/pkgconfig usr/share/pkgconfig"

# these files must exist, unless -s option given.
requiredfiles="usr/doc/$PRGNAM-$VERSION/$PRGNAM.SlackBuild"

# these files must not exist.
badfiles="\
usr/lib64/perl5/perllocal.pod \
usr/lib/perl5/perllocal.pod \
usr/share/perl5/perllocal.pod \
usr/share/perl5/vendor_perl/perllocal.pod \
etc/passwd \
etc/passwd.new \
etc/shadow \
etc/shadow.new \
etc/group \
etc/group.new \
etc/gshadow \
etc/gshadow.new \
etc/ld.so.conf"

#######################################################################

# include 'hidden' files/dirs in * wildcard expansion.
shopt -s dotglob

dir_ok() {
	[ -d "$1" ] && \
		[ "$( stat -c '%A %U %G' "$1" )" = "drwxr-xr-x root root" ]
}

dir_empty() {
	[ "$( find "$1" -mindepth 1 -maxdepth 1 )" = "" ]
}

warn_badperms() {
	warn "bad permissions/owner (should be 0755 root:root): $1"
}

if LANG=C echo "$PRGNAM" | grep -q [^-._+A-Za-z0-9]; then
	warn "package name has invalid characters, only A-Z, a-z, 0-9, - + . _ are allowed";
fi

for i in *; do
	if [ ! -d "$i" ]; then
		warn "package root dir contains non-directory: $i"
	elif ! echo "$topleveldirs" | grep -q "\\<$i\\>"; then
		warn "package root dir contains non-standard directory: $i"
	elif ! dir_ok "$i"; then
		warn_badperms "$i"
	elif dir_empty "$i"; then
		warn "package contains empty top-level directory: $i"
	fi
done

for i in usr/*; do
	if [ -e "$i" ]; then
		case "$i" in
			*-slackware-linux) ;; # OK
			*)
				if ! echo "$usrdirs" | grep -q "\\<$( basename $i )\\>"; then
					warn "nonstandard directory in /usr: $i"
				fi
			;;
		esac
	fi
done

for i in $requireddirs; do
	if [ ! -d "$i" ]; then
		warn "missing required directory: $i"
	elif ! dir_ok "$i"; then
		warn_badperms "$i"
	fi
done

for i in $baddirs; do
	if [ -d "$i" ]; then
		warn "forbidden directory exists: $i"
	elif [ -e "$i" ]; then
		warn "forbidden directory exists as a non-directory: $i"
	fi
done

# 20220414 bkw: don't complain about broken symlinks here, they get checked elsewhere.
for i in $fileonlydirs; do
	[ -d "$i" ] || continue
	dir_ok "$i" || warn_badperms "$i"
	find_warnfiles "$i should only contain files, not:" \
		-L "$i" -mindepth 1 -maxdepth 1 \! \( -type l -o -type f \)
done

for i in $bindirs; do
	[ -d "$i" ] || continue
	find_warnfiles "$i should only contain executable files, not:" \
		-L "$i" -mindepth 1 -maxdepth 1 -type f \! -perm /0111
done

for i in $nofiledirs; do
	[ -d "$i" ] || continue
	dir_ok "$i" || warn_badperms "$i"
	find_warnfiles "$i should only contain directories, not:" \
		-L "$i" -mindepth 1 -maxdepth 1 \! -type d
done

if [ -z "$SLACKBUILD_MISSING_OK" ]; then
	for i in $requiredfiles; do
		[ -f "$i" ] || warn "missing required file: $i"
	done
fi

for i in $noexecdirs; do
	[ -d "$i" ] || continue
	find_warnfiles "$i should not contain files with executable permission:" \
		"$i" -type f -a -perm /0111
done

for i in $badfiles; do
	[ -e "$i" ] && warn "forbidden file: $i"
done

# 20220414 bkw: absolute symlinks used to be an error, but there are just
# too many packages that use them. so only flag them if they're broken links.
# 20230627 bkw: note absolute symlinks outside the package. used in my own
# smc build, for instance. up to the human to decide whether it's a problem.
find . -type l -lname '/*' | while read f; do
	target="$( readlink "$f" | sed 's,^/*,,' )"
	if [ ! -e "$target" ]; then
		if [ -e "/$target" ]; then
			ls -bld "$f" > .outlinks.$$
		else
			ls -bld "$f" > .badlinks.$$
		fi
	fi
done

if [ -s .badlinks.$$ ]; then
	warn "package contains broken absolute symlinks:"
	cat .badlinks.$$
fi

if [ -s .outlinks.$$ ]; then
	note "package contains symlinks outside the package (which is OK, if intentional):"
	cat .outlinks.$$
fi

rm -f .badlinks.$$ .outlinks.$$

find_warnfiles "package contains broken relative symlinks:" \
	-L . -type l \! -lname '/*'

# 20230320 bkw: empty directories. this isn't an error, just a note, and
# we ignore any empty dirs under /var because lots of packages need these.
# 20241008 bkw: ignore empty bin sbin usr/bin usr/sbin, these are caught below.
find_warnfiles --note "package contains empty dirs, are these necessary?" \
	. -type d -a -empty \
	-a \! -path "./var/*" \
	-a \! -path ./bin \
	-a \! -path ./sbin \
	-a \! -path ./usr/bin \
	-a \! -path ./usr/sbin

# 20241008 bkw: if any of /bin /sbin /usr/bin or /usr/sbin exists, they must
# not be empty.
for i in bin sbin usr/bin usr/sbin; do
	if [ -e $i -a -z "$( ls -bld $i/* 2>/dev/null )" ]; then
		warn "package contains empty $i directory, this is probably a bug in the script."
	fi
done

find_warnfiles "package contains files owned by UID/GID >= 1000" \
	. \( -uid +999 -o -gid +999 \)