summaryrefslogtreecommitdiff
path: root/eclass/games.eclass
blob: 7d231e186cc9142259a39a517b762fb963155b50 (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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
# Copyright 1999-2015 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Id$

# @ECLASS: games.eclass
# @MAINTAINER:
# Games team <games@gentoo.org>
# @BLURB: Standardizing the install of games.
# @DESCRIPTION:
# This eclass makes sure that games are consistently handled in gentoo.
# It installs game files by default in FHS-compatible directories
# like /usr/share/games and sets more restrictive permissions in order
# to avoid some security bugs.
#
# The installation directories as well as the user and group files are
# installed as can be controlled by the user. See the variables like
# GAMES_BINDIR, GAMES_USER etc. below. These are NOT supposed to be set
# by ebuilds!
#
# For a general guide on writing games ebuilds, see:
# https://wiki.gentoo.org/wiki/Project:Games/Ebuild_howto


if [[ -z ${_GAMES_ECLASS} ]]; then
_GAMES_ECLASS=1

inherit base multilib toolchain-funcs eutils user

case ${EAPI:-0} in
	0|1) EXPORT_FUNCTIONS pkg_setup src_compile pkg_preinst pkg_postinst ;;
	2|3|4|5) EXPORT_FUNCTIONS pkg_setup src_configure src_compile pkg_preinst pkg_postinst ;;
	*) die "no support for EAPI=${EAPI} yet" ;;
esac

if [[ ${CATEGORY}/${PN} != "games-misc/games-envd" ]] ; then
	# environment file
	RDEPEND="games-misc/games-envd"
fi

# @ECLASS-VARIABLE: GAMES_PREFIX
# @DESCRIPTION:
# Prefix where to install games, mostly used by GAMES_BINDIR. Games data should
# still go into GAMES_DATADIR. May be set by the user.
GAMES_PREFIX=${GAMES_PREFIX:-/usr/games}

# @ECLASS-VARIABLE: GAMES_PREFIX_OPT
# @DESCRIPTION:
# Prefix where to install precompiled/blob games, usually followed by
# package name. May be set by the user.
GAMES_PREFIX_OPT=${GAMES_PREFIX_OPT:-/opt}

# @ECLASS-VARIABLE: GAMES_DATADIR
# @DESCRIPTION:
# Base directory where to install game data files, usually followed by
# package name. May be set by the user.
GAMES_DATADIR=${GAMES_DATADIR:-/usr/share/games}

# @ECLASS-VARIABLE: GAMES_DATADIR_BASE
# @DESCRIPTION:
# Similar to GAMES_DATADIR, but only used when a package auto appends 'games'
# to the path. May be set by the user.
GAMES_DATADIR_BASE=${GAMES_DATADIR_BASE:-/usr/share}

# @ECLASS-VARIABLE: GAMES_SYSCONFDIR
# @DESCRIPTION:
# Where to install global games configuration files, usually followed by
# package name. May be set by the user.
GAMES_SYSCONFDIR=${GAMES_SYSCONFDIR:-/etc/games}

# @ECLASS-VARIABLE: GAMES_STATEDIR
# @DESCRIPTION:
# Where to install/store global variable game data, usually followed by
# package name. May be set by the user.
GAMES_STATEDIR=${GAMES_STATEDIR:-/var/games}

# @ECLASS-VARIABLE: GAMES_LOGDIR
# @DESCRIPTION:
# Where to store global game log files, usually followed by
# package name. May be set by the user.
GAMES_LOGDIR=${GAMES_LOGDIR:-/var/log/games}

# @ECLASS-VARIABLE: GAMES_BINDIR
# @DESCRIPTION:
# Where to install the game binaries. May be set by the user. This is in PATH.
GAMES_BINDIR=${GAMES_BINDIR:-${GAMES_PREFIX}/bin}

# @ECLASS-VARIABLE: GAMES_ENVD
# @INTERNAL
# @DESCRIPTION:
# The games environment file name which sets games specific LDPATH and PATH.
GAMES_ENVD="90games"

# @ECLASS-VARIABLE: GAMES_USER
# @DESCRIPTION:
# The USER who owns all game files and usually has write permissions.
# May be set by the user.
GAMES_USER=${GAMES_USER:-root}

# @ECLASS-VARIABLE: GAMES_USER_DED
# @DESCRIPTION:
# The USER who owns all game files related to the dedicated server part
# of a package. May be set by the user.
GAMES_USER_DED=${GAMES_USER_DED:-games}

# @ECLASS-VARIABLE: GAMES_GROUP
# @DESCRIPTION:
# The GROUP that owns all game files and usually does not have
# write permissions. May be set by the user.
# If you want games world-executable, then you can at least set this variable
# to 'users' which is almost the same.
GAMES_GROUP=${GAMES_GROUP:-games}

# @FUNCTION: games_get_libdir
# @DESCRIPTION:
# Gets the directory where to install games libraries. This is in LDPATH.
games_get_libdir() {
	echo ${GAMES_PREFIX}/$(get_libdir)
}

# @FUNCTION: egamesconf
# @USAGE: [<args>...]
# @DESCRIPTION:
# Games equivalent to 'econf' for autotools based build systems. It passes
# the necessary games specific directories automatically.
egamesconf() {
	# handle verbose build log pre-EAPI5
	local _gamesconf
	if has "${EAPI:-0}" 0 1 2 3 4 ; then
		if grep -q -s disable-silent-rules "${ECONF_SOURCE:-.}"/configure ; then
			_gamesconf="--disable-silent-rules"
		fi
	fi

	# bug 493954
	if grep -q -s datarootdir "${ECONF_SOURCE:-.}"/configure ; then
		_gamesconf="${_gamesconf} --datarootdir=/usr/share"
	fi

	econf \
		--prefix="${GAMES_PREFIX}" \
		--libdir="$(games_get_libdir)" \
		--datadir="${GAMES_DATADIR}" \
		--sysconfdir="${GAMES_SYSCONFDIR}" \
		--localstatedir="${GAMES_STATEDIR}" \
		${_gamesconf} \
		"$@"
}

# @FUNCTION: gameswrapper
# @USAGE: <command> [<args>...]
# @INTERNAL
# @DESCRIPTION:
# Wraps an install command like dobin, dolib etc, so that
# it has GAMES_PREFIX as prefix.
gameswrapper() {
	# dont want to pollute calling env
	(
		into "${GAMES_PREFIX}"
		cmd=$1
		shift
		${cmd} "$@"
	)
}

# @FUNCTION: dogamesbin
# @USAGE: <path>...
# @DESCRIPTION:
# Install one or more games binaries.
dogamesbin() { gameswrapper ${FUNCNAME/games} "$@"; }

# @FUNCTION: dogamessbin
# @USAGE: <path>...
# @DESCRIPTION:
# Install one or more games system binaries.
dogamessbin() { gameswrapper ${FUNCNAME/games} "$@"; }

# @FUNCTION: dogameslib
# @USAGE: <path>...
# @DESCRIPTION:
# Install one or more games libraries.
dogameslib() { gameswrapper ${FUNCNAME/games} "$@"; }

# @FUNCTION: dogameslib.a
# @USAGE: <path>...
# @DESCRIPTION:
# Install one or more static games libraries.
dogameslib.a() { gameswrapper ${FUNCNAME/games} "$@"; }

# @FUNCTION: dogameslib.so
# @USAGE: <path>...
# @DESCRIPTION:
# Install one or more shared games libraries.
dogameslib.so() { gameswrapper ${FUNCNAME/games} "$@"; }

# @FUNCTION: newgamesbin
# @USAGE: <path> <newname>
# @DESCRIPTION:
# Install one games binary with a new name.
newgamesbin() { gameswrapper ${FUNCNAME/games} "$@"; }

# @FUNCTION: newgamessbin
# @USAGE: <path> <newname>
# @DESCRIPTION:
# Install one system games binary with a new name.
newgamessbin() { gameswrapper ${FUNCNAME/games} "$@"; }

# @FUNCTION: games_make_wrapper
# @USAGE: <wrapper> <target> [chdir] [libpaths] [installpath]
# @DESCRIPTION:
# Create a shell wrapper script named wrapper in installpath
# (defaults to the games bindir) to execute target (default of wrapper) by
# first optionally setting LD_LIBRARY_PATH to the colon-delimited
# libpaths followed by optionally changing directory to chdir.
games_make_wrapper() { gameswrapper ${FUNCNAME/games_} "$@"; }

# @FUNCTION: gamesowners
# @USAGE: [<args excluding owner/group>...] <path>...
# @DESCRIPTION:
# Run 'chown' with the given args on the given files. Owner and
# group are GAMES_USER and GAMES_GROUP and must not be passed
# as args.
gamesowners() { chown ${GAMES_USER}:${GAMES_GROUP} "$@"; }

# @FUNCTION: gamesperms
# @USAGE: <path>...
# @DESCRIPTION:
# Run 'chmod' with games specific permissions on the given files.
gamesperms() { chmod u+rw,g+r-w,o-rwx "$@"; }

# @FUNCTION: prepgamesdirs
# @DESCRIPTION:
# Fix all permissions/owners of files in games related directories,
# usually called at the end of src_install().
prepgamesdirs() {
	local dir f mode
	for dir in \
		"${GAMES_PREFIX}" "${GAMES_PREFIX_OPT}" "${GAMES_DATADIR}" \
		"${GAMES_SYSCONFDIR}" "${GAMES_STATEDIR}" "$(games_get_libdir)" \
		"${GAMES_BINDIR}" "$@"
	do
		[[ ! -d ${D}/${dir} ]] && continue
		(
			gamesowners -R "${D}/${dir}"
			find "${D}/${dir}" -type d -print0 | xargs -0 chmod 750
			mode=o-rwx,g+r,g-w
			[[ ${dir} = ${GAMES_STATEDIR} ]] && mode=o-rwx,g+r
			find "${D}/${dir}" -type f -print0 | xargs -0 chmod $mode

			# common trees should not be games owned #264872 #537580
			fowners root:0 "${dir}"
			fperms 755 "${dir}"
			if [[ ${dir} == "${GAMES_PREFIX}" \
						|| ${dir} == "${GAMES_PREFIX_OPT}" ]] ; then
				for d in $(get_libdir) bin ; do
					# check if dirs exist to avoid "nonfatal" option
					if [[ -e ${D}/${dir}/${d} ]] ; then
						fowners root:0 "${dir}/${d}"
						fperms 755 "${dir}/${d}"
					fi
				done
			fi
		) &>/dev/null

		f=$(find "${D}/${dir}" -perm +4000 -a -uid 0 2>/dev/null)
		if [[ -n ${f} ]] ; then
			eerror "A game was detected that is setuid root!"
			eerror "${f}"
			die "refusing to merge a setuid root game"
		fi
	done
	[[ -d ${D}/${GAMES_BINDIR} ]] || return 0
	find "${D}/${GAMES_BINDIR}" -maxdepth 1 -type f -exec chmod 750 '{}' \;
}

# @FUNCTION: games_pkg_setup
# @DESCRIPTION:
# Export some toolchain specific variables and create games related groups
# and users. This function is exported as pkg_setup().
games_pkg_setup() {
	tc-export CC CXX LD AR RANLIB

	enewgroup "${GAMES_GROUP}" 35
	[[ ${GAMES_USER} != "root" ]] \
		&& enewuser "${GAMES_USER}" 35 -1 "${GAMES_PREFIX}" "${GAMES_GROUP}"
	[[ ${GAMES_USER_DED} != "root" ]] \
		&& enewuser "${GAMES_USER_DED}" 36 /bin/bash "${GAMES_PREFIX}" "${GAMES_GROUP}"

	# Dear portage team, we are so sorry.  Lots of love, games team.
	# See Bug #61680
	[[ ${USERLAND} != "GNU" ]] && return 0
	[[ $(egetshell "${GAMES_USER_DED}") == "/bin/false" ]] \
		&& usermod -s /bin/bash "${GAMES_USER_DED}"
}

# @FUNCTION: games_src_configure
# @DESCRIPTION:
# Runs egamesconf if there is a configure file.
# This function is exported as src_configure().
games_src_configure() {
	[[ -x "${ECONF_SOURCE:-.}"/configure ]] && egamesconf
}

# @FUNCTION: games_src_compile
# @DESCRIPTION:
# Runs base_src_make(). This function is exported as src_compile().
games_src_compile() {
	case ${EAPI:-0} in
		0|1) games_src_configure ;;
	esac
	base_src_make
}

# @FUNCTION: games_pkg_preinst
# @DESCRIPTION:
# Synchronizes GAMES_STATEDIR of the ebuild image with the live filesystem.
games_pkg_preinst() {
	local f

	while read f ; do
		if [[ -e ${ROOT}/${GAMES_STATEDIR}/${f} ]] ; then
			cp -p \
				"${ROOT}/${GAMES_STATEDIR}/${f}" \
				"${D}/${GAMES_STATEDIR}/${f}" \
				|| die "cp failed"
			# make the date match the rest of the install
			touch "${D}/${GAMES_STATEDIR}/${f}"
		fi
	done < <(find "${D}/${GAMES_STATEDIR}" -type f -printf '%P\n' 2>/dev/null)
}

# @FUNCTION: games_pkg_postinst
# @DESCRIPTION:
# Prints some warnings and infos, also related to games groups.
games_pkg_postinst() {
	if [[ -z "${GAMES_SHOW_WARNING}" ]] ; then
		ewarn "Remember, in order to play games, you have to"
		ewarn "be in the '${GAMES_GROUP}' group."
		echo
		case ${CHOST} in
			*-darwin*) ewarn "Just run 'niutil -appendprop / /groups/games users <USER>'";;
			*-freebsd*|*-dragonfly*) ewarn "Just run 'pw groupmod ${GAMES_GROUP} -m <USER>'";;
			*) ewarn "Just run 'gpasswd -a <USER> ${GAMES_GROUP}', then have <USER> re-login.";;
		esac
		echo
		einfo "For more info about Gentoo gaming in general, see our website:"
		einfo "   https://games.gentoo.org/"
		echo
	fi
}

# @FUNCTION: games_ut_unpack
# @USAGE: <directory or file to unpack>
# @DESCRIPTION:
# Unpack .uz2 files for UT2003/UT2004.
games_ut_unpack() {
	local ut_unpack="$1"
	local f=

	if [[ -z ${ut_unpack} ]] ; then
		die "You must provide an argument to games_ut_unpack"
	fi
	if [[ -f ${ut_unpack} ]] ; then
		uz2unpack "${ut_unpack}" "${ut_unpack%.uz2}" \
			|| die "uncompressing file ${ut_unpack}"
	fi
	if [[ -d ${ut_unpack} ]] ; then
		while read f ; do
			uz2unpack "${ut_unpack}/${f}" "${ut_unpack}/${f%.uz2}" \
				|| die "uncompressing file ${f}"
			rm -f "${ut_unpack}/${f}" || die "deleting compressed file ${f}"
		done < <(find "${ut_unpack}" -maxdepth 1 -name '*.uz2' -printf '%f\n' 2>/dev/null)
	fi
}

# @FUNCTION: games_umod_unpack
# @USAGE: <file to unpack>
# @DESCRIPTION:
# Unpacks .umod/.ut2mod/.ut4mod files for UT/UT2003/UT2004.
# Don't forget to set 'dir' and 'Ddir'.
games_umod_unpack() {
	local umod=$1
	mkdir -p "${Ddir}"/System
	cp "${dir}"/System/{ucc-bin,{Manifest,Def{ault,User}}.ini,{Engine,Core,zlib,ogg,vorbis}.so,{Engine,Core}.int} "${Ddir}"/System
	cd "${Ddir}"/System
	UT_DATA_PATH=${Ddir}/System ./ucc-bin umodunpack -x "${S}/${umod}" -nohomedir &> /dev/null \
		|| die "uncompressing file ${umod}"
	rm -f "${Ddir}"/System/{ucc-bin,{Manifest,Def{ault,User},User,UT200{3,4}}.ini,{Engine,Core,zlib,ogg,vorbis}.so,{Engine,Core}.int,ucc.log} &>/dev/null \
		|| die "Removing temporary files"
}

fi