Added a nice patch from John R. Graham <john_r_graham@mindspring.com> to allow all...
[genkernel.git] / gen_funcs.sh
1 #!/bin/bash
2
3 isTrue() {
4         case "$1" in
5                 [Tt][Rr][Uu][Ee])
6                         return 0
7                 ;;
8                 [Tt])
9                         return 0
10                 ;;
11                 [Yy][Ee][Ss])
12                         return 0
13                 ;;
14                 [Yy])
15                         return 0
16                 ;;
17                 1)
18                         return 0
19                 ;;
20         esac
21         return 1
22 }
23
24 setColorVars() { 
25 if isTrue ${USECOLOR}
26 then
27         GOOD=$'\e[32;01m'
28         WARN=$'\e[33;01m'
29         BAD=$'\e[31;01m'
30         NORMAL=$'\e[0m'
31         BOLD=$'\e[0;01m'
32         UNDER=$'\e[4m'
33 else
34         GOOD=''
35         WARN=''
36         BAD=''
37         NORMAL=''
38         BOLD=''
39         UNDER=''
40 fi
41 }
42 setColorVars
43
44 dump_debugcache() {
45         TODEBUGCACHE=0
46         echo "${DEBUGCACHE}" >> ${LOGFILE}
47 }
48
49 # print_info(loglevel, print [, newline [, prefixline [, forcefile ] ] ])
50 print_info() {
51         local NEWLINE=1
52         local FORCEFILE=0
53         local PREFIXLINE=1
54         local SCRPRINT=0
55         local STR=''
56
57         # NOT ENOUGH ARGS
58         if [ "$#" -lt '2' ] ; then return 1; fi
59
60         # IF 3 OR MORE ARGS, CHECK IF WE WANT A NEWLINE AFTER PRINT
61         if [ "$#" -gt '2' ]
62         then
63                 if isTrue "$3"
64                 then
65                         NEWLINE='1';
66                 else
67                         NEWLINE='0';
68                 fi
69         fi
70
71         # IF 4 OR MORE ARGS, CHECK IF WE WANT TO PREFIX WITH A *
72         if [ "$#" -gt '3' ]
73         then
74                 if isTrue "$4"
75                 then
76                         PREFIXLINE='1'
77                 else
78                         PREFIXLINE='0'
79                 fi
80         fi
81
82         # IF 5 OR MORE ARGS, CHECK IF WE WANT TO FORCE OUTPUT TO DEBUG
83         # FILE EVEN IF IT DOESN'T MEET THE MINIMUM DEBUG REQS
84         if [ "$#" -gt '4' ]
85         then
86                 if isTrue "$5"
87                 then
88                         FORCEFILE='1'
89                 else
90                         FORCEFILE='0'
91                 fi
92         fi
93
94         # PRINT TO SCREEN ONLY IF PASSED LOGLEVEL IS HIGHER THAN
95         # OR EQUAL TO SET DEBUG LEVEL
96         if [ "$1" -lt "${LOGLEVEL}" -o "$1" -eq "${LOGLEVEL}" ]
97         then
98                 SCRPRINT='1'
99         fi
100
101         # RETURN IF NOT OUTPUTTING ANYWHERE
102         if [ "${SCRPRINT}" != '1' -a "${FORCEFILE}" != '1' ]
103         then
104                 return 0
105         fi
106
107         # STRUCTURE DATA TO BE OUTPUT TO SCREEN, AND OUTPUT IT
108         if [ "${SCRPRINT}" -eq '1' ]
109         then
110                 if [ "${PREFIXLINE}" = '1' ]
111                 then
112                         STR="${GOOD}*${NORMAL} ${2}"
113                 else
114                         STR="${2}"
115                 fi
116
117                 if [ "${NEWLINE}" = '0' ]
118                 then
119                         echo -ne "${STR}"
120                 else
121                         echo "${STR}"
122                 fi
123         fi
124
125         # STRUCTURE DATA TO BE OUTPUT TO FILE, AND OUTPUT IT
126         if [ "${SCRPRINT}" -eq '1' -o "${FORCEFILE}" -eq '1' ]
127         then
128                 STRR=${2//${WARN}/}
129                 STRR=${STRR//${BAD}/}
130                 STRR=${STRR//${BOLD}/}
131                 STRR=${STRR//${NORMAL}/}
132
133                 if [ "${PREFIXLINE}" = '1' ]
134                 then
135                         STR="* ${STRR}"
136                 else
137                         STR="${STRR}"
138                 fi
139
140                 if [ "${NEWLINE}" = '0' ]
141                 then
142                         if [ "${TODEBUGCACHE}" -eq '1' ]; then
143                                 DEBUGCACHE="${DEBUGCACHE}${STR}"
144                         else
145                                 echo -ne "${STR}" >> ${LOGFILE}
146                         fi      
147                 else
148                         if [ "${TODEBUGCACHE}" -eq '1' ]; then
149                                 DEBUGCACHE="${DEBUGCACHE}${STR}"$'\n'
150                         else
151                                 echo "${STR}" >> ${LOGFILE}
152                         fi
153                 fi
154         fi
155
156         return 0
157 }
158
159 print_error()
160 {
161         GOOD=${BAD} print_info "$@"
162 }
163
164 print_warning()
165 {
166         GOOD=${WARN} print_info "$@"
167 }
168
169 # var_replace(var_name, var_value, string)
170 # $1 = variable name
171 # $2 = variable value
172 # $3 = string
173
174 var_replace()
175 {
176   # Escape '\' and '.' in $2 to make it safe to use
177   # in the later sed expression
178   local SAFE_VAR
179   SAFE_VAR=`echo "${2}" | sed -e 's/\([\/\.]\)/\\\\\\1/g'`
180   
181   echo "${3}" | sed -e "s/%%${1}%%/${SAFE_VAR}/g" -
182 }
183
184 arch_replace() {
185   var_replace "ARCH" "${ARCH}" "${1}"
186 }
187
188 kv_replace() {
189   var_replace "KV" "${KV}" "${1}"
190 }
191
192 cache_replace() {
193   var_replace "CACHE" "${CACHE_DIR}" "${1}"
194 }
195
196 clear_log() {
197     if [ -f "${LOGFILE}" ]
198     then
199         (echo > "${LOGFILE}") 2>/dev/null || small_die "Genkernel: Could not write to ${LOGFILE}."
200     fi   
201 }
202
203 gen_die() {
204         dump_debugcache
205
206         if [ "$#" -gt '0' ]
207         then
208                 print_error 1 "ERROR: ${1}"
209         fi
210         echo
211         print_info 1 "-- Grepping log... --"
212         echo
213
214         if isTrue ${USECOLOR}
215         then
216                 GREP_COLOR='1' grep -B5 -E --colour=always "([Ww][Aa][Rr][Nn][Ii][Nn][Gg]|[Ee][Rr][Rr][Oo][Rr][ :,!]|[Ff][Aa][Ii][Ll][Ee]?[Dd]?)" ${LOGFILE}
217         else
218                 grep -B5 -E "([Ww][Aa][Rr][Nn][Ii][Nn][Gg]|[Ee][Rr][Rr][Oo][Rr][ :,!]|[Ff][Aa][Ii][Ll][Ee]?[Dd]?)" ${LOGFILE}
219         fi
220         echo
221         print_info 1 "-- End log... --"
222         echo
223         print_info 1 "Please consult ${LOGFILE} for more information and any"
224         print_info 1 "errors that were reported above."
225         echo
226         print_info 1 "Report any genkernel bugs to bugs.gentoo.org and"
227         print_info 1 "assign your bug to genkernel@gentoo.org. Please include"
228         print_info 1 "as much information as you can in your bug report; attaching"
229         print_info 1 "${LOGFILE} so that your issue can be dealt with effectively."
230         print_info 1 ''
231         print_info 1 'Please do *not* report compilation failures as genkernel bugs!'
232         print_info 1 ''
233
234         # Cleanup temp dirs and caches if requested
235         cleanup
236         exit 1
237 }
238
239 has_loop() {
240         if [ -e /var/log/dmesg ]
241         then
242                 cat /var/log/dmesg | egrep -q '^loop:'
243         else
244                 dmesg | egrep -q '^loop:'
245         fi
246         if [ -e '/dev/loop0' -o -e '/dev/loop/0' -a ${PIPESTATUS[1]} ]
247         then
248                 # We found devfs or standard dev loop device, assume
249                 # loop is compiled into the kernel or the module is loaded
250                 return 0
251         else
252                 return 1
253         fi
254 }
255
256 isBootRO()
257 {
258         return $(awk '( $2 == "'${BOOTDIR}'" && $4 ~ /(^|,)ro(,|$)/){ I=1; exit }END{print !I }' /proc/mounts);
259 }
260
261 setup_cache_dir()
262 {
263
264 [ ! -d "${CACHE_DIR}" ] && mkdir -p "${CACHE_DIR}"
265
266 if [ "${CLEAR_CACHE_DIR}" == 'yes' ]
267 then
268         print_info 1 "Clearing cache dir contents from ${CACHE_DIR}"
269         CACHE_DIR_CONTENTS=`ls ${CACHE_DIR}|grep -v CVS|grep -v cpio|grep -v README`
270         
271         for i in ${CACHE_DIR_CONTENTS}
272         do
273                 print_info 1 "   >> removing ${i}"
274                 rm ${CACHE_DIR}/${i}
275         done
276 fi
277
278 }
279
280 clear_tmpdir()
281 {
282 if ! isTrue ${CMD_NOINSTALL}
283 then
284     TMPDIR_CONTENTS=`ls ${TMPDIR}`
285     print_info 1 "Removing tmp dir contents"
286     for i in ${TMPDIR_CONTENTS}
287     do
288         print_info 1 "   >> removing ${i}"
289         rm ${TMPDIR}/${i}
290     done
291 fi
292 }       
293
294 #
295 # Function to copy various kernel boot image products to the boot directory,
296 # preserve a generation of old images (just like the manual kernel build's
297 # "make install" does), and maintain the symlinks (if enabled).
298 #
299 # Arguments:
300 #     $1  Symlink name.  Symlink on the boot directory. Path not included.
301 #     $2  Source image.  Fully qualified path name of the source image.
302 #     $3  Dest image.    Name of the destination image in the boot directory,
303 #         no path included.  This script pushd's into ${BOOTDIR} in order to
304 #         create relative symlinks just like the manual kernel build.
305 #
306 # - JRG
307 #
308 copy_image_with_preserve() {
309         local symlinkName=$1
310         local newSrceImage=$2
311         local fullDestName=$3
312
313         local currDestImage
314         local prevDestImage
315         local currDestImageExists=0
316         local prevDestImageExists=0
317
318         print_info 4 "Copying new ${symlinkName} image, " 0
319
320         # Old product might be a different version.  If so, we need to read
321         # the symlink to see what it's name is, if there are symlinks.
322         if [ "${SYMLINK}" -eq '1' ]
323         then
324                 print_info 4 "automatically managing symlinks and old images." 1 0
325                 if [ -e "${BOOTDIR}/${symlinkName}" ]
326                 then
327                         # JRG: Do I need a special case here for when the standard symlink
328                         # name is, in fact, not a symlink?
329                         currDestImage=`readlink --no-newline ${BOOTDIR}/${symlinkName}`
330                         print_info 5 "  Current ${symlinkName} symlink exists:"
331                         print_info 5 "    ${currDestImage}"
332                 else
333                         currDestImage="${fullDestName}"
334                         print_info 5 "  Current ${symlinkName} symlink did not exist."
335                         print_info 5 "    Defaulted to: ${currDestImage}"
336                 fi
337                 if [ -e "${BOOTDIR}/${currDestImage}" ]
338                 then
339                         currDestImageExists=1
340                         print_info 5 "  Actual image file exists."
341                 fi
342
343                 if [ -e "${BOOTDIR}/${symlinkName}.old" ]
344                 then
345                         # JRG: Do I need a special case here for when the standard symlink
346                         # name is, in fact, not a symlink?
347                         prevDestImage=`readlink --no-newline ${BOOTDIR}/${symlinkName}.old`
348                         print_info 5 "  Old ${symlinkName} symlink exists:"
349                         print_info 5 "    ${prevDestImage}"
350                 else
351                         prevDestImage="${fullDestName}.old"
352                         print_info 5 "  Old ${symlinkName} symlink did not exist."
353                         print_info 5 "    Defaulted to: ${prevDestImage}"
354                 fi
355                 if [ -e "${BOOTDIR}/${prevDestImage}" ]
356                 then
357                         prevDestImageExists=1
358                         print_info 5 "  Actual old image file exists."
359                 fi
360         else
361                 print_info 4 "symlinks not being handled by genkernel." 1 0
362                 currDestImage="${fullDestName}"
363                 prevDestImage="${fullDestName}.old"
364         fi
365
366         # When symlinks are not being managed by genkernel, old symlinks might
367     # still be useful.  Leave 'em alone unless managed.
368         if [ "${SYMLINK}" -eq '1' ]
369         then
370                 print_info 5 "  Deleting old symlinks, if any."
371                 rm -f "${BOOTDIR}/${symlinkName}"
372                 rm -f "${BOOTDIR}/${symlinkName}.old"
373         fi
374
375         # We only erase the .old image when it is the exact same version as the
376         # current and new images.  Different version .old (and current) images are
377         # left behind.  This is consistent with how "make install" of the manual
378         # kernel build works.
379         if [ "${currDestImage}" == "${fullDestName}" ]
380         then
381                 #
382                 # Case for new and currrent of the same base version.
383                 #
384                 print_info 5 "  Same base version.  May have to delete old image to make room."
385
386                 if [ "${currDestImageExists}" -eq '1' ]
387                 then
388                         if [ -e "${BOOTDIR}/${currDestImage}.old" ]
389                         then
390                                 print_info 5 "  Deleting old identical version ${symlinkName}."
391                                 rm -f "${BOOTDIR}/${currDestImage}.old"
392                         fi
393                         print_info 5 "  Moving ${BOOTDIR}/${currDestImage}"
394                         print_info 5 "    to ${BOOTDIR}/${currDestImage}.old"
395                         mv "${BOOTDIR}/${currDestImage}" "${BOOTDIR}/${currDestImage}.old" ||
396                             gen_die "Could not rename the old ${symlinkName} image!"
397                         prevDestImage="${currDestImage}.old"
398                         prevDestImageExists=1
399                 fi
400         else
401                 #
402                 # Case for new / current not of the same base version.
403                 #
404                 print_info 5 "  Different base version.  Do not delete old images."
405                 prevDestImage="${currDestImage}"
406                 currDestImage="${fullDestName}"
407         fi
408
409         print_info 5 "  Copying ${symlinkName}: ${newSrceImage}"
410         print_info 5 "    to ${BOOTDIR}/${currDestImage}"
411         cp "${newSrceImage}" "${BOOTDIR}/${currDestImage}" ||
412             gen_die "Could not copy the ${symlinkName} image to ${BOOTDIR}!"
413
414         if [ "${SYMLINK}" -eq '1' ]
415         then
416                 print_info 5 "  Make new symlink(s) (from ${BOOTDIR}):"
417                 print_info 5 "    ${symlinkName} -> ${currDestImage}"
418                 pushd ${BOOTDIR} >/dev/null
419                 ln -s "${currDestImage}" "${symlinkName}" || 
420                     gen_die "Could not create the ${symlinkName} symlink!"
421                 if [ "${prevDestImageExists}" -eq '1' ]
422                 then
423                         print_info 5 "    ${symlinkName}.old -> ${prevDestImage}"
424                         ln -s "${prevDestImage}" "${symlinkName}.old" ||
425                             gen_die "Could not create the ${symlinkName}.old symlink!"
426                 fi
427                 popd >/dev/null
428         fi
429 }
430
431 #
432 # Helper function to allow command line arguments to override configuration
433 # file specified values and to apply defaults.
434 #
435 # Arguments:
436 #     $1  Argument type:
437 #           1  Switch type arguments (e.g., --color / --no-color).
438 #           2  Value type arguments (e.g., --debuglevel=5).
439 #     $2  Config file variable name.
440 #     $3  Command line variable name.
441 #     $4  Default.  If both the config file variable and the command line
442 #         option are not present, then the config file variable is set to
443 #         this default value.  Optional.
444 #
445 # The order of priority of these three sources (highest first) is:
446 #     Command line, which overrides
447 #     Config file (/etc/genkernel.conf), which overrides
448 #     Default.
449 #
450 # Arguments $2 and $3 are variable *names*, not *values*.  This function uses
451 # various forms of indirection to access the values.
452 #
453 # For switch type arguments, all forms of "True" are converted to a numeric 1
454 # and all forms of "False" (everything else, really) to a numeric 0.
455 #
456 # - JRG
457 #
458 set_config_with_override() {
459         local VarType=$1
460         local CfgVar=$2
461         local OverrideVar=$3
462         local Default=$4
463         local Result
464
465         #
466         # Syntax check the function arguments.
467         #
468         case "$VarType" in
469                 1|2)
470                         ;;
471                 *)
472                         gen_die "Illegal variable type \"$VarType\" passed to set_config_with_override()."
473                         ;;
474         esac
475
476         if [ -n "${!OverrideVar}" ]
477         then
478                 Result=${!OverrideVar}
479                 if [ -n "${!CfgVar}" ]
480                 then
481                         print_info 5 "  $CfgVar overridden on command line to \"$Result\"."
482                 else
483                         print_info 5 "  $CfgVar set on command line to \"$Result\"."
484                 fi
485         else
486                 if [ -n "${!CfgVar}" ]
487                 then
488                         Result=${!CfgVar}
489                         print_info 5 "  $CfgVar set in config file to \"${Result}\"."
490                 else
491                         if [ -n "$Default" ]
492                         then
493                                 Result=${Default}
494                                 print_info 5 "  $CfgVar defaulted to \"${Result}\"."
495                         else
496                                 print_info 5 "  $CfgVar not set."
497                         fi
498                 fi
499         fi
500
501         if [ "$VarType" -eq "1" ]
502         then
503                 if isTrue "${Result}"
504                 then
505                         Result=1
506                 else
507                         Result=0
508                 fi
509         fi
510
511         eval ${CfgVar}=${Result}
512 }
513