1#!/bin/bash
2
3###############################################################################
4# Verify preload file meets the necessary requirements for preloading an app
5#
6# Copyright 2012 Nintendo.  All rights reserved.
7#
8# These coded instructions, statements, and computer programs contain
9# proprietary information of Nintendo of America Inc. and/or Nintendo
10# Company Ltd., and are protected by Federal copyright law.  They may
11# not be disclosed to third parties or copied or duplicated in any form,
12# in whole or in part, without the prior written consent of Nintendo.
13###############################################################################
14
15###############################################################################
16# Defines
17###############################################################################
18
19# 20 megabyte cap
20MEMORY_CAP=$((20*1024*1024))
21
22PRELOAD_FILE="preload.txt"
23
24###############################################################################
25# Functions
26###############################################################################
27
28function display_help {
29    echo -e "Preload File Verification\n"
30	echo -e "This script verifies that the $PRELOAD_FILE file meets"\
31			"all necessary requirements for preloading an application.\n"
32	echo -e "Usage: preloadcheck.sh [options] [optional path to code folder]\n "
33    echo -e "Options:\n"\
34			"  -h  : (help) display options\n"\
35            "  -g  : generate preload file"
36}
37
38function check_file_exists_silent {
39    if [ ! -f $working_dir$1 ]
40    then
41        return 1
42    fi
43    return 0
44}
45
46function check_file_exists {
47    if ! check_file_exists_silent $1
48    then
49        echo "Error: Unable to locate the file '$1'"
50        let error_count++
51        return 1
52    fi
53    return 0
54}
55
56function check_text {
57	local text=(`cat $working_dir$2 | tr -cs '[:upper:][:lower:][:punct:][:digit:]' '[\n*]' | grep $1`)
58
59	if [ ${#text[@]} -eq 1 ]; then return 0; fi
60
61	if [ ${#text[@]} -eq 0 ]
62	then
63		echo "Error: '$1' not found in the file '$2'"
64	else
65		echo "Error: Multiple instances of '$1' found in the file '$2'"
66	fi
67
68	let error_count++
69	return 1
70}
71
72function get_filesize {
73	if ! check_file_exists_silent $1
74	then
75		echo 0
76	else
77		echo `stat -c %s $working_dir$1`
78	fi
79}
80
81function get_content_size {
82    local size=0
83    preload_contents=($(cat $working_dir$PRELOAD_FILE | tr '\r' ' '))
84    for i in "${preload_contents[@]}"
85    do
86        let size+=$(get_filesize $i)
87    done
88	echo $size
89}
90
91function append_text {
92    echo -n $1' ' >> $working_dir$2
93}
94
95###############################################################################
96# Main
97###############################################################################
98
99relative_dir=""
100working_dir=$PWD
101generate_file=0
102
103# Process command line arguments
104for var in "$@"
105do
106    case "$var" in
107        -h) display_help
108            exit
109            ;;
110        -g) generate_file=1
111            ;;
112        *)
113            # Relative dir must not start with forward slash, but must
114            # end with one
115            relative_dir=$var
116            [[ $relative_dir = /* ]] && relative_dir=`echo $relative_dir | sed 's/^.//'`
117            [[ $relative_dir != */ ]] && relative_dir="$relative_dir"/
118            working_dir=$working_dir/$relative_dir
119            break
120            ;;
121    esac
122done
123
124# Ensure working_dir ends with forward slash
125[[ $working_dir != */ ]] && working_dir="$working_dir"/
126
127if [ $generate_file -eq 1 ]
128then
129    if check_file_exists_silent $PRELOAD_FILE
130    then
131        echo "Error: '$PRELOAD_FILE' already exists in the directory"
132        exit
133    fi
134    # Create the preload file
135    touch $working_dir$PRELOAD_FILE
136else
137    if ! check_file_exists $PRELOAD_FILE
138    then
139        exit
140    fi
141fi
142
143error_count=0
144
145# Check that the cos/app xml files exist and are listed in preload
146if check_file_exists "cos.xml"
147then
148    if [ $generate_file -eq 0 ]
149    then
150        check_text "cos.xml" $PRELOAD_FILE
151    else
152        append_text "cos.xml" $PRELOAD_FILE
153    fi
154fi
155
156if check_file_exists "app.xml"
157then
158    if [ $generate_file -eq 0 ]
159    then
160        check_text "app.xml" $PRELOAD_FILE
161    else
162        append_text "app.xml" $PRELOAD_FILE
163    fi
164fi
165
166# If the preload file was generated, get the name of the rpx and add it
167if [ $generate_file -eq 1 ]
168then
169    rpx_file=(`find $working_dir -maxdepth 1 -name '*.rpx'`)
170	if [ ${#rpx_file[@]} -eq 1 ]
171	then
172        rpx_file=`basename $rpx_file`
173        file_size=$(get_filesize $rpx_file)
174        if [ $file_size -gt $MEMORY_CAP ]
175        then
176            echo "Warning: '$rpx_file' exceeds the maximum memory size of"\
177                 "$MEMORY_CAP bytes, and will not be added to '$PRELOAD_FILE'"
178        else
179            append_text $rpx_file $PRELOAD_FILE
180        fi
181	else
182		if [ ${#rpx_file[@]} -eq 0 ]
183		then
184			echo "Error: No rpx file exists in the directory"
185		else
186            echo "Error: Multiple rpx files exist in the directory."\
187                 "Unabled to determine which one to add to '$PRELOAD_FILE'"
188		fi
189		let error_count++
190		unset rpx_file
191	fi
192else
193    # Retieve the name of the rpx from the preload file
194    rpx_file=(`cat $working_dir$PRELOAD_FILE | tr -cs '[:upper:][:lower:][:punct:][:digit:]' '[\n*]' | grep '\.rpx'`)
195	if [ ${#rpx_file[@]} -eq 1 ]
196	then
197		if ! check_file_exists $rpx_file
198		then
199			unset rpx_file
200		fi
201	else
202		if [ ${#rpx_file[@]} -eq 0 ]
203		then
204			echo "Warning: No rpx file specified in '$PRELOAD_FILE'"
205            # Attempt to retrieve the rpx name from the directory
206            rpx_file=(`find $working_dir -maxdepth 1 -name '*.rpx'`)
207            if [ ${#rpx_file[@]} -eq 1 ]
208            then
209                rpx_file=`basename $rpx_file`
210            fi
211		else
212            echo "Error: Multiple rpx files specified in '$PRELOAD_FILE'"
213            let error_count++
214            unset rpx_file
215        fi
216    fi
217fi
218
219if [ $generate_file -eq 1 ]
220then
221    content_size=$(get_content_size)
222else
223    # Verify that all listed rpls exist in the directory
224    rpl_file=(`cat $working_dir$PRELOAD_FILE | tr -cs '[:upper:][:lower:][:punct:][:digit:]' '[\n*]' | grep '\.rpl'`)
225    for i in "${rpl_file[@]}"
226    do
227        check_file_exists $i
228    done
229fi
230
231# Use dumprpl to return all statically bound rpls and verify that they
232# exist in the directory and are listed in the preload file. This is a
233# recurssive process as each rpl may have others statically bound to it
234rpl_search=($rpx_file)
235while [ ${#rpl_search[@]} -ne 0 ]
236do
237    for i in $rpl_search
238    do
239        rpl_temp=("${rpl_temp[@]}" `dumprpl -imports $relative_dir$i | grep 'Imports' |\
240                tr -cs '[:upper:][:lower:][:punct:][:digit:]' '[\n*]' |\
241                grep -E 'fimport_\w*|dimport_\w*' | cut -c10- | cut -f1 -d "," | sort -u`)
242    done
243
244    unset rpl_search
245
246    for i in "${rpl_temp[@]}"
247    do
248        i=$i".rpl"
249
250        # Only concerned with rpls that exist in the directory
251        if ! check_file_exists_silent $i; then continue; fi
252
253        # Check that the rpl is listed in the preload file
254        if [ $generate_file -eq 0 ]
255        then
256            check_text $i $PRELOAD_FILE
257        else
258            file_size=$(get_filesize $i)
259            if [ $(($content_size+$file_size)) -gt $MEMORY_CAP ]
260            then
261                echo "Warning: Unable to add $i to '$PRELOAD_FILE';"\
262                     " maximum content size exceeded"
263            else
264                append_text $i $PRELOAD_FILE
265                content_size=$(($content_size+$file_size))
266            fi
267        fi
268
269        # Add any rpls that have not already been dumped to the search list
270        match=$(echo "$rpl_files:0}" | grep -o $i)
271        [[ -z $match ]] && rpl_files=("${rpl_files[@]}" $i) \
272                        && rpl_search=("${rpl_search[@]}" $i)
273    done
274
275    unset rpl_temp
276done
277
278# Check that total size of all files in the preload file does not exceed max
279content_size=$(get_content_size)
280if [ $content_size -gt $MEMORY_CAP ]
281then
282    echo "Error: The contents of '$PRELOAD_FILE' is $content_size bytes which"\
283		 "exceeds the maximum allowed size of $MEMORY_CAP bytes"
284    let error_count++
285fi
286
287if [ $error_count -eq 0 ]
288then
289    echo -e "No errors detected."
290else
291    echo -e "\nErrors were encountered. Pleae check that $PRELOAD_FILE meets"\
292            "all necessary\nrequirements."
293fi