# Copyright 1999-2015 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Id$ # @ECLASS: games.eclass # @MAINTAINER: # Games team # @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 # # WARNING: This eclass is DEPRECATED and must not be used by new games # ebuilds, bug #574082. When writing game ebuilds, no specific eclass # is needed. For more details, see the QA team policies page: # https://wiki.gentoo.org/wiki/Project:Quality_Assurance/Policies#Games 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 "games.eclass is banned in EAPI=${EAPI}, see https://wiki.gentoo.org/wiki/Project:Quality_Assurance/Policies#Games" ;; 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: [...] # @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: [...] # @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: ... # @DESCRIPTION: # Install one or more games binaries. dogamesbin() { gameswrapper ${FUNCNAME/games} "$@"; } # @FUNCTION: dogamessbin # @USAGE: ... # @DESCRIPTION: # Install one or more games system binaries. dogamessbin() { gameswrapper ${FUNCNAME/games} "$@"; } # @FUNCTION: dogameslib # @USAGE: ... # @DESCRIPTION: # Install one or more games libraries. dogameslib() { gameswrapper ${FUNCNAME/games} "$@"; } # @FUNCTION: dogameslib.a # @USAGE: ... # @DESCRIPTION: # Install one or more static games libraries. dogameslib.a() { gameswrapper ${FUNCNAME/games} "$@"; } # @FUNCTION: dogameslib.so # @USAGE: ... # @DESCRIPTION: # Install one or more shared games libraries. dogameslib.so() { gameswrapper ${FUNCNAME/games} "$@"; } # @FUNCTION: newgamesbin # @USAGE: # @DESCRIPTION: # Install one games binary with a new name. newgamesbin() { gameswrapper ${FUNCNAME/games} "$@"; } # @FUNCTION: newgamessbin # @USAGE: # @DESCRIPTION: # Install one system games binary with a new name. newgamessbin() { gameswrapper ${FUNCNAME/games} "$@"; } # @FUNCTION: games_make_wrapper # @USAGE: [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: [...] ... # @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: ... # @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 '";; *-freebsd*|*-dragonfly*) ewarn "Just run 'pw groupmod ${GAMES_GROUP} -m '";; *) ewarn "Just run 'gpasswd -a ${GAMES_GROUP}', then have 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: # @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: # @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