summaryrefslogtreecommitdiff
blob: b866fc2379d55cf941ab6e6a40f6d6d9497a4a34 (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
# Copyright 1999-2004 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: /var/cvsroot/gentoo-x86/eclass/kmod.eclass,v 1.13 2004/06/25 00:39:48 vapier Exp $

# This eclass provides help for compiling external kernel modules from
# source.
#
# BEWARE: This eclass is superceding the old kmod.eclass. It does *not*
# implement the same functionality as the old kmod.eclass!

# DOCUMENTATION: Most documentation for this can be found at:
# http://www.gentoo.org/doc/en/2.6-koutput.xml
#
# More documentation comments will follow in the header of this soon!

# Variables you can use to change behavior
#
# KMOD_SOURCES - space seperated list of source to unpack in 
#					   src_unpack() if you don't want ${A} unpacked.
#
# KMOD_KOUTPUT_PATCH - Patch to apply in src_unpack() if a seperate output
#							directory is detected.
#

inherit eutils

ECLASS=kmod
INHERITED="$INHERITED $ECLASS"
S=${WORKDIR}/${P}
DESCRIPTION="Based on the $ECLASS eclass"

SRC_URI="${SRC_URI:-unknown - please fix me!!}"
KERNEL_DIR="${KERNEL_DIR:-${ROOT}/usr/src/linux}"

EXPORT_FUNCTIONS src_unpack src_compile pkg_postinst

kmod_get_make_var ()
{
	grep "^${1}" ${2} | head -n 1 | grep -v ":=" | cut -d = -f 2- \
		| awk '{ print $1 }'
}

# getconfigvar() - Prints the value of a certain config varaible from the
#				current kernel's config file. Will return "n" for an unset 
#				option

kmod_get_config_var()
{
	local configopt="CONFIG_${1}"
	local configresult

	if [ -z ${KV_OUTPUT} ]; then
		get_kernel_info
	fi

	configresult="`grep ^$configopt ${KV_OUTPUT}/.config | cut -d= -f 2-`"
	if [ -z "${configresult}" ]; then
		echo "n"
	else
		echo ${configresult} | awk '{ print $1 }'
	fi
}

# get_kernel_info is used to get our build environment. It initializes several
# variables that can be used in ebuilds
#
# KV_MAJOR, KV_MINOR, KV_PATCH - the kernel major, minor, and pathlevel #'s
# KV_TYPE - the type, as found from EXTRAVERSION.
#
# KV_VERSION_FULL - full string for the kernel version
#
# KV_OUTPUT - the output direcotry if used with a 2.6 kernel
#
# KV_OBJ - extension for kernel objects, "o" for 2.4 kernels and "ko" for 2.6
#
get_kernel_info()
{
	# yes, this is horrible, but it is effective
	#
	# KV_DIR contains the real directory name of the directory containing
	# the Linux kernel that we are going to compile against

	if [ -h ${KERNEL_DIR} ] ; then
		einfo "`echo ${KERNEL_DIR} | tr -s /` is a symbolic link"
		einfo "Determining the real directory of the Linux kernel source code"
		KV_DIR="`readlink ${KERNEL_DIR}`"
	elif [ -d ${KERNEL_DIR} ] ; then
		einfo "`echo ${KERNEL_DIR} | tr -s /` is a real directory"
		KV_DIR="`ls -d ${KERNEL_DIR}`"
		# KV_DIR="`ls -ld --full-time ${KERNEL_DIR} | awk '{ print $9 }'`"
	else
		eerror "Directory '${KERNEL_DIR}' cannot be found"
		die
	fi
	KV_DIR="`basename ${KV_DIR}`"

	# now, we need to break that down into versions

	KV_DIR_VERSION_FULL="`echo $KV_DIR | cut -f 2- -d -`"

	KV_DIR_MAJOR="`echo ${KV_DIR_VERSION_FULL} | cut -f 1 -d .`"
	KV_DIR_MINOR="`echo ${KV_DIR_VERSION_FULL} | cut -f 2 -d .`"
	KV_DIR_PATCH="`echo ${KV_DIR_VERSION_FULL} | cut -f 3 -d . | cut -f 1 -d -`"
	KV_DIR_TYPE="`echo ${KV_DIR_VERSION_FULL} | cut -f 2- -d -`"

	# sanity check - do the settings in the kernel's makefile match
	# the directory that the kernel src is stored in?

	KV_MK_FILE="${KERNEL_DIR}/Makefile"
	KV_MK_MAJOR="`kmod_get_make_var VERSION ${KV_MK_FILE}`"
	KV_MK_MINOR="`kmod_get_make_var PATCHLEVEL ${KV_MK_FILE}`"
	KV_MK_PATCH="`kmod_get_make_var SUBLEVEL ${KV_MK_FILE}`"
	KV_MK_TYPE="`kmod_get_make_var EXTRAVERSION ${KV_MK_FILE}`"

	KV_MK_VERSION_FULL="${KV_MK_MAJOR}.${KV_MK_MINOR}.${KV_MK_PATCH}${KV_MK_TYPE}"

	KV_MK_OUTPUT="`kmod_get_make_var KBUILD_OUTPUT ${KV_MK_FILE}`"

	# May need to deal with a dynamically set KBUILD_OUTPUT variable
	if [ "${KV_MK_OUTPUT/VERSION/}" != "${KV_MK_OUTPUT}" ]; then
		KV_MK_OUTPUT="${KV_MK_OUTPUT/\$(VERSION)/${KV_MK_MAJOR}}"
		KV_MK_OUTPUT="${KV_MK_OUTPUT/\$(PATCHLEVEL)/${KV_MK_MINOR}}"
		KV_MK_OUTPUT="${KV_MK_OUTPUT/\$(SUBLEVEL)/${KV_MK_PATCH}}"
		KV_MK_OUTPUT="${KV_MK_OUTPUT/\$(EXTRAVERSION)/${KV_MK_TYPE}}"
	fi
	
	if [ "$KV_MK_VERSION_FULL" != "${KV_DIR_VERSION_FULL}" ]; then
		ewarn
		ewarn "The kernel Makefile says that this is a ${KV_MK_VERSION_FULL} kernel"
		ewarn "but the source is in a directory for a ${KV_DIR_VERSION_FULL} kernel."
		ewarn
		ewarn "This goes against the recommended Gentoo naming convention."
		ewarn "Please rename your source directory to 'linux-${KV_MK_VERSION_FULL}'"
		ewarn
	fi

	# these variables can be used by ebuilds to determine whether they
	# will work with the targetted kernel or not
	#
	# do not rely on any of the variables above being available

	KV_VERSION_FULL="${KV_MK_VERSION_FULL}"
	KV_MAJOR="${KV_MK_MAJOR}"
	KV_MINOR="${KV_MK_MINOR}"
	KV_PATCH="${KV_MK_PATCH}"
	KV_TYPE="${KV_MK_TYPE}"

	# if we found an output location, use that. otherwise use KERNEL_DIR.
	if [ ! -z "${KV_MK_OUTPUT}" ]
	then
		KV_OUTPUT="${ROOT}/${KV_MK_OUTPUT}"
	else
		KV_OUTPUT="${KERNEL_DIR}"
	fi

	# KV_OBJ can be used when manually installing kernel modules
	if [ "${KV_MINOR}" -gt "4" ]
	then
		KV_OBJ="ko"
	else
		KV_OBJ="o"
	fi

	einfo "Building for Linux ${KV_VERSION_FULL} found in `echo ${KERNEL_DIR} | tr -s /`"

	if is_kernel 2 5 || is_kernel 2 6
	then
		einfo "which outputs to `echo ${KV_OUTPUT} | tr -s /`"

		# Warn them if they aren't using a different output directory
		if [ "${KV_OUTPUT}" = "${ROOT}/usr/src/linux" ]; then
			ewarn "By not using the kernel's ability to output to an alternative"
			ewarn "directory, some external module builds may fail."
			ewarn "See <insert link to user doc here>"
		fi
	fi
}

# kmod_make_linux_writeable() is used to allow portage to write to
# /usr/src/linux. This is a BIG no-no, but the "easiest" way for
# 2.6 module compilation. Since it's so horrible, we force users to accept
# doing it via a variable controlled by /etc/env.d/20kernel and kernel-config

kmod_make_linux_writable()
{
	# LINUX_PORTAGE_WRITABLE is set in /etc/env.d/20kernel to "yes"
	# if someone really wants to do that
	[ -x ${ROOT}/usr/bin/config-kernel ] && LINUX_PORTAGE_WRITABLE="$(${ROOT}/usr/bin/config-kernel --is-writable)"

	if [ "${LINUX_PORTAGE_WRITABLE}" != "yes" ]
	then
		if [ "${FEATURES/sandbox/}" != "${FEATURES}" ]
		then
			eerror "Due to the 2.6 kernel build system, external module compilation"
			eerror "with a normal setup requires write access to ${KERNEL_DIR}"
			eerror "There are several ways to fix/prevent this."
			eerror "Users can willingly let portage make this writable by doing"
			eerror "# config-kernel --allow-writable yes"
			eerror "However, this is considered a security risk!"
			eerror ""
			eerror "The prefered method is to enable Gentoo's new 'koutput' method"
			eerror "for kernel modules. See the doc"
			eerror "http://www.gentoo.org/doc/en/2.6-koutput-user.xml"
			eerror "To enable this, you'll need to run"
			eerror "# config-kernel --output-dir /var/tmp/kernel-output"
			eerror "and then install a new kernel"
			die "Incompatible kernel setup"
		else
			ewarn "Detected sandbox disabled for kernel module ebuild"
		fi
	fi

	eerror "Making ${ROOT}/usr/src/linux-${KV} writable by portage!!!"
	addwrite ${ROOT}/usr/src/linux-${KV}
}


# kmod_do_buildpatches performs the needed koutput patches as needed
kmod_do_buildpatches()
{
	if [ -z ${KV_OUTPUT} ]; then
		get_kernel_info
	fi

	cd ${S}
	if is_koutput && [ -n "${KMOD_KOUTPUT_PATCH}" ]; then
		EPATCH_SINGLE_MESSAGE="Patching to enable koutput compatibility" \
			epatch ${KMOD_KOUTPUT_PATCH}
	fi
}
	
kmod_src_unpack ()
{
	check_KV
	kmod_universal_unpack
}

kmod_universal_unpack()
{
	get_kernel_info

	# KMOD_SOURCES is used if you don't want to unpack just ${A}
	# It can be set to "none" if you need to unpack things by hand
	# (like the nvidia-kernel ebuild). If set to "none", you'll have
	# to do any patching by hand as ${S} won't be around yet!
	# You can just call kmod_do_buildpatches after unpacking ${S}
	# if need be.
	if [ -z "${KMOD_SOURCES}" ]
	then
		unpack ${A}
	elif [ "${KMOD_SOURCES}" != "none" ]
	then
		unpack ${KMOD_SOURCES}
	fi

	if is_kernel 2 5 || is_kernel 2 6
	then
		# If we have sources we've unpacked, patch as needed
		if [ "${KMOD_SOURCES}" != "none" ]; then
			kmod_do_buildpatches
		fi
	fi
}

kmod_src_compile ()
{
	if is_kernel 2 5 || is_kernel 2 6
	then
		# If we're on 2.5/2.6 and not koutputing, we need to make
		# /usr/src/linux writable to succeed
		if ! is_koutput
		then
			kmod_make_linux_writable
		fi

		unset ARCH
	fi
	emake KERNEL_DIR=${KERNEL_DIR} || die
}

kmod_pkg_postinst()
{
	einfo "Checking kernel module dependancies"
	test -r "${ROOT}/${KV_OUTPUT}/System.map" && \
		depmod -ae -F "${ROOT}/${KV_OUTPUT}/System.map" -b "${ROOT}" -r ${KV}
}

# is_kernel() takes two arguments. They should be the major and minor number
# of the kernel you'd like to check for. e.g.
#
# if is_kernel 2 6; then foo; fi
#
is_kernel() {
	if [ -z "${KV_MAJOR}" ]
	then
		get_kernel_info
	fi

	if [ "${KV_MAJOR}" -eq "${1}" -a "${KV_MINOR}" -eq "${2}" ]
	then    
		return 0
	else    
		return 1
	fi
}

# is_koutput() should be used to determing if we are using the koutput
# method of compilation for 2.6 kernels

is_koutput() {
	if [ -z ${KV_OUTPUT} ]
	then
		get_kernel_info
	fi

	if [ "${KV_OUTPUT}" != "${ROOT}/usr/src/linux" ]; then
		return 0
	else
		return 1
	fi
}