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
|
# By eroen <eroen-overlay@occam.eroen.eu>, 2016
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
# $Id$
# @ECLASS: steam.eclass
# @MAINTAINER:
# eroen <eroen-overlay@occam.eroen.eu>
# @AUTHOR:
# eroen <eroen-overlay@occam.eroen.eu>
# @BLURB: Eclass for fetching packages from Steam
# @DESCRIPTION:
# Conveiniently set up and authenticates with steamcmd and use it to install
# applications.
# steamcmd documentation:
# https://developer.valvesoftware.com/wiki/SteamCMD
case "${EAPI:-0}" in
6)
;;
*)
die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}"
;;
esac
[[ -z ${PYTHON_COMPAT[*]} ]] && PYTHON_COMPAT=(python2_7 python3_3 python3_4 python3_5)
[[ -n $PYTHON_REQ_USE ]] && PYTHON_REQ_USE="$PYTHON_REQ_USE "
PYTHON_REQ_USE="$PYTHON_REQ_USEssl"
inherit linux-info python-any-r1
EXPORT_FUNCTIONS pkg_setup src_unpack
DEPEND="${PYTHON_DEPS}
net-misc/steamcmd-bin"
# @ECLASS-VARIABLE: STEAM_app_id
# @DEFAULT_UNSET
# @DESCRIPTION:
# Steam App ID for steam_src_unpack to install. This must be set before
# steam_src_unpack is called. The App ID for an application can be found on
# https://steamdb.info
# @ECLASS-VARIABLE: STEAM_platform
# @DEFAULT_UNSET
# @DESCRIPTION:
# If this is set, steam_src_unpack will override the current platform in order
# to install non-native application. Possible values are: "linux", "macos", and "windows".
# @ECLASS-VARIABLE: STEAM_CREDS
# @DESCRIPTION:
# Path to credentials file. If unset, the default /etc/portage/creds_steam will
# be used.
#
# This file should be created by the user, and contain the following:
#
# @CODE
# STEAM_USER: mysteamusername
# STEAM_PASS: mysteampassword
# MAIL_SERVER: imap.mymailhost.com
# MAIL_USER: myemailusername
# MAIL_PASS: myemailpassword
# @CODE
#
# Note that the file must be readable by the user your package manager runs as.
#
# The STEAM_* settings will be used to authenticate with Steam, while the
# MAIL_* settings will be used to obtain the verification code required for new
# Steam installations. If Steam Guard is disabled from
# https://store.steampowered.com/twofactor/manage_action the MAIL_* settings
# can be omitted.
#
# MAIL_SERVER should refer to an imap4/TLS server on port 993 that supports
# PLAIN authentication. For gmail, this must be explicitly enabled by the user.
# Only the folder named "INBOX" will be checked.
: ${STEAM_CREDS:=/etc/portage/creds_steam}
# @ECLASS-VARIABLE: STEAM_CACHEDIR
# @DESCRIPTION:
# Location for caching downloaded files between runs. To disable caching, set
# this to zero-length string.
#
# This should not be set by ebuilds or profiles, it is meant for user
# configuration.
# STEAM_CACHEDIR ?= ${DISTDIR}/steam-cache
# @ECLASS-VARIABLE: STEAM_FILESDIR
# @INTERNAL
# @DESCRIPTION:
# Directory where the eclass expects to find its internal files.
STEAM_FILESDIR="${BASH_SOURCE[0]%/*}/files"
# @ECLASS-VARIABLE: STEAM_STEAMCMD
# @INTERNAL
# @DESCRIPTION:
# Absolute path to steamcmd.sh
STEAM_STEAMCMD=$T/steamcmd/steamcmd.sh
# @ECLASS-VARIABLE: STEAM_ANON
# @DESCRIPTION:
# Set this to "yes" if the application to be fetched is available with
# anonymous login.
: ${STEAM_ANON:=no}
# @FUNCTION: steam_pkg_setup
# @DESCRIPTION:
# This function is exported. It makes sanity checks and fails early for some
# issues, and sets up the python interpreter.
steam_pkg_setup() {
# CONFIG_PAX_ELFRELOCS must not be disabled (if present).
# Textrels are all over the place :(
if linux_config_exists; then
if [[ -n $(linux_chkconfig_string PAX_ELFRELOCS) ]] && \
! linux_chkconfig_present PAX_ELFRELOCS; then
die "steamcmd needs support for x86 TEXTRELs to run"
fi
else
ewarn "Could not find kernel config. The install will fail later if"
ewarn "x86 TEXTRELs are not supported on the system."
fi
if [[ $MERGE_TYPE != binary && \
yes != ${STEAM_ANON,,} && \
! -r $STEAM_CREDS ]]; then
die "\$STEAM_CREDS=$STEAM_CREDS is not readable"
fi
python-any-r1_pkg_setup
}
# @FUNCTION: steam_get_cred
# @INTERNAL
# @DESCRIPTION:
# Takes 1 argument, prints the corresponding value from STEAM_CREDS.
steam_get_cred() {
[[ 1 == $# ]] || die "$FUNCNAME - wrong number of arguments, expected 1"
[[ -n $1 ]] || die "$FUNCNAME - passed empty argument"
if [[ yes = $STEAM_ANON ]]; then
case "$1" in
STEAM_USER)
printf "anonymous\n"
;;
*)
printf "\n"
;;
esac
else
awk "/^${1^^}: /{print \$2}" "$STEAM_CREDS" || die
fi
}
# @FUNCTION: steam_get_mail
# @INTERNAL
# @DESCRIPTION:
# Prints the verification code required to log in to Steam from a new
# installation. The code is obtained through IMAP, see the description of
# STEAM_CREDS
steam_get_mail() {
printf "%s\n%s\n%s\n" \
"$(steam_get_cred MAIL_SERVER)" \
"$(steam_get_cred MAIL_USER)" \
"$(steam_get_cred MAIL_PASS)" \
| ${EPYTHON} "${STEAM_FILESDIR}"/steam-mail.py
}
# @FUNCTION: esteamcmd
# @DESCRIPTION:
# Runs steamcmd.sh with some boilerplate and passes it any arguments. Uses the
# credentials from STEAM_CREDS to log in. This is normally called by
# steam_src_install, but it can be used directly for specific uses.
esteamcmd() {
# Supply password on stdin to avoid leaking it in /proc/$pid/cmdline
printf "%s\n" "$(steam_get_cred STEAM_PASS)" \
| "$STEAM_STEAMCMD" \
"+@ShutdownOnFailedCommand 1" \
"+@NoPromptForPassword 0" \
"+login $(steam_get_cred STEAM_USER)" \
"$@" \
"+quit" || die -n "Error $? in $FUNCNAME $*"
}
# @FUNCTION: steam_firstlogin
# @DESCRIPTION:
# Runs steamcmd.sh several times in order to bring it up to date, generate the
# verfication code email, and complete authentication. This is normally called
# by steam_src_install, and must be called before esteamcmd.
steam_firstlogin() {
# make steam up to date
einfo "Update steam"
"$STEAM_STEAMCMD" "+quit" || die "unable to run steamcmd.sh"
# generate the 'special access code'
einfo "Attempt to log in, generate special access code email"
printf "%s\n" "$(steam_get_cred STEAM_PASS)" \
| "$STEAM_STEAMCMD" "+login $(steam_get_cred STEAM_USER)" "+quit"
if [[ $? == 5 ]]; then
local i imax=5
for (( i=1; i<=imax; i++ )); do
# supply 'special access code'
einfo "Supply special access code, attempt $i of $imax"
printf "%s\n" "$(steam_get_cred STEAM_PASS)" \
| "$STEAM_STEAMCMD" "+set_steam_guard_code $(steam_get_mail)" \
"+login $(steam_get_cred STEAM_USER)" \
"+quit" && break
(( i < 5 )) || die "Unable to log in"
sleep 10
done
fi
# verify we can log in
einfo "Verify we can log in"
esteamcmd
}
# @FUNCTION: steam_src_unpack
# @DESCRIPTION:
# Runs steam_firstlogin, then uses esteamcmd to install the application
# referred to by STEAM_app_id into S. STEAM_platform can be set to force a
# non-native platform.
#
# This function is exported.
steam_src_unpack() {
if [[ -z $STEAM_app_id ]]; then
die "\$STEAM_app_id is not set, $FUNCNAME cannot be used"
fi
cp -rf "$EROOT/opt/steamcmd" "${STEAM_STEAMCMD%/*}" || die
steam_firstlogin
local cmd_platform=
[[ -n $STEAM_platform ]] && cmd_platform="+@sSteamCmdForcePlatformType ${STEAM_platform}"
local distdir=${PORTAGE_ACTUAL_DISTDIR:-${DISTDIR}}
: ${STEAM_CACHEDIR:=${distdir}/steam-cache}
if [[ -n $STEAM_CACHEDIR ]]; then
local fetchdir=$STEAM_CACHEDIR/$STEAM_app_id
if [[ ! -d $fetchdir ]]; then
(
addwrite /
mkdir -p "$fetchdir"
) || die "Unable to create ${fetchdir}"
fi
else
local fetchdir=$S
fi
# fetch our thing
einfo "Install app_id ${STEAM_app_id}"
(
addwrite "${fetchdir}"
esteamcmd \
"$cmd_platform" \
"+force_install_dir \"$fetchdir\"" \
"+app_update ${STEAM_app_id} verify"
)
if [[ -n $STEAM_CACHEDIR ]]; then
einfo "Copying from cache to \$S"
cp -fPpR "$fetchdir" "$S" || die
fi
}
|