summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2016-11-01 17:04:26 +0100
committerAmaury Pouly <amaury.pouly@gmail.com>2016-11-01 17:09:07 +0100
commitd492f25c54b4134fd6632156efee07670ab4004f (patch)
tree318919b264876a3906d15ecd8781ad0a1e15b3fb
parentb045e4da34165a878c7acc9a82e76b447fe992a7 (diff)
downloadrockbox-d492f25c54b4134fd6632156efee07670ab4004f.tar.gz
rockbox-d492f25c54b4134fd6632156efee07670ab4004f.zip
nwztools: add preliminary dualboot and dualboot install script
At the moment, the script install_duaboot does the following: - rename SpiderApp to SpiderApp.of (unless it already exists) - install payload as SpiderApp - fixes permissions Since SpiderApp is the main app, it will execute instead of the OF. The current dualboot code (dualboot.c) is still a preliminary but the current version displays an "all tools" menu to choose for. When exitting the menu using BACK, it will run the OF. With the modifications made by the install script, it should not be possible to break the device. In the worst case scenario, the dualboot code crashes and it restarted by the sysmgrd, or hangs. A safe way to recover is to plug the USB cable and reset the device: the system manager will then start the USB app and one can reflash the device if necessary. Change-Id: Id9edab0347538ad2a8651a28aea7fd083feaa626
-rw-r--r--utils/nwztools/plattools/Makefile5
-rw-r--r--utils/nwztools/plattools/dualboot.c181
-rw-r--r--utils/nwztools/plattools/nwz_lib.c39
-rw-r--r--utils/nwztools/plattools/nwz_lib.h5
-rw-r--r--utils/nwztools/scripts/Makefile6
-rw-r--r--utils/nwztools/scripts/exec_file.sh4
-rw-r--r--utils/nwztools/scripts/install_dualboot.sh129
7 files changed, 363 insertions, 6 deletions
diff --git a/utils/nwztools/plattools/Makefile b/utils/nwztools/plattools/Makefile
index 8251afaf0a..f4e88cd778 100644
--- a/utils/nwztools/plattools/Makefile
+++ b/utils/nwztools/plattools/Makefile
@@ -7,7 +7,7 @@ INCLUDES=-I.
7LIB_FILES=nwz_lib.c nwz_lib_devlist.c 7LIB_FILES=nwz_lib.c nwz_lib_devlist.c
8TOOL_FILES=dest_tool.c test_adc.c test_adc.c test_bl.c test_display.c \ 8TOOL_FILES=dest_tool.c test_adc.c test_adc.c test_bl.c test_display.c \
9 test_keys.c test_power.c test_ts.c 9 test_keys.c test_power.c test_ts.c
10ALL_ELF=$(patsubst %.c,%.elf,$(TOOL_FILES)) all_tools.elf 10ALL_ELF=$(patsubst %.c,%.elf,$(TOOL_FILES)) all_tools.elf dualboot.elf
11 11
12all: $(ALL_ELF) 12all: $(ALL_ELF)
13 13
@@ -17,5 +17,8 @@ all: $(ALL_ELF)
17all_tools.elf: all_tools.c $(TOOL_FILES) $(LIB_FILES) 17all_tools.elf: all_tools.c $(TOOL_FILES) $(LIB_FILES)
18 $(CC) $(CFLAGS) -DNWZ_EMBED_TOOLS $(INCLUDES) -o $@ $^ 18 $(CC) $(CFLAGS) -DNWZ_EMBED_TOOLS $(INCLUDES) -o $@ $^
19 19
20dualboot.elf: dualboot.c all_tools.c $(TOOL_FILES) $(LIB_FILES)
21 $(CC) $(CFLAGS) -DNWZ_DUALBOOT -DNWZ_EMBED_TOOLS $(INCLUDES) -o $@ $^
22
20clean: 23clean:
21 rm -rf $(ALL_ELF) 24 rm -rf $(ALL_ELF)
diff --git a/utils/nwztools/plattools/dualboot.c b/utils/nwztools/plattools/dualboot.c
new file mode 100644
index 0000000000..965fabed72
--- /dev/null
+++ b/utils/nwztools/plattools/dualboot.c
@@ -0,0 +1,181 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 by Amaury Pouly
11 *
12 * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing
13 * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24#include "nwz_lib.h"
25#include "nwz_plattools.h"
26#include <time.h>
27
28/* Important Note: this bootloader is carefully written so that in case of
29 * error, the OF is run. This seems like the safest option since the OF is
30 * always there and might do magic things. */
31
32bool boot_rockbox(void)
33{
34 /* get time */
35 struct timeval deadline;
36 if(gettimeofday(&deadline, NULL) != 0)
37 {
38 nwz_lcdmsg(false, 0, 2, "Cannot get time");
39 sleep(2);
40 return false;
41 }
42 /* open input device */
43 int input_fd = nwz_key_open();
44 if(input_fd < 0)
45 {
46 nwz_lcdmsg(false, 0, 2, "Cannot open input device");
47 sleep(2);
48 return false;
49 }
50 deadline.tv_sec += 5;
51 /* wait for user action */
52 bool boot_rb = false;
53 while(true)
54 {
55 /* get time */
56 struct timeval cur_time;
57 if(gettimeofday(&cur_time, NULL) != 0)
58 {
59 nwz_lcdmsg(false, 0, 4, "Cannot get time");
60 sleep(2);
61 break;
62 }
63 /* check timeout */
64 if(cur_time.tv_sec > deadline.tv_sec)
65 break;
66 if(cur_time.tv_sec == deadline.tv_sec && cur_time.tv_usec >= deadline.tv_usec)
67 break;
68 /* print message */
69 int sec_left = deadline.tv_sec - cur_time.tv_sec;
70 sec_left += (deadline.tv_usec - cur_time.tv_usec + 999999) / 1000000; /* round up */
71 nwz_lcdmsgf(false, 0, 2, "Booting OF in %d seconds ", sec_left);
72 nwz_lcdmsg(false, 0, 3, "Press BACK to boot RB");
73 /* wait for a key (1s) */
74 int ret = nwz_key_wait_event(input_fd, 1000000);
75 if(ret != 1)
76 continue;
77 struct input_event evt;
78 if(nwz_key_read_event(input_fd, &evt) != 1)
79 continue;
80 if(nwz_key_event_get_keycode(&evt) == NWZ_KEY_BACK && !nwz_key_event_is_press(&evt))
81 {
82 boot_rb = true;
83 break;
84 }
85 }
86 nwz_key_close(input_fd);
87 return boot_rb;
88}
89
90static char *boot_rb_argv[] =
91{
92 "lcdmsg",
93 "-c",
94 "-l",
95 "0,3",
96 "Hello from RB",
97 NULL
98};
99
100static void wait_key(void)
101{
102 int input_fd = nwz_key_open();
103 /* display input state in a loop */
104 while(1)
105 {
106 /* wait for event (10ms) */
107 int ret = nwz_key_wait_event(input_fd, 10000);
108 if(ret != 1)
109 continue;
110 struct input_event evt;
111 if(nwz_key_read_event(input_fd, &evt) != 1)
112 continue;
113 if(nwz_key_event_get_keycode(&evt) == NWZ_KEY_BACK && !nwz_key_event_is_press(&evt))
114 break;
115 }
116 /* finish nicely */
117 nwz_key_close(input_fd);
118}
119
120int NWZ_TOOL_MAIN(all_tools)(int argc, char **argv);
121
122int main(int argc, char **argv)
123{
124#if 0
125 nwz_lcdmsg(true, 0, 0, "dualboot");
126 if(boot_rockbox())
127 {
128 /* boot rockox */
129 nwz_lcdmsg(true, 0, 3, "Booting rockbox...");
130 execvp("/usr/local/bin/lcdmsg", boot_rb_argv);
131 nwz_lcdmsg(false, 0, 4, "failed.");
132 sleep(5);
133 }
134 /* if for some reason, running rockbox failed, then try to run the OF */
135 /* boot OF */
136 nwz_lcdmsg(true, 0, 3, "Booting OF...");
137 execvp("/usr/local/bin/SpiderApp.of", argv);
138 nwz_lcdmsg(false, 0, 4, "failed.");
139 sleep(5);
140 /* if we reach this point, everything failed, so return an error so that
141 * sysmgrd knows something is wrong */
142 return 1;
143#elif 0
144 const char *args_mount[] = {"mount", NULL};
145 int status;
146 char *output = nwz_run_pipe("mount", args_mount, &status);
147 nwz_lcdmsgf(true, 0, 0, "%d\n%s", status, output);
148 free(output);
149 wait_key();
150 const char *args_ls[] = {"ls", "/var", NULL};
151 output = nwz_run_pipe("ls", args_ls, &status);
152 nwz_lcdmsgf(true, 0, 0, "%d\n%s", status, output);
153 free(output);
154 wait_key();
155 const char *args_glogctl[] = {"glogctl", "flush", NULL};
156 output = nwz_run_pipe("/usr/local/bin/glogctl", args_glogctl, &status);
157 nwz_lcdmsgf(true, 0, 0, "%d\n%s", status, output);
158 free(output);
159 wait_key();
160 system("cp /var/GEMINILOG* /contents/");
161 sync();
162 execvp("/usr/local/bin/SpiderApp.of", argv);
163 return 0;
164#else
165 /* make sure backlight is on */
166 int fb_fd = nwz_fb_open(true);
167 if(fb_fd >= 0)
168 {
169 struct nwz_fb_brightness bl;
170 nwz_fb_get_brightness(fb_fd, &bl);
171 bl.level = NWZ_FB_BL_MAX_LEVEL;
172 nwz_fb_set_brightness(fb_fd, &bl);
173 nwz_fb_close(fb_fd);
174 }
175 /* run all tools menu */
176 NWZ_TOOL_MAIN(all_tools)(argc, argv);
177 /* run OF */
178 execvp("/usr/local/bin/SpiderApp.of", argv);
179 return 0;
180#endif
181}
diff --git a/utils/nwztools/plattools/nwz_lib.c b/utils/nwztools/plattools/nwz_lib.c
index 4f49bec909..087db8834a 100644
--- a/utils/nwztools/plattools/nwz_lib.c
+++ b/utils/nwztools/plattools/nwz_lib.c
@@ -30,7 +30,7 @@ const char *nwz_get_model_name(unsigned long model_id)
30 return NULL; 30 return NULL;
31} 31}
32 32
33void nwz_run(const char *file, const char *args[], bool wait) 33int nwz_run(const char *file, const char *args[], bool wait)
34{ 34{
35 pid_t child_pid = fork(); 35 pid_t child_pid = fork();
36 if(child_pid != 0) 36 if(child_pid != 0)
@@ -39,7 +39,10 @@ void nwz_run(const char *file, const char *args[], bool wait)
39 { 39 {
40 int status; 40 int status;
41 waitpid(child_pid, &status, 0); 41 waitpid(child_pid, &status, 0);
42 return status;
42 } 43 }
44 else
45 return 0;
43 } 46 }
44 else 47 else
45 { 48 {
@@ -48,6 +51,40 @@ void nwz_run(const char *file, const char *args[], bool wait)
48 } 51 }
49} 52}
50 53
54char *nwz_run_pipe(const char *file, const char *args[], int *status)
55{
56 int pipe_fds[2];
57 pipe(pipe_fds);
58 pid_t child_pid = fork();
59 if(child_pid == 0)
60 {
61 dup2(pipe_fds[1], 1); /* redirect stdout */
62 dup2(pipe_fds[1], 2); /* redirect stderr */
63 close(pipe_fds[0]); /* close reading */
64 close(pipe_fds[1]); /* close writing */
65 execvp(file, (char * const *)args);
66 _exit(1);
67 }
68 else
69 {
70 close(pipe_fds[1]); /* close writing */
71 char buffer[1024];
72 char *output = malloc(1);
73 ssize_t count;
74 size_t size = 0;
75 while((count = read(pipe_fds[0], buffer, sizeof(buffer))) > 0)
76 {
77 output = realloc(output, size + count + 1);
78 memcpy(output + size, buffer, count);
79 size += count;
80 }
81 close(pipe_fds[0]);
82 output[size] = 0;
83 waitpid(child_pid, status, 0);
84 return output;
85 }
86}
87
51void nwz_lcdmsg(bool clear, int x, int y, const char *msg) 88void nwz_lcdmsg(bool clear, int x, int y, const char *msg)
52{ 89{
53 const char *path_lcdmsg = "/usr/local/bin/lcdmsg"; 90 const char *path_lcdmsg = "/usr/local/bin/lcdmsg";
diff --git a/utils/nwztools/plattools/nwz_lib.h b/utils/nwztools/plattools/nwz_lib.h
index 90d122003a..df0105a13d 100644
--- a/utils/nwztools/plattools/nwz_lib.h
+++ b/utils/nwztools/plattools/nwz_lib.h
@@ -30,6 +30,7 @@
30#include <linux/input.h> 30#include <linux/input.h>
31#include <fcntl.h> 31#include <fcntl.h>
32#include <string.h> 32#include <string.h>
33#include <stdlib.h>
33 34
34#include "nwz_keys.h" 35#include "nwz_keys.h"
35#include "nwz_fb.h" 36#include "nwz_fb.h"
@@ -47,7 +48,9 @@ const char *nwz_get_model_name(unsigned long model_id);
47 48
48/* run a program and exit with nonzero status in case of error 49/* run a program and exit with nonzero status in case of error
49 * argument list must be NULL terminated */ 50 * argument list must be NULL terminated */
50void nwz_run(const char *file, const char *args[], bool wait); 51int nwz_run(const char *file, const char *args[], bool wait);
52/* run a program and return program output */
53char *nwz_run_pipe(const char *file, const char *args[], int *status);
51 54
52/* invoke /usr/bin/lcdmsg to display a message using the small font, optionally 55/* invoke /usr/bin/lcdmsg to display a message using the small font, optionally
53 * clearing the screen before */ 56 * clearing the screen before */
diff --git a/utils/nwztools/scripts/Makefile b/utils/nwztools/scripts/Makefile
index 207534a006..345fd0f4cb 100644
--- a/utils/nwztools/scripts/Makefile
+++ b/utils/nwztools/scripts/Makefile
@@ -11,6 +11,7 @@ all:
11 @echo "- exec_file: craft an upgrade that embeds and execute a file" 11 @echo "- exec_file: craft an upgrade that embeds and execute a file"
12 @echo "- exec_file_extern: craft an upgrade that execute a file on the user partition" 12 @echo "- exec_file_extern: craft an upgrade that execute a file on the user partition"
13 @echo "- list_targets: produce of list of available targets" 13 @echo "- list_targets: produce of list of available targets"
14 @echo "- install_dualboot"
14 15
15ifndef UPG 16ifndef UPG
16want_upg: 17want_upg:
@@ -33,7 +34,7 @@ endif
33ifndef NWZ_TARGET 34ifndef NWZ_TARGET
34want_target: 35want_target:
35 $(info Please set NWZ_TARGET to your target. For example:) 36 $(info Please set NWZ_TARGET to your target. For example:)
36 $(info make dump_rootfs NWZ_TARGET=nwz-e463) 37 $(info make dump_rootfs NWZ_TARGET=nwz-e460)
37 $(info Run 'make list_targets' to get a list of all targets) 38 $(info Run 'make list_targets' to get a list of all targets)
38 $(error "") 39 $(error "")
39else 40else
@@ -72,6 +73,9 @@ UPGPACK=$(upgtool) -c -m $(NWZ_TARGET) $(UPG) $(1)
72exec_file: want_target want_exec want_upg 73exec_file: want_target want_exec want_upg
73 $(call UPGPACK, exec_file.sh $(EXEC)) 74 $(call UPGPACK, exec_file.sh $(EXEC))
74 75
76install_dualboot: want_target want_exec want_upg
77 $(call UPGPACK, install_dualboot.sh $(EXEC))
78
75exec_file_extern.tmp: want_exec want_upg want_log 79exec_file_extern.tmp: want_exec want_upg want_log
76 cat exec_file_extern.sh.in | sed "s|NWZ_EXEC_THIS|$(EXEC)|" |\ 80 cat exec_file_extern.sh.in | sed "s|NWZ_EXEC_THIS|$(EXEC)|" |\
77 sed "s|NWZ_LOG_THIS|$(LOG)|" > $@ 81 sed "s|NWZ_LOG_THIS|$(LOG)|" > $@
diff --git a/utils/nwztools/scripts/exec_file.sh b/utils/nwztools/scripts/exec_file.sh
index a624e4df35..b005156c37 100644
--- a/utils/nwztools/scripts/exec_file.sh
+++ b/utils/nwztools/scripts/exec_file.sh
@@ -20,7 +20,7 @@ CONTENTS_PART=`mount | grep contents | awk '{ print $1 }'`
20 20
21lcdmsg -c -f /usr/local/bin/font_08x12.bmp -l 0,3 "Contents partition:\n$CONTENTS_PART" 21lcdmsg -c -f /usr/local/bin/font_08x12.bmp -l 0,3 "Contents partition:\n$CONTENTS_PART"
22 22
23# 2) We need to remount the contents partition in read-write mode be able to 23# We need to remount the contents partition in read-write mode be able to
24# write something on it 24# write something on it
25lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,6 "Remount $CONTENTS rw" 25lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,6 "Remount $CONTENTS rw"
26if ! mount -o remount,rw $CONTENTS_PART $CONTENTS 26if ! mount -o remount,rw $CONTENTS_PART $CONTENTS
@@ -55,7 +55,7 @@ fi
55lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,7 "Running file..." 55lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,7 "Running file..."
56/tmp/exec >$CONTENTS/exec.txt 2>&1 56/tmp/exec >$CONTENTS/exec.txt 2>&1
57 57
58# 4) Success screen 58# Success screen
59lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "Rebooting in 3 seconds." 59lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "Rebooting in 3 seconds."
60sleep 3 60sleep 3
61sync 61sync
diff --git a/utils/nwztools/scripts/install_dualboot.sh b/utils/nwztools/scripts/install_dualboot.sh
new file mode 100644
index 0000000000..ece5b9e3a3
--- /dev/null
+++ b/utils/nwztools/scripts/install_dualboot.sh
@@ -0,0 +1,129 @@
1#!/bin/sh
2
3# The updater script on the NWZ has a major bug/feature:
4# it does NOT clear the update flag if the update scrit fails
5# thus causing a update/reboot loop and a bricked device
6# always clear to make sure we don't end up being screwed
7nvpflag fup 0xFFFFFFFF
8
9#
10# FIXME document this
11#
12
13
14# go to /tmp
15cd /tmp
16
17# get content partition path
18CONTENTS="/contents"
19CONTENTS_PART=`mount | grep contents | awk '{ print $1 }'`
20
21lcdmsg -c -f /usr/local/bin/font_08x12.bmp -l 0,3 "Contents partition:\n$CONTENTS_PART"
22
23# We need to remount the contents partition in read-write mode be able to
24# write something on it
25lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,6 "Remount $CONTENTS rw"
26mount -o remount,rw $CONTENTS_PART $CONTENTS
27if [ "$?" != 0 ]; then
28 lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: remount failed"
29 sleep 3
30 exit 0
31fi
32
33# import constants
34. /install_script/constant.txt
35_UPDATE_FN_=`nvpstr ufn`
36ROOTFS_TMP_DIR=/tmp/rootfs
37ROCKBOX_NAME=Rockbox
38ROCKBOX_PATH=$ROOTFS_TMP_DIR/usr/local/bin/$ROCKBOX_NAME
39SPIDERAPP_PATH=$ROOTFS_TMP_DIR/usr/local/bin/SpiderApp
40
41# mount root partition
42lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,7 "Mount root filesystem"
43mkdir $ROOTFS_TMP_DIR
44if [ "$?" != 0 ]; then
45 lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: mkdir failed"
46 sleep 3
47 exit 0
48fi
49
50# NOTE some platforms use ext3 and some ext4 with a custom mount program
51# (/usr/local/bin/icx_mount.ext4), some probably use an mtd too
52mount -t ext2 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR
53if [ "$?" != 0 ]; then
54 lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: mount failed"
55 sleep 3
56 exit 0
57fi
58
59# rename the previous main application unless there is already a copy
60lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,8 "Backup OF"
61if [ ! -e $SPIDERAPP_PATH.of ]; then
62 mv $SPIDERAPP_PATH $SPIDERAPP_PATH.of
63fi
64
65# extract our payload executable
66lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,9 "Install rockbox"
67fwpchk -f /contents/$_UPDATE_FN_.UPG -c -1 $SPIDERAPP_PATH
68if [ "$?" != 0 ]; then
69 lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: no file to extract"
70 sleep 3
71 exit 0
72fi
73
74# make it executable and change user/group
75chmod 775 $SPIDERAPP_PATH
76if [ "$?" != 0 ]; then
77 lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: cannot make it executable"
78 sleep 3
79 exit 0
80fi
81chown 500:500 $SPIDERAPP_PATH
82if [ "$?" != 0 ]; then
83 lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: cannot change owner"
84 sleep 3
85 exit 0
86fi
87
88# # change main application
89# lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,9 "Modify app list"
90# sed -i 's/Rockbox/SpiderApp/' $ROOTFS_TMP_DIR/etc/AppList.conf
91# if [ "$?" != 0 ]; then
92# lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,14 "ERROR: sed failed"
93# sleep 3
94# exit 0
95# fi
96# # and fix ownership
97# chown 500:500 $ROOTFS_TMP_DIR/etc/AppList.conf
98# if [ "$?" != 0 ]; then
99# lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,14 "ERROR: cannot change group"
100# sleep 3
101# exit 0
102# fi
103cat $ROOTFS_TMP_DIR/etc/AppList.conf >$CONTENTS/AppList.conf
104ls -l $ROOTFS_TMP_DIR/usr/local/bin/ >$CONTENTS/ls.txt
105ls -l $ROOTFS_TMP_DIR/etc/ >$CONTENTS/ls2.txt
106
107# unmount root partition
108lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,10 "Unmount root filesystem"
109sync
110if [ "$?" != 0 ]; then
111 lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: sync failed"
112 sleep 3
113 exit 0
114fi
115
116umount $ROOTFS_TMP_DIR
117if [ "$?" != 0 ]; then
118 lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: umount failed"
119 sleep 3
120 exit 0
121fi
122
123# Success screen
124lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "Rebooting in 3 seconds."
125sleep 3
126sync
127
128# finish
129exit 0