0aea4c45458185b19267ec4c29f00cb449bdaf55
[platform/core/system/upgrade-tools.git] / mk_delta / common / bin / mk_part_delta.sh
1 #!/bin/bash
2
3
4 #==================
5 # funtions
6 #==================
7
8 #------------------------------------------------------------------------------
9 # Function :
10 #       fn_mk_attribute
11 #
12
13 fn_print_line()
14 {
15         CHAR=$1
16         NUM=$2
17
18         echo "*******************************************************************"
19 }
20
21 #------------------------------------------------------------------------------
22 # Function :
23 #       fn_mk_attribute
24 #
25 # Params :
26 #       $1 - PART_NAME. to descriminate
27 #       $2 - base directory to search files for old partition
28 #       $3 - base directory to search files for new partition
29 #
30 # Description :
31 #       extract attribute information of files on the given partition
32 #
33
34 fn_mk_attribute()
35 {
36         TARGET=$1
37         BASE_DIR_OLD=$2
38         BASE_DIR_NEW=$3
39         V1_ATTR_FILE=${OUTPUT_DIR}/v1_${TARGET}_attr.txt
40         V1_NAME_FILE=${OUTPUT_DIR}/v1_list.txt
41         V2_ATTR_FILE=${OUTPUT_DIR}/v2_${TARGET}_attr.txt
42         V2_NAME_FILE=${OUTPUT_DIR}/v2_list.txtfg
43         V23_NAME_FILE=v23_${TARGET}_attr.txt
44         V13_NAME_FILE=v13_${TARGET}_attr.txt
45         ATTR_CMD=extended_attr.sh
46
47         echo "Attribute generation for ${TARGET} [START] $(date +%T)"
48
49         sudo find ./${BASE_DIR_OLD} -type f -printf '"/%P" Regular 14 %04m:%04U:%04G:' -exec ${COMMON_BINDIR}/${ATTR_CMD} {} \; >  ${V1_ATTR_FILE}
50         sudo find ./${BASE_DIR_OLD} -type l -printf '"/%P" SymLink 14 %04m:%04U:%04G:' -exec ${COMMON_BINDIR}/${ATTR_CMD} {} \; >> ${V1_ATTR_FILE}
51         sudo find ./${BASE_DIR_OLD} -type d -printf '"/%P" Regular 14 %04m:%04U:%04G:' -exec ${COMMON_BINDIR}/${ATTR_CMD} {} \; >> ${V1_ATTR_FILE}
52
53         sudo find ./${BASE_DIR_NEW} -type f -printf '"/%P" Regular 14 %04m:%04U:%04G:' -exec ${COMMON_BINDIR}/${ATTR_CMD} {} \; >  ${V2_ATTR_FILE}
54         sudo find ./${BASE_DIR_NEW} -type l -printf '"/%P" SymLink 14 %04m:%04U:%04G:' -exec ${COMMON_BINDIR}/${ATTR_CMD} {} \; >> ${V2_ATTR_FILE}
55         sudo find ./${BASE_DIR_NEW} -type d -printf '"/%P" Regular 14 %04m:%04U:%04G:' -exec ${COMMON_BINDIR}/${ATTR_CMD} {} \; >> ${V2_ATTR_FILE}
56
57         ################ Change user and group permission from '0' to '0000' ############
58         sed -i 's/:   0/:0000/g' ${V1_ATTR_FILE}
59         sed -i 's/:   /:000/g' ${V1_ATTR_FILE}
60         sed -i 's/:  /:00/g' ${V1_ATTR_FILE}
61         sed -i 's/: /:0/g' ${V1_ATTR_FILE}
62
63         sed -i 's/:   0/:0000/g' ${V2_ATTR_FILE}
64         sed -i 's/:   /:000/g' ${V2_ATTR_FILE}
65         sed -i 's/:  /:00/g' ${V2_ATTR_FILE}
66         sed -i 's/: /:0/g' ${V2_ATTR_FILE}
67
68         ################ Change ":./old" to "/" ############
69         sed -i "s/:.\/${BASE_DIR_OLD}\//:\//" ${V1_ATTR_FILE}
70         sed -i "s/:.\/${BASE_DIR_OLD}/:\//" ${V1_ATTR_FILE}
71         sed -i "s/:.\/${BASE_DIR_NEW}\//:\//" ${V2_ATTR_FILE}
72         sed -i "s/:.\/${BASE_DIR_NEW}/:\//" ${V2_ATTR_FILE}
73
74         echo "Attribute generation for ${TARGET} [END] $(date +%T)"
75 }
76
77 #------------------------------------------------------------------------------
78 # Function :
79 #       fn_mk_full_img
80 #
81
82 fn_mk_full_img()
83 {
84         PART_IMG_ORG=${PART_BIN}
85         PART_IMG_OLD=${PART_IMG_ORG}.old
86         PART_IMG_NEW=${PART_IMG_ORG}.new
87
88         #---- untar partition image and rename for old & new ----
89         if [ ! "z${OLD_TAR_FILE}" = "z" ]; then
90                 echo "untar ${OLD_TAR_FILE}"
91                 tar xvf ${OLD_TAR_DIR}/${OLD_TAR_FILE} ${PART_IMG_ORG}
92                 if [ "$?" != "0" ]; then
93                         return 1;
94                 fi
95                 sudo mv ${PART_IMG_ORG} ${PART_IMG_OLD}
96         fi
97
98         echo "untar ${NEW_TAR_FILE}"
99         tar xvf ${NEW_TAR_DIR}/${NEW_TAR_FILE} ${PART_IMG_ORG}
100         if [ "$?" != "0" ]; then
101                 return 1;
102         fi
103         sudo mv ${PART_IMG_ORG} ${PART_IMG_NEW}
104
105         if [ ! "z${OLD_TAR_FILE}" = "z" ]; then
106                 #---- check whether the binaries are same ----
107                 sudo diff ${PART_IMG_OLD} ${PART_IMG_NEW}
108                 if [ "$?" = "0" ]; then
109                         echo "[${PART_NAME}] two binaries are same"
110                         sudo rm -rf ${PART_IMG_OLD}
111                         sudo rm -rf ${PART_IMG_NEW}
112                         return 0
113                 fi
114                 sudo python ${COMMON_BINDIR}/CreatePatch.py ${UPDATE_TYPE} ${PART_NAME} ${PART_IMG_OLD} ${PART_IMG_NEW} ${OUTPUT_DIR} ${UPDATE_CFG_PATH}
115                 PythonRet=$?
116                 sudo rm ${PART_IMG_OLD}
117
118                 if [ $PythonRet != "0" ]; then
119                         echo "[${PART_NAME}] Failed to generate DELTA"
120                         exit 1
121                 fi
122         fi
123
124         sudo mv ${PART_IMG_NEW} ${OUTPUT_DIR}/${PART_IMG_ORG}
125         sudo chown ${MY_ID}:${MY_ID} ${OUTPUT_DIR}/${PART_IMG_ORG}
126
127         return 0
128 }
129
130 #------------------------------------------------------------------------------
131 # Function :
132 #       fn_mk_delta_img_core
133 #
134 # Description :
135 #       core routine for delta generation
136 #       Image Update Type
137 #
138
139 fn_mk_delta_img_core()
140 {
141
142         START_TIMESTAMP="generation of ${DELTA} [START] $(date +%T)"
143
144         #---- untar partition image and rename for old & new ----
145         echo "untar ${OLD_TAR_FILE}"
146         tar xvf ${OLD_TAR_DIR}/${OLD_TAR_FILE} ${PART_IMG_ORG}
147         if [ "$?" != "0" ]; then
148                 return 1;
149         fi
150         sudo mv ${PART_IMG_ORG} ${PART_IMG_OLD}
151
152         echo "untar ${NEW_TAR_FILE}"
153         tar xvf ${NEW_TAR_DIR}/${NEW_TAR_FILE} ${PART_IMG_ORG}
154         if [ "$?" != "0" ]; then
155                 return 1;
156         fi
157         sudo mv ${PART_IMG_ORG} ${PART_IMG_NEW}
158
159         #---- check whether the binaries are same ----
160         sudo diff ${PART_IMG_OLD} ${PART_IMG_NEW}
161         if [ "$?" = "0" ]; then
162                 echo "[${PART_NAME}] two binaries are same"
163                 sudo rm -rf ${PART_IMG_OLD}
164                 sudo rm -rf ${PART_IMG_NEW}
165                 return 0
166         fi
167
168         #---- make delta file ----
169         echo "make ${DELTA}"
170         sudo python ${COMMON_BINDIR}/CreatePatch.py ${UPDATE_TYPE} ${PART_NAME} ${PART_IMG_OLD} ${PART_IMG_NEW} ${OUTPUT_DIR} ${UPDATE_CFG_PATH}
171         PythonRet=$?
172         #sudo xdelta delta ${PART_IMG_OLD} ${PART_IMG_NEW} ./${OUTPUT_DIR}/${PART_NAME}".delta"
173
174         #---- remove files & directories ----
175         echo "remove temp files/directory & move delta/log to result directory"
176         sudo rm -rf ${PART_IMG_OLD}
177         sudo rm -rf ${PART_IMG_NEW}
178         sudo rm -rf x
179
180         if [ $PythonRet != "0" ]; then
181                 echo "[${PART_NAME}] Failed to generate DELTA"
182                 exit 1
183         fi
184         END_TIMESTAMP="generation of ${DELTA} [END] $(date +%T)"
185         echo "${START_TIMESTAMP}"
186         echo "${END_TIMESTAMP}"
187
188
189         return 0
190 }
191
192 #------------------------------------------------------------------------------
193 # Function :
194 #       fn_mk_delta_img
195 #
196 # Description :
197 #       generate delta file for image type partition
198 #
199
200 fn_mk_delta_img()
201 {
202         PART_IMG_ORG=${PART_BIN}
203         PART_IMG_OLD=${PART_IMG_ORG}.old
204         PART_IMG_NEW=${PART_IMG_ORG}.new
205
206         DELTA=${DELTA_BIN}
207         DEBUG_DELTA=debug_${DELTA}
208         #CFG_XML=${PART_NAME}_IMG.xml
209         mkdir ${OUTPUT_DIR}/i
210         fn_mk_delta_img_core
211         if [ "$?" != "0" ]; then
212                 return 1
213         fi
214
215         return 0
216
217 }
218 #------------------------------------------------------------------------------
219 # Function :
220 #       mk_inter_attrib_file
221 #
222 # Description :
223 #       makes a list of attributes for those files which differ between v1 aND V2
224 #manoj:to create intermediate attribute list
225 fn_mk_inter_attrib_file()
226 {
227         V1ref_ATTR_FILE=${OUTPUT_DIR}/v1_${TARGET}_attr.txt
228         V2ref_ATTR_FILE=${OUTPUT_DIR}/v2_${TARGET}_attr.txt
229 }
230
231 #------------------------------------------------------------------------------
232 # Function :
233 #       fn_mk_delta_fs_core
234 #
235 # Description :
236 #       core routine for delta generation
237 #       File System Update Type (DELTA_FS)
238 #
239
240 fn_mk_delta_fs_core()
241 {
242         START_TIMESTAMP="generation of ${DELTA} [START] $(date +%T)"
243         FS=ext4
244
245         if [ "${DELTA}" = "boot.img/" ]; then
246                 FS=vfat
247         fi
248
249         #---- untar partition image and rename for old & new ----
250         echo "untar ${OLD_TAR_FILE}"
251         tar xvf ${OLD_TAR_DIR}/${OLD_TAR_FILE} ${PART_IMG_ORG}
252         if [ "$?" != "0" ]; then
253                 return 1;
254         fi
255         sudo mv ${PART_IMG_ORG} ${PART_IMG_OLD}
256
257         echo "untar ${NEW_TAR_FILE}"
258         tar xvf ${NEW_TAR_DIR}/${NEW_TAR_FILE} ${PART_IMG_ORG}
259         if [ "$?" != "0" ]; then
260                 return 1;
261         fi
262         sudo mv ${PART_IMG_ORG} ${PART_IMG_NEW}
263
264         #---- check whether the binaries are same ----
265         sudo diff ${PART_IMG_OLD} ${PART_IMG_NEW}
266         if [ "$?" = "0" ]; then
267                 echo "[${PART_NAME}] two binaries are same"
268                 sudo rm -rf ${PART_IMG_OLD}
269                 sudo rm -rf ${PART_IMG_NEW}
270                 sudo rm -rf ${OUTPUT_DIR}
271                 return 0
272         fi
273
274         #---- make mount point ----
275         mkdir -p ${MNT_PNT_OLD}
276         mkdir -p ${MNT_PNT_NEW}
277
278         #---- mount partition image to mount point  ----
279         echo "mount ${PART_IMG_OLD} & ${PART_IMG_NEW}"
280         sudo mount -t ${FS} -o loop ${PART_IMG_OLD} ${MNT_PNT_OLD}
281         if [ "$?" != "0" ]; then
282                 return 1;
283         fi
284         sudo mount -t ${FS} -o loop ${PART_IMG_NEW} ${MNT_PNT_NEW}
285         if [ "$?" != "0" ]; then
286                 return 1;
287         fi
288
289         #---- remove unnecessary files & directories  ----
290         for ff in ${EXCLUDE_FILES}
291         do
292                 sudo rm -rf ${MNT_PNT_OLD}/${ff}
293                 sudo rm -rf ${MNT_PNT_NEW}/${ff}
294         done
295
296         #---- make attribute ----
297         fn_mk_attribute ${PART_NAME} ${BASE_OLD} ${BASE_NEW}
298
299         #PART_IMG_ORG parameter should match with DELTA name that is part of default config file. Which will be used to update MAX size file that is present in respective partition.
300         sudo python ${COMMON_BINDIR}/CreatePatch.py ${UPDATE_TYPE} ${PART_NAME} ${BASE_OLD} ${BASE_NEW} ${OUTPUT_DIR} ${V1_ATTR_FILE} ${V2_ATTR_FILE} ${UPDATE_CFG_PATH}
301         PythonRet=$?
302
303         #---- unmount partition image ----
304         echo "umount ${MNT_PNT_OLD} & ${MNT_PNT_NEW}"
305         sudo umount ${MNT_PNT_OLD}
306         sudo umount ${MNT_PNT_NEW}
307
308         #---- remove files & directories ----
309         echo "remove temp files/directory & move delta/log to result directory"
310         sudo rm -rf ${PART_IMG_OLD}
311         sudo rm -rf ${PART_IMG_NEW}
312         sudo rm -rf ${BASE_OLD} ${BASE_NEW}
313         sudo rm -rf x
314
315         #---- extra cleanup ----
316         sudo mv ./file_attr_updated_image.txt ${OUTPUT_DIR}/${PART_NAME}_file_attr_updated_image.txt
317
318         if [ $PythonRet != "0" ]; then
319                 echo "[${PART_NAME}] Failed to generate DELTA"
320                 exit 1
321         fi
322         END_TIMESTAMP="generation of ${DELTA} [END] $(date +%T)"
323         echo "${START_TIMESTAMP}"
324         echo "${END_TIMESTAMP}"
325
326         return 0
327 }
328
329 #------------------------------------------------------------------------------
330 # Function :
331 #       Mk_delta_fs
332 #
333 # Description :
334 #       generate delta file for filesystem type partition
335 #
336
337 fn_mk_delta_fs()
338 {
339         PART_IMG_ORG=${PART_BIN}
340         PART_IMG_OLD=${PART_IMG_ORG}.old
341         PART_IMG_NEW=${PART_IMG_ORG}.new
342
343         DELTA=${DELTA_BIN}
344         DEBUG_DELTA=debug_${DELTA}
345         #CFG_XML=${PART_NAME}_FS.xml
346
347         FAKE_ROOT=system
348         BASE_OLD=${PART_NAME}_OLD
349         BASE_NEW=${PART_NAME}_NEW
350
351         #--- !!! this should be modified according to partition ---
352         case "${PART_NAME}" in
353         "rootfs" )
354                 EXCLUDE_FILES="lost+found dev proc tmp var sys csa"
355                 TGT_MNT_PNT=${FAKE_ROOT}
356
357                 echo "===== Start writing image versions ====="
358                 local TMP_MNT_PNT="TMP_MNT_PNT"
359                 mkdir -p ${TMP_MNT_PNT}
360
361                 tar xvf ${OLD_TAR_DIR}/${OLD_TAR_FILE} ${PART_IMG_ORG}
362                 sudo mount -t ext4 -o loop ${PART_IMG_ORG} ${TMP_MNT_PNT}
363                 echo `cat ${TMP_MNT_PNT}/etc/info.ini | grep "Release=" | sed "s/Release/old/"` > version.txt
364                 sudo umount ${TMP_MNT_PNT}
365                 rm -rf ${PART_IMG_ORG}
366
367                 tar xvf ${NEW_TAR_DIR}/${NEW_TAR_FILE} ${PART_IMG_ORG}
368                 sudo mount -t ext4 -o loop ${PART_IMG_ORG} ${TMP_MNT_PNT}
369                 echo `cat ${TMP_MNT_PNT}/etc/info.ini | grep "Release=" | sed "s/Release/new/"` >> version.txt
370                 sudo umount ${TMP_MNT_PNT}
371                 rm -rf ${PART_IMG_ORG}
372
373                 rm -rf ${TMP_MNT_PNT}
374                 echo "===== Finish writing image versions ====="
375
376                 ;;
377         "ramdisk1" | "ramdisk" )
378                 EXCLUDE_FILES="lost+found dev proc tmp sys"
379                 TGT_MNT_PNT=${FAKE_ROOT}/mnt/initrd
380                 ;;
381         "ramdisk2" | "ramdisk-recovery" )
382                 EXCLUDE_FILES="lost+found"
383                 TGT_MNT_PNT=${FAKE_ROOT}/mnt/initrd-recovery
384                 ;;
385         "user" )
386                 EXCLUDE_FILES="lost+found"
387                 TGT_MNT_PNT=${FAKE_ROOT}/opt/usr
388                 ;;
389         "system-data" )
390                 EXCLUDE_FILES="lost+found"
391                 TGT_MNT_PNT=${FAKE_ROOT}/opt
392                 ;;
393         "kernel" | "boot" )
394                 EXCLUDE_FILES=""
395                 TGT_MNT_PNT=${FAKE_ROOT}/boot
396                 ;;
397         * )
398                 echo "${PART_NAME} not supported !!!"
399                 return 1
400                 ;;
401         esac
402
403         MNT_PNT_OLD=${BASE_OLD}/${TGT_MNT_PNT}
404         MNT_PNT_NEW=${BASE_NEW}/${TGT_MNT_PNT}
405
406
407         fn_mk_delta_fs_core
408         if [ "$?" != "0" ]; then
409                 return 1
410         fi
411
412         return 0
413 }
414
415 #------------------------------------------------------------------------------
416 # Function :
417 #       fn_mk_flash_img
418 #
419
420 fn_mk_flash_img()
421 {
422         PART_IMG_NEW=${PART_BIN}
423
424         #---- untar partition image and rename for old & new ----
425         echo "untar ${NEW_TAR_FILE}"
426         tar xvf ${NEW_TAR_DIR}/${NEW_TAR_FILE} ${PART_IMG_NEW}
427         if [ "$?" != "0" ]; then
428                 return 1;
429         fi
430
431         sudo mv ${PART_IMG_NEW} ${OUTPUT_DIR}/${PART_BIN}
432         sudo chown ${MY_ID}:${MY_ID} ${OUTPUT_DIR}/${PART_BIN}
433
434         return 0
435 }
436
437
438
439 #------------------------------------------------------------------------------
440 # Function :
441 #       get_tar_file_names
442 #
443 # Description :
444 #       find tar file name (without path) that contains given partition binary
445 #
446
447 fn_get_tar_file_names()
448 {
449         BIN_TO_FIND=$1
450
451         cd ${DATA_DIR}/${OLD_TAR_DIR}
452         OLD_TAR_LIST=`ls *.tar *.tar.gz *.tgz *.tar.md5 2>/dev/null`
453         cd ${CUR_DIR}
454
455         cd ${DATA_DIR}/${NEW_TAR_DIR}
456         NEW_TAR_LIST=`ls *.tar *.tar.gz *.tgz *.tar.md5 2>/dev/null`
457         cd ${CUR_DIR}
458
459         #--- find which tar contains the binary ---
460         for tar_file in ${OLD_TAR_LIST}
461         do
462                 result=`tar -tvf ${DATA_DIR}/${OLD_TAR_DIR}/${tar_file} | grep " ${BIN_TO_FIND}$"`
463                 if [ "$?" = "0" ]; then
464                         OLD_TAR_FILE=${tar_file}
465                         break
466                 fi
467         done
468
469         for tar_file in ${NEW_TAR_LIST}
470         do
471                 result=`tar -tvf ${DATA_DIR}/${NEW_TAR_DIR}/${tar_file} | grep " ${BIN_TO_FIND}$"`
472                 if [ "$?" = "0" ]; then
473                         NEW_TAR_FILE=${tar_file}
474                         break
475                 fi
476         done
477
478 }
479
480 ###############################################################################
481 #==================
482 # Main Start
483 #==================
484
485 fn_print_line - 80
486
487 #--- assign input params to internal variables ---
488 param_num=$#
489 if [ "${param_num}" != "4" ]; then
490         echo "Invalid param num"
491         echo "[Usage] $0 PART_NAME UPDATE_TYPE PART_BIN DELTA_BIN"
492         exit 1
493 fi
494
495 PART_NAME=$1
496 UPDATE_TYPE=$2
497 PART_BIN=$3
498 DELTA_BIN=$4
499
500 #--- set some default variables ---
501 MY_ID=`whoami`
502 CUR_DIR=`pwd`
503 DATA_DIR=./data
504 CFG_DIR=./cfg
505 #XML_DIR=./xml
506 COMMON_BINDIR=${CUR_DIR}/../common/bin
507 UPDATE_CFG_PATH=./cfg/update.cfg
508
509 #--- check if the current working directory is the parent directory of bin, data, cfg, xml ---
510 TEST_DIR=${DATA_DIR}
511 if [ ! -d ${TEST_DIR} ]; then
512         echo "Invalid working directory. ${TEST_DIR} does not exist"
513         exit 1
514 fi
515
516 TEST_DIR=${CFG_DIR}
517 if [ ! -d ${TEST_DIR} ]; then
518         echo "Invalid working directory. ${TEST_DIR} does not exist"
519         exit 1
520 fi
521
522 #TEST_DIR=${XML_DIR}
523 #if [ ! -d ${TEST_DIR} ]; then
524 #       echo "Invalid working directory. ${TEST_DIR} does not exist"
525 #       exit 1
526 #fi
527
528 #--- get old/new tar file which includes $PART_BIN ---
529 if [ "z${OLD_TAR_DIR}" = "z" ]; then
530         OLD_TAR_DIR="old_tar"
531 fi
532 if [ "z${NEW_TAR_DIR}" = "z" ]; then
533         NEW_TAR_DIR="new_tar"
534 fi
535 OLD_TAR_FILE=
536 NEW_TAR_FILE=
537
538 fn_get_tar_file_names ${PART_BIN}
539
540 if [ "z${OLD_TAR_FILE}" = "z" ]; then
541         if [ ! "${UPDATE_TYPE}" = "FULL_IMG" ] && [ ! "${UPDATE_TYPE}" = "PRE_UA" ]; then
542                 echo "[old] tar file does not exist in ${DATA_DIR}/${OLD_TAR_DIR} which contains ${PART_BIN}"
543                 #exit 0, cos this is not an error.
544                 exit 0
545         fi
546 fi
547
548 if [ "z${NEW_TAR_FILE}" = "z" ]; then
549         echo "[new] tar file does not exist in ${DATA_DIR}/${NEW_TAR_DIR} which contains ${PART_BIN}"
550         exit 0
551 fi
552
553 if [ ! "z${OLD_TAR_FILE}" = "z" ]; then
554         echo "[old] ${OLD_TAR_FILE} contains ${PART_BIN}"
555 fi
556 echo "[new] ${NEW_TAR_FILE} contains ${PART_BIN}"
557
558
559 #--- generate delta binary ---
560
561 cd ${DATA_DIR}
562
563 OUTPUT_DIR=${PART_NAME}_OUT
564 if [ ! -d ${OUTPUT_DIR} ]; then
565         if [ -f ${OUTPUT_DIR} ]; then
566                 sudo rm -f ${OUTPUT_DIR}
567         fi
568         mkdir ${OUTPUT_DIR}
569 fi
570
571 if [ "${UPDATE_TYPE}" = "FULL_IMG" ] || [ "${UPDATE_TYPE}" = "PRE_UA" ]; then
572         fn_mk_full_img
573 elif [ "${UPDATE_TYPE}" = "DELTA_IMG" ]; then
574         fn_mk_delta_img
575 elif [ "${UPDATE_TYPE}" = "DELTA_FS" ]; then
576         fn_mk_delta_fs
577 else
578         echo "Invalid update type"
579         exit 1
580 fi
581
582 exit 0