/doc/forum/upgrading_to_propellor_3.0/

tion]Nicolas Schodet
summaryrefslogtreecommitdiff
path: root/cleopatre/busybox-1.11.1-spc300
diff options
context:
space:
mode:
authorYacine Belkadi2012-05-03 11:01:33 +0200
committerYacine Belkadi2012-06-27 11:07:22 +0200
commitb31db02df546187d7b2f27e14eb587b4561dda8d (patch)
treeb5b259dba96a419de4d2d55e51acf270374717fd /cleopatre/busybox-1.11.1-spc300
parent4d7cb28e1ab17aad9145278c05d48eed0623a1da (diff)
cleo: add directory for busybox sources, refs #3085
Create a source directory for busybox, by extracting the content of busybox-1.11.1.tar.bz2.
Diffstat (limited to 'cleopatre/busybox-1.11.1-spc300')
-rw-r--r--cleopatre/busybox-1.11.1-spc300/.indent.pro33
-rw-r--r--cleopatre/busybox-1.11.1-spc300/AUTHORS173
-rw-r--r--cleopatre/busybox-1.11.1-spc300/Config.in582
-rw-r--r--cleopatre/busybox-1.11.1-spc300/INSTALL125
-rw-r--r--cleopatre/busybox-1.11.1-spc300/LICENSE348
-rw-r--r--cleopatre/busybox-1.11.1-spc300/Makefile1309
-rw-r--r--cleopatre/busybox-1.11.1-spc300/Makefile.custom165
-rw-r--r--cleopatre/busybox-1.11.1-spc300/Makefile.flags115
-rw-r--r--cleopatre/busybox-1.11.1-spc300/Makefile.help43
-rw-r--r--cleopatre/busybox-1.11.1-spc300/README201
-rw-r--r--cleopatre/busybox-1.11.1-spc300/TODO298
-rw-r--r--cleopatre/busybox-1.11.1-spc300/TODO_config_nommu843
-rw-r--r--cleopatre/busybox-1.11.1-spc300/applets/Kbuild34
-rw-r--r--cleopatre/busybox-1.11.1-spc300/applets/applet_tables.c126
-rw-r--r--cleopatre/busybox-1.11.1-spc300/applets/applets.c18
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/applets/busybox.mkll24
-rw-r--r--cleopatre/busybox-1.11.1-spc300/applets/individual.c24
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/applets/install.sh110
-rw-r--r--cleopatre/busybox-1.11.1-spc300/applets/usage.c29
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/applets/usage_compressed27
-rw-r--r--cleopatre/busybox-1.11.1-spc300/arch/i386/Makefile7
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/Config.in344
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/Kbuild23
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/ar.c95
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/bbunzip.c362
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/bbunzip_test.sh61
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/bbunzip_test2.sh10
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/bbunzip_test3.sh23
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/bz/LICENSE44
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/bz/README90
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/bz/blocksort.c1072
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/bz/bzlib.c429
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/bz/bzlib.h65
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/bz/bzlib_private.h219
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/bz/compress.c687
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/bz/huffman.c229
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/bzip2.c184
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/cpio.c350
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/dpkg.c1778
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/dpkg_deb.c97
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/gzip.c2100
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/Kbuild67
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/archive_xread_all_eof.c20
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/data_align.c15
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/data_extract_all.c146
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/data_extract_to_buffer.c17
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/data_extract_to_stdout.c14
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/data_skip.c12
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/decompress_bunzip2.c705
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/decompress_uncompress.c305
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/decompress_unlzma.c500
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/decompress_unzip.c1241
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/filter_accept_all.c17
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/filter_accept_list.c19
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/filter_accept_list_reassign.c44
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/filter_accept_reject_list.c36
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/find_list_entry.c54
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_ar.c126
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_cpio.c169
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_tar.c368
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_tar_bz2.c21
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_tar_gz.c35
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_tar_lzma.c24
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/header_list.c11
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/header_skip.c10
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/header_verbose_list.c58
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/init_handle.c22
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/open_transformer.c64
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/seek_by_jump.c17
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/seek_by_read.c16
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/libunarchive/unpack_ar_archive.c20
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/rpm.c398
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/rpm2cpio.c89
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/tar.c980
-rw-r--r--cleopatre/busybox-1.11.1-spc300/archival/unzip.c408
-rw-r--r--cleopatre/busybox-1.11.1-spc300/console-tools/Config.in111
-rw-r--r--cleopatre/busybox-1.11.1-spc300/console-tools/Kbuild20
-rw-r--r--cleopatre/busybox-1.11.1-spc300/console-tools/chvt.c25
-rw-r--r--cleopatre/busybox-1.11.1-spc300/console-tools/clear.c19
-rw-r--r--cleopatre/busybox-1.11.1-spc300/console-tools/deallocvt.c33
-rw-r--r--cleopatre/busybox-1.11.1-spc300/console-tools/dumpkmap.c69
-rw-r--r--cleopatre/busybox-1.11.1-spc300/console-tools/kbd_mode.c55
-rw-r--r--cleopatre/busybox-1.11.1-spc300/console-tools/loadfont.c181
-rw-r--r--cleopatre/busybox-1.11.1-spc300/console-tools/loadkmap.c63
-rw-r--r--cleopatre/busybox-1.11.1-spc300/console-tools/openvt.c181
-rw-r--r--cleopatre/busybox-1.11.1-spc300/console-tools/reset.c47
-rw-r--r--cleopatre/busybox-1.11.1-spc300/console-tools/resize.c71
-rw-r--r--cleopatre/busybox-1.11.1-spc300/console-tools/setconsole.c39
-rw-r--r--cleopatre/busybox-1.11.1-spc300/console-tools/setkeycodes.c49
-rw-r--r--cleopatre/busybox-1.11.1-spc300/console-tools/setlogcons.c30
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/Config.in811
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/Kbuild92
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/basename.c52
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/cal.c347
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/cat.c48
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/catv.c75
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/chgrp.c31
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/chmod.c160
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/chown.c170
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/chroot.c37
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/cksum.c56
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/comm.c113
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/cp.c107
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/cut.c279
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/date.c239
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/dd.c356
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/df.c175
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/dirname.c27
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/dos2unix.c98
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/du.c240
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/echo.c300
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/env.c123
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/expand.c200
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/expr.c504
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/false.c21
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/fold.c151
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/head.c140
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/hostid.c26
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/id.c126
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/install.c222
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/length.c19
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/libcoreutils/Kbuild12
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/libcoreutils/coreutils.h24
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/libcoreutils/cp_mv_stat.c50
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/libcoreutils/getopt_mk_fifo_nod.c48
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/ln.c109
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/logname.c43
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/ls.c979
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/md5_sha1_sum.c175
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/mkdir.c80
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/mkfifo.c37
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/mknod.c57
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/mv.c135
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/nice.c55
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/nohup.c78
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/od.c224
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/od_bloaty.c1428
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/printenv.c33
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/printf.c320
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/pwd.c27
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/readlink.c49
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/realpath.c46
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/rm.c55
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/rmdir.c70
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/seq.c40
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/sleep.c63
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/sort.c407
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/split.c139
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/stat.c654
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/stty.c1439
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/sum.c99
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/sync.c25
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/tac.c106
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/tail.c284
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/tee.c102
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/test.c637
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/test_ptr_hack.c23
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/touch.c58
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/tr.c246
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/true.c21
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/tty.c44
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/uname.c99
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/uniq.c102
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/usleep.c28
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/uudecode.c224
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/uuencode.c61
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/wc.c205
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/who.c80
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/whoami.c26
-rw-r--r--cleopatre/busybox-1.11.1-spc300/coreutils/yes.c42
-rw-r--r--cleopatre/busybox-1.11.1-spc300/debianutils/Config.in83
-rw-r--r--cleopatre/busybox-1.11.1-spc300/debianutils/Kbuild12
-rw-r--r--cleopatre/busybox-1.11.1-spc300/debianutils/mktemp.c69
-rw-r--r--cleopatre/busybox-1.11.1-spc300/debianutils/pipe_progress.c39
-rw-r--r--cleopatre/busybox-1.11.1-spc300/debianutils/run_parts.c173
-rw-r--r--cleopatre/busybox-1.11.1-spc300/debianutils/start_stop_daemon.c447
-rw-r--r--cleopatre/busybox-1.11.1-spc300/debianutils/which.c90
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/docs/autodocifier.pl303
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/FAQ.html1143
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/about.html24
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/busybox-growth.ps404
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/copyright.txt30
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/developer.html69
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/download.html60
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/fix.html15
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/footer.html47
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/header.html102
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/back.pngbin0 -> 322 bytes
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/busybox.jpegbin0 -> 9023 bytes
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/busybox.pngbin0 -> 34014 bytes
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/busybox1.pngbin0 -> 10913 bytes
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/busybox2.jpgbin0 -> 8204 bytes
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/busybox3.jpgbin0 -> 3292 bytes
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/dir.pngbin0 -> 309 bytes
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/donate.pngbin0 -> 807 bytes
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/fm.mini.pngbin0 -> 7708 bytes
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/gfx_by_gimp.pngbin0 -> 3955 bytes
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/ltbutton2.pngbin0 -> 6798 bytes
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/osuosl.pngbin0 -> 8683 bytes
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/sdsmall.pngbin0 -> 1593 bytes
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/text.pngbin0 -> 307 bytes
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/valid-html401.pngbin0 -> 1950 bytes
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/vh40.gifbin0 -> 906 bytes
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/written.in.vi.pngbin0 -> 4394 bytes
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/index.html1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/license.html97
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/links.html19
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/lists.html46
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/news.html248
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/oldnews.html1939
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/products.html170
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/screenshot.html75
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/shame.html82
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/sponsors.html52
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/subversion.html51
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox.net/tinyutils.html86
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox_footer.pod256
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/busybox_header.pod82
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/cgi/cl.html46
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/cgi/env.html149
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/cgi/in.html33
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/cgi/interface.html29
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/cgi/out.html126
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/contributing.txt449
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/ctty.htm476
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/draft-coar-cgi-v11-03-clean.html2674
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/ifupdown_design.txt44
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/keep_data_small.txt216
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/mdev.txt97
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/new-applet-HOWTO.txt182
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/nofork_noexec.txt79
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/sigint.htm627
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/style-guide.txt714
-rw-r--r--cleopatre/busybox-1.11.1-spc300/docs/tar_pax.txt239
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/Config.in68
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/Kbuild12
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/README12
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/chattr.c172
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/e2fs_defs.h561
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/e2fs_lib.c227
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/e2fs_lib.h51
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/fsck.c1187
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/lsattr.c109
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/Config.in67
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/Kbuild16
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/README3
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/Kbuild23
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/blkid.h105
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/blkidP.h187
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/blkid_getsize.c179
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/cache.c125
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/dev.c213
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/devname.c367
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/devno.c222
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/list.c110
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/list.h73
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/probe.c721
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/probe.h375
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/read.c461
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/resolve.c139
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/save.c189
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/tag.c431
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/chattr.c220
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2fsbb.h43
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2fsck.c13548
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2fsck.h640
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/Kbuild15
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/e2p.h64
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/feature.c187
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/fgetsetflags.c70
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/fgetsetversion.c70
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/hashstr.c70
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/iod.c52
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/ls.c273
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/mntopts.c134
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/ostype.c74
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/parse_num.c65
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/pe.c32
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/pf.c74
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/ps.c27
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/uuid.c78
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/Kbuild23
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/alloc.c174
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/alloc_sb.c58
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/alloc_stats.c53
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/alloc_tables.c118
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/badblocks.c328
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bb_compat.c64
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bb_inode.c268
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bitmaps.c211
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bitops.c91
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bitops.h107
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/block.c438
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bmap.c264
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bmove.c156
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/brel.h87
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/brel_ma.c196
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/check_desc.c69
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/closefs.c381
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/cmp_bitmaps.c73
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dblist.c260
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dblist_dir.c76
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dir_iterate.c220
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dirblock.c133
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dirhash.c234
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dupfs.c97
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/e2image.h52
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/expanddir.c127
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2_err.h116
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2_ext_attr.h53
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2_fs.h570
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2_io.h114
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2_types.h2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs.h923
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2fsP.h89
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c367
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext_attr.c101
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/fileio.c377
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/finddev.c199
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/flushb.c83
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/freefs.c128
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/gen_bitmap.c49
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/get_pathname.c157
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/getsectsize.c58
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/getsize.c291
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/icount.c467
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/imager.c377
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ind_block.c71
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/initialize.c388
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/inline.c33
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/inode.c767
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/inode_io.c271
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/io_manager.c70
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/irel.h115
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/irel_ma.c367
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ismounted.c357
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/jfs_dat.h65
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/kernel-jbd.h236
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/kernel-list.h113
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/link.c135
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/lookup.c70
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/mkdir.c142
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/mkjournal.c428
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/namei.c205
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/newdir.c73
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/openfs.c330
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/read_bb.c98
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/read_bb_file.c98
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/res_gdt.c221
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/rs_bitmap.c107
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/rw_bitmaps.c296
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/sparse.c79
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/swapfs.c236
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/test_io.c380
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/unix_io.c703
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/unlink.c100
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/valid_blk.c57
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/version.c51
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/write_bb_file.c35
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/fsck.c1391
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/fsck.h16
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/lsattr.c129
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/mke2fs.c1336
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/tune2fs.c713
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/util.c267
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/util.h22
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/Kbuild14
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/compare.c55
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/gen_uuid.c304
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/pack.c69
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/parse.c80
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/unpack.c63
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/unparse.c77
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/uuid.h104
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/uuidP.h60
-rw-r--r--cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/uuid_time.c161
-rw-r--r--cleopatre/busybox-1.11.1-spc300/editors/Config.in196
-rw-r--r--cleopatre/busybox-1.11.1-spc300/editors/Kbuild14
-rw-r--r--cleopatre/busybox-1.11.1-spc300/editors/awk.c2889
-rw-r--r--cleopatre/busybox-1.11.1-spc300/editors/cmp.c135
-rw-r--r--cleopatre/busybox-1.11.1-spc300/editors/diff.c1344
-rw-r--r--cleopatre/busybox-1.11.1-spc300/editors/ed.c1049
-rw-r--r--cleopatre/busybox-1.11.1-spc300/editors/patch.c254
-rw-r--r--cleopatre/busybox-1.11.1-spc300/editors/sed.c1350
-rw-r--r--cleopatre/busybox-1.11.1-spc300/editors/sed1line.txt425
-rw-r--r--cleopatre/busybox-1.11.1-spc300/editors/sed_summary.htm223
-rw-r--r--cleopatre/busybox-1.11.1-spc300/editors/vi.c4073
-rw-r--r--cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/bootfloppy.txt180
-rw-r--r--cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/display.txt4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/etc/fstab2
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/examples/bootfloppy/etc/init.d/rcS3
-rw-r--r--cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/etc/inittab5
-rw-r--r--cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/etc/profile8
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/examples/bootfloppy/mkdevs.sh62
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/examples/bootfloppy/mkrootfs.sh105
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/examples/bootfloppy/mksyslinux.sh48
-rw-r--r--cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/quickstart.txt15
-rw-r--r--cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/syslinux.cfg7
-rw-r--r--cleopatre/busybox-1.11.1-spc300/examples/busybox.spec44
-rw-r--r--cleopatre/busybox-1.11.1-spc300/examples/depmod57
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/examples/depmod.pl292
-rw-r--r--cleopatre/busybox-1.11.1-spc300/examples/devfsd.conf133
-rw-r--r--cleopatre/busybox-1.11.1-spc300/examples/dnsd.conf1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/examples/inetd.conf73
-rw-r--r--cleopatre/busybox-1.11.1-spc300/examples/inittab90
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/examples/mk2knr.pl84
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/examples/udhcp/sample.bound31
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/examples/udhcp/sample.deconfig4
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/examples/udhcp/sample.nak4
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/examples/udhcp/sample.renew31
-rw-r--r--cleopatre/busybox-1.11.1-spc300/examples/udhcp/sample.script7
-rw-r--r--cleopatre/busybox-1.11.1-spc300/examples/udhcp/simple.script40
-rw-r--r--cleopatre/busybox-1.11.1-spc300/examples/udhcp/udhcpd.conf123
-rw-r--r--cleopatre/busybox-1.11.1-spc300/examples/undeb53
-rw-r--r--cleopatre/busybox-1.11.1-spc300/examples/unrpm48
-rw-r--r--cleopatre/busybox-1.11.1-spc300/examples/zcip.script38
-rw-r--r--cleopatre/busybox-1.11.1-spc300/findutils/Config.in247
-rw-r--r--cleopatre/busybox-1.11.1-spc300/findutils/Kbuild10
-rw-r--r--cleopatre/busybox-1.11.1-spc300/findutils/find.c908
-rw-r--r--cleopatre/busybox-1.11.1-spc300/findutils/grep.c549
-rw-r--r--cleopatre/busybox-1.11.1-spc300/findutils/xargs.c527
-rw-r--r--cleopatre/busybox-1.11.1-spc300/include/applets.h404
-rw-r--r--cleopatre/busybox-1.11.1-spc300/include/busybox.h78
-rw-r--r--cleopatre/busybox-1.11.1-spc300/include/dump.h59
-rw-r--r--cleopatre/busybox-1.11.1-spc300/include/grp_.h128
-rw-r--r--cleopatre/busybox-1.11.1-spc300/include/inet_common.h26
-rw-r--r--cleopatre/busybox-1.11.1-spc300/include/libbb.h1400
-rw-r--r--cleopatre/busybox-1.11.1-spc300/include/platform.h349
-rw-r--r--cleopatre/busybox-1.11.1-spc300/include/pwd_.h123
-rw-r--r--cleopatre/busybox-1.11.1-spc300/include/rtc_.h79
-rw-r--r--cleopatre/busybox-1.11.1-spc300/include/shadow_.h115
-rw-r--r--cleopatre/busybox-1.11.1-spc300/include/unarchive.h137
-rw-r--r--cleopatre/busybox-1.11.1-spc300/include/usage.h4591
-rw-r--r--cleopatre/busybox-1.11.1-spc300/include/volume_id.h22
-rw-r--r--cleopatre/busybox-1.11.1-spc300/include/xatonum.h176
-rw-r--r--cleopatre/busybox-1.11.1-spc300/include/xregex.h27
-rw-r--r--cleopatre/busybox-1.11.1-spc300/init/Config.in112
-rw-r--r--cleopatre/busybox-1.11.1-spc300/init/Kbuild10
-rw-r--r--cleopatre/busybox-1.11.1-spc300/init/halt.c90
-rw-r--r--cleopatre/busybox-1.11.1-spc300/init/init.c994
-rw-r--r--cleopatre/busybox-1.11.1-spc300/init/mesg.c46
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/Config.in154
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/Kbuild145
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/README11
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/appletlib.c773
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/ask_confirmation.c34
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/bb_askpass.c77
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/bb_basename.c18
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/bb_do_delay.c22
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/bb_pwd.c99
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/bb_qsort.c20
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/bb_strtonum.c156
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/change_identity.c41
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/chomp.c19
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/compare_string_array.c78
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/concat_path_file.c29
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/concat_subpath_file.c23
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/copy_file.c399
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/copyfd.c119
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/correct_password.c80
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/crc32.c40
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/create_icmp6_socket.c36
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/create_icmp_socket.c34
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/crypt_make_salt.c45
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/default_error_retval.c18
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/device_open.c32
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/die_if_bad_username.c36
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/dump.c811
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/error_msg.c19
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/error_msg_and_die.c20
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/execable.c78
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/fclose_nonstdin.c25
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/fflush_stdout_and_exit.c29
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/fgets_str.c66
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/find_mount_point.c53
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/find_pid_by_name.c92
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/find_root_device.c74
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/full_write.c42
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/get_console.c82
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/get_last_path_component.c42
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/get_line_from_file.c69
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/getopt32.c605
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/getpty.c60
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/herror_msg.c19
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/herror_msg_and_die.c20
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/human_readable.c88
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/inet_common.c224
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/info_msg.c30
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/inode_hash.c87
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/isdirectory.c36
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/kernel_version.c37
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/last_char_is.c24
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/lineedit.c1906
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/lineedit_ptr_hack.c23
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/llist.c108
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/login.c130
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/loop.c154
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/make_directory.c103
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/makedev.c23
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/match_fstype.c44
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/md5.c446
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/messages.c73
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/mode_string.c128
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/mtab.c52
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/mtab_file.c15
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/obscure.c170
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/parse_mode.c150
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/perror_msg.c25
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/perror_msg_and_die.c26
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/perror_nomsg.c21
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/perror_nomsg_and_die.c21
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/pidfile.c40
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/print_flags.c32
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/printable.c34
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/process_escape_sequence.c86
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/procps.c458
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/ptr_to_globals.c35
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/pw_encrypt.c84
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/pw_encrypt_des.c798
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/pw_encrypt_md5.c648
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/read.c293
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/recursive_action.c127
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/remove_file.c102
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/restricted_shell.c46
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/rtc.c88
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/run_shell.c92
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/safe_gethostname.c53
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/safe_poll.c34
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/safe_strncpy.c18
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/safe_write.c21
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/selinux_common.c54
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/setup_environment.c70
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/sha1.c170
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/signals.c113
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/simplify_path.c53
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/skip_whitespace.c25
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/speed_table.c117
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/str_tolower.c13
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/strrstr.c71
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/time.c49
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/trim.c31
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/u_signal_names.c180
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/udp_io.c168
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/update_passwd.c153
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/uuencode.c71
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/vdprintf.c21
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/verror_msg.c127
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/vfork_daemon_rexec.c292
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/warn_ignoring_args.c17
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/wfopen.c20
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/wfopen_input.c48
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/write.c20
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/xatonum.c70
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/xatonum_template.c187
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/xconnect.c386
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/xfunc_die.c40
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/xfuncs.c291
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/xfuncs_printf.c521
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/xgetcwd.c41
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/xgethostbyname.c19
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/xreadlink.c111
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libbb/xregcomp.c32
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libpwdgrp/Kbuild9
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libpwdgrp/pwd_grp.c1059
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libpwdgrp/pwd_grp_internal.c62
-rw-r--r--cleopatre/busybox-1.11.1-spc300/libpwdgrp/uidgid_get.c133
-rw-r--r--cleopatre/busybox-1.11.1-spc300/loginutils/Config.in283
-rw-r--r--cleopatre/busybox-1.11.1-spc300/loginutils/Kbuild19
-rw-r--r--cleopatre/busybox-1.11.1-spc300/loginutils/addgroup.c183
-rw-r--r--cleopatre/busybox-1.11.1-spc300/loginutils/adduser.c178
-rw-r--r--cleopatre/busybox-1.11.1-spc300/loginutils/chpasswd.c72
-rw-r--r--cleopatre/busybox-1.11.1-spc300/loginutils/cryptpw.c58
-rw-r--r--cleopatre/busybox-1.11.1-spc300/loginutils/deluser.c125
-rw-r--r--cleopatre/busybox-1.11.1-spc300/loginutils/getty.c778
-rw-r--r--cleopatre/busybox-1.11.1-spc300/loginutils/login.c502
-rw-r--r--cleopatre/busybox-1.11.1-spc300/loginutils/passwd.c206
-rw-r--r--cleopatre/busybox-1.11.1-spc300/loginutils/su.c102
-rw-r--r--cleopatre/busybox-1.11.1-spc300/loginutils/sulogin.c116
-rw-r--r--cleopatre/busybox-1.11.1-spc300/loginutils/vlock.c106
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/Config.in520
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/Kbuild37
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/adjtimex.c145
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/bbconfig.c12
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/chat.c444
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/chrt.c123
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/crond.c944
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/crontab.c234
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/dc.c224
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/devfsd.c1801
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/eject.c116
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/fbsplash.c437
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/fbsplash.cfg9
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/hdparm.c2063
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/inotifyd.c152
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/last.c133
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/last_fancy.c297
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/less.c1412
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/makedevs.c231
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/man.c163
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/microcom.c179
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/mountpoint.c66
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/mt.c140
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/raidautorun.c25
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/readahead.c40
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/runlevel.c43
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/rx.c254
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/setsid.c35
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/strings.c84
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/taskset.c115
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/time.c428
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/ttysize.c44
-rw-r--r--cleopatre/busybox-1.11.1-spc300/miscutils/watchdog.c71
-rw-r--r--cleopatre/busybox-1.11.1-spc300/modutils/Config.in218
-rw-r--r--cleopatre/busybox-1.11.1-spc300/modutils/Kbuild12
-rw-r--r--cleopatre/busybox-1.11.1-spc300/modutils/depmod.c288
-rw-r--r--cleopatre/busybox-1.11.1-spc300/modutils/insmod.c4274
-rw-r--r--cleopatre/busybox-1.11.1-spc300/modutils/lsmod.c194
-rw-r--r--cleopatre/busybox-1.11.1-spc300/modutils/modprobe.c915
-rw-r--r--cleopatre/busybox-1.11.1-spc300/modutils/rmmod.c100
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/Config.in911
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/Kbuild45
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/arp.c497
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/arping.c402
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/brctl.c272
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/dnsd.c409
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/ether-wake.c276
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/ftpgetput.c325
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/hostname.c102
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/httpd.c2411
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/httpd_indexcgi.c342
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/httpd_post_upload.txt76
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/ifconfig.c540
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/ifenslave.c592
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/ifupdown.c1277
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/inetd.c1629
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/interface.c1282
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/ip.c123
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/ipcalc.c190
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/isrv.c338
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/isrv.h41
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/isrv_identd.c147
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/libiproute/Kbuild64
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/libiproute/ip_common.h41
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/libiproute/ip_parse_common_args.c84
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/libiproute/ipaddress.c784
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/libiproute/iplink.c303
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/libiproute/iproute.c897
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/libiproute/iprule.c334
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/libiproute/iptunnel.c539
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/libiproute/libnetlink.c409
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/libiproute/libnetlink.h55
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/libiproute/ll_addr.c79
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/libiproute/ll_map.c200
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/libiproute/ll_map.h21
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/libiproute/ll_proto.c126
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/libiproute/ll_types.c205
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/libiproute/rt_names.c365
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/libiproute/rt_names.h36
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/libiproute/rtm_map.c118
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/libiproute/rtm_map.h18
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/libiproute/utils.c322
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/libiproute/utils.h94
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/nameif.c254
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/nc.c203
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/nc_bloaty.c832
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/netstat.c573
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/nslookup.c154
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/ping.c807
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/pscan.c154
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/route.c699
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/sendmail.c611
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/slattach.c243
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/tcpudp.c609
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/tcpudp_perhost.c65
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/tcpudp_perhost.h37
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/telnet.c658
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/telnetd.c596
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/tftp.c745
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/traceroute.c1349
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/Config.in122
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/Kbuild25
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/arpping.c116
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/clientpacket.c244
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/clientsocket.c108
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/common.c11
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/common.h110
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/dhcpc.c628
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/dhcpc.h56
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/dhcpd.c272
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/dhcpd.h125
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/dhcprelay.c314
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/domain_codec.c205
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/dumpleases.c66
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/files.c435
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/leases.c149
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/options.c234
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/options.h123
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/packet.c237
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/script.c239
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/serverpacket.c264
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/signalpipe.c82
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/socket.c112
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/udhcp/static_leases.c99
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/vconfig.c161
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/wget.c828
-rw-r--r--cleopatre/busybox-1.11.1-spc300/networking/zcip.c549
-rw-r--r--cleopatre/busybox-1.11.1-spc300/printutils/Config.in21
-rw-r--r--cleopatre/busybox-1.11.1-spc300/printutils/Kbuild9
-rw-r--r--cleopatre/busybox-1.11.1-spc300/printutils/lpd.c276
-rw-r--r--cleopatre/busybox-1.11.1-spc300/printutils/lpr.c247
-rw-r--r--cleopatre/busybox-1.11.1-spc300/procps/Config.in183
-rw-r--r--cleopatre/busybox-1.11.1-spc300/procps/Kbuild21
-rw-r--r--cleopatre/busybox-1.11.1-spc300/procps/free.c68
-rw-r--r--cleopatre/busybox-1.11.1-spc300/procps/fuser.c345
-rw-r--r--cleopatre/busybox-1.11.1-spc300/procps/kill.c180
-rw-r--r--cleopatre/busybox-1.11.1-spc300/procps/nmeter.c897
-rw-r--r--cleopatre/busybox-1.11.1-spc300/procps/pgrep.c137
-rw-r--r--cleopatre/busybox-1.11.1-spc300/procps/pidof.c88
-rw-r--r--cleopatre/busybox-1.11.1-spc300/procps/ps.c571
-rw-r--r--cleopatre/busybox-1.11.1-spc300/procps/ps.posix175
-rw-r--r--cleopatre/busybox-1.11.1-spc300/procps/renice.c128
-rw-r--r--cleopatre/busybox-1.11.1-spc300/procps/sysctl.c294
-rw-r--r--cleopatre/busybox-1.11.1-spc300/procps/top.c945
-rw-r--r--cleopatre/busybox-1.11.1-spc300/procps/uptime.c60
-rw-r--r--cleopatre/busybox-1.11.1-spc300/procps/watch.c75
-rw-r--r--cleopatre/busybox-1.11.1-spc300/runit/Config.in66
-rw-r--r--cleopatre/busybox-1.11.1-spc300/runit/Kbuild17
-rw-r--r--cleopatre/busybox-1.11.1-spc300/runit/chpst.c407
-rw-r--r--cleopatre/busybox-1.11.1-spc300/runit/runit_lib.c273
-rw-r--r--cleopatre/busybox-1.11.1-spc300/runit/runit_lib.h105
-rw-r--r--cleopatre/busybox-1.11.1-spc300/runit/runsv.c654
-rw-r--r--cleopatre/busybox-1.11.1-spc300/runit/runsvdir.c361
-rw-r--r--cleopatre/busybox-1.11.1-spc300/runit/sv.c598
-rw-r--r--cleopatre/busybox-1.11.1-spc300/runit/svlogd.c1054
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/Kbuild7
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/Kbuild.include154
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/Makefile.IMA207
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/Makefile.build338
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/Makefile.clean102
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/Makefile.host156
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/Makefile.lib168
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/basic/Makefile18
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/basic/docproc.c398
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/basic/fixdep.c404
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/basic/split-include.c226
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/scripts/bb_release34
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/scripts/bloat-o-meter80
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/scripts/checkhelp.awk40
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/scripts/checkstack.pl141
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/scripts/cleanup_printf2puts9
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/defconfig855
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/echo.c230
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/scripts/find_bad_common_bufsiz13
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/scripts/find_stray_common_vars10
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/scripts/gcc-version.sh12
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/scripts/individual129
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/Makefile248
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/POTFILES.in5
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/scripts/kconfig/check.sh14
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/conf.c612
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/confdata.c571
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/expr.c1099
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/expr.h194
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/gconf.c1644
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/gconf.glade648
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/images.c326
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/kconfig_load.c35
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/kxgettext.c227
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/lex.zconf.c_shipped2317
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/lkc.h147
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/lkc_proto.h41
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/lxdialog/BIG.FAT.WARNING4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/lxdialog/Makefile21
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/lxdialog/check-lxdialog.sh86
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/lxdialog/checklist.c333
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/lxdialog/colors.h154
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/lxdialog/dialog.h177
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/lxdialog/inputbox.c224
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/lxdialog/lxdialog.c204
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/lxdialog/menubox.c426
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/lxdialog/msgbox.c71
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/lxdialog/textbox.c533
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/lxdialog/util.c362
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/lxdialog/yesno.c102
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/mconf.c1098
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/menu.c397
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/qconf.cc1425
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/qconf.h263
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/symbol.c882
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/util.c109
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/zconf.gperf43
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/zconf.hash.c_shipped231
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/zconf.l350
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/zconf.tab.c_shipped2173
-rw-r--r--cleopatre/busybox-1.11.1-spc300/scripts/kconfig/zconf.y681
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/scripts/memusage16
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/scripts/mkconfigs52
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/scripts/mkmakefile36
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/scripts/objsizes19
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/scripts/sample_pmap11
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/scripts/showasm21
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/scripts/trylink306
-rw-r--r--cleopatre/busybox-1.11.1-spc300/selinux/Config.in123
-rw-r--r--cleopatre/busybox-1.11.1-spc300/selinux/Kbuild20
-rw-r--r--cleopatre/busybox-1.11.1-spc300/selinux/chcon.c177
-rw-r--r--cleopatre/busybox-1.11.1-spc300/selinux/getenforce.c34
-rw-r--r--cleopatre/busybox-1.11.1-spc300/selinux/getsebool.c66
-rw-r--r--cleopatre/busybox-1.11.1-spc300/selinux/load_policy.c22
-rw-r--r--cleopatre/busybox-1.11.1-spc300/selinux/matchpathcon.c86
-rw-r--r--cleopatre/busybox-1.11.1-spc300/selinux/runcon.c136
-rw-r--r--cleopatre/busybox-1.11.1-spc300/selinux/selinuxenabled.c14
-rw-r--r--cleopatre/busybox-1.11.1-spc300/selinux/sestatus.c219
-rw-r--r--cleopatre/busybox-1.11.1-spc300/selinux/setenforce.c42
-rw-r--r--cleopatre/busybox-1.11.1-spc300/selinux/setfiles.c645
-rw-r--r--cleopatre/busybox-1.11.1-spc300/selinux/setsebool.c34
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/Config.in334
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/Kbuild11
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/README108
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/README.job304
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash.c13538
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_doc.txt31
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_ptr_hack.c29
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-alias/alias.right4
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-alias/alias.tests37
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-arith/README.ash1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-arith/arith-bash1.right2
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-arith/arith-bash1.tests5
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-arith/arith-for.right74
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-arith/arith-for.testsx94
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-arith/arith.right138
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-arith/arith.tests302
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-arith/arith1.sub40
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-arith/arith2.sub57
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-heredoc/heredoc.right21
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-heredoc/heredoc.tests94
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-invert/invert.right10
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-invert/invert.tests19
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-quoting/dollar_squote_bash1.right9
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-quoting/dollar_squote_bash1.tests7
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-read/read_n.right3
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-read/read_n.tests3
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-read/read_r.right2
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-read/read_r.tests2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-read/read_t.right4
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-read/read_t.tests10
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-redir/redir.right1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-redir/redir.tests6
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-signals/signal1.right20
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-signals/signal1.tests24
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-vars/var1.right6
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-vars/var1.tests14
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-vars/var2.right1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-vars/var2.tests1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-vars/var_bash1.right14
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-vars/var_bash1.tests18
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-vars/var_bash2.right10
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-vars/var_bash2.tests24
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-vars/var_bash3.right20
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-vars/var_bash3.tests41
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-vars/var_leak.right2
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-vars/var_leak.tests9
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-vars/var_posix1.right17
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/ash_test/ash-vars/var_posix1.tests21
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_test/printenv.c67
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_test/recho.c63
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/ash_test/run-all74
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/ash_test/zecho.c39
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/bbsh.c223
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/cttyhack.c77
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush.c4316
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_doc.txt39
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_leaktool.sh13
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-glob/glob1.right2
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-glob/glob1.tests2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-glob/glob_and_assign.right6
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-glob/glob_and_assign.tests10
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-glob/glob_redir.right2
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-glob/glob_redir.tests9
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-misc/colon.right2
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-misc/colon.tests5
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-misc/empty_for.right1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-misc/empty_for.tests3
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-misc/pid.right1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-misc/pid.tests1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-misc/read.right4
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-misc/read.tests4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-misc/shift.right6
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-misc/shift.tests14
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-misc/syntax_err.right2
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-misc/syntax_err.tests3
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-misc/syntax_err_negate.right2
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-misc/syntax_err_negate.tests2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-misc/while_in_subshell.right1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-misc/while_in_subshell.tests2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/argv0.right1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/argv0.tests4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/escape1.right4
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/escape1.tests4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/escape2.right4
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/escape2.tests4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/escape3.right23
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/escape3.tests8
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/negate.right35
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/negate.tests16
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/noeol.right1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/noeol.tests2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/noeol2.right1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/noeol2.tests7
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/noeol3.right1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/noeol3.tests2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/process_subst.right3
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/process_subst.tests3
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/quote1.right1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/quote1.tests2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/quote2.right1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/quote2.tests2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/quote3.right12
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/quote3.tests21
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/quote4.right1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/quote4.tests2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/redir_space.right3
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/redir_space.tests6
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/starquoted.right8
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-parsing/starquoted.tests8
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-psubst/tick.right2
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-psubst/tick.tests4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-psubst/tick2.right1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-psubst/tick2.tests5
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-psubst/tick3.right6
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-psubst/tick3.tests10
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-psubst/tick4.right7
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-psubst/tick4.tests7
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-vars/empty.right3
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-vars/empty.tests5
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-vars/glob_and_vars.right1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-vars/glob_and_vars.tests2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-vars/param_glob.right4
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-vars/param_glob.tests10
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-vars/star.right6
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-vars/star.tests8
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-vars/var.right4
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-vars/var.tests9
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-vars/var_expand_in_assign.right5
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-vars/var_expand_in_assign.tests15
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-vars/var_expand_in_redir.right3
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-vars/var_expand_in_redir.tests13
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-vars/var_subst_in_for.right40
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-vars/var_subst_in_for.tests40
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-z_slow/leak_var.right2
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/hush-z_slow/leak_var.tests91
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/hush_test/run-all73
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/lash_unused.c1570
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh.c5328
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh_function.patch350
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-bugs/noeol3.right1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-bugs/noeol3.tests2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-bugs/process_subst.right3
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-bugs/process_subst.tests3
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-bugs/read.right4
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-bugs/read.tests4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-bugs/shift.right6
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-bugs/shift.tests14
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-bugs/starquoted.right8
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-bugs/starquoted.tests8
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-bugs/syntax_err.right2
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-bugs/syntax_err.tests3
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-bugs/var_expand_in_assign.right5
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-bugs/var_expand_in_assign.tests15
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-bugs/var_expand_in_redir.right3
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-bugs/var_expand_in_redir.tests13
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-execution/exitcode_EACCES.right2
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-execution/exitcode_EACCES.tests2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-execution/exitcode_ENOENT.right2
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-execution/exitcode_ENOENT.tests2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-execution/nested_break.right8
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-execution/nested_break.tests17
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-misc/tick.right2
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-misc/tick.tests4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-parsing/argv0.right1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-parsing/argv0.tests4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-parsing/noeol.right1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-parsing/noeol.tests2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-parsing/noeol2.right1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-parsing/noeol2.tests7
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-parsing/quote1.right1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-parsing/quote1.tests2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-parsing/quote2.right1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-parsing/quote2.tests2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-parsing/quote3.right3
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-parsing/quote3.tests8
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-parsing/quote4.right1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-parsing/quote4.tests2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-vars/star.right6
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-vars/star.tests8
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-vars/var.right4
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-vars/var.tests9
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-vars/var_subst_in_for.right40
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/msh_test/msh-vars/var_subst_in_for.tests40
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/shell/msh_test/run-all64
-rw-r--r--cleopatre/busybox-1.11.1-spc300/shell/susv3_doc.tar.bz2bin0 -> 71444 bytes
-rw-r--r--cleopatre/busybox-1.11.1-spc300/sysklogd/Config.in118
-rw-r--r--cleopatre/busybox-1.11.1-spc300/sysklogd/Kbuild11
-rw-r--r--cleopatre/busybox-1.11.1-spc300/sysklogd/klogd.c122
-rw-r--r--cleopatre/busybox-1.11.1-spc300/sysklogd/logger.c157
-rw-r--r--cleopatre/busybox-1.11.1-spc300/sysklogd/logread.c185
-rw-r--r--cleopatre/busybox-1.11.1-spc300/sysklogd/syslogd.c696
-rw-r--r--cleopatre/busybox-1.11.1-spc300/sysklogd/syslogd_and_logger.c51
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/README33
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/TODO26
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/all_sourcecode.tests92
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/awk.tests20
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/basename/basename-does-not-remove-identical-extension1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/basename/basename-works2
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/bunzip2.tests84
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/bunzip2/bunzip2-reads-from-standard-input2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/bunzip2/bunzip2-removes-compressed-file3
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/bunzip2/bzcat-does-not-remove-compressed-file3
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/busybox.tests46
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/bzcat.tests49
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cat/cat-prints-a-file3
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cat/cat-prints-a-file-and-standard-input7
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cmp/cmp-detects-difference9
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cp/cp-RHL-does_not_preserve-links6
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cp/cp-a-files-to-dir15
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cp/cp-a-preserves-links5
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cp/cp-copies-empty-file3
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cp/cp-copies-large-file3
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cp/cp-copies-small-file3
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cp/cp-d-files-to-dir11
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cp/cp-dev-file2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cp/cp-dir-create-dir4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cp/cp-dir-existing-dir5
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cp/cp-does-not-copy-unreadable-file11
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cp/cp-files-to-dir11
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cp/cp-follows-links4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cp/cp-preserves-hard-links6
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cp/cp-preserves-links5
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cp/cp-preserves-source-file3
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/cpio.tests83
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/cut.tests18
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cut/cut-cuts-a-character1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cut/cut-cuts-a-closed-range1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cut/cut-cuts-a-field1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cut/cut-cuts-an-open-range1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/cut/cut-cuts-an-unclosed-range1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/date/date-R-works1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/date/date-format-works4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/date/date-u-works1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/date/date-works44
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/date/date-works-1129
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/dd/dd-accepts-if2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/dd/dd-accepts-of2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/dd/dd-copies-from-standard-input-to-standard-output1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/dd/dd-prints-count-to-standard-error2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/dd/dd-reports-write-errors2
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/diff.tests124
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/dirname/dirname-handles-absolute-path1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/dirname/dirname-handles-empty-path1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/dirname/dirname-handles-multiple-slashes1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/dirname/dirname-handles-relative-path1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/dirname/dirname-handles-root1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/dirname/dirname-handles-single-component1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/dirname/dirname-works2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/du/du-h-works4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/du/du-k-works4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/du/du-l-works4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/du/du-m-works4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/du/du-s-works4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/du/du-works4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/echo/echo-does-not-print-newline1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/echo/echo-prints-argument1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/echo/echo-prints-arguments1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/echo/echo-prints-newline1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/echo/echo-prints-slash-zero1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/expand/expand-works-like-GNU18
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/expr/expr-big16
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/expr/expr-works59
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/false/false-is-silent1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/false/false-returns-failure1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/find/find-supports-minus-xdev1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/grep.tests92
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/gunzip.tests3
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/gunzip/gunzip-reads-from-standard-input2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/gzip/gzip-accepts-multiple-files3
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/gzip/gzip-accepts-single-minus1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/gzip/gzip-removes-original-file3
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/head/head-n-works4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/head/head-works4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/hostid/hostid-works2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/hostname/hostname-d-works2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/hostname/hostname-i-works2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/hostname/hostname-s-works1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/hostname/hostname-works1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/id/id-g-works1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/id/id-u-works1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/id/id-un-works1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/id/id-ur-works1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/ln/ln-creates-hard-links4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/ln/ln-creates-soft-links4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/ln/ln-force-creates-hard-links5
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/ln/ln-force-creates-soft-links5
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/ln/ln-preserves-hard-links8
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/ln/ln-preserves-soft-links9
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/ls/ls-1-works4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/ls/ls-h-works4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/ls/ls-l-works4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/ls/ls-s-works4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/md5sum/md5sum-verifies-non-binary-file3
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/mdev.tests115
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/mkdir/mkdir-makes-a-directory2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/mkdir/mkdir-makes-parent-directories2
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/mkfs.minix.tests22
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/mount.testroot183
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/msh/msh-supports-underscores-in-variable-names1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/mv/mv-files-to-dir16
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/mv/mv-follows-links4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/mv/mv-moves-empty-file4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/mv/mv-moves-file3
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/mv/mv-moves-hardlinks4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/mv/mv-moves-large-file4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/mv/mv-moves-small-file4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/mv/mv-moves-symlinks6
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/mv/mv-moves-unreadable-files5
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/mv/mv-preserves-hard-links6
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/mv/mv-preserves-links5
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/mv/mv-refuses-mv-dir-to-subdir23
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/mv/mv-removes-source-file4
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/od.tests17
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/patch.tests65
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/pidof.tests31
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/printf.tests27
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/pwd/pwd-prints-working-directory1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/readlink.tests32
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/rm/rm-removes-file3
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/rmdir/rmdir-removes-parent-directories3
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/runtest151
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/sed.tests210
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/seq.tests36
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/sort.tests119
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/strings/strings-works-like-GNU9
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/sum.tests24
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tail/tail-n-works4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tail/tail-works4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tar/tar-archives-multiple-files6
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tar/tar-complains-about-missing-file3
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tar/tar-demands-at-least-one-ctx1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tar/tar-demands-at-most-one-ctx1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tar/tar-extracts-all-subdirs12
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tar/tar-extracts-file5
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tar/tar-extracts-from-standard-input5
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tar/tar-extracts-multiple-files6
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tar/tar-extracts-to-standard-output3
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tar/tar-handles-cz-options5
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tar/tar-handles-empty-include-and-non-empty-exclude-list6
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tar/tar-handles-exclude-and-extract-lists8
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tar/tar-handles-multiple-X-options10
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tar/tar-handles-nested-exclude9
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tar/tar_with_prefix_fields259
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/taskset.tests17
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tee/tee-appends-input5
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tee/tee-tees-input3
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/test.tests26
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/testing.sh167
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/touch/touch-creates-file2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/touch/touch-does-not-create-file2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/touch/touch-touches-files-after-non-existent-file3
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tr/tr-d-alnum-works4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tr/tr-d-works4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tr/tr-non-gnu1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tr/tr-rejects-wrong-class19
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/tr/tr-works26
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/true/true-is-silent1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/true/true-returns-success1
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/umlwrapper.sh20
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/unexpand/unexpand-works-like-GNU52
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/uniq.tests87
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/unzip.tests38
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/uptime/uptime-works2
-rwxr-xr-xcleopatre/busybox-1.11.1-spc300/testsuite/uuencode.tests28
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/wc/wc-counts-all2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/wc/wc-counts-characters1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/wc/wc-counts-lines1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/wc/wc-counts-words1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/wc/wc-prints-longest-line-length1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/wget/wget--O-overrides--P3
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/wget/wget-handles-empty-path1
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/wget/wget-retrieves-google-index2
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/wget/wget-supports--P3
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/which/which-uses-default-path4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/testsuite/xargs/xargs-works4
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/Config.in831
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/Kbuild35
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/dmesg.c67
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/fbset.c410
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/fdformat.c130
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/fdisk.c2982
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/fdisk_aix.c73
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/fdisk_osf.c1059
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/fdisk_sgi.c892
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/fdisk_sun.c730
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/findfs.c38
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/freeramdisk.c33
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/fsck_minix.c1309
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/getopt.c353
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/hexdump.c156
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/hwclock.c127
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/ipcrm.c220
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/ipcs.c621
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/losetup.c79
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/mdev.c453
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/minix.h98
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/mkfs_minix.c734
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/mkswap.c129
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/more.c205
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/mount.c1935
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/pivot_root.c27
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/rdate.c71
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/readprofile.c247
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/rtcwake.c199
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/script.c185
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/setarch.c48
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/swaponoff.c102
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/switch_root.c125
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/umount.c173
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/Kbuild41
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/cramfs.c58
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/ext.c73
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/fat.c335
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/get_devname.c429
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/hfs.c291
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/iso9660.c119
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/jfs.c59
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/linux_raid.c79
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/linux_swap.c73
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/luks.c75
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/ntfs.c193
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/ocfs2.c105
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/reiserfs.c112
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/romfs.c54
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/sysv.c125
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/udf.c172
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/unused_highpoint.c86
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/unused_hpfs.c49
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/unused_isw_raid.c58
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/unused_lsi_raid.c52
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/unused_lvm.c87
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/unused_mac.c123
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/unused_minix.c75
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/unused_msdos.c193
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/unused_nvidia_raid.c56
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/unused_promise_raid.c63
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/unused_silicon_raid.c69
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/unused_ufs.c206
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/unused_via_raid.c68
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/util.c263
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/volume_id.c243
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/volume_id_internal.h233
-rw-r--r--cleopatre/busybox-1.11.1-spc300/util-linux/volume_id/xfs.c59
1258 files changed, 267938 insertions, 0 deletions
diff --git a/cleopatre/busybox-1.11.1-spc300/.indent.pro b/cleopatre/busybox-1.11.1-spc300/.indent.pro
new file mode 100644
index 0000000000..492ecf1c7d
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/.indent.pro
@@ -0,0 +1,33 @@
+--blank-lines-after-declarations
+--blank-lines-after-procedures
+--break-before-boolean-operator
+--no-blank-lines-after-commas
+--braces-on-if-line
+--braces-on-struct-decl-line
+--comment-indentation25
+--declaration-comment-column25
+--no-comment-delimiters-on-blank-lines
+--cuddle-else
+--continuation-indentation4
+--case-indentation0
+--else-endif-column33
+--space-after-cast
+--line-comments-indentation0
+--declaration-indentation1
+--dont-format-first-column-comments
+--dont-format-comments
+--honour-newlines
+--indent-level4
+/* changed from 0 to 4 */
+--parameter-indentation4
+--line-length78 /* changed from 75 */
+--continue-at-parentheses
+--no-space-after-function-call-names
+--dont-break-procedure-type
+--dont-star-comments
+--leave-optional-blank-lines
+--dont-space-special-semicolon
+--tab-size4
+/* additions by Mark */
+--case-brace-indentation0
+--leave-preprocessor-space
diff --git a/cleopatre/busybox-1.11.1-spc300/AUTHORS b/cleopatre/busybox-1.11.1-spc300/AUTHORS
new file mode 100644
index 0000000000..9755ad9dda
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/AUTHORS
@@ -0,0 +1,173 @@
+List of the authors of code contained in BusyBox.
+
+If you have code in BusyBox, you should be listed here. If you should be
+listed, or the description of what you have done needs more detail, or is
+incorrect, _please_ let me know.
+
+ -Erik
+
+-----------
+
+Peter Willis <psyphreak@phreaker.net>
+ eject
+
+Emanuele Aina <emanuele.aina@tiscali.it>
+ run-parts
+
+Erik Andersen <andersen@codepoet.org>
+ Tons of new stuff, major rewrite of most of the
+ core apps, tons of new apps as noted in header files.
+ Lots of tedious effort writing these boring docs that
+ nobody is going to actually read.
+
+Laurence Anderson <l.d.anderson@warwick.ac.uk>
+ rpm2cpio, unzip, get_header_cpio, read_gz interface, rpm
+
+Jeff Angielski <jeff@theptrgroup.com>
+ ftpput, ftpget
+
+Enrik Berkhan <Enrik.Berkhan@inka.de>
+ setconsole
+
+Jim Bauer <jfbauer@nfr.com>
+ modprobe shell dependency
+
+Edward Betts <edward@debian.org>
+ expr, hostid, logname, whoami
+
+John Beppu <beppu@codepoet.org>
+ du, nslookup, sort
+
+David Brownell <dbrownell@users.sourceforge.net>
+ zcip
+
+Brian Candler <B.Candler@pobox.com>
+ tiny-ls(ls)
+
+Randolph Chung <tausq@debian.org>
+ fbset, ping, hostname
+
+Dave Cinege <dcinege@psychosis.com>
+ more(v2), makedevs, dutmp, modularization, auto links file,
+ various fixes, Linux Router Project maintenance
+
+Jordan Crouse <jordan@cosmicpenguin.net>
+ ipcalc
+
+Magnus Damm <damm@opensource.se>
+ tftp client
+ insmod powerpc support
+
+Larry Doolittle <ldoolitt@recycle.lbl.gov>
+ pristine source directory compilation, lots of patches and fixes.
+
+Glenn Engel <glenne@engel.org>
+ httpd
+
+Gennady Feldman <gfeldman@gena01.com>
+ Sysklogd (single threaded syslogd, IPC Circular buffer support,
+ logread), various fixes.
+
+Robert Griebl <sandman@handhelds.org>
+ modprobe, hwclock, suid/sgid handling, tinylogin integration
+ many bugfixes and enhancements
+
+Karl M. Hegbloom <karlheg@debian.org>
+ cp_mv.c, the test suite, various fixes to utility.c, &c.
+
+Daniel Jacobowitz <dan@debian.org>
+ mktemp.c
+
+Matt Kraai <kraai@alumni.cmu.edu>
+ documentation, bugfixes, test suite
+
+Rob Landley <rob@landley.net>
+ Became busybox maintainer in 2006.
+
+ sed (major rewrite in 2003, and I now maintain the thing)
+ bunzip2 (complete from-scratch rewrite, then mjn3 optimized the result)
+ sort (more or less from scratch rewrite in 2004, I now maintain it)
+ mount (rewrite in 2005, I maintain the new one)
+
+Stephan Linz <linz@li-pro.net>
+ ipcalc, Red Hat equivalence
+
+John Lombardo <john@deltanet.com>
+ tr
+
+Glenn McGrath <glenn.l.mcgrath@gmail.com>
+ Common unarchiving code and unarchiving applets, ifupdown, ftpgetput,
+ nameif, sed, patch, fold, install, uudecode.
+ Various bugfixes, review and apply numerous patches.
+
+Manuel Novoa III <mjn3@codepoet.org>
+ cat, head, mkfifo, mknod, rmdir, sleep, tee, tty, uniq, usleep, wc, yes,
+ mesg, vconfig, nice, renice,
+ make_directory, parse_mode, dirname, mode_string,
+ get_last_path_component, simplify_path, and a number trivial libbb routines
+
+ also bug fixes, partial rewrites, and size optimizations in
+ ash, basename, cal, cmp, cp, df, du, echo, env, ln, logname, md5sum, mkdir,
+ mv, realpath, rm, sort, tail, touch, uname, watch, arith, human_readable,
+ interface, dutmp, ifconfig, route
+
+Vladimir Oleynik <dzo@simtreas.ru>
+ cmdedit; bb_mkdep, xargs(current), httpd(current);
+ ports: ash, crond, fdisk (initial, unmaintained now), inetd, stty, traceroute,
+ top;
+ locale, various fixes
+ and irreconcilable critic of everything not perfect.
+
+Bruce Perens <bruce@pixar.com>
+ Original author of BusyBox in 1995, 1996. Some of his code can
+ still be found hiding here and there...
+
+Rodney Radford <rradford@mindspring.com>
+ ipcs, ipcrm
+
+Tim Riker <Tim@Rikers.org>
+ bug fixes, member of fan club
+
+Kent Robotti <robotti@metconnect.com>
+ reset, tons and tons of bug reports and patches.
+
+Chip Rosenthal <chip@unicom.com>, <crosenth@covad.com>
+ wget - Contributed by permission of Covad Communications
+
+Pavel Roskin <proski@gnu.org>
+ Lots of bugs fixes and patches.
+
+Gyepi Sam <gyepi@praxis-sw.com>
+ Remote logging feature for syslogd
+
+Rob Sullivan <cogito.ergo.cogito@gmail.com>
+ comm
+
+Linus Torvalds
+ mkswap, fsck.minix, mkfs.minix
+
+Mark Whitley <markw@codepoet.org>
+ grep, sed, cut, xargs(previous),
+ style-guide, new-applet-HOWTO, bug fixes, etc.
+
+Charles P. Wright <cpwright@villagenet.com>
+ gzip, mini-netcat(nc)
+
+Enrique Zanardi <ezanardi@ull.es>
+ tarcat (since removed), loadkmap, various fixes, Debian maintenance
+
+Tito Ragusa <farmatito@tiscali.it>
+ devfsd and size optimizations in strings, openvt, chvt, deallocvt, hdparm,
+ fdformat, lsattr, chattr, id and eject.
+
+Paul Fox <pgf@foxharp.boston.ma.us>
+ vi editing mode for ash, various other patches/fixes
+
+Roberto A. Foglietta <me@roberto.foglietta.name>
+ port: dnsd
+
+Bernhard Fischer <rep.nop@aon.at>
+ misc
+
+Mike Frysinger <vapier@gentoo.org>
+ initial e2fsprogs, printenv, setarch, sum, misc
diff --git a/cleopatre/busybox-1.11.1-spc300/Config.in b/cleopatre/busybox-1.11.1-spc300/Config.in
new file mode 100644
index 0000000000..a7c3149cbf
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/Config.in
@@ -0,0 +1,582 @@
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+mainmenu "BusyBox Configuration"
+
+config HAVE_DOT_CONFIG
+ bool
+ default y
+
+menu "Busybox Settings"
+
+menu "General Configuration"
+
+config DESKTOP
+ bool "Enable options for full-blown desktop systems"
+ default n
+ help
+ Enable options and features which are not essential.
+ Select this only if you plan to use busybox on full-blown
+ desktop machine with common Linux distro, not on an embedded box.
+
+config FEATURE_ASSUME_UNICODE
+ bool "Assume that 1:1 char/glyph correspondence is not true"
+ default n
+ help
+ This makes various applets aware that one byte is not
+ one character on screen.
+
+ Busybox aims to eventually work correctly with Unicode displays.
+ Any older encodings are not guaranteed to work.
+ Probably by the time when busybox will be fully Unicode-clean,
+ other encodings will be mainly of historic interest.
+
+choice
+ prompt "Buffer allocation policy"
+ default FEATURE_BUFFERS_USE_MALLOC
+ help
+ There are 3 ways BusyBox can handle buffer allocations:
+ - Use malloc. This costs code size for the call to xmalloc.
+ - Put them on stack. For some very small machines with limited stack
+ space, this can be deadly. For most folks, this works just fine.
+ - Put them in BSS. This works beautifully for computers with a real
+ MMU (and OS support), but wastes runtime RAM for uCLinux. This
+ behavior was the only one available for BusyBox versions 0.48 and
+ earlier.
+
+config FEATURE_BUFFERS_USE_MALLOC
+ bool "Allocate with Malloc"
+
+config FEATURE_BUFFERS_GO_ON_STACK
+ bool "Allocate on the Stack"
+
+config FEATURE_BUFFERS_GO_IN_BSS
+ bool "Allocate in the .bss section"
+
+endchoice
+
+config SHOW_USAGE
+ bool "Show terse applet usage messages"
+ default y
+ help
+ All BusyBox applets will show help messages when invoked with
+ wrong arguments. You can turn off printing these terse usage
+ messages if you say no here.
+ This will save you up to 7k.
+
+config FEATURE_VERBOSE_USAGE
+ bool "Show verbose applet usage messages"
+ default n
+ select SHOW_USAGE
+ help
+ All BusyBox applets will show more verbose help messages when
+ busybox is invoked with --help. This will add a lot of text to the
+ busybox binary. In the default configuration, this will add about
+ 13k, but it can add much more depending on your configuration.
+
+config FEATURE_COMPRESS_USAGE
+ bool "Store applet usage messages in compressed form"
+ default y
+ depends on SHOW_USAGE
+ help
+ Store usage messages in compressed form, uncompress them on-the-fly
+ when <applet> --help is called.
+
+ If you have a really tiny busybox with few applets enabled (and
+ bunzip2 isn't one of them), the overhead of the decompressor might
+ be noticeable. Also, if you run executables directly from ROM
+ and have very little memory, this might not be a win. Otherwise,
+ you probably want this.
+
+config FEATURE_INSTALLER
+ bool "Support --install [-s] to install applet links at runtime"
+ default n
+ help
+ Enable 'busybox --install [-s]' support. This will allow you to use
+ busybox at runtime to create hard links or symlinks for all the
+ applets that are compiled into busybox.
+
+config LOCALE_SUPPORT
+ bool "Enable locale support (system needs locale for this to work)"
+ default n
+ help
+ Enable this if your system has locale support and you would like
+ busybox to support locale settings.
+
+config GETOPT_LONG
+ bool "Support for --long-options"
+ default y
+ help
+ Enable this if you want busybox applets to use the gnu --long-option
+ style, in addition to single character -a -b -c style options.
+
+config FEATURE_DEVPTS
+ bool "Use the devpts filesystem for Unix98 PTYs"
+ default y
+ help
+ Enable if you want BusyBox to use Unix98 PTY support. If enabled,
+ busybox will use /dev/ptmx for the master side of the pseudoterminal
+ and /dev/pts/<number> for the slave side. Otherwise, BSD style
+ /dev/ttyp<number> will be used. To use this option, you should have
+ devpts mounted.
+
+config FEATURE_CLEAN_UP
+ bool "Clean up all memory before exiting (usually not needed)"
+ default n
+ help
+ As a size optimization, busybox normally exits without explicitly
+ freeing dynamically allocated memory or closing files. This saves
+ space since the OS will clean up for us, but it can confuse debuggers
+ like valgrind, which report tons of memory and resource leaks.
+
+ Don't enable this unless you have a really good reason to clean
+ things up manually.
+
+config FEATURE_PIDFILE
+ bool "Support writing pidfiles"
+ default n
+ help
+ This option makes some applets (e.g. crond, syslogd, inetd) write
+ a pidfile in /var/run. Some applications rely on them.
+
+config FEATURE_SUID
+ bool "Support for SUID/SGID handling"
+ default n
+ help
+ With this option you can install the busybox binary belonging
+ to root with the suid bit set, and it'll and it'll automatically drop
+ priviledges for applets that don't need root access.
+
+ If you're really paranoid and don't want to do this, build two
+ busybox binaries with different applets in them (and the appropriate
+ symlinks pointing to each binary), and only set the suid bit on the
+ one that needs it. The applets currently marked to need the suid bit
+ are login, passwd, su, ping, traceroute, crontab, dnsd, ipcrm, ipcs,
+ and vlock.
+
+config FEATURE_SUID_CONFIG
+ bool "Runtime SUID/SGID configuration via /etc/busybox.conf"
+ default n if FEATURE_SUID
+ depends on FEATURE_SUID
+ help
+ Allow the SUID / SGID state of an applet to be determined at runtime
+ by checking /etc/busybox.conf. (This is sort of a poor man's sudo.)
+ The format of this file is as follows:
+
+ <applet> = [Ssx-][Ssx-][x-] (<username>|<uid>).(<groupname>|<gid>)
+
+ An example might help:
+
+ [SUID]
+ su = ssx root.0 # applet su can be run by anyone and runs with euid=0/egid=0
+ su = ssx # exactly the same
+
+ mount = sx- root.disk # applet mount can be run by root and members of group disk
+ # and runs with euid=0
+
+ cp = --- # disable applet cp for everyone
+
+ The file has to be owned by user root, group root and has to be
+ writeable only by root:
+ (chown 0.0 /etc/busybox.conf; chmod 600 /etc/busybox.conf)
+ The busybox executable has to be owned by user root, group
+ root and has to be setuid root for this to work:
+ (chown 0.0 /bin/busybox; chmod 4755 /bin/busybox)
+
+ Robert 'sandman' Griebl has more information here:
+ <url: http://www.softforge.de/bb/suid.html >.
+
+config FEATURE_SUID_CONFIG_QUIET
+ bool "Suppress warning message if /etc/busybox.conf is not readable"
+ default y
+ depends on FEATURE_SUID_CONFIG
+ help
+ /etc/busybox.conf should be readable by the user needing the SUID, check
+ this option to avoid users to be notified about missing permissions.
+
+config SELINUX
+ bool "Support NSA Security Enhanced Linux"
+ default n
+ help
+ Enable support for SELinux in applets ls, ps, and id. Also provide
+ the option of compiling in SELinux applets.
+
+ If you do not have a complete SELinux userland installed, this stuff
+ will not compile. Go visit
+ http://www.nsa.gov/selinux/index.html
+ to download the necessary stuff to allow busybox to compile with
+ this option enabled. Specifially, libselinux 1.28 or better is
+ directly required by busybox. If the installation is located in a
+ non-standard directory, provide it by invoking make as follows:
+ CFLAGS=-I<libselinux-include-path> \
+ LDFLAGS=-L<libselinux-lib-path> \
+ make
+
+ Most people will leave this set to 'N'.
+
+config FEATURE_PREFER_APPLETS
+ bool "exec prefers applets"
+ default n
+ help
+ This is an experimental option which directs applets about to
+ call 'exec' to try and find an applicable busybox applet before
+ searching the PATH. This is typically done by exec'ing
+ /proc/self/exe.
+ This may affect shell, find -exec, xargs and similar applets.
+ They will use applets even if /bin/<applet> -> busybox link
+ is missing (or is not a link to busybox). However, this causes
+ problems in chroot jails without mounted /proc and with ps/top
+ (command name can be shown as 'exe' for applets started this way).
+
+config BUSYBOX_EXEC_PATH
+ string "Path to BusyBox executable"
+ default "/proc/self/exe"
+ help
+ When Busybox applets need to run other busybox applets, BusyBox
+ sometimes needs to exec() itself. When the /proc filesystem is
+ mounted, /proc/self/exe always points to the currently running
+ executable. If you haven't got /proc, set this to wherever you
+ want to run BusyBox from.
+
+# These are auto-selected by other options
+
+config FEATURE_SYSLOG
+ bool "Support for logging to syslog"
+ default n
+ help
+ This option is auto-selected when you select any applet which may
+ send its output to syslog. You do not need to select it manually.
+
+config FEATURE_HAVE_RPC
+ bool "RPC support"
+ default n
+ help
+ This is automatically selected if any of enabled applets need it.
+ You do not need to select it manually.
+
+endmenu
+
+menu 'Build Options'
+
+config STATIC
+ bool "Build BusyBox as a static binary (no shared libs)"
+ default n
+ help
+ If you want to build a static BusyBox binary, which does not
+ use or require any shared libraries, then enable this option.
+ This can cause BusyBox to be considerably larger, so you should
+ leave this option false unless you have a good reason (i.e.
+ your target platform does not support shared libraries, or
+ you are building an initrd which doesn't need anything but
+ BusyBox, etc).
+
+ Most people will leave this set to 'N'.
+
+config PIE
+ bool "Build BusyBox as a position independent executable"
+ default n
+ depends on !STATIC
+ help
+ (TODO: what is it and why/when is it useful?)
+ Most people will leave this set to 'N'.
+
+config NOMMU
+ bool "Force NOMMU build"
+ default n
+ help
+ Busybox tries to detect whether architecture it is being
+ built against supports MMU or not. If this detection fails,
+ or if you want to build NOMMU version of busybox for testing,
+ you may force NOMMU build here.
+
+ Most people will leave this set to 'N'.
+
+# PIE can be made to work with BUILD_LIBBUSYBOX, but currently
+# build system does not support that
+config BUILD_LIBBUSYBOX
+ bool "Build shared libbusybox"
+ default n
+ depends on !FEATURE_PREFER_APPLETS && !PIE && !STATIC
+ help
+ Build a shared library libbusybox.so.N.N.N which contains all
+ busybox code.
+
+ This feature allows every applet to be built as a tiny
+ separate executable. Enabling it for "one big busybox binary"
+ approach serves no purpose and increases code size.
+ You should almost certainly say "no" to this.
+
+### config FEATURE_FULL_LIBBUSYBOX
+### bool "Feature-complete libbusybox"
+### default n if !FEATURE_SHARED_BUSYBOX
+### depends on BUILD_LIBBUSYBOX
+### help
+### Build a libbusybox with the complete feature-set, disregarding
+### the actually selected config.
+###
+### Normally, libbusybox will only contain the features which are
+### used by busybox itself. If you plan to write a separate
+### standalone application which uses libbusybox say 'Y'.
+###
+### Note: libbusybox is GPL, not LGPL, and exports no stable API that
+### might act as a copyright barrier. We can and will modify the
+### exported function set between releases (even minor version number
+### changes), and happily break out-of-tree features.
+###
+### Say 'N' if in doubt.
+
+config FEATURE_INDIVIDUAL
+ bool "Produce a binary for each applet, linked against libbusybox"
+ default y
+ depends on !STATIC && BUILD_LIBBUSYBOX
+ help
+ If your CPU architecture doesn't allow for sharing text/rodata
+ sections of running binaries, but allows for runtime dynamic
+ libraries, this option will allow you to reduce memory footprint
+ when you have many different applets running at once.
+
+ If your CPU architecture allows for sharing text/rodata,
+ having single binary is more optimal.
+
+ Each applet will be a tiny program, dynamically linked
+ against libbusybox.so.N.N.N.
+
+ You need to have a working dynamic linker.
+
+config FEATURE_SHARED_BUSYBOX
+ bool "Produce additional busybox binary linked against libbusybox"
+ default y
+ depends on !STATIC && BUILD_LIBBUSYBOX
+ help
+ Build busybox, dynamically linked against libbusybox.so.N.N.N.
+
+ You need to have a working dynamic linker.
+
+### config BUILD_AT_ONCE
+### bool "Compile all sources at once"
+### default n
+### help
+### Normally each source-file is compiled with one invocation of
+### the compiler.
+### If you set this option, all sources are compiled at once.
+### This gives the compiler more opportunities to optimize which can
+### result in smaller and/or faster binaries.
+###
+### Setting this option will consume alot of memory, e.g. if you
+### enable all applets with all features, gcc uses more than 300MB
+### RAM during compilation of busybox.
+###
+### This option is most likely only beneficial for newer compilers
+### such as gcc-4.1 and above.
+###
+### Say 'N' unless you know what you are doing.
+
+config LFS
+ bool "Build with Large File Support (for accessing files > 2 GB)"
+ default n
+ select FDISK_SUPPORT_LARGE_DISKS
+ help
+ If you want to build BusyBox with large file support, then enable
+ this option. This will have no effect if your kernel or your C
+ library lacks large file support for large files. Some of the
+ programs that can benefit from large file support include dd, gzip,
+ cp, mount, tar, and many others. If you want to access files larger
+ than 2 Gigabytes, enable this option. Otherwise, leave it set to 'N'.
+
+config CROSS_COMPILER_PREFIX
+ string "Cross Compiler prefix"
+ default ""
+ help
+ If you want to build BusyBox with a cross compiler, then you
+ will need to set this to the cross-compiler prefix, for example,
+ "i386-uclibc-". Note that CROSS_COMPILE environment variable
+ or "make CROSS_COMPILE=xxx ..." will override this selection.
+ For native build leave it empty.
+
+endmenu
+
+menu 'Debugging Options'
+
+config DEBUG
+ bool "Build BusyBox with extra Debugging symbols"
+ default n
+ help
+ Say Y here if you wish to examine BusyBox internals while applets are
+ running. This increases the size of the binary considerably, and
+ should only be used when doing development. If you are doing
+ development and want to debug BusyBox, answer Y.
+
+ Most people should answer N.
+
+config DEBUG_PESSIMIZE
+ bool "Disable compiler optimizations."
+ default n
+ depends on DEBUG
+ help
+ The compiler's optimization of source code can eliminate and reorder
+ code, resulting in an executable that's hard to understand when
+ stepping through it with a debugger. This switches it off, resulting
+ in a much bigger executable that more closely matches the source
+ code.
+
+config WERROR
+ bool "Abort compilation on any warning"
+ default n
+ help
+ Selecting this will add -Werror to gcc command line.
+
+ Most people should answer N.
+
+choice
+ prompt "Additional debugging library"
+ default NO_DEBUG_LIB
+ help
+ Using an additional debugging library will make BusyBox become
+ considerable larger and will cause it to run more slowly. You
+ should always leave this option disabled for production use.
+
+ dmalloc support:
+ ----------------
+ This enables compiling with dmalloc ( http://dmalloc.com/ )
+ which is an excellent public domain mem leak and malloc problem
+ detector. To enable dmalloc, before running busybox you will
+ want to properly set your environment, for example:
+ export DMALLOC_OPTIONS=debug=0x34f47d83,inter=100,log=logfile
+ The 'debug=' value is generated using the following command
+ dmalloc -p log-stats -p log-non-free -p log-bad-space -p log-elapsed-time \
+ -p check-fence -p check-heap -p check-lists -p check-blank \
+ -p check-funcs -p realloc-copy -p allow-free-null
+
+ Electric-fence support:
+ -----------------------
+ This enables compiling with Electric-fence support. Electric
+ fence is another very useful malloc debugging library which uses
+ your computer's virtual memory hardware to detect illegal memory
+ accesses. This support will make BusyBox be considerable larger
+ and run slower, so you should leave this option disabled unless
+ you are hunting a hard to find memory problem.
+
+
+config NO_DEBUG_LIB
+ bool "None"
+
+config DMALLOC
+ bool "Dmalloc"
+
+config EFENCE
+ bool "Electric-fence"
+
+endchoice
+
+config INCLUDE_SUSv2
+ bool "Enable obsolete features removed before SUSv3?"
+ default y
+ help
+ This option will enable backwards compatibility with SuSv2,
+ specifically, old-style numeric options ('command -1 <file>')
+ will be supported in head, tail, and fold. (Note: should
+ affect renice too.)
+
+endmenu
+
+menu 'Installation Options'
+
+config INSTALL_NO_USR
+ bool "Don't use /usr"
+ default n
+ help
+ Disable use of /usr. Don't activate this option if you don't know
+ that you really want this behaviour.
+
+choice
+ prompt "Applets links"
+ default INSTALL_APPLET_SYMLINKS
+ help
+ Choose how you install applets links.
+
+config INSTALL_APPLET_SYMLINKS
+ bool "as soft-links"
+ help
+ Install applets as soft-links to the busybox binary. This needs some
+ free inodes on the filesystem, but might help with filesystem
+ generators that can't cope with hard-links.
+
+config INSTALL_APPLET_HARDLINKS
+ bool "as hard-links"
+ help
+ Install applets as hard-links to the busybox binary. This might count
+ on a filesystem with few inodes.
+
+config INSTALL_APPLET_SCRIPT_WRAPPERS
+ bool "as script wrappers"
+ help
+ Install applets as script wrappers that call the busybox binary.
+
+config INSTALL_APPLET_DONT
+ bool "not installed"
+ depends on FEATURE_INSTALLER || FEATURE_SH_STANDALONE || FEATURE_PREFER_APPLETS
+ help
+ Do not install applet links. Useful when using the -install feature
+ or a standalone shell for rescue purposes.
+
+endchoice
+
+choice
+ prompt "/bin/sh applet link"
+ default INSTALL_SH_APPLET_SYMLINK
+ depends on INSTALL_APPLET_SCRIPT_WRAPPERS
+ help
+ Choose how you install /bin/sh applet link.
+
+config INSTALL_SH_APPLET_SYMLINK
+ bool "as soft-link"
+ help
+ Install /bin/sh applet as soft-link to the busybox binary.
+
+config INSTALL_SH_APPLET_HARDLINK
+ bool "as hard-link"
+ help
+ Install /bin/sh applet as hard-link to the busybox binary.
+
+config INSTALL_SH_APPLET_SCRIPT_WRAPPER
+ bool "as script wrapper"
+ help
+ Install /bin/sh applet as script wrapper that call the busybox binary.
+
+endchoice
+
+config PREFIX
+ string "BusyBox installation prefix"
+ default "./_install"
+ help
+ Define your directory to install BusyBox files/subdirs in.
+
+endmenu
+
+source libbb/Config.in
+
+endmenu
+
+comment "Applets"
+
+source archival/Config.in
+source coreutils/Config.in
+source console-tools/Config.in
+source debianutils/Config.in
+source editors/Config.in
+source findutils/Config.in
+source init/Config.in
+source loginutils/Config.in
+source e2fsprogs/Config.in
+source modutils/Config.in
+source util-linux/Config.in
+source miscutils/Config.in
+source networking/Config.in
+source procps/Config.in
+source shell/Config.in
+source sysklogd/Config.in
+source runit/Config.in
+source selinux/Config.in
+source printutils/Config.in
diff --git a/cleopatre/busybox-1.11.1-spc300/INSTALL b/cleopatre/busybox-1.11.1-spc300/INSTALL
new file mode 100644
index 0000000000..a7902ab8dc
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/INSTALL
@@ -0,0 +1,125 @@
+Building:
+=========
+
+The BusyBox build process is similar to the Linux kernel build:
+
+ make menuconfig # This creates a file called ".config"
+ make # This creates the "busybox" executable
+ make install # or make CONFIG_PREFIX=/path/from/root install
+
+The full list of configuration and install options is available by typing:
+
+ make help
+
+Quick Start:
+============
+
+The easy way to try out BusyBox for the first time, without having to install
+it, is to enable all features and then use "standalone shell" mode with a
+blank command $PATH.
+
+To enable all features, use "make defconfig", which produces the largest
+general-purpose configuration. (It's allyesconfig minus debugging options,
+optional packaging choices, and a few special-purpose features requiring
+extra configuration to use.)
+
+ make defconfig
+ make
+ PATH= ./busybox ash
+
+Standalone shell mode causes busybox's built-in command shell to run
+any built-in busybox applets directly, without looking for external
+programs by that name. Supplying an empty command path (as above) means
+the only commands busybox can find are the built-in ones.
+
+Note that the standalone shell requires CONFIG_BUSYBOX_EXEC_PATH
+to be set appropriately, depending on whether or not /proc/self/exe is
+available or not. If you do not have /proc, then point that config option
+to the location of your busybox binary, usually /bin/busybox.
+
+Configuring Busybox:
+====================
+
+Busybox is optimized for size, but enabling the full set of functionality
+still results in a fairly large executable -- more than 1 megabyte when
+statically linked. To save space, busybox can be configured with only the
+set of applets needed for each environment. The minimal configuration, with
+all applets disabled, produces a 4k executable. (It's useless, but very small.)
+
+The manual configurator "make menuconfig" modifies the existing configuration.
+(For systems without ncurses, try "make config" instead.) The two most
+interesting starting configurations are "make allnoconfig" (to start with
+everything disabled and add just what you need), and "make defconfig" (to
+start with everything enabled and remove what you don't need). If menuconfig
+is run without an existing configuration, make defconfig will run first to
+create a known starting point.
+
+Other starting configurations (mostly used for testing purposes) include
+"make allbareconfig" (enables all applets but disables all optional features),
+"make allyesconfig" (enables absolutely everything including debug features),
+and "make randconfig" (produce a random configuration).
+
+Configuring BusyBox produces a file ".config", which can be saved for future
+use. Run "make oldconfig" to bring a .config file from an older version of
+busybox up to date.
+
+Installing Busybox:
+===================
+
+Busybox is a single executable that can behave like many different commands,
+and BusyBox uses the name it was invoked under to determine the desired
+behavior. (Try "mv busybox ls" and then "./ls -l".)
+
+Installing busybox consists of creating symlinks (or hardlinks) to the busybox
+binary for each applet enabled in busybox, and making sure these symlinks are
+in the shell's command $PATH. Running "make install" creates these symlinks,
+or "make install-hardlinks" creates hardlinks instead (useful on systems with
+a limited number of inodes). This install process uses the file
+"busybox.links" (created by make), which contains the list of enabled applets
+and the path at which to install them.
+
+Installing links to busybox is not always necessary. The special applet name
+"busybox" (or with any optional suffix, such as "busybox-static") uses the
+first argument to determine which applet to behave as, for example
+"./busybox cat LICENSE". (Running the busybox applet with no arguments gives
+a list of all enabled applets.) The standalone shell can also call busybox
+applets without links to busybox under other names in the filesystem. You can
+also configure a standaone install capability into the busybox base applet,
+and then install such links at runtime with one of "busybox --install" (for
+hardlinks) or "busybox --install -s" (for symlinks).
+
+If you enabled the busybox shared library feature (libbusybox.so) and want
+to run tests without installing, set your LD_LIBRARY_PATH accordingly when
+running the executable:
+
+ LD_LIBRARY_PATH=`pwd` ./busybox
+
+Building out-of-tree:
+=====================
+
+By default, the BusyBox build puts its temporary files in the source tree.
+Building from a read-only source tree, or building multiple configurations from
+the same source directory, requires the ability to put the temporary files
+somewhere else.
+
+To build out of tree, cd to an empty directory and configure busybox from there:
+
+ make -f /path/to/source/Makefile defconfig
+ make
+ make install
+
+Alternately, use the O=$BUILDPATH option (with an absolute path) during the
+configuration step, as in:
+
+ make O=/some/empty/directory allyesconfig
+ cd /some/empty/directory
+ make
+ make CONFIG_PREFIX=. install
+
+More Information:
+=================
+
+Se also the busybox FAQ, under the questions "How can I get started using
+BusyBox" and "How do I build a BusyBox-based system?" The BusyBox FAQ is
+available from http://www.busybox.net/FAQ.html or as the file
+docs/busybox.net/FAQ.html in this tarball.
diff --git a/cleopatre/busybox-1.11.1-spc300/LICENSE b/cleopatre/busybox-1.11.1-spc300/LICENSE
new file mode 100644
index 0000000000..9d9bdc7e31
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/LICENSE
@@ -0,0 +1,348 @@
+--- A note on GPL versions
+
+BusyBox is distributed under version 2 of the General Public License (included
+in its entirety, below). Version 2 is the only version of this license which
+this version of BusyBox (or modified versions derived from this one) may be
+distributed under.
+
+------------------------------------------------------------------------
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/cleopatre/busybox-1.11.1-spc300/Makefile b/cleopatre/busybox-1.11.1-spc300/Makefile
new file mode 100644
index 0000000000..6d0cc3898d
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/Makefile
@@ -0,0 +1,1309 @@
+VERSION = 1
+PATCHLEVEL = 11
+SUBLEVEL = 1
+EXTRAVERSION =
+NAME = Unnamed
+
+# *DOCUMENTATION*
+# To see a list of typical targets execute "make help"
+# More info can be located in ./README
+# Comments in this file are targeted only to the developer, do not
+# expect to learn how to build the kernel reading this file.
+
+# Do not print "Entering directory ..."
+MAKEFLAGS += --no-print-directory
+
+# We are using a recursive build, so we need to do a little thinking
+# to get the ordering right.
+#
+# Most importantly: sub-Makefiles should only ever modify files in
+# their own directory. If in some directory we have a dependency on
+# a file in another dir (which doesn't happen often, but it's often
+# unavoidable when linking the built-in.o targets which finally
+# turn into busybox), we will call a sub make in that other dir, and
+# after that we are sure that everything which is in that other dir
+# is now up to date.
+#
+# The only cases where we need to modify files which have global
+# effects are thus separated out and done before the recursive
+# descending is started. They are now explicitly listed as the
+# prepare rule.
+
+# To put more focus on warnings, be less verbose as default
+# Use 'make V=1' to see the full commands
+
+ifdef V
+ ifeq ("$(origin V)", "command line")
+ KBUILD_VERBOSE = $(V)
+ endif
+endif
+ifndef KBUILD_VERBOSE
+ KBUILD_VERBOSE = 0
+endif
+
+# Call sparse as part of compilation of C files
+# Use 'make C=1' to enable sparse checking
+
+ifdef C
+ ifeq ("$(origin C)", "command line")
+ KBUILD_CHECKSRC = $(C)
+ endif
+endif
+ifndef KBUILD_CHECKSRC
+ KBUILD_CHECKSRC = 0
+endif
+
+# Use make M=dir to specify directory of external module to build
+# Old syntax make ... SUBDIRS=$PWD is still supported
+# Setting the environment variable KBUILD_EXTMOD take precedence
+ifdef SUBDIRS
+ KBUILD_EXTMOD ?= $(SUBDIRS)
+endif
+ifdef M
+ ifeq ("$(origin M)", "command line")
+ KBUILD_EXTMOD := $(M)
+ endif
+endif
+
+
+# kbuild supports saving output files in a separate directory.
+# To locate output files in a separate directory two syntaxes are supported.
+# In both cases the working directory must be the root of the kernel src.
+# 1) O=
+# Use "make O=dir/to/store/output/files/"
+#
+# 2) Set KBUILD_OUTPUT
+# Set the environment variable KBUILD_OUTPUT to point to the directory
+# where the output files shall be placed.
+# export KBUILD_OUTPUT=dir/to/store/output/files/
+# make
+#
+# The O= assignment takes precedence over the KBUILD_OUTPUT environment
+# variable.
+
+
+# KBUILD_SRC is set on invocation of make in OBJ directory
+# KBUILD_SRC is not intended to be used by the regular user (for now)
+ifeq ($(KBUILD_SRC),)
+
+# OK, Make called in directory where kernel src resides
+# Do we want to locate output files in a separate directory?
+ifdef O
+ ifeq ("$(origin O)", "command line")
+ KBUILD_OUTPUT := $(O)
+ endif
+endif
+
+# That's our default target when none is given on the command line
+PHONY := _all
+_all:
+
+ifneq ($(KBUILD_OUTPUT),)
+# Invoke a second make in the output directory, passing relevant variables
+# check that the output directory actually exists
+saved-output := $(KBUILD_OUTPUT)
+KBUILD_OUTPUT := $(shell cd $(KBUILD_OUTPUT) && /bin/pwd)
+$(if $(KBUILD_OUTPUT),, \
+ $(error output directory "$(saved-output)" does not exist))
+
+PHONY += $(MAKECMDGOALS)
+
+$(filter-out _all,$(MAKECMDGOALS)) _all:
+ $(if $(KBUILD_VERBOSE:1=),@)$(MAKE) -C $(KBUILD_OUTPUT) \
+ KBUILD_SRC=$(CURDIR) \
+ KBUILD_EXTMOD="$(KBUILD_EXTMOD)" -f $(CURDIR)/Makefile $@
+
+# Leave processing to above invocation of make
+skip-makefile := 1
+endif # ifneq ($(KBUILD_OUTPUT),)
+endif # ifeq ($(KBUILD_SRC),)
+
+# We process the rest of the Makefile if this is the final invocation of make
+ifeq ($(skip-makefile),)
+
+# If building an external module we do not care about the all: rule
+# but instead _all depend on modules
+PHONY += all
+ifeq ($(KBUILD_EXTMOD),)
+_all: all
+else
+_all: modules
+endif
+
+srctree := $(if $(KBUILD_SRC),$(KBUILD_SRC),$(CURDIR))
+TOPDIR := $(srctree)
+# FIXME - TOPDIR is obsolete, use srctree/objtree
+objtree := $(CURDIR)
+src := $(srctree)
+obj := $(objtree)
+
+VPATH := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD))
+
+export srctree objtree VPATH TOPDIR
+
+
+# Cross compiling and selecting different set of gcc/bin-utils
+# ---------------------------------------------------------------------------
+#
+# When performing cross compilation for other architectures ARCH shall be set
+# to the target architecture. (See arch/* for the possibilities).
+# ARCH can be set during invocation of make:
+# make ARCH=ia64
+# Another way is to have ARCH set in the environment.
+# The default ARCH is the host where make is executed.
+
+# CROSS_COMPILE specify the prefix used for all executables used
+# during compilation. Only gcc and related bin-utils executables
+# are prefixed with $(CROSS_COMPILE).
+# CROSS_COMPILE can be set on the command line
+# make CROSS_COMPILE=ia64-linux-
+# Alternatively CROSS_COMPILE can be set in the environment.
+# Default value for CROSS_COMPILE is not to prefix executables
+# Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile
+
+CROSS_COMPILE ?=
+# bbox: we may have CONFIG_CROSS_COMPILER_PREFIX in .config,
+# and it has not been included yet... thus using an awkward syntax.
+ifeq ($(CROSS_COMPILE),)
+CROSS_COMPILE := $(shell grep ^CONFIG_CROSS_COMPILER_PREFIX .config 2>/dev/null)
+CROSS_COMPILE := $(subst CONFIG_CROSS_COMPILER_PREFIX=,,$(CROSS_COMPILE))
+CROSS_COMPILE := $(subst ",,$(CROSS_COMPILE))
+endif
+
+# SUBARCH tells the usermode build what the underlying arch is. That is set
+# first, and if a usermode build is happening, the "ARCH=um" on the command
+# line overrides the setting of ARCH below. If a native build is happening,
+# then ARCH is assigned, getting whatever value it gets normally, and
+# SUBARCH is subsequently ignored.
+
+ifneq ($(CROSS_COMPILE),)
+SUBARCH := $(shell echo $(CROSS_COMPILE) | cut -d- -f1)
+else
+SUBARCH := $(shell uname -m)
+endif
+SUBARCH := $(shell echo $(SUBARCH) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
+ -e s/arm.*/arm/ -e s/sa110/arm/ \
+ -e s/s390x/s390/ -e s/parisc64/parisc/ \
+ -e s/ppc.*/powerpc/ -e s/mips.*/mips/ )
+
+ARCH ?= $(SUBARCH)
+
+# Architecture as present in compile.h
+UTS_MACHINE := $(ARCH)
+
+# SHELL used by kbuild
+CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
+ else if [ -x /bin/bash ]; then echo /bin/bash; \
+ else echo sh; fi ; fi)
+
+# Decide whether to build built-in, modular, or both.
+# Normally, just do built-in.
+
+KBUILD_MODULES :=
+KBUILD_BUILTIN := 1
+
+# If we have only "make modules", don't compile built-in objects.
+# When we're building modules with modversions, we need to consider
+# the built-in objects during the descend as well, in order to
+# make sure the checksums are uptodate before we record them.
+
+ifeq ($(MAKECMDGOALS),modules)
+ KBUILD_BUILTIN := $(if $(CONFIG_MODVERSIONS),1)
+endif
+
+# If we have "make <whatever> modules", compile modules
+# in addition to whatever we do anyway.
+# Just "make" or "make all" shall build modules as well
+
+ifneq ($(filter all _all modules,$(MAKECMDGOALS)),)
+ KBUILD_MODULES := 1
+endif
+
+ifeq ($(MAKECMDGOALS),)
+ KBUILD_MODULES := 1
+endif
+
+export KBUILD_MODULES KBUILD_BUILTIN
+export KBUILD_CHECKSRC KBUILD_SRC KBUILD_EXTMOD
+
+# Beautify output
+# ---------------------------------------------------------------------------
+#
+# Normally, we echo the whole command before executing it. By making
+# that echo $($(quiet)$(cmd)), we now have the possibility to set
+# $(quiet) to choose other forms of output instead, e.g.
+#
+# quiet_cmd_cc_o_c = Compiling $(RELDIR)/$@
+# cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
+#
+# If $(quiet) is empty, the whole command will be printed.
+# If it is set to "quiet_", only the short version will be printed.
+# If it is set to "silent_", nothing wil be printed at all, since
+# the variable $(silent_cmd_cc_o_c) doesn't exist.
+#
+# A simple variant is to prefix commands with $(Q) - that's useful
+# for commands that shall be hidden in non-verbose mode.
+#
+# $(Q)ln $@ :<
+#
+# If KBUILD_VERBOSE equals 0 then the above command will be hidden.
+# If KBUILD_VERBOSE equals 1 then the above command is displayed.
+
+ifeq ($(KBUILD_VERBOSE),1)
+ quiet =
+ Q =
+else
+ quiet=quiet_
+ Q = @
+endif
+
+# If the user is running make -s (silent mode), suppress echoing of
+# commands
+
+ifneq ($(findstring s,$(MAKEFLAGS)),)
+ quiet=silent_
+endif
+
+export quiet Q KBUILD_VERBOSE
+
+
+# Look for make include files relative to root of kernel src
+MAKEFLAGS += --include-dir=$(srctree)
+
+HOSTCC = gcc
+HOSTCXX = g++
+HOSTCFLAGS :=
+HOSTCXXFLAGS :=
+# We need some generic definitions
+include $(srctree)/scripts/Kbuild.include
+
+HOSTCFLAGS += $(call hostcc-option,-Wall -Wstrict-prototypes -O2 -fomit-frame-pointer,)
+HOSTCXXFLAGS += -O2
+
+# For maximum performance (+ possibly random breakage, uncomment
+# the following)
+
+MAKEFLAGS += -rR
+
+# Make variables (CC, etc...)
+
+AS = $(CROSS_COMPILE)as
+CC = $(CROSS_COMPILE)gcc
+LD = $(CC) -nostdlib
+CPP = $(CC) -E
+AR = $(CROSS_COMPILE)ar
+NM = $(CROSS_COMPILE)nm
+STRIP = $(CROSS_COMPILE)strip
+OBJCOPY = $(CROSS_COMPILE)objcopy
+OBJDUMP = $(CROSS_COMPILE)objdump
+AWK = awk
+GENKSYMS = scripts/genksyms/genksyms
+DEPMOD = /sbin/depmod
+KALLSYMS = scripts/kallsyms
+PERL = perl
+CHECK = sparse
+
+CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise $(CF)
+MODFLAGS = -DMODULE
+CFLAGS_MODULE = $(MODFLAGS)
+AFLAGS_MODULE = $(MODFLAGS)
+LDFLAGS_MODULE = -r
+CFLAGS_KERNEL =
+AFLAGS_KERNEL =
+
+
+# Use LINUXINCLUDE when you must reference the include/ directory.
+# Needed to be compatible with the O= option
+CFLAGS := $(CFLAGS)
+# Added only to final link stage of busybox binary
+CFLAGS_busybox := $(CFLAGS_busybox)
+CPPFLAGS := $(CPPFLAGS)
+AFLAGS := $(AFLAGS)
+LDFLAGS := $(LDFLAGS)
+LDLIBS :=
+
+# Read KERNELRELEASE from .kernelrelease (if it exists)
+KERNELRELEASE = $(shell cat .kernelrelease 2> /dev/null)
+KERNELVERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
+
+export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION \
+ ARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC \
+ CPP AR NM STRIP OBJCOPY OBJDUMP MAKE AWK GENKSYMS PERL UTS_MACHINE \
+ HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS
+
+export CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS
+export CFLAGS CFLAGS_KERNEL CFLAGS_MODULE
+export AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
+export FLTFLAGS
+
+# When compiling out-of-tree modules, put MODVERDIR in the module
+# tree rather than in the kernel tree. The kernel tree might
+# even be read-only.
+export MODVERDIR := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_versions
+
+# Files to ignore in find ... statements
+
+RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS -o -name .pc -o -name .hg -o -name .git \) -prune -o
+export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CVS --exclude .pc --exclude .hg --exclude .git
+
+# ===========================================================================
+# Rules shared between *config targets and build targets
+
+# Basic helpers built in scripts/
+PHONY += scripts_basic
+scripts_basic:
+ $(Q)$(MAKE) $(build)=scripts/basic
+
+# To avoid any implicit rule to kick in, define an empty command.
+scripts/basic/%: scripts_basic ;
+
+PHONY += outputmakefile
+# outputmakefile generates a Makefile in the output directory, if using a
+# separate output directory. This allows convenient use of make in the
+# output directory.
+outputmakefile:
+ifneq ($(KBUILD_SRC),)
+ $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \
+ $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
+endif
+
+# To make sure we do not include .config for any of the *config targets
+# catch them early, and hand them over to scripts/kconfig/Makefile
+# It is allowed to specify more targets when calling make, including
+# mixing *config targets and build targets.
+# For example 'make oldconfig all'.
+# Detect when mixed targets is specified, and make a second invocation
+# of make so .config is not included in this case either (for *config).
+
+no-dot-config-targets := clean mrproper distclean \
+ cscope TAGS tags help %docs
+#bbox# check% is removed from above
+
+config-targets := 0
+mixed-targets := 0
+dot-config := 1
+
+ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)
+ ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)
+ dot-config := 0
+ endif
+endif
+
+ifeq ($(KBUILD_EXTMOD),)
+ ifneq ($(filter config %config,$(MAKECMDGOALS)),)
+ config-targets := 1
+ ifneq ($(filter-out config %config,$(MAKECMDGOALS)),)
+ mixed-targets := 1
+ endif
+ endif
+endif
+
+ifeq ($(mixed-targets),1)
+# ===========================================================================
+# We're called with mixed targets (*config and build targets).
+# Handle them one by one.
+
+%:: FORCE
+ $(Q)$(MAKE) -C $(srctree) KBUILD_SRC= $@
+
+else
+ifeq ($(config-targets),1)
+# ===========================================================================
+# *config targets only - make sure prerequisites are updated, and descend
+# in scripts/kconfig to make the *config target
+
+# Read arch specific Makefile to set KBUILD_DEFCONFIG as needed.
+# KBUILD_DEFCONFIG may point out an alternative default configuration
+# used for 'make defconfig'
+-include $(srctree)/arch/$(ARCH)/Makefile
+export KBUILD_DEFCONFIG
+
+config %config: scripts_basic outputmakefile FORCE
+ $(Q)mkdir -p include
+ $(Q)$(MAKE) $(build)=scripts/kconfig $@
+ $(Q)$(MAKE) -C $(srctree) KBUILD_SRC= .kernelrelease
+
+else
+# ===========================================================================
+# Build targets only - this includes busybox, arch specific targets, clean
+# targets and others. In general all targets except *config targets.
+
+ifeq ($(KBUILD_EXTMOD),)
+# Additional helpers built in scripts/
+# Carefully list dependencies so we do not try to build scripts twice
+# in parrallel
+PHONY += scripts
+scripts: scripts_basic include/config/MARKER
+ $(Q)$(MAKE) $(build)=$(@)
+
+scripts_basic: include/autoconf.h
+
+# Objects we will link into busybox / subdirs we need to visit
+core-y := \
+ applets/ \
+
+libs-y := \
+ archival/ \
+ archival/libunarchive/ \
+ console-tools/ \
+ coreutils/ \
+ coreutils/libcoreutils/ \
+ debianutils/ \
+ e2fsprogs/ \
+ editors/ \
+ findutils/ \
+ init/ \
+ libbb/ \
+ libpwdgrp/ \
+ loginutils/ \
+ miscutils/ \
+ modutils/ \
+ networking/ \
+ networking/libiproute/ \
+ networking/udhcp/ \
+ printutils/ \
+ procps/ \
+ runit/ \
+ selinux/ \
+ shell/ \
+ sysklogd/ \
+ util-linux/ \
+ util-linux/volume_id/ \
+
+endif # KBUILD_EXTMOD
+
+ifeq ($(dot-config),1)
+# In this section, we need .config
+
+# Read in dependencies to all Kconfig* files, make sure to run
+# oldconfig if changes are detected.
+-include .kconfig.d
+
+-include .config
+
+# If .config needs to be updated, it will be done via the dependency
+# that autoconf has on .config.
+# To avoid any implicit rule to kick in, define an empty command
+.config .kconfig.d: ;
+
+# Now we can define CFLAGS etc according to .config
+include $(srctree)/Makefile.flags
+
+# If .config is newer than include/autoconf.h, someone tinkered
+# with it and forgot to run make oldconfig.
+# If kconfig.d is missing then we are probarly in a cleaned tree so
+# we execute the config step to be sure to catch updated Kconfig files
+include/autoconf.h: .kconfig.d .config
+ $(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
+
+else
+# Dummy target needed, because used as prerequisite
+include/autoconf.h: ;
+endif
+
+# The all: target is the default when no target is given on the
+# command line.
+# This allow a user to issue only 'make' to build a kernel including modules
+# Defaults busybox but it is usually overridden in the arch makefile
+all: busybox
+
+-include $(srctree)/arch/$(ARCH)/Makefile
+
+# arch Makefile may override CC so keep this after arch Makefile is included
+#bbox# NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include)
+CHECKFLAGS += $(NOSTDINC_FLAGS)
+
+# Default kernel image to build when no specific target is given.
+# KBUILD_IMAGE may be overruled on the commandline or
+# set in the environment
+# Also any assignments in arch/$(ARCH)/Makefile take precedence over
+# this default value
+export KBUILD_IMAGE ?= busybox
+
+#
+# INSTALL_PATH specifies where to place the updated kernel and system map
+# images. Default is /boot, but you can set it to other values
+export INSTALL_PATH ?= /boot
+
+#
+# INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory
+# relocations required by build roots. This is not defined in the
+# makefile but the arguement can be passed to make if needed.
+#
+
+MODLIB = $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)
+export MODLIB
+
+
+ifeq ($(KBUILD_EXTMOD),)
+busybox-dirs := $(patsubst %/,%,$(filter %/, $(core-y) $(core-m) $(libs-y) $(libs-m)))
+
+busybox-alldirs := $(sort $(busybox-dirs) $(patsubst %/,%,$(filter %/, \
+ $(core-n) $(core-) $(libs-n) $(libs-) \
+ )))
+
+core-y := $(patsubst %/, %/built-in.o, $(core-y))
+libs-y1 := $(patsubst %/, %/lib.a, $(libs-y))
+libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y))
+libs-y := $(libs-y1) $(libs-y2)
+
+# Build busybox
+# ---------------------------------------------------------------------------
+# busybox is build from the objects selected by $(busybox-init) and
+# $(busybox-main). Most are built-in.o files from top-level directories
+# in the kernel tree, others are specified in arch/$(ARCH)Makefile.
+# Ordering when linking is important, and $(busybox-init) must be first.
+#
+# busybox
+# ^
+# |
+# +-< $(busybox-init)
+# | +--< init/version.o + more
+# |
+# +--< $(busybox-main)
+# | +--< driver/built-in.o mm/built-in.o + more
+# |
+# +-< kallsyms.o (see description in CONFIG_KALLSYMS section)
+#
+# busybox version (uname -v) cannot be updated during normal
+# descending-into-subdirs phase since we do not yet know if we need to
+# update busybox.
+# Therefore this step is delayed until just before final link of busybox -
+# except in the kallsyms case where it is done just before adding the
+# symbols to the kernel.
+#
+# System.map is generated to document addresses of all kernel symbols
+
+busybox-all := $(core-y) $(libs-y)
+
+# Rule to link busybox - also used during CONFIG_KALLSYMS
+# May be overridden by arch/$(ARCH)/Makefile
+quiet_cmd_busybox__ ?= LINK $@
+ cmd_busybox__ ?= $(srctree)/scripts/trylink \
+ "$@" \
+ "$(CC)" \
+ "$(CFLAGS) $(CFLAGS_busybox)" \
+ "$(LDFLAGS) $(EXTRA_LDFLAGS)" \
+ "$(core-y)" \
+ "$(libs-y)" \
+ "$(LDLIBS)"
+
+# Generate System.map
+quiet_cmd_sysmap = SYSMAP
+ cmd_sysmap = $(CONFIG_SHELL) $(srctree)/scripts/mksysmap
+
+# Link of busybox
+# If CONFIG_KALLSYMS is set .version is already updated
+# Generate System.map and verify that the content is consistent
+# Use + in front of the busybox_version rule to silent warning with make -j2
+# First command is ':' to allow us to use + in front of the rule
+define rule_busybox__
+ :
+ $(call cmd,busybox__)
+ $(Q)echo 'cmd_$@ := $(cmd_busybox__)' > $(@D)/.$(@F).cmd
+endef
+
+
+ifdef CONFIG_KALLSYMS
+# Generate section listing all symbols and add it into busybox $(kallsyms.o)
+# It's a three stage process:
+# o .tmp_busybox1 has all symbols and sections, but __kallsyms is
+# empty
+# Running kallsyms on that gives us .tmp_kallsyms1.o with
+# the right size - busybox version (uname -v) is updated during this step
+# o .tmp_busybox2 now has a __kallsyms section of the right size,
+# but due to the added section, some addresses have shifted.
+# From here, we generate a correct .tmp_kallsyms2.o
+# o The correct .tmp_kallsyms2.o is linked into the final busybox.
+# o Verify that the System.map from busybox matches the map from
+# .tmp_busybox2, just in case we did not generate kallsyms correctly.
+# o If CONFIG_KALLSYMS_EXTRA_PASS is set, do an extra pass using
+# .tmp_busybox3 and .tmp_kallsyms3.o. This is only meant as a
+# temporary bypass to allow the kernel to be built while the
+# maintainers work out what went wrong with kallsyms.
+
+ifdef CONFIG_KALLSYMS_EXTRA_PASS
+last_kallsyms := 3
+else
+last_kallsyms := 2
+endif
+
+kallsyms.o := .tmp_kallsyms$(last_kallsyms).o
+
+define verify_kallsyms
+ $(Q)$(if $($(quiet)cmd_sysmap), \
+ echo ' $($(quiet)cmd_sysmap) .tmp_System.map' &&) \
+ $(cmd_sysmap) .tmp_busybox$(last_kallsyms) .tmp_System.map
+ $(Q)cmp -s System.map .tmp_System.map || \
+ (echo Inconsistent kallsyms data; \
+ echo Try setting CONFIG_KALLSYMS_EXTRA_PASS; \
+ rm .tmp_kallsyms* ; /bin/false )
+endef
+
+# Update busybox version before link
+# Use + in front of this rule to silent warning about make -j1
+# First command is ':' to allow us to use + in front of this rule
+cmd_ksym_ld = $(cmd_busybox__)
+define rule_ksym_ld
+ :
+ +$(call cmd,busybox_version)
+ $(call cmd,busybox__)
+ $(Q)echo 'cmd_$@ := $(cmd_busybox__)' > $(@D)/.$(@F).cmd
+endef
+
+# Generate .S file with all kernel symbols
+quiet_cmd_kallsyms = KSYM $@
+ cmd_kallsyms = $(NM) -n $< | $(KALLSYMS) \
+ $(if $(CONFIG_KALLSYMS_ALL),--all-symbols) > $@
+
+.tmp_kallsyms1.o .tmp_kallsyms2.o .tmp_kallsyms3.o: %.o: %.S scripts FORCE
+ $(call if_changed_dep,as_o_S)
+
+.tmp_kallsyms%.S: .tmp_busybox% $(KALLSYMS)
+ $(call cmd,kallsyms)
+
+# .tmp_busybox1 must be complete except kallsyms, so update busybox version
+.tmp_busybox1: $(busybox-lds) $(busybox-all) FORCE
+ $(call if_changed_rule,ksym_ld)
+
+.tmp_busybox2: $(busybox-lds) $(busybox-all) .tmp_kallsyms1.o FORCE
+ $(call if_changed,busybox__)
+
+.tmp_busybox3: $(busybox-lds) $(busybox-all) .tmp_kallsyms2.o FORCE
+ $(call if_changed,busybox__)
+
+# Needs to visit scripts/ before $(KALLSYMS) can be used.
+$(KALLSYMS): scripts ;
+
+# Generate some data for debugging strange kallsyms problems
+debug_kallsyms: .tmp_map$(last_kallsyms)
+
+.tmp_map%: .tmp_busybox% FORCE
+ ($(OBJDUMP) -h $< | $(AWK) '/^ +[0-9]/{print $$4 " 0 " $$2}'; $(NM) $<) | sort > $@
+
+.tmp_map3: .tmp_map2
+
+.tmp_map2: .tmp_map1
+
+endif # ifdef CONFIG_KALLSYMS
+
+# busybox image - including updated kernel symbols
+busybox_unstripped: $(busybox-all) FORCE
+ $(call if_changed_rule,busybox__)
+ $(Q)rm -f .old_version
+
+busybox: busybox_unstripped
+ifeq ($(SKIP_STRIP),y)
+ $(Q)cp $< $@
+else
+ $(Q)$(STRIP) -s --remove-section=.note --remove-section=.comment \
+ busybox_unstripped -o $@
+# strip is confused by PIE executable and does not set exec bits
+ $(Q)chmod a+x $@
+endif
+
+# The actual objects are generated when descending,
+# make sure no implicit rule kicks in
+$(sort $(busybox-all)): $(busybox-dirs) ;
+
+# Handle descending into subdirectories listed in $(busybox-dirs)
+# Preset locale variables to speed up the build process. Limit locale
+# tweaks to this spot to avoid wrong language settings when running
+# make menuconfig etc.
+# Error messages still appears in the original language
+
+PHONY += $(busybox-dirs)
+$(busybox-dirs): prepare scripts
+ $(Q)$(MAKE) $(build)=$@
+
+# Build the kernel release string
+# The KERNELRELEASE is stored in a file named .kernelrelease
+# to be used when executing for example make install or make modules_install
+#
+# Take the contents of any files called localversion* and the config
+# variable CONFIG_LOCALVERSION and append them to KERNELRELEASE.
+# LOCALVERSION from the command line override all of this
+
+nullstring :=
+space := $(nullstring) # end of line
+
+___localver = $(objtree)/localversion* $(srctree)/localversion*
+__localver = $(sort $(wildcard $(___localver)))
+# skip backup files (containing '~')
+_localver = $(foreach f, $(__localver), $(if $(findstring ~, $(f)),,$(f)))
+
+localver = $(subst $(space),, \
+ $(shell cat /dev/null $(_localver)) \
+ $(patsubst "%",%,$(CONFIG_LOCALVERSION)))
+
+# If CONFIG_LOCALVERSION_AUTO is set scripts/setlocalversion is called
+# and if the SCM is know a tag from the SCM is appended.
+# The appended tag is determinded by the SCM used.
+#
+# Currently, only git is supported.
+# Other SCMs can edit scripts/setlocalversion and add the appropriate
+# checks as needed.
+ifdef _BB_DISABLED_CONFIG_LOCALVERSION_AUTO
+ _localver-auto = $(shell $(CONFIG_SHELL) \
+ $(srctree)/scripts/setlocalversion $(srctree))
+ localver-auto = $(LOCALVERSION)$(_localver-auto)
+endif
+
+localver-full = $(localver)$(localver-auto)
+
+# Store (new) KERNELRELASE string in .kernelrelease
+kernelrelease = $(KERNELVERSION)$(localver-full)
+.kernelrelease: FORCE
+ $(Q)rm -f $@
+ $(Q)echo $(kernelrelease) > $@
+
+
+# Things we need to do before we recursively start building the kernel
+# or the modules are listed in "prepare".
+# A multi level approach is used. prepareN is processed before prepareN-1.
+# archprepare is used in arch Makefiles and when processed asm symlink,
+# version.h and scripts_basic is processed / created.
+
+# Listed in dependency order
+PHONY += prepare archprepare prepare0 prepare1 prepare2 prepare3
+
+# prepare-all is deprecated, use prepare as valid replacement
+PHONY += prepare-all
+
+# prepare3 is used to check if we are building in a separate output directory,
+# and if so do:
+# 1) Check that make has not been executed in the kernel src $(srctree)
+# 2) Create the include2 directory, used for the second asm symlink
+prepare3: .kernelrelease
+ifneq ($(KBUILD_SRC),)
+ @echo ' Using $(srctree) as source for busybox'
+ $(Q)if [ -f $(srctree)/.config ]; then \
+ echo " $(srctree) is not clean, please run 'make mrproper'";\
+ echo " in the '$(srctree)' directory.";\
+ /bin/false; \
+ fi;
+ $(Q)if [ ! -d include2 ]; then mkdir -p include2; fi;
+ $(Q)ln -fsn $(srctree)/include/asm-$(ARCH) include2/asm
+endif
+
+# prepare2 creates a makefile if using a separate output directory
+prepare2: prepare3 outputmakefile
+
+prepare1: prepare2 include/config/MARKER
+ifneq ($(KBUILD_MODULES),)
+ $(Q)mkdir -p $(MODVERDIR)
+ $(Q)rm -f $(MODVERDIR)/*
+endif
+
+archprepare: prepare1 scripts_basic
+
+prepare0: archprepare FORCE
+ $(Q)$(MAKE) $(build)=.
+
+# All the preparing..
+prepare prepare-all: prepare0
+
+# Leave this as default for preprocessing busybox.lds.S, which is now
+# done in arch/$(ARCH)/kernel/Makefile
+
+export CPPFLAGS_busybox.lds += -P -C -U$(ARCH)
+
+# FIXME: The asm symlink changes when $(ARCH) changes. That's
+# hard to detect, but I suppose "make mrproper" is a good idea
+# before switching between archs anyway.
+
+#bbox# include/asm:
+#bbox# @echo ' SYMLINK $@ -> include/asm-$(ARCH)'
+#bbox# $(Q)if [ ! -d include ]; then mkdir -p include; fi;
+#bbox# @ln -fsn asm-$(ARCH) $@
+
+# Split autoconf.h into include/linux/config/*
+quiet_cmd_gen_bbconfigopts = GEN include/bbconfigopts.h
+ cmd_gen_bbconfigopts = $(srctree)/scripts/mkconfigs > include/bbconfigopts.h
+quiet_cmd_split_autoconf = SPLIT include/autoconf.h -> include/config/*
+ cmd_split_autoconf = scripts/basic/split-include include/autoconf.h include/config
+#bbox# piggybacked generation of few .h files
+include/config/MARKER: scripts/basic/split-include include/autoconf.h
+ $(call cmd,split_autoconf)
+ $(call cmd,gen_bbconfigopts)
+ @touch $@
+
+# Generate some files
+# ---------------------------------------------------------------------------
+
+# KERNELRELEASE can change from a few different places, meaning version.h
+# needs to be updated, so this check is forced on all builds
+
+uts_len := 64
+
+define filechk_version.h
+ if [ `echo -n "$(KERNELRELEASE)" | wc -c ` -gt $(uts_len) ]; then \
+ echo '"$(KERNELRELEASE)" exceeds $(uts_len) characters' >&2; \
+ exit 1; \
+ fi; \
+ (echo \#define UTS_RELEASE \"$(KERNELRELEASE)\"; \
+ echo \#define LINUX_VERSION_CODE `expr $(VERSION) \\* 65536 + $(PATCHLEVEL) \\* 256 + $(SUBLEVEL)`; \
+ echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))'; \
+ )
+endef
+
+# ---------------------------------------------------------------------------
+
+PHONY += depend dep
+depend dep:
+ @echo '*** Warning: make $@ is unnecessary now.'
+
+# ---------------------------------------------------------------------------
+# Modules
+
+ifdef _BB_DISABLED_CONFIG_MODULES
+
+# By default, build modules as well
+
+all: modules
+
+# Build modules
+
+PHONY += modules
+modules: $(busybox-dirs) $(if $(KBUILD_BUILTIN),busybox)
+ @echo ' Building modules, stage 2.';
+ $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modpost
+
+
+# Target to prepare building external modules
+PHONY += modules_prepare
+modules_prepare: prepare scripts
+
+# Target to install modules
+PHONY += modules_install
+modules_install: _modinst_ _modinst_post
+
+PHONY += _modinst_
+_modinst_:
+ @if [ -z "`$(DEPMOD) -V 2>/dev/null | grep module-init-tools`" ]; then \
+ echo "Warning: you may need to install module-init-tools"; \
+ echo "See http://www.codemonkey.org.uk/docs/post-halloween-2.6.txt";\
+ sleep 1; \
+ fi
+ @rm -rf $(MODLIB)/kernel
+ @rm -f $(MODLIB)/source
+ @mkdir -p $(MODLIB)/kernel
+ @ln -s $(srctree) $(MODLIB)/source
+ @if [ ! $(objtree) -ef $(MODLIB)/build ]; then \
+ rm -f $(MODLIB)/build ; \
+ ln -s $(objtree) $(MODLIB)/build ; \
+ fi
+ $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modinst
+
+# If System.map exists, run depmod. This deliberately does not have a
+# dependency on System.map since that would run the dependency tree on
+# busybox. This depmod is only for convenience to give the initial
+# boot a modules.dep even before / is mounted read-write. However the
+# boot script depmod is the master version.
+ifeq "$(strip $(INSTALL_MOD_PATH))" ""
+depmod_opts :=
+else
+depmod_opts := -b $(INSTALL_MOD_PATH) -r
+endif
+PHONY += _modinst_post
+_modinst_post: _modinst_
+ if [ -r System.map -a -x $(DEPMOD) ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi
+
+else # CONFIG_MODULES
+
+# Modules not configured
+# ---------------------------------------------------------------------------
+
+modules modules_install: FORCE
+ @echo
+ @echo "The present busybox configuration has modules disabled."
+ @echo "Type 'make config' and enable loadable module support."
+ @echo "Then build a kernel with module support enabled."
+ @echo
+ @exit 1
+
+endif # CONFIG_MODULES
+
+###
+# Cleaning is done on three levels.
+# make clean Delete most generated files
+# Leave enough to build external modules
+# make mrproper Delete the current configuration, and all generated files
+# make distclean Remove editor backup files, patch leftover files and the like
+
+# Directories & files removed with 'make clean'
+CLEAN_DIRS += $(MODVERDIR)
+CLEAN_FILES += busybox busybox_unstripped* System.map .kernelrelease \
+ .tmp_kallsyms* .tmp_version .tmp_busybox* .tmp_System.map
+
+# Directories & files removed with 'make mrproper'
+MRPROPER_DIRS += include/config include2
+MRPROPER_FILES += .config .config.old include/asm .version .old_version \
+ include/autoconf.h \
+ include/bbconfigopts.h \
+ include/usage_compressed.h \
+ include/applet_tables.h \
+ applets/usage \
+ .kernelrelease Module.symvers tags TAGS cscope*
+
+# clean - Delete most, but leave enough to build external modules
+#
+clean: rm-dirs := $(CLEAN_DIRS)
+clean: rm-files := $(CLEAN_FILES)
+clean-dirs := $(addprefix _clean_,$(srctree) $(busybox-alldirs))
+
+PHONY += $(clean-dirs) clean archclean
+$(clean-dirs):
+ $(Q)$(MAKE) $(clean)=$(patsubst _clean_%,%,$@)
+
+clean: archclean $(clean-dirs)
+ $(call cmd,rmdirs)
+ $(call cmd,rmfiles)
+ @find . $(RCS_FIND_IGNORE) \
+ \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
+ -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \) \
+ -type f -print | xargs rm -f
+
+# mrproper - Delete all generated files, including .config
+#
+mrproper: rm-dirs := $(wildcard $(MRPROPER_DIRS))
+mrproper: rm-files := $(wildcard $(MRPROPER_FILES))
+mrproper-dirs := $(addprefix _mrproper_,scripts)
+
+PHONY += $(mrproper-dirs) mrproper archmrproper
+$(mrproper-dirs):
+ $(Q)$(MAKE) $(clean)=$(patsubst _mrproper_%,%,$@)
+
+mrproper: clean archmrproper $(mrproper-dirs)
+ $(call cmd,rmdirs)
+ $(call cmd,rmfiles)
+
+# distclean
+#
+PHONY += distclean
+
+distclean: mrproper
+ @find $(srctree) $(RCS_FIND_IGNORE) \
+ \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
+ -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
+ -o -name '.*.rej' -o -name '*.tmp' -o -size 0 \
+ -o -name '*%' -o -name '.*.cmd' -o -name 'core' \) \
+ -type f -print | xargs rm -f
+
+
+# Packaging of the kernel to various formats
+# ---------------------------------------------------------------------------
+# rpm target kept for backward compatibility
+package-dir := $(srctree)/scripts/package
+
+%pkg: FORCE
+ $(Q)$(MAKE) $(build)=$(package-dir) $@
+rpm: FORCE
+ $(Q)$(MAKE) $(build)=$(package-dir) $@
+
+
+# Brief documentation of the typical targets used
+# ---------------------------------------------------------------------------
+
+boards := $(wildcard $(srctree)/arch/$(ARCH)/configs/*_defconfig)
+boards := $(notdir $(boards))
+
+-include $(srctree)/Makefile.help
+
+# Documentation targets
+# ---------------------------------------------------------------------------
+%docs: scripts_basic FORCE
+ $(Q)$(MAKE) $(build)=Documentation/DocBook $@
+
+else # KBUILD_EXTMOD
+
+###
+# External module support.
+# When building external modules the kernel used as basis is considered
+# read-only, and no consistency checks are made and the make
+# system is not used on the basis kernel. If updates are required
+# in the basis kernel ordinary make commands (without M=...) must
+# be used.
+#
+# The following are the only valid targets when building external
+# modules.
+# make M=dir clean Delete all automatically generated files
+# make M=dir modules Make all modules in specified dir
+# make M=dir Same as 'make M=dir modules'
+# make M=dir modules_install
+# Install the modules build in the module directory
+# Assumes install directory is already created
+
+# We are always building modules
+KBUILD_MODULES := 1
+PHONY += crmodverdir
+crmodverdir:
+ $(Q)mkdir -p $(MODVERDIR)
+ $(Q)rm -f $(MODVERDIR)/*
+
+PHONY += $(objtree)/Module.symvers
+$(objtree)/Module.symvers:
+ @test -e $(objtree)/Module.symvers || ( \
+ echo; \
+ echo " WARNING: Symbol version dump $(objtree)/Module.symvers"; \
+ echo " is missing; modules will have no dependencies and modversions."; \
+ echo )
+
+module-dirs := $(addprefix _module_,$(KBUILD_EXTMOD))
+PHONY += $(module-dirs) modules
+$(module-dirs): crmodverdir $(objtree)/Module.symvers
+ $(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@)
+
+modules: $(module-dirs)
+ @echo ' Building modules, stage 2.';
+ $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modpost
+
+PHONY += modules_install
+modules_install: _emodinst_ _emodinst_post
+
+install-dir := $(if $(INSTALL_MOD_DIR),$(INSTALL_MOD_DIR),extra)
+PHONY += _emodinst_
+_emodinst_:
+ $(Q)mkdir -p $(MODLIB)/$(install-dir)
+ $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modinst
+
+# Run depmod only is we have System.map and depmod is executable
+quiet_cmd_depmod = DEPMOD $(KERNELRELEASE)
+ cmd_depmod = if [ -r System.map -a -x $(DEPMOD) ]; then \
+ $(DEPMOD) -ae -F System.map \
+ $(if $(strip $(INSTALL_MOD_PATH)), \
+ -b $(INSTALL_MOD_PATH) -r) \
+ $(KERNELRELEASE); \
+ fi
+
+PHONY += _emodinst_post
+_emodinst_post: _emodinst_
+ $(call cmd,depmod)
+
+clean-dirs := $(addprefix _clean_,$(KBUILD_EXTMOD))
+
+PHONY += $(clean-dirs) clean
+$(clean-dirs):
+ $(Q)$(MAKE) $(clean)=$(patsubst _clean_%,%,$@)
+
+clean: rm-dirs := $(MODVERDIR)
+clean: $(clean-dirs)
+ $(call cmd,rmdirs)
+ @find $(KBUILD_EXTMOD) $(RCS_FIND_IGNORE) \
+ \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
+ -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \) \
+ -type f -print | xargs rm -f
+
+help:
+ @echo ' Building external modules.'
+ @echo ' Syntax: make -C path/to/kernel/src M=$$PWD target'
+ @echo ''
+ @echo ' modules - default target, build the module(s)'
+ @echo ' modules_install - install the module'
+ @echo ' clean - remove generated files in module directory only'
+ @echo ''
+
+# Dummies...
+PHONY += prepare scripts
+prepare: ;
+scripts: ;
+endif # KBUILD_EXTMOD
+
+# Generate tags for editors
+# ---------------------------------------------------------------------------
+
+#We want __srctree to totally vanish out when KBUILD_OUTPUT is not set
+#(which is the most common case IMHO) to avoid unneeded clutter in the big tags file.
+#Adding $(srctree) adds about 20M on i386 to the size of the output file!
+
+ifeq ($(src),$(obj))
+__srctree =
+else
+__srctree = $(srctree)/
+endif
+
+ifeq ($(ALLSOURCE_ARCHS),)
+ifeq ($(ARCH),um)
+ALLINCLUDE_ARCHS := $(ARCH) $(SUBARCH)
+else
+ALLINCLUDE_ARCHS := $(ARCH)
+endif
+else
+#Allow user to specify only ALLSOURCE_PATHS on the command line, keeping existing behaviour.
+ALLINCLUDE_ARCHS := $(ALLSOURCE_ARCHS)
+endif
+
+ALLSOURCE_ARCHS := $(ARCH)
+
+define all-sources
+ ( find $(__srctree) $(RCS_FIND_IGNORE) \
+ \( -name include -o -name arch \) -prune -o \
+ -name '*.[chS]' -print; \
+ for ARCH in $(ALLSOURCE_ARCHS) ; do \
+ find $(__srctree)arch/$${ARCH} $(RCS_FIND_IGNORE) \
+ -name '*.[chS]' -print; \
+ done ; \
+ find $(__srctree)security/selinux/include $(RCS_FIND_IGNORE) \
+ -name '*.[chS]' -print; \
+ find $(__srctree)include $(RCS_FIND_IGNORE) \
+ \( -name config -o -name 'asm-*' \) -prune \
+ -o -name '*.[chS]' -print; \
+ for ARCH in $(ALLINCLUDE_ARCHS) ; do \
+ find $(__srctree)include/asm-$${ARCH} $(RCS_FIND_IGNORE) \
+ -name '*.[chS]' -print; \
+ done ; \
+ find $(__srctree)include/asm-generic $(RCS_FIND_IGNORE) \
+ -name '*.[chS]' -print )
+endef
+
+quiet_cmd_cscope-file = FILELST cscope.files
+ cmd_cscope-file = (echo \-k; echo \-q; $(all-sources)) > cscope.files
+
+quiet_cmd_cscope = MAKE cscope.out
+ cmd_cscope = cscope -b
+
+cscope: FORCE
+ $(call cmd,cscope-file)
+ $(call cmd,cscope)
+
+quiet_cmd_TAGS = MAKE $@
+define cmd_TAGS
+ rm -f $@; \
+ ETAGSF=`etags --version | grep -i exuberant >/dev/null && \
+ echo "-I __initdata,__exitdata,__acquires,__releases \
+ -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL \
+ --extra=+f --c-kinds=+px"`; \
+ $(all-sources) | xargs etags $$ETAGSF -a
+endef
+
+TAGS: FORCE
+ $(call cmd,TAGS)
+
+
+quiet_cmd_tags = MAKE $@
+define cmd_tags
+ rm -f $@; \
+ CTAGSF=`ctags --version | grep -i exuberant >/dev/null && \
+ echo "-I __initdata,__exitdata,__acquires,__releases \
+ -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL \
+ --extra=+f --c-kinds=+px"`; \
+ $(all-sources) | xargs ctags $$CTAGSF -a
+endef
+
+tags: FORCE
+ $(call cmd,tags)
+
+
+# Scripts to check various things for consistency
+# ---------------------------------------------------------------------------
+
+includecheck:
+ find * $(RCS_FIND_IGNORE) \
+ -name '*.[hcS]' -type f -print | sort \
+ | xargs $(PERL) -w scripts/checkincludes.pl
+
+versioncheck:
+ find * $(RCS_FIND_IGNORE) \
+ -name '*.[hcS]' -type f -print | sort \
+ | xargs $(PERL) -w scripts/checkversion.pl
+
+namespacecheck:
+ $(PERL) $(srctree)/scripts/namespace.pl
+
+endif #ifeq ($(config-targets),1)
+endif #ifeq ($(mixed-targets),1)
+
+PHONY += checkstack
+checkstack:
+ $(OBJDUMP) -d busybox $$(find . -name '*.ko') | \
+ $(PERL) $(src)/scripts/checkstack.pl $(ARCH)
+
+kernelrelease:
+ $(if $(wildcard .kernelrelease), $(Q)echo $(KERNELRELEASE), \
+ $(error kernelrelease not valid - run 'make *config' to update it))
+kernelversion:
+ @echo $(KERNELVERSION)
+
+# Single targets
+# ---------------------------------------------------------------------------
+# Single targets are compatible with:
+# - build whith mixed source and output
+# - build with separate output dir 'make O=...'
+# - external modules
+#
+# target-dir => where to store outputfile
+# build-dir => directory in kernel source tree to use
+
+ifeq ($(KBUILD_EXTMOD),)
+ build-dir = $(patsubst %/,%,$(dir $@))
+ target-dir = $(dir $@)
+else
+ zap-slash=$(filter-out .,$(patsubst %/,%,$(dir $@)))
+ build-dir = $(KBUILD_EXTMOD)$(if $(zap-slash),/$(zap-slash))
+ target-dir = $(if $(KBUILD_EXTMOD),$(dir $<),$(dir $@))
+endif
+
+%.s: %.c prepare scripts FORCE
+ $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
+%.i: %.c prepare scripts FORCE
+ $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
+%.o: %.c prepare scripts FORCE
+ $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
+%.lst: %.c prepare scripts FORCE
+ $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
+%.s: %.S prepare scripts FORCE
+ $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
+%.o: %.S prepare scripts FORCE
+ $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
+
+# Modules
+/ %/: prepare scripts FORCE
+ $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \
+ $(build)=$(build-dir)
+%.ko: prepare scripts FORCE
+ $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \
+ $(build)=$(build-dir) $(@:.ko=.o)
+ $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modpost
+
+# FIXME Should go into a make.lib or something
+# ===========================================================================
+
+quiet_cmd_rmdirs = $(if $(wildcard $(rm-dirs)),CLEAN $(wildcard $(rm-dirs)))
+ cmd_rmdirs = rm -rf $(rm-dirs)
+
+quiet_cmd_rmfiles = $(if $(wildcard $(rm-files)),CLEAN $(wildcard $(rm-files)))
+ cmd_rmfiles = rm -f $(rm-files)
+
+
+a_flags = -Wp,-MD,$(depfile) $(AFLAGS) $(AFLAGS_KERNEL) \
+ $(NOSTDINC_FLAGS) $(CPPFLAGS) \
+ $(modkern_aflags) $(EXTRA_AFLAGS) $(AFLAGS_$(*F).o)
+
+quiet_cmd_as_o_S = AS $@
+cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $<
+
+# read all saved command lines
+
+targets := $(wildcard $(sort $(targets)))
+cmd_files := $(wildcard .*.cmd $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd))
+
+ifneq ($(cmd_files),)
+ $(cmd_files): ; # Do not try to update included dependency files
+ include $(cmd_files)
+endif
+
+# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.clean obj=dir
+# Usage:
+# $(Q)$(MAKE) $(clean)=dir
+clean := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.clean obj
+
+endif # skip-makefile
+
+PHONY += FORCE
+FORCE:
+
+-include $(srctree)/Makefile.custom
+
+# Declare the contents of the .PHONY variable as phony. We keep that
+# information in a variable se we can use it in if_changed and friends.
+.PHONY: $(PHONY)
diff --git a/cleopatre/busybox-1.11.1-spc300/Makefile.custom b/cleopatre/busybox-1.11.1-spc300/Makefile.custom
new file mode 100644
index 0000000000..58a979e112
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/Makefile.custom
@@ -0,0 +1,165 @@
+# ==========================================================================
+# Build system
+# ==========================================================================
+
+busybox.links: $(srctree)/applets/busybox.mkll $(objtree)/include/autoconf.h $(srctree)/include/applets.h
+ $(Q)-$(SHELL) $^ >$@
+
+.PHONY: install
+ifeq ($(CONFIG_INSTALL_APPLET_SYMLINKS),y)
+INSTALL_OPTS:= --symlinks
+endif
+ifeq ($(CONFIG_INSTALL_APPLET_HARDLINKS),y)
+INSTALL_OPTS:= --hardlinks
+endif
+ifeq ($(CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS),y)
+ifeq ($(CONFIG_INSTALL_SH_APPLET_SYMLINK),y)
+INSTALL_OPTS:= --sw-sh-sym
+endif
+ifeq ($(CONFIG_INSTALL_SH_APPLET_HARDLINK),y)
+INSTALL_OPTS:= --sw-sh-hard
+endif
+ifeq ($(CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER),y)
+INSTALL_OPTS:= --scriptwrapper
+endif
+endif
+install: $(srctree)/applets/install.sh busybox busybox.links
+ $(Q)DO_INSTALL_LIBS="$(strip $(LIBBUSYBOX_SONAME) $(DO_INSTALL_LIBS))" \
+ $(SHELL) $< $(CONFIG_PREFIX) $(INSTALL_OPTS)
+ifeq ($(strip $(CONFIG_FEATURE_SUID)),y)
+ @echo
+ @echo
+ @echo --------------------------------------------------
+ @echo You will probably need to make your busybox binary
+ @echo setuid root to ensure all configured applets will
+ @echo work properly.
+ @echo --------------------------------------------------
+ @echo
+endif
+
+uninstall: busybox.links
+ rm -f $(CONFIG_PREFIX)/bin/busybox
+ for i in `cat busybox.links` ; do rm -f $(CONFIG_PREFIX)$$i; done
+ifneq ($(strip $(DO_INSTALL_LIBS)),n)
+ for i in $(LIBBUSYBOX_SONAME) $(DO_INSTALL_LIBS); do \
+ rm -f $(CONFIG_PREFIX)$$i; \
+ done
+endif
+
+# Not very elegant: copies testsuite to objdir...
+# (cp -pPR is POSIX-compliant (cp -dpR or cp -a would not be))
+.PHONY: check
+.PHONY: test
+check test: busybox busybox.links
+ test -d $(objtree)/testsuite || cp -pPR $(srctree)/testsuite $(objtree)
+ bindir=$(objtree) srcdir=$(srctree)/testsuite \
+ $(SHELL) -c "cd $(objtree)/testsuite && $(srctree)/testsuite/runtest $(if $(KBUILD_VERBOSE:0=),-v)"
+
+.PHONY: release
+release: distclean
+ cd ..; \
+ rm -r -f busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION); \
+ cp -pPR busybox busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) && { \
+ find busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)/ -type d \
+ -name .svn \
+ -print \
+ -exec rm -r -f {} \; ; \
+ find busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)/ -type f \
+ -name .\#* \
+ -print \
+ -exec rm -f {} \; ; \
+ tar -czf busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION).tar.gz \
+ busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)/ ; }
+
+.PHONY: checkhelp
+checkhelp:
+ $(Q)$(srctree)/scripts/checkhelp.awk \
+ $(patsubst %,$(srctree)/%,$(wildcard $(patsubst %,%/Config.in,$(busybox-dirs) ./)))
+
+.PHONY: sizes
+sizes: busybox_unstripped
+ $(NM) --size-sort $(<)
+
+.PHONY: bloatcheck
+bloatcheck: busybox_old busybox_unstripped
+ @$(srctree)/scripts/bloat-o-meter busybox_old busybox_unstripped
+ @$(CROSS_COMPILE)size busybox_old busybox_unstripped
+
+.PHONY: baseline
+baseline: busybox_unstripped
+ @mv busybox_unstripped busybox_old
+
+.PHONY: objsizes
+objsizes: busybox_unstripped
+ $(srctree)/scripts/objsizes
+
+.PHONY: stksizes
+stksizes: busybox_unstripped
+ $(CROSS_COMPILE)objdump -d busybox_unstripped | $(srctree)/scripts/checkstack.pl $(ARCH) | uniq
+
+.PHONY: bigdata
+bigdata: busybox_unstripped
+ $(CROSS_COMPILE)nm --size-sort busybox_unstripped | grep -vi ' [trw] '
+
+# Documentation Targets
+.PHONY: doc
+doc: docs/busybox.pod docs/BusyBox.txt docs/BusyBox.1 docs/BusyBox.html
+
+docs/busybox.pod: $(srctree)/docs/busybox_header.pod \
+ $(srctree)/include/usage.h \
+ $(srctree)/docs/busybox_footer.pod \
+ $(srctree)/docs/autodocifier.pl
+ $(disp_doc)
+ $(Q)-mkdir -p docs
+ $(Q)-( cat $(srctree)/docs/busybox_header.pod ; \
+ $(srctree)/docs/autodocifier.pl $(srctree)/include/usage.h ; \
+ cat $(srctree)/docs/busybox_footer.pod ; ) > docs/busybox.pod
+
+docs/BusyBox.txt: docs/busybox.pod
+ $(disp_doc)
+ $(Q)-mkdir -p docs
+ $(Q)-pod2text $< > $@
+
+docs/BusyBox.1: docs/busybox.pod
+ $(disp_doc)
+ $(Q)-mkdir -p docs
+ $(Q)-pod2man --center=BusyBox --release="version $(VERSION)" \
+ $< > $@
+
+docs/BusyBox.html: docs/busybox.net/BusyBox.html
+ $(disp_doc)
+ $(Q)-mkdir -p docs
+ $(Q)-rm -f docs/BusyBox.html
+ $(Q)-cp docs/busybox.net/BusyBox.html docs/BusyBox.html
+
+docs/busybox.net/BusyBox.html: docs/busybox.pod
+ $(Q)-mkdir -p docs/busybox.net
+ $(Q)-pod2html --noindex $< > \
+ docs/busybox.net/BusyBox.html
+ $(Q)-rm -f pod2htm*
+
+# documentation, cross-reference
+# Modern distributions already ship synopsis packages (e.g. debian)
+# If you have an old distribution go to http://synopsis.fresco.org/
+syn_tgt = $(wildcard $(patsubst %,%/*.c,$(busybox-alldirs)))
+syn = $(patsubst %.c, %.syn, $(syn_tgt))
+
+comma:= ,
+brace_open:= (
+brace_close:= )
+
+SYN_CPPFLAGS := $(strip $(CPPFLAGS) $(EXTRA_CPPFLAGS))
+SYN_CPPFLAGS := $(subst $(brace_open),\$(brace_open),$(SYN_CPPFLAGS))
+SYN_CPPFLAGS := $(subst $(brace_close),\$(brace_close),$(SYN_CPPFLAGS))
+#SYN_CPPFLAGS := $(subst ",\",$(SYN_CPPFLAGS))
+#")
+#SYN_CPPFLAGS := [$(patsubst %,'%'$(comma),$(SYN_CPPFLAGS))'']
+
+%.syn: %.c
+ synopsis -p C -l Comments.SSDFilter,Comments.Previous -Wp,preprocess=True,cppflags="'$(SYN_CPPFLAGS)'" -o $@ $<
+
+.PHONY: html
+html: $(syn)
+ synopsis -f HTML -Wf,title="'BusyBox Documentation'" -o $@ $^
+
+-include $(srctree)/Makefile.local
diff --git a/cleopatre/busybox-1.11.1-spc300/Makefile.flags b/cleopatre/busybox-1.11.1-spc300/Makefile.flags
new file mode 100644
index 0000000000..0ffc05c355
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/Makefile.flags
@@ -0,0 +1,115 @@
+# ==========================================================================
+# Build system
+# ==========================================================================
+
+BB_VER = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
+export BB_VER
+SKIP_STRIP = n
+
+# -std=gnu99 needed for [U]LLONG_MAX on some systems
+CPPFLAGS += $(call cc-option,-std=gnu99,)
+
+CPPFLAGS += \
+ -Iinclude -Ilibbb \
+ $(if $(KBUILD_SRC),-Iinclude2 -I$(srctree)/include -I$(srctree)/libbb) \
+ -include include/autoconf.h \
+ -D_GNU_SOURCE -DNDEBUG \
+ $(if $(CONFIG_LFS),-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64) \
+ -D"BB_VER=KBUILD_STR($(BB_VER))" -DBB_BT=AUTOCONF_TIMESTAMP
+
+CFLAGS += $(call cc-option,-Wall,)
+CFLAGS += $(call cc-option,-Wshadow,)
+CFLAGS += $(call cc-option,-Wwrite-strings,)
+CFLAGS += $(call cc-option,-Wundef,)
+CFLAGS += $(call cc-option,-Wstrict-prototypes,)
+CFLAGS += $(call cc-option,-Wunused -Wunused-parameter,)
+CFLAGS += $(call cc-option,-Wmissing-prototypes -Wmissing-declarations,)
+# warn about C99 declaration after statement
+CFLAGS += $(call cc-option,-Wdeclaration-after-statement,)
+# If you want to add more -Wsomething above, make sure that it is
+# still possible to build bbox without warnings.
+
+ifeq ($(CONFIG_WERROR),y)
+CFLAGS += $(call cc-option,-Werror,)
+endif
+# gcc 3.x emits bogus "old style proto" warning on find.c:alloc_action()
+CFLAGS += $(call cc-ifversion, -ge, 0400, -Wold-style-definition)
+
+CFLAGS += $(call cc-option,-fno-builtin-strlen -finline-limit=0 -fomit-frame-pointer -ffunction-sections -fdata-sections,)
+# -fno-guess-branch-probability: prohibit pseudo-random guessing
+# of branch probabilities (hopefully makes bloatcheck more stable):
+CFLAGS += $(call cc-option,-fno-guess-branch-probability,)
+CFLAGS += $(call cc-option,-funsigned-char -static-libgcc,)
+CFLAGS += $(call cc-option,-falign-functions=1 -falign-jumps=1 -falign-labels=1 -falign-loops=1,)
+
+# FIXME: These warnings are at least partially to be concerned about and should
+# be fixed..
+#CFLAGS+=$(call cc-option,-Wconversion,)
+
+ifneq ($(CONFIG_DEBUG),y)
+CFLAGS += $(call cc-option,-Os,)
+else
+CFLAGS += $(call cc-option,-g,)
+ifeq ($(CONFIG_DEBUG_PESSIMIZE),y)
+CFLAGS += $(call cc-option,-O0,)
+else
+CFLAGS += $(call cc-option,-Os,)
+endif
+endif
+
+# If arch/$(ARCH)/Makefile did not override it (with, say, -fPIC)...
+ARCH_FPIC ?= -fpic
+ARCH_FPIE ?= -fpie
+ARCH_PIE ?= -pie
+
+ifeq ($(CONFIG_BUILD_LIBBUSYBOX),y)
+# on i386: 14% smaller libbusybox.so
+# (code itself is 9% bigger, we save on relocs/PLT/GOT)
+CFLAGS += $(ARCH_FPIC)
+# and another 4% reduction of libbusybox.so:
+# (external entry points must be marked EXTERNALLY_VISIBLE)
+CFLAGS += $(call cc-option,-fvisibility=hidden)
+endif
+
+ifeq ($(CONFIG_STATIC),y)
+CFLAGS_busybox += -static
+endif
+
+ifeq ($(CONFIG_PIE),y)
+CFLAGS_busybox += $(ARCH_PIE)
+CFLAGS += $(ARCH_FPIE)
+endif
+
+LDLIBS += m crypt
+
+ifeq ($(CONFIG_PAM),y)
+LDLIBS += pam pam_misc
+endif
+
+ifeq ($(CONFIG_SELINUX),y)
+LDLIBS += selinux sepol
+endif
+
+ifeq ($(CONFIG_EFENCE),y)
+LDLIBS += efence
+endif
+
+ifeq ($(CONFIG_DMALLOC),y)
+LDLIBS += dmalloc
+endif
+
+# If a flat binary should be built, CFLAGS_busybox="-Wl,-elf2flt"
+# env var should be set for make invocation.
+# Here we check whether CFLAGS_busybox indeed contains that flag.
+# (For historical reasons, we also check LDFLAGS, which doesn't
+# seem to be entirely correct variable to put "-Wl,-elf2flt" into).
+W_ELF2FLT = -Wl,-elf2flt
+ifneq (,$(findstring $(W_ELF2FLT),$(LDFLAGS) $(CFLAGS_busybox)))
+SKIP_STRIP = y
+endif
+
+# Busybox is a stack-fatty so make sure we increase default size
+# TODO: use "make stksizes" to find & fix big stack users
+# (we stole scripts/checkstack.pl from the kernel... thanks guys!)
+# Reduced from 20k to 16k in 1.9.0.
+FLTFLAGS += -s 16000
diff --git a/cleopatre/busybox-1.11.1-spc300/Makefile.help b/cleopatre/busybox-1.11.1-spc300/Makefile.help
new file mode 100644
index 0000000000..f957403652
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/Makefile.help
@@ -0,0 +1,43 @@
+# ==========================================================================
+# Build system
+# ==========================================================================
+
+help:
+ @echo 'Cleaning:'
+ @echo ' clean - delete temporary files created by build'
+ @echo ' distclean - delete all non-source files (including .config)'
+ @echo
+ @echo 'Build:'
+ @echo ' all - Executable and documentation'
+ @echo ' busybox - the swiss-army executable'
+ @echo ' doc - docs/BusyBox.{txt,html,1}'
+ @echo ' html - create html-based cross-reference'
+ @echo
+ @echo 'Configuration:'
+ @echo ' allnoconfig - disable all symbols in .config'
+ @echo ' allyesconfig - enable all symbols in .config (see defconfig)'
+ @echo ' config - text based configurator (of last resort)'
+ @echo ' defconfig - set .config to largest generic configuration'
+ @echo ' menuconfig - interactive curses-based configurator'
+ @echo ' oldconfig - resolve any unresolved symbols in .config'
+ @echo ' hosttools - build sed for the host.'
+ @echo ' You can use these commands if the commands on the host'
+ @echo ' is unusable. Afterwards use it like:'
+ @echo ' make SED="$(objtree)/sed"'
+ @echo
+ @echo 'Installation:'
+ @echo ' install - install busybox into CONFIG_PREFIX'
+ @echo ' uninstall'
+ @echo
+ @echo 'Development:'
+ @echo ' baseline - create busybox_old for bloatcheck.'
+ @echo ' bloatcheck - show size difference between old and new versions'
+ @echo ' check - run the test suite for all applets'
+ @echo ' checkhelp - check for missing help-entries in Config.in'
+ @echo ' randconfig - generate a random configuration'
+ @echo ' release - create a distribution tarball'
+ @echo ' sizes - show size of all enabled busybox symbols'
+ @echo ' objsizes - show size of each .o object built'
+ @echo ' bigdata - show data objects, biggest first'
+ @echo ' stksizes - show stack users, biggest first'
+ @echo
diff --git a/cleopatre/busybox-1.11.1-spc300/README b/cleopatre/busybox-1.11.1-spc300/README
new file mode 100644
index 0000000000..24a26ed052
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/README
@@ -0,0 +1,201 @@
+Please see the LICENSE file for details on copying and usage.
+Please refer to the INSTALL file for instructions on how to build.
+
+What is busybox:
+
+ BusyBox combines tiny versions of many common UNIX utilities into a single
+ small executable. It provides minimalist replacements for most of the
+ utilities you usually find in bzip2, coreutils, dhcp, diffutils, e2fsprogs,
+ file, findutils, gawk, grep, inetutils, less, modutils, net-tools, procps,
+ sed, shadow, sysklogd, sysvinit, tar, util-linux, and vim. The utilities
+ in BusyBox often have fewer options than their full-featured cousins;
+ however, the options that are included provide the expected functionality
+ and behave very much like their larger counterparts.
+
+ BusyBox has been written with size-optimization and limited resources in
+ mind, both to produce small binaries and to reduce run-time memory usage.
+ Busybox is also extremely modular so you can easily include or exclude
+ commands (or features) at compile time. This makes it easy to customize
+ embedded systems; to create a working system, just add /dev, /etc, and a
+ Linux kernel. Busybox (usually together with uClibc) has also been used as
+ a component of "thin client" desktop systems, live-CD distributions, rescue
+ disks, installers, and so on.
+
+ BusyBox provides a fairly complete POSIX environment for any small system,
+ both embedded environments and more full featured systems concerned about
+ space. Busybox is slowly working towards implementing the full Single Unix
+ Specification V3 (http://www.opengroup.org/onlinepubs/009695399/), but isn't
+ there yet (and for size reasons will probably support at most UTF-8 for
+ internationalization). We are also interested in passing the Linux Test
+ Project (http://ltp.sourceforge.net).
+
+----------------
+
+Using busybox:
+
+ BusyBox is extremely configurable. This allows you to include only the
+ components and options you need, thereby reducing binary size. Run 'make
+ config' or 'make menuconfig' to select the functionality that you wish to
+ enable. (See 'make help' for more commands.)
+
+ The behavior of busybox is determined by the name it's called under: as
+ "cp" it behaves like cp, as "sed" it behaves like sed, and so on. Called
+ as "busybox" it takes the second argument as the name of the applet to
+ run (I.E. "./busybox ls -l /proc").
+
+ The "standalone shell" mode is an easy way to try out busybox; this is a
+ command shell that calls the builtin applets without needing them to be
+ installed in the path. (Note that this requires /proc to be mounted, if
+ testing from a boot floppy or in a chroot environment.)
+
+ The build automatically generates a file "busybox.links", which is used by
+ 'make install' to create symlinks to the BusyBox binary for all compiled in
+ commands. This uses the CONFIG_PREFIX environment variable to specify
+ where to install, and installs hardlinks or symlinks depending
+ on the configuration preferences. (You can also manually run
+ the install script at "applets/install.sh").
+
+----------------
+
+Downloading the current source code:
+
+ Source for the latest released version, as well as daily snapshots, can always
+ be downloaded from
+
+ http://busybox.net/downloads/
+
+ You can browse the up to the minute source code and change history online.
+
+ http://www.busybox.net/cgi-bin/viewcvs.cgi/trunk/busybox/
+
+ Anonymous SVN access is available. For instructions, check out:
+
+ http://busybox.net/subversion.html
+
+ For those that are actively contributing and would like to check files in,
+ see:
+
+ http://busybox.net/developer.html
+
+ The developers also have a bug and patch tracking system
+ (http://bugs.busybox.net) although posting a bug/patch to the mailing list
+ is generally a faster way of getting it fixed, and the complete archive of
+ what happened is the subversion changelog.
+
+ Note: if you want to compile busybox in a busybox environment you must
+ select ENABLE_DESKTOP.
+
+----------------
+
+getting help:
+
+ when you find you need help, you can check out the busybox mailing list
+ archives at http://busybox.net/lists/busybox/ or even join
+ the mailing list if you are interested.
+
+----------------
+
+bugs:
+
+ if you find bugs, please submit a detailed bug report to the busybox mailing
+ list at busybox@busybox.net. a well-written bug report should include a
+ transcript of a shell session that demonstrates the bad behavior and enables
+ anyone else to duplicate the bug on their own machine. the following is such
+ an example:
+
+ to: busybox@busybox.net
+ from: diligent@testing.linux.org
+ subject: /bin/date doesn't work
+
+ package: busybox
+ version: 1.00
+
+ when i execute busybox 'date' it produces unexpected results.
+ with gnu date i get the following output:
+
+ $ date
+ fri oct 8 14:19:41 mdt 2004
+
+ but when i use busybox date i get this instead:
+
+ $ date
+ illegal instruction
+
+ i am using debian unstable, kernel version 2.4.25-vrs2 on a netwinder,
+ and the latest uclibc from cvs. thanks for the wonderful program!
+
+ -diligent
+
+ note the careful description and use of examples showing not only what
+ busybox does, but also a counter example showing what an equivalent app
+ does (or pointing to the text of a relevant standard). Bug reports lacking
+ such detail may never be fixed... Thanks for understanding.
+
+----------------
+
+Portability:
+
+ Busybox is developed and tested on Linux 2.4 and 2.6 kernels, compiled
+ with gcc (the unit-at-a-time optimizations in version 3.4 and later are
+ worth upgrading to get, but older versions should work), and linked against
+ uClibc (0.9.27 or greater) or glibc (2.2 or greater). In such an
+ environment, the full set of busybox features should work, and if
+ anything doesn't we want to know about it so we can fix it.
+
+ There are many other environments out there, in which busybox may build
+ and run just fine. We just don't test them. Since busybox consists of a
+ large number of more or less independent applets, portability is a question
+ of which features work where. Some busybox applets (such as cat and rm) are
+ highly portable and likely to work just about anywhere, while others (such as
+ insmod and losetup) require recent Linux kernels with recent C libraries.
+
+ Earlier versions of Linux and glibc may or may not work, for any given
+ configuration. Linux 2.2 or earlier should mostly work (there's still
+ some support code in things like mount.c) but this is no longer regularly
+ tested, and inherently won't support certain features (such as long files
+ and --bind mounts). The same is true for glibc 2.0 and 2.1: expect a higher
+ testing and debugging burden using such old infrastructure. (The busybox
+ developers are not very interested in supporting these older versions, but
+ will probably accept small self-contained patches to fix simple problems.)
+
+ Some environments are not recommended. Early versions of uClibc were buggy
+ and missing many features: upgrade. Linking against libc5 or dietlibc is
+ not supported and not interesting to the busybox developers. (The first is
+ obsolete and has no known size or feature advantages over uClibc, the second
+ has known bugs that its developers have actively refused to fix.) Ancient
+ Linux kernels (2.0.x and earlier) are similarly uninteresting.
+
+ In theory it's possible to use Busybox under other operating systems (such as
+ MacOS X, Solaris, Cygwin, or the BSD Fork Du Jour). This generally involves
+ a different kernel and a different C library at the same time. While it
+ should be possible to port the majority of the code to work in one of
+ these environments, don't be suprised if it doesn't work out of the box. If
+ you're into that sort of thing, start small (selecting just a few applets)
+ and work your way up.
+
+ Shaun Jackman has recently (2005) ported busybox to a combination of newlib
+ and libgloss, and some of his patches have been integrated. This platform
+ may join glibc/uclibc and Linux as a supported combination with the 1.1
+ release, but is not supported in 1.0.
+
+Supported hardware:
+
+ BusyBox in general will build on any architecture supported by gcc. We
+ support both 32 and 64 bit platforms, and both big and little endian
+ systems.
+
+ Under 2.4 Linux kernels, kernel module loading was implemented in a
+ platform-specific manner. Busybox's insmod utility has been reported to
+ work under ARM, CRIS, H8/300, x86, ia64, x86_64, m68k, MIPS, PowerPC, S390,
+ SH3/4/5, Sparc, v850e, and x86_64. Anything else probably won't work.
+
+ The module loading mechanism for the 2.6 kernel is much more generic, and
+ we believe 2.6.x kernel module loading support should work on all
+ architectures supported by the kernel.
+
+----------------
+
+Please feed suggestions, bug reports, insults, and bribes back to the busybox
+maintainer:
+ Denis Vlasenko
+ <vda.linux@googlemail.com>
diff --git a/cleopatre/busybox-1.11.1-spc300/TODO b/cleopatre/busybox-1.11.1-spc300/TODO
new file mode 100644
index 0000000000..133fd4bedc
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/TODO
@@ -0,0 +1,298 @@
+Busybox TODO
+
+Stuff that needs to be done. This is organized by who plans to get around to
+doing it eventually, but that doesn't mean they "own" the item. If you want to
+do one of these bounce an email off the person it's listed under to see if they
+have any suggestions how they plan to go about it, and to minimize conflicts
+between your work and theirs. But otherwise, all of these are fair game.
+
+Rob Landley suggested these:
+ Add a libbb/platform.c
+ Implement fdprintf() for platforms that haven't got one.
+ Implement bb_realpath() that can handle NULL on non-glibc.
+ Cleanup bb_asprintf()
+
+ Remove obsolete _() wrapper crud for internationalization we don't do.
+ Figure out where we need utf8 support, and add it.
+
+ sh
+ The command shell situation is a big mess. We have three different
+ shells that don't really share any code, and the "standalone shell" doesn't
+ work all that well (especially not in a chroot environment), due to apps not
+ being reentrant.
+ lash is phased out. hush can be configured down to be nearly as small,
+ but less buggy :)
+ init
+ General cleanup (should use ENABLE_FEATURE_INIT_SYSLOG and ENABLE_FEATURE_INIT_DEBUG).
+ Do a SUSv3 audit
+ Look at the full Single Unix Specification version 3 (available online at
+ "http://www.opengroup.org/onlinepubs/009695399/nfindex.html") and
+ figure out which of our apps are compliant, and what we're missing that
+ we might actually care about.
+
+ Even better would be some kind of automated compliance test harness that
+ exercises each command line option and the various corner cases.
+ Internationalization
+ How much internationalization should we do?
+
+ The low hanging fruit is UTF-8 character set support. We should do this.
+ (Vodz pointed out the shell's cmdedit as needing work here. What else?)
+
+ We also have lots of hardwired english text messages. Consolidating this
+ into some kind of message table not only makes translation easier, but
+ also allows us to consolidate redundant (or close) strings.
+
+ We probably don't want to be bloated with locale support. (Not unless we
+ can cleanly export it from our underlying C library without having to
+ concern ourselves with it directly. Perhaps a few specific things like a
+ config option for "date" are low hanging fruit here?)
+
+ What level should things happen at? How much do we care about
+ internationalizing the text console when X11 and xterms are so much better
+ at it? (There's some infrastructure here we don't implement: The
+ "unicode_start" and "unicode_stop" shell scripts need "vt-is-UTF8" and a
+ --unicode option to loadkeys. That implies a real loadkeys/dumpkeys
+ implementation to replace loadkmap/dumpkmap. Plus messing with console font
+ loading. Is it worth it, or do we just say "use X"?)
+
+ Individual compilation of applets.
+ It would be nice if busybox had the option to compile to individual applets,
+ for people who want an alternate implementation less bloated than the gnu
+ utils (or simply with less political baggage), but without it being one big
+ executable.
+
+ Turning libbb into a real dll is another possibility, especially if libbb
+ could export some of the other library interfaces we've already more or less
+ got the code for (like zlib).
+ buildroot - Make a "dogfood" option
+ Busybox 1.1 will be capable of replacing most gnu packages for real world
+ use, such as developing software or in a live CD. It needs wider testing.
+
+ Busybox should now be able to replace bzip2, coreutils, e2fsprogs, file,
+ findutils, gawk, grep, inetutils, less, modutils, net-tools, patch, procps,
+ sed, shadow, sysklogd, sysvinit, tar, util-linux, and vim. The resulting
+ system should be self-hosting (I.E. able to rebuild itself from source
+ code). This means it would need (at least) binutils, gcc, and make, or
+ equivalents.
+
+ It would be a good "eating our own dogfood" test if buildroot had the option
+ of using a "make allyesconfig" busybox instead of the all of the above
+ packages. Anything that's wrong with the resulting system, we can fix. (It
+ would be nice to be able to upgrade busybox to be able to replace bash and
+ diffutils as well, but we're not there yet.)
+
+ One example of an existing system that does this already is Firmware Linux:
+ http://www.landley.net/code/firmware
+ initramfs
+ Busybox should have a sample initramfs build script. This depends on
+ bbsh, mdev, and switch_root.
+ mkdep
+ Write a mkdep that doesn't segfault if there's a directory it doesn't
+ have permission to read, isn't based on manually editing the output of
+ lexx and yacc, doesn't make such a mess under include/config, etc.
+ Group globals into unions of structures.
+ Go through and turn all the global and static variables into structures,
+ and have all those structures be in a big union shared between processes,
+ so busybox uses less bss. (This is a big win on nommu machines.) See
+ sed.c and mdev.c for examples.
+ Go through bugs.busybox.net and close out all of that somehow.
+ This one's open to everybody, but I'll wind up doing it...
+
+
+Bernhard Fischer <busybox@busybox.net> suggests to look at these:
+ New debug options:
+ -Wlarger-than-127
+ Cleanup any big users
+ -Wunused-parameter
+ Facilitate applet PROTOTYPES to provide means for having applets that
+ do a) not take any arguments b) need only one of argc or argv c) need
+ both argc and argv. All of these three options should go for the most
+ feature complete denominator.
+ Collate BUFSIZ IOBUF_SIZE MY_BUF_SIZE PIPE_PROGRESS_SIZE BUFSIZE PIPESIZE
+ make bb_common_bufsiz1 configurable, size wise.
+ make pipesize configurable, size wise.
+ Use bb_common_bufsiz1 throughout applets!
+
+As yet unclaimed:
+
+----
+diff
+ Make sure we handle empty files properly:
+ From the patch man page:
+
+ you can remove a file by sending out a context diff that compares
+ the file to be deleted with an empty file dated the Epoch. The
+ file will be removed unless patch is conforming to POSIX and the
+ -E or --remove-empty-files option is not given.
+---
+patch
+ Should have simple fuzz factor support to apply patches at an offset which
+ shouldn't take up too much space.
+
+ And while we're at it, a new patch filename quoting format is apparently
+ coming soon: http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
+---
+man
+ It would be nice to have a man command. Not one that handles troff or
+ anything, just one that can handle preformatted ascii man pages, possibly
+ compressed. This could probably be a script in the extras directory that
+ calls cat/zcat/bzcat | less
+
+ (How doclifter might work into this is anybody's guess.)
+---
+ar
+ Write support!
+---
+stty / catv
+ stty's visible() function and catv's guts are identical. Merge them into
+ an appropriate libbb function.
+---
+struct suffix_mult
+ Several duplicate users of: grep -r "1024\*1024" * -B2 -A1
+ Merge to a single size_suffixes[] in libbb.
+ Users: head tail od_bloaty hexdump and (partially as it wouldn't hurt) svlogd
+---
+tail
+ ./busybox tail -f foo.c~ TODO
+ should not print fmt=header_fmt for subsequent date >> TODO; i.e. only
+ fmt+ if another (not the current) file did change
+
+Architectural issues:
+
+bb_close() with fsync()
+ We should have a bb_close() in place of normal close, with a CONFIG_ option
+ to not just check the return value of close() for an error, but fsync().
+ Close can't reliably report anything useful because if write() accepted the
+ data then it either went out to the network or it's in cache or a pipe
+ buffer. Either way, there's no guarantee it'll make it to its final
+ destination before close() gets called, so there's no guarantee that any
+ error will be reported.
+
+ You need to call fsync() if you care about errors that occur after write(),
+ but that can have a big performance impact. So make it a config option.
+---
+Unify archivers
+ Lots of archivers have the same general infrastructure. The directory
+ traversal code should be factored out, and the guts of each archiver could
+ be some setup code and a series of callbacks for "add this file",
+ "add this directory", "add this symlink" and so on.
+
+ This could clean up tar and zip, and make it cheaper to add cpio and ar
+ write support, and possibly even cheaply add things like mkisofs or
+ mksquashfs someday, if they become relevant.
+---
+Text buffer support.
+ Several existing applets (sort, vi, less...) read
+ a whole file into memory and act on it. There might be an opportunity
+ for shared code in there that could be moved into libbb...
+---
+Memory Allocation
+ We have a CONFIG_BUFFER mechanism that lets us select whether to do memory
+ allocation on the stack or the heap. Unfortunately, we're not using it much.
+ We need to audit our memory allocations and turn a lot of malloc/free calls
+ into RESERVE_CONFIG_BUFFER/RELEASE_CONFIG_BUFFER.
+ For a start, see e.g. make EXTRA_CFLAGS=-Wlarger-than-64
+
+ And while we're at it, many of the CONFIG_FEATURE_CLEAN_UP #ifdefs will be
+ optimized out by the compiler in the stack allocation case (since there's no
+ free for an alloca()), and this means that various cleanup loops that just
+ call free might also be optimized out by the compiler if written right, so
+ we can yank those #ifdefs too, and generally clean up the code.
+---
+Switch CONFIG_SYMBOLS to ENABLE_SYMBOLS
+
+ In busybox 1.0 and earlier, configuration was done by CONFIG_SYMBOLS
+ that were either defined or undefined to indicate whether the symbol was
+ selected in the .config file. They were used with #ifdefs, ala:
+
+ #ifdef CONFIG_SYMBOL
+ if (other_test) {
+ do_code();
+ }
+ #endif
+
+ In 1.1, we have new ENABLE_SYMBOLS which are always defined (as 0 or 1),
+ meaning you can still use them for preprocessor tests by replacing
+ "#ifdef CONFIG_SYMBOL" with "#if ENABLE_SYMBOL". But more importantly, we
+ can use them as a true or false test in normal C code:
+
+ if (ENABLE_SYMBOL && other_test) {
+ do_code();
+ }
+
+ (Optimizing away if() statements that resolve to a constant value
+ is known as "dead code elimination", an optimization so old and simple that
+ Turbo Pascal for DOS did it twenty years ago. Even modern mini-compilers
+ like the Tiny C Compiler (tcc) and the Small Device C Compiler (SDCC)
+ perform dead code elimination.)
+
+ Right now, busybox.h is #including both "config.h" (defining the
+ CONFIG_SYMBOLS) and "bb_config.h" (defining the ENABLE_SYMBOLS). At some
+ point in the future, it would be nice to wean ourselves off of the
+ CONFIG versions. (Among other things, some defective build environments
+ leak the Linux kernel's CONFIG_SYMBOLS into the system's standard #include
+ files. We've experienced collisions before.)
+---
+FEATURE_CLEAN_UP
+ This is more an unresolved issue than a to-do item. More thought is needed.
+
+ Normally we rely on exit() to free memory, close files, and unmap segments
+ for us. This makes most calls to free(), close(), and unmap() optional in
+ busybox applets that don't intend to run for very long, and optional stuff
+ can be omitted to save size.
+
+ The idea was raised that we could simulate fork/exit with setjmp/longjmp
+ for _really_ brainless embedded systems, or speed up the standalone shell
+ by not forking. Doing so would require a reliable FEATURE_CLEAN_UP.
+ Unfortunately, this isn't as easy as it sounds.
+
+ The problem is, lots of things exit(), sometimes unexpectedly (xmalloc())
+ and sometimes reliably (bb_perror_msg_and_die() or show_usage()). This
+ jumps out of the normal flow control and bypasses any cleanup code we
+ put at the end of our applets.
+
+ It's possible to add hooks to libbb functions like xmalloc() and xopen()
+ to add their entries to a linked list, which could be traversed and
+ freed/closed automatically. (This would need to be able to free just the
+ entries after a checkpoint to be usable for a forkless standalone shell.
+ You don't want to free the shell's own resources.)
+
+ Right now, FEATURE_CLEAN_UP is more or less a debugging aid, to make things
+ like valgrind happy. It's also documentation of _what_ we're trusting
+ exit() to clean up for us. But new infrastructure to auto-free stuff would
+ render the existing FEATURE_CLEAN_UP code redundant.
+
+ For right now, exit() handles it just fine.
+
+
+
+Minor stuff:
+ watchdog.c could autodetect the timer duration via:
+ if(!ioctl (fd, WDIOC_GETTIMEOUT, &tmo)) timer_duration = 1 + (tmo / 2);
+ Unfortunately, that needs linux/watchdog.h and that contains unfiltered
+ kernel types on some distros, which breaks the build.
+---
+ use bb_error_msg where appropriate: See
+ egrep "(printf.*\([[:space:]]*(stderr|2)|[^_]write.*\([[:space:]]*(stderr|2))"
+---
+ use bb_perror_msg where appropriate: See
+ egrep "[^_]perror"
+---
+ possible code duplication ingroup() and is_a_group_member()
+---
+ Move __get_hz() to a better place and (re)use it in route.c, ash.c, msh.c
+---
+ See grep -r strtod
+ Alot of duplication that wants cleanup.
+---
+ in_ether duplicated in network/{interface,ifconfig}.c
+---
+
+
+Code cleanup:
+
+Replace deprecated functions.
+
+---
+vdprintf() -> similar sized functionality
+---
diff --git a/cleopatre/busybox-1.11.1-spc300/TODO_config_nommu b/cleopatre/busybox-1.11.1-spc300/TODO_config_nommu
new file mode 100644
index 0000000000..308e5d7fae
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/TODO_config_nommu
@@ -0,0 +1,843 @@
+#
+# Automatically generated make config: don't edit
+# Busybox version: 1.11.0.svn
+# Mon Apr 21 23:20:35 2008
+#
+CONFIG_HAVE_DOT_CONFIG=y
+
+#
+# Busybox Settings
+#
+
+#
+# General Configuration
+#
+CONFIG_DESKTOP=y
+CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
+# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
+# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
+CONFIG_SHOW_USAGE=y
+CONFIG_FEATURE_VERBOSE_USAGE=y
+CONFIG_FEATURE_COMPRESS_USAGE=y
+CONFIG_FEATURE_INSTALLER=y
+# CONFIG_LOCALE_SUPPORT is not set
+CONFIG_GETOPT_LONG=y
+CONFIG_FEATURE_DEVPTS=y
+# CONFIG_FEATURE_CLEAN_UP is not set
+CONFIG_FEATURE_PIDFILE=y
+CONFIG_FEATURE_SUID=y
+CONFIG_FEATURE_SUID_CONFIG=y
+CONFIG_FEATURE_SUID_CONFIG_QUIET=y
+CONFIG_SELINUX=y
+CONFIG_FEATURE_PREFER_APPLETS=y
+CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe"
+CONFIG_FEATURE_SYSLOG=y
+CONFIG_FEATURE_HAVE_RPC=y
+
+#
+# Build Options
+#
+# CONFIG_STATIC is not set
+CONFIG_NOMMU=y
+# CONFIG_BUILD_LIBBUSYBOX is not set
+# CONFIG_FEATURE_INDIVIDUAL is not set
+# CONFIG_FEATURE_SHARED_BUSYBOX is not set
+CONFIG_LFS=y
+
+#
+# Debugging Options
+#
+# CONFIG_DEBUG is not set
+# CONFIG_WERROR is not set
+CONFIG_NO_DEBUG_LIB=y
+# CONFIG_DMALLOC is not set
+# CONFIG_EFENCE is not set
+CONFIG_INCLUDE_SUSv2=y
+
+#
+# Installation Options
+#
+# CONFIG_INSTALL_NO_USR is not set
+CONFIG_INSTALL_APPLET_SYMLINKS=y
+# CONFIG_INSTALL_APPLET_HARDLINKS is not set
+# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set
+# CONFIG_INSTALL_APPLET_DONT is not set
+# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set
+# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set
+# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set
+CONFIG_PREFIX="./_install"
+
+#
+# Busybox Library Tuning
+#
+CONFIG_PASSWORD_MINLEN=6
+CONFIG_MD5_SIZE_VS_SPEED=2
+CONFIG_FEATURE_FAST_TOP=y
+CONFIG_FEATURE_ETC_NETWORKS=y
+CONFIG_FEATURE_EDITING=y
+CONFIG_FEATURE_EDITING_MAX_LEN=1024
+CONFIG_FEATURE_EDITING_VI=y
+CONFIG_FEATURE_EDITING_HISTORY=15
+# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set
+CONFIG_FEATURE_TAB_COMPLETION=y
+CONFIG_FEATURE_USERNAME_COMPLETION=y
+CONFIG_FEATURE_EDITING_FANCY_PROMPT=y
+CONFIG_FEATURE_VERBOSE_CP_MESSAGE=y
+CONFIG_FEATURE_COPYBUF_KB=4
+CONFIG_MONOTONIC_SYSCALL=y
+CONFIG_IOCTL_HEX2STR_ERROR=y
+
+#
+# Applets
+#
+
+#
+# Archival Utilities
+#
+CONFIG_AR=y
+CONFIG_FEATURE_AR_LONG_FILENAMES=y
+CONFIG_BUNZIP2=y
+CONFIG_BZIP2=y
+CONFIG_CPIO=y
+CONFIG_FEATURE_CPIO_O=y
+CONFIG_DPKG=y
+CONFIG_DPKG_DEB=y
+CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY=y
+CONFIG_GUNZIP=y
+CONFIG_FEATURE_GUNZIP_UNCOMPRESS=y
+CONFIG_GZIP=y
+CONFIG_RPM2CPIO=y
+CONFIG_RPM=y
+CONFIG_FEATURE_RPM_BZ2=y
+CONFIG_TAR=y
+CONFIG_FEATURE_TAR_CREATE=y
+CONFIG_FEATURE_TAR_GZIP=y
+CONFIG_FEATURE_TAR_BZIP2=y
+CONFIG_FEATURE_TAR_LZMA=y
+CONFIG_FEATURE_TAR_COMPRESS=y
+CONFIG_FEATURE_TAR_AUTODETECT=y
+CONFIG_FEATURE_TAR_FROM=y
+CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y
+CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y
+CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y
+CONFIG_FEATURE_TAR_LONG_OPTIONS=y
+CONFIG_FEATURE_TAR_UNAME_GNAME=y
+CONFIG_UNCOMPRESS=y
+CONFIG_UNLZMA=y
+CONFIG_FEATURE_LZMA_FAST=y
+CONFIG_UNZIP=y
+
+#
+# Common options for cpio and tar
+#
+
+#
+# Common options for dpkg and dpkg_deb
+#
+CONFIG_FEATURE_DEB_TAR_GZ=y
+CONFIG_FEATURE_DEB_TAR_BZ2=y
+CONFIG_FEATURE_DEB_TAR_LZMA=y
+
+#
+# Coreutils
+#
+CONFIG_BASENAME=y
+CONFIG_CAL=y
+CONFIG_CAT=y
+CONFIG_CATV=y
+CONFIG_CHGRP=y
+CONFIG_CHMOD=y
+CONFIG_CHOWN=y
+CONFIG_CHROOT=y
+CONFIG_CKSUM=y
+CONFIG_COMM=y
+CONFIG_CP=y
+CONFIG_CUT=y
+CONFIG_DATE=y
+CONFIG_FEATURE_DATE_ISOFMT=y
+CONFIG_DD=y
+CONFIG_FEATURE_DD_SIGNAL_HANDLING=y
+CONFIG_FEATURE_DD_IBS_OBS=y
+CONFIG_DF=y
+CONFIG_FEATURE_DF_INODE=y
+CONFIG_DIRNAME=y
+CONFIG_DOS2UNIX=y
+CONFIG_UNIX2DOS=y
+CONFIG_DU=y
+CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y
+CONFIG_ECHO=y
+CONFIG_FEATURE_FANCY_ECHO=y
+CONFIG_ENV=y
+CONFIG_FEATURE_ENV_LONG_OPTIONS=y
+CONFIG_EXPAND=y
+CONFIG_FEATURE_EXPAND_LONG_OPTIONS=y
+CONFIG_EXPR=y
+CONFIG_EXPR_MATH_SUPPORT_64=y
+CONFIG_FALSE=y
+CONFIG_FOLD=y
+CONFIG_HEAD=y
+CONFIG_FEATURE_FANCY_HEAD=y
+CONFIG_HOSTID=y
+CONFIG_ID=y
+CONFIG_INSTALL=y
+CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y
+CONFIG_LENGTH=y
+CONFIG_LN=y
+CONFIG_LOGNAME=y
+CONFIG_LS=y
+CONFIG_FEATURE_LS_FILETYPES=y
+CONFIG_FEATURE_LS_FOLLOWLINKS=y
+CONFIG_FEATURE_LS_RECURSIVE=y
+CONFIG_FEATURE_LS_SORTFILES=y
+CONFIG_FEATURE_LS_TIMESTAMPS=y
+CONFIG_FEATURE_LS_USERNAME=y
+CONFIG_FEATURE_LS_COLOR=y
+CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y
+CONFIG_MD5SUM=y
+CONFIG_MKDIR=y
+CONFIG_FEATURE_MKDIR_LONG_OPTIONS=y
+CONFIG_MKFIFO=y
+CONFIG_MKNOD=y
+CONFIG_MV=y
+CONFIG_FEATURE_MV_LONG_OPTIONS=y
+CONFIG_NICE=y
+CONFIG_NOHUP=y
+CONFIG_OD=y
+CONFIG_PRINTENV=y
+CONFIG_PRINTF=y
+CONFIG_PWD=y
+CONFIG_READLINK=y
+CONFIG_FEATURE_READLINK_FOLLOW=y
+CONFIG_REALPATH=y
+CONFIG_RM=y
+CONFIG_RMDIR=y
+CONFIG_FEATURE_RMDIR_LONG_OPTIONS=y
+CONFIG_SEQ=y
+CONFIG_SHA1SUM=y
+CONFIG_SLEEP=y
+CONFIG_FEATURE_FANCY_SLEEP=y
+CONFIG_SORT=y
+CONFIG_FEATURE_SORT_BIG=y
+CONFIG_SPLIT=y
+CONFIG_FEATURE_SPLIT_FANCY=y
+CONFIG_STAT=y
+CONFIG_FEATURE_STAT_FORMAT=y
+CONFIG_STTY=y
+CONFIG_SUM=y
+CONFIG_SYNC=y
+CONFIG_TAC=y
+CONFIG_TAIL=y
+CONFIG_FEATURE_FANCY_TAIL=y
+CONFIG_TEE=y
+CONFIG_FEATURE_TEE_USE_BLOCK_IO=y
+CONFIG_TEST=y
+CONFIG_FEATURE_TEST_64=y
+CONFIG_TOUCH=y
+CONFIG_TR=y
+CONFIG_FEATURE_TR_CLASSES=y
+CONFIG_FEATURE_TR_EQUIV=y
+CONFIG_TRUE=y
+CONFIG_TTY=y
+CONFIG_UNAME=y
+CONFIG_UNEXPAND=y
+CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS=y
+CONFIG_UNIQ=y
+CONFIG_USLEEP=y
+CONFIG_UUDECODE=y
+CONFIG_UUENCODE=y
+CONFIG_WC=y
+CONFIG_FEATURE_WC_LARGE=y
+CONFIG_WHO=y
+CONFIG_WHOAMI=y
+CONFIG_YES=y
+
+#
+# Common options for cp and mv
+#
+CONFIG_FEATURE_PRESERVE_HARDLINKS=y
+
+#
+# Common options for ls, more and telnet
+#
+CONFIG_FEATURE_AUTOWIDTH=y
+
+#
+# Common options for df, du, ls
+#
+CONFIG_FEATURE_HUMAN_READABLE=y
+
+#
+# Common options for md5sum, sha1sum
+#
+CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y
+
+#
+# Console Utilities
+#
+CONFIG_CHVT=y
+CONFIG_CLEAR=y
+CONFIG_DEALLOCVT=y
+CONFIG_DUMPKMAP=y
+CONFIG_KBD_MODE=y
+CONFIG_LOADFONT=y
+CONFIG_LOADKMAP=y
+CONFIG_OPENVT=y
+CONFIG_RESET=y
+CONFIG_RESIZE=y
+CONFIG_FEATURE_RESIZE_PRINT=y
+CONFIG_SETCONSOLE=y
+CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS=y
+CONFIG_SETKEYCODES=y
+CONFIG_SETLOGCONS=y
+
+#
+# Debian Utilities
+#
+CONFIG_MKTEMP=y
+CONFIG_PIPE_PROGRESS=y
+CONFIG_RUN_PARTS=y
+CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS=y
+CONFIG_FEATURE_RUN_PARTS_FANCY=y
+CONFIG_START_STOP_DAEMON=y
+CONFIG_FEATURE_START_STOP_DAEMON_FANCY=y
+CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS=y
+CONFIG_WHICH=y
+
+#
+# Editors
+#
+CONFIG_AWK=y
+CONFIG_FEATURE_AWK_MATH=y
+CONFIG_CMP=y
+CONFIG_DIFF=y
+CONFIG_FEATURE_DIFF_BINARY=y
+CONFIG_FEATURE_DIFF_DIR=y
+CONFIG_FEATURE_DIFF_MINIMAL=y
+CONFIG_ED=y
+CONFIG_PATCH=y
+CONFIG_SED=y
+CONFIG_VI=y
+CONFIG_FEATURE_VI_MAX_LEN=4096
+CONFIG_FEATURE_VI_8BIT=y
+CONFIG_FEATURE_VI_COLON=y
+CONFIG_FEATURE_VI_YANKMARK=y
+CONFIG_FEATURE_VI_SEARCH=y
+CONFIG_FEATURE_VI_USE_SIGNALS=y
+CONFIG_FEATURE_VI_DOT_CMD=y
+CONFIG_FEATURE_VI_READONLY=y
+CONFIG_FEATURE_VI_SETOPTS=y
+CONFIG_FEATURE_VI_SET=y
+CONFIG_FEATURE_VI_WIN_RESIZE=y
+CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y
+CONFIG_FEATURE_ALLOW_EXEC=y
+
+#
+# Finding Utilities
+#
+CONFIG_FIND=y
+CONFIG_FEATURE_FIND_PRINT0=y
+CONFIG_FEATURE_FIND_MTIME=y
+CONFIG_FEATURE_FIND_MMIN=y
+CONFIG_FEATURE_FIND_PERM=y
+CONFIG_FEATURE_FIND_TYPE=y
+CONFIG_FEATURE_FIND_XDEV=y
+CONFIG_FEATURE_FIND_MAXDEPTH=y
+CONFIG_FEATURE_FIND_NEWER=y
+CONFIG_FEATURE_FIND_INUM=y
+CONFIG_FEATURE_FIND_EXEC=y
+CONFIG_FEATURE_FIND_USER=y
+CONFIG_FEATURE_FIND_GROUP=y
+CONFIG_FEATURE_FIND_NOT=y
+CONFIG_FEATURE_FIND_DEPTH=y
+CONFIG_FEATURE_FIND_PAREN=y
+CONFIG_FEATURE_FIND_SIZE=y
+CONFIG_FEATURE_FIND_PRUNE=y
+CONFIG_FEATURE_FIND_DELETE=y
+CONFIG_FEATURE_FIND_PATH=y
+CONFIG_FEATURE_FIND_REGEX=y
+CONFIG_FEATURE_FIND_CONTEXT=y
+CONFIG_GREP=y
+CONFIG_FEATURE_GREP_EGREP_ALIAS=y
+CONFIG_FEATURE_GREP_FGREP_ALIAS=y
+CONFIG_FEATURE_GREP_CONTEXT=y
+CONFIG_XARGS=y
+CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y
+CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y
+CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y
+CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y
+
+#
+# Init Utilities
+#
+CONFIG_INIT=y
+# CONFIG_DEBUG_INIT is not set
+CONFIG_FEATURE_USE_INITTAB=y
+CONFIG_FEATURE_KILL_REMOVED=y
+CONFIG_FEATURE_KILL_DELAY=1
+CONFIG_FEATURE_INIT_SCTTY=y
+CONFIG_FEATURE_INIT_SYSLOG=y
+CONFIG_FEATURE_EXTRA_QUIET=y
+CONFIG_FEATURE_INIT_COREDUMPS=y
+CONFIG_FEATURE_INITRD=y
+CONFIG_HALT=y
+CONFIG_MESG=y
+
+#
+# Login/Password Management Utilities
+#
+CONFIG_FEATURE_SHADOWPASSWDS=y
+CONFIG_USE_BB_SHADOW=y
+CONFIG_USE_BB_PWD_GRP=y
+CONFIG_ADDGROUP=y
+CONFIG_FEATURE_ADDUSER_TO_GROUP=y
+CONFIG_DELGROUP=y
+CONFIG_FEATURE_DEL_USER_FROM_GROUP=y
+CONFIG_FEATURE_CHECK_NAMES=y
+CONFIG_ADDUSER=y
+CONFIG_FEATURE_ADDUSER_LONG_OPTIONS=y
+CONFIG_DELUSER=y
+CONFIG_GETTY=y
+CONFIG_FEATURE_UTMP=y
+CONFIG_FEATURE_WTMP=y
+CONFIG_LOGIN=y
+# CONFIG_PAM is not set
+CONFIG_LOGIN_SCRIPTS=y
+CONFIG_FEATURE_NOLOGIN=y
+CONFIG_FEATURE_SECURETTY=y
+CONFIG_PASSWD=y
+CONFIG_FEATURE_PASSWD_WEAK_CHECK=y
+CONFIG_CRYPTPW=y
+CONFIG_CHPASSWD=y
+CONFIG_SU=y
+CONFIG_FEATURE_SU_SYSLOG=y
+CONFIG_FEATURE_SU_CHECKS_SHELLS=y
+CONFIG_SULOGIN=y
+CONFIG_VLOCK=y
+
+#
+# Linux Ext2 FS Progs
+#
+CONFIG_CHATTR=y
+CONFIG_FSCK=y
+CONFIG_LSATTR=y
+
+#
+# Linux Module Utilities
+#
+CONFIG_INSMOD=y
+CONFIG_FEATURE_INSMOD_VERSION_CHECKING=y
+CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS=y
+CONFIG_FEATURE_INSMOD_LOADINKMEM=y
+CONFIG_FEATURE_INSMOD_LOAD_MAP=y
+CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL=y
+CONFIG_RMMOD=y
+CONFIG_LSMOD=y
+CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT=y
+CONFIG_MODPROBE=y
+CONFIG_FEATURE_MODPROBE_MULTIPLE_OPTIONS=y
+CONFIG_FEATURE_MODPROBE_FANCY_ALIAS=y
+
+#
+# Options common to multiple modutils
+#
+CONFIG_FEATURE_CHECK_TAINTED_MODULE=y
+CONFIG_FEATURE_2_4_MODULES=y
+CONFIG_FEATURE_2_6_MODULES=y
+# CONFIG_FEATURE_QUERY_MODULE_INTERFACE is not set
+
+#
+# Linux System Utilities
+#
+CONFIG_DMESG=y
+CONFIG_FEATURE_DMESG_PRETTY=y
+CONFIG_FBSET=y
+CONFIG_FEATURE_FBSET_FANCY=y
+CONFIG_FEATURE_FBSET_READMODE=y
+CONFIG_FDFLUSH=y
+CONFIG_FDFORMAT=y
+CONFIG_FDISK=y
+CONFIG_FDISK_SUPPORT_LARGE_DISKS=y
+CONFIG_FEATURE_FDISK_WRITABLE=y
+CONFIG_FEATURE_AIX_LABEL=y
+CONFIG_FEATURE_SGI_LABEL=y
+CONFIG_FEATURE_SUN_LABEL=y
+CONFIG_FEATURE_OSF_LABEL=y
+CONFIG_FEATURE_FDISK_ADVANCED=y
+CONFIG_FINDFS=y
+CONFIG_FREERAMDISK=y
+CONFIG_FSCK_MINIX=y
+CONFIG_MKFS_MINIX=y
+
+#
+# Minix filesystem support
+#
+CONFIG_FEATURE_MINIX2=y
+CONFIG_GETOPT=y
+CONFIG_HEXDUMP=y
+CONFIG_FEATURE_HEXDUMP_REVERSE=y
+CONFIG_HD=y
+CONFIG_HWCLOCK=y
+CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS=y
+CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS=y
+CONFIG_IPCRM=y
+CONFIG_IPCS=y
+CONFIG_LOSETUP=y
+CONFIG_MDEV=y
+CONFIG_FEATURE_MDEV_CONF=y
+CONFIG_FEATURE_MDEV_RENAME=y
+CONFIG_FEATURE_MDEV_RENAME_REGEXP=y
+CONFIG_FEATURE_MDEV_EXEC=y
+CONFIG_FEATURE_MDEV_LOAD_FIRMWARE=y
+CONFIG_MKSWAP=y
+CONFIG_FEATURE_MKSWAP_V0=y
+CONFIG_MORE=y
+CONFIG_FEATURE_USE_TERMIOS=y
+CONFIG_VOLUMEID=y
+CONFIG_FEATURE_VOLUMEID_EXT=y
+CONFIG_FEATURE_VOLUMEID_REISERFS=y
+CONFIG_FEATURE_VOLUMEID_FAT=y
+CONFIG_FEATURE_VOLUMEID_HFS=y
+CONFIG_FEATURE_VOLUMEID_JFS=y
+CONFIG_FEATURE_VOLUMEID_XFS=y
+CONFIG_FEATURE_VOLUMEID_NTFS=y
+CONFIG_FEATURE_VOLUMEID_ISO9660=y
+CONFIG_FEATURE_VOLUMEID_UDF=y
+CONFIG_FEATURE_VOLUMEID_LUKS=y
+CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y
+CONFIG_FEATURE_VOLUMEID_CRAMFS=y
+CONFIG_FEATURE_VOLUMEID_ROMFS=y
+CONFIG_FEATURE_VOLUMEID_SYSV=y
+CONFIG_FEATURE_VOLUMEID_OCFS2=y
+CONFIG_FEATURE_VOLUMEID_LINUXRAID=y
+CONFIG_MOUNT=y
+CONFIG_FEATURE_MOUNT_FAKE=y
+CONFIG_FEATURE_MOUNT_VERBOSE=y
+CONFIG_FEATURE_MOUNT_HELPERS=y
+CONFIG_FEATURE_MOUNT_LABEL=y
+CONFIG_FEATURE_MOUNT_NFS=y
+CONFIG_FEATURE_MOUNT_CIFS=y
+CONFIG_FEATURE_MOUNT_FLAGS=y
+CONFIG_FEATURE_MOUNT_FSTAB=y
+CONFIG_PIVOT_ROOT=y
+CONFIG_RDATE=y
+CONFIG_READPROFILE=y
+CONFIG_RTCWAKE=y
+CONFIG_SCRIPT=y
+CONFIG_SETARCH=y
+CONFIG_SWAPONOFF=y
+CONFIG_SWITCH_ROOT=y
+CONFIG_UMOUNT=y
+CONFIG_FEATURE_UMOUNT_ALL=y
+
+#
+# Common options for mount/umount
+#
+CONFIG_FEATURE_MOUNT_LOOP=y
+# CONFIG_FEATURE_MTAB_SUPPORT is not set
+
+#
+# Miscellaneous Utilities
+#
+CONFIG_ADJTIMEX=y
+CONFIG_BBCONFIG=y
+CONFIG_CHAT=y
+CONFIG_FEATURE_CHAT_NOFAIL=y
+CONFIG_FEATURE_CHAT_TTY_HIFI=y
+CONFIG_FEATURE_CHAT_IMPLICIT_CR=y
+CONFIG_FEATURE_CHAT_SWALLOW_OPTS=y
+CONFIG_FEATURE_CHAT_SEND_ESCAPES=y
+CONFIG_FEATURE_CHAT_VAR_ABORT_LEN=y
+CONFIG_FEATURE_CHAT_CLR_ABORT=y
+CONFIG_CHRT=y
+CONFIG_CROND=y
+CONFIG_DEBUG_CROND_OPTION=y
+CONFIG_FEATURE_CROND_CALL_SENDMAIL=y
+CONFIG_CRONTAB=y
+CONFIG_DC=y
+# CONFIG_DEVFSD is not set
+# CONFIG_DEVFSD_MODLOAD is not set
+# CONFIG_DEVFSD_FG_NP is not set
+# CONFIG_DEVFSD_VERBOSE is not set
+# CONFIG_FEATURE_DEVFS is not set
+CONFIG_EJECT=y
+CONFIG_FEATURE_EJECT_SCSI=y
+CONFIG_FBSPLASH=y
+CONFIG_LAST=y
+CONFIG_LESS=y
+CONFIG_FEATURE_LESS_MAXLINES=9999999
+CONFIG_FEATURE_LESS_BRACKETS=y
+CONFIG_FEATURE_LESS_FLAGS=y
+CONFIG_FEATURE_LESS_FLAGCS=y
+CONFIG_FEATURE_LESS_MARKS=y
+CONFIG_FEATURE_LESS_REGEXP=y
+CONFIG_HDPARM=y
+CONFIG_FEATURE_HDPARM_GET_IDENTITY=y
+CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF=y
+CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF=y
+CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET=y
+CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF=y
+CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA=y
+CONFIG_MAKEDEVS=y
+# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
+CONFIG_FEATURE_MAKEDEVS_TABLE=y
+CONFIG_MAN=y
+CONFIG_MICROCOM=y
+CONFIG_MOUNTPOINT=y
+CONFIG_MT=y
+CONFIG_RAIDAUTORUN=y
+CONFIG_READAHEAD=y
+CONFIG_RUNLEVEL=y
+CONFIG_RX=y
+CONFIG_SETSID=y
+CONFIG_STRINGS=y
+CONFIG_SYMLINKS=y
+CONFIG_TASKSET=y
+CONFIG_FEATURE_TASKSET_FANCY=y
+CONFIG_TIME=y
+CONFIG_TTYSIZE=y
+CONFIG_WATCHDOG=y
+
+#
+# Networking Utilities
+#
+CONFIG_FEATURE_IPV6=y
+CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y
+CONFIG_VERBOSE_RESOLUTION_ERRORS=y
+CONFIG_ARP=y
+CONFIG_ARPING=y
+CONFIG_BRCTL=y
+CONFIG_FEATURE_BRCTL_FANCY=y
+CONFIG_FEATURE_BRCTL_SHOW=y
+CONFIG_DNSD=y
+CONFIG_ETHER_WAKE=y
+CONFIG_FAKEIDENTD=y
+CONFIG_FTPGET=y
+CONFIG_FTPPUT=y
+CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y
+CONFIG_HOSTNAME=y
+CONFIG_HTTPD=y
+CONFIG_FEATURE_HTTPD_RANGES=y
+CONFIG_FEATURE_HTTPD_USE_SENDFILE=y
+CONFIG_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP=y
+CONFIG_FEATURE_HTTPD_SETUID=y
+CONFIG_FEATURE_HTTPD_BASIC_AUTH=y
+CONFIG_FEATURE_HTTPD_AUTH_MD5=y
+CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES=y
+CONFIG_FEATURE_HTTPD_CGI=y
+CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y
+CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV=y
+CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y
+CONFIG_FEATURE_HTTPD_ERROR_PAGES=y
+CONFIG_FEATURE_HTTPD_PROXY=y
+CONFIG_IFCONFIG=y
+CONFIG_FEATURE_IFCONFIG_STATUS=y
+CONFIG_FEATURE_IFCONFIG_SLIP=y
+CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ=y
+CONFIG_FEATURE_IFCONFIG_HW=y
+CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y
+CONFIG_IFENSLAVE=y
+CONFIG_IFUPDOWN=y
+CONFIG_IFUPDOWN_IFSTATE_PATH="/var/run/ifstate"
+CONFIG_FEATURE_IFUPDOWN_IP=y
+CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN=y
+# CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set
+CONFIG_FEATURE_IFUPDOWN_IPV4=y
+CONFIG_FEATURE_IFUPDOWN_IPV6=y
+CONFIG_FEATURE_IFUPDOWN_MAPPING=y
+CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP=y
+CONFIG_INETD=y
+CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO=y
+CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD=y
+CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME=y
+CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME=y
+CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN=y
+CONFIG_FEATURE_INETD_RPC=y
+CONFIG_IP=y
+CONFIG_FEATURE_IP_ADDRESS=y
+CONFIG_FEATURE_IP_LINK=y
+CONFIG_FEATURE_IP_ROUTE=y
+CONFIG_FEATURE_IP_TUNNEL=y
+CONFIG_FEATURE_IP_RULE=y
+CONFIG_FEATURE_IP_SHORT_FORMS=y
+CONFIG_FEATURE_IP_RARE_PROTOCOLS=y
+CONFIG_IPADDR=y
+CONFIG_IPLINK=y
+CONFIG_IPROUTE=y
+CONFIG_IPTUNNEL=y
+CONFIG_IPRULE=y
+CONFIG_IPCALC=y
+CONFIG_FEATURE_IPCALC_FANCY=y
+CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y
+CONFIG_NAMEIF=y
+CONFIG_FEATURE_NAMEIF_EXTENDED=y
+CONFIG_NC=y
+CONFIG_NC_SERVER=y
+CONFIG_NC_EXTRA=y
+CONFIG_NETSTAT=y
+CONFIG_FEATURE_NETSTAT_WIDE=y
+CONFIG_NSLOOKUP=y
+CONFIG_PING=y
+CONFIG_PING6=y
+CONFIG_FEATURE_FANCY_PING=y
+CONFIG_PSCAN=y
+CONFIG_ROUTE=y
+CONFIG_SENDMAIL=y
+CONFIG_FETCHMAIL=y
+CONFIG_SLATTACH=y
+CONFIG_TELNET=y
+CONFIG_FEATURE_TELNET_TTYPE=y
+CONFIG_FEATURE_TELNET_AUTOLOGIN=y
+CONFIG_TELNETD=y
+CONFIG_FEATURE_TELNETD_STANDALONE=y
+CONFIG_TFTP=y
+CONFIG_TFTPD=y
+CONFIG_FEATURE_TFTP_GET=y
+CONFIG_FEATURE_TFTP_PUT=y
+CONFIG_FEATURE_TFTP_BLOCKSIZE=y
+CONFIG_DEBUG_TFTP=y
+CONFIG_TRACEROUTE=y
+CONFIG_FEATURE_TRACEROUTE_VERBOSE=y
+CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE=y
+CONFIG_FEATURE_TRACEROUTE_USE_ICMP=y
+CONFIG_APP_UDHCPD=y
+CONFIG_APP_DHCPRELAY=y
+CONFIG_APP_DUMPLEASES=y
+CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY=y
+CONFIG_DHCPD_LEASES_FILE="/var/lib/misc/udhcpd.leases"
+CONFIG_APP_UDHCPC=y
+CONFIG_FEATURE_UDHCPC_ARPING=y
+CONFIG_FEATURE_UDHCP_PORT=y
+CONFIG_FEATURE_UDHCP_DEBUG=y
+CONFIG_FEATURE_RFC3397=y
+CONFIG_DHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script"
+CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80
+CONFIG_VCONFIG=y
+CONFIG_WGET=y
+CONFIG_FEATURE_WGET_STATUSBAR=y
+CONFIG_FEATURE_WGET_AUTHENTICATION=y
+CONFIG_FEATURE_WGET_LONG_OPTIONS=y
+CONFIG_ZCIP=y
+CONFIG_TCPSVD=y
+CONFIG_UDPSVD=y
+
+#
+# Process Utilities
+#
+CONFIG_FREE=y
+CONFIG_FUSER=y
+CONFIG_KILL=y
+CONFIG_KILLALL=y
+CONFIG_KILLALL5=y
+CONFIG_NMETER=y
+CONFIG_PGREP=y
+CONFIG_PIDOF=y
+CONFIG_FEATURE_PIDOF_SINGLE=y
+CONFIG_FEATURE_PIDOF_OMIT=y
+CONFIG_PKILL=y
+CONFIG_PS=y
+CONFIG_FEATURE_PS_WIDE=y
+CONFIG_FEATURE_PS_TIME=y
+CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS=y
+CONFIG_RENICE=y
+CONFIG_BB_SYSCTL=y
+CONFIG_TOP=y
+CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y
+CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y
+CONFIG_FEATURE_TOP_DECIMALS=y
+CONFIG_FEATURE_TOPMEM=y
+CONFIG_UPTIME=y
+CONFIG_WATCH=y
+
+#
+# Shells
+#
+# CONFIG_FEATURE_SH_IS_ASH is not set
+# CONFIG_FEATURE_SH_IS_HUSH is not set
+# CONFIG_FEATURE_SH_IS_MSH is not set
+CONFIG_FEATURE_SH_IS_NONE=y
+# CONFIG_ASH is not set
+# CONFIG_ASH_BASH_COMPAT is not set
+# CONFIG_ASH_JOB_CONTROL is not set
+# CONFIG_ASH_READ_NCHARS is not set
+# CONFIG_ASH_READ_TIMEOUT is not set
+# CONFIG_ASH_ALIAS is not set
+# CONFIG_ASH_MATH_SUPPORT is not set
+# CONFIG_ASH_MATH_SUPPORT_64 is not set
+# CONFIG_ASH_GETOPTS is not set
+# CONFIG_ASH_BUILTIN_ECHO is not set
+# CONFIG_ASH_BUILTIN_TEST is not set
+# CONFIG_ASH_CMDCMD is not set
+# CONFIG_ASH_MAIL is not set
+# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set
+# CONFIG_ASH_RANDOM_SUPPORT is not set
+# CONFIG_ASH_EXPAND_PRMT is not set
+CONFIG_HUSH=y
+CONFIG_HUSH_HELP=y
+CONFIG_HUSH_INTERACTIVE=y
+CONFIG_HUSH_JOB=y
+CONFIG_HUSH_TICK=y
+CONFIG_HUSH_IF=y
+CONFIG_HUSH_LOOPS=y
+CONFIG_LASH=y
+CONFIG_MSH=y
+
+#
+# Bourne Shell Options
+#
+CONFIG_FEATURE_SH_EXTRA_QUIET=y
+CONFIG_FEATURE_SH_STANDALONE=y
+CONFIG_FEATURE_SH_NOFORK=y
+CONFIG_CTTYHACK=y
+
+#
+# System Logging Utilities
+#
+CONFIG_SYSLOGD=y
+CONFIG_FEATURE_ROTATE_LOGFILE=y
+CONFIG_FEATURE_REMOTE_LOG=y
+CONFIG_FEATURE_SYSLOGD_DUP=y
+CONFIG_FEATURE_IPC_SYSLOG=y
+CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=16
+CONFIG_LOGREAD=y
+CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING=y
+CONFIG_KLOGD=y
+CONFIG_LOGGER=y
+
+#
+# Runit Utilities
+#
+CONFIG_RUNSV=y
+CONFIG_RUNSVDIR=y
+CONFIG_SV=y
+CONFIG_SVLOGD=y
+CONFIG_CHPST=y
+CONFIG_SETUIDGID=y
+CONFIG_ENVUIDGID=y
+CONFIG_ENVDIR=y
+CONFIG_SOFTLIMIT=y
+
+#
+# Selinux Utilities
+#
+CONFIG_CHCON=y
+CONFIG_FEATURE_CHCON_LONG_OPTIONS=y
+CONFIG_GETENFORCE=y
+CONFIG_GETSEBOOL=y
+CONFIG_LOAD_POLICY=y
+CONFIG_MATCHPATHCON=y
+CONFIG_RESTORECON=y
+CONFIG_RUNCON=y
+CONFIG_FEATURE_RUNCON_LONG_OPTIONS=y
+CONFIG_SELINUXENABLED=y
+CONFIG_SETENFORCE=y
+CONFIG_SETFILES=y
+CONFIG_FEATURE_SETFILES_CHECK_OPTION=y
+CONFIG_SETSEBOOL=y
+CONFIG_SESTATUS=y
+
+#
+# Print Utilities
+#
+CONFIG_LPD=y
+CONFIG_LPR=y
+CONFIG_LPQ=y
diff --git a/cleopatre/busybox-1.11.1-spc300/applets/Kbuild b/cleopatre/busybox-1.11.1-spc300/applets/Kbuild
new file mode 100644
index 0000000000..2969e79228
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/applets/Kbuild
@@ -0,0 +1,34 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+obj-y :=
+obj-y += applets.o
+
+hostprogs-y:=
+hostprogs-y += usage applet_tables
+
+always:= $(hostprogs-y)
+
+# Generated files need additional love
+
+HOSTCFLAGS_usage.o = -I$(srctree)/include
+
+applets/applets.o: include/usage_compressed.h include/applet_tables.h
+
+applets/usage: .config $(srctree)/applets/usage_compressed
+applets/applet_tables: .config
+
+quiet_cmd_gen_usage_compressed = GEN include/usage_compressed.h
+ cmd_gen_usage_compressed = $(srctree)/applets/usage_compressed include/usage_compressed.h applets
+
+include/usage_compressed.h: applets/usage $(srctree)/applets/usage_compressed
+ $(call cmd,gen_usage_compressed)
+
+quiet_cmd_gen_applet_tables = GEN include/applet_tables.h
+ cmd_gen_applet_tables = applets/applet_tables include/applet_tables.h
+
+include/applet_tables.h: applets/applet_tables
+ $(call cmd,gen_applet_tables)
diff --git a/cleopatre/busybox-1.11.1-spc300/applets/applet_tables.c b/cleopatre/busybox-1.11.1-spc300/applets/applet_tables.c
new file mode 100644
index 0000000000..17135ddc1f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/applets/applet_tables.c
@@ -0,0 +1,126 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Applet table generator.
+ * Runs on host and produces include/applet_tables.h
+ *
+ * Copyright (C) 2007 Denys Vlasenko <vda.linux@googlemail.com>
+ *
+ * Licensed under GPLv2, see file License in this tarball for details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "../include/autoconf.h"
+#include "../include/busybox.h"
+
+struct bb_applet {
+ const char *name;
+ const char *main;
+ enum bb_install_loc_t install_loc;
+ enum bb_suid_t need_suid;
+ /* true if instead of fork(); exec("applet"); waitpid();
+ * one can do fork(); exit(applet_main(argc,argv)); waitpid(); */
+ unsigned char noexec;
+ /* Even nicer */
+ /* true if instead of fork(); exec("applet"); waitpid();
+ * one can simply call applet_main(argc,argv); */
+ unsigned char nofork;
+};
+
+/* Define struct bb_applet applets[] */
+#include "../include/applets.h"
+
+enum { NUM_APPLETS = ARRAY_SIZE(applets) };
+
+static int offset[NUM_APPLETS];
+
+static int cmp_name(const void *a, const void *b)
+{
+ const struct bb_applet *aa = a;
+ const struct bb_applet *bb = b;
+ return strcmp(aa->name, bb->name);
+}
+
+int main(int argc, char **argv)
+{
+ int i;
+ int ofs;
+ unsigned MAX_APPLET_NAME_LEN = 1;
+
+ qsort(applets, NUM_APPLETS, sizeof(applets[0]), cmp_name);
+
+ ofs = 0;
+ for (i = 0; i < NUM_APPLETS; i++) {
+ offset[i] = ofs;
+ ofs += strlen(applets[i].name) + 1;
+ }
+ /* We reuse 4 high-order bits of offset array for other purposes,
+ * so if they are indeed needed, refuse to proceed */
+ if (ofs > 0xfff)
+ return 1;
+ if (!argv[1])
+ return 1;
+
+ i = open(argv[1], O_WRONLY | O_TRUNC | O_CREAT, 0666);
+ if (i < 0)
+ return 1;
+ dup2(i, 1);
+
+ /* Keep in sync with include/busybox.h! */
+
+ puts("/* This is a generated file, don't edit */\n");
+
+ printf("#define NUM_APPLETS %u\n", NUM_APPLETS);
+ if (NUM_APPLETS == 1) {
+ printf("#define SINGLE_APPLET_STR \"%s\"\n", applets[0].name);
+ printf("#define SINGLE_APPLET_MAIN %s_main\n", applets[0].name);
+ }
+
+ puts("\nconst char applet_names[] ALIGN1 = \"\"");
+ for (i = 0; i < NUM_APPLETS; i++) {
+ printf("\"%s\" \"\\0\"\n", applets[i].name);
+ if (MAX_APPLET_NAME_LEN < strlen(applets[i].name))
+ MAX_APPLET_NAME_LEN = strlen(applets[i].name);
+ }
+ puts(";");
+
+ puts("\nint (*const applet_main[])(int argc, char **argv) = {");
+ for (i = 0; i < NUM_APPLETS; i++) {
+ printf("%s_main,\n", applets[i].main);
+ }
+ puts("};");
+
+ puts("const uint16_t applet_nameofs[] ALIGN2 = {");
+ for (i = 0; i < NUM_APPLETS; i++) {
+ printf("0x%04x,\n",
+ offset[i]
+#if ENABLE_FEATURE_PREFER_APPLETS
+ + (applets[i].nofork << 12)
+ + (applets[i].noexec << 13)
+#endif
+#if ENABLE_FEATURE_SUID
+ + (applets[i].need_suid << 14) /* 2 bits */
+#endif
+ );
+ }
+ puts("};");
+
+#if ENABLE_FEATURE_INSTALLER
+ puts("const uint8_t applet_install_loc[] ALIGN1 = {");
+ i = 0;
+ while (i < NUM_APPLETS) {
+ int v = applets[i].install_loc; /* 3 bits */
+ if (++i < NUM_APPLETS)
+ v |= applets[i].install_loc << 4; /* 3 bits */
+ printf("0x%02x,\n", v);
+ i++;
+ }
+ puts("};\n");
+#endif
+
+ printf("#define MAX_APPLET_NAME_LEN %u\n", MAX_APPLET_NAME_LEN);
+
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/applets/applets.c b/cleopatre/busybox-1.11.1-spc300/applets/applets.c
new file mode 100644
index 0000000000..fbe766623e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/applets/applets.c
@@ -0,0 +1,18 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Stub for linking busybox binary against libbusybox.
+ *
+ * Copyright (C) 2007 Denys Vlasenko <vda.linux@googlemail.com>
+ *
+ * Licensed under GPLv2, see file License in this tarball for details.
+ */
+
+#include <assert.h>
+#include "busybox.h"
+
+#if ENABLE_BUILD_LIBBUSYBOX
+int main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ return lbb_main(argv);
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/applets/busybox.mkll b/cleopatre/busybox-1.11.1-spc300/applets/busybox.mkll
new file mode 100755
index 0000000000..6d61f7e82d
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/applets/busybox.mkll
@@ -0,0 +1,24 @@
+#!/bin/sh
+# Make busybox links list file.
+
+# input $1: full path to Config.h
+# input $2: full path to applets.h
+# output (stdout): list of pathnames that should be linked to busybox
+
+# Maintainer: Larry Doolittle <ldoolitt@recycle.lbl.gov>
+
+export LC_ALL=POSIX
+export LC_CTYPE=POSIX
+
+CONFIG_H=${1:-include/autoconf.h}
+APPLETS_H=${2:-include/applets.h}
+$HOSTCC -E -DMAKE_LINKS -include $CONFIG_H $APPLETS_H |
+ awk '/^[ \t]*LINK/{
+ dir=substr($2,8)
+ gsub("_","/",dir)
+ if(dir=="/ROOT") dir=""
+ file=$3
+ gsub("\"","",file)
+ if (file=="busybox") next
+ print tolower(dir) "/" file
+ }'
diff --git a/cleopatre/busybox-1.11.1-spc300/applets/individual.c b/cleopatre/busybox-1.11.1-spc300/applets/individual.c
new file mode 100644
index 0000000000..341f4d1c2c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/applets/individual.c
@@ -0,0 +1,24 @@
+/* Minimal wrapper to build an individual busybox applet.
+ *
+ * Copyright 2005 Rob Landley <rob@landley.net
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details
+ */
+
+const char *applet_name;
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "usage.h"
+
+int main(int argc, char **argv)
+{
+ applet_name = argv[0];
+ return APPLET_main(argc,argv);
+}
+
+void bb_show_usage(void)
+{
+ fputs(APPLET_full_usage "\n", stdout);
+ exit(EXIT_FAILURE);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/applets/install.sh b/cleopatre/busybox-1.11.1-spc300/applets/install.sh
new file mode 100755
index 0000000000..32049b1579
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/applets/install.sh
@@ -0,0 +1,110 @@
+#!/bin/sh
+
+export LC_ALL=POSIX
+export LC_CTYPE=POSIX
+
+prefix=${1}
+if [ -z "$prefix" ]; then
+ echo "usage: applets/install.sh DESTINATION [--symlinks/--hardlinks/--scriptwrapper]"
+ exit 1;
+fi
+h=`sort busybox.links | uniq`
+scriptwrapper="n"
+cleanup="0"
+noclobber="0"
+case "$2" in
+ --hardlinks) linkopts="-f";;
+ --symlinks) linkopts="-fs";;
+ --scriptwrapper) scriptwrapper="y";swrapall="y";;
+ --sw-sh-hard) scriptwrapper="y";linkopts="-f";;
+ --sw-sh-sym) scriptwrapper="y";linkopts="-fs";;
+ --cleanup) cleanup="1";;
+ --noclobber) noclobber="1";;
+ "") h="";;
+ *) echo "Unknown install option: $2"; exit 1;;
+esac
+
+if [ -n "$DO_INSTALL_LIBS" ] && [ "$DO_INSTALL_LIBS" != "n" ]; then
+ # get the target dir for the libs
+ # assume it starts with lib
+ libdir=$($CC -print-file-name=libc.so | \
+ sed -n 's%^.*\(/lib[^\/]*\)/libc.so%\1%p')
+ if test -z "$libdir"; then
+ libdir=/lib
+ fi
+
+ mkdir -p $prefix/$libdir || exit 1
+ for i in $DO_INSTALL_LIBS; do
+ rm -f $prefix/$libdir/$i || exit 1
+ if [ -f $i ]; then
+ cp -pPR $i $prefix/$libdir/ || exit 1
+ chmod 0644 $prefix/$libdir/$i || exit 1
+ fi
+ done
+fi
+
+if [ "$cleanup" = "1" ] && [ -e "$prefix/bin/busybox" ]; then
+ inode=`ls -i "$prefix/bin/busybox" | awk '{print $1}'`
+ sub_shell_it=`
+ cd "$prefix"
+ for d in usr/sbin usr/bin sbin bin; do
+ pd=$PWD
+ if [ -d "$d" ]; then
+ cd $d
+ ls -iL . | grep "^ *$inode" | awk '{print $2}' | env -i xargs rm -f
+ fi
+ cd "$pd"
+ done
+ `
+ exit 0
+fi
+
+rm -f $prefix/bin/busybox || exit 1
+mkdir -p $prefix/bin || exit 1
+install -m 755 busybox $prefix/bin/busybox || exit 1
+
+for i in $h; do
+ appdir=`dirname $i`
+ mkdir -p $prefix/$appdir || exit 1
+ if [ "$scriptwrapper" = "y" ]; then
+ if [ "$swrapall" != "y" ] && [ "$i" = "/bin/sh" ]; then
+ ln $linkopts busybox $prefix$i || exit 1
+ else
+ rm -f $prefix$i
+ echo "#!/bin/busybox" > $prefix$i
+ chmod +x $prefix/$i
+ fi
+ echo " $prefix$i"
+ else
+ if [ "$2" = "--hardlinks" ]; then
+ bb_path="$prefix/bin/busybox"
+ else
+ case "$appdir" in
+ /)
+ bb_path="bin/busybox"
+ ;;
+ /bin)
+ bb_path="busybox"
+ ;;
+ /sbin)
+ bb_path="../bin/busybox"
+ ;;
+ /usr/bin|/usr/sbin)
+ bb_path="../../bin/busybox"
+ ;;
+ *)
+ echo "Unknown installation directory: $appdir"
+ exit 1
+ ;;
+ esac
+ fi
+ if [ "$noclobber" = "0" ] || [ ! -e "$prefix$i" ]; then
+ echo " $prefix$i -> $bb_path"
+ ln $linkopts $bb_path $prefix$i || exit 1
+ else
+ echo " $prefix$i already exists"
+ fi
+ fi
+done
+
+exit 0
diff --git a/cleopatre/busybox-1.11.1-spc300/applets/usage.c b/cleopatre/busybox-1.11.1-spc300/applets/usage.c
new file mode 100644
index 0000000000..a35817f9f7
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/applets/usage.c
@@ -0,0 +1,29 @@
+/* vi: set sw=4 ts=4: */
+#include <unistd.h>
+
+/* Just #include "autoconf.h" doesn't work for builds in separate
+ * object directory */
+#include "../include/autoconf.h"
+
+/* Since we can't use platform.h, have to do this again by hand: */
+#if ENABLE_NOMMU
+#define BB_MMU 0
+#define USE_FOR_NOMMU(...) __VA_ARGS__
+#define USE_FOR_MMU(...)
+#else
+#define BB_MMU 1
+#define USE_FOR_NOMMU(...)
+#define USE_FOR_MMU(...) __VA_ARGS__
+#endif
+
+static const char usage_messages[] = ""
+#define MAKE_USAGE
+#include "usage.h"
+#include "applets.h"
+;
+
+int main(void)
+{
+ write(STDOUT_FILENO, usage_messages, sizeof(usage_messages));
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/applets/usage_compressed b/cleopatre/busybox-1.11.1-spc300/applets/usage_compressed
new file mode 100755
index 0000000000..551b4b4ba0
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/applets/usage_compressed
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+target="$1"
+loc="$2"
+
+test "$target" || exit 1
+test "$loc" || loc=.
+test -x "$loc/usage" || exit 1
+test "$SED" || SED=sed
+
+sz=`"$loc/usage" | wc -c` || exit 1
+
+exec >"$target"
+
+echo 'static const char packed_usage[] ALIGN1 = {'
+
+# Extra effort to avoid using "od -t x1": -t is not available
+# in non-CONFIG_DESKTOPed busybox od
+
+"$loc/usage" | bzip2 -1 | od -v -x \
+| $SED -e 's/^[^ ]*//' \
+| $SED -e 's/ //g' \
+| grep -v '^$' \
+| $SED -e 's/\(..\)\(..\)/0x\2,0x\1,/g'
+
+echo '};'
+echo '#define SIZEOF_usage_messages' `expr 0 + $sz`
diff --git a/cleopatre/busybox-1.11.1-spc300/arch/i386/Makefile b/cleopatre/busybox-1.11.1-spc300/arch/i386/Makefile
new file mode 100644
index 0000000000..e6c99c67d8
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/arch/i386/Makefile
@@ -0,0 +1,7 @@
+# ==========================================================================
+# Build system
+# ==========================================================================
+
+# -mpreferred-stack-boundary=2 is essential in preventing gcc 4.2.x
+# from aligning stack to 16 bytes. (Which is gcc's way of supporting SSE).
+CFLAGS += $(call cc-option,-march=i386 -mpreferred-stack-boundary=2,)
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/Config.in b/cleopatre/busybox-1.11.1-spc300/archival/Config.in
new file mode 100644
index 0000000000..4599b68d43
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/Config.in
@@ -0,0 +1,344 @@
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Archival Utilities"
+
+config AR
+ bool "ar"
+ default n
+ help
+ ar is an archival utility program used to create, modify, and
+ extract contents from archives. An archive is a single file holding
+ a collection of other files in a structure that makes it possible to
+ retrieve the original individual files (called archive members).
+ The original files' contents, mode (permissions), timestamp, owner,
+ and group are preserved in the archive, and can be restored on
+ extraction.
+
+ The stored filename is limited to 15 characters. (for more information
+ see long filename support).
+ ar has 60 bytes of overheads for every stored file.
+
+ This implementation of ar can extract archives, it cannot create or
+ modify them.
+ On an x86 system, the ar applet adds about 1K.
+
+ Unless you have a specific application which requires ar, you should
+ probably say N here.
+
+config FEATURE_AR_LONG_FILENAMES
+ bool "Support for long filenames (not need for debs)"
+ default n
+ depends on AR
+ help
+ By default the ar format can only store the first 15 characters of the
+ filename, this option removes that limitation.
+ It supports the GNU ar long filename method which moves multiple long
+ filenames into a the data section of a new ar entry.
+
+config BUNZIP2
+ bool "bunzip2"
+ default n
+ help
+ bunzip2 is a compression utility using the Burrows-Wheeler block
+ sorting text compression algorithm, and Huffman coding. Compression
+ is generally considerably better than that achieved by more
+ conventional LZ77/LZ78-based compressors, and approaches the
+ performance of the PPM family of statistical compressors.
+
+ Unless you have a specific application which requires bunzip2, you
+ should probably say N here.
+
+config BZIP2
+ bool "bzip2"
+ default n
+ help
+ bzip2 is a compression utility using the Burrows-Wheeler block
+ sorting text compression algorithm, and Huffman coding. Compression
+ is generally considerably better than that achieved by more
+ conventional LZ77/LZ78-based compressors, and approaches the
+ performance of the PPM family of statistical compressors.
+
+ Unless you have a specific application which requires bzip2, you
+ should probably say N here.
+
+config CPIO
+ bool "cpio"
+ default n
+ help
+ cpio is an archival utility program used to create, modify, and extract
+ contents from archives.
+ cpio has 110 bytes of overheads for every stored file.
+
+ This implementation of cpio can extract cpio archives created in the
+ "newc" or "crc" format, it cannot create or modify them.
+
+ Unless you have a specific application which requires cpio, you should
+ probably say N here.
+
+config FEATURE_CPIO_O
+ bool "Support for archive creation"
+ default n
+ depends on CPIO
+ help
+ This implementation of cpio can create cpio archives in the "newc"
+ format only.
+
+config DPKG
+ bool "dpkg"
+ default n
+ help
+ dpkg is a medium-level tool to install, build, remove and manage Debian packages.
+
+ This implementation of dpkg has a number of limitations, you should use the
+ official dpkg if possible.
+
+config DPKG_DEB
+ bool "dpkg_deb"
+ default n
+ help
+ dpkg-deb packs, unpacks and provides information about Debian archives.
+
+ This implementation of dpkg-deb cannot pack archives.
+
+ Unless you have a specific application which requires dpkg-deb, you should
+ probably say N here.
+
+config FEATURE_DPKG_DEB_EXTRACT_ONLY
+ bool "Extract only (-x)"
+ default n
+ depends on DPKG_DEB
+ help
+ This reduces dpkg-deb to the equivalent of "ar -p <deb> data.tar.gz | tar -zx".
+ However it saves space as none of the extra dpkg-deb, ar or tar options are
+ needed, they are linked to internally.
+
+config GUNZIP
+ bool "gunzip"
+ default n
+ help
+ gunzip is used to decompress archives created by gzip.
+ You can use the `-t' option to test the integrity of
+ an archive, without decompressing it.
+
+config FEATURE_GUNZIP_UNCOMPRESS
+ bool "Uncompress support"
+ default n
+ depends on GUNZIP
+ help
+ Enable if you want gunzip to have the ability to decompress
+ archives created by the program compress (not much
+ used anymore).
+
+config GZIP
+ bool "gzip"
+ default n
+ help
+ gzip is used to compress files.
+ It's probably the most widely used UNIX compression program.
+
+config RPM2CPIO
+ bool "rpm2cpio"
+ default n
+ help
+ Converts an RPM file into a CPIO archive.
+
+config RPM
+ bool "rpm"
+ default n
+ help
+ Mini RPM applet - queries and extracts RPM packages.
+
+config FEATURE_RPM_BZ2
+ bool "Enable handling of rpms with bzip2-compressed data inside"
+ default n
+ depends on RPM
+ help
+ Enable handling of rpms with bzip2-compressed data inside.
+
+config TAR
+ bool "tar"
+ default n
+ help
+ tar is an archiving program. It's commonly used with gzip to
+ create compressed archives. It's probably the most widely used
+ UNIX archive program.
+
+config FEATURE_TAR_CREATE
+ bool "Enable archive creation"
+ default y
+ depends on TAR
+ help
+ If you enable this option you'll be able to create
+ tar archives using the `-c' option.
+
+config FEATURE_TAR_GZIP
+ bool "Enable -z option"
+ default y
+ depends on TAR
+ help
+ If you enable this option tar will be able to call gzip,
+ when creating or extracting tar gziped archives.
+
+config FEATURE_TAR_BZIP2
+ bool "Enable -j option to handle .tar.bz2 files"
+ default n
+ depends on TAR
+ help
+ If you enable this option you'll be able to extract
+ archives compressed with bzip2.
+
+config FEATURE_TAR_LZMA
+ bool "Enable -a option to handle .tar.lzma files"
+ default n
+ depends on TAR
+ help
+ If you enable this option you'll be able to extract
+ archives compressed with lzma.
+
+config FEATURE_TAR_COMPRESS
+ bool "Enable -Z option"
+ default n
+ depends on TAR
+ help
+ If you enable this option tar will be able to call uncompress,
+ when extracting .tar.Z archives.
+
+config FEATURE_TAR_AUTODETECT
+ bool "Let tar autodetect gz/bz2 compresses tarballs"
+ default n
+ depends on FEATURE_TAR_GZIP || FEATURE_TAR_BZIP2
+ help
+ With this option tar can automatically detect gzip/bzip2 compressed
+ tarballs. Currently it works only on seekable streams.
+
+config FEATURE_TAR_FROM
+ bool "Enable -X (exclude from) and -T (include from) options)"
+ default n
+ depends on TAR
+ help
+ If you enable this option you'll be able to specify
+ a list of files to include or exclude from an archive.
+
+config FEATURE_TAR_OLDGNU_COMPATIBILITY
+ bool "Support for old tar header format"
+ default N
+ depends on TAR
+ help
+ This option is required to unpack archives created in
+ the old GNU format; help to kill this old format by
+ repacking your ancient archives with the new format.
+
+config FEATURE_TAR_OLDSUN_COMPATIBILITY
+ bool "Enable untarring of tarballs with checksums produced by buggy Sun tar"
+ default N
+ depends on TAR
+ help
+ This option is required to unpack archives created by some old
+ version of Sun's tar (it was calculating checksum using signed arithmetic).
+ It is said to be fixed in newer Sun tar, but "old" tarballs still exist.
+
+config FEATURE_TAR_GNU_EXTENSIONS
+ bool "Support for GNU tar extensions (long filenames)"
+ default y
+ depends on TAR
+ help
+ With this option busybox supports GNU long filenames and
+ linknames.
+
+config FEATURE_TAR_LONG_OPTIONS
+ bool "Enable long options"
+ default n
+ depends on TAR && GETOPT_LONG
+ help
+ Enable use of long options, increases size by about 400 Bytes
+
+config FEATURE_TAR_UNAME_GNAME
+ bool "Enable use of user and group names"
+ default n
+ depends on TAR
+ help
+ Enables use of user and group names in tar. This affects contents
+ listings (-t) and preserving permissions when unpacking (-p).
+ +200 bytes.
+
+config UNCOMPRESS
+ bool "uncompress"
+ default n
+ help
+ uncompress is used to decompress archives created by compress.
+ Not much used anymore, replaced by gzip/gunzip.
+
+config UNLZMA
+ bool "unlzma"
+ default n
+ help
+ unlzma is a compression utility using the Lempel-Ziv-Markov chain
+ compression algorithm, and range coding. Compression
+ is generally considerably better than that achieved by the bzip2
+ compressors.
+
+ The BusyBox unlzma applet is limited to de-compression only.
+ On an x86 system, this applet adds about 4K.
+
+ Unless you have a specific application which requires unlzma, you
+ should probably say N here.
+
+config FEATURE_LZMA_FAST
+ bool "Optimize unlzma for speed"
+ default n
+ depends on UNLZMA
+ help
+ This option reduces decompression time by about 33% at the cost of
+ a 2K bigger binary.
+
+config UNZIP
+ bool "unzip"
+ default n
+ help
+ unzip will list or extract files from a ZIP archive,
+ commonly found on DOS/WIN systems. The default behavior
+ (with no options) is to extract the archive into the
+ current directory. Use the `-d' option to extract to a
+ directory of your choice.
+
+comment "Common options for cpio and tar"
+ depends on CPIO || TAR
+
+comment "Common options for dpkg and dpkg_deb"
+ depends on DPKG || DPKG_DEB
+
+config FEATURE_DEB_TAR_GZ
+ bool "gzip debian packages (normal)"
+ default y if DPKG || DPKG_DEB
+ depends on DPKG || DPKG_DEB
+ help
+ This is the default compression method inside the debian ar file.
+
+ If you want compatibility with standard .deb's you should say yes here.
+
+config FEATURE_DEB_TAR_BZ2
+ bool "bzip2 debian packages"
+ default n
+ depends on DPKG || DPKG_DEB
+ help
+ This allows dpkg and dpkg-deb to extract deb's that are compressed internally
+ with bzip2 instead of gzip.
+
+ You only want this if you are creating your own custom debian packages that
+ use an internal control.tar.bz2 or data.tar.bz2.
+
+config FEATURE_DEB_TAR_LZMA
+ bool "lzma debian packages"
+ default n
+ depends on DPKG || DPKG_DEB
+ help
+ This allows dpkg and dpkg-deb to extract deb's that are compressed
+ internally with lzma instead of gzip.
+
+ You only want this if you are creating your own custom debian
+ packages that use an internal control.tar.lzma or data.tar.lzma.
+
+endmenu
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/Kbuild b/cleopatre/busybox-1.11.1-spc300/archival/Kbuild
new file mode 100644
index 0000000000..72dbdda0e7
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/Kbuild
@@ -0,0 +1,23 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+libs-y += libunarchive/
+
+lib-y:=
+lib-$(CONFIG_AR) += ar.o
+lib-$(CONFIG_BUNZIP2) += bbunzip.o
+lib-$(CONFIG_BZIP2) += bzip2.o bbunzip.o
+lib-$(CONFIG_UNLZMA) += bbunzip.o
+lib-$(CONFIG_CPIO) += cpio.o
+lib-$(CONFIG_DPKG) += dpkg.o
+lib-$(CONFIG_DPKG_DEB) += dpkg_deb.o
+lib-$(CONFIG_GUNZIP) += bbunzip.o
+lib-$(CONFIG_GZIP) += gzip.o bbunzip.o
+lib-$(CONFIG_RPM2CPIO) += rpm2cpio.o
+lib-$(CONFIG_RPM) += rpm.o
+lib-$(CONFIG_TAR) += tar.o
+lib-$(CONFIG_UNCOMPRESS) += bbunzip.o
+lib-$(CONFIG_UNZIP) += unzip.o
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/ar.c b/cleopatre/busybox-1.11.1-spc300/archival/ar.c
new file mode 100644
index 0000000000..0a95e5c854
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/ar.c
@@ -0,0 +1,95 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini ar implementation for busybox
+ *
+ * Copyright (C) 2000 by Glenn McGrath
+ *
+ * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ * There is no single standard to adhere to so ar may not portable
+ * between different systems
+ * http://www.unix-systems.org/single_unix_specification_v2/xcu/ar.html
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+static void header_verbose_list_ar(const file_header_t *file_header)
+{
+ const char *mode = bb_mode_string(file_header->mode);
+ char *mtime;
+
+ mtime = ctime(&file_header->mtime);
+ mtime[16] = ' ';
+ memmove(&mtime[17], &mtime[20], 4);
+ mtime[21] = '\0';
+ printf("%s %d/%d%7d %s %s\n", &mode[1], file_header->uid, file_header->gid,
+ (int) file_header->size, &mtime[4], file_header->name);
+}
+
+#define AR_CTX_PRINT 0x01
+#define AR_CTX_LIST 0x02
+#define AR_CTX_EXTRACT 0x04
+#define AR_OPT_PRESERVE_DATE 0x08
+#define AR_OPT_VERBOSE 0x10
+#define AR_OPT_CREATE 0x20
+#define AR_OPT_INSERT 0x40
+
+int ar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int ar_main(int argc, char **argv)
+{
+ static const char msg_unsupported_err[] ALIGN1 =
+ "archive %s is not supported";
+
+ archive_handle_t *archive_handle;
+ unsigned opt;
+ char magic[8];
+
+ archive_handle = init_handle();
+
+ /* Prepend '-' to the first argument if required */
+ opt_complementary = "--:p:t:x:-1:p--tx:t--px:x--pt";
+ opt = getopt32(argv, "ptxovcr");
+
+ if (opt & AR_CTX_PRINT) {
+ archive_handle->action_data = data_extract_to_stdout;
+ }
+ if (opt & AR_CTX_LIST) {
+ archive_handle->action_header = header_list;
+ }
+ if (opt & AR_CTX_EXTRACT) {
+ archive_handle->action_data = data_extract_all;
+ }
+ if (opt & AR_OPT_PRESERVE_DATE) {
+ archive_handle->flags |= ARCHIVE_PRESERVE_DATE;
+ }
+ if (opt & AR_OPT_VERBOSE) {
+ archive_handle->action_header = header_verbose_list_ar;
+ }
+ if (opt & AR_OPT_CREATE) {
+ bb_error_msg_and_die(msg_unsupported_err, "creation");
+ }
+ if (opt & AR_OPT_INSERT) {
+ bb_error_msg_and_die(msg_unsupported_err, "insertion");
+ }
+
+ archive_handle->src_fd = xopen(argv[optind++], O_RDONLY);
+
+ while (optind < argc) {
+ archive_handle->filter = filter_accept_list;
+ llist_add_to(&(archive_handle->accept), argv[optind++]);
+ }
+
+ xread(archive_handle->src_fd, magic, 7);
+ if (strncmp(magic, "!<arch>", 7) != 0) {
+ bb_error_msg_and_die("invalid ar magic");
+ }
+ archive_handle->offset += 7;
+
+ while (get_header_ar(archive_handle) == EXIT_SUCCESS)
+ continue;
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/bbunzip.c b/cleopatre/busybox-1.11.1-spc300/archival/bbunzip.c
new file mode 100644
index 0000000000..90d39f6828
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/bbunzip.c
@@ -0,0 +1,362 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Common code for gunzip-like applets
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+enum {
+ OPT_STDOUT = 0x1,
+ OPT_FORCE = 0x2,
+/* gunzip and bunzip2 only: */
+ OPT_VERBOSE = 0x4,
+ OPT_DECOMPRESS = 0x8,
+ OPT_TEST = 0x10,
+};
+
+static
+int open_to_or_warn(int to_fd, const char *filename, int flags, int mode)
+{
+ int fd = open3_or_warn(filename, flags, mode);
+ if (fd < 0) {
+ return 1;
+ }
+ xmove_fd(fd, to_fd);
+ return 0;
+}
+
+int bbunpack(char **argv,
+ char* (*make_new_name)(char *filename),
+ USE_DESKTOP(long long) int (*unpacker)(void)
+)
+{
+ struct stat stat_buf;
+ USE_DESKTOP(long long) int status;
+ char *filename, *new_name;
+ smallint exitcode = 0;
+
+ do {
+ /* NB: new_name is *maybe* malloc'ed! */
+ new_name = NULL;
+ filename = *argv; /* can be NULL - 'streaming' bunzip2 */
+
+ if (filename && LONE_DASH(filename))
+ filename = NULL;
+
+ /* Open src */
+ if (filename) {
+ if (stat(filename, &stat_buf) != 0) {
+ bb_simple_perror_msg(filename);
+ err:
+ exitcode = 1;
+ goto free_name;
+ }
+ if (open_to_or_warn(STDIN_FILENO, filename, O_RDONLY, 0))
+ goto err;
+ }
+
+ /* Special cases: test, stdout */
+ if (option_mask32 & (OPT_STDOUT|OPT_TEST)) {
+ if (option_mask32 & OPT_TEST)
+ if (open_to_or_warn(STDOUT_FILENO, bb_dev_null, O_WRONLY, 0))
+ goto err;
+ filename = NULL;
+ }
+
+ /* Open dst if we are going to unpack to file */
+ if (filename) {
+ new_name = make_new_name(filename);
+ if (!new_name) {
+ bb_error_msg("%s: unknown suffix - ignored", filename);
+ goto err;
+ }
+ /* O_EXCL: "real" bunzip2 doesn't overwrite files */
+ /* GNU gunzip does not bail out, but goes to next file */
+ if (open_to_or_warn(STDOUT_FILENO, new_name, O_WRONLY | O_CREAT | O_EXCL,
+ stat_buf.st_mode))
+ goto err;
+ }
+
+ /* Check that the input is sane */
+ if (isatty(STDIN_FILENO) && (option_mask32 & OPT_FORCE) == 0) {
+ bb_error_msg_and_die("compressed data not read from terminal, "
+ "use -f to force it");
+ }
+
+ status = unpacker();
+ if (status < 0)
+ exitcode = 1;
+
+ if (filename) {
+ char *del = new_name;
+ if (status >= 0) {
+ /* TODO: restore user/group/times here? */
+ /* Delete _compressed_ file */
+ del = filename;
+ /* restore extension (unless tgz -> tar case) */
+ if (new_name == filename)
+ filename[strlen(filename)] = '.';
+ }
+ xunlink(del);
+
+#if 0 /* Currently buggy - wrong name: "a.gz: 261% - replaced with a.gz" */
+ /* Extreme bloat for gunzip compat */
+ if (ENABLE_DESKTOP && (option_mask32 & OPT_VERBOSE) && status >= 0) {
+ fprintf(stderr, "%s: %u%% - replaced with %s\n",
+ filename, (unsigned)(stat_buf.st_size*100 / (status+1)), new_name);
+ }
+#endif
+
+ free_name:
+ if (new_name != filename)
+ free(new_name);
+ }
+ } while (*argv && *++argv);
+
+ return exitcode;
+}
+
+#if ENABLE_BUNZIP2 || ENABLE_UNLZMA || ENABLE_UNCOMPRESS
+
+static
+char* make_new_name_generic(char *filename, const char *expected_ext)
+{
+ char *extension = strrchr(filename, '.');
+ if (!extension || strcmp(extension + 1, expected_ext) != 0) {
+ /* Mimic GNU gunzip - "real" bunzip2 tries to */
+ /* unpack file anyway, to file.out */
+ return NULL;
+ }
+ *extension = '\0';
+ return filename;
+}
+
+#endif
+
+
+/*
+ * Modified for busybox by Glenn McGrath
+ * Added support output to stdout by Thomas Lundquist <thomasez@zelow.no>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#if ENABLE_BUNZIP2
+
+static
+char* make_new_name_bunzip2(char *filename)
+{
+ return make_new_name_generic(filename, "bz2");
+}
+
+static
+USE_DESKTOP(long long) int unpack_bunzip2(void)
+{
+ return unpack_bz2_stream(STDIN_FILENO, STDOUT_FILENO);
+}
+
+int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int bunzip2_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ getopt32(argv, "cfvdt");
+ argv += optind;
+ if (applet_name[2] == 'c')
+ option_mask32 |= OPT_STDOUT;
+
+ return bbunpack(argv, make_new_name_bunzip2, unpack_bunzip2);
+}
+
+#endif
+
+
+/*
+ * Gzip implementation for busybox
+ *
+ * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly.
+ *
+ * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
+ * based on gzip sources
+ *
+ * Adjusted further by Erik Andersen <andersen@codepoet.org> to support files as
+ * well as stdin/stdout, and to generally behave itself wrt command line
+ * handling.
+ *
+ * General cleanup to better adhere to the style guide and make use of standard
+ * busybox functions by Glenn McGrath
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * The unzip code was written and put in the public domain by Mark Adler.
+ * Portions of the lzw code are derived from the public domain 'compress'
+ * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
+ * Ken Turkowski, Dave Mack and Peter Jannesen.
+ *
+ * See the license_msg below and the file COPYING for the software license.
+ * See the file algorithm.doc for the compression algorithms and file formats.
+ */
+
+#if ENABLE_GUNZIP
+
+static
+char* make_new_name_gunzip(char *filename)
+{
+ char *extension = strrchr(filename, '.');
+
+ if (!extension)
+ return NULL;
+
+ extension++;
+ if (strcmp(extension, "tgz" + 1) == 0
+#if ENABLE_FEATURE_GUNZIP_UNCOMPRESS
+ || strcmp(extension, "Z") == 0
+#endif
+ ) {
+ extension[-1] = '\0';
+ } else if (strcmp(extension, "tgz") == 0) {
+ filename = xstrdup(filename);
+ extension = strrchr(filename, '.');
+ extension[2] = 'a';
+ extension[3] = 'r';
+ } else {
+ return NULL;
+ }
+ return filename;
+}
+
+static
+USE_DESKTOP(long long) int unpack_gunzip(void)
+{
+ USE_DESKTOP(long long) int status = -1;
+
+ /* do the decompression, and cleanup */
+ if (xread_char(STDIN_FILENO) == 0x1f) {
+ unsigned char magic2;
+
+ magic2 = xread_char(STDIN_FILENO);
+ if (ENABLE_FEATURE_GUNZIP_UNCOMPRESS && magic2 == 0x9d) {
+ status = uncompress(STDIN_FILENO, STDOUT_FILENO);
+ } else if (magic2 == 0x8b) {
+ status = unpack_gz_stream(STDIN_FILENO, STDOUT_FILENO);
+ } else {
+ goto bad_magic;
+ }
+ if (status < 0) {
+ bb_error_msg("error inflating");
+ }
+ } else {
+ bad_magic:
+ bb_error_msg("invalid magic");
+ /* status is still == -1 */
+ }
+ return status;
+}
+
+/*
+ * Linux kernel build uses gzip -d -n. We accept and ignore it.
+ * Man page says:
+ * -n --no-name
+ * gzip: do not save the original file name and time stamp.
+ * (The original name is always saved if the name had to be truncated.)
+ * gunzip: do not restore the original file name/time even if present
+ * (remove only the gzip suffix from the compressed file name).
+ * This option is the default when decompressing.
+ * -N --name
+ * gzip: always save the original file name and time stamp (this is the default)
+ * gunzip: restore the original file name and time stamp if present.
+ */
+
+int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int gunzip_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ getopt32(argv, "cfvdtn");
+ argv += optind;
+ /* if called as zcat */
+ if (applet_name[1] == 'c')
+ option_mask32 |= OPT_STDOUT;
+
+ return bbunpack(argv, make_new_name_gunzip, unpack_gunzip);
+}
+
+#endif
+
+
+/*
+ * Small lzma deflate implementation.
+ * Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
+ *
+ * Based on bunzip.c from busybox
+ *
+ * Licensed under GPL v2, see file LICENSE in this tarball for details.
+ */
+
+#if ENABLE_UNLZMA
+
+static
+char* make_new_name_unlzma(char *filename)
+{
+ return make_new_name_generic(filename, "lzma");
+}
+
+static
+USE_DESKTOP(long long) int unpack_unlzma(void)
+{
+ return unpack_lzma_stream(STDIN_FILENO, STDOUT_FILENO);
+}
+
+int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int unlzma_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ getopt32(argv, "cf");
+ argv += optind;
+ /* lzmacat? */
+ if (applet_name[4] == 'c')
+ option_mask32 |= OPT_STDOUT;
+
+ return bbunpack(argv, make_new_name_unlzma, unpack_unlzma);
+}
+
+#endif
+
+
+/*
+ * Uncompress applet for busybox (c) 2002 Glenn McGrath
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#if ENABLE_UNCOMPRESS
+
+static
+char* make_new_name_uncompress(char *filename)
+{
+ return make_new_name_generic(filename, "Z");
+}
+
+static
+USE_DESKTOP(long long) int unpack_uncompress(void)
+{
+ USE_DESKTOP(long long) int status = -1;
+
+ if ((xread_char(STDIN_FILENO) != 0x1f) || (xread_char(STDIN_FILENO) != 0x9d)) {
+ bb_error_msg("invalid magic");
+ } else {
+ status = uncompress(STDIN_FILENO, STDOUT_FILENO);
+ }
+ return status;
+}
+
+int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int uncompress_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ getopt32(argv, "cf");
+ argv += optind;
+
+ return bbunpack(argv, make_new_name_uncompress, unpack_uncompress);
+}
+
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/bbunzip_test.sh b/cleopatre/busybox-1.11.1-spc300/archival/bbunzip_test.sh
new file mode 100644
index 0000000000..b8e31bf973
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/bbunzip_test.sh
@@ -0,0 +1,61 @@
+#!/bin/sh
+# Test that concatenated gz files are unpacking correctly.
+# It also tests that unpacking in general is working right.
+# Since zip code has many corner cases, run it for a few hours
+# to get a decent coverage (200000 tests or more).
+
+gzip="gzip"
+gunzip="../busybox gunzip"
+# Or the other way around:
+#gzip="../busybox gzip"
+#gunzip="gunzip"
+
+c=0
+i=$PID
+while true; do
+ c=$((c+1))
+
+ # RANDOM is not very random on some shells. Spice it up.
+ # 100003 is prime
+ len1=$(( (((RANDOM*RANDOM)^i) & 0x7ffffff) % 100003 ))
+ i=$((i * 1664525 + 1013904223))
+ len2=$(( (((RANDOM*RANDOM)^i) & 0x7ffffff) % 100003 ))
+
+ # Just using urandom will make gzip use method 0 (store) -
+ # not good for test coverage!
+ cat /dev/urandom | while true; do read junk; echo "junk $c $i $junk"; done \
+ | dd bs=$len1 count=1 >z1 2>/dev/null
+ cat /dev/urandom | while true; do read junk; echo "junk $c $i $junk"; done \
+ | dd bs=$len2 count=1 >z2 2>/dev/null
+
+ $gzip <z1 >zz.gz
+ $gzip <z2 >>zz.gz
+ $gunzip -c zz.gz >z9 || {
+ echo "Exitcode $?"
+ exit
+ }
+ sum=`cat z1 z2 | md5sum`
+ sum9=`md5sum <z9`
+ test "$sum" == "$sum9" || {
+ echo "md5sums don't match"
+ exit
+ }
+ echo "Test $c ok: len1=$len1 len2=$len2 sum=$sum"
+
+ sum=`cat z1 z2 z1 z2 | md5sum`
+ rm z1.gz z2.gz 2>/dev/null
+ $gzip z1
+ $gzip z2
+ cat z1.gz z2.gz z1.gz z2.gz >zz.gz
+ $gunzip -c zz.gz >z9 || {
+ echo "Exitcode $? (2)"
+ exit
+ }
+ sum9=`md5sum <z9`
+ test "$sum" == "$sum9" || {
+ echo "md5sums don't match (1)"
+ exit
+ }
+
+ echo "Test $c ok: len1=$len1 len2=$len2 sum=$sum (2)"
+done
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/bbunzip_test2.sh b/cleopatre/busybox-1.11.1-spc300/archival/bbunzip_test2.sh
new file mode 100644
index 0000000000..5b7e83e132
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/bbunzip_test2.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+# Leak test for gunzip. Watch top for growing process size.
+
+# Just using urandom will make gzip use method 0 (store) -
+# not good for test coverage!
+
+cat /dev/urandom \
+| while true; do read junk; echo "junk $RANDOM $junk"; done \
+| ../busybox gzip \
+| ../busybox gunzip -c >/dev/null
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/bbunzip_test3.sh b/cleopatre/busybox-1.11.1-spc300/archival/bbunzip_test3.sh
new file mode 100644
index 0000000000..2dc4afda18
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/bbunzip_test3.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+# Leak test for gunzip. Watch top for growing process size.
+# In this case we look for leaks in "concatenated .gz" code -
+# we feed gunzip with a stream of .gz files.
+
+i=$PID
+c=0
+while true; do
+ c=$((c + 1))
+ echo "Block# $c" >&2
+ # RANDOM is not very random on some shells. Spice it up.
+ i=$((i * 1664525 + 1013904223))
+ # 100003 is prime
+ len=$(( (((RANDOM*RANDOM)^i) & 0x7ffffff) % 100003 ))
+
+ # Just using urandom will make gzip use method 0 (store) -
+ # not good for test coverage!
+ cat /dev/urandom \
+ | while true; do read junk; echo "junk $c $i $junk"; done \
+ | dd bs=$len count=1 2>/dev/null \
+ | gzip >xxx.gz
+ cat xxx.gz xxx.gz xxx.gz xxx.gz xxx.gz xxx.gz xxx.gz xxx.gz
+done | ../busybox gunzip -c >/dev/null
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/bz/LICENSE b/cleopatre/busybox-1.11.1-spc300/archival/bz/LICENSE
new file mode 100644
index 0000000000..da4346520f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/bz/LICENSE
@@ -0,0 +1,44 @@
+bzip2 applet in busybox is based on lightly-modified source
+of bzip2 version 1.0.4. bzip2 source is distributed
+under the following conditions (copied verbatim from LICENSE file)
+===========================================================
+
+
+This program, "bzip2", the associated library "libbzip2", and all
+documentation, are copyright (C) 1996-2006 Julian R Seward. All
+rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. The origin of this software must not be misrepresented; you must
+ not claim that you wrote the original software. If you use this
+ software in a product, an acknowledgment in the product
+ documentation would be appreciated but is not required.
+
+3. Altered source versions must be plainly marked as such, and must
+ not be misrepresented as being the original software.
+
+4. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Julian Seward, Cambridge, UK.
+jseward@bzip.org
+bzip2/libbzip2 version 1.0.4 of 20 December 2006
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/bz/README b/cleopatre/busybox-1.11.1-spc300/archival/bz/README
new file mode 100644
index 0000000000..3015342cb4
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/bz/README
@@ -0,0 +1,90 @@
+This file is an abridged version of README from bizp2 1.0.4
+Build instructions (which are not relevant to busyboxed bzip2)
+are removed.
+===========================================================
+
+
+This is the README for bzip2/libzip2.
+This version is fully compatible with the previous public releases.
+
+------------------------------------------------------------------
+This file is part of bzip2/libbzip2, a program and library for
+lossless, block-sorting data compression.
+
+bzip2/libbzip2 version 1.0.4 of 20 December 2006
+Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
+
+Please read the WARNING, DISCLAIMER and PATENTS sections in this file.
+
+This program is released under the terms of the license contained
+in the file LICENSE.
+------------------------------------------------------------------
+
+Please read and be aware of the following:
+
+
+WARNING:
+
+ This program and library (attempts to) compress data by
+ performing several non-trivial transformations on it.
+ Unless you are 100% familiar with *all* the algorithms
+ contained herein, and with the consequences of modifying them,
+ you should NOT meddle with the compression or decompression
+ machinery. Incorrect changes can and very likely *will*
+ lead to disastrous loss of data.
+
+
+DISCLAIMER:
+
+ I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE
+ USE OF THIS PROGRAM/LIBRARY, HOWSOEVER CAUSED.
+
+ Every compression of a file implies an assumption that the
+ compressed file can be decompressed to reproduce the original.
+ Great efforts in design, coding and testing have been made to
+ ensure that this program works correctly. However, the complexity
+ of the algorithms, and, in particular, the presence of various
+ special cases in the code which occur with very low but non-zero
+ probability make it impossible to rule out the possibility of bugs
+ remaining in the program. DO NOT COMPRESS ANY DATA WITH THIS
+ PROGRAM UNLESS YOU ARE PREPARED TO ACCEPT THE POSSIBILITY, HOWEVER
+ SMALL, THAT THE DATA WILL NOT BE RECOVERABLE.
+
+ That is not to say this program is inherently unreliable.
+ Indeed, I very much hope the opposite is true. bzip2/libbzip2
+ has been carefully constructed and extensively tested.
+
+
+PATENTS:
+
+ To the best of my knowledge, bzip2/libbzip2 does not use any
+ patented algorithms. However, I do not have the resources
+ to carry out a patent search. Therefore I cannot give any
+ guarantee of the above statement.
+
+
+I hope you find bzip2 useful. Feel free to contact me at
+ jseward@bzip.org
+if you have any suggestions or queries. Many people mailed me with
+comments, suggestions and patches after the releases of bzip-0.15,
+bzip-0.21, and bzip2 versions 0.1pl2, 0.9.0, 0.9.5, 1.0.0, 1.0.1,
+1.0.2 and 1.0.3, and the changes in bzip2 are largely a result of this
+feedback. I thank you for your comments.
+
+bzip2's "home" is http://www.bzip.org/
+
+Julian Seward
+jseward@bzip.org
+Cambridge, UK.
+
+18 July 1996 (version 0.15)
+25 August 1996 (version 0.21)
+ 7 August 1997 (bzip2, version 0.1)
+29 August 1997 (bzip2, version 0.1pl2)
+23 August 1998 (bzip2, version 0.9.0)
+ 8 June 1999 (bzip2, version 0.9.5)
+ 4 Sept 1999 (bzip2, version 0.9.5d)
+ 5 May 2000 (bzip2, version 1.0pre8)
+30 December 2001 (bzip2, version 1.0.2pre1)
+15 February 2005 (bzip2, version 1.0.3)
+20 December 2006 (bzip2, version 1.0.4)
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/bz/blocksort.c b/cleopatre/busybox-1.11.1-spc300/archival/bz/blocksort.c
new file mode 100644
index 0000000000..0e73ffeba8
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/bz/blocksort.c
@@ -0,0 +1,1072 @@
+/*
+ * bzip2 is written by Julian Seward <jseward@bzip.org>.
+ * Adapted for busybox by Denys Vlasenko <vda.linux@googlemail.com>.
+ * See README and LICENSE files in this directory for more information.
+ */
+
+/*-------------------------------------------------------------*/
+/*--- Block sorting machinery ---*/
+/*--- blocksort.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+This file is part of bzip2/libbzip2, a program and library for
+lossless, block-sorting data compression.
+
+bzip2/libbzip2 version 1.0.4 of 20 December 2006
+Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
+
+Please read the WARNING, DISCLAIMER and PATENTS sections in the
+README file.
+
+This program is released under the terms of the license contained
+in the file LICENSE.
+------------------------------------------------------------------ */
+
+/* #include "bzlib_private.h" */
+
+#define mswap(zz1, zz2) \
+{ \
+ int32_t zztmp = zz1; \
+ zz1 = zz2; \
+ zz2 = zztmp; \
+}
+
+static
+/* No measurable speed gain with inlining */
+/* ALWAYS_INLINE */
+void mvswap(uint32_t* ptr, int32_t zzp1, int32_t zzp2, int32_t zzn)
+{
+ while (zzn > 0) {
+ mswap(ptr[zzp1], ptr[zzp2]);
+ zzp1++;
+ zzp2++;
+ zzn--;
+ }
+}
+
+static
+ALWAYS_INLINE
+int32_t mmin(int32_t a, int32_t b)
+{
+ return (a < b) ? a : b;
+}
+
+
+/*---------------------------------------------*/
+/*--- Fallback O(N log(N)^2) sorting ---*/
+/*--- algorithm, for repetitive blocks ---*/
+/*---------------------------------------------*/
+
+/*---------------------------------------------*/
+static
+inline
+void fallbackSimpleSort(uint32_t* fmap,
+ uint32_t* eclass,
+ int32_t lo,
+ int32_t hi)
+{
+ int32_t i, j, tmp;
+ uint32_t ec_tmp;
+
+ if (lo == hi) return;
+
+ if (hi - lo > 3) {
+ for (i = hi-4; i >= lo; i--) {
+ tmp = fmap[i];
+ ec_tmp = eclass[tmp];
+ for (j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4)
+ fmap[j-4] = fmap[j];
+ fmap[j-4] = tmp;
+ }
+ }
+
+ for (i = hi-1; i >= lo; i--) {
+ tmp = fmap[i];
+ ec_tmp = eclass[tmp];
+ for (j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++)
+ fmap[j-1] = fmap[j];
+ fmap[j-1] = tmp;
+ }
+}
+
+
+/*---------------------------------------------*/
+#define fpush(lz,hz) { \
+ stackLo[sp] = lz; \
+ stackHi[sp] = hz; \
+ sp++; \
+}
+
+#define fpop(lz,hz) { \
+ sp--; \
+ lz = stackLo[sp]; \
+ hz = stackHi[sp]; \
+}
+
+#define FALLBACK_QSORT_SMALL_THRESH 10
+#define FALLBACK_QSORT_STACK_SIZE 100
+
+static
+void fallbackQSort3(uint32_t* fmap,
+ uint32_t* eclass,
+ int32_t loSt,
+ int32_t hiSt)
+{
+ int32_t unLo, unHi, ltLo, gtHi, n, m;
+ int32_t sp, lo, hi;
+ uint32_t med, r, r3;
+ int32_t stackLo[FALLBACK_QSORT_STACK_SIZE];
+ int32_t stackHi[FALLBACK_QSORT_STACK_SIZE];
+
+ r = 0;
+
+ sp = 0;
+ fpush(loSt, hiSt);
+
+ while (sp > 0) {
+ AssertH(sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004);
+
+ fpop(lo, hi);
+ if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) {
+ fallbackSimpleSort(fmap, eclass, lo, hi);
+ continue;
+ }
+
+ /* Random partitioning. Median of 3 sometimes fails to
+ * avoid bad cases. Median of 9 seems to help but
+ * looks rather expensive. This too seems to work but
+ * is cheaper. Guidance for the magic constants
+ * 7621 and 32768 is taken from Sedgewick's algorithms
+ * book, chapter 35.
+ */
+ r = ((r * 7621) + 1) % 32768;
+ r3 = r % 3;
+ if (r3 == 0)
+ med = eclass[fmap[lo]];
+ else if (r3 == 1)
+ med = eclass[fmap[(lo+hi)>>1]];
+ else
+ med = eclass[fmap[hi]];
+
+ unLo = ltLo = lo;
+ unHi = gtHi = hi;
+
+ while (1) {
+ while (1) {
+ if (unLo > unHi) break;
+ n = (int32_t)eclass[fmap[unLo]] - (int32_t)med;
+ if (n == 0) {
+ mswap(fmap[unLo], fmap[ltLo]);
+ ltLo++;
+ unLo++;
+ continue;
+ };
+ if (n > 0) break;
+ unLo++;
+ }
+ while (1) {
+ if (unLo > unHi) break;
+ n = (int32_t)eclass[fmap[unHi]] - (int32_t)med;
+ if (n == 0) {
+ mswap(fmap[unHi], fmap[gtHi]);
+ gtHi--; unHi--;
+ continue;
+ };
+ if (n < 0) break;
+ unHi--;
+ }
+ if (unLo > unHi) break;
+ mswap(fmap[unLo], fmap[unHi]); unLo++; unHi--;
+ }
+
+ AssertD(unHi == unLo-1, "fallbackQSort3(2)");
+
+ if (gtHi < ltLo) continue;
+
+ n = mmin(ltLo-lo, unLo-ltLo); mvswap(fmap, lo, unLo-n, n);
+ m = mmin(hi-gtHi, gtHi-unHi); mvswap(fmap, unLo, hi-m+1, m);
+
+ n = lo + unLo - ltLo - 1;
+ m = hi - (gtHi - unHi) + 1;
+
+ if (n - lo > hi - m) {
+ fpush(lo, n);
+ fpush(m, hi);
+ } else {
+ fpush(m, hi);
+ fpush(lo, n);
+ }
+ }
+}
+
+#undef fpush
+#undef fpop
+#undef FALLBACK_QSORT_SMALL_THRESH
+#undef FALLBACK_QSORT_STACK_SIZE
+
+
+/*---------------------------------------------*/
+/* Pre:
+ * nblock > 0
+ * eclass exists for [0 .. nblock-1]
+ * ((uint8_t*)eclass) [0 .. nblock-1] holds block
+ * ptr exists for [0 .. nblock-1]
+ *
+ * Post:
+ * ((uint8_t*)eclass) [0 .. nblock-1] holds block
+ * All other areas of eclass destroyed
+ * fmap [0 .. nblock-1] holds sorted order
+ * bhtab[0 .. 2+(nblock/32)] destroyed
+*/
+
+#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31))
+#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31))
+#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31)))
+#define WORD_BH(zz) bhtab[(zz) >> 5]
+#define UNALIGNED_BH(zz) ((zz) & 0x01f)
+
+static
+void fallbackSort(uint32_t* fmap,
+ uint32_t* eclass,
+ uint32_t* bhtab,
+ int32_t nblock)
+{
+ int32_t ftab[257];
+ int32_t ftabCopy[256];
+ int32_t H, i, j, k, l, r, cc, cc1;
+ int32_t nNotDone;
+ int32_t nBhtab;
+ uint8_t* eclass8 = (uint8_t*)eclass;
+
+ /*
+ * Initial 1-char radix sort to generate
+ * initial fmap and initial BH bits.
+ */
+ for (i = 0; i < 257; i++) ftab[i] = 0;
+ for (i = 0; i < nblock; i++) ftab[eclass8[i]]++;
+ for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i];
+
+ j = ftab[0]; /* bbox: optimized */
+ for (i = 1; i < 257; i++) {
+ j += ftab[i];
+ ftab[i] = j;
+ }
+
+ for (i = 0; i < nblock; i++) {
+ j = eclass8[i];
+ k = ftab[j] - 1;
+ ftab[j] = k;
+ fmap[k] = i;
+ }
+
+ nBhtab = 2 + ((uint32_t)nblock / 32); /* bbox: unsigned div is easier */
+ for (i = 0; i < nBhtab; i++) bhtab[i] = 0;
+ for (i = 0; i < 256; i++) SET_BH(ftab[i]);
+
+ /*
+ * Inductively refine the buckets. Kind-of an
+ * "exponential radix sort" (!), inspired by the
+ * Manber-Myers suffix array construction algorithm.
+ */
+
+ /*-- set sentinel bits for block-end detection --*/
+ for (i = 0; i < 32; i++) {
+ SET_BH(nblock + 2*i);
+ CLEAR_BH(nblock + 2*i + 1);
+ }
+
+ /*-- the log(N) loop --*/
+ H = 1;
+ while (1) {
+ j = 0;
+ for (i = 0; i < nblock; i++) {
+ if (ISSET_BH(i))
+ j = i;
+ k = fmap[i] - H;
+ if (k < 0)
+ k += nblock;
+ eclass[k] = j;
+ }
+
+ nNotDone = 0;
+ r = -1;
+ while (1) {
+
+ /*-- find the next non-singleton bucket --*/
+ k = r + 1;
+ while (ISSET_BH(k) && UNALIGNED_BH(k))
+ k++;
+ if (ISSET_BH(k)) {
+ while (WORD_BH(k) == 0xffffffff) k += 32;
+ while (ISSET_BH(k)) k++;
+ }
+ l = k - 1;
+ if (l >= nblock)
+ break;
+ while (!ISSET_BH(k) && UNALIGNED_BH(k))
+ k++;
+ if (!ISSET_BH(k)) {
+ while (WORD_BH(k) == 0x00000000) k += 32;
+ while (!ISSET_BH(k)) k++;
+ }
+ r = k - 1;
+ if (r >= nblock)
+ break;
+
+ /*-- now [l, r] bracket current bucket --*/
+ if (r > l) {
+ nNotDone += (r - l + 1);
+ fallbackQSort3(fmap, eclass, l, r);
+
+ /*-- scan bucket and generate header bits-- */
+ cc = -1;
+ for (i = l; i <= r; i++) {
+ cc1 = eclass[fmap[i]];
+ if (cc != cc1) {
+ SET_BH(i);
+ cc = cc1;
+ };
+ }
+ }
+ }
+
+ H *= 2;
+ if (H > nblock || nNotDone == 0)
+ break;
+ }
+
+ /*
+ * Reconstruct the original block in
+ * eclass8 [0 .. nblock-1], since the
+ * previous phase destroyed it.
+ */
+ j = 0;
+ for (i = 0; i < nblock; i++) {
+ while (ftabCopy[j] == 0)
+ j++;
+ ftabCopy[j]--;
+ eclass8[fmap[i]] = (uint8_t)j;
+ }
+ AssertH(j < 256, 1005);
+}
+
+#undef SET_BH
+#undef CLEAR_BH
+#undef ISSET_BH
+#undef WORD_BH
+#undef UNALIGNED_BH
+
+
+/*---------------------------------------------*/
+/*--- The main, O(N^2 log(N)) sorting ---*/
+/*--- algorithm. Faster for "normal" ---*/
+/*--- non-repetitive blocks. ---*/
+/*---------------------------------------------*/
+
+/*---------------------------------------------*/
+static
+NOINLINE
+int mainGtU(
+ uint32_t i1,
+ uint32_t i2,
+ uint8_t* block,
+ uint16_t* quadrant,
+ uint32_t nblock,
+ int32_t* budget)
+{
+ int32_t k;
+ uint8_t c1, c2;
+ uint16_t s1, s2;
+
+/* Loop unrolling here is actually very useful
+ * (generated code is much simpler),
+ * code size increase is only 270 bytes (i386)
+ * but speeds up compression 10% overall
+ */
+
+#if CONFIG_BZIP2_FEATURE_SPEED >= 1
+
+#define TIMES_8(code) \
+ code; code; code; code; \
+ code; code; code; code;
+#define TIMES_12(code) \
+ code; code; code; code; \
+ code; code; code; code; \
+ code; code; code; code;
+
+#else
+
+#define TIMES_8(code) \
+{ \
+ int nn = 8; \
+ do { \
+ code; \
+ } while (--nn); \
+}
+#define TIMES_12(code) \
+{ \
+ int nn = 12; \
+ do { \
+ code; \
+ } while (--nn); \
+}
+
+#endif
+
+ AssertD(i1 != i2, "mainGtU");
+ TIMES_12(
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ )
+
+ k = nblock + 8;
+
+ do {
+ TIMES_8(
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ )
+
+ if (i1 >= nblock) i1 -= nblock;
+ if (i2 >= nblock) i2 -= nblock;
+
+ (*budget)--;
+ k -= 8;
+ } while (k >= 0);
+
+ return False;
+}
+#undef TIMES_8
+#undef TIMES_12
+
+/*---------------------------------------------*/
+/*
+ * Knuth's increments seem to work better
+ * than Incerpi-Sedgewick here. Possibly
+ * because the number of elems to sort is
+ * usually small, typically <= 20.
+ */
+static
+const int32_t incs[14] = {
+ 1, 4, 13, 40, 121, 364, 1093, 3280,
+ 9841, 29524, 88573, 265720,
+ 797161, 2391484
+};
+
+static
+void mainSimpleSort(uint32_t* ptr,
+ uint8_t* block,
+ uint16_t* quadrant,
+ int32_t nblock,
+ int32_t lo,
+ int32_t hi,
+ int32_t d,
+ int32_t* budget)
+{
+ int32_t i, j, h, bigN, hp;
+ uint32_t v;
+
+ bigN = hi - lo + 1;
+ if (bigN < 2) return;
+
+ hp = 0;
+ while (incs[hp] < bigN) hp++;
+ hp--;
+
+ for (; hp >= 0; hp--) {
+ h = incs[hp];
+
+ i = lo + h;
+ while (1) {
+ /*-- copy 1 --*/
+ if (i > hi) break;
+ v = ptr[i];
+ j = i;
+ while (mainGtU(ptr[j-h]+d, v+d, block, quadrant, nblock, budget)) {
+ ptr[j] = ptr[j-h];
+ j = j - h;
+ if (j <= (lo + h - 1)) break;
+ }
+ ptr[j] = v;
+ i++;
+
+/* 1.5% overall speedup, +290 bytes */
+#if CONFIG_BZIP2_FEATURE_SPEED >= 3
+ /*-- copy 2 --*/
+ if (i > hi) break;
+ v = ptr[i];
+ j = i;
+ while (mainGtU(ptr[j-h]+d, v+d, block, quadrant, nblock, budget)) {
+ ptr[j] = ptr[j-h];
+ j = j - h;
+ if (j <= (lo + h - 1)) break;
+ }
+ ptr[j] = v;
+ i++;
+
+ /*-- copy 3 --*/
+ if (i > hi) break;
+ v = ptr[i];
+ j = i;
+ while (mainGtU(ptr[j-h]+d, v+d, block, quadrant, nblock, budget)) {
+ ptr[j] = ptr[j-h];
+ j = j - h;
+ if (j <= (lo + h - 1)) break;
+ }
+ ptr[j] = v;
+ i++;
+#endif
+ if (*budget < 0) return;
+ }
+ }
+}
+
+
+/*---------------------------------------------*/
+/*
+ * The following is an implementation of
+ * an elegant 3-way quicksort for strings,
+ * described in a paper "Fast Algorithms for
+ * Sorting and Searching Strings", by Robert
+ * Sedgewick and Jon L. Bentley.
+ */
+
+static
+ALWAYS_INLINE
+uint8_t mmed3(uint8_t a, uint8_t b, uint8_t c)
+{
+ uint8_t t;
+ if (a > b) {
+ t = a;
+ a = b;
+ b = t;
+ };
+ /* here b >= a */
+ if (b > c) {
+ b = c;
+ if (a > b)
+ b = a;
+ }
+ return b;
+}
+
+#define mpush(lz,hz,dz) \
+{ \
+ stackLo[sp] = lz; \
+ stackHi[sp] = hz; \
+ stackD [sp] = dz; \
+ sp++; \
+}
+
+#define mpop(lz,hz,dz) \
+{ \
+ sp--; \
+ lz = stackLo[sp]; \
+ hz = stackHi[sp]; \
+ dz = stackD [sp]; \
+}
+
+#define mnextsize(az) (nextHi[az] - nextLo[az])
+
+#define mnextswap(az,bz) \
+{ \
+ int32_t tz; \
+ tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \
+ tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \
+ tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; \
+}
+
+#define MAIN_QSORT_SMALL_THRESH 20
+#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT)
+#define MAIN_QSORT_STACK_SIZE 100
+
+static
+void mainQSort3(uint32_t* ptr,
+ uint8_t* block,
+ uint16_t* quadrant,
+ int32_t nblock,
+ int32_t loSt,
+ int32_t hiSt,
+ int32_t dSt,
+ int32_t* budget)
+{
+ int32_t unLo, unHi, ltLo, gtHi, n, m, med;
+ int32_t sp, lo, hi, d;
+
+ int32_t stackLo[MAIN_QSORT_STACK_SIZE];
+ int32_t stackHi[MAIN_QSORT_STACK_SIZE];
+ int32_t stackD [MAIN_QSORT_STACK_SIZE];
+
+ int32_t nextLo[3];
+ int32_t nextHi[3];
+ int32_t nextD [3];
+
+ sp = 0;
+ mpush(loSt, hiSt, dSt);
+
+ while (sp > 0) {
+ AssertH(sp < MAIN_QSORT_STACK_SIZE - 2, 1001);
+
+ mpop(lo, hi, d);
+ if (hi - lo < MAIN_QSORT_SMALL_THRESH
+ || d > MAIN_QSORT_DEPTH_THRESH
+ ) {
+ mainSimpleSort(ptr, block, quadrant, nblock, lo, hi, d, budget);
+ if (*budget < 0)
+ return;
+ continue;
+ }
+ med = (int32_t) mmed3(block[ptr[lo ] + d],
+ block[ptr[hi ] + d],
+ block[ptr[(lo+hi) >> 1] + d]);
+
+ unLo = ltLo = lo;
+ unHi = gtHi = hi;
+
+ while (1) {
+ while (1) {
+ if (unLo > unHi)
+ break;
+ n = ((int32_t)block[ptr[unLo]+d]) - med;
+ if (n == 0) {
+ mswap(ptr[unLo], ptr[ltLo]);
+ ltLo++;
+ unLo++;
+ continue;
+ };
+ if (n > 0) break;
+ unLo++;
+ }
+ while (1) {
+ if (unLo > unHi)
+ break;
+ n = ((int32_t)block[ptr[unHi]+d]) - med;
+ if (n == 0) {
+ mswap(ptr[unHi], ptr[gtHi]);
+ gtHi--;
+ unHi--;
+ continue;
+ };
+ if (n < 0) break;
+ unHi--;
+ }
+ if (unLo > unHi)
+ break;
+ mswap(ptr[unLo], ptr[unHi]);
+ unLo++;
+ unHi--;
+ }
+
+ AssertD(unHi == unLo-1, "mainQSort3(2)");
+
+ if (gtHi < ltLo) {
+ mpush(lo, hi, d + 1);
+ continue;
+ }
+
+ n = mmin(ltLo-lo, unLo-ltLo); mvswap(ptr, lo, unLo-n, n);
+ m = mmin(hi-gtHi, gtHi-unHi); mvswap(ptr, unLo, hi-m+1, m);
+
+ n = lo + unLo - ltLo - 1;
+ m = hi - (gtHi - unHi) + 1;
+
+ nextLo[0] = lo; nextHi[0] = n; nextD[0] = d;
+ nextLo[1] = m; nextHi[1] = hi; nextD[1] = d;
+ nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1;
+
+ if (mnextsize(0) < mnextsize(1)) mnextswap(0, 1);
+ if (mnextsize(1) < mnextsize(2)) mnextswap(1, 2);
+ if (mnextsize(0) < mnextsize(1)) mnextswap(0, 1);
+
+ AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)");
+ AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)");
+
+ mpush(nextLo[0], nextHi[0], nextD[0]);
+ mpush(nextLo[1], nextHi[1], nextD[1]);
+ mpush(nextLo[2], nextHi[2], nextD[2]);
+ }
+}
+
+#undef mpush
+#undef mpop
+#undef mnextsize
+#undef mnextswap
+#undef MAIN_QSORT_SMALL_THRESH
+#undef MAIN_QSORT_DEPTH_THRESH
+#undef MAIN_QSORT_STACK_SIZE
+
+
+/*---------------------------------------------*/
+/* Pre:
+ * nblock > N_OVERSHOOT
+ * block32 exists for [0 .. nblock-1 +N_OVERSHOOT]
+ * ((uint8_t*)block32) [0 .. nblock-1] holds block
+ * ptr exists for [0 .. nblock-1]
+ *
+ * Post:
+ * ((uint8_t*)block32) [0 .. nblock-1] holds block
+ * All other areas of block32 destroyed
+ * ftab[0 .. 65536] destroyed
+ * ptr [0 .. nblock-1] holds sorted order
+ * if (*budget < 0), sorting was abandoned
+ */
+
+#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8])
+#define SETMASK (1 << 21)
+#define CLEARMASK (~(SETMASK))
+
+static NOINLINE
+void mainSort(EState* state,
+ uint32_t* ptr,
+ uint8_t* block,
+ uint16_t* quadrant,
+ uint32_t* ftab,
+ int32_t nblock,
+ int32_t* budget)
+{
+ int32_t i, j, k, ss, sb;
+ uint8_t c1;
+ int32_t numQSorted;
+ uint16_t s;
+ Bool bigDone[256];
+ /* bbox: moved to EState to save stack
+ int32_t runningOrder[256];
+ int32_t copyStart[256];
+ int32_t copyEnd [256];
+ */
+#define runningOrder (state->mainSort__runningOrder)
+#define copyStart (state->mainSort__copyStart)
+#define copyEnd (state->mainSort__copyEnd)
+
+ /*-- set up the 2-byte frequency table --*/
+ /* was: for (i = 65536; i >= 0; i--) ftab[i] = 0; */
+ memset(ftab, 0, 65537 * sizeof(ftab[0]));
+
+ j = block[0] << 8;
+ i = nblock - 1;
+/* 3%, +300 bytes */
+#if CONFIG_BZIP2_FEATURE_SPEED >= 2
+ for (; i >= 3; i -= 4) {
+ quadrant[i] = 0;
+ j = (j >> 8) | (((uint16_t)block[i]) << 8);
+ ftab[j]++;
+ quadrant[i-1] = 0;
+ j = (j >> 8) | (((uint16_t)block[i-1]) << 8);
+ ftab[j]++;
+ quadrant[i-2] = 0;
+ j = (j >> 8) | (((uint16_t)block[i-2]) << 8);
+ ftab[j]++;
+ quadrant[i-3] = 0;
+ j = (j >> 8) | (((uint16_t)block[i-3]) << 8);
+ ftab[j]++;
+ }
+#endif
+ for (; i >= 0; i--) {
+ quadrant[i] = 0;
+ j = (j >> 8) | (((uint16_t)block[i]) << 8);
+ ftab[j]++;
+ }
+
+ /*-- (emphasises close relationship of block & quadrant) --*/
+ for (i = 0; i < BZ_N_OVERSHOOT; i++) {
+ block [nblock+i] = block[i];
+ quadrant[nblock+i] = 0;
+ }
+
+ /*-- Complete the initial radix sort --*/
+ j = ftab[0]; /* bbox: optimized */
+ for (i = 1; i <= 65536; i++) {
+ j += ftab[i];
+ ftab[i] = j;
+ }
+
+ s = block[0] << 8;
+ i = nblock - 1;
+#if CONFIG_BZIP2_FEATURE_SPEED >= 2
+ for (; i >= 3; i -= 4) {
+ s = (s >> 8) | (block[i] << 8);
+ j = ftab[s] - 1;
+ ftab[s] = j;
+ ptr[j] = i;
+ s = (s >> 8) | (block[i-1] << 8);
+ j = ftab[s] - 1;
+ ftab[s] = j;
+ ptr[j] = i-1;
+ s = (s >> 8) | (block[i-2] << 8);
+ j = ftab[s] - 1;
+ ftab[s] = j;
+ ptr[j] = i-2;
+ s = (s >> 8) | (block[i-3] << 8);
+ j = ftab[s] - 1;
+ ftab[s] = j;
+ ptr[j] = i-3;
+ }
+#endif
+ for (; i >= 0; i--) {
+ s = (s >> 8) | (block[i] << 8);
+ j = ftab[s] - 1;
+ ftab[s] = j;
+ ptr[j] = i;
+ }
+
+ /*
+ * Now ftab contains the first loc of every small bucket.
+ * Calculate the running order, from smallest to largest
+ * big bucket.
+ */
+ for (i = 0; i <= 255; i++) {
+ bigDone [i] = False;
+ runningOrder[i] = i;
+ }
+
+ {
+ int32_t vv;
+ /* bbox: was: int32_t h = 1; */
+ /* do h = 3 * h + 1; while (h <= 256); */
+ uint32_t h = 364;
+
+ do {
+ /*h = h / 3;*/
+ h = (h * 171) >> 9; /* bbox: fast h/3 */
+ for (i = h; i <= 255; i++) {
+ vv = runningOrder[i];
+ j = i;
+ while (BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv)) {
+ runningOrder[j] = runningOrder[j-h];
+ j = j - h;
+ if (j <= (h - 1))
+ goto zero;
+ }
+ zero:
+ runningOrder[j] = vv;
+ }
+ } while (h != 1);
+ }
+
+ /*
+ * The main sorting loop.
+ */
+
+ numQSorted = 0;
+
+ for (i = 0; i <= 255; i++) {
+
+ /*
+ * Process big buckets, starting with the least full.
+ * Basically this is a 3-step process in which we call
+ * mainQSort3 to sort the small buckets [ss, j], but
+ * also make a big effort to avoid the calls if we can.
+ */
+ ss = runningOrder[i];
+
+ /*
+ * Step 1:
+ * Complete the big bucket [ss] by quicksorting
+ * any unsorted small buckets [ss, j], for j != ss.
+ * Hopefully previous pointer-scanning phases have already
+ * completed many of the small buckets [ss, j], so
+ * we don't have to sort them at all.
+ */
+ for (j = 0; j <= 255; j++) {
+ if (j != ss) {
+ sb = (ss << 8) + j;
+ if (!(ftab[sb] & SETMASK)) {
+ int32_t lo = ftab[sb] & CLEARMASK;
+ int32_t hi = (ftab[sb+1] & CLEARMASK) - 1;
+ if (hi > lo) {
+ mainQSort3(
+ ptr, block, quadrant, nblock,
+ lo, hi, BZ_N_RADIX, budget
+ );
+ if (*budget < 0) return;
+ numQSorted += (hi - lo + 1);
+ }
+ }
+ ftab[sb] |= SETMASK;
+ }
+ }
+
+ AssertH(!bigDone[ss], 1006);
+
+ /*
+ * Step 2:
+ * Now scan this big bucket [ss] so as to synthesise the
+ * sorted order for small buckets [t, ss] for all t,
+ * including, magically, the bucket [ss,ss] too.
+ * This will avoid doing Real Work in subsequent Step 1's.
+ */
+ {
+ for (j = 0; j <= 255; j++) {
+ copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK;
+ copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1;
+ }
+ for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) {
+ k = ptr[j] - 1;
+ if (k < 0)
+ k += nblock;
+ c1 = block[k];
+ if (!bigDone[c1])
+ ptr[copyStart[c1]++] = k;
+ }
+ for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) {
+ k = ptr[j]-1;
+ if (k < 0)
+ k += nblock;
+ c1 = block[k];
+ if (!bigDone[c1])
+ ptr[copyEnd[c1]--] = k;
+ }
+ }
+
+ /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1.
+ * Necessity for this case is demonstrated by compressing
+ * a sequence of approximately 48.5 million of character
+ * 251; 1.0.0/1.0.1 will then die here. */
+ AssertH((copyStart[ss]-1 == copyEnd[ss]) \
+ || (copyStart[ss] == 0 && copyEnd[ss] == nblock-1), 1007);
+
+ for (j = 0; j <= 255; j++)
+ ftab[(j << 8) + ss] |= SETMASK;
+
+ /*
+ * Step 3:
+ * The [ss] big bucket is now done. Record this fact,
+ * and update the quadrant descriptors. Remember to
+ * update quadrants in the overshoot area too, if
+ * necessary. The "if (i < 255)" test merely skips
+ * this updating for the last bucket processed, since
+ * updating for the last bucket is pointless.
+ *
+ * The quadrant array provides a way to incrementally
+ * cache sort orderings, as they appear, so as to
+ * make subsequent comparisons in fullGtU() complete
+ * faster. For repetitive blocks this makes a big
+ * difference (but not big enough to be able to avoid
+ * the fallback sorting mechanism, exponential radix sort).
+ *
+ * The precise meaning is: at all times:
+ *
+ * for 0 <= i < nblock and 0 <= j <= nblock
+ *
+ * if block[i] != block[j],
+ *
+ * then the relative values of quadrant[i] and
+ * quadrant[j] are meaningless.
+ *
+ * else {
+ * if quadrant[i] < quadrant[j]
+ * then the string starting at i lexicographically
+ * precedes the string starting at j
+ *
+ * else if quadrant[i] > quadrant[j]
+ * then the string starting at j lexicographically
+ * precedes the string starting at i
+ *
+ * else
+ * the relative ordering of the strings starting
+ * at i and j has not yet been determined.
+ * }
+ */
+ bigDone[ss] = True;
+
+ if (i < 255) {
+ int32_t bbStart = ftab[ss << 8] & CLEARMASK;
+ int32_t bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart;
+ int32_t shifts = 0;
+
+ while ((bbSize >> shifts) > 65534) shifts++;
+
+ for (j = bbSize-1; j >= 0; j--) {
+ int32_t a2update = ptr[bbStart + j];
+ uint16_t qVal = (uint16_t)(j >> shifts);
+ quadrant[a2update] = qVal;
+ if (a2update < BZ_N_OVERSHOOT)
+ quadrant[a2update + nblock] = qVal;
+ }
+ AssertH(((bbSize-1) >> shifts) <= 65535, 1002);
+ }
+ }
+#undef runningOrder
+#undef copyStart
+#undef copyEnd
+}
+
+#undef BIGFREQ
+#undef SETMASK
+#undef CLEARMASK
+
+
+/*---------------------------------------------*/
+/* Pre:
+ * nblock > 0
+ * arr2 exists for [0 .. nblock-1 +N_OVERSHOOT]
+ * ((uint8_t*)arr2)[0 .. nblock-1] holds block
+ * arr1 exists for [0 .. nblock-1]
+ *
+ * Post:
+ * ((uint8_t*)arr2) [0 .. nblock-1] holds block
+ * All other areas of block destroyed
+ * ftab[0 .. 65536] destroyed
+ * arr1[0 .. nblock-1] holds sorted order
+ */
+static NOINLINE
+void BZ2_blockSort(EState* s)
+{
+ /* In original bzip2 1.0.4, it's a parameter, but 30
+ * (which was the default) should work ok. */
+ enum { wfact = 30 };
+
+ uint32_t* ptr = s->ptr;
+ uint8_t* block = s->block;
+ uint32_t* ftab = s->ftab;
+ int32_t nblock = s->nblock;
+ uint16_t* quadrant;
+ int32_t budget;
+ int32_t i;
+
+ if (nblock < 10000) {
+ fallbackSort(s->arr1, s->arr2, ftab, nblock);
+ } else {
+ /* Calculate the location for quadrant, remembering to get
+ * the alignment right. Assumes that &(block[0]) is at least
+ * 2-byte aligned -- this should be ok since block is really
+ * the first section of arr2.
+ */
+ i = nblock + BZ_N_OVERSHOOT;
+ if (i & 1) i++;
+ quadrant = (uint16_t*)(&(block[i]));
+
+ /* (wfact-1) / 3 puts the default-factor-30
+ * transition point at very roughly the same place as
+ * with v0.1 and v0.9.0.
+ * Not that it particularly matters any more, since the
+ * resulting compressed stream is now the same regardless
+ * of whether or not we use the main sort or fallback sort.
+ */
+ budget = nblock * ((wfact-1) / 3);
+
+ mainSort(s, ptr, block, quadrant, ftab, nblock, &budget);
+ if (budget < 0) {
+ fallbackSort(s->arr1, s->arr2, ftab, nblock);
+ }
+ }
+
+ s->origPtr = -1;
+ for (i = 0; i < s->nblock; i++)
+ if (ptr[i] == 0) {
+ s->origPtr = i;
+ break;
+ };
+
+ AssertH(s->origPtr != -1, 1003);
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end blocksort.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/bz/bzlib.c b/cleopatre/busybox-1.11.1-spc300/archival/bz/bzlib.c
new file mode 100644
index 0000000000..9957c2fbd7
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/bz/bzlib.c
@@ -0,0 +1,429 @@
+/*
+ * bzip2 is written by Julian Seward <jseward@bzip.org>.
+ * Adapted for busybox by Denys Vlasenko <vda.linux@googlemail.com>.
+ * See README and LICENSE files in this directory for more information.
+ */
+
+/*-------------------------------------------------------------*/
+/*--- Library top-level functions. ---*/
+/*--- bzlib.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+This file is part of bzip2/libbzip2, a program and library for
+lossless, block-sorting data compression.
+
+bzip2/libbzip2 version 1.0.4 of 20 December 2006
+Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
+
+Please read the WARNING, DISCLAIMER and PATENTS sections in the
+README file.
+
+This program is released under the terms of the license contained
+in the file LICENSE.
+------------------------------------------------------------------ */
+
+/* CHANGES
+ * 0.9.0 -- original version.
+ * 0.9.0a/b -- no changes in this file.
+ * 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress().
+ * fixed bzWrite/bzRead to ignore zero-length requests.
+ * fixed bzread to correctly handle read requests after EOF.
+ * wrong parameter order in call to bzDecompressInit in
+ * bzBuffToBuffDecompress. Fixed.
+ */
+
+/* #include "bzlib_private.h" */
+
+/*---------------------------------------------------*/
+/*--- Compression stuff ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+#if BZ_LIGHT_DEBUG
+static
+void bz_assert_fail(int errcode)
+{
+ /* if (errcode == 1007) bb_error_msg_and_die("probably bad RAM"); */
+ bb_error_msg_and_die("internal error %d", errcode);
+}
+#endif
+
+/*---------------------------------------------------*/
+static
+void prepare_new_block(EState* s)
+{
+ int i;
+ s->nblock = 0;
+ s->numZ = 0;
+ s->state_out_pos = 0;
+ BZ_INITIALISE_CRC(s->blockCRC);
+ /* inlined memset would be nice to have here */
+ for (i = 0; i < 256; i++)
+ s->inUse[i] = 0;
+ s->blockNo++;
+}
+
+
+/*---------------------------------------------------*/
+static
+ALWAYS_INLINE
+void init_RL(EState* s)
+{
+ s->state_in_ch = 256;
+ s->state_in_len = 0;
+}
+
+
+static
+int isempty_RL(EState* s)
+{
+ return (s->state_in_ch >= 256 || s->state_in_len <= 0);
+}
+
+
+/*---------------------------------------------------*/
+static
+void BZ2_bzCompressInit(bz_stream *strm, int blockSize100k)
+{
+ int32_t n;
+ EState* s;
+
+ s = xzalloc(sizeof(EState));
+ s->strm = strm;
+
+ n = 100000 * blockSize100k;
+ s->arr1 = xmalloc(n * sizeof(uint32_t));
+ s->mtfv = (uint16_t*)s->arr1;
+ s->ptr = (uint32_t*)s->arr1;
+ s->arr2 = xmalloc((n + BZ_N_OVERSHOOT) * sizeof(uint32_t));
+ s->block = (uint8_t*)s->arr2;
+ s->ftab = xmalloc(65537 * sizeof(uint32_t));
+
+ s->crc32table = crc32_filltable(NULL, 1);
+
+ s->state = BZ_S_INPUT;
+ s->mode = BZ_M_RUNNING;
+ s->blockSize100k = blockSize100k;
+ s->nblockMAX = n - 19;
+
+ strm->state = s;
+ /*strm->total_in = 0;*/
+ strm->total_out = 0;
+ init_RL(s);
+ prepare_new_block(s);
+}
+
+
+/*---------------------------------------------------*/
+static
+void add_pair_to_block(EState* s)
+{
+ int32_t i;
+ uint8_t ch = (uint8_t)(s->state_in_ch);
+ for (i = 0; i < s->state_in_len; i++) {
+ BZ_UPDATE_CRC(s, s->blockCRC, ch);
+ }
+ s->inUse[s->state_in_ch] = 1;
+ switch (s->state_in_len) {
+ case 3:
+ s->block[s->nblock] = (uint8_t)ch; s->nblock++;
+ /* fall through */
+ case 2:
+ s->block[s->nblock] = (uint8_t)ch; s->nblock++;
+ /* fall through */
+ case 1:
+ s->block[s->nblock] = (uint8_t)ch; s->nblock++;
+ break;
+ default:
+ s->inUse[s->state_in_len - 4] = 1;
+ s->block[s->nblock] = (uint8_t)ch; s->nblock++;
+ s->block[s->nblock] = (uint8_t)ch; s->nblock++;
+ s->block[s->nblock] = (uint8_t)ch; s->nblock++;
+ s->block[s->nblock] = (uint8_t)ch; s->nblock++;
+ s->block[s->nblock] = (uint8_t)(s->state_in_len - 4);
+ s->nblock++;
+ break;
+ }
+}
+
+
+/*---------------------------------------------------*/
+static
+void flush_RL(EState* s)
+{
+ if (s->state_in_ch < 256) add_pair_to_block(s);
+ init_RL(s);
+}
+
+
+/*---------------------------------------------------*/
+#define ADD_CHAR_TO_BLOCK(zs, zchh0) \
+{ \
+ uint32_t zchh = (uint32_t)(zchh0); \
+ /*-- fast track the common case --*/ \
+ if (zchh != zs->state_in_ch && zs->state_in_len == 1) { \
+ uint8_t ch = (uint8_t)(zs->state_in_ch); \
+ BZ_UPDATE_CRC(zs, zs->blockCRC, ch); \
+ zs->inUse[zs->state_in_ch] = 1; \
+ zs->block[zs->nblock] = (uint8_t)ch; \
+ zs->nblock++; \
+ zs->state_in_ch = zchh; \
+ } \
+ else \
+ /*-- general, uncommon cases --*/ \
+ if (zchh != zs->state_in_ch || zs->state_in_len == 255) { \
+ if (zs->state_in_ch < 256) \
+ add_pair_to_block(zs); \
+ zs->state_in_ch = zchh; \
+ zs->state_in_len = 1; \
+ } else { \
+ zs->state_in_len++; \
+ } \
+}
+
+
+/*---------------------------------------------------*/
+static
+void /*Bool*/ copy_input_until_stop(EState* s)
+{
+ /*Bool progress_in = False;*/
+
+#ifdef SAME_CODE_AS_BELOW
+ if (s->mode == BZ_M_RUNNING) {
+ /*-- fast track the common case --*/
+ while (1) {
+ /*-- no input? --*/
+ if (s->strm->avail_in == 0) break;
+ /*-- block full? --*/
+ if (s->nblock >= s->nblockMAX) break;
+ /*progress_in = True;*/
+ ADD_CHAR_TO_BLOCK(s, (uint32_t)(*(uint8_t*)(s->strm->next_in)));
+ s->strm->next_in++;
+ s->strm->avail_in--;
+ /*s->strm->total_in++;*/
+ }
+ } else
+#endif
+ {
+ /*-- general, uncommon case --*/
+ while (1) {
+ /*-- no input? --*/
+ if (s->strm->avail_in == 0) break;
+ /*-- block full? --*/
+ if (s->nblock >= s->nblockMAX) break;
+ //# /*-- flush/finish end? --*/
+ //# if (s->avail_in_expect == 0) break;
+ /*progress_in = True;*/
+ ADD_CHAR_TO_BLOCK(s, *(uint8_t*)(s->strm->next_in));
+ s->strm->next_in++;
+ s->strm->avail_in--;
+ /*s->strm->total_in++;*/
+ //# s->avail_in_expect--;
+ }
+ }
+ /*return progress_in;*/
+}
+
+
+/*---------------------------------------------------*/
+static
+void /*Bool*/ copy_output_until_stop(EState* s)
+{
+ /*Bool progress_out = False;*/
+
+ while (1) {
+ /*-- no output space? --*/
+ if (s->strm->avail_out == 0) break;
+
+ /*-- block done? --*/
+ if (s->state_out_pos >= s->numZ) break;
+
+ /*progress_out = True;*/
+ *(s->strm->next_out) = s->zbits[s->state_out_pos];
+ s->state_out_pos++;
+ s->strm->avail_out--;
+ s->strm->next_out++;
+ s->strm->total_out++;
+ }
+ /*return progress_out;*/
+}
+
+
+/*---------------------------------------------------*/
+static
+void /*Bool*/ handle_compress(bz_stream *strm)
+{
+ /*Bool progress_in = False;*/
+ /*Bool progress_out = False;*/
+ EState* s = strm->state;
+
+ while (1) {
+ if (s->state == BZ_S_OUTPUT) {
+ /*progress_out |=*/ copy_output_until_stop(s);
+ if (s->state_out_pos < s->numZ) break;
+ if (s->mode == BZ_M_FINISHING
+ //# && s->avail_in_expect == 0
+ && s->strm->avail_in == 0
+ && isempty_RL(s))
+ break;
+ prepare_new_block(s);
+ s->state = BZ_S_INPUT;
+#ifdef FLUSH_IS_UNUSED
+ if (s->mode == BZ_M_FLUSHING
+ && s->avail_in_expect == 0
+ && isempty_RL(s))
+ break;
+#endif
+ }
+
+ if (s->state == BZ_S_INPUT) {
+ /*progress_in |=*/ copy_input_until_stop(s);
+ //#if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) {
+ if (s->mode != BZ_M_RUNNING && s->strm->avail_in == 0) {
+ flush_RL(s);
+ BZ2_compressBlock(s, (s->mode == BZ_M_FINISHING));
+ s->state = BZ_S_OUTPUT;
+ } else
+ if (s->nblock >= s->nblockMAX) {
+ BZ2_compressBlock(s, 0);
+ s->state = BZ_S_OUTPUT;
+ } else
+ if (s->strm->avail_in == 0) {
+ break;
+ }
+ }
+ }
+
+ /*return progress_in || progress_out;*/
+}
+
+
+/*---------------------------------------------------*/
+static
+int BZ2_bzCompress(bz_stream *strm, int action)
+{
+ /*Bool progress;*/
+ EState* s;
+
+ s = strm->state;
+
+ switch (s->mode) {
+ case BZ_M_RUNNING:
+ if (action == BZ_RUN) {
+ /*progress =*/ handle_compress(strm);
+ /*return progress ? BZ_RUN_OK : BZ_PARAM_ERROR;*/
+ return BZ_RUN_OK;
+ }
+#ifdef FLUSH_IS_UNUSED
+ else
+ if (action == BZ_FLUSH) {
+ //#s->avail_in_expect = strm->avail_in;
+ s->mode = BZ_M_FLUSHING;
+ goto case_BZ_M_FLUSHING;
+ }
+#endif
+ else
+ /*if (action == BZ_FINISH)*/ {
+ //#s->avail_in_expect = strm->avail_in;
+ s->mode = BZ_M_FINISHING;
+ goto case_BZ_M_FINISHING;
+ }
+
+#ifdef FLUSH_IS_UNUSED
+ case_BZ_M_FLUSHING:
+ case BZ_M_FLUSHING:
+ /*if (s->avail_in_expect != s->strm->avail_in)
+ return BZ_SEQUENCE_ERROR;*/
+ /*progress =*/ handle_compress(strm);
+ if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ)
+ return BZ_FLUSH_OK;
+ s->mode = BZ_M_RUNNING;
+ return BZ_RUN_OK;
+#endif
+
+ case_BZ_M_FINISHING:
+ /*case BZ_M_FINISHING:*/
+ default:
+ /*if (s->avail_in_expect != s->strm->avail_in)
+ return BZ_SEQUENCE_ERROR;*/
+ /*progress =*/ handle_compress(strm);
+ /*if (!progress) return BZ_SEQUENCE_ERROR;*/
+ //#if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ)
+ //# return BZ_FINISH_OK;
+ if (s->strm->avail_in > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ)
+ return BZ_FINISH_OK;
+ /*s->mode = BZ_M_IDLE;*/
+ return BZ_STREAM_END;
+ }
+ /* return BZ_OK; --not reached--*/
+}
+
+
+/*---------------------------------------------------*/
+#if ENABLE_FEATURE_CLEAN_UP
+static
+void BZ2_bzCompressEnd(bz_stream *strm)
+{
+ EState* s;
+
+ s = strm->state;
+ free(s->arr1);
+ free(s->arr2);
+ free(s->ftab);
+ free(s->crc32table);
+ free(strm->state);
+}
+#endif
+
+
+/*---------------------------------------------------*/
+/*--- Misc convenience stuff ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+#ifdef EXAMPLE_CODE_FOR_MEM_TO_MEM_COMPRESSION
+static
+int BZ2_bzBuffToBuffCompress(char* dest,
+ unsigned int* destLen,
+ char* source,
+ unsigned int sourceLen,
+ int blockSize100k)
+{
+ bz_stream strm;
+ int ret;
+
+ if (dest == NULL || destLen == NULL ||
+ source == NULL ||
+ blockSize100k < 1 || blockSize100k > 9)
+ return BZ_PARAM_ERROR;
+
+ BZ2_bzCompressInit(&strm, blockSize100k);
+
+ strm.next_in = source;
+ strm.next_out = dest;
+ strm.avail_in = sourceLen;
+ strm.avail_out = *destLen;
+
+ ret = BZ2_bzCompress(&strm, BZ_FINISH);
+ if (ret == BZ_FINISH_OK) goto output_overflow;
+ if (ret != BZ_STREAM_END) goto errhandler;
+
+ /* normal termination */
+ *destLen -= strm.avail_out;
+ BZ2_bzCompressEnd(&strm);
+ return BZ_OK;
+
+ output_overflow:
+ BZ2_bzCompressEnd(&strm);
+ return BZ_OUTBUFF_FULL;
+
+ errhandler:
+ BZ2_bzCompressEnd(&strm);
+ return ret;
+}
+#endif
+
+/*-------------------------------------------------------------*/
+/*--- end bzlib.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/bz/bzlib.h b/cleopatre/busybox-1.11.1-spc300/archival/bz/bzlib.h
new file mode 100644
index 0000000000..1bb811c4a1
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/bz/bzlib.h
@@ -0,0 +1,65 @@
+/*
+ * bzip2 is written by Julian Seward <jseward@bzip.org>.
+ * Adapted for busybox by Denys Vlasenko <vda.linux@googlemail.com>.
+ * See README and LICENSE files in this directory for more information.
+ */
+
+/*-------------------------------------------------------------*/
+/*--- Public header file for the library. ---*/
+/*--- bzlib.h ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+This file is part of bzip2/libbzip2, a program and library for
+lossless, block-sorting data compression.
+
+bzip2/libbzip2 version 1.0.4 of 20 December 2006
+Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
+
+Please read the WARNING, DISCLAIMER and PATENTS sections in the
+README file.
+
+This program is released under the terms of the license contained
+in the file LICENSE.
+------------------------------------------------------------------ */
+
+#define BZ_RUN 0
+#define BZ_FLUSH 1
+#define BZ_FINISH 2
+
+#define BZ_OK 0
+#define BZ_RUN_OK 1
+#define BZ_FLUSH_OK 2
+#define BZ_FINISH_OK 3
+#define BZ_STREAM_END 4
+#define BZ_SEQUENCE_ERROR (-1)
+#define BZ_PARAM_ERROR (-2)
+#define BZ_MEM_ERROR (-3)
+#define BZ_DATA_ERROR (-4)
+#define BZ_DATA_ERROR_MAGIC (-5)
+#define BZ_IO_ERROR (-6)
+#define BZ_UNEXPECTED_EOF (-7)
+#define BZ_OUTBUFF_FULL (-8)
+#define BZ_CONFIG_ERROR (-9)
+
+typedef struct bz_stream {
+ void *state;
+ char *next_in;
+ char *next_out;
+ unsigned avail_in;
+ unsigned avail_out;
+ /*unsigned long long total_in;*/
+ unsigned long long total_out;
+} bz_stream;
+
+/*-- Core (low-level) library functions --*/
+
+static void BZ2_bzCompressInit(bz_stream *strm, int blockSize100k);
+static int BZ2_bzCompress(bz_stream *strm, int action);
+#if ENABLE_FEATURE_CLEAN_UP
+static void BZ2_bzCompressEnd(bz_stream *strm);
+#endif
+
+/*-------------------------------------------------------------*/
+/*--- end bzlib.h ---*/
+/*-------------------------------------------------------------*/
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/bz/bzlib_private.h b/cleopatre/busybox-1.11.1-spc300/archival/bz/bzlib_private.h
new file mode 100644
index 0000000000..48676a3915
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/bz/bzlib_private.h
@@ -0,0 +1,219 @@
+/*
+ * bzip2 is written by Julian Seward <jseward@bzip.org>.
+ * Adapted for busybox by Denys Vlasenko <vda.linux@googlemail.com>.
+ * See README and LICENSE files in this directory for more information.
+ */
+
+/*-------------------------------------------------------------*/
+/*--- Private header file for the library. ---*/
+/*--- bzlib_private.h ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+This file is part of bzip2/libbzip2, a program and library for
+lossless, block-sorting data compression.
+
+bzip2/libbzip2 version 1.0.4 of 20 December 2006
+Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
+
+Please read the WARNING, DISCLAIMER and PATENTS sections in the
+README file.
+
+This program is released under the terms of the license contained
+in the file LICENSE.
+------------------------------------------------------------------ */
+
+/* #include "bzlib.h" */
+
+/*-- General stuff. --*/
+
+typedef unsigned char Bool;
+
+#define True ((Bool)1)
+#define False ((Bool)0)
+
+#if BZ_LIGHT_DEBUG
+static void bz_assert_fail(int errcode) ATTRIBUTE_NORETURN;
+#define AssertH(cond, errcode) \
+do { \
+ if (!(cond)) \
+ bz_assert_fail(errcode); \
+} while (0)
+#else
+#define AssertH(cond, msg) do { } while (0)
+#endif
+
+#if BZ_DEBUG
+#define AssertD(cond, msg) \
+do { \
+ if (!(cond)) \
+ bb_error_msg_and_die("(debug build): internal error %s", msg); \
+} while (0)
+#else
+#define AssertD(cond, msg) do { } while (0)
+#endif
+
+
+/*-- Header bytes. --*/
+
+#define BZ_HDR_B 0x42 /* 'B' */
+#define BZ_HDR_Z 0x5a /* 'Z' */
+#define BZ_HDR_h 0x68 /* 'h' */
+#define BZ_HDR_0 0x30 /* '0' */
+
+#define BZ_HDR_BZh0 0x425a6830
+
+/*-- Constants for the back end. --*/
+
+#define BZ_MAX_ALPHA_SIZE 258
+#define BZ_MAX_CODE_LEN 23
+
+#define BZ_RUNA 0
+#define BZ_RUNB 1
+
+#define BZ_N_GROUPS 6
+#define BZ_G_SIZE 50
+#define BZ_N_ITERS 4
+
+#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE))
+
+
+/*-- Stuff for doing CRCs. --*/
+
+#define BZ_INITIALISE_CRC(crcVar) \
+{ \
+ crcVar = 0xffffffffL; \
+}
+
+#define BZ_FINALISE_CRC(crcVar) \
+{ \
+ crcVar = ~(crcVar); \
+}
+
+#define BZ_UPDATE_CRC(s, crcVar, cha) \
+{ \
+ crcVar = (crcVar << 8) ^ s->crc32table[(crcVar >> 24) ^ ((uint8_t)cha)]; \
+}
+
+
+/*-- States and modes for compression. --*/
+
+#define BZ_M_IDLE 1
+#define BZ_M_RUNNING 2
+#define BZ_M_FLUSHING 3
+#define BZ_M_FINISHING 4
+
+#define BZ_S_OUTPUT 1
+#define BZ_S_INPUT 2
+
+#define BZ_N_RADIX 2
+#define BZ_N_QSORT 12
+#define BZ_N_SHELL 18
+#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2)
+
+
+/*-- Structure holding all the compression-side stuff. --*/
+
+typedef struct EState {
+ /* pointer back to the struct bz_stream */
+ bz_stream *strm;
+
+ /* mode this stream is in, and whether inputting */
+ /* or outputting data */
+ int32_t mode;
+ int32_t state;
+
+ /* remembers avail_in when flush/finish requested */
+/* bbox: not needed, strm->avail_in always has the same value */
+/* commented out with '//#' throughout the code */
+ /* uint32_t avail_in_expect; */
+
+ /* for doing the block sorting */
+ int32_t origPtr;
+ uint32_t *arr1;
+ uint32_t *arr2;
+ uint32_t *ftab;
+
+ /* aliases for arr1 and arr2 */
+ uint32_t *ptr;
+ uint8_t *block;
+ uint16_t *mtfv;
+ uint8_t *zbits;
+
+ /* guess what */
+ uint32_t *crc32table;
+
+ /* run-length-encoding of the input */
+ uint32_t state_in_ch;
+ int32_t state_in_len;
+
+ /* input and output limits and current posns */
+ int32_t nblock;
+ int32_t nblockMAX;
+ int32_t numZ;
+ int32_t state_out_pos;
+
+ /* the buffer for bit stream creation */
+ uint32_t bsBuff;
+ int32_t bsLive;
+
+ /* block and combined CRCs */
+ uint32_t blockCRC;
+ uint32_t combinedCRC;
+
+ /* misc administratium */
+ int32_t blockNo;
+ int32_t blockSize100k;
+
+ /* stuff for coding the MTF values */
+ int32_t nMTF;
+
+ /* map of bytes used in block */
+ int32_t nInUse;
+ Bool inUse[256] __attribute__(( aligned(sizeof(long)) ));
+ uint8_t unseqToSeq[256];
+
+ /* stuff for coding the MTF values */
+ int32_t mtfFreq [BZ_MAX_ALPHA_SIZE];
+ uint8_t selector [BZ_MAX_SELECTORS];
+ uint8_t selectorMtf[BZ_MAX_SELECTORS];
+
+ uint8_t len[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+
+ /* stack-saving measures: these can be local, but they are too big */
+ int32_t sendMTFValues__code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ int32_t sendMTFValues__rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+#if CONFIG_BZIP2_FEATURE_SPEED >= 5
+ /* second dimension: only 3 needed; 4 makes index calculations faster */
+ uint32_t sendMTFValues__len_pack[BZ_MAX_ALPHA_SIZE][4];
+#endif
+ int32_t BZ2_hbMakeCodeLengths__heap [BZ_MAX_ALPHA_SIZE + 2];
+ int32_t BZ2_hbMakeCodeLengths__weight[BZ_MAX_ALPHA_SIZE * 2];
+ int32_t BZ2_hbMakeCodeLengths__parent[BZ_MAX_ALPHA_SIZE * 2];
+
+ int32_t mainSort__runningOrder[256];
+ int32_t mainSort__copyStart[256];
+ int32_t mainSort__copyEnd[256];
+} EState;
+
+
+/*-- compression. --*/
+
+static void
+BZ2_blockSort(EState*);
+
+static void
+BZ2_compressBlock(EState*, int);
+
+static void
+BZ2_bsInitWrite(EState*);
+
+static void
+BZ2_hbAssignCodes(int32_t*, uint8_t*, int32_t, int32_t, int32_t);
+
+static void
+BZ2_hbMakeCodeLengths(EState*, uint8_t*, int32_t*, int32_t, int32_t);
+
+/*-------------------------------------------------------------*/
+/*--- end bzlib_private.h ---*/
+/*-------------------------------------------------------------*/
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/bz/compress.c b/cleopatre/busybox-1.11.1-spc300/archival/bz/compress.c
new file mode 100644
index 0000000000..640b8872be
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/bz/compress.c
@@ -0,0 +1,687 @@
+/*
+ * bzip2 is written by Julian Seward <jseward@bzip.org>.
+ * Adapted for busybox by Denys Vlasenko <vda.linux@googlemail.com>.
+ * See README and LICENSE files in this directory for more information.
+ */
+
+/*-------------------------------------------------------------*/
+/*--- Compression machinery (not incl block sorting) ---*/
+/*--- compress.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+This file is part of bzip2/libbzip2, a program and library for
+lossless, block-sorting data compression.
+
+bzip2/libbzip2 version 1.0.4 of 20 December 2006
+Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
+
+Please read the WARNING, DISCLAIMER and PATENTS sections in the
+README file.
+
+This program is released under the terms of the license contained
+in the file LICENSE.
+------------------------------------------------------------------ */
+
+/* CHANGES
+ * 0.9.0 -- original version.
+ * 0.9.0a/b -- no changes in this file.
+ * 0.9.0c -- changed setting of nGroups in sendMTFValues()
+ * so as to do a bit better on small files
+*/
+
+/* #include "bzlib_private.h" */
+
+/*---------------------------------------------------*/
+/*--- Bit stream I/O ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+static
+void BZ2_bsInitWrite(EState* s)
+{
+ s->bsLive = 0;
+ s->bsBuff = 0;
+}
+
+
+/*---------------------------------------------------*/
+static NOINLINE
+void bsFinishWrite(EState* s)
+{
+ while (s->bsLive > 0) {
+ s->zbits[s->numZ] = (uint8_t)(s->bsBuff >> 24);
+ s->numZ++;
+ s->bsBuff <<= 8;
+ s->bsLive -= 8;
+ }
+}
+
+
+/*---------------------------------------------------*/
+static
+/* Helps only on level 5, on other levels hurts. ? */
+#if CONFIG_BZIP2_FEATURE_SPEED >= 5
+ALWAYS_INLINE
+#endif
+void bsW(EState* s, int32_t n, uint32_t v)
+{
+ while (s->bsLive >= 8) {
+ s->zbits[s->numZ] = (uint8_t)(s->bsBuff >> 24);
+ s->numZ++;
+ s->bsBuff <<= 8;
+ s->bsLive -= 8;
+ }
+ s->bsBuff |= (v << (32 - s->bsLive - n));
+ s->bsLive += n;
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsPutU32(EState* s, unsigned u)
+{
+ bsW(s, 8, (u >> 24) & 0xff);
+ bsW(s, 8, (u >> 16) & 0xff);
+ bsW(s, 8, (u >> 8) & 0xff);
+ bsW(s, 8, u & 0xff);
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsPutU16(EState* s, unsigned u)
+{
+ bsW(s, 8, (u >> 8) & 0xff);
+ bsW(s, 8, u & 0xff);
+}
+
+
+/*---------------------------------------------------*/
+/*--- The back end proper ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+static
+void makeMaps_e(EState* s)
+{
+ int i;
+ s->nInUse = 0;
+ for (i = 0; i < 256; i++) {
+ if (s->inUse[i]) {
+ s->unseqToSeq[i] = s->nInUse;
+ s->nInUse++;
+ }
+ }
+}
+
+
+/*---------------------------------------------------*/
+static NOINLINE
+void generateMTFValues(EState* s)
+{
+ uint8_t yy[256];
+ int32_t i, j;
+ int32_t zPend;
+ int32_t wr;
+ int32_t EOB;
+
+ /*
+ * After sorting (eg, here),
+ * s->arr1[0 .. s->nblock-1] holds sorted order,
+ * and
+ * ((uint8_t*)s->arr2)[0 .. s->nblock-1]
+ * holds the original block data.
+ *
+ * The first thing to do is generate the MTF values,
+ * and put them in
+ * ((uint16_t*)s->arr1)[0 .. s->nblock-1].
+ * Because there are strictly fewer or equal MTF values
+ * than block values, ptr values in this area are overwritten
+ * with MTF values only when they are no longer needed.
+ *
+ * The final compressed bitstream is generated into the
+ * area starting at
+ * &((uint8_t*)s->arr2)[s->nblock]
+ *
+ * These storage aliases are set up in bzCompressInit(),
+ * except for the last one, which is arranged in
+ * compressBlock().
+ */
+ uint32_t* ptr = s->ptr;
+ uint8_t* block = s->block;
+ uint16_t* mtfv = s->mtfv;
+
+ makeMaps_e(s);
+ EOB = s->nInUse+1;
+
+ for (i = 0; i <= EOB; i++)
+ s->mtfFreq[i] = 0;
+
+ wr = 0;
+ zPend = 0;
+ for (i = 0; i < s->nInUse; i++)
+ yy[i] = (uint8_t) i;
+
+ for (i = 0; i < s->nblock; i++) {
+ uint8_t ll_i;
+ AssertD(wr <= i, "generateMTFValues(1)");
+ j = ptr[i] - 1;
+ if (j < 0)
+ j += s->nblock;
+ ll_i = s->unseqToSeq[block[j]];
+ AssertD(ll_i < s->nInUse, "generateMTFValues(2a)");
+
+ if (yy[0] == ll_i) {
+ zPend++;
+ } else {
+ if (zPend > 0) {
+ zPend--;
+ while (1) {
+ if (zPend & 1) {
+ mtfv[wr] = BZ_RUNB; wr++;
+ s->mtfFreq[BZ_RUNB]++;
+ } else {
+ mtfv[wr] = BZ_RUNA; wr++;
+ s->mtfFreq[BZ_RUNA]++;
+ }
+ if (zPend < 2) break;
+ zPend = (uint32_t)(zPend - 2) / 2;
+ /* bbox: unsigned div is easier */
+ };
+ zPend = 0;
+ }
+ {
+ register uint8_t rtmp;
+ register uint8_t* ryy_j;
+ register uint8_t rll_i;
+ rtmp = yy[1];
+ yy[1] = yy[0];
+ ryy_j = &(yy[1]);
+ rll_i = ll_i;
+ while (rll_i != rtmp) {
+ register uint8_t rtmp2;
+ ryy_j++;
+ rtmp2 = rtmp;
+ rtmp = *ryy_j;
+ *ryy_j = rtmp2;
+ };
+ yy[0] = rtmp;
+ j = ryy_j - &(yy[0]);
+ mtfv[wr] = j+1;
+ wr++;
+ s->mtfFreq[j+1]++;
+ }
+
+ }
+ }
+
+ if (zPend > 0) {
+ zPend--;
+ while (1) {
+ if (zPend & 1) {
+ mtfv[wr] = BZ_RUNB;
+ wr++;
+ s->mtfFreq[BZ_RUNB]++;
+ } else {
+ mtfv[wr] = BZ_RUNA;
+ wr++;
+ s->mtfFreq[BZ_RUNA]++;
+ }
+ if (zPend < 2)
+ break;
+ zPend = (uint32_t)(zPend - 2) / 2;
+ /* bbox: unsigned div is easier */
+ };
+ zPend = 0;
+ }
+
+ mtfv[wr] = EOB;
+ wr++;
+ s->mtfFreq[EOB]++;
+
+ s->nMTF = wr;
+}
+
+
+/*---------------------------------------------------*/
+#define BZ_LESSER_ICOST 0
+#define BZ_GREATER_ICOST 15
+
+static NOINLINE
+void sendMTFValues(EState* s)
+{
+ int32_t v, t, i, j, gs, ge, totc, bt, bc, iter;
+ int32_t nSelectors, alphaSize, minLen, maxLen, selCtr;
+ int32_t nGroups, nBytes;
+
+ /*
+ * uint8_t len[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ * is a global since the decoder also needs it.
+ *
+ * int32_t code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ * int32_t rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ * are also globals only used in this proc.
+ * Made global to keep stack frame size small.
+ */
+#define code sendMTFValues__code
+#define rfreq sendMTFValues__rfreq
+#define len_pack sendMTFValues__len_pack
+
+ uint16_t cost[BZ_N_GROUPS];
+ int32_t fave[BZ_N_GROUPS];
+
+ uint16_t* mtfv = s->mtfv;
+
+ alphaSize = s->nInUse + 2;
+ for (t = 0; t < BZ_N_GROUPS; t++)
+ for (v = 0; v < alphaSize; v++)
+ s->len[t][v] = BZ_GREATER_ICOST;
+
+ /*--- Decide how many coding tables to use ---*/
+ AssertH(s->nMTF > 0, 3001);
+ if (s->nMTF < 200) nGroups = 2; else
+ if (s->nMTF < 600) nGroups = 3; else
+ if (s->nMTF < 1200) nGroups = 4; else
+ if (s->nMTF < 2400) nGroups = 5; else
+ nGroups = 6;
+
+ /*--- Generate an initial set of coding tables ---*/
+ {
+ int32_t nPart, remF, tFreq, aFreq;
+
+ nPart = nGroups;
+ remF = s->nMTF;
+ gs = 0;
+ while (nPart > 0) {
+ tFreq = remF / nPart;
+ ge = gs - 1;
+ aFreq = 0;
+ while (aFreq < tFreq && ge < alphaSize-1) {
+ ge++;
+ aFreq += s->mtfFreq[ge];
+ }
+
+ if (ge > gs
+ && nPart != nGroups && nPart != 1
+ && ((nGroups - nPart) % 2 == 1) /* bbox: can this be replaced by x & 1? */
+ ) {
+ aFreq -= s->mtfFreq[ge];
+ ge--;
+ }
+
+ for (v = 0; v < alphaSize; v++)
+ if (v >= gs && v <= ge)
+ s->len[nPart-1][v] = BZ_LESSER_ICOST;
+ else
+ s->len[nPart-1][v] = BZ_GREATER_ICOST;
+
+ nPart--;
+ gs = ge + 1;
+ remF -= aFreq;
+ }
+ }
+
+ /*
+ * Iterate up to BZ_N_ITERS times to improve the tables.
+ */
+ for (iter = 0; iter < BZ_N_ITERS; iter++) {
+ for (t = 0; t < nGroups; t++)
+ fave[t] = 0;
+
+ for (t = 0; t < nGroups; t++)
+ for (v = 0; v < alphaSize; v++)
+ s->rfreq[t][v] = 0;
+
+#if CONFIG_BZIP2_FEATURE_SPEED >= 5
+ /*
+ * Set up an auxiliary length table which is used to fast-track
+ * the common case (nGroups == 6).
+ */
+ if (nGroups == 6) {
+ for (v = 0; v < alphaSize; v++) {
+ s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v];
+ s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v];
+ s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v];
+ }
+ }
+#endif
+ nSelectors = 0;
+ totc = 0;
+ gs = 0;
+ while (1) {
+ /*--- Set group start & end marks. --*/
+ if (gs >= s->nMTF)
+ break;
+ ge = gs + BZ_G_SIZE - 1;
+ if (ge >= s->nMTF)
+ ge = s->nMTF-1;
+
+ /*
+ * Calculate the cost of this group as coded
+ * by each of the coding tables.
+ */
+ for (t = 0; t < nGroups; t++)
+ cost[t] = 0;
+#if CONFIG_BZIP2_FEATURE_SPEED >= 5
+ if (nGroups == 6 && 50 == ge-gs+1) {
+ /*--- fast track the common case ---*/
+ register uint32_t cost01, cost23, cost45;
+ register uint16_t icv;
+ cost01 = cost23 = cost45 = 0;
+#define BZ_ITER(nn) \
+ icv = mtfv[gs+(nn)]; \
+ cost01 += s->len_pack[icv][0]; \
+ cost23 += s->len_pack[icv][1]; \
+ cost45 += s->len_pack[icv][2];
+ BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4);
+ BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9);
+ BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14);
+ BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19);
+ BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24);
+ BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29);
+ BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34);
+ BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39);
+ BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44);
+ BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49);
+#undef BZ_ITER
+ cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16;
+ cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16;
+ cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16;
+
+ } else
+#endif
+ {
+ /*--- slow version which correctly handles all situations ---*/
+ for (i = gs; i <= ge; i++) {
+ uint16_t icv = mtfv[i];
+ for (t = 0; t < nGroups; t++)
+ cost[t] += s->len[t][icv];
+ }
+ }
+ /*
+ * Find the coding table which is best for this group,
+ * and record its identity in the selector table.
+ */
+ /*bc = 999999999;*/
+ /*bt = -1;*/
+ bc = cost[0];
+ bt = 0;
+ for (t = 1 /*0*/; t < nGroups; t++) {
+ if (cost[t] < bc) {
+ bc = cost[t];
+ bt = t;
+ }
+ }
+ totc += bc;
+ fave[bt]++;
+ s->selector[nSelectors] = bt;
+ nSelectors++;
+
+ /*
+ * Increment the symbol frequencies for the selected table.
+ */
+/* 1% faster compress. +800 bytes */
+#if CONFIG_BZIP2_FEATURE_SPEED >= 4
+ if (nGroups == 6 && 50 == ge-gs+1) {
+ /*--- fast track the common case ---*/
+#define BZ_ITUR(nn) s->rfreq[bt][mtfv[gs + (nn)]]++
+ BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4);
+ BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9);
+ BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14);
+ BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19);
+ BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24);
+ BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29);
+ BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34);
+ BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39);
+ BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44);
+ BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49);
+#undef BZ_ITUR
+ gs = ge + 1;
+ } else
+#endif
+ {
+ /*--- slow version which correctly handles all situations ---*/
+ while (gs <= ge) {
+ s->rfreq[bt][mtfv[gs]]++;
+ gs++;
+ }
+ /* already is: gs = ge + 1; */
+ }
+ }
+
+ /*
+ * Recompute the tables based on the accumulated frequencies.
+ */
+ /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See
+ * comment in huffman.c for details. */
+ for (t = 0; t < nGroups; t++)
+ BZ2_hbMakeCodeLengths(s, &(s->len[t][0]), &(s->rfreq[t][0]), alphaSize, 17 /*20*/);
+ }
+
+ AssertH(nGroups < 8, 3002);
+ AssertH(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZ_G_SIZE)), 3003);
+
+ /*--- Compute MTF values for the selectors. ---*/
+ {
+ uint8_t pos[BZ_N_GROUPS], ll_i, tmp2, tmp;
+
+ for (i = 0; i < nGroups; i++)
+ pos[i] = i;
+ for (i = 0; i < nSelectors; i++) {
+ ll_i = s->selector[i];
+ j = 0;
+ tmp = pos[j];
+ while (ll_i != tmp) {
+ j++;
+ tmp2 = tmp;
+ tmp = pos[j];
+ pos[j] = tmp2;
+ };
+ pos[0] = tmp;
+ s->selectorMtf[i] = j;
+ }
+ };
+
+ /*--- Assign actual codes for the tables. --*/
+ for (t = 0; t < nGroups; t++) {
+ minLen = 32;
+ maxLen = 0;
+ for (i = 0; i < alphaSize; i++) {
+ if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
+ if (s->len[t][i] < minLen) minLen = s->len[t][i];
+ }
+ AssertH(!(maxLen > 17 /*20*/), 3004);
+ AssertH(!(minLen < 1), 3005);
+ BZ2_hbAssignCodes(&(s->code[t][0]), &(s->len[t][0]), minLen, maxLen, alphaSize);
+ }
+
+ /*--- Transmit the mapping table. ---*/
+ {
+ /* bbox: optimized a bit more than in bzip2 */
+ int inUse16 = 0;
+ for (i = 0; i < 16; i++) {
+ if (sizeof(long) <= 4) {
+ inUse16 = inUse16*2 +
+ ((*(uint32_t*)&(s->inUse[i * 16 + 0])
+ | *(uint32_t*)&(s->inUse[i * 16 + 4])
+ | *(uint32_t*)&(s->inUse[i * 16 + 8])
+ | *(uint32_t*)&(s->inUse[i * 16 + 12])) != 0);
+ } else { /* Our CPU can do better */
+ inUse16 = inUse16*2 +
+ ((*(uint64_t*)&(s->inUse[i * 16 + 0])
+ | *(uint64_t*)&(s->inUse[i * 16 + 8])) != 0);
+ }
+ }
+
+ nBytes = s->numZ;
+ bsW(s, 16, inUse16);
+
+ inUse16 <<= (sizeof(int)*8 - 16); /* move 15th bit into sign bit */
+ for (i = 0; i < 16; i++) {
+ if (inUse16 < 0) {
+ unsigned v16 = 0;
+ for (j = 0; j < 16; j++)
+ v16 = v16*2 + s->inUse[i * 16 + j];
+ bsW(s, 16, v16);
+ }
+ inUse16 <<= 1;
+ }
+ }
+
+ /*--- Now the selectors. ---*/
+ nBytes = s->numZ;
+ bsW(s, 3, nGroups);
+ bsW(s, 15, nSelectors);
+ for (i = 0; i < nSelectors; i++) {
+ for (j = 0; j < s->selectorMtf[i]; j++)
+ bsW(s, 1, 1);
+ bsW(s, 1, 0);
+ }
+
+ /*--- Now the coding tables. ---*/
+ nBytes = s->numZ;
+
+ for (t = 0; t < nGroups; t++) {
+ int32_t curr = s->len[t][0];
+ bsW(s, 5, curr);
+ for (i = 0; i < alphaSize; i++) {
+ while (curr < s->len[t][i]) { bsW(s, 2, 2); curr++; /* 10 */ };
+ while (curr > s->len[t][i]) { bsW(s, 2, 3); curr--; /* 11 */ };
+ bsW(s, 1, 0);
+ }
+ }
+
+ /*--- And finally, the block data proper ---*/
+ nBytes = s->numZ;
+ selCtr = 0;
+ gs = 0;
+ while (1) {
+ if (gs >= s->nMTF)
+ break;
+ ge = gs + BZ_G_SIZE - 1;
+ if (ge >= s->nMTF)
+ ge = s->nMTF-1;
+ AssertH(s->selector[selCtr] < nGroups, 3006);
+
+/* Costs 1300 bytes and is _slower_ (on Intel Core 2) */
+#if 0
+ if (nGroups == 6 && 50 == ge-gs+1) {
+ /*--- fast track the common case ---*/
+ uint16_t mtfv_i;
+ uint8_t* s_len_sel_selCtr = &(s->len[s->selector[selCtr]][0]);
+ int32_t* s_code_sel_selCtr = &(s->code[s->selector[selCtr]][0]);
+#define BZ_ITAH(nn) \
+ mtfv_i = mtfv[gs+(nn)]; \
+ bsW(s, s_len_sel_selCtr[mtfv_i], s_code_sel_selCtr[mtfv_i])
+ BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4);
+ BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9);
+ BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14);
+ BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19);
+ BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24);
+ BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29);
+ BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34);
+ BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39);
+ BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44);
+ BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49);
+#undef BZ_ITAH
+ gs = ge+1;
+ } else
+#endif
+ {
+ /*--- slow version which correctly handles all situations ---*/
+ /* code is bit bigger, but moves multiply out of the loop */
+ uint8_t* s_len_sel_selCtr = &(s->len [s->selector[selCtr]][0]);
+ int32_t* s_code_sel_selCtr = &(s->code[s->selector[selCtr]][0]);
+ while (gs <= ge) {
+ bsW(s,
+ s_len_sel_selCtr[mtfv[gs]],
+ s_code_sel_selCtr[mtfv[gs]]
+ );
+ gs++;
+ }
+ /* already is: gs = ge+1; */
+ }
+ selCtr++;
+ }
+ AssertH(selCtr == nSelectors, 3007);
+#undef code
+#undef rfreq
+#undef len_pack
+}
+
+
+/*---------------------------------------------------*/
+static
+void BZ2_compressBlock(EState* s, int is_last_block)
+{
+ if (s->nblock > 0) {
+ BZ_FINALISE_CRC(s->blockCRC);
+ s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31);
+ s->combinedCRC ^= s->blockCRC;
+ if (s->blockNo > 1)
+ s->numZ = 0;
+
+ BZ2_blockSort(s);
+ }
+
+ s->zbits = &((uint8_t*)s->arr2)[s->nblock];
+
+ /*-- If this is the first block, create the stream header. --*/
+ if (s->blockNo == 1) {
+ BZ2_bsInitWrite(s);
+ /*bsPutU8(s, BZ_HDR_B);*/
+ /*bsPutU8(s, BZ_HDR_Z);*/
+ /*bsPutU8(s, BZ_HDR_h);*/
+ /*bsPutU8(s, BZ_HDR_0 + s->blockSize100k);*/
+ bsPutU32(s, BZ_HDR_BZh0 + s->blockSize100k);
+ }
+
+ if (s->nblock > 0) {
+ /*bsPutU8(s, 0x31);*/
+ /*bsPutU8(s, 0x41);*/
+ /*bsPutU8(s, 0x59);*/
+ /*bsPutU8(s, 0x26);*/
+ bsPutU32(s, 0x31415926);
+ /*bsPutU8(s, 0x53);*/
+ /*bsPutU8(s, 0x59);*/
+ bsPutU16(s, 0x5359);
+
+ /*-- Now the block's CRC, so it is in a known place. --*/
+ bsPutU32(s, s->blockCRC);
+
+ /*
+ * Now a single bit indicating (non-)randomisation.
+ * As of version 0.9.5, we use a better sorting algorithm
+ * which makes randomisation unnecessary. So always set
+ * the randomised bit to 'no'. Of course, the decoder
+ * still needs to be able to handle randomised blocks
+ * so as to maintain backwards compatibility with
+ * older versions of bzip2.
+ */
+ bsW(s, 1, 0);
+
+ bsW(s, 24, s->origPtr);
+ generateMTFValues(s);
+ sendMTFValues(s);
+ }
+
+ /*-- If this is the last block, add the stream trailer. --*/
+ if (is_last_block) {
+ /*bsPutU8(s, 0x17);*/
+ /*bsPutU8(s, 0x72);*/
+ /*bsPutU8(s, 0x45);*/
+ /*bsPutU8(s, 0x38);*/
+ bsPutU32(s, 0x17724538);
+ /*bsPutU8(s, 0x50);*/
+ /*bsPutU8(s, 0x90);*/
+ bsPutU16(s, 0x5090);
+ bsPutU32(s, s->combinedCRC);
+ bsFinishWrite(s);
+ }
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end compress.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/bz/huffman.c b/cleopatre/busybox-1.11.1-spc300/archival/bz/huffman.c
new file mode 100644
index 0000000000..676b1af66a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/bz/huffman.c
@@ -0,0 +1,229 @@
+/*
+ * bzip2 is written by Julian Seward <jseward@bzip.org>.
+ * Adapted for busybox by Denys Vlasenko <vda.linux@googlemail.com>.
+ * See README and LICENSE files in this directory for more information.
+ */
+
+/*-------------------------------------------------------------*/
+/*--- Huffman coding low-level stuff ---*/
+/*--- huffman.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+This file is part of bzip2/libbzip2, a program and library for
+lossless, block-sorting data compression.
+
+bzip2/libbzip2 version 1.0.4 of 20 December 2006
+Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
+
+Please read the WARNING, DISCLAIMER and PATENTS sections in the
+README file.
+
+This program is released under the terms of the license contained
+in the file LICENSE.
+------------------------------------------------------------------ */
+
+/* #include "bzlib_private.h" */
+
+/*---------------------------------------------------*/
+#define WEIGHTOF(zz0) ((zz0) & 0xffffff00)
+#define DEPTHOF(zz1) ((zz1) & 0x000000ff)
+#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3))
+
+#define ADDWEIGHTS(zw1,zw2) \
+ (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \
+ (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2)))
+
+#define UPHEAP(z) \
+{ \
+ int32_t zz, tmp; \
+ zz = z; \
+ tmp = heap[zz]; \
+ while (weight[tmp] < weight[heap[zz >> 1]]) { \
+ heap[zz] = heap[zz >> 1]; \
+ zz >>= 1; \
+ } \
+ heap[zz] = tmp; \
+}
+
+
+/* 90 bytes, 0.3% of overall compress speed */
+#if CONFIG_BZIP2_FEATURE_SPEED >= 1
+
+/* macro works better than inline (gcc 4.2.1) */
+#define DOWNHEAP1(heap, weight, Heap) \
+{ \
+ int32_t zz, yy, tmp; \
+ zz = 1; \
+ tmp = heap[zz]; \
+ while (1) { \
+ yy = zz << 1; \
+ if (yy > nHeap) \
+ break; \
+ if (yy < nHeap \
+ && weight[heap[yy+1]] < weight[heap[yy]]) \
+ yy++; \
+ if (weight[tmp] < weight[heap[yy]]) \
+ break; \
+ heap[zz] = heap[yy]; \
+ zz = yy; \
+ } \
+ heap[zz] = tmp; \
+}
+
+#else
+
+static
+void DOWNHEAP1(int32_t *heap, int32_t *weight, int32_t nHeap)
+{
+ int32_t zz, yy, tmp;
+ zz = 1;
+ tmp = heap[zz];
+ while (1) {
+ yy = zz << 1;
+ if (yy > nHeap)
+ break;
+ if (yy < nHeap
+ && weight[heap[yy + 1]] < weight[heap[yy]])
+ yy++;
+ if (weight[tmp] < weight[heap[yy]])
+ break;
+ heap[zz] = heap[yy];
+ zz = yy;
+ }
+ heap[zz] = tmp;
+}
+
+#endif
+
+/*---------------------------------------------------*/
+static
+void BZ2_hbMakeCodeLengths(EState *s,
+ uint8_t *len,
+ int32_t *freq,
+ int32_t alphaSize,
+ int32_t maxLen)
+{
+ /*
+ * Nodes and heap entries run from 1. Entry 0
+ * for both the heap and nodes is a sentinel.
+ */
+ int32_t nNodes, nHeap, n1, n2, i, j, k;
+ Bool tooLong;
+
+ /* bbox: moved to EState to save stack
+ int32_t heap [BZ_MAX_ALPHA_SIZE + 2];
+ int32_t weight[BZ_MAX_ALPHA_SIZE * 2];
+ int32_t parent[BZ_MAX_ALPHA_SIZE * 2];
+ */
+#define heap (s->BZ2_hbMakeCodeLengths__heap)
+#define weight (s->BZ2_hbMakeCodeLengths__weight)
+#define parent (s->BZ2_hbMakeCodeLengths__parent)
+
+ for (i = 0; i < alphaSize; i++)
+ weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
+
+ while (1) {
+ nNodes = alphaSize;
+ nHeap = 0;
+
+ heap[0] = 0;
+ weight[0] = 0;
+ parent[0] = -2;
+
+ for (i = 1; i <= alphaSize; i++) {
+ parent[i] = -1;
+ nHeap++;
+ heap[nHeap] = i;
+ UPHEAP(nHeap);
+ }
+
+ AssertH(nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001);
+
+ while (nHeap > 1) {
+ n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP1(heap, weight, nHeap);
+ n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP1(heap, weight, nHeap);
+ nNodes++;
+ parent[n1] = parent[n2] = nNodes;
+ weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]);
+ parent[nNodes] = -1;
+ nHeap++;
+ heap[nHeap] = nNodes;
+ UPHEAP(nHeap);
+ }
+
+ AssertH(nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002);
+
+ tooLong = False;
+ for (i = 1; i <= alphaSize; i++) {
+ j = 0;
+ k = i;
+ while (parent[k] >= 0) {
+ k = parent[k];
+ j++;
+ }
+ len[i-1] = j;
+ if (j > maxLen)
+ tooLong = True;
+ }
+
+ if (!tooLong)
+ break;
+
+ /* 17 Oct 04: keep-going condition for the following loop used
+ to be 'i < alphaSize', which missed the last element,
+ theoretically leading to the possibility of the compressor
+ looping. However, this count-scaling step is only needed if
+ one of the generated Huffman code words is longer than
+ maxLen, which up to and including version 1.0.2 was 20 bits,
+ which is extremely unlikely. In version 1.0.3 maxLen was
+ changed to 17 bits, which has minimal effect on compression
+ ratio, but does mean this scaling step is used from time to
+ time, enough to verify that it works.
+
+ This means that bzip2-1.0.3 and later will only produce
+ Huffman codes with a maximum length of 17 bits. However, in
+ order to preserve backwards compatibility with bitstreams
+ produced by versions pre-1.0.3, the decompressor must still
+ handle lengths of up to 20. */
+
+ for (i = 1; i <= alphaSize; i++) {
+ j = weight[i] >> 8;
+ /* bbox: yes, it is a signed division.
+ * don't replace with shift! */
+ j = 1 + (j / 2);
+ weight[i] = j << 8;
+ }
+ }
+#undef heap
+#undef weight
+#undef parent
+}
+
+
+/*---------------------------------------------------*/
+static
+void BZ2_hbAssignCodes(int32_t *code,
+ uint8_t *length,
+ int32_t minLen,
+ int32_t maxLen,
+ int32_t alphaSize)
+{
+ int32_t n, vec, i;
+
+ vec = 0;
+ for (n = minLen; n <= maxLen; n++) {
+ for (i = 0; i < alphaSize; i++) {
+ if (length[i] == n) {
+ code[i] = vec;
+ vec++;
+ };
+ }
+ vec <<= 1;
+ }
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end huffman.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/bzip2.c b/cleopatre/busybox-1.11.1-spc300/archival/bzip2.c
new file mode 100644
index 0000000000..eb570c4349
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/bzip2.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2007 Denys Vlasenko <vda.linux@googlemail.com>
+ *
+ * This file uses bzip2 library code which is written
+ * by Julian Seward <jseward@bzip.org>.
+ * See README and LICENSE files in bz/ directory for more information
+ * about bzip2 library code.
+ */
+
+#include "libbb.h"
+
+#define CONFIG_BZIP2_FEATURE_SPEED 1
+
+/* Speed test:
+ * Compiled with gcc 4.2.1, run on Athlon 64 1800 MHz (512K L2 cache).
+ * Stock bzip2 is 26.4% slower than bbox bzip2 at SPEED 1
+ * (time to compress gcc-4.2.1.tar is 126.4% compared to bbox).
+ * At SPEED 5 difference is 32.7%.
+ *
+ * Test run of all CONFIG_BZIP2_FEATURE_SPEED values on a 11Mb text file:
+ * Size Time (3 runs)
+ * 0: 10828 4.145 4.146 4.148
+ * 1: 11097 3.845 3.860 3.861
+ * 2: 11392 3.763 3.767 3.768
+ * 3: 11892 3.722 3.724 3.727
+ * 4: 12740 3.637 3.640 3.644
+ * 5: 17273 3.497 3.509 3.509
+ */
+
+
+#define BZ_DEBUG 0
+/* Takes ~300 bytes, detects corruption caused by bad RAM etc */
+#define BZ_LIGHT_DEBUG 0
+
+#include "bz/bzlib.h"
+
+#include "bz/bzlib_private.h"
+
+#include "bz/blocksort.c"
+#include "bz/bzlib.c"
+#include "bz/compress.c"
+#include "bz/huffman.c"
+
+/* No point in being shy and having very small buffer here.
+ * bzip2 internal buffers are much bigger anyway, hundreds of kbytes.
+ * If iobuf is several pages long, malloc() may use mmap,
+ * making iobuf is page aligned and thus (maybe) have one memcpy less
+ * if kernel is clever enough.
+ */
+enum {
+ IOBUF_SIZE = 8 * 1024
+};
+
+static uint8_t level;
+
+/* NB: compressStream() has to return -1 on errors, not die.
+ * bbunpack() will correctly clean up in this case
+ * (delete incomplete .bz2 file)
+ */
+
+/* Returns:
+ * -1 on errors
+ * total written bytes so far otherwise
+ */
+static
+USE_DESKTOP(long long) int bz_write(bz_stream *strm, void* rbuf, ssize_t rlen, void *wbuf)
+{
+ int n, n2, ret;
+
+ strm->avail_in = rlen;
+ strm->next_in = rbuf;
+ while (1) {
+ strm->avail_out = IOBUF_SIZE;
+ strm->next_out = wbuf;
+
+ ret = BZ2_bzCompress(strm, rlen ? BZ_RUN : BZ_FINISH);
+ if (ret != BZ_RUN_OK /* BZ_RUNning */
+ && ret != BZ_FINISH_OK /* BZ_FINISHing, but not done yet */
+ && ret != BZ_STREAM_END /* BZ_FINISHed */
+ ) {
+ bb_error_msg_and_die("internal error %d", ret);
+ }
+
+ n = IOBUF_SIZE - strm->avail_out;
+ if (n) {
+ n2 = full_write(STDOUT_FILENO, wbuf, n);
+ if (n2 != n) {
+ if (n2 >= 0)
+ errno = 0; /* prevent bogus error message */
+ bb_perror_msg(n2 >= 0 ? "short write" : "write error");
+ return -1;
+ }
+ }
+
+ if (ret == BZ_STREAM_END)
+ break;
+ if (rlen && strm->avail_in == 0)
+ break;
+ }
+ return 0 USE_DESKTOP( + strm->total_out );
+}
+
+static
+USE_DESKTOP(long long) int compressStream(void)
+{
+ USE_DESKTOP(long long) int total;
+ ssize_t count;
+ bz_stream bzs; /* it's small */
+#define strm (&bzs)
+ char *iobuf;
+#define rbuf iobuf
+#define wbuf (iobuf + IOBUF_SIZE)
+
+ iobuf = xmalloc(2 * IOBUF_SIZE);
+ BZ2_bzCompressInit(strm, level);
+
+ while (1) {
+ count = full_read(STDIN_FILENO, rbuf, IOBUF_SIZE);
+ if (count < 0) {
+ bb_perror_msg("read error");
+ total = -1;
+ break;
+ }
+ /* if count == 0, bz_write finalizes compression */
+ total = bz_write(strm, rbuf, count, wbuf);
+ if (count == 0 || total < 0)
+ break;
+ }
+
+#if ENABLE_FEATURE_CLEAN_UP
+ BZ2_bzCompressEnd(strm);
+ free(iobuf);
+#endif
+ return total;
+}
+
+static
+char* make_new_name_bzip2(char *filename)
+{
+ return xasprintf("%s.bz2", filename);
+}
+
+int bzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int bzip2_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ unsigned opt;
+
+ /* standard bzip2 flags
+ * -d --decompress force decompression
+ * -z --compress force compression
+ * -k --keep keep (don't delete) input files
+ * -f --force overwrite existing output files
+ * -t --test test compressed file integrity
+ * -c --stdout output to standard out
+ * -q --quiet suppress noncritical error messages
+ * -v --verbose be verbose (a 2nd -v gives more)
+ * -s --small use less memory (at most 2500k)
+ * -1 .. -9 set block size to 100k .. 900k
+ * --fast alias for -1
+ * --best alias for -9
+ */
+
+ opt_complementary = "s2"; /* -s means -2 (compatibility) */
+ /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */
+ opt = getopt32(argv, "cfv" USE_BUNZIP2("d") "123456789qzs" );
+#if ENABLE_BUNZIP2 /* bunzip2_main may not be visible... */
+ if (opt & 0x8) // -d
+ return bunzip2_main(argc, argv);
+ opt >>= 4;
+#else
+ opt >>= 3;
+#endif
+ opt = (uint8_t)opt; /* isolate bits for -1..-8 */
+ opt |= 0x100; /* if nothing else, assume -9 */
+ level = 1;
+ while (!(opt & 1)) {
+ level++;
+ opt >>= 1;
+ }
+
+ argv += optind;
+ option_mask32 &= 0x7; /* ignore all except -cfv */
+ return bbunpack(argv, make_new_name_bzip2, compressStream);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/cpio.c b/cleopatre/busybox-1.11.1-spc300/archival/cpio.c
new file mode 100644
index 0000000000..6a8ee67451
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/cpio.c
@@ -0,0 +1,350 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini cpio implementation for busybox
+ *
+ * Copyright (C) 2001 by Glenn McGrath
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ * Limitations:
+ * Doesn't check CRC's
+ * Only supports new ASCII and CRC formats
+ *
+ */
+#include "libbb.h"
+#include "unarchive.h"
+
+#if ENABLE_FEATURE_CPIO_O
+static off_t cpio_pad4(off_t size)
+{
+ int i;
+
+ i = (- size) & 3;
+ size += i;
+ while (--i >= 0)
+ bb_putchar('\0');
+ return size;
+}
+
+/* Return value will become exit code.
+ * It's ok to exit instead of return. */
+static int cpio_o(void)
+{
+ struct name_s {
+ struct name_s *next;
+ char name[1];
+ };
+ struct inodes_s {
+ struct inodes_s *next;
+ struct name_s *names;
+ struct stat st;
+ };
+
+ struct inodes_s *links = NULL;
+ off_t bytes = 0; /* output bytes count */
+
+ while (1) {
+ const char *name;
+ char *line;
+ struct stat st;
+
+ line = xmalloc_fgetline(stdin);
+
+ if (line) {
+ /* Strip leading "./[./]..." from the filename */
+ name = line;
+ while (name[0] == '.' && name[1] == '/') {
+ while (*++name == '/')
+ continue;
+ }
+ if (!*name) { /* line is empty */
+ free(line);
+ continue;
+ }
+ if (lstat(name, &st)) {
+ abort_cpio_o:
+ bb_simple_perror_msg_and_die(name);
+ }
+
+ if (!(S_ISLNK(st.st_mode) || S_ISREG(st.st_mode)))
+ st.st_size = 0; /* paranoia */
+
+ /* Store hardlinks for later processing, dont output them */
+ if (!S_ISDIR(st.st_mode) && st.st_nlink > 1) {
+ struct name_s *n;
+ struct inodes_s *l;
+
+ /* Do we have this hardlink remembered? */
+ l = links;
+ while (1) {
+ if (l == NULL) {
+ /* Not found: add new item to "links" list */
+ l = xzalloc(sizeof(*l));
+ l->st = st;
+ l->next = links;
+ links = l;
+ break;
+ }
+ if (l->st.st_ino == st.st_ino) {
+ /* found */
+ break;
+ }
+ l = l->next;
+ }
+ /* Add new name to "l->names" list */
+ n = xmalloc(sizeof(*n) + strlen(name));
+ strcpy(n->name, name);
+ n->next = l->names;
+ l->names = n;
+
+ free(line);
+ continue;
+ }
+
+ } else { /* line == NULL: EOF */
+ next_link:
+ if (links) {
+ /* Output hardlink's data */
+ st = links->st;
+ name = links->names->name;
+ links->names = links->names->next;
+ /* GNU cpio is reported to emit file data
+ * only for the last instance. Mimic that. */
+ if (links->names == NULL)
+ links = links->next;
+ else
+ st.st_size = 0;
+ /* NB: we leak links->names and/or links,
+ * this is intended (we exit soon anyway) */
+ } else {
+ /* If no (more) hardlinks to output,
+ * output "trailer" entry */
+ name = "TRAILER!!!";
+ /* st.st_size == 0 is a must, but for uniformity
+ * in the output, we zero out everything */
+ memset(&st, 0, sizeof(st));
+ /* st.st_nlink = 1; - GNU cpio does this */
+ }
+ }
+
+ bytes += printf("070701"
+ "%08X%08X%08X%08X%08X%08X%08X"
+ "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */
+ /* strlen+1: */ "%08X"
+ /* chksum: */ "00000000" /* (only for "070702" files) */
+ /* name,NUL: */ "%s%c",
+ (unsigned)(uint32_t) st.st_ino,
+ (unsigned)(uint32_t) st.st_mode,
+ (unsigned)(uint32_t) st.st_uid,
+ (unsigned)(uint32_t) st.st_gid,
+ (unsigned)(uint32_t) st.st_nlink,
+ (unsigned)(uint32_t) st.st_mtime,
+ (unsigned)(uint32_t) st.st_size,
+ (unsigned)(uint32_t) major(st.st_dev),
+ (unsigned)(uint32_t) minor(st.st_dev),
+ (unsigned)(uint32_t) major(st.st_rdev),
+ (unsigned)(uint32_t) minor(st.st_rdev),
+ (unsigned)(strlen(name) + 1),
+ name, '\0');
+ bytes = cpio_pad4(bytes);
+
+ if (st.st_size) {
+ if (S_ISLNK(st.st_mode)) {
+ char *lpath = xmalloc_readlink_or_warn(name);
+ if (!lpath)
+ goto abort_cpio_o;
+ bytes += printf("%s", lpath);
+ free(lpath);
+ } else { /* S_ISREG */
+ int fd = xopen(name, O_RDONLY);
+ fflush(stdout);
+ /* We must abort if file got shorter too! */
+ bb_copyfd_exact_size(fd, STDOUT_FILENO, st.st_size);
+ bytes += st.st_size;
+ close(fd);
+ }
+ bytes = cpio_pad4(bytes);
+ }
+
+ if (!line) {
+ if (links)
+ goto next_link;
+ /* TODO: GNU cpio pads trailer to 512 bytes, do we want that? */
+ return EXIT_SUCCESS;
+ }
+
+ free(line);
+ } /* end of "while (1)" */
+}
+#endif
+
+/* GNU cpio (GNU cpio) 2.9 help (abridged):
+
+ Main operation mode:
+ -i, --extract Extract files from an archive
+ -o, --create Create the archive
+ -p, --pass-through Copy-pass mode (was ist das?!)
+ -t, --list List the archive
+
+ Operation modifiers valid in any mode:
+ --block-size=SIZE I/O block size = SIZE * 512 bytes
+ -B I/O block size = 5120 bytes
+ -c Use the old portable (ASCII) archive format
+ -C, --io-size=NUMBER I/O block size to the given NUMBER bytes
+ -f, --nonmatching Only copy files that do not match given pattern
+ -F, --file=FILE Use FILE instead of standard input or output
+ -H, --format=FORMAT Use given archive FORMAT
+ -M, --message=STRING Print STRING when the end of a volume of the
+ backup media is reached
+ -n, --numeric-uid-gid If -v, show numeric UID and GID
+ --quiet Do not print the number of blocks copied
+ --rsh-command=COMMAND Use remote COMMAND instead of rsh
+ -v, --verbose Verbosely list the files processed
+ -V, --dot Print a "." for each file processed
+ -W, --warning=FLAG Control warning display: 'none','truncate','all';
+ multiple options accumulate
+
+ Operation modifiers valid only in --extract mode:
+ -b, --swap Swap both halfwords of words and bytes of
+ halfwords in the data (equivalent to -sS)
+ -r, --rename Interactively rename files
+ -s, --swap-bytes Swap the bytes of each halfword in the files
+ -S, --swap-halfwords Swap the halfwords of each word (4 bytes)
+ --to-stdout Extract files to standard output
+ -E, --pattern-file=FILE Read additional patterns specifying filenames to
+ extract or list from FILE
+ --only-verify-crc Verify CRC's, don't actually extract the files
+
+ Operation modifiers valid only in --create mode:
+ -A, --append Append to an existing archive
+ -O FILE File to use instead of standard output
+
+ Operation modifiers valid only in --pass-through mode:
+ -l, --link Link files instead of copying them, when possible
+
+ Operation modifiers valid in --extract and --create modes:
+ --absolute-filenames Do not strip file system prefix components from
+ the file names
+ --no-absolute-filenames Create all files relative to the current dir
+
+ Operation modifiers valid in --create and --pass-through modes:
+ -0, --null A list of filenames is terminated by a NUL
+ -a, --reset-access-time Reset the access times of files after reading them
+ -I FILE File to use instead of standard input
+ -L, --dereference Dereference symbolic links (copy the files
+ that they point to instead of copying the links)
+ -R, --owner=[USER][:.][GROUP] Set owner of created files
+
+ Operation modifiers valid in --extract and --pass-through modes:
+ -d, --make-directories Create leading directories where needed
+ -m, --preserve-modification-time
+ Retain previous file modification times when
+ creating files
+ --no-preserve-owner Do not change the ownership of the files
+ --sparse Write files with blocks of zeros as sparse files
+ -u, --unconditional Replace all files unconditionally
+ */
+
+int cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int cpio_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ archive_handle_t *archive_handle;
+ char *cpio_filename;
+ USE_FEATURE_CPIO_O(const char *cpio_fmt = "";)
+ unsigned opt;
+ enum {
+ CPIO_OPT_EXTRACT = (1 << 0),
+ CPIO_OPT_TEST = (1 << 1),
+ CPIO_OPT_UNCONDITIONAL = (1 << 2),
+ CPIO_OPT_VERBOSE = (1 << 3),
+ CPIO_OPT_FILE = (1 << 4),
+ CPIO_OPT_CREATE_LEADING_DIR = (1 << 5),
+ CPIO_OPT_PRESERVE_MTIME = (1 << 6),
+ CPIO_OPT_CREATE = (1 << 7),
+ CPIO_OPT_FORMAT = (1 << 8),
+ };
+
+#if ENABLE_GETOPT_LONG && ENABLE_DESKTOP
+ applet_long_options =
+ "extract\0" No_argument "i"
+ "list\0" No_argument "t"
+#if ENABLE_FEATURE_CPIO_O
+ "create\0" No_argument "o"
+ "format\0" Required_argument "H"
+#endif
+ ;
+#endif
+
+ /* Initialize */
+ archive_handle = init_handle();
+ archive_handle->src_fd = STDIN_FILENO;
+ archive_handle->seek = seek_by_read;
+ archive_handle->flags = ARCHIVE_EXTRACT_NEWER;
+
+#if ENABLE_FEATURE_CPIO_O
+ opt = getopt32(argv, "ituvF:dmoH:", &cpio_filename, &cpio_fmt);
+
+ if (opt & CPIO_OPT_CREATE) {
+ if (*cpio_fmt != 'n')
+ bb_show_usage();
+ if (opt & CPIO_OPT_FILE) {
+ fclose(stdout);
+ stdout = fopen(cpio_filename, "w");
+ /* Paranoia: I don't trust libc that much */
+ xdup2(fileno(stdout), STDOUT_FILENO);
+ }
+ return cpio_o();
+ }
+#else
+ opt = getopt32(argv, "ituvF:dm", &cpio_filename);
+#endif
+ argv += optind;
+
+ /* One of either extract or test options must be given */
+ if ((opt & (CPIO_OPT_TEST | CPIO_OPT_EXTRACT)) == 0) {
+ bb_show_usage();
+ }
+
+ if (opt & CPIO_OPT_TEST) {
+ /* if both extract and test options are given, ignore extract option */
+ if (opt & CPIO_OPT_EXTRACT) {
+ opt &= ~CPIO_OPT_EXTRACT;
+ }
+ archive_handle->action_header = header_list;
+ }
+ if (opt & CPIO_OPT_EXTRACT) {
+ archive_handle->action_data = data_extract_all;
+ }
+ if (opt & CPIO_OPT_UNCONDITIONAL) {
+ archive_handle->flags |= ARCHIVE_EXTRACT_UNCONDITIONAL;
+ archive_handle->flags &= ~ARCHIVE_EXTRACT_NEWER;
+ }
+ if (opt & CPIO_OPT_VERBOSE) {
+ if (archive_handle->action_header == header_list) {
+ archive_handle->action_header = header_verbose_list;
+ } else {
+ archive_handle->action_header = header_list;
+ }
+ }
+ if (opt & CPIO_OPT_FILE) { /* -F */
+ archive_handle->src_fd = xopen(cpio_filename, O_RDONLY);
+ archive_handle->seek = seek_by_jump;
+ }
+ if (opt & CPIO_OPT_CREATE_LEADING_DIR) {
+ archive_handle->flags |= ARCHIVE_CREATE_LEADING_DIRS;
+ }
+ if (opt & CPIO_OPT_PRESERVE_MTIME) {
+ archive_handle->flags |= ARCHIVE_PRESERVE_DATE;
+ }
+
+ while (*argv) {
+ archive_handle->filter = filter_accept_list;
+ llist_add_to(&(archive_handle->accept), *argv);
+ argv++;
+ }
+
+ while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
+ continue;
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/dpkg.c b/cleopatre/busybox-1.11.1-spc300/archival/dpkg.c
new file mode 100644
index 0000000000..ee5bd7affe
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/dpkg.c
@@ -0,0 +1,1778 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * mini dpkg implementation for busybox.
+ * this is not meant as a replacement for dpkg
+ *
+ * written by glenn mcgrath with the help of others
+ * copyright (c) 2001 by glenn mcgrath
+ *
+ * started life as a busybox implementation of udpkg
+ *
+ * licensed under gplv2 or later, see file license in this tarball for details.
+ */
+
+/*
+ * known difference between busybox dpkg and the official dpkg that i don't
+ * consider important, its worth keeping a note of differences anyway, just to
+ * make it easier to maintain.
+ * - the first value for the confflile: field isnt placed on a new line.
+ * - when installing a package the status: field is placed at the end of the
+ * section, rather than just after the package: field.
+ *
+ * bugs that need to be fixed
+ * - (unknown, please let me know when you find any)
+ *
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+/* note: if you vary hash_prime sizes be aware,
+ * 1) tweaking these will have a big effect on how much memory this program uses.
+ * 2) for computational efficiency these hash tables should be at least 20%
+ * larger than the maximum number of elements stored in it.
+ * 3) all _hash_prime's must be a prime number or chaos is assured, if your looking
+ * for a prime, try http://www.utm.edu/research/primes/lists/small/10000.txt
+ * 4) if you go bigger than 15 bits you may get into trouble (untested) as its
+ * sometimes cast to an unsigned, if you go to 16 bit you will overlap
+ * int's and chaos is assured, 16381 is the max prime for 14 bit field
+ */
+
+/* NAME_HASH_PRIME, Stores package names and versions,
+ * I estimate it should be at least 50% bigger than PACKAGE_HASH_PRIME,
+ * as there a lot of duplicate version numbers */
+#define NAME_HASH_PRIME 16381
+
+/* PACKAGE_HASH_PRIME, Maximum number of unique packages,
+ * It must not be smaller than STATUS_HASH_PRIME,
+ * Currently only packages from status_hashtable are stored in here, but in
+ * future this may be used to store packages not only from a status file,
+ * but an available_hashtable, and even multiple packages files.
+ * Package can be stored more than once if they have different versions.
+ * e.g. The same package may have different versions in the status file
+ * and available file */
+#define PACKAGE_HASH_PRIME 10007
+typedef struct edge_s {
+ unsigned operator:4; /* was:3 */
+ unsigned type:4;
+ unsigned name:16; /* was:14 */
+ unsigned version:16; /* was:14 */
+} edge_t;
+
+typedef struct common_node_s {
+ unsigned name:16; /* was:14 */
+ unsigned version:16; /* was:14 */
+ unsigned num_of_edges:16; /* was:14 */
+ edge_t **edge;
+} common_node_t;
+
+/* Currently it doesnt store packages that have state-status of not-installed
+ * So it only really has to be the size of the maximum number of packages
+ * likely to be installed at any one time, so there is a bit of leeway here */
+#define STATUS_HASH_PRIME 8191
+typedef struct status_node_s {
+ unsigned package:16; /* was:14 */ /* has to fit PACKAGE_HASH_PRIME */
+ unsigned status:16; /* was:14 */ /* has to fit STATUS_HASH_PRIME */
+} status_node_t;
+
+
+/* Globals */
+struct globals {
+ char *name_hashtable[NAME_HASH_PRIME + 1];
+ common_node_t *package_hashtable[PACKAGE_HASH_PRIME + 1];
+ status_node_t *status_hashtable[STATUS_HASH_PRIME + 1];
+};
+#define G (*ptr_to_globals)
+#define name_hashtable (G.name_hashtable )
+#define package_hashtable (G.package_hashtable)
+#define status_hashtable (G.status_hashtable )
+#define INIT_G() do { \
+ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
+} while (0)
+
+
+/* Even numbers are for 'extras', like ored dependencies or null */
+enum edge_type_e {
+ EDGE_NULL = 0,
+ EDGE_PRE_DEPENDS = 1,
+ EDGE_OR_PRE_DEPENDS = 2,
+ EDGE_DEPENDS = 3,
+ EDGE_OR_DEPENDS = 4,
+ EDGE_REPLACES = 5,
+ EDGE_PROVIDES = 7,
+ EDGE_CONFLICTS = 9,
+ EDGE_SUGGESTS = 11,
+ EDGE_RECOMMENDS = 13,
+ EDGE_ENHANCES = 15
+};
+enum operator_e {
+ VER_NULL = 0,
+ VER_EQUAL = 1,
+ VER_LESS = 2,
+ VER_LESS_EQUAL = 3,
+ VER_MORE = 4,
+ VER_MORE_EQUAL = 5,
+ VER_ANY = 6
+};
+
+typedef struct deb_file_s {
+ char *control_file;
+ char *filename;
+ unsigned package:16; /* was:14 */
+} deb_file_t;
+
+
+static void make_hash(const char *key, unsigned *start, unsigned *decrement, const int hash_prime)
+{
+ unsigned long hash_num = key[0];
+ int len = strlen(key);
+ int i;
+
+ /* Maybe i should have uses a "proper" hashing algorithm here instead
+ * of making one up myself, seems to be working ok though. */
+ for (i = 1; i < len; i++) {
+ /* shifts the ascii based value and adds it to previous value
+ * shift amount is mod 24 because long int is 32 bit and data
+ * to be shifted is 8, don't want to shift data to where it has
+ * no effect*/
+ hash_num += (key[i] + key[i-1]) << ((key[i] * i) % 24);
+ }
+ *start = (unsigned) hash_num % hash_prime;
+ *decrement = (unsigned) 1 + (hash_num % (hash_prime - 1));
+}
+
+/* this adds the key to the hash table */
+static int search_name_hashtable(const char *key)
+{
+ unsigned probe_address;
+ unsigned probe_decrement;
+
+ make_hash(key, &probe_address, &probe_decrement, NAME_HASH_PRIME);
+ while (name_hashtable[probe_address] != NULL) {
+ if (strcmp(name_hashtable[probe_address], key) == 0) {
+ return probe_address;
+ }
+ probe_address -= probe_decrement;
+ if ((int)probe_address < 0) {
+ probe_address += NAME_HASH_PRIME;
+ }
+ }
+ name_hashtable[probe_address] = xstrdup(key);
+ return probe_address;
+}
+
+/* this DOESNT add the key to the hashtable
+ * TODO make it consistent with search_name_hashtable
+ */
+static unsigned search_status_hashtable(const char *key)
+{
+ unsigned probe_address;
+ unsigned probe_decrement;
+
+ make_hash(key, &probe_address, &probe_decrement, STATUS_HASH_PRIME);
+ while (status_hashtable[probe_address] != NULL) {
+ if (strcmp(key, name_hashtable[package_hashtable[status_hashtable[probe_address]->package]->name]) == 0) {
+ break;
+ }
+ probe_address -= probe_decrement;
+ if ((int)probe_address < 0) {
+ probe_address += STATUS_HASH_PRIME;
+ }
+ }
+ return probe_address;
+}
+
+/* Need to rethink version comparison, maybe the official dpkg has something i can use ? */
+static int version_compare_part(const char *version1, const char *version2)
+{
+ int upstream_len1 = 0;
+ int upstream_len2 = 0;
+ char *name1_char;
+ char *name2_char;
+ int len1 = 0;
+ int len2 = 0;
+ int tmp_int;
+ int ver_num1;
+ int ver_num2;
+
+ if (version1 == NULL) {
+ version1 = xstrdup("");
+ }
+ if (version2 == NULL) {
+ version2 = xstrdup("");
+ }
+ upstream_len1 = strlen(version1);
+ upstream_len2 = strlen(version2);
+
+ while ((len1 < upstream_len1) || (len2 < upstream_len2)) {
+ /* Compare non-digit section */
+ tmp_int = strcspn(&version1[len1], "0123456789");
+ name1_char = xstrndup(&version1[len1], tmp_int);
+ len1 += tmp_int;
+ tmp_int = strcspn(&version2[len2], "0123456789");
+ name2_char = xstrndup(&version2[len2], tmp_int);
+ len2 += tmp_int;
+ tmp_int = strcmp(name1_char, name2_char);
+ free(name1_char);
+ free(name2_char);
+ if (tmp_int != 0) {
+ return tmp_int;
+ }
+
+ /* Compare digits */
+ tmp_int = strspn(&version1[len1], "0123456789");
+ name1_char = xstrndup(&version1[len1], tmp_int);
+ len1 += tmp_int;
+ tmp_int = strspn(&version2[len2], "0123456789");
+ name2_char = xstrndup(&version2[len2], tmp_int);
+ len2 += tmp_int;
+ ver_num1 = atoi(name1_char);
+ ver_num2 = atoi(name2_char);
+ free(name1_char);
+ free(name2_char);
+ if (ver_num1 < ver_num2) {
+ return -1;
+ }
+ if (ver_num1 > ver_num2) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* if ver1 < ver2 return -1,
+ * if ver1 = ver2 return 0,
+ * if ver1 > ver2 return 1,
+ */
+static int version_compare(const unsigned ver1, const unsigned ver2)
+{
+ char *ch_ver1 = name_hashtable[ver1];
+ char *ch_ver2 = name_hashtable[ver2];
+
+ char epoch1, epoch2;
+ char *deb_ver1, *deb_ver2;
+ char *ver1_ptr, *ver2_ptr;
+ char *upstream_ver1;
+ char *upstream_ver2;
+ int result;
+
+ /* Compare epoch */
+ if (ch_ver1[1] == ':') {
+ epoch1 = ch_ver1[0];
+ ver1_ptr = strchr(ch_ver1, ':') + 1;
+ } else {
+ epoch1 = '0';
+ ver1_ptr = ch_ver1;
+ }
+ if (ch_ver2[1] == ':') {
+ epoch2 = ch_ver2[0];
+ ver2_ptr = strchr(ch_ver2, ':') + 1;
+ } else {
+ epoch2 = '0';
+ ver2_ptr = ch_ver2;
+ }
+ if (epoch1 < epoch2) {
+ return -1;
+ }
+ else if (epoch1 > epoch2) {
+ return 1;
+ }
+
+ /* Compare upstream version */
+ upstream_ver1 = xstrdup(ver1_ptr);
+ upstream_ver2 = xstrdup(ver2_ptr);
+
+ /* Chop off debian version, and store for later use */
+ deb_ver1 = strrchr(upstream_ver1, '-');
+ deb_ver2 = strrchr(upstream_ver2, '-');
+ if (deb_ver1) {
+ deb_ver1[0] = '\0';
+ deb_ver1++;
+ }
+ if (deb_ver2) {
+ deb_ver2[0] = '\0';
+ deb_ver2++;
+ }
+ result = version_compare_part(upstream_ver1, upstream_ver2);
+ if (!result)
+ /* Compare debian versions */
+ result = version_compare_part(deb_ver1, deb_ver2);
+
+ free(upstream_ver1);
+ free(upstream_ver2);
+ return result;
+}
+
+static int test_version(const unsigned version1, const unsigned version2, const unsigned operator)
+{
+ const int version_result = version_compare(version1, version2);
+ switch (operator) {
+ case VER_ANY:
+ return TRUE;
+ case VER_EQUAL:
+ return (version_result == 0);
+ case VER_LESS:
+ return (version_result < 0);
+ case VER_LESS_EQUAL:
+ return (version_result <= 0);
+ case VER_MORE:
+ return (version_result > 0);
+ case VER_MORE_EQUAL:
+ return (version_result >= 0);
+ }
+ return FALSE;
+}
+
+static int search_package_hashtable(const unsigned name, const unsigned version, const unsigned operator)
+{
+ unsigned probe_address;
+ unsigned probe_decrement;
+
+ make_hash(name_hashtable[name], &probe_address, &probe_decrement, PACKAGE_HASH_PRIME);
+ while (package_hashtable[probe_address] != NULL) {
+ if (package_hashtable[probe_address]->name == name) {
+ if (operator == VER_ANY) {
+ return probe_address;
+ }
+ if (test_version(package_hashtable[probe_address]->version, version, operator)) {
+ return probe_address;
+ }
+ }
+ probe_address -= probe_decrement;
+ if ((int)probe_address < 0) {
+ probe_address += PACKAGE_HASH_PRIME;
+ }
+ }
+ return probe_address;
+}
+
+/*
+ * This function searches through the entire package_hashtable looking
+ * for a package which provides "needle". It returns the index into
+ * the package_hashtable for the providing package.
+ *
+ * needle is the index into name_hashtable of the package we are
+ * looking for.
+ *
+ * start_at is the index in the package_hashtable to start looking
+ * at. If start_at is -1 then start at the beginning. This is to allow
+ * for repeated searches since more than one package might provide
+ * needle.
+ *
+ * FIXME: I don't think this is very efficient, but I thought I'd keep
+ * it simple for now until it proves to be a problem.
+ */
+static int search_for_provides(int needle, int start_at)
+{
+ int i, j;
+ common_node_t *p;
+ for (i = start_at + 1; i < PACKAGE_HASH_PRIME; i++) {
+ p = package_hashtable[i];
+ if (p == NULL)
+ continue;
+ for (j = 0; j < p->num_of_edges; j++)
+ if (p->edge[j]->type == EDGE_PROVIDES && p->edge[j]->name == needle)
+ return i;
+ }
+ return -1;
+}
+
+/*
+ * Add an edge to a node
+ */
+static void add_edge_to_node(common_node_t *node, edge_t *edge)
+{
+ node->num_of_edges++;
+ node->edge = xrealloc(node->edge, sizeof(edge_t) * (node->num_of_edges + 1));
+ node->edge[node->num_of_edges - 1] = edge;
+}
+
+/*
+ * Create one new node and one new edge for every dependency.
+ *
+ * Dependencies which contain multiple alternatives are represented as
+ * an EDGE_OR_PRE_DEPENDS or EDGE_OR_DEPENDS node, followed by a
+ * number of EDGE_PRE_DEPENDS or EDGE_DEPENDS nodes. The name field of
+ * the OR edge contains the full dependency string while the version
+ * field contains the number of EDGE nodes which follow as part of
+ * this alternative.
+ */
+static void add_split_dependencies(common_node_t *parent_node, const char *whole_line, unsigned edge_type)
+{
+ char *line = xstrdup(whole_line);
+ char *line2;
+ char *line_ptr1 = NULL;
+ char *line_ptr2 = NULL;
+ char *field;
+ char *field2;
+ char *version;
+ edge_t *edge;
+ edge_t *or_edge;
+ int offset_ch;
+
+ field = strtok_r(line, ",", &line_ptr1);
+ do {
+ /* skip leading spaces */
+ field += strspn(field, " ");
+ line2 = xstrdup(field);
+ field2 = strtok_r(line2, "|", &line_ptr2);
+ or_edge = NULL;
+ if ((edge_type == EDGE_DEPENDS || edge_type == EDGE_PRE_DEPENDS)
+ && (strcmp(field, field2) != 0)
+ ) {
+ or_edge = xzalloc(sizeof(edge_t));
+ or_edge->type = edge_type + 1;
+ or_edge->name = search_name_hashtable(field);
+ //or_edge->version = 0; // tracks the number of alternatives
+ add_edge_to_node(parent_node, or_edge);
+ }
+
+ do {
+ edge = xmalloc(sizeof(edge_t));
+ edge->type = edge_type;
+
+ /* Skip any extra leading spaces */
+ field2 += strspn(field2, " ");
+
+ /* Get dependency version info */
+ version = strchr(field2, '(');
+ if (version == NULL) {
+ edge->operator = VER_ANY;
+ /* Get the versions hash number, adding it if the number isnt already in there */
+ edge->version = search_name_hashtable("ANY");
+ } else {
+ /* Skip leading ' ' or '(' */
+ version += strspn(version, " (");
+ /* Calculate length of any operator characters */
+ offset_ch = strspn(version, "<=>");
+ /* Determine operator */
+ if (offset_ch > 0) {
+ if (strncmp(version, "=", offset_ch) == 0) {
+ edge->operator = VER_EQUAL;
+ } else if (strncmp(version, "<<", offset_ch) == 0) {
+ edge->operator = VER_LESS;
+ } else if (strncmp(version, "<=", offset_ch) == 0) {
+ edge->operator = VER_LESS_EQUAL;
+ } else if (strncmp(version, ">>", offset_ch) == 0) {
+ edge->operator = VER_MORE;
+ } else if (strncmp(version, ">=", offset_ch) == 0) {
+ edge->operator = VER_MORE_EQUAL;
+ } else {
+ bb_error_msg_and_die("illegal operator");
+ }
+ }
+ /* skip to start of version numbers */
+ version += offset_ch;
+ version += strspn(version, " ");
+
+ /* Truncate version at trailing ' ' or ')' */
+ version[strcspn(version, " )")] = '\0';
+ /* Get the versions hash number, adding it if the number isnt already in there */
+ edge->version = search_name_hashtable(version);
+ }
+
+ /* Get the dependency name */
+ field2[strcspn(field2, " (")] = '\0';
+ edge->name = search_name_hashtable(field2);
+
+ if (or_edge)
+ or_edge->version++;
+
+ add_edge_to_node(parent_node, edge);
+ field2 = strtok_r(NULL, "|", &line_ptr2);
+ } while (field2 != NULL);
+
+ free(line2);
+ field = strtok_r(NULL, ",", &line_ptr1);
+ } while (field != NULL);
+
+ free(line);
+}
+
+static void free_package(common_node_t *node)
+{
+ unsigned i;
+ if (node) {
+ for (i = 0; i < node->num_of_edges; i++) {
+ free(node->edge[i]);
+ }
+ free(node->edge);
+ free(node);
+ }
+}
+
+/*
+ * Gets the next package field from package_buffer, seperated into the field name
+ * and field value, it returns the int offset to the first character of the next field
+ */
+static int read_package_field(const char *package_buffer, char **field_name, char **field_value)
+{
+ int offset_name_start = 0;
+ int offset_name_end = 0;
+ int offset_value_start = 0;
+ int offset_value_end = 0;
+ int offset = 0;
+ int next_offset;
+ int name_length;
+ int value_length;
+ int exit_flag = FALSE;
+
+ if (package_buffer == NULL) {
+ *field_name = NULL;
+ *field_value = NULL;
+ return -1;
+ }
+ while (1) {
+ next_offset = offset + 1;
+ switch (package_buffer[offset]) {
+ case '\0':
+ exit_flag = TRUE;
+ break;
+ case ':':
+ if (offset_name_end == 0) {
+ offset_name_end = offset;
+ offset_value_start = next_offset;
+ }
+ /* TODO: Name might still have trailing spaces if ':' isnt
+ * immediately after name */
+ break;
+ case '\n':
+ /* TODO: The char next_offset may be out of bounds */
+ if (package_buffer[next_offset] != ' ') {
+ exit_flag = TRUE;
+ break;
+ }
+ case '\t':
+ case ' ':
+ /* increment the value start point if its a just filler */
+ if (offset_name_start == offset) {
+ offset_name_start++;
+ }
+ if (offset_value_start == offset) {
+ offset_value_start++;
+ }
+ break;
+ }
+ if (exit_flag) {
+ /* Check that the names are valid */
+ offset_value_end = offset;
+ name_length = offset_name_end - offset_name_start;
+ value_length = offset_value_end - offset_value_start;
+ if (name_length == 0) {
+ break;
+ }
+ if ((name_length > 0) && (value_length > 0)) {
+ break;
+ }
+
+ /* If not valid, start fresh with next field */
+ exit_flag = FALSE;
+ offset_name_start = offset + 1;
+ offset_name_end = 0;
+ offset_value_start = offset + 1;
+ offset_value_end = offset + 1;
+ offset++;
+ }
+ offset++;
+ }
+ *field_name = NULL;
+ if (name_length) {
+ *field_name = xstrndup(&package_buffer[offset_name_start], name_length);
+ }
+ *field_value = NULL;
+ if (value_length > 0) {
+ *field_value = xstrndup(&package_buffer[offset_value_start], value_length);
+ }
+ return next_offset;
+}
+
+static unsigned fill_package_struct(char *control_buffer)
+{
+ static const char field_names[] ALIGN1 =
+ "Package\0""Version\0"
+ "Pre-Depends\0""Depends\0""Replaces\0""Provides\0"
+ "Conflicts\0""Suggests\0""Recommends\0""Enhances\0";
+
+ common_node_t *new_node = xzalloc(sizeof(common_node_t));
+ char *field_name;
+ char *field_value;
+ int field_start = 0;
+ int num = -1;
+ int buffer_length = strlen(control_buffer);
+
+ new_node->version = search_name_hashtable("unknown");
+ while (field_start < buffer_length) {
+ unsigned field_num;
+
+ field_start += read_package_field(&control_buffer[field_start],
+ &field_name, &field_value);
+
+ if (field_name == NULL) {
+ goto fill_package_struct_cleanup;
+ }
+
+ field_num = index_in_strings(field_names, field_name);
+ switch (field_num) {
+ case 0: /* Package */
+ new_node->name = search_name_hashtable(field_value);
+ break;
+ case 1: /* Version */
+ new_node->version = search_name_hashtable(field_value);
+ break;
+ case 2: /* Pre-Depends */
+ add_split_dependencies(new_node, field_value, EDGE_PRE_DEPENDS);
+ break;
+ case 3: /* Depends */
+ add_split_dependencies(new_node, field_value, EDGE_DEPENDS);
+ break;
+ case 4: /* Replaces */
+ add_split_dependencies(new_node, field_value, EDGE_REPLACES);
+ break;
+ case 5: /* Provides */
+ add_split_dependencies(new_node, field_value, EDGE_PROVIDES);
+ break;
+ case 6: /* Conflicts */
+ add_split_dependencies(new_node, field_value, EDGE_CONFLICTS);
+ break;
+ case 7: /* Suggests */
+ add_split_dependencies(new_node, field_value, EDGE_SUGGESTS);
+ break;
+ case 8: /* Recommends */
+ add_split_dependencies(new_node, field_value, EDGE_RECOMMENDS);
+ break;
+ case 9: /* Enhances */
+ add_split_dependencies(new_node, field_value, EDGE_ENHANCES);
+ break;
+ }
+ fill_package_struct_cleanup:
+ free(field_name);
+ free(field_value);
+ }
+
+ if (new_node->version == search_name_hashtable("unknown")) {
+ free_package(new_node);
+ return -1;
+ }
+ num = search_package_hashtable(new_node->name, new_node->version, VER_EQUAL);
+ free_package(package_hashtable[num]);
+ package_hashtable[num] = new_node;
+ return num;
+}
+
+/* if num = 1, it returns the want status, 2 returns flag, 3 returns status */
+static unsigned get_status(const unsigned status_node, const int num)
+{
+ char *status_string = name_hashtable[status_hashtable[status_node]->status];
+ char *state_sub_string;
+ unsigned state_sub_num;
+ int len;
+ int i;
+
+ /* set tmp_string to point to the start of the word number */
+ for (i = 1; i < num; i++) {
+ /* skip past a word */
+ status_string += strcspn(status_string, " ");
+ /* skip past the separating spaces */
+ status_string += strspn(status_string, " ");
+ }
+ len = strcspn(status_string, " \n");
+ state_sub_string = xstrndup(status_string, len);
+ state_sub_num = search_name_hashtable(state_sub_string);
+ free(state_sub_string);
+ return state_sub_num;
+}
+
+static void set_status(const unsigned status_node_num, const char *new_value, const int position)
+{
+ const unsigned new_value_len = strlen(new_value);
+ const unsigned new_value_num = search_name_hashtable(new_value);
+ unsigned want = get_status(status_node_num, 1);
+ unsigned flag = get_status(status_node_num, 2);
+ unsigned status = get_status(status_node_num, 3);
+ int want_len = strlen(name_hashtable[want]);
+ int flag_len = strlen(name_hashtable[flag]);
+ int status_len = strlen(name_hashtable[status]);
+ char *new_status;
+
+ switch (position) {
+ case 1:
+ want = new_value_num;
+ want_len = new_value_len;
+ break;
+ case 2:
+ flag = new_value_num;
+ flag_len = new_value_len;
+ break;
+ case 3:
+ status = new_value_num;
+ status_len = new_value_len;
+ break;
+ default:
+ bb_error_msg_and_die("DEBUG ONLY: this shouldnt happen");
+ }
+
+ new_status = xasprintf("%s %s %s", name_hashtable[want], name_hashtable[flag], name_hashtable[status]);
+ status_hashtable[status_node_num]->status = search_name_hashtable(new_status);
+ free(new_status);
+}
+
+static const char *describe_status(int status_num)
+{
+ int status_want, status_state;
+ if (status_hashtable[status_num] == NULL || status_hashtable[status_num]->status == 0)
+ return "is not installed or flagged to be installed";
+
+ status_want = get_status(status_num, 1);
+ status_state = get_status(status_num, 3);
+
+ if (status_state == search_name_hashtable("installed")) {
+ if (status_want == search_name_hashtable("install"))
+ return "is installed";
+ if (status_want == search_name_hashtable("deinstall"))
+ return "is marked to be removed";
+ if (status_want == search_name_hashtable("purge"))
+ return "is marked to be purged";
+ }
+ if (status_want == search_name_hashtable("unknown"))
+ return "is in an indeterminate state";
+ if (status_want == search_name_hashtable("install"))
+ return "is marked to be installed";
+
+ return "is not installed or flagged to be installed";
+}
+
+static void index_status_file(const char *filename)
+{
+ FILE *status_file;
+ char *control_buffer;
+ char *status_line;
+ status_node_t *status_node = NULL;
+ unsigned status_num;
+
+ status_file = xfopen(filename, "r");
+ while ((control_buffer = xmalloc_fgetline_str(status_file, "\n\n")) != NULL) {
+ const unsigned package_num = fill_package_struct(control_buffer);
+ if (package_num != -1) {
+ status_node = xmalloc(sizeof(status_node_t));
+ /* fill_package_struct doesnt handle the status field */
+ status_line = strstr(control_buffer, "Status:");
+ if (status_line != NULL) {
+ status_line += 7;
+ status_line += strspn(status_line, " \n\t");
+ status_line = xstrndup(status_line, strcspn(status_line, "\n"));
+ status_node->status = search_name_hashtable(status_line);
+ free(status_line);
+ }
+ status_node->package = package_num;
+ status_num = search_status_hashtable(name_hashtable[package_hashtable[status_node->package]->name]);
+ status_hashtable[status_num] = status_node;
+ }
+ free(control_buffer);
+ }
+ fclose(status_file);
+}
+
+static void write_buffer_no_status(FILE *new_status_file, const char *control_buffer)
+{
+ char *name;
+ char *value;
+ int start = 0;
+ while (1) {
+ start += read_package_field(&control_buffer[start], &name, &value);
+ if (name == NULL) {
+ break;
+ }
+ if (strcmp(name, "Status") != 0) {
+ fprintf(new_status_file, "%s: %s\n", name, value);
+ }
+ }
+}
+
+/* This could do with a cleanup */
+static void write_status_file(deb_file_t **deb_file)
+{
+ FILE *old_status_file = xfopen("/var/lib/dpkg/status", "r");
+ FILE *new_status_file = xfopen("/var/lib/dpkg/status.udeb", "w");
+ char *package_name;
+ char *status_from_file;
+ char *control_buffer = NULL;
+ char *tmp_string;
+ int status_num;
+ int field_start = 0;
+ int write_flag;
+ int i = 0;
+
+ /* Update previously known packages */
+ while ((control_buffer = xmalloc_fgetline_str(old_status_file, "\n\n")) != NULL) {
+ tmp_string = strstr(control_buffer, "Package:");
+ if (tmp_string == NULL) {
+ continue;
+ }
+
+ tmp_string += 8;
+ tmp_string += strspn(tmp_string, " \n\t");
+ package_name = xstrndup(tmp_string, strcspn(tmp_string, "\n"));
+ write_flag = FALSE;
+ tmp_string = strstr(control_buffer, "Status:");
+ if (tmp_string != NULL) {
+ /* Seperate the status value from the control buffer */
+ tmp_string += 7;
+ tmp_string += strspn(tmp_string, " \n\t");
+ status_from_file = xstrndup(tmp_string, strcspn(tmp_string, "\n"));
+ } else {
+ status_from_file = NULL;
+ }
+
+ /* Find this package in the status hashtable */
+ status_num = search_status_hashtable(package_name);
+ if (status_hashtable[status_num] != NULL) {
+ const char *status_from_hashtable = name_hashtable[status_hashtable[status_num]->status];
+ if (strcmp(status_from_file, status_from_hashtable) != 0) {
+ /* New status isnt exactly the same as old status */
+ const int state_status = get_status(status_num, 3);
+ if ((strcmp("installed", name_hashtable[state_status]) == 0)
+ || (strcmp("unpacked", name_hashtable[state_status]) == 0)
+ ) {
+ /* We need to add the control file from the package */
+ i = 0;
+ while (deb_file[i] != NULL) {
+ if (strcmp(package_name, name_hashtable[package_hashtable[deb_file[i]->package]->name]) == 0) {
+ /* Write a status file entry with a modified status */
+ /* remove trailing \n's */
+ write_buffer_no_status(new_status_file, deb_file[i]->control_file);
+ set_status(status_num, "ok", 2);
+ fprintf(new_status_file, "Status: %s\n\n",
+ name_hashtable[status_hashtable[status_num]->status]);
+ write_flag = TRUE;
+ break;
+ }
+ i++;
+ }
+ /* This is temperary, debugging only */
+ if (deb_file[i] == NULL) {
+ bb_error_msg_and_die("ALERT: cannot find a control file, "
+ "your status file may be broken, status may be "
+ "incorrect for %s", package_name);
+ }
+ }
+ else if (strcmp("not-installed", name_hashtable[state_status]) == 0) {
+ /* Only write the Package, Status, Priority and Section lines */
+ fprintf(new_status_file, "Package: %s\n", package_name);
+ fprintf(new_status_file, "Status: %s\n", status_from_hashtable);
+
+ while (1) {
+ char *field_name;
+ char *field_value;
+ field_start += read_package_field(&control_buffer[field_start], &field_name, &field_value);
+ if (field_name == NULL) {
+ break;
+ }
+ if ((strcmp(field_name, "Priority") == 0) ||
+ (strcmp(field_name, "Section") == 0)) {
+ fprintf(new_status_file, "%s: %s\n", field_name, field_value);
+ }
+ }
+ write_flag = TRUE;
+ fputs("\n", new_status_file);
+ }
+ else if (strcmp("config-files", name_hashtable[state_status]) == 0) {
+ /* only change the status line */
+ while (1) {
+ char *field_name;
+ char *field_value;
+ field_start += read_package_field(&control_buffer[field_start], &field_name, &field_value);
+ if (field_name == NULL) {
+ break;
+ }
+ /* Setup start point for next field */
+ if (strcmp(field_name, "Status") == 0) {
+ fprintf(new_status_file, "Status: %s\n", status_from_hashtable);
+ } else {
+ fprintf(new_status_file, "%s: %s\n", field_name, field_value);
+ }
+ }
+ write_flag = TRUE;
+ fputs("\n", new_status_file);
+ }
+ }
+ }
+ /* If the package from the status file wasnt handle above, do it now*/
+ if (!write_flag) {
+ fprintf(new_status_file, "%s\n\n", control_buffer);
+ }
+
+ free(status_from_file);
+ free(package_name);
+ free(control_buffer);
+ }
+
+ /* Write any new packages */
+ for (i = 0; deb_file[i] != NULL; i++) {
+ status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[i]->package]->name]);
+ if (strcmp("reinstreq", name_hashtable[get_status(status_num, 2)]) == 0) {
+ write_buffer_no_status(new_status_file, deb_file[i]->control_file);
+ set_status(status_num, "ok", 2);
+ fprintf(new_status_file, "Status: %s\n\n", name_hashtable[status_hashtable[status_num]->status]);
+ }
+ }
+ fclose(old_status_file);
+ fclose(new_status_file);
+
+ /* Create a separate backfile to dpkg */
+ if (rename("/var/lib/dpkg/status", "/var/lib/dpkg/status.udeb.bak") == -1) {
+ if (errno != ENOENT)
+ bb_error_msg_and_die("cannot create backup status file");
+ /* Its ok if renaming the status file fails because status
+ * file doesnt exist, maybe we are starting from scratch */
+ bb_error_msg("no status file found, creating new one");
+ }
+
+ xrename("/var/lib/dpkg/status.udeb", "/var/lib/dpkg/status");
+}
+
+/* This function returns TRUE if the given package can satisfy a
+ * dependency of type depend_type.
+ *
+ * A pre-depends is satisfied only if a package is already installed,
+ * which a regular depends can be satisfied by a package which we want
+ * to install.
+ */
+static int package_satisfies_dependency(int package, int depend_type)
+{
+ int status_num = search_status_hashtable(name_hashtable[package_hashtable[package]->name]);
+
+ /* status could be unknown if package is a pure virtual
+ * provides which cannot satisfy any dependency by itself.
+ */
+ if (status_hashtable[status_num] == NULL)
+ return 0;
+
+ switch (depend_type) {
+ case EDGE_PRE_DEPENDS: return get_status(status_num, 3) == search_name_hashtable("installed");
+ case EDGE_DEPENDS: return get_status(status_num, 1) == search_name_hashtable("install");
+ }
+ return 0;
+}
+
+static int check_deps(deb_file_t **deb_file, int deb_start /*, int dep_max_count - ?? */)
+{
+ int *conflicts = NULL;
+ int conflicts_num = 0;
+ int i = deb_start;
+ int j;
+
+ /* Check for conflicts
+ * TODO: TEST if conflicts with other packages to be installed
+ *
+ * Add install packages and the packages they provide
+ * to the list of files to check conflicts for
+ */
+
+ /* Create array of package numbers to check against
+ * installed package for conflicts*/
+ while (deb_file[i] != NULL) {
+ const unsigned package_num = deb_file[i]->package;
+ conflicts = xrealloc(conflicts, sizeof(int) * (conflicts_num + 1));
+ conflicts[conflicts_num] = package_num;
+ conflicts_num++;
+ /* add provides to conflicts list */
+ for (j = 0; j < package_hashtable[package_num]->num_of_edges; j++) {
+ if (package_hashtable[package_num]->edge[j]->type == EDGE_PROVIDES) {
+ const int conflicts_package_num = search_package_hashtable(
+ package_hashtable[package_num]->edge[j]->name,
+ package_hashtable[package_num]->edge[j]->version,
+ package_hashtable[package_num]->edge[j]->operator);
+ if (package_hashtable[conflicts_package_num] == NULL) {
+ /* create a new package */
+ common_node_t *new_node = xzalloc(sizeof(common_node_t));
+ new_node->name = package_hashtable[package_num]->edge[j]->name;
+ new_node->version = package_hashtable[package_num]->edge[j]->version;
+ package_hashtable[conflicts_package_num] = new_node;
+ }
+ conflicts = xrealloc(conflicts, sizeof(int) * (conflicts_num + 1));
+ conflicts[conflicts_num] = conflicts_package_num;
+ conflicts_num++;
+ }
+ }
+ i++;
+ }
+
+ /* Check conflicts */
+ i = 0;
+ while (deb_file[i] != NULL) {
+ const common_node_t *package_node = package_hashtable[deb_file[i]->package];
+ int status_num = 0;
+ status_num = search_status_hashtable(name_hashtable[package_node->name]);
+
+ if (get_status(status_num, 3) == search_name_hashtable("installed")) {
+ i++;
+ continue;
+ }
+
+ for (j = 0; j < package_node->num_of_edges; j++) {
+ const edge_t *package_edge = package_node->edge[j];
+
+ if (package_edge->type == EDGE_CONFLICTS) {
+ const unsigned package_num =
+ search_package_hashtable(package_edge->name,
+ package_edge->version,
+ package_edge->operator);
+ int result = 0;
+ if (package_hashtable[package_num] != NULL) {
+ status_num = search_status_hashtable(name_hashtable[package_hashtable[package_num]->name]);
+
+ if (get_status(status_num, 1) == search_name_hashtable("install")) {
+ result = test_version(package_hashtable[deb_file[i]->package]->version,
+ package_edge->version, package_edge->operator);
+ }
+ }
+
+ if (result) {
+ bb_error_msg_and_die("package %s conflicts with %s",
+ name_hashtable[package_node->name],
+ name_hashtable[package_edge->name]);
+ }
+ }
+ }
+ i++;
+ }
+
+
+ /* Check dependendcies */
+ for (i = 0; i < PACKAGE_HASH_PRIME; i++) {
+ int status_num = 0;
+ int number_of_alternatives = 0;
+ const edge_t * root_of_alternatives = NULL;
+ const common_node_t *package_node = package_hashtable[i];
+
+ /* If the package node does not exist then this
+ * package is a virtual one. In which case there are
+ * no dependencies to check.
+ */
+ if (package_node == NULL) continue;
+
+ status_num = search_status_hashtable(name_hashtable[package_node->name]);
+
+ /* If there is no status then this package is a
+ * virtual one provided by something else. In which
+ * case there are no dependencies to check.
+ */
+ if (status_hashtable[status_num] == NULL) continue;
+
+ /* If we don't want this package installed then we may
+ * as well ignore it's dependencies.
+ */
+ if (get_status(status_num, 1) != search_name_hashtable("install")) {
+ continue;
+ }
+
+ /* This code is tested only for EDGE_DEPENDS, since I
+ * have no suitable pre-depends available. There is no
+ * reason that it shouldn't work though :-)
+ */
+ for (j = 0; j < package_node->num_of_edges; j++) {
+ const edge_t *package_edge = package_node->edge[j];
+ unsigned package_num;
+
+ if (package_edge->type == EDGE_OR_PRE_DEPENDS
+ || package_edge->type == EDGE_OR_DEPENDS
+ ) { /* start an EDGE_OR_ list */
+ number_of_alternatives = package_edge->version;
+ root_of_alternatives = package_edge;
+ continue;
+ }
+ if (number_of_alternatives == 0) { /* not in the middle of an EDGE_OR_ list */
+ number_of_alternatives = 1;
+ root_of_alternatives = NULL;
+ }
+
+ package_num = search_package_hashtable(package_edge->name, package_edge->version, package_edge->operator);
+
+ if (package_edge->type == EDGE_PRE_DEPENDS ||
+ package_edge->type == EDGE_DEPENDS) {
+ int result=1;
+ status_num = 0;
+
+ /* If we are inside an alternative then check
+ * this edge is the right type.
+ *
+ * EDGE_DEPENDS == OR_DEPENDS -1
+ * EDGE_PRE_DEPENDS == OR_PRE_DEPENDS -1
+ */
+ if (root_of_alternatives && package_edge->type != root_of_alternatives->type - 1)
+ bb_error_msg_and_die("fatal error, package dependencies corrupt: %d != %d - 1",
+ package_edge->type, root_of_alternatives->type);
+
+ if (package_hashtable[package_num] != NULL)
+ result = !package_satisfies_dependency(package_num, package_edge->type);
+
+ if (result) { /* check for other package which provide what we are looking for */
+ int provider = -1;
+
+ while ((provider = search_for_provides(package_edge->name, provider)) > -1) {
+ if (package_hashtable[provider] == NULL) {
+ puts("Have a provider but no package information for it");
+ continue;
+ }
+ result = !package_satisfies_dependency(provider, package_edge->type);
+
+ if (result == 0)
+ break;
+ }
+ }
+
+ /* It must be already installed, or to be installed */
+ number_of_alternatives--;
+ if (result && number_of_alternatives == 0) {
+ if (root_of_alternatives)
+ bb_error_msg_and_die(
+ "package %s %sdepends on %s, "
+ "which cannot be satisfied",
+ name_hashtable[package_node->name],
+ package_edge->type == EDGE_PRE_DEPENDS ? "pre-" : "",
+ name_hashtable[root_of_alternatives->name]);
+ bb_error_msg_and_die(
+ "package %s %sdepends on %s, which %s\n",
+ name_hashtable[package_node->name],
+ package_edge->type == EDGE_PRE_DEPENDS ? "pre-" : "",
+ name_hashtable[package_edge->name],
+ describe_status(status_num));
+ }
+ if (result == 0 && number_of_alternatives) {
+ /* we've found a package which
+ * satisfies the dependency,
+ * so skip over the rest of
+ * the alternatives.
+ */
+ j += number_of_alternatives;
+ number_of_alternatives = 0;
+ }
+ }
+ }
+ }
+ free(conflicts);
+ return TRUE;
+}
+
+static char **create_list(const char *filename)
+{
+ FILE *list_stream;
+ char **file_list;
+ char *line;
+ int count;
+
+ /* don't use [xw]fopen here, handle error ourself */
+ list_stream = fopen(filename, "r");
+ if (list_stream == NULL) {
+ return NULL;
+ }
+
+ file_list = NULL;
+ count = 0;
+ while ((line = xmalloc_fgetline(list_stream)) != NULL) {
+ file_list = xrealloc(file_list, sizeof(char *) * (count + 2));
+ file_list[count++] = line;
+ file_list[count] = NULL;
+ }
+ fclose(list_stream);
+
+ return file_list;
+}
+
+/* maybe i should try and hook this into remove_file.c somehow */
+static int remove_file_array(char **remove_names, char **exclude_names)
+{
+ struct stat path_stat;
+ int remove_flag = 1; /* not removed anything yet */
+ int i, j;
+
+ if (remove_names == NULL) {
+ return 0;
+ }
+ for (i = 0; remove_names[i] != NULL; i++) {
+ if (exclude_names != NULL) {
+ for (j = 0; exclude_names[j] != NULL; j++) {
+ if (strcmp(remove_names[i], exclude_names[j]) == 0) {
+ goto skip;
+ }
+ }
+ }
+ /* TODO: why we are checking lstat? we can just try rm/rmdir */
+ if (lstat(remove_names[i], &path_stat) < 0) {
+ continue;
+ }
+ if (S_ISDIR(path_stat.st_mode)) {
+ remove_flag &= rmdir(remove_names[i]); /* 0 if no error */
+ } else {
+ remove_flag &= unlink(remove_names[i]); /* 0 if no error */
+ }
+ skip:
+ continue;
+ }
+ return (remove_flag == 0);
+}
+
+static void run_package_script_or_die(const char *package_name, const char *script_type)
+{
+ char *script_path;
+ int result;
+
+ script_path = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, script_type);
+
+ /* If the file doesnt exist is isnt fatal */
+ result = access(script_path, F_OK) ? EXIT_SUCCESS : system(script_path);
+ free(script_path);
+ if (result)
+ bb_error_msg_and_die("%s failed, exit code %d", script_type, result);
+}
+
+/*
+The policy manual defines what scripts get called when and with
+what arguments. I realize that busybox does not support all of
+these scenarios, but it does support some of them; it does not,
+however, run them with any parameters in run_package_script_or_die().
+Here are the scripts:
+
+preinst install
+preinst install <old_version>
+preinst upgrade <old_version>
+preinst abort_upgrade <new_version>
+postinst configure <most_recent_version>
+postinst abort-upgade <new_version>
+postinst abort-remove
+postinst abort-remove in-favour <package> <version>
+postinst abort-deconfigure in-favor <failed_install_package> removing <conflicting_package> <version>
+prerm remove
+prerm upgrade <new_version>
+prerm failed-upgrade <old_version>
+prerm remove in-favor <package> <new_version>
+prerm deconfigure in-favour <package> <version> removing <package> <version>
+postrm remove
+postrm purge
+postrm upgrade <new_version>
+postrm failed-upgrade <old_version>
+postrm abort-install
+postrm abort-install <old_version>
+postrm abort-upgrade <old_version>
+postrm disappear <overwriter> <version>
+*/
+static const char *const all_control_files[] = {
+ "preinst", "postinst", "prerm", "postrm",
+ "list", "md5sums", "shlibs", "conffiles",
+ "config", "templates"
+};
+
+static char **all_control_list(const char *package_name)
+{
+ unsigned i = 0;
+ char **remove_files;
+
+ /* Create a list of all /var/lib/dpkg/info/<package> files */
+ remove_files = xzalloc(sizeof(all_control_files) + sizeof(char*));
+ while (i < ARRAY_SIZE(all_control_files)) {
+ remove_files[i] = xasprintf("/var/lib/dpkg/info/%s.%s",
+ package_name, all_control_files[i]);
+ i++;
+ }
+
+ return remove_files;
+}
+
+static void free_array(char **array)
+{
+ if (array) {
+ unsigned i = 0;
+ while (array[i]) {
+ free(array[i]);
+ i++;
+ }
+ free(array);
+ }
+}
+
+/* This function lists information on the installed packages. It loops through
+ * the status_hashtable to retrieve the info. This results in smaller code than
+ * scanning the status file. The resulting list, however, is unsorted.
+ */
+static void list_packages(void)
+{
+ int i;
+
+ puts(" Name Version");
+ puts("+++-==============-==============");
+
+ /* go through status hash, dereference package hash and finally strings */
+ for (i = 0; i < STATUS_HASH_PRIME+1; i++) {
+ if (status_hashtable[i]) {
+ const char *stat_str; /* status string */
+ const char *name_str; /* package name */
+ const char *vers_str; /* version */
+ char s1, s2; /* status abbreviations */
+ int spccnt; /* space count */
+ int j;
+
+ stat_str = name_hashtable[status_hashtable[i]->status];
+ name_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->name];
+ vers_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->version];
+
+ /* get abbreviation for status field 1 */
+ s1 = stat_str[0] == 'i' ? 'i' : 'r';
+
+ /* get abbreviation for status field 2 */
+ for (j = 0, spccnt = 0; stat_str[j] && spccnt < 2; j++) {
+ if (stat_str[j] == ' ') spccnt++;
+ }
+ s2 = stat_str[j];
+
+ /* print out the line formatted like Debian dpkg */
+ printf("%c%c %-14s %s\n", s1, s2, name_str, vers_str);
+ }
+ }
+}
+
+static void remove_package(const unsigned package_num, int noisy)
+{
+ const char *package_name = name_hashtable[package_hashtable[package_num]->name];
+ const char *package_version = name_hashtable[package_hashtable[package_num]->version];
+ const unsigned status_num = search_status_hashtable(package_name);
+ const int package_name_length = strlen(package_name);
+ char **remove_files;
+ char **exclude_files;
+ char list_name[package_name_length + 25];
+ char conffile_name[package_name_length + 30];
+
+ if (noisy)
+ printf("Removing %s (%s)...\n", package_name, package_version);
+
+ /* Run prerm script */
+ run_package_script_or_die(package_name, "prerm");
+
+ /* Create a list of files to remove, and a separate list of those to keep */
+ sprintf(list_name, "/var/lib/dpkg/info/%s.%s", package_name, "list");
+ remove_files = create_list(list_name);
+
+ sprintf(conffile_name, "/var/lib/dpkg/info/%s.%s", package_name, "conffiles");
+ exclude_files = create_list(conffile_name);
+
+ /* Some directories can't be removed straight away, so do multiple passes */
+ while (remove_file_array(remove_files, exclude_files))
+ continue;
+ free_array(exclude_files);
+ free_array(remove_files);
+
+ /* Create a list of files in /var/lib/dpkg/info/<package>.* to keep */
+ exclude_files = xzalloc(sizeof(char*) * 3);
+ exclude_files[0] = xstrdup(conffile_name);
+ exclude_files[1] = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "postrm");
+
+ /* Create a list of all /var/lib/dpkg/info/<package> files */
+ remove_files = all_control_list(package_name);
+
+ remove_file_array(remove_files, exclude_files);
+ free_array(remove_files);
+ free_array(exclude_files);
+
+ /* rename <package>.conffiles to <package>.list
+ * The conffiles control file isn't required in Debian packages, so don't
+ * error out if it's missing. */
+ rename(conffile_name, list_name);
+
+ /* Change package status */
+ set_status(status_num, "config-files", 3);
+}
+
+static void purge_package(const unsigned package_num)
+{
+ const char *package_name = name_hashtable[package_hashtable[package_num]->name];
+ const char *package_version = name_hashtable[package_hashtable[package_num]->version];
+ const unsigned status_num = search_status_hashtable(package_name);
+ char **remove_files;
+ char **exclude_files;
+ char list_name[strlen(package_name) + 25];
+
+ printf("Purging %s (%s)...\n", package_name, package_version);
+
+ /* Run prerm script */
+ run_package_script_or_die(package_name, "prerm");
+
+ /* Create a list of files to remove */
+ sprintf(list_name, "/var/lib/dpkg/info/%s.%s", package_name, "list");
+ remove_files = create_list(list_name);
+
+ exclude_files = xzalloc(sizeof(char*));
+
+ /* Some directories cant be removed straight away, so do multiple passes */
+ while (remove_file_array(remove_files, exclude_files)) /* repeat */;
+ free_array(remove_files);
+
+ /* Create a list of all /var/lib/dpkg/info/<package> files */
+ remove_files = all_control_list(package_name);
+ remove_file_array(remove_files, exclude_files);
+ free_array(remove_files);
+ free(exclude_files);
+
+ /* Run postrm script */
+ run_package_script_or_die(package_name, "postrm");
+
+ /* Change package status */
+ set_status(status_num, "not-installed", 3);
+}
+
+static archive_handle_t *init_archive_deb_ar(const char *filename)
+{
+ archive_handle_t *ar_handle;
+
+ /* Setup an ar archive handle that refers to the gzip sub archive */
+ ar_handle = init_handle();
+ ar_handle->filter = filter_accept_list_reassign;
+ ar_handle->src_fd = xopen(filename, O_RDONLY);
+
+ return ar_handle;
+}
+
+static void init_archive_deb_control(archive_handle_t *ar_handle)
+{
+ archive_handle_t *tar_handle;
+
+ /* Setup the tar archive handle */
+ tar_handle = init_handle();
+ tar_handle->src_fd = ar_handle->src_fd;
+
+ /* We don't care about data.tar.* or debian-binary, just control.tar.* */
+#if ENABLE_FEATURE_DEB_TAR_GZ
+ llist_add_to(&(ar_handle->accept), (char*)"control.tar.gz");
+#endif
+#if ENABLE_FEATURE_DEB_TAR_BZ2
+ llist_add_to(&(ar_handle->accept), (char*)"control.tar.bz2");
+#endif
+
+ /* Assign the tar handle as a subarchive of the ar handle */
+ ar_handle->sub_archive = tar_handle;
+}
+
+static void init_archive_deb_data(archive_handle_t *ar_handle)
+{
+ archive_handle_t *tar_handle;
+
+ /* Setup the tar archive handle */
+ tar_handle = init_handle();
+ tar_handle->src_fd = ar_handle->src_fd;
+
+ /* We don't care about control.tar.* or debian-binary, just data.tar.* */
+#if ENABLE_FEATURE_DEB_TAR_GZ
+ llist_add_to(&(ar_handle->accept), (char*)"data.tar.gz");
+#endif
+#if ENABLE_FEATURE_DEB_TAR_BZ2
+ llist_add_to(&(ar_handle->accept), (char*)"data.tar.bz2");
+#endif
+
+ /* Assign the tar handle as a subarchive of the ar handle */
+ ar_handle->sub_archive = tar_handle;
+}
+
+static char *deb_extract_control_file_to_buffer(archive_handle_t *ar_handle, llist_t *myaccept)
+{
+ ar_handle->sub_archive->action_data = data_extract_to_buffer;
+ ar_handle->sub_archive->accept = myaccept;
+ ar_handle->sub_archive->filter = filter_accept_list;
+
+ unpack_ar_archive(ar_handle);
+ close(ar_handle->src_fd);
+
+ return ar_handle->sub_archive->buffer;
+}
+
+static void data_extract_all_prefix(archive_handle_t *archive_handle)
+{
+ char *name_ptr = archive_handle->file_header->name;
+
+ name_ptr += strspn(name_ptr, "./");
+ if (name_ptr[0] != '\0') {
+ archive_handle->file_header->name = xasprintf("%s%s", archive_handle->buffer, name_ptr);
+ data_extract_all(archive_handle);
+ }
+}
+
+static void unpack_package(deb_file_t *deb_file)
+{
+ const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name];
+ const unsigned status_num = search_status_hashtable(package_name);
+ const unsigned status_package_num = status_hashtable[status_num]->package;
+ char *info_prefix;
+ char *list_filename;
+ archive_handle_t *archive_handle;
+ FILE *out_stream;
+ llist_t *accept_list;
+ int i;
+
+ /* If existing version, remove it first */
+ if (strcmp(name_hashtable[get_status(status_num, 3)], "installed") == 0) {
+ /* Package is already installed, remove old version first */
+ printf("Preparing to replace %s %s (using %s)...\n", package_name,
+ name_hashtable[package_hashtable[status_package_num]->version],
+ deb_file->filename);
+ remove_package(status_package_num, 0);
+ } else {
+ printf("Unpacking %s (from %s)...\n", package_name, deb_file->filename);
+ }
+
+ /* Extract control.tar.gz to /var/lib/dpkg/info/<package>.filename */
+ info_prefix = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "");
+ archive_handle = init_archive_deb_ar(deb_file->filename);
+ init_archive_deb_control(archive_handle);
+
+ accept_list = NULL;
+ i = 0;
+ while (i < ARRAY_SIZE(all_control_files)) {
+ char *c = xasprintf("./%s", all_control_files[i]);
+ llist_add_to(&accept_list, c);
+ i++;
+ }
+ archive_handle->sub_archive->accept = accept_list;
+ archive_handle->sub_archive->filter = filter_accept_list;
+ archive_handle->sub_archive->action_data = data_extract_all_prefix;
+ archive_handle->sub_archive->buffer = info_prefix;
+ archive_handle->sub_archive->flags |= ARCHIVE_EXTRACT_UNCONDITIONAL;
+ unpack_ar_archive(archive_handle);
+
+ /* Run the preinst prior to extracting */
+ run_package_script_or_die(package_name, "preinst");
+
+ /* Extract data.tar.gz to the root directory */
+ archive_handle = init_archive_deb_ar(deb_file->filename);
+ init_archive_deb_data(archive_handle);
+ archive_handle->sub_archive->action_data = data_extract_all_prefix;
+ archive_handle->sub_archive->buffer = (char*)"/"; /* huh? */
+ archive_handle->sub_archive->flags |= ARCHIVE_EXTRACT_UNCONDITIONAL;
+ unpack_ar_archive(archive_handle);
+
+ /* Create the list file */
+ list_filename = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "list");
+ out_stream = xfopen(list_filename, "w");
+ while (archive_handle->sub_archive->passed) {
+ /* the leading . has been stripped by data_extract_all_prefix already */
+ fputs(archive_handle->sub_archive->passed->data, out_stream);
+ fputc('\n', out_stream);
+ archive_handle->sub_archive->passed = archive_handle->sub_archive->passed->link;
+ }
+ fclose(out_stream);
+
+ /* change status */
+ set_status(status_num, "install", 1);
+ set_status(status_num, "unpacked", 3);
+
+ free(info_prefix);
+ free(list_filename);
+}
+
+static void configure_package(deb_file_t *deb_file)
+{
+ const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name];
+ const char *package_version = name_hashtable[package_hashtable[deb_file->package]->version];
+ const int status_num = search_status_hashtable(package_name);
+
+ printf("Setting up %s (%s)...\n", package_name, package_version);
+
+ /* Run the postinst script */
+ /* TODO: handle failure gracefully */
+ run_package_script_or_die(package_name, "postinst");
+
+ /* Change status to reflect success */
+ set_status(status_num, "install", 1);
+ set_status(status_num, "installed", 3);
+}
+
+int dpkg_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int dpkg_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ deb_file_t **deb_file = NULL;
+ status_node_t *status_node;
+ char *str_f;
+ int opt;
+ int package_num;
+ int deb_count = 0;
+ int state_status;
+ int status_num;
+ int i;
+ enum {
+ OPT_configure = 0x1,
+ OPT_force_ignore_depends = 0x2,
+ OPT_install = 0x4,
+ OPT_list_installed = 0x8,
+ OPT_purge = 0x10,
+ OPT_remove = 0x20,
+ OPT_unpack = 0x40,
+ };
+
+ INIT_G();
+
+ opt = getopt32(argv, "CF:ilPru", &str_f);
+ //if (opt & OPT_configure) ... // -C
+ if (opt & OPT_force_ignore_depends) { // -F (--force in official dpkg)
+ if (strcmp(str_f, "depends"))
+ opt &= ~OPT_force_ignore_depends;
+ }
+ //if (opt & OPT_install) ... // -i
+ //if (opt & OPT_list_installed) ... // -l
+ //if (opt & OPT_purge) ... // -P
+ //if (opt & OPT_remove) ... // -r
+ //if (opt & OPT_unpack) ... // -u (--unpack in official dpkg)
+ argv += optind;
+ /* check for non-option argument if expected */
+ if (!opt || (!argv[0] && !(opt && OPT_list_installed)))
+ bb_show_usage();
+
+/* puts("(Reading database ... xxxxx files and directories installed.)"); */
+ index_status_file("/var/lib/dpkg/status");
+
+ /* if the list action was given print the installed packages and exit */
+ if (opt & OPT_list_installed) {
+ list_packages();
+ return EXIT_SUCCESS;
+ }
+
+ /* Read arguments and store relevant info in structs */
+ while (*argv) {
+ /* deb_count = nb_elem - 1 and we need nb_elem + 1 to allocate terminal node [NULL pointer] */
+ deb_file = xrealloc(deb_file, sizeof(deb_file[0]) * (deb_count + 2));
+ deb_file[deb_count] = xzalloc(sizeof(deb_file[0][0]));
+ if (opt & (OPT_install | OPT_unpack)) {
+ /* -i/-u: require filename */
+ archive_handle_t *archive_handle;
+ llist_t *control_list = NULL;
+
+ /* Extract the control file */
+ llist_add_to(&control_list, (char*)"./control");
+ archive_handle = init_archive_deb_ar(argv[0]);
+ init_archive_deb_control(archive_handle);
+ deb_file[deb_count]->control_file = deb_extract_control_file_to_buffer(archive_handle, control_list);
+ if (deb_file[deb_count]->control_file == NULL) {
+ bb_error_msg_and_die("cannot extract control file");
+ }
+ deb_file[deb_count]->filename = xstrdup(argv[0]);
+ package_num = fill_package_struct(deb_file[deb_count]->control_file);
+
+ if (package_num == -1) {
+ bb_error_msg("invalid control file in %s", argv[0]);
+ argv++;
+ continue;
+ }
+ deb_file[deb_count]->package = (unsigned) package_num;
+
+ /* Add the package to the status hashtable */
+ if (opt & (OPT_unpack | OPT_install)) {
+ /* Try and find a currently installed version of this package */
+ status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]);
+ /* If no previous entry was found initialise a new entry */
+ if (status_hashtable[status_num] == NULL
+ || status_hashtable[status_num]->status == 0
+ ) {
+ status_node = xmalloc(sizeof(status_node_t));
+ status_node->package = deb_file[deb_count]->package;
+ /* reinstreq isnt changed to "ok" until the package control info
+ * is written to the status file*/
+ status_node->status = search_name_hashtable("install reinstreq not-installed");
+ status_hashtable[status_num] = status_node;
+ } else {
+ set_status(status_num, "install", 1);
+ set_status(status_num, "reinstreq", 2);
+ }
+ }
+ } else if (opt & (OPT_configure | OPT_purge | OPT_remove)) {
+ /* -C/-p/-r: require package name */
+ deb_file[deb_count]->package = search_package_hashtable(
+ search_name_hashtable(argv[0]),
+ search_name_hashtable("ANY"), VER_ANY);
+ if (package_hashtable[deb_file[deb_count]->package] == NULL) {
+ bb_error_msg_and_die("package %s is uninstalled or unknown", argv[0]);
+ }
+ package_num = deb_file[deb_count]->package;
+ status_num = search_status_hashtable(name_hashtable[package_hashtable[package_num]->name]);
+ state_status = get_status(status_num, 3);
+
+ /* check package status is "installed" */
+ if (opt & OPT_remove) {
+ if (strcmp(name_hashtable[state_status], "not-installed") == 0
+ || strcmp(name_hashtable[state_status], "config-files") == 0
+ ) {
+ bb_error_msg_and_die("%s is already removed", name_hashtable[package_hashtable[package_num]->name]);
+ }
+ set_status(status_num, "deinstall", 1);
+ } else if (opt & OPT_purge) {
+ /* if package status is "conf-files" then its ok */
+ if (strcmp(name_hashtable[state_status], "not-installed") == 0) {
+ bb_error_msg_and_die("%s is already purged", name_hashtable[package_hashtable[package_num]->name]);
+ }
+ set_status(status_num, "purge", 1);
+ }
+ }
+ deb_count++;
+ argv++;
+ }
+ if (!deb_count)
+ bb_error_msg_and_die("no package files specified");
+ deb_file[deb_count] = NULL;
+
+ /* Check that the deb file arguments are installable */
+ if (!(opt & OPT_force_ignore_depends)) {
+ if (!check_deps(deb_file, 0 /*, deb_count*/)) {
+ bb_error_msg_and_die("dependency check failed");
+ }
+ }
+
+ /* TODO: install or remove packages in the correct dependency order */
+ for (i = 0; i < deb_count; i++) {
+ /* Remove or purge packages */
+ if (opt & OPT_remove) {
+ remove_package(deb_file[i]->package, 1);
+ }
+ else if (opt & OPT_purge) {
+ purge_package(deb_file[i]->package);
+ }
+ else if (opt & OPT_unpack) {
+ unpack_package(deb_file[i]);
+ }
+ else if (opt & OPT_install) {
+ unpack_package(deb_file[i]);
+ /* package is configured in second pass below */
+ }
+ else if (opt & OPT_configure) {
+ configure_package(deb_file[i]);
+ }
+ }
+ /* configure installed packages */
+ if (opt & OPT_install) {
+ for (i = 0; i < deb_count; i++)
+ configure_package(deb_file[i]);
+ }
+
+ write_status_file(deb_file);
+
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ for (i = 0; i < deb_count; i++) {
+ free(deb_file[i]->control_file);
+ free(deb_file[i]->filename);
+ free(deb_file[i]);
+ }
+
+ free(deb_file);
+
+ for (i = 0; i < NAME_HASH_PRIME; i++) {
+ free(name_hashtable[i]);
+ }
+
+ for (i = 0; i < PACKAGE_HASH_PRIME; i++) {
+ free_package(package_hashtable[i]);
+ }
+
+ for (i = 0; i < STATUS_HASH_PRIME; i++) {
+ free(status_hashtable[i]);
+ }
+
+ free(status_hashtable);
+ free(package_hashtable);
+ free(name_hashtable);
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/dpkg_deb.c b/cleopatre/busybox-1.11.1-spc300/archival/dpkg_deb.c
new file mode 100644
index 0000000000..cbacc91f8c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/dpkg_deb.c
@@ -0,0 +1,97 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * dpkg-deb packs, unpacks and provides information about Debian archives.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+#include "libbb.h"
+#include "unarchive.h"
+
+#define DPKG_DEB_OPT_CONTENTS 1
+#define DPKG_DEB_OPT_CONTROL 2
+#define DPKG_DEB_OPT_FIELD 4
+#define DPKG_DEB_OPT_EXTRACT 8
+#define DPKG_DEB_OPT_EXTRACT_VERBOSE 16
+
+int dpkg_deb_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int dpkg_deb_main(int argc, char **argv)
+{
+ archive_handle_t *ar_archive;
+ archive_handle_t *tar_archive;
+ llist_t *control_tar_llist = NULL;
+ unsigned opt;
+ const char *extract_dir = NULL;
+ short argcount = 1;
+
+ /* Setup the tar archive handle */
+ tar_archive = init_handle();
+
+ /* Setup an ar archive handle that refers to the gzip sub archive */
+ ar_archive = init_handle();
+ ar_archive->sub_archive = tar_archive;
+ ar_archive->filter = filter_accept_list_reassign;
+
+#if ENABLE_FEATURE_DEB_TAR_GZ
+ llist_add_to(&(ar_archive->accept), (char*)"data.tar.gz");
+ llist_add_to(&control_tar_llist, (char*)"control.tar.gz");
+#endif
+
+#if ENABLE_FEATURE_DEB_TAR_BZ2
+ llist_add_to(&(ar_archive->accept), (char*)"data.tar.bz2");
+ llist_add_to(&control_tar_llist, (char*)"control.tar.bz2");
+#endif
+
+ opt_complementary = "c--efXx:e--cfXx:f--ceXx:X--cefx:x--cefX";
+ opt = getopt32(argv, "cefXx");
+
+ if (opt & DPKG_DEB_OPT_CONTENTS) {
+ tar_archive->action_header = header_verbose_list;
+ }
+ if (opt & DPKG_DEB_OPT_CONTROL) {
+ ar_archive->accept = control_tar_llist;
+ tar_archive->action_data = data_extract_all;
+ if (optind + 1 == argc) {
+ extract_dir = "./DEBIAN";
+ } else {
+ argcount++;
+ }
+ }
+ if (opt & DPKG_DEB_OPT_FIELD) {
+ /* Print the entire control file
+ * it should accept a second argument which specifies a
+ * specific field to print */
+ ar_archive->accept = control_tar_llist;
+ llist_add_to(&(tar_archive->accept), (char*)"./control");
+ tar_archive->filter = filter_accept_list;
+ tar_archive->action_data = data_extract_to_stdout;
+ }
+ if (opt & DPKG_DEB_OPT_EXTRACT) {
+ tar_archive->action_header = header_list;
+ }
+ if (opt & (DPKG_DEB_OPT_EXTRACT_VERBOSE | DPKG_DEB_OPT_EXTRACT)) {
+ tar_archive->action_data = data_extract_all;
+ argcount = 2;
+ }
+
+ if ((optind + argcount) != argc) {
+ bb_show_usage();
+ }
+
+ tar_archive->src_fd = ar_archive->src_fd = xopen(argv[optind++], O_RDONLY);
+
+ /* Workout where to extract the files */
+ /* 2nd argument is a dir name */
+ if (argv[optind]) {
+ extract_dir = argv[optind];
+ }
+ if (extract_dir) {
+ mkdir(extract_dir, 0777); /* bb_make_directory(extract_dir, 0777, 0) */
+ xchdir(extract_dir);
+ }
+ unpack_ar_archive(ar_archive);
+
+ /* Cleanup */
+ close(ar_archive->src_fd);
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/gzip.c b/cleopatre/busybox-1.11.1-spc300/archival/gzip.c
new file mode 100644
index 0000000000..dce40ec922
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/gzip.c
@@ -0,0 +1,2100 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Gzip implementation for busybox
+ *
+ * Based on GNU gzip Copyright (C) 1992-1993 Jean-loup Gailly.
+ *
+ * Originally adjusted for busybox by Charles P. Wright <cpw@unix.asb.com>
+ * "this is a stripped down version of gzip I put into busybox, it does
+ * only standard in to standard out with -9 compression. It also requires
+ * the zcat module for some important functions."
+ *
+ * Adjusted further by Erik Andersen <andersen@codepoet.org> to support
+ * files as well as stdin/stdout, and to generally behave itself wrt
+ * command line handling.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* big objects in bss:
+ * 00000020 b bl_count
+ * 00000074 b base_length
+ * 00000078 b base_dist
+ * 00000078 b static_dtree
+ * 0000009c b bl_tree
+ * 000000f4 b dyn_dtree
+ * 00000100 b length_code
+ * 00000200 b dist_code
+ * 0000023d b depth
+ * 00000400 b flag_buf
+ * 0000047a b heap
+ * 00000480 b static_ltree
+ * 000008f4 b dyn_ltree
+ */
+
+/* TODO: full support for -v for DESKTOP
+ * "/usr/bin/gzip -v a bogus aa" should say:
+a: 85.1% -- replaced with a.gz
+gzip: bogus: No such file or directory
+aa: 85.1% -- replaced with aa.gz
+*/
+
+#include "libbb.h"
+
+
+/* ===========================================================================
+ */
+//#define DEBUG 1
+/* Diagnostic functions */
+#ifdef DEBUG
+# define Assert(cond,msg) { if (!(cond)) bb_error_msg(msg); }
+# define Trace(x) fprintf x
+# define Tracev(x) {if (verbose) fprintf x; }
+# define Tracevv(x) {if (verbose > 1) fprintf x; }
+# define Tracec(c,x) {if (verbose && (c)) fprintf x; }
+# define Tracecv(c,x) {if (verbose > 1 && (c)) fprintf x; }
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+
+/* ===========================================================================
+ */
+#define SMALL_MEM
+
+#ifndef INBUFSIZ
+# ifdef SMALL_MEM
+# define INBUFSIZ 0x2000 /* input buffer size */
+# else
+# define INBUFSIZ 0x8000 /* input buffer size */
+# endif
+#endif
+
+#ifndef OUTBUFSIZ
+# ifdef SMALL_MEM
+# define OUTBUFSIZ 8192 /* output buffer size */
+# else
+# define OUTBUFSIZ 16384 /* output buffer size */
+# endif
+#endif
+
+#ifndef DIST_BUFSIZE
+# ifdef SMALL_MEM
+# define DIST_BUFSIZE 0x2000 /* buffer for distances, see trees.c */
+# else
+# define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */
+# endif
+#endif
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define RESERVED 0xC0 /* bit 6,7: reserved */
+
+/* internal file attribute */
+#define UNKNOWN 0xffff
+#define BINARY 0
+#define ASCII 1
+
+#ifndef WSIZE
+# define WSIZE 0x8000 /* window size--must be a power of two, and */
+#endif /* at least 32K for zip's deflate method */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST (WSIZE-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+#ifndef MAX_PATH_LEN
+# define MAX_PATH_LEN 1024 /* max pathname length */
+#endif
+
+#define seekable() 0 /* force sequential output */
+#define translate_eol 0 /* no option -a yet */
+
+#ifndef BITS
+# define BITS 16
+#endif
+#define INIT_BITS 9 /* Initial number of bits per code */
+
+#define BIT_MASK 0x1f /* Mask for 'number of compression bits' */
+/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free.
+ * It's a pity that old uncompress does not check bit 0x20. That makes
+ * extension of the format actually undesirable because old compress
+ * would just crash on the new format instead of giving a meaningful
+ * error message. It does check the number of bits, but it's more
+ * helpful to say "unsupported format, get a new version" than
+ * "can only handle 16 bits".
+ */
+
+#ifdef MAX_EXT_CHARS
+# define MAX_SUFFIX MAX_EXT_CHARS
+#else
+# define MAX_SUFFIX 30
+#endif
+
+
+/* ===========================================================================
+ * Compile with MEDIUM_MEM to reduce the memory requirements or
+ * with SMALL_MEM to use as little memory as possible. Use BIG_MEM if the
+ * entire input file can be held in memory (not possible on 16 bit systems).
+ * Warning: defining these symbols affects HASH_BITS (see below) and thus
+ * affects the compression ratio. The compressed output
+ * is still correct, and might even be smaller in some cases.
+ */
+
+#ifdef SMALL_MEM
+# define HASH_BITS 13 /* Number of bits used to hash strings */
+#endif
+#ifdef MEDIUM_MEM
+# define HASH_BITS 14
+#endif
+#ifndef HASH_BITS
+# define HASH_BITS 15
+ /* For portability to 16 bit machines, do not use values above 15. */
+#endif
+
+#define HASH_SIZE (unsigned)(1<<HASH_BITS)
+#define HASH_MASK (HASH_SIZE-1)
+#define WMASK (WSIZE-1)
+/* HASH_SIZE and WSIZE must be powers of two */
+#ifndef TOO_FAR
+# define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+
+/* ===========================================================================
+ * These types are not really 'char', 'short' and 'long'
+ */
+typedef uint8_t uch;
+typedef uint16_t ush;
+typedef uint32_t ulg;
+typedef int32_t lng;
+
+typedef ush Pos;
+typedef unsigned IPos;
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+enum {
+ WINDOW_SIZE = 2 * WSIZE,
+/* window size, 2*WSIZE except for MMAP or BIG_MEM, where it is the
+ * input file length plus MIN_LOOKAHEAD.
+ */
+
+ max_chain_length = 4096,
+/* To speed up deflation, hash chains are never searched beyond this length.
+ * A higher limit improves compression ratio but degrades the speed.
+ */
+
+ max_lazy_match = 258,
+/* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+
+ max_insert_length = max_lazy_match,
+/* Insert new strings in the hash table only if the match length
+ * is not greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+ good_match = 32,
+/* Use a faster search when the previous match is longer than this */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+
+ nice_match = 258, /* Stop searching when current match exceeds this */
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+};
+
+
+struct globals {
+
+ lng block_start;
+
+/* window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+ unsigned ins_h; /* hash index of string to be inserted */
+
+#define H_SHIFT ((HASH_BITS+MIN_MATCH-1) / MIN_MATCH)
+/* Number of bits by which ins_h and del_h must be shifted at each
+ * input step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ * H_SHIFT * MIN_MATCH >= HASH_BITS
+ */
+
+ unsigned prev_length;
+
+/* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+ unsigned strstart; /* start of string to insert */
+ unsigned match_start; /* start of matching string */
+ unsigned lookahead; /* number of valid bytes ahead in window */
+
+/* ===========================================================================
+ */
+#define DECLARE(type, array, size) \
+ type * array
+#define ALLOC(type, array, size) \
+ array = xzalloc((size_t)(((size)+1L)/2) * 2*sizeof(type));
+#define FREE(array) \
+ do { free(array); array = NULL; } while (0)
+
+ /* global buffers */
+
+ /* buffer for literals or lengths */
+ /* DECLARE(uch, l_buf, LIT_BUFSIZE); */
+ DECLARE(uch, l_buf, INBUFSIZ);
+
+ DECLARE(ush, d_buf, DIST_BUFSIZE);
+ DECLARE(uch, outbuf, OUTBUFSIZ);
+
+/* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least WSIZE
+ * bytes. With this organization, matches are limited to a distance of
+ * WSIZE-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: limit the window size to WSIZE+BSZ if SMALL_MEM (the code would
+ * be less efficient).
+ */
+ DECLARE(uch, window, 2L * WSIZE);
+
+/* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+ /* DECLARE(Pos, prev, WSIZE); */
+ DECLARE(ush, prev, 1L << BITS);
+
+/* Heads of the hash chains or 0. */
+ /* DECLARE(Pos, head, 1<<HASH_BITS); */
+#define head (G1.prev + WSIZE) /* hash head (see deflate.c) */
+
+/* number of input bytes */
+ ulg isize; /* only 32 bits stored in .gz file */
+
+/* bbox always use stdin/stdout */
+#define ifd STDIN_FILENO /* input file descriptor */
+#define ofd STDOUT_FILENO /* output file descriptor */
+
+#ifdef DEBUG
+ unsigned insize; /* valid bytes in l_buf */
+#endif
+ unsigned outcnt; /* bytes in output buffer */
+
+ smallint eofile; /* flag set at end of input file */
+
+/* ===========================================================================
+ * Local data used by the "bit string" routines.
+ */
+
+ unsigned short bi_buf;
+
+/* Output buffer. bits are inserted starting at the bottom (least significant
+ * bits).
+ */
+
+#undef BUF_SIZE
+#define BUF_SIZE (8 * sizeof(G1.bi_buf))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+ int bi_valid;
+
+/* Current input function. Set to mem_read for in-memory compression */
+
+#ifdef DEBUG
+ ulg bits_sent; /* bit length of the compressed data */
+#endif
+
+ uint32_t *crc_32_tab;
+ uint32_t crc; /* shift register contents */
+};
+
+#define G1 (*(ptr_to_globals - 1))
+
+
+/* ===========================================================================
+ * Write the output buffer outbuf[0..outcnt-1] and update bytes_out.
+ * (used for the compressed data only)
+ */
+static void flush_outbuf(void)
+{
+ if (G1.outcnt == 0)
+ return;
+
+ xwrite(ofd, (char *) G1.outbuf, G1.outcnt);
+ G1.outcnt = 0;
+}
+
+
+/* ===========================================================================
+ */
+/* put_8bit is used for the compressed output */
+#define put_8bit(c) \
+do { \
+ G1.outbuf[G1.outcnt++] = (c); \
+ if (G1.outcnt == OUTBUFSIZ) flush_outbuf(); \
+} while (0)
+
+/* Output a 16 bit value, lsb first */
+static void put_16bit(ush w)
+{
+ if (G1.outcnt < OUTBUFSIZ - 2) {
+ G1.outbuf[G1.outcnt++] = w;
+ G1.outbuf[G1.outcnt++] = w >> 8;
+ } else {
+ put_8bit(w);
+ put_8bit(w >> 8);
+ }
+}
+
+static void put_32bit(ulg n)
+{
+ put_16bit(n);
+ put_16bit(n >> 16);
+}
+
+/* ===========================================================================
+ * Clear input and output buffers
+ */
+static void clear_bufs(void)
+{
+ G1.outcnt = 0;
+#ifdef DEBUG
+ G1.insize = 0;
+#endif
+ G1.isize = 0;
+}
+
+
+/* ===========================================================================
+ * Run a set of bytes through the crc shift register. If s is a NULL
+ * pointer, then initialize the crc shift register contents instead.
+ * Return the current crc in either case.
+ */
+static uint32_t updcrc(uch * s, unsigned n)
+{
+ uint32_t c = G1.crc;
+ while (n) {
+ c = G1.crc_32_tab[(uch)(c ^ *s++)] ^ (c >> 8);
+ n--;
+ }
+ G1.crc = c;
+ return c;
+}
+
+
+/* ===========================================================================
+ * Read a new buffer from the current input file, perform end-of-line
+ * translation, and update the crc and input file size.
+ * IN assertion: size >= 2 (for end-of-line translation)
+ */
+static unsigned file_read(void *buf, unsigned size)
+{
+ unsigned len;
+
+ Assert(G1.insize == 0, "l_buf not empty");
+
+ len = safe_read(ifd, buf, size);
+ if (len == (unsigned)(-1) || len == 0)
+ return len;
+
+ updcrc(buf, len);
+ G1.isize += len;
+ return len;
+}
+
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+static void send_bits(int value, int length)
+{
+#ifdef DEBUG
+ Tracev((stderr, " l %2d v %4x ", length, value));
+ Assert(length > 0 && length <= 15, "invalid length");
+ G1.bits_sent += length;
+#endif
+ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+ * unused bits in value.
+ */
+ if (G1.bi_valid > (int) BUF_SIZE - length) {
+ G1.bi_buf |= (value << G1.bi_valid);
+ put_16bit(G1.bi_buf);
+ G1.bi_buf = (ush) value >> (BUF_SIZE - G1.bi_valid);
+ G1.bi_valid += length - BUF_SIZE;
+ } else {
+ G1.bi_buf |= value << G1.bi_valid;
+ G1.bi_valid += length;
+ }
+}
+
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+static unsigned bi_reverse(unsigned code, int len)
+{
+ unsigned res = 0;
+
+ while (1) {
+ res |= code & 1;
+ if (--len <= 0) return res;
+ code >>= 1;
+ res <<= 1;
+ }
+}
+
+
+/* ===========================================================================
+ * Write out any remaining bits in an incomplete byte.
+ */
+static void bi_windup(void)
+{
+ if (G1.bi_valid > 8) {
+ put_16bit(G1.bi_buf);
+ } else if (G1.bi_valid > 0) {
+ put_8bit(G1.bi_buf);
+ }
+ G1.bi_buf = 0;
+ G1.bi_valid = 0;
+#ifdef DEBUG
+ G1.bits_sent = (G1.bits_sent + 7) & ~7;
+#endif
+}
+
+
+/* ===========================================================================
+ * Copy a stored block to the zip file, storing first the length and its
+ * one's complement if requested.
+ */
+static void copy_block(char *buf, unsigned len, int header)
+{
+ bi_windup(); /* align on byte boundary */
+
+ if (header) {
+ put_16bit(len);
+ put_16bit(~len);
+#ifdef DEBUG
+ G1.bits_sent += 2 * 16;
+#endif
+ }
+#ifdef DEBUG
+ G1.bits_sent += (ulg) len << 3;
+#endif
+ while (len--) {
+ put_8bit(*buf++);
+ }
+}
+
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead, and sets eofile if end of input file.
+ * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
+ * OUT assertions: at least one byte has been read, or eofile is set;
+ * file reads are performed for at least two bytes (required for the
+ * translate_eol option).
+ */
+static void fill_window(void)
+{
+ unsigned n, m;
+ unsigned more = WINDOW_SIZE - G1.lookahead - G1.strstart;
+ /* Amount of free space at the end of the window. */
+
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ if (more == (unsigned) -1) {
+ /* Very unlikely, but possible on 16 bit machine if strstart == 0
+ * and lookahead == 1 (input done one byte at time)
+ */
+ more--;
+ } else if (G1.strstart >= WSIZE + MAX_DIST) {
+ /* By the IN assertion, the window is not empty so we can't confuse
+ * more == 0 with more == 64K on a 16 bit machine.
+ */
+ Assert(WINDOW_SIZE == 2 * WSIZE, "no sliding with BIG_MEM");
+
+ memcpy(G1.window, G1.window + WSIZE, WSIZE);
+ G1.match_start -= WSIZE;
+ G1.strstart -= WSIZE; /* we now have strstart >= MAX_DIST: */
+
+ G1.block_start -= WSIZE;
+
+ for (n = 0; n < HASH_SIZE; n++) {
+ m = head[n];
+ head[n] = (Pos) (m >= WSIZE ? m - WSIZE : 0);
+ }
+ for (n = 0; n < WSIZE; n++) {
+ m = G1.prev[n];
+ G1.prev[n] = (Pos) (m >= WSIZE ? m - WSIZE : 0);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ }
+ more += WSIZE;
+ }
+ /* At this point, more >= 2 */
+ if (!G1.eofile) {
+ n = file_read(G1.window + G1.strstart + G1.lookahead, more);
+ if (n == 0 || n == (unsigned) -1) {
+ G1.eofile = 1;
+ } else {
+ G1.lookahead += n;
+ }
+ }
+}
+
+
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ */
+
+/* For MSDOS, OS/2 and 386 Unix, an optimized version is in match.asm or
+ * match.s. The code is functionally equivalent, so you can use the C version
+ * if desired.
+ */
+static int longest_match(IPos cur_match)
+{
+ unsigned chain_length = max_chain_length; /* max hash chain length */
+ uch *scan = G1.window + G1.strstart; /* current string */
+ uch *match; /* matched string */
+ int len; /* length of current match */
+ int best_len = G1.prev_length; /* best match length so far */
+ IPos limit = G1.strstart > (IPos) MAX_DIST ? G1.strstart - (IPos) MAX_DIST : 0;
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+
+/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+#if HASH_BITS < 8 || MAX_MATCH != 258
+# error Code too clever
+#endif
+ uch *strend = G1.window + G1.strstart + MAX_MATCH;
+ uch scan_end1 = scan[best_len - 1];
+ uch scan_end = scan[best_len];
+
+ /* Do not waste too much time if we already have a good match: */
+ if (G1.prev_length >= good_match) {
+ chain_length >>= 2;
+ }
+ Assert(G1.strstart <= WINDOW_SIZE - MIN_LOOKAHEAD, "insufficient lookahead");
+
+ do {
+ Assert(cur_match < G1.strstart, "no future");
+ match = G1.window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2:
+ */
+ if (match[best_len] != scan_end ||
+ match[best_len - 1] != scan_end1 ||
+ *match != *scan || *++match != scan[1])
+ continue;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match++;
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match && scan < strend);
+
+ len = MAX_MATCH - (int) (strend - scan);
+ scan = strend - MAX_MATCH;
+
+ if (len > best_len) {
+ G1.match_start = cur_match;
+ best_len = len;
+ if (len >= nice_match)
+ break;
+ scan_end1 = scan[best_len - 1];
+ scan_end = scan[best_len];
+ }
+ } while ((cur_match = G1.prev[cur_match & WMASK]) > limit
+ && --chain_length != 0);
+
+ return best_len;
+}
+
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+static void check_match(IPos start, IPos match, int length)
+{
+ /* check that the match is indeed a match */
+ if (memcmp(G1.window + match, G1.window + start, length) != 0) {
+ bb_error_msg(" start %d, match %d, length %d", start, match, length);
+ bb_error_msg("invalid match");
+ }
+ if (verbose > 1) {
+ bb_error_msg("\\[%d,%d]", start - match, length);
+ do {
+ fputc(G1.window[start++], stderr);
+ } while (--length != 0);
+ }
+}
+#else
+# define check_match(start, match, length) ((void)0)
+#endif
+
+
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+/* PURPOSE
+ * Encode various sets of source values using variable-length
+ * binary code trees.
+ *
+ * DISCUSSION
+ * The PKZIP "deflation" process uses several Huffman trees. The more
+ * common source values are represented by shorter bit sequences.
+ *
+ * Each code tree is stored in the ZIP file in a compressed form
+ * which is itself a Huffman encoding of the lengths of
+ * all the code strings (in ascending order by source values).
+ * The actual code strings are reconstructed from the lengths in
+ * the UNZIP process, as described in the "application note"
+ * (APPNOTE.TXT) distributed as part of PKWARE's PKZIP program.
+ *
+ * REFERENCES
+ * Lynch, Thomas J.
+ * Data Compression: Techniques and Applications, pp. 53-55.
+ * Lifetime Learning Publications, 1985. ISBN 0-534-03418-7.
+ *
+ * Storer, James A.
+ * Data Compression: Methods and Theory, pp. 49-50.
+ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
+ *
+ * Sedgewick, R.
+ * Algorithms, p290.
+ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ *
+ * INTERFACE
+ * void ct_init()
+ * Allocate the match buffer, initialize the various tables [and save
+ * the location of the internal file attribute (ascii/binary) and
+ * method (DEFLATE/STORE) -- deleted in bbox]
+ *
+ * void ct_tally(int dist, int lc);
+ * Save the match info and tally the frequency counts.
+ *
+ * ulg flush_block(char *buf, ulg stored_len, int eof)
+ * Determine the best encoding for the current block: dynamic trees,
+ * static trees or store, and output the encoded block to the zip
+ * file. Returns the total compressed length for the file so far.
+ */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS 256
+/* number of literal bytes 0..255 */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES 30
+/* number of distance codes */
+
+#define BL_CODES 19
+/* number of codes used to transfer the bit lengths */
+
+/* extra bits for each length code */
+static const uint8_t extra_lbits[LENGTH_CODES] ALIGN1 = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4,
+ 4, 4, 5, 5, 5, 5, 0
+};
+
+/* extra bits for each distance code */
+static const uint8_t extra_dbits[D_CODES] ALIGN1 = {
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,
+ 10, 10, 11, 11, 12, 12, 13, 13
+};
+
+/* extra bits for each bit length code */
+static const uint8_t extra_blbits[BL_CODES] ALIGN1 = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7 };
+
+/* number of codes at each bit length for an optimal tree */
+static const uint8_t bl_order[BL_CODES] ALIGN1 = {
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#ifndef LIT_BUFSIZE
+# ifdef SMALL_MEM
+# define LIT_BUFSIZE 0x2000
+# else
+# ifdef MEDIUM_MEM
+# define LIT_BUFSIZE 0x4000
+# else
+# define LIT_BUFSIZE 0x8000
+# endif
+# endif
+#endif
+#ifndef DIST_BUFSIZE
+# define DIST_BUFSIZE LIT_BUFSIZE
+#endif
+/* Sizes of match buffers for literals/lengths and distances. There are
+ * 4 reasons for limiting LIT_BUFSIZE to 64K:
+ * - frequencies can be kept in 16 bit counters
+ * - if compression is not successful for the first block, all input data is
+ * still in the window so we can still emit a stored block even when input
+ * comes from standard input. (This can also be done for all blocks if
+ * LIT_BUFSIZE is not greater than 32K.)
+ * - if compression is not successful for a file smaller than 64K, we can
+ * even emit a stored file instead of a stored block (saving 5 bytes).
+ * - creating new Huffman trees less frequently may not provide fast
+ * adaptation to changes in the input data statistics. (Take for
+ * example a binary file with poorly compressible code followed by
+ * a highly compressible string table.) Smaller buffer sizes give
+ * fast adaptation but have of course the overhead of transmitting trees
+ * more frequently.
+ * - I can't count above 4
+ * The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save
+ * memory at the expense of compression). Some optimizations would be possible
+ * if we rely on DIST_BUFSIZE == LIT_BUFSIZE.
+ */
+#define REP_3_6 16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+#define REPZ_3_10 17
+/* repeat a zero length 3-10 times (3 bits of repeat count) */
+#define REPZ_11_138 18
+/* repeat a zero length 11-138 times (7 bits of repeat count) */
+
+/* ===========================================================================
+*/
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data {
+ union {
+ ush freq; /* frequency count */
+ ush code; /* bit string */
+ } fc;
+ union {
+ ush dad; /* father node in Huffman tree */
+ ush len; /* length of bit string */
+ } dl;
+} ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad dl.dad
+#define Len dl.len
+
+#define HEAP_SIZE (2*L_CODES + 1)
+/* maximum heap size */
+
+typedef struct tree_desc {
+ ct_data *dyn_tree; /* the dynamic tree */
+ ct_data *static_tree; /* corresponding static tree or NULL */
+ const uint8_t *extra_bits; /* extra bits for each code or NULL */
+ int extra_base; /* base index for extra_bits */
+ int elems; /* max number of elements in the tree */
+ int max_length; /* max bit length for the codes */
+ int max_code; /* largest code with non zero frequency */
+} tree_desc;
+
+struct globals2 {
+
+ ush heap[HEAP_SIZE]; /* heap used to build the Huffman trees */
+ int heap_len; /* number of elements in the heap */
+ int heap_max; /* element of largest frequency */
+
+/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+ ct_data dyn_ltree[HEAP_SIZE]; /* literal and length tree */
+ ct_data dyn_dtree[2 * D_CODES + 1]; /* distance tree */
+
+ ct_data static_ltree[L_CODES + 2];
+
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see ct_init
+ * below).
+ */
+
+ ct_data static_dtree[D_CODES];
+
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+ ct_data bl_tree[2 * BL_CODES + 1];
+
+/* Huffman tree for the bit lengths */
+
+ tree_desc l_desc;
+ tree_desc d_desc;
+ tree_desc bl_desc;
+
+ ush bl_count[MAX_BITS + 1];
+
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+ uch depth[2 * L_CODES + 1];
+
+/* Depth of each subtree used as tie breaker for trees of equal frequency */
+
+ uch length_code[MAX_MATCH - MIN_MATCH + 1];
+
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+ uch dist_code[512];
+
+/* distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+ int base_length[LENGTH_CODES];
+
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+ int base_dist[D_CODES];
+
+/* First normalized distance for each code (0 = distance of 1) */
+
+ uch flag_buf[LIT_BUFSIZE / 8];
+
+/* flag_buf is a bit array distinguishing literals from lengths in
+ * l_buf, thus indicating the presence or absence of a distance.
+ */
+
+ unsigned last_lit; /* running index in l_buf */
+ unsigned last_dist; /* running index in d_buf */
+ unsigned last_flags; /* running index in flag_buf */
+ uch flags; /* current flags not yet saved in flag_buf */
+ uch flag_bit; /* current bit used in flags */
+
+/* bits are filled in flags starting at bit 0 (least significant).
+ * Note: these flags are overkill in the current code since we don't
+ * take advantage of DIST_BUFSIZE == LIT_BUFSIZE.
+ */
+
+ ulg opt_len; /* bit length of current block with optimal trees */
+ ulg static_len; /* bit length of current block with static trees */
+
+ ulg compressed_len; /* total bit length of compressed file */
+};
+
+#define G2ptr ((struct globals2*)(ptr_to_globals))
+#define G2 (*G2ptr)
+
+
+/* ===========================================================================
+ */
+static void gen_codes(ct_data * tree, int max_code);
+static void build_tree(tree_desc * desc);
+static void scan_tree(ct_data * tree, int max_code);
+static void send_tree(ct_data * tree, int max_code);
+static int build_bl_tree(void);
+static void send_all_trees(int lcodes, int dcodes, int blcodes);
+static void compress_block(ct_data * ltree, ct_data * dtree);
+
+
+#ifndef DEBUG
+/* Send a code of the given tree. c and tree must not have side effects */
+# define SEND_CODE(c, tree) send_bits(tree[c].Code, tree[c].Len)
+#else
+# define SEND_CODE(c, tree) \
+{ \
+ if (verbose > 1) bb_error_msg("\ncd %3d ",(c)); \
+ send_bits(tree[c].Code, tree[c].Len); \
+}
+#endif
+
+#define D_CODE(dist) \
+ ((dist) < 256 ? G2.dist_code[dist] : G2.dist_code[256 + ((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. dist_code[256] and dist_code[257] are never
+ * used.
+ * The arguments must not have side effects.
+ */
+
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+static void init_block(void)
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++)
+ G2.dyn_ltree[n].Freq = 0;
+ for (n = 0; n < D_CODES; n++)
+ G2.dyn_dtree[n].Freq = 0;
+ for (n = 0; n < BL_CODES; n++)
+ G2.bl_tree[n].Freq = 0;
+
+ G2.dyn_ltree[END_BLOCK].Freq = 1;
+ G2.opt_len = G2.static_len = 0;
+ G2.last_lit = G2.last_dist = G2.last_flags = 0;
+ G2.flags = 0;
+ G2.flag_bit = 1;
+}
+
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+
+/* Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length. */
+#define SMALLER(tree, n, m) \
+ (tree[n].Freq < tree[m].Freq \
+ || (tree[n].Freq == tree[m].Freq && G2.depth[n] <= G2.depth[m]))
+
+static void pqdownheap(ct_data * tree, int k)
+{
+ int v = G2.heap[k];
+ int j = k << 1; /* left son of k */
+
+ while (j <= G2.heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if (j < G2.heap_len && SMALLER(tree, G2.heap[j + 1], G2.heap[j]))
+ j++;
+
+ /* Exit if v is smaller than both sons */
+ if (SMALLER(tree, v, G2.heap[j]))
+ break;
+
+ /* Exchange v with the smallest son */
+ G2.heap[k] = G2.heap[j];
+ k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ G2.heap[k] = v;
+}
+
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+static void gen_bitlen(tree_desc * desc)
+{
+ ct_data *tree = desc->dyn_tree;
+ const uint8_t *extra = desc->extra_bits;
+ int base = desc->extra_base;
+ int max_code = desc->max_code;
+ int max_length = desc->max_length;
+ ct_data *stree = desc->static_tree;
+ int h; /* heap index */
+ int n, m; /* iterate over the tree elements */
+ int bits; /* bit length */
+ int xbits; /* extra bits */
+ ush f; /* frequency */
+ int overflow = 0; /* number of elements with bit length too large */
+
+ for (bits = 0; bits <= MAX_BITS; bits++)
+ G2.bl_count[bits] = 0;
+
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+ tree[G2.heap[G2.heap_max]].Len = 0; /* root of the heap */
+
+ for (h = G2.heap_max + 1; h < HEAP_SIZE; h++) {
+ n = G2.heap[h];
+ bits = tree[tree[n].Dad].Len + 1;
+ if (bits > max_length) {
+ bits = max_length;
+ overflow++;
+ }
+ tree[n].Len = (ush) bits;
+ /* We overwrite tree[n].Dad which is no longer needed */
+
+ if (n > max_code)
+ continue; /* not a leaf node */
+
+ G2.bl_count[bits]++;
+ xbits = 0;
+ if (n >= base)
+ xbits = extra[n - base];
+ f = tree[n].Freq;
+ G2.opt_len += (ulg) f *(bits + xbits);
+
+ if (stree)
+ G2.static_len += (ulg) f * (stree[n].Len + xbits);
+ }
+ if (overflow == 0)
+ return;
+
+ Trace((stderr, "\nbit length overflow\n"));
+ /* This happens for example on obj2 and pic of the Calgary corpus */
+
+ /* Find the first bit length which could increase: */
+ do {
+ bits = max_length - 1;
+ while (G2.bl_count[bits] == 0)
+ bits--;
+ G2.bl_count[bits]--; /* move one leaf down the tree */
+ G2.bl_count[bits + 1] += 2; /* move one overflow item as its brother */
+ G2.bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+ overflow -= 2;
+ } while (overflow > 0);
+
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+ for (bits = max_length; bits != 0; bits--) {
+ n = G2.bl_count[bits];
+ while (n != 0) {
+ m = G2.heap[--h];
+ if (m > max_code)
+ continue;
+ if (tree[m].Len != (unsigned) bits) {
+ Trace((stderr, "code %d bits %d->%d\n", m, tree[m].Len, bits));
+ G2.opt_len += ((int32_t) bits - tree[m].Len) * tree[m].Freq;
+ tree[m].Len = bits;
+ }
+ n--;
+ }
+ }
+}
+
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+static void gen_codes(ct_data * tree, int max_code)
+{
+ ush next_code[MAX_BITS + 1]; /* next code value for each bit length */
+ ush code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (code + G2.bl_count[bits - 1]) << 1;
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert(code + G2.bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1,
+ "inconsistent bit counts");
+ Tracev((stderr, "\ngen_codes: max_code %d ", max_code));
+
+ for (n = 0; n <= max_code; n++) {
+ int len = tree[n].Len;
+
+ if (len == 0)
+ continue;
+ /* Now reverse the bits */
+ tree[n].Code = bi_reverse(next_code[len]++, len);
+
+ Tracec(tree != G2.static_ltree,
+ (stderr, "\nn %3d %c l %2d c %4x (%x) ", n,
+ (isgraph(n) ? n : ' '), len, tree[n].Code,
+ next_code[len] - 1));
+ }
+}
+
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ * and corresponding code. The length opt_len is updated; static_len is
+ * also updated if stree is not null. The field max_code is set.
+ */
+
+/* Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len. */
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+#define PQREMOVE(tree, top) \
+do { \
+ top = G2.heap[SMALLEST]; \
+ G2.heap[SMALLEST] = G2.heap[G2.heap_len--]; \
+ pqdownheap(tree, SMALLEST); \
+} while (0)
+
+static void build_tree(tree_desc * desc)
+{
+ ct_data *tree = desc->dyn_tree;
+ ct_data *stree = desc->static_tree;
+ int elems = desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node = elems; /* next internal node of the tree */
+
+ /* Construct the initial heap, with least frequent element in
+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ * heap[0] is not used.
+ */
+ G2.heap_len = 0;
+ G2.heap_max = HEAP_SIZE;
+
+ for (n = 0; n < elems; n++) {
+ if (tree[n].Freq != 0) {
+ G2.heap[++G2.heap_len] = max_code = n;
+ G2.depth[n] = 0;
+ } else {
+ tree[n].Len = 0;
+ }
+ }
+
+ /* The pkzip format requires that at least one distance code exists,
+ * and that at least one bit should be sent even if there is only one
+ * possible code. So to avoid special checks later on we force at least
+ * two codes of non zero frequency.
+ */
+ while (G2.heap_len < 2) {
+ int new = G2.heap[++G2.heap_len] = (max_code < 2 ? ++max_code : 0);
+
+ tree[new].Freq = 1;
+ G2.depth[new] = 0;
+ G2.opt_len--;
+ if (stree)
+ G2.static_len -= stree[new].Len;
+ /* new is 0 or 1 so it does not have extra bits */
+ }
+ desc->max_code = max_code;
+
+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ * establish sub-heaps of increasing lengths:
+ */
+ for (n = G2.heap_len / 2; n >= 1; n--)
+ pqdownheap(tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ do {
+ PQREMOVE(tree, n); /* n = node of least frequency */
+ m = G2.heap[SMALLEST]; /* m = node of next least frequency */
+
+ G2.heap[--G2.heap_max] = n; /* keep the nodes sorted by frequency */
+ G2.heap[--G2.heap_max] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].Freq = tree[n].Freq + tree[m].Freq;
+ G2.depth[node] = MAX(G2.depth[n], G2.depth[m]) + 1;
+ tree[n].Dad = tree[m].Dad = (ush) node;
+#ifdef DUMP_BL_TREE
+ if (tree == G2.bl_tree) {
+ bb_error_msg("\nnode %d(%d), sons %d(%d) %d(%d)",
+ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+ }
+#endif
+ /* and insert the new node in the heap */
+ G2.heap[SMALLEST] = node++;
+ pqdownheap(tree, SMALLEST);
+
+ } while (G2.heap_len >= 2);
+
+ G2.heap[--G2.heap_max] = G2.heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen((tree_desc *) desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes((ct_data *) tree, max_code);
+}
+
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree. Updates opt_len to take into account the repeat
+ * counts. (The contribution of the bit length codes will be added later
+ * during the construction of bl_tree.)
+ */
+static void scan_tree(ct_data * tree, int max_code)
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ if (nextlen == 0) {
+ max_count = 138;
+ min_count = 3;
+ }
+ tree[max_code + 1].Len = 0xffff; /* guard */
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen;
+ nextlen = tree[n + 1].Len;
+ if (++count < max_count && curlen == nextlen)
+ continue;
+
+ if (count < min_count) {
+ G2.bl_tree[curlen].Freq += count;
+ } else if (curlen != 0) {
+ if (curlen != prevlen)
+ G2.bl_tree[curlen].Freq++;
+ G2.bl_tree[REP_3_6].Freq++;
+ } else if (count <= 10) {
+ G2.bl_tree[REPZ_3_10].Freq++;
+ } else {
+ G2.bl_tree[REPZ_11_138].Freq++;
+ }
+ count = 0;
+ prevlen = curlen;
+
+ max_count = 7;
+ min_count = 4;
+ if (nextlen == 0) {
+ max_count = 138;
+ min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6;
+ min_count = 3;
+ }
+ }
+}
+
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+static void send_tree(ct_data * tree, int max_code)
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+/* tree[max_code+1].Len = -1; *//* guard already set */
+ if (nextlen == 0)
+ max_count = 138, min_count = 3;
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen;
+ nextlen = tree[n + 1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ do {
+ SEND_CODE(curlen, G2.bl_tree);
+ } while (--count);
+ } else if (curlen != 0) {
+ if (curlen != prevlen) {
+ SEND_CODE(curlen, G2.bl_tree);
+ count--;
+ }
+ Assert(count >= 3 && count <= 6, " 3_6?");
+ SEND_CODE(REP_3_6, G2.bl_tree);
+ send_bits(count - 3, 2);
+ } else if (count <= 10) {
+ SEND_CODE(REPZ_3_10, G2.bl_tree);
+ send_bits(count - 3, 3);
+ } else {
+ SEND_CODE(REPZ_11_138, G2.bl_tree);
+ send_bits(count - 11, 7);
+ }
+ count = 0;
+ prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138;
+ min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6;
+ min_count = 3;
+ } else {
+ max_count = 7;
+ min_count = 4;
+ }
+ }
+}
+
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+static int build_bl_tree(void)
+{
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ /* Determine the bit length frequencies for literal and distance trees */
+ scan_tree(G2.dyn_ltree, G2.l_desc.max_code);
+ scan_tree(G2.dyn_dtree, G2.d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree(&G2.bl_desc);
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+ for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) {
+ if (G2.bl_tree[bl_order[max_blindex]].Len != 0)
+ break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ G2.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", G2.opt_len, G2.static_len));
+
+ return max_blindex;
+}
+
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+static void send_all_trees(int lcodes, int dcodes, int blcodes)
+{
+ int rank; /* index in bl_order */
+
+ Assert(lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ Assert(lcodes <= L_CODES && dcodes <= D_CODES
+ && blcodes <= BL_CODES, "too many codes");
+ Tracev((stderr, "\nbl counts: "));
+ send_bits(lcodes - 257, 5); /* not +255 as stated in appnote.txt */
+ send_bits(dcodes - 1, 5);
+ send_bits(blcodes - 4, 4); /* not -3 as stated in appnote.txt */
+ for (rank = 0; rank < blcodes; rank++) {
+ Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+ send_bits(G2.bl_tree[bl_order[rank]].Len, 3);
+ }
+ Tracev((stderr, "\nbl tree: sent %ld", G1.bits_sent));
+
+ send_tree((ct_data *) G2.dyn_ltree, lcodes - 1); /* send the literal tree */
+ Tracev((stderr, "\nlit tree: sent %ld", G1.bits_sent));
+
+ send_tree((ct_data *) G2.dyn_dtree, dcodes - 1); /* send the distance tree */
+ Tracev((stderr, "\ndist tree: sent %ld", G1.bits_sent));
+}
+
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+static int ct_tally(int dist, int lc)
+{
+ G1.l_buf[G2.last_lit++] = lc;
+ if (dist == 0) {
+ /* lc is the unmatched char */
+ G2.dyn_ltree[lc].Freq++;
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert((ush) dist < (ush) MAX_DIST
+ && (ush) lc <= (ush) (MAX_MATCH - MIN_MATCH)
+ && (ush) D_CODE(dist) < (ush) D_CODES, "ct_tally: bad match"
+ );
+
+ G2.dyn_ltree[G2.length_code[lc] + LITERALS + 1].Freq++;
+ G2.dyn_dtree[D_CODE(dist)].Freq++;
+
+ G1.d_buf[G2.last_dist++] = dist;
+ G2.flags |= G2.flag_bit;
+ }
+ G2.flag_bit <<= 1;
+
+ /* Output the flags if they fill a byte: */
+ if ((G2.last_lit & 7) == 0) {
+ G2.flag_buf[G2.last_flags++] = G2.flags;
+ G2.flags = 0;
+ G2.flag_bit = 1;
+ }
+ /* Try to guess if it is profitable to stop the current block here */
+ if ((G2.last_lit & 0xfff) == 0) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = G2.last_lit * 8L;
+ ulg in_length = (ulg) G1.strstart - G1.block_start;
+ int dcode;
+
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += G2.dyn_dtree[dcode].Freq * (5L + extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Trace((stderr,
+ "\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ",
+ G2.last_lit, G2.last_dist, in_length, out_length,
+ 100L - out_length * 100L / in_length));
+ if (G2.last_dist < G2.last_lit / 2 && out_length < in_length / 2)
+ return 1;
+ }
+ return (G2.last_lit == LIT_BUFSIZE - 1 || G2.last_dist == DIST_BUFSIZE);
+ /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+static void compress_block(ct_data * ltree, ct_data * dtree)
+{
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned lx = 0; /* running index in l_buf */
+ unsigned dx = 0; /* running index in d_buf */
+ unsigned fx = 0; /* running index in flag_buf */
+ uch flag = 0; /* current flags */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (G2.last_lit != 0) do {
+ if ((lx & 7) == 0)
+ flag = G2.flag_buf[fx++];
+ lc = G1.l_buf[lx++];
+ if ((flag & 1) == 0) {
+ SEND_CODE(lc, ltree); /* send a literal byte */
+ Tracecv(isgraph(lc), (stderr, " '%c' ", lc));
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = G2.length_code[lc];
+ SEND_CODE(code + LITERALS + 1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= G2.base_length[code];
+ send_bits(lc, extra); /* send the extra length bits */
+ }
+ dist = G1.d_buf[dx++];
+ /* Here, dist is the match distance - 1 */
+ code = D_CODE(dist);
+ Assert(code < D_CODES, "bad d_code");
+
+ SEND_CODE(code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= G2.base_dist[code];
+ send_bits(dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+ flag >>= 1;
+ } while (lx < G2.last_lit);
+
+ SEND_CODE(END_BLOCK, ltree);
+}
+
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file. This function
+ * returns the total compressed length for the file so far.
+ */
+static ulg flush_block(char *buf, ulg stored_len, int eof)
+{
+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ G2.flag_buf[G2.last_flags] = G2.flags; /* Save the flags for the last 8 items */
+
+ /* Construct the literal and distance trees */
+ build_tree(&G2.l_desc);
+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld", G2.opt_len, G2.static_len));
+
+ build_tree(&G2.d_desc);
+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld", G2.opt_len, G2.static_len));
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+ max_blindex = build_bl_tree();
+
+ /* Determine the best encoding. Compute first the block length in bytes */
+ opt_lenb = (G2.opt_len + 3 + 7) >> 3;
+ static_lenb = (G2.static_len + 3 + 7) >> 3;
+
+ Trace((stderr,
+ "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ",
+ opt_lenb, G2.opt_len, static_lenb, G2.static_len, stored_len,
+ G2.last_lit, G2.last_dist));
+
+ if (static_lenb <= opt_lenb)
+ opt_lenb = static_lenb;
+
+ /* If compression failed and this is the first and last block,
+ * and if the zip file can be seeked (to rewrite the local header),
+ * the whole file is transformed into a stored file:
+ */
+ if (stored_len <= opt_lenb && eof && G2.compressed_len == 0L && seekable()) {
+ /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
+ if (buf == NULL)
+ bb_error_msg("block vanished");
+
+ copy_block(buf, (unsigned) stored_len, 0); /* without header */
+ G2.compressed_len = stored_len << 3;
+
+ } else if (stored_len + 4 <= opt_lenb && buf != NULL) {
+ /* 4: two words for the lengths */
+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+ send_bits((STORED_BLOCK << 1) + eof, 3); /* send block type */
+ G2.compressed_len = (G2.compressed_len + 3 + 7) & ~7L;
+ G2.compressed_len += (stored_len + 4) << 3;
+
+ copy_block(buf, (unsigned) stored_len, 1); /* with header */
+
+ } else if (static_lenb == opt_lenb) {
+ send_bits((STATIC_TREES << 1) + eof, 3);
+ compress_block((ct_data *) G2.static_ltree, (ct_data *) G2.static_dtree);
+ G2.compressed_len += 3 + G2.static_len;
+ } else {
+ send_bits((DYN_TREES << 1) + eof, 3);
+ send_all_trees(G2.l_desc.max_code + 1, G2.d_desc.max_code + 1,
+ max_blindex + 1);
+ compress_block((ct_data *) G2.dyn_ltree, (ct_data *) G2.dyn_dtree);
+ G2.compressed_len += 3 + G2.opt_len;
+ }
+ Assert(G2.compressed_len == G1.bits_sent, "bad compressed size");
+ init_block();
+
+ if (eof) {
+ bi_windup();
+ G2.compressed_len += 7; /* align on byte boundary */
+ }
+ Tracev((stderr, "\ncomprlen %lu(%lu) ", G2.compressed_len >> 3,
+ G2.compressed_len - 7 * eof));
+
+ return G2.compressed_len >> 3;
+}
+
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ * input characters, so that a running hash key can be computed from the
+ * previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(h, c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK)
+
+
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ *
+ * Processes a new input file and return its compressed length. Sets
+ * the compressed length, crc, deflate flags and internal file
+ * attributes.
+ */
+
+/* Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match. */
+#define FLUSH_BLOCK(eof) \
+ flush_block( \
+ G1.block_start >= 0L \
+ ? (char*)&G1.window[(unsigned)G1.block_start] \
+ : (char*)NULL, \
+ (ulg)G1.strstart - G1.block_start, \
+ (eof) \
+ )
+
+/* Insert string s in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * input characters and the first MIN_MATCH bytes of s are valid
+ * (except for the last MIN_MATCH-1 bytes of the input file). */
+#define INSERT_STRING(s, match_head) \
+do { \
+ UPDATE_HASH(G1.ins_h, G1.window[(s) + MIN_MATCH-1]); \
+ G1.prev[(s) & WMASK] = match_head = head[G1.ins_h]; \
+ head[G1.ins_h] = (s); \
+} while (0)
+
+static ulg deflate(void)
+{
+ IPos hash_head; /* head of hash chain */
+ IPos prev_match; /* previous match */
+ int flush; /* set if current block must be flushed */
+ int match_available = 0; /* set if previous match exists */
+ unsigned match_length = MIN_MATCH - 1; /* length of best match */
+
+ /* Process the input block. */
+ while (G1.lookahead != 0) {
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ INSERT_STRING(G1.strstart, hash_head);
+
+ /* Find the longest match, discarding those <= prev_length.
+ */
+ G1.prev_length = match_length;
+ prev_match = G1.match_start;
+ match_length = MIN_MATCH - 1;
+
+ if (hash_head != 0 && G1.prev_length < max_lazy_match
+ && G1.strstart - hash_head <= MAX_DIST
+ ) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ match_length = longest_match(hash_head);
+ /* longest_match() sets match_start */
+ if (match_length > G1.lookahead)
+ match_length = G1.lookahead;
+
+ /* Ignore a length 3 match if it is too distant: */
+ if (match_length == MIN_MATCH && G1.strstart - G1.match_start > TOO_FAR) {
+ /* If prev_match is also MIN_MATCH, G1.match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ match_length--;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+ if (G1.prev_length >= MIN_MATCH && match_length <= G1.prev_length) {
+ check_match(G1.strstart - 1, prev_match, G1.prev_length);
+ flush = ct_tally(G1.strstart - 1 - prev_match, G1.prev_length - MIN_MATCH);
+
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted.
+ */
+ G1.lookahead -= G1.prev_length - 1;
+ G1.prev_length -= 2;
+ do {
+ G1.strstart++;
+ INSERT_STRING(G1.strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
+ * these bytes are garbage, but it does not matter since the
+ * next lookahead bytes will always be emitted as literals.
+ */
+ } while (--G1.prev_length != 0);
+ match_available = 0;
+ match_length = MIN_MATCH - 1;
+ G1.strstart++;
+ if (flush) {
+ FLUSH_BLOCK(0);
+ G1.block_start = G1.strstart;
+ }
+ } else if (match_available) {
+ /* If there was no match at the previous position, output a
+ * single literal. If there was a match but the current match
+ * is longer, truncate the previous match to a single literal.
+ */
+ Tracevv((stderr, "%c", G1.window[G1.strstart - 1]));
+ if (ct_tally(0, G1.window[G1.strstart - 1])) {
+ FLUSH_BLOCK(0);
+ G1.block_start = G1.strstart;
+ }
+ G1.strstart++;
+ G1.lookahead--;
+ } else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ match_available = 1;
+ G1.strstart++;
+ G1.lookahead--;
+ }
+ Assert(G1.strstart <= G1.isize && lookahead <= G1.isize, "a bit too far");
+
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ while (G1.lookahead < MIN_LOOKAHEAD && !G1.eofile)
+ fill_window();
+ }
+ if (match_available)
+ ct_tally(0, G1.window[G1.strstart - 1]);
+
+ return FLUSH_BLOCK(1); /* eof */
+}
+
+
+/* ===========================================================================
+ * Initialize the bit string routines.
+ */
+static void bi_init(void)
+{
+ G1.bi_buf = 0;
+ G1.bi_valid = 0;
+#ifdef DEBUG
+ G1.bits_sent = 0L;
+#endif
+}
+
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new file
+ */
+static void lm_init(ush * flagsp)
+{
+ unsigned j;
+
+ /* Initialize the hash table. */
+ memset(head, 0, HASH_SIZE * sizeof(*head));
+ /* prev will be initialized on the fly */
+
+ /* speed options for the general purpose bit flag */
+ *flagsp |= 2; /* FAST 4, SLOW 2 */
+ /* ??? reduce max_chain_length for binary files */
+
+ G1.strstart = 0;
+ G1.block_start = 0L;
+
+ G1.lookahead = file_read(G1.window,
+ sizeof(int) <= 2 ? (unsigned) WSIZE : 2 * WSIZE);
+
+ if (G1.lookahead == 0 || G1.lookahead == (unsigned) -1) {
+ G1.eofile = 1;
+ G1.lookahead = 0;
+ return;
+ }
+ G1.eofile = 0;
+ /* Make sure that we always have enough lookahead. This is important
+ * if input comes from a device such as a tty.
+ */
+ while (G1.lookahead < MIN_LOOKAHEAD && !G1.eofile)
+ fill_window();
+
+ G1.ins_h = 0;
+ for (j = 0; j < MIN_MATCH - 1; j++)
+ UPDATE_HASH(G1.ins_h, G1.window[j]);
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but this is
+ * not important since only literal bytes will be emitted.
+ */
+}
+
+
+/* ===========================================================================
+ * Allocate the match buffer, initialize the various tables and save the
+ * location of the internal file attribute (ascii/binary) and method
+ * (DEFLATE/STORE).
+ * One callsite in zip()
+ */
+static void ct_init(void)
+{
+ int n; /* iterates over tree elements */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+
+ G2.compressed_len = 0L;
+
+#ifdef NOT_NEEDED
+ if (G2.static_dtree[0].Len != 0)
+ return; /* ct_init already called */
+#endif
+
+ /* Initialize the mapping length (0..255) -> length code (0..28) */
+ length = 0;
+ for (code = 0; code < LENGTH_CODES - 1; code++) {
+ G2.base_length[code] = length;
+ for (n = 0; n < (1 << extra_lbits[code]); n++) {
+ G2.length_code[length++] = code;
+ }
+ }
+ Assert(length == 256, "ct_init: length != 256");
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+ G2.length_code[length - 1] = code;
+
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+ dist = 0;
+ for (code = 0; code < 16; code++) {
+ G2.base_dist[code] = dist;
+ for (n = 0; n < (1 << extra_dbits[code]); n++) {
+ G2.dist_code[dist++] = code;
+ }
+ }
+ Assert(dist == 256, "ct_init: dist != 256");
+ dist >>= 7; /* from now on, all distances are divided by 128 */
+ for (; code < D_CODES; code++) {
+ G2.base_dist[code] = dist << 7;
+ for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) {
+ G2.dist_code[256 + dist++] = code;
+ }
+ }
+ Assert(dist == 256, "ct_init: 256+dist != 512");
+
+ /* Construct the codes of the static literal tree */
+ /* already zeroed - it's in bss
+ for (n = 0; n <= MAX_BITS; n++)
+ G2.bl_count[n] = 0; */
+
+ n = 0;
+ while (n <= 143) {
+ G2.static_ltree[n++].Len = 8;
+ G2.bl_count[8]++;
+ }
+ while (n <= 255) {
+ G2.static_ltree[n++].Len = 9;
+ G2.bl_count[9]++;
+ }
+ while (n <= 279) {
+ G2.static_ltree[n++].Len = 7;
+ G2.bl_count[7]++;
+ }
+ while (n <= 287) {
+ G2.static_ltree[n++].Len = 8;
+ G2.bl_count[8]++;
+ }
+ /* Codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+ gen_codes((ct_data *) G2.static_ltree, L_CODES + 1);
+
+ /* The static distance tree is trivial: */
+ for (n = 0; n < D_CODES; n++) {
+ G2.static_dtree[n].Len = 5;
+ G2.static_dtree[n].Code = bi_reverse(n, 5);
+ }
+
+ /* Initialize the first block of the first file: */
+ init_block();
+}
+
+
+/* ===========================================================================
+ * Deflate in to out.
+ * IN assertions: the input and output buffers are cleared.
+ */
+
+static void zip(ulg time_stamp)
+{
+ ush deflate_flags = 0; /* pkzip -es, -en or -ex equivalent */
+
+ G1.outcnt = 0;
+
+ /* Write the header to the gzip file. See algorithm.doc for the format */
+ /* magic header for gzip files: 1F 8B */
+ /* compression method: 8 (DEFLATED) */
+ /* general flags: 0 */
+ put_32bit(0x00088b1f);
+ put_32bit(time_stamp);
+
+ /* Write deflated file to zip file */
+ G1.crc = ~0;
+
+ bi_init();
+ ct_init();
+ lm_init(&deflate_flags);
+
+ put_8bit(deflate_flags); /* extra flags */
+ put_8bit(3); /* OS identifier = 3 (Unix) */
+
+ deflate();
+
+ /* Write the crc and uncompressed size */
+ put_32bit(~G1.crc);
+ put_32bit(G1.isize);
+
+ flush_outbuf();
+}
+
+
+/* ======================================================================== */
+static
+char* make_new_name_gzip(char *filename)
+{
+ return xasprintf("%s.gz", filename);
+}
+
+static
+USE_DESKTOP(long long) int pack_gzip(void)
+{
+ struct stat s;
+
+ clear_bufs();
+ s.st_ctime = 0;
+ fstat(STDIN_FILENO, &s);
+ zip(s.st_ctime);
+ return 0;
+}
+
+/*
+ * Linux kernel build uses gzip -d -n. We accept and ignore it.
+ * Man page says:
+ * -n --no-name
+ * gzip: do not save the original file name and time stamp.
+ * (The original name is always saved if the name had to be truncated.)
+ * gunzip: do not restore the original file name/time even if present
+ * (remove only the gzip suffix from the compressed file name).
+ * This option is the default when decompressing.
+ * -N --name
+ * gzip: always save the original file name and time stamp (this is the default)
+ * gunzip: restore the original file name and time stamp if present.
+ */
+
+int gzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+#if ENABLE_GUNZIP
+int gzip_main(int argc, char **argv)
+#else
+int gzip_main(int argc ATTRIBUTE_UNUSED, char **argv)
+#endif
+{
+ unsigned opt;
+
+ /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */
+ opt = getopt32(argv, "cfv" USE_GUNZIP("d") "q123456789n" );
+#if ENABLE_GUNZIP /* gunzip_main may not be visible... */
+ if (opt & 0x8) // -d
+ return gunzip_main(argc, argv);
+#endif
+ option_mask32 &= 0x7; /* ignore -q, -0..9 */
+ //if (opt & 0x1) // -c
+ //if (opt & 0x2) // -f
+ //if (opt & 0x4) // -v
+ argv += optind;
+
+ SET_PTR_TO_GLOBALS(xzalloc(sizeof(struct globals) + sizeof(struct globals2))
+ + sizeof(struct globals));
+ G2.l_desc.dyn_tree = G2.dyn_ltree;
+ G2.l_desc.static_tree = G2.static_ltree;
+ G2.l_desc.extra_bits = extra_lbits;
+ G2.l_desc.extra_base = LITERALS + 1;
+ G2.l_desc.elems = L_CODES;
+ G2.l_desc.max_length = MAX_BITS;
+ //G2.l_desc.max_code = 0;
+
+ G2.d_desc.dyn_tree = G2.dyn_dtree;
+ G2.d_desc.static_tree = G2.static_dtree;
+ G2.d_desc.extra_bits = extra_dbits;
+ //G2.d_desc.extra_base = 0;
+ G2.d_desc.elems = D_CODES;
+ G2.d_desc.max_length = MAX_BITS;
+ //G2.d_desc.max_code = 0;
+
+ G2.bl_desc.dyn_tree = G2.bl_tree;
+ //G2.bl_desc.static_tree = NULL;
+ G2.bl_desc.extra_bits = extra_blbits,
+ //G2.bl_desc.extra_base = 0;
+ G2.bl_desc.elems = BL_CODES;
+ G2.bl_desc.max_length = MAX_BL_BITS;
+ //G2.bl_desc.max_code = 0;
+
+ /* Allocate all global buffers (for DYN_ALLOC option) */
+ ALLOC(uch, G1.l_buf, INBUFSIZ);
+ ALLOC(uch, G1.outbuf, OUTBUFSIZ);
+ ALLOC(ush, G1.d_buf, DIST_BUFSIZE);
+ ALLOC(uch, G1.window, 2L * WSIZE);
+ ALLOC(ush, G1.prev, 1L << BITS);
+
+ /* Initialise the CRC32 table */
+ G1.crc_32_tab = crc32_filltable(NULL, 0);
+
+ return bbunpack(argv, make_new_name_gzip, pack_gzip);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/Kbuild b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/Kbuild
new file mode 100644
index 0000000000..1bc054a962
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/Kbuild
@@ -0,0 +1,67 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+
+lib-y:= \
+\
+ data_skip.o \
+ data_extract_all.o \
+ data_extract_to_stdout.o \
+ data_extract_to_buffer.o \
+\
+ filter_accept_all.o \
+ filter_accept_list.o \
+ filter_accept_reject_list.o \
+\
+ header_skip.o \
+ header_list.o \
+ header_verbose_list.o \
+\
+ archive_xread_all_eof.o \
+\
+ seek_by_read.o \
+ seek_by_jump.o \
+\
+ data_align.o \
+ find_list_entry.o \
+ init_handle.o
+
+DPKG_FILES:= \
+ get_header_ar.o \
+ unpack_ar_archive.o \
+ get_header_tar.o \
+ filter_accept_list_reassign.o
+
+lib-$(CONFIG_RPM) += open_transformer.o
+lib-$(CONFIG_FEATURE_TAR_BZIP2) += open_transformer.o
+lib-$(CONFIG_FEATURE_TAR_LZMA) += open_transformer.o
+lib-$(CONFIG_FEATURE_TAR_GZIP) += open_transformer.o
+lib-$(CONFIG_FEATURE_TAR_COMPRESS) += open_transformer.o
+lib-$(CONFIG_FEATURE_DEB_TAR_GZ) += open_transformer.o
+lib-$(CONFIG_FEATURE_DEB_TAR_BZ2) += open_transformer.o
+lib-$(CONFIG_FEATURE_DEB_TAR_LZMA) += open_transformer.o
+
+lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o
+lib-$(CONFIG_BUNZIP2) += decompress_bunzip2.o
+lib-$(CONFIG_UNLZMA) += decompress_unlzma.o
+lib-$(CONFIG_CPIO) += get_header_cpio.o
+lib-$(CONFIG_DPKG) += $(DPKG_FILES)
+lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES)
+lib-$(CONFIG_FEATURE_DEB_TAR_GZ) += decompress_unzip.o get_header_tar_gz.o
+lib-$(CONFIG_FEATURE_DEB_TAR_BZ2) += decompress_bunzip2.o get_header_tar_bz2.o
+lib-$(CONFIG_FEATURE_DEB_TAR_LZMA) += decompress_unlzma.o get_header_tar_lzma.o
+lib-$(CONFIG_GUNZIP) += decompress_unzip.o
+lib-$(CONFIG_FEATURE_GUNZIP_UNCOMPRESS) += decompress_uncompress.o
+lib-$(CONFIG_RPM2CPIO) += decompress_unzip.o get_header_cpio.o
+lib-$(CONFIG_RPM) += decompress_unzip.o get_header_cpio.o
+lib-$(CONFIG_FEATURE_RPM_BZ2) += decompress_bunzip2.o
+lib-$(CONFIG_TAR) += get_header_tar.o
+lib-$(CONFIG_FEATURE_TAR_BZIP2) += decompress_bunzip2.o get_header_tar_bz2.o
+lib-$(CONFIG_FEATURE_TAR_LZMA) += decompress_unlzma.o get_header_tar_lzma.o
+lib-$(CONFIG_FEATURE_TAR_GZIP) += decompress_unzip.o get_header_tar_gz.o
+lib-$(CONFIG_FEATURE_TAR_COMPRESS) += decompress_uncompress.o
+lib-$(CONFIG_UNCOMPRESS) += decompress_uncompress.o
+lib-$(CONFIG_UNZIP) += decompress_unzip.o
+lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += decompress_bunzip2.o
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/archive_xread_all_eof.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/archive_xread_all_eof.c
new file mode 100644
index 0000000000..c93dfa282c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/archive_xread_all_eof.c
@@ -0,0 +1,20 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+ssize_t archive_xread_all_eof(archive_handle_t *archive_handle,
+ unsigned char *buf, size_t count)
+{
+ ssize_t size;
+
+ size = full_read(archive_handle->src_fd, buf, count);
+ if (size != 0 && size != (ssize_t)count) {
+ bb_error_msg_and_die("short read: %u of %u",
+ (unsigned)size, (unsigned)count);
+ }
+ return size;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/data_align.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/data_align.c
new file mode 100644
index 0000000000..d98dc57641
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/data_align.c
@@ -0,0 +1,15 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+void data_align(archive_handle_t *archive_handle, unsigned boundary)
+{
+ unsigned skip_amount = (boundary - (archive_handle->offset % boundary)) % boundary;
+
+ archive_handle->seek(archive_handle, skip_amount);
+ archive_handle->offset += skip_amount;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/data_extract_all.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/data_extract_all.c
new file mode 100644
index 0000000000..29a224bbce
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/data_extract_all.c
@@ -0,0 +1,146 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+void data_extract_all(archive_handle_t *archive_handle)
+{
+ file_header_t *file_header = archive_handle->file_header;
+ int dst_fd;
+ int res;
+
+ if (archive_handle->flags & ARCHIVE_CREATE_LEADING_DIRS) {
+ char *name = xstrdup(file_header->name);
+ bb_make_directory(dirname(name), -1, FILEUTILS_RECUR);
+ free(name);
+ }
+
+ /* Check if the file already exists */
+ if (archive_handle->flags & ARCHIVE_EXTRACT_UNCONDITIONAL) {
+ /* Remove the entry if it exists */
+ if (((file_header->mode & S_IFMT) != S_IFDIR)
+ && (unlink(file_header->name) == -1)
+ && (errno != ENOENT)
+ ) {
+ bb_perror_msg_and_die("cannot remove old file %s",
+ file_header->name);
+ }
+ }
+ else if (archive_handle->flags & ARCHIVE_EXTRACT_NEWER) {
+ /* Remove the existing entry if its older than the extracted entry */
+ struct stat statbuf;
+ if (lstat(file_header->name, &statbuf) == -1) {
+ if (errno != ENOENT) {
+ bb_perror_msg_and_die("cannot stat old file");
+ }
+ }
+ else if (statbuf.st_mtime <= file_header->mtime) {
+ if (!(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
+ bb_error_msg("%s not created: newer or "
+ "same age file exists", file_header->name);
+ }
+ data_skip(archive_handle);
+ return;
+ }
+ else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) {
+ bb_perror_msg_and_die("cannot remove old file %s",
+ file_header->name);
+ }
+ }
+
+ /* Handle hard links separately
+ * We identified hard links as regular files of size 0 with a symlink */
+ if (S_ISREG(file_header->mode) && (file_header->link_target)
+ && (file_header->size == 0)
+ ) {
+ /* hard link */
+ res = link(file_header->link_target, file_header->name);
+ if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
+ bb_perror_msg("cannot create %slink "
+ "from %s to %s", "hard",
+ file_header->name,
+ file_header->link_target);
+ }
+ } else {
+ /* Create the filesystem entry */
+ switch (file_header->mode & S_IFMT) {
+ case S_IFREG: {
+ /* Regular file */
+ dst_fd = xopen3(file_header->name, O_WRONLY | O_CREAT | O_EXCL,
+ file_header->mode);
+ bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size);
+ close(dst_fd);
+ break;
+ }
+ case S_IFDIR:
+ res = mkdir(file_header->name, file_header->mode);
+ if ((res == -1) && (errno != EISDIR)
+ && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)
+ ) {
+ bb_perror_msg("cannot make dir %s", file_header->name);
+ }
+ break;
+ case S_IFLNK:
+ /* Symlink */
+ res = symlink(file_header->link_target, file_header->name);
+ if ((res == -1)
+ && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)
+ ) {
+ bb_perror_msg("cannot create %slink "
+ "from %s to %s", "sym",
+ file_header->name,
+ file_header->link_target);
+ }
+ break;
+ case S_IFSOCK:
+ case S_IFBLK:
+ case S_IFCHR:
+ case S_IFIFO:
+ res = mknod(file_header->name, file_header->mode, file_header->device);
+ if ((res == -1)
+ && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)
+ ) {
+ bb_perror_msg("cannot create node %s", file_header->name);
+ }
+ break;
+ default:
+ bb_error_msg_and_die("unrecognized file type");
+ }
+ }
+
+ if (!(archive_handle->flags & ARCHIVE_NOPRESERVE_OWN)) {
+#if ENABLE_FEATURE_TAR_UNAME_GNAME
+ uid_t uid = file_header->uid;
+ gid_t gid = file_header->gid;
+
+ if (file_header->uname) {
+ struct passwd *pwd = getpwnam(file_header->uname);
+ if (pwd) uid = pwd->pw_uid;
+ }
+ if (file_header->gname) {
+ struct group *grp = getgrnam(file_header->gname);
+ if (grp) gid = grp->gr_gid;
+ }
+ lchown(file_header->name, uid, gid);
+#else
+ lchown(file_header->name, file_header->uid, file_header->gid);
+#endif
+ }
+ if ((file_header->mode & S_IFMT) != S_IFLNK) {
+ /* uclibc has no lchmod, glibc is even stranger -
+ * it has lchmod which seems to do nothing!
+ * so we use chmod... */
+ if (!(archive_handle->flags & ARCHIVE_NOPRESERVE_PERM)) {
+ chmod(file_header->name, file_header->mode);
+ }
+ /* same for utime */
+ if (archive_handle->flags & ARCHIVE_PRESERVE_DATE) {
+ struct utimbuf t;
+ t.actime = t.modtime = file_header->mtime;
+ utime(file_header->name, &t);
+ }
+ }
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/data_extract_to_buffer.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/data_extract_to_buffer.c
new file mode 100644
index 0000000000..d8fcdf3d3f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/data_extract_to_buffer.c
@@ -0,0 +1,17 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 2002 Glenn McGrath
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+void data_extract_to_buffer(archive_handle_t *archive_handle)
+{
+ unsigned int size = archive_handle->file_header->size;
+
+ archive_handle->buffer = xzalloc(size + 1);
+ xread(archive_handle->src_fd, archive_handle->buffer, size);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/data_extract_to_stdout.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/data_extract_to_stdout.c
new file mode 100644
index 0000000000..c8895ed650
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/data_extract_to_stdout.c
@@ -0,0 +1,14 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+void data_extract_to_stdout(archive_handle_t *archive_handle)
+{
+ bb_copyfd_exact_size(archive_handle->src_fd,
+ STDOUT_FILENO,
+ archive_handle->file_header->size);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/data_skip.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/data_skip.c
new file mode 100644
index 0000000000..d9778da2ee
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/data_skip.c
@@ -0,0 +1,12 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+void data_skip(archive_handle_t *archive_handle)
+{
+ archive_handle->seek(archive_handle, archive_handle->file_header->size);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/decompress_bunzip2.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/decompress_bunzip2.c
new file mode 100644
index 0000000000..e034814c09
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/decompress_bunzip2.c
@@ -0,0 +1,705 @@
+/* vi: set sw=4 ts=4: */
+/* Small bzip2 deflate implementation, by Rob Landley (rob@landley.net).
+
+ Based on bzip2 decompression code by Julian R Seward (jseward@acm.org),
+ which also acknowledges contributions by Mike Burrows, David Wheeler,
+ Peter Fenwick, Alistair Moffat, Radford Neal, Ian H. Witten,
+ Robert Sedgewick, and Jon L. Bentley.
+
+ Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+*/
+
+/*
+ Size and speed optimizations by Manuel Novoa III (mjn3@codepoet.org).
+
+ More efficient reading of Huffman codes, a streamlined read_bunzip()
+ function, and various other tweaks. In (limited) tests, approximately
+ 20% faster than bzcat on x86 and about 10% faster on arm.
+
+ Note that about 2/3 of the time is spent in read_unzip() reversing
+ the Burrows-Wheeler transformation. Much of that time is delay
+ resulting from cache misses.
+
+ I would ask that anyone benefiting from this work, especially those
+ using it in commercial products, consider making a donation to my local
+ non-profit hospice organization (www.hospiceacadiana.com) in the name of
+ the woman I loved, Toni W. Hagan, who passed away Feb. 12, 2003.
+
+ Manuel
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+/* Constants for Huffman coding */
+#define MAX_GROUPS 6
+#define GROUP_SIZE 50 /* 64 would have been more efficient */
+#define MAX_HUFCODE_BITS 20 /* Longest Huffman code allowed */
+#define MAX_SYMBOLS 258 /* 256 literals + RUNA + RUNB */
+#define SYMBOL_RUNA 0
+#define SYMBOL_RUNB 1
+
+/* Status return values */
+#define RETVAL_OK 0
+#define RETVAL_LAST_BLOCK (-1)
+#define RETVAL_NOT_BZIP_DATA (-2)
+#define RETVAL_UNEXPECTED_INPUT_EOF (-3)
+#define RETVAL_SHORT_WRITE (-4)
+#define RETVAL_DATA_ERROR (-5)
+#define RETVAL_OUT_OF_MEMORY (-6)
+#define RETVAL_OBSOLETE_INPUT (-7)
+
+/* Other housekeeping constants */
+#define IOBUF_SIZE 4096
+
+/* This is what we know about each Huffman coding group */
+struct group_data {
+ /* We have an extra slot at the end of limit[] for a sentinel value. */
+ int limit[MAX_HUFCODE_BITS+1], base[MAX_HUFCODE_BITS], permute[MAX_SYMBOLS];
+ int minLen, maxLen;
+};
+
+/* Structure holding all the housekeeping data, including IO buffers and
+ * memory that persists between calls to bunzip
+ * Found the most used member:
+ * cat this_file.c | sed -e 's/"/ /g' -e "s/'/ /g" | xargs -n1 \
+ * | grep 'bd->' | sed 's/^.*bd->/bd->/' | sort | $PAGER
+ * and moved it (inbufBitCount) to offset 0.
+ */
+struct bunzip_data {
+ /* I/O tracking data (file handles, buffers, positions, etc.) */
+ unsigned inbufBitCount, inbufBits;
+ int in_fd, out_fd, inbufCount, inbufPos /*, outbufPos*/;
+ unsigned char *inbuf /*,*outbuf*/;
+
+ /* State for interrupting output loop */
+ int writeCopies, writePos, writeRunCountdown, writeCount, writeCurrent;
+
+ /* The CRC values stored in the block header and calculated from the data */
+ uint32_t headerCRC, totalCRC, writeCRC;
+
+ /* Intermediate buffer and its size (in bytes) */
+ unsigned *dbuf, dbufSize;
+
+ /* For I/O error handling */
+ jmp_buf jmpbuf;
+
+ /* Big things go last (register-relative addressing can be larger for big offsets) */
+ uint32_t crc32Table[256];
+ unsigned char selectors[32768]; /* nSelectors=15 bits */
+ struct group_data groups[MAX_GROUPS]; /* Huffman coding tables */
+};
+/* typedef struct bunzip_data bunzip_data; -- done in .h file */
+
+
+/* Return the next nnn bits of input. All reads from the compressed input
+ are done through this function. All reads are big endian */
+
+static unsigned get_bits(bunzip_data *bd, int bits_wanted)
+{
+ unsigned bits = 0;
+
+ /* If we need to get more data from the byte buffer, do so. (Loop getting
+ one byte at a time to enforce endianness and avoid unaligned access.) */
+ while ((int)(bd->inbufBitCount) < bits_wanted) {
+
+ /* If we need to read more data from file into byte buffer, do so */
+ if (bd->inbufPos == bd->inbufCount) {
+ /* if "no input fd" case: in_fd == -1, read fails, we jump */
+ bd->inbufCount = read(bd->in_fd, bd->inbuf, IOBUF_SIZE);
+ if (bd->inbufCount <= 0)
+ longjmp(bd->jmpbuf, RETVAL_UNEXPECTED_INPUT_EOF);
+ bd->inbufPos = 0;
+ }
+
+ /* Avoid 32-bit overflow (dump bit buffer to top of output) */
+ if (bd->inbufBitCount >= 24) {
+ bits = bd->inbufBits & ((1 << bd->inbufBitCount) - 1);
+ bits_wanted -= bd->inbufBitCount;
+ bits <<= bits_wanted;
+ bd->inbufBitCount = 0;
+ }
+
+ /* Grab next 8 bits of input from buffer. */
+ bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++];
+ bd->inbufBitCount += 8;
+ }
+
+ /* Calculate result */
+ bd->inbufBitCount -= bits_wanted;
+ bits |= (bd->inbufBits >> bd->inbufBitCount) & ((1 << bits_wanted) - 1);
+
+ return bits;
+}
+
+/* Unpacks the next block and sets up for the inverse burrows-wheeler step. */
+static int get_next_block(bunzip_data *bd)
+{
+ struct group_data *hufGroup;
+ int dbufCount, nextSym, dbufSize, groupCount, *base, *limit, selector,
+ i, j, k, t, runPos, symCount, symTotal, nSelectors, byteCount[256];
+ unsigned char uc, symToByte[256], mtfSymbol[256], *selectors;
+ unsigned *dbuf, origPtr;
+
+ dbuf = bd->dbuf;
+ dbufSize = bd->dbufSize;
+ selectors = bd->selectors;
+
+ /* Reset longjmp I/O error handling */
+ i = setjmp(bd->jmpbuf);
+ if (i) return i;
+
+ /* Read in header signature and CRC, then validate signature.
+ (last block signature means CRC is for whole file, return now) */
+ i = get_bits(bd, 24);
+ j = get_bits(bd, 24);
+ bd->headerCRC = get_bits(bd, 32);
+ if ((i == 0x177245) && (j == 0x385090)) return RETVAL_LAST_BLOCK;
+ if ((i != 0x314159) || (j != 0x265359)) return RETVAL_NOT_BZIP_DATA;
+
+ /* We can add support for blockRandomised if anybody complains. There was
+ some code for this in busybox 1.0.0-pre3, but nobody ever noticed that
+ it didn't actually work. */
+ if (get_bits(bd, 1)) return RETVAL_OBSOLETE_INPUT;
+ origPtr = get_bits(bd, 24);
+ if ((int)origPtr > dbufSize) return RETVAL_DATA_ERROR;
+
+ /* mapping table: if some byte values are never used (encoding things
+ like ascii text), the compression code removes the gaps to have fewer
+ symbols to deal with, and writes a sparse bitfield indicating which
+ values were present. We make a translation table to convert the symbols
+ back to the corresponding bytes. */
+ t = get_bits(bd, 16);
+ symTotal = 0;
+ for (i = 0; i < 16; i++) {
+ if (t & (1 << (15-i))) {
+ k = get_bits(bd, 16);
+ for (j = 0; j < 16; j++)
+ if (k & (1 << (15-j)))
+ symToByte[symTotal++] = (16*i) + j;
+ }
+ }
+
+ /* How many different Huffman coding groups does this block use? */
+ groupCount = get_bits(bd, 3);
+ if (groupCount < 2 || groupCount > MAX_GROUPS)
+ return RETVAL_DATA_ERROR;
+
+ /* nSelectors: Every GROUP_SIZE many symbols we select a new Huffman coding
+ group. Read in the group selector list, which is stored as MTF encoded
+ bit runs. (MTF=Move To Front, as each value is used it's moved to the
+ start of the list.) */
+ nSelectors = get_bits(bd, 15);
+ if (!nSelectors) return RETVAL_DATA_ERROR;
+ for (i = 0; i < groupCount; i++) mtfSymbol[i] = i;
+ for (i = 0; i < nSelectors; i++) {
+
+ /* Get next value */
+ for (j = 0; get_bits(bd, 1); j++)
+ if (j >= groupCount) return RETVAL_DATA_ERROR;
+
+ /* Decode MTF to get the next selector */
+ uc = mtfSymbol[j];
+ for (;j;j--) mtfSymbol[j] = mtfSymbol[j-1];
+ mtfSymbol[0] = selectors[i] = uc;
+ }
+
+ /* Read the Huffman coding tables for each group, which code for symTotal
+ literal symbols, plus two run symbols (RUNA, RUNB) */
+ symCount = symTotal + 2;
+ for (j = 0; j < groupCount; j++) {
+ unsigned char length[MAX_SYMBOLS];
+ /* 8 bits is ALMOST enough for temp[], see below */
+ unsigned temp[MAX_HUFCODE_BITS+1];
+ int minLen, maxLen, pp;
+
+ /* Read Huffman code lengths for each symbol. They're stored in
+ a way similar to mtf; record a starting value for the first symbol,
+ and an offset from the previous value for everys symbol after that.
+ (Subtracting 1 before the loop and then adding it back at the end is
+ an optimization that makes the test inside the loop simpler: symbol
+ length 0 becomes negative, so an unsigned inequality catches it.) */
+ t = get_bits(bd, 5) - 1;
+ for (i = 0; i < symCount; i++) {
+ for (;;) {
+ if ((unsigned)t > (MAX_HUFCODE_BITS-1))
+ return RETVAL_DATA_ERROR;
+
+ /* If first bit is 0, stop. Else second bit indicates whether
+ to increment or decrement the value. Optimization: grab 2
+ bits and unget the second if the first was 0. */
+ k = get_bits(bd, 2);
+ if (k < 2) {
+ bd->inbufBitCount++;
+ break;
+ }
+
+ /* Add one if second bit 1, else subtract 1. Avoids if/else */
+ t += (((k+1) & 2) - 1);
+ }
+
+ /* Correct for the initial -1, to get the final symbol length */
+ length[i] = t + 1;
+ }
+
+ /* Find largest and smallest lengths in this group */
+ minLen = maxLen = length[0];
+ for (i = 1; i < symCount; i++) {
+ if (length[i] > maxLen) maxLen = length[i];
+ else if (length[i] < minLen) minLen = length[i];
+ }
+
+ /* Calculate permute[], base[], and limit[] tables from length[].
+ *
+ * permute[] is the lookup table for converting Huffman coded symbols
+ * into decoded symbols. base[] is the amount to subtract from the
+ * value of a Huffman symbol of a given length when using permute[].
+ *
+ * limit[] indicates the largest numerical value a symbol with a given
+ * number of bits can have. This is how the Huffman codes can vary in
+ * length: each code with a value>limit[length] needs another bit.
+ */
+ hufGroup = bd->groups + j;
+ hufGroup->minLen = minLen;
+ hufGroup->maxLen = maxLen;
+
+ /* Note that minLen can't be smaller than 1, so we adjust the base
+ and limit array pointers so we're not always wasting the first
+ entry. We do this again when using them (during symbol decoding).*/
+ base = hufGroup->base - 1;
+ limit = hufGroup->limit - 1;
+
+ /* Calculate permute[]. Concurently, initialize temp[] and limit[]. */
+ pp = 0;
+ for (i = minLen; i <= maxLen; i++) {
+ temp[i] = limit[i] = 0;
+ for (t = 0; t < symCount; t++)
+ if (length[t] == i)
+ hufGroup->permute[pp++] = t;
+ }
+
+ /* Count symbols coded for at each bit length */
+ /* NB: in pathological cases, temp[8] can end ip being 256.
+ * That's why uint8_t is too small for temp[]. */
+ for (i = 0; i < symCount; i++) temp[length[i]]++;
+
+ /* Calculate limit[] (the largest symbol-coding value at each bit
+ * length, which is (previous limit<<1)+symbols at this level), and
+ * base[] (number of symbols to ignore at each bit length, which is
+ * limit minus the cumulative count of symbols coded for already). */
+ pp = t = 0;
+ for (i = minLen; i < maxLen; i++) {
+ pp += temp[i];
+
+ /* We read the largest possible symbol size and then unget bits
+ after determining how many we need, and those extra bits could
+ be set to anything. (They're noise from future symbols.) At
+ each level we're really only interested in the first few bits,
+ so here we set all the trailing to-be-ignored bits to 1 so they
+ don't affect the value>limit[length] comparison. */
+ limit[i] = (pp << (maxLen - i)) - 1;
+ pp <<= 1;
+ t += temp[i];
+ base[i+1] = pp - t;
+ }
+ limit[maxLen+1] = INT_MAX; /* Sentinel value for reading next sym. */
+ limit[maxLen] = pp + temp[maxLen] - 1;
+ base[minLen] = 0;
+ }
+
+ /* We've finished reading and digesting the block header. Now read this
+ block's Huffman coded symbols from the file and undo the Huffman coding
+ and run length encoding, saving the result into dbuf[dbufCount++] = uc */
+
+ /* Initialize symbol occurrence counters and symbol Move To Front table */
+ memset(byteCount, 0, sizeof(byteCount)); /* smaller, maybe slower? */
+ for (i = 0; i < 256; i++) {
+ //byteCount[i] = 0;
+ mtfSymbol[i] = (unsigned char)i;
+ }
+
+ /* Loop through compressed symbols. */
+
+ runPos = dbufCount = selector = 0;
+ for (;;) {
+
+ /* Fetch next Huffman coding group from list. */
+ symCount = GROUP_SIZE - 1;
+ if (selector >= nSelectors) return RETVAL_DATA_ERROR;
+ hufGroup = bd->groups + selectors[selector++];
+ base = hufGroup->base - 1;
+ limit = hufGroup->limit - 1;
+ continue_this_group:
+
+ /* Read next Huffman-coded symbol. */
+
+ /* Note: It is far cheaper to read maxLen bits and back up than it is
+ to read minLen bits and then an additional bit at a time, testing
+ as we go. Because there is a trailing last block (with file CRC),
+ there is no danger of the overread causing an unexpected EOF for a
+ valid compressed file. As a further optimization, we do the read
+ inline (falling back to a call to get_bits if the buffer runs
+ dry). The following (up to got_huff_bits:) is equivalent to
+ j = get_bits(bd, hufGroup->maxLen);
+ */
+ while ((int)(bd->inbufBitCount) < hufGroup->maxLen) {
+ if (bd->inbufPos == bd->inbufCount) {
+ j = get_bits(bd, hufGroup->maxLen);
+ goto got_huff_bits;
+ }
+ bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++];
+ bd->inbufBitCount += 8;
+ };
+ bd->inbufBitCount -= hufGroup->maxLen;
+ j = (bd->inbufBits >> bd->inbufBitCount) & ((1 << hufGroup->maxLen) - 1);
+
+ got_huff_bits:
+
+ /* Figure how how many bits are in next symbol and unget extras */
+ i = hufGroup->minLen;
+ while (j > limit[i]) ++i;
+ bd->inbufBitCount += (hufGroup->maxLen - i);
+
+ /* Huffman decode value to get nextSym (with bounds checking) */
+ if (i > hufGroup->maxLen)
+ return RETVAL_DATA_ERROR;
+ j = (j >> (hufGroup->maxLen - i)) - base[i];
+ if ((unsigned)j >= MAX_SYMBOLS)
+ return RETVAL_DATA_ERROR;
+ nextSym = hufGroup->permute[j];
+
+ /* We have now decoded the symbol, which indicates either a new literal
+ byte, or a repeated run of the most recent literal byte. First,
+ check if nextSym indicates a repeated run, and if so loop collecting
+ how many times to repeat the last literal. */
+ if ((unsigned)nextSym <= SYMBOL_RUNB) { /* RUNA or RUNB */
+
+ /* If this is the start of a new run, zero out counter */
+ if (!runPos) {
+ runPos = 1;
+ t = 0;
+ }
+
+ /* Neat trick that saves 1 symbol: instead of or-ing 0 or 1 at
+ each bit position, add 1 or 2 instead. For example,
+ 1011 is 1<<0 + 1<<1 + 2<<2. 1010 is 2<<0 + 2<<1 + 1<<2.
+ You can make any bit pattern that way using 1 less symbol than
+ the basic or 0/1 method (except all bits 0, which would use no
+ symbols, but a run of length 0 doesn't mean anything in this
+ context). Thus space is saved. */
+ t += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */
+ if (runPos < dbufSize) runPos <<= 1;
+ goto end_of_huffman_loop;
+ }
+
+ /* When we hit the first non-run symbol after a run, we now know
+ how many times to repeat the last literal, so append that many
+ copies to our buffer of decoded symbols (dbuf) now. (The last
+ literal used is the one at the head of the mtfSymbol array.) */
+ if (runPos) {
+ runPos = 0;
+ if (dbufCount + t >= dbufSize) return RETVAL_DATA_ERROR;
+
+ uc = symToByte[mtfSymbol[0]];
+ byteCount[uc] += t;
+ while (t--) dbuf[dbufCount++] = uc;
+ }
+
+ /* Is this the terminating symbol? */
+ if (nextSym > symTotal) break;
+
+ /* At this point, nextSym indicates a new literal character. Subtract
+ one to get the position in the MTF array at which this literal is
+ currently to be found. (Note that the result can't be -1 or 0,
+ because 0 and 1 are RUNA and RUNB. But another instance of the
+ first symbol in the mtf array, position 0, would have been handled
+ as part of a run above. Therefore 1 unused mtf position minus
+ 2 non-literal nextSym values equals -1.) */
+ if (dbufCount >= dbufSize) return RETVAL_DATA_ERROR;
+ i = nextSym - 1;
+ uc = mtfSymbol[i];
+
+ /* Adjust the MTF array. Since we typically expect to move only a
+ * small number of symbols, and are bound by 256 in any case, using
+ * memmove here would typically be bigger and slower due to function
+ * call overhead and other assorted setup costs. */
+ do {
+ mtfSymbol[i] = mtfSymbol[i-1];
+ } while (--i);
+ mtfSymbol[0] = uc;
+ uc = symToByte[uc];
+
+ /* We have our literal byte. Save it into dbuf. */
+ byteCount[uc]++;
+ dbuf[dbufCount++] = (unsigned)uc;
+
+ /* Skip group initialization if we're not done with this group. Done
+ * this way to avoid compiler warning. */
+ end_of_huffman_loop:
+ if (symCount--) goto continue_this_group;
+ }
+
+ /* At this point, we've read all the Huffman-coded symbols (and repeated
+ runs) for this block from the input stream, and decoded them into the
+ intermediate buffer. There are dbufCount many decoded bytes in dbuf[].
+ Now undo the Burrows-Wheeler transform on dbuf.
+ See http://dogma.net/markn/articles/bwt/bwt.htm
+ */
+
+ /* Turn byteCount into cumulative occurrence counts of 0 to n-1. */
+ j = 0;
+ for (i = 0; i < 256; i++) {
+ k = j + byteCount[i];
+ byteCount[i] = j;
+ j = k;
+ }
+
+ /* Figure out what order dbuf would be in if we sorted it. */
+ for (i = 0; i < dbufCount; i++) {
+ uc = (unsigned char)(dbuf[i] & 0xff);
+ dbuf[byteCount[uc]] |= (i << 8);
+ byteCount[uc]++;
+ }
+
+ /* Decode first byte by hand to initialize "previous" byte. Note that it
+ doesn't get output, and if the first three characters are identical
+ it doesn't qualify as a run (hence writeRunCountdown=5). */
+ if (dbufCount) {
+ if ((int)origPtr >= dbufCount) return RETVAL_DATA_ERROR;
+ bd->writePos = dbuf[origPtr];
+ bd->writeCurrent = (unsigned char)(bd->writePos & 0xff);
+ bd->writePos >>= 8;
+ bd->writeRunCountdown = 5;
+ }
+ bd->writeCount = dbufCount;
+
+ return RETVAL_OK;
+}
+
+/* Undo burrows-wheeler transform on intermediate buffer to produce output.
+ If start_bunzip was initialized with out_fd=-1, then up to len bytes of
+ data are written to outbuf. Return value is number of bytes written or
+ error (all errors are negative numbers). If out_fd!=-1, outbuf and len
+ are ignored, data is written to out_fd and return is RETVAL_OK or error.
+*/
+int read_bunzip(bunzip_data *bd, char *outbuf, int len)
+{
+ const unsigned *dbuf;
+ int pos, current, previous, gotcount;
+
+ /* If last read was short due to end of file, return last block now */
+ if (bd->writeCount < 0) return bd->writeCount;
+
+ gotcount = 0;
+ dbuf = bd->dbuf;
+ pos = bd->writePos;
+ current = bd->writeCurrent;
+
+ /* We will always have pending decoded data to write into the output
+ buffer unless this is the very first call (in which case we haven't
+ Huffman-decoded a block into the intermediate buffer yet). */
+ if (bd->writeCopies) {
+
+ /* Inside the loop, writeCopies means extra copies (beyond 1) */
+ --bd->writeCopies;
+
+ /* Loop outputting bytes */
+ for (;;) {
+
+ /* If the output buffer is full, snapshot state and return */
+ if (gotcount >= len) {
+ bd->writePos = pos;
+ bd->writeCurrent = current;
+ bd->writeCopies++;
+ return len;
+ }
+
+ /* Write next byte into output buffer, updating CRC */
+ outbuf[gotcount++] = current;
+ bd->writeCRC = (bd->writeCRC << 8)
+ ^ bd->crc32Table[(bd->writeCRC >> 24) ^ current];
+
+ /* Loop now if we're outputting multiple copies of this byte */
+ if (bd->writeCopies) {
+ --bd->writeCopies;
+ continue;
+ }
+ decode_next_byte:
+ if (!bd->writeCount--) break;
+ /* Follow sequence vector to undo Burrows-Wheeler transform */
+ previous = current;
+ pos = dbuf[pos];
+ current = pos & 0xff;
+ pos >>= 8;
+
+ /* After 3 consecutive copies of the same byte, the 4th
+ * is a repeat count. We count down from 4 instead
+ * of counting up because testing for non-zero is faster */
+ if (--bd->writeRunCountdown) {
+ if (current != previous)
+ bd->writeRunCountdown = 4;
+ } else {
+
+ /* We have a repeated run, this byte indicates the count */
+ bd->writeCopies = current;
+ current = previous;
+ bd->writeRunCountdown = 5;
+
+ /* Sometimes there are just 3 bytes (run length 0) */
+ if (!bd->writeCopies) goto decode_next_byte;
+
+ /* Subtract the 1 copy we'd output anyway to get extras */
+ --bd->writeCopies;
+ }
+ }
+
+ /* Decompression of this block completed successfully */
+ bd->writeCRC = ~bd->writeCRC;
+ bd->totalCRC = ((bd->totalCRC << 1) | (bd->totalCRC >> 31)) ^ bd->writeCRC;
+
+ /* If this block had a CRC error, force file level CRC error. */
+ if (bd->writeCRC != bd->headerCRC) {
+ bd->totalCRC = bd->headerCRC + 1;
+ return RETVAL_LAST_BLOCK;
+ }
+ }
+
+ /* Refill the intermediate buffer by Huffman-decoding next block of input */
+ /* (previous is just a convenient unused temp variable here) */
+ previous = get_next_block(bd);
+ if (previous) {
+ bd->writeCount = previous;
+ return (previous != RETVAL_LAST_BLOCK) ? previous : gotcount;
+ }
+ bd->writeCRC = ~0;
+ pos = bd->writePos;
+ current = bd->writeCurrent;
+ goto decode_next_byte;
+}
+
+/* Allocate the structure, read file header. If in_fd==-1, inbuf must contain
+ a complete bunzip file (len bytes long). If in_fd!=-1, inbuf and len are
+ ignored, and data is read from file handle into temporary buffer. */
+
+/* Because bunzip2 is used for help text unpacking, and because bb_show_usage()
+ should work for NOFORK applets too, we must be extremely careful to not leak
+ any allocations! */
+int start_bunzip(bunzip_data **bdp, int in_fd, const unsigned char *inbuf,
+ int len)
+{
+ bunzip_data *bd;
+ unsigned i;
+ enum {
+ BZh0 = ('B' << 24) + ('Z' << 16) + ('h' << 8) + '0'
+ };
+
+ /* Figure out how much data to allocate */
+ i = sizeof(bunzip_data);
+ if (in_fd != -1) i += IOBUF_SIZE;
+
+ /* Allocate bunzip_data. Most fields initialize to zero. */
+ bd = *bdp = xzalloc(i);
+
+ /* Setup input buffer */
+ bd->in_fd = in_fd;
+ if (-1 == in_fd) {
+ /* in this case, bd->inbuf is read-only */
+ bd->inbuf = (void*)inbuf; /* cast away const-ness */
+ bd->inbufCount = len;
+ } else
+ bd->inbuf = (unsigned char *)(bd + 1);
+
+ /* Init the CRC32 table (big endian) */
+ crc32_filltable(bd->crc32Table, 1);
+
+ /* Setup for I/O error handling via longjmp */
+ i = setjmp(bd->jmpbuf);
+ if (i) return i;
+
+ /* Ensure that file starts with "BZh['1'-'9']." */
+ i = get_bits(bd, 32);
+ if ((unsigned)(i - BZh0 - 1) >= 9) return RETVAL_NOT_BZIP_DATA;
+
+ /* Fourth byte (ascii '1'-'9') indicates block size in units of 100k of
+ uncompressed data. Allocate intermediate buffer for block. */
+ bd->dbufSize = 100000 * (i - BZh0);
+
+ /* Cannot use xmalloc - may leak bd in NOFORK case! */
+ bd->dbuf = malloc_or_warn(bd->dbufSize * sizeof(int));
+ if (!bd->dbuf) {
+ free(bd);
+ xfunc_die();
+ }
+ return RETVAL_OK;
+}
+
+void dealloc_bunzip(bunzip_data *bd)
+{
+ free(bd->dbuf);
+ free(bd);
+}
+
+
+/* Decompress src_fd to dst_fd. Stops at end of bzip data, not end of file. */
+USE_DESKTOP(long long) int
+unpack_bz2_stream(int src_fd, int dst_fd)
+{
+ USE_DESKTOP(long long total_written = 0;)
+ char *outbuf;
+ bunzip_data *bd;
+ int i;
+
+ outbuf = xmalloc(IOBUF_SIZE);
+ i = start_bunzip(&bd, src_fd, NULL, 0);
+ if (!i) {
+ for (;;) {
+ i = read_bunzip(bd, outbuf, IOBUF_SIZE);
+ if (i <= 0) break;
+ if (i != full_write(dst_fd, outbuf, i)) {
+ i = RETVAL_SHORT_WRITE;
+ break;
+ }
+ USE_DESKTOP(total_written += i;)
+ }
+ }
+
+ /* Check CRC and release memory */
+
+ if (i == RETVAL_LAST_BLOCK) {
+ if (bd->headerCRC != bd->totalCRC) {
+ bb_error_msg("CRC error");
+ } else {
+ i = RETVAL_OK;
+ }
+ } else if (i == RETVAL_SHORT_WRITE) {
+ bb_error_msg("short write");
+ } else {
+ bb_error_msg("bunzip error %d", i);
+ }
+ dealloc_bunzip(bd);
+ free(outbuf);
+
+ return i ? i : USE_DESKTOP(total_written) + 0;
+}
+
+#ifdef TESTING
+
+static char *const bunzip_errors[] = {
+ NULL, "Bad file checksum", "Not bzip data",
+ "Unexpected input EOF", "Unexpected output EOF", "Data error",
+ "Out of memory", "Obsolete (pre 0.9.5) bzip format not supported"
+};
+
+/* Dumb little test thing, decompress stdin to stdout */
+int main(int argc, char **argv)
+{
+ int i = unpack_bz2_stream(0, 1);
+ char c;
+
+ if (i < 0)
+ fprintf(stderr, "%s\n", bunzip_errors[-i]);
+ else if (read(STDIN_FILENO, &c, 1))
+ fprintf(stderr, "Trailing garbage ignored\n");
+ return -i;
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/decompress_uncompress.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/decompress_uncompress.c
new file mode 100644
index 0000000000..8c3c65d1af
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/decompress_uncompress.c
@@ -0,0 +1,305 @@
+/* vi: set sw=4 ts=4: */
+#include "libbb.h"
+
+/* uncompress for busybox -- (c) 2002 Robert Griebl
+ *
+ * based on the original compress42.c source
+ * (see disclaimer below)
+ */
+
+/* (N)compress42.c - File compression ala IEEE Computer, Mar 1992.
+ *
+ * Authors:
+ * Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
+ * Jim McKie (decvax!mcvax!jim)
+ * Steve Davies (decvax!vax135!petsd!peora!srd)
+ * Ken Turkowski (decvax!decwrl!turtlevax!ken)
+ * James A. Woods (decvax!ihnp4!ames!jaw)
+ * Joe Orost (decvax!vax135!petsd!joe)
+ * Dave Mack (csu@alembic.acs.com)
+ * Peter Jannesen, Network Communication Systems
+ * (peter@ncs.nl)
+ *
+ * marc@suse.de : a small security fix for a buffer overflow
+ *
+ * [... History snipped ...]
+ *
+ */
+
+/* Default input buffer size */
+#define IBUFSIZ 2048
+
+/* Default output buffer size */
+#define OBUFSIZ 2048
+
+/* Defines for third byte of header */
+#define BIT_MASK 0x1f /* Mask for 'number of compresssion bits' */
+ /* Masks 0x20 and 0x40 are free. */
+ /* I think 0x20 should mean that there is */
+ /* a fourth header byte (for expansion). */
+#define BLOCK_MODE 0x80 /* Block compression if table is full and */
+ /* compression rate is dropping flush tables */
+ /* the next two codes should not be changed lightly, as they must not */
+ /* lie within the contiguous general code space. */
+#define FIRST 257 /* first free entry */
+#define CLEAR 256 /* table clear output code */
+
+#define INIT_BITS 9 /* initial number of bits/code */
+
+
+/* machine variants which require cc -Dmachine: pdp11, z8000, DOS */
+#define HBITS 17 /* 50% occupancy */
+#define HSIZE (1<<HBITS)
+#define HMASK (HSIZE-1) /* unused */
+#define HPRIME 9941 /* unused */
+#define BITS 16
+#define BITS_STR "16"
+#undef MAXSEG_64K /* unused */
+#define MAXCODE(n) (1L << (n))
+
+#define htabof(i) htab[i]
+#define codetabof(i) codetab[i]
+#define tab_prefixof(i) codetabof(i)
+#define tab_suffixof(i) ((unsigned char *)(htab))[i]
+#define de_stack ((unsigned char *)&(htab[HSIZE-1]))
+#define clear_tab_prefixof() memset(codetab, 0, 256)
+
+/*
+ * Decompress stdin to stdout. This routine adapts to the codes in the
+ * file building the "string" table on-the-fly; requiring no table to
+ * be stored in the compressed file.
+ */
+
+USE_DESKTOP(long long) int
+uncompress(int fd_in, int fd_out)
+{
+ USE_DESKTOP(long long total_written = 0;)
+ USE_DESKTOP(long long) int retval = -1;
+ unsigned char *stackp;
+ long code;
+ int finchar;
+ long oldcode;
+ long incode;
+ int inbits;
+ int posbits;
+ int outpos;
+ int insize;
+ int bitmask;
+ long free_ent;
+ long maxcode;
+ long maxmaxcode;
+ int n_bits;
+ int rsize = 0;
+ unsigned char *inbuf; /* were eating insane amounts of stack - */
+ unsigned char *outbuf; /* bad for some embedded targets */
+ unsigned char *htab;
+ unsigned short *codetab;
+
+ /* Hmm, these were statics - why?! */
+ /* user settable max # bits/code */
+ int maxbits; /* = BITS; */
+ /* block compress mode -C compatible with 2.0 */
+ int block_mode; /* = BLOCK_MODE; */
+
+ inbuf = xzalloc(IBUFSIZ + 64);
+ outbuf = xzalloc(OBUFSIZ + 2048);
+ htab = xzalloc(HSIZE); /* wsn't zeroed out before, maybe can xmalloc? */
+ codetab = xzalloc(HSIZE * sizeof(codetab[0]));
+
+ insize = 0;
+
+ /* xread isn't good here, we have to return - caller may want
+ * to do some cleanup (e.g. delete incomplete unpacked file etc) */
+ if (full_read(fd_in, inbuf, 1) != 1) {
+ bb_error_msg("short read");
+ goto err;
+ }
+
+ maxbits = inbuf[0] & BIT_MASK;
+ block_mode = inbuf[0] & BLOCK_MODE;
+ maxmaxcode = MAXCODE(maxbits);
+
+ if (maxbits > BITS) {
+ bb_error_msg("compressed with %d bits, can only handle "
+ BITS_STR" bits", maxbits);
+ goto err;
+ }
+
+ n_bits = INIT_BITS;
+ maxcode = MAXCODE(INIT_BITS) - 1;
+ bitmask = (1 << INIT_BITS) - 1;
+ oldcode = -1;
+ finchar = 0;
+ outpos = 0;
+ posbits = 0 << 3;
+
+ free_ent = ((block_mode) ? FIRST : 256);
+
+ /* As above, initialize the first 256 entries in the table. */
+ /*clear_tab_prefixof(); - done by xzalloc */
+
+ for (code = 255; code >= 0; --code) {
+ tab_suffixof(code) = (unsigned char) code;
+ }
+
+ do {
+ resetbuf:
+ {
+ int i;
+ int e;
+ int o;
+
+ o = posbits >> 3;
+ e = insize - o;
+
+ for (i = 0; i < e; ++i)
+ inbuf[i] = inbuf[i + o];
+
+ insize = e;
+ posbits = 0;
+ }
+
+ if (insize < (int) (IBUFSIZ + 64) - IBUFSIZ) {
+ rsize = safe_read(fd_in, inbuf + insize, IBUFSIZ);
+//error check??
+ insize += rsize;
+ }
+
+ inbits = ((rsize > 0) ? (insize - insize % n_bits) << 3 :
+ (insize << 3) - (n_bits - 1));
+
+ while (inbits > posbits) {
+ if (free_ent > maxcode) {
+ posbits =
+ ((posbits - 1) +
+ ((n_bits << 3) -
+ (posbits - 1 + (n_bits << 3)) % (n_bits << 3)));
+ ++n_bits;
+ if (n_bits == maxbits) {
+ maxcode = maxmaxcode;
+ } else {
+ maxcode = MAXCODE(n_bits) - 1;
+ }
+ bitmask = (1 << n_bits) - 1;
+ goto resetbuf;
+ }
+ {
+ unsigned char *p = &inbuf[posbits >> 3];
+
+ code = ((((long) (p[0])) | ((long) (p[1]) << 8) |
+ ((long) (p[2]) << 16)) >> (posbits & 0x7)) & bitmask;
+ }
+ posbits += n_bits;
+
+
+ if (oldcode == -1) {
+ oldcode = code;
+ finchar = (int) oldcode;
+ outbuf[outpos++] = (unsigned char) finchar;
+ continue;
+ }
+
+ if (code == CLEAR && block_mode) {
+ clear_tab_prefixof();
+ free_ent = FIRST - 1;
+ posbits =
+ ((posbits - 1) +
+ ((n_bits << 3) -
+ (posbits - 1 + (n_bits << 3)) % (n_bits << 3)));
+ n_bits = INIT_BITS;
+ maxcode = MAXCODE(INIT_BITS) - 1;
+ bitmask = (1 << INIT_BITS) - 1;
+ goto resetbuf;
+ }
+
+ incode = code;
+ stackp = de_stack;
+
+ /* Special case for KwKwK string. */
+ if (code >= free_ent) {
+ if (code > free_ent) {
+ unsigned char *p;
+
+ posbits -= n_bits;
+ p = &inbuf[posbits >> 3];
+
+ bb_error_msg
+ ("insize:%d posbits:%d inbuf:%02X %02X %02X %02X %02X (%d)",
+ insize, posbits, p[-1], p[0], p[1], p[2], p[3],
+ (posbits & 07));
+ bb_error_msg("uncompress: corrupt input");
+ goto err;
+ }
+
+ *--stackp = (unsigned char) finchar;
+ code = oldcode;
+ }
+
+ /* Generate output characters in reverse order */
+ while ((long) code >= (long) 256) {
+ *--stackp = tab_suffixof(code);
+ code = tab_prefixof(code);
+ }
+
+ finchar = tab_suffixof(code);
+ *--stackp = (unsigned char) finchar;
+
+ /* And put them out in forward order */
+ {
+ int i;
+
+ i = de_stack - stackp;
+ if (outpos + i >= OBUFSIZ) {
+ do {
+ if (i > OBUFSIZ - outpos) {
+ i = OBUFSIZ - outpos;
+ }
+
+ if (i > 0) {
+ memcpy(outbuf + outpos, stackp, i);
+ outpos += i;
+ }
+
+ if (outpos >= OBUFSIZ) {
+ full_write(fd_out, outbuf, outpos);
+//error check??
+ USE_DESKTOP(total_written += outpos;)
+ outpos = 0;
+ }
+ stackp += i;
+ i = de_stack - stackp;
+ } while (i > 0);
+ } else {
+ memcpy(outbuf + outpos, stackp, i);
+ outpos += i;
+ }
+ }
+
+ /* Generate the new entry. */
+ code = free_ent;
+ if (code < maxmaxcode) {
+ tab_prefixof(code) = (unsigned short) oldcode;
+ tab_suffixof(code) = (unsigned char) finchar;
+ free_ent = code + 1;
+ }
+
+ /* Remember previous code. */
+ oldcode = incode;
+ }
+
+ } while (rsize > 0);
+
+ if (outpos > 0) {
+ full_write(fd_out, outbuf, outpos);
+//error check??
+ USE_DESKTOP(total_written += outpos;)
+ }
+
+ retval = USE_DESKTOP(total_written) + 0;
+ err:
+ free(inbuf);
+ free(outbuf);
+ free(htab);
+ free(codetab);
+ return retval;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/decompress_unlzma.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/decompress_unlzma.c
new file mode 100644
index 0000000000..c320400758
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/decompress_unlzma.c
@@ -0,0 +1,500 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Small lzma deflate implementation.
+ * Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
+ *
+ * Based on LzmaDecode.c from the LZMA SDK 4.22 (http://www.7-zip.org/)
+ * Copyright (C) 1999-2005 Igor Pavlov
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+#if ENABLE_FEATURE_LZMA_FAST
+# define speed_inline ALWAYS_INLINE
+#else
+# define speed_inline
+#endif
+
+
+typedef struct {
+ int fd;
+ uint8_t *ptr;
+
+/* Was keeping rc on stack in unlzma and separately allocating buffer,
+ * but with "buffer 'attached to' allocated rc" code is smaller: */
+ /* uint8_t *buffer; */
+#define RC_BUFFER ((uint8_t*)(rc+1))
+
+ uint8_t *buffer_end;
+
+/* Had provisions for variable buffer, but we don't need it here */
+ /* int buffer_size; */
+#define RC_BUFFER_SIZE 0x10000
+
+ uint32_t code;
+ uint32_t range;
+ uint32_t bound;
+} rc_t;
+
+#define RC_TOP_BITS 24
+#define RC_MOVE_BITS 5
+#define RC_MODEL_TOTAL_BITS 11
+
+
+/* Called twice: once at startup and once in rc_normalize() */
+static void rc_read(rc_t * rc)
+{
+ int buffer_size = safe_read(rc->fd, RC_BUFFER, RC_BUFFER_SIZE);
+ if (buffer_size <= 0)
+ bb_error_msg_and_die("unexpected EOF");
+ rc->ptr = RC_BUFFER;
+ rc->buffer_end = RC_BUFFER + buffer_size;
+}
+
+/* Called once */
+static rc_t* rc_init(int fd) /*, int buffer_size) */
+{
+ int i;
+ rc_t* rc;
+
+ rc = xmalloc(sizeof(rc_t) + RC_BUFFER_SIZE);
+
+ rc->fd = fd;
+ /* rc->buffer_size = buffer_size; */
+ rc->buffer_end = RC_BUFFER + RC_BUFFER_SIZE;
+ rc->ptr = rc->buffer_end;
+
+ rc->code = 0;
+ rc->range = 0xFFFFFFFF;
+ for (i = 0; i < 5; i++) {
+ if (rc->ptr >= rc->buffer_end)
+ rc_read(rc);
+ rc->code = (rc->code << 8) | *rc->ptr++;
+ }
+ return rc;
+}
+
+/* Called once */
+static ALWAYS_INLINE void rc_free(rc_t * rc)
+{
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(rc);
+}
+
+/* Called twice, but one callsite is in speed_inline'd rc_is_bit_0_helper() */
+static void rc_do_normalize(rc_t * rc)
+{
+ if (rc->ptr >= rc->buffer_end)
+ rc_read(rc);
+ rc->range <<= 8;
+ rc->code = (rc->code << 8) | *rc->ptr++;
+}
+static ALWAYS_INLINE void rc_normalize(rc_t * rc)
+{
+ if (rc->range < (1 << RC_TOP_BITS)) {
+ rc_do_normalize(rc);
+ }
+}
+
+/* rc_is_bit_0 is called 9 times */
+/* Why rc_is_bit_0_helper exists?
+ * Because we want to always expose (rc->code < rc->bound) to optimizer.
+ * Thus rc_is_bit_0 is always inlined, and rc_is_bit_0_helper is inlined
+ * only if we compile for speed.
+ */
+static speed_inline uint32_t rc_is_bit_0_helper(rc_t * rc, uint16_t * p)
+{
+ rc_normalize(rc);
+ rc->bound = *p * (rc->range >> RC_MODEL_TOTAL_BITS);
+ return rc->bound;
+}
+static ALWAYS_INLINE int rc_is_bit_0(rc_t * rc, uint16_t * p)
+{
+ uint32_t t = rc_is_bit_0_helper(rc, p);
+ return rc->code < t;
+}
+
+/* Called ~10 times, but very small, thus inlined */
+static speed_inline void rc_update_bit_0(rc_t * rc, uint16_t * p)
+{
+ rc->range = rc->bound;
+ *p += ((1 << RC_MODEL_TOTAL_BITS) - *p) >> RC_MOVE_BITS;
+}
+static speed_inline void rc_update_bit_1(rc_t * rc, uint16_t * p)
+{
+ rc->range -= rc->bound;
+ rc->code -= rc->bound;
+ *p -= *p >> RC_MOVE_BITS;
+}
+
+/* Called 4 times in unlzma loop */
+static int rc_get_bit(rc_t * rc, uint16_t * p, int *symbol)
+{
+ if (rc_is_bit_0(rc, p)) {
+ rc_update_bit_0(rc, p);
+ *symbol *= 2;
+ return 0;
+ } else {
+ rc_update_bit_1(rc, p);
+ *symbol = *symbol * 2 + 1;
+ return 1;
+ }
+}
+
+/* Called once */
+static ALWAYS_INLINE int rc_direct_bit(rc_t * rc)
+{
+ rc_normalize(rc);
+ rc->range >>= 1;
+ if (rc->code >= rc->range) {
+ rc->code -= rc->range;
+ return 1;
+ }
+ return 0;
+}
+
+/* Called twice */
+static speed_inline void
+rc_bit_tree_decode(rc_t * rc, uint16_t * p, int num_levels, int *symbol)
+{
+ int i = num_levels;
+
+ *symbol = 1;
+ while (i--)
+ rc_get_bit(rc, p + *symbol, symbol);
+ *symbol -= 1 << num_levels;
+}
+
+
+typedef struct {
+ uint8_t pos;
+ uint32_t dict_size;
+ uint64_t dst_size;
+} __attribute__ ((packed)) lzma_header_t;
+
+
+/* #defines will force compiler to compute/optimize each one with each usage.
+ * Have heart and use enum instead. */
+enum {
+ LZMA_BASE_SIZE = 1846,
+ LZMA_LIT_SIZE = 768,
+
+ LZMA_NUM_POS_BITS_MAX = 4,
+
+ LZMA_LEN_NUM_LOW_BITS = 3,
+ LZMA_LEN_NUM_MID_BITS = 3,
+ LZMA_LEN_NUM_HIGH_BITS = 8,
+
+ LZMA_LEN_CHOICE = 0,
+ LZMA_LEN_CHOICE_2 = (LZMA_LEN_CHOICE + 1),
+ LZMA_LEN_LOW = (LZMA_LEN_CHOICE_2 + 1),
+ LZMA_LEN_MID = (LZMA_LEN_LOW \
+ + (1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_LOW_BITS))),
+ LZMA_LEN_HIGH = (LZMA_LEN_MID \
+ + (1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_MID_BITS))),
+ LZMA_NUM_LEN_PROBS = (LZMA_LEN_HIGH + (1 << LZMA_LEN_NUM_HIGH_BITS)),
+
+ LZMA_NUM_STATES = 12,
+ LZMA_NUM_LIT_STATES = 7,
+
+ LZMA_START_POS_MODEL_INDEX = 4,
+ LZMA_END_POS_MODEL_INDEX = 14,
+ LZMA_NUM_FULL_DISTANCES = (1 << (LZMA_END_POS_MODEL_INDEX >> 1)),
+
+ LZMA_NUM_POS_SLOT_BITS = 6,
+ LZMA_NUM_LEN_TO_POS_STATES = 4,
+
+ LZMA_NUM_ALIGN_BITS = 4,
+
+ LZMA_MATCH_MIN_LEN = 2,
+
+ LZMA_IS_MATCH = 0,
+ LZMA_IS_REP = (LZMA_IS_MATCH + (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX)),
+ LZMA_IS_REP_G0 = (LZMA_IS_REP + LZMA_NUM_STATES),
+ LZMA_IS_REP_G1 = (LZMA_IS_REP_G0 + LZMA_NUM_STATES),
+ LZMA_IS_REP_G2 = (LZMA_IS_REP_G1 + LZMA_NUM_STATES),
+ LZMA_IS_REP_0_LONG = (LZMA_IS_REP_G2 + LZMA_NUM_STATES),
+ LZMA_POS_SLOT = (LZMA_IS_REP_0_LONG \
+ + (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX)),
+ LZMA_SPEC_POS = (LZMA_POS_SLOT \
+ + (LZMA_NUM_LEN_TO_POS_STATES << LZMA_NUM_POS_SLOT_BITS)),
+ LZMA_ALIGN = (LZMA_SPEC_POS \
+ + LZMA_NUM_FULL_DISTANCES - LZMA_END_POS_MODEL_INDEX),
+ LZMA_LEN_CODER = (LZMA_ALIGN + (1 << LZMA_NUM_ALIGN_BITS)),
+ LZMA_REP_LEN_CODER = (LZMA_LEN_CODER + LZMA_NUM_LEN_PROBS),
+ LZMA_LITERAL = (LZMA_REP_LEN_CODER + LZMA_NUM_LEN_PROBS),
+};
+
+
+USE_DESKTOP(long long) int
+unpack_lzma_stream(int src_fd, int dst_fd)
+{
+ USE_DESKTOP(long long total_written = 0;)
+ lzma_header_t header;
+ int lc, pb, lp;
+ uint32_t pos_state_mask;
+ uint32_t literal_pos_mask;
+ uint32_t pos;
+ uint16_t *p;
+ uint16_t *prob;
+ uint16_t *prob_lit;
+ int num_bits;
+ int num_probs;
+ rc_t *rc;
+ int i, mi;
+ uint8_t *buffer;
+ uint8_t previous_byte = 0;
+ size_t buffer_pos = 0, global_pos = 0;
+ int len = 0;
+ int state = 0;
+ uint32_t rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+
+ xread(src_fd, &header, sizeof(header));
+
+ if (header.pos >= (9 * 5 * 5))
+ bb_error_msg_and_die("bad header");
+ mi = header.pos / 9;
+ lc = header.pos % 9;
+ pb = mi / 5;
+ lp = mi % 5;
+ pos_state_mask = (1 << pb) - 1;
+ literal_pos_mask = (1 << lp) - 1;
+
+ header.dict_size = SWAP_LE32(header.dict_size);
+ header.dst_size = SWAP_LE64(header.dst_size);
+
+ if (header.dict_size == 0)
+ header.dict_size = 1;
+
+ buffer = xmalloc(MIN(header.dst_size, header.dict_size));
+
+ num_probs = LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp));
+ p = xmalloc(num_probs * sizeof(*p));
+ num_probs = LZMA_LITERAL + (LZMA_LIT_SIZE << (lc + lp));
+ for (i = 0; i < num_probs; i++)
+ p[i] = (1 << RC_MODEL_TOTAL_BITS) >> 1;
+
+ rc = rc_init(src_fd); /*, RC_BUFFER_SIZE); */
+
+ while (global_pos + buffer_pos < header.dst_size) {
+ int pos_state = (buffer_pos + global_pos) & pos_state_mask;
+
+ prob = p + LZMA_IS_MATCH + (state << LZMA_NUM_POS_BITS_MAX) + pos_state;
+ if (rc_is_bit_0(rc, prob)) {
+ mi = 1;
+ rc_update_bit_0(rc, prob);
+ prob = (p + LZMA_LITERAL
+ + (LZMA_LIT_SIZE * ((((buffer_pos + global_pos) & literal_pos_mask) << lc)
+ + (previous_byte >> (8 - lc))
+ )
+ )
+ );
+
+ if (state >= LZMA_NUM_LIT_STATES) {
+ int match_byte;
+
+ pos = buffer_pos - rep0;
+ while (pos >= header.dict_size)
+ pos += header.dict_size;
+ match_byte = buffer[pos];
+ do {
+ int bit;
+
+ match_byte <<= 1;
+ bit = match_byte & 0x100;
+ prob_lit = prob + 0x100 + bit + mi;
+ bit ^= (rc_get_bit(rc, prob_lit, &mi) << 8); /* 0x100 or 0 */
+ if (bit)
+ break;
+ } while (mi < 0x100);
+ }
+ while (mi < 0x100) {
+ prob_lit = prob + mi;
+ rc_get_bit(rc, prob_lit, &mi);
+ }
+
+ state -= 3;
+ if (state < 4-3)
+ state = 0;
+ if (state >= 10-3)
+ state -= 6-3;
+
+ previous_byte = (uint8_t) mi;
+#if ENABLE_FEATURE_LZMA_FAST
+ one_byte1:
+ buffer[buffer_pos++] = previous_byte;
+ if (buffer_pos == header.dict_size) {
+ buffer_pos = 0;
+ global_pos += header.dict_size;
+ if (full_write(dst_fd, buffer, header.dict_size) != (ssize_t)header.dict_size)
+ goto bad;
+ USE_DESKTOP(total_written += header.dict_size;)
+ }
+#else
+ len = 1;
+ goto one_byte2;
+#endif
+ } else {
+ int offset;
+ uint16_t *prob_len;
+
+ rc_update_bit_1(rc, prob);
+ prob = p + LZMA_IS_REP + state;
+ if (rc_is_bit_0(rc, prob)) {
+ rc_update_bit_0(rc, prob);
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ state = state < LZMA_NUM_LIT_STATES ? 0 : 3;
+ prob = p + LZMA_LEN_CODER;
+ } else {
+ rc_update_bit_1(rc, prob);
+ prob = p + LZMA_IS_REP_G0 + state;
+ if (rc_is_bit_0(rc, prob)) {
+ rc_update_bit_0(rc, prob);
+ prob = (p + LZMA_IS_REP_0_LONG
+ + (state << LZMA_NUM_POS_BITS_MAX)
+ + pos_state
+ );
+ if (rc_is_bit_0(rc, prob)) {
+ rc_update_bit_0(rc, prob);
+
+ state = state < LZMA_NUM_LIT_STATES ? 9 : 11;
+#if ENABLE_FEATURE_LZMA_FAST
+ pos = buffer_pos - rep0;
+ while (pos >= header.dict_size)
+ pos += header.dict_size;
+ previous_byte = buffer[pos];
+ goto one_byte1;
+#else
+ len = 1;
+ goto string;
+#endif
+ } else {
+ rc_update_bit_1(rc, prob);
+ }
+ } else {
+ uint32_t distance;
+
+ rc_update_bit_1(rc, prob);
+ prob = p + LZMA_IS_REP_G1 + state;
+ if (rc_is_bit_0(rc, prob)) {
+ rc_update_bit_0(rc, prob);
+ distance = rep1;
+ } else {
+ rc_update_bit_1(rc, prob);
+ prob = p + LZMA_IS_REP_G2 + state;
+ if (rc_is_bit_0(rc, prob)) {
+ rc_update_bit_0(rc, prob);
+ distance = rep2;
+ } else {
+ rc_update_bit_1(rc, prob);
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ state = state < LZMA_NUM_LIT_STATES ? 8 : 11;
+ prob = p + LZMA_REP_LEN_CODER;
+ }
+
+ prob_len = prob + LZMA_LEN_CHOICE;
+ if (rc_is_bit_0(rc, prob_len)) {
+ rc_update_bit_0(rc, prob_len);
+ prob_len = (prob + LZMA_LEN_LOW
+ + (pos_state << LZMA_LEN_NUM_LOW_BITS));
+ offset = 0;
+ num_bits = LZMA_LEN_NUM_LOW_BITS;
+ } else {
+ rc_update_bit_1(rc, prob_len);
+ prob_len = prob + LZMA_LEN_CHOICE_2;
+ if (rc_is_bit_0(rc, prob_len)) {
+ rc_update_bit_0(rc, prob_len);
+ prob_len = (prob + LZMA_LEN_MID
+ + (pos_state << LZMA_LEN_NUM_MID_BITS));
+ offset = 1 << LZMA_LEN_NUM_LOW_BITS;
+ num_bits = LZMA_LEN_NUM_MID_BITS;
+ } else {
+ rc_update_bit_1(rc, prob_len);
+ prob_len = prob + LZMA_LEN_HIGH;
+ offset = ((1 << LZMA_LEN_NUM_LOW_BITS)
+ + (1 << LZMA_LEN_NUM_MID_BITS));
+ num_bits = LZMA_LEN_NUM_HIGH_BITS;
+ }
+ }
+ rc_bit_tree_decode(rc, prob_len, num_bits, &len);
+ len += offset;
+
+ if (state < 4) {
+ int pos_slot;
+
+ state += LZMA_NUM_LIT_STATES;
+ prob = p + LZMA_POS_SLOT +
+ ((len < LZMA_NUM_LEN_TO_POS_STATES ? len :
+ LZMA_NUM_LEN_TO_POS_STATES - 1)
+ << LZMA_NUM_POS_SLOT_BITS);
+ rc_bit_tree_decode(rc, prob, LZMA_NUM_POS_SLOT_BITS,
+ &pos_slot);
+ if (pos_slot >= LZMA_START_POS_MODEL_INDEX) {
+ num_bits = (pos_slot >> 1) - 1;
+ rep0 = 2 | (pos_slot & 1);
+ if (pos_slot < LZMA_END_POS_MODEL_INDEX) {
+ rep0 <<= num_bits;
+ prob = p + LZMA_SPEC_POS + rep0 - pos_slot - 1;
+ } else {
+ num_bits -= LZMA_NUM_ALIGN_BITS;
+ while (num_bits--)
+ rep0 = (rep0 << 1) | rc_direct_bit(rc);
+ prob = p + LZMA_ALIGN;
+ rep0 <<= LZMA_NUM_ALIGN_BITS;
+ num_bits = LZMA_NUM_ALIGN_BITS;
+ }
+ i = 1;
+ mi = 1;
+ while (num_bits--) {
+ if (rc_get_bit(rc, prob + mi, &mi))
+ rep0 |= i;
+ i <<= 1;
+ }
+ } else
+ rep0 = pos_slot;
+ if (++rep0 == 0)
+ break;
+ }
+
+ len += LZMA_MATCH_MIN_LEN;
+ SKIP_FEATURE_LZMA_FAST(string:)
+ do {
+ pos = buffer_pos - rep0;
+ while (pos >= header.dict_size)
+ pos += header.dict_size;
+ previous_byte = buffer[pos];
+ SKIP_FEATURE_LZMA_FAST(one_byte2:)
+ buffer[buffer_pos++] = previous_byte;
+ if (buffer_pos == header.dict_size) {
+ buffer_pos = 0;
+ global_pos += header.dict_size;
+ if (full_write(dst_fd, buffer, header.dict_size) != (ssize_t)header.dict_size)
+ goto bad;
+ USE_DESKTOP(total_written += header.dict_size;)
+ }
+ len--;
+ } while (len != 0 && buffer_pos < header.dst_size);
+ }
+ }
+
+ if (full_write(dst_fd, buffer, buffer_pos) != (ssize_t)buffer_pos) {
+ bad:
+ rc_free(rc);
+ return -1;
+ }
+ rc_free(rc);
+ USE_DESKTOP(total_written += buffer_pos;)
+ return USE_DESKTOP(total_written) + 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/decompress_unzip.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/decompress_unzip.c
new file mode 100644
index 0000000000..9036fabf23
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/decompress_unzip.c
@@ -0,0 +1,1241 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * gunzip implementation for busybox
+ *
+ * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly.
+ *
+ * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
+ * based on gzip sources
+ *
+ * Adjusted further by Erik Andersen <andersen@codepoet.org> to support
+ * files as well as stdin/stdout, and to generally behave itself wrt
+ * command line handling.
+ *
+ * General cleanup to better adhere to the style guide and make use of standard
+ * busybox functions by Glenn McGrath
+ *
+ * read_gz interface + associated hacking by Laurence Anderson
+ *
+ * Fixed huft_build() so decoding end-of-block code does not grab more bits
+ * than necessary (this is required by unzip applet), added inflate_cleanup()
+ * to free leaked bytebuffer memory (used in unzip.c), and some minor style
+ * guide cleanups by Ed Clark
+ *
+ * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * The unzip code was written and put in the public domain by Mark Adler.
+ * Portions of the lzw code are derived from the public domain 'compress'
+ * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
+ * Ken Turkowski, Dave Mack and Peter Jannesen.
+ *
+ * See the file algorithm.doc for the compression algorithms and file formats.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include <setjmp.h>
+#include "libbb.h"
+#include "unarchive.h"
+
+typedef struct huft_t {
+ unsigned char e; /* number of extra bits or operation */
+ unsigned char b; /* number of bits in this code or subcode */
+ union {
+ unsigned short n; /* literal, length base, or distance base */
+ struct huft_t *t; /* pointer to next level of table */
+ } v;
+} huft_t;
+
+enum {
+ /* gunzip_window size--must be a power of two, and
+ * at least 32K for zip's deflate method */
+ GUNZIP_WSIZE = 0x8000,
+ /* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
+ BMAX = 16, /* maximum bit length of any code (16 for explode) */
+ N_MAX = 288, /* maximum number of codes in any set */
+};
+
+
+/* This is somewhat complex-looking arrangement, but it allows
+ * to place decompressor state either in bss or in
+ * malloc'ed space simply by changing #defines below.
+ * Sizes on i386:
+ * text data bss dec hex
+ * 5256 0 108 5364 14f4 - bss
+ * 4915 0 0 4915 1333 - malloc
+ */
+#define STATE_IN_BSS 0
+#define STATE_IN_MALLOC 1
+
+
+typedef struct state_t {
+ off_t gunzip_bytes_out; /* number of output bytes */
+ uint32_t gunzip_crc;
+
+ int gunzip_src_fd;
+ unsigned gunzip_outbuf_count; /* bytes in output buffer */
+
+ unsigned char *gunzip_window;
+
+ uint32_t *gunzip_crc_table;
+
+ /* bitbuffer */
+ unsigned gunzip_bb; /* bit buffer */
+ unsigned char gunzip_bk; /* bits in bit buffer */
+
+ /* input (compressed) data */
+ unsigned char *bytebuffer; /* buffer itself */
+ off_t to_read; /* compressed bytes to read (unzip only, -1 for gunzip) */
+// unsigned bytebuffer_max; /* buffer size */
+ unsigned bytebuffer_offset; /* buffer position */
+ unsigned bytebuffer_size; /* how much data is there (size <= max) */
+
+ /* private data of inflate_codes() */
+ unsigned inflate_codes_ml; /* masks for bl and bd bits */
+ unsigned inflate_codes_md; /* masks for bl and bd bits */
+ unsigned inflate_codes_bb; /* bit buffer */
+ unsigned inflate_codes_k; /* number of bits in bit buffer */
+ unsigned inflate_codes_w; /* current gunzip_window position */
+ huft_t *inflate_codes_tl;
+ huft_t *inflate_codes_td;
+ unsigned inflate_codes_bl;
+ unsigned inflate_codes_bd;
+ unsigned inflate_codes_nn; /* length and index for copy */
+ unsigned inflate_codes_dd;
+
+ smallint resume_copy;
+
+ /* private data of inflate_get_next_window() */
+ smallint method; /* method == -1 for stored, -2 for codes */
+ smallint need_another_block;
+ smallint end_reached;
+
+ /* private data of inflate_stored() */
+ unsigned inflate_stored_n;
+ unsigned inflate_stored_b;
+ unsigned inflate_stored_k;
+ unsigned inflate_stored_w;
+
+ const char *error_msg;
+ jmp_buf error_jmp;
+} state_t;
+#define gunzip_bytes_out (S()gunzip_bytes_out )
+#define gunzip_crc (S()gunzip_crc )
+#define gunzip_src_fd (S()gunzip_src_fd )
+#define gunzip_outbuf_count (S()gunzip_outbuf_count)
+#define gunzip_window (S()gunzip_window )
+#define gunzip_crc_table (S()gunzip_crc_table )
+#define gunzip_bb (S()gunzip_bb )
+#define gunzip_bk (S()gunzip_bk )
+#define to_read (S()to_read )
+// #define bytebuffer_max (S()bytebuffer_max )
+// Both gunzip and unzip can use constant buffer size now (16k):
+#define bytebuffer_max 0x4000
+#define bytebuffer (S()bytebuffer )
+#define bytebuffer_offset (S()bytebuffer_offset )
+#define bytebuffer_size (S()bytebuffer_size )
+#define inflate_codes_ml (S()inflate_codes_ml )
+#define inflate_codes_md (S()inflate_codes_md )
+#define inflate_codes_bb (S()inflate_codes_bb )
+#define inflate_codes_k (S()inflate_codes_k )
+#define inflate_codes_w (S()inflate_codes_w )
+#define inflate_codes_tl (S()inflate_codes_tl )
+#define inflate_codes_td (S()inflate_codes_td )
+#define inflate_codes_bl (S()inflate_codes_bl )
+#define inflate_codes_bd (S()inflate_codes_bd )
+#define inflate_codes_nn (S()inflate_codes_nn )
+#define inflate_codes_dd (S()inflate_codes_dd )
+#define resume_copy (S()resume_copy )
+#define method (S()method )
+#define need_another_block (S()need_another_block )
+#define end_reached (S()end_reached )
+#define inflate_stored_n (S()inflate_stored_n )
+#define inflate_stored_b (S()inflate_stored_b )
+#define inflate_stored_k (S()inflate_stored_k )
+#define inflate_stored_w (S()inflate_stored_w )
+#define error_msg (S()error_msg )
+#define error_jmp (S()error_jmp )
+
+/* This is a generic part */
+#if STATE_IN_BSS /* Use global data segment */
+#define DECLARE_STATE /*nothing*/
+#define ALLOC_STATE /*nothing*/
+#define DEALLOC_STATE ((void)0)
+#define S() state.
+#define PASS_STATE /*nothing*/
+#define PASS_STATE_ONLY /*nothing*/
+#define STATE_PARAM /*nothing*/
+#define STATE_PARAM_ONLY void
+static state_t state;
+#endif
+
+#if STATE_IN_MALLOC /* Use malloc space */
+#define DECLARE_STATE state_t *state
+#define ALLOC_STATE (state = xzalloc(sizeof(*state)))
+#define DEALLOC_STATE free(state)
+#define S() state->
+#define PASS_STATE state,
+#define PASS_STATE_ONLY state
+#define STATE_PARAM state_t *state,
+#define STATE_PARAM_ONLY state_t *state
+#endif
+
+
+static const uint16_t mask_bits[] ALIGN2 = {
+ 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+/* Copy lengths for literal codes 257..285 */
+static const uint16_t cplens[] ALIGN2 = {
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59,
+ 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
+};
+
+/* note: see note #13 above about the 258 in this list. */
+/* Extra bits for literal codes 257..285 */
+static const uint8_t cplext[] ALIGN1 = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5,
+ 5, 5, 5, 0, 99, 99
+}; /* 99 == invalid */
+
+/* Copy offsets for distance codes 0..29 */
+static const uint16_t cpdist[] ALIGN2 = {
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513,
+ 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577
+};
+
+/* Extra bits for distance codes */
+static const uint8_t cpdext[] ALIGN1 = {
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10,
+ 11, 11, 12, 12, 13, 13
+};
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+/* Order of the bit length code lengths */
+static const uint8_t border[] ALIGN1 = {
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
+};
+
+
+/*
+ * Free the malloc'ed tables built by huft_build(), which makes a linked
+ * list of the tables it made, with the links in a dummy first entry of
+ * each table.
+ * t: table to free
+ */
+static void huft_free(huft_t *p)
+{
+ huft_t *q;
+
+ /* Go through linked list, freeing from the malloced (t[-1]) address. */
+ while (p) {
+ q = (--p)->v.t;
+ free(p);
+ p = q;
+ }
+}
+
+static void huft_free_all(STATE_PARAM_ONLY)
+{
+ huft_free(inflate_codes_tl);
+ huft_free(inflate_codes_td);
+ inflate_codes_tl = NULL;
+ inflate_codes_td = NULL;
+}
+
+static void abort_unzip(STATE_PARAM_ONLY) ATTRIBUTE_NORETURN;
+static void abort_unzip(STATE_PARAM_ONLY)
+{
+ huft_free_all(PASS_STATE_ONLY);
+ longjmp(error_jmp, 1);
+}
+
+static unsigned fill_bitbuffer(STATE_PARAM unsigned bitbuffer, unsigned *current, const unsigned required)
+{
+ while (*current < required) {
+ if (bytebuffer_offset >= bytebuffer_size) {
+ unsigned sz = bytebuffer_max - 4;
+ if (to_read >= 0 && to_read < sz) /* unzip only */
+ sz = to_read;
+ /* Leave the first 4 bytes empty so we can always unwind the bitbuffer
+ * to the front of the bytebuffer */
+ bytebuffer_size = safe_read(gunzip_src_fd, &bytebuffer[4], sz);
+ if ((int)bytebuffer_size < 1) {
+ error_msg = "unexpected end of file";
+ abort_unzip(PASS_STATE_ONLY);
+ }
+ if (to_read >= 0) /* unzip only */
+ to_read -= bytebuffer_size;
+ bytebuffer_size += 4;
+ bytebuffer_offset = 4;
+ }
+ bitbuffer |= ((unsigned) bytebuffer[bytebuffer_offset]) << *current;
+ bytebuffer_offset++;
+ *current += 8;
+ }
+ return bitbuffer;
+}
+
+
+/* Given a list of code lengths and a maximum table size, make a set of
+ * tables to decode that set of codes. Return zero on success, one if
+ * the given code set is incomplete (the tables are still built in this
+ * case), two if the input is invalid (all zero length codes or an
+ * oversubscribed set of lengths) - in this case stores NULL in *t.
+ *
+ * b: code lengths in bits (all assumed <= BMAX)
+ * n: number of codes (assumed <= N_MAX)
+ * s: number of simple-valued codes (0..s-1)
+ * d: list of base values for non-simple codes
+ * e: list of extra bits for non-simple codes
+ * t: result: starting table
+ * m: maximum lookup bits, returns actual
+ */
+static int huft_build(const unsigned *b, const unsigned n,
+ const unsigned s, const unsigned short *d,
+ const unsigned char *e, huft_t **t, unsigned *m)
+{
+ unsigned a; /* counter for codes of length k */
+ unsigned c[BMAX + 1]; /* bit length count table */
+ unsigned eob_len; /* length of end-of-block code (value 256) */
+ unsigned f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int htl; /* table level */
+ unsigned i; /* counter, current code */
+ unsigned j; /* counter */
+ int k; /* number of bits in current code */
+ unsigned *p; /* pointer into c[], b[], or v[] */
+ huft_t *q; /* points to current table */
+ huft_t r; /* table entry for structure assignment */
+ huft_t *u[BMAX]; /* table stack */
+ unsigned v[N_MAX]; /* values in order of bit length */
+ int ws[BMAX + 1]; /* bits decoded stack */
+ int w; /* bits decoded */
+ unsigned x[BMAX + 1]; /* bit offsets, then code stack */
+ unsigned *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ unsigned z; /* number of entries in current table */
+
+ /* Length of EOB code, if any */
+ eob_len = n > 256 ? b[256] : BMAX;
+
+ *t = NULL;
+
+ /* Generate counts for each bit length */
+ memset(c, 0, sizeof(c));
+ p = (unsigned *) b; /* cast allows us to reuse p for pointing to b */
+ i = n;
+ do {
+ c[*p]++; /* assume all entries <= BMAX */
+ p++; /* can't combine with above line (Solaris bug) */
+ } while (--i);
+ if (c[0] == n) { /* null input - all zero length codes */
+ *m = 0;
+ return 2;
+ }
+
+ /* Find minimum and maximum length, bound *m by those */
+ for (j = 1; (c[j] == 0) && (j <= BMAX); j++)
+ continue;
+ k = j; /* minimum code length */
+ for (i = BMAX; (c[i] == 0) && i; i--)
+ continue;
+ g = i; /* maximum code length */
+ *m = (*m < j) ? j : ((*m > i) ? i : *m);
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1) {
+ y -= c[j];
+ if (y < 0)
+ return 2; /* bad input: more codes than bits */
+ }
+ y -= c[i];
+ if (y < 0)
+ return 2;
+ c[i] += y;
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1;
+ xp = x + 2;
+ while (--i) { /* note that i == g from above */
+ j += *p++;
+ *xp++ = j;
+ }
+
+ /* Make a table of values in order of bit lengths */
+ p = (unsigned *) b;
+ i = 0;
+ do {
+ j = *p++;
+ if (j != 0) {
+ v[x[j]++] = i;
+ }
+ } while (++i < n);
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ htl = -1; /* no tables yet--level -1 */
+ w = ws[0] = 0; /* bits decoded */
+ u[0] = NULL; /* just to keep compilers happy */
+ q = NULL; /* ditto */
+ z = 0; /* ditto */
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++) {
+ a = c[k];
+ while (a--) {
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > ws[htl + 1]) {
+ w = ws[++htl];
+
+ /* compute minimum size table less than or equal to *m bits */
+ z = g - w;
+ z = z > *m ? *m : z; /* upper limit on table size */
+ j = k - w;
+ f = 1 << j;
+ if (f > a + 1) { /* try a k-w bit table */
+ /* too few codes for k-w bit table */
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ while (++j < z) { /* try smaller tables up to z bits */
+ f <<= 1;
+ if (f <= *++xp) {
+ break; /* enough codes to use up j bits */
+ }
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+ j = (w + j > eob_len && w < eob_len) ? eob_len - w : j; /* make EOB code end at table */
+ z = 1 << j; /* table entries for j-bit table */
+ ws[htl+1] = w + j; /* set bits decoded in stack */
+
+ /* allocate and link in new table */
+ q = xzalloc((z + 1) * sizeof(huft_t));
+ *t = q + 1; /* link to list for huft_free() */
+ t = &(q->v.t);
+ u[htl] = ++q; /* table starts after link */
+
+ /* connect to last table, if there is one */
+ if (htl) {
+ x[htl] = i; /* save pattern for backing up */
+ r.b = (unsigned char) (w - ws[htl - 1]); /* bits to dump before this table */
+ r.e = (unsigned char) (16 + j); /* bits in this table */
+ r.v.t = q; /* pointer to this table */
+ j = (i & ((1 << w) - 1)) >> ws[htl - 1];
+ u[htl - 1][j] = r; /* connect to last table */
+ }
+ }
+
+ /* set up table entry in r */
+ r.b = (unsigned char) (k - w);
+ if (p >= v + n) {
+ r.e = 99; /* out of values--invalid code */
+ } else if (*p < s) {
+ r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is EOB code */
+ r.v.n = (unsigned short) (*p++); /* simple code is just the value */
+ } else {
+ r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */
+ r.v.n = d[*p++ - s];
+ }
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f) {
+ q[j] = r;
+ }
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1) {
+ i ^= j;
+ }
+ i ^= j;
+
+ /* backup over finished tables */
+ while ((i & ((1 << w) - 1)) != x[htl]) {
+ w = ws[--htl];
+ }
+ }
+ }
+
+ /* return actual size of base table */
+ *m = ws[1];
+
+ /* Return 1 if we were given an incomplete table */
+ return y != 0 && g != 1;
+}
+
+
+/*
+ * inflate (decompress) the codes in a deflated (compressed) block.
+ * Return an error code or zero if it all goes ok.
+ *
+ * tl, td: literal/length and distance decoder tables
+ * bl, bd: number of bits decoded by tl[] and td[]
+ */
+/* called once from inflate_block */
+
+/* map formerly local static variables to globals */
+#define ml inflate_codes_ml
+#define md inflate_codes_md
+#define bb inflate_codes_bb
+#define k inflate_codes_k
+#define w inflate_codes_w
+#define tl inflate_codes_tl
+#define td inflate_codes_td
+#define bl inflate_codes_bl
+#define bd inflate_codes_bd
+#define nn inflate_codes_nn
+#define dd inflate_codes_dd
+static void inflate_codes_setup(STATE_PARAM unsigned my_bl, unsigned my_bd)
+{
+ bl = my_bl;
+ bd = my_bd;
+ /* make local copies of globals */
+ bb = gunzip_bb; /* initialize bit buffer */
+ k = gunzip_bk;
+ w = gunzip_outbuf_count; /* initialize gunzip_window position */
+ /* inflate the coded data */
+ ml = mask_bits[bl]; /* precompute masks for speed */
+ md = mask_bits[bd];
+}
+/* called once from inflate_get_next_window */
+static int inflate_codes(STATE_PARAM_ONLY)
+{
+ unsigned e; /* table entry flag/number of extra bits */
+ huft_t *t; /* pointer to table entry */
+
+ if (resume_copy)
+ goto do_copy;
+
+ while (1) { /* do until end of block */
+ bb = fill_bitbuffer(PASS_STATE bb, &k, bl);
+ t = tl + ((unsigned) bb & ml);
+ e = t->e;
+ if (e > 16)
+ do {
+ if (e == 99)
+ abort_unzip(PASS_STATE_ONLY);;
+ bb >>= t->b;
+ k -= t->b;
+ e -= 16;
+ bb = fill_bitbuffer(PASS_STATE bb, &k, e);
+ t = t->v.t + ((unsigned) bb & mask_bits[e]);
+ e = t->e;
+ } while (e > 16);
+ bb >>= t->b;
+ k -= t->b;
+ if (e == 16) { /* then it's a literal */
+ gunzip_window[w++] = (unsigned char) t->v.n;
+ if (w == GUNZIP_WSIZE) {
+ gunzip_outbuf_count = w;
+ //flush_gunzip_window();
+ w = 0;
+ return 1; // We have a block to read
+ }
+ } else { /* it's an EOB or a length */
+ /* exit if end of block */
+ if (e == 15) {
+ break;
+ }
+
+ /* get length of block to copy */
+ bb = fill_bitbuffer(PASS_STATE bb, &k, e);
+ nn = t->v.n + ((unsigned) bb & mask_bits[e]);
+ bb >>= e;
+ k -= e;
+
+ /* decode distance of block to copy */
+ bb = fill_bitbuffer(PASS_STATE bb, &k, bd);
+ t = td + ((unsigned) bb & md);
+ e = t->e;
+ if (e > 16)
+ do {
+ if (e == 99)
+ abort_unzip(PASS_STATE_ONLY);
+ bb >>= t->b;
+ k -= t->b;
+ e -= 16;
+ bb = fill_bitbuffer(PASS_STATE bb, &k, e);
+ t = t->v.t + ((unsigned) bb & mask_bits[e]);
+ e = t->e;
+ } while (e > 16);
+ bb >>= t->b;
+ k -= t->b;
+ bb = fill_bitbuffer(PASS_STATE bb, &k, e);
+ dd = w - t->v.n - ((unsigned) bb & mask_bits[e]);
+ bb >>= e;
+ k -= e;
+
+ /* do the copy */
+ do_copy:
+ do {
+ /* Was: nn -= (e = (e = GUNZIP_WSIZE - ((dd &= GUNZIP_WSIZE - 1) > w ? dd : w)) > nn ? nn : e); */
+ /* Who wrote THAT?? rewritten as: */
+ dd &= GUNZIP_WSIZE - 1;
+ e = GUNZIP_WSIZE - (dd > w ? dd : w);
+ if (e > nn) e = nn;
+ nn -= e;
+
+ /* copy to new buffer to prevent possible overwrite */
+ if (w - dd >= e) { /* (this test assumes unsigned comparison) */
+ memcpy(gunzip_window + w, gunzip_window + dd, e);
+ w += e;
+ dd += e;
+ } else {
+ /* do it slow to avoid memcpy() overlap */
+ /* !NOMEMCPY */
+ do {
+ gunzip_window[w++] = gunzip_window[dd++];
+ } while (--e);
+ }
+ if (w == GUNZIP_WSIZE) {
+ gunzip_outbuf_count = w;
+ resume_copy = (nn != 0);
+ //flush_gunzip_window();
+ w = 0;
+ return 1;
+ }
+ } while (nn);
+ resume_copy = 0;
+ }
+ }
+
+ /* restore the globals from the locals */
+ gunzip_outbuf_count = w; /* restore global gunzip_window pointer */
+ gunzip_bb = bb; /* restore global bit buffer */
+ gunzip_bk = k;
+
+ /* normally just after call to inflate_codes, but save code by putting it here */
+ /* free the decoding tables (tl and td), return */
+ huft_free_all(PASS_STATE_ONLY);
+
+ /* done */
+ return 0;
+}
+#undef ml
+#undef md
+#undef bb
+#undef k
+#undef w
+#undef tl
+#undef td
+#undef bl
+#undef bd
+#undef nn
+#undef dd
+
+
+/* called once from inflate_block */
+static void inflate_stored_setup(STATE_PARAM int my_n, int my_b, int my_k)
+{
+ inflate_stored_n = my_n;
+ inflate_stored_b = my_b;
+ inflate_stored_k = my_k;
+ /* initialize gunzip_window position */
+ inflate_stored_w = gunzip_outbuf_count;
+}
+/* called once from inflate_get_next_window */
+static int inflate_stored(STATE_PARAM_ONLY)
+{
+ /* read and output the compressed data */
+ while (inflate_stored_n--) {
+ inflate_stored_b = fill_bitbuffer(PASS_STATE inflate_stored_b, &inflate_stored_k, 8);
+ gunzip_window[inflate_stored_w++] = (unsigned char) inflate_stored_b;
+ if (inflate_stored_w == GUNZIP_WSIZE) {
+ gunzip_outbuf_count = inflate_stored_w;
+ //flush_gunzip_window();
+ inflate_stored_w = 0;
+ inflate_stored_b >>= 8;
+ inflate_stored_k -= 8;
+ return 1; /* We have a block */
+ }
+ inflate_stored_b >>= 8;
+ inflate_stored_k -= 8;
+ }
+
+ /* restore the globals from the locals */
+ gunzip_outbuf_count = inflate_stored_w; /* restore global gunzip_window pointer */
+ gunzip_bb = inflate_stored_b; /* restore global bit buffer */
+ gunzip_bk = inflate_stored_k;
+ return 0; /* Finished */
+}
+
+
+/*
+ * decompress an inflated block
+ * e: last block flag
+ *
+ * GLOBAL VARIABLES: bb, kk,
+ */
+/* Return values: -1 = inflate_stored, -2 = inflate_codes */
+/* One callsite in inflate_get_next_window */
+static int inflate_block(STATE_PARAM smallint *e)
+{
+ unsigned ll[286 + 30]; /* literal/length and distance code lengths */
+ unsigned t; /* block type */
+ unsigned b; /* bit buffer */
+ unsigned k; /* number of bits in bit buffer */
+
+ /* make local bit buffer */
+
+ b = gunzip_bb;
+ k = gunzip_bk;
+
+ /* read in last block bit */
+ b = fill_bitbuffer(PASS_STATE b, &k, 1);
+ *e = b & 1;
+ b >>= 1;
+ k -= 1;
+
+ /* read in block type */
+ b = fill_bitbuffer(PASS_STATE b, &k, 2);
+ t = (unsigned) b & 3;
+ b >>= 2;
+ k -= 2;
+
+ /* restore the global bit buffer */
+ gunzip_bb = b;
+ gunzip_bk = k;
+
+ /* Do we see block type 1 often? Yes!
+ * TODO: fix performance problem (see below) */
+ //bb_error_msg("blktype %d", t);
+
+ /* inflate that block type */
+ switch (t) {
+ case 0: /* Inflate stored */
+ {
+ unsigned n; /* number of bytes in block */
+ unsigned b_stored; /* bit buffer */
+ unsigned k_stored; /* number of bits in bit buffer */
+
+ /* make local copies of globals */
+ b_stored = gunzip_bb; /* initialize bit buffer */
+ k_stored = gunzip_bk;
+
+ /* go to byte boundary */
+ n = k_stored & 7;
+ b_stored >>= n;
+ k_stored -= n;
+
+ /* get the length and its complement */
+ b_stored = fill_bitbuffer(PASS_STATE b_stored, &k_stored, 16);
+ n = ((unsigned) b_stored & 0xffff);
+ b_stored >>= 16;
+ k_stored -= 16;
+
+ b_stored = fill_bitbuffer(PASS_STATE b_stored, &k_stored, 16);
+ if (n != (unsigned) ((~b_stored) & 0xffff)) {
+ abort_unzip(PASS_STATE_ONLY); /* error in compressed data */
+ }
+ b_stored >>= 16;
+ k_stored -= 16;
+
+ inflate_stored_setup(PASS_STATE n, b_stored, k_stored);
+
+ return -1;
+ }
+ case 1:
+ /* Inflate fixed
+ * decompress an inflated type 1 (fixed Huffman codes) block. We should
+ * either replace this with a custom decoder, or at least precompute the
+ * Huffman tables. TODO */
+ {
+ int i; /* temporary variable */
+ unsigned bl; /* lookup bits for tl */
+ unsigned bd; /* lookup bits for td */
+ /* gcc 4.2.1 is too dumb to reuse stackspace. Moved up... */
+ //unsigned ll[288]; /* length list for huft_build */
+
+ /* set up literal table */
+ for (i = 0; i < 144; i++)
+ ll[i] = 8;
+ for (; i < 256; i++)
+ ll[i] = 9;
+ for (; i < 280; i++)
+ ll[i] = 7;
+ for (; i < 288; i++) /* make a complete, but wrong code set */
+ ll[i] = 8;
+ bl = 7;
+ huft_build(ll, 288, 257, cplens, cplext, &inflate_codes_tl, &bl);
+ /* huft_build() never return nonzero - we use known data */
+
+ /* set up distance table */
+ for (i = 0; i < 30; i++) /* make an incomplete code set */
+ ll[i] = 5;
+ bd = 5;
+ huft_build(ll, 30, 0, cpdist, cpdext, &inflate_codes_td, &bd);
+
+ /* set up data for inflate_codes() */
+ inflate_codes_setup(PASS_STATE bl, bd);
+
+ /* huft_free code moved into inflate_codes */
+
+ return -2;
+ }
+ case 2: /* Inflate dynamic */
+ {
+ enum { dbits = 6 }; /* bits in base distance lookup table */
+ enum { lbits = 9 }; /* bits in base literal/length lookup table */
+
+ huft_t *td; /* distance code table */
+ unsigned i; /* temporary variables */
+ unsigned j;
+ unsigned l; /* last length */
+ unsigned m; /* mask for bit lengths table */
+ unsigned n; /* number of lengths to get */
+ unsigned bl; /* lookup bits for tl */
+ unsigned bd; /* lookup bits for td */
+ unsigned nb; /* number of bit length codes */
+ unsigned nl; /* number of literal/length codes */
+ unsigned nd; /* number of distance codes */
+
+ //unsigned ll[286 + 30];/* literal/length and distance code lengths */
+ unsigned b_dynamic; /* bit buffer */
+ unsigned k_dynamic; /* number of bits in bit buffer */
+
+ /* make local bit buffer */
+ b_dynamic = gunzip_bb;
+ k_dynamic = gunzip_bk;
+
+ /* read in table lengths */
+ b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 5);
+ nl = 257 + ((unsigned) b_dynamic & 0x1f); /* number of literal/length codes */
+
+ b_dynamic >>= 5;
+ k_dynamic -= 5;
+ b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 5);
+ nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */
+
+ b_dynamic >>= 5;
+ k_dynamic -= 5;
+ b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 4);
+ nb = 4 + ((unsigned) b_dynamic & 0xf); /* number of bit length codes */
+
+ b_dynamic >>= 4;
+ k_dynamic -= 4;
+ if (nl > 286 || nd > 30)
+ abort_unzip(PASS_STATE_ONLY); /* bad lengths */
+
+ /* read in bit-length-code lengths */
+ for (j = 0; j < nb; j++) {
+ b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 3);
+ ll[border[j]] = (unsigned) b_dynamic & 7;
+ b_dynamic >>= 3;
+ k_dynamic -= 3;
+ }
+ for (; j < 19; j++)
+ ll[border[j]] = 0;
+
+ /* build decoding table for trees - single level, 7 bit lookup */
+ bl = 7;
+ i = huft_build(ll, 19, 19, NULL, NULL, &inflate_codes_tl, &bl);
+ if (i != 0) {
+ abort_unzip(PASS_STATE_ONLY); //return i; /* incomplete code set */
+ }
+
+ /* read in literal and distance code lengths */
+ n = nl + nd;
+ m = mask_bits[bl];
+ i = l = 0;
+ while ((unsigned) i < n) {
+ b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, (unsigned)bl);
+ td = inflate_codes_tl + ((unsigned) b_dynamic & m);
+ j = td->b;
+ b_dynamic >>= j;
+ k_dynamic -= j;
+ j = td->v.n;
+ if (j < 16) { /* length of code in bits (0..15) */
+ ll[i++] = l = j; /* save last length in l */
+ } else if (j == 16) { /* repeat last length 3 to 6 times */
+ b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 2);
+ j = 3 + ((unsigned) b_dynamic & 3);
+ b_dynamic >>= 2;
+ k_dynamic -= 2;
+ if ((unsigned) i + j > n) {
+ abort_unzip(PASS_STATE_ONLY); //return 1;
+ }
+ while (j--) {
+ ll[i++] = l;
+ }
+ } else if (j == 17) { /* 3 to 10 zero length codes */
+ b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 3);
+ j = 3 + ((unsigned) b_dynamic & 7);
+ b_dynamic >>= 3;
+ k_dynamic -= 3;
+ if ((unsigned) i + j > n) {
+ abort_unzip(PASS_STATE_ONLY); //return 1;
+ }
+ while (j--) {
+ ll[i++] = 0;
+ }
+ l = 0;
+ } else { /* j == 18: 11 to 138 zero length codes */
+ b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 7);
+ j = 11 + ((unsigned) b_dynamic & 0x7f);
+ b_dynamic >>= 7;
+ k_dynamic -= 7;
+ if ((unsigned) i + j > n) {
+ abort_unzip(PASS_STATE_ONLY); //return 1;
+ }
+ while (j--) {
+ ll[i++] = 0;
+ }
+ l = 0;
+ }
+ }
+
+ /* free decoding table for trees */
+ huft_free(inflate_codes_tl);
+
+ /* restore the global bit buffer */
+ gunzip_bb = b_dynamic;
+ gunzip_bk = k_dynamic;
+
+ /* build the decoding tables for literal/length and distance codes */
+ bl = lbits;
+
+ i = huft_build(ll, nl, 257, cplens, cplext, &inflate_codes_tl, &bl);
+ if (i != 0)
+ abort_unzip(PASS_STATE_ONLY);
+ bd = dbits;
+ i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &inflate_codes_td, &bd);
+ if (i != 0)
+ abort_unzip(PASS_STATE_ONLY);
+
+ /* set up data for inflate_codes() */
+ inflate_codes_setup(PASS_STATE bl, bd);
+
+ /* huft_free code moved into inflate_codes */
+
+ return -2;
+ }
+ default:
+ abort_unzip(PASS_STATE_ONLY);
+ }
+}
+
+/* Two callsites, both in inflate_get_next_window */
+static void calculate_gunzip_crc(STATE_PARAM_ONLY)
+{
+ unsigned n;
+ for (n = 0; n < gunzip_outbuf_count; n++) {
+ gunzip_crc = gunzip_crc_table[((int) gunzip_crc ^ (gunzip_window[n])) & 0xff] ^ (gunzip_crc >> 8);
+ }
+ gunzip_bytes_out += gunzip_outbuf_count;
+}
+
+/* One callsite in inflate_unzip_internal */
+static int inflate_get_next_window(STATE_PARAM_ONLY)
+{
+ gunzip_outbuf_count = 0;
+
+ while (1) {
+ int ret;
+
+ if (need_another_block) {
+ if (end_reached) {
+ calculate_gunzip_crc(PASS_STATE_ONLY);
+ end_reached = 0;
+ /* NB: need_another_block is still set */
+ return 0; /* Last block */
+ }
+ method = inflate_block(PASS_STATE &end_reached);
+ need_another_block = 0;
+ }
+
+ switch (method) {
+ case -1:
+ ret = inflate_stored(PASS_STATE_ONLY);
+ break;
+ case -2:
+ ret = inflate_codes(PASS_STATE_ONLY);
+ break;
+ default: /* cannot happen */
+ abort_unzip(PASS_STATE_ONLY);
+ }
+
+ if (ret == 1) {
+ calculate_gunzip_crc(PASS_STATE_ONLY);
+ return 1; /* more data left */
+ }
+ need_another_block = 1; /* end of that block */
+ }
+ /* Doesnt get here */
+}
+
+
+/* Called from unpack_gz_stream() and inflate_unzip() */
+static USE_DESKTOP(long long) int
+inflate_unzip_internal(STATE_PARAM int in, int out)
+{
+ USE_DESKTOP(long long) int n = 0;
+ ssize_t nwrote;
+
+ /* Allocate all global buffers (for DYN_ALLOC option) */
+ gunzip_window = xmalloc(GUNZIP_WSIZE);
+ gunzip_outbuf_count = 0;
+ gunzip_bytes_out = 0;
+ gunzip_src_fd = in;
+
+ /* (re) initialize state */
+ method = -1;
+ need_another_block = 1;
+ resume_copy = 0;
+ gunzip_bk = 0;
+ gunzip_bb = 0;
+
+ /* Create the crc table */
+ gunzip_crc_table = crc32_filltable(NULL, 0);
+ gunzip_crc = ~0;
+
+ error_msg = "corrupted data";
+ if (setjmp(error_jmp)) {
+ /* Error from deep inside zip machinery */
+ n = -1;
+ goto ret;
+ }
+
+ while (1) {
+ int r = inflate_get_next_window(PASS_STATE_ONLY);
+ nwrote = full_write(out, gunzip_window, gunzip_outbuf_count);
+ if (nwrote != (ssize_t)gunzip_outbuf_count) {
+ bb_perror_msg("write");
+ n = -1;
+ goto ret;
+ }
+ USE_DESKTOP(n += nwrote;)
+ if (r == 0) break;
+ }
+
+ /* Store unused bytes in a global buffer so calling applets can access it */
+ if (gunzip_bk >= 8) {
+ /* Undo too much lookahead. The next read will be byte aligned
+ * so we can discard unused bits in the last meaningful byte. */
+ bytebuffer_offset--;
+ bytebuffer[bytebuffer_offset] = gunzip_bb & 0xff;
+ gunzip_bb >>= 8;
+ gunzip_bk -= 8;
+ }
+ ret:
+ /* Cleanup */
+ free(gunzip_window);
+ free(gunzip_crc_table);
+ return n;
+}
+
+
+/* External entry points */
+
+/* For unzip */
+
+USE_DESKTOP(long long) int
+inflate_unzip(inflate_unzip_result *res, off_t compr_size, int in, int out)
+{
+ USE_DESKTOP(long long) int n;
+ DECLARE_STATE;
+
+ ALLOC_STATE;
+
+ to_read = compr_size;
+// bytebuffer_max = 0x8000;
+ bytebuffer_offset = 4;
+ bytebuffer = xmalloc(bytebuffer_max);
+ n = inflate_unzip_internal(PASS_STATE in, out);
+ free(bytebuffer);
+
+ res->crc = gunzip_crc;
+ res->bytes_out = gunzip_bytes_out;
+ DEALLOC_STATE;
+ return n;
+}
+
+
+/* For gunzip */
+
+/* helpers first */
+
+/* Top up the input buffer with at least n bytes. */
+static int top_up(STATE_PARAM unsigned n)
+{
+ int count = bytebuffer_size - bytebuffer_offset;
+
+ if (count < (int)n) {
+ memmove(bytebuffer, &bytebuffer[bytebuffer_offset], count);
+ bytebuffer_offset = 0;
+ bytebuffer_size = full_read(gunzip_src_fd, &bytebuffer[count], bytebuffer_max - count);
+ if ((int)bytebuffer_size < 0) {
+ bb_error_msg("read error");
+ return 0;
+ }
+ bytebuffer_size += count;
+ if (bytebuffer_size < n)
+ return 0;
+ }
+ return 1;
+}
+
+static uint16_t buffer_read_le_u16(STATE_PARAM_ONLY)
+{
+ uint16_t res;
+#if BB_LITTLE_ENDIAN
+ /* gcc 4.2.1 is very clever */
+ memcpy(&res, &bytebuffer[bytebuffer_offset], 2);
+#else
+ res = bytebuffer[bytebuffer_offset];
+ res |= bytebuffer[bytebuffer_offset + 1] << 8;
+#endif
+ bytebuffer_offset += 2;
+ return res;
+}
+
+static uint32_t buffer_read_le_u32(STATE_PARAM_ONLY)
+{
+ uint32_t res;
+#if BB_LITTLE_ENDIAN
+ memcpy(&res, &bytebuffer[bytebuffer_offset], 4);
+#else
+ res = bytebuffer[bytebuffer_offset];
+ res |= bytebuffer[bytebuffer_offset + 1] << 8;
+ res |= bytebuffer[bytebuffer_offset + 2] << 16;
+ res |= bytebuffer[bytebuffer_offset + 3] << 24;
+#endif
+ bytebuffer_offset += 4;
+ return res;
+}
+
+static int check_header_gzip(STATE_PARAM_ONLY)
+{
+ union {
+ unsigned char raw[8];
+ struct {
+ uint8_t gz_method;
+ uint8_t flags;
+ //uint32_t mtime; - unused fields
+ //uint8_t xtra_flags;
+ //uint8_t os_flags;
+ } formatted; /* packed */
+ } header;
+
+ /*
+ * Rewind bytebuffer. We use the beginning because the header has 8
+ * bytes, leaving enough for unwinding afterwards.
+ */
+ bytebuffer_size -= bytebuffer_offset;
+ memmove(bytebuffer, &bytebuffer[bytebuffer_offset], bytebuffer_size);
+ bytebuffer_offset = 0;
+
+ if (!top_up(PASS_STATE 8))
+ return 0;
+ memcpy(header.raw, &bytebuffer[bytebuffer_offset], 8);
+ bytebuffer_offset += 8;
+
+ /* Check the compression method */
+ if (header.formatted.gz_method != 8) {
+ return 0;
+ }
+
+ if (header.formatted.flags & 0x04) {
+ /* bit 2 set: extra field present */
+ unsigned extra_short;
+
+ if (!top_up(PASS_STATE 2))
+ return 0;
+ extra_short = buffer_read_le_u16(PASS_STATE_ONLY);
+ if (!top_up(PASS_STATE extra_short))
+ return 0;
+ /* Ignore extra field */
+ bytebuffer_offset += extra_short;
+ }
+
+ /* Discard original name and file comment if any */
+ /* bit 3 set: original file name present */
+ /* bit 4 set: file comment present */
+ if (header.formatted.flags & 0x18) {
+ while (1) {
+ do {
+ if (!top_up(PASS_STATE 1))
+ return 0;
+ } while (bytebuffer[bytebuffer_offset++] != 0);
+ if ((header.formatted.flags & 0x18) != 0x18)
+ break;
+ header.formatted.flags &= ~0x18;
+ }
+ }
+
+ /* Read the header checksum */
+ if (header.formatted.flags & 0x02) {
+ if (!top_up(PASS_STATE 2))
+ return 0;
+ bytebuffer_offset += 2;
+ }
+ return 1;
+}
+
+USE_DESKTOP(long long) int
+unpack_gz_stream(int in, int out)
+{
+ uint32_t v32;
+ USE_DESKTOP(long long) int n;
+ DECLARE_STATE;
+
+ n = 0;
+
+ ALLOC_STATE;
+ to_read = -1;
+// bytebuffer_max = 0x8000;
+ bytebuffer = xmalloc(bytebuffer_max);
+ gunzip_src_fd = in;
+
+ again:
+ if (!check_header_gzip(PASS_STATE_ONLY)) {
+ bb_error_msg("corrupted data");
+ n = -1;
+ goto ret;
+ }
+ n += inflate_unzip_internal(PASS_STATE in, out);
+ if (n < 0)
+ goto ret;
+
+ if (!top_up(PASS_STATE 8)) {
+ bb_error_msg("corrupted data");
+ n = -1;
+ goto ret;
+ }
+
+ /* Validate decompression - crc */
+ v32 = buffer_read_le_u32(PASS_STATE_ONLY);
+ if ((~gunzip_crc) != v32) {
+ bb_error_msg("crc error");
+ n = -1;
+ goto ret;
+ }
+
+ /* Validate decompression - size */
+ v32 = buffer_read_le_u32(PASS_STATE_ONLY);
+ if ((uint32_t)gunzip_bytes_out != v32) {
+ bb_error_msg("incorrect length");
+ n = -1;
+ }
+
+ if (!top_up(PASS_STATE 2))
+ goto ret; /* EOF */
+
+ if (bytebuffer[bytebuffer_offset] == 0x1f
+ && bytebuffer[bytebuffer_offset + 1] == 0x8b
+ ) {
+ bytebuffer_offset += 2;
+ goto again;
+ }
+ /* GNU gzip says: */
+ /*bb_error_msg("decompression OK, trailing garbage ignored");*/
+
+ ret:
+ free(bytebuffer);
+ DEALLOC_STATE;
+ return n;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/filter_accept_all.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/filter_accept_all.c
new file mode 100644
index 0000000000..47d771e432
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/filter_accept_all.c
@@ -0,0 +1,17 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2002 by Glenn McGrath
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+/* Accept any non-null name, its not really a filter at all */
+char filter_accept_all(archive_handle_t *archive_handle)
+{
+ if (archive_handle->file_header->name)
+ return EXIT_SUCCESS;
+ return EXIT_FAILURE;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/filter_accept_list.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/filter_accept_list.c
new file mode 100644
index 0000000000..6e571ad4e3
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/filter_accept_list.c
@@ -0,0 +1,19 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2002 by Glenn McGrath
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+/*
+ * Accept names that are in the accept list, ignoring reject list.
+ */
+char filter_accept_list(archive_handle_t *archive_handle)
+{
+ if (find_list_entry(archive_handle->accept, archive_handle->file_header->name))
+ return EXIT_SUCCESS;
+ return EXIT_FAILURE;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/filter_accept_list_reassign.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/filter_accept_list_reassign.c
new file mode 100644
index 0000000000..969dd1e3ef
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/filter_accept_list_reassign.c
@@ -0,0 +1,44 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2002 by Glenn McGrath
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+/*
+ * Reassign the subarchive metadata parser based on the filename extension
+ * e.g. if its a .tar.gz modify archive_handle->sub_archive to process a .tar.gz
+ * or if its a .tar.bz2 make archive_handle->sub_archive handle that
+ */
+char filter_accept_list_reassign(archive_handle_t *archive_handle)
+{
+ /* Check the file entry is in the accept list */
+ if (find_list_entry(archive_handle->accept, archive_handle->file_header->name)) {
+ const char *name_ptr;
+
+ /* Extract the last 2 extensions */
+ name_ptr = strrchr(archive_handle->file_header->name, '.');
+
+ /* Modify the subarchive handler based on the extension */
+#if ENABLE_FEATURE_DEB_TAR_GZ
+ if (strcmp(name_ptr, ".gz") == 0) {
+ archive_handle->action_data_subarchive = get_header_tar_gz;
+ return EXIT_SUCCESS;
+ }
+#endif
+#if ENABLE_FEATURE_DEB_TAR_BZ2
+ if (strcmp(name_ptr, ".bz2") == 0) {
+ archive_handle->action_data_subarchive = get_header_tar_bz2;
+ return EXIT_SUCCESS;
+ }
+#endif
+ if (ENABLE_FEATURE_DEB_TAR_LZMA && !strcmp(name_ptr, ".lzma")) {
+ archive_handle->action_data_subarchive = get_header_tar_lzma;
+ return EXIT_SUCCESS;
+ }
+ }
+ return EXIT_FAILURE;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/filter_accept_reject_list.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/filter_accept_reject_list.c
new file mode 100644
index 0000000000..439ba20cae
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/filter_accept_reject_list.c
@@ -0,0 +1,36 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2002 by Glenn McGrath
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+/*
+ * Accept names that are in the accept list and not in the reject list
+ */
+char filter_accept_reject_list(archive_handle_t *archive_handle)
+{
+ const char *key;
+ const llist_t *reject_entry;
+ const llist_t *accept_entry;
+
+ key = archive_handle->file_header->name;
+
+ /* If the key is in a reject list fail */
+ reject_entry = find_list_entry2(archive_handle->reject, key);
+ if (reject_entry) {
+ return EXIT_FAILURE;
+ }
+ accept_entry = find_list_entry2(archive_handle->accept, key);
+
+ /* Fail if an accept list was specified and the key wasnt in there */
+ if ((accept_entry == NULL) && archive_handle->accept) {
+ return EXIT_FAILURE;
+ }
+
+ /* Accepted */
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/find_list_entry.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/find_list_entry.c
new file mode 100644
index 0000000000..7540589530
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/find_list_entry.c
@@ -0,0 +1,54 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2002 by Glenn McGrath
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include <fnmatch.h>
+#include "libbb.h"
+#include "unarchive.h"
+
+/* Find a string in a shell pattern list */
+const llist_t *find_list_entry(const llist_t *list, const char *filename)
+{
+ while (list) {
+ if (fnmatch(list->data, filename, 0) == 0) {
+ return list;
+ }
+ list = list->link;
+ }
+ return NULL;
+}
+
+/* Same, but compares only path components present in pattern
+ * (extra trailing path components in filename are assumed to match)
+ */
+const llist_t *find_list_entry2(const llist_t *list, const char *filename)
+{
+ char buf[PATH_MAX];
+ int pattern_slash_cnt;
+ const char *c;
+ char *d;
+
+ while (list) {
+ c = list->data;
+ pattern_slash_cnt = 0;
+ while (*c)
+ if (*c++ == '/') pattern_slash_cnt++;
+ c = filename;
+ d = buf;
+ /* paranoia is better than buffer overflows */
+ while (*c && d != buf + sizeof(buf)-1) {
+ if (*c == '/' && --pattern_slash_cnt < 0)
+ break;
+ *d++ = *c++;
+ }
+ *d = '\0';
+ if (fnmatch(list->data, buf, 0) == 0) {
+ return list;
+ }
+ list = list->link;
+ }
+ return NULL;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_ar.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_ar.c
new file mode 100644
index 0000000000..88c0220adf
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_ar.c
@@ -0,0 +1,126 @@
+/* vi: set sw=4 ts=4: */
+/* Copyright 2001 Glenn McGrath.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+char get_header_ar(archive_handle_t *archive_handle)
+{
+ int err;
+ file_header_t *typed = archive_handle->file_header;
+ union {
+ char raw[60];
+ struct {
+ char name[16];
+ char date[12];
+ char uid[6];
+ char gid[6];
+ char mode[8];
+ char size[10];
+ char magic[2];
+ } formatted;
+ } ar;
+#if ENABLE_FEATURE_AR_LONG_FILENAMES
+ static char *ar_long_names;
+ static unsigned ar_long_name_size;
+#endif
+
+ /* dont use xread as we want to handle the error ourself */
+ if (read(archive_handle->src_fd, ar.raw, 60) != 60) {
+ /* End Of File */
+ return EXIT_FAILURE;
+ }
+
+ /* ar header starts on an even byte (2 byte aligned)
+ * '\n' is used for padding
+ */
+ if (ar.raw[0] == '\n') {
+ /* fix up the header, we started reading 1 byte too early */
+ memmove(ar.raw, &ar.raw[1], 59);
+ ar.raw[59] = xread_char(archive_handle->src_fd);
+ archive_handle->offset++;
+ }
+ archive_handle->offset += 60;
+
+ /* align the headers based on the header magic */
+ if (ar.formatted.magic[0] != '`' || ar.formatted.magic[1] != '\n')
+ bb_error_msg_and_die("invalid ar header");
+
+ /* FIXME: more thorough routine would be in order here */
+ /* (we have something like that in tar) */
+ /* but for now we are lax. This code works because */
+ /* on misformatted numbers bb_strtou returns all-ones */
+ typed->mode = err = bb_strtou(ar.formatted.mode, NULL, 8);
+ if (err == -1) bb_error_msg_and_die("invalid ar header");
+ typed->mtime = err = bb_strtou(ar.formatted.date, NULL, 10);
+ if (err == -1) bb_error_msg_and_die("invalid ar header");
+ typed->uid = err = bb_strtou(ar.formatted.uid, NULL, 10);
+ if (err == -1) bb_error_msg_and_die("invalid ar header");
+ typed->gid = err = bb_strtou(ar.formatted.gid, NULL, 10);
+ if (err == -1) bb_error_msg_and_die("invalid ar header");
+ typed->size = err = bb_strtou(ar.formatted.size, NULL, 10);
+ if (err == -1) bb_error_msg_and_die("invalid ar header");
+
+ /* long filenames have '/' as the first character */
+ if (ar.formatted.name[0] == '/') {
+#if ENABLE_FEATURE_AR_LONG_FILENAMES
+ unsigned long_offset;
+
+ if (ar.formatted.name[1] == '/') {
+ /* If the second char is a '/' then this entries data section
+ * stores long filename for multiple entries, they are stored
+ * in static variable long_names for use in future entries */
+ ar_long_name_size = typed->size;
+ ar_long_names = xmalloc(ar_long_name_size);
+ xread(archive_handle->src_fd, ar_long_names, ar_long_name_size);
+ archive_handle->offset += ar_long_name_size;
+ /* This ar entries data section only contained filenames for other records
+ * they are stored in the static ar_long_names for future reference */
+ return get_header_ar(archive_handle); /* Return next header */
+ }
+
+ if (ar.formatted.name[1] == ' ') {
+ /* This is the index of symbols in the file for compilers */
+ data_skip(archive_handle);
+ archive_handle->offset += typed->size;
+ return get_header_ar(archive_handle); /* Return next header */
+ }
+
+ /* The number after the '/' indicates the offset in the ar data section
+ * (saved in variable long_name) that conatains the real filename */
+ long_offset = atoi(&ar.formatted.name[1]);
+ if (long_offset >= ar_long_name_size) {
+ bb_error_msg_and_die("can't resolve long filename");
+ }
+ typed->name = xstrdup(ar_long_names + long_offset);
+#else
+ bb_error_msg_and_die("long filenames not supported");
+#endif
+ } else {
+ /* short filenames */
+ typed->name = xstrndup(ar.formatted.name, 16);
+ }
+
+ typed->name[strcspn(typed->name, " /")] = '\0';
+
+ if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
+ archive_handle->action_header(typed);
+ if (archive_handle->sub_archive) {
+ while (archive_handle->action_data_subarchive(archive_handle->sub_archive) == EXIT_SUCCESS)
+ /* repeat */;
+ } else {
+ archive_handle->action_data(archive_handle);
+ }
+ } else {
+ data_skip(archive_handle);
+ }
+
+ archive_handle->offset += typed->size;
+ /* Set the file pointer to the correct spot, we may have been reading a compressed file */
+ lseek(archive_handle->src_fd, archive_handle->offset, SEEK_SET);
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_cpio.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_cpio.c
new file mode 100644
index 0000000000..0b9d385c1b
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_cpio.c
@@ -0,0 +1,169 @@
+/* vi: set sw=4 ts=4: */
+/* Copyright 2002 Laurence Anderson
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+typedef struct hardlinks_t {
+ struct hardlinks_t *next;
+ int inode; /* TODO: must match maj/min too! */
+ int mode ;
+ int mtime; /* These three are useful only in corner case */
+ int uid ; /* of hardlinks with zero size body */
+ int gid ;
+ char name[1];
+} hardlinks_t;
+
+char get_header_cpio(archive_handle_t *archive_handle)
+{
+ static hardlinks_t *saved_hardlinks = NULL;
+ static hardlinks_t *saved_hardlinks_created = NULL;
+
+ file_header_t *file_header = archive_handle->file_header;
+ char cpio_header[110];
+ char dummy[16];
+ int namesize;
+ int major, minor, nlink, mode, inode;
+ unsigned size, uid, gid, mtime;
+
+ /* There can be padding before archive header */
+ data_align(archive_handle, 4);
+
+ if (archive_xread_all_eof(archive_handle, (unsigned char*)cpio_header, 110) == 0) {
+ goto create_hardlinks;
+ }
+ archive_handle->offset += 110;
+
+ if (strncmp(&cpio_header[0], "07070", 5) != 0
+ || (cpio_header[5] != '1' && cpio_header[5] != '2')
+ ) {
+ bb_error_msg_and_die("unsupported cpio format, use newc or crc");
+ }
+
+ sscanf(cpio_header + 6,
+ "%8x" "%8x" "%8x" "%8x"
+ "%8x" "%8x" "%8x" /*maj,min:*/ "%16c"
+ /*rmaj,rmin:*/"%8x" "%8x" "%8x" /*chksum:*/ "%8c",
+ &inode, &mode, &uid, &gid,
+ &nlink, &mtime, &size, dummy,
+ &major, &minor, &namesize, dummy);
+ file_header->mode = mode;
+ file_header->uid = uid;
+ file_header->gid = gid;
+ file_header->mtime = mtime;
+ file_header->size = size;
+
+ file_header->name = xzalloc(namesize + 1);
+ /* Read in filename */
+ xread(archive_handle->src_fd, file_header->name, namesize);
+ archive_handle->offset += namesize;
+
+ /* Update offset amount and skip padding before file contents */
+ data_align(archive_handle, 4);
+
+ if (strcmp(file_header->name, "TRAILER!!!") == 0) {
+ /* Always round up. ">> 9" divides by 512 */
+ printf("%"OFF_FMT"u blocks\n", (archive_handle->offset + 511) >> 9);
+ goto create_hardlinks;
+ }
+
+ if (S_ISLNK(file_header->mode)) {
+ file_header->link_target = xzalloc(file_header->size + 1);
+ xread(archive_handle->src_fd, file_header->link_target, file_header->size);
+ archive_handle->offset += file_header->size;
+ file_header->size = 0; /* Stop possible seeks in future */
+ } else {
+ file_header->link_target = NULL;
+ }
+
+// TODO: data_extract_all can't deal with hardlinks to non-files...
+// (should be !S_ISDIR instead of S_ISREG here)
+
+ if (nlink > 1 && S_ISREG(file_header->mode)) {
+ hardlinks_t *new = xmalloc(sizeof(*new) + namesize);
+ new->inode = inode;
+ new->mode = mode ;
+ new->mtime = mtime;
+ new->uid = uid ;
+ new->gid = gid ;
+ strcpy(new->name, file_header->name);
+ /* Put file on a linked list for later */
+ if (size == 0) {
+ new->next = saved_hardlinks;
+ saved_hardlinks = new;
+ return EXIT_SUCCESS; /* Skip this one */
+ /* TODO: this breaks cpio -t (it does not show hardlinks) */
+ }
+ new->next = saved_hardlinks_created;
+ saved_hardlinks_created = new;
+ }
+ file_header->device = makedev(major, minor);
+
+ if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
+ archive_handle->action_data(archive_handle);
+ archive_handle->action_header(file_header);
+ } else {
+ data_skip(archive_handle);
+ }
+
+ archive_handle->offset += file_header->size;
+
+ free(file_header->link_target);
+ free(file_header->name);
+ file_header->link_target = NULL;
+ file_header->name = NULL;
+
+ return EXIT_SUCCESS;
+
+ create_hardlinks:
+ free(file_header->link_target);
+ free(file_header->name);
+
+ while (saved_hardlinks) {
+ hardlinks_t *cur;
+ hardlinks_t *make_me = saved_hardlinks;
+ saved_hardlinks = make_me->next;
+
+ memset(file_header, 0, sizeof(*file_header));
+ file_header->name = make_me->name;
+ file_header->mode = make_me->mode;
+ /*file_header->size = 0;*/
+
+ /* Try to find a file we are hardlinked to */
+ cur = saved_hardlinks_created;
+ while (cur) {
+ /* TODO: must match maj/min too! */
+ if (cur->inode == make_me->inode) {
+ file_header->link_target = cur->name;
+ /* link_target != NULL, size = 0: "I am a hardlink" */
+ if (archive_handle->filter(archive_handle) == EXIT_SUCCESS)
+ archive_handle->action_data(archive_handle);
+ free(make_me);
+ goto next_link;
+ }
+ cur = cur->next;
+ }
+ /* Oops... no file with such inode was created... do it now
+ * (happens when hardlinked files are empty (zero length)) */
+ file_header->mtime = make_me->mtime;
+ file_header->uid = make_me->uid ;
+ file_header->gid = make_me->gid ;
+ if (archive_handle->filter(archive_handle) == EXIT_SUCCESS)
+ archive_handle->action_data(archive_handle);
+ /* Move to the list of created hardlinked files */
+ make_me->next = saved_hardlinks_created;
+ saved_hardlinks_created = make_me;
+ next_link: ;
+ }
+
+ while (saved_hardlinks_created) {
+ hardlinks_t *p = saved_hardlinks_created;
+ saved_hardlinks_created = p->next;
+ free(p);
+ }
+
+ return EXIT_FAILURE; /* "No more files to process" */
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_tar.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_tar.c
new file mode 100644
index 0000000000..187552c284
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_tar.c
@@ -0,0 +1,368 @@
+/* vi: set sw=4 ts=4: */
+/* Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ * FIXME:
+ * In privileged mode if uname and gname map to a uid and gid then use the
+ * mapped value instead of the uid/gid values in tar header
+ *
+ * References:
+ * GNU tar and star man pages,
+ * Opengroup's ustar interchange format,
+ * http://www.opengroup.org/onlinepubs/007904975/utilities/pax.html
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+static char *longname;
+static char *linkname;
+#else
+enum {
+ longname = 0,
+ linkname = 0,
+};
+#endif
+
+/* NB: _DESTROYS_ str[len] character! */
+static unsigned long long getOctal(char *str, int len)
+{
+ unsigned long long v;
+ /* Actually, tar header allows leading spaces also.
+ * Oh well, we will be liberal and skip this...
+ * The only downside probably is that we allow "-123" too :)
+ if (*str < '0' || *str > '7')
+ bb_error_msg_and_die("corrupted octal value in tar header");
+ */
+ str[len] = '\0';
+ v = strtoull(str, &str, 8);
+ if (*str && (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY || *str != ' '))
+ bb_error_msg_and_die("corrupted octal value in tar header");
+ return v;
+}
+#define GET_OCTAL(a) getOctal((a), sizeof(a))
+
+void BUG_tar_header_size(void);
+char get_header_tar(archive_handle_t *archive_handle)
+{
+ static smallint end;
+#if ENABLE_FEATURE_TAR_AUTODETECT
+ static smallint not_first;
+#endif
+
+ file_header_t *file_header = archive_handle->file_header;
+ struct {
+ /* ustar header, Posix 1003.1 */
+ char name[100]; /* 0-99 */
+ char mode[8]; /* 100-107 */
+ char uid[8]; /* 108-115 */
+ char gid[8]; /* 116-123 */
+ char size[12]; /* 124-135 */
+ char mtime[12]; /* 136-147 */
+ char chksum[8]; /* 148-155 */
+ char typeflag; /* 156-156 */
+ char linkname[100]; /* 157-256 */
+ /* POSIX: "ustar" NUL "00" */
+ /* GNU tar: "ustar " NUL */
+ /* Normally it's defined as magic[6] followed by
+ * version[2], but we put them together to save code.
+ */
+ char magic[8]; /* 257-264 */
+ char uname[32]; /* 265-296 */
+ char gname[32]; /* 297-328 */
+ char devmajor[8]; /* 329-336 */
+ char devminor[8]; /* 337-344 */
+ char prefix[155]; /* 345-499 */
+ char padding[12]; /* 500-512 */
+ } tar;
+ char *cp;
+ int i, sum_u, sum;
+#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
+ int sum_s;
+#endif
+ int parse_names;
+
+ if (sizeof(tar) != 512)
+ BUG_tar_header_size();
+
+#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+ again:
+#endif
+ /* Align header */
+ data_align(archive_handle, 512);
+
+ again_after_align:
+
+#if ENABLE_DESKTOP
+ i = full_read(archive_handle->src_fd, &tar, 512);
+ /* if GNU tar sees EOF in above read, it says:
+ * "tar: A lone zero block at N", where N = kilobyte
+ * where EOF was met (not EOF block, actual EOF!),
+ * and tar will exit with error code 0.
+ * We will mimic exit(EXIT_SUCCESS), although we will not mimic
+ * the message and we don't check whether we indeed
+ * saw zero block directly before this. */
+ if (i == 0)
+ xfunc_error_retval = 0;
+ if (i != 512)
+ bb_error_msg_and_die("short read");
+#else
+ xread(archive_handle->src_fd, &tar, 512);
+#endif
+ archive_handle->offset += 512;
+
+ /* If there is no filename its an empty header */
+ if (tar.name[0] == 0 && tar.prefix[0] == 0) {
+ if (end) {
+ /* This is the second consecutive empty header! End of archive!
+ * Read until the end to empty the pipe from gz or bz2
+ */
+ while (full_read(archive_handle->src_fd, &tar, 512) == 512)
+ continue;
+ return EXIT_FAILURE;
+ }
+ end = 1;
+ return EXIT_SUCCESS;
+ }
+ end = 0;
+
+ /* Check header has valid magic, "ustar" is for the proper tar,
+ * five NULs are for the old tar format */
+ if (strncmp(tar.magic, "ustar", 5) != 0
+ && (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
+ || memcmp(tar.magic, "\0\0\0\0", 5) != 0)
+ ) {
+#if ENABLE_FEATURE_TAR_AUTODETECT
+ char (*get_header_ptr)(archive_handle_t *);
+
+ /* tar gz/bz autodetect: check for gz/bz2 magic.
+ * If it is the very first block, and we see the magic,
+ * we can switch to get_header_tar_gz/bz2/lzma().
+ * Needs seekable fd. I wish recv(MSG_PEEK) works
+ * on any fd... */
+ if (not_first)
+ goto err;
+#if ENABLE_FEATURE_TAR_GZIP
+ if (tar.name[0] == 0x1f && tar.name[1] == (char)0x8b) { /* gzip */
+ get_header_ptr = get_header_tar_gz;
+ } else
+#endif
+#if ENABLE_FEATURE_TAR_BZIP2
+ if (tar.name[0] == 'B' && tar.name[1] == 'Z'
+ && tar.name[2] == 'h' && isdigit(tar.name[3])
+ ) { /* bzip2 */
+ get_header_ptr = get_header_tar_bz2;
+ } else
+#endif
+ goto err;
+ if (lseek(archive_handle->src_fd, -512, SEEK_CUR) != 0)
+ goto err;
+ while (get_header_ptr(archive_handle) == EXIT_SUCCESS)
+ continue;
+ return EXIT_FAILURE;
+ err:
+#endif /* FEATURE_TAR_AUTODETECT */
+ bb_error_msg_and_die("invalid tar magic");
+ }
+
+#if ENABLE_FEATURE_TAR_AUTODETECT
+ not_first = 1;
+#endif
+
+ /* Do checksum on headers.
+ * POSIX says that checksum is done on unsigned bytes, but
+ * Sun and HP-UX gets it wrong... more details in
+ * GNU tar source. */
+#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
+ sum_s = ' ' * sizeof(tar.chksum);
+#endif
+ sum_u = ' ' * sizeof(tar.chksum);
+ for (i = 0; i < 148; i++) {
+ sum_u += ((unsigned char*)&tar)[i];
+#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
+ sum_s += ((signed char*)&tar)[i];
+#endif
+ }
+ for (i = 156; i < 512; i++) {
+ sum_u += ((unsigned char*)&tar)[i];
+#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
+ sum_s += ((signed char*)&tar)[i];
+#endif
+ }
+#if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
+ sum = strtoul(tar.chksum, &cp, 8);
+ if ((*cp && *cp != ' ')
+ || (sum_u != sum USE_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum))
+ ) {
+ bb_error_msg_and_die("invalid tar header checksum");
+ }
+#else
+ /* This field does not need special treatment (getOctal) */
+ sum = xstrtoul(tar.chksum, 8);
+ if (sum_u != sum USE_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)) {
+ bb_error_msg_and_die("invalid tar header checksum");
+ }
+#endif
+
+ /* 0 is reserved for high perf file, treat as normal file */
+ if (!tar.typeflag) tar.typeflag = '0';
+ parse_names = (tar.typeflag >= '0' && tar.typeflag <= '7');
+
+ /* getOctal trashes subsequent field, therefore we call it
+ * on fields in reverse order */
+ if (tar.devmajor[0]) {
+ char t = tar.prefix[0];
+ /* we trash prefix[0] here, but we DO need it later! */
+ unsigned minor = GET_OCTAL(tar.devminor);
+ unsigned major = GET_OCTAL(tar.devmajor);
+ file_header->device = makedev(major, minor);
+ tar.prefix[0] = t;
+ }
+ file_header->link_target = NULL;
+ if (!linkname && parse_names && tar.linkname[0]) {
+ file_header->link_target = xstrndup(tar.linkname, sizeof(tar.linkname));
+ /* FIXME: what if we have non-link object with link_target? */
+ /* Will link_target be free()ed? */
+ }
+#if ENABLE_FEATURE_TAR_UNAME_GNAME
+ file_header->uname = tar.uname[0] ? xstrndup(tar.uname, sizeof(tar.uname)) : NULL;
+ file_header->gname = tar.gname[0] ? xstrndup(tar.gname, sizeof(tar.gname)) : NULL;
+#endif
+ file_header->mtime = GET_OCTAL(tar.mtime);
+ file_header->size = GET_OCTAL(tar.size);
+ file_header->gid = GET_OCTAL(tar.gid);
+ file_header->uid = GET_OCTAL(tar.uid);
+ /* Set bits 0-11 of the files mode */
+ file_header->mode = 07777 & GET_OCTAL(tar.mode);
+
+ file_header->name = NULL;
+ if (!longname && parse_names) {
+ /* we trash mode[0] here, it's ok */
+ //tar.name[sizeof(tar.name)] = '\0'; - gcc 4.3.0 would complain
+ tar.mode[0] = '\0';
+ if (tar.prefix[0]) {
+ /* and padding[0] */
+ //tar.prefix[sizeof(tar.prefix)] = '\0'; - gcc 4.3.0 would complain
+ tar.padding[0] = '\0';
+ file_header->name = concat_path_file(tar.prefix, tar.name);
+ } else
+ file_header->name = xstrdup(tar.name);
+ }
+
+ /* Set bits 12-15 of the files mode */
+ /* (typeflag was not trashed because chksum does not use getOctal) */
+ switch (tar.typeflag) {
+ /* busybox identifies hard links as being regular files with 0 size and a link name */
+ case '1':
+ file_header->mode |= S_IFREG;
+ break;
+ case '7':
+ /* case 0: */
+ case '0':
+#if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
+ if (last_char_is(file_header->name, '/')) {
+ file_header->mode |= S_IFDIR;
+ } else
+#endif
+ file_header->mode |= S_IFREG;
+ break;
+ case '2':
+ file_header->mode |= S_IFLNK;
+ break;
+ case '3':
+ file_header->mode |= S_IFCHR;
+ break;
+ case '4':
+ file_header->mode |= S_IFBLK;
+ break;
+ case '5':
+ file_header->mode |= S_IFDIR;
+ break;
+ case '6':
+ file_header->mode |= S_IFIFO;
+ break;
+#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+ case 'L':
+ /* free: paranoia: tar with several consecutive longnames */
+ free(longname);
+ /* For paranoia reasons we allocate extra NUL char */
+ longname = xzalloc(file_header->size + 1);
+ /* We read ASCIZ string, including NUL */
+ xread(archive_handle->src_fd, longname, file_header->size);
+ archive_handle->offset += file_header->size;
+ /* return get_header_tar(archive_handle); */
+ /* gcc 4.1.1 didn't optimize it into jump */
+ /* so we will do it ourself, this also saves stack */
+ goto again;
+ case 'K':
+ free(linkname);
+ linkname = xzalloc(file_header->size + 1);
+ xread(archive_handle->src_fd, linkname, file_header->size);
+ archive_handle->offset += file_header->size;
+ /* return get_header_tar(archive_handle); */
+ goto again;
+ case 'D': /* GNU dump dir */
+ case 'M': /* Continuation of multi volume archive */
+ case 'N': /* Old GNU for names > 100 characters */
+ case 'S': /* Sparse file */
+ case 'V': /* Volume header */
+#endif
+ case 'g': /* pax global header */
+ case 'x': { /* pax extended header */
+ off_t sz;
+ bb_error_msg("warning: skipping header '%c'", tar.typeflag);
+ sz = (file_header->size + 511) & ~(off_t)511;
+ archive_handle->offset += sz;
+ sz >>= 9; /* sz /= 512 but w/o contortions for signed div */
+ while (sz--)
+ xread(archive_handle->src_fd, &tar, 512);
+ /* return get_header_tar(archive_handle); */
+ goto again_after_align;
+ }
+ default:
+ bb_error_msg_and_die("unknown typeflag: 0x%x", tar.typeflag);
+ }
+
+#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+ if (longname) {
+ file_header->name = longname;
+ longname = NULL;
+ }
+ if (linkname) {
+ file_header->link_target = linkname;
+ linkname = NULL;
+ }
+#endif
+ if (!strncmp(file_header->name, "/../"+1, 3)
+ || strstr(file_header->name, "/../")
+ ) {
+ bb_error_msg_and_die("name with '..' encountered: '%s'",
+ file_header->name);
+ }
+
+ /* Strip trailing '/' in directories */
+ /* Must be done after mode is set as '/' is used to check if it's a directory */
+ cp = last_char_is(file_header->name, '/');
+
+ if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
+ archive_handle->action_header(archive_handle->file_header);
+ /* Note that we kill the '/' only after action_header() */
+ /* (like GNU tar 1.15.1: verbose mode outputs "dir/dir/") */
+ if (cp) *cp = '\0';
+ archive_handle->flags |= ARCHIVE_EXTRACT_QUIET;
+ archive_handle->action_data(archive_handle);
+ llist_add_to(&(archive_handle->passed), file_header->name);
+ } else {
+ data_skip(archive_handle);
+ free(file_header->name);
+ }
+ archive_handle->offset += file_header->size;
+
+ free(file_header->link_target);
+ /* Do not free(file_header->name)! */
+#if ENABLE_FEATURE_TAR_UNAME_GNAME
+ free(file_header->uname);
+ free(file_header->gname);
+#endif
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_tar_bz2.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_tar_bz2.c
new file mode 100644
index 0000000000..c2cbaff5fc
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_tar_bz2.c
@@ -0,0 +1,21 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+char get_header_tar_bz2(archive_handle_t *archive_handle)
+{
+ /* Can't lseek over pipes */
+ archive_handle->seek = seek_by_read;
+
+ archive_handle->src_fd = open_transformer(archive_handle->src_fd, unpack_bz2_stream, "bunzip2");
+ archive_handle->offset = 0;
+ while (get_header_tar(archive_handle) == EXIT_SUCCESS)
+ continue;
+
+ /* Can only do one file at a time */
+ return EXIT_FAILURE;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_tar_gz.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_tar_gz.c
new file mode 100644
index 0000000000..9772e33fbc
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_tar_gz.c
@@ -0,0 +1,35 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+char get_header_tar_gz(archive_handle_t *archive_handle)
+{
+#if BB_MMU
+ unsigned char magic[2];
+#endif
+
+ /* Can't lseek over pipes */
+ archive_handle->seek = seek_by_read;
+
+ /* Check gzip magic only if open_transformer will invoke unpack_gz_stream (MMU case).
+ * Otherwise, it will invoke an external helper "gunzip -cf" (NOMMU case) which will
+ * need the header. */
+#if BB_MMU
+ xread(archive_handle->src_fd, &magic, 2);
+ if ((magic[0] != 0x1f) || (magic[1] != 0x8b)) {
+ bb_error_msg_and_die("invalid gzip magic");
+ }
+#endif
+
+ archive_handle->src_fd = open_transformer(archive_handle->src_fd, unpack_gz_stream, "gunzip");
+ archive_handle->offset = 0;
+ while (get_header_tar(archive_handle) == EXIT_SUCCESS)
+ continue;
+
+ /* Can only do one file at a time */
+ return EXIT_FAILURE;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_tar_lzma.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_tar_lzma.c
new file mode 100644
index 0000000000..c859dcc583
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/get_header_tar_lzma.c
@@ -0,0 +1,24 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Small lzma deflate implementation.
+ * Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
+ *
+ * Licensed under GPL v2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+char get_header_tar_lzma(archive_handle_t * archive_handle)
+{
+ /* Can't lseek over pipes */
+ archive_handle->seek = seek_by_read;
+
+ archive_handle->src_fd = open_transformer(archive_handle->src_fd, unpack_lzma_stream, "unlzma");
+ archive_handle->offset = 0;
+ while (get_header_tar(archive_handle) == EXIT_SUCCESS)
+ continue;
+
+ /* Can only do one file at a time */
+ return EXIT_FAILURE;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/header_list.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/header_list.c
new file mode 100644
index 0000000000..8cb8f40d97
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/header_list.c
@@ -0,0 +1,11 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+#include "libbb.h"
+#include "unarchive.h"
+
+void header_list(const file_header_t *file_header)
+{
+ puts(file_header->name);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/header_skip.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/header_skip.c
new file mode 100644
index 0000000000..ef2172bb3e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/header_skip.c
@@ -0,0 +1,10 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+#include "libbb.h"
+#include "unarchive.h"
+
+void header_skip(const file_header_t *file_header ATTRIBUTE_UNUSED)
+{
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/header_verbose_list.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/header_verbose_list.c
new file mode 100644
index 0000000000..ea623ed85a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/header_verbose_list.c
@@ -0,0 +1,58 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+void header_verbose_list(const file_header_t *file_header)
+{
+ struct tm *mtime = localtime(&(file_header->mtime));
+
+#if ENABLE_FEATURE_TAR_UNAME_GNAME
+ char uid[8];
+ char gid[8];
+ char *user = file_header->uname;
+ char *group = file_header->gname;
+
+ if (user == NULL) {
+ snprintf(uid, sizeof(uid), "%u", (unsigned)file_header->uid);
+ user = uid;
+ }
+ if (group == NULL) {
+ snprintf(gid, sizeof(gid), "%u", (unsigned)file_header->gid);
+ group = gid;
+ }
+ printf("%s %s/%s %9u %4u-%02u-%02u %02u:%02u:%02u %s",
+ bb_mode_string(file_header->mode),
+ user,
+ group,
+ (unsigned int) file_header->size,
+ 1900 + mtime->tm_year,
+ 1 + mtime->tm_mon,
+ mtime->tm_mday,
+ mtime->tm_hour,
+ mtime->tm_min,
+ mtime->tm_sec,
+ file_header->name);
+#else /* !FEATURE_TAR_UNAME_GNAME */
+ printf("%s %d/%d %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s",
+ bb_mode_string(file_header->mode),
+ file_header->uid,
+ file_header->gid,
+ file_header->size,
+ 1900 + mtime->tm_year,
+ 1 + mtime->tm_mon,
+ mtime->tm_mday,
+ mtime->tm_hour,
+ mtime->tm_min,
+ mtime->tm_sec,
+ file_header->name);
+#endif /* FEATURE_TAR_UNAME_GNAME */
+
+ if (file_header->link_target) {
+ printf(" -> %s", file_header->link_target);
+ }
+ bb_putchar('\n');
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/init_handle.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/init_handle.c
new file mode 100644
index 0000000000..309d329eae
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/init_handle.c
@@ -0,0 +1,22 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+archive_handle_t *init_handle(void)
+{
+ archive_handle_t *archive_handle;
+
+ /* Initialize default values */
+ archive_handle = xzalloc(sizeof(archive_handle_t));
+ archive_handle->file_header = xzalloc(sizeof(file_header_t));
+ archive_handle->action_header = header_skip;
+ archive_handle->action_data = data_skip;
+ archive_handle->filter = filter_accept_all;
+ archive_handle->seek = seek_by_jump;
+
+ return archive_handle;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/open_transformer.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/open_transformer.c
new file mode 100644
index 0000000000..d0a2b7c36a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/open_transformer.c
@@ -0,0 +1,64 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+/* transformer(), more than meets the eye */
+/*
+ * On MMU machine, the transform_prog is removed by macro magic
+ * in include/unarchive.h. On NOMMU, transformer is removed.
+ */
+int open_transformer(int src_fd,
+ USE_DESKTOP(long long) int (*transformer)(int src_fd, int dst_fd),
+ const char *transform_prog)
+{
+ struct fd_pair fd_pipe;
+ int pid;
+
+ xpiped_pair(fd_pipe);
+
+#if BB_MMU
+ pid = fork();
+ if (pid == -1)
+ bb_perror_msg_and_die("can't fork");
+#else
+ pid = vfork();
+ if (pid == -1)
+ bb_perror_msg_and_die("can't vfork");
+#endif
+
+ if (pid == 0) {
+ /* child process */
+ close(fd_pipe.rd); /* We don't want to read from the parent */
+ // FIXME: error check?
+#if BB_MMU
+ transformer(src_fd, fd_pipe.wr);
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ close(fd_pipe.wr); /* Send EOF */
+ close(src_fd);
+ }
+ exit(EXIT_SUCCESS);
+#else
+ {
+ char *argv[4];
+ xmove_fd(src_fd, 0);
+ xmove_fd(fd_pipe.wr, 1);
+ argv[0] = (char*)transform_prog;
+ argv[1] = (char*)"-cf";
+ argv[2] = (char*)"-";
+ argv[3] = NULL;
+ BB_EXECVP(transform_prog, argv);
+ bb_perror_msg_and_die("can't exec %s", transform_prog);
+ }
+#endif
+ /* notreached */
+ }
+
+ /* parent process */
+ close(fd_pipe.wr); /* Don't want to write to the child */
+
+ return fd_pipe.rd;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/seek_by_jump.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/seek_by_jump.c
new file mode 100644
index 0000000000..5288c1d736
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/seek_by_jump.c
@@ -0,0 +1,17 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+void seek_by_jump(const archive_handle_t *archive_handle, unsigned amount)
+{
+ if (lseek(archive_handle->src_fd, (off_t) amount, SEEK_CUR) == (off_t) -1) {
+ if (errno == ESPIPE)
+ seek_by_read(archive_handle, amount);
+ else
+ bb_perror_msg_and_die("seek failure");
+ }
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/seek_by_read.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/seek_by_read.c
new file mode 100644
index 0000000000..1f2b805711
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/seek_by_read.c
@@ -0,0 +1,16 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+/* If we are reading through a pipe, or from stdin then we can't lseek,
+ * we must read and discard the data to skip over it.
+ */
+void seek_by_read(const archive_handle_t *archive_handle, unsigned jump_size)
+{
+ if (jump_size)
+ bb_copyfd_exact_size(archive_handle->src_fd, -1, jump_size);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/unpack_ar_archive.c b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/unpack_ar_archive.c
new file mode 100644
index 0000000000..fc1820b97b
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/libunarchive/unpack_ar_archive.c
@@ -0,0 +1,20 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+void unpack_ar_archive(archive_handle_t *ar_archive)
+{
+ char magic[7];
+
+ xread(ar_archive->src_fd, magic, 7);
+ if (strncmp(magic, "!<arch>", 7) != 0) {
+ bb_error_msg_and_die("invalid ar magic");
+ }
+ ar_archive->offset += 7;
+
+ while (get_header_ar(ar_archive) == EXIT_SUCCESS);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/rpm.c b/cleopatre/busybox-1.11.1-spc300/archival/rpm.c
new file mode 100644
index 0000000000..41b8c81b22
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/rpm.c
@@ -0,0 +1,398 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini rpm applet for busybox
+ *
+ * Copyright (C) 2001,2002 by Laurence Anderson
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+#define RPM_HEADER_MAGIC "\216\255\350"
+#define RPM_CHAR_TYPE 1
+#define RPM_INT8_TYPE 2
+#define RPM_INT16_TYPE 3
+#define RPM_INT32_TYPE 4
+/* #define RPM_INT64_TYPE 5 ---- These aren't supported (yet) */
+#define RPM_STRING_TYPE 6
+#define RPM_BIN_TYPE 7
+#define RPM_STRING_ARRAY_TYPE 8
+#define RPM_I18NSTRING_TYPE 9
+
+#define TAG_NAME 1000
+#define TAG_VERSION 1001
+#define TAG_RELEASE 1002
+#define TAG_SUMMARY 1004
+#define TAG_DESCRIPTION 1005
+#define TAG_BUILDTIME 1006
+#define TAG_BUILDHOST 1007
+#define TAG_SIZE 1009
+#define TAG_VENDOR 1011
+#define TAG_LICENSE 1014
+#define TAG_PACKAGER 1015
+#define TAG_GROUP 1016
+#define TAG_URL 1020
+#define TAG_PREIN 1023
+#define TAG_POSTIN 1024
+#define TAG_FILEFLAGS 1037
+#define TAG_FILEUSERNAME 1039
+#define TAG_FILEGROUPNAME 1040
+#define TAG_SOURCERPM 1044
+#define TAG_PREINPROG 1085
+#define TAG_POSTINPROG 1086
+#define TAG_PREFIXS 1098
+#define TAG_DIRINDEXES 1116
+#define TAG_BASENAMES 1117
+#define TAG_DIRNAMES 1118
+#define RPMFILE_CONFIG (1 << 0)
+#define RPMFILE_DOC (1 << 1)
+
+enum rpm_functions_e {
+ rpm_query = 1,
+ rpm_install = 2,
+ rpm_query_info = 4,
+ rpm_query_package = 8,
+ rpm_query_list = 16,
+ rpm_query_list_doc = 32,
+ rpm_query_list_config = 64
+};
+
+typedef struct {
+ uint32_t tag; /* 4 byte tag */
+ uint32_t type; /* 4 byte type */
+ uint32_t offset; /* 4 byte offset */
+ uint32_t count; /* 4 byte count */
+} rpm_index;
+
+static void *map;
+static rpm_index **mytags;
+static int tagcount;
+
+static void extract_cpio_gz(int fd);
+static rpm_index **rpm_gettags(int fd, int *num_tags);
+static int bsearch_rpmtag(const void *key, const void *item);
+static char *rpm_getstr(int tag, int itemindex);
+static int rpm_getint(int tag, int itemindex);
+static int rpm_getcount(int tag);
+static void fileaction_dobackup(char *filename, int fileref);
+static void fileaction_setowngrp(char *filename, int fileref);
+static void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref));
+
+int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int rpm_main(int argc, char **argv)
+{
+ int opt = 0, func = 0, rpm_fd, offset;
+ const int pagesize = getpagesize();
+
+ while ((opt = getopt(argc, argv, "iqpldc")) != -1) {
+ switch (opt) {
+ case 'i': /* First arg: Install mode, with q: Information */
+ if (!func) func = rpm_install;
+ else func |= rpm_query_info;
+ break;
+ case 'q': /* First arg: Query mode */
+ if (func) bb_show_usage();
+ func = rpm_query;
+ break;
+ case 'p': /* Query a package */
+ func |= rpm_query_package;
+ break;
+ case 'l': /* List files in a package */
+ func |= rpm_query_list;
+ break;
+ case 'd': /* List doc files in a package (implies list) */
+ func |= rpm_query_list;
+ func |= rpm_query_list_doc;
+ break;
+ case 'c': /* List config files in a package (implies list) */
+ func |= rpm_query_list;
+ func |= rpm_query_list_config;
+ break;
+ default:
+ bb_show_usage();
+ }
+ }
+ argv += optind;
+ argc -= optind;
+ if (!argc) bb_show_usage();
+
+ while (*argv) {
+ rpm_fd = xopen(*argv++, O_RDONLY);
+ mytags = rpm_gettags(rpm_fd, &tagcount);
+ if (!mytags)
+ bb_error_msg_and_die("error reading rpm header");
+ offset = xlseek(rpm_fd, 0, SEEK_CUR);
+ /* Mimimum is one page */
+ map = mmap(0, offset > pagesize ? (offset + offset % pagesize) : pagesize, PROT_READ, MAP_PRIVATE, rpm_fd, 0);
+
+ if (func & rpm_install) {
+ /* Backup any config files */
+ loop_through_files(TAG_BASENAMES, fileaction_dobackup);
+ /* Extact the archive */
+ extract_cpio_gz(rpm_fd);
+ /* Set the correct file uid/gid's */
+ loop_through_files(TAG_BASENAMES, fileaction_setowngrp);
+ }
+ else if ((func & (rpm_query|rpm_query_package)) == (rpm_query|rpm_query_package)) {
+ if (!(func & (rpm_query_info|rpm_query_list))) {
+ /* If just a straight query, just give package name */
+ printf("%s-%s-%s\n", rpm_getstr(TAG_NAME, 0), rpm_getstr(TAG_VERSION, 0), rpm_getstr(TAG_RELEASE, 0));
+ }
+ if (func & rpm_query_info) {
+ /* Do the nice printout */
+ time_t bdate_time;
+ struct tm *bdate;
+ char bdatestring[50];
+ printf("Name : %-29sRelocations: %s\n", rpm_getstr(TAG_NAME, 0), rpm_getstr(TAG_PREFIXS, 0) ? rpm_getstr(TAG_PREFIXS, 0) : "(not relocateable)");
+ printf("Version : %-34sVendor: %s\n", rpm_getstr(TAG_VERSION, 0), rpm_getstr(TAG_VENDOR, 0) ? rpm_getstr(TAG_VENDOR, 0) : "(none)");
+ bdate_time = rpm_getint(TAG_BUILDTIME, 0);
+ bdate = localtime((time_t *) &bdate_time);
+ strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate);
+ printf("Release : %-30sBuild Date: %s\n", rpm_getstr(TAG_RELEASE, 0), bdatestring);
+ printf("Install date: %-30sBuild Host: %s\n", "(not installed)", rpm_getstr(TAG_BUILDHOST, 0));
+ printf("Group : %-30sSource RPM: %s\n", rpm_getstr(TAG_GROUP, 0), rpm_getstr(TAG_SOURCERPM, 0));
+ printf("Size : %-33dLicense: %s\n", rpm_getint(TAG_SIZE, 0), rpm_getstr(TAG_LICENSE, 0));
+ printf("URL : %s\n", rpm_getstr(TAG_URL, 0));
+ printf("Summary : %s\n", rpm_getstr(TAG_SUMMARY, 0));
+ printf("Description :\n%s\n", rpm_getstr(TAG_DESCRIPTION, 0));
+ }
+ if (func & rpm_query_list) {
+ int count, it, flags;
+ count = rpm_getcount(TAG_BASENAMES);
+ for (it = 0; it < count; it++) {
+ flags = rpm_getint(TAG_FILEFLAGS, it);
+ switch (func & (rpm_query_list_doc|rpm_query_list_config)) {
+ case rpm_query_list_doc:
+ if (!(flags & RPMFILE_DOC)) continue;
+ break;
+ case rpm_query_list_config:
+ if (!(flags & RPMFILE_CONFIG)) continue;
+ break;
+ case rpm_query_list_doc|rpm_query_list_config:
+ if (!(flags & (RPMFILE_CONFIG|RPMFILE_DOC))) continue;
+ break;
+ }
+ printf("%s%s\n",
+ rpm_getstr(TAG_DIRNAMES, rpm_getint(TAG_DIRINDEXES, it)),
+ rpm_getstr(TAG_BASENAMES, it));
+ }
+ }
+ }
+ free(mytags);
+ }
+ return 0;
+}
+
+static void extract_cpio_gz(int fd)
+{
+ archive_handle_t *archive_handle;
+ unsigned char magic[2];
+#if BB_MMU
+ USE_DESKTOP(long long) int (*xformer)(int src_fd, int dst_fd);
+ enum { xformer_prog = 0 };
+#else
+ enum { xformer = 0 };
+ const char *xformer_prog;
+#endif
+
+ /* Initialize */
+ archive_handle = init_handle();
+ archive_handle->seek = seek_by_read;
+ //archive_handle->action_header = header_list;
+ archive_handle->action_data = data_extract_all;
+ archive_handle->flags |= ARCHIVE_PRESERVE_DATE;
+ archive_handle->flags |= ARCHIVE_CREATE_LEADING_DIRS;
+ archive_handle->src_fd = fd;
+ archive_handle->offset = 0;
+
+ xread(archive_handle->src_fd, &magic, 2);
+#if BB_MMU
+ xformer = unpack_gz_stream;
+#else
+ xformer_prog = "gunzip";
+#endif
+ if ((magic[0] != 0x1f) || (magic[1] != 0x8b)) {
+ if (ENABLE_FEATURE_RPM_BZ2
+ && (magic[0] == 0x42) && (magic[1] == 0x5a)) {
+#if BB_MMU
+ xformer = unpack_bz2_stream;
+#else
+ xformer_prog = "bunzip2";
+#endif
+ /* We can do better, need modifying unpack_bz2_stream to not require
+ * first 2 bytes. Not very hard to do... I mean, TODO :) */
+ xlseek(archive_handle->src_fd, -2, SEEK_CUR);
+ } else
+ bb_error_msg_and_die("no gzip"
+ USE_FEATURE_RPM_BZ2("/bzip")
+ " magic");
+ } else {
+#if !BB_MMU
+ /* NOMMU version of open_transformer execs an external unzipper that should
+ * have the file position at the start of the file */
+ xlseek(archive_handle->src_fd, 0, SEEK_SET);
+#endif
+ }
+
+ xchdir("/"); /* Install RPM's to root */
+ archive_handle->src_fd = open_transformer(archive_handle->src_fd, xformer, xformer_prog);
+ archive_handle->offset = 0;
+ while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
+ continue;
+}
+
+
+static rpm_index **rpm_gettags(int fd, int *num_tags)
+{
+ /* We should never need mode than 200, and realloc later */
+ rpm_index **tags = xzalloc(200 * sizeof(struct rpmtag *));
+ int pass, tagindex = 0;
+
+ xlseek(fd, 96, SEEK_CUR); /* Seek past the unused lead */
+
+ /* 1st pass is the signature headers, 2nd is the main stuff */
+ for (pass = 0; pass < 2; pass++) {
+ struct {
+ char magic[3]; /* 3 byte magic: 0x8e 0xad 0xe8 */
+ uint8_t version; /* 1 byte version number */
+ uint32_t reserved; /* 4 bytes reserved */
+ uint32_t entries; /* Number of entries in header (4 bytes) */
+ uint32_t size; /* Size of store (4 bytes) */
+ } header;
+ rpm_index *tmpindex;
+ int storepos;
+
+ xread(fd, &header, sizeof(header));
+ if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC, 3) != 0)
+ return NULL; /* Invalid magic */
+ if (header.version != 1)
+ return NULL; /* This program only supports v1 headers */
+ header.size = ntohl(header.size);
+ header.entries = ntohl(header.entries);
+ storepos = xlseek(fd,0,SEEK_CUR) + header.entries * 16;
+
+ while (header.entries--) {
+ tmpindex = tags[tagindex++] = xmalloc(sizeof(rpm_index));
+ xread(fd, tmpindex, sizeof(rpm_index));
+ tmpindex->tag = ntohl(tmpindex->tag);
+ tmpindex->type = ntohl(tmpindex->type);
+ tmpindex->count = ntohl(tmpindex->count);
+ tmpindex->offset = storepos + ntohl(tmpindex->offset);
+ if (pass==0)
+ tmpindex->tag -= 743;
+ }
+ xlseek(fd, header.size, SEEK_CUR); /* Seek past store */
+ /* Skip padding to 8 byte boundary after reading signature headers */
+ if (pass==0)
+ xlseek(fd, (8 - (xlseek(fd,0,SEEK_CUR) % 8)) % 8, SEEK_CUR);
+ }
+ tags = xrealloc(tags, tagindex * sizeof(struct rpmtag *)); /* realloc tags to save space */
+ *num_tags = tagindex;
+ return tags; /* All done, leave the file at the start of the gzipped cpio archive */
+}
+
+static int bsearch_rpmtag(const void *key, const void *item)
+{
+ int *tag = (int *)key;
+ rpm_index **tmp = (rpm_index **) item;
+ return (*tag - tmp[0]->tag);
+}
+
+static int rpm_getcount(int tag)
+{
+ rpm_index **found;
+ found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
+ if (!found)
+ return 0;
+ return found[0]->count;
+}
+
+static char *rpm_getstr(int tag, int itemindex)
+{
+ rpm_index **found;
+ found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
+ if (!found || itemindex >= found[0]->count)
+ return NULL;
+ if (found[0]->type == RPM_STRING_TYPE || found[0]->type == RPM_I18NSTRING_TYPE || found[0]->type == RPM_STRING_ARRAY_TYPE) {
+ int n;
+ char *tmpstr = (char *) (map + found[0]->offset);
+ for (n=0; n < itemindex; n++)
+ tmpstr = tmpstr + strlen(tmpstr) + 1;
+ return tmpstr;
+ }
+ return NULL;
+}
+
+static int rpm_getint(int tag, int itemindex)
+{
+ rpm_index **found;
+ int *tmpint; /* NB: using int8_t* would be easier to code */
+
+ /* gcc throws warnings here when sizeof(void*)!=sizeof(int) ...
+ * it's ok to ignore it because tag won't be used as a pointer */
+ found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
+ if (!found || itemindex >= found[0]->count)
+ return -1;
+
+ tmpint = (int *) (map + found[0]->offset);
+
+ if (found[0]->type == RPM_INT32_TYPE) {
+ tmpint = (int *) ((char *) tmpint + itemindex*4);
+ /*return ntohl(*tmpint);*/
+ /* int can be != int32_t */
+ return ntohl(*(int32_t*)tmpint);
+ }
+ if (found[0]->type == RPM_INT16_TYPE) {
+ tmpint = (int *) ((char *) tmpint + itemindex*2);
+ /* ??? read int, and THEN ntohs() it?? */
+ /*return ntohs(*tmpint);*/
+ return ntohs(*(int16_t*)tmpint);
+ }
+ if (found[0]->type == RPM_INT8_TYPE) {
+ tmpint = (int *) ((char *) tmpint + itemindex);
+ /* ??? why we don't read byte here??? */
+ /*return ntohs(*tmpint);*/
+ return *(int8_t*)tmpint;
+ }
+ return -1;
+}
+
+static void fileaction_dobackup(char *filename, int fileref)
+{
+ struct stat oldfile;
+ int stat_res;
+ char *newname;
+ if (rpm_getint(TAG_FILEFLAGS, fileref) & RPMFILE_CONFIG) {
+ /* Only need to backup config files */
+ stat_res = lstat(filename, &oldfile);
+ if (stat_res == 0 && S_ISREG(oldfile.st_mode)) {
+ /* File already exists - really should check MD5's etc to see if different */
+ newname = xasprintf("%s.rpmorig", filename);
+ copy_file(filename, newname, FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS);
+ remove_file(filename, FILEUTILS_RECUR | FILEUTILS_FORCE);
+ free(newname);
+ }
+ }
+}
+
+static void fileaction_setowngrp(char *filename, int fileref)
+{
+ int uid, gid;
+ uid = xuname2uid(rpm_getstr(TAG_FILEUSERNAME, fileref));
+ gid = xgroup2gid(rpm_getstr(TAG_FILEGROUPNAME, fileref));
+ chown(filename, uid, gid);
+}
+
+static void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref))
+{
+ int count = 0;
+ while (rpm_getstr(filetag, count)) {
+ char* filename = xasprintf("%s%s",
+ rpm_getstr(TAG_DIRNAMES, rpm_getint(TAG_DIRINDEXES, count)),
+ rpm_getstr(TAG_BASENAMES, count));
+ fileaction(filename, count++);
+ free(filename);
+ }
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/rpm2cpio.c b/cleopatre/busybox-1.11.1-spc300/archival/rpm2cpio.c
new file mode 100644
index 0000000000..ee938716f1
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/rpm2cpio.c
@@ -0,0 +1,89 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini rpm2cpio implementation for busybox
+ *
+ * Copyright (C) 2001 by Laurence Anderson
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+#include "libbb.h"
+#include "unarchive.h"
+
+#define RPM_MAGIC "\355\253\356\333"
+#define RPM_HEADER_MAGIC "\216\255\350"
+
+struct rpm_lead {
+ unsigned char magic[4];
+ uint8_t major, minor;
+ uint16_t type;
+ uint16_t archnum;
+ char name[66];
+ uint16_t osnum;
+ uint16_t signature_type;
+ char reserved[16];
+};
+
+struct rpm_header {
+ char magic[3]; /* 3 byte magic: 0x8e 0xad 0xe8 */
+ uint8_t version; /* 1 byte version number */
+ uint32_t reserved; /* 4 bytes reserved */
+ uint32_t entries; /* Number of entries in header (4 bytes) */
+ uint32_t size; /* Size of store (4 bytes) */
+};
+
+static void skip_header(int rpm_fd)
+{
+ struct rpm_header header;
+
+ xread(rpm_fd, &header, sizeof(struct rpm_header));
+ if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC, 3) != 0) {
+ bb_error_msg_and_die("invalid RPM header magic"); /* Invalid magic */
+ }
+ if (header.version != 1) {
+ bb_error_msg_and_die("unsupported RPM header version"); /* This program only supports v1 headers */
+ }
+ header.entries = ntohl(header.entries);
+ header.size = ntohl(header.size);
+ lseek (rpm_fd, 16 * header.entries, SEEK_CUR); /* Seek past index entries */
+ lseek (rpm_fd, header.size, SEEK_CUR); /* Seek past store */
+}
+
+/* No getopt required */
+int rpm2cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int rpm2cpio_main(int argc, char **argv)
+{
+ struct rpm_lead lead;
+ int rpm_fd;
+ unsigned char magic[2];
+
+ if (argc == 1) {
+ rpm_fd = STDIN_FILENO;
+ } else {
+ rpm_fd = xopen(argv[1], O_RDONLY);
+ }
+
+ xread(rpm_fd, &lead, sizeof(struct rpm_lead));
+ if (strncmp((char *) &lead.magic, RPM_MAGIC, 4) != 0) {
+ bb_error_msg_and_die("invalid RPM magic"); /* Just check the magic, the rest is irrelevant */
+ }
+
+ /* Skip the signature header */
+ skip_header(rpm_fd);
+ lseek(rpm_fd, (8 - (lseek(rpm_fd, 0, SEEK_CUR) % 8)) % 8, SEEK_CUR);
+
+ /* Skip the main header */
+ skip_header(rpm_fd);
+
+ xread(rpm_fd, &magic, 2);
+ if ((magic[0] != 0x1f) || (magic[1] != 0x8b)) {
+ bb_error_msg_and_die("invalid gzip magic");
+ }
+
+ if (unpack_gz_stream(rpm_fd, STDOUT_FILENO) < 0) {
+ bb_error_msg("error inflating");
+ }
+
+ close(rpm_fd);
+
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/tar.c b/cleopatre/busybox-1.11.1-spc300/archival/tar.c
new file mode 100644
index 0000000000..0162e06239
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/tar.c
@@ -0,0 +1,980 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini tar implementation for busybox
+ *
+ * Modified to use common extraction code used by ar, cpio, dpkg-deb, dpkg
+ * by Glenn McGrath
+ *
+ * Note, that as of BusyBox-0.43, tar has been completely rewritten from the
+ * ground up. It still has remnants of the old code lying about, but it is
+ * very different now (i.e., cleaner, less global variables, etc.)
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Based in part in the tar implementation in sash
+ * Copyright (c) 1999 by David I. Bell
+ * Permission is granted to use, distribute, or modify this source,
+ * provided that this copyright notice remains intact.
+ * Permission to distribute sash derived code under the GPL has been granted.
+ *
+ * Based in part on the tar implementation from busybox-0.28
+ * Copyright (C) 1995 Bruce Perens
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include <fnmatch.h>
+#include "libbb.h"
+#include "unarchive.h"
+
+/* FIXME: Stop using this non-standard feature */
+#ifndef FNM_LEADING_DIR
+#define FNM_LEADING_DIR 0
+#endif
+
+
+#define block_buf bb_common_bufsiz1
+
+
+#if !ENABLE_FEATURE_TAR_GZIP && !ENABLE_FEATURE_TAR_BZIP2
+/* Do not pass gzip flag to writeTarFile() */
+#define writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude, gzip) \
+ writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude)
+#endif
+
+
+#if ENABLE_FEATURE_TAR_CREATE
+
+/* Tar file constants */
+
+#define TAR_BLOCK_SIZE 512
+
+/* POSIX tar Header Block, from POSIX 1003.1-1990 */
+#define NAME_SIZE 100
+#define NAME_SIZE_STR "100"
+typedef struct TarHeader TarHeader;
+struct TarHeader { /* byte offset */
+ char name[NAME_SIZE]; /* 0-99 */
+ char mode[8]; /* 100-107 */
+ char uid[8]; /* 108-115 */
+ char gid[8]; /* 116-123 */
+ char size[12]; /* 124-135 */
+ char mtime[12]; /* 136-147 */
+ char chksum[8]; /* 148-155 */
+ char typeflag; /* 156-156 */
+ char linkname[NAME_SIZE]; /* 157-256 */
+ /* POSIX: "ustar" NUL "00" */
+ /* GNU tar: "ustar " NUL */
+ /* Normally it's defined as magic[6] followed by
+ * version[2], but we put them together to save code.
+ */
+ char magic[8]; /* 257-264 */
+ char uname[32]; /* 265-296 */
+ char gname[32]; /* 297-328 */
+ char devmajor[8]; /* 329-336 */
+ char devminor[8]; /* 337-344 */
+ char prefix[155]; /* 345-499 */
+ char padding[12]; /* 500-512 (pad to exactly TAR_BLOCK_SIZE) */
+};
+
+/*
+** writeTarFile(), writeFileToTarball(), and writeTarHeader() are
+** the only functions that deal with the HardLinkInfo structure.
+** Even these functions use the xxxHardLinkInfo() functions.
+*/
+typedef struct HardLinkInfo HardLinkInfo;
+struct HardLinkInfo {
+ HardLinkInfo *next; /* Next entry in list */
+ dev_t dev; /* Device number */
+ ino_t ino; /* Inode number */
+ short linkCount; /* (Hard) Link Count */
+ char name[1]; /* Start of filename (must be last) */
+};
+
+/* Some info to be carried along when creating a new tarball */
+typedef struct TarBallInfo TarBallInfo;
+struct TarBallInfo {
+ int tarFd; /* Open-for-write file descriptor
+ * for the tarball */
+ struct stat statBuf; /* Stat info for the tarball, letting
+ * us know the inode and device that the
+ * tarball lives, so we can avoid trying
+ * to include the tarball into itself */
+ int verboseFlag; /* Whether to print extra stuff or not */
+ const llist_t *excludeList; /* List of files to not include */
+ HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */
+ HardLinkInfo *hlInfo; /* Hard Link Info for the current file */
+};
+
+/* A nice enum with all the possible tar file content types */
+enum TarFileType {
+ REGTYPE = '0', /* regular file */
+ REGTYPE0 = '\0', /* regular file (ancient bug compat) */
+ LNKTYPE = '1', /* hard link */
+ SYMTYPE = '2', /* symbolic link */
+ CHRTYPE = '3', /* character special */
+ BLKTYPE = '4', /* block special */
+ DIRTYPE = '5', /* directory */
+ FIFOTYPE = '6', /* FIFO special */
+ CONTTYPE = '7', /* reserved */
+ GNULONGLINK = 'K', /* GNU long (>100 chars) link name */
+ GNULONGNAME = 'L', /* GNU long (>100 chars) file name */
+};
+typedef enum TarFileType TarFileType;
+
+/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
+static void addHardLinkInfo(HardLinkInfo **hlInfoHeadPtr,
+ struct stat *statbuf,
+ const char *fileName)
+{
+ /* Note: hlInfoHeadPtr can never be NULL! */
+ HardLinkInfo *hlInfo;
+
+ hlInfo = xmalloc(sizeof(HardLinkInfo) + strlen(fileName));
+ hlInfo->next = *hlInfoHeadPtr;
+ *hlInfoHeadPtr = hlInfo;
+ hlInfo->dev = statbuf->st_dev;
+ hlInfo->ino = statbuf->st_ino;
+ hlInfo->linkCount = statbuf->st_nlink;
+ strcpy(hlInfo->name, fileName);
+}
+
+static void freeHardLinkInfo(HardLinkInfo **hlInfoHeadPtr)
+{
+ HardLinkInfo *hlInfo;
+ HardLinkInfo *hlInfoNext;
+
+ if (hlInfoHeadPtr) {
+ hlInfo = *hlInfoHeadPtr;
+ while (hlInfo) {
+ hlInfoNext = hlInfo->next;
+ free(hlInfo);
+ hlInfo = hlInfoNext;
+ }
+ *hlInfoHeadPtr = NULL;
+ }
+}
+
+/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
+static HardLinkInfo *findHardLinkInfo(HardLinkInfo *hlInfo, struct stat *statbuf)
+{
+ while (hlInfo) {
+ if ((statbuf->st_ino == hlInfo->ino) && (statbuf->st_dev == hlInfo->dev))
+ break;
+ hlInfo = hlInfo->next;
+ }
+ return hlInfo;
+}
+
+/* Put an octal string into the specified buffer.
+ * The number is zero padded and possibly null terminated.
+ * Stores low-order bits only if whole value does not fit. */
+static void putOctal(char *cp, int len, off_t value)
+{
+ char tempBuffer[sizeof(off_t)*3+1];
+ char *tempString = tempBuffer;
+ int width;
+
+ width = sprintf(tempBuffer, "%0*"OFF_FMT"o", len, value);
+ tempString += (width - len);
+
+ /* If string has leading zeroes, we can drop one */
+ /* and field will have trailing '\0' */
+ /* (increases chances of compat with other tars) */
+ if (tempString[0] == '0')
+ tempString++;
+
+ /* Copy the string to the field */
+ memcpy(cp, tempString, len);
+}
+#define PUT_OCTAL(a, b) putOctal((a), sizeof(a), (b))
+
+static void chksum_and_xwrite(int fd, struct TarHeader* hp)
+{
+ /* POSIX says that checksum is done on unsigned bytes
+ * (Sun and HP-UX gets it wrong... more details in
+ * GNU tar source) */
+ const unsigned char *cp;
+ int chksum, size;
+
+ strcpy(hp->magic, "ustar ");
+
+ /* Calculate and store the checksum (i.e., the sum of all of the bytes of
+ * the header). The checksum field must be filled with blanks for the
+ * calculation. The checksum field is formatted differently from the
+ * other fields: it has 6 digits, a null, then a space -- rather than
+ * digits, followed by a null like the other fields... */
+ memset(hp->chksum, ' ', sizeof(hp->chksum));
+ cp = (const unsigned char *) hp;
+ chksum = 0;
+ size = sizeof(*hp);
+ do { chksum += *cp++; } while (--size);
+ putOctal(hp->chksum, sizeof(hp->chksum)-1, chksum);
+
+ /* Now write the header out to disk */
+ xwrite(fd, hp, sizeof(*hp));
+}
+
+#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+static void writeLongname(int fd, int type, const char *name, int dir)
+{
+ static const struct {
+ char mode[8]; /* 100-107 */
+ char uid[8]; /* 108-115 */
+ char gid[8]; /* 116-123 */
+ char size[12]; /* 124-135 */
+ char mtime[12]; /* 136-147 */
+ } prefilled = {
+ "0000000",
+ "0000000",
+ "0000000",
+ "00000000000",
+ "00000000000",
+ };
+ struct TarHeader header;
+ int size;
+
+ dir = !!dir; /* normalize: 0/1 */
+ size = strlen(name) + 1 + dir; /* GNU tar uses strlen+1 */
+ /* + dir: account for possible '/' */
+
+ memset(&header, 0, sizeof(header));
+ strcpy(header.name, "././@LongLink");
+ memcpy(header.mode, prefilled.mode, sizeof(prefilled));
+ PUT_OCTAL(header.size, size);
+ header.typeflag = type;
+ chksum_and_xwrite(fd, &header);
+
+ /* Write filename[/] and pad the block. */
+ /* dir=0: writes 'name<NUL>', pads */
+ /* dir=1: writes 'name', writes '/<NUL>', pads */
+ dir *= 2;
+ xwrite(fd, name, size - dir);
+ xwrite(fd, "/", dir);
+ size = (-size) & (TAR_BLOCK_SIZE-1);
+ memset(&header, 0, size);
+ xwrite(fd, &header, size);
+}
+#endif
+
+/* Write out a tar header for the specified file/directory/whatever */
+void BUG_tar_header_size(void);
+static int writeTarHeader(struct TarBallInfo *tbInfo,
+ const char *header_name, const char *fileName, struct stat *statbuf)
+{
+ struct TarHeader header;
+
+ if (sizeof(header) != 512)
+ BUG_tar_header_size();
+
+ memset(&header, 0, sizeof(struct TarHeader));
+
+ strncpy(header.name, header_name, sizeof(header.name));
+
+ /* POSIX says to mask mode with 07777. */
+ PUT_OCTAL(header.mode, statbuf->st_mode & 07777);
+ PUT_OCTAL(header.uid, statbuf->st_uid);
+ PUT_OCTAL(header.gid, statbuf->st_gid);
+ memset(header.size, '0', sizeof(header.size)-1); /* Regular file size is handled later */
+ PUT_OCTAL(header.mtime, statbuf->st_mtime);
+
+ /* Enter the user and group names */
+ safe_strncpy(header.uname, get_cached_username(statbuf->st_uid), sizeof(header.uname));
+ safe_strncpy(header.gname, get_cached_groupname(statbuf->st_gid), sizeof(header.gname));
+
+ if (tbInfo->hlInfo) {
+ /* This is a hard link */
+ header.typeflag = LNKTYPE;
+ strncpy(header.linkname, tbInfo->hlInfo->name,
+ sizeof(header.linkname));
+#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+ /* Write out long linkname if needed */
+ if (header.linkname[sizeof(header.linkname)-1])
+ writeLongname(tbInfo->tarFd, GNULONGLINK,
+ tbInfo->hlInfo->name, 0);
+#endif
+ } else if (S_ISLNK(statbuf->st_mode)) {
+ char *lpath = xmalloc_readlink_or_warn(fileName);
+ if (!lpath)
+ return FALSE;
+ header.typeflag = SYMTYPE;
+ strncpy(header.linkname, lpath, sizeof(header.linkname));
+#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+ /* Write out long linkname if needed */
+ if (header.linkname[sizeof(header.linkname)-1])
+ writeLongname(tbInfo->tarFd, GNULONGLINK, lpath, 0);
+#else
+ /* If it is larger than 100 bytes, bail out */
+ if (header.linkname[sizeof(header.linkname)-1]) {
+ free(lpath);
+ bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
+ return FALSE;
+ }
+#endif
+ free(lpath);
+ } else if (S_ISDIR(statbuf->st_mode)) {
+ header.typeflag = DIRTYPE;
+ /* Append '/' only if there is a space for it */
+ if (!header.name[sizeof(header.name)-1])
+ header.name[strlen(header.name)] = '/';
+ } else if (S_ISCHR(statbuf->st_mode)) {
+ header.typeflag = CHRTYPE;
+ PUT_OCTAL(header.devmajor, major(statbuf->st_rdev));
+ PUT_OCTAL(header.devminor, minor(statbuf->st_rdev));
+ } else if (S_ISBLK(statbuf->st_mode)) {
+ header.typeflag = BLKTYPE;
+ PUT_OCTAL(header.devmajor, major(statbuf->st_rdev));
+ PUT_OCTAL(header.devminor, minor(statbuf->st_rdev));
+ } else if (S_ISFIFO(statbuf->st_mode)) {
+ header.typeflag = FIFOTYPE;
+ } else if (S_ISREG(statbuf->st_mode)) {
+ if (sizeof(statbuf->st_size) > 4
+ && statbuf->st_size > (off_t)0777777777777LL
+ ) {
+ bb_error_msg_and_die("cannot store file '%s' "
+ "of size %"OFF_FMT"d, aborting",
+ fileName, statbuf->st_size);
+ }
+ header.typeflag = REGTYPE;
+ PUT_OCTAL(header.size, statbuf->st_size);
+ } else {
+ bb_error_msg("%s: unknown file type", fileName);
+ return FALSE;
+ }
+
+#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+ /* Write out long name if needed */
+ /* (we, like GNU tar, output long linkname *before* long name) */
+ if (header.name[sizeof(header.name)-1])
+ writeLongname(tbInfo->tarFd, GNULONGNAME,
+ header_name, S_ISDIR(statbuf->st_mode));
+#endif
+
+ /* Now write the header out to disk */
+ chksum_and_xwrite(tbInfo->tarFd, &header);
+
+ /* Now do the verbose thing (or not) */
+ if (tbInfo->verboseFlag) {
+ FILE *vbFd = stdout;
+
+ if (tbInfo->tarFd == STDOUT_FILENO) /* If the archive goes to stdout, verbose to stderr */
+ vbFd = stderr;
+ /* GNU "tar cvvf" prints "extended" listing a-la "ls -l" */
+ /* We don't have such excesses here: for us "v" == "vv" */
+ /* '/' is probably a GNUism */
+ fprintf(vbFd, "%s%s\n", header_name,
+ S_ISDIR(statbuf->st_mode) ? "/" : "");
+ }
+
+ return TRUE;
+}
+
+#if ENABLE_FEATURE_TAR_FROM
+static int exclude_file(const llist_t *excluded_files, const char *file)
+{
+ while (excluded_files) {
+ if (excluded_files->data[0] == '/') {
+ if (fnmatch(excluded_files->data, file,
+ FNM_PATHNAME | FNM_LEADING_DIR) == 0)
+ return 1;
+ } else {
+ const char *p;
+
+ for (p = file; p[0] != '\0'; p++) {
+ if ((p == file || p[-1] == '/') && p[0] != '/' &&
+ fnmatch(excluded_files->data, p,
+ FNM_PATHNAME | FNM_LEADING_DIR) == 0)
+ return 1;
+ }
+ }
+ excluded_files = excluded_files->link;
+ }
+
+ return 0;
+}
+#else
+#define exclude_file(excluded_files, file) 0
+#endif
+
+static int writeFileToTarball(const char *fileName, struct stat *statbuf,
+ void *userData, int depth ATTRIBUTE_UNUSED)
+{
+ struct TarBallInfo *tbInfo = (struct TarBallInfo *) userData;
+ const char *header_name;
+ int inputFileFd = -1;
+
+ /* Strip leading '/' (must be before memorizing hardlink's name) */
+ header_name = fileName;
+ while (header_name[0] == '/') {
+ static smallint warned;
+
+ if (!warned) {
+ bb_error_msg("removing leading '/' from member names");
+ warned = 1;
+ }
+ header_name++;
+ }
+
+ if (header_name[0] == '\0')
+ return TRUE;
+
+ /* It is against the rules to archive a socket */
+ if (S_ISSOCK(statbuf->st_mode)) {
+ bb_error_msg("%s: socket ignored", fileName);
+ return TRUE;
+ }
+
+ /*
+ * Check to see if we are dealing with a hard link.
+ * If so -
+ * Treat the first occurance of a given dev/inode as a file while
+ * treating any additional occurances as hard links. This is done
+ * by adding the file information to the HardLinkInfo linked list.
+ */
+ tbInfo->hlInfo = NULL;
+ if (statbuf->st_nlink > 1) {
+ tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf);
+ if (tbInfo->hlInfo == NULL)
+ addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, header_name);
+ }
+
+ /* It is a bad idea to store the archive we are in the process of creating,
+ * so check the device and inode to be sure that this particular file isn't
+ * the new tarball */
+ if (tbInfo->statBuf.st_dev == statbuf->st_dev
+ && tbInfo->statBuf.st_ino == statbuf->st_ino
+ ) {
+ bb_error_msg("%s: file is the archive; skipping", fileName);
+ return TRUE;
+ }
+
+ if (exclude_file(tbInfo->excludeList, header_name))
+ return SKIP;
+
+#if !ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+ if (strlen(header_name) >= NAME_SIZE) {
+ bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
+ return TRUE;
+ }
+#endif
+
+ /* Is this a regular file? */
+ if (tbInfo->hlInfo == NULL && S_ISREG(statbuf->st_mode)) {
+ /* open the file we want to archive, and make sure all is well */
+ inputFileFd = open_or_warn(fileName, O_RDONLY);
+ if (inputFileFd < 0) {
+ return FALSE;
+ }
+ }
+
+ /* Add an entry to the tarball */
+ if (writeTarHeader(tbInfo, header_name, fileName, statbuf) == FALSE) {
+ return FALSE;
+ }
+
+ /* If it was a regular file, write out the body */
+ if (inputFileFd >= 0) {
+ size_t readSize;
+ /* Write the file to the archive. */
+ /* We record size into header first, */
+ /* and then write out file. If file shrinks in between, */
+ /* tar will be corrupted. So we don't allow for that. */
+ /* NB: GNU tar 1.16 warns and pads with zeroes */
+ /* or even seeks back and updates header */
+ bb_copyfd_exact_size(inputFileFd, tbInfo->tarFd, statbuf->st_size);
+ ////off_t readSize;
+ ////readSize = bb_copyfd_size(inputFileFd, tbInfo->tarFd, statbuf->st_size);
+ ////if (readSize != statbuf->st_size && readSize >= 0) {
+ //// bb_error_msg_and_die("short read from %s, aborting", fileName);
+ ////}
+
+ /* Check that file did not grow in between? */
+ /* if (safe_read(inputFileFd, 1) == 1) warn but continue? */
+
+ close(inputFileFd);
+
+ /* Pad the file up to the tar block size */
+ /* (a few tricks here in the name of code size) */
+ readSize = (-(int)statbuf->st_size) & (TAR_BLOCK_SIZE-1);
+ memset(block_buf, 0, readSize);
+ xwrite(tbInfo->tarFd, block_buf, readSize);
+ }
+
+ return TRUE;
+}
+
+#if ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2
+#if !(ENABLE_FEATURE_TAR_GZIP && ENABLE_FEATURE_TAR_BZIP2)
+#define vfork_compressor(tar_fd, gzip) vfork_compressor(tar_fd)
+#endif
+/* Don't inline: vfork scares gcc and pessimizes code */
+static void NOINLINE vfork_compressor(int tar_fd, int gzip)
+{
+ pid_t gzipPid;
+#if ENABLE_FEATURE_TAR_GZIP && ENABLE_FEATURE_TAR_BZIP2
+ const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2";
+#elif ENABLE_FEATURE_TAR_GZIP
+ const char *zip_exec = "gzip";
+#else /* only ENABLE_FEATURE_TAR_BZIP2 */
+ const char *zip_exec = "bzip2";
+#endif
+ // On Linux, vfork never unpauses parent early, although standard
+ // allows for that. Do we want to waste bytes checking for it?
+#define WAIT_FOR_CHILD 0
+ volatile int vfork_exec_errno = 0;
+ struct fd_pair gzipDataPipe;
+#if WAIT_FOR_CHILD
+ struct fd_pair gzipStatusPipe;
+ xpiped_pair(gzipStatusPipe);
+#endif
+ xpiped_pair(gzipDataPipe);
+
+ signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */
+
+#if defined(__GNUC__) && __GNUC__
+ /* Avoid vfork clobbering */
+ (void) &zip_exec;
+#endif
+
+ gzipPid = vfork();
+ if (gzipPid < 0)
+ bb_perror_msg_and_die("can't vfork");
+
+ if (gzipPid == 0) {
+ /* child */
+ /* NB: close _first_, then move fds! */
+ close(gzipDataPipe.wr);
+#if WAIT_FOR_CHILD
+ close(gzipStatusPipe.rd);
+ /* gzipStatusPipe.wr will close only on exec -
+ * parent waits for this close to happen */
+ fcntl(gzipStatusPipe.wr, F_SETFD, FD_CLOEXEC);
+#endif
+ xmove_fd(gzipDataPipe.rd, 0);
+ xmove_fd(tar_fd, 1);
+ /* exec gzip/bzip2 program/applet */
+ BB_EXECLP(zip_exec, zip_exec, "-f", NULL);
+ vfork_exec_errno = errno;
+ _exit(EXIT_FAILURE);
+ }
+
+ /* parent */
+ xmove_fd(gzipDataPipe.wr, tar_fd);
+ close(gzipDataPipe.rd);
+#if WAIT_FOR_CHILD
+ close(gzipStatusPipe.wr);
+ while (1) {
+ char buf;
+ int n;
+
+ /* Wait until child execs (or fails to) */
+ n = full_read(gzipStatusPipe.rd, &buf, 1);
+ if (n < 0 /* && errno == EAGAIN */)
+ continue; /* try it again */
+ }
+ close(gzipStatusPipe.rd);
+#endif
+ if (vfork_exec_errno) {
+ errno = vfork_exec_errno;
+ bb_perror_msg_and_die("cannot exec %s", zip_exec);
+ }
+}
+#endif /* ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2 */
+
+
+/* gcc 4.2.1 inlines it, making code bigger */
+static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
+ int dereferenceFlag, const llist_t *include,
+ const llist_t *exclude, int gzip)
+{
+ int errorFlag = FALSE;
+ struct TarBallInfo tbInfo;
+
+ tbInfo.hlInfoHead = NULL;
+
+ fchmod(tar_fd, 0644);
+ tbInfo.tarFd = tar_fd;
+ tbInfo.verboseFlag = verboseFlag;
+
+ /* Store the stat info for the tarball's file, so
+ * can avoid including the tarball into itself.... */
+ if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0)
+ bb_perror_msg_and_die("cannot stat tar file");
+
+#if ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2
+ if (gzip)
+ vfork_compressor(tbInfo.tarFd, gzip);
+#endif
+
+ tbInfo.excludeList = exclude;
+
+ /* Read the directory/files and iterate over them one at a time */
+ while (include) {
+ if (!recursive_action(include->data, ACTION_RECURSE |
+ (dereferenceFlag ? ACTION_FOLLOWLINKS : 0),
+ writeFileToTarball, writeFileToTarball, &tbInfo, 0))
+ {
+ errorFlag = TRUE;
+ }
+ include = include->link;
+ }
+ /* Write two empty blocks to the end of the archive */
+ memset(block_buf, 0, 2*TAR_BLOCK_SIZE);
+ xwrite(tbInfo.tarFd, block_buf, 2*TAR_BLOCK_SIZE);
+
+ /* To be pedantically correct, we would check if the tarball
+ * is smaller than 20 tar blocks, and pad it if it was smaller,
+ * but that isn't necessary for GNU tar interoperability, and
+ * so is considered a waste of space */
+
+ /* Close so the child process (if any) will exit */
+ close(tbInfo.tarFd);
+
+ /* Hang up the tools, close up shop, head home */
+ if (ENABLE_FEATURE_CLEAN_UP)
+ freeHardLinkInfo(&tbInfo.hlInfoHead);
+
+ if (errorFlag)
+ bb_error_msg("error exit delayed from previous errors");
+
+#if ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2
+ if (gzip) {
+ int status;
+ if (safe_waitpid(-1, &status, 0) == -1)
+ bb_perror_msg("waitpid");
+ else if (!WIFEXITED(status) || WEXITSTATUS(status))
+ /* gzip was killed or has exited with nonzero! */
+ errorFlag = TRUE;
+ }
+#endif
+ return errorFlag;
+}
+#else
+int writeTarFile(int tar_fd, int verboseFlag,
+ int dereferenceFlag, const llist_t *include,
+ const llist_t *exclude, int gzip);
+#endif /* FEATURE_TAR_CREATE */
+
+#if ENABLE_FEATURE_TAR_FROM
+static llist_t *append_file_list_to_list(llist_t *list)
+{
+ FILE *src_stream;
+ char *line;
+ llist_t *newlist = NULL;
+
+ while (list) {
+ src_stream = xfopen(llist_pop(&list), "r");
+ while ((line = xmalloc_fgetline(src_stream)) != NULL) {
+ /* kill trailing '/' unless the string is just "/" */
+ char *cp = last_char_is(line, '/');
+ if (cp > line)
+ *cp = '\0';
+ llist_add_to(&newlist, line);
+ }
+ fclose(src_stream);
+ }
+ return newlist;
+}
+#else
+#define append_file_list_to_list(x) 0
+#endif
+
+#if ENABLE_FEATURE_TAR_COMPRESS
+static char get_header_tar_Z(archive_handle_t *archive_handle)
+{
+ /* Can't lseek over pipes */
+ archive_handle->seek = seek_by_read;
+
+ /* do the decompression, and cleanup */
+ if (xread_char(archive_handle->src_fd) != 0x1f
+ || xread_char(archive_handle->src_fd) != 0x9d
+ ) {
+ bb_error_msg_and_die("invalid magic");
+ }
+
+ archive_handle->src_fd = open_transformer(archive_handle->src_fd, uncompress, "uncompress");
+ archive_handle->offset = 0;
+ while (get_header_tar(archive_handle) == EXIT_SUCCESS)
+ continue;
+
+ /* Can only do one file at a time */
+ return EXIT_FAILURE;
+}
+#else
+#define get_header_tar_Z NULL
+#endif
+
+#ifdef CHECK_FOR_CHILD_EXITCODE
+/* Looks like it isn't needed - tar detects malformed (truncated)
+ * archive if e.g. bunzip2 fails */
+static int child_error;
+
+static void handle_SIGCHLD(int status)
+{
+ /* Actually, 'status' is a signo. We reuse it for other needs */
+
+ /* Wait for any child without blocking */
+ if (wait_any_nohang(&status) < 0)
+ /* wait failed?! I'm confused... */
+ return;
+
+ if (WIFEXITED(status) && WEXITSTATUS(status)==0)
+ /* child exited with 0 */
+ return;
+ /* Cannot happen?
+ if (!WIFSIGNALED(status) && !WIFEXITED(status)) return; */
+ child_error = 1;
+}
+#endif
+
+enum {
+ OPTBIT_KEEP_OLD = 7,
+ USE_FEATURE_TAR_CREATE( OPTBIT_CREATE ,)
+ USE_FEATURE_TAR_CREATE( OPTBIT_DEREFERENCE ,)
+ USE_FEATURE_TAR_BZIP2( OPTBIT_BZIP2 ,)
+ USE_FEATURE_TAR_LZMA( OPTBIT_LZMA ,)
+ USE_FEATURE_TAR_FROM( OPTBIT_INCLUDE_FROM,)
+ USE_FEATURE_TAR_FROM( OPTBIT_EXCLUDE_FROM,)
+ USE_FEATURE_TAR_GZIP( OPTBIT_GZIP ,)
+ USE_FEATURE_TAR_COMPRESS(OPTBIT_COMPRESS ,)
+ OPTBIT_NOPRESERVE_OWN,
+ OPTBIT_NOPRESERVE_PERM,
+ OPT_TEST = 1 << 0, // t
+ OPT_EXTRACT = 1 << 1, // x
+ OPT_BASEDIR = 1 << 2, // C
+ OPT_TARNAME = 1 << 3, // f
+ OPT_2STDOUT = 1 << 4, // O
+ OPT_P = 1 << 5, // p
+ OPT_VERBOSE = 1 << 6, // v
+ OPT_KEEP_OLD = 1 << 7, // k
+ OPT_CREATE = USE_FEATURE_TAR_CREATE( (1<<OPTBIT_CREATE )) + 0, // c
+ OPT_DEREFERENCE = USE_FEATURE_TAR_CREATE( (1<<OPTBIT_DEREFERENCE )) + 0, // h
+ OPT_BZIP2 = USE_FEATURE_TAR_BZIP2( (1<<OPTBIT_BZIP2 )) + 0, // j
+ OPT_LZMA = USE_FEATURE_TAR_LZMA( (1<<OPTBIT_LZMA )) + 0, // a
+ OPT_INCLUDE_FROM = USE_FEATURE_TAR_FROM( (1<<OPTBIT_INCLUDE_FROM)) + 0, // T
+ OPT_EXCLUDE_FROM = USE_FEATURE_TAR_FROM( (1<<OPTBIT_EXCLUDE_FROM)) + 0, // X
+ OPT_GZIP = USE_FEATURE_TAR_GZIP( (1<<OPTBIT_GZIP )) + 0, // z
+ OPT_COMPRESS = USE_FEATURE_TAR_COMPRESS((1<<OPTBIT_COMPRESS )) + 0, // Z
+ OPT_NOPRESERVE_OWN = 1 << OPTBIT_NOPRESERVE_OWN , // no-same-owner
+ OPT_NOPRESERVE_PERM = 1 << OPTBIT_NOPRESERVE_PERM, // no-same-permissions
+};
+#if ENABLE_FEATURE_TAR_LONG_OPTIONS
+static const char tar_longopts[] ALIGN1 =
+ "list\0" No_argument "t"
+ "extract\0" No_argument "x"
+ "directory\0" Required_argument "C"
+ "file\0" Required_argument "f"
+ "to-stdout\0" No_argument "O"
+ "same-permissions\0" No_argument "p"
+ "verbose\0" No_argument "v"
+ "keep-old\0" No_argument "k"
+# if ENABLE_FEATURE_TAR_CREATE
+ "create\0" No_argument "c"
+ "dereference\0" No_argument "h"
+# endif
+# if ENABLE_FEATURE_TAR_BZIP2
+ "bzip2\0" No_argument "j"
+# endif
+# if ENABLE_FEATURE_TAR_LZMA
+ "lzma\0" No_argument "a"
+# endif
+# if ENABLE_FEATURE_TAR_FROM
+ "files-from\0" Required_argument "T"
+ "exclude-from\0" Required_argument "X"
+# endif
+# if ENABLE_FEATURE_TAR_GZIP
+ "gzip\0" No_argument "z"
+# endif
+# if ENABLE_FEATURE_TAR_COMPRESS
+ "compress\0" No_argument "Z"
+# endif
+ "no-same-owner\0" No_argument "\xfd"
+ "no-same-permissions\0" No_argument "\xfe"
+ /* --exclude takes next bit position in option mask, */
+ /* therefore we have to either put it _after_ --no-same-perm */
+ /* or add OPT[BIT]_EXCLUDE before OPT[BIT]_NOPRESERVE_OWN */
+# if ENABLE_FEATURE_TAR_FROM
+ "exclude\0" Required_argument "\xff"
+# endif
+ ;
+#endif
+
+int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int tar_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ char (*get_header_ptr)(archive_handle_t *) = get_header_tar;
+ archive_handle_t *tar_handle;
+ char *base_dir = NULL;
+ const char *tar_filename = "-";
+ unsigned opt;
+ int verboseFlag = 0;
+#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
+ llist_t *excludes = NULL;
+#endif
+
+ /* Initialise default values */
+ tar_handle = init_handle();
+ tar_handle->flags = ARCHIVE_CREATE_LEADING_DIRS
+ | ARCHIVE_PRESERVE_DATE
+ | ARCHIVE_EXTRACT_UNCONDITIONAL;
+
+ /* Prepend '-' to the first argument if required */
+ opt_complementary = "--:" // first arg is options
+ "tt:vv:" // count -t,-v
+ "?:" // bail out with usage instead of error return
+ "X::T::" // cumulative lists
+#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
+ "\xff::" // cumulative lists for --exclude
+#endif
+ USE_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd
+ USE_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive
+ SKIP_FEATURE_TAR_CREATE("t--x:x--t"); // mutually exclusive
+#if ENABLE_FEATURE_TAR_LONG_OPTIONS
+ applet_long_options = tar_longopts;
+#endif
+ opt = getopt32(argv,
+ "txC:f:Opvk"
+ USE_FEATURE_TAR_CREATE( "ch" )
+ USE_FEATURE_TAR_BZIP2( "j" )
+ USE_FEATURE_TAR_LZMA( "a" )
+ USE_FEATURE_TAR_FROM( "T:X:")
+ USE_FEATURE_TAR_GZIP( "z" )
+ USE_FEATURE_TAR_COMPRESS("Z" )
+ , &base_dir // -C dir
+ , &tar_filename // -f filename
+ USE_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T
+ USE_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X
+#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
+ , &excludes // --exclude
+#endif
+ , &verboseFlag // combined count for -t and -v
+ , &verboseFlag // combined count for -t and -v
+ );
+ argv += optind;
+
+ if (verboseFlag) tar_handle->action_header = header_verbose_list;
+ if (verboseFlag == 1) tar_handle->action_header = header_list;
+
+ if (opt & OPT_EXTRACT)
+ tar_handle->action_data = data_extract_all;
+
+ if (opt & OPT_2STDOUT)
+ tar_handle->action_data = data_extract_to_stdout;
+
+ if (opt & OPT_KEEP_OLD)
+ tar_handle->flags &= ~ARCHIVE_EXTRACT_UNCONDITIONAL;
+
+ if (opt & OPT_NOPRESERVE_OWN)
+ tar_handle->flags |= ARCHIVE_NOPRESERVE_OWN;
+
+ if (opt & OPT_NOPRESERVE_PERM)
+ tar_handle->flags |= ARCHIVE_NOPRESERVE_PERM;
+
+ if (opt & OPT_GZIP)
+ get_header_ptr = get_header_tar_gz;
+
+ if (opt & OPT_BZIP2)
+ get_header_ptr = get_header_tar_bz2;
+
+ if (opt & OPT_LZMA)
+ get_header_ptr = get_header_tar_lzma;
+
+ if (opt & OPT_COMPRESS)
+ get_header_ptr = get_header_tar_Z;
+
+#if ENABLE_FEATURE_TAR_FROM
+ tar_handle->reject = append_file_list_to_list(tar_handle->reject);
+#if ENABLE_FEATURE_TAR_LONG_OPTIONS
+ /* Append excludes to reject */
+ while (excludes) {
+ llist_t *next = excludes->link;
+ excludes->link = tar_handle->reject;
+ tar_handle->reject = excludes;
+ excludes = next;
+ }
+#endif
+ tar_handle->accept = append_file_list_to_list(tar_handle->accept);
+#endif
+
+ /* Setup an array of filenames to work with */
+ /* TODO: This is the same as in ar, separate function ? */
+ while (*argv) {
+ /* kill trailing '/' unless the string is just "/" */
+ char *cp = last_char_is(*argv, '/');
+ if (cp > *argv)
+ *cp = '\0';
+ llist_add_to_end(&tar_handle->accept, *argv);
+ argv++;
+ }
+
+ if (tar_handle->accept || tar_handle->reject)
+ tar_handle->filter = filter_accept_reject_list;
+
+ /* Open the tar file */
+ {
+ FILE *tar_stream;
+ int flags;
+
+ if (opt & OPT_CREATE) {
+ /* Make sure there is at least one file to tar up. */
+ if (tar_handle->accept == NULL)
+ bb_error_msg_and_die("empty archive");
+
+ tar_stream = stdout;
+ /* Mimicking GNU tar 1.15.1: */
+ flags = O_WRONLY|O_CREAT|O_TRUNC;
+ /* was doing unlink; open(O_WRONLY|O_CREAT|O_EXCL); why? */
+ } else {
+ tar_stream = stdin;
+ flags = O_RDONLY;
+ }
+
+ if (LONE_DASH(tar_filename)) {
+ tar_handle->src_fd = fileno(tar_stream);
+ tar_handle->seek = seek_by_read;
+ } else {
+ tar_handle->src_fd = xopen(tar_filename, flags);
+ }
+ }
+
+ if (base_dir)
+ xchdir(base_dir);
+
+#ifdef CHECK_FOR_CHILD_EXITCODE
+ /* We need to know whether child (gzip/bzip/etc) exits abnormally */
+ signal(SIGCHLD, handle_SIGCHLD);
+#endif
+
+ /* create an archive */
+ if (opt & OPT_CREATE) {
+#if ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2
+ int zipMode = 0;
+ if (ENABLE_FEATURE_TAR_GZIP && (opt & OPT_GZIP))
+ zipMode = 1;
+ if (ENABLE_FEATURE_TAR_BZIP2 && (opt & OPT_BZIP2))
+ zipMode = 2;
+#endif
+ /* NB: writeTarFile() closes tar_handle->src_fd */
+ return writeTarFile(tar_handle->src_fd, verboseFlag, opt & OPT_DEREFERENCE,
+ tar_handle->accept,
+ tar_handle->reject, zipMode);
+ }
+
+ while (get_header_ptr(tar_handle) == EXIT_SUCCESS)
+ continue;
+
+ /* Check that every file that should have been extracted was */
+ while (tar_handle->accept) {
+ if (!find_list_entry(tar_handle->reject, tar_handle->accept->data)
+ && !find_list_entry(tar_handle->passed, tar_handle->accept->data)
+ ) {
+ bb_error_msg_and_die("%s: not found in archive",
+ tar_handle->accept->data);
+ }
+ tar_handle->accept = tar_handle->accept->link;
+ }
+ if (ENABLE_FEATURE_CLEAN_UP /* && tar_handle->src_fd != STDIN_FILENO */)
+ close(tar_handle->src_fd);
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/archival/unzip.c b/cleopatre/busybox-1.11.1-spc300/archival/unzip.c
new file mode 100644
index 0000000000..c7d39daefc
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/archival/unzip.c
@@ -0,0 +1,408 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini unzip implementation for busybox
+ *
+ * Copyright (C) 2004 by Ed Clark
+ *
+ * Loosely based on original busybox unzip applet by Laurence Anderson.
+ * All options and features should work in this version.
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+/* For reference see
+ * http://www.pkware.com/company/standards/appnote/
+ * http://www.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
+ */
+
+/* TODO
+ * Endian issues
+ * Zip64 + other methods
+ * Improve handling of zip format, ie.
+ * - deferred CRC, comp. & uncomp. lengths (zip header flags bit 3)
+ * - unix file permissions, etc.
+ * - central directory
+ */
+
+#include "libbb.h"
+#include "unarchive.h"
+
+enum {
+#if BB_BIG_ENDIAN
+ ZIP_FILEHEADER_MAGIC = 0x504b0304,
+ ZIP_CDS_MAGIC = 0x504b0102,
+ ZIP_CDS_END_MAGIC = 0x504b0506,
+ ZIP_DD_MAGIC = 0x504b0708,
+#else
+ ZIP_FILEHEADER_MAGIC = 0x04034b50,
+ ZIP_CDS_MAGIC = 0x02014b50,
+ ZIP_CDS_END_MAGIC = 0x06054b50,
+ ZIP_DD_MAGIC = 0x08074b50,
+#endif
+};
+
+#define ZIP_HEADER_LEN 26
+
+typedef union {
+ uint8_t raw[ZIP_HEADER_LEN];
+ struct {
+ uint16_t version; /* 0-1 */
+ uint16_t flags; /* 2-3 */
+ uint16_t method; /* 4-5 */
+ uint16_t modtime; /* 6-7 */
+ uint16_t moddate; /* 8-9 */
+ uint32_t crc32 ATTRIBUTE_PACKED; /* 10-13 */
+ uint32_t cmpsize ATTRIBUTE_PACKED; /* 14-17 */
+ uint32_t ucmpsize ATTRIBUTE_PACKED; /* 18-21 */
+ uint16_t filename_len; /* 22-23 */
+ uint16_t extra_len; /* 24-25 */
+ } formatted ATTRIBUTE_PACKED;
+} zip_header_t; /* ATTRIBUTE_PACKED - gcc 4.2.1 doesn't like it (spews warning) */
+
+/* Check the offset of the last element, not the length. This leniency
+ * allows for poor packing, whereby the overall struct may be too long,
+ * even though the elements are all in the right place.
+ */
+struct BUG_zip_header_must_be_26_bytes {
+ char BUG_zip_header_must_be_26_bytes[
+ offsetof(zip_header_t, formatted.extra_len) + 2 ==
+ ZIP_HEADER_LEN ? 1 : -1];
+};
+
+#define FIX_ENDIANNESS(zip_header) do { \
+ (zip_header).formatted.version = SWAP_LE16((zip_header).formatted.version ); \
+ (zip_header).formatted.flags = SWAP_LE16((zip_header).formatted.flags ); \
+ (zip_header).formatted.method = SWAP_LE16((zip_header).formatted.method ); \
+ (zip_header).formatted.modtime = SWAP_LE16((zip_header).formatted.modtime ); \
+ (zip_header).formatted.moddate = SWAP_LE16((zip_header).formatted.moddate ); \
+ (zip_header).formatted.crc32 = SWAP_LE32((zip_header).formatted.crc32 ); \
+ (zip_header).formatted.cmpsize = SWAP_LE32((zip_header).formatted.cmpsize ); \
+ (zip_header).formatted.ucmpsize = SWAP_LE32((zip_header).formatted.ucmpsize ); \
+ (zip_header).formatted.filename_len = SWAP_LE16((zip_header).formatted.filename_len); \
+ (zip_header).formatted.extra_len = SWAP_LE16((zip_header).formatted.extra_len ); \
+} while (0)
+
+static void unzip_skip(int fd, off_t skip)
+{
+ bb_copyfd_exact_size(fd, -1, skip);
+}
+
+static void unzip_create_leading_dirs(const char *fn)
+{
+ /* Create all leading directories */
+ char *name = xstrdup(fn);
+ if (bb_make_directory(dirname(name), 0777, FILEUTILS_RECUR)) {
+ bb_error_msg_and_die("exiting"); /* bb_make_directory is noisy */
+ }
+ free(name);
+}
+
+static void unzip_extract(zip_header_t *zip_header, int src_fd, int dst_fd)
+{
+ if (zip_header->formatted.method == 0) {
+ /* Method 0 - stored (not compressed) */
+ off_t size = zip_header->formatted.ucmpsize;
+ if (size)
+ bb_copyfd_exact_size(src_fd, dst_fd, size);
+ } else {
+ /* Method 8 - inflate */
+ inflate_unzip_result res;
+ if (inflate_unzip(&res, zip_header->formatted.cmpsize, src_fd, dst_fd) < 0)
+ bb_error_msg_and_die("inflate error");
+ /* Validate decompression - crc */
+ if (zip_header->formatted.crc32 != (res.crc ^ 0xffffffffL)) {
+ bb_error_msg_and_die("crc error");
+ }
+ /* Validate decompression - size */
+ if (zip_header->formatted.ucmpsize != res.bytes_out) {
+ /* Don't die. Who knows, maybe len calculation
+ * was botched somewhere. After all, crc matched! */
+ bb_error_msg("bad length");
+ }
+ }
+}
+
+int unzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int unzip_main(int argc, char **argv)
+{
+ enum { O_PROMPT, O_NEVER, O_ALWAYS };
+
+ zip_header_t zip_header;
+ smallint verbose = 1;
+ smallint listing = 0;
+ smallint overwrite = O_PROMPT;
+ unsigned total_size;
+ unsigned total_entries;
+ int src_fd = -1;
+ int dst_fd = -1;
+ char *src_fn = NULL;
+ char *dst_fn = NULL;
+ llist_t *zaccept = NULL;
+ llist_t *zreject = NULL;
+ char *base_dir = NULL;
+ int i, opt;
+ int opt_range = 0;
+ char key_buf[80];
+ struct stat stat_buf;
+
+ /* '-' makes getopt return 1 for non-options */
+ while ((opt = getopt(argc, argv, "-d:lnopqx")) != -1) {
+ switch (opt_range) {
+ case 0: /* Options */
+ switch (opt) {
+ case 'l': /* List */
+ listing = 1;
+ break;
+
+ case 'n': /* Never overwrite existing files */
+ overwrite = O_NEVER;
+ break;
+
+ case 'o': /* Always overwrite existing files */
+ overwrite = O_ALWAYS;
+ break;
+
+ case 'p': /* Extract files to stdout and fall through to set verbosity */
+ dst_fd = STDOUT_FILENO;
+
+ case 'q': /* Be quiet */
+ verbose = 0;
+ break;
+
+ case 1: /* The zip file */
+ /* +5: space for ".zip" and NUL */
+ src_fn = xmalloc(strlen(optarg) + 5);
+ strcpy(src_fn, optarg);
+ opt_range++;
+ break;
+
+ default:
+ bb_show_usage();
+
+ }
+ break;
+
+ case 1: /* Include files */
+ if (opt == 1) {
+ llist_add_to(&zaccept, optarg);
+ break;
+ }
+ if (opt == 'd') {
+ base_dir = optarg;
+ opt_range += 2;
+ break;
+ }
+ if (opt == 'x') {
+ opt_range++;
+ break;
+ }
+ bb_show_usage();
+
+ case 2 : /* Exclude files */
+ if (opt == 1) {
+ llist_add_to(&zreject, optarg);
+ break;
+ }
+ if (opt == 'd') { /* Extract to base directory */
+ base_dir = optarg;
+ opt_range++;
+ break;
+ }
+ /* fall through */
+
+ default:
+ bb_show_usage();
+ }
+ }
+
+ if (src_fn == NULL) {
+ bb_show_usage();
+ }
+
+ /* Open input file */
+ if (LONE_DASH(src_fn)) {
+ src_fd = STDIN_FILENO;
+ /* Cannot use prompt mode since zip data is arriving on STDIN */
+ if (overwrite == O_PROMPT)
+ overwrite = O_NEVER;
+ } else {
+ static const char extn[][5] = {"", ".zip", ".ZIP"};
+ int orig_src_fn_len = strlen(src_fn);
+
+ for (i = 0; (i < 3) && (src_fd == -1); i++) {
+ strcpy(src_fn + orig_src_fn_len, extn[i]);
+ src_fd = open(src_fn, O_RDONLY);
+ }
+ if (src_fd == -1) {
+ src_fn[orig_src_fn_len] = '\0';
+ bb_error_msg_and_die("can't open %s, %s.zip, %s.ZIP", src_fn, src_fn, src_fn);
+ }
+ }
+
+ /* Change dir if necessary */
+ if (base_dir)
+ xchdir(base_dir);
+
+ if (verbose) {
+ printf("Archive: %s\n", src_fn);
+ if (listing){
+ puts(" Length Date Time Name\n"
+ " -------- ---- ---- ----");
+ }
+ }
+
+ total_size = 0;
+ total_entries = 0;
+ while (1) {
+ uint32_t magic;
+
+ /* Check magic number */
+ xread(src_fd, &magic, 4);
+ if (magic == ZIP_CDS_MAGIC)
+ break;
+ if (magic != ZIP_FILEHEADER_MAGIC)
+ bb_error_msg_and_die("invalid zip magic %08X", magic);
+
+ /* Read the file header */
+ xread(src_fd, zip_header.raw, ZIP_HEADER_LEN);
+ FIX_ENDIANNESS(zip_header);
+ if ((zip_header.formatted.method != 0) && (zip_header.formatted.method != 8)) {
+ bb_error_msg_and_die("unsupported method %d", zip_header.formatted.method);
+ }
+
+ /* Read filename */
+ free(dst_fn);
+ dst_fn = xzalloc(zip_header.formatted.filename_len + 1);
+ xread(src_fd, dst_fn, zip_header.formatted.filename_len);
+
+ /* Skip extra header bytes */
+ unzip_skip(src_fd, zip_header.formatted.extra_len);
+
+ /* Filter zip entries */
+ if (find_list_entry(zreject, dst_fn)
+ || (zaccept && !find_list_entry(zaccept, dst_fn))
+ ) { /* Skip entry */
+ i = 'n';
+
+ } else { /* Extract entry */
+ if (listing) { /* List entry */
+ if (verbose) {
+ unsigned dostime = zip_header.formatted.modtime | (zip_header.formatted.moddate << 16);
+ printf("%9u %02u-%02u-%02u %02u:%02u %s\n",
+ zip_header.formatted.ucmpsize,
+ (dostime & 0x01e00000) >> 21,
+ (dostime & 0x001f0000) >> 16,
+ (((dostime & 0xfe000000) >> 25) + 1980) % 100,
+ (dostime & 0x0000f800) >> 11,
+ (dostime & 0x000007e0) >> 5,
+ dst_fn);
+ total_size += zip_header.formatted.ucmpsize;
+ total_entries++;
+ } else {
+ /* short listing -- filenames only */
+ puts(dst_fn);
+ }
+ i = 'n';
+ } else if (dst_fd == STDOUT_FILENO) { /* Extracting to STDOUT */
+ i = -1;
+ } else if (last_char_is(dst_fn, '/')) { /* Extract directory */
+ if (stat(dst_fn, &stat_buf) == -1) {
+ if (errno != ENOENT) {
+ bb_perror_msg_and_die("cannot stat '%s'",dst_fn);
+ }
+ if (verbose) {
+ printf(" creating: %s\n", dst_fn);
+ }
+ unzip_create_leading_dirs(dst_fn);
+ if (bb_make_directory(dst_fn, 0777, 0)) {
+ bb_error_msg_and_die("exiting");
+ }
+ } else {
+ if (!S_ISDIR(stat_buf.st_mode)) {
+ bb_error_msg_and_die("'%s' exists but is not directory", dst_fn);
+ }
+ }
+ i = 'n';
+
+ } else { /* Extract file */
+ _check_file:
+ if (stat(dst_fn, &stat_buf) == -1) { /* File does not exist */
+ if (errno != ENOENT) {
+ bb_perror_msg_and_die("cannot stat '%s'",dst_fn);
+ }
+ i = 'y';
+ } else { /* File already exists */
+ if (overwrite == O_NEVER) {
+ i = 'n';
+ } else if (S_ISREG(stat_buf.st_mode)) { /* File is regular file */
+ if (overwrite == O_ALWAYS) {
+ i = 'y';
+ } else {
+ printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", dst_fn);
+ if (!fgets(key_buf, sizeof(key_buf), stdin)) {
+ bb_perror_msg_and_die("cannot read input");
+ }
+ i = key_buf[0];
+ }
+ } else { /* File is not regular file */
+ bb_error_msg_and_die("'%s' exists but is not regular file",dst_fn);
+ }
+ }
+ }
+ }
+
+ switch (i) {
+ case 'A':
+ overwrite = O_ALWAYS;
+ case 'y': /* Open file and fall into unzip */
+ unzip_create_leading_dirs(dst_fn);
+ dst_fd = xopen(dst_fn, O_WRONLY | O_CREAT | O_TRUNC);
+ case -1: /* Unzip */
+ if (verbose) {
+ printf(" inflating: %s\n", dst_fn);
+ }
+ unzip_extract(&zip_header, src_fd, dst_fd);
+ if (dst_fd != STDOUT_FILENO) {
+ /* closing STDOUT is potentially bad for future business */
+ close(dst_fd);
+ }
+ break;
+
+ case 'N':
+ overwrite = O_NEVER;
+ case 'n':
+ /* Skip entry data */
+ unzip_skip(src_fd, zip_header.formatted.cmpsize);
+ break;
+
+ case 'r':
+ /* Prompt for new name */
+ printf("new name: ");
+ if (!fgets(key_buf, sizeof(key_buf), stdin)) {
+ bb_perror_msg_and_die("cannot read input");
+ }
+ free(dst_fn);
+ dst_fn = xstrdup(key_buf);
+ chomp(dst_fn);
+ goto _check_file;
+
+ default:
+ printf("error: invalid response [%c]\n",(char)i);
+ goto _check_file;
+ }
+
+ /* Data descriptor section */
+ if (zip_header.formatted.flags & 4) {
+ /* skip over duplicate crc, compressed size and uncompressed size */
+ unzip_skip(src_fd, 12);
+ }
+ }
+
+ if (listing && verbose) {
+ printf(" -------- -------\n"
+ "%9d %d files\n",
+ total_size, total_entries);
+ }
+
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/console-tools/Config.in b/cleopatre/busybox-1.11.1-spc300/console-tools/Config.in
new file mode 100644
index 0000000000..4b7f02d257
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/console-tools/Config.in
@@ -0,0 +1,111 @@
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Console Utilities"
+
+config CHVT
+ bool "chvt"
+ default n
+ help
+ This program is used to change to another terminal.
+ Example: chvt 4 (change to terminal /dev/tty4)
+
+config CLEAR
+ bool "clear"
+ default n
+ help
+ This program clears the terminal screen.
+
+config DEALLOCVT
+ bool "deallocvt"
+ default n
+ help
+ This program deallocates unused virtual consoles.
+
+config DUMPKMAP
+ bool "dumpkmap"
+ default n
+ help
+ This program dumps the kernel's keyboard translation table to
+ stdout, in binary format. You can then use loadkmap to load it.
+
+config KBD_MODE
+ bool "kbd_mode"
+ default n
+ help
+ This program reports and sets keyboard mode.
+
+config LOADFONT
+ bool "loadfont"
+ default n
+ help
+ This program loads a console font from standard input.
+
+config LOADKMAP
+ bool "loadkmap"
+ default n
+ help
+ This program loads a keyboard translation table from
+ standard input.
+
+config OPENVT
+ bool "openvt"
+ default n
+ help
+ This program is used to start a command on an unused
+ virtual terminal.
+
+config RESET
+ bool "reset"
+ default n
+ help
+ This program is used to reset the terminal screen, if it
+ gets messed up.
+
+config RESIZE
+ bool "resize"
+ default n
+ help
+ This program is used to (re)set the width and height of your current
+ terminal.
+
+config FEATURE_RESIZE_PRINT
+ bool "Print environment variables"
+ default n
+ depends on RESIZE
+ help
+ Prints the newly set size (number of columns and rows) of
+ the terminal.
+ E.g.:
+ COLUMNS=80;LINES=44;export COLUMNS LINES;
+
+config SETCONSOLE
+ bool "setconsole"
+ default n
+ help
+ This program redirects the system console to another device,
+ like the current tty while logged in via telnet.
+
+config FEATURE_SETCONSOLE_LONG_OPTIONS
+ bool "Enable long options"
+ default n
+ depends on SETCONSOLE && GETOPT_LONG
+ help
+ Support long options for the setconsole applet.
+
+config SETKEYCODES
+ bool "setkeycodes"
+ default n
+ help
+ This program loads entries into the kernel's scancode-to-keycode
+ map, allowing unusual keyboards to generate usable keycodes.
+
+config SETLOGCONS
+ bool "setlogcons"
+ default n
+ help
+ This program redirects the output console of kernel messages.
+
+endmenu
diff --git a/cleopatre/busybox-1.11.1-spc300/console-tools/Kbuild b/cleopatre/busybox-1.11.1-spc300/console-tools/Kbuild
new file mode 100644
index 0000000000..cf3825ec62
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/console-tools/Kbuild
@@ -0,0 +1,20 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+lib-y:=
+lib-$(CONFIG_CHVT) += chvt.o
+lib-$(CONFIG_CLEAR) += clear.o
+lib-$(CONFIG_DEALLOCVT) += deallocvt.o
+lib-$(CONFIG_DUMPKMAP) += dumpkmap.o
+lib-$(CONFIG_SETCONSOLE) += setconsole.o
+lib-$(CONFIG_KBD_MODE) += kbd_mode.o
+lib-$(CONFIG_LOADFONT) += loadfont.o
+lib-$(CONFIG_LOADKMAP) += loadkmap.o
+lib-$(CONFIG_OPENVT) += openvt.o
+lib-$(CONFIG_RESET) += reset.o
+lib-$(CONFIG_RESIZE) += resize.o
+lib-$(CONFIG_SETKEYCODES) += setkeycodes.o
+lib-$(CONFIG_SETLOGCONS) += setlogcons.o
diff --git a/cleopatre/busybox-1.11.1-spc300/console-tools/chvt.c b/cleopatre/busybox-1.11.1-spc300/console-tools/chvt.c
new file mode 100644
index 0000000000..ea3e7c0485
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/console-tools/chvt.c
@@ -0,0 +1,25 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini chvt implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+int chvt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int chvt_main(int argc, char **argv)
+{
+ int num;
+
+ if (argc != 2) {
+ bb_show_usage();
+ }
+
+ num = xatou_range(argv[1], 1, 63);
+ /* double cast suppresses "cast to ptr from int of different size" */
+ console_make_active(get_console_fd(), num);
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/console-tools/clear.c b/cleopatre/busybox-1.11.1-spc300/console-tools/clear.c
new file mode 100644
index 0000000000..0d94e35b82
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/console-tools/clear.c
@@ -0,0 +1,19 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini clear implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ */
+
+/* no options, no getopt */
+
+#include "libbb.h"
+
+int clear_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int clear_main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
+{
+ return printf("\033[H\033[J") != 6;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/console-tools/deallocvt.c b/cleopatre/busybox-1.11.1-spc300/console-tools/deallocvt.c
new file mode 100644
index 0000000000..1200cae1dd
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/console-tools/deallocvt.c
@@ -0,0 +1,33 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Disallocate virtual terminal(s)
+ *
+ * Copyright (C) 2003 by Tito Ragusa <farmatito@tiscali.it>
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* no options, no getopt */
+
+#include "libbb.h"
+
+/* From <linux/vt.h> */
+enum { VT_DISALLOCATE = 0x5608 }; /* free memory associated to vt */
+
+int deallocvt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int deallocvt_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ /* num = 0 deallocate all unused consoles */
+ int num = 0;
+
+ if (argv[1]) {
+ if (argv[2])
+ bb_show_usage();
+ num = xatou_range(argv[1], 1, 63);
+ }
+
+ /* double cast suppresses "cast to ptr from int of different size" */
+ xioctl(get_console_fd(), VT_DISALLOCATE, (void *)(ptrdiff_t)num);
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/console-tools/dumpkmap.c b/cleopatre/busybox-1.11.1-spc300/console-tools/dumpkmap.c
new file mode 100644
index 0000000000..1adfdd7384
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/console-tools/dumpkmap.c
@@ -0,0 +1,69 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini dumpkmap implementation for busybox
+ *
+ * Copyright (C) Arne Bernin <arne@matrix.loopback.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ */
+/* no options, no getopt */
+
+#include "libbb.h"
+
+/* From <linux/kd.h> */
+struct kbentry {
+ unsigned char kb_table;
+ unsigned char kb_index;
+ unsigned short kb_value;
+};
+#define KDGKBENT 0x4B46 /* gets one entry in translation table */
+
+/* From <linux/keyboard.h> */
+#define NR_KEYS 128
+#define MAX_NR_KEYMAPS 256
+
+int dumpkmap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int dumpkmap_main(int ATTRIBUTE_UNUSED argc, char ATTRIBUTE_UNUSED **argv)
+{
+ struct kbentry ke;
+ int i, j, fd;
+ RESERVE_CONFIG_BUFFER(flags,MAX_NR_KEYMAPS);
+
+/* bb_warn_ignoring_args(argc>=2);*/
+
+ fd = xopen(CURRENT_VC, O_RDWR);
+
+ write(STDOUT_FILENO, "bkeymap", 7);
+
+ /* Here we want to set everything to 0 except for indexes:
+ * [0-2] [4-6] [8-10] [12] */
+ memset(flags, 0x00, MAX_NR_KEYMAPS);
+ memset(flags, 0x01, 13);
+ flags[3] = flags[7] = flags[11] = 0;
+
+ /* dump flags */
+ write(STDOUT_FILENO, flags, MAX_NR_KEYMAPS);
+
+ for (i = 0; i < MAX_NR_KEYMAPS; i++) {
+ if (flags[i] == 1) {
+ for (j = 0; j < NR_KEYS; j++) {
+ ke.kb_index = j;
+ ke.kb_table = i;
+ if (!ioctl_or_perror(fd, KDGKBENT, &ke,
+ "ioctl failed with %s, %s, %p",
+ (char *)&ke.kb_index,
+ (char *)&ke.kb_table,
+ &ke.kb_value)
+ ) {
+ write(STDOUT_FILENO, (void*)&ke.kb_value, 2);
+ }
+ }
+ }
+ }
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ close(fd);
+ RELEASE_CONFIG_BUFFER(flags);
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/console-tools/kbd_mode.c b/cleopatre/busybox-1.11.1-spc300/console-tools/kbd_mode.c
new file mode 100644
index 0000000000..1614957192
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/console-tools/kbd_mode.c
@@ -0,0 +1,55 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini kbd_mode implementation for busybox
+ *
+ * Copyright (C) 2007 Loïc Grenié <loic.grenie@gmail.com>
+ * written using Andries Brouwer <aeb@cwi.nl>'s kbd_mode from
+ * console-utils v0.2.3, licensed under GNU GPLv2
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ */
+
+#include "libbb.h"
+#include <linux/kd.h>
+
+int kbd_mode_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int kbd_mode_main(int ATTRIBUTE_UNUSED argc, char **argv)
+{
+ int fd;
+ unsigned opt;
+ enum {
+ SCANCODE = (1<<0),
+ ASCII = (1<<1),
+ MEDIUMRAW= (1<<2),
+ UNICODE = (1<<3)
+ };
+ static const char KD_xxx[] ALIGN1 = "saku";
+ opt = getopt32(argv, KD_xxx);
+ fd = get_console_fd();
+/* if (fd < 0)
+ return EXIT_FAILURE;
+*/
+ if (!opt) { /* print current setting */
+ const char *mode = "unknown";
+ int m;
+
+ ioctl(fd, KDGKBMODE, &m);
+ if (m == K_RAW)
+ mode = "raw (scancode)";
+ else if (m == K_XLATE)
+ mode = "default (ASCII)";
+ else if (m == K_MEDIUMRAW)
+ mode = "mediumraw (keycode)";
+ else if (m == K_UNICODE)
+ mode = "Unicode (UTF-8)";
+ printf("The keyboard is in %s mode\n", mode);
+ } else {
+ opt = opt & UNICODE ? 3 : opt >> 1;
+ xioctl(fd, KDSKBMODE, &opt);
+ }
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close(fd);
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/console-tools/loadfont.c b/cleopatre/busybox-1.11.1-spc300/console-tools/loadfont.c
new file mode 100644
index 0000000000..843f4b035b
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/console-tools/loadfont.c
@@ -0,0 +1,181 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * loadfont.c - Eugene Crosser & Andries Brouwer
+ *
+ * Version 0.96bb
+ *
+ * Loads the console font, and possibly the corresponding screen map(s).
+ * (Adapted for busybox by Matej Vela.)
+ */
+#include "libbb.h"
+#include <sys/kd.h>
+
+enum {
+ PSF_MAGIC1 = 0x36,
+ PSF_MAGIC2 = 0x04,
+
+ PSF_MODE512 = 0x01,
+ PSF_MODEHASTAB = 0x02,
+ PSF_MAXMODE = 0x03,
+ PSF_SEPARATOR = 0xFFFF
+};
+
+struct psf_header {
+ unsigned char magic1, magic2; /* Magic number */
+ unsigned char mode; /* PSF font mode */
+ unsigned char charsize; /* Character size */
+};
+
+#define PSF_MAGIC_OK(x) ((x).magic1 == PSF_MAGIC1 && (x).magic2 == PSF_MAGIC2)
+
+static void do_loadfont(int fd, unsigned char *inbuf, int unit, int fontsize)
+{
+ char *buf;
+ int i;
+
+ if (unit < 1 || unit > 32)
+ bb_error_msg_and_die("bad character size %d", unit);
+
+ buf = xzalloc(16 * 1024);
+ /*memset(buf, 0, 16 * 1024);*/
+ for (i = 0; i < fontsize; i++)
+ memcpy(buf + (32 * i), inbuf + (unit * i), unit);
+
+#if defined(PIO_FONTX) && !defined(__sparc__)
+ {
+ struct consolefontdesc cfd;
+
+ cfd.charcount = fontsize;
+ cfd.charheight = unit;
+ cfd.chardata = buf;
+
+ if (!ioctl_or_perror(fd, PIO_FONTX, &cfd, "PIO_FONTX ioctl failed (will try PIO_FONT)"))
+ goto ret; /* success */
+ }
+#endif
+ xioctl(fd, PIO_FONT, buf);
+ ret:
+ free(buf);
+}
+
+static void
+do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize)
+{
+ struct unimapinit advice;
+ struct unimapdesc ud;
+ struct unipair *up;
+ int ct = 0, maxct;
+ int glyph;
+ uint16_t unicode;
+
+ maxct = tailsz; /* more than enough */
+ up = xmalloc(maxct * sizeof(struct unipair));
+
+ for (glyph = 0; glyph < fontsize; glyph++) {
+ while (tailsz >= 2) {
+ unicode = (((uint16_t) inbuf[1]) << 8) + inbuf[0];
+ tailsz -= 2;
+ inbuf += 2;
+ if (unicode == PSF_SEPARATOR)
+ break;
+ up[ct].unicode = unicode;
+ up[ct].fontpos = glyph;
+ ct++;
+ }
+ }
+
+ /* Note: after PIO_UNIMAPCLR and before PIO_UNIMAP
+ this printf did not work on many kernels */
+
+ advice.advised_hashsize = 0;
+ advice.advised_hashstep = 0;
+ advice.advised_hashlevel = 0;
+ xioctl(fd, PIO_UNIMAPCLR, &advice);
+ ud.entry_ct = ct;
+ ud.entries = up;
+ xioctl(fd, PIO_UNIMAP, &ud);
+}
+
+static void loadnewfont(int fd)
+{
+ enum { INBUF_SIZE = 32*1024 + 1 };
+
+ int unit;
+ unsigned inputlth, offset;
+ /* Was on stack, but 32k is a bit too much: */
+ unsigned char *inbuf = xmalloc(INBUF_SIZE);
+
+ /*
+ * We used to look at the length of the input file
+ * with stat(); now that we accept compressed files,
+ * just read the entire file.
+ */
+ inputlth = full_read(STDIN_FILENO, inbuf, INBUF_SIZE);
+ if (inputlth < 0)
+ bb_perror_msg_and_die("error reading input font");
+ if (inputlth >= INBUF_SIZE)
+ bb_error_msg_and_die("font too large");
+
+ /* test for psf first */
+ {
+ struct psf_header psfhdr;
+ int fontsize;
+ int hastable;
+ unsigned head0, head;
+
+ if (inputlth < sizeof(struct psf_header))
+ goto no_psf;
+
+ psfhdr = *(struct psf_header *) &inbuf[0];
+
+ if (!PSF_MAGIC_OK(psfhdr))
+ goto no_psf;
+
+ if (psfhdr.mode > PSF_MAXMODE)
+ bb_error_msg_and_die("unsupported psf file mode");
+ fontsize = ((psfhdr.mode & PSF_MODE512) ? 512 : 256);
+#if !defined(PIO_FONTX) || defined(__sparc__)
+ if (fontsize != 256)
+ bb_error_msg_and_die("only fontsize 256 supported");
+#endif
+ hastable = (psfhdr.mode & PSF_MODEHASTAB);
+ unit = psfhdr.charsize;
+ head0 = sizeof(struct psf_header);
+
+ head = head0 + fontsize * unit;
+ if (head > inputlth || (!hastable && head != inputlth))
+ bb_error_msg_and_die("input file: bad length");
+ do_loadfont(fd, inbuf + head0, unit, fontsize);
+ if (hastable)
+ do_loadtable(fd, inbuf + head, inputlth - head, fontsize);
+ return;
+ }
+
+ no_psf:
+ /* file with three code pages? */
+ if (inputlth == 9780) {
+ offset = 40;
+ unit = 16;
+ } else {
+ /* bare font */
+ if (inputlth & 0377)
+ bb_error_msg_and_die("bad input file size");
+ offset = 0;
+ unit = inputlth / 256;
+ }
+ do_loadfont(fd, inbuf + offset, unit, 256);
+}
+
+int loadfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int loadfont_main(int argc, char **argv ATTRIBUTE_UNUSED)
+{
+ int fd;
+
+ if (argc != 1)
+ bb_show_usage();
+
+ fd = xopen(CURRENT_VC, O_RDWR);
+ loadnewfont(fd);
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/console-tools/loadkmap.c b/cleopatre/busybox-1.11.1-spc300/console-tools/loadkmap.c
new file mode 100644
index 0000000000..28e53ebcad
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/console-tools/loadkmap.c
@@ -0,0 +1,63 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini loadkmap implementation for busybox
+ *
+ * Copyright (C) 1998 Enrique Zanardi <ezanardi@ull.es>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ */
+
+#include "libbb.h"
+
+#define BINARY_KEYMAP_MAGIC "bkeymap"
+
+/* From <linux/kd.h> */
+struct kbentry {
+ unsigned char kb_table;
+ unsigned char kb_index;
+ unsigned short kb_value;
+};
+/* sets one entry in translation table */
+#define KDSKBENT 0x4B47
+
+/* From <linux/keyboard.h> */
+#define NR_KEYS 128
+#define MAX_NR_KEYMAPS 256
+
+int loadkmap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int loadkmap_main(int ATTRIBUTE_UNUSED argc, char **argv ATTRIBUTE_UNUSED)
+{
+ struct kbentry ke;
+ int i, j, fd;
+ uint16_t ibuff[NR_KEYS];
+ RESERVE_CONFIG_BUFFER(flags,MAX_NR_KEYMAPS);
+
+/* bb_warn_ignoring_args(argc>=2);*/
+
+ fd = xopen(CURRENT_VC, O_RDWR);
+
+ xread(STDIN_FILENO, flags, 7);
+ if (strncmp(flags, BINARY_KEYMAP_MAGIC, 7))
+ bb_error_msg_and_die("not a valid binary keymap");
+
+ xread(STDIN_FILENO, flags, MAX_NR_KEYMAPS);
+
+ for (i = 0; i < MAX_NR_KEYMAPS; i++) {
+ if (flags[i] == 1) {
+ xread(STDIN_FILENO, ibuff, NR_KEYS * sizeof(uint16_t));
+ for (j = 0; j < NR_KEYS; j++) {
+ ke.kb_index = j;
+ ke.kb_table = i;
+ ke.kb_value = ibuff[j];
+ ioctl(fd, KDSKBENT, &ke);
+ }
+ }
+ }
+
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ close(fd);
+ RELEASE_CONFIG_BUFFER(flags);
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/console-tools/openvt.c b/cleopatre/busybox-1.11.1-spc300/console-tools/openvt.c
new file mode 100644
index 0000000000..2085224183
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/console-tools/openvt.c
@@ -0,0 +1,181 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * openvt.c - open a vt to run a command.
+ *
+ * busyboxed by Quy Tonthat <quy@signal3.com>
+ * hacked by Tito <farmatito@tiscali.it>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include <linux/vt.h>
+#include "libbb.h"
+
+/* "Standard" openvt's man page (we do not support all of this):
+
+openvt [-c NUM] [-fsulv] [--] [command [args]]
+
+Find the first available VT, and run command on it. Stdio is directed
+to that VT. If no command is specified then $SHELL is used.
+
+-c NUM
+ Use the given VT number, not the first free one.
+-f
+ Force opening a VT: don't try to check if VT is already in use.
+-s
+ Switch to the new VT when starting the command.
+ The VT of the new command will be made the new current VT.
+-u
+ Figure out the owner of the current VT, and run login as that user.
+ Suitable to be called by init. Shouldn't be used with -c or -l.
+-l
+ Make the command a login shell: a "-" is prepended to the argv[0]
+ when command is executed.
+-v
+ Verbose.
+-w
+ Wait for command to complete. If -w and -s are used together,
+ switch back to the controlling terminal when the command completes.
+
+bbox:
+-u: not implemented
+-f: always in effect
+-l: not implemented, ignored
+-v: ignored
+-ws: does NOT switch back
+*/
+
+/* Helper: does this fd understand VT_xxx? */
+static int not_vt_fd(int fd)
+{
+ struct vt_stat vtstat;
+ return ioctl(fd, VT_GETSTATE, &vtstat); /* !0: error, it's not VT fd */
+}
+
+/* Helper: get a fd suitable for VT_xxx */
+static int get_vt_fd(void)
+{
+ int fd;
+
+ /* Do we, by chance, already have it? */
+ for (fd = 0; fd < 3; fd++)
+ if (!not_vt_fd(fd))
+ return fd;
+ /* _only_ O_NONBLOCK: ask for neither read nor write perms */
+ /*FIXME: use? device_open(DEV_CONSOLE,0); */
+ fd = open(DEV_CONSOLE, O_NONBLOCK);
+ if (fd >= 0 && !not_vt_fd(fd))
+ return fd;
+ bb_error_msg_and_die("can't find open VT");
+}
+
+static int find_free_vtno(void)
+{
+ int vtno;
+ int fd = get_vt_fd();
+
+ errno = 0;
+ /*xfunc_error_retval = 3; - do we need compat? */
+ if (ioctl(fd, VT_OPENQRY, &vtno) != 0 || vtno <= 0)
+ bb_perror_msg_and_die("can't find open VT");
+// Not really needed, grep for DAEMON_ONLY_SANITIZE
+// if (fd > 2)
+// close(fd);
+ return vtno;
+}
+
+/* vfork scares gcc, it generates bigger code.
+ * Keep it away from main program.
+ * TODO: move to libbb; or adapt existing libbb's spawn().
+ */
+static NOINLINE void vfork_child(char **argv)
+{
+ if (vfork() == 0) {
+ /* CHILD */
+ /* Try to make this VT our controlling tty */
+ setsid(); /* lose old ctty */
+ ioctl(STDIN_FILENO, TIOCSCTTY, 0 /* 0: don't forcibly steal */);
+ //bb_error_msg("our sid %d", getsid(0));
+ //bb_error_msg("our pgrp %d", getpgrp());
+ //bb_error_msg("VT's sid %d", tcgetsid(0));
+ //bb_error_msg("VT's pgrp %d", tcgetpgrp(0));
+ BB_EXECVP(argv[0], argv);
+ bb_perror_msg_and_die("exec %s", argv[0]);
+ }
+}
+
+int openvt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int openvt_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ char vtname[sizeof(VC_FORMAT) + sizeof(int)*3];
+ struct vt_stat vtstat;
+ char *str_c;
+ int vtno;
+ int flags;
+ enum {
+ OPT_c = (1 << 0),
+ OPT_w = (1 << 1),
+ OPT_s = (1 << 2),
+ OPT_l = (1 << 3),
+ OPT_f = (1 << 4),
+ OPT_v = (1 << 5),
+ };
+
+ /* "+" - stop on first non-option */
+ flags = getopt32(argv, "+c:wslfv", &str_c);
+ argv += optind;
+
+ if (flags & OPT_c) {
+ /* Check for illegal vt number: < 1 or > 63 */
+ vtno = xatou_range(str_c, 1, 63);
+ } else {
+ vtno = find_free_vtno();
+ }
+
+ /* Grab new VT */
+ sprintf(vtname, VC_FORMAT, vtno);
+ /* (Try to) clean up stray open fds above fd 2 */
+ bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS | DAEMON_ONLY_SANITIZE, NULL);
+ close(STDIN_FILENO);
+ /*setsid(); - BAD IDEA: after we exit, child is SIGHUPed... */
+ xopen(vtname, O_RDWR);
+ xioctl(STDIN_FILENO, VT_GETSTATE, &vtstat);
+
+ if (flags & OPT_s) {
+ console_make_active(STDIN_FILENO, vtno);
+ }
+
+ if (!argv[0]) {
+ argv--;
+ argv[0] = getenv("SHELL");
+ if (!argv[0])
+ argv[0] = (char *) DEFAULT_SHELL;
+ /*argv[1] = NULL; - already is */
+ }
+
+ xdup2(STDIN_FILENO, STDOUT_FILENO);
+ xdup2(STDIN_FILENO, STDERR_FILENO);
+
+#ifdef BLOAT
+ {
+ /* Handle -l (login shell) option */
+ const char *prog = argv[0];
+ if (flags & OPT_l)
+ argv[0] = xasprintf("-%s", argv[0]);
+ }
+#endif
+
+ vfork_child(argv);
+ if (flags & OPT_w) {
+ /* We have only one child, wait for it */
+ safe_waitpid(-1, NULL, 0); /* loops on EINTR */
+ if (flags & OPT_s) {
+ console_make_active(STDIN_FILENO, vtstat.v_active);
+ // Compat: even with -c N (try to) disallocate:
+ // # /usr/app/kbd-1.12/bin/openvt -f -c 9 -ws sleep 5
+ // openvt: could not deallocate console 9
+ xioctl(STDIN_FILENO, VT_DISALLOCATE, (void*)(ptrdiff_t)vtno);
+ }
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/console-tools/reset.c b/cleopatre/busybox-1.11.1-spc300/console-tools/reset.c
new file mode 100644
index 0000000000..5d5d4e27be
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/console-tools/reset.c
@@ -0,0 +1,47 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini reset implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Written by Erik Andersen and Kent Robotti <robotti@metconnect.com>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* BTW, which "standard" package has this utility? It doesn't seem
+ * to be ncurses, coreutils, console-tools... then what? */
+
+#if ENABLE_STTY
+int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+#endif
+
+int reset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int reset_main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
+{
+ static const char *const args[] = {
+ "stty", "sane", NULL
+ };
+
+ /* no options, no getopt */
+
+ if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
+ /* See 'man 4 console_codes' for details:
+ * "ESC c" -- Reset
+ * "ESC ( K" -- Select user mapping
+ * "ESC [ J" -- Erase display
+ * "ESC [ 0 m" -- Reset all display attributes
+ * "ESC [ ? 25 h" -- Make cursor visible.
+ */
+ printf("\033c\033(K\033[J\033[0m\033[?25h");
+ /* http://bugs.busybox.net/view.php?id=1414:
+ * people want it to reset echo etc: */
+#if ENABLE_STTY
+ return stty_main(2, (char**)args);
+#else
+ execvp("stty", (char**)args);
+#endif
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/console-tools/resize.c b/cleopatre/busybox-1.11.1-spc300/console-tools/resize.c
new file mode 100644
index 0000000000..8a50f9dcd5
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/console-tools/resize.c
@@ -0,0 +1,71 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * resize - set terminal width and height.
+ *
+ * Copyright 2006 Bernhard Fischer
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+/* no options, no getopt */
+#include "libbb.h"
+
+#define ESC "\033"
+
+#define old_termios (*(struct termios*)&bb_common_bufsiz1)
+
+static void
+onintr(int sig ATTRIBUTE_UNUSED)
+{
+ tcsetattr(STDERR_FILENO, TCSANOW, &old_termios);
+ exit(EXIT_FAILURE);
+}
+
+int resize_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int resize_main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
+{
+ struct termios new;
+ struct winsize w = { 0, 0, 0, 0 };
+ int ret;
+
+ /* We use _stderr_ in order to make resize usable
+ * in shell backticks (those redirect stdout away from tty).
+ * NB: other versions of resize open "/dev/tty"
+ * and operate on it - should we do the same?
+ */
+
+ tcgetattr(STDERR_FILENO, &old_termios); /* fiddle echo */
+ new = old_termios;
+ new.c_cflag |= (CLOCAL | CREAD);
+ new.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
+ bb_signals(0
+ + (1 << SIGINT)
+ + (1 << SIGQUIT)
+ + (1 << SIGTERM)
+ + (1 << SIGALRM)
+ , onintr);
+ tcsetattr(STDERR_FILENO, TCSANOW, &new);
+
+ /* save_cursor_pos 7
+ * scroll_whole_screen [r
+ * put_cursor_waaaay_off [$x;$yH
+ * get_cursor_pos [6n
+ * restore_cursor_pos 8
+ */
+ fprintf(stderr, ESC"7" ESC"[r" ESC"[999;999H" ESC"[6n");
+ alarm(3); /* Just in case terminal won't answer */
+ scanf(ESC"[%hu;%huR", &w.ws_row, &w.ws_col);
+ fprintf(stderr, ESC"8");
+
+ /* BTW, other versions of resize recalculate w.ws_xpixel, ws.ws_ypixel
+ * by calculating character cell HxW from old values
+ * (gotten via TIOCGWINSZ) and recomputing *pixel values */
+ ret = ioctl(STDERR_FILENO, TIOCSWINSZ, &w);
+
+ tcsetattr(STDERR_FILENO, TCSANOW, &old_termios);
+
+ if (ENABLE_FEATURE_RESIZE_PRINT)
+ printf("COLUMNS=%d;LINES=%d;export COLUMNS LINES;\n",
+ w.ws_col, w.ws_row);
+
+ return ret;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/console-tools/setconsole.c b/cleopatre/busybox-1.11.1-spc300/console-tools/setconsole.c
new file mode 100644
index 0000000000..82fe83f228
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/console-tools/setconsole.c
@@ -0,0 +1,39 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * setconsole.c - redirect system console output
+ *
+ * Copyright (C) 2004,2005 Enrik Berkhan <Enrik.Berkhan@inka.de>
+ * Copyright (C) 2008 Bernhard Fischer
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+int setconsole_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int setconsole_main(int ATTRIBUTE_UNUSED argc, char **argv)
+{
+ const char *device = CURRENT_TTY;
+ bool reset;
+
+#if ENABLE_FEATURE_SETCONSOLE_LONG_OPTIONS
+ static const char setconsole_longopts[] ALIGN1 =
+ "reset\0" No_argument "r"
+ ;
+ applet_long_options = setconsole_longopts;
+#endif
+ /* at most one non-option argument */
+ opt_complementary = "?1";
+ reset = getopt32(argv, "r");
+
+ argv += 1 + reset;
+ if (*argv) {
+ device = *argv;
+ } else {
+ if (reset)
+ device = DEV_CONSOLE;
+ }
+
+ xioctl(xopen(device, O_RDONLY), TIOCCONS, NULL);
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/console-tools/setkeycodes.c b/cleopatre/busybox-1.11.1-spc300/console-tools/setkeycodes.c
new file mode 100644
index 0000000000..e9a050862b
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/console-tools/setkeycodes.c
@@ -0,0 +1,49 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * setkeycodes
+ *
+ * Copyright (C) 1994-1998 Andries E. Brouwer <aeb@cwi.nl>
+ *
+ * Adjusted for BusyBox by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+//#include <sys/ioctl.h>
+#include "libbb.h"
+
+/* From <linux/kd.h> */
+struct kbkeycode {
+ unsigned scancode, keycode;
+};
+enum {
+ KDSETKEYCODE = 0x4B4D /* write kernel keycode table entry */
+};
+
+int setkeycodes_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int setkeycodes_main(int argc, char **argv)
+{
+ int fd, sc;
+ struct kbkeycode a;
+
+ if (argc % 2 != 1 || argc < 2) {
+ bb_show_usage();
+ }
+
+ fd = get_console_fd();
+
+ while (argc > 2) {
+ a.keycode = xatou_range(argv[2], 0, 127);
+ a.scancode = sc = xstrtoul_range(argv[1], 16, 0, 255);
+ if (a.scancode > 127) {
+ a.scancode -= 0xe000;
+ a.scancode += 128;
+ }
+ ioctl_or_perror_and_die(fd, KDSETKEYCODE, &a,
+ "failed to set SCANCODE %x to KEYCODE %d",
+ sc, a.keycode);
+ argc -= 2;
+ argv += 2;
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/console-tools/setlogcons.c b/cleopatre/busybox-1.11.1-spc300/console-tools/setlogcons.c
new file mode 100644
index 0000000000..aa8e0806fb
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/console-tools/setlogcons.c
@@ -0,0 +1,30 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * setlogcons: Send kernel messages to the current console or to console N
+ *
+ * Copyright (C) 2006 by Jan Kiszka <jan.kiszka@web.de>
+ *
+ * Based on setlogcons (kbd-1.12) by Andries E. Brouwer
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+int setlogcons_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int setlogcons_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ struct {
+ char fn;
+ char subarg;
+ } arg = { 11, /* redirect kernel messages */
+ 0 /* to specified console (current as default) */
+ };
+
+ if (argv[1])
+ arg.subarg = xatou_range(argv[1], 0, 63);
+
+ xioctl(xopen(VC_1, O_RDONLY), TIOCLINUX, &arg);
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/Config.in b/cleopatre/busybox-1.11.1-spc300/coreutils/Config.in
new file mode 100644
index 0000000000..8d61925863
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/Config.in
@@ -0,0 +1,811 @@
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Coreutils"
+
+config BASENAME
+ bool "basename"
+ default n
+ help
+ basename is used to strip the directory and suffix from filenames,
+ leaving just the filename itself. Enable this option if you wish
+ to enable the 'basename' utility.
+
+config CAL
+ bool "cal"
+ default n
+ help
+ cal is used to display a monthly calender.
+
+config CAT
+ bool "cat"
+ default n
+ help
+ cat is used to concatenate files and print them to the standard
+ output. Enable this option if you wish to enable the 'cat' utility.
+
+config CATV
+ bool "catv"
+ default n
+ help
+ Display nonprinting characters as escape sequences (like some
+ implementations' cat -v option).
+
+config CHGRP
+ bool "chgrp"
+ default n
+ help
+ chgrp is used to change the group ownership of files.
+
+config CHMOD
+ bool "chmod"
+ default n
+ help
+ chmod is used to change the access permission of files.
+
+config CHOWN
+ bool "chown"
+ default n
+ help
+ chown is used to change the user and/or group ownership
+ of files.
+
+config CHROOT
+ bool "chroot"
+ default n
+ help
+ chroot is used to change the root directory and run a command.
+ The default command is `/bin/sh'.
+
+config CKSUM
+ bool "cksum"
+ default n
+ help
+ cksum is used to calculate the CRC32 checksum of a file.
+
+config COMM
+ bool "comm"
+ default n
+ help
+ comm is used to compare two files line by line and return
+ a three-column output.
+
+config CP
+ bool "cp"
+ default n
+ help
+ cp is used to copy files and directories.
+
+config CUT
+ bool "cut"
+ default n
+ help
+ cut is used to print selected parts of lines from
+ each file to stdout.
+
+config DATE
+ bool "date"
+ default n
+ help
+ date is used to set the system date or display the
+ current time in the given format.
+
+config FEATURE_DATE_ISOFMT
+ bool "Enable ISO date format output (-I)"
+ default y
+ depends on DATE
+ help
+ Enable option (-I) to output an ISO-8601 compliant
+ date/time string.
+
+config DD
+ bool "dd"
+ default n
+ help
+ dd copies a file (from standard input to standard output,
+ by default) using specific input and output blocksizes,
+ while optionally performing conversions on it.
+
+config FEATURE_DD_SIGNAL_HANDLING
+ bool "Enable DD signal handling for status reporting"
+ default y
+ depends on DD
+ help
+ sending a SIGUSR1 signal to a running `dd' process makes it
+ print to standard error the number of records read and written
+ so far, then to resume copying.
+
+ $ dd if=/dev/zero of=/dev/null& pid=$! $ kill -USR1 $pid; sleep 1; kill $pid
+ 10899206+0 records in 10899206+0 records out
+
+config FEATURE_DD_IBS_OBS
+ bool "Enable ibs, obs and conv options"
+ default n
+ depends on DD
+ help
+ Enables support for writing a certain number of bytes in and out,
+ at a time, and performing conversions on the data stream.
+
+config DF
+ bool "df"
+ default n
+ help
+ df reports the amount of disk space used and available
+ on filesystems.
+
+config FEATURE_DF_INODE
+ bool "Enable -i (inode information)"
+ default n
+ depends on DF
+ help
+ This option enables support for df -i.
+
+config DIRNAME
+ bool "dirname"
+ default n
+ help
+ dirname is used to strip a non-directory suffix from
+ a file name.
+
+config DOS2UNIX
+ bool "dos2unix/unix2dos"
+ default n
+ help
+ dos2unix is used to convert a text file from DOS format to
+ UNIX format, and vice versa.
+
+config UNIX2DOS
+ bool
+ default y
+ depends on DOS2UNIX
+ help
+ unix2dos is used to convert a text file from UNIX format to
+ DOS format, and vice versa.
+
+config DU
+ bool "du (default blocksize of 512 bytes)"
+ default n
+ help
+ du is used to report the amount of disk space used
+ for specified files.
+
+config FEATURE_DU_DEFAULT_BLOCKSIZE_1K
+ bool "Use a default blocksize of 1024 bytes (1K)"
+ default y
+ depends on DU
+ help
+ Use a blocksize of (1K) instead of the default 512b.
+
+config ECHO
+ bool "echo (basic SuSv3 version taking no options)"
+ default n
+ help
+ echo is used to print a specified string to stdout.
+
+# this entry also appears in shell/Config.in, next to the echo builtin
+config FEATURE_FANCY_ECHO
+ bool "Enable echo options (-n and -e)"
+ default y
+ depends on ECHO
+ help
+ This adds options (-n and -e) to echo.
+
+config ENV
+ bool "env"
+ default n
+ help
+ env is used to set an environment variable and run
+ a command; without options it displays the current
+ environment.
+
+config FEATURE_ENV_LONG_OPTIONS
+ bool "Enable long options"
+ default n
+ depends on ENV && GETOPT_LONG
+ help
+ Support long options for the env applet.
+
+config EXPAND
+ bool "expand"
+ default n
+ help
+ By default, convert all tabs to spaces.
+
+config FEATURE_EXPAND_LONG_OPTIONS
+ bool "Enable long options"
+ default n
+ depends on EXPAND && GETOPT_LONG
+ help
+ Support long options for the expand applet.
+
+config EXPR
+ bool "expr"
+ default n
+ help
+ expr is used to calculate numbers and print the result
+ to standard output.
+
+config EXPR_MATH_SUPPORT_64
+ bool "Extend Posix numbers support to 64 bit"
+ default n
+ depends on EXPR
+ help
+ Enable 64-bit math support in the expr applet. This will make
+ the applet slightly larger, but will allow computation with very
+ large numbers.
+
+config FALSE
+ bool "false"
+ default n
+ help
+ false returns an exit code of FALSE (1).
+
+config FOLD
+ bool "fold"
+ default n
+ help
+ Wrap text to fit a specific width.
+
+config HEAD
+ bool "head"
+ default n
+ help
+ head is used to print the first specified number of lines
+ from files.
+
+config FEATURE_FANCY_HEAD
+ bool "Enable head options (-c, -q, and -v)"
+ default n
+ depends on HEAD
+ help
+ This enables the head options (-c, -q, and -v).
+
+config HOSTID
+ bool "hostid"
+ default n
+ help
+ hostid prints the numeric identifier (in hexadecimal) for
+ the current host.
+
+config ID
+ bool "id"
+ default n
+ help
+ id displays the current user and group ID names.
+
+config INSTALL
+ bool "install"
+ default n
+ help
+ Copy files and set attributes.
+
+config FEATURE_INSTALL_LONG_OPTIONS
+ bool "Enable long options"
+ default n
+ depends on INSTALL && GETOPT_LONG
+ help
+ Support long options for the install applet.
+
+config LENGTH
+ bool "length"
+ default n
+ help
+ length is used to print out the length of a specified string.
+
+config LN
+ bool "ln"
+ default n
+ help
+ ln is used to create hard or soft links between files.
+
+config LOGNAME
+ bool "logname"
+ default n
+ help
+ logname is used to print the current user's login name.
+
+config LS
+ bool "ls"
+ default n
+ help
+ ls is used to list the contents of directories.
+
+config FEATURE_LS_FILETYPES
+ bool "Enable filetyping options (-p and -F)"
+ default y
+ depends on LS
+ help
+ Enable the ls options (-p and -F).
+
+config FEATURE_LS_FOLLOWLINKS
+ bool "Enable symlinks dereferencing (-L)"
+ default y
+ depends on LS
+ help
+ Enable the ls option (-L).
+
+config FEATURE_LS_RECURSIVE
+ bool "Enable recursion (-R)"
+ default y
+ depends on LS
+ help
+ Enable the ls option (-R).
+
+config FEATURE_LS_SORTFILES
+ bool "Sort the file names"
+ default y
+ depends on LS
+ help
+ Allow ls to sort file names alphabetically.
+
+config FEATURE_LS_TIMESTAMPS
+ bool "Show file timestamps"
+ default y
+ depends on LS
+ help
+ Allow ls to display timestamps for files.
+
+config FEATURE_LS_USERNAME
+ bool "Show username/groupnames"
+ default y
+ depends on LS
+ help
+ Allow ls to display username/groupname for files.
+
+config FEATURE_LS_COLOR
+ bool "Allow use of color to identify file types"
+ default y
+ depends on LS && GETOPT_LONG
+ help
+ This enables the --color option to ls.
+
+config FEATURE_LS_COLOR_IS_DEFAULT
+ bool "Produce colored ls output by default"
+ default n
+ depends on FEATURE_LS_COLOR
+ help
+ Saying yes here will turn coloring on by default,
+ even if no "--color" option is given to the ls command.
+ This is not recommended, since the colors are not
+ configurable, and the output may not be legible on
+ many output screens.
+
+config MD5SUM
+ bool "md5sum"
+ default n
+ help
+ md5sum is used to print or check MD5 checksums.
+
+config MKDIR
+ bool "mkdir"
+ default n
+ help
+ mkdir is used to create directories with the specified names.
+
+config FEATURE_MKDIR_LONG_OPTIONS
+ bool "Enable long options"
+ default n
+ depends on MKDIR && GETOPT_LONG
+ help
+ Support long options for the mkdir applet.
+
+config MKFIFO
+ bool "mkfifo"
+ default n
+ help
+ mkfifo is used to create FIFOs (named pipes).
+ The `mknod' program can also create FIFOs.
+
+config MKNOD
+ bool "mknod"
+ default n
+ help
+ mknod is used to create FIFOs or block/character special
+ files with the specified names.
+
+config MV
+ bool "mv"
+ default n
+ help
+ mv is used to move or rename files or directories.
+
+config FEATURE_MV_LONG_OPTIONS
+ bool "Enable long options"
+ default n
+ depends on MV && GETOPT_LONG
+ help
+ Support long options for the mv applet.
+
+config NICE
+ bool "nice"
+ default n
+ help
+ nice runs a program with modified scheduling priority.
+
+config NOHUP
+ bool "nohup"
+ default n
+ help
+ run a command immune to hangups, with output to a non-tty.
+
+config OD
+ bool "od"
+ default n
+ help
+ od is used to dump binary files in octal and other formats.
+
+config PRINTENV
+ bool "printenv"
+ default n
+ help
+ printenv is used to print all or part of environment.
+
+config PRINTF
+ bool "printf"
+ default n
+ help
+ printf is used to format and print specified strings.
+ It's similar to `echo' except it has more options.
+
+config PWD
+ bool "pwd"
+ default n
+ help
+ pwd is used to print the current directory.
+
+config READLINK
+ bool "readlink"
+ default n
+ help
+ This program reads a symbolic link and returns the name
+ of the file it points to
+
+config FEATURE_READLINK_FOLLOW
+ bool "Enable canonicalization by following all symlinks (-f)"
+ default n
+ depends on READLINK
+ help
+ Enable the readlink option (-f).
+
+config REALPATH
+ bool "realpath"
+ default n
+ help
+ Return the canonicalized absolute pathname.
+ This isn't provided by GNU shellutils, but where else does it belong.
+
+config RM
+ bool "rm"
+ default n
+ help
+ rm is used to remove files or directories.
+
+config RMDIR
+ bool "rmdir"
+ default n
+ help
+ rmdir is used to remove empty directories.
+
+config FEATURE_RMDIR_LONG_OPTIONS
+ bool "Enable long options"
+ default n
+ depends on RMDIR && GETOPT_LONG
+ help
+ Support long options for the rmdir applet, including
+ --ignore-fail-on-non-empty for compatibility with GNU rmdir.
+
+config SEQ
+ bool "seq"
+ default n
+ help
+ print a sequence of numbers
+
+config SHA1SUM
+ bool "sha1sum"
+ default n
+ help
+ Compute and check SHA1 message digest
+
+config SLEEP
+ bool "sleep (single integer arg with no suffix)"
+ default n
+ help
+ sleep is used to pause for a specified number of seconds,
+
+config FEATURE_FANCY_SLEEP
+ bool "Enable multiple integer args and optional time suffixes"
+ default n
+ depends on SLEEP
+ help
+ Allow sleep to pause for specified minutes, hours, and days.
+
+config SORT
+ bool "sort"
+ default n
+ help
+ sort is used to sort lines of text in specified files.
+
+config FEATURE_SORT_BIG
+ bool "Full SuSv3 compliant sort (support -ktcsbdfiozgM)"
+ default y
+ depends on SORT
+ help
+ Without this, sort only supports -r, -u, and an integer version
+ of -n. Selecting this adds sort keys, floating point support, and
+ more. This adds a little over 3k to a nonstatic build on x86.
+
+ The SuSv3 sort standard is available at:
+ http://www.opengroup.org/onlinepubs/007904975/utilities/sort.html
+
+config SPLIT
+ bool "split"
+ default n
+ help
+ split a file into pieces.
+
+config FEATURE_SPLIT_FANCY
+ bool "Fancy extensions"
+ default n
+ depends on SPLIT
+ help
+ Add support for features not required by SUSv3.
+ Supports additional suffixes 'b' for 512 bytes,
+ 'g' for 1GiB for the -b option.
+
+config STAT
+ bool "stat"
+ default n
+ help
+ display file or filesystem status.
+
+config FEATURE_STAT_FORMAT
+ bool "Enable custom formats (-c)"
+ default n
+ depends on STAT
+ help
+ Without this, stat will not support the '-c format' option where
+ users can pass a custom format string for output. This adds about
+ 7k to a nonstatic build on amd64.
+
+config STTY
+ bool "stty"
+ default n
+ help
+ stty is used to change and print terminal line settings.
+
+config SUM
+ bool "sum"
+ default n
+ help
+ checksum and count the blocks in a file
+
+config SYNC
+ bool "sync"
+ default n
+ help
+ sync is used to flush filesystem buffers.
+
+config TAC
+ bool "tac"
+ default n
+ help
+ tac is used to concatenate and print files in reverse.
+
+config TAIL
+ bool "tail"
+ default n
+ help
+ tail is used to print the last specified number of lines
+ from files.
+
+config FEATURE_FANCY_TAIL
+ bool "Enable extra tail options (-q, -s, and -v)"
+ default y
+ depends on TAIL
+ help
+ The options (-q, -s, and -v) are provided by GNU tail, but
+ are not specific in the SUSv3 standard.
+
+config TEE
+ bool "tee"
+ default n
+ help
+ tee is used to read from standard input and write
+ to standard output and files.
+
+config FEATURE_TEE_USE_BLOCK_IO
+ bool "Enable block I/O (larger/faster) instead of byte I/O"
+ default n
+ depends on TEE
+ help
+ Enable this option for a faster tee, at expense of size.
+
+config TEST
+ bool "test"
+ default n
+ help
+ test is used to check file types and compare values,
+ returning an appropriate exit code. The bash shell
+ has test built in, ash can build it in optionally.
+
+config FEATURE_TEST_64
+ bool "Extend test to 64 bit"
+ default n
+ depends on TEST
+ help
+ Enable 64-bit support in test.
+
+config TOUCH
+ bool "touch"
+ default n
+ help
+ touch is used to create or change the access and/or
+ modification timestamp of specified files.
+
+config TR
+ bool "tr"
+ default n
+ help
+ tr is used to squeeze, and/or delete characters from standard
+ input, writing to standard output.
+
+config FEATURE_TR_CLASSES
+ bool "Enable character classes (such as [:upper:])"
+ default n
+ depends on TR
+ help
+ Enable character classes, enabling commands such as:
+ tr [:upper:] [:lower:] to convert input into lowercase.
+
+config FEATURE_TR_EQUIV
+ bool "Enable equivalence classes"
+ default n
+ depends on TR
+ help
+ Enable equivalence classes, which essentially add the enclosed
+ character to the current set. For instance, tr [=a=] xyz would
+ replace all instances of 'a' with 'xyz'. This option is mainly
+ useful for cases when no other way of expressing a character
+ is possible.
+
+config TRUE
+ bool "true"
+ default n
+ help
+ true returns an exit code of TRUE (0).
+
+config TTY
+ bool "tty"
+ default n
+ help
+ tty is used to print the name of the current terminal to
+ standard output.
+
+config UNAME
+ bool "uname"
+ default n
+ help
+ uname is used to print system information.
+
+config UNEXPAND
+ bool "unexpand"
+ default n
+ help
+ By default, convert only leading sequences of blanks to tabs.
+
+config FEATURE_UNEXPAND_LONG_OPTIONS
+ bool "Enable long options"
+ default n
+ depends on UNEXPAND && GETOPT_LONG
+ help
+ Support long options for the unexpand applet.
+
+config UNIQ
+ bool "uniq"
+ default n
+ help
+ uniq is used to remove duplicate lines from a sorted file.
+
+config USLEEP
+ bool "usleep"
+ default n
+ help
+ usleep is used to pause for a specified number of microseconds.
+
+config UUDECODE
+ bool "uudecode"
+ default n
+ help
+ uudecode is used to decode a uuencoded file.
+
+config UUENCODE
+ bool "uuencode"
+ default n
+ help
+ uuencode is used to uuencode a file.
+
+config WC
+ bool "wc"
+ default n
+ help
+ wc is used to print the number of bytes, words, and lines,
+ in specified files.
+
+config FEATURE_WC_LARGE
+ bool "Support very large files in wc"
+ default n
+ depends on WC
+ help
+ Use "unsigned long long" in wc for count variables
+
+config WHO
+ bool "who"
+ default n
+ select FEATURE_UTMP
+ help
+ who is used to show who is logged on.
+
+config WHOAMI
+ bool "whoami"
+ default n
+ help
+ whoami is used to print the username of the current
+ user id (same as id -un).
+
+config YES
+ bool "yes"
+ default n
+ help
+ yes is used to repeatedly output a specific string, or
+ the default string `y'.
+
+comment "Common options for cp and mv"
+ depends on CP || MV
+
+config FEATURE_PRESERVE_HARDLINKS
+ bool "Preserve hard links"
+ default n
+ depends on CP || MV
+ help
+ Allow cp and mv to preserve hard links.
+
+comment "Common options for ls, more and telnet"
+ depends on LS || MORE || TELNET
+
+config FEATURE_AUTOWIDTH
+ bool "Calculate terminal & column widths"
+ default y
+ depends on LS || MORE || TELNET
+ help
+ This option allows utilities such as 'ls', 'more' and 'telnet'
+ to determine the width of the screen, which can allow them to
+ display additional text or avoid wrapping text onto the next line.
+ If you leave this disabled, your utilities will be especially
+ primitive and will be unable to determine the current screen width.
+
+comment "Common options for df, du, ls"
+ depends on DF || DU || LS
+
+config FEATURE_HUMAN_READABLE
+ bool "Support for human readable output (example 13k, 23M, 235G)"
+ default n
+ depends on DF || DU || LS
+ help
+ Allow df, du, and ls to have human readable output.
+
+comment "Common options for md5sum, sha1sum"
+ depends on MD5SUM || SHA1SUM
+
+config FEATURE_MD5_SHA1_SUM_CHECK
+ bool "Enable -c, -s and -w options"
+ default n
+ depends on MD5SUM || SHA1SUM
+ help
+ Enabling the -c options allows files to be checked
+ against pre-calculated hash values.
+
+ -s and -w are useful options when verifying checksums.
+
+endmenu
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/Kbuild b/cleopatre/busybox-1.11.1-spc300/coreutils/Kbuild
new file mode 100644
index 0000000000..a5a2d4c26f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/Kbuild
@@ -0,0 +1,92 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+libs-y += libcoreutils/
+
+lib-y:=
+lib-$(CONFIG_BASENAME) += basename.o
+lib-$(CONFIG_CAL) += cal.o
+lib-$(CONFIG_CAT) += cat.o
+lib-$(CONFIG_MORE) += cat.o # more uses it if stdout isn't a tty
+lib-$(CONFIG_LESS) += cat.o # less too
+lib-$(CONFIG_CRONTAB) += cat.o # crontab -l
+lib-$(CONFIG_CATV) += catv.o
+lib-$(CONFIG_CHGRP) += chgrp.o chown.o
+lib-$(CONFIG_CHMOD) += chmod.o
+lib-$(CONFIG_CHOWN) += chown.o
+lib-$(CONFIG_CHROOT) += chroot.o
+lib-$(CONFIG_CKSUM) += cksum.o
+lib-$(CONFIG_COMM) += comm.o
+lib-$(CONFIG_CP) += cp.o
+lib-$(CONFIG_CUT) += cut.o
+lib-$(CONFIG_DATE) += date.o
+lib-$(CONFIG_DD) += dd.o
+lib-$(CONFIG_DF) += df.o
+lib-$(CONFIG_DIRNAME) += dirname.o
+lib-$(CONFIG_DOS2UNIX) += dos2unix.o
+lib-$(CONFIG_DU) += du.o
+lib-$(CONFIG_ECHO) += echo.o
+lib-$(CONFIG_ASH) += echo.o # used by ash
+lib-$(CONFIG_HUSH) += echo.o # used by hush
+lib-$(CONFIG_ENV) += env.o
+lib-$(CONFIG_EXPR) += expr.o
+lib-$(CONFIG_EXPAND) += expand.o
+lib-$(CONFIG_FALSE) += false.o
+lib-$(CONFIG_FOLD) += fold.o
+lib-$(CONFIG_HEAD) += head.o
+lib-$(CONFIG_HOSTID) += hostid.o
+lib-$(CONFIG_ID) += id.o
+lib-$(CONFIG_INSTALL) += install.o
+lib-$(CONFIG_LENGTH) += length.o
+lib-$(CONFIG_LN) += ln.o
+lib-$(CONFIG_LOGNAME) += logname.o
+lib-$(CONFIG_LS) += ls.o
+lib-$(CONFIG_MD5SUM) += md5_sha1_sum.o
+lib-$(CONFIG_MKDIR) += mkdir.o
+lib-$(CONFIG_MKFIFO) += mkfifo.o
+lib-$(CONFIG_MKNOD) += mknod.o
+lib-$(CONFIG_MV) += mv.o
+lib-$(CONFIG_NICE) += nice.o
+lib-$(CONFIG_NOHUP) += nohup.o
+lib-$(CONFIG_OD) += od.o
+lib-$(CONFIG_PRINTENV) += printenv.o
+lib-$(CONFIG_PRINTF) += printf.o
+lib-$(CONFIG_ASH_BUILTIN_PRINTF) += printf.o
+lib-$(CONFIG_PWD) += pwd.o
+lib-$(CONFIG_READLINK) += readlink.o
+lib-$(CONFIG_REALPATH) += realpath.o
+lib-$(CONFIG_RM) += rm.o
+lib-$(CONFIG_RMDIR) += rmdir.o
+lib-$(CONFIG_SEQ) += seq.o
+lib-$(CONFIG_SHA1SUM) += md5_sha1_sum.o
+lib-$(CONFIG_SLEEP) += sleep.o
+lib-$(CONFIG_SPLIT) += split.o
+lib-$(CONFIG_SORT) += sort.o
+lib-$(CONFIG_STAT) += stat.o
+lib-$(CONFIG_STTY) += stty.o
+lib-$(CONFIG_SUM) += sum.o
+lib-$(CONFIG_SYNC) += sync.o
+lib-$(CONFIG_TAC) += tac.o
+lib-$(CONFIG_TAIL) += tail.o
+lib-$(CONFIG_TEE) += tee.o
+lib-$(CONFIG_TEST) += test.o test_ptr_hack.o
+lib-$(CONFIG_ASH) += test.o test_ptr_hack.o # used by ash
+lib-$(CONFIG_HUSH) += test.o test_ptr_hack.o # used by hush
+lib-$(CONFIG_MSH) += test.o test_ptr_hack.o # used by msh
+lib-$(CONFIG_TOUCH) += touch.o
+lib-$(CONFIG_TR) += tr.o
+lib-$(CONFIG_TRUE) += true.o
+lib-$(CONFIG_TTY) += tty.o
+lib-$(CONFIG_UNAME) += uname.o
+lib-$(CONFIG_UNEXPAND) += expand.o
+lib-$(CONFIG_UNIQ) += uniq.o
+lib-$(CONFIG_USLEEP) += usleep.o
+lib-$(CONFIG_UUDECODE) += uudecode.o
+lib-$(CONFIG_UUENCODE) += uuencode.o
+lib-$(CONFIG_WC) += wc.o
+lib-$(CONFIG_WHO) += who.o
+lib-$(CONFIG_WHOAMI) += whoami.o
+lib-$(CONFIG_YES) += yes.o
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/basename.c b/cleopatre/busybox-1.11.1-spc300/coreutils/basename.c
new file mode 100644
index 0000000000..a3085ede30
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/basename.c
@@ -0,0 +1,52 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini basename implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ */
+
+/* BB_AUDIT SUSv3 compliant */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/basename.html */
+
+
+/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
+ *
+ * Changes:
+ * 1) Now checks for too many args. Need at least one and at most two.
+ * 2) Don't check for options, as per SUSv3.
+ * 3) Save some space by using strcmp(). Calling strncmp() here was silly.
+ */
+
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
+
+int basename_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int basename_main(int argc, char **argv)
+{
+ size_t m, n;
+ char *s;
+
+ if (((unsigned int)(argc-2)) >= 2) {
+ bb_show_usage();
+ }
+
+ /* It should strip slash: /abc/def/ -> def */
+ s = bb_get_last_path_component_strip(*++argv);
+
+ m = strlen(s);
+ if (*++argv) {
+ n = strlen(*argv);
+ if ((m > n) && ((strcmp)(s+m-n, *argv) == 0)) {
+ m -= n;
+ /*s[m] = '\0'; - redundant */
+ }
+ }
+
+ /* puts(s) will do, but we can do without stdio this way: */
+ s[m++] = '\n';
+ return full_write(STDOUT_FILENO, s, m) == (ssize_t)m;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/cal.c b/cleopatre/busybox-1.11.1-spc300/coreutils/cal.c
new file mode 100644
index 0000000000..8a93057b04
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/cal.c
@@ -0,0 +1,347 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Calendar implementation for busybox
+ *
+ * See original copyright at the end of this file
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 compliant with -j and -y extensions (from util-linux). */
+/* BB_AUDIT BUG: The output of 'cal -j 1752' is incorrect. The upstream
+ * BB_AUDIT BUG: version in util-linux seems to be broken as well. */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/cal.html */
+
+/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
+ *
+ * Major size reduction... over 50% (>1.5k) on i386.
+ */
+
+#include "libbb.h"
+
+/* We often use "unsigned" intead of "int", it's easier to div on most CPUs */
+
+#define THURSDAY 4 /* for reformation */
+#define SATURDAY 6 /* 1 Jan 1 was a Saturday */
+
+#define FIRST_MISSING_DAY 639787 /* 3 Sep 1752 */
+#define NUMBER_MISSING_DAYS 11 /* 11 day correction */
+
+#define MAXDAYS 42 /* max slots in a month array */
+#define SPACE -1 /* used in day array */
+
+static const unsigned char days_in_month[] ALIGN1 = {
+ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+static const unsigned char sep1752[] ALIGN1 = {
+ 1, 2, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30
+};
+
+static unsigned julian;
+
+/* leap year -- account for Gregorian reformation in 1752 */
+static int leap_year(unsigned yr)
+{
+ if (yr <= 1752)
+ return !(yr % 4);
+ return (!(yr % 4) && (yr % 100)) || !(yr % 400);
+}
+
+/* number of centuries since 1700, not inclusive */
+#define centuries_since_1700(yr) \
+ ((yr) > 1700 ? (yr) / 100 - 17 : 0)
+
+/* number of centuries since 1700 whose modulo of 400 is 0 */
+#define quad_centuries_since_1700(yr) \
+ ((yr) > 1600 ? ((yr) - 1600) / 400 : 0)
+
+/* number of leap years between year 1 and this year, not inclusive */
+#define leap_years_since_year_1(yr) \
+ ((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr))
+
+static void center(char *, unsigned, unsigned);
+static void day_array(unsigned, unsigned, unsigned *);
+static void trim_trailing_spaces_and_print(char *);
+
+static void blank_string(char *buf, size_t buflen);
+static char *build_row(char *p, unsigned *dp);
+
+#define DAY_LEN 3 /* 3 spaces per day */
+#define J_DAY_LEN (DAY_LEN + 1)
+#define WEEK_LEN 20 /* 7 * 3 - one space at the end */
+#define J_WEEK_LEN (WEEK_LEN + 7)
+#define HEAD_SEP 2 /* spaces between day headings */
+
+int cal_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int cal_main(int argc, char **argv)
+{
+ struct tm *local_time;
+ struct tm zero_tm;
+ time_t now;
+ unsigned month, year, flags, i;
+ char *month_names[12];
+ char day_headings[28]; /* 28 for julian, 21 for nonjulian */
+ char buf[40];
+
+ flags = getopt32(argv, "jy");
+ julian = flags & 1;
+ month = 0;
+ argv += optind;
+ argc -= optind;
+
+ if (argc > 2) {
+ bb_show_usage();
+ }
+
+ if (!argc) {
+ time(&now);
+ local_time = localtime(&now);
+ year = local_time->tm_year + 1900;
+ if (!(flags & 2)) {
+ month = local_time->tm_mon + 1;
+ }
+ } else {
+ if (argc == 2) {
+ month = xatou_range(*argv++, 1, 12);
+ }
+ year = xatou_range(*argv, 1, 9999);
+ }
+
+ blank_string(day_headings, sizeof(day_headings) - 7 + 7*julian);
+
+ i = 0;
+ do {
+ zero_tm.tm_mon = i;
+ strftime(buf, sizeof(buf), "%B", &zero_tm);
+ month_names[i] = xstrdup(buf);
+
+ if (i < 7) {
+ zero_tm.tm_wday = i;
+ strftime(buf, sizeof(buf), "%a", &zero_tm);
+ strncpy(day_headings + i * (3+julian) + julian, buf, 2);
+ }
+ } while (++i < 12);
+
+ if (month) {
+ unsigned row, len, days[MAXDAYS];
+ unsigned *dp = days;
+ char lineout[30];
+
+ day_array(month, year, dp);
+ len = sprintf(lineout, "%s %d", month_names[month - 1], year);
+ printf("%*s%s\n%s\n",
+ ((7*julian + WEEK_LEN) - len) / 2, "",
+ lineout, day_headings);
+ for (row = 0; row < 6; row++) {
+ build_row(lineout, dp)[0] = '\0';
+ dp += 7;
+ trim_trailing_spaces_and_print(lineout);
+ }
+ } else {
+ unsigned row, which_cal, week_len, days[12][MAXDAYS];
+ unsigned *dp;
+ char lineout[80];
+
+ sprintf(lineout, "%d", year);
+ center(lineout,
+ (WEEK_LEN * 3 + HEAD_SEP * 2)
+ + julian * (J_WEEK_LEN * 2 + HEAD_SEP
+ - (WEEK_LEN * 3 + HEAD_SEP * 2)),
+ 0);
+ puts("\n"); /* two \n's */
+ for (i = 0; i < 12; i++) {
+ day_array(i + 1, year, days[i]);
+ }
+ blank_string(lineout, sizeof(lineout));
+ week_len = WEEK_LEN + julian * (J_WEEK_LEN - WEEK_LEN);
+ for (month = 0; month < 12; month += 3-julian) {
+ center(month_names[month], week_len, HEAD_SEP);
+ if (!julian) {
+ center(month_names[month + 1], week_len, HEAD_SEP);
+ }
+ center(month_names[month + 2 - julian], week_len, 0);
+ printf("\n%s%*s%s", day_headings, HEAD_SEP, "", day_headings);
+ if (!julian) {
+ printf("%*s%s", HEAD_SEP, "", day_headings);
+ }
+ bb_putchar('\n');
+ for (row = 0; row < (6*7); row += 7) {
+ for (which_cal = 0; which_cal < 3-julian; which_cal++) {
+ dp = days[month + which_cal] + row;
+ build_row(lineout + which_cal * (week_len + 2), dp);
+ }
+ /* blank_string took care of nul termination. */
+ trim_trailing_spaces_and_print(lineout);
+ }
+ }
+ }
+
+ fflush_stdout_and_exit(EXIT_SUCCESS);
+}
+
+/*
+ * day_array --
+ * Fill in an array of 42 integers with a calendar. Assume for a moment
+ * that you took the (maximum) 6 rows in a calendar and stretched them
+ * out end to end. You would have 42 numbers or spaces. This routine
+ * builds that array for any month from Jan. 1 through Dec. 9999.
+ */
+static void day_array(unsigned month, unsigned year, unsigned *days)
+{
+ unsigned long temp;
+ unsigned i;
+ unsigned day, dw, dm;
+
+ memset(days, SPACE, MAXDAYS * sizeof(int));
+
+ if ((month == 9) && (year == 1752)) {
+ /* Assumes the Gregorian reformation eliminates
+ * 3 Sep. 1752 through 13 Sep. 1752.
+ */
+ unsigned j_offset = julian * 244;
+ size_t oday = 0;
+
+ do {
+ days[oday+2] = sep1752[oday] + j_offset;
+ } while (++oday < sizeof(sep1752));
+
+ return;
+ }
+
+ /* day_in_year
+ * return the 1 based day number within the year
+ */
+ day = 1;
+ if ((month > 2) && leap_year(year)) {
+ ++day;
+ }
+
+ i = month;
+ while (i) {
+ day += days_in_month[--i];
+ }
+
+ /* day_in_week
+ * return the 0 based day number for any date from 1 Jan. 1 to
+ * 31 Dec. 9999. Assumes the Gregorian reformation eliminates
+ * 3 Sep. 1752 through 13 Sep. 1752. Returns Thursday for all
+ * missing days.
+ */
+ temp = (long)(year - 1) * 365 + leap_years_since_year_1(year - 1) + day;
+ if (temp < FIRST_MISSING_DAY) {
+ dw = ((temp - 1 + SATURDAY) % 7);
+ } else {
+ dw = (((temp - 1 + SATURDAY) - NUMBER_MISSING_DAYS) % 7);
+ }
+
+ if (!julian) {
+ day = 1;
+ }
+
+ dm = days_in_month[month];
+ if ((month == 2) && leap_year(year)) {
+ ++dm;
+ }
+
+ do {
+ days[dw++] = day++;
+ } while (--dm);
+}
+
+static void trim_trailing_spaces_and_print(char *s)
+{
+ char *p = s;
+
+ while (*p) {
+ ++p;
+ }
+ while (p != s) {
+ --p;
+ if (!(isspace)(*p)) { /* We want the function... not the inline. */
+ p[1] = '\0';
+ break;
+ }
+ }
+
+ puts(s);
+}
+
+static void center(char *str, unsigned len, unsigned separate)
+{
+ unsigned n = strlen(str);
+ len -= n;
+ printf("%*s%*s", (len/2) + n, str, (len/2) + (len % 2) + separate, "");
+}
+
+static void blank_string(char *buf, size_t buflen)
+{
+ memset(buf, ' ', buflen);
+ buf[buflen-1] = '\0';
+}
+
+static char *build_row(char *p, unsigned *dp)
+{
+ unsigned col, val, day;
+
+ memset(p, ' ', (julian + DAY_LEN) * 7);
+
+ col = 0;
+ do {
+ day = *dp++;
+ if (day != SPACE) {
+ if (julian) {
+ ++p;
+ if (day >= 100) {
+ *p = '0';
+ p[-1] = (day / 100) + '0';
+ day %= 100;
+ }
+ }
+ val = day / 10;
+ if (val > 0) {
+ *p = val + '0';
+ }
+ *++p = day % 10 + '0';
+ p += 2;
+ } else {
+ p += DAY_LEN + julian;
+ }
+ } while (++col < 7);
+
+ return p;
+}
+
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kim Letkeman.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/cat.c b/cleopatre/busybox-1.11.1-spc300/coreutils/cat.c
new file mode 100644
index 0000000000..989147b391
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/cat.c
@@ -0,0 +1,48 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * cat implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2, see file License in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 compliant */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/cat.html */
+
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
+
+
+int bb_cat(char **argv)
+{
+ int fd;
+ int retval = EXIT_SUCCESS;
+
+ if (!*argv)
+ argv = (char**) &bb_argv_dash;
+
+ do {
+ fd = open_or_warn_stdin(*argv);
+ if (fd >= 0) {
+ /* This is not a xfunc - never exits */
+ off_t r = bb_copyfd_eof(fd, STDOUT_FILENO);
+ if (fd != STDIN_FILENO)
+ close(fd);
+ if (r >= 0)
+ continue;
+ }
+ retval = EXIT_FAILURE;
+ } while (*++argv);
+
+ return retval;
+}
+
+int cat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int cat_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ getopt32(argv, "u");
+ argv += optind;
+ return bb_cat(argv);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/catv.c b/cleopatre/busybox-1.11.1-spc300/coreutils/catv.c
new file mode 100644
index 0000000000..b87740ec9e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/catv.c
@@ -0,0 +1,75 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * cat -v implementation for busybox
+ *
+ * Copyright (C) 2006 Rob Landley <rob@landley.net>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* See "Cat -v considered harmful" at
+ * http://cm.bell-labs.com/cm/cs/doc/84/kp.ps.gz */
+
+#include "libbb.h"
+
+int catv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int catv_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ int retval = EXIT_SUCCESS;
+ int fd;
+ unsigned flags;
+
+ flags = getopt32(argv, "etv");
+#define CATV_OPT_e (1<<0)
+#define CATV_OPT_t (1<<1)
+#define CATV_OPT_v (1<<2)
+ flags ^= CATV_OPT_v;
+ argv += optind;
+
+ /* Read from stdin if there's nothing else to do. */
+ if (!argv[0])
+ *--argv = (char*)"-";
+ do {
+ fd = open_or_warn_stdin(*argv);
+ if (fd < 0) {
+ retval = EXIT_FAILURE;
+ continue;
+ }
+ for (;;) {
+ int i, res;
+
+#define read_buf bb_common_bufsiz1
+ res = read(fd, read_buf, COMMON_BUFSIZE);
+ if (res < 0)
+ retval = EXIT_FAILURE;
+ if (res < 1)
+ break;
+ for (i = 0; i < res; i++) {
+ unsigned char c = read_buf[i];
+
+ if (c > 126 && (flags & CATV_OPT_v)) {
+ if (c == 127) {
+ printf("^?");
+ continue;
+ }
+ printf("M-");
+ c -= 128;
+ }
+ if (c < 32) {
+ if (c == 10) {
+ if (flags & CATV_OPT_e)
+ bb_putchar('$');
+ } else if (flags & (c==9 ? CATV_OPT_t : CATV_OPT_v)) {
+ printf("^%c", c+'@');
+ continue;
+ }
+ }
+ bb_putchar(c);
+ }
+ }
+ if (ENABLE_FEATURE_CLEAN_UP && fd)
+ close(fd);
+ } while (*++argv);
+
+ fflush_stdout_and_exit(retval);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/chgrp.c b/cleopatre/busybox-1.11.1-spc300/coreutils/chgrp.c
new file mode 100644
index 0000000000..7f39048054
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/chgrp.c
@@ -0,0 +1,31 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini chgrp implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 defects - none? */
+/* BB_AUDIT GNU defects - unsupported long options. */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/chgrp.html */
+
+#include "libbb.h"
+
+/* This is a NOEXEC applet. Be very careful! */
+
+
+int chgrp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int chgrp_main(int argc, char **argv)
+{
+ /* "chgrp [opts] abc file(s)" == "chown [opts] :abc file(s)" */
+ char **p = argv;
+ while (*++p) {
+ if (p[0][0] != '-') {
+ p[0] = xasprintf(":%s", p[0]);
+ break;
+ }
+ }
+ return chown_main(argc, argv);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/chmod.c b/cleopatre/busybox-1.11.1-spc300/coreutils/chmod.c
new file mode 100644
index 0000000000..1bd0bd5c29
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/chmod.c
@@ -0,0 +1,160 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini chmod implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Reworked by (C) 2002 Vladimir Oleynik <dzo@simtreas.ru>
+ * to correctly parse '-rwxgoa'
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 compliant */
+/* BB_AUDIT GNU defects - unsupported long options. */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/chmod.html */
+
+#include "libbb.h"
+
+/* This is a NOEXEC applet. Be very careful! */
+
+
+#define OPT_RECURSE (option_mask32 & 1)
+#define OPT_VERBOSE (USE_DESKTOP(option_mask32 & 2) SKIP_DESKTOP(0))
+#define OPT_CHANGED (USE_DESKTOP(option_mask32 & 4) SKIP_DESKTOP(0))
+#define OPT_QUIET (USE_DESKTOP(option_mask32 & 8) SKIP_DESKTOP(0))
+#define OPT_STR "R" USE_DESKTOP("vcf")
+
+/* coreutils:
+ * chmod never changes the permissions of symbolic links; the chmod
+ * system call cannot change their permissions. This is not a problem
+ * since the permissions of symbolic links are never used.
+ * However, for each symbolic link listed on the command line, chmod changes
+ * the permissions of the pointed-to file. In contrast, chmod ignores
+ * symbolic links encountered during recursive directory traversals.
+ */
+
+static int fileAction(const char *fileName, struct stat *statbuf, void* param, int depth)
+{
+ mode_t newmode;
+
+ /* match coreutils behavior */
+ if (depth == 0) {
+ /* statbuf holds lstat result, but we need stat (follow link) */
+ if (stat(fileName, statbuf))
+ goto err;
+ } else { /* depth > 0: skip links */
+ if (S_ISLNK(statbuf->st_mode))
+ return TRUE;
+ }
+ newmode = statbuf->st_mode;
+
+ if (!bb_parse_mode((char *)param, &newmode))
+ bb_error_msg_and_die("invalid mode: %s", (char *)param);
+
+ if (chmod(fileName, newmode) == 0) {
+ if (OPT_VERBOSE
+ || (OPT_CHANGED && statbuf->st_mode != newmode)
+ ) {
+ printf("mode of '%s' changed to %04o (%s)\n", fileName,
+ newmode & 07777, bb_mode_string(newmode)+1);
+ }
+ return TRUE;
+ }
+ err:
+ if (!OPT_QUIET)
+ bb_simple_perror_msg(fileName);
+ return FALSE;
+}
+
+int chmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int chmod_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ int retval = EXIT_SUCCESS;
+ char *arg, **argp;
+ char *smode;
+
+ /* Convert first encountered -r into ar, -w into aw etc
+ * so that getopt would not eat it */
+ argp = argv;
+ while ((arg = *++argp)) {
+ /* Mode spec must be the first arg (sans -R etc) */
+ /* (protect against mishandling e.g. "chmod 644 -r") */
+ if (arg[0] != '-') {
+ arg = NULL;
+ break;
+ }
+ /* An option. Not a -- or valid option? */
+ if (arg[1] && !strchr("-"OPT_STR, arg[1])) {
+ arg[0] = 'a';
+ break;
+ }
+ }
+
+ /* Parse options */
+ opt_complementary = "-2";
+ getopt32(argv, ("-"OPT_STR) + 1); /* Reuse string */
+ argv += optind;
+
+ /* Restore option-like mode if needed */
+ if (arg) arg[0] = '-';
+
+ /* Ok, ready to do the deed now */
+ smode = *argv++;
+ do {
+ if (!recursive_action(*argv,
+ OPT_RECURSE, // recurse
+ fileAction, // file action
+ fileAction, // dir action
+ smode, // user data
+ 0) // depth
+ ) {
+ retval = EXIT_FAILURE;
+ }
+ } while (*++argv);
+
+ return retval;
+}
+
+/*
+Security: chmod is too important and too subtle.
+This is a test script (busybox chmod versus coreutils).
+Run it in empty directory.
+
+#!/bin/sh
+t1="/tmp/busybox chmod"
+t2="/usr/bin/chmod"
+create() {
+ rm -rf $1; mkdir $1
+ (
+ cd $1 || exit 1
+ mkdir dir
+ >up
+ >file
+ >dir/file
+ ln -s dir linkdir
+ ln -s file linkfile
+ ln -s ../up dir/up
+ )
+}
+tst() {
+ (cd test1; $t1 $1)
+ (cd test2; $t2 $1)
+ (cd test1; ls -lR) >out1
+ (cd test2; ls -lR) >out2
+ echo "chmod $1" >out.diff
+ if ! diff -u out1 out2 >>out.diff; then exit 1; fi
+ rm out.diff
+}
+echo "If script produced 'out.diff' file, then at least one testcase failed"
+create test1; create test2
+tst "a+w file"
+tst "a-w dir"
+tst "a+w linkfile"
+tst "a-w linkdir"
+tst "-R a+w file"
+tst "-R a-w dir"
+tst "-R a+w linkfile"
+tst "-R a-w linkdir"
+tst "a-r,a+x linkfile"
+*/
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/chown.c b/cleopatre/busybox-1.11.1-spc300/coreutils/chown.c
new file mode 100644
index 0000000000..78377e6a02
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/chown.c
@@ -0,0 +1,170 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini chown implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 defects - none? */
+/* BB_AUDIT GNU defects - unsupported long options. */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/chown.html */
+
+#include "libbb.h"
+
+/* This is a NOEXEC applet. Be very careful! */
+
+
+#define OPT_STR ("Rh" USE_DESKTOP("vcfLHP"))
+#define BIT_RECURSE 1
+#define OPT_RECURSE (option_mask32 & 1)
+#define OPT_NODEREF (option_mask32 & 2)
+#define OPT_VERBOSE (USE_DESKTOP(option_mask32 & 0x04) SKIP_DESKTOP(0))
+#define OPT_CHANGED (USE_DESKTOP(option_mask32 & 0x08) SKIP_DESKTOP(0))
+#define OPT_QUIET (USE_DESKTOP(option_mask32 & 0x10) SKIP_DESKTOP(0))
+/* POSIX options
+ * -L traverse every symbolic link to a directory encountered
+ * -H if a command line argument is a symbolic link to a directory, traverse it
+ * -P do not traverse any symbolic links (default)
+ * We do not conform to the following:
+ * "Specifying more than one of -H, -L, and -P is not an error.
+ * The last option specified shall determine the behavior of the utility." */
+/* -L */
+#define BIT_TRAVERSE 0x20
+#define OPT_TRAVERSE (USE_DESKTOP(option_mask32 & BIT_TRAVERSE) SKIP_DESKTOP(0))
+/* -H or -L */
+#define BIT_TRAVERSE_TOP (0x20|0x40)
+#define OPT_TRAVERSE_TOP (USE_DESKTOP(option_mask32 & BIT_TRAVERSE_TOP) SKIP_DESKTOP(0))
+
+typedef int (*chown_fptr)(const char *, uid_t, gid_t);
+
+static struct bb_uidgid_t ugid = { -1, -1 };
+
+static int fileAction(const char *fileName, struct stat *statbuf,
+ void *cf, int depth ATTRIBUTE_UNUSED)
+{
+ uid_t u = (ugid.uid == (uid_t)-1) ? statbuf->st_uid : ugid.uid;
+ gid_t g = (ugid.gid == (gid_t)-1) ? statbuf->st_gid : ugid.gid;
+
+ if (!((chown_fptr)cf)(fileName, u, g)) {
+ if (OPT_VERBOSE
+ || (OPT_CHANGED && (statbuf->st_uid != u || statbuf->st_gid != g))
+ ) {
+ printf("changed ownership of '%s' to %u:%u\n",
+ fileName, (unsigned)u, (unsigned)g);
+ }
+ return TRUE;
+ }
+ if (!OPT_QUIET)
+ bb_simple_perror_msg(fileName); /* A filename can have % in it... */
+ return FALSE;
+}
+
+int chown_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ int retval = EXIT_SUCCESS;
+ int flags;
+ chown_fptr chown_func;
+
+ opt_complementary = "-2";
+ getopt32(argv, OPT_STR);
+ argv += optind;
+
+ /* This matches coreutils behavior (almost - see below) */
+ chown_func = chown;
+ if (OPT_NODEREF
+ /* || (OPT_RECURSE && !OPT_TRAVERSE_TOP): */
+ USE_DESKTOP( || (option_mask32 & (BIT_RECURSE|BIT_TRAVERSE_TOP)) == BIT_RECURSE)
+ ) {
+ chown_func = lchown;
+ }
+
+ flags = ACTION_DEPTHFIRST; /* match coreutils order */
+ if (OPT_RECURSE)
+ flags |= ACTION_RECURSE;
+ if (OPT_TRAVERSE_TOP)
+ flags |= ACTION_FOLLOWLINKS_L0; /* -H/-L: follow links on depth 0 */
+ if (OPT_TRAVERSE)
+ flags |= ACTION_FOLLOWLINKS; /* follow links if -L */
+
+ parse_chown_usergroup_or_die(&ugid, argv[0]);
+
+ /* Ok, ready to do the deed now */
+ argv++;
+ do {
+ if (!recursive_action(*argv,
+ flags, /* flags */
+ fileAction, /* file action */
+ fileAction, /* dir action */
+ chown_func, /* user data */
+ 0) /* depth */
+ ) {
+ retval = EXIT_FAILURE;
+ }
+ } while (*++argv);
+
+ return retval;
+}
+
+/*
+Testcase. Run in empty directory.
+
+#!/bin/sh
+t1="/tmp/busybox chown"
+t2="/usr/bin/chown"
+create() {
+ rm -rf $1; mkdir $1
+ (
+ cd $1 || exit 1
+ mkdir dir dir2
+ >up
+ >file
+ >dir/file
+ >dir2/file
+ ln -s dir linkdir
+ ln -s file linkfile
+ ln -s ../up dir/linkup
+ ln -s ../dir2 dir/linkupdir2
+ )
+ chown -R 0:0 $1
+}
+tst() {
+ create test1
+ create test2
+ echo "[$1]" >>test1.out
+ echo "[$1]" >>test2.out
+ (cd test1; $t1 $1) >>test1.out 2>&1
+ (cd test2; $t2 $1) >>test2.out 2>&1
+ (cd test1; ls -lnR) >out1
+ (cd test2; ls -lnR) >out2
+ echo "chown $1" >out.diff
+ if ! diff -u out1 out2 >>out.diff; then exit 1; fi
+ rm out.diff
+}
+tst_for_each() {
+ tst "$1 1:1 file"
+ tst "$1 1:1 dir"
+ tst "$1 1:1 linkdir"
+ tst "$1 1:1 linkfile"
+}
+echo "If script produced 'out.diff' file, then at least one testcase failed"
+>test1.out
+>test2.out
+# These match coreutils 6.8:
+tst_for_each "-v"
+tst_for_each "-vR"
+tst_for_each "-vRP"
+tst_for_each "-vRL"
+tst_for_each "-vRH"
+tst_for_each "-vh"
+tst_for_each "-vhR"
+tst_for_each "-vhRP"
+tst_for_each "-vhRL"
+tst_for_each "-vhRH"
+# Fix `name' in coreutils output
+sed 's/`/'"'"'/g' -i test2.out
+# Compare us with coreutils output
+diff -u test1.out test2.out
+
+*/
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/chroot.c b/cleopatre/busybox-1.11.1-spc300/coreutils/chroot.c
new file mode 100644
index 0000000000..1198a415a2
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/chroot.c
@@ -0,0 +1,37 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini chroot implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */
+
+#include "libbb.h"
+
+int chroot_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int chroot_main(int argc, char **argv)
+{
+ if (argc < 2) {
+ bb_show_usage();
+ }
+
+ ++argv;
+ xchroot(*argv);
+ xchdir("/");
+
+ ++argv;
+ if (argc == 2) {
+ argv -= 2;
+ argv[0] = getenv("SHELL");
+ if (!argv[0]) {
+ argv[0] = (char *) DEFAULT_SHELL;
+ }
+ argv[1] = (char *) "-i";
+ }
+
+ BB_EXECVP(*argv, argv);
+ bb_perror_msg_and_die("cannot execute %s", *argv);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/cksum.c b/cleopatre/busybox-1.11.1-spc300/coreutils/cksum.c
new file mode 100644
index 0000000000..074d068118
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/cksum.c
@@ -0,0 +1,56 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * cksum - calculate the CRC32 checksum of a file
+ *
+ * Copyright (C) 2006 by Rob Sullivan, with ideas from code by Walter Harms
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */
+
+#include "libbb.h"
+
+int cksum_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int cksum_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ uint32_t *crc32_table = crc32_filltable(NULL, 1);
+ uint32_t crc;
+ long length, filesize;
+ int bytes_read;
+ uint8_t *cp;
+
+#if ENABLE_DESKTOP
+ getopt32(argv, ""); /* coreutils 6.9 compat */
+ argv += optind;
+#else
+ argv++;
+#endif
+
+ do {
+ int fd = open_or_warn_stdin(*argv ? *argv : bb_msg_standard_input);
+
+ if (fd < 0)
+ continue;
+ crc = 0;
+ length = 0;
+
+#define read_buf bb_common_bufsiz1
+ while ((bytes_read = safe_read(fd, read_buf, sizeof(read_buf))) > 0) {
+ cp = (uint8_t *) read_buf;
+ length += bytes_read;
+ do {
+ crc = (crc << 8) ^ crc32_table[(crc >> 24) ^ *cp++];
+ } while (--bytes_read);
+ }
+ close(fd);
+
+ filesize = length;
+
+ for (; length; length >>= 8)
+ crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ length) & 0xff];
+ crc ^= 0xffffffffL;
+
+ printf((*argv ? "%" PRIu32 " %li %s\n" : "%" PRIu32 " %li\n"),
+ crc, filesize, *argv);
+ } while (*argv && *++argv);
+
+ fflush_stdout_and_exit(EXIT_SUCCESS);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/comm.c b/cleopatre/busybox-1.11.1-spc300/coreutils/comm.c
new file mode 100644
index 0000000000..4dbc0d4778
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/comm.c
@@ -0,0 +1,113 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini comm implementation for busybox
+ *
+ * Copyright (C) 2005 by Robert Sullivan <cogito.ergo.cogito@gmail.com>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+#define COMM_OPT_1 (1 << 0)
+#define COMM_OPT_2 (1 << 1)
+#define COMM_OPT_3 (1 << 2)
+
+/* writeline outputs the input given, appropriately aligned according to class */
+static void writeline(char *line, int class, int flags)
+{
+ if (class == 0) {
+ if (flags & COMM_OPT_1)
+ return;
+ } else if (class == 1) {
+ if (flags & COMM_OPT_2)
+ return;
+ if (!(flags & COMM_OPT_1))
+ putchar('\t');
+ } else /*if (class == 2)*/ {
+ if (flags & COMM_OPT_3)
+ return;
+ if (!(flags & COMM_OPT_1))
+ putchar('\t');
+ if (!(flags & COMM_OPT_2))
+ putchar('\t');
+ }
+ fputs(line, stdout);
+}
+
+int comm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int comm_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+#define LINE_LEN 100
+#define BB_EOF_0 0x1
+#define BB_EOF_1 0x2
+ char thisline[2][LINE_LEN];
+ FILE *streams[2];
+ int i;
+ unsigned flags;
+
+ opt_complementary = "=2";
+ flags = getopt32(argv, "123");
+ argv += optind;
+
+ for (i = 0; i < 2; ++i) {
+ streams[i] = (argv[i][0] == '-' && !argv[i][1]) ? stdin : xfopen(argv[i], "r");
+ fgets(thisline[i], LINE_LEN, streams[i]);
+ }
+
+ /* This is the real core of the program - lines are compared here */
+
+ while (*thisline[0] || *thisline[1]) {
+ int order = 0;
+
+ i = 0;
+ if (feof(streams[0])) i |= BB_EOF_0;
+ if (feof(streams[1])) i |= BB_EOF_1;
+
+ if (!*thisline[0])
+ order = 1;
+ else if (!*thisline[1])
+ order = -1;
+ else {
+ int tl0_len, tl1_len;
+ tl0_len = strlen(thisline[0]);
+ tl1_len = strlen(thisline[1]);
+ order = memcmp(thisline[0], thisline[1], tl0_len < tl1_len ? tl0_len : tl1_len);
+ if (!order)
+ order = tl0_len < tl1_len ? -1 : tl0_len != tl1_len;
+ }
+
+ if (order == 0 && !i)
+ writeline(thisline[1], 2, flags);
+ else if (order > 0 && !(i & BB_EOF_1))
+ writeline(thisline[1], 1, flags);
+ else if (order < 0 && !(i & BB_EOF_0))
+ writeline(thisline[0], 0, flags);
+
+ if (i & BB_EOF_0 & BB_EOF_1) {
+ break;
+
+ } else if (i) {
+ i = (i & BB_EOF_0 ? 1 : 0);
+ while (!feof(streams[i])) {
+ if ((order < 0 && i) || (order > 0 && !i))
+ writeline(thisline[i], i, flags);
+ fgets(thisline[i], LINE_LEN, streams[i]);
+ }
+ break;
+
+ } else {
+ if (order >= 0)
+ fgets(thisline[1], LINE_LEN, streams[1]);
+ if (order <= 0)
+ fgets(thisline[0], LINE_LEN, streams[0]);
+ }
+ }
+
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ fclose(streams[0]);
+ fclose(streams[1]);
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/cp.c b/cleopatre/busybox-1.11.1-spc300/coreutils/cp.c
new file mode 100644
index 0000000000..40d3625b32
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/cp.c
@@ -0,0 +1,107 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini cp implementation for busybox
+ *
+ * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ * SELinux support by Yuichi Nakamura <ynakam@hitachisoft.jp>
+ *
+ * Licensed under GPL v2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/cp.html */
+
+/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
+ *
+ * Size reduction.
+ */
+
+#include "libbb.h"
+#include "libcoreutils/coreutils.h"
+
+/* This is a NOEXEC applet. Be very careful! */
+
+
+int cp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int cp_main(int argc, char **argv)
+{
+ struct stat source_stat;
+ struct stat dest_stat;
+ const char *last;
+ const char *dest;
+ int s_flags;
+ int d_flags;
+ int flags;
+ int status = 0;
+ enum {
+ OPT_a = 1 << (sizeof(FILEUTILS_CP_OPTSTR)-1),
+ OPT_r = 1 << (sizeof(FILEUTILS_CP_OPTSTR)),
+ OPT_P = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+1),
+ OPT_H = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+2),
+ };
+
+ // Need at least two arguments
+ // Soft- and hardlinking doesn't mix
+ // -P and -d are the same (-P is POSIX, -d is GNU)
+ // -r and -R are the same
+ // -R (and therefore -r) turns on -d (coreutils does this)
+ // -a = -pdR
+ opt_complementary = "-2:l--s:s--l:Pd:rRd:Rd:apdR:HL";
+ flags = getopt32(argv, FILEUTILS_CP_OPTSTR "arPH");
+ argc -= optind;
+ argv += optind;
+ flags ^= FILEUTILS_DEREFERENCE; /* the sense of this flag was reversed */
+ /* coreutils 6.9 compat:
+ * by default, "cp" derefs symlinks (creates regular dest files),
+ * but "cp -R" does not. We switch off deref if -r or -R (see above).
+ * However, "cp -RL" must still deref symlinks: */
+ if (flags & FILEUTILS_DEREF_SOFTLINK) /* -L */
+ flags |= FILEUTILS_DEREFERENCE;
+ /* The behavior of -H is *almost* like -L, but not quite, so let's
+ * just ignore it too for fun. TODO.
+ if (flags & OPT_H) ... // deref command-line params only
+ */
+
+#if ENABLE_SELINUX
+ if (flags & FILEUTILS_PRESERVE_SECURITY_CONTEXT) {
+ selinux_or_die();
+ }
+#endif
+
+ last = argv[argc - 1];
+ /* If there are only two arguments and... */
+ if (argc == 2) {
+ s_flags = cp_mv_stat2(*argv, &source_stat,
+ (flags & FILEUTILS_DEREFERENCE) ? stat : lstat);
+ if (s_flags < 0)
+ return EXIT_FAILURE;
+ d_flags = cp_mv_stat(last, &dest_stat);
+ if (d_flags < 0)
+ return EXIT_FAILURE;
+
+ /* ...if neither is a directory or... */
+ if ( !((s_flags | d_flags) & 2) ||
+ /* ...recursing, the 1st is a directory, and the 2nd doesn't exist... */
+ ((flags & FILEUTILS_RECUR) && (s_flags & 2) && !d_flags)
+ ) {
+ /* ...do a simple copy. */
+ dest = last;
+ goto DO_COPY; /* NB: argc==2 -> *++argv==last */
+ }
+ }
+
+ while (1) {
+ dest = concat_path_file(last, bb_get_last_path_component_strip(*argv));
+ DO_COPY:
+ if (copy_file(*argv, dest, flags) < 0) {
+ status = 1;
+ }
+ if (*++argv == last) {
+ /* possibly leaking dest... */
+ break;
+ }
+ free((void*)dest);
+ }
+
+ /* Exit. We are NOEXEC, not NOFORK. We do exit at the end of main() */
+ return status;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/cut.c b/cleopatre/busybox-1.11.1-spc300/coreutils/cut.c
new file mode 100644
index 0000000000..1634fc8c8e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/cut.c
@@ -0,0 +1,279 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * cut.c - minimalist version of cut
+ *
+ * Copyright (C) 1999,2000,2001 by Lineo, inc.
+ * Written by Mark Whitley <markw@codepoet.org>
+ * debloated by Bernhard Fischer
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* This is a NOEXEC applet. Be very careful! */
+
+
+/* option vars */
+static const char optstring[] ALIGN1 = "b:c:f:d:sn";
+#define CUT_OPT_BYTE_FLGS (1 << 0)
+#define CUT_OPT_CHAR_FLGS (1 << 1)
+#define CUT_OPT_FIELDS_FLGS (1 << 2)
+#define CUT_OPT_DELIM_FLGS (1 << 3)
+#define CUT_OPT_SUPPRESS_FLGS (1 << 4)
+
+struct cut_list {
+ int startpos;
+ int endpos;
+};
+
+enum {
+ BOL = 0,
+ EOL = INT_MAX,
+ NON_RANGE = -1
+};
+
+/* growable array holding a series of lists */
+static struct cut_list *cut_lists;
+static unsigned int nlists; /* number of elements in above list */
+
+
+static int cmpfunc(const void *a, const void *b)
+{
+ return (((struct cut_list *) a)->startpos -
+ ((struct cut_list *) b)->startpos);
+
+}
+
+static void cut_file(FILE *file, char delim)
+{
+ char *line = NULL;
+ unsigned int linenum = 0; /* keep these zero-based to be consistent */
+
+ /* go through every line in the file */
+ while ((line = xmalloc_fgetline(file)) != NULL) {
+
+ /* set up a list so we can keep track of what's been printed */
+ char * printed = xzalloc(strlen(line) * sizeof(char));
+ char * orig_line = line;
+ unsigned int cl_pos = 0;
+ int spos;
+
+ /* cut based on chars/bytes XXX: only works when sizeof(char) == byte */
+ if (option_mask32 & (CUT_OPT_CHAR_FLGS | CUT_OPT_BYTE_FLGS)) {
+ /* print the chars specified in each cut list */
+ for (; cl_pos < nlists; cl_pos++) {
+ spos = cut_lists[cl_pos].startpos;
+ while (spos < (int)strlen(line)) {
+ if (!printed[spos]) {
+ printed[spos] = 'X';
+ putchar(line[spos]);
+ }
+ spos++;
+ if (spos > cut_lists[cl_pos].endpos
+ || cut_lists[cl_pos].endpos == NON_RANGE)
+ break;
+ }
+ }
+ } else if (delim == '\n') { /* cut by lines */
+ spos = cut_lists[cl_pos].startpos;
+
+ /* get out if we have no more lists to process or if the lines
+ * are lower than what we're interested in */
+ if (((int)linenum < spos) || (cl_pos >= nlists))
+ goto next_line;
+
+ /* if the line we're looking for is lower than the one we were
+ * passed, it means we displayed it already, so move on */
+ while (spos < (int)linenum) {
+ spos++;
+ /* go to the next list if we're at the end of this one */
+ if (spos > cut_lists[cl_pos].endpos
+ || cut_lists[cl_pos].endpos == NON_RANGE) {
+ cl_pos++;
+ /* get out if there's no more lists to process */
+ if (cl_pos >= nlists)
+ goto next_line;
+ spos = cut_lists[cl_pos].startpos;
+ /* get out if the current line is lower than the one
+ * we just became interested in */
+ if ((int)linenum < spos)
+ goto next_line;
+ }
+ }
+
+ /* If we made it here, it means we've found the line we're
+ * looking for, so print it */
+ puts(line);
+ goto next_line;
+ } else { /* cut by fields */
+ int ndelim = -1; /* zero-based / one-based problem */
+ int nfields_printed = 0;
+ char *field = NULL;
+ const char delimiter[2] = { delim, 0 };
+
+ /* does this line contain any delimiters? */
+ if (strchr(line, delim) == NULL) {
+ if (!(option_mask32 & CUT_OPT_SUPPRESS_FLGS))
+ puts(line);
+ goto next_line;
+ }
+
+ /* process each list on this line, for as long as we've got
+ * a line to process */
+ for (; cl_pos < nlists && line; cl_pos++) {
+ spos = cut_lists[cl_pos].startpos;
+ do {
+ /* find the field we're looking for */
+ while (line && ndelim < spos) {
+ field = strsep(&line, delimiter);
+ ndelim++;
+ }
+
+ /* we found it, and it hasn't been printed yet */
+ if (field && ndelim == spos && !printed[ndelim]) {
+ /* if this isn't our first time through, we need to
+ * print the delimiter after the last field that was
+ * printed */
+ if (nfields_printed > 0)
+ putchar(delim);
+ fputs(field, stdout);
+ printed[ndelim] = 'X';
+ nfields_printed++; /* shouldn't overflow.. */
+ }
+
+ spos++;
+
+ /* keep going as long as we have a line to work with,
+ * this is a list, and we're not at the end of that
+ * list */
+ } while (spos <= cut_lists[cl_pos].endpos && line
+ && cut_lists[cl_pos].endpos != NON_RANGE);
+ }
+ }
+ /* if we printed anything at all, we need to finish it with a
+ * newline cuz we were handed a chomped line */
+ putchar('\n');
+ next_line:
+ linenum++;
+ free(printed);
+ free(orig_line);
+ }
+}
+
+int cut_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int cut_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ char delim = '\t'; /* delimiter, default is tab */
+ char *sopt, *ltok;
+
+ opt_complementary = "b--bcf:c--bcf:f--bcf";
+ getopt32(argv, optstring, &sopt, &sopt, &sopt, &ltok);
+// argc -= optind;
+ argv += optind;
+ if (!(option_mask32 & (CUT_OPT_BYTE_FLGS | CUT_OPT_CHAR_FLGS | CUT_OPT_FIELDS_FLGS)))
+ bb_error_msg_and_die("expected a list of bytes, characters, or fields");
+
+ if (option_mask32 & CUT_OPT_DELIM_FLGS) {
+ if (ltok[0] && ltok[1]) { /* more than 1 char? */
+ bb_error_msg_and_die("the delimiter must be a single character");
+ }
+ delim = ltok[0];
+ }
+
+ /* non-field (char or byte) cutting has some special handling */
+ if (!(option_mask32 & CUT_OPT_FIELDS_FLGS)) {
+ static const char _op_on_field[] ALIGN1 = " only when operating on fields";
+
+ if (option_mask32 & CUT_OPT_SUPPRESS_FLGS) {
+ bb_error_msg_and_die
+ ("suppressing non-delimited lines makes sense%s",
+ _op_on_field);
+ }
+ if (delim != '\t') {
+ bb_error_msg_and_die
+ ("a delimiter may be specified%s", _op_on_field);
+ }
+ }
+
+ /*
+ * parse list and put values into startpos and endpos.
+ * valid list formats: N, N-, N-M, -M
+ * more than one list can be separated by commas
+ */
+ {
+ char *ntok;
+ int s = 0, e = 0;
+
+ /* take apart the lists, one by one (they are separated with commas) */
+ while ((ltok = strsep(&sopt, ",")) != NULL) {
+
+ /* it's actually legal to pass an empty list */
+ if (!ltok[0])
+ continue;
+
+ /* get the start pos */
+ ntok = strsep(&ltok, "-");
+ if (!ntok[0]) {
+ s = BOL;
+ } else {
+ s = xatoi_u(ntok);
+ /* account for the fact that arrays are zero based, while
+ * the user expects the first char on the line to be char #1 */
+ if (s != 0)
+ s--;
+ }
+
+ /* get the end pos */
+ if (ltok == NULL) {
+ e = NON_RANGE;
+ } else if (!ltok[0]) {
+ e = EOL;
+ } else {
+ e = xatoi_u(ltok);
+ /* if the user specified and end position of 0, that means "til the
+ * end of the line */
+ if (e == 0)
+ e = EOL;
+ e--; /* again, arrays are zero based, lines are 1 based */
+ if (e == s)
+ e = NON_RANGE;
+ }
+
+ /* add the new list */
+ cut_lists = xrealloc(cut_lists, sizeof(struct cut_list) * (++nlists));
+ cut_lists[nlists-1].startpos = s;
+ cut_lists[nlists-1].endpos = e;
+ }
+
+ /* make sure we got some cut positions out of all that */
+ if (nlists == 0)
+ bb_error_msg_and_die("missing list of positions");
+
+ /* now that the lists are parsed, we need to sort them to make life
+ * easier on us when it comes time to print the chars / fields / lines
+ */
+ qsort(cut_lists, nlists, sizeof(struct cut_list), cmpfunc);
+ }
+
+ {
+ int retval = EXIT_SUCCESS;
+
+ if (!*argv)
+ *--argv = (char *)"-";
+
+ do {
+ FILE *file = fopen_or_warn_stdin(*argv);
+ if (!file) {
+ retval = EXIT_FAILURE;
+ continue;
+ }
+ cut_file(file, delim);
+ fclose_if_not_stdin(file);
+ } while (*++argv);
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(cut_lists);
+ fflush_stdout_and_exit(retval);
+ }
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/date.c b/cleopatre/busybox-1.11.1-spc300/coreutils/date.c
new file mode 100644
index 0000000000..5b0f60f1ab
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/date.c
@@ -0,0 +1,239 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini date implementation for busybox
+ *
+ * by Matthew Grant <grantma@anathoth.gen.nz>
+ *
+ * iso-format handling added by Robert Griebl <griebl@gmx.de>
+ * bugfixes and cleanup by Bernhard Fischer
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+*/
+
+#include "libbb.h"
+
+/* This 'date' command supports only 2 time setting formats,
+ all the GNU strftime stuff (its in libc, lets use it),
+ setting time using UTC and displaying it, as well as
+ an RFC 2822 compliant date output for shell scripting
+ mail commands */
+
+/* Input parsing code is always bulky - used heavy duty libc stuff as
+ much as possible, missed out a lot of bounds checking */
+
+/* Default input handling to save surprising some people */
+
+
+#define DATE_OPT_RFC2822 0x01
+#define DATE_OPT_SET 0x02
+#define DATE_OPT_UTC 0x04
+#define DATE_OPT_DATE 0x08
+#define DATE_OPT_REFERENCE 0x10
+#define DATE_OPT_TIMESPEC 0x20
+#define DATE_OPT_HINT 0x40
+
+static void maybe_set_utc(int opt)
+{
+ if (opt & DATE_OPT_UTC)
+ putenv((char*)"TZ=UTC0");
+}
+
+int date_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int date_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ struct tm tm_time;
+ time_t tm;
+ unsigned opt;
+ int ifmt = -1;
+ char *date_str;
+ char *fmt_dt2str;
+ char *fmt_str2dt;
+ char *filename;
+ char *isofmt_arg = NULL;
+
+ opt_complementary = "d--s:s--d"
+ USE_FEATURE_DATE_ISOFMT(":R--I:I--R");
+ opt = getopt32(argv, "Rs:ud:r:"
+ USE_FEATURE_DATE_ISOFMT("I::D:"),
+ &date_str, &date_str, &filename
+ USE_FEATURE_DATE_ISOFMT(, &isofmt_arg, &fmt_str2dt));
+ argv += optind;
+ maybe_set_utc(opt);
+
+ if (ENABLE_FEATURE_DATE_ISOFMT && (opt & DATE_OPT_TIMESPEC)) {
+ ifmt = 0; /* default is date */
+ if (isofmt_arg) {
+ static const char isoformats[] ALIGN1 =
+ "date\0""hours\0""minutes\0""seconds\0";
+ ifmt = index_in_strings(isoformats, isofmt_arg);
+ if (ifmt < 0)
+ bb_show_usage();
+ }
+ }
+
+ fmt_dt2str = NULL;
+ if (argv[0] && argv[0][0] == '+') {
+ fmt_dt2str = &argv[0][1]; /* Skip over the '+' */
+ argv++;
+ }
+ if (!(opt & (DATE_OPT_SET | DATE_OPT_DATE))) {
+ opt |= DATE_OPT_SET;
+ date_str = argv[0]; /* can be NULL */
+ if (date_str)
+ argv++;
+ }
+ if (*argv)
+ bb_show_usage();
+
+ /* Now we have parsed all the information except the date format
+ which depends on whether the clock is being set or read */
+
+ if (opt & DATE_OPT_REFERENCE) {
+ struct stat statbuf;
+ xstat(filename, &statbuf);
+ tm = statbuf.st_mtime;
+ } else
+ time(&tm);
+ memcpy(&tm_time, localtime(&tm), sizeof(tm_time));
+
+ /* If date string is given, update tm_time, and maybe set date */
+ if (date_str != NULL) {
+ /* Zero out fields - take her back to midnight! */
+ tm_time.tm_sec = 0;
+ tm_time.tm_min = 0;
+ tm_time.tm_hour = 0;
+
+ /* Process any date input to UNIX time since 1 Jan 1970 */
+ if (ENABLE_FEATURE_DATE_ISOFMT && (opt & DATE_OPT_HINT)) {
+ if (strptime(date_str, fmt_str2dt, &tm_time) == NULL)
+ bb_error_msg_and_die(bb_msg_invalid_date, date_str);
+ } else {
+ char end = '\0';
+ const char *last_colon = strrchr(date_str, ':');
+
+ if (last_colon != NULL) {
+ /* Parse input and assign appropriately to tm_time */
+
+ if (sscanf(date_str, "%u:%u%c",
+ &tm_time.tm_hour,
+ &tm_time.tm_min,
+ &end) >= 2) {
+ /* no adjustments needed */
+ } else if (sscanf(date_str, "%u.%u-%u:%u%c",
+ &tm_time.tm_mon, &tm_time.tm_mday,
+ &tm_time.tm_hour, &tm_time.tm_min,
+ &end) >= 4) {
+ /* Adjust dates from 1-12 to 0-11 */
+ tm_time.tm_mon -= 1;
+ } else if (sscanf(date_str, "%u.%u.%u-%u:%u%c", &tm_time.tm_year,
+ &tm_time.tm_mon, &tm_time.tm_mday,
+ &tm_time.tm_hour, &tm_time.tm_min,
+ &end) >= 5) {
+ tm_time.tm_year -= 1900; /* Adjust years */
+ tm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
+ } else if (sscanf(date_str, "%u-%u-%u %u:%u%c", &tm_time.tm_year,
+ &tm_time.tm_mon, &tm_time.tm_mday,
+ &tm_time.tm_hour, &tm_time.tm_min,
+ &end) >= 5) {
+ tm_time.tm_year -= 1900; /* Adjust years */
+ tm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
+//TODO: coreutils 6.9 also accepts "YYYY-MM-DD HH" (no minutes)
+ } else {
+ bb_error_msg_and_die(bb_msg_invalid_date, date_str);
+ }
+ if (end == ':') {
+ if (sscanf(last_colon + 1, "%u%c", &tm_time.tm_sec, &end) == 1)
+ end = '\0';
+ /* else end != NUL and we error out */
+ }
+ } else {
+ if (sscanf(date_str, "%2u%2u%2u%2u%u%c", &tm_time.tm_mon,
+ &tm_time.tm_mday, &tm_time.tm_hour, &tm_time.tm_min,
+ &tm_time.tm_year, &end) < 4)
+ bb_error_msg_and_die(bb_msg_invalid_date, date_str);
+ /* correct for century - minor Y2K problem here? */
+ if (tm_time.tm_year >= 1900) {
+ tm_time.tm_year -= 1900;
+ }
+ /* adjust date */
+ tm_time.tm_mon -= 1;
+ if (end == '.') {
+ if (sscanf(strchr(date_str, '.') + 1, "%u%c",
+ &tm_time.tm_sec, &end) == 1)
+ end = '\0';
+ /* else end != NUL and we error out */
+ }
+ }
+ if (end != '\0') {
+ bb_error_msg_and_die(bb_msg_invalid_date, date_str);
+ }
+ }
+ /* Correct any day of week and day of year etc. fields */
+ tm_time.tm_isdst = -1; /* Be sure to recheck dst. */
+ tm = mktime(&tm_time);
+ if (tm < 0) {
+ bb_error_msg_and_die(bb_msg_invalid_date, date_str);
+ }
+ maybe_set_utc(opt);
+
+ /* if setting time, set it */
+ if ((opt & DATE_OPT_SET) && stime(&tm) < 0) {
+ bb_perror_msg("cannot set date");
+ }
+ }
+
+ /* Display output */
+
+ /* Deal with format string */
+ if (fmt_dt2str == NULL) {
+ int i;
+ fmt_dt2str = xzalloc(32);
+ if (ENABLE_FEATURE_DATE_ISOFMT && ifmt >= 0) {
+ strcpy(fmt_dt2str, "%Y-%m-%d");
+ if (ifmt > 0) {
+ i = 8;
+ fmt_dt2str[i++] = 'T';
+ fmt_dt2str[i++] = '%';
+ fmt_dt2str[i++] = 'H';
+ if (ifmt > 1) {
+ fmt_dt2str[i++] = ':';
+ fmt_dt2str[i++] = '%';
+ fmt_dt2str[i++] = 'M';
+ if (ifmt > 2) {
+ fmt_dt2str[i++] = ':';
+ fmt_dt2str[i++] = '%';
+ fmt_dt2str[i++] = 'S';
+ }
+ }
+ format_utc:
+ fmt_dt2str[i++] = '%';
+ fmt_dt2str[i] = (opt & DATE_OPT_UTC) ? 'Z' : 'z';
+ }
+ } else if (opt & DATE_OPT_RFC2822) {
+ /* Undo busybox.c for date -R */
+ if (ENABLE_LOCALE_SUPPORT)
+ setlocale(LC_TIME, "C");
+ strcpy(fmt_dt2str, "%a, %d %b %Y %H:%M:%S ");
+ i = 22;
+ goto format_utc;
+ } else /* default case */
+ fmt_dt2str = (char*)"%a %b %e %H:%M:%S %Z %Y";
+ }
+
+#define date_buf bb_common_bufsiz1
+ if (*fmt_dt2str == '\0') {
+ /* With no format string, just print a blank line */
+ date_buf[0] = '\0';
+ } else {
+ /* Handle special conversions */
+ if (strncmp(fmt_dt2str, "%f", 2) == 0) {
+ fmt_dt2str = (char*)"%Y.%m.%d-%H:%M:%S";
+ }
+
+ /* Generate output string */
+ strftime(date_buf, sizeof(date_buf), fmt_dt2str, &tm_time);
+ }
+ puts(date_buf);
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/dd.c b/cleopatre/busybox-1.11.1-spc300/coreutils/dd.c
new file mode 100644
index 0000000000..6b66366b60
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/dd.c
@@ -0,0 +1,356 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini dd implementation for busybox
+ *
+ *
+ * Copyright (C) 2000,2001 Matt Kraai
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include <signal.h> /* For FEATURE_DD_SIGNAL_HANDLING */
+#include "libbb.h"
+
+/* This is a NOEXEC applet. Be very careful! */
+
+
+enum {
+ ifd = STDIN_FILENO,
+ ofd = STDOUT_FILENO,
+};
+
+static const struct suffix_mult dd_suffixes[] = {
+ { "c", 1 },
+ { "w", 2 },
+ { "b", 512 },
+ { "kD", 1000 },
+ { "k", 1024 },
+ { "K", 1024 }, /* compat with coreutils dd */
+ { "MD", 1000000 },
+ { "M", 1048576 },
+ { "GD", 1000000000 },
+ { "G", 1073741824 },
+ { }
+};
+
+struct globals {
+ off_t out_full, out_part, in_full, in_part;
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+/* We have to zero it out because of NOEXEC */
+#define INIT_G() memset(&G, 0, sizeof(G))
+
+
+static void dd_output_status(int ATTRIBUTE_UNUSED cur_signal)
+{
+ /* Deliberately using %u, not %d */
+ fprintf(stderr, "%"OFF_FMT"u+%"OFF_FMT"u records in\n"
+ "%"OFF_FMT"u+%"OFF_FMT"u records out\n",
+ G.in_full, G.in_part,
+ G.out_full, G.out_part);
+}
+
+static ssize_t full_write_or_warn(const void *buf, size_t len,
+ const char *const filename)
+{
+ ssize_t n = full_write(ofd, buf, len);
+ if (n < 0)
+ bb_perror_msg("writing '%s'", filename);
+ return n;
+}
+
+static bool write_and_stats(const void *buf, size_t len, size_t obs,
+ const char *filename)
+{
+ ssize_t n = full_write_or_warn(buf, len, filename);
+ if (n < 0)
+ return 1;
+ if ((size_t)n == obs)
+ G.out_full++;
+ else if (n) /* > 0 */
+ G.out_part++;
+ return 0;
+}
+
+#if ENABLE_LFS
+#define XATOU_SFX xatoull_sfx
+#else
+#define XATOU_SFX xatoul_sfx
+#endif
+
+int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int dd_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ enum {
+ /* Must be in the same order as OP_conv_XXX! */
+ /* (see "flags |= (1 << what)" below) */
+ FLAG_NOTRUNC = 1 << 0,
+ FLAG_SYNC = 1 << 1,
+ FLAG_NOERROR = 1 << 2,
+ FLAG_FSYNC = 1 << 3,
+ /* end of conv flags */
+ FLAG_TWOBUFS = 1 << 4,
+ FLAG_COUNT = 1 << 5,
+ };
+ static const char keywords[] ALIGN1 =
+ "bs\0""count\0""seek\0""skip\0""if\0""of\0"
+#if ENABLE_FEATURE_DD_IBS_OBS
+ "ibs\0""obs\0""conv\0"
+#endif
+ ;
+#if ENABLE_FEATURE_DD_IBS_OBS
+ static const char conv_words[] ALIGN1 =
+ "notrunc\0""sync\0""noerror\0""fsync\0";
+#endif
+ enum {
+ OP_bs = 0,
+ OP_count,
+ OP_seek,
+ OP_skip,
+ OP_if,
+ OP_of,
+#if ENABLE_FEATURE_DD_IBS_OBS
+ OP_ibs,
+ OP_obs,
+ OP_conv,
+ /* Must be in the same order as FLAG_XXX! */
+ OP_conv_notrunc = 0,
+ OP_conv_sync,
+ OP_conv_noerror,
+ OP_conv_fsync,
+ /* Unimplemented conv=XXX: */
+ //nocreat do not create the output file
+ //excl fail if the output file already exists
+ //fdatasync physically write output file data before finishing
+ //swab swap every pair of input bytes
+ //lcase change upper case to lower case
+ //ucase change lower case to upper case
+ //block pad newline-terminated records with spaces to cbs-size
+ //unblock replace trailing spaces in cbs-size records with newline
+ //ascii from EBCDIC to ASCII
+ //ebcdic from ASCII to EBCDIC
+ //ibm from ASCII to alternate EBCDIC
+#endif
+ };
+ int exitcode = EXIT_FAILURE;
+ size_t ibs = 512, obs = 512;
+ ssize_t n, w;
+ char *ibuf, *obuf;
+ /* And these are all zeroed at once! */
+ struct {
+ int flags;
+ size_t oc;
+ off_t count;
+ off_t seek, skip;
+ const char *infile, *outfile;
+ } Z;
+#define flags (Z.flags )
+#define oc (Z.oc )
+#define count (Z.count )
+#define seek (Z.seek )
+#define skip (Z.skip )
+#define infile (Z.infile )
+#define outfile (Z.outfile)
+
+ memset(&Z, 0, sizeof(Z));
+ INIT_G();
+ //fflush(NULL); - is this needed because of NOEXEC?
+
+#if ENABLE_FEATURE_DD_SIGNAL_HANDLING
+ signal_SA_RESTART_empty_mask(SIGUSR1, dd_output_status);
+#endif
+
+ for (n = 1; argv[n]; n++) {
+ int what;
+ char *val;
+ char *arg = argv[n];
+
+#if ENABLE_DESKTOP
+ /* "dd --". NB: coreutils 6.9 will complain if they see
+ * more than one of them. We wouldn't. */
+ if (arg[0] == '-' && arg[1] == '-' && arg[2] == '\0')
+ continue;
+#endif
+ val = strchr(arg, '=');
+ if (val == NULL)
+ bb_show_usage();
+ *val = '\0';
+ what = index_in_strings(keywords, arg);
+ if (what < 0)
+ bb_show_usage();
+ /* *val = '='; - to preserve ps listing? */
+ val++;
+#if ENABLE_FEATURE_DD_IBS_OBS
+ if (what == OP_ibs) {
+ /* Must fit into positive ssize_t */
+ ibs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, dd_suffixes);
+ /*continue;*/
+ }
+ if (what == OP_obs) {
+ obs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, dd_suffixes);
+ /*continue;*/
+ }
+ if (what == OP_conv) {
+ while (1) {
+ /* find ',', replace them with NUL so we can use val for
+ * index_in_strings() without copying.
+ * We rely on val being non-null, else strchr would fault.
+ */
+ arg = strchr(val, ',');
+ if (arg)
+ *arg = '\0';
+ what = index_in_strings(conv_words, val);
+ if (what < 0)
+ bb_error_msg_and_die(bb_msg_invalid_arg, val, "conv");
+ flags |= (1 << what);
+ if (!arg) /* no ',' left, so this was the last specifier */
+ break;
+ /* *arg = ','; - to preserve ps listing? */
+ val = arg + 1; /* skip this keyword and ',' */
+ }
+ continue; /* we trashed 'what', can't fall through */
+ }
+#endif
+ if (what == OP_bs) {
+ ibs = obs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, dd_suffixes);
+ /*continue;*/
+ }
+ /* These can be large: */
+ if (what == OP_count) {
+ flags |= FLAG_COUNT;
+ count = XATOU_SFX(val, dd_suffixes);
+ /*continue;*/
+ }
+ if (what == OP_seek) {
+ seek = XATOU_SFX(val, dd_suffixes);
+ /*continue;*/
+ }
+ if (what == OP_skip) {
+ skip = XATOU_SFX(val, dd_suffixes);
+ /*continue;*/
+ }
+ if (what == OP_if) {
+ infile = val;
+ /*continue;*/
+ }
+ if (what == OP_of) {
+ outfile = val;
+ /*continue;*/
+ }
+ } /* end of "for (argv[n])" */
+
+//XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever
+ ibuf = obuf = xmalloc(ibs);
+ if (ibs != obs) {
+ flags |= FLAG_TWOBUFS;
+ obuf = xmalloc(obs);
+ }
+ if (infile != NULL)
+ xmove_fd(xopen(infile, O_RDONLY), ifd);
+ else {
+ infile = bb_msg_standard_input;
+ }
+ if (outfile != NULL) {
+ int oflag = O_WRONLY | O_CREAT;
+
+ if (!seek && !(flags & FLAG_NOTRUNC))
+ oflag |= O_TRUNC;
+
+ xmove_fd(xopen(outfile, oflag), ofd);
+
+ if (seek && !(flags & FLAG_NOTRUNC)) {
+ if (ftruncate(ofd, seek * obs) < 0) {
+ struct stat st;
+
+ if (fstat(ofd, &st) < 0 || S_ISREG(st.st_mode) ||
+ S_ISDIR(st.st_mode))
+ goto die_outfile;
+ }
+ }
+ } else {
+ outfile = bb_msg_standard_output;
+ }
+ if (skip) {
+ if (lseek(ifd, skip * ibs, SEEK_CUR) < 0) {
+ while (skip-- > 0) {
+ n = safe_read(ifd, ibuf, ibs);
+ if (n < 0)
+ goto die_infile;
+ if (n == 0)
+ break;
+ }
+ }
+ }
+ if (seek) {
+ if (lseek(ofd, seek * obs, SEEK_CUR) < 0)
+ goto die_outfile;
+ }
+
+ while (!(flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) {
+ if (flags & FLAG_NOERROR) /* Pre-zero the buffer if conv=noerror */
+ memset(ibuf, 0, ibs);
+ n = safe_read(ifd, ibuf, ibs);
+ if (n == 0)
+ break;
+ if (n < 0) {
+ if (!(flags & FLAG_NOERROR))
+ goto die_infile;
+ n = ibs;
+ bb_simple_perror_msg(infile);
+ }
+ if ((size_t)n == ibs)
+ G.in_full++;
+ else {
+ G.in_part++;
+ if (flags & FLAG_SYNC) {
+ memset(ibuf + n, '\0', ibs - n);
+ n = ibs;
+ }
+ }
+ if (flags & FLAG_TWOBUFS) {
+ char *tmp = ibuf;
+ while (n) {
+ size_t d = obs - oc;
+
+ if (d > (size_t)n)
+ d = n;
+ memcpy(obuf + oc, tmp, d);
+ n -= d;
+ tmp += d;
+ oc += d;
+ if (oc == obs) {
+ if (write_and_stats(obuf, obs, obs, outfile))
+ goto out_status;
+ oc = 0;
+ }
+ }
+ } else if (write_and_stats(ibuf, n, obs, outfile))
+ goto out_status;
+
+ if (flags & FLAG_FSYNC) {
+ if (fsync(ofd) < 0)
+ goto die_outfile;
+ }
+ }
+
+ if (ENABLE_FEATURE_DD_IBS_OBS && oc) {
+ w = full_write_or_warn(obuf, oc, outfile);
+ if (w < 0) goto out_status;
+ if (w > 0) G.out_part++;
+ }
+ if (close(ifd) < 0) {
+ die_infile:
+ bb_simple_perror_msg_and_die(infile);
+ }
+
+ if (close(ofd) < 0) {
+ die_outfile:
+ bb_simple_perror_msg_and_die(outfile);
+ }
+
+ exitcode = EXIT_SUCCESS;
+ out_status:
+ dd_output_status(0);
+
+ return exitcode;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/df.c b/cleopatre/busybox-1.11.1-spc300/coreutils/df.c
new file mode 100644
index 0000000000..9cb328aa31
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/df.c
@@ -0,0 +1,175 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini df implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * based on original code by (I think) Bruce Perens <bruce@pixar.com>.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 _NOT_ compliant -- options -P and -t missing. Also blocksize. */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/df.html */
+
+/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
+ *
+ * Size reduction. Removed floating point dependency. Added error checking
+ * on output. Output stats on 0-sized filesystems if specifically listed on
+ * the command line. Properly round *-blocks, Used, and Available quantities.
+ */
+
+#include <mntent.h>
+#include <sys/vfs.h>
+#include "libbb.h"
+
+#if !ENABLE_FEATURE_HUMAN_READABLE
+static unsigned long kscale(unsigned long b, unsigned long bs)
+{
+ return (b * (unsigned long long) bs + 1024/2) / 1024;
+}
+#endif
+
+int df_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int df_main(int argc, char **argv)
+{
+ unsigned long blocks_used;
+ unsigned blocks_percent_used;
+#if ENABLE_FEATURE_HUMAN_READABLE
+ unsigned df_disp_hr = 1024;
+#endif
+ int status = EXIT_SUCCESS;
+ unsigned opt;
+ FILE *mount_table;
+ struct mntent *mount_entry;
+ struct statfs s;
+ /* default display is kilobytes */
+ const char *disp_units_hdr = "1k-blocks";
+
+ enum {
+ OPT_ALL = (1 << 0),
+ OPT_INODE = (ENABLE_FEATURE_HUMAN_READABLE ? (1 << 4) : (1 << 2))
+ * ENABLE_FEATURE_DF_INODE
+ };
+
+#if ENABLE_FEATURE_HUMAN_READABLE
+ opt_complementary = "h-km:k-hm:m-hk";
+ opt = getopt32(argv, "ahmk" USE_FEATURE_DF_INODE("i"));
+ if (opt & (1 << 1)) { // -h
+ df_disp_hr = 0;
+ disp_units_hdr = " Size";
+ }
+ if (opt & (1 << 2)) { // -m
+ df_disp_hr = 1024*1024;
+ disp_units_hdr = "1M-blocks";
+ }
+ if (opt & OPT_INODE) {
+ disp_units_hdr = " Inodes";
+ }
+#else
+ opt = getopt32(argv, "ak" USE_FEATURE_DF_INODE("i"));
+#endif
+
+ printf("Filesystem %-15sUsed Available Use%% Mounted on\n",
+ disp_units_hdr);
+
+ mount_table = NULL;
+ argv += optind;
+ if (optind >= argc) {
+ mount_table = setmntent(bb_path_mtab_file, "r");
+ if (!mount_table) {
+ bb_perror_msg_and_die(bb_path_mtab_file);
+ }
+ }
+
+ while (1) {
+ const char *device;
+ const char *mount_point;
+
+ if (mount_table) {
+ mount_entry = getmntent(mount_table);
+ if (!mount_entry) {
+ endmntent(mount_table);
+ break;
+ }
+ } else {
+ mount_point = *argv++;
+ if (!mount_point) {
+ break;
+ }
+ mount_entry = find_mount_point(mount_point, bb_path_mtab_file);
+ if (!mount_entry) {
+ bb_error_msg("%s: can't find mount point", mount_point);
+ SET_ERROR:
+ status = EXIT_FAILURE;
+ continue;
+ }
+ }
+
+ device = mount_entry->mnt_fsname;
+ mount_point = mount_entry->mnt_dir;
+
+ if (statfs(mount_point, &s) != 0) {
+ bb_simple_perror_msg(mount_point);
+ goto SET_ERROR;
+ }
+
+ if ((s.f_blocks > 0) || !mount_table || (opt & OPT_ALL)) {
+ if (opt & OPT_INODE) {
+ s.f_blocks = s.f_files;
+ s.f_bavail = s.f_bfree = s.f_ffree;
+ s.f_bsize = 1;
+#if ENABLE_FEATURE_HUMAN_READABLE
+ if (df_disp_hr)
+ df_disp_hr = 1;
+#endif
+ }
+ blocks_used = s.f_blocks - s.f_bfree;
+ blocks_percent_used = 0;
+ if (blocks_used + s.f_bavail) {
+ blocks_percent_used = (blocks_used * 100ULL
+ + (blocks_used + s.f_bavail)/2
+ ) / (blocks_used + s.f_bavail);
+ }
+
+#ifdef WHY_IT_SHOULD_BE_HIDDEN
+ if (strcmp(device, "rootfs") == 0) {
+ continue;
+ }
+#endif
+#ifdef WHY_WE_DO_IT_FOR_DEV_ROOT_ONLY
+/* ... and also this is the only user of find_block_device */
+ if (strcmp(device, "/dev/root") == 0) {
+ /* Adjusts device to be the real root device,
+ * or leaves device alone if it can't find it */
+ device = find_block_device("/");
+ if (!device) {
+ goto SET_ERROR;
+ }
+ }
+#endif
+
+ if (printf("\n%-20s" + 1, device) > 20)
+ printf("\n%-20s", "");
+#if ENABLE_FEATURE_HUMAN_READABLE
+ printf(" %9s ",
+ make_human_readable_str(s.f_blocks, s.f_bsize, df_disp_hr));
+
+ printf(" %9s " + 1,
+ make_human_readable_str((s.f_blocks - s.f_bfree),
+ s.f_bsize, df_disp_hr));
+
+ printf("%9s %3u%% %s\n",
+ make_human_readable_str(s.f_bavail, s.f_bsize, df_disp_hr),
+ blocks_percent_used, mount_point);
+#else
+ printf(" %9lu %9lu %9lu %3u%% %s\n",
+ kscale(s.f_blocks, s.f_bsize),
+ kscale(s.f_blocks-s.f_bfree, s.f_bsize),
+ kscale(s.f_bavail, s.f_bsize),
+ blocks_percent_used, mount_point);
+#endif
+ }
+ }
+
+ fflush_stdout_and_exit(status);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/dirname.c b/cleopatre/busybox-1.11.1-spc300/coreutils/dirname.c
new file mode 100644
index 0000000000..c0c0925e5b
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/dirname.c
@@ -0,0 +1,27 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini dirname implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 compliant */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/dirname.html */
+
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
+
+int dirname_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int dirname_main(int argc, char **argv)
+{
+ if (argc != 2) {
+ bb_show_usage();
+ }
+
+ puts(dirname(argv[1]));
+
+ return fflush(stdout);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/dos2unix.c b/cleopatre/busybox-1.11.1-spc300/coreutils/dos2unix.c
new file mode 100644
index 0000000000..311dc13808
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/dos2unix.c
@@ -0,0 +1,98 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * dos2unix for BusyBox
+ *
+ * dos2unix '\n' convertor 0.5.0
+ * based on Unix2Dos 0.9.0 by Peter Hanecak (made 19.2.1997)
+ * Copyright 1997,.. by Peter Hanecak <hanecak@megaloman.sk>.
+ * All rights reserved.
+ *
+ * dos2unix filters reading input from stdin and writing output to stdout.
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+*/
+
+#include "libbb.h"
+
+enum {
+ CT_UNIX2DOS = 1,
+ CT_DOS2UNIX
+};
+
+/* if fn is NULL then input is stdin and output is stdout */
+static void convert(char *fn, int conv_type)
+{
+ FILE *in, *out;
+ int i;
+ char *temp_fn = temp_fn; /* for compiler */
+ char *resolved_fn = resolved_fn;
+
+ in = stdin;
+ out = stdout;
+ if (fn != NULL) {
+ struct stat st;
+
+ resolved_fn = xmalloc_follow_symlinks(fn);
+ if (resolved_fn == NULL)
+ bb_simple_perror_msg_and_die(fn);
+ in = xfopen(resolved_fn, "r");
+ fstat(fileno(in), &st);
+
+ temp_fn = xasprintf("%sXXXXXX", resolved_fn);
+ i = mkstemp(temp_fn);
+ if (i == -1
+ || fchmod(i, st.st_mode) == -1
+ || !(out = fdopen(i, "w+"))
+ ) {
+ bb_simple_perror_msg_and_die(temp_fn);
+ }
+ }
+
+ while ((i = fgetc(in)) != EOF) {
+ if (i == '\r')
+ continue;
+ if (i == '\n')
+ if (conv_type == CT_UNIX2DOS)
+ fputc('\r', out);
+ fputc(i, out);
+ }
+
+ if (fn != NULL) {
+ if (fclose(in) < 0 || fclose(out) < 0) {
+ unlink(temp_fn);
+ bb_perror_nomsg_and_die();
+ }
+ xrename(temp_fn, resolved_fn);
+ free(temp_fn);
+ free(resolved_fn);
+ }
+}
+
+int dos2unix_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int dos2unix_main(int argc, char **argv)
+{
+ int o, conv_type;
+
+ /* See if we are supposed to be doing dos2unix or unix2dos */
+ conv_type = CT_UNIX2DOS;
+ if (applet_name[0] == 'd') {
+ conv_type = CT_DOS2UNIX;
+ }
+
+ /* -u convert to unix, -d convert to dos */
+ opt_complementary = "u--d:d--u"; /* mutually exclusive */
+ o = getopt32(argv, "du");
+
+ /* Do the conversion requested by an argument else do the default
+ * conversion depending on our name. */
+ if (o)
+ conv_type = o;
+
+ do {
+ /* might be convert(NULL) if there is no filename given */
+ convert(argv[optind], conv_type);
+ optind++;
+ } while (optind < argc);
+
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/du.c b/cleopatre/busybox-1.11.1-spc300/coreutils/du.c
new file mode 100644
index 0000000000..b469824ea7
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/du.c
@@ -0,0 +1,240 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini du implementation for busybox
+ *
+ * Copyright (C) 1999,2000,2001 by Lineo, inc. and John Beppu
+ * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
+ * Copyright (C) 2002 Edward Betts <edward@debian.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 compliant (unless default blocksize set to 1k) */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/du.html */
+
+/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
+ *
+ * Mostly rewritten for SUSv3 compliance and to fix bugs/defects.
+ * 1) Added support for SUSv3 -a, -H, -L, gnu -c, and (busybox) -d options.
+ * The -d option allows setting of max depth (similar to gnu --max-depth).
+ * 2) Fixed incorrect size calculations for links and directories, especially
+ * when errors occurred. Calculates sizes should now match gnu du output.
+ * 3) Added error checking of output.
+ * 4) Fixed busybox bug #1284 involving long overflow with human_readable.
+ */
+
+#include "libbb.h"
+
+struct globals {
+#if ENABLE_FEATURE_HUMAN_READABLE
+ unsigned long disp_hr;
+#else
+ unsigned disp_k;
+#endif
+
+ int max_print_depth;
+ nlink_t count_hardlinks;
+
+ bool status;
+ bool one_file_system;
+ int print_files;
+ int slink_depth;
+ int du_depth;
+ dev_t dir_dev;
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+
+
+static void print(unsigned long size, const char *filename)
+{
+ /* TODO - May not want to defer error checking here. */
+#if ENABLE_FEATURE_HUMAN_READABLE
+ printf("%s\t%s\n", make_human_readable_str(size, 512, G.disp_hr),
+ filename);
+#else
+ if (G.disp_k) {
+ size++;
+ size >>= 1;
+ }
+ printf("%ld\t%s\n", size, filename);
+#endif
+}
+
+/* tiny recursive du */
+static unsigned long du(const char *filename)
+{
+ struct stat statbuf;
+ unsigned long sum;
+
+ if (lstat(filename, &statbuf) != 0) {
+ bb_simple_perror_msg(filename);
+ G.status = EXIT_FAILURE;
+ return 0;
+ }
+
+ if (G.one_file_system) {
+ if (G.du_depth == 0) {
+ G.dir_dev = statbuf.st_dev;
+ } else if (G.dir_dev != statbuf.st_dev) {
+ return 0;
+ }
+ }
+
+ sum = statbuf.st_blocks;
+
+ if (S_ISLNK(statbuf.st_mode)) {
+ if (G.slink_depth > G.du_depth) { /* -H or -L */
+ if (stat(filename, &statbuf) != 0) {
+ bb_simple_perror_msg(filename);
+ G.status = EXIT_FAILURE;
+ return 0;
+ }
+ sum = statbuf.st_blocks;
+ if (G.slink_depth == 1) {
+ G.slink_depth = INT_MAX; /* Convert -H to -L. */
+ }
+ }
+ }
+
+ if (statbuf.st_nlink > G.count_hardlinks) {
+ /* Add files/directories with links only once */
+ if (is_in_ino_dev_hashtable(&statbuf)) {
+ return 0;
+ }
+ add_to_ino_dev_hashtable(&statbuf, NULL);
+ }
+
+ if (S_ISDIR(statbuf.st_mode)) {
+ DIR *dir;
+ struct dirent *entry;
+ char *newfile;
+
+ dir = warn_opendir(filename);
+ if (!dir) {
+ G.status = EXIT_FAILURE;
+ return sum;
+ }
+
+ newfile = last_char_is(filename, '/');
+ if (newfile)
+ *newfile = '\0';
+
+ while ((entry = readdir(dir))) {
+ char *name = entry->d_name;
+
+ newfile = concat_subpath_file(filename, name);
+ if (newfile == NULL)
+ continue;
+ ++G.du_depth;
+ sum += du(newfile);
+ --G.du_depth;
+ free(newfile);
+ }
+ closedir(dir);
+ } else if (G.du_depth > G.print_files) {
+ return sum;
+ }
+ if (G.du_depth <= G.max_print_depth) {
+ print(sum, filename);
+ }
+ return sum;
+}
+
+int du_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int du_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ unsigned long total;
+ int slink_depth_save;
+ bool print_final_total;
+ unsigned opt;
+
+#if ENABLE_FEATURE_HUMAN_READABLE
+ USE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_hr = 1024;)
+ SKIP_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_hr = 512;)
+ if (getenv("POSIXLY_CORRECT")) /* TODO - a new libbb function? */
+ G.disp_hr = 512;
+#else
+ USE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_k = 1;)
+ /* SKIP_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_k = 0;) - G is pre-zeroed */
+#endif
+ G.max_print_depth = INT_MAX;
+ G.count_hardlinks = 1;
+
+ /* Note: SUSv3 specifies that -a and -s options cannot be used together
+ * in strictly conforming applications. However, it also says that some
+ * du implementations may produce output when -a and -s are used together.
+ * gnu du exits with an error code in this case. We choose to simply
+ * ignore -a. This is consistent with -s being equivalent to -d 0.
+ */
+#if ENABLE_FEATURE_HUMAN_READABLE
+ opt_complementary = "h-km:k-hm:m-hk:H-L:L-H:s-d:d-s:d+";
+ opt = getopt32(argv, "aHkLsx" "d:" "lc" "hm", &G.max_print_depth);
+ argv += optind;
+ if (opt & (1 << 9)) {
+ /* -h opt */
+ G.disp_hr = 0;
+ }
+ if (opt & (1 << 10)) {
+ /* -m opt */
+ G.disp_hr = 1024*1024;
+ }
+ if (opt & (1 << 2)) {
+ /* -k opt */
+ G.disp_hr = 1024;
+ }
+#else
+ opt_complementary = "H-L:L-H:s-d:d-s:d+";
+ opt = getopt32(argv, "aHkLsx" "d:" "lc", &G.max_print_depth);
+ argv += optind;
+#if !ENABLE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K
+ if (opt & (1 << 2)) {
+ /* -k opt */
+ G.disp_k = 1;
+ }
+#endif
+#endif
+ if (opt & (1 << 0)) {
+ /* -a opt */
+ G.print_files = INT_MAX;
+ }
+ if (opt & (1 << 1)) {
+ /* -H opt */
+ G.slink_depth = 1;
+ }
+ if (opt & (1 << 3)) {
+ /* -L opt */
+ G.slink_depth = INT_MAX;
+ }
+ if (opt & (1 << 4)) {
+ /* -s opt */
+ G.max_print_depth = 0;
+ }
+ G.one_file_system = opt & (1 << 5); /* -x opt */
+ if (opt & (1 << 7)) {
+ /* -l opt */
+ G.count_hardlinks = MAXINT(nlink_t);
+ }
+ print_final_total = opt & (1 << 8); /* -c opt */
+
+ /* go through remaining args (if any) */
+ if (!*argv) {
+ *--argv = (char*)".";
+ if (G.slink_depth == 1) {
+ G.slink_depth = 0;
+ }
+ }
+
+ slink_depth_save = G.slink_depth;
+ total = 0;
+ do {
+ total += du(*argv);
+ G.slink_depth = slink_depth_save;
+ } while (*++argv);
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ reset_ino_dev_hashtable();
+ if (print_final_total)
+ print(total, "total");
+
+ fflush_stdout_and_exit(G.status);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/echo.c b/cleopatre/busybox-1.11.1-spc300/coreutils/echo.c
new file mode 100644
index 0000000000..cc9b9e6f45
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/echo.c
@@ -0,0 +1,300 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * echo implementation for busybox
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ * Original copyright notice is retained at the end of this file.
+ */
+
+/* BB_AUDIT SUSv3 compliant -- unless configured as fancy echo. */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/echo.html */
+
+/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
+ *
+ * Because of behavioral differences, implemented configurable SUSv3
+ * or 'fancy' gnu-ish behaviors. Also, reduced size and fixed bugs.
+ * 1) In handling '\c' escape, the previous version only suppressed the
+ * trailing newline. SUSv3 specifies _no_ output after '\c'.
+ * 2) SUSv3 specifies that octal escapes are of the form \0{#{#{#}}}.
+ * The previous version did not allow 4-digit octals.
+ */
+
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
+
+/* NB: can be used by shell even if not enabled as applet */
+
+int echo_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ const char *arg;
+#if !ENABLE_FEATURE_FANCY_ECHO
+ enum {
+ eflag = '\\',
+ nflag = 1, /* 1 -- print '\n' */
+ };
+
+ /* We must check that stdout is not closed.
+ * The reason for this is highly non-obvious.
+ * echo_main is used from shell. Shell must correctly handle "echo foo"
+ * if stdout is closed. With stdio, output gets shoveled into
+ * stdout buffer, and even fflush cannot clear it out. It seems that
+ * even if libc receives EBADF on write attempts, it feels determined
+ * to output data no matter what. So it will try later,
+ * and possibly will clobber future output. Not good. */
+ if (dup2(1, 1) != 1)
+ return -1;
+
+ arg = *++argv;
+ if (!arg)
+ goto newline_ret;
+#else
+ const char *p;
+ char nflag = 1;
+ char eflag = 0;
+
+ /* We must check that stdout is not closed. */
+ if (dup2(1, 1) != 1)
+ return -1;
+
+ while (1) {
+ arg = *++argv;
+ if (!arg)
+ goto newline_ret;
+ if (*arg != '-')
+ break;
+
+ /* If it appears that we are handling options, then make sure
+ * that all of the options specified are actually valid.
+ * Otherwise, the string should just be echoed.
+ */
+ p = arg + 1;
+ if (!*p) /* A single '-', so echo it. */
+ goto just_echo;
+
+ do {
+ if (!strrchr("neE", *p))
+ goto just_echo;
+ } while (*++p);
+
+ /* All of the options in this arg are valid, so handle them. */
+ p = arg + 1;
+ do {
+ if (*p == 'n')
+ nflag = 0;
+ if (*p == 'e')
+ eflag = '\\';
+ } while (*++p);
+ }
+ just_echo:
+#endif
+ while (1) {
+ /* arg is already == *argv and isn't NULL */
+ int c;
+
+ if (!eflag) {
+ /* optimization for very common case */
+ fputs(arg, stdout);
+ } else while ((c = *arg++)) {
+ if (c == eflag) { /* Check for escape seq. */
+ if (*arg == 'c') {
+ /* '\c' means cancel newline and
+ * ignore all subsequent chars. */
+ goto ret;
+ }
+#if !ENABLE_FEATURE_FANCY_ECHO
+ /* SUSv3 specifies that octal escapes must begin with '0'. */
+ if ( ((int)(unsigned char)(*arg) - '0') >= 8) /* '8' or bigger */
+#endif
+ {
+ /* Since SUSv3 mandates a first digit of 0, 4-digit octals
+ * of the form \0### are accepted. */
+ if (*arg == '0') {
+ /* NB: don't turn "...\0" into "...\" */
+ if (arg[1] && ((unsigned char)(arg[1]) - '0') < 8) {
+ arg++;
+ }
+ }
+ /* bb_process_escape_sequence handles NUL correctly
+ * ("...\" case). */
+ c = bb_process_escape_sequence(&arg);
+ }
+ }
+ bb_putchar(c);
+ }
+
+ arg = *++argv;
+ if (!arg)
+ break;
+ bb_putchar(' ');
+ }
+
+ newline_ret:
+ if (nflag) {
+ bb_putchar('\n');
+ }
+ ret:
+ return fflush(stdout);
+}
+
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
+ * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
+ *
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)echo.c 8.1 (Berkeley) 5/31/93
+ */
+
+#ifdef VERSION_WITH_WRITEV
+/* We can't use stdio.
+ * The reason for this is highly non-obvious.
+ * echo_main is used from shell. Shell must correctly handle "echo foo"
+ * if stdout is closed. With stdio, output gets shoveled into
+ * stdout buffer, and even fflush cannot clear it out. It seems that
+ * even if libc receives EBADF on write attempts, it feels determined
+ * to output data no matter what. So it will try later,
+ * and possibly will clobber future output. Not good.
+ *
+ * Using writev instead, with 'direct' conversion of argv vector.
+ */
+
+int echo_main(int argc, char **argv)
+{
+ struct iovec io[argc];
+ struct iovec *cur_io = io;
+ char *arg;
+ char *p;
+#if !ENABLE_FEATURE_FANCY_ECHO
+ enum {
+ eflag = '\\',
+ nflag = 1, /* 1 -- print '\n' */
+ };
+ arg = *++argv;
+ if (!arg)
+ goto newline_ret;
+#else
+ char nflag = 1;
+ char eflag = 0;
+
+ while (1) {
+ arg = *++argv;
+ if (!arg)
+ goto newline_ret;
+ if (*arg != '-')
+ break;
+
+ /* If it appears that we are handling options, then make sure
+ * that all of the options specified are actually valid.
+ * Otherwise, the string should just be echoed.
+ */
+ p = arg + 1;
+ if (!*p) /* A single '-', so echo it. */
+ goto just_echo;
+
+ do {
+ if (!strrchr("neE", *p))
+ goto just_echo;
+ } while (*++p);
+
+ /* All of the options in this arg are valid, so handle them. */
+ p = arg + 1;
+ do {
+ if (*p == 'n')
+ nflag = 0;
+ if (*p == 'e')
+ eflag = '\\';
+ } while (*++p);
+ }
+ just_echo:
+#endif
+
+ while (1) {
+ /* arg is already == *argv and isn't NULL */
+ int c;
+
+ cur_io->iov_base = p = arg;
+
+ if (!eflag) {
+ /* optimization for very common case */
+ p += strlen(arg);
+ } else while ((c = *arg++)) {
+ if (c == eflag) { /* Check for escape seq. */
+ if (*arg == 'c') {
+ /* '\c' means cancel newline and
+ * ignore all subsequent chars. */
+ cur_io->iov_len = p - (char*)cur_io->iov_base;
+ cur_io++;
+ goto ret;
+ }
+#if !ENABLE_FEATURE_FANCY_ECHO
+ /* SUSv3 specifies that octal escapes must begin with '0'. */
+ if ( (((unsigned char)*arg) - '1') >= 7)
+#endif
+ {
+ /* Since SUSv3 mandates a first digit of 0, 4-digit octals
+ * of the form \0### are accepted. */
+ if (*arg == '0' && ((unsigned char)(arg[1]) - '0') < 8) {
+ arg++;
+ }
+ /* bb_process_escape_sequence can handle nul correctly */
+ c = bb_process_escape_sequence( (void*) &arg);
+ }
+ }
+ *p++ = c;
+ }
+
+ arg = *++argv;
+ if (arg)
+ *p++ = ' ';
+ cur_io->iov_len = p - (char*)cur_io->iov_base;
+ cur_io++;
+ if (!arg)
+ break;
+ }
+
+ newline_ret:
+ if (nflag) {
+ cur_io->iov_base = (char*)"\n";
+ cur_io->iov_len = 1;
+ cur_io++;
+ }
+ ret:
+ /* TODO: implement and use full_writev? */
+ return writev(1, io, (cur_io - io)) >= 0;
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/env.c b/cleopatre/busybox-1.11.1-spc300/coreutils/env.c
new file mode 100644
index 0000000000..8d8753e8b6
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/env.c
@@ -0,0 +1,123 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * env implementation for busybox
+ *
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ * Original copyright notice is retained at the end of this file.
+ *
+ * Modified for BusyBox by Erik Andersen <andersen@codepoet.org>
+ */
+
+/* BB_AUDIT SUSv3 compliant */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/env.html */
+
+/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
+ *
+ * Fixed bug involving exit return codes if execvp fails. Also added
+ * output error checking.
+ */
+
+/*
+ * Modified by Vladimir Oleynik <dzo@simtreas.ru> (C) 2003
+ * - correct "-" option usage
+ * - multiple "-u unsetenv" support
+ * - GNU long option support
+ * - use xfunc_error_retval
+ */
+
+#include "libbb.h"
+
+#if ENABLE_FEATURE_ENV_LONG_OPTIONS
+static const char env_longopts[] ALIGN1 =
+ "ignore-environment\0" No_argument "i"
+ "unset\0" Required_argument "u"
+ ;
+#endif
+
+int env_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int env_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ /* cleanenv was static - why? */
+ char *cleanenv[1];
+ char **ep;
+ unsigned opt;
+ llist_t *unset_env = NULL;
+
+ opt_complementary = "u::";
+#if ENABLE_FEATURE_ENV_LONG_OPTIONS
+ applet_long_options = env_longopts;
+#endif
+ opt = getopt32(argv, "+iu:", &unset_env);
+ argv += optind;
+ if (*argv && LONE_DASH(argv[0])) {
+ opt |= 1;
+ ++argv;
+ }
+ if (opt & 1) {
+ cleanenv[0] = NULL;
+ environ = cleanenv;
+ } else {
+ while (unset_env) {
+ unsetenv(llist_pop(&unset_env));
+ }
+ }
+
+ while (*argv && (strchr(*argv, '=') != NULL)) {
+ if (putenv(*argv) < 0) {
+ bb_perror_msg_and_die("putenv");
+ }
+ ++argv;
+ }
+
+ if (*argv) {
+ BB_EXECVP(*argv, argv);
+ /* SUSv3-mandated exit codes. */
+ xfunc_error_retval = (errno == ENOENT) ? 127 : 126;
+ bb_simple_perror_msg_and_die(*argv);
+ }
+
+ for (ep = environ; *ep; ep++) {
+ puts(*ep);
+ }
+
+ fflush_stdout_and_exit(EXIT_SUCCESS);
+}
+
+/*
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
+ * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
+ *
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/expand.c b/cleopatre/busybox-1.11.1-spc300/coreutils/expand.c
new file mode 100644
index 0000000000..af2ef8675a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/expand.c
@@ -0,0 +1,200 @@
+/* expand - convert tabs to spaces
+ * unexpand - convert spaces to tabs
+ *
+ * Copyright (C) 89, 91, 1995-2006 Free Software Foundation, Inc.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ * David MacKenzie <djm@gnu.ai.mit.edu>
+ *
+ * Options for expand:
+ * -t num --tabs=NUM Convert tabs to num spaces (default 8 spaces).
+ * -i --initial Only convert initial tabs on each line to spaces.
+ *
+ * Options for unexpand:
+ * -a --all Convert all blanks, instead of just initial blanks.
+ * -f --first-only Convert only leading sequences of blanks (default).
+ * -t num --tabs=NUM Have tabs num characters apart instead of 8.
+ *
+ * Busybox version (C) 2007 by Tito Ragusa <farmatito@tiscali.it>
+ *
+ * Caveat: this versions of expand and unexpand don't accept tab lists.
+ */
+
+#include "libbb.h"
+
+enum {
+ OPT_INITIAL = 1 << 0,
+ OPT_TABS = 1 << 1,
+ OPT_ALL = 1 << 2,
+};
+
+static void xputchar(char c)
+{
+ if (putchar(c) < 0)
+ bb_error_msg_and_die(bb_msg_write_error);
+}
+
+#if ENABLE_EXPAND
+static void expand(FILE *file, unsigned tab_size, unsigned opt)
+{
+ char *line;
+ char *ptr;
+ int convert;
+ unsigned pos;
+
+ /* Increment tab_size by 1 locally.*/
+ tab_size++;
+
+ while ((line = xmalloc_fgets(file)) != NULL) {
+ convert = 1;
+ pos = 0;
+ ptr = line;
+ while (*line) {
+ pos++;
+ if (*line == '\t' && convert) {
+ for (; pos < tab_size; pos++) {
+ xputchar(' ');
+ }
+ } else {
+ if ((opt & OPT_INITIAL) && !isblank(*line)) {
+ convert = 0;
+ }
+ xputchar(*line);
+ }
+ if (pos == tab_size) {
+ pos = 0;
+ }
+ line++;
+ }
+ free(ptr);
+ }
+}
+#endif
+
+#if ENABLE_UNEXPAND
+static void unexpand(FILE *file, unsigned int tab_size, unsigned opt)
+{
+ char *line;
+ char *ptr;
+ int convert;
+ int pos;
+ int i = 0;
+ unsigned column = 0;
+
+ while ((line = xmalloc_fgets(file)) != NULL) {
+ convert = 1;
+ pos = 0;
+ ptr = line;
+ while (*line) {
+ while ((*line == ' ' || *line == '\t') && convert) {
+ pos += (*line == ' ') ? 1 : tab_size;
+ line++;
+ column++;
+ if ((opt & OPT_ALL) && column == tab_size) {
+ column = 0;
+ goto put_tab;
+ }
+ }
+ if (pos) {
+ i = pos / tab_size;
+ if (i) {
+ for (; i > 0; i--) {
+ put_tab:
+ xputchar('\t');
+ }
+ } else {
+ for (i = pos % tab_size; i > 0; i--) {
+ xputchar(' ');
+ }
+ }
+ pos = 0;
+ } else {
+ if (opt & OPT_INITIAL) {
+ convert = 0;
+ }
+ if (opt & OPT_ALL) {
+ column++;
+ }
+ xputchar(*line);
+ line++;
+ }
+ }
+ free(ptr);
+ }
+}
+#endif
+
+int expand_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int expand_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ /* Default 8 spaces for 1 tab */
+ const char *opt_t = "8";
+ FILE *file;
+ unsigned tab_size;
+ unsigned opt;
+ int exit_status = EXIT_SUCCESS;
+
+#if ENABLE_FEATURE_EXPAND_LONG_OPTIONS
+ static const char expand_longopts[] ALIGN1 =
+ /* name, has_arg, val */
+ "initial\0" No_argument "i"
+ "tabs\0" Required_argument "t"
+ ;
+#endif
+#if ENABLE_FEATURE_UNEXPAND_LONG_OPTIONS
+ static const char unexpand_longopts[] ALIGN1 =
+ /* name, has_arg, val */
+ "first-only\0" No_argument "i"
+ "tabs\0" Required_argument "t"
+ "all\0" No_argument "a"
+ ;
+#endif
+
+ if (ENABLE_EXPAND && (!ENABLE_UNEXPAND || applet_name[0] == 'e')) {
+ USE_FEATURE_EXPAND_LONG_OPTIONS(applet_long_options = expand_longopts);
+ opt = getopt32(argv, "it:", &opt_t);
+ } else {
+ USE_FEATURE_UNEXPAND_LONG_OPTIONS(applet_long_options = unexpand_longopts);
+ /* -t NUM sets also -a */
+ opt_complementary = "ta";
+ opt = getopt32(argv, "ft:a", &opt_t);
+ /* -f --first-only is the default */
+ if (!(opt & OPT_ALL)) opt |= OPT_INITIAL;
+ }
+ tab_size = xatou_range(opt_t, 1, UINT_MAX);
+
+ argv += optind;
+
+ if (!*argv) {
+ *--argv = (char*)bb_msg_standard_input;
+ }
+ do {
+ file = fopen_or_warn_stdin(*argv);
+ if (!file) {
+ exit_status = EXIT_FAILURE;
+ continue;
+ }
+
+ if (ENABLE_EXPAND && (!ENABLE_UNEXPAND || applet_name[0] == 'e'))
+ USE_EXPAND(expand(file, tab_size, opt));
+ else
+ USE_UNEXPAND(unexpand(file, tab_size, opt));
+
+ /* Check and close the file */
+ if (fclose_if_not_stdin(file)) {
+ bb_simple_perror_msg(*argv);
+ exit_status = EXIT_FAILURE;
+ }
+ /* If stdin also clear EOF */
+ if (file == stdin)
+ clearerr(file);
+ } while (*++argv);
+
+ /* Now close stdin also */
+ /* (if we didn't read from it, it's a no-op) */
+ if (fclose(stdin))
+ bb_perror_msg_and_die(bb_msg_standard_input);
+
+ fflush_stdout_and_exit(exit_status);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/expr.c b/cleopatre/busybox-1.11.1-spc300/coreutils/expr.c
new file mode 100644
index 0000000000..2f9c5c1e37
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/expr.c
@@ -0,0 +1,504 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini expr implementation for busybox
+ *
+ * based on GNU expr Mike Parker.
+ * Copyright (C) 86, 1991-1997, 1999 Free Software Foundation, Inc.
+ *
+ * Busybox modifications
+ * Copyright (c) 2000 Edward Betts <edward@debian.org>.
+ * Copyright (C) 2003-2005 Vladimir Oleynik <dzo@simtreas.ru>
+ * - reduced 464 bytes.
+ * - 64 math support
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* This program evaluates expressions. Each token (operator, operand,
+ * parenthesis) of the expression must be a separate argument. The
+ * parser used is a reasonably general one, though any incarnation of
+ * it is language-specific. It is especially nice for expressions.
+ *
+ * No parse tree is needed; a new node is evaluated immediately.
+ * One function can handle multiple operators all of equal precedence,
+ * provided they all associate ((x op x) op x). */
+
+/* no getopt needed */
+
+#include "libbb.h"
+#include "xregex.h"
+
+#if ENABLE_EXPR_MATH_SUPPORT_64
+typedef int64_t arith_t;
+
+#define PF_REZ "ll"
+#define PF_REZ_TYPE (long long)
+#define STRTOL(s, e, b) strtoll(s, e, b)
+#else
+typedef long arith_t;
+
+#define PF_REZ "l"
+#define PF_REZ_TYPE (long)
+#define STRTOL(s, e, b) strtol(s, e, b)
+#endif
+
+/* TODO: use bb_strtol[l]? It's easier to check for errors... */
+
+/* The kinds of value we can have. */
+enum {
+ INTEGER,
+ STRING
+};
+
+/* A value is.... */
+struct valinfo {
+ smallint type; /* Which kind. */
+ union { /* The value itself. */
+ arith_t i;
+ char *s;
+ } u;
+};
+typedef struct valinfo VALUE;
+
+/* The arguments given to the program, minus the program name. */
+struct globals {
+ char **args;
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+
+/* forward declarations */
+static VALUE *eval(void);
+
+
+/* Return a VALUE for I. */
+
+static VALUE *int_value(arith_t i)
+{
+ VALUE *v;
+
+ v = xzalloc(sizeof(VALUE));
+ if (INTEGER) /* otherwise xzaaloc did it already */
+ v->type = INTEGER;
+ v->u.i = i;
+ return v;
+}
+
+/* Return a VALUE for S. */
+
+static VALUE *str_value(const char *s)
+{
+ VALUE *v;
+
+ v = xzalloc(sizeof(VALUE));
+ if (STRING) /* otherwise xzaaloc did it already */
+ v->type = STRING;
+ v->u.s = xstrdup(s);
+ return v;
+}
+
+/* Free VALUE V, including structure components. */
+
+static void freev(VALUE *v)
+{
+ if (v->type == STRING)
+ free(v->u.s);
+ free(v);
+}
+
+/* Return nonzero if V is a null-string or zero-number. */
+
+static int null(VALUE *v)
+{
+ if (v->type == INTEGER)
+ return v->u.i == 0;
+ /* STRING: */
+ return v->u.s[0] == '\0' || LONE_CHAR(v->u.s, '0');
+}
+
+/* Coerce V to a STRING value (can't fail). */
+
+static void tostring(VALUE *v)
+{
+ if (v->type == INTEGER) {
+ v->u.s = xasprintf("%" PF_REZ "d", PF_REZ_TYPE v->u.i);
+ v->type = STRING;
+ }
+}
+
+/* Coerce V to an INTEGER value. Return 1 on success, 0 on failure. */
+
+static bool toarith(VALUE *v)
+{
+ if (v->type == STRING) {
+ arith_t i;
+ char *e;
+
+ /* Don't interpret the empty string as an integer. */
+ /* Currently does not worry about overflow or int/long differences. */
+ i = STRTOL(v->u.s, &e, 10);
+ if ((v->u.s == e) || *e)
+ return 0;
+ free(v->u.s);
+ v->u.i = i;
+ v->type = INTEGER;
+ }
+ return 1;
+}
+
+/* Return str[0]+str[1] if the next token matches STR exactly.
+ STR must not be NULL. */
+
+static int nextarg(const char *str)
+{
+ if (*G.args == NULL || strcmp(*G.args, str) != 0)
+ return 0;
+ return (unsigned char)str[0] + (unsigned char)str[1];
+}
+
+/* The comparison operator handling functions. */
+
+static int cmp_common(VALUE *l, VALUE *r, int op)
+{
+ arith_t ll, rr;
+
+ ll = l->u.i;
+ rr = r->u.i;
+ if (l->type == STRING || r->type == STRING) {
+ tostring(l);
+ tostring(r);
+ ll = strcmp(l->u.s, r->u.s);
+ rr = 0;
+ }
+ /* calculating ll - rr and checking the result is prone to overflows.
+ * We'll do it differently: */
+ if (op == '<')
+ return ll < rr;
+ if (op == ('<' + '='))
+ return ll <= rr;
+ if (op == '=' || (op == '=' + '='))
+ return ll == rr;
+ if (op == '!' + '=')
+ return ll != rr;
+ if (op == '>')
+ return ll > rr;
+ /* >= */
+ return ll >= rr;
+}
+
+/* The arithmetic operator handling functions. */
+
+static arith_t arithmetic_common(VALUE *l, VALUE *r, int op)
+{
+ arith_t li, ri;
+
+ if (!toarith(l) || !toarith(r))
+ bb_error_msg_and_die("non-numeric argument");
+ li = l->u.i;
+ ri = r->u.i;
+ if (op == '+')
+ return li + ri;
+ if (op == '-')
+ return li - ri;
+ if (op == '*')
+ return li * ri;
+ if (ri == 0)
+ bb_error_msg_and_die("division by zero");
+ if (op == '/')
+ return li / ri;
+ return li % ri;
+}
+
+/* Do the : operator.
+ SV is the VALUE for the lhs (the string),
+ PV is the VALUE for the rhs (the pattern). */
+
+static VALUE *docolon(VALUE *sv, VALUE *pv)
+{
+ VALUE *v;
+ regex_t re_buffer;
+ const int NMATCH = 2;
+ regmatch_t re_regs[NMATCH];
+
+ tostring(sv);
+ tostring(pv);
+
+ if (pv->u.s[0] == '^') {
+ bb_error_msg("\
+warning: unportable BRE: `%s': using `^' as the first character\n\
+of a basic regular expression is not portable; it is being ignored", pv->u.s);
+ }
+
+ memset(&re_buffer, 0, sizeof(re_buffer));
+ memset(re_regs, 0, sizeof(*re_regs));
+ xregcomp(&re_buffer, pv->u.s, 0);
+
+ /* expr uses an anchored pattern match, so check that there was a
+ * match and that the match starts at offset 0. */
+ if (regexec(&re_buffer, sv->u.s, NMATCH, re_regs, 0) != REG_NOMATCH
+ && re_regs[0].rm_so == 0
+ ) {
+ /* Were \(...\) used? */
+ if (re_buffer.re_nsub > 0) {
+ sv->u.s[re_regs[1].rm_eo] = '\0';
+ v = str_value(sv->u.s + re_regs[1].rm_so);
+ } else {
+ v = int_value(re_regs[0].rm_eo);
+ }
+ } else {
+ /* Match failed -- return the right kind of null. */
+ if (re_buffer.re_nsub > 0)
+ v = str_value("");
+ else
+ v = int_value(0);
+ }
+//FIXME: sounds like here is a bit missing: regfree(&re_buffer);
+ return v;
+}
+
+/* Handle bare operands and ( expr ) syntax. */
+
+static VALUE *eval7(void)
+{
+ VALUE *v;
+
+ if (!*G.args)
+ bb_error_msg_and_die("syntax error");
+
+ if (nextarg("(")) {
+ G.args++;
+ v = eval();
+ if (!nextarg(")"))
+ bb_error_msg_and_die("syntax error");
+ G.args++;
+ return v;
+ }
+
+ if (nextarg(")"))
+ bb_error_msg_and_die("syntax error");
+
+ return str_value(*G.args++);
+}
+
+/* Handle match, substr, index, length, and quote keywords. */
+
+static VALUE *eval6(void)
+{
+ static const char keywords[] ALIGN1 =
+ "quote\0""length\0""match\0""index\0""substr\0";
+
+ VALUE *r, *i1, *i2;
+ VALUE *l = l; /* silence gcc */
+ VALUE *v = v; /* silence gcc */
+ int key = *G.args ? index_in_strings(keywords, *G.args) + 1 : 0;
+
+ if (key == 0) /* not a keyword */
+ return eval7();
+ G.args++; /* We have a valid token, so get the next argument. */
+ if (key == 1) { /* quote */
+ if (!*G.args)
+ bb_error_msg_and_die("syntax error");
+ return str_value(*G.args++);
+ }
+ if (key == 2) { /* length */
+ r = eval6();
+ tostring(r);
+ v = int_value(strlen(r->u.s));
+ freev(r);
+ } else
+ l = eval6();
+
+ if (key == 3) { /* match */
+ r = eval6();
+ v = docolon(l, r);
+ freev(l);
+ freev(r);
+ }
+ if (key == 4) { /* index */
+ r = eval6();
+ tostring(l);
+ tostring(r);
+ v = int_value(strcspn(l->u.s, r->u.s) + 1);
+ if (v->u.i == (arith_t) strlen(l->u.s) + 1)
+ v->u.i = 0;
+ freev(l);
+ freev(r);
+ }
+ if (key == 5) { /* substr */
+ i1 = eval6();
+ i2 = eval6();
+ tostring(l);
+ if (!toarith(i1) || !toarith(i2)
+ || i1->u.i > (arith_t) strlen(l->u.s)
+ || i1->u.i <= 0 || i2->u.i <= 0)
+ v = str_value("");
+ else {
+ v = xmalloc(sizeof(VALUE));
+ v->type = STRING;
+ v->u.s = xstrndup(l->u.s + i1->u.i - 1, i2->u.i);
+ }
+ freev(l);
+ freev(i1);
+ freev(i2);
+ }
+ return v;
+
+}
+
+/* Handle : operator (pattern matching).
+ Calls docolon to do the real work. */
+
+static VALUE *eval5(void)
+{
+ VALUE *l, *r, *v;
+
+ l = eval6();
+ while (nextarg(":")) {
+ G.args++;
+ r = eval6();
+ v = docolon(l, r);
+ freev(l);
+ freev(r);
+ l = v;
+ }
+ return l;
+}
+
+/* Handle *, /, % operators. */
+
+static VALUE *eval4(void)
+{
+ VALUE *l, *r;
+ int op;
+ arith_t val;
+
+ l = eval5();
+ while (1) {
+ op = nextarg("*");
+ if (!op) { op = nextarg("/");
+ if (!op) { op = nextarg("%");
+ if (!op) return l;
+ }}
+ G.args++;
+ r = eval5();
+ val = arithmetic_common(l, r, op);
+ freev(l);
+ freev(r);
+ l = int_value(val);
+ }
+}
+
+/* Handle +, - operators. */
+
+static VALUE *eval3(void)
+{
+ VALUE *l, *r;
+ int op;
+ arith_t val;
+
+ l = eval4();
+ while (1) {
+ op = nextarg("+");
+ if (!op) {
+ op = nextarg("-");
+ if (!op) return l;
+ }
+ G.args++;
+ r = eval4();
+ val = arithmetic_common(l, r, op);
+ freev(l);
+ freev(r);
+ l = int_value(val);
+ }
+}
+
+/* Handle comparisons. */
+
+static VALUE *eval2(void)
+{
+ VALUE *l, *r;
+ int op;
+ arith_t val;
+
+ l = eval3();
+ while (1) {
+ op = nextarg("<");
+ if (!op) { op = nextarg("<=");
+ if (!op) { op = nextarg("=");
+ if (!op) { op = nextarg("==");
+ if (!op) { op = nextarg("!=");
+ if (!op) { op = nextarg(">=");
+ if (!op) { op = nextarg(">");
+ if (!op) return l;
+ }}}}}}
+ G.args++;
+ r = eval3();
+ toarith(l);
+ toarith(r);
+ val = cmp_common(l, r, op);
+ freev(l);
+ freev(r);
+ l = int_value(val);
+ }
+}
+
+/* Handle &. */
+
+static VALUE *eval1(void)
+{
+ VALUE *l, *r;
+
+ l = eval2();
+ while (nextarg("&")) {
+ G.args++;
+ r = eval2();
+ if (null(l) || null(r)) {
+ freev(l);
+ freev(r);
+ l = int_value(0);
+ } else
+ freev(r);
+ }
+ return l;
+}
+
+/* Handle |. */
+
+static VALUE *eval(void)
+{
+ VALUE *l, *r;
+
+ l = eval1();
+ while (nextarg("|")) {
+ G.args++;
+ r = eval1();
+ if (null(l)) {
+ freev(l);
+ l = r;
+ } else
+ freev(r);
+ }
+ return l;
+}
+
+int expr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int expr_main(int argc, char **argv)
+{
+ VALUE *v;
+
+ if (argc == 1) {
+ bb_error_msg_and_die("too few arguments");
+ }
+
+ G.args = argv + 1;
+
+ v = eval();
+ if (*G.args)
+ bb_error_msg_and_die("syntax error");
+
+ if (v->type == INTEGER)
+ printf("%" PF_REZ "d\n", PF_REZ_TYPE v->u.i);
+ else
+ puts(v->u.s);
+
+ fflush_stdout_and_exit(null(v));
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/false.c b/cleopatre/busybox-1.11.1-spc300/coreutils/false.c
new file mode 100644
index 0000000000..e3121363c9
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/false.c
@@ -0,0 +1,21 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini false implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 compliant */
+/* http://www.opengroup.org/onlinepubs/000095399/utilities/false.html */
+
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
+
+int false_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int false_main(int ATTRIBUTE_UNUSED argc, char ATTRIBUTE_UNUSED **argv)
+{
+ return EXIT_FAILURE;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/fold.c b/cleopatre/busybox-1.11.1-spc300/coreutils/fold.c
new file mode 100644
index 0000000000..e2a30d5d4e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/fold.c
@@ -0,0 +1,151 @@
+/* vi: set sw=4 ts=4: */
+/* fold -- wrap each input line to fit in specified width.
+
+ Written by David MacKenzie, djm@gnu.ai.mit.edu.
+ Copyright (C) 91, 1995-2002 Free Software Foundation, Inc.
+
+ Modified for busybox based on coreutils v 5.0
+ Copyright (C) 2003 Glenn McGrath
+
+ Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+*/
+
+#include "libbb.h"
+
+/* Must match getopt32 call */
+#define FLAG_COUNT_BYTES 1
+#define FLAG_BREAK_SPACES 2
+#define FLAG_WIDTH 4
+
+/* Assuming the current column is COLUMN, return the column that
+ printing C will move the cursor to.
+ The first column is 0. */
+static int adjust_column(int column, char c)
+{
+ if (!(option_mask32 & FLAG_COUNT_BYTES)) {
+ if (c == '\b') {
+ if (column > 0)
+ column--;
+ } else if (c == '\r')
+ column = 0;
+ else if (c == '\t')
+ column = column + 8 - column % 8;
+ else /* if (isprint (c)) */
+ column++;
+ } else
+ column++;
+ return column;
+}
+
+int fold_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int fold_main(int argc, char **argv)
+{
+ char *line_out = NULL;
+ int allocated_out = 0;
+ char *w_opt;
+ int width = 80;
+ int i;
+ int errs = 0;
+
+ if (ENABLE_INCLUDE_SUSv2) {
+ /* Turn any numeric options into -w options. */
+ for (i = 1; i < argc; i++) {
+ char const *a = argv[i];
+
+ if (*a++ == '-') {
+ if (*a == '-' && !a[1]) /* "--" */
+ break;
+ if (isdigit(*a))
+ argv[i] = xasprintf("-w%s", a);
+ }
+ }
+ }
+
+ getopt32(argv, "bsw:", &w_opt);
+ if (option_mask32 & FLAG_WIDTH)
+ width = xatoul_range(w_opt, 1, 10000);
+
+ argv += optind;
+ if (!*argv)
+ *--argv = (char*)"-";
+
+ do {
+ FILE *istream = fopen_or_warn_stdin(*argv);
+ int c;
+ int column = 0; /* Screen column where next char will go. */
+ int offset_out = 0; /* Index in 'line_out' for next char. */
+
+ if (istream == NULL) {
+ errs |= EXIT_FAILURE;
+ continue;
+ }
+
+ while ((c = getc(istream)) != EOF) {
+ if (offset_out + 1 >= allocated_out) {
+ allocated_out += 1024;
+ line_out = xrealloc(line_out, allocated_out);
+ }
+
+ if (c == '\n') {
+ line_out[offset_out++] = c;
+ fwrite(line_out, sizeof(char), (size_t) offset_out, stdout);
+ column = offset_out = 0;
+ continue;
+ }
+ rescan:
+ column = adjust_column(column, c);
+
+ if (column > width) {
+ /* This character would make the line too long.
+ Print the line plus a newline, and make this character
+ start the next line. */
+ if (option_mask32 & FLAG_BREAK_SPACES) {
+ /* Look for the last blank. */
+ int logical_end;
+
+ for (logical_end = offset_out - 1; logical_end >= 0; logical_end--) {
+ if (isblank(line_out[logical_end])) {
+ break;
+ }
+ }
+ if (logical_end >= 0) {
+ /* Found a blank. Don't output the part after it. */
+ logical_end++;
+ fwrite(line_out, sizeof(char), (size_t) logical_end, stdout);
+ bb_putchar('\n');
+ /* Move the remainder to the beginning of the next line.
+ The areas being copied here might overlap. */
+ memmove(line_out, line_out + logical_end, offset_out - logical_end);
+ offset_out -= logical_end;
+ for (column = i = 0; i < offset_out; i++) {
+ column = adjust_column(column, line_out[i]);
+ }
+ goto rescan;
+ }
+ } else {
+ if (offset_out == 0) {
+ line_out[offset_out++] = c;
+ continue;
+ }
+ }
+ line_out[offset_out++] = '\n';
+ fwrite(line_out, sizeof(char), (size_t) offset_out, stdout);
+ column = offset_out = 0;
+ goto rescan;
+ }
+
+ line_out[offset_out++] = c;
+ }
+
+ if (offset_out) {
+ fwrite(line_out, sizeof(char), (size_t) offset_out, stdout);
+ }
+
+ if (fclose_if_not_stdin(istream)) {
+ bb_simple_perror_msg(*argv); /* Avoid multibyte problems. */
+ errs |= EXIT_FAILURE;
+ }
+ } while (*++argv);
+
+ fflush_stdout_and_exit(errs);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/head.c b/cleopatre/busybox-1.11.1-spc300/coreutils/head.c
new file mode 100644
index 0000000000..570f140b1d
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/head.c
@@ -0,0 +1,140 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * head implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 compliant */
+/* BB_AUDIT GNU compatible -c, -q, and -v options in 'fancy' configuration. */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/head.html */
+
+#include "libbb.h"
+
+static const char head_opts[] ALIGN1 =
+ "n:"
+#if ENABLE_FEATURE_FANCY_HEAD
+ "c:qv"
+#endif
+ ;
+
+#if ENABLE_FEATURE_FANCY_HEAD
+static const struct suffix_mult head_suffixes[] = {
+ { "b", 512 },
+ { "k", 1024 },
+ { "m", 1024*1024 },
+ { }
+};
+#endif
+
+static const char header_fmt_str[] ALIGN1 = "\n==> %s <==\n";
+
+int head_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int head_main(int argc, char **argv)
+{
+ unsigned long count = 10;
+ unsigned long i;
+#if ENABLE_FEATURE_FANCY_HEAD
+ int count_bytes = 0;
+ int header_threshhold = 1;
+#endif
+
+ FILE *fp;
+ const char *fmt;
+ char *p;
+ int opt;
+ int c;
+ int retval = EXIT_SUCCESS;
+
+#if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD
+ /* Allow legacy syntax of an initial numeric option without -n. */
+ if (argc > 1 && argv[1][0] == '-'
+ && isdigit(argv[1][1])
+ ) {
+ --argc;
+ ++argv;
+ p = (*argv) + 1;
+ goto GET_COUNT;
+ }
+#endif
+
+ /* No size benefit in converting this to getopt32 */
+ while ((opt = getopt(argc, argv, head_opts)) > 0) {
+ switch (opt) {
+#if ENABLE_FEATURE_FANCY_HEAD
+ case 'q':
+ header_threshhold = INT_MAX;
+ break;
+ case 'v':
+ header_threshhold = -1;
+ break;
+ case 'c':
+ count_bytes = 1;
+ /* fall through */
+#endif
+ case 'n':
+ p = optarg;
+#if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD
+ GET_COUNT:
+#endif
+
+#if !ENABLE_FEATURE_FANCY_HEAD
+ count = xatoul(p);
+#else
+ count = xatoul_sfx(p, head_suffixes);
+#endif
+ break;
+ default:
+ bb_show_usage();
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ if (!*argv)
+ *--argv = (char*)"-";
+
+ fmt = header_fmt_str + 1;
+#if ENABLE_FEATURE_FANCY_HEAD
+ if (argc <= header_threshhold) {
+ header_threshhold = 0;
+ }
+#else
+ if (argc <= 1) {
+ fmt += 11; /* "" */
+ }
+ /* Now define some things here to avoid #ifdefs in the code below.
+ * These should optimize out of the if conditions below. */
+#define header_threshhold 1
+#define count_bytes 0
+#endif
+
+ do {
+ fp = fopen_or_warn_stdin(*argv);
+ if (fp) {
+ if (fp == stdin) {
+ *argv = (char *) bb_msg_standard_input;
+ }
+ if (header_threshhold) {
+ printf(fmt, *argv);
+ }
+ i = count;
+ while (i && ((c = getc(fp)) != EOF)) {
+ if (count_bytes || (c == '\n')) {
+ --i;
+ }
+ putchar(c);
+ }
+ if (fclose_if_not_stdin(fp)) {
+ bb_simple_perror_msg(*argv); /* Avoid multibyte problems. */
+ retval = EXIT_FAILURE;
+ }
+ die_if_ferror_stdout();
+ }
+ fmt = header_fmt_str;
+ } while (*++argv);
+
+ fflush_stdout_and_exit(retval);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/hostid.c b/cleopatre/busybox-1.11.1-spc300/coreutils/hostid.c
new file mode 100644
index 0000000000..433eccc458
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/hostid.c
@@ -0,0 +1,26 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini hostid implementation for busybox
+ *
+ * Copyright (C) 2000 Edward Betts <edward@debian.org>.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */
+
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
+
+int hostid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int hostid_main(int argc, char ATTRIBUTE_UNUSED **argv)
+{
+ if (argc > 1) {
+ bb_show_usage();
+ }
+
+ printf("%lx\n", gethostid());
+
+ return fflush(stdout);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/id.c b/cleopatre/busybox-1.11.1-spc300/coreutils/id.c
new file mode 100644
index 0000000000..9afb100886
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/id.c
@@ -0,0 +1,126 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini id implementation for busybox
+ *
+ * Copyright (C) 2000 by Randolph Chung <tausq@debian.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 _NOT_ compliant -- option -G is not currently supported. */
+/* Hacked by Tito Ragusa (C) 2004 to handle usernames of whatever length and to
+ * be more similar to GNU id.
+ * -Z option support: by Yuichi Nakamura <ynakam@hitachisoft.jp>
+ */
+
+#include "libbb.h"
+
+#define PRINT_REAL 1
+#define NAME_NOT_NUMBER 2
+#define JUST_USER 4
+#define JUST_GROUP 8
+#if ENABLE_SELINUX
+#define JUST_CONTEXT 16
+#endif
+
+static int printf_full(unsigned int id, const char *arg, const char prefix)
+{
+ const char *fmt = "%cid=%u";
+ int status = EXIT_FAILURE;
+
+ if (arg) {
+ fmt = "%cid=%u(%s)";
+ status = EXIT_SUCCESS;
+ }
+ printf(fmt, prefix, id, arg);
+ return status;
+}
+
+int id_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int id_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ struct passwd *p;
+ uid_t uid;
+ gid_t gid;
+ unsigned long flags;
+ short status;
+#if ENABLE_SELINUX
+ security_context_t scontext;
+#endif
+ /* Don't allow -n -r -nr -ug -rug -nug -rnug */
+ /* Don't allow more than one username */
+ opt_complementary = "?1:u--g:g--u:r?ug:n?ug" USE_SELINUX(":u--Z:Z--u:g--Z:Z--g");
+ flags = getopt32(argv, "rnug" USE_SELINUX("Z"));
+
+ /* This values could be overwritten later */
+ uid = geteuid();
+ gid = getegid();
+ if (flags & PRINT_REAL) {
+ uid = getuid();
+ gid = getgid();
+ }
+
+ if (argv[optind]) {
+ p = getpwnam(argv[optind]);
+ /* xuname2uid is needed because it exits on failure */
+ uid = xuname2uid(argv[optind]);
+ gid = p->pw_gid;
+ /* in this case PRINT_REAL is the same */
+ }
+
+ if (flags & (JUST_GROUP | JUST_USER USE_SELINUX(| JUST_CONTEXT))) {
+ /* JUST_GROUP and JUST_USER are mutually exclusive */
+ if (flags & NAME_NOT_NUMBER) {
+ /* bb_getXXXid(-1) exit on failure, puts cannot segfault */
+ puts((flags & JUST_USER) ? bb_getpwuid(NULL, -1, uid) : bb_getgrgid(NULL, -1, gid));
+ } else {
+ if (flags & JUST_USER) {
+ printf("%u\n", uid);
+ }
+ if (flags & JUST_GROUP) {
+ printf("%u\n", gid);
+ }
+ }
+
+#if ENABLE_SELINUX
+ if (flags & JUST_CONTEXT) {
+ selinux_or_die();
+ if (argc - optind == 1) {
+ bb_error_msg_and_die("user name can't be passed with -Z");
+ }
+
+ if (getcon(&scontext)) {
+ bb_error_msg_and_die("can't get process context");
+ }
+ puts(scontext);
+ }
+#endif
+ /* exit */
+ fflush_stdout_and_exit(EXIT_SUCCESS);
+ }
+
+ /* Print full info like GNU id */
+ /* bb_getpwuid(0) doesn't exit on failure (returns NULL) */
+ status = printf_full(uid, bb_getpwuid(NULL, 0, uid), 'u');
+ bb_putchar(' ');
+ status |= printf_full(gid, bb_getgrgid(NULL, 0, gid), 'g');
+
+#if ENABLE_SELINUX
+ if (is_selinux_enabled()) {
+ security_context_t mysid;
+ const char *context;
+
+ context = "unknown";
+ getcon(&mysid);
+ if (mysid) {
+ context = alloca(strlen(mysid) + 1);
+ strcpy((char*)context, mysid);
+ freecon(mysid);
+ }
+ printf(" context=%s", context);
+ }
+#endif
+
+ bb_putchar('\n');
+ fflush_stdout_and_exit(status);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/install.c b/cleopatre/busybox-1.11.1-spc300/coreutils/install.c
new file mode 100644
index 0000000000..0b5eda0acd
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/install.c
@@ -0,0 +1,222 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2003 by Glenn McGrath
+ * SELinux support: by Yuichi Nakamura <ynakam@hitachisoft.jp>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ * TODO: -d option, need a way of recursively making directories and changing
+ * owner/group, will probably modify bb_make_directory(...)
+ */
+
+#include "libbb.h"
+#include "libcoreutils/coreutils.h"
+
+#if ENABLE_FEATURE_INSTALL_LONG_OPTIONS
+static const char install_longopts[] ALIGN1 =
+ "directory\0" No_argument "d"
+ "preserve-timestamps\0" No_argument "p"
+ "strip\0" No_argument "s"
+ "group\0" No_argument "g"
+ "mode\0" No_argument "m"
+ "owner\0" No_argument "o"
+/* autofs build insists of using -b --suffix=.orig */
+/* TODO? (short option for --suffix is -S) */
+#if ENABLE_SELINUX
+ "context\0" Required_argument "Z"
+ "preserve_context\0" No_argument "\xff"
+ "preserve-context\0" No_argument "\xff"
+#endif
+ ;
+#endif
+
+
+#if ENABLE_SELINUX
+static void setdefaultfilecon(const char *path)
+{
+ struct stat s;
+ security_context_t scontext = NULL;
+
+ if (!is_selinux_enabled()) {
+ return;
+ }
+ if (lstat(path, &s) != 0) {
+ return;
+ }
+
+ if (matchpathcon(path, s.st_mode, &scontext) < 0) {
+ goto out;
+ }
+ if (strcmp(scontext, "<<none>>") == 0) {
+ goto out;
+ }
+
+ if (lsetfilecon(path, scontext) < 0) {
+ if (errno != ENOTSUP) {
+ bb_perror_msg("warning: failed to change context of %s to %s", path, scontext);
+ }
+ }
+
+ out:
+ freecon(scontext);
+}
+
+#endif
+
+int install_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int install_main(int argc, char **argv)
+{
+ struct stat statbuf;
+ mode_t mode;
+ uid_t uid;
+ gid_t gid;
+ char *arg, *last;
+ const char *gid_str;
+ const char *uid_str;
+ const char *mode_str;
+ int copy_flags = FILEUTILS_DEREFERENCE | FILEUTILS_FORCE;
+ int flags;
+ int ret = EXIT_SUCCESS;
+ int isdir;
+#if ENABLE_SELINUX
+ security_context_t scontext;
+ bool use_default_selinux_context = 1;
+#endif
+ enum {
+ OPT_c = 1 << 0,
+ OPT_v = 1 << 1,
+ OPT_b = 1 << 2,
+ OPT_DIRECTORY = 1 << 3,
+ OPT_PRESERVE_TIME = 1 << 4,
+ OPT_STRIP = 1 << 5,
+ OPT_GROUP = 1 << 6,
+ OPT_MODE = 1 << 7,
+ OPT_OWNER = 1 << 8,
+#if ENABLE_SELINUX
+ OPT_SET_SECURITY_CONTEXT = 1 << 9,
+ OPT_PRESERVE_SECURITY_CONTEXT = 1 << 10,
+#endif
+ };
+
+#if ENABLE_FEATURE_INSTALL_LONG_OPTIONS
+ applet_long_options = install_longopts;
+#endif
+ opt_complementary = "s--d:d--s" USE_SELINUX(":Z--\xff:\xff--Z");
+ /* -c exists for backwards compatibility, it's needed */
+ /* -v is ignored ("print name of each created directory") */
+ /* -b is ignored ("make a backup of each existing destination file") */
+ flags = getopt32(argv, "cvb" "dpsg:m:o:" USE_SELINUX("Z:"),
+ &gid_str, &mode_str, &uid_str USE_SELINUX(, &scontext));
+ argc -= optind;
+ argv += optind;
+
+#if ENABLE_SELINUX
+ if (flags & (OPT_PRESERVE_SECURITY_CONTEXT|OPT_SET_SECURITY_CONTEXT)) {
+ selinux_or_die();
+ use_default_selinux_context = 0;
+ if (flags & OPT_PRESERVE_SECURITY_CONTEXT) {
+ copy_flags |= FILEUTILS_PRESERVE_SECURITY_CONTEXT;
+ }
+ if (flags & OPT_SET_SECURITY_CONTEXT) {
+ setfscreatecon_or_die(scontext);
+ copy_flags |= FILEUTILS_SET_SECURITY_CONTEXT;
+ }
+ }
+#endif
+
+ /* preserve access and modification time, this is GNU behaviour, BSD only preserves modification time */
+ if (flags & OPT_PRESERVE_TIME) {
+ copy_flags |= FILEUTILS_PRESERVE_STATUS;
+ }
+ mode = 0666;
+ if (flags & OPT_MODE)
+ bb_parse_mode(mode_str, &mode);
+ uid = (flags & OPT_OWNER) ? get_ug_id(uid_str, xuname2uid) : getuid();
+ gid = (flags & OPT_GROUP) ? get_ug_id(gid_str, xgroup2gid) : getgid();
+ if (flags & (OPT_OWNER|OPT_GROUP))
+ umask(0);
+
+ /* Create directories
+ * don't use bb_make_directory() as it can't change uid or gid
+ * perhaps bb_make_directory() should be improved.
+ */
+ if (flags & OPT_DIRECTORY) {
+ while ((arg = *argv++) != NULL) {
+ char *slash = arg;
+ while (1) {
+ slash = strchr(slash + 1, '/');
+ if (slash)
+ *slash = '\0';
+ if (mkdir(arg, mode | 0111) == -1) {
+ if (errno != EEXIST) {
+ bb_perror_msg("cannot create %s", arg);
+ ret = EXIT_FAILURE;
+ break;
+ }
+ } /* dir was created, chown? */
+ else if ((flags & (OPT_OWNER|OPT_GROUP))
+ && lchown(arg, uid, gid) == -1
+ ) {
+ bb_perror_msg("cannot change ownership of %s", arg);
+ ret = EXIT_FAILURE;
+ break;
+ }
+ if (!slash)
+ break;
+ *slash = '/';
+ }
+ }
+ return ret;
+ }
+
+ if (argc < 2)
+ bb_show_usage();
+
+ last = argv[argc - 1];
+ argv[argc - 1] = NULL;
+ /* coreutils install resolves link in this case, don't use lstat */
+ isdir = stat(last, &statbuf) < 0 ? 0 : S_ISDIR(statbuf.st_mode);
+
+ while ((arg = *argv++) != NULL) {
+ char *dest = last;
+ if (isdir)
+ dest = concat_path_file(last, basename(arg));
+ if (copy_file(arg, dest, copy_flags)) {
+ /* copy is not made */
+ ret = EXIT_FAILURE;
+ goto next;
+ }
+
+ /* Set the file mode */
+ if ((flags & OPT_MODE) && chmod(dest, mode) == -1) {
+ bb_perror_msg("cannot change permissions of %s", dest);
+ ret = EXIT_FAILURE;
+ }
+#if ENABLE_SELINUX
+ if (use_default_selinux_context)
+ setdefaultfilecon(dest);
+#endif
+ /* Set the user and group id */
+ if ((flags & (OPT_OWNER|OPT_GROUP))
+ && lchown(dest, uid, gid) == -1
+ ) {
+ bb_perror_msg("cannot change ownership of %s", dest);
+ ret = EXIT_FAILURE;
+ }
+ if (flags & OPT_STRIP) {
+ char *args[3];
+ args[0] = (char*)"strip";
+ args[1] = dest;
+ args[2] = NULL;
+ if (spawn_and_wait(args)) {
+ bb_perror_msg("strip");
+ ret = EXIT_FAILURE;
+ }
+ }
+ next:
+ if (ENABLE_FEATURE_CLEAN_UP && isdir)
+ free(dest);
+ }
+
+ return ret;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/length.c b/cleopatre/busybox-1.11.1-spc300/coreutils/length.c
new file mode 100644
index 0000000000..c7523a02a1
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/length.c
@@ -0,0 +1,19 @@
+/* vi: set sw=4 ts=4: */
+
+/* BB_AUDIT SUSv3 N/A -- Apparently a busybox (obsolete?) extension. */
+
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
+
+int length_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int length_main(int argc, char **argv)
+{
+ if ((argc != 2) || (**(++argv) == '-')) {
+ bb_show_usage();
+ }
+
+ printf("%u\n", (unsigned)strlen(*argv));
+
+ return fflush(stdout);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/libcoreutils/Kbuild b/cleopatre/busybox-1.11.1-spc300/coreutils/libcoreutils/Kbuild
new file mode 100644
index 0000000000..755d01f86f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/libcoreutils/Kbuild
@@ -0,0 +1,12 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+
+lib-y:=
+lib-$(CONFIG_MKFIFO) += getopt_mk_fifo_nod.o
+lib-$(CONFIG_MKNOD) += getopt_mk_fifo_nod.o
+lib-$(CONFIG_INSTALL) += cp_mv_stat.o
+lib-$(CONFIG_CP) += cp_mv_stat.o
+lib-$(CONFIG_MV) += cp_mv_stat.o
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/libcoreutils/coreutils.h b/cleopatre/busybox-1.11.1-spc300/coreutils/libcoreutils/coreutils.h
new file mode 100644
index 0000000000..be9af1227c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/libcoreutils/coreutils.h
@@ -0,0 +1,24 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+#ifndef COREUTILS_H
+#define COREUTILS_H 1
+
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility push(hidden)
+#endif
+
+typedef int (*stat_func)(const char *fn, struct stat *ps);
+
+int cp_mv_stat2(const char *fn, struct stat *fn_stat, stat_func sf);
+int cp_mv_stat(const char *fn, struct stat *fn_stat);
+
+mode_t getopt_mk_fifo_nod(char **argv);
+
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility pop
+#endif
+
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/libcoreutils/cp_mv_stat.c b/cleopatre/busybox-1.11.1-spc300/coreutils/libcoreutils/cp_mv_stat.c
new file mode 100644
index 0000000000..ff7c27399e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/libcoreutils/cp_mv_stat.c
@@ -0,0 +1,50 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * coreutils utility routine
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "libbb.h"
+#include "coreutils.h"
+
+int cp_mv_stat2(const char *fn, struct stat *fn_stat, stat_func sf)
+{
+ if (sf(fn, fn_stat) < 0) {
+ if (errno != ENOENT) {
+#if ENABLE_FEATURE_VERBOSE_CP_MESSAGE
+ if (errno == ENOTDIR) {
+ bb_error_msg("cannot stat '%s': Path has non-directory component", fn);
+ return -1;
+ }
+#endif
+ bb_perror_msg("cannot stat '%s'", fn);
+ return -1;
+ }
+ return 0;
+ }
+ if (S_ISDIR(fn_stat->st_mode)) {
+ return 3;
+ }
+ return 1;
+}
+
+int cp_mv_stat(const char *fn, struct stat *fn_stat)
+{
+ return cp_mv_stat2(fn, fn_stat, stat);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/libcoreutils/getopt_mk_fifo_nod.c b/cleopatre/busybox-1.11.1-spc300/coreutils/libcoreutils/getopt_mk_fifo_nod.c
new file mode 100644
index 0000000000..32e55a56b9
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/libcoreutils/getopt_mk_fifo_nod.c
@@ -0,0 +1,48 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * coreutils utility routine
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "libbb.h"
+#include "coreutils.h"
+
+mode_t getopt_mk_fifo_nod(char **argv)
+{
+ mode_t mode = 0666;
+ char *smode = NULL;
+#if ENABLE_SELINUX
+ security_context_t scontext;
+#endif
+ int opt;
+ opt = getopt32(argv, "m:" USE_SELINUX("Z:"), &smode USE_SELINUX(,&scontext));
+ if (opt & 1) {
+ if (bb_parse_mode(smode, &mode))
+ umask(0);
+ }
+
+#if ENABLE_SELINUX
+ if (opt & 2) {
+ selinux_or_die();
+ setfscreatecon_or_die(scontext);
+ }
+#endif
+
+ return mode;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/ln.c b/cleopatre/busybox-1.11.1-spc300/coreutils/ln.c
new file mode 100644
index 0000000000..eb7171959c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/ln.c
@@ -0,0 +1,109 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini ln implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 compliant */
+/* BB_AUDIT GNU options missing: -d, -F, -i, and -v. */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/ln.html */
+
+#include "libbb.h"
+
+/* This is a NOEXEC applet. Be very careful! */
+
+
+#define LN_SYMLINK 1
+#define LN_FORCE 2
+#define LN_NODEREFERENCE 4
+#define LN_BACKUP 8
+#define LN_SUFFIX 16
+
+int ln_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int ln_main(int argc, char **argv)
+{
+ int status = EXIT_SUCCESS;
+ int flag;
+ char *last;
+ char *src_name;
+ char *src;
+ char *suffix = (char*)"~";
+ struct stat statbuf;
+ int (*link_func)(const char *, const char *);
+
+ flag = getopt32(argv, "sfnbS:", &suffix);
+
+ if (argc == optind) {
+ bb_show_usage();
+ }
+
+ last = argv[argc - 1];
+ argv += optind;
+
+ if (argc == optind + 1) {
+ *--argv = last;
+ last = bb_get_last_path_component_strip(xstrdup(last));
+ }
+
+ do {
+ src_name = NULL;
+ src = last;
+
+ if (is_directory(src,
+ (flag & LN_NODEREFERENCE) ^ LN_NODEREFERENCE,
+ NULL)
+ ) {
+ src_name = xstrdup(*argv);
+ src = concat_path_file(src, bb_get_last_path_component_strip(src_name));
+ free(src_name);
+ src_name = src;
+ }
+ if (!(flag & LN_SYMLINK) && stat(*argv, &statbuf)) {
+ // coreutils: "ln dangling_symlink new_hardlink" works
+ if (lstat(*argv, &statbuf) || !S_ISLNK(statbuf.st_mode)) {
+ bb_simple_perror_msg(*argv);
+ status = EXIT_FAILURE;
+ free(src_name);
+ continue;
+ }
+ }
+
+ if (flag & LN_BACKUP) {
+ char *backup;
+ backup = xasprintf("%s%s", src, suffix);
+ if (rename(src, backup) < 0 && errno != ENOENT) {
+ bb_simple_perror_msg(src);
+ status = EXIT_FAILURE;
+ free(backup);
+ continue;
+ }
+ free(backup);
+ /*
+ * When the source and dest are both hard links to the same
+ * inode, a rename may succeed even though nothing happened.
+ * Therefore, always unlink().
+ */
+ unlink(src);
+ } else if (flag & LN_FORCE) {
+ unlink(src);
+ }
+
+ link_func = link;
+ if (flag & LN_SYMLINK) {
+ link_func = symlink;
+ }
+
+ if (link_func(*argv, src) != 0) {
+ bb_simple_perror_msg(src);
+ status = EXIT_FAILURE;
+ }
+
+ free(src_name);
+
+ } while ((++argv)[1]);
+
+ return status;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/logname.c b/cleopatre/busybox-1.11.1-spc300/coreutils/logname.c
new file mode 100644
index 0000000000..09fd3960d8
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/logname.c
@@ -0,0 +1,43 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini logname implementation for busybox
+ *
+ * Copyright (C) 2000 Edward Betts <edward@debian.org>.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 compliant */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/logname.html */
+
+/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
+ *
+ * SUSv3 specifies the string used is that returned from getlogin().
+ * The previous implementation used getpwuid() for geteuid(), which
+ * is _not_ the same. Erik apparently made this change almost 3 years
+ * ago to avoid failing when no utmp was available. However, the
+ * correct course of action wrt SUSv3 for a failing getlogin() is
+ * a diagnostic message and an error return.
+ */
+
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
+
+int logname_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int logname_main(int argc, char ATTRIBUTE_UNUSED **argv)
+{
+ char buf[128];
+
+ if (argc > 1) {
+ bb_show_usage();
+ }
+
+ /* Using _r function - avoid pulling in static buffer from libc */
+ if (getlogin_r(buf, sizeof(buf)) == 0) {
+ puts(buf);
+ return fflush(stdout);
+ }
+
+ bb_perror_msg_and_die("getlogin");
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/ls.c b/cleopatre/busybox-1.11.1-spc300/coreutils/ls.c
new file mode 100644
index 0000000000..7fddefef59
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/ls.c
@@ -0,0 +1,979 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * tiny-ls.c version 0.1.0: A minimalist 'ls'
+ * Copyright (C) 1996 Brian Candler <B.Candler@pobox.com>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/*
+ * To achieve a small memory footprint, this version of 'ls' doesn't do any
+ * file sorting, and only has the most essential command line switches
+ * (i.e., the ones I couldn't live without :-) All features which involve
+ * linking in substantial chunks of libc can be disabled.
+ *
+ * Although I don't really want to add new features to this program to
+ * keep it small, I *am* interested to receive bug fixes and ways to make
+ * it more portable.
+ *
+ * KNOWN BUGS:
+ * 1. ls -l of a directory doesn't give "total <blocks>" header
+ * 2. ls of a symlink to a directory doesn't list directory contents
+ * 3. hidden files can make column width too large
+ *
+ * NON-OPTIMAL BEHAVIOUR:
+ * 1. autowidth reads directories twice
+ * 2. if you do a short directory listing without filetype characters
+ * appended, there's no need to stat each one
+ * PORTABILITY:
+ * 1. requires lstat (BSD) - how do you do it without?
+ */
+
+#include "libbb.h"
+
+#if ENABLE_FEATURE_ASSUME_UNICODE
+#include <wchar.h>
+#endif
+
+/* This is a NOEXEC applet. Be very careful! */
+
+
+enum {
+
+TERMINAL_WIDTH = 80, /* use 79 if terminal has linefold bug */
+COLUMN_GAP = 2, /* includes the file type char */
+
+/* what is the overall style of the listing */
+STYLE_COLUMNS = 1 << 21, /* fill columns */
+STYLE_LONG = 2 << 21, /* one record per line, extended info */
+STYLE_SINGLE = 3 << 21, /* one record per line */
+STYLE_MASK = STYLE_SINGLE,
+
+/* 51306 lrwxrwxrwx 1 root root 2 May 11 01:43 /bin/view -> vi* */
+/* what file information will be listed */
+LIST_INO = 1 << 0,
+LIST_BLOCKS = 1 << 1,
+LIST_MODEBITS = 1 << 2,
+LIST_NLINKS = 1 << 3,
+LIST_ID_NAME = 1 << 4,
+LIST_ID_NUMERIC = 1 << 5,
+LIST_CONTEXT = 1 << 6,
+LIST_SIZE = 1 << 7,
+LIST_DEV = 1 << 8,
+LIST_DATE_TIME = 1 << 9,
+LIST_FULLTIME = 1 << 10,
+LIST_FILENAME = 1 << 11,
+LIST_SYMLINK = 1 << 12,
+LIST_FILETYPE = 1 << 13,
+LIST_EXEC = 1 << 14,
+LIST_MASK = (LIST_EXEC << 1) - 1,
+
+/* what files will be displayed */
+DISP_DIRNAME = 1 << 15, /* 2 or more items? label directories */
+DISP_HIDDEN = 1 << 16, /* show filenames starting with . */
+DISP_DOT = 1 << 17, /* show . and .. */
+DISP_NOLIST = 1 << 18, /* show directory as itself, not contents */
+DISP_RECURSIVE = 1 << 19, /* show directory and everything below it */
+DISP_ROWS = 1 << 20, /* print across rows */
+DISP_MASK = ((DISP_ROWS << 1) - 1) & ~(DISP_DIRNAME - 1),
+
+/* how will the files be sorted (CONFIG_FEATURE_LS_SORTFILES) */
+SORT_FORWARD = 0, /* sort in reverse order */
+SORT_REVERSE = 1 << 27, /* sort in reverse order */
+
+SORT_NAME = 0, /* sort by file name */
+SORT_SIZE = 1 << 28, /* sort by file size */
+SORT_ATIME = 2 << 28, /* sort by last access time */
+SORT_CTIME = 3 << 28, /* sort by last change time */
+SORT_MTIME = 4 << 28, /* sort by last modification time */
+SORT_VERSION = 5 << 28, /* sort by version */
+SORT_EXT = 6 << 28, /* sort by file name extension */
+SORT_DIR = 7 << 28, /* sort by file or directory */
+SORT_MASK = (7 << 28) * ENABLE_FEATURE_LS_SORTFILES,
+
+/* which of the three times will be used */
+TIME_CHANGE = (1 << 23) * ENABLE_FEATURE_LS_TIMESTAMPS,
+TIME_ACCESS = (1 << 24) * ENABLE_FEATURE_LS_TIMESTAMPS,
+TIME_MASK = (3 << 23) * ENABLE_FEATURE_LS_TIMESTAMPS,
+
+FOLLOW_LINKS = (1 << 25) * ENABLE_FEATURE_LS_FOLLOWLINKS,
+
+LS_DISP_HR = (1 << 26) * ENABLE_FEATURE_HUMAN_READABLE,
+
+LIST_SHORT = LIST_FILENAME,
+LIST_LONG = LIST_MODEBITS | LIST_NLINKS | LIST_ID_NAME | LIST_SIZE | \
+ LIST_DATE_TIME | LIST_FILENAME | LIST_SYMLINK,
+
+SPLIT_DIR = 1,
+SPLIT_FILE = 0,
+SPLIT_SUBDIR = 2,
+
+};
+
+#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
+#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
+#define APPCHAR(mode) ("\0|\0\0/\0\0\0\0\0@\0=\0\0\0" [TYPEINDEX(mode)])
+#define COLOR(mode) ("\000\043\043\043\042\000\043\043"\
+ "\000\000\044\000\043\000\000\040" [TYPEINDEX(mode)])
+#define ATTR(mode) ("\00\00\01\00\01\00\01\00"\
+ "\00\00\01\00\01\00\00\01" [TYPEINDEX(mode)])
+
+/*
+ * a directory entry and its stat info are stored here
+ */
+struct dnode { /* the basic node */
+ const char *name; /* the dir entry name */
+ const char *fullname; /* the dir entry name */
+ int allocated;
+ struct stat dstat; /* the file stat info */
+ USE_SELINUX(security_context_t sid;)
+ struct dnode *next; /* point at the next node */
+};
+
+static struct dnode **list_dir(const char *);
+static struct dnode **dnalloc(int);
+static int list_single(const struct dnode *);
+
+
+struct globals {
+#if ENABLE_FEATURE_LS_COLOR
+ smallint show_color;
+#endif
+ smallint exit_code;
+ unsigned all_fmt;
+#if ENABLE_FEATURE_AUTOWIDTH
+ unsigned tabstops; // = COLUMN_GAP;
+ unsigned terminal_width; // = TERMINAL_WIDTH;
+#endif
+#if ENABLE_FEATURE_LS_TIMESTAMPS
+ /* Do time() just once. Saves one syscall per file for "ls -l" */
+ time_t current_time_t;
+#endif
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+#if ENABLE_FEATURE_LS_COLOR
+#define show_color (G.show_color )
+#else
+enum { show_color = 0 };
+#endif
+#define exit_code (G.exit_code )
+#define all_fmt (G.all_fmt )
+#if ENABLE_FEATURE_AUTOWIDTH
+#define tabstops (G.tabstops )
+#define terminal_width (G.terminal_width)
+#else
+enum {
+ tabstops = COLUMN_GAP,
+ terminal_width = TERMINAL_WIDTH,
+};
+#endif
+#define current_time_t (G.current_time_t)
+/* memset: we have to zero it out because of NOEXEC */
+#define INIT_G() do { \
+ memset(&G, 0, sizeof(G)); \
+ USE_FEATURE_AUTOWIDTH(tabstops = COLUMN_GAP;) \
+ USE_FEATURE_AUTOWIDTH(terminal_width = TERMINAL_WIDTH;) \
+ USE_FEATURE_LS_TIMESTAMPS(time(&current_time_t);) \
+} while (0)
+
+
+#if ENABLE_FEATURE_ASSUME_UNICODE
+/* libbb candidate */
+static size_t mbstrlen(const char *string)
+{
+ size_t width = mbsrtowcs(NULL /*dest*/, &string,
+ MAXINT(size_t) /*len*/, NULL /*state*/);
+ if (width == (size_t)-1)
+ return strlen(string);
+ return width;
+}
+#else
+#define mbstrlen(string) strlen(string)
+#endif
+
+
+static struct dnode *my_stat(const char *fullname, const char *name, int force_follow)
+{
+ struct stat dstat;
+ struct dnode *cur;
+ USE_SELINUX(security_context_t sid = NULL;)
+
+ if ((all_fmt & FOLLOW_LINKS) || force_follow) {
+#if ENABLE_SELINUX
+ if (is_selinux_enabled()) {
+ getfilecon(fullname, &sid);
+ }
+#endif
+ if (stat(fullname, &dstat)) {
+ bb_simple_perror_msg(fullname);
+ exit_code = EXIT_FAILURE;
+ return 0;
+ }
+ } else {
+#if ENABLE_SELINUX
+ if (is_selinux_enabled()) {
+ lgetfilecon(fullname, &sid);
+ }
+#endif
+ if (lstat(fullname, &dstat)) {
+ bb_simple_perror_msg(fullname);
+ exit_code = EXIT_FAILURE;
+ return 0;
+ }
+ }
+
+ cur = xmalloc(sizeof(struct dnode));
+ cur->fullname = fullname;
+ cur->name = name;
+ cur->dstat = dstat;
+ USE_SELINUX(cur->sid = sid;)
+ return cur;
+}
+
+#if ENABLE_FEATURE_LS_COLOR
+static char fgcolor(mode_t mode)
+{
+ /* Check wheter the file is existing (if so, color it red!) */
+ if (errno == ENOENT)
+ return '\037';
+ if (S_ISREG(mode) && (mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+ return COLOR(0xF000); /* File is executable ... */
+ return COLOR(mode);
+}
+
+static char bgcolor(mode_t mode)
+{
+ if (S_ISREG(mode) && (mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+ return ATTR(0xF000); /* File is executable ... */
+ return ATTR(mode);
+}
+#endif
+
+#if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR
+static char append_char(mode_t mode)
+{
+ if (!(all_fmt & LIST_FILETYPE))
+ return '\0';
+ if (S_ISDIR(mode))
+ return '/';
+ if (!(all_fmt & LIST_EXEC))
+ return '\0';
+ if (S_ISREG(mode) && (mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+ return '*';
+ return APPCHAR(mode);
+}
+#endif
+
+#define countdirs(A, B) count_dirs((A), (B), 1)
+#define countsubdirs(A, B) count_dirs((A), (B), 0)
+static int count_dirs(struct dnode **dn, int nfiles, int notsubdirs)
+{
+ int i, dirs;
+
+ if (!dn)
+ return 0;
+ dirs = 0;
+ for (i = 0; i < nfiles; i++) {
+ const char *name;
+ if (!S_ISDIR(dn[i]->dstat.st_mode))
+ continue;
+ name = dn[i]->name;
+ if (notsubdirs
+ || name[0]!='.' || (name[1] && (name[1]!='.' || name[2]))
+ ) {
+ dirs++;
+ }
+ }
+ return dirs;
+}
+
+static int countfiles(struct dnode **dnp)
+{
+ int nfiles;
+ struct dnode *cur;
+
+ if (dnp == NULL)
+ return 0;
+ nfiles = 0;
+ for (cur = dnp[0]; cur->next; cur = cur->next)
+ nfiles++;
+ nfiles++;
+ return nfiles;
+}
+
+/* get memory to hold an array of pointers */
+static struct dnode **dnalloc(int num)
+{
+ if (num < 1)
+ return NULL;
+
+ return xzalloc(num * sizeof(struct dnode *));
+}
+
+#if ENABLE_FEATURE_LS_RECURSIVE
+static void dfree(struct dnode **dnp, int nfiles)
+{
+ int i;
+
+ if (dnp == NULL)
+ return;
+
+ for (i = 0; i < nfiles; i++) {
+ struct dnode *cur = dnp[i];
+ if (cur->allocated)
+ free((char*)cur->fullname); /* free the filename */
+ free(cur); /* free the dnode */
+ }
+ free(dnp); /* free the array holding the dnode pointers */
+}
+#else
+#define dfree(...) ((void)0)
+#endif
+
+static struct dnode **splitdnarray(struct dnode **dn, int nfiles, int which)
+{
+ int dncnt, i, d;
+ struct dnode **dnp;
+
+ if (dn == NULL || nfiles < 1)
+ return NULL;
+
+ /* count how many dirs and regular files there are */
+ if (which == SPLIT_SUBDIR)
+ dncnt = countsubdirs(dn, nfiles);
+ else {
+ dncnt = countdirs(dn, nfiles); /* assume we are looking for dirs */
+ if (which == SPLIT_FILE)
+ dncnt = nfiles - dncnt; /* looking for files */
+ }
+
+ /* allocate a file array and a dir array */
+ dnp = dnalloc(dncnt);
+
+ /* copy the entrys into the file or dir array */
+ for (d = i = 0; i < nfiles; i++) {
+ if (S_ISDIR(dn[i]->dstat.st_mode)) {
+ const char *name;
+ if (!(which & (SPLIT_DIR|SPLIT_SUBDIR)))
+ continue;
+ name = dn[i]->name;
+ if ((which & SPLIT_DIR)
+ || name[0]!='.' || (name[1] && (name[1]!='.' || name[2]))
+ ) {
+ dnp[d++] = dn[i];
+ }
+ } else if (!(which & (SPLIT_DIR|SPLIT_SUBDIR))) {
+ dnp[d++] = dn[i];
+ }
+ }
+ return dnp;
+}
+
+#if ENABLE_FEATURE_LS_SORTFILES
+static int sortcmp(const void *a, const void *b)
+{
+ struct dnode *d1 = *(struct dnode **)a;
+ struct dnode *d2 = *(struct dnode **)b;
+ unsigned sort_opts = all_fmt & SORT_MASK;
+ int dif;
+
+ dif = 0; /* assume SORT_NAME */
+ // TODO: use pre-initialized function pointer
+ // instead of branch forest
+ if (sort_opts == SORT_SIZE) {
+ dif = (int) (d2->dstat.st_size - d1->dstat.st_size);
+ } else if (sort_opts == SORT_ATIME) {
+ dif = (int) (d2->dstat.st_atime - d1->dstat.st_atime);
+ } else if (sort_opts == SORT_CTIME) {
+ dif = (int) (d2->dstat.st_ctime - d1->dstat.st_ctime);
+ } else if (sort_opts == SORT_MTIME) {
+ dif = (int) (d2->dstat.st_mtime - d1->dstat.st_mtime);
+ } else if (sort_opts == SORT_DIR) {
+ dif = S_ISDIR(d2->dstat.st_mode) - S_ISDIR(d1->dstat.st_mode);
+ /* } else if (sort_opts == SORT_VERSION) { */
+ /* } else if (sort_opts == SORT_EXT) { */
+ }
+
+ if (dif == 0) {
+ /* sort by name - may be a tie_breaker for time or size cmp */
+ if (ENABLE_LOCALE_SUPPORT) dif = strcoll(d1->name, d2->name);
+ else dif = strcmp(d1->name, d2->name);
+ }
+
+ if (all_fmt & SORT_REVERSE) {
+ dif = -dif;
+ }
+ return dif;
+}
+
+static void dnsort(struct dnode **dn, int size)
+{
+ qsort(dn, size, sizeof(*dn), sortcmp);
+}
+#else
+#define dnsort(dn, size) ((void)0)
+#endif
+
+
+static void showfiles(struct dnode **dn, int nfiles)
+{
+ int i, ncols, nrows, row, nc;
+ int column = 0;
+ int nexttab = 0;
+ int column_width = 0; /* for STYLE_LONG and STYLE_SINGLE not used */
+
+ if (dn == NULL || nfiles < 1)
+ return;
+
+ if (all_fmt & STYLE_LONG) {
+ ncols = 1;
+ } else {
+ /* find the longest file name, use that as the column width */
+ for (i = 0; i < nfiles; i++) {
+ int len = mbstrlen(dn[i]->name);
+ if (column_width < len)
+ column_width = len;
+ }
+ column_width += tabstops +
+ USE_SELINUX( ((all_fmt & LIST_CONTEXT) ? 33 : 0) + )
+ ((all_fmt & LIST_INO) ? 8 : 0) +
+ ((all_fmt & LIST_BLOCKS) ? 5 : 0);
+ ncols = (int) (terminal_width / column_width);
+ }
+
+ if (ncols > 1) {
+ nrows = nfiles / ncols;
+ if (nrows * ncols < nfiles)
+ nrows++; /* round up fractionals */
+ } else {
+ nrows = nfiles;
+ ncols = 1;
+ }
+
+ for (row = 0; row < nrows; row++) {
+ for (nc = 0; nc < ncols; nc++) {
+ /* reach into the array based on the column and row */
+ i = (nc * nrows) + row; /* assume display by column */
+ if (all_fmt & DISP_ROWS)
+ i = (row * ncols) + nc; /* display across row */
+ if (i < nfiles) {
+ if (column > 0) {
+ nexttab -= column;
+ printf("%*s", nexttab, "");
+ column += nexttab;
+ }
+ nexttab = column + column_width;
+ column += list_single(dn[i]);
+ }
+ }
+ putchar('\n');
+ column = 0;
+ }
+}
+
+
+static void showdirs(struct dnode **dn, int ndirs, int first)
+{
+ int i, nfiles;
+ struct dnode **subdnp;
+ int dndirs;
+ struct dnode **dnd;
+
+ if (dn == NULL || ndirs < 1)
+ return;
+
+ for (i = 0; i < ndirs; i++) {
+ if (all_fmt & (DISP_DIRNAME | DISP_RECURSIVE)) {
+ if (!first)
+ bb_putchar('\n');
+ first = 0;
+ printf("%s:\n", dn[i]->fullname);
+ }
+ subdnp = list_dir(dn[i]->fullname);
+ nfiles = countfiles(subdnp);
+ if (nfiles > 0) {
+ /* list all files at this level */
+ dnsort(subdnp, nfiles);
+ showfiles(subdnp, nfiles);
+ if (ENABLE_FEATURE_LS_RECURSIVE) {
+ if (all_fmt & DISP_RECURSIVE) {
+ /* recursive- list the sub-dirs */
+ dnd = splitdnarray(subdnp, nfiles, SPLIT_SUBDIR);
+ dndirs = countsubdirs(subdnp, nfiles);
+ if (dndirs > 0) {
+ dnsort(dnd, dndirs);
+ showdirs(dnd, dndirs, 0);
+ /* free the array of dnode pointers to the dirs */
+ free(dnd);
+ }
+ }
+ /* free the dnodes and the fullname mem */
+ dfree(subdnp, nfiles);
+ }
+ }
+ }
+}
+
+
+static struct dnode **list_dir(const char *path)
+{
+ struct dnode *dn, *cur, **dnp;
+ struct dirent *entry;
+ DIR *dir;
+ int i, nfiles;
+
+ if (path == NULL)
+ return NULL;
+
+ dn = NULL;
+ nfiles = 0;
+ dir = warn_opendir(path);
+ if (dir == NULL) {
+ exit_code = EXIT_FAILURE;
+ return NULL; /* could not open the dir */
+ }
+ while ((entry = readdir(dir)) != NULL) {
+ char *fullname;
+
+ /* are we going to list the file- it may be . or .. or a hidden file */
+ if (entry->d_name[0] == '.') {
+ if ((!entry->d_name[1] || (entry->d_name[1] == '.' && !entry->d_name[2]))
+ && !(all_fmt & DISP_DOT)
+ ) {
+ continue;
+ }
+ if (!(all_fmt & DISP_HIDDEN))
+ continue;
+ }
+ fullname = concat_path_file(path, entry->d_name);
+ cur = my_stat(fullname, bb_basename(fullname), 0);
+ if (!cur) {
+ free(fullname);
+ continue;
+ }
+ cur->allocated = 1;
+ cur->next = dn;
+ dn = cur;
+ nfiles++;
+ }
+ closedir(dir);
+
+ /* now that we know how many files there are
+ * allocate memory for an array to hold dnode pointers
+ */
+ if (dn == NULL)
+ return NULL;
+ dnp = dnalloc(nfiles);
+ for (i = 0, cur = dn; i < nfiles; i++) {
+ dnp[i] = cur; /* save pointer to node in array */
+ cur = cur->next;
+ }
+
+ return dnp;
+}
+
+
+static int list_single(const struct dnode *dn)
+{
+ int i, column = 0;
+
+#if ENABLE_FEATURE_LS_TIMESTAMPS
+ char *filetime;
+ time_t ttime, age;
+#endif
+#if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR
+ struct stat info;
+ char append;
+#endif
+
+ if (dn->fullname == NULL)
+ return 0;
+
+#if ENABLE_FEATURE_LS_TIMESTAMPS
+ ttime = dn->dstat.st_mtime; /* the default time */
+ if (all_fmt & TIME_ACCESS)
+ ttime = dn->dstat.st_atime;
+ if (all_fmt & TIME_CHANGE)
+ ttime = dn->dstat.st_ctime;
+ filetime = ctime(&ttime);
+#endif
+#if ENABLE_FEATURE_LS_FILETYPES
+ append = append_char(dn->dstat.st_mode);
+#endif
+
+ for (i = 0; i <= 31; i++) {
+ switch (all_fmt & (1 << i)) {
+ case LIST_INO:
+ column += printf("%7ld ", (long) dn->dstat.st_ino);
+ break;
+ case LIST_BLOCKS:
+ column += printf("%4"OFF_FMT"d ", (off_t) dn->dstat.st_blocks >> 1);
+ break;
+ case LIST_MODEBITS:
+ column += printf("%-10s ", (char *) bb_mode_string(dn->dstat.st_mode));
+ break;
+ case LIST_NLINKS:
+ column += printf("%4ld ", (long) dn->dstat.st_nlink);
+ break;
+ case LIST_ID_NAME:
+#if ENABLE_FEATURE_LS_USERNAME
+ printf("%-8.8s %-8.8s",
+ get_cached_username(dn->dstat.st_uid),
+ get_cached_groupname(dn->dstat.st_gid));
+ column += 17;
+ break;
+#endif
+ case LIST_ID_NUMERIC:
+ column += printf("%-8d %-8d", dn->dstat.st_uid, dn->dstat.st_gid);
+ break;
+ case LIST_SIZE:
+ case LIST_DEV:
+ if (S_ISBLK(dn->dstat.st_mode) || S_ISCHR(dn->dstat.st_mode)) {
+ column += printf("%4d, %3d ", (int) major(dn->dstat.st_rdev),
+ (int) minor(dn->dstat.st_rdev));
+ } else {
+ if (all_fmt & LS_DISP_HR) {
+ column += printf("%9s ",
+ make_human_readable_str(dn->dstat.st_size, 1, 0));
+ } else {
+ column += printf("%9"OFF_FMT"d ", (off_t) dn->dstat.st_size);
+ }
+ }
+ break;
+#if ENABLE_FEATURE_LS_TIMESTAMPS
+ case LIST_FULLTIME:
+ printf("%24.24s ", filetime);
+ column += 25;
+ break;
+ case LIST_DATE_TIME:
+ if ((all_fmt & LIST_FULLTIME) == 0) {
+ /* current_time_t ~== time(NULL) */
+ age = current_time_t - ttime;
+ printf("%6.6s ", filetime + 4);
+ if (age < 3600L * 24 * 365 / 2 && age > -15 * 60) {
+ /* hh:mm if less than 6 months old */
+ printf("%5.5s ", filetime + 11);
+ } else {
+ printf(" %4.4s ", filetime + 20);
+ }
+ column += 13;
+ }
+ break;
+#endif
+#if ENABLE_SELINUX
+ case LIST_CONTEXT:
+ {
+ char context[80];
+ int len = 0;
+
+ if (dn->sid) {
+ /* I assume sid initilized with NULL */
+ len = strlen(dn->sid) + 1;
+ safe_strncpy(context, dn->sid, len);
+ freecon(dn->sid);
+ } else {
+ safe_strncpy(context, "unknown", 8);
+ }
+ printf("%-32s ", context);
+ column += MAX(33, len);
+ }
+ break;
+#endif
+ case LIST_FILENAME:
+ errno = 0;
+#if ENABLE_FEATURE_LS_COLOR
+ if (show_color && !lstat(dn->fullname, &info)) {
+ printf("\033[%d;%dm", bgcolor(info.st_mode),
+ fgcolor(info.st_mode));
+ }
+#endif
+#if ENABLE_FEATURE_ASSUME_UNICODE
+ printf("%s", dn->name);
+ column += mbstrlen(dn->name);
+#else
+ column += printf("%s", dn->name);
+#endif
+ if (show_color) {
+ printf("\033[0m");
+ }
+ break;
+ case LIST_SYMLINK:
+ if (S_ISLNK(dn->dstat.st_mode)) {
+ char *lpath = xmalloc_readlink_or_warn(dn->fullname);
+ if (!lpath) break;
+ printf(" -> ");
+#if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR
+ if (!stat(dn->fullname, &info)) {
+ append = append_char(info.st_mode);
+ }
+#endif
+#if ENABLE_FEATURE_LS_COLOR
+ if (show_color) {
+ errno = 0;
+ printf("\033[%d;%dm", bgcolor(info.st_mode),
+ fgcolor(info.st_mode));
+ }
+#endif
+ column += printf("%s", lpath) + 4;
+ if (show_color) {
+ printf("\033[0m");
+ }
+ free(lpath);
+ }
+ break;
+#if ENABLE_FEATURE_LS_FILETYPES
+ case LIST_FILETYPE:
+ if (append) {
+ putchar(append);
+ column++;
+ }
+ break;
+#endif
+ }
+ }
+
+ return column;
+}
+
+
+/* "[-]Cadil1", POSIX mandated options, busybox always supports */
+/* "[-]gnsx", POSIX non-mandated options, busybox always supports */
+/* "[-]Ak" GNU options, busybox always supports */
+/* "[-]FLRctur", POSIX mandated options, busybox optionally supports */
+/* "[-]p", POSIX non-mandated options, busybox optionally supports */
+/* "[-]SXvThw", GNU options, busybox optionally supports */
+/* "[-]K", SELinux mandated options, busybox optionally supports */
+/* "[-]e", I think we made this one up */
+static const char ls_options[] ALIGN1 =
+ "Cadil1gnsxAk"
+ USE_FEATURE_LS_TIMESTAMPS("cetu")
+ USE_FEATURE_LS_SORTFILES("SXrv")
+ USE_FEATURE_LS_FILETYPES("Fp")
+ USE_FEATURE_LS_FOLLOWLINKS("L")
+ USE_FEATURE_LS_RECURSIVE("R")
+ USE_FEATURE_HUMAN_READABLE("h")
+ USE_SELINUX("K")
+ USE_FEATURE_AUTOWIDTH("T:w:")
+ USE_SELINUX("Z");
+
+enum {
+ LIST_MASK_TRIGGER = 0,
+ STYLE_MASK_TRIGGER = STYLE_MASK,
+ DISP_MASK_TRIGGER = DISP_ROWS,
+ SORT_MASK_TRIGGER = SORT_MASK,
+};
+
+static const unsigned opt_flags[] = {
+ LIST_SHORT | STYLE_COLUMNS, /* C */
+ DISP_HIDDEN | DISP_DOT, /* a */
+ DISP_NOLIST, /* d */
+ LIST_INO, /* i */
+ LIST_LONG | STYLE_LONG, /* l - remember LS_DISP_HR in mask! */
+ LIST_SHORT | STYLE_SINGLE, /* 1 */
+ 0, /* g - ingored */
+ LIST_ID_NUMERIC, /* n */
+ LIST_BLOCKS, /* s */
+ DISP_ROWS, /* x */
+ DISP_HIDDEN, /* A */
+ ENABLE_SELINUX * LIST_CONTEXT, /* k (ignored if !SELINUX) */
+#if ENABLE_FEATURE_LS_TIMESTAMPS
+ TIME_CHANGE | (ENABLE_FEATURE_LS_SORTFILES * SORT_CTIME), /* c */
+ LIST_FULLTIME, /* e */
+ ENABLE_FEATURE_LS_SORTFILES * SORT_MTIME, /* t */
+ TIME_ACCESS | (ENABLE_FEATURE_LS_SORTFILES * SORT_ATIME), /* u */
+#endif
+#if ENABLE_FEATURE_LS_SORTFILES
+ SORT_SIZE, /* S */
+ SORT_EXT, /* X */
+ SORT_REVERSE, /* r */
+ SORT_VERSION, /* v */
+#endif
+#if ENABLE_FEATURE_LS_FILETYPES
+ LIST_FILETYPE | LIST_EXEC, /* F */
+ LIST_FILETYPE, /* p */
+#endif
+#if ENABLE_FEATURE_LS_FOLLOWLINKS
+ FOLLOW_LINKS, /* L */
+#endif
+#if ENABLE_FEATURE_LS_RECURSIVE
+ DISP_RECURSIVE, /* R */
+#endif
+#if ENABLE_FEATURE_HUMAN_READABLE
+ LS_DISP_HR, /* h */
+#endif
+#if ENABLE_SELINUX
+ LIST_MODEBITS|LIST_NLINKS|LIST_CONTEXT|LIST_SIZE|LIST_DATE_TIME, /* K */
+#endif
+#if ENABLE_FEATURE_AUTOWIDTH
+ 0, 0, /* T, w - ignored */
+#endif
+#if ENABLE_SELINUX
+ LIST_MODEBITS|LIST_ID_NAME|LIST_CONTEXT, /* Z */
+#endif
+ (1U<<31)
+};
+
+
+/* colored LS support by JaWi, janwillem.janssen@lxtreme.nl */
+#if ENABLE_FEATURE_LS_COLOR
+/* long option entry used only for --color, which has no short option
+ * equivalent */
+static const char ls_color_opt[] ALIGN1 =
+ "color\0" Optional_argument "\xff" /* no short equivalent */
+ ;
+#endif
+
+
+int ls_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int ls_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ struct dnode **dnd;
+ struct dnode **dnf;
+ struct dnode **dnp;
+ struct dnode *dn;
+ struct dnode *cur;
+ unsigned opt;
+ int nfiles;
+ int dnfiles;
+ int dndirs;
+ int i;
+ USE_FEATURE_LS_COLOR(char *color_opt;)
+
+ INIT_G();
+
+ all_fmt = LIST_SHORT |
+ (ENABLE_FEATURE_LS_SORTFILES * (SORT_NAME | SORT_FORWARD));
+
+#if ENABLE_FEATURE_AUTOWIDTH
+ /* Obtain the terminal width */
+ get_terminal_width_height(STDIN_FILENO, &terminal_width, NULL);
+ /* Go one less... */
+ terminal_width--;
+#endif
+
+ /* process options */
+ USE_FEATURE_LS_COLOR(applet_long_options = ls_color_opt;)
+#if ENABLE_FEATURE_AUTOWIDTH
+ opt_complementary = "T+:w+"; /* -T N, -w N */
+ opt = getopt32(argv, ls_options, &tabstops, &terminal_width
+ USE_FEATURE_LS_COLOR(, &color_opt));
+#else
+ opt = getopt32(argv, ls_options USE_FEATURE_LS_COLOR(, &color_opt));
+#endif
+ for (i = 0; opt_flags[i] != (1U<<31); i++) {
+ if (opt & (1 << i)) {
+ unsigned flags = opt_flags[i];
+
+ if (flags & LIST_MASK_TRIGGER)
+ all_fmt &= ~LIST_MASK;
+ if (flags & STYLE_MASK_TRIGGER)
+ all_fmt &= ~STYLE_MASK;
+ if (flags & SORT_MASK_TRIGGER)
+ all_fmt &= ~SORT_MASK;
+ if (flags & DISP_MASK_TRIGGER)
+ all_fmt &= ~DISP_MASK;
+ if (flags & TIME_MASK)
+ all_fmt &= ~TIME_MASK;
+ if (flags & LIST_CONTEXT)
+ all_fmt |= STYLE_SINGLE;
+ /* huh?? opt cannot be 'l' */
+ //if (LS_DISP_HR && opt == 'l')
+ // all_fmt &= ~LS_DISP_HR;
+ all_fmt |= flags;
+ }
+ }
+
+#if ENABLE_FEATURE_LS_COLOR
+ /* find color bit value - last position for short getopt */
+ if (ENABLE_FEATURE_LS_COLOR_IS_DEFAULT && isatty(STDOUT_FILENO)) {
+ char *p = getenv("LS_COLORS");
+ /* LS_COLORS is unset, or (not empty && not "none") ? */
+ if (!p || (p[0] && strcmp(p, "none")))
+ show_color = 1;
+ }
+ if (opt & (1 << i)) { /* next flag after short options */
+ if (!color_opt || !strcmp("always", color_opt))
+ show_color = 1;
+ else if (color_opt && !strcmp("never", color_opt))
+ show_color = 0;
+ else if (color_opt && !strcmp("auto", color_opt) && isatty(STDOUT_FILENO))
+ show_color = 1;
+ }
+#endif
+
+ /* sort out which command line options take precedence */
+ if (ENABLE_FEATURE_LS_RECURSIVE && (all_fmt & DISP_NOLIST))
+ all_fmt &= ~DISP_RECURSIVE; /* no recurse if listing only dir */
+ if (ENABLE_FEATURE_LS_TIMESTAMPS && ENABLE_FEATURE_LS_SORTFILES) {
+ if (all_fmt & TIME_CHANGE)
+ all_fmt = (all_fmt & ~SORT_MASK) | SORT_CTIME;
+ if (all_fmt & TIME_ACCESS)
+ all_fmt = (all_fmt & ~SORT_MASK) | SORT_ATIME;
+ }
+ if ((all_fmt & STYLE_MASK) != STYLE_LONG) /* only for long list */
+ all_fmt &= ~(LIST_ID_NUMERIC|LIST_FULLTIME|LIST_ID_NAME|LIST_ID_NUMERIC);
+ if (ENABLE_FEATURE_LS_USERNAME)
+ if ((all_fmt & STYLE_MASK) == STYLE_LONG && (all_fmt & LIST_ID_NUMERIC))
+ all_fmt &= ~LIST_ID_NAME; /* don't list names if numeric uid */
+
+ /* choose a display format */
+ if (!(all_fmt & STYLE_MASK))
+ all_fmt |= (isatty(STDOUT_FILENO) ? STYLE_COLUMNS : STYLE_SINGLE);
+
+ argv += optind;
+ if (!argv[0])
+ *--argv = (char*)".";
+
+ if (argv[1])
+ all_fmt |= DISP_DIRNAME; /* 2 or more items? label directories */
+
+ /* stuff the command line file names into a dnode array */
+ dn = NULL;
+ nfiles = 0;
+ do {
+ /* ls w/o -l follows links on command line */
+ cur = my_stat(*argv, *argv, !(all_fmt & STYLE_LONG));
+ argv++;
+ if (!cur)
+ continue;
+ cur->allocated = 0;
+ cur->next = dn;
+ dn = cur;
+ nfiles++;
+ } while (*argv);
+
+ /* now that we know how many files there are
+ * allocate memory for an array to hold dnode pointers
+ */
+ dnp = dnalloc(nfiles);
+ for (i = 0, cur = dn; i < nfiles; i++) {
+ dnp[i] = cur; /* save pointer to node in array */
+ cur = cur->next;
+ }
+
+ if (all_fmt & DISP_NOLIST) {
+ dnsort(dnp, nfiles);
+ if (nfiles > 0)
+ showfiles(dnp, nfiles);
+ } else {
+ dnd = splitdnarray(dnp, nfiles, SPLIT_DIR);
+ dnf = splitdnarray(dnp, nfiles, SPLIT_FILE);
+ dndirs = countdirs(dnp, nfiles);
+ dnfiles = nfiles - dndirs;
+ if (dnfiles > 0) {
+ dnsort(dnf, dnfiles);
+ showfiles(dnf, dnfiles);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(dnf);
+ }
+ if (dndirs > 0) {
+ dnsort(dnd, dndirs);
+ showdirs(dnd, dndirs, dnfiles == 0);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(dnd);
+ }
+ }
+ if (ENABLE_FEATURE_CLEAN_UP)
+ dfree(dnp, nfiles);
+ return exit_code;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/md5_sha1_sum.c b/cleopatre/busybox-1.11.1-spc300/coreutils/md5_sha1_sum.c
new file mode 100644
index 0000000000..c816194930
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/md5_sha1_sum.c
@@ -0,0 +1,175 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2003 Glenn L. McGrath
+ * Copyright (C) 2003-2004 Erik Andersen
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+
+typedef enum { HASH_SHA1, HASH_MD5 } hash_algo_t;
+
+#define FLAG_SILENT 1
+#define FLAG_CHECK 2
+#define FLAG_WARN 4
+
+/* This might be useful elsewhere */
+static unsigned char *hash_bin_to_hex(unsigned char *hash_value,
+ unsigned hash_length)
+{
+ /* xzalloc zero-terminates */
+ char *hex_value = xzalloc((hash_length * 2) + 1);
+ bin2hex(hex_value, (char*)hash_value, hash_length);
+ return (unsigned char *)hex_value;
+}
+
+static uint8_t *hash_file(const char *filename, hash_algo_t hash_algo)
+{
+ int src_fd, hash_len, count;
+ union _ctx_ {
+ sha1_ctx_t sha1;
+ md5_ctx_t md5;
+ } context;
+ uint8_t *hash_value = NULL;
+ RESERVE_CONFIG_UBUFFER(in_buf, 4096);
+ void (*update)(const void*, size_t, void*);
+ void (*final)(void*, void*);
+
+ src_fd = open_or_warn_stdin(filename);
+ if (src_fd < 0) {
+ return NULL;
+ }
+
+ /* figure specific hash algorithims */
+ if (ENABLE_MD5SUM && hash_algo==HASH_MD5) {
+ md5_begin(&context.md5);
+ update = (void (*)(const void*, size_t, void*))md5_hash;
+ final = (void (*)(void*, void*))md5_end;
+ hash_len = 16;
+ } else if (ENABLE_SHA1SUM && hash_algo==HASH_SHA1) {
+ sha1_begin(&context.sha1);
+ update = (void (*)(const void*, size_t, void*))sha1_hash;
+ final = (void (*)(void*, void*))sha1_end;
+ hash_len = 20;
+ } else {
+ bb_error_msg_and_die("algorithm not supported");
+ }
+
+ while (0 < (count = safe_read(src_fd, in_buf, 4096))) {
+ update(in_buf, count, &context);
+ }
+
+ if (count == 0) {
+ final(in_buf, &context);
+ hash_value = hash_bin_to_hex(in_buf, hash_len);
+ }
+
+ RELEASE_CONFIG_BUFFER(in_buf);
+
+ if (src_fd != STDIN_FILENO) {
+ close(src_fd);
+ }
+
+ return hash_value;
+}
+
+int md5_sha1_sum_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int md5_sha1_sum_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ int return_value = EXIT_SUCCESS;
+ uint8_t *hash_value;
+ unsigned flags;
+ hash_algo_t hash_algo = ENABLE_MD5SUM
+ ? (ENABLE_SHA1SUM ? (applet_name[0] == 'm' ? HASH_MD5 : HASH_SHA1) : HASH_MD5)
+ : HASH_SHA1;
+
+ if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK)
+ flags = getopt32(argv, "scw");
+ else optind = 1;
+ argv += optind;
+ //argc -= optind;
+ if (!*argv)
+ *--argv = (char*)"-";
+
+ if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK && !(flags & FLAG_CHECK)) {
+ if (flags & FLAG_SILENT) {
+ bb_error_msg_and_die
+ ("-%c is meaningful only when verifying checksums", 's');
+ } else if (flags & FLAG_WARN) {
+ bb_error_msg_and_die
+ ("-%c is meaningful only when verifying checksums", 'w');
+ }
+ }
+
+ if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK && (flags & FLAG_CHECK)) {
+ FILE *pre_computed_stream;
+ int count_total = 0;
+ int count_failed = 0;
+ char *line;
+
+ if (argv[1]) {
+ bb_error_msg_and_die
+ ("only one argument may be specified when using -c");
+ }
+
+ pre_computed_stream = xfopen_stdin(argv[0]);
+
+ while ((line = xmalloc_fgetline(pre_computed_stream)) != NULL) {
+ char *filename_ptr;
+
+ count_total++;
+ filename_ptr = strstr(line, " ");
+ /* handle format for binary checksums */
+ if (filename_ptr == NULL) {
+ filename_ptr = strstr(line, " *");
+ }
+ if (filename_ptr == NULL) {
+ if (flags & FLAG_WARN) {
+ bb_error_msg("invalid format");
+ }
+ count_failed++;
+ return_value = EXIT_FAILURE;
+ free(line);
+ continue;
+ }
+ *filename_ptr = '\0';
+ filename_ptr += 2;
+
+ hash_value = hash_file(filename_ptr, hash_algo);
+
+ if (hash_value && (strcmp((char*)hash_value, line) == 0)) {
+ if (!(flags & FLAG_SILENT))
+ printf("%s: OK\n", filename_ptr);
+ } else {
+ if (!(flags & FLAG_SILENT))
+ printf("%s: FAILED\n", filename_ptr);
+ count_failed++;
+ return_value = EXIT_FAILURE;
+ }
+ /* possible free(NULL) */
+ free(hash_value);
+ free(line);
+ }
+ if (count_failed && !(flags & FLAG_SILENT)) {
+ bb_error_msg("WARNING: %d of %d computed checksums did NOT match",
+ count_failed, count_total);
+ }
+ /*
+ if (fclose_if_not_stdin(pre_computed_stream) == EOF) {
+ bb_perror_msg_and_die("cannot close file %s", file_ptr);
+ }
+ */
+ } else {
+ do {
+ hash_value = hash_file(*argv, hash_algo);
+ if (hash_value == NULL) {
+ return_value = EXIT_FAILURE;
+ } else {
+ printf("%s %s\n", hash_value, *argv);
+ free(hash_value);
+ }
+ } while (*++argv);
+ }
+ return return_value;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/mkdir.c b/cleopatre/busybox-1.11.1-spc300/coreutils/mkdir.c
new file mode 100644
index 0000000000..72bd10581c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/mkdir.c
@@ -0,0 +1,80 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini mkdir implementation for busybox
+ *
+ * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 compliant */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/mkdir.html */
+
+/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
+ *
+ * Fixed broken permission setting when -p was used; especially in
+ * conjunction with -m.
+ */
+
+/* Nov 28, 2006 Yoshinori Sato <ysato@users.sourceforge.jp>: Add SELinux Support.
+ */
+
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
+
+#if ENABLE_FEATURE_MKDIR_LONG_OPTIONS
+static const char mkdir_longopts[] ALIGN1 =
+ "mode\0" Required_argument "m"
+ "parents\0" No_argument "p"
+#if ENABLE_SELINUX
+ "context\0" Required_argument "Z"
+#endif
+ ;
+#endif
+
+int mkdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int mkdir_main(int argc, char **argv)
+{
+ mode_t mode = (mode_t)(-1);
+ int status = EXIT_SUCCESS;
+ int flags = 0;
+ unsigned opt;
+ char *smode;
+#if ENABLE_SELINUX
+ security_context_t scontext;
+#endif
+
+#if ENABLE_FEATURE_MKDIR_LONG_OPTIONS
+ applet_long_options = mkdir_longopts;
+#endif
+ opt = getopt32(argv, "m:p" USE_SELINUX("Z:"), &smode USE_SELINUX(,&scontext));
+ if (opt & 1) {
+ mode = 0777;
+ if (!bb_parse_mode(smode, &mode)) {
+ bb_error_msg_and_die("invalid mode '%s'", smode);
+ }
+ }
+ if (opt & 2)
+ flags |= FILEUTILS_RECUR;
+#if ENABLE_SELINUX
+ if (opt & 4) {
+ selinux_or_die();
+ setfscreatecon_or_die(scontext);
+ }
+#endif
+
+ if (optind == argc) {
+ bb_show_usage();
+ }
+
+ argv += optind;
+
+ do {
+ if (bb_make_directory(*argv, mode, flags)) {
+ status = EXIT_FAILURE;
+ }
+ } while (*++argv);
+
+ return status;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/mkfifo.c b/cleopatre/busybox-1.11.1-spc300/coreutils/mkfifo.c
new file mode 100644
index 0000000000..d9261b96af
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/mkfifo.c
@@ -0,0 +1,37 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * mkfifo implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 compliant */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/mkfifo.html */
+
+#include "libbb.h"
+#include "libcoreutils/coreutils.h"
+
+int mkfifo_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int mkfifo_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ mode_t mode;
+ int retval = EXIT_SUCCESS;
+
+ mode = getopt_mk_fifo_nod(argv);
+
+ argv += optind;
+ if (!*argv) {
+ bb_show_usage();
+ }
+
+ do {
+ if (mkfifo(*argv, mode) < 0) {
+ bb_simple_perror_msg(*argv); /* Avoid multibyte problems. */
+ retval = EXIT_FAILURE;
+ }
+ } while (*++argv);
+
+ return retval;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/mknod.c b/cleopatre/busybox-1.11.1-spc300/coreutils/mknod.c
new file mode 100644
index 0000000000..0c694948e7
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/mknod.c
@@ -0,0 +1,57 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * mknod implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */
+
+#include <sys/sysmacros.h> // For makedev
+
+#include "libbb.h"
+#include "libcoreutils/coreutils.h"
+
+static const char modes_chars[] ALIGN1 = { 'p', 'c', 'u', 'b', 0, 1, 1, 2 };
+static const mode_t modes_cubp[] = { S_IFIFO, S_IFCHR, S_IFBLK };
+
+int mknod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int mknod_main(int argc, char **argv)
+{
+ mode_t mode;
+ dev_t dev;
+ const char *name;
+
+ mode = getopt_mk_fifo_nod(argv);
+ argv += optind;
+ argc -= optind;
+
+ if (argc >= 2) {
+ name = strchr(modes_chars, argv[1][0]);
+ if (name != NULL) {
+ mode |= modes_cubp[(int)(name[4])];
+
+ dev = 0;
+ if (*name != 'p') {
+ argc -= 2;
+ if (argc == 2) {
+ /* Autodetect what the system supports; these macros should
+ * optimize out to two constants. */
+ dev = makedev(xatoul_range(argv[2], 0, major(UINT_MAX)),
+ xatoul_range(argv[3], 0, minor(UINT_MAX)));
+ }
+ }
+
+ if (argc == 2) {
+ name = *argv;
+ if (mknod(name, mode, dev) == 0) {
+ return EXIT_SUCCESS;
+ }
+ bb_simple_perror_msg_and_die(name);
+ }
+ }
+ }
+ bb_show_usage();
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/mv.c b/cleopatre/busybox-1.11.1-spc300/coreutils/mv.c
new file mode 100644
index 0000000000..5611ecd012
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/mv.c
@@ -0,0 +1,135 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini mv implementation for busybox
+ *
+ * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ * SELinux support by Yuichi Nakamura <ynakam@hitachisoft.jp>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
+ *
+ * Size reduction and improved error checking.
+ */
+
+#include "libbb.h"
+#include "libcoreutils/coreutils.h"
+
+#if ENABLE_FEATURE_MV_LONG_OPTIONS
+static const char mv_longopts[] ALIGN1 =
+ "interactive\0" No_argument "i"
+ "force\0" No_argument "f"
+ ;
+#endif
+
+#define OPT_FILEUTILS_FORCE 1
+#define OPT_FILEUTILS_INTERACTIVE 2
+
+static const char fmt[] ALIGN1 =
+ "cannot overwrite %sdirectory with %sdirectory";
+
+int mv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int mv_main(int argc, char **argv)
+{
+ struct stat dest_stat;
+ const char *last;
+ const char *dest;
+ unsigned long flags;
+ int dest_exists;
+ int status = 0;
+ int copy_flag = 0;
+
+#if ENABLE_FEATURE_MV_LONG_OPTIONS
+ applet_long_options = mv_longopts;
+#endif
+ // Need at least two arguments
+ // -f unsets -i, -i unsets -f
+ opt_complementary = "-2:f-i:i-f";
+ flags = getopt32(argv, "fi");
+ argc -= optind;
+ argv += optind;
+ last = argv[argc - 1];
+
+ if (argc == 2) {
+ dest_exists = cp_mv_stat(last, &dest_stat);
+ if (dest_exists < 0) {
+ return EXIT_FAILURE;
+ }
+
+ if (!(dest_exists & 2)) {
+ dest = last;
+ goto DO_MOVE;
+ }
+ }
+
+ do {
+ dest = concat_path_file(last, bb_get_last_path_component_strip(*argv));
+ dest_exists = cp_mv_stat(dest, &dest_stat);
+ if (dest_exists < 0) {
+ goto RET_1;
+ }
+
+ DO_MOVE:
+ if (dest_exists
+ && !(flags & OPT_FILEUTILS_FORCE)
+ && ((access(dest, W_OK) < 0 && isatty(0))
+ || (flags & OPT_FILEUTILS_INTERACTIVE))
+ ) {
+ if (fprintf(stderr, "mv: overwrite '%s'? ", dest) < 0) {
+ goto RET_1; /* Ouch! fprintf failed! */
+ }
+ if (!bb_ask_confirmation()) {
+ goto RET_0;
+ }
+ }
+ if (rename(*argv, dest) < 0) {
+ struct stat source_stat;
+ int source_exists;
+
+ if (errno != EXDEV
+ || (source_exists = cp_mv_stat(*argv, &source_stat)) < 1
+ ) {
+ bb_perror_msg("cannot rename '%s'", *argv);
+ } else {
+ if (dest_exists) {
+ if (dest_exists == 3) {
+ if (source_exists != 3) {
+ bb_error_msg(fmt, "", "non-");
+ goto RET_1;
+ }
+ } else {
+ if (source_exists == 3) {
+ bb_error_msg(fmt, "non-", "");
+ goto RET_1;
+ }
+ }
+ if (unlink(dest) < 0) {
+ bb_perror_msg("cannot remove '%s'", dest);
+ goto RET_1;
+ }
+ }
+ /* FILEUTILS_RECUR also prevents nasties like
+ * "read from device and write contents to dst"
+ * instead of "create same device node" */
+ copy_flag = FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS;
+#if ENABLE_SELINUX
+ copy_flag |= FILEUTILS_PRESERVE_SECURITY_CONTEXT;
+#endif
+ if ((copy_file(*argv, dest, copy_flag) >= 0)
+ && (remove_file(*argv, FILEUTILS_RECUR | FILEUTILS_FORCE) >= 0)
+ ) {
+ goto RET_0;
+ }
+ }
+ RET_1:
+ status = 1;
+ }
+ RET_0:
+ if (dest != last) {
+ free((void *) dest);
+ }
+ } while (*++argv != last);
+
+ return status;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/nice.c b/cleopatre/busybox-1.11.1-spc300/coreutils/nice.c
new file mode 100644
index 0000000000..d24a95b45f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/nice.c
@@ -0,0 +1,55 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * nice implementation for busybox
+ *
+ * Copyright (C) 2005 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include <sys/resource.h>
+#include "libbb.h"
+
+int nice_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int nice_main(int argc, char **argv)
+{
+ int old_priority, adjustment;
+
+ old_priority = getpriority(PRIO_PROCESS, 0);
+
+ if (!*++argv) { /* No args, so (GNU) output current nice value. */
+ printf("%d\n", old_priority);
+ fflush_stdout_and_exit(EXIT_SUCCESS);
+ }
+
+ adjustment = 10; /* Set default adjustment. */
+
+ if (argv[0][0] == '-') {
+ if (argv[0][1] == 'n') { /* -n */
+ if (argv[0][2]) { /* -nNNNN (w/o space) */
+ argv[0] += 2; argv--; argc++;
+ }
+ } else { /* -NNN (NNN may be negative) == -n NNN */
+ argv[0] += 1; argv--; argc++;
+ }
+ if (argc < 4) { /* Missing priority and/or utility! */
+ bb_show_usage();
+ }
+ adjustment = xatoi_range(argv[1], INT_MIN/2, INT_MAX/2);
+ argv += 2;
+ }
+
+ { /* Set our priority. */
+ int prio = old_priority + adjustment;
+
+ if (setpriority(PRIO_PROCESS, 0, prio) < 0) {
+ bb_perror_msg_and_die("setpriority(%d)", prio);
+ }
+ }
+
+ BB_EXECVP(*argv, argv); /* Now exec the desired program. */
+
+ /* The exec failed... */
+ xfunc_error_retval = (errno == ENOENT) ? 127 : 126; /* SUSv3 */
+ bb_simple_perror_msg_and_die(*argv);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/nohup.c b/cleopatre/busybox-1.11.1-spc300/coreutils/nohup.c
new file mode 100644
index 0000000000..7d6a51ae9d
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/nohup.c
@@ -0,0 +1,78 @@
+/* vi: set sw=4 ts=4: */
+/* nohup - invoke a utility immune to hangups.
+ *
+ * Busybox version based on nohup specification at
+ * http://www.opengroup.org/onlinepubs/007904975/utilities/nohup.html
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ * Copyright 2006 Bernhard Fischer
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* Compat info: nohup (GNU coreutils 6.8) does this:
+# nohup true
+nohup: ignoring input and appending output to `nohup.out'
+# nohup true 1>/dev/null
+nohup: ignoring input and redirecting stderr to stdout
+# nohup true 2>zz
+# cat zz
+nohup: ignoring input and appending output to `nohup.out'
+# nohup true 2>zz 1>/dev/null
+# cat zz
+nohup: ignoring input
+# nohup true </dev/null 1>/dev/null
+nohup: redirecting stderr to stdout
+# nohup true </dev/null 2>zz 1>/dev/null
+# cat zz
+ (nothing)
+#
+*/
+
+int nohup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int nohup_main(int argc, char **argv)
+{
+ const char *nohupout;
+ char *home;
+
+ xfunc_error_retval = 127;
+
+ if (argc < 2) bb_show_usage();
+
+ /* If stdin is a tty, detach from it. */
+ if (isatty(STDIN_FILENO)) {
+ /* bb_error_msg("ignoring input"); */
+ close(STDIN_FILENO);
+ xopen(bb_dev_null, O_RDONLY); /* will be fd 0 (STDIN_FILENO) */
+ }
+
+ nohupout = "nohup.out";
+ /* Redirect stdout to nohup.out, either in "." or in "$HOME". */
+ if (isatty(STDOUT_FILENO)) {
+ close(STDOUT_FILENO);
+ if (open(nohupout, O_CREAT|O_WRONLY|O_APPEND, S_IRUSR|S_IWUSR) < 0) {
+ home = getenv("HOME");
+ if (home) {
+ nohupout = concat_path_file(home, nohupout);
+ xopen3(nohupout, O_CREAT|O_WRONLY|O_APPEND, S_IRUSR|S_IWUSR);
+ } else {
+ xopen(bb_dev_null, O_RDONLY); /* will be fd 1 */
+ }
+ }
+ bb_error_msg("appending output to %s", nohupout);
+ }
+
+ /* If we have a tty on stderr, redirect to stdout. */
+ if (isatty(STDERR_FILENO)) {
+ /* if (stdout_wasnt_a_tty)
+ bb_error_msg("redirecting stderr to stdout"); */
+ dup2(STDOUT_FILENO, STDERR_FILENO);
+ }
+
+ signal(SIGHUP, SIG_IGN);
+
+ BB_EXECVP(argv[1], argv+1);
+ bb_simple_perror_msg_and_die(argv[1]);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/od.c b/cleopatre/busybox-1.11.1-spc300/coreutils/od.c
new file mode 100644
index 0000000000..94a6b95df5
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/od.c
@@ -0,0 +1,224 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * od implementation for busybox
+ * Based on code from util-linux v 2.11l
+ *
+ * Copyright (c) 1990
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ * Original copyright notice is retained at the end of this file.
+ */
+
+
+#include "libbb.h"
+#if ENABLE_DESKTOP
+/* This one provides -t (busybox's own build script needs it) */
+#include "od_bloaty.c"
+#else
+
+#include "dump.h"
+
+#define isdecdigit(c) isdigit(c)
+#define ishexdigit(c) (isxdigit)(c)
+
+static void
+odoffset(int argc, char ***argvp)
+{
+ char *num, *p;
+ int base;
+ char *end;
+
+ /*
+ * The offset syntax of od(1) was genuinely bizarre. First, if
+ * it started with a plus it had to be an offset. Otherwise, if
+ * there were at least two arguments, a number or lower-case 'x'
+ * followed by a number makes it an offset. By default it was
+ * octal; if it started with 'x' or '0x' it was hex. If it ended
+ * in a '.', it was decimal. If a 'b' or 'B' was appended, it
+ * multiplied the number by 512 or 1024 byte units. There was
+ * no way to assign a block count to a hex offset.
+ *
+ * We assumes it's a file if the offset is bad.
+ */
+ p = **argvp;
+
+ if (!p) {
+ /* hey someone is probably piping to us ... */
+ return;
+ }
+
+ if ((*p != '+')
+ && (argc < 2
+ || (!isdecdigit(p[0])
+ && ((p[0] != 'x') || !ishexdigit(p[1])))))
+ return;
+
+ base = 0;
+ /*
+ * bb_dump_skip over leading '+', 'x[0-9a-fA-f]' or '0x', and
+ * set base.
+ */
+ if (p[0] == '+')
+ ++p;
+ if (p[0] == 'x' && ishexdigit(p[1])) {
+ ++p;
+ base = 16;
+ } else if (p[0] == '0' && p[1] == 'x') {
+ p += 2;
+ base = 16;
+ }
+
+ /* bb_dump_skip over the number */
+ if (base == 16)
+ for (num = p; ishexdigit(*p); ++p);
+ else
+ for (num = p; isdecdigit(*p); ++p);
+
+ /* check for no number */
+ if (num == p)
+ return;
+
+ /* if terminates with a '.', base is decimal */
+ if (*p == '.') {
+ if (base)
+ return;
+ base = 10;
+ }
+
+ bb_dump_skip = strtol(num, &end, base ? base : 8);
+
+ /* if end isn't the same as p, we got a non-octal digit */
+ if (end != p)
+ bb_dump_skip = 0;
+ else {
+ if (*p) {
+ if (*p == 'b') {
+ bb_dump_skip *= 512;
+ ++p;
+ } else if (*p == 'B') {
+ bb_dump_skip *= 1024;
+ ++p;
+ }
+ }
+ if (*p)
+ bb_dump_skip = 0;
+ else {
+ ++*argvp;
+ /*
+ * If the offset uses a non-octal base, the base of
+ * the offset is changed as well. This isn't pretty,
+ * but it's easy.
+ */
+#define TYPE_OFFSET 7
+ {
+ char x_or_d;
+ if (base == 16) {
+ x_or_d = 'x';
+ goto DO_X_OR_D;
+ }
+ if (base == 10) {
+ x_or_d = 'd';
+ DO_X_OR_D:
+ bb_dump_fshead->nextfu->fmt[TYPE_OFFSET]
+ = bb_dump_fshead->nextfs->nextfu->fmt[TYPE_OFFSET]
+ = x_or_d;
+ }
+ }
+ }
+ }
+}
+
+static const char *const add_strings[] = {
+ "16/1 \"%3_u \" \"\\n\"", /* a */
+ "8/2 \" %06o \" \"\\n\"", /* B, o */
+ "16/1 \"%03o \" \"\\n\"", /* b */
+ "16/1 \"%3_c \" \"\\n\"", /* c */
+ "8/2 \" %05u \" \"\\n\"", /* d */
+ "4/4 \" %010u \" \"\\n\"", /* D */
+ "2/8 \" %21.14e \" \"\\n\"", /* e (undocumented in od), F */
+ "4/4 \" %14.7e \" \"\\n\"", /* f */
+ "4/4 \" %08x \" \"\\n\"", /* H, X */
+ "8/2 \" %04x \" \"\\n\"", /* h, x */
+ "4/4 \" %11d \" \"\\n\"", /* I, L, l */
+ "8/2 \" %6d \" \"\\n\"", /* i */
+ "4/4 \" %011o \" \"\\n\"", /* O */
+};
+
+static const char od_opts[] ALIGN1 = "aBbcDdeFfHhIiLlOoXxv";
+
+static const char od_o2si[] ALIGN1 = {
+ 0, 1, 2, 3, 5,
+ 4, 6, 6, 7, 8,
+ 9, 0xa, 0xb, 0xa, 0xa,
+ 0xb, 1, 8, 9,
+};
+
+int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int od_main(int argc, char **argv)
+{
+ int ch;
+ int first = 1;
+ char *p;
+ bb_dump_vflag = FIRST;
+ bb_dump_length = -1;
+
+ while ((ch = getopt(argc, argv, od_opts)) > 0) {
+ if (ch == 'v') {
+ bb_dump_vflag = ALL;
+ } else if (((p = strchr(od_opts, ch)) != NULL) && (*p != '\0')) {
+ if (first) {
+ first = 0;
+ bb_dump_add("\"%07.7_Ao\n\"");
+ bb_dump_add("\"%07.7_ao \"");
+ } else {
+ bb_dump_add("\" \"");
+ }
+ bb_dump_add(add_strings[(int)od_o2si[(p-od_opts)]]);
+ } else { /* P, p, s, w, or other unhandled */
+ bb_show_usage();
+ }
+ }
+ if (!bb_dump_fshead) {
+ bb_dump_add("\"%07.7_Ao\n\"");
+ bb_dump_add("\"%07.7_ao \" 8/2 \"%06o \" \"\\n\"");
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ odoffset(argc, &argv);
+
+ return bb_dump_dump(argv);
+}
+#endif /* ENABLE_DESKTOP */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/od_bloaty.c b/cleopatre/busybox-1.11.1-spc300/coreutils/od_bloaty.c
new file mode 100644
index 0000000000..ce963db8af
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/od_bloaty.c
@@ -0,0 +1,1428 @@
+/* od -- dump files in octal and other formats
+ Copyright (C) 92, 1995-2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Jim Meyering. */
+
+/* Busyboxed by Denys Vlasenko
+
+Based on od.c from coreutils-5.2.1
+Top bloat sources:
+
+00000073 t parse_old_offset
+0000007b t get_lcm
+00000090 r long_options
+00000092 t print_named_ascii
+000000bf t print_ascii
+00000168 t write_block
+00000366 t decode_format_string
+00000a71 T od_main
+
+Tested for compat with coreutils 6.3
+using this script. Minor differences fixed.
+
+#!/bin/sh
+echo STD
+time /path/to/coreutils/od \
+...params... \
+>std
+echo Exit code $?
+echo BBOX
+time ./busybox od \
+...params... \
+>bbox
+echo Exit code $?
+diff -u -a std bbox >bbox.diff || { echo Different!; sleep 1; }
+
+*/
+
+#include "libbb.h"
+
+#define assert(a) ((void)0)
+
+/* Check for 0x7f is a coreutils 6.3 addition */
+#define ISPRINT(c) (((c)>=' ') && (c) != 0x7f)
+
+typedef long double longdouble_t;
+typedef unsigned long long ulonglong_t;
+typedef long long llong;
+
+#if ENABLE_LFS
+# define xstrtooff_sfx xstrtoull_sfx
+#else
+# define xstrtooff_sfx xstrtoul_sfx
+#endif
+
+/* The default number of input bytes per output line. */
+#define DEFAULT_BYTES_PER_BLOCK 16
+
+/* The number of decimal digits of precision in a float. */
+#ifndef FLT_DIG
+# define FLT_DIG 7
+#endif
+
+/* The number of decimal digits of precision in a double. */
+#ifndef DBL_DIG
+# define DBL_DIG 15
+#endif
+
+/* The number of decimal digits of precision in a long double. */
+#ifndef LDBL_DIG
+# define LDBL_DIG DBL_DIG
+#endif
+
+enum size_spec {
+ NO_SIZE,
+ CHAR,
+ SHORT,
+ INT,
+ LONG,
+ LONG_LONG,
+ FLOAT_SINGLE,
+ FLOAT_DOUBLE,
+ FLOAT_LONG_DOUBLE,
+ N_SIZE_SPECS
+};
+
+enum output_format {
+ SIGNED_DECIMAL,
+ UNSIGNED_DECIMAL,
+ OCTAL,
+ HEXADECIMAL,
+ FLOATING_POINT,
+ NAMED_CHARACTER,
+ CHARACTER
+};
+
+/* Each output format specification (from '-t spec' or from
+ old-style options) is represented by one of these structures. */
+struct tspec {
+ enum output_format fmt;
+ enum size_spec size;
+ void (*print_function) (size_t, const char *, const char *);
+ char *fmt_string;
+ int hexl_mode_trailer;
+ int field_width;
+};
+
+/* Convert the number of 8-bit bytes of a binary representation to
+ the number of characters (digits + sign if the type is signed)
+ required to represent the same quantity in the specified base/type.
+ For example, a 32-bit (4-byte) quantity may require a field width
+ as wide as the following for these types:
+ 11 unsigned octal
+ 11 signed decimal
+ 10 unsigned decimal
+ 8 unsigned hexadecimal */
+
+static const uint8_t bytes_to_oct_digits[] ALIGN1 =
+{0, 3, 6, 8, 11, 14, 16, 19, 22, 25, 27, 30, 32, 35, 38, 41, 43};
+
+static const uint8_t bytes_to_signed_dec_digits[] ALIGN1 =
+{1, 4, 6, 8, 11, 13, 16, 18, 20, 23, 25, 28, 30, 33, 35, 37, 40};
+
+static const uint8_t bytes_to_unsigned_dec_digits[] ALIGN1 =
+{0, 3, 5, 8, 10, 13, 15, 17, 20, 22, 25, 27, 29, 32, 34, 37, 39};
+
+static const uint8_t bytes_to_hex_digits[] ALIGN1 =
+{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32};
+
+/* Convert enum size_spec to the size of the named type. */
+static const signed char width_bytes[] ALIGN1 = {
+ -1,
+ sizeof(char),
+ sizeof(short),
+ sizeof(int),
+ sizeof(long),
+ sizeof(ulonglong_t),
+ sizeof(float),
+ sizeof(double),
+ sizeof(longdouble_t)
+};
+/* Ensure that for each member of 'enum size_spec' there is an
+ initializer in the width_bytes array. */
+struct ERR_width_bytes_has_bad_size {
+ char ERR_width_bytes_has_bad_size[ARRAY_SIZE(width_bytes) == N_SIZE_SPECS ? 1 : -1];
+};
+
+static smallint flag_dump_strings;
+/* Non-zero if an old-style 'pseudo-address' was specified. */
+static smallint flag_pseudo_start;
+static smallint limit_bytes_to_format;
+/* When zero and two or more consecutive blocks are equal, format
+ only the first block and output an asterisk alone on the following
+ line to indicate that identical blocks have been elided. */
+static smallint verbose;
+static smallint ioerror;
+
+static size_t string_min;
+
+/* An array of specs describing how to format each input block. */
+static size_t n_specs;
+static struct tspec *spec;
+
+/* Function that accepts an address and an optional following char,
+ and prints the address and char to stdout. */
+static void (*format_address)(off_t, char);
+/* The difference between the old-style pseudo starting address and
+ the number of bytes to skip. */
+static off_t pseudo_offset;
+/* When zero, MAX_BYTES_TO_FORMAT and END_OFFSET are ignored, and all
+ input is formatted. */
+
+/* The number of input bytes formatted per output line. It must be
+ a multiple of the least common multiple of the sizes associated with
+ the specified output types. It should be as large as possible, but
+ no larger than 16 -- unless specified with the -w option. */
+static unsigned bytes_per_block = 32; /* have to use unsigned, not size_t */
+
+/* A NULL-terminated list of the file-arguments from the command line. */
+static const char *const *file_list;
+
+/* The input stream associated with the current file. */
+static FILE *in_stream;
+
+#define MAX_INTEGRAL_TYPE_SIZE sizeof(ulonglong_t)
+static const unsigned char integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1] ALIGN1 = {
+ [sizeof(char)] = CHAR,
+#if USHRT_MAX != UCHAR_MAX
+ [sizeof(short)] = SHORT,
+#endif
+#if UINT_MAX != USHRT_MAX
+ [sizeof(int)] = INT,
+#endif
+#if ULONG_MAX != UINT_MAX
+ [sizeof(long)] = LONG,
+#endif
+#if ULLONG_MAX != ULONG_MAX
+ [sizeof(ulonglong_t)] = LONG_LONG,
+#endif
+};
+
+#define MAX_FP_TYPE_SIZE sizeof(longdouble_t)
+static const unsigned char fp_type_size[MAX_FP_TYPE_SIZE + 1] ALIGN1 = {
+ /* gcc seems to allow repeated indexes. Last one stays */
+ [sizeof(longdouble_t)] = FLOAT_LONG_DOUBLE,
+ [sizeof(double)] = FLOAT_DOUBLE,
+ [sizeof(float)] = FLOAT_SINGLE
+};
+
+
+static unsigned
+gcd(unsigned u, unsigned v)
+{
+ unsigned t;
+ while (v != 0) {
+ t = u % v;
+ u = v;
+ v = t;
+ }
+ return u;
+}
+
+/* Compute the least common multiple of U and V. */
+static unsigned
+lcm(unsigned u, unsigned v) {
+ unsigned t = gcd(u, v);
+ if (t == 0)
+ return 0;
+ return u * v / t;
+}
+
+static void
+print_s_char(size_t n_bytes, const char *block, const char *fmt_string)
+{
+ while (n_bytes--) {
+ int tmp = *(signed char *) block;
+ printf(fmt_string, tmp);
+ block += sizeof(unsigned char);
+ }
+}
+
+static void
+print_char(size_t n_bytes, const char *block, const char *fmt_string)
+{
+ while (n_bytes--) {
+ unsigned tmp = *(unsigned char *) block;
+ printf(fmt_string, tmp);
+ block += sizeof(unsigned char);
+ }
+}
+
+static void
+print_s_short(size_t n_bytes, const char *block, const char *fmt_string)
+{
+ n_bytes /= sizeof(signed short);
+ while (n_bytes--) {
+ int tmp = *(signed short *) block;
+ printf(fmt_string, tmp);
+ block += sizeof(unsigned short);
+ }
+}
+
+static void
+print_short(size_t n_bytes, const char *block, const char *fmt_string)
+{
+ n_bytes /= sizeof(unsigned short);
+ while (n_bytes--) {
+ unsigned tmp = *(unsigned short *) block;
+ printf(fmt_string, tmp);
+ block += sizeof(unsigned short);
+ }
+}
+
+static void
+print_int(size_t n_bytes, const char *block, const char *fmt_string)
+{
+ n_bytes /= sizeof(unsigned);
+ while (n_bytes--) {
+ unsigned tmp = *(unsigned *) block;
+ printf(fmt_string, tmp);
+ block += sizeof(unsigned);
+ }
+}
+
+#if UINT_MAX == ULONG_MAX
+# define print_long print_int
+#else
+static void
+print_long(size_t n_bytes, const char *block, const char *fmt_string)
+{
+ n_bytes /= sizeof(unsigned long);
+ while (n_bytes--) {
+ unsigned long tmp = *(unsigned long *) block;
+ printf(fmt_string, tmp);
+ block += sizeof(unsigned long);
+ }
+}
+#endif
+
+#if ULONG_MAX == ULLONG_MAX
+# define print_long_long print_long
+#else
+static void
+print_long_long(size_t n_bytes, const char *block, const char *fmt_string)
+{
+ n_bytes /= sizeof(ulonglong_t);
+ while (n_bytes--) {
+ ulonglong_t tmp = *(ulonglong_t *) block;
+ printf(fmt_string, tmp);
+ block += sizeof(ulonglong_t);
+ }
+}
+#endif
+
+static void
+print_float(size_t n_bytes, const char *block, const char *fmt_string)
+{
+ n_bytes /= sizeof(float);
+ while (n_bytes--) {
+ float tmp = *(float *) block;
+ printf(fmt_string, tmp);
+ block += sizeof(float);
+ }
+}
+
+static void
+print_double(size_t n_bytes, const char *block, const char *fmt_string)
+{
+ n_bytes /= sizeof(double);
+ while (n_bytes--) {
+ double tmp = *(double *) block;
+ printf(fmt_string, tmp);
+ block += sizeof(double);
+ }
+}
+
+static void
+print_long_double(size_t n_bytes, const char *block, const char *fmt_string)
+{
+ n_bytes /= sizeof(longdouble_t);
+ while (n_bytes--) {
+ longdouble_t tmp = *(longdouble_t *) block;
+ printf(fmt_string, tmp);
+ block += sizeof(longdouble_t);
+ }
+}
+
+/* print_[named]_ascii are optimized for speed.
+ * Remember, someday you may want to pump gigabytes through this thing.
+ * Saving a dozen of .text bytes here is counter-productive */
+
+static void
+print_named_ascii(size_t n_bytes, const char *block,
+ const char *unused_fmt_string ATTRIBUTE_UNUSED)
+{
+ /* Names for some non-printing characters. */
+ static const char charname[33][3] ALIGN1 = {
+ "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
+ " bs", " ht", " nl", " vt", " ff", " cr", " so", " si",
+ "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
+ "can", " em", "sub", "esc", " fs", " gs", " rs", " us",
+ " sp"
+ };
+ // buf[N] pos: 01234 56789
+ char buf[12] = " x\0 0xx\0";
+ // actually " x\0 xxx\0", but I want to share the string with below.
+ // [12] because we take three 32bit stack slots anyway, and
+ // gcc is too dumb to initialize with constant stores,
+ // it copies initializer from rodata. Oh well.
+
+ while (n_bytes--) {
+ unsigned masked_c = *(unsigned char *) block++;
+
+ masked_c &= 0x7f;
+ if (masked_c == 0x7f) {
+ fputs(" del", stdout);
+ continue;
+ }
+ if (masked_c > ' ') {
+ buf[3] = masked_c;
+ fputs(buf, stdout);
+ continue;
+ }
+ /* Why? Because printf(" %3.3s") is much slower... */
+ buf[6] = charname[masked_c][0];
+ buf[7] = charname[masked_c][1];
+ buf[8] = charname[masked_c][2];
+ fputs(buf+5, stdout);
+ }
+}
+
+static void
+print_ascii(size_t n_bytes, const char *block,
+ const char *unused_fmt_string ATTRIBUTE_UNUSED)
+{
+ // buf[N] pos: 01234 56789
+ char buf[12] = " x\0 0xx\0";
+
+ while (n_bytes--) {
+ const char *s;
+ unsigned c = *(unsigned char *) block++;
+
+ if (ISPRINT(c)) {
+ buf[3] = c;
+ fputs(buf, stdout);
+ continue;
+ }
+ switch (c) {
+ case '\0':
+ s = " \\0";
+ break;
+ case '\007':
+ s = " \\a";
+ break;
+ case '\b':
+ s = " \\b";
+ break;
+ case '\f':
+ s = " \\f";
+ break;
+ case '\n':
+ s = " \\n";
+ break;
+ case '\r':
+ s = " \\r";
+ break;
+ case '\t':
+ s = " \\t";
+ break;
+ case '\v':
+ s = " \\v";
+ break;
+ case '\x7f':
+ s = " 177";
+ break;
+ default: /* c is never larger than 040 */
+ buf[7] = (c >> 3) + '0';
+ buf[8] = (c & 7) + '0';
+ s = buf + 5;
+ }
+ fputs(s, stdout);
+ }
+}
+
+/* Given a list of one or more input filenames FILE_LIST, set the global
+ file pointer IN_STREAM and the global string INPUT_FILENAME to the
+ first one that can be successfully opened. Modify FILE_LIST to
+ reference the next filename in the list. A file name of "-" is
+ interpreted as standard input. If any file open fails, give an error
+ message and return nonzero. */
+
+static void
+open_next_file(void)
+{
+ while (1) {
+ if (!*file_list)
+ return;
+ in_stream = fopen_or_warn_stdin(*file_list++);
+ if (in_stream) {
+ break;
+ }
+ ioerror = 1;
+ }
+
+ if (limit_bytes_to_format && !flag_dump_strings)
+ setbuf(in_stream, NULL);
+}
+
+/* Test whether there have been errors on in_stream, and close it if
+ it is not standard input. Return nonzero if there has been an error
+ on in_stream or stdout; return zero otherwise. This function will
+ report more than one error only if both a read and a write error
+ have occurred. IN_ERRNO, if nonzero, is the error number
+ corresponding to the most recent action for IN_STREAM. */
+
+static void
+check_and_close(void)
+{
+ if (in_stream) {
+ if (ferror(in_stream)) {
+ bb_error_msg("%s: read error", (in_stream == stdin)
+ ? bb_msg_standard_input
+ : file_list[-1]
+ );
+ ioerror = 1;
+ }
+ fclose_if_not_stdin(in_stream);
+ in_stream = NULL;
+ }
+
+ if (ferror(stdout)) {
+ bb_error_msg("write error");
+ ioerror = 1;
+ }
+}
+
+/* If S points to a single valid modern od format string, put
+ a description of that format in *TSPEC, return pointer to
+ character following the just-decoded format.
+ For example, if S were "d4afL", we will return a rtp to "afL"
+ and *TSPEC would be
+ {
+ fmt = SIGNED_DECIMAL;
+ size = INT or LONG; (whichever integral_type_size[4] resolves to)
+ print_function = print_int; (assuming size == INT)
+ fmt_string = "%011d%c";
+ }
+ S_ORIG is solely for reporting errors. It should be the full format
+ string argument. */
+
+static const char *
+decode_one_format(const char *s_orig, const char *s, struct tspec *tspec)
+{
+ enum size_spec size_spec;
+ unsigned size;
+ enum output_format fmt;
+ const char *p;
+ char *end;
+ char *fmt_string = NULL;
+ void (*print_function) (size_t, const char *, const char *);
+ unsigned c;
+ unsigned field_width = 0;
+ int pos;
+
+
+ switch (*s) {
+ case 'd':
+ case 'o':
+ case 'u':
+ case 'x': {
+ static const char CSIL[] ALIGN1 = "CSIL";
+
+ c = *s++;
+ p = strchr(CSIL, *s);
+ if (!p) {
+ size = sizeof(int);
+ if (isdigit(s[0])) {
+ size = bb_strtou(s, &end, 0);
+ if (errno == ERANGE
+ || MAX_INTEGRAL_TYPE_SIZE < size
+ || integral_type_size[size] == NO_SIZE
+ ) {
+ bb_error_msg_and_die("invalid type string '%s'; "
+ "%u-byte %s type is not supported",
+ s_orig, size, "integral");
+ }
+ s = end;
+ }
+ } else {
+ static const uint8_t CSIL_sizeof[4] = {
+ sizeof(char),
+ sizeof(short),
+ sizeof(int),
+ sizeof(long),
+ };
+ size = CSIL_sizeof[p - CSIL];
+ s++; /* skip C/S/I/L */
+ }
+
+#define ISPEC_TO_FORMAT(Spec, Min_format, Long_format, Max_format) \
+ ((Spec) == LONG_LONG ? (Max_format) \
+ : ((Spec) == LONG ? (Long_format) : (Min_format)))
+
+#define FMT_BYTES_ALLOCATED 9
+ size_spec = integral_type_size[size];
+
+ {
+ static const char doux[] ALIGN1 = "doux";
+ static const char doux_fmt_letter[][4] = {
+ "lld", "llo", "llu", "llx"
+ };
+ static const enum output_format doux_fmt[] = {
+ SIGNED_DECIMAL,
+ OCTAL,
+ UNSIGNED_DECIMAL,
+ HEXADECIMAL,
+ };
+ static const uint8_t *const doux_bytes_to_XXX[] = {
+ bytes_to_signed_dec_digits,
+ bytes_to_oct_digits,
+ bytes_to_unsigned_dec_digits,
+ bytes_to_hex_digits,
+ };
+ static const char doux_fmtstring[][sizeof(" %%0%u%s")] = {
+ " %%%u%s",
+ " %%0%u%s",
+ " %%%u%s",
+ " %%0%u%s",
+ };
+
+ pos = strchr(doux, c) - doux;
+ fmt = doux_fmt[pos];
+ field_width = doux_bytes_to_XXX[pos][size];
+ p = doux_fmt_letter[pos] + 2;
+ if (size_spec == LONG) p--;
+ if (size_spec == LONG_LONG) p -= 2;
+ fmt_string = xasprintf(doux_fmtstring[pos], field_width, p);
+ }
+
+ switch (size_spec) {
+ case CHAR:
+ print_function = (fmt == SIGNED_DECIMAL
+ ? print_s_char
+ : print_char);
+ break;
+ case SHORT:
+ print_function = (fmt == SIGNED_DECIMAL
+ ? print_s_short
+ : print_short);
+ break;
+ case INT:
+ print_function = print_int;
+ break;
+ case LONG:
+ print_function = print_long;
+ break;
+ default: /* case LONG_LONG: */
+ print_function = print_long_long;
+ break;
+ }
+ break;
+ }
+
+ case 'f': {
+ static const char FDL[] ALIGN1 = "FDL";
+
+ fmt = FLOATING_POINT;
+ ++s;
+ p = strchr(FDL, *s);
+ if (!p) {
+ size = sizeof(double);
+ if (isdigit(s[0])) {
+ size = bb_strtou(s, &end, 0);
+ if (errno == ERANGE || size > MAX_FP_TYPE_SIZE
+ || fp_type_size[size] == NO_SIZE
+ ) {
+ bb_error_msg_and_die("invalid type string '%s'; "
+ "%u-byte %s type is not supported",
+ s_orig, size, "floating point");
+ }
+ s = end;
+ }
+ } else {
+ static const uint8_t FDL_sizeof[] = {
+ sizeof(float),
+ sizeof(double),
+ sizeof(longdouble_t),
+ };
+
+ size = FDL_sizeof[p - FDL];
+ }
+
+ size_spec = fp_type_size[size];
+
+ switch (size_spec) {
+ case FLOAT_SINGLE:
+ print_function = print_float;
+ field_width = FLT_DIG + 8;
+ /* Don't use %#e; not all systems support it. */
+ fmt_string = xasprintf(" %%%d.%de", field_width, FLT_DIG);
+ break;
+ case FLOAT_DOUBLE:
+ print_function = print_double;
+ field_width = DBL_DIG + 8;
+ fmt_string = xasprintf(" %%%d.%de", field_width, DBL_DIG);
+ break;
+ default: /* case FLOAT_LONG_DOUBLE: */
+ print_function = print_long_double;
+ field_width = LDBL_DIG + 8;
+ fmt_string = xasprintf(" %%%d.%dLe", field_width, LDBL_DIG);
+ break;
+ }
+ break;
+ }
+
+ case 'a':
+ ++s;
+ fmt = NAMED_CHARACTER;
+ size_spec = CHAR;
+ print_function = print_named_ascii;
+ field_width = 3;
+ break;
+ case 'c':
+ ++s;
+ fmt = CHARACTER;
+ size_spec = CHAR;
+ print_function = print_ascii;
+ field_width = 3;
+ break;
+ default:
+ bb_error_msg_and_die("invalid character '%c' "
+ "in type string '%s'", *s, s_orig);
+ }
+
+ tspec->size = size_spec;
+ tspec->fmt = fmt;
+ tspec->print_function = print_function;
+ tspec->fmt_string = fmt_string;
+
+ tspec->field_width = field_width;
+ tspec->hexl_mode_trailer = (*s == 'z');
+ if (tspec->hexl_mode_trailer)
+ s++;
+
+ return s;
+}
+
+/* Decode the modern od format string S. Append the decoded
+ representation to the global array SPEC, reallocating SPEC if
+ necessary. */
+
+static void
+decode_format_string(const char *s)
+{
+ const char *s_orig = s;
+
+ while (*s != '\0') {
+ struct tspec tspec;
+ const char *next;
+
+ next = decode_one_format(s_orig, s, &tspec);
+
+ assert(s != next);
+ s = next;
+ n_specs++;
+ spec = xrealloc(spec, n_specs * sizeof(*spec));
+ memcpy(&spec[n_specs-1], &tspec, sizeof *spec);
+ }
+}
+
+/* Given a list of one or more input filenames FILE_LIST, set the global
+ file pointer IN_STREAM to position N_SKIP in the concatenation of
+ those files. If any file operation fails or if there are fewer than
+ N_SKIP bytes in the combined input, give an error message and return
+ nonzero. When possible, use seek rather than read operations to
+ advance IN_STREAM. */
+
+static void
+skip(off_t n_skip)
+{
+ if (n_skip == 0)
+ return;
+
+ while (in_stream) { /* !EOF */
+ struct stat file_stats;
+
+ /* First try seeking. For large offsets, this extra work is
+ worthwhile. If the offset is below some threshold it may be
+ more efficient to move the pointer by reading. There are two
+ issues when trying to seek:
+ - the file must be seekable.
+ - before seeking to the specified position, make sure
+ that the new position is in the current file.
+ Try to do that by getting file's size using fstat.
+ But that will work only for regular files. */
+
+ /* The st_size field is valid only for regular files
+ (and for symbolic links, which cannot occur here).
+ If the number of bytes left to skip is at least
+ as large as the size of the current file, we can
+ decrement n_skip and go on to the next file. */
+ if (fstat(fileno(in_stream), &file_stats) == 0
+ && S_ISREG(file_stats.st_mode) && file_stats.st_size > 0
+ ) {
+ if (file_stats.st_size < n_skip) {
+ n_skip -= file_stats.st_size;
+ /* take "check & close / open_next" route */
+ } else {
+ if (fseeko(in_stream, n_skip, SEEK_CUR) != 0)
+ ioerror = 1;
+ return;
+ }
+ } else {
+ /* If it's not a regular file with positive size,
+ position the file pointer by reading. */
+ char buf[1024];
+ size_t n_bytes_to_read = 1024;
+ size_t n_bytes_read;
+
+ while (n_skip > 0) {
+ if (n_skip < n_bytes_to_read)
+ n_bytes_to_read = n_skip;
+ n_bytes_read = fread(buf, 1, n_bytes_to_read, in_stream);
+ n_skip -= n_bytes_read;
+ if (n_bytes_read != n_bytes_to_read)
+ break; /* EOF on this file or error */
+ }
+ }
+ if (n_skip == 0)
+ return;
+
+ check_and_close();
+ open_next_file();
+ }
+
+ if (n_skip)
+ bb_error_msg_and_die("cannot skip past end of combined input");
+}
+
+
+typedef void FN_format_address(off_t address, char c);
+
+static void
+format_address_none(off_t address ATTRIBUTE_UNUSED, char c ATTRIBUTE_UNUSED)
+{
+}
+
+static char address_fmt[] ALIGN1 = "%0n"OFF_FMT"xc";
+/* Corresponds to 'x' above */
+#define address_base_char address_fmt[sizeof(address_fmt)-3]
+/* Corresponds to 'n' above */
+#define address_pad_len_char address_fmt[2]
+
+static void
+format_address_std(off_t address, char c)
+{
+ /* Corresponds to 'c' */
+ address_fmt[sizeof(address_fmt)-2] = c;
+ printf(address_fmt, address);
+}
+
+#if ENABLE_GETOPT_LONG
+/* only used with --traditional */
+static void
+format_address_paren(off_t address, char c)
+{
+ putchar('(');
+ format_address_std(address, ')');
+ if (c) putchar(c);
+}
+
+static void
+format_address_label(off_t address, char c)
+{
+ format_address_std(address, ' ');
+ format_address_paren(address + pseudo_offset, c);
+}
+#endif
+
+static void
+dump_hexl_mode_trailer(size_t n_bytes, const char *block)
+{
+ fputs(" >", stdout);
+ while (n_bytes--) {
+ unsigned c = *(unsigned char *) block++;
+ c = (ISPRINT(c) ? c : '.');
+ putchar(c);
+ }
+ putchar('<');
+}
+
+/* Write N_BYTES bytes from CURR_BLOCK to standard output once for each
+ of the N_SPEC format specs. CURRENT_OFFSET is the byte address of
+ CURR_BLOCK in the concatenation of input files, and it is printed
+ (optionally) only before the output line associated with the first
+ format spec. When duplicate blocks are being abbreviated, the output
+ for a sequence of identical input blocks is the output for the first
+ block followed by an asterisk alone on a line. It is valid to compare
+ the blocks PREV_BLOCK and CURR_BLOCK only when N_BYTES == BYTES_PER_BLOCK.
+ That condition may be false only for the last input block -- and then
+ only when it has not been padded to length BYTES_PER_BLOCK. */
+
+static void
+write_block(off_t current_offset, size_t n_bytes,
+ const char *prev_block, const char *curr_block)
+{
+ static char first = 1;
+ static char prev_pair_equal = 0;
+ size_t i;
+
+ if (!verbose && !first
+ && n_bytes == bytes_per_block
+ && memcmp(prev_block, curr_block, bytes_per_block) == 0
+ ) {
+ if (prev_pair_equal) {
+ /* The two preceding blocks were equal, and the current
+ block is the same as the last one, so print nothing. */
+ } else {
+ puts("*");
+ prev_pair_equal = 1;
+ }
+ } else {
+ first = 0;
+ prev_pair_equal = 0;
+ for (i = 0; i < n_specs; i++) {
+ if (i == 0)
+ format_address(current_offset, '\0');
+ else
+ printf("%*s", address_pad_len_char - '0', "");
+ (*spec[i].print_function) (n_bytes, curr_block, spec[i].fmt_string);
+ if (spec[i].hexl_mode_trailer) {
+ /* space-pad out to full line width, then dump the trailer */
+ int datum_width = width_bytes[spec[i].size];
+ int blank_fields = (bytes_per_block - n_bytes) / datum_width;
+ int field_width = spec[i].field_width + 1;
+ printf("%*s", blank_fields * field_width, "");
+ dump_hexl_mode_trailer(n_bytes, curr_block);
+ }
+ putchar('\n');
+ }
+ }
+}
+
+static void
+read_block(size_t n, char *block, size_t *n_bytes_in_buffer)
+{
+ assert(0 < n && n <= bytes_per_block);
+
+ *n_bytes_in_buffer = 0;
+
+ if (n == 0)
+ return;
+
+ while (in_stream != NULL) { /* EOF. */
+ size_t n_needed;
+ size_t n_read;
+
+ n_needed = n - *n_bytes_in_buffer;
+ n_read = fread(block + *n_bytes_in_buffer, 1, n_needed, in_stream);
+ *n_bytes_in_buffer += n_read;
+ if (n_read == n_needed)
+ break;
+ /* error check is done in check_and_close */
+ check_and_close();
+ open_next_file();
+ }
+}
+
+/* Return the least common multiple of the sizes associated
+ with the format specs. */
+
+static int
+get_lcm(void)
+{
+ size_t i;
+ int l_c_m = 1;
+
+ for (i = 0; i < n_specs; i++)
+ l_c_m = lcm(l_c_m, width_bytes[(int) spec[i].size]);
+ return l_c_m;
+}
+
+#if ENABLE_GETOPT_LONG
+/* If S is a valid traditional offset specification with an optional
+ leading '+' return nonzero and set *OFFSET to the offset it denotes. */
+
+static int
+parse_old_offset(const char *s, off_t *offset)
+{
+ static const struct suffix_mult Bb[] = {
+ { "B", 1024 },
+ { "b", 512 },
+ { }
+ };
+ char *p;
+ int radix;
+
+ /* Skip over any leading '+'. */
+ if (s[0] == '+') ++s;
+
+ /* Determine the radix we'll use to interpret S. If there is a '.',
+ * it's decimal, otherwise, if the string begins with '0X'or '0x',
+ * it's hexadecimal, else octal. */
+ p = strchr(s, '.');
+ radix = 8;
+ if (p) {
+ p[0] = '\0'; /* cheating */
+ radix = 10;
+ } else if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
+ radix = 16;
+
+ *offset = xstrtooff_sfx(s, radix, Bb);
+ if (p) p[0] = '.';
+
+ return (*offset >= 0);
+}
+#endif
+
+/* Read a chunk of size BYTES_PER_BLOCK from the input files, write the
+ formatted block to standard output, and repeat until the specified
+ maximum number of bytes has been read or until all input has been
+ processed. If the last block read is smaller than BYTES_PER_BLOCK
+ and its size is not a multiple of the size associated with a format
+ spec, extend the input block with zero bytes until its length is a
+ multiple of all format spec sizes. Write the final block. Finally,
+ write on a line by itself the offset of the byte after the last byte
+ read. */
+
+static void
+dump(off_t current_offset, off_t end_offset)
+{
+ char *block[2];
+ int idx;
+ size_t n_bytes_read;
+
+ block[0] = xmalloc(2*bytes_per_block);
+ block[1] = block[0] + bytes_per_block;
+
+ idx = 0;
+ if (limit_bytes_to_format) {
+ while (1) {
+ size_t n_needed;
+ if (current_offset >= end_offset) {
+ n_bytes_read = 0;
+ break;
+ }
+ n_needed = MIN(end_offset - current_offset,
+ (off_t) bytes_per_block);
+ read_block(n_needed, block[idx], &n_bytes_read);
+ if (n_bytes_read < bytes_per_block)
+ break;
+ assert(n_bytes_read == bytes_per_block);
+ write_block(current_offset, n_bytes_read,
+ block[!idx], block[idx]);
+ current_offset += n_bytes_read;
+ idx = !idx;
+ }
+ } else {
+ while (1) {
+ read_block(bytes_per_block, block[idx], &n_bytes_read);
+ if (n_bytes_read < bytes_per_block)
+ break;
+ assert(n_bytes_read == bytes_per_block);
+ write_block(current_offset, n_bytes_read,
+ block[!idx], block[idx]);
+ current_offset += n_bytes_read;
+ idx = !idx;
+ }
+ }
+
+ if (n_bytes_read > 0) {
+ int l_c_m;
+ size_t bytes_to_write;
+
+ l_c_m = get_lcm();
+
+ /* Make bytes_to_write the smallest multiple of l_c_m that
+ is at least as large as n_bytes_read. */
+ bytes_to_write = l_c_m * ((n_bytes_read + l_c_m - 1) / l_c_m);
+
+ memset(block[idx] + n_bytes_read, 0, bytes_to_write - n_bytes_read);
+ write_block(current_offset, bytes_to_write,
+ block[!idx], block[idx]);
+ current_offset += n_bytes_read;
+ }
+
+ format_address(current_offset, '\n');
+
+ if (limit_bytes_to_format && current_offset >= end_offset)
+ check_and_close();
+
+ free(block[0]);
+}
+
+/* Read a single byte into *C from the concatenation of the input files
+ named in the global array FILE_LIST. On the first call to this
+ function, the global variable IN_STREAM is expected to be an open
+ stream associated with the input file INPUT_FILENAME. If IN_STREAM
+ is at end-of-file, close it and update the global variables IN_STREAM
+ and INPUT_FILENAME so they correspond to the next file in the list.
+ Then try to read a byte from the newly opened file. Repeat if
+ necessary until EOF is reached for the last file in FILE_LIST, then
+ set *C to EOF and return. Subsequent calls do likewise. */
+
+static void
+read_char(int *c)
+{
+ while (in_stream) { /* !EOF */
+ *c = fgetc(in_stream);
+ if (*c != EOF)
+ return;
+ check_and_close();
+ open_next_file();
+ }
+ *c = EOF;
+}
+
+/* Read N bytes into BLOCK from the concatenation of the input files
+ named in the global array FILE_LIST. On the first call to this
+ function, the global variable IN_STREAM is expected to be an open
+ stream associated with the input file INPUT_FILENAME. If all N
+ bytes cannot be read from IN_STREAM, close IN_STREAM and update
+ the global variables IN_STREAM and INPUT_FILENAME. Then try to
+ read the remaining bytes from the newly opened file. Repeat if
+ necessary until EOF is reached for the last file in FILE_LIST.
+ On subsequent calls, don't modify BLOCK and return zero. Set
+ *N_BYTES_IN_BUFFER to the number of bytes read. If an error occurs,
+ it will be detected through ferror when the stream is about to be
+ closed. If there is an error, give a message but continue reading
+ as usual and return nonzero. Otherwise return zero. */
+
+/* STRINGS mode. Find each "string constant" in the input.
+ A string constant is a run of at least 'string_min' ASCII
+ graphic (or formatting) characters terminated by a null.
+ Based on a function written by Richard Stallman for a
+ traditional version of od. */
+
+static void
+dump_strings(off_t address, off_t end_offset)
+{
+ size_t bufsize = MAX(100, string_min);
+ char *buf = xmalloc(bufsize);
+
+ while (1) {
+ size_t i;
+ int c;
+
+ /* See if the next 'string_min' chars are all printing chars. */
+ tryline:
+ if (limit_bytes_to_format && (end_offset - string_min <= address))
+ break;
+ i = 0;
+ while (!limit_bytes_to_format || address < end_offset) {
+ if (i == bufsize) {
+ bufsize += bufsize/8;
+ buf = xrealloc(buf, bufsize);
+ }
+ read_char(&c);
+ if (c < 0) { /* EOF */
+ free(buf);
+ return;
+ }
+ address++;
+ if (!c)
+ break;
+ if (!ISPRINT(c))
+ goto tryline; /* It isn't; give up on this string. */
+ buf[i++] = c; /* String continues; store it all. */
+ }
+
+ if (i < string_min) /* Too short! */
+ goto tryline;
+
+ /* If we get here, the string is all printable and NUL-terminated,
+ * so print it. It is all in 'buf' and 'i' is its length. */
+ buf[i] = 0;
+ format_address(address - i - 1, ' ');
+
+ for (i = 0; (c = buf[i]); i++) {
+ switch (c) {
+ case '\007': fputs("\\a", stdout); break;
+ case '\b': fputs("\\b", stdout); break;
+ case '\f': fputs("\\f", stdout); break;
+ case '\n': fputs("\\n", stdout); break;
+ case '\r': fputs("\\r", stdout); break;
+ case '\t': fputs("\\t", stdout); break;
+ case '\v': fputs("\\v", stdout); break;
+ default: putchar(c);
+ }
+ }
+ putchar('\n');
+ }
+
+ /* We reach this point only if we search through
+ (max_bytes_to_format - string_min) bytes before reaching EOF. */
+ free(buf);
+
+ check_and_close();
+}
+
+int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int od_main(int argc, char **argv)
+{
+ static const struct suffix_mult bkm[] = {
+ { "b", 512 },
+ { "k", 1024 },
+ { "m", 1024*1024 },
+ { }
+ };
+ enum {
+ OPT_A = 1 << 0,
+ OPT_N = 1 << 1,
+ OPT_a = 1 << 2,
+ OPT_b = 1 << 3,
+ OPT_c = 1 << 4,
+ OPT_d = 1 << 5,
+ OPT_f = 1 << 6,
+ OPT_h = 1 << 7,
+ OPT_i = 1 << 8,
+ OPT_j = 1 << 9,
+ OPT_l = 1 << 10,
+ OPT_o = 1 << 11,
+ OPT_t = 1 << 12,
+ OPT_v = 1 << 13,
+ OPT_x = 1 << 14,
+ OPT_s = 1 << 15,
+ OPT_S = 1 << 16,
+ OPT_w = 1 << 17,
+ OPT_traditional = (1 << 18) * ENABLE_GETOPT_LONG,
+ };
+#if ENABLE_GETOPT_LONG
+ static const char od_longopts[] ALIGN1 =
+ "skip-bytes\0" Required_argument "j"
+ "address-radix\0" Required_argument "A"
+ "read-bytes\0" Required_argument "N"
+ "format\0" Required_argument "t"
+ "output-duplicates\0" No_argument "v"
+ "strings\0" Optional_argument "S"
+ "width\0" Optional_argument "w"
+ "traditional\0" No_argument "\xff"
+ ;
+#endif
+ char *str_A, *str_N, *str_j, *str_S;
+ llist_t *lst_t = NULL;
+ unsigned opt;
+ int l_c_m;
+ /* The old-style 'pseudo starting address' to be printed in parentheses
+ after any true address. */
+ off_t pseudo_start = pseudo_start; // for gcc
+ /* The number of input bytes to skip before formatting and writing. */
+ off_t n_bytes_to_skip = 0;
+ /* The offset of the first byte after the last byte to be formatted. */
+ off_t end_offset = 0;
+ /* The maximum number of bytes that will be formatted. */
+ off_t max_bytes_to_format = 0;
+
+ spec = NULL;
+ format_address = format_address_std;
+ address_base_char = 'o';
+ address_pad_len_char = '7';
+ /* flag_dump_strings = 0; - already is */
+
+ /* Parse command line */
+ opt_complementary = "w+:t::"; /* -w N, -t is a list */
+#if ENABLE_GETOPT_LONG
+ applet_long_options = od_longopts;
+#endif
+ opt = getopt32(argv, "A:N:abcdfhij:lot:vxsS:"
+ "w::", // -w with optional param
+ // -S was -s and also had optional parameter
+ // but in coreutils 6.3 it was renamed and now has
+ // _mandatory_ parameter
+ &str_A, &str_N, &str_j, &lst_t, &str_S, &bytes_per_block);
+ argc -= optind;
+ argv += optind;
+ if (opt & OPT_A) {
+ static const char doxn[] ALIGN1 = "doxn";
+ static const char doxn_address_base_char[] ALIGN1 = {
+ 'u', 'o', 'x', /* '?' fourth one is not important */
+ };
+ static const uint8_t doxn_address_pad_len_char[] ALIGN1 = {
+ '7', '7', '6', /* '?' */
+ };
+ char *p;
+ int pos;
+ p = strchr(doxn, str_A[0]);
+ if (!p)
+ bb_error_msg_and_die("bad output address radix "
+ "'%c' (must be [doxn])", str_A[0]);
+ pos = p - doxn;
+ if (pos == 3) format_address = format_address_none;
+ address_base_char = doxn_address_base_char[pos];
+ address_pad_len_char = doxn_address_pad_len_char[pos];
+ }
+ if (opt & OPT_N) {
+ limit_bytes_to_format = 1;
+ max_bytes_to_format = xstrtooff_sfx(str_N, 0, bkm);
+ }
+ if (opt & OPT_a) decode_format_string("a");
+ if (opt & OPT_b) decode_format_string("oC");
+ if (opt & OPT_c) decode_format_string("c");
+ if (opt & OPT_d) decode_format_string("u2");
+ if (opt & OPT_f) decode_format_string("fF");
+ if (opt & OPT_h) decode_format_string("x2");
+ if (opt & OPT_i) decode_format_string("d2");
+ if (opt & OPT_j) n_bytes_to_skip = xstrtooff_sfx(str_j, 0, bkm);
+ if (opt & OPT_l) decode_format_string("d4");
+ if (opt & OPT_o) decode_format_string("o2");
+ //if (opt & OPT_t)...
+ while (lst_t) {
+ decode_format_string(llist_pop(&lst_t));
+ }
+ if (opt & OPT_v) verbose = 1;
+ if (opt & OPT_x) decode_format_string("x2");
+ if (opt & OPT_s) decode_format_string("d2");
+ if (opt & OPT_S) {
+ string_min = 3;
+ string_min = xstrtou_sfx(str_S, 0, bkm);
+ flag_dump_strings = 1;
+ }
+ //if (opt & OPT_w)...
+ //if (opt & OPT_traditional)...
+
+ if (flag_dump_strings && n_specs > 0)
+ bb_error_msg_and_die("no type may be specified when dumping strings");
+
+ /* If the --traditional option is used, there may be from
+ * 0 to 3 remaining command line arguments; handle each case
+ * separately.
+ * od [file] [[+]offset[.][b] [[+]label[.][b]]]
+ * The offset and pseudo_start have the same syntax.
+ *
+ * FIXME: POSIX 1003.1-2001 with XSI requires support for the
+ * traditional syntax even if --traditional is not given. */
+
+#if ENABLE_GETOPT_LONG
+ if (opt & OPT_traditional) {
+ off_t o1, o2;
+
+ if (argc == 1) {
+ if (parse_old_offset(argv[0], &o1)) {
+ n_bytes_to_skip = o1;
+ --argc;
+ ++argv;
+ }
+ } else if (argc == 2) {
+ if (parse_old_offset(argv[0], &o1)
+ && parse_old_offset(argv[1], &o2)
+ ) {
+ n_bytes_to_skip = o1;
+ flag_pseudo_start = 1;
+ pseudo_start = o2;
+ argv += 2;
+ argc -= 2;
+ } else if (parse_old_offset(argv[1], &o2)) {
+ n_bytes_to_skip = o2;
+ --argc;
+ argv[1] = argv[0];
+ ++argv;
+ } else {
+ bb_error_msg_and_die("invalid second operand "
+ "in compatibility mode '%s'", argv[1]);
+ }
+ } else if (argc == 3) {
+ if (parse_old_offset(argv[1], &o1)
+ && parse_old_offset(argv[2], &o2)
+ ) {
+ n_bytes_to_skip = o1;
+ flag_pseudo_start = 1;
+ pseudo_start = o2;
+ argv[2] = argv[0];
+ argv += 2;
+ argc -= 2;
+ } else {
+ bb_error_msg_and_die("in compatibility mode "
+ "the last two arguments must be offsets");
+ }
+ } else if (argc > 3) {
+ bb_error_msg_and_die("compatibility mode supports "
+ "at most three arguments");
+ }
+
+ if (flag_pseudo_start) {
+ if (format_address == format_address_none) {
+ address_base_char = 'o';
+ address_pad_len_char = '7';
+ format_address = format_address_paren;
+ } else
+ format_address = format_address_label;
+ }
+ }
+#endif
+
+ if (limit_bytes_to_format) {
+ end_offset = n_bytes_to_skip + max_bytes_to_format;
+ if (end_offset < n_bytes_to_skip)
+ bb_error_msg_and_die("skip-bytes + read-bytes is too large");
+ }
+
+ if (n_specs == 0) {
+ decode_format_string("o2");
+ n_specs = 1;
+ }
+
+ /* If no files were listed on the command line,
+ set the global pointer FILE_LIST so that it
+ references the null-terminated list of one name: "-". */
+ file_list = bb_argv_dash;
+ if (argc > 0) {
+ /* Set the global pointer FILE_LIST so that it
+ references the first file-argument on the command-line. */
+ file_list = (char const *const *) argv;
+ }
+
+ /* open the first input file */
+ open_next_file();
+ /* skip over any unwanted header bytes */
+ skip(n_bytes_to_skip);
+ if (!in_stream)
+ return EXIT_FAILURE;
+
+ pseudo_offset = (flag_pseudo_start ? pseudo_start - n_bytes_to_skip : 0);
+
+ /* Compute output block length. */
+ l_c_m = get_lcm();
+
+ if (opt & OPT_w) { /* -w: width */
+ if (!bytes_per_block || bytes_per_block % l_c_m != 0) {
+ bb_error_msg("warning: invalid width %u; using %d instead",
+ (unsigned)bytes_per_block, l_c_m);
+ bytes_per_block = l_c_m;
+ }
+ } else {
+ bytes_per_block = l_c_m;
+ if (l_c_m < DEFAULT_BYTES_PER_BLOCK)
+ bytes_per_block *= DEFAULT_BYTES_PER_BLOCK / l_c_m;
+ }
+
+#ifdef DEBUG
+ for (i = 0; i < n_specs; i++) {
+ printf("%d: fmt=\"%s\" width=%d\n",
+ i, spec[i].fmt_string, width_bytes[spec[i].size]);
+ }
+#endif
+
+ if (flag_dump_strings)
+ dump_strings(n_bytes_to_skip, end_offset);
+ else
+ dump(n_bytes_to_skip, end_offset);
+
+ if (fclose(stdin) == EOF)
+ bb_perror_msg_and_die(bb_msg_standard_input);
+
+ return ioerror;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/printenv.c b/cleopatre/busybox-1.11.1-spc300/coreutils/printenv.c
new file mode 100644
index 0000000000..2fc01f22f5
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/printenv.c
@@ -0,0 +1,33 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * printenv implementation for busybox
+ *
+ * Copyright (C) 2005 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2005 by Mike Frysinger <vapier@gentoo.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+int printenv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int printenv_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ /* no variables specified, show whole env */
+ if (!argv[1]) {
+ int e = 0;
+ while (environ[e])
+ puts(environ[e++]);
+ } else {
+ /* search for specified variables and print them out if found */
+ char *arg, *env;
+
+ while ((arg = *++argv) != NULL) {
+ env = getenv(arg);
+ if (env)
+ puts(env);
+ }
+ }
+
+ fflush_stdout_and_exit(EXIT_SUCCESS);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/printf.c b/cleopatre/busybox-1.11.1-spc300/coreutils/printf.c
new file mode 100644
index 0000000000..b7752369c5
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/printf.c
@@ -0,0 +1,320 @@
+/* vi: set sw=4 ts=4: */
+/* printf - format and print data
+
+ Copyright 1999 Dave Cinege
+ Portions copyright (C) 1990-1996 Free Software Foundation, Inc.
+
+ Licensed under GPL v2 or later, see file LICENSE in this tarball for details.
+*/
+
+/* Usage: printf format [argument...]
+
+ A front end to the printf function that lets it be used from the shell.
+
+ Backslash escapes:
+
+ \" = double quote
+ \\ = backslash
+ \a = alert (bell)
+ \b = backspace
+ \c = produce no further output
+ \f = form feed
+ \n = new line
+ \r = carriage return
+ \t = horizontal tab
+ \v = vertical tab
+ \0ooo = octal number (ooo is 0 to 3 digits)
+ \xhhh = hexadecimal number (hhh is 1 to 3 digits)
+
+ Additional directive:
+
+ %b = print an argument string, interpreting backslash escapes
+
+ The 'format' argument is re-used as many times as necessary
+ to convert all of the given arguments.
+
+ David MacKenzie <djm@gnu.ai.mit.edu> */
+
+
+// 19990508 Busy Boxed! Dave Cinege
+
+#include "libbb.h"
+
+typedef void (*converter)(const char *arg, void *result);
+
+static void multiconvert(const char *arg, void *result, converter convert)
+{
+ char s[sizeof(int)*3 + 2];
+
+ if (*arg == '"' || *arg == '\'') {
+ sprintf(s, "%d", (unsigned char)arg[1]);
+ arg = s;
+ }
+ convert(arg, result);
+ /* if there was conversion error, print unconverted string */
+ if (errno)
+ fputs(arg, stderr);
+}
+
+static void conv_strtoul(const char *arg, void *result)
+{
+ *(unsigned long*)result = bb_strtoul(arg, NULL, 0);
+}
+static void conv_strtol(const char *arg, void *result)
+{
+ *(long*)result = bb_strtol(arg, NULL, 0);
+}
+static void conv_strtod(const char *arg, void *result)
+{
+ char *end;
+ /* Well, this one allows leading whitespace... so what */
+ /* What I like much less is that "-" is accepted too! :( */
+ *(double*)result = strtod(arg, &end);
+ if (end[0]) errno = ERANGE;
+}
+
+static unsigned long my_xstrtoul(const char *arg)
+{
+ unsigned long result;
+ multiconvert(arg, &result, conv_strtoul);
+ return result;
+}
+
+static long my_xstrtol(const char *arg)
+{
+ long result;
+ multiconvert(arg, &result, conv_strtol);
+ return result;
+}
+
+static double my_xstrtod(const char *arg)
+{
+ double result;
+ multiconvert(arg, &result, conv_strtod);
+ return result;
+}
+
+static void print_esc_string(char *str)
+{
+ for (; *str; str++) {
+ if (*str == '\\') {
+ str++;
+ bb_putchar(bb_process_escape_sequence((const char **)&str));
+ } else {
+ bb_putchar(*str);
+ }
+
+ }
+}
+
+static void print_direc(char *format, unsigned fmt_length,
+ int field_width, int precision,
+ const char *argument)
+{
+ char saved;
+
+ saved = format[fmt_length];
+ format[fmt_length] = '\0';
+
+ switch (format[fmt_length - 1]) {
+ case 'd':
+ case 'i':
+ if (field_width < 0) {
+ if (precision < 0)
+ printf(format, my_xstrtol(argument));
+ else
+ printf(format, precision, my_xstrtol(argument));
+ } else {
+ if (precision < 0)
+ printf(format, field_width, my_xstrtol(argument));
+ else
+ printf(format, field_width, precision, my_xstrtol(argument));
+ }
+ break;
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ if (field_width < 0) {
+ if (precision < 0)
+ printf(format, my_xstrtoul(argument));
+ else
+ printf(format, precision, my_xstrtoul(argument));
+ } else {
+ if (precision < 0)
+ printf(format, field_width, my_xstrtoul(argument));
+ else
+ printf(format, field_width, precision, my_xstrtoul(argument));
+ }
+ break;
+ case 'f':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ if (field_width < 0) {
+ if (precision < 0)
+ printf(format, my_xstrtod(argument));
+ else
+ printf(format, precision, my_xstrtod(argument));
+ } else {
+ if (precision < 0)
+ printf(format, field_width, my_xstrtod(argument));
+ else
+ printf(format, field_width, precision, my_xstrtod(argument));
+ }
+ break;
+ case 'c':
+ printf(format, *argument);
+ break;
+ case 's':
+ if (field_width < 0) {
+ if (precision < 0)
+ printf(format, argument);
+ else
+ printf(format, precision, argument);
+ } else {
+ if (precision < 0)
+ printf(format, field_width, argument);
+ else
+ printf(format, field_width, precision, argument);
+ }
+ break;
+ }
+
+ format[fmt_length] = saved;
+}
+
+/* Print the text in FORMAT, using ARGV for arguments to any '%' directives.
+ Return advanced ARGV. */
+static char **print_formatted(char *f, char **argv)
+{
+ char *direc_start; /* Start of % directive. */
+ unsigned direc_length; /* Length of % directive. */
+ int field_width; /* Arg to first '*', or -1 if none. */
+ int precision; /* Arg to second '*', or -1 if none. */
+ char **saved_argv = argv;
+
+ for (; *f; ++f) {
+ switch (*f) {
+ case '%':
+ direc_start = f++;
+ direc_length = 1;
+ field_width = precision = -1;
+ if (*f == '%') {
+ bb_putchar('%');
+ break;
+ }
+ if (*f == 'b') {
+ if (*argv) {
+ print_esc_string(*argv);
+ ++argv;
+ }
+ break;
+ }
+ if (strchr("-+ #", *f)) {
+ ++f;
+ ++direc_length;
+ }
+ if (*f == '*') {
+ ++f;
+ ++direc_length;
+ if (*argv) {
+ field_width = my_xstrtoul(*argv);
+ ++argv;
+ } else
+ field_width = 0;
+ } else {
+ while (isdigit(*f)) {
+ ++f;
+ ++direc_length;
+ }
+ }
+ if (*f == '.') {
+ ++f;
+ ++direc_length;
+ if (*f == '*') {
+ ++f;
+ ++direc_length;
+ if (*argv) {
+ precision = my_xstrtoul(*argv);
+ ++argv;
+ } else
+ precision = 0;
+ } else
+ while (isdigit(*f)) {
+ ++f;
+ ++direc_length;
+ }
+ }
+ if (*f == 'l' || *f == 'L' || *f == 'h') {
+ ++f;
+ ++direc_length;
+ }
+ /*
+ if (!strchr ("diouxXfeEgGcs", *f))
+ fprintf(stderr, "%%%c: invalid directive", *f);
+ */
+ ++direc_length;
+ if (*argv) {
+ print_direc(direc_start, direc_length, field_width,
+ precision, *argv);
+ ++argv;
+ } else
+ print_direc(direc_start, direc_length, field_width,
+ precision, "");
+ break;
+ case '\\':
+ if (*++f == 'c') {
+ return saved_argv; /* causes main() to exit */
+ }
+ bb_putchar(bb_process_escape_sequence((const char **)&f));
+ f--;
+ break;
+ default:
+ bb_putchar(*f);
+ }
+ }
+
+ return argv;
+}
+
+int printf_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ char *format;
+ char **argv2;
+
+ /* We must check that stdout is not closed.
+ * The reason for this is highly non-obvious. printf_main is used from shell.
+ * Shell must correctly handle 'printf "%s" foo'
+ * if stdout is closed. With stdio, output gets shoveled into
+ * stdout buffer, and even fflush cannot clear it out. It seems that
+ * even if libc receives EBADF on write attempts, it feels determined
+ * to output data no matter what. So it will try later,
+ * and possibly will clobber future output. Not good. */
+ if (dup2(1, 1) != 1)
+ return -1;
+
+ /* bash builtin errors out on "printf '-%s-\n' foo",
+ * coreutils-6.9 works. Both work with "printf -- '-%s-\n' foo".
+ * We will mimic coreutils. */
+ if (argv[1] && argv[1][0] == '-' && argv[1][1] == '-' && argv[1][2] == '\0')
+ argv++;
+ if (!argv[1])
+ bb_show_usage();
+
+ format = argv[1];
+ argv2 = argv + 2;
+
+ do {
+ argv = argv2;
+ argv2 = print_formatted(format, argv);
+ } while (argv2 != argv && *argv2);
+
+ /* coreutils compat (bash doesn't do this):
+ if (*argv)
+ fprintf(stderr, "excess args ignored");
+ */
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/pwd.c b/cleopatre/busybox-1.11.1-spc300/coreutils/pwd.c
new file mode 100644
index 0000000000..9279dbee62
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/pwd.c
@@ -0,0 +1,27 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini pwd implementation for busybox
+ *
+ * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
+
+int pwd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int pwd_main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
+{
+ char *buf;
+
+ buf = xrealloc_getcwd_or_warn(NULL);
+ if (buf != NULL) {
+ puts(buf);
+ free(buf);
+ return fflush(stdout);
+ }
+
+ return EXIT_FAILURE;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/readlink.c b/cleopatre/busybox-1.11.1-spc300/coreutils/readlink.c
new file mode 100644
index 0000000000..0c45e1234a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/readlink.c
@@ -0,0 +1,49 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini readlink implementation for busybox
+ *
+ * Copyright (C) 2000,2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * Licensed under GPL v2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+int readlink_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int readlink_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ char *buf;
+ char *fname;
+ char pathbuf[PATH_MAX];
+
+ USE_FEATURE_READLINK_FOLLOW(
+ unsigned opt;
+ /* We need exactly one non-option argument. */
+ opt_complementary = "=1";
+ opt = getopt32(argv, "f");
+ fname = argv[optind];
+ )
+ SKIP_FEATURE_READLINK_FOLLOW(
+ const unsigned opt = 0;
+ if (argc != 2) bb_show_usage();
+ fname = argv[1];
+ )
+
+ /* compat: coreutils readlink reports errors silently via exit code */
+ logmode = LOGMODE_NONE;
+
+ if (opt) {
+ buf = realpath(fname, pathbuf);
+ } else {
+ buf = xmalloc_readlink_or_warn(fname);
+ }
+
+ if (!buf)
+ return EXIT_FAILURE;
+ puts(buf);
+
+ if (ENABLE_FEATURE_CLEAN_UP && !opt)
+ free(buf);
+
+ fflush_stdout_and_exit(EXIT_SUCCESS);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/realpath.c b/cleopatre/busybox-1.11.1-spc300/coreutils/realpath.c
new file mode 100644
index 0000000000..6766524a77
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/realpath.c
@@ -0,0 +1,46 @@
+/* vi: set sw=4 ts=4: */
+
+/* BB_AUDIT SUSv3 N/A -- Apparently a busybox extension. */
+
+/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
+ *
+ * Now does proper error checking on output and returns a failure exit code
+ * if one or more paths cannot be resolved.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+int realpath_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int realpath_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ int retval = EXIT_SUCCESS;
+
+#if PATH_MAX > (BUFSIZ+1)
+ RESERVE_CONFIG_BUFFER(resolved_path, PATH_MAX);
+# define resolved_path_MUST_FREE 1
+#else
+#define resolved_path bb_common_bufsiz1
+# define resolved_path_MUST_FREE 0
+#endif
+
+ if (!*++argv) {
+ bb_show_usage();
+ }
+
+ do {
+ if (realpath(*argv, resolved_path) != NULL) {
+ puts(resolved_path);
+ } else {
+ retval = EXIT_FAILURE;
+ bb_simple_perror_msg(*argv);
+ }
+ } while (*++argv);
+
+#if ENABLE_FEATURE_CLEAN_UP && resolved_path_MUST_FREE
+ RELEASE_CONFIG_BUFFER(resolved_path);
+#endif
+
+ fflush_stdout_and_exit(retval);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/rm.c b/cleopatre/busybox-1.11.1-spc300/coreutils/rm.c
new file mode 100644
index 0000000000..1774ce2963
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/rm.c
@@ -0,0 +1,55 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini rm implementation for busybox
+ *
+ * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 compliant */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/rm.html */
+
+/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
+ *
+ * Size reduction.
+ */
+
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
+
+int rm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int rm_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ int status = 0;
+ int flags = 0;
+ unsigned opt;
+
+ opt_complementary = "f-i:i-f";
+ opt = getopt32(argv, "fiRr");
+ argv += optind;
+ if (opt & 1)
+ flags |= FILEUTILS_FORCE;
+ if (opt & 2)
+ flags |= FILEUTILS_INTERACTIVE;
+ if (opt & 12)
+ flags |= FILEUTILS_RECUR;
+
+ if (*argv != NULL) {
+ do {
+ const char *base = bb_get_last_path_component_strip(*argv);
+
+ if (DOT_OR_DOTDOT(base)) {
+ bb_error_msg("cannot remove '.' or '..'");
+ } else if (remove_file(*argv, flags) >= 0) {
+ continue;
+ }
+ status = 1;
+ } while (*++argv);
+ } else if (!(flags & FILEUTILS_FORCE)) {
+ bb_show_usage();
+ }
+
+ return status;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/rmdir.c b/cleopatre/busybox-1.11.1-spc300/coreutils/rmdir.c
new file mode 100644
index 0000000000..cb6046617d
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/rmdir.c
@@ -0,0 +1,70 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * rmdir implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 compliant */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/rmdir.html */
+
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
+
+
+#define PARENTS 0x01
+#define IGNORE_NON_EMPTY 0x02
+
+int rmdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int rmdir_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ int status = EXIT_SUCCESS;
+ int flags;
+ char *path;
+
+#if ENABLE_FEATURE_RMDIR_LONG_OPTIONS
+ static const char rmdir_longopts[] ALIGN1 =
+ "parents\0" No_argument "p"
+ /* Debian etch: many packages fail to be purged or installed
+ * because they desperately want this option: */
+ "ignore-fail-on-non-empty\0" No_argument "\xff"
+ ;
+ applet_long_options = rmdir_longopts;
+#endif
+ flags = getopt32(argv, "p");
+ argv += optind;
+
+ if (!*argv) {
+ bb_show_usage();
+ }
+
+ do {
+ path = *argv;
+
+ while (1) {
+ if (rmdir(path) < 0) {
+#if ENABLE_FEATURE_RMDIR_LONG_OPTIONS
+ if ((flags & IGNORE_NON_EMPTY) && errno == ENOTEMPTY)
+ break;
+#endif
+ bb_perror_msg("'%s'", path); /* Match gnu rmdir msg. */
+ status = EXIT_FAILURE;
+ } else if (flags & PARENTS) {
+ /* Note: path was not "" since rmdir succeeded. */
+ path = dirname(path);
+ /* Path is now just the parent component. Dirname
+ * returns "." if there are no parents.
+ */
+ if (NOT_LONE_CHAR(path, '.')) {
+ continue;
+ }
+ }
+ break;
+ }
+ } while (*++argv);
+
+ return status;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/seq.c b/cleopatre/busybox-1.11.1-spc300/coreutils/seq.c
new file mode 100644
index 0000000000..01d71f256b
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/seq.c
@@ -0,0 +1,40 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * seq implementation for busybox
+ *
+ * Copyright (C) 2004, Glenn McGrath
+ *
+ * Licensed under the GPL v2, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
+
+
+int seq_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int seq_main(int argc, char **argv)
+{
+ double last, increment, i;
+
+ i = increment = 1;
+ switch (argc) {
+ case 4:
+ increment = atof(argv[2]);
+ case 3:
+ i = atof(argv[1]);
+ case 2:
+ last = atof(argv[argc-1]);
+ break;
+ default:
+ bb_show_usage();
+ }
+
+ /* You should note that this is pos-5.0.91 semantics, -- FK. */
+ while ((increment > 0 && i <= last) || (increment < 0 && i >= last)) {
+ printf("%g\n", i);
+ i += increment;
+ }
+
+ return fflush(stdout);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/sleep.c b/cleopatre/busybox-1.11.1-spc300/coreutils/sleep.c
new file mode 100644
index 0000000000..78f9a8ebfb
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/sleep.c
@@ -0,0 +1,63 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * sleep implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 compliant */
+/* BB_AUDIT GNU issues -- fancy version matches except args must be ints. */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/sleep.html */
+
+/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
+ *
+ * Rewritten to do proper arg and error checking.
+ * Also, added a 'fancy' configuration to accept multiple args with
+ * time suffixes for seconds, minutes, hours, and days.
+ */
+
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
+
+
+#if ENABLE_FEATURE_FANCY_SLEEP
+static const struct suffix_mult sfx[] = {
+ { "s", 1 },
+ { "m", 60 },
+ { "h", 60*60 },
+ { "d", 24*60*60 },
+ { }
+};
+#endif
+
+int sleep_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int sleep_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ unsigned duration;
+
+ ++argv;
+ if (!*argv)
+ bb_show_usage();
+
+#if ENABLE_FEATURE_FANCY_SLEEP
+
+ duration = 0;
+ do {
+ duration += xatoul_range_sfx(*argv, 0, UINT_MAX-duration, sfx);
+ } while (*++argv);
+
+#else /* FEATURE_FANCY_SLEEP */
+
+ duration = xatou(*argv);
+
+#endif /* FEATURE_FANCY_SLEEP */
+
+ if (sleep(duration)) {
+ bb_perror_nomsg_and_die();
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/sort.c b/cleopatre/busybox-1.11.1-spc300/coreutils/sort.c
new file mode 100644
index 0000000000..1f531fb763
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/sort.c
@@ -0,0 +1,407 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * SuS3 compliant sort implementation for busybox
+ *
+ * Copyright (C) 2004 by Rob Landley <rob@landley.net>
+ *
+ * MAINTAINER: Rob Landley <rob@landley.net>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ * See SuS3 sort standard at:
+ * http://www.opengroup.org/onlinepubs/007904975/utilities/sort.html
+ */
+
+#include "libbb.h"
+
+/* This is a NOEXEC applet. Be very careful! */
+
+
+/*
+ sort [-m][-o output][-bdfinru][-t char][-k keydef]... [file...]
+ sort -c [-bdfinru][-t char][-k keydef][file]
+*/
+
+/* These are sort types */
+static const char OPT_STR[] ALIGN1 = "ngMucszbrdfimS:T:o:k:t:";
+enum {
+ FLAG_n = 1, /* Numeric sort */
+ FLAG_g = 2, /* Sort using strtod() */
+ FLAG_M = 4, /* Sort date */
+/* ucsz apply to root level only, not keys. b at root level implies bb */
+ FLAG_u = 8, /* Unique */
+ FLAG_c = 0x10, /* Check: no output, exit(!ordered) */
+ FLAG_s = 0x20, /* Stable sort, no ascii fallback at end */
+ FLAG_z = 0x40, /* Input and output is NUL terminated, not \n */
+/* These can be applied to search keys, the previous four can't */
+ FLAG_b = 0x80, /* Ignore leading blanks */
+ FLAG_r = 0x100, /* Reverse */
+ FLAG_d = 0x200, /* Ignore !(isalnum()|isspace()) */
+ FLAG_f = 0x400, /* Force uppercase */
+ FLAG_i = 0x800, /* Ignore !isprint() */
+ FLAG_m = 0x1000, /* ignored: merge already sorted files; do not sort */
+ FLAG_S = 0x2000, /* ignored: -S, --buffer-size=SIZE */
+ FLAG_T = 0x4000, /* ignored: -T, --temporary-directory=DIR */
+ FLAG_o = 0x8000,
+ FLAG_k = 0x10000,
+ FLAG_t = 0x20000,
+ FLAG_bb = 0x80000000, /* Ignore trailing blanks */
+};
+
+#if ENABLE_FEATURE_SORT_BIG
+static char key_separator;
+
+static struct sort_key {
+ struct sort_key *next_key; /* linked list */
+ unsigned range[4]; /* start word, start char, end word, end char */
+ unsigned flags;
+} *key_list;
+
+static char *get_key(char *str, struct sort_key *key, int flags)
+{
+ int start = 0, end = 0, len, j;
+ unsigned i;
+
+ /* Special case whole string, so we don't have to make a copy */
+ if (key->range[0] == 1 && !key->range[1] && !key->range[2] && !key->range[3]
+ && !(flags & (FLAG_b | FLAG_d | FLAG_f | FLAG_i | FLAG_bb))
+ ) {
+ return str;
+ }
+
+ /* Find start of key on first pass, end on second pass */
+ len = strlen(str);
+ for (j = 0; j < 2; j++) {
+ if (!key->range[2*j])
+ end = len;
+ /* Loop through fields */
+ else {
+ end = 0;
+ for (i = 1; i < key->range[2*j] + j; i++) {
+ if (key_separator) {
+ /* Skip body of key and separator */
+ while (str[end]) {
+ if (str[end++] == key_separator)
+ break;
+ }
+ } else {
+ /* Skip leading blanks */
+ while (isspace(str[end]))
+ end++;
+ /* Skip body of key */
+ while (str[end]) {
+ if (isspace(str[end]))
+ break;
+ end++;
+ }
+ }
+ }
+ }
+ if (!j) start = end;
+ }
+ /* Strip leading whitespace if necessary */
+//XXX: skip_whitespace()
+ if (flags & FLAG_b)
+ while (isspace(str[start])) start++;
+ /* Strip trailing whitespace if necessary */
+ if (flags & FLAG_bb)
+ while (end > start && isspace(str[end-1])) end--;
+ /* Handle offsets on start and end */
+ if (key->range[3]) {
+ end += key->range[3] - 1;
+ if (end > len) end = len;
+ }
+ if (key->range[1]) {
+ start += key->range[1] - 1;
+ if (start > len) start = len;
+ }
+ /* Make the copy */
+ if (end < start) end = start;
+ str = xstrndup(str+start, end-start);
+ /* Handle -d */
+ if (flags & FLAG_d) {
+ for (start = end = 0; str[end]; end++)
+ if (isspace(str[end]) || isalnum(str[end]))
+ str[start++] = str[end];
+ str[start] = '\0';
+ }
+ /* Handle -i */
+ if (flags & FLAG_i) {
+ for (start = end = 0; str[end]; end++)
+ if (isprint(str[end]))
+ str[start++] = str[end];
+ str[start] = '\0';
+ }
+ /* Handle -f */
+ if (flags & FLAG_f)
+ for (i = 0; str[i]; i++)
+ str[i] = toupper(str[i]);
+
+ return str;
+}
+
+static struct sort_key *add_key(void)
+{
+ struct sort_key **pkey = &key_list;
+ while (*pkey)
+ pkey = &((*pkey)->next_key);
+ return *pkey = xzalloc(sizeof(struct sort_key));
+}
+
+#define GET_LINE(fp) \
+ ((option_mask32 & FLAG_z) \
+ ? bb_get_chunk_from_file(fp, NULL) \
+ : xmalloc_fgetline(fp))
+#else
+#define GET_LINE(fp) xmalloc_fgetline(fp)
+#endif
+
+/* Iterate through keys list and perform comparisons */
+static int compare_keys(const void *xarg, const void *yarg)
+{
+ int flags = option_mask32, retval = 0;
+ char *x, *y;
+
+#if ENABLE_FEATURE_SORT_BIG
+ struct sort_key *key;
+
+ for (key = key_list; !retval && key; key = key->next_key) {
+ flags = key->flags ? key->flags : option_mask32;
+ /* Chop out and modify key chunks, handling -dfib */
+ x = get_key(*(char **)xarg, key, flags);
+ y = get_key(*(char **)yarg, key, flags);
+#else
+ /* This curly bracket serves no purpose but to match the nesting
+ level of the for () loop we're not using */
+ {
+ x = *(char **)xarg;
+ y = *(char **)yarg;
+#endif
+ /* Perform actual comparison */
+ switch (flags & 7) {
+ default:
+ bb_error_msg_and_die("unknown sort type");
+ break;
+ /* Ascii sort */
+ case 0:
+#if ENABLE_LOCALE_SUPPORT
+ retval = strcoll(x, y);
+#else
+ retval = strcmp(x, y);
+#endif
+ break;
+#if ENABLE_FEATURE_SORT_BIG
+ case FLAG_g: {
+ char *xx, *yy;
+ double dx = strtod(x, &xx);
+ double dy = strtod(y, &yy);
+ /* not numbers < NaN < -infinity < numbers < +infinity) */
+ if (x == xx)
+ retval = (y == yy ? 0 : -1);
+ else if (y == yy)
+ retval = 1;
+ /* Check for isnan */
+ else if (dx != dx)
+ retval = (dy != dy) ? 0 : -1;
+ else if (dy != dy)
+ retval = 1;
+ /* Check for infinity. Could underflow, but it avoids libm. */
+ else if (1.0 / dx == 0.0) {
+ if (dx < 0)
+ retval = (1.0 / dy == 0.0 && dy < 0) ? 0 : -1;
+ else
+ retval = (1.0 / dy == 0.0 && dy > 0) ? 0 : 1;
+ } else if (1.0 / dy == 0.0)
+ retval = (dy < 0) ? 1 : -1;
+ else
+ retval = (dx > dy) ? 1 : ((dx < dy) ? -1 : 0);
+ break;
+ }
+ case FLAG_M: {
+ struct tm thyme;
+ int dx;
+ char *xx, *yy;
+
+ xx = strptime(x, "%b", &thyme);
+ dx = thyme.tm_mon;
+ yy = strptime(y, "%b", &thyme);
+ if (!xx)
+ retval = (!yy) ? 0 : -1;
+ else if (!yy)
+ retval = 1;
+ else
+ retval = (dx == thyme.tm_mon) ? 0 : dx - thyme.tm_mon;
+ break;
+ }
+ /* Full floating point version of -n */
+ case FLAG_n: {
+ double dx = atof(x);
+ double dy = atof(y);
+ retval = (dx > dy) ? 1 : ((dx < dy) ? -1 : 0);
+ break;
+ }
+ } /* switch */
+ /* Free key copies. */
+ if (x != *(char **)xarg) free(x);
+ if (y != *(char **)yarg) free(y);
+ /* if (retval) break; - done by for () anyway */
+#else
+ /* Integer version of -n for tiny systems */
+ case FLAG_n:
+ retval = atoi(x) - atoi(y);
+ break;
+ } /* switch */
+#endif
+ } /* for */
+
+ /* Perform fallback sort if necessary */
+ if (!retval && !(option_mask32 & FLAG_s))
+ retval = strcmp(*(char **)xarg, *(char **)yarg);
+
+ if (flags & FLAG_r) return -retval;
+ return retval;
+}
+
+#if ENABLE_FEATURE_SORT_BIG
+static unsigned str2u(char **str)
+{
+ unsigned long lu;
+ if (!isdigit((*str)[0]))
+ bb_error_msg_and_die("bad field specification");
+ lu = strtoul(*str, str, 10);
+ if ((sizeof(long) > sizeof(int) && lu > INT_MAX) || !lu)
+ bb_error_msg_and_die("bad field specification");
+ return lu;
+}
+#endif
+
+int sort_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int sort_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ FILE *fp, *outfile = stdout;
+ char *line, **lines = NULL;
+ char *str_ignored, *str_o, *str_t;
+ llist_t *lst_k = NULL;
+ int i, flag;
+ int linecount = 0;
+
+ xfunc_error_retval = 2;
+
+ /* Parse command line options */
+ /* -o and -t can be given at most once */
+ opt_complementary = "o--o:t--t:" /* -t, -o: maximum one of each */
+ "k::"; /* -k takes list */
+ getopt32(argv, OPT_STR, &str_ignored, &str_ignored, &str_o, &lst_k, &str_t);
+#if ENABLE_FEATURE_SORT_BIG
+ if (option_mask32 & FLAG_o) outfile = xfopen(str_o, "w");
+ if (option_mask32 & FLAG_t) {
+ if (!str_t[0] || str_t[1])
+ bb_error_msg_and_die("bad -t parameter");
+ key_separator = str_t[0];
+ }
+ /* parse sort key */
+ while (lst_k) {
+ enum {
+ FLAG_allowed_for_k =
+ FLAG_n | /* Numeric sort */
+ FLAG_g | /* Sort using strtod() */
+ FLAG_M | /* Sort date */
+ FLAG_b | /* Ignore leading blanks */
+ FLAG_r | /* Reverse */
+ FLAG_d | /* Ignore !(isalnum()|isspace()) */
+ FLAG_f | /* Force uppercase */
+ FLAG_i | /* Ignore !isprint() */
+ 0
+ };
+ struct sort_key *key = add_key();
+ char *str_k = llist_pop(&lst_k);
+ const char *temp2;
+
+ i = 0; /* i==0 before comma, 1 after (-k3,6) */
+ while (*str_k) {
+ /* Start of range */
+ /* Cannot use bb_strtou - suffix can be a letter */
+ key->range[2*i] = str2u(&str_k);
+ if (*str_k == '.') {
+ str_k++;
+ key->range[2*i+1] = str2u(&str_k);
+ }
+ while (*str_k) {
+ if (*str_k == ',' && !i++) {
+ str_k++;
+ break;
+ } /* no else needed: fall through to syntax error
+ because comma isn't in OPT_STR */
+ temp2 = strchr(OPT_STR, *str_k);
+ if (!temp2)
+ bb_error_msg_and_die("unknown key option");
+ flag = 1 << (temp2 - OPT_STR);
+ if (flag & ~FLAG_allowed_for_k)
+ bb_error_msg_and_die("unknown sort type");
+ /* b after ',' means strip _trailing_ space */
+ if (i && flag == FLAG_b) flag = FLAG_bb;
+ key->flags |= flag;
+ str_k++;
+ }
+ }
+ }
+#endif
+ /* global b strips leading and trailing spaces */
+ if (option_mask32 & FLAG_b) option_mask32 |= FLAG_bb;
+
+ /* Open input files and read data */
+ argv += optind;
+ if (!*argv)
+ *--argv = (char*)"-";
+ do {
+ /* coreutils 6.9 compat: abort on first open error,
+ * do not continue to next file: */
+ fp = xfopen_stdin(*argv);
+ for (;;) {
+ line = GET_LINE(fp);
+ if (!line) break;
+ if (!(linecount & 63))
+ lines = xrealloc(lines, sizeof(char *) * (linecount + 64));
+ lines[linecount++] = line;
+ }
+ fclose_if_not_stdin(fp);
+ } while (*++argv);
+
+#if ENABLE_FEATURE_SORT_BIG
+ /* if no key, perform alphabetic sort */
+ if (!key_list)
+ add_key()->range[0] = 1;
+ /* handle -c */
+ if (option_mask32 & FLAG_c) {
+ int j = (option_mask32 & FLAG_u) ? -1 : 0;
+ for (i = 1; i < linecount; i++)
+ if (compare_keys(&lines[i-1], &lines[i]) > j) {
+ fprintf(stderr, "Check line %d\n", i);
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+ }
+#endif
+ /* Perform the actual sort */
+ qsort(lines, linecount, sizeof(char *), compare_keys);
+ /* handle -u */
+ if (option_mask32 & FLAG_u) {
+ flag = 0;
+ /* coreutils 6.3 drop lines for which only key is the same */
+ /* -- disabling last-resort compare... */
+ option_mask32 |= FLAG_s;
+ for (i = 1; i < linecount; i++) {
+ if (!compare_keys(&lines[flag], &lines[i]))
+ free(lines[i]);
+ else
+ lines[++flag] = lines[i];
+ }
+ if (linecount) linecount = flag+1;
+ }
+ /* Print it */
+ flag = (option_mask32 & FLAG_z) ? '\0' : '\n';
+ for (i = 0; i < linecount; i++)
+ fprintf(outfile, "%s%c", lines[i], flag);
+
+ fflush_stdout_and_exit(EXIT_SUCCESS);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/split.c b/cleopatre/busybox-1.11.1-spc300/coreutils/split.c
new file mode 100644
index 0000000000..39f62e6ddb
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/split.c
@@ -0,0 +1,139 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * split - split a file into pieces
+ * Copyright (c) 2007 Bernhard Fischer
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+/* BB_AUDIT: SUSv3 compliant
+ * SUSv3 requirements:
+ * http://www.opengroup.org/onlinepubs/009695399/utilities/split.html
+ */
+#include "libbb.h"
+
+static const struct suffix_mult split_suffices[] = {
+#if ENABLE_FEATURE_SPLIT_FANCY
+ { "b", 512 },
+#endif
+ { "k", 1024 },
+ { "m", 1024*1024 },
+#if ENABLE_FEATURE_SPLIT_FANCY
+ { "g", 1024*1024*1024 },
+#endif
+ { }
+};
+
+/* Increment the suffix part of the filename.
+ * Returns NULL if we are out of filenames.
+ */
+static char *next_file(char *old, unsigned suffix_len)
+{
+ size_t end = strlen(old);
+ unsigned i = 1;
+ char *curr;
+
+ do {
+ curr = old + end - i;
+ if (*curr < 'z') {
+ *curr += 1;
+ break;
+ }
+ i++;
+ if (i > suffix_len) {
+ return NULL;
+ }
+ *curr = 'a';
+ } while (1);
+
+ return old;
+}
+
+#define read_buffer bb_common_bufsiz1
+enum { READ_BUFFER_SIZE = COMMON_BUFSIZE - 1 };
+
+#define SPLIT_OPT_l (1<<0)
+#define SPLIT_OPT_b (1<<1)
+#define SPLIT_OPT_a (1<<2)
+
+int split_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int split_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ unsigned suffix_len = 2;
+ char *pfx;
+ char *count_p;
+ const char *sfx;
+ off_t cnt = 1000;
+ off_t remaining = 0;
+ unsigned opt;
+ ssize_t bytes_read, to_write;
+ char *src;
+
+ opt_complementary = "?2:a+"; /* max 2 args; -a N */
+ opt = getopt32(argv, "l:b:a:", &count_p, &count_p, &suffix_len);
+
+ if (opt & SPLIT_OPT_l)
+ cnt = XATOOFF(count_p);
+ if (opt & SPLIT_OPT_b) // FIXME: also needs XATOOFF
+ cnt = xatoull_sfx(count_p, split_suffices);
+ sfx = "x";
+
+ argv += optind;
+ if (argv[0]) {
+ if (argv[1])
+ sfx = argv[1];
+ xmove_fd(xopen(argv[0], O_RDONLY), 0);
+ } else {
+ argv[0] = (char *) bb_msg_standard_input;
+ }
+
+ if (NAME_MAX < strlen(sfx) + suffix_len)
+ bb_error_msg_and_die("suffix too long");
+
+ {
+ char *char_p = xzalloc(suffix_len + 1);
+ memset(char_p, 'a', suffix_len);
+ pfx = xasprintf("%s%s", sfx, char_p);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(char_p);
+ }
+
+ while (1) {
+ bytes_read = safe_read(STDIN_FILENO, read_buffer, READ_BUFFER_SIZE);
+ if (!bytes_read)
+ break;
+ if (bytes_read < 0)
+ bb_simple_perror_msg_and_die(argv[0]);
+ src = read_buffer;
+ do {
+ if (!remaining) {
+ if (!pfx)
+ bb_error_msg_and_die("suffixes exhausted");
+ xmove_fd(xopen(pfx, O_WRONLY | O_CREAT | O_TRUNC), 1);
+ pfx = next_file(pfx, suffix_len);
+ remaining = cnt;
+ }
+
+ if (opt & SPLIT_OPT_b) {
+ /* split by bytes */
+ to_write = (bytes_read < remaining) ? bytes_read : remaining;
+ remaining -= to_write;
+ } else {
+ /* split by lines */
+ /* can be sped up by using _memrchr_
+ * and writing many lines at once... */
+ char *end = memchr(src, '\n', bytes_read);
+ if (end) {
+ --remaining;
+ to_write = end - src + 1;
+ } else {
+ to_write = bytes_read;
+ }
+ }
+
+ xwrite(STDOUT_FILENO, src, to_write);
+ bytes_read -= to_write;
+ src += to_write;
+ } while (bytes_read);
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/stat.c b/cleopatre/busybox-1.11.1-spc300/coreutils/stat.c
new file mode 100644
index 0000000000..b2b1913a9e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/stat.c
@@ -0,0 +1,654 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * stat -- display file or file system status
+ *
+ * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation.
+ * Copyright (C) 2005 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2005 by Mike Frysinger <vapier@gentoo.org>
+ * Copyright (C) 2006 by Yoshinori Sato <ysato@users.sourceforge.jp>
+ *
+ * Written by Michael Meskes
+ * Taken from coreutils and turned into a busybox applet by Mike Frysinger
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* vars to control behavior */
+#define OPT_FILESYS (1 << 0)
+#define OPT_TERSE (1 << 1)
+#define OPT_DEREFERENCE (1 << 2)
+#define OPT_SELINUX (1 << 3)
+
+#if ENABLE_FEATURE_STAT_FORMAT
+typedef bool (*statfunc_ptr)(const char *, const char *);
+#else
+typedef bool (*statfunc_ptr)(const char *);
+#endif
+
+static const char *file_type(const struct stat *st)
+{
+ /* See POSIX 1003.1-2001 XCU Table 4-8 lines 17093-17107
+ * for some of these formats.
+ * To keep diagnostics grammatical in English, the
+ * returned string must start with a consonant.
+ */
+ if (S_ISREG(st->st_mode)) return st->st_size == 0 ? "regular empty file" : "regular file";
+ if (S_ISDIR(st->st_mode)) return "directory";
+ if (S_ISBLK(st->st_mode)) return "block special file";
+ if (S_ISCHR(st->st_mode)) return "character special file";
+ if (S_ISFIFO(st->st_mode)) return "fifo";
+ if (S_ISLNK(st->st_mode)) return "symbolic link";
+ if (S_ISSOCK(st->st_mode)) return "socket";
+ if (S_TYPEISMQ(st)) return "message queue";
+ if (S_TYPEISSEM(st)) return "semaphore";
+ if (S_TYPEISSHM(st)) return "shared memory object";
+#ifdef S_TYPEISTMO
+ if (S_TYPEISTMO(st)) return "typed memory object";
+#endif
+ return "weird file";
+}
+
+static const char *human_time(time_t t)
+{
+ /* Old
+ static char *str;
+ str = ctime(&t);
+ str[strlen(str)-1] = '\0';
+ return str;
+ */
+ /* coreutils 6.3 compat: */
+
+ /*static char buf[sizeof("YYYY-MM-DD HH:MM:SS.000000000")] ALIGN1;*/
+#define buf bb_common_bufsiz1
+
+ strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S.000000000", localtime(&t));
+ return buf;
+#undef buf
+}
+
+/* Return the type of the specified file system.
+ * Some systems have statfvs.f_basetype[FSTYPSZ]. (AIX, HP-UX, and Solaris)
+ * Others have statfs.f_fstypename[MFSNAMELEN]. (NetBSD 1.5.2)
+ * Still others have neither and have to get by with f_type (Linux).
+ */
+static const char *human_fstype(uint32_t f_type)
+{
+ static const struct types {
+ uint32_t type;
+ const char *const fs;
+ } humantypes[] = {
+ { 0xADFF, "affs" },
+ { 0x1Cd1, "devpts" },
+ { 0x137D, "ext" },
+ { 0xEF51, "ext2" },
+ { 0xEF53, "ext2/ext3" },
+ { 0x3153464a, "jfs" },
+ { 0x58465342, "xfs" },
+ { 0xF995E849, "hpfs" },
+ { 0x9660, "isofs" },
+ { 0x4000, "isofs" },
+ { 0x4004, "isofs" },
+ { 0x137F, "minix" },
+ { 0x138F, "minix (30 char.)" },
+ { 0x2468, "minix v2" },
+ { 0x2478, "minix v2 (30 char.)" },
+ { 0x4d44, "msdos" },
+ { 0x4006, "fat" },
+ { 0x564c, "novell" },
+ { 0x6969, "nfs" },
+ { 0x9fa0, "proc" },
+ { 0x517B, "smb" },
+ { 0x012FF7B4, "xenix" },
+ { 0x012FF7B5, "sysv4" },
+ { 0x012FF7B6, "sysv2" },
+ { 0x012FF7B7, "coh" },
+ { 0x00011954, "ufs" },
+ { 0x012FD16D, "xia" },
+ { 0x5346544e, "ntfs" },
+ { 0x1021994, "tmpfs" },
+ { 0x52654973, "reiserfs" },
+ { 0x28cd3d45, "cramfs" },
+ { 0x7275, "romfs" },
+ { 0x858458f6, "romfs" },
+ { 0x73717368, "squashfs" },
+ { 0x62656572, "sysfs" },
+ { 0, "UNKNOWN" }
+ };
+
+ int i;
+
+ for (i = 0; humantypes[i].type; ++i)
+ if (humantypes[i].type == f_type)
+ break;
+ return humantypes[i].fs;
+}
+
+#if ENABLE_FEATURE_STAT_FORMAT
+static void strcatc(char *str, char c)
+{
+ int len = strlen(str);
+ str[len++] = c;
+ str[len] = '\0';
+}
+
+static void printfs(char *pformat, const char *msg)
+{
+ strcatc(pformat, 's');
+ printf(pformat, msg);
+}
+
+/* print statfs info */
+static void print_statfs(char *pformat, const char m,
+ const char *const filename, const void *data
+ USE_SELINUX(, security_context_t scontext))
+{
+ const struct statfs *statfsbuf = data;
+ if (m == 'n') {
+ printfs(pformat, filename);
+ } else if (m == 'i') {
+ strcat(pformat, "Lx");
+ printf(pformat, statfsbuf->f_fsid);
+ } else if (m == 'l') {
+ strcat(pformat, "lu");
+ printf(pformat, statfsbuf->f_namelen);
+ } else if (m == 't') {
+ strcat(pformat, "lx");
+ printf(pformat, (unsigned long) (statfsbuf->f_type)); /* no equiv */
+ } else if (m == 'T') {
+ printfs(pformat, human_fstype(statfsbuf->f_type));
+ } else if (m == 'b') {
+ strcat(pformat, "jd");
+ printf(pformat, (intmax_t) (statfsbuf->f_blocks));
+ } else if (m == 'f') {
+ strcat(pformat, "jd");
+ printf(pformat, (intmax_t) (statfsbuf->f_bfree));
+ } else if (m == 'a') {
+ strcat(pformat, "jd");
+ printf(pformat, (intmax_t) (statfsbuf->f_bavail));
+ } else if (m == 's' || m == 'S') {
+ strcat(pformat, "lu");
+ printf(pformat, (unsigned long) (statfsbuf->f_bsize));
+ } else if (m == 'c') {
+ strcat(pformat, "jd");
+ printf(pformat, (intmax_t) (statfsbuf->f_files));
+ } else if (m == 'd') {
+ strcat(pformat, "jd");
+ printf(pformat, (intmax_t) (statfsbuf->f_ffree));
+#if ENABLE_SELINUX
+ } else if (m == 'C' && (option_mask32 & OPT_SELINUX)) {
+ printfs(pformat, scontext);
+#endif
+ } else {
+ strcatc(pformat, 'c');
+ printf(pformat, m);
+ }
+}
+
+/* print stat info */
+static void print_stat(char *pformat, const char m,
+ const char *const filename, const void *data
+ USE_SELINUX(, security_context_t scontext))
+{
+#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
+ struct stat *statbuf = (struct stat *) data;
+ struct passwd *pw_ent;
+ struct group *gw_ent;
+
+ if (m == 'n') {
+ printfs(pformat, filename);
+ } else if (m == 'N') {
+ strcatc(pformat, 's');
+ if (S_ISLNK(statbuf->st_mode)) {
+ char *linkname = xmalloc_readlink_or_warn(filename);
+ if (linkname == NULL)
+ return;
+ /*printf("\"%s\" -> \"%s\"", filename, linkname); */
+ printf(pformat, filename);
+ printf(" -> ");
+ printf(pformat, linkname);
+ free(linkname);
+ } else {
+ printf(pformat, filename);
+ }
+ } else if (m == 'd') {
+ strcat(pformat, "ju");
+ printf(pformat, (uintmax_t) statbuf->st_dev);
+ } else if (m == 'D') {
+ strcat(pformat, "jx");
+ printf(pformat, (uintmax_t) statbuf->st_dev);
+ } else if (m == 'i') {
+ strcat(pformat, "ju");
+ printf(pformat, (uintmax_t) statbuf->st_ino);
+ } else if (m == 'a') {
+ strcat(pformat, "lo");
+ printf(pformat, (unsigned long) (statbuf->st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)));
+ } else if (m == 'A') {
+ printfs(pformat, bb_mode_string(statbuf->st_mode));
+ } else if (m == 'f') {
+ strcat(pformat, "lx");
+ printf(pformat, (unsigned long) statbuf->st_mode);
+ } else if (m == 'F') {
+ printfs(pformat, file_type(statbuf));
+ } else if (m == 'h') {
+ strcat(pformat, "lu");
+ printf(pformat, (unsigned long) statbuf->st_nlink);
+ } else if (m == 'u') {
+ strcat(pformat, "lu");
+ printf(pformat, (unsigned long) statbuf->st_uid);
+ } else if (m == 'U') {
+ setpwent();
+ pw_ent = getpwuid(statbuf->st_uid);
+ printfs(pformat, (pw_ent != 0L) ? pw_ent->pw_name : "UNKNOWN");
+ } else if (m == 'g') {
+ strcat(pformat, "lu");
+ printf(pformat, (unsigned long) statbuf->st_gid);
+ } else if (m == 'G') {
+ setgrent();
+ gw_ent = getgrgid(statbuf->st_gid);
+ printfs(pformat, (gw_ent != 0L) ? gw_ent->gr_name : "UNKNOWN");
+ } else if (m == 't') {
+ strcat(pformat, "lx");
+ printf(pformat, (unsigned long) major(statbuf->st_rdev));
+ } else if (m == 'T') {
+ strcat(pformat, "lx");
+ printf(pformat, (unsigned long) minor(statbuf->st_rdev));
+ } else if (m == 's') {
+ strcat(pformat, "ju");
+ printf(pformat, (uintmax_t) (statbuf->st_size));
+ } else if (m == 'B') {
+ strcat(pformat, "lu");
+ printf(pformat, (unsigned long) 512); //ST_NBLOCKSIZE
+ } else if (m == 'b') {
+ strcat(pformat, "ju");
+ printf(pformat, (uintmax_t) statbuf->st_blocks);
+ } else if (m == 'o') {
+ strcat(pformat, "lu");
+ printf(pformat, (unsigned long) statbuf->st_blksize);
+ } else if (m == 'x') {
+ printfs(pformat, human_time(statbuf->st_atime));
+ } else if (m == 'X') {
+ strcat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu");
+ printf(pformat, (unsigned long) statbuf->st_atime);
+ } else if (m == 'y') {
+ printfs(pformat, human_time(statbuf->st_mtime));
+ } else if (m == 'Y') {
+ strcat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu");
+ printf(pformat, (unsigned long) statbuf->st_mtime);
+ } else if (m == 'z') {
+ printfs(pformat, human_time(statbuf->st_ctime));
+ } else if (m == 'Z') {
+ strcat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu");
+ printf(pformat, (unsigned long) statbuf->st_ctime);
+#if ENABLE_SELINUX
+ } else if (m == 'C' && (option_mask32 & OPT_SELINUX)) {
+ printfs(pformat, scontext);
+#endif
+ } else {
+ strcatc(pformat, 'c');
+ printf(pformat, m);
+ }
+}
+
+static void print_it(const char *masterformat, const char *filename,
+ void (*print_func) (char*, char, const char*, const void* USE_SELINUX(, security_context_t scontext)),
+ const void *data
+ USE_SELINUX(, security_context_t scontext) )
+{
+ /* Create a working copy of the format string */
+ char *format = xstrdup(masterformat);
+ /* Add 2 to accomodate our conversion of the stat '%s' format string
+ * to the printf '%llu' one. */
+ char *dest = xmalloc(strlen(format) + 2 + 1);
+ char *b;
+
+ b = format;
+ while (b) {
+ size_t len;
+ char *p = strchr(b, '%');
+ if (!p) {
+ /* coreutils 6.3 always prints <cr> at the end */
+ /*fputs(b, stdout);*/
+ puts(b);
+ break;
+ }
+ *p++ = '\0';
+ fputs(b, stdout);
+
+ /* dest = "%<modifiers>" */
+ len = strspn(p, "#-+.I 0123456789");
+ dest[0] = '%';
+ memcpy(dest + 1, p, len);
+ dest[1 + len] = '\0';
+ p += len;
+
+ b = p + 1;
+ switch (*p) {
+ case '\0':
+ b = NULL;
+ /* fall through */
+ case '%':
+ bb_putchar('%');
+ break;
+ default:
+ /* Completes "%<modifiers>" with specifier and printfs */
+ print_func(dest, *p, filename, data USE_SELINUX(,scontext));
+ break;
+ }
+ }
+
+ free(format);
+ free(dest);
+}
+#endif
+
+/* Stat the file system and print what we find. */
+#if !ENABLE_FEATURE_STAT_FORMAT
+#define do_statfs(filename, format) do_statfs(filename)
+#endif
+static bool do_statfs(const char *filename, const char *format)
+{
+#if !ENABLE_FEATURE_STAT_FORMAT
+ const char *format;
+#endif
+ struct statfs statfsbuf;
+#if ENABLE_SELINUX
+ security_context_t scontext = NULL;
+
+ if (option_mask32 & OPT_SELINUX) {
+ if ((option_mask32 & OPT_DEREFERENCE
+ ? lgetfilecon(filename, &scontext)
+ : getfilecon(filename, &scontext)
+ ) < 0
+ ) {
+ bb_perror_msg(filename);
+ return 0;
+ }
+ }
+#endif
+ if (statfs(filename, &statfsbuf) != 0) {
+ bb_perror_msg("cannot read file system information for '%s'", filename);
+ return 0;
+ }
+
+#if ENABLE_FEATURE_STAT_FORMAT
+ if (format == NULL) {
+#if !ENABLE_SELINUX
+ format = (option_mask32 & OPT_TERSE
+ ? "%n %i %l %t %s %b %f %a %c %d\n"
+ : " File: \"%n\"\n"
+ " ID: %-8i Namelen: %-7l Type: %T\n"
+ "Block size: %-10s\n"
+ "Blocks: Total: %-10b Free: %-10f Available: %a\n"
+ "Inodes: Total: %-10c Free: %d");
+#else
+ format = (option_mask32 & OPT_TERSE
+ ? (option_mask32 & OPT_SELINUX ? "%n %i %l %t %s %b %f %a %c %d %C\n":
+ "%n %i %l %t %s %b %f %a %c %d\n")
+ : (option_mask32 & OPT_SELINUX ?
+ " File: \"%n\"\n"
+ " ID: %-8i Namelen: %-7l Type: %T\n"
+ "Block size: %-10s\n"
+ "Blocks: Total: %-10b Free: %-10f Available: %a\n"
+ "Inodes: Total: %-10c Free: %d"
+ " S_context: %C\n":
+ " File: \"%n\"\n"
+ " ID: %-8i Namelen: %-7l Type: %T\n"
+ "Block size: %-10s\n"
+ "Blocks: Total: %-10b Free: %-10f Available: %a\n"
+ "Inodes: Total: %-10c Free: %d\n")
+ );
+#endif /* SELINUX */
+ }
+ print_it(format, filename, print_statfs, &statfsbuf USE_SELINUX(, scontext));
+#else /* FEATURE_STAT_FORMAT */
+ format = (option_mask32 & OPT_TERSE
+ ? "%s %llx %lu "
+ : " File: \"%s\"\n"
+ " ID: %-8Lx Namelen: %-7lu ");
+ printf(format,
+ filename,
+ statfsbuf.f_fsid,
+ statfsbuf.f_namelen);
+
+ if (option_mask32 & OPT_TERSE)
+ printf("%lx ", (unsigned long) (statfsbuf.f_type));
+ else
+ printf("Type: %s\n", human_fstype(statfsbuf.f_type));
+
+#if !ENABLE_SELINUX
+ format = (option_mask32 & OPT_TERSE
+ ? "%lu %ld %ld %ld %ld %ld\n"
+ : "Block size: %-10lu\n"
+ "Blocks: Total: %-10jd Free: %-10jd Available: %jd\n"
+ "Inodes: Total: %-10jd Free: %jd\n");
+ printf(format,
+ (unsigned long) (statfsbuf.f_bsize),
+ (intmax_t) (statfsbuf.f_blocks),
+ (intmax_t) (statfsbuf.f_bfree),
+ (intmax_t) (statfsbuf.f_bavail),
+ (intmax_t) (statfsbuf.f_files),
+ (intmax_t) (statfsbuf.f_ffree));
+#else
+ format = (option_mask32 & OPT_TERSE
+ ? (option_mask32 & OPT_SELINUX ? "%lu %ld %ld %ld %ld %ld %C\n":
+ "%lu %ld %ld %ld %ld %ld\n")
+ : (option_mask32 & OPT_SELINUX ?
+ "Block size: %-10lu\n"
+ "Blocks: Total: %-10jd Free: %-10jd Available: %jd\n"
+ "Inodes: Total: %-10jd Free: %jd"
+ "S_context: %C\n":
+ "Block size: %-10lu\n"
+ "Blocks: Total: %-10jd Free: %-10jd Available: %jd\n"
+ "Inodes: Total: %-10jd Free: %jd\n"));
+ printf(format,
+ (unsigned long) (statfsbuf.f_bsize),
+ (intmax_t) (statfsbuf.f_blocks),
+ (intmax_t) (statfsbuf.f_bfree),
+ (intmax_t) (statfsbuf.f_bavail),
+ (intmax_t) (statfsbuf.f_files),
+ (intmax_t) (statfsbuf.f_ffree),
+ scontext);
+
+ if (scontext)
+ freecon(scontext);
+#endif
+#endif /* FEATURE_STAT_FORMAT */
+ return 1;
+}
+
+/* stat the file and print what we find */
+#if !ENABLE_FEATURE_STAT_FORMAT
+#define do_stat(filename, format) do_stat(filename)
+#endif
+static bool do_stat(const char *filename, const char *format)
+{
+ struct stat statbuf;
+#if ENABLE_SELINUX
+ security_context_t scontext = NULL;
+
+ if (option_mask32 & OPT_SELINUX) {
+ if ((option_mask32 & OPT_DEREFERENCE
+ ? lgetfilecon(filename, &scontext)
+ : getfilecon(filename, &scontext)
+ ) < 0
+ ) {
+ bb_perror_msg(filename);
+ return 0;
+ }
+ }
+#endif
+ if ((option_mask32 & OPT_DEREFERENCE ? stat : lstat) (filename, &statbuf) != 0) {
+ bb_perror_msg("cannot stat '%s'", filename);
+ return 0;
+ }
+
+#if ENABLE_FEATURE_STAT_FORMAT
+ if (format == NULL) {
+#if !ENABLE_SELINUX
+ if (option_mask32 & OPT_TERSE) {
+ format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o";
+ } else {
+ if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) {
+ format =
+ " File: \"%N\"\n"
+ " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
+ "Device: %Dh/%dd\tInode: %-10i Links: %-5h"
+ " Device type: %t,%T\n"
+ "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
+ "Access: %x\n" "Modify: %y\n" "Change: %z\n";
+ } else {
+ format =
+ " File: \"%N\"\n"
+ " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
+ "Device: %Dh/%dd\tInode: %-10i Links: %h\n"
+ "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
+ "Access: %x\n" "Modify: %y\n" "Change: %z\n";
+ }
+ }
+#else
+ if (option_mask32 & OPT_TERSE) {
+ format = (option_mask32 & OPT_SELINUX ?
+ "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o %C\n":
+ "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\n");
+ } else {
+ if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) {
+ format = (option_mask32 & OPT_SELINUX ?
+ " File: \"%N\"\n"
+ " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
+ "Device: %Dh/%dd\tInode: %-10i Links: %-5h"
+ " Device type: %t,%T\n"
+ "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
+ " S_Context: %C\n"
+ "Access: %x\n" "Modify: %y\n" "Change: %z\n":
+ " File: \"%N\"\n"
+ " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
+ "Device: %Dh/%dd\tInode: %-10i Links: %-5h"
+ " Device type: %t,%T\n"
+ "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
+ "Access: %x\n" "Modify: %y\n" "Change: %z\n");
+ } else {
+ format = (option_mask32 & OPT_SELINUX ?
+ " File: \"%N\"\n"
+ " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
+ "Device: %Dh/%dd\tInode: %-10i Links: %h\n"
+ "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
+ "S_Context: %C\n"
+ "Access: %x\n" "Modify: %y\n" "Change: %z\n":
+ " File: \"%N\"\n"
+ " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
+ "Device: %Dh/%dd\tInode: %-10i Links: %h\n"
+ "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
+ "Access: %x\n" "Modify: %y\n" "Change: %z\n");
+ }
+ }
+#endif
+ }
+ print_it(format, filename, print_stat, &statbuf USE_SELINUX(, scontext));
+#else /* FEATURE_STAT_FORMAT */
+ if (option_mask32 & OPT_TERSE) {
+ printf("%s %ju %ju %lx %lu %lu %jx %ju %lu %lx %lx %lu %lu %lu %lu"
+ SKIP_SELINUX("\n"),
+ filename,
+ (uintmax_t) (statbuf.st_size),
+ (uintmax_t) statbuf.st_blocks,
+ (unsigned long) statbuf.st_mode,
+ (unsigned long) statbuf.st_uid,
+ (unsigned long) statbuf.st_gid,
+ (uintmax_t) statbuf.st_dev,
+ (uintmax_t) statbuf.st_ino,
+ (unsigned long) statbuf.st_nlink,
+ (unsigned long) major(statbuf.st_rdev),
+ (unsigned long) minor(statbuf.st_rdev),
+ (unsigned long) statbuf.st_atime,
+ (unsigned long) statbuf.st_mtime,
+ (unsigned long) statbuf.st_ctime,
+ (unsigned long) statbuf.st_blksize
+ );
+#if ENABLE_SELINUX
+ if (option_mask32 & OPT_SELINUX)
+ printf(" %lc\n", *scontext);
+ else
+ bb_putchar('\n');
+#endif
+ } else {
+ char *linkname = NULL;
+
+ struct passwd *pw_ent;
+ struct group *gw_ent;
+ setgrent();
+ gw_ent = getgrgid(statbuf.st_gid);
+ setpwent();
+ pw_ent = getpwuid(statbuf.st_uid);
+
+ if (S_ISLNK(statbuf.st_mode))
+ linkname = xmalloc_readlink_or_warn(filename);
+ if (linkname)
+ printf(" File: \"%s\" -> \"%s\"\n", filename, linkname);
+ else
+ printf(" File: \"%s\"\n", filename);
+
+ printf(" Size: %-10ju\tBlocks: %-10ju IO Block: %-6lu %s\n"
+ "Device: %jxh/%jud\tInode: %-10ju Links: %-5lu",
+ (uintmax_t) (statbuf.st_size),
+ (uintmax_t) statbuf.st_blocks,
+ (unsigned long) statbuf.st_blksize,
+ file_type(&statbuf),
+ (uintmax_t) statbuf.st_dev,
+ (uintmax_t) statbuf.st_dev,
+ (uintmax_t) statbuf.st_ino,
+ (unsigned long) statbuf.st_nlink);
+ if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode))
+ printf(" Device type: %lx,%lx\n",
+ (unsigned long) major(statbuf.st_rdev),
+ (unsigned long) minor(statbuf.st_rdev));
+ else
+ bb_putchar('\n');
+ printf("Access: (%04lo/%10.10s) Uid: (%5lu/%8s) Gid: (%5lu/%8s)\n",
+ (unsigned long) (statbuf.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)),
+ bb_mode_string(statbuf.st_mode),
+ (unsigned long) statbuf.st_uid,
+ (pw_ent != 0L) ? pw_ent->pw_name : "UNKNOWN",
+ (unsigned long) statbuf.st_gid,
+ (gw_ent != 0L) ? gw_ent->gr_name : "UNKNOWN");
+#if ENABLE_SELINUX
+ printf(" S_Context: %lc\n", *scontext);
+#endif
+ printf("Access: %s\n" "Modify: %s\n" "Change: %s\n",
+ human_time(statbuf.st_atime),
+ human_time(statbuf.st_mtime),
+ human_time(statbuf.st_ctime));
+ }
+#endif /* FEATURE_STAT_FORMAT */
+ return 1;
+}
+
+int stat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int stat_main(int argc, char **argv)
+{
+ USE_FEATURE_STAT_FORMAT(char *format = NULL;)
+ int i;
+ int ok = 1;
+ statfunc_ptr statfunc = do_stat;
+
+ getopt32(argv, "ftL"
+ USE_SELINUX("Z")
+ USE_FEATURE_STAT_FORMAT("c:", &format)
+ );
+
+ if (option_mask32 & OPT_FILESYS) /* -f */
+ statfunc = do_statfs;
+ if (argc == optind) /* files */
+ bb_show_usage();
+
+#if ENABLE_SELINUX
+ if (option_mask32 & OPT_SELINUX) {
+ selinux_or_die();
+ }
+#endif /* ENABLE_SELINUX */
+ for (i = optind; i < argc; ++i)
+ ok &= statfunc(argv[i] USE_FEATURE_STAT_FORMAT(, format));
+
+ return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/stty.c b/cleopatre/busybox-1.11.1-spc300/coreutils/stty.c
new file mode 100644
index 0000000000..c9f11a8dab
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/stty.c
@@ -0,0 +1,1439 @@
+/* vi: set sw=4 ts=4: */
+/* stty -- change and print terminal line settings
+ Copyright (C) 1990-1999 Free Software Foundation, Inc.
+
+ Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+*/
+/* Usage: stty [-ag] [-F device] [setting...]
+
+ Options:
+ -a Write all current settings to stdout in human-readable form.
+ -g Write all current settings to stdout in stty-readable form.
+ -F Open and use the specified device instead of stdin
+
+ If no args are given, write to stdout the baud rate and settings that
+ have been changed from their defaults. Mode reading and changes
+ are done on the specified device, or stdin if none was specified.
+
+ David MacKenzie <djm@gnu.ai.mit.edu>
+
+ Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
+
+ */
+
+#include "libbb.h"
+
+#ifndef _POSIX_VDISABLE
+# define _POSIX_VDISABLE ((unsigned char) 0)
+#endif
+
+#define Control(c) ((c) & 0x1f)
+/* Canonical values for control characters */
+#ifndef CINTR
+# define CINTR Control('c')
+#endif
+#ifndef CQUIT
+# define CQUIT 28
+#endif
+#ifndef CERASE
+# define CERASE 127
+#endif
+#ifndef CKILL
+# define CKILL Control('u')
+#endif
+#ifndef CEOF
+# define CEOF Control('d')
+#endif
+#ifndef CEOL
+# define CEOL _POSIX_VDISABLE
+#endif
+#ifndef CSTART
+# define CSTART Control('q')
+#endif
+#ifndef CSTOP
+# define CSTOP Control('s')
+#endif
+#ifndef CSUSP
+# define CSUSP Control('z')
+#endif
+#if defined(VEOL2) && !defined(CEOL2)
+# define CEOL2 _POSIX_VDISABLE
+#endif
+/* ISC renamed swtch to susp for termios, but we'll accept either name */
+#if defined(VSUSP) && !defined(VSWTCH)
+# define VSWTCH VSUSP
+# define CSWTCH CSUSP
+#endif
+#if defined(VSWTCH) && !defined(CSWTCH)
+# define CSWTCH _POSIX_VDISABLE
+#endif
+
+/* SunOS 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'.
+ So the default is to disable 'swtch.' */
+#if defined(__sparc__) && defined(__svr4__)
+# undef CSWTCH
+# define CSWTCH _POSIX_VDISABLE
+#endif
+
+#if defined(VWERSE) && !defined(VWERASE) /* AIX-3.2.5 */
+# define VWERASE VWERSE
+#endif
+#if defined(VDSUSP) && !defined(CDSUSP)
+# define CDSUSP Control('y')
+#endif
+#if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
+# define VREPRINT VRPRNT
+#endif
+#if defined(VREPRINT) && !defined(CRPRNT)
+# define CRPRNT Control('r')
+#endif
+#if defined(VWERASE) && !defined(CWERASE)
+# define CWERASE Control('w')
+#endif
+#if defined(VLNEXT) && !defined(CLNEXT)
+# define CLNEXT Control('v')
+#endif
+#if defined(VDISCARD) && !defined(VFLUSHO)
+# define VFLUSHO VDISCARD
+#endif
+#if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
+# define VFLUSHO VFLUSH
+#endif
+#if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
+# define ECHOCTL CTLECH
+#endif
+#if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
+# define ECHOCTL TCTLECH
+#endif
+#if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
+# define ECHOKE CRTKIL
+#endif
+#if defined(VFLUSHO) && !defined(CFLUSHO)
+# define CFLUSHO Control('o')
+#endif
+#if defined(VSTATUS) && !defined(CSTATUS)
+# define CSTATUS Control('t')
+#endif
+
+/* Which speeds to set */
+enum speed_setting {
+ input_speed, output_speed, both_speeds
+};
+
+/* Which member(s) of 'struct termios' a mode uses */
+enum {
+ /* Do NOT change the order or values, as mode_type_flag()
+ * depends on them */
+ control, input, output, local, combination
+};
+
+/* Flags for 'struct mode_info' */
+#define SANE_SET 1 /* Set in 'sane' mode */
+#define SANE_UNSET 2 /* Unset in 'sane' mode */
+#define REV 4 /* Can be turned off by prepending '-' */
+#define OMIT 8 /* Don't display value */
+
+
+/* Each mode.
+ * This structure should be kept as small as humanly possible.
+ */
+struct mode_info {
+ const uint8_t type; /* Which structure element to change */
+ const uint8_t flags; /* Setting and display options */
+ /* only these values are ever used, so... */
+#if (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x100
+ const uint8_t mask;
+#elif (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x10000
+ const uint16_t mask;
+#else
+ const tcflag_t mask; /* Other bits to turn off for this mode */
+#endif
+ /* was using short here, but ppc32 was unhappy */
+ const tcflag_t bits; /* Bits to set for this mode */
+};
+
+enum {
+ /* Must match mode_name[] and mode_info[] order! */
+ IDX_evenp = 0,
+ IDX_parity,
+ IDX_oddp,
+ IDX_nl,
+ IDX_ek,
+ IDX_sane,
+ IDX_cooked,
+ IDX_raw,
+ IDX_pass8,
+ IDX_litout,
+ IDX_cbreak,
+ IDX_crt,
+ IDX_dec,
+#ifdef IXANY
+ IDX_decctlq,
+#endif
+#if defined(TABDLY) || defined(OXTABS)
+ IDX_tabs,
+#endif
+#if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
+ IDX_lcase,
+ IDX_LCASE,
+#endif
+};
+
+#define MI_ENTRY(N,T,F,B,M) N "\0"
+
+/* Mode names given on command line */
+static const char mode_name[] =
+ MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("ek", combination, OMIT, 0, 0 )
+ MI_ENTRY("sane", combination, OMIT, 0, 0 )
+ MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("crt", combination, OMIT, 0, 0 )
+ MI_ENTRY("dec", combination, OMIT, 0, 0 )
+#ifdef IXANY
+ MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
+#endif
+#if defined(TABDLY) || defined(OXTABS)
+ MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
+#endif
+#if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
+ MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
+#endif
+ MI_ENTRY("parenb", control, REV, PARENB, 0 )
+ MI_ENTRY("parodd", control, REV, PARODD, 0 )
+ MI_ENTRY("cs5", control, 0, CS5, CSIZE)
+ MI_ENTRY("cs6", control, 0, CS6, CSIZE)
+ MI_ENTRY("cs7", control, 0, CS7, CSIZE)
+ MI_ENTRY("cs8", control, 0, CS8, CSIZE)
+ MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
+ MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
+ MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
+ MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
+ MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
+#ifdef CRTSCTS
+ MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
+#endif
+ MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
+ MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
+ MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
+ MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
+ MI_ENTRY("inpck", input, REV, INPCK, 0 )
+ MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
+ MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
+ MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
+ MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
+ MI_ENTRY("ixon", input, REV, IXON, 0 )
+ MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
+ MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 )
+#ifdef IUCLC
+ MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
+#endif
+#ifdef IXANY
+ MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
+#endif
+#ifdef IMAXBEL
+ MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
+#endif
+ MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
+#ifdef OLCUC
+ MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
+#endif
+#ifdef OCRNL
+ MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
+#endif
+#ifdef ONLCR
+ MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
+#endif
+#ifdef ONOCR
+ MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
+#endif
+#ifdef ONLRET
+ MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
+#endif
+#ifdef OFILL
+ MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
+#endif
+#ifdef OFDEL
+ MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
+#endif
+#ifdef NLDLY
+ MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
+ MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
+#endif
+#ifdef CRDLY
+ MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
+ MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
+ MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
+ MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
+#endif
+
+#ifdef TABDLY
+ MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
+ MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
+ MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
+ MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
+#else
+# ifdef OXTABS
+ MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
+# endif
+#endif
+
+#ifdef BSDLY
+ MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
+ MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
+#endif
+#ifdef VTDLY
+ MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
+ MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
+#endif
+#ifdef FFDLY
+ MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
+ MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
+#endif
+ MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
+ MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
+#ifdef IEXTEN
+ MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
+#endif
+ MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
+ MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
+ MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 )
+ MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
+ MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
+ MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
+#ifdef XCASE
+ MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
+#endif
+#ifdef TOSTOP
+ MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
+#endif
+#ifdef ECHOPRT
+ MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
+ MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 )
+#endif
+#ifdef ECHOCTL
+ MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
+ MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 )
+#endif
+#ifdef ECHOKE
+ MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
+ MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 )
+#endif
+ ;
+
+#undef MI_ENTRY
+#define MI_ENTRY(N,T,F,B,M) { T, F, M, B },
+
+static const struct mode_info mode_info[] = {
+ /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */
+ MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("ek", combination, OMIT, 0, 0 )
+ MI_ENTRY("sane", combination, OMIT, 0, 0 )
+ MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("crt", combination, OMIT, 0, 0 )
+ MI_ENTRY("dec", combination, OMIT, 0, 0 )
+#ifdef IXANY
+ MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
+#endif
+#if defined(TABDLY) || defined(OXTABS)
+ MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
+#endif
+#if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
+ MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
+#endif
+ MI_ENTRY("parenb", control, REV, PARENB, 0 )
+ MI_ENTRY("parodd", control, REV, PARODD, 0 )
+ MI_ENTRY("cs5", control, 0, CS5, CSIZE)
+ MI_ENTRY("cs6", control, 0, CS6, CSIZE)
+ MI_ENTRY("cs7", control, 0, CS7, CSIZE)
+ MI_ENTRY("cs8", control, 0, CS8, CSIZE)
+ MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
+ MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
+ MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
+ MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
+ MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
+#ifdef CRTSCTS
+ MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
+#endif
+ MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
+ MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
+ MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
+ MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
+ MI_ENTRY("inpck", input, REV, INPCK, 0 )
+ MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
+ MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
+ MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
+ MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
+ MI_ENTRY("ixon", input, REV, IXON, 0 )
+ MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
+ MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 )
+#ifdef IUCLC
+ MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
+#endif
+#ifdef IXANY
+ MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
+#endif
+#ifdef IMAXBEL
+ MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
+#endif
+ MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
+#ifdef OLCUC
+ MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
+#endif
+#ifdef OCRNL
+ MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
+#endif
+#ifdef ONLCR
+ MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
+#endif
+#ifdef ONOCR
+ MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
+#endif
+#ifdef ONLRET
+ MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
+#endif
+#ifdef OFILL
+ MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
+#endif
+#ifdef OFDEL
+ MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
+#endif
+#ifdef NLDLY
+ MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
+ MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
+#endif
+#ifdef CRDLY
+ MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
+ MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
+ MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
+ MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
+#endif
+
+#ifdef TABDLY
+ MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
+ MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
+ MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
+ MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
+#else
+# ifdef OXTABS
+ MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
+# endif
+#endif
+
+#ifdef BSDLY
+ MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
+ MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
+#endif
+#ifdef VTDLY
+ MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
+ MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
+#endif
+#ifdef FFDLY
+ MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
+ MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
+#endif
+ MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
+ MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
+#ifdef IEXTEN
+ MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
+#endif
+ MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
+ MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
+ MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 )
+ MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
+ MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
+ MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
+#ifdef XCASE
+ MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
+#endif
+#ifdef TOSTOP
+ MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
+#endif
+#ifdef ECHOPRT
+ MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
+ MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 )
+#endif
+#ifdef ECHOCTL
+ MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
+ MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 )
+#endif
+#ifdef ECHOKE
+ MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
+ MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 )
+#endif
+};
+
+enum {
+ NUM_mode_info = ARRAY_SIZE(mode_info)
+};
+
+
+/* Control characters */
+struct control_info {
+ const uint8_t saneval; /* Value to set for 'stty sane' */
+ const uint8_t offset; /* Offset in c_cc */
+};
+
+enum {
+ /* Must match control_name[] and control_info[] order! */
+ CIDX_intr = 0,
+ CIDX_quit,
+ CIDX_erase,
+ CIDX_kill,
+ CIDX_eof,
+ CIDX_eol,
+#ifdef VEOL2
+ CIDX_eol2,
+#endif
+#ifdef VSWTCH
+ CIDX_swtch,
+#endif
+ CIDX_start,
+ CIDX_stop,
+ CIDX_susp,
+#ifdef VDSUSP
+ CIDX_dsusp,
+#endif
+#ifdef VREPRINT
+ CIDX_rprnt,
+#endif
+#ifdef VWERASE
+ CIDX_werase,
+#endif
+#ifdef VLNEXT
+ CIDX_lnext,
+#endif
+#ifdef VFLUSHO
+ CIDX_flush,
+#endif
+#ifdef VSTATUS
+ CIDX_status,
+#endif
+ CIDX_min,
+ CIDX_time,
+};
+
+#define CI_ENTRY(n,s,o) n "\0"
+
+/* Name given on command line */
+static const char control_name[] =
+ CI_ENTRY("intr", CINTR, VINTR )
+ CI_ENTRY("quit", CQUIT, VQUIT )
+ CI_ENTRY("erase", CERASE, VERASE )
+ CI_ENTRY("kill", CKILL, VKILL )
+ CI_ENTRY("eof", CEOF, VEOF )
+ CI_ENTRY("eol", CEOL, VEOL )
+#ifdef VEOL2
+ CI_ENTRY("eol2", CEOL2, VEOL2 )
+#endif
+#ifdef VSWTCH
+ CI_ENTRY("swtch", CSWTCH, VSWTCH )
+#endif
+ CI_ENTRY("start", CSTART, VSTART )
+ CI_ENTRY("stop", CSTOP, VSTOP )
+ CI_ENTRY("susp", CSUSP, VSUSP )
+#ifdef VDSUSP
+ CI_ENTRY("dsusp", CDSUSP, VDSUSP )
+#endif
+#ifdef VREPRINT
+ CI_ENTRY("rprnt", CRPRNT, VREPRINT)
+#endif
+#ifdef VWERASE
+ CI_ENTRY("werase", CWERASE, VWERASE )
+#endif
+#ifdef VLNEXT
+ CI_ENTRY("lnext", CLNEXT, VLNEXT )
+#endif
+#ifdef VFLUSHO
+ CI_ENTRY("flush", CFLUSHO, VFLUSHO )
+#endif
+#ifdef VSTATUS
+ CI_ENTRY("status", CSTATUS, VSTATUS )
+#endif
+ /* These must be last because of the display routines */
+ CI_ENTRY("min", 1, VMIN )
+ CI_ENTRY("time", 0, VTIME )
+ ;
+
+#undef CI_ENTRY
+#define CI_ENTRY(n,s,o) { s, o },
+
+static const struct control_info control_info[] = {
+ /* This should be verbatim cut-n-paste copy of the above CI_ENTRYs */
+ CI_ENTRY("intr", CINTR, VINTR )
+ CI_ENTRY("quit", CQUIT, VQUIT )
+ CI_ENTRY("erase", CERASE, VERASE )
+ CI_ENTRY("kill", CKILL, VKILL )
+ CI_ENTRY("eof", CEOF, VEOF )
+ CI_ENTRY("eol", CEOL, VEOL )
+#ifdef VEOL2
+ CI_ENTRY("eol2", CEOL2, VEOL2 )
+#endif
+#ifdef VSWTCH
+ CI_ENTRY("swtch", CSWTCH, VSWTCH )
+#endif
+ CI_ENTRY("start", CSTART, VSTART )
+ CI_ENTRY("stop", CSTOP, VSTOP )
+ CI_ENTRY("susp", CSUSP, VSUSP )
+#ifdef VDSUSP
+ CI_ENTRY("dsusp", CDSUSP, VDSUSP )
+#endif
+#ifdef VREPRINT
+ CI_ENTRY("rprnt", CRPRNT, VREPRINT)
+#endif
+#ifdef VWERASE
+ CI_ENTRY("werase", CWERASE, VWERASE )
+#endif
+#ifdef VLNEXT
+ CI_ENTRY("lnext", CLNEXT, VLNEXT )
+#endif
+#ifdef VFLUSHO
+ CI_ENTRY("flush", CFLUSHO, VFLUSHO )
+#endif
+#ifdef VSTATUS
+ CI_ENTRY("status", CSTATUS, VSTATUS )
+#endif
+ /* These must be last because of the display routines */
+ CI_ENTRY("min", 1, VMIN )
+ CI_ENTRY("time", 0, VTIME )
+};
+
+enum {
+ NUM_control_info = ARRAY_SIZE(control_info)
+};
+
+
+struct globals {
+ const char *device_name; // = bb_msg_standard_input;
+ /* The width of the screen, for output wrapping */
+ unsigned max_col; // = 80;
+ /* Current position, to know when to wrap */
+ unsigned current_col;
+ char buf[10];
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+#define INIT_G() do { \
+ G.device_name = bb_msg_standard_input; \
+ G.max_col = 80; \
+} while (0)
+
+
+/* Return a string that is the printable representation of character CH */
+/* Adapted from 'cat' by Torbjorn Granlund */
+static const char *visible(unsigned ch)
+{
+ char *bpout = G.buf;
+
+ if (ch == _POSIX_VDISABLE)
+ return "<undef>";
+
+ if (ch >= 128) {
+ ch -= 128;
+ *bpout++ = 'M';
+ *bpout++ = '-';
+ }
+
+ if (ch < 32) {
+ *bpout++ = '^';
+ *bpout++ = ch + 64;
+ } else if (ch < 127) {
+ *bpout++ = ch;
+ } else {
+ *bpout++ = '^';
+ *bpout++ = '?';
+ }
+
+ *bpout = '\0';
+ return G.buf;
+}
+
+static tcflag_t *mode_type_flag(unsigned type, const struct termios *mode)
+{
+ static const uint8_t tcflag_offsets[] ALIGN1 = {
+ offsetof(struct termios, c_cflag), /* control */
+ offsetof(struct termios, c_iflag), /* input */
+ offsetof(struct termios, c_oflag), /* output */
+ offsetof(struct termios, c_lflag) /* local */
+ };
+
+ if (type <= local) {
+ return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]);
+ }
+ return NULL;
+}
+
+static void set_speed_or_die(enum speed_setting type, const char *const arg,
+ struct termios * const mode)
+{
+ speed_t baud;
+
+ baud = tty_value_to_baud(xatou(arg));
+
+ if (type != output_speed) { /* either input or both */
+ cfsetispeed(mode, baud);
+ }
+ if (type != input_speed) { /* either output or both */
+ cfsetospeed(mode, baud);
+ }
+}
+
+static ATTRIBUTE_NORETURN void perror_on_device_and_die(const char *fmt)
+{
+ bb_perror_msg_and_die(fmt, G.device_name);
+}
+
+static void perror_on_device(const char *fmt)
+{
+ bb_perror_msg(fmt, G.device_name);
+}
+
+/* Print format string MESSAGE and optional args.
+ Wrap to next line first if it won't fit.
+ Print a space first unless MESSAGE will start a new line */
+static void wrapf(const char *message, ...)
+{
+ char buf[128];
+ va_list args;
+ unsigned buflen;
+
+ va_start(args, message);
+ buflen = vsnprintf(buf, sizeof(buf), message, args);
+ va_end(args);
+ /* We seem to be called only with suitable lengths, but check if
+ somebody failed to adhere to this assumption just to be sure. */
+ if (!buflen || buflen >= sizeof(buf)) return;
+
+ if (G.current_col > 0) {
+ G.current_col++;
+ if (buf[0] != '\n') {
+ if (G.current_col + buflen >= G.max_col) {
+ bb_putchar('\n');
+ G.current_col = 0;
+ } else
+ bb_putchar(' ');
+ }
+ }
+ fputs(buf, stdout);
+ G.current_col += buflen;
+ if (buf[buflen-1] == '\n')
+ G.current_col = 0;
+}
+
+static void set_window_size(const int rows, const int cols)
+{
+ struct winsize win = { 0, 0, 0, 0 };
+
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win)) {
+ if (errno != EINVAL) {
+ goto bail;
+ }
+ memset(&win, 0, sizeof(win));
+ }
+
+ if (rows >= 0)
+ win.ws_row = rows;
+ if (cols >= 0)
+ win.ws_col = cols;
+
+ if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
+bail:
+ perror_on_device("%s");
+}
+
+static void display_window_size(const int fancy)
+{
+ const char *fmt_str = "%s\0%s: no size information for this device";
+ unsigned width, height;
+
+ if (get_terminal_width_height(STDIN_FILENO, &width, &height)) {
+ if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
+ perror_on_device(fmt_str);
+ }
+ } else {
+ wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
+ height, width);
+ }
+}
+
+static const struct suffix_mult stty_suffixes[] = {
+ { "b", 512 },
+ { "k", 1024 },
+ { "B", 1024 },
+ { }
+};
+
+static const struct mode_info *find_mode(const char *name)
+{
+ int i = index_in_strings(mode_name, name);
+ return i >= 0 ? &mode_info[i] : NULL;
+}
+
+static const struct control_info *find_control(const char *name)
+{
+ int i = index_in_strings(control_name, name);
+ return i >= 0 ? &control_info[i] : NULL;
+}
+
+enum {
+ param_need_arg = 0x80,
+ param_line = 1 | 0x80,
+ param_rows = 2 | 0x80,
+ param_cols = 3 | 0x80,
+ param_columns = 4 | 0x80,
+ param_size = 5,
+ param_speed = 6,
+ param_ispeed = 7 | 0x80,
+ param_ospeed = 8 | 0x80,
+};
+
+static int find_param(const char *const name)
+{
+ static const char params[] ALIGN1 =
+ "line\0" /* 1 */
+ "rows\0" /* 2 */
+ "cols\0" /* 3 */
+ "columns\0" /* 4 */
+ "size\0" /* 5 */
+ "speed\0" /* 6 */
+ "ispeed\0"
+ "ospeed\0";
+ int i = index_in_strings(params, name) + 1;
+ if (i == 0)
+ return 0;
+ if (i != 5 && i != 6)
+ i |= 0x80;
+ return i;
+}
+
+static int recover_mode(const char *arg, struct termios *mode)
+{
+ int i, n;
+ unsigned chr;
+ unsigned long iflag, oflag, cflag, lflag;
+
+ /* Scan into temporaries since it is too much trouble to figure out
+ the right format for 'tcflag_t' */
+ if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
+ &iflag, &oflag, &cflag, &lflag, &n) != 4)
+ return 0;
+ mode->c_iflag = iflag;
+ mode->c_oflag = oflag;
+ mode->c_cflag = cflag;
+ mode->c_lflag = lflag;
+ arg += n;
+ for (i = 0; i < NCCS; ++i) {
+ if (sscanf(arg, ":%x%n", &chr, &n) != 1)
+ return 0;
+ mode->c_cc[i] = chr;
+ arg += n;
+ }
+
+ /* Fail if there are too many fields */
+ if (*arg != '\0')
+ return 0;
+
+ return 1;
+}
+
+static void display_recoverable(const struct termios *mode,
+ int ATTRIBUTE_UNUSED dummy)
+{
+ int i;
+ printf("%lx:%lx:%lx:%lx",
+ (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
+ (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
+ for (i = 0; i < NCCS; ++i)
+ printf(":%x", (unsigned int) mode->c_cc[i]);
+ bb_putchar('\n');
+}
+
+static void display_speed(const struct termios *mode, int fancy)
+{
+ //01234567 8 9
+ const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;";
+ unsigned long ispeed, ospeed;
+
+ ospeed = ispeed = cfgetispeed(mode);
+ if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) {
+ ispeed = ospeed; /* in case ispeed was 0 */
+ //0123 4 5 6 7 8 9
+ fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;";
+ }
+ if (fancy) fmt_str += 9;
+ wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
+}
+
+static void do_display(const struct termios *mode, const int all)
+{
+ int i;
+ tcflag_t *bitsp;
+ unsigned long mask;
+ int prev_type = control;
+
+ display_speed(mode, 1);
+ if (all)
+ display_window_size(1);
+#ifdef HAVE_C_LINE
+ wrapf("line = %d;\n", mode->c_line);
+#else
+ wrapf("\n");
+#endif
+
+ for (i = 0; i != CIDX_min; ++i) {
+ /* If swtch is the same as susp, don't print both */
+#if VSWTCH == VSUSP
+ if (i == CIDX_swtch)
+ continue;
+#endif
+ /* If eof uses the same slot as min, only print whichever applies */
+#if VEOF == VMIN
+ if ((mode->c_lflag & ICANON) == 0
+ && (i == CIDX_eof || i == CIDX_eol)
+ ) {
+ continue;
+ }
+#endif
+ wrapf("%s = %s;", nth_string(control_name, i),
+ visible(mode->c_cc[control_info[i].offset]));
+ }
+#if VEOF == VMIN
+ if ((mode->c_lflag & ICANON) == 0)
+#endif
+ wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
+ if (G.current_col) wrapf("\n");
+
+ for (i = 0; i < NUM_mode_info; ++i) {
+ if (mode_info[i].flags & OMIT)
+ continue;
+ if (mode_info[i].type != prev_type) {
+ /* wrapf("\n"); */
+ if (G.current_col) wrapf("\n");
+ prev_type = mode_info[i].type;
+ }
+
+ bitsp = mode_type_flag(mode_info[i].type, mode);
+ mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
+ if ((*bitsp & mask) == mode_info[i].bits) {
+ if (all || (mode_info[i].flags & SANE_UNSET))
+ wrapf("-%s"+1, nth_string(mode_name, i));
+ } else {
+ if ((all && mode_info[i].flags & REV)
+ || (!all && (mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
+ ) {
+ wrapf("-%s", nth_string(mode_name, i));
+ }
+ }
+ }
+ if (G.current_col) wrapf("\n");
+}
+
+static void sane_mode(struct termios *mode)
+{
+ int i;
+ tcflag_t *bitsp;
+
+ for (i = 0; i < NUM_control_info; ++i) {
+#if VMIN == VEOF
+ if (i == CIDX_min)
+ break;
+#endif
+ mode->c_cc[control_info[i].offset] = control_info[i].saneval;
+ }
+
+ for (i = 0; i < NUM_mode_info; ++i) {
+ if (mode_info[i].flags & SANE_SET) {
+ bitsp = mode_type_flag(mode_info[i].type, mode);
+ *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask))
+ | mode_info[i].bits;
+ } else if (mode_info[i].flags & SANE_UNSET) {
+ bitsp = mode_type_flag(mode_info[i].type, mode);
+ *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask)
+ & ~mode_info[i].bits;
+ }
+ }
+}
+
+/* Save set_mode from #ifdef forest plague */
+#ifndef ONLCR
+#define ONLCR 0
+#endif
+#ifndef OCRNL
+#define OCRNL 0
+#endif
+#ifndef ONLRET
+#define ONLRET 0
+#endif
+#ifndef XCASE
+#define XCASE 0
+#endif
+#ifndef IXANY
+#define IXANY 0
+#endif
+#ifndef TABDLY
+#define TABDLY 0
+#endif
+#ifndef OXTABS
+#define OXTABS 0
+#endif
+#ifndef IUCLC
+#define IUCLC 0
+#endif
+#ifndef OLCUC
+#define OLCUC 0
+#endif
+#ifndef ECHOCTL
+#define ECHOCTL 0
+#endif
+#ifndef ECHOKE
+#define ECHOKE 0
+#endif
+
+static void set_mode(const struct mode_info *info, int reversed,
+ struct termios *mode)
+{
+ tcflag_t *bitsp;
+
+ bitsp = mode_type_flag(info->type, mode);
+
+ if (bitsp) {
+ if (reversed)
+ *bitsp = *bitsp & ~info->mask & ~info->bits;
+ else
+ *bitsp = (*bitsp & ~info->mask) | info->bits;
+ return;
+ }
+
+ /* Combination mode */
+ if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) {
+ if (reversed)
+ mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
+ else
+ mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
+ } else if (info == &mode_info[IDX_oddp]) {
+ if (reversed)
+ mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
+ else
+ mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
+ } else if (info == &mode_info[IDX_nl]) {
+ if (reversed) {
+ mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
+ mode->c_oflag = (mode->c_oflag | ONLCR) & ~OCRNL & ~ONLRET;
+ } else {
+ mode->c_iflag = mode->c_iflag & ~ICRNL;
+ if (ONLCR) mode->c_oflag = mode->c_oflag & ~ONLCR;
+ }
+ } else if (info == &mode_info[IDX_ek]) {
+ mode->c_cc[VERASE] = CERASE;
+ mode->c_cc[VKILL] = CKILL;
+ } else if (info == &mode_info[IDX_sane]) {
+ sane_mode(mode);
+ } else if (info == &mode_info[IDX_cbreak]) {
+ if (reversed)
+ mode->c_lflag |= ICANON;
+ else
+ mode->c_lflag &= ~ICANON;
+ } else if (info == &mode_info[IDX_pass8]) {
+ if (reversed) {
+ mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
+ mode->c_iflag |= ISTRIP;
+ } else {
+ mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
+ mode->c_iflag &= ~ISTRIP;
+ }
+ } else if (info == &mode_info[IDX_litout]) {
+ if (reversed) {
+ mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
+ mode->c_iflag |= ISTRIP;
+ mode->c_oflag |= OPOST;
+ } else {
+ mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
+ mode->c_iflag &= ~ISTRIP;
+ mode->c_oflag &= ~OPOST;
+ }
+ } else if (info == &mode_info[IDX_raw] || info == &mode_info[IDX_cooked]) {
+ if ((info == &mode_info[IDX_raw] && reversed)
+ || (info == &mode_info[IDX_cooked] && !reversed)
+ ) {
+ /* Cooked mode */
+ mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
+ mode->c_oflag |= OPOST;
+ mode->c_lflag |= ISIG | ICANON;
+#if VMIN == VEOF
+ mode->c_cc[VEOF] = CEOF;
+#endif
+#if VTIME == VEOL
+ mode->c_cc[VEOL] = CEOL;
+#endif
+ } else {
+ /* Raw mode */
+ mode->c_iflag = 0;
+ mode->c_oflag &= ~OPOST;
+ mode->c_lflag &= ~(ISIG | ICANON | XCASE);
+ mode->c_cc[VMIN] = 1;
+ mode->c_cc[VTIME] = 0;
+ }
+ }
+ else if (IXANY && info == &mode_info[IDX_decctlq]) {
+ if (reversed)
+ mode->c_iflag |= IXANY;
+ else
+ mode->c_iflag &= ~IXANY;
+ }
+ else if (TABDLY && info == &mode_info[IDX_tabs]) {
+ if (reversed)
+ mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
+ else
+ mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
+ }
+ else if (OXTABS && info == &mode_info[IDX_tabs]) {
+ if (reversed)
+ mode->c_oflag |= OXTABS;
+ else
+ mode->c_oflag &= ~OXTABS;
+ } else
+ if (XCASE && IUCLC && OLCUC
+ && (info == &mode_info[IDX_lcase] || info == &mode_info[IDX_LCASE])
+ ) {
+ if (reversed) {
+ mode->c_lflag &= ~XCASE;
+ mode->c_iflag &= ~IUCLC;
+ mode->c_oflag &= ~OLCUC;
+ } else {
+ mode->c_lflag |= XCASE;
+ mode->c_iflag |= IUCLC;
+ mode->c_oflag |= OLCUC;
+ }
+ } else if (info == &mode_info[IDX_crt]) {
+ mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
+ } else if (info == &mode_info[IDX_dec]) {
+ mode->c_cc[VINTR] = 3; /* ^C */
+ mode->c_cc[VERASE] = 127; /* DEL */
+ mode->c_cc[VKILL] = 21; /* ^U */
+ mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
+ if (IXANY) mode->c_iflag &= ~IXANY;
+ }
+}
+
+static void set_control_char_or_die(const struct control_info *info,
+ const char *arg, struct termios *mode)
+{
+ unsigned char value;
+
+ if (info == &control_info[CIDX_min] || info == &control_info[CIDX_time])
+ value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
+ else if (arg[0] == '\0' || arg[1] == '\0')
+ value = arg[0];
+ else if (!strcmp(arg, "^-") || !strcmp(arg, "undef"))
+ value = _POSIX_VDISABLE;
+ else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */
+ value = arg[1] & 0x1f; /* Non-letters get weird results */
+ if (arg[1] == '?')
+ value = 127;
+ } else
+ value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
+ mode->c_cc[info->offset] = value;
+}
+
+#define STTY_require_set_attr (1 << 0)
+#define STTY_speed_was_set (1 << 1)
+#define STTY_verbose_output (1 << 2)
+#define STTY_recoverable_output (1 << 3)
+#define STTY_noargs (1 << 4)
+
+int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int stty_main(int argc, char **argv)
+{
+ struct termios mode;
+ void (*output_func)(const struct termios *, const int);
+ const char *file_name = NULL;
+ int display_all = 0;
+ int stty_state;
+ int k;
+
+ INIT_G();
+
+ stty_state = STTY_noargs;
+ output_func = do_display;
+
+ /* First pass: only parse/verify command line params */
+ k = 0;
+ while (argv[++k]) {
+ const struct mode_info *mp;
+ const struct control_info *cp;
+ const char *arg = argv[k];
+ const char *argnext = argv[k+1];
+ int param;
+
+ if (arg[0] == '-') {
+ int i;
+ mp = find_mode(arg+1);
+ if (mp) {
+ if (!(mp->flags & REV))
+ goto invalid_argument;
+ stty_state &= ~STTY_noargs;
+ continue;
+ }
+ /* It is an option - parse it */
+ i = 0;
+ while (arg[++i]) {
+ switch (arg[i]) {
+ case 'a':
+ stty_state |= STTY_verbose_output;
+ output_func = do_display;
+ display_all = 1;
+ break;
+ case 'g':
+ stty_state |= STTY_recoverable_output;
+ output_func = display_recoverable;
+ break;
+ case 'F':
+ if (file_name)
+ bb_error_msg_and_die("only one device may be specified");
+ file_name = &arg[i+1]; /* "-Fdevice" ? */
+ if (!file_name[0]) { /* nope, "-F device" */
+ int p = k+1; /* argv[p] is argnext */
+ file_name = argnext;
+ if (!file_name)
+ bb_error_msg_and_die(bb_msg_requires_arg, "-F");
+ /* remove -F param from arg[vc] */
+ --argc;
+ while (argv[p]) { argv[p] = argv[p+1]; ++p; }
+ }
+ goto end_option;
+ default:
+ goto invalid_argument;
+ }
+ }
+ end_option:
+ continue;
+ }
+
+ mp = find_mode(arg);
+ if (mp) {
+ stty_state &= ~STTY_noargs;
+ continue;
+ }
+
+ cp = find_control(arg);
+ if (cp) {
+ if (!argnext)
+ bb_error_msg_and_die(bb_msg_requires_arg, arg);
+ /* called for the side effect of xfunc death only */
+ set_control_char_or_die(cp, argnext, &mode);
+ stty_state &= ~STTY_noargs;
+ ++k;
+ continue;
+ }
+
+ param = find_param(arg);
+ if (param & param_need_arg) {
+ if (!argnext)
+ bb_error_msg_and_die(bb_msg_requires_arg, arg);
+ ++k;
+ }
+
+ switch (param) {
+#ifdef HAVE_C_LINE
+ case param_line:
+# ifndef TIOCGWINSZ
+ xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
+ break;
+# endif /* else fall-through */
+#endif
+#ifdef TIOCGWINSZ
+ case param_rows:
+ case param_cols:
+ case param_columns:
+ xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
+ break;
+ case param_size:
+#endif
+ case param_speed:
+ break;
+ case param_ispeed:
+ /* called for the side effect of xfunc death only */
+ set_speed_or_die(input_speed, argnext, &mode);
+ break;
+ case param_ospeed:
+ /* called for the side effect of xfunc death only */
+ set_speed_or_die(output_speed, argnext, &mode);
+ break;
+ default:
+ if (recover_mode(arg, &mode) == 1) break;
+ if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break;
+ invalid_argument:
+ bb_error_msg_and_die("invalid argument '%s'", arg);
+ }
+ stty_state &= ~STTY_noargs;
+ }
+
+ /* Specifying both -a and -g is an error */
+ if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) ==
+ (STTY_verbose_output | STTY_recoverable_output))
+ bb_error_msg_and_die("verbose and stty-readable output styles are mutually exclusive");
+ /* Specifying -a or -g with non-options is an error */
+ if (!(stty_state & STTY_noargs) &&
+ (stty_state & (STTY_verbose_output | STTY_recoverable_output)))
+ bb_error_msg_and_die("modes may not be set when specifying an output style");
+
+ /* Now it is safe to start doing things */
+ if (file_name) {
+ int fd, fdflags;
+ G.device_name = file_name;
+ fd = xopen(G.device_name, O_RDONLY | O_NONBLOCK);
+ if (fd != STDIN_FILENO) {
+ dup2(fd, STDIN_FILENO);
+ close(fd);
+ }
+ fdflags = fcntl(STDIN_FILENO, F_GETFL);
+ if (fdflags < 0 ||
+ fcntl(STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
+ perror_on_device_and_die("%s: cannot reset non-blocking mode");
+ }
+
+ /* Initialize to all zeroes so there is no risk memcmp will report a
+ spurious difference in an uninitialized portion of the structure */
+ memset(&mode, 0, sizeof(mode));
+ if (tcgetattr(STDIN_FILENO, &mode))
+ perror_on_device_and_die("%s");
+
+ if (stty_state & (STTY_verbose_output | STTY_recoverable_output | STTY_noargs)) {
+ get_terminal_width_height(STDOUT_FILENO, &G.max_col, NULL);
+ output_func(&mode, display_all);
+ return EXIT_SUCCESS;
+ }
+
+ /* Second pass: perform actions */
+ k = 0;
+ while (argv[++k]) {
+ const struct mode_info *mp;
+ const struct control_info *cp;
+ const char *arg = argv[k];
+ const char *argnext = argv[k+1];
+ int param;
+
+ if (arg[0] == '-') {
+ mp = find_mode(arg+1);
+ if (mp) {
+ set_mode(mp, 1 /* reversed */, &mode);
+ stty_state |= STTY_require_set_attr;
+ }
+ /* It is an option - already parsed. Skip it */
+ continue;
+ }
+
+ mp = find_mode(arg);
+ if (mp) {
+ set_mode(mp, 0 /* non-reversed */, &mode);
+ stty_state |= STTY_require_set_attr;
+ continue;
+ }
+
+ cp = find_control(arg);
+ if (cp) {
+ ++k;
+ set_control_char_or_die(cp, argnext, &mode);
+ stty_state |= STTY_require_set_attr;
+ continue;
+ }
+
+ param = find_param(arg);
+ if (param & param_need_arg) {
+ ++k;
+ }
+
+ switch (param) {
+#ifdef HAVE_C_LINE
+ case param_line:
+ mode.c_line = xatoul_sfx(argnext, stty_suffixes);
+ stty_state |= STTY_require_set_attr;
+ break;
+#endif
+#ifdef TIOCGWINSZ
+ case param_cols:
+ set_window_size(-1, xatoul_sfx(argnext, stty_suffixes));
+ break;
+ case param_size:
+ display_window_size(0);
+ break;
+ case param_rows:
+ set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
+ break;
+#endif
+ case param_speed:
+ display_speed(&mode, 0);
+ break;
+ case param_ispeed:
+ set_speed_or_die(input_speed, argnext, &mode);
+ stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
+ break;
+ case param_ospeed:
+ set_speed_or_die(output_speed, argnext, &mode);
+ stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
+ break;
+ default:
+ if (recover_mode(arg, &mode) == 1)
+ stty_state |= STTY_require_set_attr;
+ else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{
+ set_speed_or_die(both_speeds, arg, &mode);
+ stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
+ } /* else - impossible (caught in the first pass):
+ bb_error_msg_and_die("invalid argument '%s'", arg); */
+ }
+ }
+
+ if (stty_state & STTY_require_set_attr) {
+ struct termios new_mode;
+
+ if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
+ perror_on_device_and_die("%s");
+
+ /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
+ it performs *any* of the requested operations. This means it
+ can report 'success' when it has actually failed to perform
+ some proper subset of the requested operations. To detect
+ this partial failure, get the current terminal attributes and
+ compare them to the requested ones */
+
+ /* Initialize to all zeroes so there is no risk memcmp will report a
+ spurious difference in an uninitialized portion of the structure */
+ memset(&new_mode, 0, sizeof(new_mode));
+ if (tcgetattr(STDIN_FILENO, &new_mode))
+ perror_on_device_and_die("%s");
+
+ if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
+#ifdef CIBAUD
+ /* SunOS 4.1.3 (at least) has the problem that after this sequence,
+ tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
+ sometimes (m1 != m2). The only difference is in the four bits
+ of the c_cflag field corresponding to the baud rate. To save
+ Sun users a little confusion, don't report an error if this
+ happens. But suppress the error only if we haven't tried to
+ set the baud rate explicitly -- otherwise we'd never give an
+ error for a true failure to set the baud rate */
+
+ new_mode.c_cflag &= (~CIBAUD);
+ if ((stty_state & STTY_speed_was_set)
+ || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
+#endif
+ perror_on_device_and_die("%s: cannot perform all requested operations");
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/sum.c b/cleopatre/busybox-1.11.1-spc300/coreutils/sum.c
new file mode 100644
index 0000000000..e6cfbfd806
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/sum.c
@@ -0,0 +1,99 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * sum -- checksum and count the blocks in a file
+ * Like BSD sum or SysV sum -r, except like SysV sum if -s option is given.
+ *
+ * Copyright (C) 86, 89, 91, 1995-2002, 2004 Free Software Foundation, Inc.
+ * Copyright (C) 2005 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2005 by Mike Frysinger <vapier@gentoo.org>
+ *
+ * Written by Kayvan Aghaiepour and David MacKenzie
+ * Taken from coreutils and turned into a busybox applet by Mike Frysinger
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+
+enum { SUM_BSD, PRINT_NAME, SUM_SYSV };
+
+/* BSD: calculate and print the rotated checksum and the size in 1K blocks
+ The checksum varies depending on sizeof (int). */
+/* SYSV: calculate and print the checksum and the size in 512-byte blocks */
+/* Return 1 if successful. */
+static unsigned sum_file(const char *file, unsigned type)
+{
+#define buf bb_common_bufsiz1
+ unsigned long long total_bytes = 0;
+ int fd, r;
+ /* The sum of all the input bytes, modulo (UINT_MAX + 1). */
+ unsigned s = 0;
+
+ fd = open_or_warn_stdin(file);
+ if (fd == -1)
+ return 0;
+
+ while (1) {
+ size_t bytes_read = safe_read(fd, buf, BUFSIZ);
+
+ if ((ssize_t)bytes_read <= 0) {
+ r = (fd && close(fd) != 0);
+ if (!bytes_read && !r)
+ /* no error */
+ break;
+ bb_perror_msg(file);
+ return 0;
+ }
+
+ total_bytes += bytes_read;
+ if (type >= SUM_SYSV) {
+ do s += buf[--bytes_read]; while (bytes_read);
+ } else {
+ r = 0;
+ do {
+ s = (s >> 1) + ((s & 1) << 15);
+ s += buf[r++];
+ s &= 0xffff; /* Keep it within bounds. */
+ } while (--bytes_read);
+ }
+ }
+
+ if (type < PRINT_NAME)
+ file = "";
+ if (type >= SUM_SYSV) {
+ r = (s & 0xffff) + ((s & 0xffffffff) >> 16);
+ s = (r & 0xffff) + (r >> 16);
+ printf("%d %llu %s\n", s, (total_bytes + 511) / 512, file);
+ } else
+ printf("%05d %5llu %s\n", s, (total_bytes + 1023) / 1024, file);
+ return 1;
+#undef buf
+}
+
+int sum_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int sum_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ unsigned n;
+ unsigned type = SUM_BSD;
+
+ n = getopt32(argv, "sr");
+ argv += optind;
+ if (n & 1) type = SUM_SYSV;
+ /* give the bsd priority over sysv func */
+ if (n & 2) type = SUM_BSD;
+
+ if (!argv[0]) {
+ /* Do not print the name */
+ n = sum_file("-", type);
+ } else {
+ /* Need to print the name if either
+ - more than one file given
+ - doing sysv */
+ type += (argv[1] || type == SUM_SYSV);
+ n = 1;
+ do {
+ n &= sum_file(*argv, type);
+ } while (*++argv);
+ }
+ return !n;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/sync.c b/cleopatre/busybox-1.11.1-spc300/coreutils/sync.c
new file mode 100644
index 0000000000..5c9d0926f7
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/sync.c
@@ -0,0 +1,25 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini sync implementation for busybox
+ *
+ * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */
+
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
+
+int sync_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int sync_main(int argc, char **argv ATTRIBUTE_UNUSED)
+{
+ /* coreutils-6.9 compat */
+ bb_warn_ignoring_args(argc - 1);
+
+ sync();
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/tac.c b/cleopatre/busybox-1.11.1-spc300/coreutils/tac.c
new file mode 100644
index 0000000000..af70f30925
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/tac.c
@@ -0,0 +1,106 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * tac implementation for busybox
+ *
+ * Copyright (C) 2003 Yang Xiaopeng <yxp at hanwang.com.cn>
+ * Copyright (C) 2007 Natanael Copa <natanael.copa@gmail.com>
+ * Copyright (C) 2007 Tito Ragusa <farmatito@tiscali.it>
+ *
+ * Licensed under GPLv2, see file License in this tarball for details.
+ *
+ */
+
+/* tac - concatenate and print files in reverse */
+
+/* Based on Yang Xiaopeng's (yxp at hanwang.com.cn) patch
+ * http://www.uclibc.org/lists/busybox/2003-July/008813.html
+ */
+
+#include "libbb.h"
+
+/* This is a NOEXEC applet. Be very careful! */
+
+struct lstring {
+ int size;
+ char buf[1];
+};
+
+int tac_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int tac_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ char **name;
+ FILE *f;
+ struct lstring *line = NULL;
+ llist_t *list = NULL;
+ int retval = EXIT_SUCCESS;
+
+#if ENABLE_DESKTOP
+/* tac from coreutils 6.9 supports:
+ -b, --before
+ attach the separator before instead of after
+ -r, --regex
+ interpret the separator as a regular expression
+ -s, --separator=STRING
+ use STRING as the separator instead of newline
+We support none, but at least we will complain or handle "--":
+*/
+ getopt32(argv, "");
+ argv += optind;
+#else
+ argv++;
+#endif
+ if (!*argv)
+ *--argv = (char *)"-";
+ /* We will read from last file to first */
+ name = argv;
+ while (*name)
+ name++;
+
+ do {
+ int ch, i;
+
+ name--;
+ f = fopen_or_warn_stdin(*name);
+ if (f == NULL) {
+ /* error message is printed by fopen_or_warn_stdin */
+ retval = EXIT_FAILURE;
+ continue;
+ }
+
+ errno = i = 0;
+ do {
+ ch = fgetc(f);
+ if (ch != EOF) {
+ if (!(i & 0x7f))
+ /* Grow on every 128th char */
+ line = xrealloc(line, i + 0x7f + sizeof(int) + 1);
+ line->buf[i++] = ch;
+ }
+ if (ch == '\n' || (ch == EOF && i != 0)) {
+ line = xrealloc(line, i + sizeof(int));
+ line->size = i;
+ llist_add_to(&list, line);
+ line = NULL;
+ i = 0;
+ }
+ } while (ch != EOF);
+ /* fgetc sets errno to ENOENT on EOF, we don't want
+ * to warn on this non-error! */
+ if (errno && errno != ENOENT) {
+ bb_simple_perror_msg(*name);
+ retval = EXIT_FAILURE;
+ }
+ } while (name != argv);
+
+ while (list) {
+ line = (struct lstring *)list->data;
+ xwrite(STDOUT_FILENO, line->buf, line->size);
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ free(llist_pop(&list));
+ } else {
+ list = list->link;
+ }
+ }
+
+ return retval;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/tail.c b/cleopatre/busybox-1.11.1-spc300/coreutils/tail.c
new file mode 100644
index 0000000000..2505fc3a60
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/tail.c
@@ -0,0 +1,284 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini tail implementation for busybox
+ *
+ * Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 compliant (need fancy for -c) */
+/* BB_AUDIT GNU compatible -c, -q, and -v options in 'fancy' configuration. */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/tail.html */
+
+/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
+ *
+ * Pretty much rewritten to fix numerous bugs and reduce realloc() calls.
+ * Bugs fixed (although I may have forgotten one or two... it was pretty bad)
+ * 1) mixing printf/write without fflush()ing stdout
+ * 2) no check that any open files are present
+ * 3) optstring had -q taking an arg
+ * 4) no error checking on write in some cases, and a warning even then
+ * 5) q and s interaction bug
+ * 6) no check for lseek error
+ * 7) lseek attempted when count==0 even if arg was +0 (from top)
+ */
+
+#include "libbb.h"
+
+static const struct suffix_mult tail_suffixes[] = {
+ { "b", 512 },
+ { "k", 1024 },
+ { "m", 1024*1024 },
+ { }
+};
+
+struct globals {
+ bool status;
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+
+static void tail_xprint_header(const char *fmt, const char *filename)
+{
+ if (fdprintf(STDOUT_FILENO, fmt, filename) < 0)
+ bb_perror_nomsg_and_die();
+}
+
+static ssize_t tail_read(int fd, char *buf, size_t count)
+{
+ ssize_t r;
+ off_t current;
+ struct stat sbuf;
+
+ /* (A good comment is missing here) */
+ current = lseek(fd, 0, SEEK_CUR);
+ /* /proc files report zero st_size, don't lseek them. */
+ if (fstat(fd, &sbuf) == 0 && sbuf.st_size)
+ if (sbuf.st_size < current)
+ lseek(fd, 0, SEEK_SET);
+
+ r = full_read(fd, buf, count);
+ if (r < 0) {
+ bb_perror_msg(bb_msg_read_error);
+ G.status = EXIT_FAILURE;
+ }
+
+ return r;
+}
+
+static const char header_fmt[] ALIGN1 = "\n==> %s <==\n";
+
+static unsigned eat_num(const char *p)
+{
+ if (*p == '-')
+ p++;
+ else if (*p == '+') {
+ p++;
+ G.status = 1; /* mark that we saw "+" */
+ }
+ return xatou_sfx(p, tail_suffixes);
+}
+
+int tail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int tail_main(int argc, char **argv)
+{
+ unsigned count = 10;
+ unsigned sleep_period = 1;
+ bool from_top;
+ int header_threshhold = 1;
+ const char *str_c, *str_n;
+
+ char *tailbuf;
+ size_t tailbufsize;
+ int taillen = 0;
+ int newlines_seen = 0;
+ int nfiles, nread, nwrite, i, opt;
+ unsigned seen;
+
+ int *fds;
+ char *s, *buf;
+ const char *fmt;
+
+#if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_TAIL
+ /* Allow legacy syntax of an initial numeric option without -n. */
+ if (argv[1] && (argv[1][0] == '+' || argv[1][0] == '-')
+ && isdigit(argv[1][1])
+ ) {
+ count = eat_num(&argv[1][1]);
+ argv++;
+ argc--;
+ }
+#endif
+
+ USE_FEATURE_FANCY_TAIL(opt_complementary = "s+";) /* -s N */
+ opt = getopt32(argv, "fc:n:" USE_FEATURE_FANCY_TAIL("qs:v"),
+ &str_c, &str_n USE_FEATURE_FANCY_TAIL(,&sleep_period));
+#define FOLLOW (opt & 0x1)
+#define COUNT_BYTES (opt & 0x2)
+ //if (opt & 0x1) // -f
+ if (opt & 0x2) count = eat_num(str_c); // -c
+ if (opt & 0x4) count = eat_num(str_n); // -n
+#if ENABLE_FEATURE_FANCY_TAIL
+ if (opt & 0x8) header_threshhold = INT_MAX; // -q
+ if (opt & 0x20) header_threshhold = 0; // -v
+#endif
+ argc -= optind;
+ argv += optind;
+ from_top = G.status; /* 1 if there was "-c +N" or "-n +N" */
+ G.status = EXIT_SUCCESS;
+
+ /* open all the files */
+ fds = xmalloc(sizeof(int) * (argc + 1));
+ if (!argv[0]) {
+ struct stat statbuf;
+
+ if (!fstat(STDIN_FILENO, &statbuf) && S_ISFIFO(statbuf.st_mode)) {
+ opt &= ~1; /* clear FOLLOW */
+ }
+ *argv = (char *) bb_msg_standard_input;
+ }
+ nfiles = i = 0;
+ do {
+ int fd = open_or_warn_stdin(argv[i]);
+ if (fd < 0) {
+ G.status = EXIT_FAILURE;
+ continue;
+ }
+ fds[nfiles] = fd;
+ argv[nfiles++] = argv[i];
+ } while (++i < argc);
+
+ if (!nfiles)
+ bb_error_msg_and_die("no files");
+
+ /* prepare the buffer */
+ tailbufsize = BUFSIZ;
+ if (!from_top && COUNT_BYTES) {
+ if (tailbufsize < count + BUFSIZ) {
+ tailbufsize = count + BUFSIZ;
+ }
+ }
+ tailbuf = xmalloc(tailbufsize);
+
+ /* tail the files */
+ fmt = header_fmt + 1; /* Skip header leading newline on first output. */
+ i = 0;
+ do {
+ if (nfiles > header_threshhold) {
+ tail_xprint_header(fmt, argv[i]);
+ fmt = header_fmt;
+ }
+
+ /* Optimizing count-bytes case if the file is seekable.
+ * Beware of backing up too far.
+ * Also we exclude files with size 0 (because of /proc/xxx) */
+ if (COUNT_BYTES && !from_top) {
+ off_t current = lseek(fds[i], 0, SEEK_END);
+ if (current > 0) {
+ if (count == 0)
+ continue; /* showing zero lines is easy :) */
+ current -= count;
+ if (current < 0)
+ current = 0;
+ xlseek(fds[i], current, SEEK_SET);
+ bb_copyfd_size(fds[i], STDOUT_FILENO, count);
+ continue;
+ }
+ }
+
+ buf = tailbuf;
+ taillen = 0;
+ seen = 1;
+ newlines_seen = 0;
+ while ((nread = tail_read(fds[i], buf, tailbufsize-taillen)) > 0) {
+ if (from_top) {
+ nwrite = nread;
+ if (seen < count) {
+ if (COUNT_BYTES) {
+ nwrite -= (count - seen);
+ seen = count;
+ } else {
+ s = buf;
+ do {
+ --nwrite;
+ if (*s++ == '\n' && ++seen == count) {
+ break;
+ }
+ } while (nwrite);
+ }
+ }
+ xwrite(STDOUT_FILENO, buf + nread - nwrite, nwrite);
+ } else if (count) {
+ if (COUNT_BYTES) {
+ taillen += nread;
+ if (taillen > (int)count) {
+ memmove(tailbuf, tailbuf + taillen - count, count);
+ taillen = count;
+ }
+ } else {
+ int k = nread;
+ int newlines_in_buf = 0;
+
+ do { /* count '\n' in last read */
+ k--;
+ if (buf[k] == '\n') {
+ newlines_in_buf++;
+ }
+ } while (k);
+
+ if (newlines_seen + newlines_in_buf < (int)count) {
+ newlines_seen += newlines_in_buf;
+ taillen += nread;
+ } else {
+ int extra = (buf[nread-1] != '\n');
+
+ k = newlines_seen + newlines_in_buf + extra - count;
+ s = tailbuf;
+ while (k) {
+ if (*s == '\n') {
+ k--;
+ }
+ s++;
+ }
+ taillen += nread - (s - tailbuf);
+ memmove(tailbuf, s, taillen);
+ newlines_seen = count - extra;
+ }
+ if (tailbufsize < (size_t)taillen + BUFSIZ) {
+ tailbufsize = taillen + BUFSIZ;
+ tailbuf = xrealloc(tailbuf, tailbufsize);
+ }
+ }
+ buf = tailbuf + taillen;
+ }
+ } /* while (tail_read() > 0) */
+ if (!from_top) {
+ xwrite(STDOUT_FILENO, tailbuf, taillen);
+ }
+ } while (++i < nfiles);
+
+ buf = xrealloc(tailbuf, BUFSIZ);
+
+ fmt = NULL;
+
+ if (FOLLOW) while (1) {
+ sleep(sleep_period);
+ i = 0;
+ do {
+ if (nfiles > header_threshhold) {
+ fmt = header_fmt;
+ }
+ while ((nread = tail_read(fds[i], buf, BUFSIZ)) > 0) {
+ if (fmt) {
+ tail_xprint_header(fmt, argv[i]);
+ fmt = NULL;
+ }
+ xwrite(STDOUT_FILENO, buf, nread);
+ }
+ } while (++i < nfiles);
+ }
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ free(fds);
+ }
+ return G.status;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/tee.c b/cleopatre/busybox-1.11.1-spc300/coreutils/tee.c
new file mode 100644
index 0000000000..b38801755b
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/tee.c
@@ -0,0 +1,102 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * tee implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 compliant */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/tee.html */
+
+#include "libbb.h"
+#include <signal.h>
+
+int tee_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int tee_main(int argc, char **argv)
+{
+ const char *mode = "w\0a";
+ FILE **files;
+ FILE **fp;
+ char **names;
+ char **np;
+ char retval;
+//TODO: make unconditional
+#if ENABLE_FEATURE_TEE_USE_BLOCK_IO
+ ssize_t c;
+# define buf bb_common_bufsiz1
+#else
+ int c;
+#endif
+ retval = getopt32(argv, "ia"); /* 'a' must be 2nd */
+ argc -= optind;
+ argv += optind;
+
+ mode += (retval & 2); /* Since 'a' is the 2nd option... */
+
+ if (retval & 1) {
+ signal(SIGINT, SIG_IGN); /* TODO - switch to sigaction. (why?) */
+ }
+ retval = EXIT_SUCCESS;
+ /* gnu tee ignores SIGPIPE in case one of the output files is a pipe
+ * that doesn't consume all its input. Good idea... */
+ signal(SIGPIPE, SIG_IGN);
+
+ /* Allocate an array of FILE *'s, with one extra for a sentinal. */
+ fp = files = xzalloc(sizeof(FILE *) * (argc + 2));
+ np = names = argv - 1;
+
+ files[0] = stdout;
+ goto GOT_NEW_FILE;
+ do {
+ *fp = fopen_or_warn(*argv, mode);
+ if (*fp == NULL) {
+ retval = EXIT_FAILURE;
+ continue;
+ }
+ *np = *argv++;
+ GOT_NEW_FILE:
+ setbuf(*fp++, NULL); /* tee must not buffer output. */
+ np++;
+ } while (*argv);
+ /* names[0] will be filled later */
+
+#if ENABLE_FEATURE_TEE_USE_BLOCK_IO
+ while ((c = safe_read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
+ fp = files;
+ do
+ fwrite(buf, 1, c, *fp++);
+ while (*fp);
+ }
+ if (c < 0) { /* Make sure read errors are signaled. */
+ retval = EXIT_FAILURE;
+ }
+#else
+ setvbuf(stdout, NULL, _IONBF, 0);
+ while ((c = getchar()) != EOF) {
+ fp = files;
+ do
+ putc(c, *fp++);
+ while (*fp);
+ }
+#endif
+
+ /* Now we need to check for i/o errors on stdin and the various
+ * output files. Since we know that the first entry in the output
+ * file table is stdout, we can save one "if ferror" test by
+ * setting the first entry to stdin and checking stdout error
+ * status with fflush_stdout_and_exit()... although fflush()ing
+ * is unnecessary here. */
+ np = names;
+ fp = files;
+ names[0] = (char *) bb_msg_standard_input;
+ files[0] = stdin;
+ do { /* Now check for input and output errors. */
+ /* Checking ferror should be sufficient, but we may want to fclose.
+ * If we do, remember not to close stdin! */
+ die_if_ferror(*fp++, *np++);
+ } while (*fp);
+
+ fflush_stdout_and_exit(retval);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/test.c b/cleopatre/busybox-1.11.1-spc300/coreutils/test.c
new file mode 100644
index 0000000000..270ca21a93
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/test.c
@@ -0,0 +1,637 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * test implementation for busybox
+ *
+ * Copyright (c) by a whole pile of folks:
+ *
+ * test(1); version 7-like -- author Erik Baalbergen
+ * modified by Eric Gisin to be used as built-in.
+ * modified by Arnold Robbins to add SVR3 compatibility
+ * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
+ * modified by J.T. Conklin for NetBSD.
+ * modified by Herbert Xu to be used as built-in in ash.
+ * modified by Erik Andersen <andersen@codepoet.org> to be used
+ * in busybox.
+ * modified by Bernhard Fischer to be useable (i.e. a bit less bloaty).
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ * Original copyright notice states:
+ * "This program is in the Public Domain."
+ */
+
+#include "libbb.h"
+#include <setjmp.h>
+
+/* This is a NOFORK applet. Be very careful! */
+
+/* test_main() is called from shells, and we need to be extra careful here.
+ * This is true regardless of PREFER_APPLETS and STANDALONE_SHELL
+ * state. */
+
+
+/* test(1) accepts the following grammar:
+ oexpr ::= aexpr | aexpr "-o" oexpr ;
+ aexpr ::= nexpr | nexpr "-a" aexpr ;
+ nexpr ::= primary | "!" primary
+ primary ::= unary-operator operand
+ | operand binary-operator operand
+ | operand
+ | "(" oexpr ")"
+ ;
+ unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
+ "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
+
+ binary-operator ::= "="|"=="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
+ "-nt"|"-ot"|"-ef";
+ operand ::= <any legal UNIX file name>
+*/
+
+enum token {
+ EOI,
+ FILRD,
+ FILWR,
+ FILEX,
+ FILEXIST,
+ FILREG,
+ FILDIR,
+ FILCDEV,
+ FILBDEV,
+ FILFIFO,
+ FILSOCK,
+ FILSYM,
+ FILGZ,
+ FILTT,
+ FILSUID,
+ FILSGID,
+ FILSTCK,
+ FILNT,
+ FILOT,
+ FILEQ,
+ FILUID,
+ FILGID,
+ STREZ,
+ STRNZ,
+ STREQ,
+ STRNE,
+ STRLT,
+ STRGT,
+ INTEQ,
+ INTNE,
+ INTGE,
+ INTGT,
+ INTLE,
+ INTLT,
+ UNOT,
+ BAND,
+ BOR,
+ LPAREN,
+ RPAREN,
+ OPERAND
+};
+#define is_int_op(a) (((unsigned char)((a) - INTEQ)) <= 5)
+#define is_str_op(a) (((unsigned char)((a) - STREZ)) <= 5)
+#define is_file_op(a) (((unsigned char)((a) - FILNT)) <= 2)
+#define is_file_access(a) (((unsigned char)((a) - FILRD)) <= 2)
+#define is_file_type(a) (((unsigned char)((a) - FILREG)) <= 5)
+#define is_file_bit(a) (((unsigned char)((a) - FILSUID)) <= 2)
+enum token_types {
+ UNOP,
+ BINOP,
+ BUNOP,
+ BBINOP,
+ PAREN
+};
+
+static const struct t_op {
+ char op_text[4];
+ unsigned char op_num, op_type;
+} ops[] = {
+ { "-r", FILRD , UNOP },
+ { "-w", FILWR , UNOP },
+ { "-x", FILEX , UNOP },
+ { "-e", FILEXIST, UNOP },
+ { "-f", FILREG , UNOP },
+ { "-d", FILDIR , UNOP },
+ { "-c", FILCDEV , UNOP },
+ { "-b", FILBDEV , UNOP },
+ { "-p", FILFIFO , UNOP },
+ { "-u", FILSUID , UNOP },
+ { "-g", FILSGID , UNOP },
+ { "-k", FILSTCK , UNOP },
+ { "-s", FILGZ , UNOP },
+ { "-t", FILTT , UNOP },
+ { "-z", STREZ , UNOP },
+ { "-n", STRNZ , UNOP },
+ { "-h", FILSYM , UNOP }, /* for backwards compat */
+
+ { "-O" , FILUID , UNOP },
+ { "-G" , FILGID , UNOP },
+ { "-L" , FILSYM , UNOP },
+ { "-S" , FILSOCK, UNOP },
+ { "=" , STREQ , BINOP },
+ { "==" , STREQ , BINOP },
+ { "!=" , STRNE , BINOP },
+ { "<" , STRLT , BINOP },
+ { ">" , STRGT , BINOP },
+ { "-eq", INTEQ , BINOP },
+ { "-ne", INTNE , BINOP },
+ { "-ge", INTGE , BINOP },
+ { "-gt", INTGT , BINOP },
+ { "-le", INTLE , BINOP },
+ { "-lt", INTLT , BINOP },
+ { "-nt", FILNT , BINOP },
+ { "-ot", FILOT , BINOP },
+ { "-ef", FILEQ , BINOP },
+ { "!" , UNOT , BUNOP },
+ { "-a" , BAND , BBINOP },
+ { "-o" , BOR , BBINOP },
+ { "(" , LPAREN , PAREN },
+ { ")" , RPAREN , PAREN },
+};
+
+
+#if ENABLE_FEATURE_TEST_64
+typedef int64_t arith_t;
+#else
+typedef int arith_t;
+#endif
+
+
+/* We try to minimize both static and stack usage. */
+struct test_statics {
+ char **t_wp;
+ const struct t_op *t_wp_op;
+ gid_t *group_array;
+ int ngroups;
+ jmp_buf leaving;
+};
+
+/* See test_ptr_hack.c */
+extern struct test_statics *const test_ptr_to_statics;
+
+#define S (*test_ptr_to_statics)
+#define t_wp (S.t_wp )
+#define t_wp_op (S.t_wp_op )
+#define group_array (S.group_array )
+#define ngroups (S.ngroups )
+#define leaving (S.leaving )
+
+#define INIT_S() do { \
+ (*(struct test_statics**)&test_ptr_to_statics) = xzalloc(sizeof(S)); \
+ barrier(); \
+} while (0)
+#define DEINIT_S() do { \
+ free(test_ptr_to_statics); \
+} while (0)
+
+static arith_t primary(enum token n);
+
+static void syntax(const char *op, const char *msg) ATTRIBUTE_NORETURN;
+static void syntax(const char *op, const char *msg)
+{
+ if (op && *op) {
+ bb_error_msg("%s: %s", op, msg);
+ } else {
+ bb_error_msg("%s: %s"+4, msg);
+ }
+ longjmp(leaving, 2);
+}
+
+/* atoi with error detection */
+//XXX: FIXME: duplicate of existing libbb function?
+static arith_t getn(const char *s)
+{
+ char *p;
+#if ENABLE_FEATURE_TEST_64
+ long long r;
+#else
+ long r;
+#endif
+
+ errno = 0;
+#if ENABLE_FEATURE_TEST_64
+ r = strtoll(s, &p, 10);
+#else
+ r = strtol(s, &p, 10);
+#endif
+
+ if (errno != 0)
+ syntax(s, "out of range");
+
+ if (*(skip_whitespace(p)))
+ syntax(s, "bad number");
+
+ return r;
+}
+
+/* UNUSED
+static int newerf(const char *f1, const char *f2)
+{
+ struct stat b1, b2;
+
+ return (stat(f1, &b1) == 0 &&
+ stat(f2, &b2) == 0 && b1.st_mtime > b2.st_mtime);
+}
+
+static int olderf(const char *f1, const char *f2)
+{
+ struct stat b1, b2;
+
+ return (stat(f1, &b1) == 0 &&
+ stat(f2, &b2) == 0 && b1.st_mtime < b2.st_mtime);
+}
+
+static int equalf(const char *f1, const char *f2)
+{
+ struct stat b1, b2;
+
+ return (stat(f1, &b1) == 0 &&
+ stat(f2, &b2) == 0 &&
+ b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino);
+}
+*/
+
+
+static enum token t_lex(char *s)
+{
+ const struct t_op *op;
+
+ t_wp_op = NULL;
+ if (s == NULL) {
+ return EOI;
+ }
+
+ op = ops;
+ do {
+ if (strcmp(s, op->op_text) == 0) {
+ t_wp_op = op;
+ return op->op_num;
+ }
+ op++;
+ } while (op < ops + ARRAY_SIZE(ops));
+
+ return OPERAND;
+}
+
+
+static int binop(void)
+{
+ const char *opnd1, *opnd2;
+ struct t_op const *op;
+ arith_t val1, val2;
+
+ opnd1 = *t_wp;
+ (void) t_lex(*++t_wp);
+ op = t_wp_op;
+
+ opnd2 = *++t_wp;
+ if (opnd2 == NULL)
+ syntax(op->op_text, "argument expected");
+
+ if (is_int_op(op->op_num)) {
+ val1 = getn(opnd1);
+ val2 = getn(opnd2);
+ if (op->op_num == INTEQ)
+ return val1 == val2;
+ if (op->op_num == INTNE)
+ return val1 != val2;
+ if (op->op_num == INTGE)
+ return val1 >= val2;
+ if (op->op_num == INTGT)
+ return val1 > val2;
+ if (op->op_num == INTLE)
+ return val1 <= val2;
+ if (op->op_num == INTLT)
+ return val1 < val2;
+ }
+ if (is_str_op(op->op_num)) {
+ val1 = strcmp(opnd1, opnd2);
+ if (op->op_num == STREQ)
+ return val1 == 0;
+ if (op->op_num == STRNE)
+ return val1 != 0;
+ if (op->op_num == STRLT)
+ return val1 < 0;
+ if (op->op_num == STRGT)
+ return val1 > 0;
+ }
+ /* We are sure that these three are by now the only binops we didn't check
+ * yet, so we do not check if the class is correct:
+ */
+/* if (is_file_op(op->op_num)) */
+ {
+ struct stat b1, b2;
+
+ if (stat(opnd1, &b1) || stat(opnd2, &b2))
+ return 0; /* false, since at least one stat failed */
+ if (op->op_num == FILNT)
+ return b1.st_mtime > b2.st_mtime;
+ if (op->op_num == FILOT)
+ return b1.st_mtime < b2.st_mtime;
+ if (op->op_num == FILEQ)
+ return b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino;
+ }
+ return 1; /* NOTREACHED */
+}
+
+
+static void initialize_group_array(void)
+{
+ ngroups = getgroups(0, NULL);
+ if (ngroups > 0) {
+ /* FIXME: ash tries so hard to not die on OOM,
+ * and we spoil it with just one xrealloc here */
+ /* We realloc, because test_main can be entered repeatedly by shell.
+ * Testcase (ash): 'while true; do test -x some_file; done'
+ * and watch top. (some_file must have owner != you) */
+ group_array = xrealloc(group_array, ngroups * sizeof(gid_t));
+ getgroups(ngroups, group_array);
+ }
+}
+
+
+/* Return non-zero if GID is one that we have in our groups list. */
+//XXX: FIXME: duplicate of existing libbb function?
+// see toplevel TODO file:
+// possible code duplication ingroup() and is_a_group_member()
+static int is_a_group_member(gid_t gid)
+{
+ int i;
+
+ /* Short-circuit if possible, maybe saving a call to getgroups(). */
+ if (gid == getgid() || gid == getegid())
+ return 1;
+
+ if (ngroups == 0)
+ initialize_group_array();
+
+ /* Search through the list looking for GID. */
+ for (i = 0; i < ngroups; i++)
+ if (gid == group_array[i])
+ return 1;
+
+ return 0;
+}
+
+
+/* Do the same thing access(2) does, but use the effective uid and gid,
+ and don't make the mistake of telling root that any file is
+ executable. */
+static int test_eaccess(char *path, int mode)
+{
+ struct stat st;
+ unsigned int euid = geteuid();
+
+ if (stat(path, &st) < 0)
+ return -1;
+
+ if (euid == 0) {
+ /* Root can read or write any file. */
+ if (mode != X_OK)
+ return 0;
+
+ /* Root can execute any file that has any one of the execute
+ bits set. */
+ if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
+ return 0;
+ }
+
+ if (st.st_uid == euid) /* owner */
+ mode <<= 6;
+ else if (is_a_group_member(st.st_gid))
+ mode <<= 3;
+
+ if (st.st_mode & mode)
+ return 0;
+
+ return -1;
+}
+
+
+static int filstat(char *nm, enum token mode)
+{
+ struct stat s;
+ unsigned i = i; /* gcc 3.x thinks it can be used uninitialized */
+
+ if (mode == FILSYM) {
+#ifdef S_IFLNK
+ if (lstat(nm, &s) == 0) {
+ i = S_IFLNK;
+ goto filetype;
+ }
+#endif
+ return 0;
+ }
+
+ if (stat(nm, &s) != 0)
+ return 0;
+ if (mode == FILEXIST)
+ return 1;
+ if (is_file_access(mode)) {
+ if (mode == FILRD)
+ i = R_OK;
+ if (mode == FILWR)
+ i = W_OK;
+ if (mode == FILEX)
+ i = X_OK;
+ return test_eaccess(nm, i) == 0;
+ }
+ if (is_file_type(mode)) {
+ if (mode == FILREG)
+ i = S_IFREG;
+ if (mode == FILDIR)
+ i = S_IFDIR;
+ if (mode == FILCDEV)
+ i = S_IFCHR;
+ if (mode == FILBDEV)
+ i = S_IFBLK;
+ if (mode == FILFIFO) {
+#ifdef S_IFIFO
+ i = S_IFIFO;
+#else
+ return 0;
+#endif
+ }
+ if (mode == FILSOCK) {
+#ifdef S_IFSOCK
+ i = S_IFSOCK;
+#else
+ return 0;
+#endif
+ }
+ filetype:
+ return ((s.st_mode & S_IFMT) == i);
+ }
+ if (is_file_bit(mode)) {
+ if (mode == FILSUID)
+ i = S_ISUID;
+ if (mode == FILSGID)
+ i = S_ISGID;
+ if (mode == FILSTCK)
+ i = S_ISVTX;
+ return ((s.st_mode & i) != 0);
+ }
+ if (mode == FILGZ)
+ return s.st_size > 0L;
+ if (mode == FILUID)
+ return s.st_uid == geteuid();
+ if (mode == FILGID)
+ return s.st_gid == getegid();
+ return 1; /* NOTREACHED */
+}
+
+
+static arith_t nexpr(enum token n)
+{
+ if (n == UNOT)
+ return !nexpr(t_lex(*++t_wp));
+ return primary(n);
+}
+
+
+static arith_t aexpr(enum token n)
+{
+ arith_t res;
+
+ res = nexpr(n);
+ if (t_lex(*++t_wp) == BAND)
+ return aexpr(t_lex(*++t_wp)) && res;
+ t_wp--;
+ return res;
+}
+
+
+static arith_t oexpr(enum token n)
+{
+ arith_t res;
+
+ res = aexpr(n);
+ if (t_lex(*++t_wp) == BOR) {
+ return oexpr(t_lex(*++t_wp)) || res;
+ }
+ t_wp--;
+ return res;
+}
+
+
+
+static arith_t primary(enum token n)
+{
+ arith_t res;
+
+ if (n == EOI) {
+ syntax(NULL, "argument expected");
+ }
+ if (n == LPAREN) {
+ res = oexpr(t_lex(*++t_wp));
+ if (t_lex(*++t_wp) != RPAREN)
+ syntax(NULL, "closing paren expected");
+ return res;
+ }
+ if (t_wp_op && t_wp_op->op_type == UNOP) {
+ /* unary expression */
+ if (*++t_wp == NULL)
+ syntax(t_wp_op->op_text, "argument expected");
+ if (n == STREZ)
+ return t_wp[0][0] == '\0';
+ if (n == STRNZ)
+ return t_wp[0][0] != '\0';
+ if (n == FILTT)
+ return isatty(getn(*t_wp));
+ return filstat(*t_wp, n);
+ }
+
+ t_lex(t_wp[1]);
+ if (t_wp_op && t_wp_op->op_type == BINOP) {
+ return binop();
+ }
+
+ return t_wp[0][0] != '\0';
+}
+
+
+int test_main(int argc, char **argv)
+{
+ int res;
+ const char *arg0;
+ bool negate = 0;
+
+ arg0 = bb_basename(argv[0]);
+ if (arg0[0] == '[') {
+ --argc;
+ if (!arg0[1]) { /* "[" ? */
+ if (NOT_LONE_CHAR(argv[argc], ']')) {
+ bb_error_msg("missing ]");
+ return 2;
+ }
+ } else { /* assuming "[[" */
+ if (strcmp(argv[argc], "]]") != 0) {
+ bb_error_msg("missing ]]");
+ return 2;
+ }
+ }
+ argv[argc] = NULL;
+ }
+
+ /* We must do DEINIT_S() prior to returning */
+ INIT_S();
+
+ res = setjmp(leaving);
+ if (res)
+ goto ret;
+
+ /* resetting ngroups is probably unnecessary. it will
+ * force a new call to getgroups(), which prevents using
+ * group data fetched during a previous call. but the
+ * only way the group data could be stale is if there's
+ * been an intervening call to setgroups(), and this
+ * isn't likely in the case of a shell. paranoia
+ * prevails...
+ */
+ ngroups = 0;
+
+ //argc--;
+ argv++;
+
+ /* Implement special cases from POSIX.2, section 4.62.4 */
+ if (!argv[0]) { /* "test" */
+ res = 1;
+ goto ret;
+ }
+ if (LONE_CHAR(argv[0], '!') && argv[1]) {
+ negate = 1;
+ //argc--;
+ argv++;
+ }
+ if (!argv[1]) { /* "test [!] arg" */
+ res = (*argv[0] == '\0');
+ goto ret;
+ }
+ if (argv[2] && !argv[3]) {
+ t_lex(argv[1]);
+ if (t_wp_op && t_wp_op->op_type == BINOP) {
+ /* "test [!] arg1 <binary_op> arg2" */
+ t_wp = &argv[0];
+ res = (binop() == 0);
+ goto ret;
+ }
+ }
+
+ /* Some complex expression. Undo '!' removal */
+ if (negate) {
+ negate = 0;
+ //argc++;
+ argv--;
+ }
+ t_wp = &argv[0];
+ res = !oexpr(t_lex(*t_wp));
+
+ if (*t_wp != NULL && *++t_wp != NULL) {
+ bb_error_msg("%s: unknown operand", *t_wp);
+ res = 2;
+ }
+ ret:
+ DEINIT_S();
+ return negate ? !res : res;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/test_ptr_hack.c b/cleopatre/busybox-1.11.1-spc300/coreutils/test_ptr_hack.c
new file mode 100644
index 0000000000..a05203d689
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/test_ptr_hack.c
@@ -0,0 +1,23 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2008 by Denys Vlasenko <vda.linux@googlemail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+struct test_statics;
+
+#ifndef GCC_COMBINE
+
+/* We cheat here. It is declared as const ptr in libbb.h,
+ * but here we make it live in R/W memory */
+struct test_statics *test_ptr_to_statics;
+
+#else
+
+/* gcc -combine will see through and complain */
+/* Using alternative method which is more likely to break
+ * on weird architectures, compilers, linkers and so on */
+struct test_statics *const test_ptr_to_statics __attribute__ ((section (".data")));
+
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/touch.c b/cleopatre/busybox-1.11.1-spc300/coreutils/touch.c
new file mode 100644
index 0000000000..0b58179e79
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/touch.c
@@ -0,0 +1,58 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini touch implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 _NOT_ compliant -- options -a, -m, -r, -t not supported. */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/touch.html */
+
+/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
+ *
+ * Previous version called open() and then utime(). While this will be
+ * be necessary to implement -r and -t, it currently only makes things bigger.
+ * Also, exiting on a failure was a bug. All args should be processed.
+ */
+
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
+
+int touch_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int touch_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ int fd;
+ int status = EXIT_SUCCESS;
+ int flags = getopt32(argv, "cf");
+
+ flags &= 1; /* ignoring -f (BSD compat thingy) */
+ argv += optind;
+
+ if (!*argv) {
+ bb_show_usage();
+ }
+
+ do {
+ if (utime(*argv, NULL)) {
+ if (errno == ENOENT) { /* no such file */
+ if (flags) { /* Creation is disabled, so ignore. */
+ continue;
+ }
+ /* Try to create the file. */
+ fd = open(*argv, O_RDWR | O_CREAT,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH
+ );
+ if ((fd >= 0) && !close(fd)) {
+ continue;
+ }
+ }
+ status = EXIT_FAILURE;
+ bb_simple_perror_msg(*argv);
+ }
+ } while (*++argv);
+
+ return status;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/tr.c b/cleopatre/busybox-1.11.1-spc300/coreutils/tr.c
new file mode 100644
index 0000000000..8b2d308024
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/tr.c
@@ -0,0 +1,246 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini tr implementation for busybox
+ *
+ ** Copyright (c) 1987,1997, Prentice Hall All rights reserved.
+ *
+ * The name of Prentice Hall may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * Copyright (c) Michiel Huisjes
+ *
+ * This version of tr is adapted from Minix tr and was modified
+ * by Erik Andersen <andersen@codepoet.org> to be used in busybox.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+/* http://www.opengroup.org/onlinepubs/009695399/utilities/tr.html
+ * TODO: xdigit, graph, print
+ */
+#include "libbb.h"
+
+#define ASCII 0377
+
+static void map(char *pvector,
+ unsigned char *string1, unsigned int string1_len,
+ unsigned char *string2, unsigned int string2_len)
+{
+ char last = '0';
+ unsigned int i, j;
+
+ for (j = 0, i = 0; i < string1_len; i++) {
+ if (string2_len <= j)
+ pvector[string1[i]] = last;
+ else
+ pvector[string1[i]] = last = string2[j++];
+ }
+}
+
+/* supported constructs:
+ * Ranges, e.g., 0-9 ==> 0123456789
+ * Ranges, e.g., [0-9] ==> 0123456789
+ * Escapes, e.g., \a ==> Control-G
+ * Character classes, e.g. [:upper:] ==> A...Z
+ * Equiv classess, e.g. [=A=] ==> A (hmmmmmmm?)
+ */
+static unsigned int expand(const char *arg, char *buffer)
+{
+ char *buffer_start = buffer;
+ unsigned i; /* can't be unsigned char: must be able to hold 256 */
+ unsigned char ac;
+
+ while (*arg) {
+ if (*arg == '\\') {
+ arg++;
+ *buffer++ = bb_process_escape_sequence(&arg);
+ continue;
+ }
+ if (arg[1] == '-') { /* "0-9..." */
+ ac = arg[2];
+ if (ac == '\0') { /* "0-": copy verbatim */
+ *buffer++ = *arg++; /* copy '0' */
+ continue; /* next iter will copy '-' and stop */
+ }
+ i = *arg;
+ while (i <= ac) /* ok: i is unsigned _int_ */
+ *buffer++ = i++;
+ arg += 3; /* skip 0-9 */
+ continue;
+ }
+ if (*arg == '[') { /* "[xyz..." */
+ arg++;
+ i = *arg++;
+ /* "[xyz...", i=x, arg points to y */
+ if (ENABLE_FEATURE_TR_CLASSES && i == ':') {
+#define CLO ":]\0"
+ static const char classes[] ALIGN1 =
+ "alpha"CLO "alnum"CLO "digit"CLO
+ "lower"CLO "upper"CLO "space"CLO
+ "blank"CLO "punct"CLO "cntrl"CLO;
+#define CLASS_invalid 0 /* we increment the retval */
+#define CLASS_alpha 1
+#define CLASS_alnum 2
+#define CLASS_digit 3
+#define CLASS_lower 4
+#define CLASS_upper 5
+#define CLASS_space 6
+#define CLASS_blank 7
+#define CLASS_punct 8
+#define CLASS_cntrl 9
+//#define CLASS_xdigit 10
+//#define CLASS_graph 11
+//#define CLASS_print 12
+ smalluint j;
+ { /* not really pretty.. */
+ char *tmp = xstrndup(arg, 7); // warning: xdigit would need 8, not 7
+ j = index_in_strings(classes, tmp) + 1;
+ free(tmp);
+ }
+ if (j == CLASS_alnum || j == CLASS_digit) {
+ for (i = '0'; i <= '9'; i++)
+ *buffer++ = i;
+ }
+ if (j == CLASS_alpha || j == CLASS_alnum || j == CLASS_upper) {
+ for (i = 'A'; i <= 'Z'; i++)
+ *buffer++ = i;
+ }
+ if (j == CLASS_alpha || j == CLASS_alnum || j == CLASS_lower) {
+ for (i = 'a'; i <= 'z'; i++)
+ *buffer++ = i;
+ }
+ if (j == CLASS_space || j == CLASS_blank) {
+ *buffer++ = '\t';
+ if (j == CLASS_space) {
+ *buffer++ = '\n';
+ *buffer++ = '\v';
+ *buffer++ = '\f';
+ *buffer++ = '\r';
+ }
+ *buffer++ = ' ';
+ }
+ if (j == CLASS_punct || j == CLASS_cntrl) {
+ for (i = '\0'; i <= ASCII; i++)
+ if ((j == CLASS_punct && isprint(i) && !isalnum(i) && !isspace(i))
+ || (j == CLASS_cntrl && iscntrl(i)))
+ *buffer++ = i;
+ }
+ if (j == CLASS_invalid) {
+ *buffer++ = '[';
+ *buffer++ = ':';
+ continue;
+ }
+ break;
+ }
+ /* "[xyz...", i=x, arg points to y */
+ if (ENABLE_FEATURE_TR_EQUIV && i == '=') { /* [=CHAR=] */
+ *buffer++ = *arg; /* copy CHAR */
+ arg += 3; /* skip CHAR=] */
+ continue;
+ }
+ if (*arg != '-') { /* not [x-...] - copy verbatim */
+ *buffer++ = '[';
+ arg--; /* points to x */
+ continue; /* copy all, including eventual ']' */
+ }
+ /* [x-y...] */
+ arg++;
+ ac = *arg++;
+ while (i <= ac)
+ *buffer++ = i++;
+ arg++; /* skip the assumed ']' */
+ continue;
+ }
+ *buffer++ = *arg++;
+ }
+ return (buffer - buffer_start);
+}
+
+static int complement(char *buffer, int buffer_len)
+{
+ int i, j, ix;
+ char conv[ASCII + 2];
+
+ ix = 0;
+ for (i = '\0'; i <= ASCII; i++) {
+ for (j = 0; j < buffer_len; j++)
+ if (buffer[j] == i)
+ break;
+ if (j == buffer_len)
+ conv[ix++] = i & ASCII;
+ }
+ memcpy(buffer, conv, ix);
+ return ix;
+}
+
+int tr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int tr_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ int output_length = 0, input_length;
+ int i;
+ smalluint flags;
+ ssize_t read_chars = 0;
+ size_t in_index = 0, out_index = 0;
+ unsigned last = UCHAR_MAX + 1; /* not equal to any char */
+ unsigned char coded, c;
+ unsigned char *output = xmalloc(BUFSIZ);
+ char *vector = xzalloc((ASCII+1) * 3);
+ char *invec = vector + (ASCII+1);
+ char *outvec = vector + (ASCII+1) * 2;
+
+#define TR_OPT_complement (1 << 0)
+#define TR_OPT_delete (1 << 1)
+#define TR_OPT_squeeze_reps (1 << 2)
+
+ flags = getopt32(argv, "+cds"); /* '+': stop at first non-option */
+ argv += optind;
+
+ for (i = 0; i <= ASCII; i++) {
+ vector[i] = i;
+ /*invec[i] = outvec[i] = FALSE; - done by xzalloc */
+ }
+
+#define tr_buf bb_common_bufsiz1
+ if (*argv != NULL) {
+ input_length = expand(*argv++, tr_buf);
+ if (flags & TR_OPT_complement)
+ input_length = complement(tr_buf, input_length);
+ if (*argv) {
+ if (argv[0][0] == '\0')
+ bb_error_msg_and_die("STRING2 cannot be empty");
+ output_length = expand(*argv, (char *)output);
+ map(vector, (unsigned char *)tr_buf, input_length, output, output_length);
+ }
+ for (i = 0; i < input_length; i++)
+ invec[(unsigned char)tr_buf[i]] = TRUE;
+ for (i = 0; i < output_length; i++)
+ outvec[output[i]] = TRUE;
+ }
+
+ for (;;) {
+ /* If we're out of input, flush output and read more input. */
+ if ((ssize_t)in_index == read_chars) {
+ if (out_index) {
+ xwrite(STDOUT_FILENO, (char *)output, out_index);
+ out_index = 0;
+ }
+ read_chars = safe_read(STDIN_FILENO, tr_buf, BUFSIZ);
+ if (read_chars <= 0) {
+ if (read_chars < 0)
+ bb_perror_msg_and_die(bb_msg_read_error);
+ exit(EXIT_SUCCESS);
+ }
+ in_index = 0;
+ }
+ c = tr_buf[in_index++];
+ coded = vector[c];
+ if ((flags & TR_OPT_delete) && invec[c])
+ continue;
+ if ((flags & TR_OPT_squeeze_reps) && last == coded
+ && (invec[c] || outvec[coded]))
+ continue;
+ output[out_index++] = last = coded;
+ }
+ /* NOTREACHED */
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/true.c b/cleopatre/busybox-1.11.1-spc300/coreutils/true.c
new file mode 100644
index 0000000000..565e68b83c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/true.c
@@ -0,0 +1,21 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini true implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 compliant */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/true.html */
+
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
+
+int true_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int true_main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
+{
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/tty.c b/cleopatre/busybox-1.11.1-spc300/coreutils/tty.c
new file mode 100644
index 0000000000..48e15117c2
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/tty.c
@@ -0,0 +1,44 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * tty implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 compliant */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/tty.html */
+
+#include "libbb.h"
+
+int tty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int tty_main(int argc, char **argv SKIP_INCLUDE_SUSv2(ATTRIBUTE_UNUSED))
+{
+ const char *s;
+ USE_INCLUDE_SUSv2(int silent;) /* Note: No longer relevant in SUSv3. */
+ int retval;
+
+ xfunc_error_retval = 2; /* SUSv3 requires > 1 for error. */
+
+ USE_INCLUDE_SUSv2(silent = getopt32(argv, "s");)
+ USE_INCLUDE_SUSv2(argc -= optind;)
+ SKIP_INCLUDE_SUSv2(argc -= 1;)
+
+ /* gnu tty outputs a warning that it is ignoring all args. */
+ bb_warn_ignoring_args(argc);
+
+ retval = 0;
+
+ s = ttyname(0);
+ if (s == NULL) {
+ /* According to SUSv3, ttyname can fail with EBADF or ENOTTY.
+ * We know the file descriptor is good, so failure means not a tty. */
+ s = "not a tty";
+ retval = 1;
+ }
+ USE_INCLUDE_SUSv2(if (!silent) puts(s);)
+ SKIP_INCLUDE_SUSv2(puts(s);)
+
+ fflush_stdout_and_exit(retval);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/uname.c b/cleopatre/busybox-1.11.1-spc300/coreutils/uname.c
new file mode 100644
index 0000000000..76fd3ca8d1
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/uname.c
@@ -0,0 +1,99 @@
+/* vi: set sw=4 ts=4: */
+/* uname -- print system information
+ * Copyright (C) 1989-1999 Free Software Foundation, Inc.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 compliant */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/uname.html */
+
+/* Option Example
+
+ -s, --sysname SunOS
+ -n, --nodename rocky8
+ -r, --release 4.0
+ -v, --version
+ -m, --machine sun
+ -a, --all SunOS rocky8 4.0 sun
+
+ The default behavior is equivalent to '-s'.
+
+ David MacKenzie <djm@gnu.ai.mit.edu> */
+
+/* Busyboxed by Erik Andersen */
+
+/* Further size reductions by Glenn McGrath and Manuel Novoa III. */
+
+/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
+ *
+ * Now does proper error checking on i/o. Plus some further space savings.
+ */
+
+#include <sys/utsname.h>
+#include "libbb.h"
+
+typedef struct {
+ struct utsname name;
+ char processor[8]; /* for "unknown" */
+} uname_info_t;
+
+static const char options[] ALIGN1 = "snrvmpa";
+static const unsigned short utsname_offset[] = {
+ offsetof(uname_info_t, name.sysname),
+ offsetof(uname_info_t, name.nodename),
+ offsetof(uname_info_t, name.release),
+ offsetof(uname_info_t, name.version),
+ offsetof(uname_info_t, name.machine),
+ offsetof(uname_info_t, processor)
+};
+
+int uname_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int uname_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ uname_info_t uname_info;
+#if defined(__sparc__) && defined(__linux__)
+ char *fake_sparc = getenv("FAKE_SPARC");
+#endif
+ const unsigned short *delta;
+ char toprint;
+
+ toprint = getopt32(argv, options);
+
+ if (argv[optind]) { /* coreutils-6.9 compat */
+ bb_show_usage();
+ }
+
+ if (toprint & (1 << 6)) { /* -a => all opts on */
+ toprint = 0x3f;
+ }
+
+ if (toprint == 0) { /* no opts => -s (sysname) */
+ toprint = 1;
+ }
+
+ uname(&uname_info.name); /* never fails */
+
+#if defined(__sparc__) && defined(__linux__)
+ if (fake_sparc && (fake_sparc[0] | 0x20) == 'y') {
+ strcpy(uname_info.name.machine, "sparc");
+ }
+#endif
+
+ strcpy(uname_info.processor, "unknown");
+
+ delta = utsname_offset;
+ do {
+ if (toprint & 1) {
+ /* printf would not be safe here */
+ fputs((char *)(&uname_info) + *delta, stdout);
+ if (toprint > 1) {
+ bb_putchar(' ');
+ }
+ }
+ ++delta;
+ } while (toprint >>= 1);
+ bb_putchar('\n');
+
+ fflush_stdout_and_exit(EXIT_SUCCESS); /* coreutils-6.9 compat */
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/uniq.c b/cleopatre/busybox-1.11.1-spc300/coreutils/uniq.c
new file mode 100644
index 0000000000..41f1fed7b7
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/uniq.c
@@ -0,0 +1,102 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * uniq implementation for busybox
+ *
+ * Copyright (C) 2005 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+/* BB_AUDIT SUSv3 compliant */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/uniq.html */
+
+#include "libbb.h"
+
+static FILE *xgetoptfile_uniq_s(char **argv, int read0write2)
+{
+ const char *n;
+
+ n = *argv;
+ if (n != NULL) {
+ if ((*n != '-') || n[1]) {
+ return xfopen(n, "r\0w" + read0write2);
+ }
+ }
+ return (read0write2) ? stdout : stdin;
+}
+
+int uniq_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int uniq_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ FILE *in, *out;
+ const char *s0, *e0, *s1, *e1, *input_filename;
+ unsigned long dups;
+ unsigned skip_fields, skip_chars, max_chars;
+ unsigned opt;
+ unsigned i;
+
+ enum {
+ OPT_c = 0x1,
+ OPT_d = 0x2,
+ OPT_u = 0x4,
+ OPT_f = 0x8,
+ OPT_s = 0x10,
+ OPT_w = 0x20,
+ };
+
+ skip_fields = skip_chars = 0;
+ max_chars = -1;
+
+ opt_complementary = "f+:s+:w+";
+ opt = getopt32(argv, "cduf:s:w:", &skip_fields, &skip_chars, &max_chars);
+ argv += optind;
+
+ input_filename = *argv;
+
+ in = xgetoptfile_uniq_s(argv, 0);
+ if (*argv) {
+ ++argv;
+ }
+ out = xgetoptfile_uniq_s(argv, 2);
+ if (*argv && argv[1]) {
+ bb_show_usage();
+ }
+
+ s1 = e1 = NULL; /* prime the pump */
+
+ do {
+ s0 = s1;
+ e0 = e1;
+ dups = 0;
+
+ /* gnu uniq ignores newlines */
+ while ((s1 = xmalloc_fgetline(in)) != NULL) {
+ e1 = s1;
+ for (i = skip_fields; i; i--) {
+ e1 = skip_whitespace(e1);
+ e1 = skip_non_whitespace(e1);
+ }
+ for (i = skip_chars; *e1 && i; i--) {
+ ++e1;
+ }
+
+ if (!s0 || strncmp(e0, e1, max_chars)) {
+ break;
+ }
+
+ ++dups; /* note: testing for overflow seems excessive. */
+ }
+
+ if (s0) {
+ if (!(opt & (OPT_d << !!dups))) { /* (if dups, opt & OPT_e) */
+ fprintf(out, "\0%ld " + (opt & 1), dups + 1); /* 1 == OPT_c */
+ fprintf(out, "%s\n", s0);
+ }
+ free((void *)s0);
+ }
+ } while (s1);
+
+ die_if_ferror(in, input_filename);
+
+ fflush_stdout_and_exit(EXIT_SUCCESS);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/usleep.c b/cleopatre/busybox-1.11.1-spc300/coreutils/usleep.c
new file mode 100644
index 0000000000..d34880d3ad
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/usleep.c
@@ -0,0 +1,28 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * usleep implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 N/A -- Apparently a busybox extension. */
+
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
+
+int usleep_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int usleep_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ if (!argv[1]) {
+ bb_show_usage();
+ }
+
+ if (usleep(xatou(argv[1]))) {
+ bb_perror_nomsg_and_die();
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/uudecode.c b/cleopatre/busybox-1.11.1-spc300/coreutils/uudecode.c
new file mode 100644
index 0000000000..c06747622f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/uudecode.c
@@ -0,0 +1,224 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 2003, Glenn McGrath
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ * Based on specification from
+ * http://www.opengroup.org/onlinepubs/007904975/utilities/uuencode.html
+ *
+ * Bugs: the spec doesn't mention anything about "`\n`\n" prior to the
+ * "end" line
+ */
+
+
+#include "libbb.h"
+
+static void read_stduu(FILE *src_stream, FILE *dst_stream)
+{
+ char *line;
+
+ while ((line = xmalloc_fgetline(src_stream)) != NULL) {
+ int encoded_len, str_len;
+ char *line_ptr, *dst;
+
+ if (strcmp(line, "end") == 0) {
+ return; /* the only non-error exit */
+ }
+
+ line_ptr = line;
+ while (*line_ptr) {
+ *line_ptr = (*line_ptr - 0x20) & 0x3f;
+ line_ptr++;
+ }
+ str_len = line_ptr - line;
+
+ encoded_len = line[0] * 4 / 3;
+ /* Check that line is not too short. (we tolerate
+ * overly _long_ line to accomodate possible extra '`').
+ * Empty line case is also caught here. */
+ if (str_len <= encoded_len) {
+ break; /* go to bb_error_msg_and_die("short file"); */
+ }
+ if (encoded_len <= 0) {
+ /* Ignore the "`\n" line, why is it even in the encode file ? */
+ free(line);
+ continue;
+ }
+ if (encoded_len > 60) {
+ bb_error_msg_and_die("line too long");
+ }
+
+ dst = line;
+ line_ptr = line + 1;
+ do {
+ /* Merge four 6 bit chars to three 8 bit chars */
+ *dst++ = line_ptr[0] << 2 | line_ptr[1] >> 4;
+ encoded_len--;
+ if (encoded_len == 0) {
+ break;
+ }
+
+ *dst++ = line_ptr[1] << 4 | line_ptr[2] >> 2;
+ encoded_len--;
+ if (encoded_len == 0) {
+ break;
+ }
+
+ *dst++ = line_ptr[2] << 6 | line_ptr[3];
+ line_ptr += 4;
+ encoded_len -= 2;
+ } while (encoded_len > 0);
+ fwrite(line, 1, dst - line, dst_stream);
+ free(line);
+ }
+ bb_error_msg_and_die("short file");
+}
+
+static void read_base64(FILE *src_stream, FILE *dst_stream)
+{
+ int term_count = 1;
+
+ while (1) {
+ char translated[4];
+ int count = 0;
+
+ while (count < 4) {
+ char *table_ptr;
+ int ch;
+
+ /* Get next _valid_ character.
+ * global vector bb_uuenc_tbl_base64[] contains this string:
+ * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n"
+ */
+ do {
+ ch = fgetc(src_stream);
+ if (ch == EOF) {
+ bb_error_msg_and_die("short file");
+ }
+ table_ptr = strchr(bb_uuenc_tbl_base64, ch);
+ } while (table_ptr == NULL);
+
+ /* Convert encoded character to decimal */
+ ch = table_ptr - bb_uuenc_tbl_base64;
+
+ if (*table_ptr == '=') {
+ if (term_count == 0) {
+ translated[count] = '\0';
+ break;
+ }
+ term_count++;
+ } else if (*table_ptr == '\n') {
+ /* Check for terminating line */
+ if (term_count == 5) {
+ return;
+ }
+ term_count = 1;
+ continue;
+ } else {
+ translated[count] = ch;
+ count++;
+ term_count = 0;
+ }
+ }
+
+ /* Merge 6 bit chars to 8 bit */
+ if (count > 1) {
+ fputc(translated[0] << 2 | translated[1] >> 4, dst_stream);
+ }
+ if (count > 2) {
+ fputc(translated[1] << 4 | translated[2] >> 2, dst_stream);
+ }
+ if (count > 3) {
+ fputc(translated[2] << 6 | translated[3], dst_stream);
+ }
+ }
+}
+
+int uudecode_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int uudecode_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ FILE *src_stream;
+ char *outname = NULL;
+ char *line;
+
+ opt_complementary = "?1"; /* 1 argument max */
+ getopt32(argv, "o:", &outname);
+ argv += optind;
+
+ if (!*argv)
+ *--argv = (char*)"-";
+ src_stream = xfopen_stdin(*argv);
+
+ /* Search for the start of the encoding */
+ while ((line = xmalloc_fgetline(src_stream)) != NULL) {
+ void (*decode_fn_ptr)(FILE * src, FILE * dst);
+ char *line_ptr;
+ FILE *dst_stream;
+ int mode;
+
+ if (strncmp(line, "begin-base64 ", 13) == 0) {
+ line_ptr = line + 13;
+ decode_fn_ptr = read_base64;
+ } else if (strncmp(line, "begin ", 6) == 0) {
+ line_ptr = line + 6;
+ decode_fn_ptr = read_stduu;
+ } else {
+ free(line);
+ continue;
+ }
+
+ /* begin line found. decode and exit */
+ mode = bb_strtou(line_ptr, NULL, 8);
+ if (outname == NULL) {
+ outname = strchr(line_ptr, ' ');
+ if ((outname == NULL) || (*outname == '\0')) {
+ break;
+ }
+ outname++;
+ }
+ dst_stream = stdout;
+ if (NOT_LONE_DASH(outname)) {
+ dst_stream = xfopen(outname, "w");
+ fchmod(fileno(dst_stream), mode & (S_IRWXU | S_IRWXG | S_IRWXO));
+ }
+ free(line);
+ decode_fn_ptr(src_stream, dst_stream);
+ /* fclose_if_not_stdin(src_stream); - redundant */
+ return EXIT_SUCCESS;
+ }
+ bb_error_msg_and_die("no 'begin' line");
+}
+
+/* Test script.
+Put this into an empty dir with busybox binary, an run.
+
+#!/bin/sh
+test -x busybox || { echo "No ./busybox?"; exit; }
+ln -sf busybox uudecode
+ln -sf busybox uuencode
+>A_null
+echo -n A >A
+echo -n AB >AB
+echo -n ABC >ABC
+echo -n ABCD >ABCD
+echo -n ABCDE >ABCDE
+echo -n ABCDEF >ABCDEF
+cat busybox >A_bbox
+for f in A*; do
+ echo uuencode $f
+ ./uuencode $f <$f >u_$f
+ ./uuencode -m $f <$f >m_$f
+done
+mkdir unpk_u unpk_m 2>/dev/null
+for f in u_*; do
+ ./uudecode <$f -o unpk_u/${f:2}
+ diff -a ${f:2} unpk_u/${f:2} >/dev/null 2>&1
+ echo uudecode $f: $?
+done
+for f in m_*; do
+ ./uudecode <$f -o unpk_m/${f:2}
+ diff -a ${f:2} unpk_m/${f:2} >/dev/null 2>&1
+ echo uudecode $f: $?
+done
+*/
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/uuencode.c b/cleopatre/busybox-1.11.1-spc300/coreutils/uuencode.c
new file mode 100644
index 0000000000..e19f996764
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/uuencode.c
@@ -0,0 +1,61 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2000 by Glenn McGrath
+ *
+ * based on the function base64_encode from http.c in wget v1.6
+ * Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+enum {
+ SRC_BUF_SIZE = 45, /* This *MUST* be a multiple of 3 */
+ DST_BUF_SIZE = 4 * ((SRC_BUF_SIZE + 2) / 3),
+};
+
+int uuencode_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int uuencode_main(int argc, char **argv)
+{
+ struct stat stat_buf;
+ int src_fd = STDIN_FILENO;
+ const char *tbl;
+ mode_t mode;
+ char src_buf[SRC_BUF_SIZE];
+ char dst_buf[DST_BUF_SIZE + 1];
+
+ tbl = bb_uuenc_tbl_std;
+ mode = 0666 & ~umask(0666);
+ opt_complementary = "-1:?2"; /* must have 1 or 2 args */
+ if (getopt32(argv, "m")) {
+ tbl = bb_uuenc_tbl_base64;
+ }
+ argv += optind;
+ if (argc == optind + 2) {
+ src_fd = xopen(*argv, O_RDONLY);
+ fstat(src_fd, &stat_buf);
+ mode = stat_buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
+ argv++;
+ }
+
+ printf("begin%s %o %s", tbl == bb_uuenc_tbl_std ? "" : "-base64", mode, *argv);
+ while (1) {
+ size_t size = full_read(src_fd, src_buf, SRC_BUF_SIZE);
+ if (!size)
+ break;
+ if ((ssize_t)size < 0)
+ bb_perror_msg_and_die(bb_msg_read_error);
+ /* Encode the buffer we just read in */
+ bb_uuencode(dst_buf, src_buf, size, tbl);
+ bb_putchar('\n');
+ if (tbl == bb_uuenc_tbl_std) {
+ bb_putchar(tbl[size]);
+ }
+ fflush(stdout);
+ xwrite(STDOUT_FILENO, dst_buf, 4 * ((size + 2) / 3));
+ }
+ printf(tbl == bb_uuenc_tbl_std ? "\n`\nend\n" : "\n====\n");
+
+ fflush_stdout_and_exit(EXIT_SUCCESS);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/wc.c b/cleopatre/busybox-1.11.1-spc300/coreutils/wc.c
new file mode 100644
index 0000000000..de3c895bd9
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/wc.c
@@ -0,0 +1,205 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * wc implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 _NOT_ compliant -- option -m is not currently supported. */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/wc.html */
+
+/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
+ *
+ * Rewritten to fix a number of problems and do some size optimizations.
+ * Problems in the previous busybox implementation (besides bloat) included:
+ * 1) broken 'wc -c' optimization (read note below)
+ * 2) broken handling of '-' args
+ * 3) no checking of ferror on EOF returns
+ * 4) isprint() wasn't considered when word counting.
+ *
+ * TODO:
+ *
+ * When locale support is enabled, count multibyte chars in the '-m' case.
+ *
+ * NOTES:
+ *
+ * The previous busybox wc attempted an optimization using stat for the
+ * case of counting chars only. I omitted that because it was broken.
+ * It didn't take into account the possibility of input coming from a
+ * pipe, or input from a file with file pointer not at the beginning.
+ *
+ * To implement such a speed optimization correctly, not only do you
+ * need the size, but also the file position. Note also that the
+ * file position may be past the end of file. Consider the example
+ * (adapted from example in gnu wc.c)
+ *
+ * echo hello > /tmp/testfile &&
+ * (dd ibs=1k skip=1 count=0 &> /dev/null; wc -c) < /tmp/testfile
+ *
+ * for which 'wc -c' should output '0'.
+ */
+
+#include "libbb.h"
+
+#if ENABLE_LOCALE_SUPPORT
+#define isspace_given_isprint(c) isspace(c)
+#else
+#undef isspace
+#undef isprint
+#define isspace(c) ((((c) == ' ') || (((unsigned int)((c) - 9)) <= (13 - 9))))
+#define isprint(c) (((unsigned int)((c) - 0x20)) <= (0x7e - 0x20))
+#define isspace_given_isprint(c) ((c) == ' ')
+#endif
+
+#if ENABLE_FEATURE_WC_LARGE
+#define COUNT_T unsigned long long
+#define COUNT_FMT "llu"
+#else
+#define COUNT_T unsigned
+#define COUNT_FMT "u"
+#endif
+
+enum {
+ WC_LINES = 0,
+ WC_WORDS = 1,
+ WC_CHARS = 2,
+ WC_LENGTH = 3
+};
+
+int wc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int wc_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ FILE *fp;
+ const char *s, *arg;
+ const char *start_fmt = " %9"COUNT_FMT + 1;
+ const char *fname_fmt = " %s\n";
+ COUNT_T *pcounts;
+ COUNT_T counts[4];
+ COUNT_T totals[4];
+ unsigned linepos;
+ unsigned u;
+ int num_files = 0;
+ int c;
+ smallint status = EXIT_SUCCESS;
+ smallint in_word;
+ unsigned print_type;
+
+ print_type = getopt32(argv, "lwcL");
+
+ if (print_type == 0) {
+ print_type = (1 << WC_LINES) | (1 << WC_WORDS) | (1 << WC_CHARS);
+ }
+
+ argv += optind;
+ if (!argv[0]) {
+ *--argv = (char *) bb_msg_standard_input;
+ fname_fmt = "\n";
+ if (!((print_type-1) & print_type)) /* exactly one option? */
+ start_fmt = "%"COUNT_FMT;
+ }
+
+ memset(totals, 0, sizeof(totals));
+
+ pcounts = counts;
+
+ while ((arg = *argv++) != 0) {
+ ++num_files;
+ fp = fopen_or_warn_stdin(arg);
+ if (!fp) {
+ status = EXIT_FAILURE;
+ continue;
+ }
+
+ memset(counts, 0, sizeof(counts));
+ linepos = 0;
+ in_word = 0;
+
+ do {
+ /* Our -w doesn't match GNU wc exactly... oh well */
+
+ ++counts[WC_CHARS];
+ c = getc(fp);
+ if (isprint(c)) {
+ ++linepos;
+ if (!isspace_given_isprint(c)) {
+ in_word = 1;
+ continue;
+ }
+ } else if (((unsigned int)(c - 9)) <= 4) {
+ /* \t 9
+ * \n 10
+ * \v 11
+ * \f 12
+ * \r 13
+ */
+ if (c == '\t') {
+ linepos = (linepos | 7) + 1;
+ } else { /* '\n', '\r', '\f', or '\v' */
+ DO_EOF:
+ if (linepos > counts[WC_LENGTH]) {
+ counts[WC_LENGTH] = linepos;
+ }
+ if (c == '\n') {
+ ++counts[WC_LINES];
+ }
+ if (c != '\v') {
+ linepos = 0;
+ }
+ }
+ } else if (c == EOF) {
+ if (ferror(fp)) {
+ bb_simple_perror_msg(arg);
+ status = EXIT_FAILURE;
+ }
+ --counts[WC_CHARS];
+ goto DO_EOF; /* Treat an EOF as '\r'. */
+ } else {
+ continue;
+ }
+
+ counts[WC_WORDS] += in_word;
+ in_word = 0;
+ if (c == EOF) {
+ break;
+ }
+ } while (1);
+
+ if (totals[WC_LENGTH] < counts[WC_LENGTH]) {
+ totals[WC_LENGTH] = counts[WC_LENGTH];
+ }
+ totals[WC_LENGTH] -= counts[WC_LENGTH];
+
+ fclose_if_not_stdin(fp);
+
+ OUTPUT:
+ /* coreutils wc tries hard to print pretty columns
+ * (saves results for all files, find max col len etc...)
+ * we won't try that hard, it will bloat us too much */
+ s = start_fmt;
+ u = 0;
+ do {
+ if (print_type & (1 << u)) {
+ printf(s, pcounts[u]);
+ s = " %9"COUNT_FMT; /* Ok... restore the leading space. */
+ }
+ totals[u] += pcounts[u];
+ } while (++u < 4);
+ printf(fname_fmt, arg);
+ }
+
+ /* If more than one file was processed, we want the totals. To save some
+ * space, we set the pcounts ptr to the totals array. This has the side
+ * effect of trashing the totals array after outputting it, but that's
+ * irrelavent since we no longer need it. */
+ if (num_files > 1) {
+ num_files = 0; /* Make sure we don't get here again. */
+ arg = "total";
+ pcounts = totals;
+ --argv;
+ goto OUTPUT;
+ }
+
+ fflush_stdout_and_exit(status);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/who.c b/cleopatre/busybox-1.11.1-spc300/coreutils/who.c
new file mode 100644
index 0000000000..72fc404531
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/who.c
@@ -0,0 +1,80 @@
+/* vi: set sw=4 ts=4: */
+/*----------------------------------------------------------------------
+ * Mini who is used to display user name, login time,
+ * idle time and host name.
+ *
+ * Author: Da Chen <dchen@ayrnetworks.com>
+ *
+ * This is a free document; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation:
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Copyright (c) 2002 AYR Networks, Inc.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ *----------------------------------------------------------------------
+ */
+/* BB_AUDIT SUSv3 _NOT_ compliant -- missing options -b, -d, -H, -l, -m, -p, -q, -r, -s, -t, -T, -u; Missing argument 'file'. */
+
+#include "libbb.h"
+#include <utmp.h>
+#include <time.h>
+
+static void idle_string(char *str6, time_t t)
+{
+ t = time(NULL) - t;
+
+ /*if (t < 60) {
+ str6[0] = '.';
+ str6[1] = '\0';
+ return;
+ }*/
+ if (t >= 0 && t < (24 * 60 * 60)) {
+ sprintf(str6, "%02d:%02d",
+ (int) (t / (60 * 60)),
+ (int) ((t % (60 * 60)) / 60));
+ return;
+ }
+ strcpy(str6, "old");
+}
+
+int who_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int who_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ char str6[6];
+ struct utmp *ut;
+ struct stat st;
+ char *name;
+ unsigned opt;
+
+ opt_complementary = "=0";
+ opt = getopt32(argv, "a");
+
+ setutent();
+ printf("USER TTY IDLE TIME HOST\n");
+ while ((ut = getutent()) != NULL) {
+ if (ut->ut_user[0] && (opt || ut->ut_type == USER_PROCESS)) {
+ time_t tmp;
+ /* ut->ut_line is device name of tty - "/dev/" */
+ name = concat_path_file("/dev", ut->ut_line);
+ str6[0] = '?';
+ str6[1] = '\0';
+ if (stat(name, &st) == 0)
+ idle_string(str6, st.st_atime);
+ /* manpages say ut_tv.tv_sec *is* time_t,
+ * but some systems have it wrong */
+ tmp = ut->ut_tv.tv_sec;
+ /* 15 chars for time: Nov 10 19:33:20 */
+ printf("%-10s %-8s %-9s %-15.15s %s\n",
+ ut->ut_user, ut->ut_line, str6,
+ ctime(&tmp) + 4, ut->ut_host);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(name);
+ }
+ }
+ if (ENABLE_FEATURE_CLEAN_UP)
+ endutent();
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/whoami.c b/cleopatre/busybox-1.11.1-spc300/coreutils/whoami.c
new file mode 100644
index 0000000000..d35572ecea
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/whoami.c
@@ -0,0 +1,26 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini whoami implementation for busybox
+ *
+ * Copyright (C) 2000 Edward Betts <edward@debian.org>.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */
+
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
+
+int whoami_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int whoami_main(int argc, char **argv ATTRIBUTE_UNUSED)
+{
+ if (argc > 1)
+ bb_show_usage();
+
+ /* Will complain and die if username not found */
+ puts(bb_getpwuid(NULL, -1, geteuid()));
+
+ return fflush(stdout);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/coreutils/yes.c b/cleopatre/busybox-1.11.1-spc300/coreutils/yes.c
new file mode 100644
index 0000000000..9d3f675501
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/coreutils/yes.c
@@ -0,0 +1,42 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * yes implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */
+
+/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
+ *
+ * Size reductions and removed redundant applet name prefix from error messages.
+ */
+
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
+
+int yes_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int yes_main(int argc, char **argv)
+{
+ char **pp;
+
+ argv[0] = (char*)"y";
+ if (argc != 1) {
+ ++argv;
+ }
+
+ do {
+ pp = argv;
+ while (1) {
+ fputs(*pp, stdout);
+ if (!*++pp)
+ break;
+ putchar(' ');
+ }
+ } while (putchar('\n') != EOF);
+
+ bb_perror_nomsg_and_die();
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/debianutils/Config.in b/cleopatre/busybox-1.11.1-spc300/debianutils/Config.in
new file mode 100644
index 0000000000..f1b73b645f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/debianutils/Config.in
@@ -0,0 +1,83 @@
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Debian Utilities"
+
+config MKTEMP
+ bool "mktemp"
+ default n
+ help
+ mktemp is used to create unique temporary files
+
+config PIPE_PROGRESS
+ bool "pipe_progress"
+ default n
+ help
+ Display a dot to indicate pipe activity.
+
+config RUN_PARTS
+ bool "run-parts"
+ default n
+ help
+ run-parts is a utility designed to run all the scripts in a directory.
+
+ It is useful to set up a directory like cron.daily, where you need to
+ execute all the scripts in that directory.
+
+ In this implementation of run-parts some features (such as report mode)
+ are not implemented.
+
+ Unless you know that run-parts is used in some of your scripts
+ you can safely say N here.
+
+config FEATURE_RUN_PARTS_LONG_OPTIONS
+ bool "Enable long options"
+ default n
+ depends on RUN_PARTS && GETOPT_LONG
+ help
+ Support long options for the run-parts applet.
+
+config FEATURE_RUN_PARTS_FANCY
+ bool "Support additional arguments"
+ default n
+ depends on RUN_PARTS
+ help
+ Support additional options:
+ -l --list print the names of the all matching files (not
+ limited to executables), but don't actually run them.
+
+config START_STOP_DAEMON
+ bool "start-stop-daemon"
+ default n
+ help
+ start-stop-daemon is used to control the creation and
+ termination of system-level processes, usually the ones
+ started during the startup of the system.
+
+config FEATURE_START_STOP_DAEMON_FANCY
+ bool "Support additional arguments"
+ default n
+ depends on START_STOP_DAEMON
+ help
+ Support additional arguments.
+ -o|--oknodo ignored since we exit with 0 anyway
+ -v|--verbose
+
+config FEATURE_START_STOP_DAEMON_LONG_OPTIONS
+ bool "Enable long options"
+ default n
+ depends on START_STOP_DAEMON && GETOPT_LONG
+ help
+ Support long options for the start-stop-daemon applet.
+
+config WHICH
+ bool "which"
+ default n
+ help
+ which is used to find programs in your PATH and
+ print out their pathnames.
+
+endmenu
+
diff --git a/cleopatre/busybox-1.11.1-spc300/debianutils/Kbuild b/cleopatre/busybox-1.11.1-spc300/debianutils/Kbuild
new file mode 100644
index 0000000000..bcf6126add
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/debianutils/Kbuild
@@ -0,0 +1,12 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+lib-y:=
+lib-$(CONFIG_MKTEMP) += mktemp.o
+lib-$(CONFIG_PIPE_PROGRESS) += pipe_progress.o
+lib-$(CONFIG_RUN_PARTS) += run_parts.o
+lib-$(CONFIG_START_STOP_DAEMON) += start_stop_daemon.o
+lib-$(CONFIG_WHICH) += which.o
diff --git a/cleopatre/busybox-1.11.1-spc300/debianutils/mktemp.c b/cleopatre/busybox-1.11.1-spc300/debianutils/mktemp.c
new file mode 100644
index 0000000000..c48b6e2d56
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/debianutils/mktemp.c
@@ -0,0 +1,69 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini mktemp implementation for busybox
+ *
+ *
+ * Copyright (C) 2000 by Daniel Jacobowitz
+ * Written by Daniel Jacobowitz <dan@debian.org>
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+/* Coreutils 6.12 man page says:
+ * mktemp [OPTION]... [TEMPLATE]
+ * Create a temporary file or directory, safely, and print its name. If
+ * TEMPLATE is not specified, use tmp.XXXXXXXXXX.
+ * -d, --directory
+ * create a directory, not a file
+ * -q, --quiet
+ * suppress diagnostics about file/dir-creation failure
+ * -u, --dry-run
+ * do not create anything; merely print a name (unsafe)
+ * --tmpdir[=DIR]
+ * interpret TEMPLATE relative to DIR. If DIR is not specified,
+ * use $TMPDIR if set, else /tmp. With this option, TEMPLATE must
+ * not be an absolute name. Unlike with -t, TEMPLATE may contain
+ * slashes, but even here, mktemp still creates only the final com-
+ * ponent.
+ * -p DIR use DIR as a prefix; implies -t [deprecated]
+ * -t interpret TEMPLATE as a single file name component, relative to
+ * a directory: $TMPDIR, if set; else the directory specified via
+ * -p; else /tmp [deprecated]
+ */
+
+
+#include "libbb.h"
+
+int mktemp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int mktemp_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ const char *path;
+ char *chp;
+ unsigned opt;
+
+ opt_complementary = "?1"; /* 1 argument max */
+ opt = getopt32(argv, "dqtp:", &path);
+ chp = argv[optind] ? argv[optind] : xstrdup("tmp.XXXXXX");
+
+ if (opt & (4|8)) { /* -t and/or -p */
+ const char *dir = getenv("TMPDIR");
+ if (dir && *dir != '\0')
+ path = dir;
+ else if (!(opt & 8)) /* no -p */
+ path = "/tmp/";
+ /* else path comes from -p DIR */
+ chp = concat_path_file(path, chp);
+ }
+
+ if (opt & 1) { /* -d */
+ if (mkdtemp(chp) == NULL)
+ return EXIT_FAILURE;
+ } else {
+ if (mkstemp(chp) < 0)
+ return EXIT_FAILURE;
+ }
+
+ puts(chp);
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/debianutils/pipe_progress.c b/cleopatre/busybox-1.11.1-spc300/debianutils/pipe_progress.c
new file mode 100644
index 0000000000..cbdd38ff42
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/debianutils/pipe_progress.c
@@ -0,0 +1,39 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Monitor a pipe with a simple progress display.
+ *
+ * Copyright (C) 2003 by Rob Landley <rob@landley.net>, Joey Hess
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+#define PIPE_PROGRESS_SIZE 4096
+
+/* Read a block of data from stdin, write it to stdout.
+ * Activity is indicated by a '.' to stderr
+ */
+int pipe_progress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int pipe_progress_main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
+{
+ RESERVE_CONFIG_BUFFER(buf, PIPE_PROGRESS_SIZE);
+ time_t t = time(NULL);
+ size_t len;
+
+ while ((len = fread(buf, 1, PIPE_PROGRESS_SIZE, stdin)) > 0) {
+ time_t new_time = time(NULL);
+ if (new_time != t) {
+ t = new_time;
+ fputc('.', stderr);
+ }
+ fwrite(buf, len, 1, stdout);
+ }
+
+ fputc('\n', stderr);
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ RELEASE_CONFIG_BUFFER(buf);
+
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/debianutils/run_parts.c b/cleopatre/busybox-1.11.1-spc300/debianutils/run_parts.c
new file mode 100644
index 0000000000..c9b0907172
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/debianutils/run_parts.c
@@ -0,0 +1,173 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini run-parts implementation for busybox
+ *
+ * Copyright (C) 2007 Bernhard Fischer
+ *
+ * Based on a older version that was in busybox which was 1k big..
+ * Copyright (C) 2001 by Emanuele Aina <emanuele.aina@tiscali.it>
+ *
+ * Based on the Debian run-parts program, version 1.15
+ * Copyright (C) 1996 Jeff Noxon <jeff@router.patch.net>,
+ * Copyright (C) 1996-1999 Guy Maor <maor@debian.org>
+ *
+ *
+ * Licensed under GPL v2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* This is my first attempt to write a program in C (well, this is my first
+ * attempt to write a program! :-) . */
+
+/* This piece of code is heavily based on the original version of run-parts,
+ * taken from debian-utils. I've only removed the long options and a the
+ * report mode. As the original run-parts support only long options, I've
+ * broken compatibility because the BusyBox policy doesn't allow them.
+ * The supported options are:
+ * -t test. Print the name of the files to be executed, without
+ * execute them.
+ * -a ARG argument. Pass ARG as an argument the program executed. It can
+ * be repeated to pass multiple arguments.
+ * -u MASK umask. Set the umask of the program executed to MASK.
+ */
+
+#include "libbb.h"
+
+struct globals {
+ char **names;
+ int cur;
+ char *cmd[1];
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+#define names (G.names)
+#define cur (G.cur )
+#define cmd (G.cmd )
+
+enum { NUM_CMD = (COMMON_BUFSIZE - sizeof(G)) / sizeof(cmd[0]) - 1 };
+
+enum {
+ OPT_r = (1 << 0),
+ OPT_a = (1 << 1),
+ OPT_u = (1 << 2),
+ OPT_t = (1 << 3),
+ OPT_l = (1 << 4) * ENABLE_FEATURE_RUN_PARTS_FANCY,
+};
+
+#if ENABLE_FEATURE_RUN_PARTS_FANCY
+#define list_mode (option_mask32 & OPT_l)
+#else
+#define list_mode 0
+#endif
+
+/* Is this a valid filename (upper/lower alpha, digits,
+ * underscores, and hyphens only?)
+ */
+static bool invalid_name(const char *c)
+{
+ c = bb_basename(c);
+
+ while (*c && (isalnum(*c) || *c == '_' || *c == '-'))
+ c++;
+
+ return *c; /* TRUE (!0) if terminating NUL is not reached */
+}
+
+static int bb_alphasort(const void *p1, const void *p2)
+{
+ int r = strcmp(*(char **) p1, *(char **) p2);
+ return (option_mask32 & OPT_r) ? -r : r;
+}
+
+static int act(const char *file, struct stat *statbuf, void *args ATTRIBUTE_UNUSED, int depth)
+{
+ if (depth == 1)
+ return TRUE;
+
+ if (depth == 2
+ && ( !(statbuf->st_mode & (S_IFREG | S_IFLNK))
+ || invalid_name(file)
+ || (!list_mode && access(file, X_OK) != 0))
+ ) {
+ return SKIP;
+ }
+
+ names = xrealloc(names, (cur + 2) * sizeof(names[0]));
+ names[cur++] = xstrdup(file);
+ names[cur] = NULL;
+
+ return TRUE;
+}
+
+#if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS
+static const char runparts_longopts[] ALIGN1 =
+ "arg\0" Required_argument "a"
+ "umask\0" Required_argument "u"
+ "test\0" No_argument "t"
+#if ENABLE_FEATURE_RUN_PARTS_FANCY
+ "list\0" No_argument "l"
+ "reverse\0" No_argument "r"
+//TODO: "verbose\0" No_argument "v"
+#endif
+ ;
+#endif
+
+int run_parts_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int run_parts_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ const char *umask_p = "22";
+ llist_t *arg_list = NULL;
+ unsigned n;
+ int ret;
+
+#if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS
+ applet_long_options = runparts_longopts;
+#endif
+ /* We require exactly one argument: the directory name */
+ /* We require exactly one argument: the directory name */
+ opt_complementary = "=1:a::";
+ getopt32(argv, "ra:u:t"USE_FEATURE_RUN_PARTS_FANCY("l"), &arg_list, &umask_p);
+
+ umask(xstrtou_range(umask_p, 8, 0, 07777));
+
+ n = 1;
+ while (arg_list && n < NUM_CMD) {
+ cmd[n++] = llist_pop(&arg_list);
+ }
+ /* cmd[n] = NULL; - is already zeroed out */
+
+ /* run-parts has to sort executables by name before running them */
+
+ recursive_action(argv[optind],
+ ACTION_RECURSE|ACTION_FOLLOWLINKS,
+ act, /* file action */
+ act, /* dir action */
+ NULL, /* user data */
+ 1 /* depth */
+ );
+
+ if (!names)
+ return 0;
+
+ qsort(names, cur, sizeof(char *), bb_alphasort);
+
+ n = 0;
+ while (1) {
+ char *name = *names++;
+ if (!name)
+ break;
+ if (option_mask32 & (OPT_t | OPT_l)) {
+ puts(name);
+ continue;
+ }
+ cmd[0] = name;
+ ret = wait4pid(spawn(cmd));
+ if (ret == 0)
+ continue;
+ n = 1;
+ if (ret < 0)
+ bb_perror_msg("can't exec %s", name);
+ else /* ret > 0 */
+ bb_error_msg("%s exited with code %d", name, ret);
+ }
+
+ return n;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/debianutils/start_stop_daemon.c b/cleopatre/busybox-1.11.1-spc300/debianutils/start_stop_daemon.c
new file mode 100644
index 0000000000..459fb77e0f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/debianutils/start_stop_daemon.c
@@ -0,0 +1,447 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini start-stop-daemon implementation(s) for busybox
+ *
+ * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
+ * Adapted for busybox David Kimdon <dwhedon@gordian.com>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/*
+This is how it is supposed to work:
+
+start-stop-daemon [OPTIONS] [--start|--stop] [[--] arguments...]
+
+One (only) of these must be given:
+ -S,--start Start
+ -K,--stop Stop
+
+Search for matching processes.
+If --stop is given, stop all matching processes (by sending a signal).
+If --start is given, start a new process unless a matching process was found.
+
+Options controlling process matching
+(if multiple conditions are specified, all must match):
+ -u,--user USERNAME|UID Only consider this user's processes
+ -n,--name PROCESS_NAME Look for processes by matching PROCESS_NAME
+ with comm field in /proc/$PID/stat.
+ Only basename is compared:
+ "ntpd" == "./ntpd" == "/path/to/ntpd".
+[TODO: can PROCESS_NAME be a full pathname? Should we require full match then
+with /proc/$PID/exe or argv[0] (comm can't be matched, it never contains path)]
+ -x,--exec EXECUTABLE Look for processes that were started with this
+ command in /proc/$PID/cmdline.
+ Unlike -n, we match against the full path:
+ "ntpd" != "./ntpd" != "/path/to/ntpd"
+ -p,--pidfile PID_FILE Look for processes with PID from this file
+
+Options which are valid for --start only:
+ -x,--exec EXECUTABLE Program to run (1st arg of execvp). Mandatory.
+ -a,--startas NAME argv[0] (defaults to EXECUTABLE)
+ -b,--background Put process into background
+ -N,--nicelevel N Add N to process' nice level
+ -c,--chuid USER[:[GRP]] Change to specified user [and group]
+ -m,--make-pidfile Write PID to the pidfile
+ (both -m and -p must be given!)
+
+Options which are valid for --stop only:
+ -s,--signal SIG Signal to send (default:TERM)
+ -t,--test Exit with status 0 if process is found
+ (we don't actually start or stop daemons)
+
+Misc options:
+ -o,--oknodo Exit with status 0 if nothing is done
+ -q,--quiet Quiet
+ -v,--verbose Verbose
+*/
+
+#include <sys/resource.h>
+
+/* Override ENABLE_FEATURE_PIDFILE */
+#define WANT_PIDFILE 1
+#include "libbb.h"
+
+struct pid_list {
+ struct pid_list *next;
+ pid_t pid;
+};
+
+enum {
+ CTX_STOP = (1 << 0),
+ CTX_START = (1 << 1),
+ OPT_BACKGROUND = (1 << 2), // -b
+ OPT_QUIET = (1 << 3), // -q
+ OPT_TEST = (1 << 4), // -t
+ OPT_MAKEPID = (1 << 5), // -m
+ OPT_a = (1 << 6), // -a
+ OPT_n = (1 << 7), // -n
+ OPT_s = (1 << 8), // -s
+ OPT_u = (1 << 9), // -u
+ OPT_c = (1 << 10), // -c
+ OPT_x = (1 << 11), // -x
+ OPT_p = (1 << 12), // -p
+ OPT_OKNODO = (1 << 13) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -o
+ OPT_VERBOSE = (1 << 14) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -v
+ OPT_NICELEVEL = (1 << 15) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -N
+};
+#define QUIET (option_mask32 & OPT_QUIET)
+#define TEST (option_mask32 & OPT_TEST)
+
+struct globals {
+ struct pid_list *found;
+ char *userspec;
+ char *cmdname;
+ char *execname;
+ char *pidfile;
+ int user_id;
+ smallint signal_nr;
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+#define found (G.found )
+#define userspec (G.userspec )
+#define cmdname (G.cmdname )
+#define execname (G.execname )
+#define pidfile (G.pidfile )
+#define user_id (G.user_id )
+#define signal_nr (G.signal_nr )
+#define INIT_G() do { \
+ user_id = -1; \
+ signal_nr = 15; \
+} while (0)
+
+#ifdef OLDER_VERSION_OF_X
+/* -x,--exec EXECUTABLE
+ * Look for processes with matching /proc/$PID/exe.
+ * Match is performed using device+inode.
+ */
+static int pid_is_exec(pid_t pid)
+{
+ struct stat st;
+ char buf[sizeof("/proc//exe") + sizeof(int)*3];
+
+ sprintf(buf, "/proc/%u/exe", (unsigned)pid);
+ if (stat(buf, &st) < 0)
+ return 0;
+ if (st.st_dev == execstat.st_dev
+ && st.st_ino == execstat.st_ino)
+ return 1;
+ return 0;
+}
+#endif
+
+static int pid_is_exec(pid_t pid)
+{
+ ssize_t bytes;
+ char buf[PATH_MAX];
+
+ sprintf(buf, "/proc/%u/cmdline", (unsigned)pid);
+ bytes = open_read_close(buf, buf, sizeof(buf) - 1);
+ if (bytes > 0) {
+ buf[bytes] = '\0';
+ return strcmp(buf, execname) == 0;
+ }
+ return 0;
+}
+
+static int pid_is_name(pid_t pid)
+{
+ /* /proc/PID/stat is "PID (comm_15_bytes_max) ..." */
+ char buf[32]; /* should be enough */
+ char *p, *pe;
+
+ sprintf(buf, "/proc/%u/stat", (unsigned)pid);
+ if (open_read_close(buf, buf, sizeof(buf) - 1) < 0)
+ return 0;
+ buf[sizeof(buf) - 1] = '\0'; /* paranoia */
+ p = strchr(buf, '(');
+ if (!p)
+ return 0;
+ pe = strrchr(++p, ')');
+ if (!pe)
+ return 0;
+ *pe = '\0';
+ /* we require comm to match and to not be truncated */
+ /* in Linux, if comm is 15 chars, it may be a truncated
+ * name, so we don't allow that to match */
+ if (strlen(p) >= COMM_LEN - 1) /* COMM_LEN is 16 */
+ return 0;
+ return strcmp(p, cmdname) == 0;
+}
+
+static int pid_is_user(int pid)
+{
+ struct stat sb;
+ char buf[sizeof("/proc/") + sizeof(int)*3];
+
+ sprintf(buf, "/proc/%u", (unsigned)pid);
+ if (stat(buf, &sb) != 0)
+ return 0;
+ return (sb.st_uid == (uid_t)user_id);
+}
+
+static void check(int pid)
+{
+ struct pid_list *p;
+
+ if (execname && !pid_is_exec(pid)) {
+ return;
+ }
+ if (cmdname && !pid_is_name(pid)) {
+ return;
+ }
+ if (userspec && !pid_is_user(pid)) {
+ return;
+ }
+ p = xmalloc(sizeof(*p));
+ p->next = found;
+ p->pid = pid;
+ found = p;
+}
+
+static void do_pidfile(void)
+{
+ FILE *f;
+ unsigned pid;
+
+ f = fopen(pidfile, "r");
+ if (f) {
+ if (fscanf(f, "%u", &pid) == 1)
+ check(pid);
+ fclose(f);
+ } else if (errno != ENOENT)
+ bb_perror_msg_and_die("open pidfile %s", pidfile);
+}
+
+static void do_procinit(void)
+{
+ DIR *procdir;
+ struct dirent *entry;
+ int pid;
+
+ if (pidfile) {
+ do_pidfile();
+ return;
+ }
+
+ procdir = xopendir("/proc");
+
+ pid = 0;
+ while (1) {
+ errno = 0; /* clear any previous error */
+ entry = readdir(procdir);
+// TODO: this check is too generic, it's better
+// to check for exact errno(s) which mean that we got stale entry
+ if (errno) /* Stale entry, process has died after opendir */
+ continue;
+ if (!entry) /* EOF, no more entries */
+ break;
+ pid = bb_strtou(entry->d_name, NULL, 10);
+ if (errno) /* NaN */
+ continue;
+ check(pid);
+ }
+ closedir(procdir);
+ if (!pid)
+ bb_error_msg_and_die("nothing in /proc - not mounted?");
+}
+
+static int do_stop(void)
+{
+ char *what;
+ struct pid_list *p;
+ int killed = 0;
+
+ if (cmdname) {
+ if (ENABLE_FEATURE_CLEAN_UP) what = xstrdup(cmdname);
+ if (!ENABLE_FEATURE_CLEAN_UP) what = cmdname;
+ } else if (execname) {
+ if (ENABLE_FEATURE_CLEAN_UP) what = xstrdup(execname);
+ if (!ENABLE_FEATURE_CLEAN_UP) what = execname;
+ } else if (pidfile) {
+ what = xasprintf("process in pidfile '%s'", pidfile);
+ } else if (userspec) {
+ what = xasprintf("process(es) owned by '%s'", userspec);
+ } else {
+ bb_error_msg_and_die("internal error, please report");
+ }
+
+ if (!found) {
+ if (!QUIET)
+ printf("no %s found; none killed\n", what);
+ killed = -1;
+ goto ret;
+ }
+ for (p = found; p; p = p->next) {
+ if (TEST || kill(p->pid, signal_nr) == 0) {
+ killed++;
+ } else {
+ p->pid = 0;
+ bb_perror_msg("warning: killing process %u", (unsigned)p->pid);
+ }
+ }
+ if (!QUIET && killed) {
+ printf("stopped %s (pid", what);
+ for (p = found; p; p = p->next)
+ if (p->pid)
+ printf(" %u", (unsigned)p->pid);
+ puts(")");
+ }
+ ret:
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(what);
+ return killed;
+}
+
+#if ENABLE_FEATURE_START_STOP_DAEMON_LONG_OPTIONS
+static const char start_stop_daemon_longopts[] ALIGN1 =
+ "stop\0" No_argument "K"
+ "start\0" No_argument "S"
+ "background\0" No_argument "b"
+ "quiet\0" No_argument "q"
+ "test\0" No_argument "t"
+ "make-pidfile\0" No_argument "m"
+#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
+ "oknodo\0" No_argument "o"
+ "verbose\0" No_argument "v"
+ "nicelevel\0" Required_argument "N"
+#endif
+ "startas\0" Required_argument "a"
+ "name\0" Required_argument "n"
+ "signal\0" Required_argument "s"
+ "user\0" Required_argument "u"
+ "chuid\0" Required_argument "c"
+ "exec\0" Required_argument "x"
+ "pidfile\0" Required_argument "p"
+#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
+ "retry\0" Required_argument "R"
+#endif
+ ;
+#endif
+
+int start_stop_daemon_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int start_stop_daemon_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ unsigned opt;
+ char *signame;
+ char *startas;
+ char *chuid;
+#ifdef OLDER_VERSION_OF_X
+ struct stat execstat;
+#endif
+#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
+// char *retry_arg = NULL;
+// int retries = -1;
+ char *opt_N;
+#endif
+
+ INIT_G();
+
+#if ENABLE_FEATURE_START_STOP_DAEMON_LONG_OPTIONS
+ applet_long_options = start_stop_daemon_longopts;
+#endif
+
+ /* -K or -S is required; they are mutually exclusive */
+ /* -p is required if -m is given */
+ /* -xpun (at least one) is required if -K is given */
+ /* -xa (at least one) is required if -S is given */
+ /* -q turns off -v */
+ opt_complementary = "K:S:K--S:S--K:m?p:K?xpun:S?xa"
+ USE_FEATURE_START_STOP_DAEMON_FANCY("q-v");
+ opt = getopt32(argv, "KSbqtma:n:s:u:c:x:p:"
+ USE_FEATURE_START_STOP_DAEMON_FANCY("ovN:"),
+// USE_FEATURE_START_STOP_DAEMON_FANCY("ovN:R:"),
+ &startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile
+ USE_FEATURE_START_STOP_DAEMON_FANCY(,&opt_N)
+// USE_FEATURE_START_STOP_DAEMON_FANCY(,&retry_arg)
+ );
+
+ if (opt & OPT_s) {
+ signal_nr = get_signum(signame);
+ if (signal_nr < 0) bb_show_usage();
+ }
+
+ if (!(opt & OPT_a))
+ startas = execname;
+ if (!execname) /* in case -a is given and -x is not */
+ execname = startas;
+
+// USE_FEATURE_START_STOP_DAEMON_FANCY(
+// if (retry_arg)
+// retries = xatoi_u(retry_arg);
+// )
+ //argc -= optind;
+ argv += optind;
+
+ if (userspec) {
+ user_id = bb_strtou(userspec, NULL, 10);
+ if (errno)
+ user_id = xuname2uid(userspec);
+ }
+ /* Both start and stop need to know current processes */
+ do_procinit();
+
+ if (opt & CTX_STOP) {
+ int i = do_stop();
+ return (opt & OPT_OKNODO) ? 0 : (i <= 0);
+ }
+
+ if (found) {
+ if (!QUIET)
+ printf("%s is already running\n%u\n", execname, (unsigned)found->pid);
+ return !(opt & OPT_OKNODO);
+ }
+
+#ifdef OLDER_VERSION_OF_X
+ if (execname)
+ xstat(execname, &execstat);
+#endif
+
+ *--argv = startas;
+ if (opt & OPT_BACKGROUND) {
+#if BB_MMU
+ bb_daemonize(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS);
+ /* DAEMON_DEVNULL_STDIO is superfluous -
+ * it's always done by bb_daemonize() */
+#else
+ pid_t pid = vfork();
+ if (pid < 0) /* error */
+ bb_perror_msg_and_die("vfork");
+ if (pid != 0) {
+ /* parent */
+ /* why _exit? the child may have changed the stack,
+ * so "return 0" may do bad things */
+ _exit(EXIT_SUCCESS);
+ }
+ /* Child */
+ setsid(); /* detach from controlling tty */
+ /* Redirect stdio to /dev/null, close extra FDs.
+ * We do not actually daemonize because of DAEMON_ONLY_SANITIZE */
+ bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO
+ + DAEMON_CLOSE_EXTRA_FDS
+ + DAEMON_ONLY_SANITIZE,
+ NULL /* argv, unused */ );
+#endif
+ }
+ if (opt & OPT_MAKEPID) {
+ /* User wants _us_ to make the pidfile */
+ write_pidfile(pidfile);
+ }
+ if (opt & OPT_c) {
+ struct bb_uidgid_t ugid;
+ parse_chown_usergroup_or_die(&ugid, chuid);
+ if (ugid.gid != (gid_t) -1) xsetgid(ugid.gid);
+ if (ugid.uid != (uid_t) -1) xsetuid(ugid.uid);
+ }
+#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
+ if (opt & OPT_NICELEVEL) {
+ /* Set process priority */
+ int prio = getpriority(PRIO_PROCESS, 0) + xatoi_range(opt_N, INT_MIN/2, INT_MAX/2);
+ if (setpriority(PRIO_PROCESS, 0, prio) < 0) {
+ bb_perror_msg_and_die("setpriority(%d)", prio);
+ }
+ }
+#endif
+ execvp(startas, argv);
+ bb_perror_msg_and_die("cannot start %s", startas);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/debianutils/which.c b/cleopatre/busybox-1.11.1-spc300/debianutils/which.c
new file mode 100644
index 0000000000..41a864cfa5
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/debianutils/which.c
@@ -0,0 +1,90 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Which implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2006 Gabriel Somlo <somlo at cmu.edu>
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ *
+ * Based on which from debianutils
+ */
+
+#include "libbb.h"
+
+int which_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int which_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ USE_DESKTOP(int opt;)
+ int status = EXIT_SUCCESS;
+ char *path;
+ char *p;
+
+ opt_complementary = "-1"; /* at least one argument */
+ USE_DESKTOP(opt =) getopt32(argv, "a");
+ argv += optind;
+
+ /* This matches what is seen on e.g. ubuntu.
+ * "which" there is a shell script. */
+ path = getenv("PATH");
+ if (!path) {
+ path = (char*)bb_PATH_root_path;
+ putenv(path);
+ path += 5; /* skip "PATH=" */
+ }
+
+ do {
+#if ENABLE_DESKTOP
+/* Much bloat just to support -a */
+ if (strchr(*argv, '/')) {
+ if (execable_file(*argv)) {
+ puts(*argv);
+ continue;
+ }
+ status = EXIT_FAILURE;
+ } else {
+ char *path2 = xstrdup(path);
+ char *tmp = path2;
+
+ p = find_execable(*argv, &tmp);
+ if (!p)
+ status = EXIT_FAILURE;
+ else {
+ print:
+ puts(p);
+ free(p);
+ if (opt) {
+ /* -a: show matches in all PATH components */
+ if (tmp) {
+ p = find_execable(*argv, &tmp);
+ if (p)
+ goto print;
+ }
+ }
+ }
+ free(path2);
+ }
+#else
+/* Just ignoring -a */
+ if (strchr(*argv, '/')) {
+ if (execable_file(*argv)) {
+ puts(*argv);
+ continue;
+ }
+ } else {
+ char *path2 = xstrdup(path);
+ char *tmp = path2;
+ p = find_execable(*argv, &tmp);
+ free(path2);
+ if (p) {
+ puts(p);
+ free(p);
+ continue;
+ }
+ }
+ status = EXIT_FAILURE;
+#endif
+ } while (*(++argv) != NULL);
+
+ fflush_stdout_and_exit(status);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/autodocifier.pl b/cleopatre/busybox-1.11.1-spc300/docs/autodocifier.pl
new file mode 100755
index 0000000000..68b6f3c058
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/autodocifier.pl
@@ -0,0 +1,303 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Getopt::Long;
+
+# collect lines continued with a '\' into an array
+sub continuation {
+ my $fh = shift;
+ my @line;
+
+ while (<$fh>) {
+ my $s = $_;
+ $s =~ s/\\\s*$//;
+ #$s =~ s/#.*$//;
+ push @line, $s;
+ last unless (/\\\s*$/);
+ }
+ return @line;
+}
+
+# regex && eval away unwanted strings from documentation
+sub beautify {
+ my $text = shift;
+ for (;;) {
+ my $text2 = $text;
+ $text =~ s/SKIP_\w+\(.*?"\s*\)//sxg;
+ $text =~ s/USE_\w+\(\s*?(.*?)"\s*\)/$1"/sxg;
+ $text =~ s/USAGE_\w+\(\s*?(.*?)"\s*\)/$1"/sxg;
+ last if ( $text2 eq $text );
+ }
+ $text =~ s/"\s*"//sg;
+ my @line = split("\n", $text);
+ $text = join('',
+ map {
+ s/^\s*"//;
+ s/"\s*$//;
+ s/%/%%/g;
+ s/\$/\\\$/g;
+ eval qq[ sprintf(qq{$_}) ]
+ } @line
+ );
+ return $text;
+}
+
+# generate POD for an applet
+sub pod_for_usage {
+ my $name = shift;
+ my $usage = shift;
+
+ # Sigh. Fixup the known odd-name applets.
+ $name =~ s/dpkg_deb/dpkg-deb/g;
+ $name =~ s/fsck_minix/fsck.minix/g;
+ $name =~ s/mkfs_minix/mkfs.minix/g;
+ $name =~ s/run_parts/run-parts/g;
+ $name =~ s/start_stop_daemon/start-stop-daemon/g;
+
+ # make options bold
+ my $trivial = $usage->{trivial};
+ if (!defined $usage->{trivial}) {
+ $trivial = "";
+ } else {
+ $trivial =~ s/(?<!\w)(-\w+)/B<$1>/sxg;
+ }
+ my @f0 =
+ map { $_ !~ /^\s/ && s/(?<!\w)(-\w+)/B<$1>/g; $_ }
+ split("\n", (defined $usage->{full} ? $usage->{full} : ""));
+
+ # add "\n" prior to certain lines to make indented
+ # lines look right
+ my @f1;
+ my $len = @f0;
+ for (my $i = 0; $i < $len; $i++) {
+ push @f1, $f0[$i];
+ if (($i+1) != $len && $f0[$i] !~ /^\s/ && $f0[$i+1] =~ /^\s/) {
+ next if ($f0[$i] =~ /^$/);
+ push(@f1, "") unless ($f0[$i+1] =~ /^\s*$/s);
+ }
+ }
+ my $full = join("\n", @f1);
+
+ # prepare notes if they exist
+ my $notes = (defined $usage->{notes})
+ ? "$usage->{notes}\n\n"
+ : "";
+
+ # prepare examples if they exist
+ my $example = (defined $usage->{example})
+ ?
+ "Example:\n\n" .
+ join ("\n",
+ map { "\t$_" }
+ split("\n", $usage->{example})) . "\n\n"
+ : "";
+
+ # Pad the name so that the applet name gets a line
+ # by itself in BusyBox.txt
+ my $spaces = 10 - length($name);
+ if ($spaces > 0) {
+ $name .= " " x $spaces;
+ }
+
+ return
+ "=item B<$name>".
+ "\n\n$name $trivial\n\n".
+ "$full\n\n" .
+ "$notes" .
+ "$example" .
+ "\n\n"
+ ;
+}
+
+# the keys are applet names, and
+# the values will contain hashrefs of the form:
+#
+# {
+# trivial => "...",
+# full => "...",
+# notes => "...",
+# example => "...",
+# }
+my %docs;
+
+
+# get command-line options
+
+my %opt;
+
+GetOptions(
+ \%opt,
+ "help|h",
+ "pod|p",
+ "verbose|v",
+);
+
+if (defined $opt{help}) {
+ print
+ "$0 [OPTION]... [FILE]...\n",
+ "\t--help\n",
+ "\t--pod\n",
+ "\t--verbose\n",
+ ;
+ exit 1;
+}
+
+
+# collect documenation into %docs
+
+foreach (@ARGV) {
+ open(USAGE, $_) || die("$0: $_: $!");
+ my $fh = *USAGE;
+ my ($applet, $type, @line);
+ while (<$fh>) {
+ if (/^#define (\w+)_(\w+)_usage/) {
+ $applet = $1;
+ $type = $2;
+ @line = continuation($fh);
+ my $doc = $docs{$applet} ||= { };
+ my $text = join("\n", @line);
+ $doc->{$type} = beautify($text);
+ }
+ }
+}
+
+
+# generate structured documentation
+
+my $generator = \&pod_for_usage;
+
+my @names = sort keys %docs;
+my $line = "\t[, [[, ";
+for (my $i = 0; $i < $#names; $i++) {
+ if (length ($line.$names[$i]) >= 65) {
+ print "$line\n\t";
+ $line = "";
+ }
+ $line .= "$names[$i], ";
+}
+print $line . $names[-1];
+
+print "\n\n=head1 COMMAND DESCRIPTIONS\n";
+print "\n=over 4\n\n";
+
+foreach my $applet (@names) {
+ print $generator->($applet, $docs{$applet});
+}
+
+exit 0;
+
+__END__
+
+=head1 NAME
+
+autodocifier.pl - generate docs for busybox based on usage.h
+
+=head1 SYNOPSIS
+
+autodocifier.pl [OPTION]... [FILE]...
+
+Example:
+
+ ( cat docs/busybox_header.pod; \
+ docs/autodocifier.pl usage.h; \
+ cat docs/busybox_footer.pod ) > docs/busybox.pod
+
+=head1 DESCRIPTION
+
+The purpose of this script is to automagically generate
+documentation for busybox using its usage.h as the original source
+for content. It used to be that same content has to be duplicated
+in 3 places in slightly different formats -- F<usage.h>,
+F<docs/busybox.pod>. This was tedious and error-prone, so it was
+decided that F<usage.h> would contain all the text in a
+machine-readable form, and scripts could be used to transform this
+text into other forms if necessary.
+
+F<autodocifier.pl> is one such script. It is based on a script by
+Erik Andersen <andersen@codepoet.org> which was in turn based on a
+script by Mark Whitley <markw@codepoet.org>
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<--help>
+
+This displays the help message.
+
+=item B<--pod>
+
+Generate POD (this is the default)
+
+=item B<--verbose>
+
+Be verbose (not implemented)
+
+=back
+
+=head1 FORMAT
+
+The following is an example of some data this script might parse.
+
+ #define length_trivial_usage \
+ "STRING"
+ #define length_full_usage \
+ "Prints out the length of the specified STRING."
+ #define length_example_usage \
+ "$ length Hello\n" \
+ "5\n"
+
+Each entry is a cpp macro that defines a string. The macros are
+named systematically in the form:
+
+ $name_$type_usage
+
+$name is the name of the applet. $type can be "trivial", "full", "notes",
+or "example". Every documentation macro must end with "_usage".
+
+The definition of the types is as follows:
+
+=over 4
+
+=item B<trivial>
+
+This should be a brief, one-line description of parameters that
+the command expects. This will be displayed when B<-h> is issued to
+a command. I<REQUIRED>
+
+=item B<full>
+
+This should contain descriptions of each option. This will also
+be displayed along with the trivial help if CONFIG_FEATURE_TRIVIAL_HELP
+is disabled. I<REQUIRED>
+
+=item B<notes>
+
+This is documentation that is intended to go in the POD or SGML, but
+not be printed when a B<-h> is given to a command. To see an example
+of notes being used, see init_notes_usage in F<usage.h>. I<OPTIONAL>
+
+=item B<example>
+
+This should be an example of how the command is actually used.
+This will not be printed when a B<-h> is given to a command -- it
+will only be included in the POD or SGML documentation. I<OPTIONAL>
+
+=back
+
+=head1 FILES
+
+F<usage.h>
+
+=head1 COPYRIGHT
+
+Copyright (c) 2001 John BEPPU. All rights reserved. This program is
+free software; you can redistribute it and/or modify it under the same
+terms as Perl itself.
+
+=head1 AUTHOR
+
+John BEPPU <b@ax9.org>
+
+=cut
+
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/FAQ.html b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/FAQ.html
new file mode 100644
index 0000000000..e0a7597813
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/FAQ.html
@@ -0,0 +1,1143 @@
+<!--#include file="header.html" -->
+
+<h3>Frequently Asked Questions</h3>
+
+This is a collection of some of the more frequently asked questions
+about BusyBox. Some of the questions even have answers. If you
+have additions to this FAQ document, we would love to add them,
+
+<h2>General questions</h2>
+<ol>
+<li><a href="#getting_started">How can I get started using BusyBox?</a></li>
+<li><a href="#configure">How do I configure busybox?</a></li>
+<li><a href="#build">How do I build BusyBox with a cross-compiler?</a></li>
+<li><a href="#build_system">How do I build a BusyBox-based system?</a></li>
+<li><a href="#kernel">Which Linux kernel versions are supported?</a></li>
+<li><a href="#arch">Which architectures does BusyBox run on?</a></li>
+<li><a href="#libc">Which C libraries are supported?</a></li>
+<li><a href="#commercial">Can I include BusyBox as part of the software on my device?</a></li>
+<li><a href="#external">Where can I find other small utilities since busybox does not include the features I want?</a></li></li>
+<li><a href="#demanding">I demand that you to add &lt;favorite feature&gt; right now! How come you don't answer all my questions on the mailing list instantly? I demand that you help me with all of my problems <em>Right Now</em>!</a></li>
+<li><a href="#helpme">I need help with BusyBox! What should I do?</a></li>
+<li><a href="#contracts">I need you to add &lt;favorite feature&gt;! Are the BusyBox developers willing to be paid in order to fix bugs or add in &lt;favorite feature&gt;? Are you willing to provide support contracts?</a></li>
+</ol>
+
+<h2>Troubleshooting</h2>
+<ol>
+<li><a href="#bugs">I think I found a bug in BusyBox! What should I do?!</a></li>
+<li><a href="#backporting">I'm using an ancient version from the dawn of time and something's broken. Can you backport fixes for free?</a></li>
+<li><a href="#init">Busybox init isn't working!</a></li>
+<li><a href="#sed">I can't configure busybox on my system.</a></li>
+<li><a href="#job_control">Why do I keep getting "sh: can't access tty; job control turned off" errors? Why doesn't Control-C work within my shell?</a></li>
+</ol>
+
+<h2>Misc. questions</h2>
+<ol>
+ <li><a href="#tz">How do I change the time zone in busybox?</a></li>
+</ol>
+
+<h2>Programming questions</h2>
+<ol>
+ <li><a href="#goals">What are the goals of busybox?</a></li>
+ <li><a href="#design">What is the design of busybox?</a></li>
+ <li><a href="#source">How is the source code organized?</a></li>
+ <ul>
+ <li><a href="#source_applets">The applet directories.</a></li>
+ <li><a href="#source_libbb">The busybox shared library (libbb)</a></li>
+ </ul>
+ <li><a href="#optimize">I want to make busybox even smaller, how do I go about it?</a></li>
+ <li><a href="#adding">Adding an applet to busybox</a></li>
+ <li><a href="#standards">What standards does busybox adhere to?</a></li>
+ <li><a href="#portability">Portability.</a></li>
+ <li><a href="#tips">Tips and tricks.</a></li>
+ <ul>
+ <li><a href="#tips_encrypted_passwords">Encrypted Passwords</a></li>
+ <li><a href="#tips_vfork">Fork and vfork</a></li>
+ <li><a href="#tips_short_read">Short reads and writes</a></li>
+ <li><a href="#tips_memory">Memory used by relocatable code, PIC, and static linking.</a></li>
+ <li><a href="#tips_kernel_headers">Including Linux kernel headers.</a></li>
+ </ul>
+ <li><a href="#who">Who are the BusyBox developers?</a></li>
+ </ul>
+</ol>
+
+
+<hr />
+<h1>General questions</h1>
+
+<hr />
+<h2><a name="getting_started">How can I get started using BusyBox?</a></h2>
+
+<p> If you just want to try out busybox without installing it, download the
+ tarball, extract it, run "make defconfig", and then run "make".
+</p>
+<p>
+ This will create a busybox binary with almost all features enabled. To try
+ out a busybox applet, type "./busybox [appletname] [options]", for
+ example "./busybox ls -l" or "./busybox cat LICENSE". Type "./busybox"
+ to see a command list, and "busybox appletname --help" to see a brief
+ usage message for a given applet.
+</p>
+<p>
+ BusyBox uses the name it was invoked under to determine which applet is
+ being invoked. (Try "mv busybox ls" and then "./ls -l".) Installing
+ busybox consists of creating symlinks (or hardlinks) to the busybox
+ binary for each applet in busybox, and making sure these links are in
+ the shell's command $PATH. The special applet name "busybox" (or with
+ any optional suffix, such as "busybox-static") uses the first argument
+ to determine which applet to run, as shown above.
+</p>
+<p>
+ BusyBox also has a feature called the
+ <a name="standalone_shell">"standalone shell"</a>, where the busybox
+ shell runs any built-in applets before checking the command path. This
+ feature is also enabled by "make allyesconfig", and to try it out run
+ the command line "PATH= ./busybox ash". This will blank your command path
+ and run busybox as your command shell, so the only commands it can find
+ (without an explicit path such as /bin/ls) are the built-in busybox ones.
+ This is another good way to see what's built into busybox.
+ Note that the standalone shell requires CONFIG_BUSYBOX_EXEC_PATH
+ to be set appropriately, depending on whether or not /proc/self/exe is
+ available or not. If you do not have /proc, then point that config option
+ to the location of your busybox binary, usually /bin/busybox.
+ (So if you set it to /proc/self/exe, and happen to be able to chroot into
+ your rootfs, you must mount /proc beforehand.)
+</p>
+<p>
+ A typical indication that you set CONFIG_BUSYBOX_EXEC_PATH to proc but
+ forgot to mount proc is:
+<pre>
+$ /bin/echo $PATH
+/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/bin/X11
+$ echo $PATH
+/bin/sh: echo: not found
+</pre>
+
+<hr />
+<h2><a name="configure">How do I configure busybox?</a></h2>
+
+<p> Busybox is configured similarly to the linux kernel. Create a default
+ configuration and then run "make menuconfig" to modify it. The end
+ result is a .config file that tells the busybox build process what features
+ to include. So instead of "./configure; make; make install" the equivalent
+ busybox build would be "make defconfig; make; make install".
+</p>
+
+<p> Busybox configured with all features enabled is a little under a megabyte
+ dynamically linked on x86. To create a smaller busybox, configure it with
+ fewer features. Individual busybox applets cost anywhere from a few
+ hundred bytes to tens of kilobytes. Disable unneeded applets to save,
+ space, using menuconfig.
+</p>
+
+<p>The most important busybox configurators are:</p>
+
+<ul>
+<li><p>make <b>defconfig</b> - Create the maximum "sane" configuration. This
+enables almost all features, minus things like debugging options and features
+that require changes to the rest of the system to work (such as selinux or
+devfs device names). Use this if you want to start from a full-featured
+busybox and remove features until it's small enough.</p></li>
+<li><p>make <b>allnoconfig</b> - Disable everything. This creates a tiny version
+of busybox that doesn't do anything. Start here if you know exactly what
+you want and would like to select only those features.</p></li>
+<li><p>make <b>menuconfig</b> - Interactively modify a .config file through a
+multi-level menu interface. Use this after one of the previous two.</p></li>
+</ul>
+
+<p>Some other configuration options are:</p>
+<ul>
+<li><p>make <b>oldconfig</b> - Update an old .config file for a newer version
+of busybox.</p></li>
+<li><p>make <b>allyesconfig</b> - Select absolutely everything. This creates
+a statically linked version of busybox full of debug code, with dependencies on
+selinux, using devfs names... This makes sure everything compiles. Whether
+or not the result would do anything useful is an open question.</p></li>
+<li><p>make <b>allbareconfig</b> - Select all applets but disable all sub-features
+within each applet. More build coverage testing.</p></li>
+<li><p>make <b>randconfig</b> - Create a random configuration for test purposes.</p></li>
+</ul>
+
+<p> Menuconfig modifies your .config file through an interactive menu where you can enable or disable
+ busybox features, and get help about each feature.
+
+<p>
+ To build a smaller busybox binary, run "make menuconfig" and disable the
+ features you don't need. (Or run "make allnoconfig" and then use
+ menuconfig to add just the features you need. Don't forget to recompile
+ with "make" once you've finished configuring.)
+</p>
+
+<hr />
+<h2><a name="build">How do I build BusyBox with a cross-compiler?</a></h2>
+
+<p>
+ To build busybox with a cross-compiler, specify CROSS_COMPILE=&lt;prefix&gt;.
+</p>
+<p>
+ CROSS_COMPILE specifies the prefix used for all executables used
+ during compilation. Only gcc and related binutils executables
+ are prefixed with $(CROSS_COMPILE) in the makefiles.
+ CROSS_COMPILE can be set on the command line:
+<pre>
+ make CROSS_COMPILE=arm-linux-uclibcgnueabi-
+</pre>
+ Alternatively CROSS_COMPILE can be set in the environment.
+ Default value for CROSS_COMPILE is not to prefix executables.
+</p>
+
+<hr />
+<h2><a name="build_system">How do I build a BusyBox-based system?</a></h2>
+
+<p>
+ BusyBox is a package that replaces a dozen standard packages, but it is
+ not by itself a complete bootable system. Building an entire Linux
+ distribution from source is a bit beyond the scope of this FAQ, but it
+ understandably keeps cropping up on the mailing list, so here are some
+ pointers.
+</p>
+<p>
+ Start by learning how to strip a working system down to the bare essentials
+ needed to run one or two commands, so you know what it is you actually
+ need. An excellent practical place to do
+ this is the <a href="http://www.tldp.org/HOWTO/Bootdisk-HOWTO/">Linux
+ BootDisk Howto</a>, or for a more theoretical approach try
+ <a href="http://www.tldp.org/HOWTO/From-PowerUp-To-Bash-Prompt-HOWTO.html">From
+ PowerUp to Bash Prompt</a>.
+</p>
+<p>
+ To learn how to build a working Linux system entirely from source code,
+ the place to go is the <a href="http://www.linuxfromscratch.org">Linux
+ From Scratch</a> project. They have an entire book of step-by-step
+ instructions you can
+ <a href="http://www.linuxfromscratch.org/lfs/view/stable/">read online</a>
+ or
+ <a href="http://www.linuxfromscratch.org/lfs/downloads/stable/">download</a>.
+ Be sure to check out the other sections of their main page, including
+ Beyond Linux From Scratch, Hardened Linux From Scratch, their Hints
+ directory, and their LiveCD project. (They also have mailing lists which
+ are better sources of answers to Linux-system building questions than
+ the busybox list.)
+</p>
+<p>
+ If you want an automated yet customizable system builder which produces
+ a BusyBox and uClibc based system, try
+ <a href="http://buildroot.uclibc.org">buildroot</a>, which is
+ another project by the maintainer of the uClibc (Erik Andersen).
+ Download the tarball, extract it, unset CC, make.
+ For more instructions, see the website.
+</p>
+
+<hr />
+<h2><a name="kernel">Which Linux kernel versions are supported?</a></h2>
+
+<p>
+ Full functionality requires Linux 2.4.x or better. (Earlier versions may
+ still work, but are no longer regularly tested.) A large fraction of the
+ code should run on just about anything. While the current code is fairly
+ Linux specific, it should be fairly easy to port the majority of the code
+ to support, say, FreeBSD or Solaris, or Mac OS X, or even Windows (if you
+ are into that sort of thing).
+</p>
+
+<hr />
+<h2><a name="arch">Which architectures does BusyBox run on?</a></h2>
+
+<p>
+ BusyBox in general will build on any architecture supported by gcc.
+ Kernel module loading for 2.4 Linux kernels is currently
+ limited to ARM, CRIS, H8/300, x86, ia64, x86_64, m68k, MIPS, PowerPC,
+ S390, SH3/4/5, Sparc, v850e, and x86_64 for 2.4.x kernels.
+</p>
+<p>
+ With 2.6.x kernels, module loading support should work on all architectures.
+</p>
+
+<hr />
+<h2><a name="libc">Which C libraries are supported?</a></h2>
+
+<p>
+ On Linux, BusyBox releases are tested against uClibc (0.9.27 or later) and
+ glibc (2.2 or later). Both should provide full functionality with busybox,
+ and if you find a bug we want to hear about it.
+</p>
+<p>
+ Linux-libc5 is no longer maintained (and has no known advantages over
+ uClibc), dietlibc is known to have numerous unfixed bugs, and klibc is
+ missing too many features to build BusyBox. If you require a small C
+ library for Linux, the busybox developers recommend uClibc.
+</p>
+<p>
+ Some BusyBox applets have been built and run under a combination
+ of newlib and libgloss (see
+ <a href="http://www.busybox.net/lists/busybox/2005-March/013759.html">this thread</a>).
+ This is still experimental, but may be supported in a future release.
+</p>
+
+<hr />
+<h2><a name="commercial">Can I include BusyBox as part of the software on my device?</a></h2>
+
+<p>
+ Yes. As long as you <a href="http://busybox.net/license.html">fully comply
+ with the generous terms of the GPL BusyBox license</a> you can ship BusyBox
+ as part of the software on your device.
+</p>
+
+<hr />
+<h2><a name="external">Where can I find other small utilities since busybox
+ does not include the features i want?</a></h2>
+
+<p>
+ we maintain such a <a href="tinyutils.html">list</a> on this site!
+</p>
+
+<hr />
+<h2><a name="demanding">I demand that you to add &lt;favorite feature&gt; right now! How come you don't answer all my questions on the mailing list instantly? I demand that you help me with all of my problems <em>Right Now</em>!</a></h2>
+
+<p>
+ You have not paid us a single cent and yet you still have the product of
+ many years of our work. We are not your slaves! We work on BusyBox
+ because we find it useful and interesting. If you go off flaming us, we
+ will ignore you.
+
+<hr />
+<h2><a name="helpme">I need help with BusyBox! What should I do?</a></h2>
+
+<p>
+ If you find that you need help with BusyBox, you can ask for help on the
+ BusyBox mailing list at busybox@busybox.net.</p>
+
+<p> In addition to the mailing list, Erik Andersen (andersee), Manuel Nova
+ (mjn3), Rob Landley (landley), Mike Frysinger (SpanKY), Bernhard Fischer
+ (blindvt), and other long-time BusyBox developers are known to hang out
+ on the uClibc IRC channel: #uclibc on irc.freenode.net. There is a
+ <a href="http://ibot.Rikers.org/%23uclibc/">web archive of
+ daily logs of the #uclibc IRC channel</a> going back to 2002.
+</p>
+
+<p>
+ <b>Please do not send private email to Rob, Erik, Manuel, or the other
+ BusyBox contributors asking for private help unless you are planning on
+ paying for consulting services.</b>
+</p>
+
+<p>
+ When we answer questions on the BusyBox mailing list, it helps everyone
+ since people with similar problems in the future will be able to get help
+ by searching the mailing list archives. Private help is reserved as a paid
+ service. If you need to use private communication, or if you are serious
+ about getting timely assistance with BusyBox, you should seriously consider
+ paying for consulting services.
+</p>
+
+<hr />
+<h2><a name="contracts">I need you to add &lt;favorite feature&gt;! Are the BusyBox developers willing to be paid in order to fix bugs or add in &lt;favorite feature&gt;? Are you willing to provide support contracts?</a></h2>
+
+<p>
+ Yes we are. The easy way to sponsor a new feature is to post an offer on
+ the mailing list to see who's interested. You can also email the project's
+ maintainer and ask them to recommend someone.
+</p>
+
+<p> If you prefer to deal with an organization rather than an individual, Rob
+ Landley (the current BusyBox maintainer) works for
+ <a http://www.timesys.com>TimeSys</a>, and Eric Andersen (the previous
+ busybox maintainer and current uClibc maintainer) owns
+ <a href="http://codepoet-consulting.com/">CodePoet Consulting</a>. Both
+ companies offer support contracts and handle new development, and there
+ are plenty of other companies that do the same.
+</p>
+
+
+<hr />
+<h1>Troubleshooting</h1>
+
+<hr />
+<h2><a name="bugs">I think I found a bug in BusyBox! What should I do?</a></h2>
+
+<p>
+ If you simply need help with using or configuring BusyBox, please submit a
+ detailed description of your problem to the BusyBox mailing list at <a
+ href="mailto:busybox@busybox.net"> busybox@busybox.net</a>.
+ Please do not send email to individual developers asking
+ for private help unless you are planning on paying for consulting services.
+ When we answer questions on the BusyBox mailing list, it helps everyone,
+ while private answers help only you...
+</p>
+
+<p>
+ Bug reports and new feature patches sometimes get lost when posted to the
+ mailing list, because the developers of BusyBox are busy people and have
+ only so much they can keep in their brains at a time. You can post a
+ polite reminder after 2-3 days without offending anybody. If that doesn't
+ result in a solution, please use the
+ <a href="http://bugs.busybox.net/">BusyBox Bug
+ and Patch Tracking System</a> to submit a detailed explanation and we'll
+ get to it as soon as we can.
+</p>
+
+<p>
+ Note that bugs entered into the bug system without being mentioned on the
+ mailing list first may languish there for months before anyone even notices
+ them. We generally go through the bug system when preparing for new
+ development releases, to see what fell through the cracks while we were
+ off writing new features. (It's a fast/unreliable vs slow/reliable thing.
+ Saves retransits, but the latency sucks.)
+</p>
+
+<hr />
+<h2><a name="backporting">I'm using an ancient version from the dawn of time and something's broken. Can you backport fixes for free?</h2>
+
+<p>Variants of this one get asked a lot.</p>
+
+<p>The purpose of the BusyBox mailing list is to develop and improve BusyBox,
+and we're happy to respond to our users' needs. But if you're coming to the
+list for free tech support we're going to ask you to upgrade to a current
+version before we try to diagnose your problem.</p>
+
+<p>If you're building BusyBox 0.50 with uClibc 0.9.19 and gcc 0.9.26 there's a
+fairly large chance that whatever problem you're seeing has already been fixed.
+To get that fix, all you have to do is upgrade to a newer version. If you
+don't at least _try_ that, you're wasting our time.</p>
+
+<p>The volunteers are happy to fix any bugs you point out in the current
+versions because doing so helps everybody and makes the project better. We
+want to make the current version work for you. But diagnosing, debugging, and
+backporting fixes to old versions isn't something we do for free, because it
+doesn't help anybody but you. The cost of volunteer tech support is using a
+reasonably current version of the project.</p>
+
+<p>If you don't want to upgrade, you have the complete source code and thus
+the ability to fix it yourself, or hire a consultant to do it for you. If you
+got your version from a vendor who still supports the older version, they can
+help you. But there are limits as to what the volunteers will feel obliged to
+do for you.</p>
+
+<p>As a rule of thumb, volunteers will generally answer polite questions about
+a given version for about three years after its release before it's so old
+we don't remember the answer off the top of our head. And if you want us to
+put any _effort_ into tracking it down, we want you to put in a little effort
+of your own by confirming it's still a problem with the current version. It's
+also hard for us to fix a problem of yours if we can't reproduce it because
+we don't have any systems running an environment that old.</p>
+
+<p>A consultant will happily set up a special environment just to reproduce
+your problem, and you can always ask on the list if any of the developers
+have consulting rates.</p>
+
+<hr />
+<h2><a name="init">Busybox init isn't working!</a></h2>
+
+<p>
+ Init is the first program that runs, so it might be that no programs are
+ working on your new system because of a problem with your cross-compiler,
+ kernel, console settings, shared libraries, root filesystem... To rule all
+ that out, first build a statically linked version of the following "hello
+ world" program with your cross compiler toolchain:
+</p>
+<pre>
+#include &lt;stdio.h&gt;
+
+int main(int argc, char *argv)
+{
+ printf("Hello world!\n");
+ sleep(999999999);
+}
+</pre>
+
+<p>
+ Now try to boot your device with an "init=" argument pointing to your
+ hello world program. Did you see the hello world message? Until you
+ do, don't bother messing with busybox init.
+</p>
+
+<p>
+ Once you've got it working statically linked, try getting it to work
+ dynamically linked. Then read the FAQ entry <a href="#build_system">How
+ do I build a BusyBox-based system?</a>, and the
+ <a href="/downloads/BusyBox.html#item_init">documentation for BusyBox
+ init</a>.
+</p>
+
+<hr />
+<h2><a name="sed">I can't configure busybox on my system.</a></h2>
+
+<p>
+ Configuring Busybox depends on a recent version of sed. Older
+ distributions (Red Hat 7.2, Debian 3.0) may not come with a
+ usable version. Luckily BusyBox can use its own sed to configure itself,
+ although this leads to a bit of a chicken and egg problem.
+ You can work around this by hand-configuring busybox to build with just
+ sed, then putting that sed in your path to configure the rest of busybox
+ with, like so:
+</p>
+
+<pre>
+ tar xvjf sources/busybox-x.x.x.tar.bz2
+ cd busybox-x.x.x
+ make allnoconfig
+ make include/bb_config.h
+ echo "CONFIG_SED=y" >> .config
+ echo "#undef ENABLE_SED" >> include/bb_config.h
+ echo "#define ENABLE_SED 1" >> include/bb_config.h
+ make
+ mv busybox sed
+ export PATH=`pwd`:"$PATH"
+</pre>
+
+<p>Then you can run "make defconfig" or "make menuconfig" normally.</p>
+
+<hr />
+<h2><a name="job_control">Why do I keep getting "sh: can't access tty; job control turned off" errors? Why doesn't Control-C work within my shell?</a></h2>
+
+<p>
+ Job control will be turned off since your shell can not obtain a controlling
+ terminal. This typically happens when you run your shell on /dev/console.
+ The kernel will not provide a controlling terminal on the /dev/console
+ device. Your should run your shell on a normal tty such as tty1 or ttyS0
+ and everything will work perfectly. If you <em>REALLY</em> want your shell
+ to run on /dev/console, then you can hack your kernel (if you are into that
+ sortof thing) by changing drivers/char/tty_io.c to change the lines where
+ it sets "noctty = 1;" to instead set it to "0". I recommend you instead
+ run your shell on a real console...
+</p>
+
+<hr />
+<h1>Misc. questions</h1>
+
+<hr />
+<h2><a name="tz">How do I change the time zone in busybox?</a></h2>
+
+<p>Busybox has nothing to do with the timezone. Please consult your libc
+documentation. (<a href='http://google.com/search?q=uclibc+glibc+timezone'>http://google.com/search?q=uclibc+glibc+timezone</a>).</p>
+
+<hr />
+<h1>Development</h1>
+
+<hr />
+<h2><a name="goals">What are the goals of busybox?</a></h2>
+
+<p>Busybox aims to be the smallest and simplest correct implementation of the
+standard Linux command line tools. First and foremost, this means the
+smallest executable size we can manage. We also want to have the simplest
+and cleanest implementation we can manage, be <a href="#standards">standards
+compliant</a>, minimize run-time memory usage (heap and stack), run fast, and
+take over the world.</p>
+
+<hr />
+<h2><a name="design">What is the design of busybox?</a></h2>
+
+<p>Busybox is like a swiss army knife: one thing with many functions.
+The busybox executable can act like many different programs depending on
+the name used to invoke it. Normal practice is to create a bunch of symlinks
+pointing to the busybox binary, each of which triggers a different busybox
+function. (See <a href="FAQ.html#getting_started">getting started</a> in the
+FAQ for more information on usage, and <a href="BusyBox.html">the
+busybox documentation</a> for a list of symlink names and what they do.)
+
+<p>The "one binary to rule them all" approach is primarily for size reasons: a
+single multi-purpose executable is smaller then many small files could be.
+This way busybox only has one set of ELF headers, it can easily share code
+between different apps even when statically linked, it has better packing
+efficiency by avoding gaps between files or compression dictionary resets,
+and so on.</p>
+
+<p>Work is underway on new options such as "make standalone" to build separate
+binaries for each applet, and a "libbb.so" to make the busybox common code
+available as a shared library. Neither is ready yet at the time of this
+writing.</p>
+
+<a name="source"></a>
+
+<hr />
+<h2><a name="source_applets">The applet directories</a></h2>
+
+<p>The directory "applets" contains the busybox startup code (applets.c and
+busybox.c), and several subdirectories containing the code for the individual
+applets.</p>
+
+<p>Busybox execution starts with the main() function in applets/busybox.c,
+which sets the global variable applet_name to argv[0] and calls
+run_applet_and_exit() in applets/applets.c. That uses the applets[] array
+(defined in include/busybox.h and filled out in include/applets.h) to
+transfer control to the appropriate APPLET_main() function (such as
+cat_main() or sed_main()). The individual applet takes it from there.</p>
+
+<p>This is why calling busybox under a different name triggers different
+functionality: main() looks up argv[0] in applets[] to get a function pointer
+to APPLET_main().</p>
+
+<p>Busybox applets may also be invoked through the multiplexor applet
+"busybox" (see busybox_main() in libbb/appletlib.c), and through the
+standalone shell (grep for STANDALONE_SHELL in applets/shell/*.c).
+See <a href="FAQ.html#getting_started">getting started</a> in the
+FAQ for more information on these alternate usage mechanisms, which are
+just different ways to reach the relevant APPLET_main() function.</p>
+
+<p>The applet subdirectories (archival, console-tools, coreutils,
+debianutils, e2fsprogs, editors, findutils, init, loginutils, miscutils,
+modutils, networking, procps, shell, sysklogd, and util-linux) correspond
+to the configuration sub-menus in menuconfig. Each subdirectory contains the
+code to implement the applets in that sub-menu, as well as a Config.in
+file defining that configuration sub-menu (with dependencies and help text
+for each applet), and the makefile segment (Makefile.in) for that
+subdirectory.</p>
+
+<p>The run-time --help is stored in usage_messages[], which is initialized at
+the start of applets/applets.c and gets its help text from usage.h. During the
+build this help text is also used to generate the BusyBox documentation (in
+html, txt, and man page formats) in the docs directory. See
+<a href="#adding">adding an applet to busybox</a> for more
+information.</p>
+
+<hr />
+<h2><a name="source_libbb"><b>libbb</b></a></h2>
+
+<p>Most non-setup code shared between busybox applets lives in the libbb
+directory. It's a mess that evolved over the years without much auditing
+or cleanup. For anybody looking for a great project to break into busybox
+development with, documenting libbb would be both incredibly useful and good
+experience.</p>
+
+<p>Common themes in libbb include allocation functions that test
+for failure and abort the program with an error message so the caller doesn't
+have to test the return value (xmalloc(), xstrdup(), etc), wrapped versions
+of open(), close(), read(), and write() that test for their own failures
+and/or retry automatically, linked list management functions (llist.c),
+command line argument parsing (getopt32.c), and a whole lot more.</p>
+
+<hr />
+<h2><a name="optimize">I want to make busybox even smaller, how do I go about it?</a></h2>
+
+<p>
+ To conserve bytes it's good to know where they're being used, and the
+ size of the final executable isn't always a reliable indicator of
+ the size of the components (since various structures are rounded up,
+ so a small change may not even be visible by itself, but many small
+ savings add up).
+</p>
+
+<p> The busybox Makefile builds two versions of busybox, one of which
+ (busybox_unstripped) has extra information that various analysis tools
+ can use. (This has nothing to do with CONFIG_DEBUG, leave that off
+ when trying to optimize for size.)
+</p>
+
+<p> The <b>"make bloatcheck"</b> option uses Matt Mackall's bloat-o-meter
+ script to compare two versions of busybox (busybox_unstripped vs
+ busybox_old), and report which symbols changed size and by how much.
+ To use it, first build a base version with <b>"make baseline"</b>.
+ (This creates busybox_old, which should have the original sizes for
+ comparison purposes.) Then build the new version with your changes
+ and run "make bloatcheck" to see the size differences from the old
+ version.
+</p>
+<p>
+ The first line of output has totals: how many symbols were added or
+ removed, how many symbols grew or shrank, the number of bytes added
+ and number of bytes removed by these changes, and finally the total
+ number of bytes difference between the two files. The remaining
+ lines show each individual symbol, the old and new sizes, and the
+ increase or decrease in size (which results are sorted by).
+</p>
+<p>
+ The <b>"make sizes"</b> option produces raw symbol size information for
+ busybox_unstripped. This is the output from the "nm --size-sort"
+ command (see "man nm" for more information), and is the information
+ bloat-o-meter parses to produce the comparison report above. For
+ defconfig, this is a good way to find the largest symbols in the tree
+ (which is a good place to start when trying to shrink the code). To
+ take a closer look at individual applets, configure busybox with just
+ one applet (run "make allnoconfig" and then switch on a single applet
+ with menuconfig), and then use "make sizes" to see the size of that
+ applet's components.
+</p>
+<p>
+ The "showasm" command (in the scripts directory) produces an assembly
+ dump of a function, providing a closer look at what changed. Try
+ "scripts/showasm busybox_unstripped" to list available symbols, and
+ "scripts/showasm busybox_unstripped symbolname" to see the assembly
+ for a sepecific symbol.
+</p>
+
+<hr />
+<h2><a name="adding">Adding an applet to busybox</a></h2>
+
+<p>To add a new applet to busybox, first pick a name for the applet and
+a corresponding CONFIG_NAME. Then do this:</p>
+
+<ul>
+<li>Figure out where in the busybox source tree your applet best fits,
+and put your source code there. Be sure to use APPLET_main() instead
+of main(), where APPLET is the name of your applet.</li>
+
+<li>Add your applet to the relevant Config.in file (which file you add
+it to determines where it shows up in "make menuconfig"). This uses
+the same general format as the linux kernel's configuration system.</li>
+
+<li>Add your applet to the relevant Makefile.in file (in the same
+directory as the Config.in you chose), using the existing entries as a
+template and the same CONFIG symbol as you used for Config.in. (Don't
+forget "needlibm" or "needcrypt" if your applet needs libm or
+libcrypt.)</li>
+
+<li>Add your applet to "include/applets.h", using one of the existing
+entries as a template. (Note: this is in alphabetical order. Applets
+are found via binary search, and if you add an applet out of order it
+won't work.)</li>
+
+<li>Add your applet's runtime help text to "include/usage.h". You need
+at least appname_trivial_usage (the minimal help text, always included
+in the busybox binary when this applet is enabled) and appname_full_usage
+(extra help text included in the busybox binary with
+CONFIG_FEATURE_VERBOSE_USAGE is enabled), or it won't compile.
+The other two help entry types (appname_example_usage and
+appname_notes_usage) are optional. They don't take up space in the binary,
+but instead show up in the generated documentation (BusyBox.html,
+BusyBox.txt, and the man page BusyBox.1).</li>
+
+<li>Run menuconfig, switch your applet on, compile, test, and fix the
+bugs. Be sure to try both "allyesconfig" and "allnoconfig" (and
+"allbareconfig" if relevant).</li>
+
+</ul>
+
+<hr />
+<h2><a name="standards">What standards does busybox adhere to?</a></h2>
+
+<p>The standard we're paying attention to is the "Shell and Utilities"
+portion of the <a href="http://www.opengroup.org/onlinepubs/009695399/">Open
+Group Base Standards</a> (also known as the Single Unix Specification version
+3 or SUSv3). Note that paying attention isn't necessarily the same thing as
+following it.</p>
+
+<p>SUSv3 doesn't even mention things like init, mount, tar, or losetup, nor
+commonly used options like echo's '-e' and '-n', or sed's '-i'. Busybox is
+driven by what real users actually need, not the fact the standard believes
+we should implement ed or sccs. For size reasons, we're unlikely to include
+much internationalization support beyond UTF-8, and on top of all that, our
+configuration menu lets developers chop out features to produce smaller but
+very non-standard utilities.</p>
+
+<p>Also, Busybox is aimed primarily at Linux. Unix standards are interesting
+because Linux tries to adhere to them, but portability to dozens of platforms
+is only interesting in terms of offering a restricted feature set that works
+everywhere, not growing dozens of platform-specific extensions. Busybox
+should be portable to all hardware platforms Linux supports, and any other
+similar operating systems that are easy to do and won't require much
+maintenance.</p>
+
+<p>In practice, standards compliance tends to be a clean-up step once an
+applet is otherwise finished. When polishing and testing a busybox applet,
+we ensure we have at least the option of full standards compliance, or else
+document where we (intentionally) fall short.</p>
+
+<hr />
+<h2><a name="portability">Portability.</a></h2>
+
+<p>Busybox is a Linux project, but that doesn't mean we don't have to worry
+about portability. First of all, there are different hardware platforms,
+different C library implementations, different versions of the kernel and
+build toolchain... The file "include/platform.h" exists to centralize and
+encapsulate various platform-specific things in one place, so most busybox
+code doesn't have to care where it's running.</p>
+
+<p>To start with, Linux runs on dozens of hardware platforms. We try to test
+each release on x86, x86-64, arm, power pc, and mips. (Since qemu can handle
+all of these, this isn't that hard.) This means we have to care about a number
+of portability issues like endianness, word size, and alignment, all of which
+belong in platform.h. That header handles conditional #includes and gives
+us macros we can use in the rest of our code. At some point in the future
+we might grow a platform.c, possibly even a platform subdirectory. As long
+as the applets themselves don't have to care.</p>
+
+<p>On a related note, we made the "default signedness of char varies" problem
+go away by feeding the compiler -funsigned-char. This gives us consistent
+behavior on all platforms, and defaults to 8-bit clean text processing (which
+gets us halfway to UTF-8 support). NOMMU support is less easily separated
+(see the tips section later in this document), but we're working on it.</p>
+
+<p>Another type of portability is build environments: we unapologetically use
+a number of gcc and glibc extensions (as does the Linux kernel), but these have
+been picked up by packages like uClibc, TCC, and Intel's C Compiler. As for
+gcc, we take advantage of newer compiler optimizations to get the smallest
+possible size, but we also regression test against an older build environment
+using the Red Hat 9 image at "http://busybox.net/downloads/qemu". This has a
+2.4 kernel, gcc 3.2, make 3.79.1, and glibc 2.3, and is the oldest
+build/deployment environment we still put any effort into maintaining. (If
+anyone takes an interest in older kernels you're welcome to submit patches,
+but the effort would probably be better spent
+<a href="http://www.selenic.com/linux-tiny/">trimming
+down the 2.6 kernel</a>.) Older gcc versions than that are uninteresting since
+we now use c99 features, although
+<a href="http://fabrice.bellard.free.fr/tcc/">tcc</a> might be worth a
+look.</p>
+
+<p>We also test busybox against the current release of uClibc. Older versions
+of uClibc aren't very interesting (they were buggy, and uClibc wasn't really
+usable as a general-purpose C library before version 0.9.26 anyway).</p>
+
+<p>Other unix implementations are mostly uninteresting, since Linux binaries
+have become the new standard for portable Unix programs. Specifically,
+the ubiquity of Linux was cited as the main reason the Intel Binary
+Compatability Standard 2 died, by the standards group organized to name a
+successor to ibcs2: <a href="http://www.telly.org/86open/">the 86open
+project</a>. That project disbanded in 1999 with the endorsement of an
+existing standard: Linux ELF binaries. Since then, the major players at the
+time (such as <a
+href=http://www-03.ibm.com/servers/aix/products/aixos/linux/index.html>AIX</a>, <a
+href=http://www.sun.com/software/solaris/ds/linux_interop.jsp#3>Solaris</a>, and
+<a href=http://www.onlamp.com/pub/a/bsd/2000/03/17/linuxapps.html>FreeBSD</a>)
+have all either grown Linux support or folded.</p>
+
+<p>The major exceptions are newcomer MacOS X, some embedded environments
+(such as newlib+libgloss) which provide a posix environment but not a full
+Linux environment, and environments like Cygwin that provide only partial Linux
+emulation. Also, some embedded Linux systems run a Linux kernel but amputate
+things like the /proc directory to save space.</p>
+
+<p>Supporting these systems is largely a question of providing a clean subset
+of BusyBox's functionality -- whichever applets can easily be made to
+work in that environment. Annotating the configuration system to
+indicate which applets require which prerequisites (such as procfs) is
+also welcome. Other efforts to support these systems (swapping #include
+files to build in different environments, adding adapter code to platform.h,
+adding more extensive special-case supporting infrastructure such as mount's
+legacy mtab support) are handled on a case-by-case basis. Support that can be
+cleanly hidden in platform.h is reasonably attractive, and failing that
+support that can be cleanly separated into a separate conditionally compiled
+file is at least worth a look. Special-case code in the body of an applet is
+something we're trying to avoid.</p>
+
+<hr />
+<h2><a name="tips" />Programming tips and tricks.</a></h2>
+
+<p>Various things busybox uses that aren't particularly well documented
+elsewhere.</p>
+
+<hr />
+<h2><a name="tips_encrypted_passwords">Encrypted Passwords</a></h2>
+
+<p>Password fields in /etc/passwd and /etc/shadow are in a special format.
+If the first character isn't '$', then it's an old DES style password. If
+the first character is '$' then the password is actually three fields
+separated by '$' characters:</p>
+<pre>
+ <b>$type$salt$encrypted_password</b>
+</pre>
+
+<p>The "type" indicates which encryption algorithm to use: 1 for MD5 and 2 for SHA1.</p>
+
+<p>The "salt" is a bunch of ramdom characters (generally 8) the encryption
+algorithm uses to perturb the password in a known and reproducible way (such
+as by appending the random data to the unencrypted password, or combining
+them with exclusive or). Salt is randomly generated when setting a password,
+and then the same salt value is re-used when checking the password. (Salt is
+thus stored unencrypted.)</p>
+
+<p>The advantage of using salt is that the same cleartext password encrypted
+with a different salt value produces a different encrypted value.
+If each encrypted password uses a different salt value, an attacker is forced
+to do the cryptographic math all over again for each password they want to
+check. Without salt, they could simply produce a big dictionary of commonly
+used passwords ahead of time, and look up each password in a stolen password
+file to see if it's a known value. (Even if there are billions of possible
+passwords in the dictionary, checking each one is just a binary search against
+a file only a few gigabytes long.) With salt they can't even tell if two
+different users share the same password without guessing what that password
+is and decrypting it. They also can't precompute the attack dictionary for
+a specific password until they know what the salt value is.</p>
+
+<p>The third field is the encrypted password (plus the salt). For md5 this
+is 22 bytes.</p>
+
+<p>The busybox function to handle all this is pw_encrypt(clear, salt) in
+"libbb/pw_encrypt.c". The first argument is the clear text password to be
+encrypted, and the second is a string in "$type$salt$password" format, from
+which the "type" and "salt" fields will be extracted to produce an encrypted
+value. (Only the first two fields are needed, the third $ is equivalent to
+the end of the string.) The return value is an encrypted password in
+/etc/passwd format, with all three $ separated fields. It's stored in
+a static buffer, 128 bytes long.</p>
+
+<p>So when checking an existing password, if pw_encrypt(text,
+old_encrypted_password) returns a string that compares identical to
+old_encrypted_password, you've got the right password. When setting a new
+password, generate a random 8 character salt string, put it in the right
+format with sprintf(buffer, "$%c$%s", type, salt), and feed buffer as the
+second argument to pw_encrypt(text,buffer).</p>
+
+<hr />
+<h2><a name="tips_vfork">Fork and vfork</a></h2>
+
+<p>On systems that haven't got a Memory Management Unit, fork() is unreasonably
+expensive to implement (and sometimes even impossible), so a less capable
+function called vfork() is used instead. (Using vfork() on a system with an
+MMU is like pounding a nail with a wrench. Not the best tool for the job, but
+it works.)</p>
+
+<p>Busybox hides the difference between fork() and vfork() in
+libbb/bb_fork_exec.c. If you ever want to fork and exec, use bb_fork_exec()
+(which returns a pid and takes the same arguments as execve(), although in
+this case envp can be NULL) and don't worry about it. This description is
+here in case you want to know why that does what it does.</p>
+
+<p>Implementing fork() depends on having a Memory Management Unit. With an
+MMU then you can simply set up a second set of page tables and share the
+physical memory via copy-on-write. So a fork() followed quickly by exec()
+only copies a few pages of the parent's memory, just the ones it changes
+before freeing them.</p>
+
+<p>With a very primitive MMU (using a base pointer plus length instead of page
+tables, which can provide virtual addresses and protect processes from each
+other, but no copy on write) you can still implement fork. But it's
+unreasonably expensive, because you have to copy all the parent process'
+memory into the new process (which could easily be several megabytes per fork).
+And you have to do this even though that memory gets freed again as soon as the
+exec happens. (This is not just slow and a waste of space but causes memory
+usage spikes that can easily cause the system to run out of memory.)</p>
+
+<p>Without even a primitive MMU, you have no virtual addresses. Every process
+can reach out and touch any other process' memory, because all pointers are to
+physical addresses with no protection. Even if you copy a process' memory to
+new physical addresses, all of its pointers point to the old objects in the
+old process. (Searching through the new copy's memory for pointers and
+redirect them to the new locations is not an easy problem.)</p>
+
+<p>So with a primitive or missing MMU, fork() is just not a good idea.</p>
+
+<p>In theory, vfork() is just a fork() that writeably shares the heap and stack
+rather than copying it (so what one process writes the other one sees). In
+practice, vfork() has to suspend the parent process until the child does exec,
+at which point the parent wakes up and resumes by returning from the call to
+vfork(). All modern kernel/libc combinations implement vfork() to put the
+parent to sleep until the child does its exec. There's just no other way to
+make it work: the parent has to know the child has done its exec() or exit()
+before it's safe to return from the function it's in, so it has to block
+until that happens. In fact without suspending the parent there's no way to
+even store separate copies of the return value (the pid) from the vfork() call
+itself: both assignments write into the same memory location.</p>
+
+<p>One way to understand (and in fact implement) vfork() is this: imagine
+the parent does a setjmp and then continues on (pretending to be the child)
+until the exec() comes around, then the _exec_ does the actual fork, and the
+parent does a longjmp back to the original vfork call and continues on from
+there. (It thus becomes obvious why the child can't return, or modify
+local variables it doesn't want the parent to see changed when it resumes.)
+
+<p>Note a common mistake: the need for vfork doesn't mean you can't have two
+processes running at the same time. It means you can't have two processes
+sharing the same memory without stomping all over each other. As soon as
+the child calls exec(), the parent resumes.</p>
+
+<p>If the child's attempt to call exec() fails, the child should call _exit()
+rather than a normal exit(). This avoids any atexit() code that might confuse
+the parent. (The parent should never call _exit(), only a vforked child that
+failed to exec.)</p>
+
+<p>(Now in theory, a nommu system could just copy the _stack_ when it forks
+(which presumably is much shorter than the heap), and leave the heap shared.
+Even with no MMU at all
+In practice, you've just wound up in a multi-threaded situation and you can't
+do a malloc() or free() on your heap without freeing the other process' memory
+(and if you don't have the proper locking for being threaded, corrupting the
+heap if both of you try to do it at the same time and wind up stomping on
+each other while traversing the free memory lists). The thing about vfork is
+that it's a big red flag warning "there be dragons here" rather than
+something subtle and thus even more dangerous.)</p>
+
+<hr />
+<h2><a name="tips_sort_read">Short reads and writes</a></h2>
+
+<p>Busybox has special functions, bb_full_read() and bb_full_write(), to
+check that all the data we asked for got read or written. Is this a real
+world consideration? Try the following:</p>
+
+<pre>while true; do echo hello; sleep 1; done | tee out.txt</pre>
+
+<p>If tee is implemented with bb_full_read(), tee doesn't display output
+in real time but blocks until its entire input buffer (generally a couple
+kilobytes) is read, then displays it all at once. In that case, we _want_
+the short read, for user interface reasons. (Note that read() should never
+return 0 unless it has hit the end of input, and an attempt to write 0
+bytes should be ignored by the OS.)</p>
+
+<p>As for short writes, play around with two processes piping data to each
+other on the command line (cat bigfile | gzip &gt; out.gz) and suspend and
+resume a few times (ctrl-z to suspend, "fg" to resume). The writer can
+experience short writes, which are especially dangerous because if you don't
+notice them you'll discard data. They can also happen when a system is under
+load and a fast process is piping to a slower one. (Such as an xterm waiting
+on x11 when the scheduler decides X is being a CPU hog with all that
+text console scrolling...)</p>
+
+<p>So will data always be read from the far end of a pipe at the
+same chunk sizes it was written in? Nope. Don't rely on that. For one
+counterexample, see <a href="http://www.faqs.org/rfcs/rfc896.html">rfc 896
+for Nagle's algorithm</a>, which waits a fraction of a second or so before
+sending out small amounts of data through a TCP/IP connection in case more
+data comes in that can be merged into the same packet. (In case you were
+wondering why action games that use TCP/IP set TCP_NODELAY to lower the latency
+on their their sockets, now you know.)</p>
+
+<hr />
+<h2><a name="tips_memory">Memory used by relocatable code, PIC, and static linking.</a></h2>
+
+<p>The downside of standard dynamic linking is that it results in self-modifying
+code. Although each executable's pages are mmaped() into a process' address
+space from the executable file and are thus naturally shared between processes
+out of the page cache, the library loader (ld-linux.so.2 or ld-uClibc.so.0)
+writes to these pages to supply addresses for relocatable symbols. This
+dirties the pages, triggering copy-on-write allocation of new memory for each
+processes' dirtied pages.</p>
+
+<p>One solution to this is Position Independent Code (PIC), a way of linking
+a file so all the relocations are grouped together. This dirties fewer
+pages (often just a single page) for each process' relocations. The down
+side is this results in larger executables, which take up more space on disk
+(and a correspondingly larger space in memory). But when many copies of the
+same program are running, PIC dynamic linking trades a larger disk footprint
+for a smaller memory footprint, by sharing more pages.</p>
+
+<p>A third solution is static linking. A statically linked program has no
+relocations, and thus the entire executable is shared between all running
+instances. This tends to have a significantly larger disk footprint, but
+on a system with only one or two executables, shared libraries aren't much
+of a win anyway.</p>
+
+<p>You can tell the glibc linker to display debugging information about its
+relocations with the environment variable "LD_DEBUG". Try
+"LD_DEBUG=help /bin/true" for a list of commands. Learning to interpret
+"LD_DEBUG=statistics cat /proc/self/statm" could be interesting.</p>
+
+<p>For more on this topic, here's Rich Felker:</p>
+<blockquote>
+<p>Dynamic linking (without fixed load addresses) fundamentally requires
+at least one dirty page per dso that uses symbols. Making calls (but
+never taking the address explicitly) to functions within the same dso
+does not require a dirty page by itself, but will with ELF unless you
+use -Bsymbolic or hidden symbols when linking.</p>
+
+<p>ELF uses significant additional stack space for the kernel to pass all
+the ELF data structures to the newly created process image. These are
+located above the argument list and environment. This normally adds 1
+dirty page to the process size.</p>
+
+<p>The ELF dynamic linker has its own data segment, adding one or more
+dirty pages. I believe it also performs relocations on itself.</p>
+
+<p>The ELF dynamic linker makes significant dynamic allocations to manage
+the global symbol table and the loaded dso's. This data is never
+freed. It will be needed again if libdl is used, so unconditionally
+freeing it is not possible, but normal programs do not use libdl. Of
+course with glibc all programs use libdl (due to nsswitch) so the
+issue was never addressed.</p>
+
+<p>ELF also has the issue that segments are not page-aligned on disk.
+This saves up to 4k on disk, but at the expense of using an additional
+dirty page in most cases, due to a large portion of the first data
+page being filled with a duplicate copy of the last text page.</p>
+
+<p>The above is just a partial list of the tiny memory penalties of ELF
+dynamic linking, which eventually add up to quite a bit. The smallest
+I've been able to get a process down to is 8 dirty pages, and the
+above factors seem to mostly account for it (but some were difficult
+to measure).</p>
+</blockquote>
+
+<hr />
+<h2><a name="tips_kernel_headers"></a>Including kernel headers</h2>
+
+<p>The "linux" or "asm" directories of /usr/include contain Linux kernel
+headers, so that the C library can talk directly to the Linux kernel. In
+a perfect world, applications shouldn't include these headers directly, but
+we don't live in a perfect world.</p>
+
+<p>For example, Busybox's losetup code wants linux/loop.c because nothing else
+#defines the structures to call the kernel's loopback device setup ioctls.
+Attempts to cut and paste the information into a local busybox header file
+proved incredibly painful, because portions of the loop_info structure vary by
+architecture, namely the type __kernel_dev_t has different sizes on alpha,
+arm, x86, and so on. Meaning we either #include <linux/posix_types.h> or
+we hardwire #ifdefs to check what platform we're building on and define this
+type appropriately for every single hardware architecture supported by
+Linux, which is simply unworkable.</p>
+
+<p>This is aside from the fact that the relevant type defined in
+posix_types.h was renamed to __kernel_old_dev_t during the 2.5 series, so
+to cut and paste the structure into our header we have to #include
+<linux/version.h> to figure out which name to use. (What we actually do is
+check if we're building on 2.6, and if so just use the new 64 bit structure
+instead to avoid the rename entirely.) But we still need the version
+check, since 2.4 didn't have the 64 bit structure.</p>
+
+<p>The BusyBox developers spent <u>two years</u> trying to figure
+out a clean way to do all this. There isn't one. The losetup in the
+util-linux package from kernel.org isn't doing it cleanly either, they just
+hide the ugliness by nesting #include files. Their mount/loop.h
+#includes "my_dev_t.h", which #includes <linux/posix_types.h> and
+<linux/version.h> just like we do. There simply is no alternative.</p>
+
+<p>Just because directly #including kernel headers is sometimes
+unavoidable doesn't me we should include them when there's a better
+way to do it. However, block copying information out of the kernel headers
+is not a better way.</p>
+
+<hr />
+<h2><a name="who">Who are the BusyBox developers?</a></h2>
+
+<p>The following login accounts currently exist on busybox.net. (I.E. these
+people can commit <a href="http://busybox.net/downloads/patches">patches</a>
+into subversion for the BusyBox, uClibc, and buildroot projects.)</p>
+
+<pre>
+aldot :Bernhard Fischer
+andersen :Erik Andersen - uClibc and BuildRoot maintainer.
+bug1 :Glenn McGrath
+davidm :David McCullough
+gkajmowi :Garrett Kajmowicz - uClibc++ maintainer
+jbglaw :Jan-Benedict Glaw
+jocke :Joakim Tjernlund
+landley :Rob Landley - BusyBox maintainer
+lethal :Paul Mundt
+mjn3 :Manuel Novoa III
+osuadmin :osuadmin
+pgf :Paul Fox
+pkj :Peter Kjellerstedt
+prpplague :David Anders
+psm :Peter S. Mazinger
+russ :Russ Dill
+sandman :Robert Griebl
+sjhill :Steven J. Hill
+solar :Ned Ludd
+timr :Tim Riker
+tobiasa :Tobias Anderberg
+vapier :Mike Frysinger
+</pre>
+
+<p>The following accounts used to exist on busybox.net, but don't anymore so
+I can't ask /etc/passwd for their names. Rob Wentworth <robwen@gmail.com>
+asked Google and recovered the names:</p>
+
+<pre>
+aaronl :Aaron Lehmann
+beppu :John Beppu
+dwhedon :David Whedon
+erik :Erik Andersen
+gfeldman :Gennady Feldman
+jimg :Jim Gleason
+kraai :Matt Kraai
+markw :Mark Whitley
+miles :Miles Bader
+proski :Pavel Roskin
+rjune :Richard June
+tausq :Randolph Chung
+vodz :Vladimir N. Oleynik
+</pre>
+
+
+<br>
+<br>
+<br>
+
+<!--#include file="footer.html" -->
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/about.html b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/about.html
new file mode 100644
index 0000000000..7b79afce9f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/about.html
@@ -0,0 +1,24 @@
+<!--#include file="header.html" -->
+
+<h3>BusyBox: The Swiss Army Knife of Embedded Linux</h3>
+
+<p>BusyBox combines tiny versions of many common UNIX utilities into a single
+small executable. It provides replacements for most of the utilities you
+usually find in GNU fileutils, shellutils, etc. The utilities in BusyBox
+generally have fewer options than their full-featured GNU cousins; however,
+the options that are included provide the expected functionality and behave
+very much like their GNU counterparts. BusyBox provides a fairly complete
+environment for any small or embedded system.</p>
+
+<p>BusyBox has been written with size-optimization and limited resources in
+mind. It is also extremely modular so you can easily include or exclude
+commands (or features) at compile time. This makes it easy to customize
+your embedded systems. To create a working system, just add some device
+nodes in /dev, a few configuration files in /etc, and a Linux kernel.</p>
+
+<p>BusyBox is maintained by
+<a href="mailto:vda.linux@googlemail.com">Denys Vlasenko</a>,
+and licensed under the <a href="/license.html">GNU GENERAL PUBLIC LICENSE</a>
+version 2.</p>
+
+<!--#include file="footer.html" -->
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/busybox-growth.ps b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/busybox-growth.ps
new file mode 100644
index 0000000000..2379defa43
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/busybox-growth.ps
@@ -0,0 +1,404 @@
+%!PS-Adobe-2.0
+%%Title: busybox-growth.ps
+%%Creator: gnuplot 3.5 (pre 3.6) patchlevel beta 347
+%%CreationDate: Tue Apr 10 14:03:36 2001
+%%DocumentFonts: (atend)
+%%BoundingBox: 50 40 554 770
+%%Orientation: Landscape
+%%Pages: (atend)
+%%EndComments
+/gnudict 120 dict def
+gnudict begin
+/Color true def
+/Solid true def
+/gnulinewidth 5.000 def
+/userlinewidth gnulinewidth def
+/vshift -46 def
+/dl {10 mul} def
+/hpt_ 31.5 def
+/vpt_ 31.5 def
+/hpt hpt_ def
+/vpt vpt_ def
+/M {moveto} bind def
+/L {lineto} bind def
+/R {rmoveto} bind def
+/V {rlineto} bind def
+/vpt2 vpt 2 mul def
+/hpt2 hpt 2 mul def
+/Lshow { currentpoint stroke M
+ 0 vshift R show } def
+/Rshow { currentpoint stroke M
+ dup stringwidth pop neg vshift R show } def
+/Cshow { currentpoint stroke M
+ dup stringwidth pop -2 div vshift R show } def
+/UP { dup vpt_ mul /vpt exch def hpt_ mul /hpt exch def
+ /hpt2 hpt 2 mul def /vpt2 vpt 2 mul def } def
+/DL { Color {setrgbcolor Solid {pop []} if 0 setdash }
+ {pop pop pop Solid {pop []} if 0 setdash} ifelse } def
+/BL { stroke gnulinewidth 2 mul setlinewidth } def
+/AL { stroke gnulinewidth 2 div setlinewidth } def
+/UL { gnulinewidth mul /userlinewidth exch def } def
+/PL { stroke userlinewidth setlinewidth } def
+/LTb { BL [] 0 0 0 DL } def
+/LTa { AL [1 dl 2 dl] 0 setdash 0 0 0 setrgbcolor } def
+/LT0 { PL [] 1 0 0 DL } def
+/LT1 { PL [4 dl 2 dl] 0 1 0 DL } def
+/LT2 { PL [2 dl 3 dl] 0 0 1 DL } def
+/LT3 { PL [1 dl 1.5 dl] 1 0 1 DL } def
+/LT4 { PL [5 dl 2 dl 1 dl 2 dl] 0 1 1 DL } def
+/LT5 { PL [4 dl 3 dl 1 dl 3 dl] 1 1 0 DL } def
+/LT6 { PL [2 dl 2 dl 2 dl 4 dl] 0 0 0 DL } def
+/LT7 { PL [2 dl 2 dl 2 dl 2 dl 2 dl 4 dl] 1 0.3 0 DL } def
+/LT8 { PL [2 dl 2 dl 2 dl 2 dl 2 dl 2 dl 2 dl 4 dl] 0.5 0.5 0.5 DL } def
+/Pnt { stroke [] 0 setdash
+ gsave 1 setlinecap M 0 0 V stroke grestore } def
+/Dia { stroke [] 0 setdash 2 copy vpt add M
+ hpt neg vpt neg V hpt vpt neg V
+ hpt vpt V hpt neg vpt V closepath stroke
+ Pnt } def
+/Pls { stroke [] 0 setdash vpt sub M 0 vpt2 V
+ currentpoint stroke M
+ hpt neg vpt neg R hpt2 0 V stroke
+ } def
+/Box { stroke [] 0 setdash 2 copy exch hpt sub exch vpt add M
+ 0 vpt2 neg V hpt2 0 V 0 vpt2 V
+ hpt2 neg 0 V closepath stroke
+ Pnt } def
+/Crs { stroke [] 0 setdash exch hpt sub exch vpt add M
+ hpt2 vpt2 neg V currentpoint stroke M
+ hpt2 neg 0 R hpt2 vpt2 V stroke } def
+/TriU { stroke [] 0 setdash 2 copy vpt 1.12 mul add M
+ hpt neg vpt -1.62 mul V
+ hpt 2 mul 0 V
+ hpt neg vpt 1.62 mul V closepath stroke
+ Pnt } def
+/Star { 2 copy Pls Crs } def
+/BoxF { stroke [] 0 setdash exch hpt sub exch vpt add M
+ 0 vpt2 neg V hpt2 0 V 0 vpt2 V
+ hpt2 neg 0 V closepath fill } def
+/TriUF { stroke [] 0 setdash vpt 1.12 mul add M
+ hpt neg vpt -1.62 mul V
+ hpt 2 mul 0 V
+ hpt neg vpt 1.62 mul V closepath fill } def
+/TriD { stroke [] 0 setdash 2 copy vpt 1.12 mul sub M
+ hpt neg vpt 1.62 mul V
+ hpt 2 mul 0 V
+ hpt neg vpt -1.62 mul V closepath stroke
+ Pnt } def
+/TriDF { stroke [] 0 setdash vpt 1.12 mul sub M
+ hpt neg vpt 1.62 mul V
+ hpt 2 mul 0 V
+ hpt neg vpt -1.62 mul V closepath fill} def
+/DiaF { stroke [] 0 setdash vpt add M
+ hpt neg vpt neg V hpt vpt neg V
+ hpt vpt V hpt neg vpt V closepath fill } def
+/Pent { stroke [] 0 setdash 2 copy gsave
+ translate 0 hpt M 4 {72 rotate 0 hpt L} repeat
+ closepath stroke grestore Pnt } def
+/PentF { stroke [] 0 setdash gsave
+ translate 0 hpt M 4 {72 rotate 0 hpt L} repeat
+ closepath fill grestore } def
+/Circle { stroke [] 0 setdash 2 copy
+ hpt 0 360 arc stroke Pnt } def
+/CircleF { stroke [] 0 setdash hpt 0 360 arc fill } def
+/C0 { BL [] 0 setdash 2 copy moveto vpt 90 450 arc } bind def
+/C1 { BL [] 0 setdash 2 copy moveto
+ 2 copy vpt 0 90 arc closepath fill
+ vpt 0 360 arc closepath } bind def
+/C2 { BL [] 0 setdash 2 copy moveto
+ 2 copy vpt 90 180 arc closepath fill
+ vpt 0 360 arc closepath } bind def
+/C3 { BL [] 0 setdash 2 copy moveto
+ 2 copy vpt 0 180 arc closepath fill
+ vpt 0 360 arc closepath } bind def
+/C4 { BL [] 0 setdash 2 copy moveto
+ 2 copy vpt 180 270 arc closepath fill
+ vpt 0 360 arc closepath } bind def
+/C5 { BL [] 0 setdash 2 copy moveto
+ 2 copy vpt 0 90 arc
+ 2 copy moveto
+ 2 copy vpt 180 270 arc closepath fill
+ vpt 0 360 arc } bind def
+/C6 { BL [] 0 setdash 2 copy moveto
+ 2 copy vpt 90 270 arc closepath fill
+ vpt 0 360 arc closepath } bind def
+/C7 { BL [] 0 setdash 2 copy moveto
+ 2 copy vpt 0 270 arc closepath fill
+ vpt 0 360 arc closepath } bind def
+/C8 { BL [] 0 setdash 2 copy moveto
+ 2 copy vpt 270 360 arc closepath fill
+ vpt 0 360 arc closepath } bind def
+/C9 { BL [] 0 setdash 2 copy moveto
+ 2 copy vpt 270 450 arc closepath fill
+ vpt 0 360 arc closepath } bind def
+/C10 { BL [] 0 setdash 2 copy 2 copy moveto vpt 270 360 arc closepath fill
+ 2 copy moveto
+ 2 copy vpt 90 180 arc closepath fill
+ vpt 0 360 arc closepath } bind def
+/C11 { BL [] 0 setdash 2 copy moveto
+ 2 copy vpt 0 180 arc closepath fill
+ 2 copy moveto
+ 2 copy vpt 270 360 arc closepath fill
+ vpt 0 360 arc closepath } bind def
+/C12 { BL [] 0 setdash 2 copy moveto
+ 2 copy vpt 180 360 arc closepath fill
+ vpt 0 360 arc closepath } bind def
+/C13 { BL [] 0 setdash 2 copy moveto
+ 2 copy vpt 0 90 arc closepath fill
+ 2 copy moveto
+ 2 copy vpt 180 360 arc closepath fill
+ vpt 0 360 arc closepath } bind def
+/C14 { BL [] 0 setdash 2 copy moveto
+ 2 copy vpt 90 360 arc closepath fill
+ vpt 0 360 arc } bind def
+/C15 { BL [] 0 setdash 2 copy vpt 0 360 arc closepath fill
+ vpt 0 360 arc closepath } bind def
+/Rec { newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto
+ neg 0 rlineto closepath } bind def
+/Square { dup Rec } bind def
+/Bsquare { vpt sub exch vpt sub exch vpt2 Square } bind def
+/S0 { BL [] 0 setdash 2 copy moveto 0 vpt rlineto BL Bsquare } bind def
+/S1 { BL [] 0 setdash 2 copy vpt Square fill Bsquare } bind def
+/S2 { BL [] 0 setdash 2 copy exch vpt sub exch vpt Square fill Bsquare } bind def
+/S3 { BL [] 0 setdash 2 copy exch vpt sub exch vpt2 vpt Rec fill Bsquare } bind def
+/S4 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt Square fill Bsquare } bind def
+/S5 { BL [] 0 setdash 2 copy 2 copy vpt Square fill
+ exch vpt sub exch vpt sub vpt Square fill Bsquare } bind def
+/S6 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt vpt2 Rec fill Bsquare } bind def
+/S7 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt vpt2 Rec fill
+ 2 copy vpt Square fill
+ Bsquare } bind def
+/S8 { BL [] 0 setdash 2 copy vpt sub vpt Square fill Bsquare } bind def
+/S9 { BL [] 0 setdash 2 copy vpt sub vpt vpt2 Rec fill Bsquare } bind def
+/S10 { BL [] 0 setdash 2 copy vpt sub vpt Square fill 2 copy exch vpt sub exch vpt Square fill
+ Bsquare } bind def
+/S11 { BL [] 0 setdash 2 copy vpt sub vpt Square fill 2 copy exch vpt sub exch vpt2 vpt Rec fill
+ Bsquare } bind def
+/S12 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt2 vpt Rec fill Bsquare } bind def
+/S13 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt2 vpt Rec fill
+ 2 copy vpt Square fill Bsquare } bind def
+/S14 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt2 vpt Rec fill
+ 2 copy exch vpt sub exch vpt Square fill Bsquare } bind def
+/S15 { BL [] 0 setdash 2 copy Bsquare fill Bsquare } bind def
+/D0 { gsave translate 45 rotate 0 0 S0 stroke grestore } bind def
+/D1 { gsave translate 45 rotate 0 0 S1 stroke grestore } bind def
+/D2 { gsave translate 45 rotate 0 0 S2 stroke grestore } bind def
+/D3 { gsave translate 45 rotate 0 0 S3 stroke grestore } bind def
+/D4 { gsave translate 45 rotate 0 0 S4 stroke grestore } bind def
+/D5 { gsave translate 45 rotate 0 0 S5 stroke grestore } bind def
+/D6 { gsave translate 45 rotate 0 0 S6 stroke grestore } bind def
+/D7 { gsave translate 45 rotate 0 0 S7 stroke grestore } bind def
+/D8 { gsave translate 45 rotate 0 0 S8 stroke grestore } bind def
+/D9 { gsave translate 45 rotate 0 0 S9 stroke grestore } bind def
+/D10 { gsave translate 45 rotate 0 0 S10 stroke grestore } bind def
+/D11 { gsave translate 45 rotate 0 0 S11 stroke grestore } bind def
+/D12 { gsave translate 45 rotate 0 0 S12 stroke grestore } bind def
+/D13 { gsave translate 45 rotate 0 0 S13 stroke grestore } bind def
+/D14 { gsave translate 45 rotate 0 0 S14 stroke grestore } bind def
+/D15 { gsave translate 45 rotate 0 0 S15 stroke grestore } bind def
+/DiaE { stroke [] 0 setdash vpt add M
+ hpt neg vpt neg V hpt vpt neg V
+ hpt vpt V hpt neg vpt V closepath stroke } def
+/BoxE { stroke [] 0 setdash exch hpt sub exch vpt add M
+ 0 vpt2 neg V hpt2 0 V 0 vpt2 V
+ hpt2 neg 0 V closepath stroke } def
+/TriUE { stroke [] 0 setdash vpt 1.12 mul add M
+ hpt neg vpt -1.62 mul V
+ hpt 2 mul 0 V
+ hpt neg vpt 1.62 mul V closepath stroke } def
+/TriDE { stroke [] 0 setdash vpt 1.12 mul sub M
+ hpt neg vpt 1.62 mul V
+ hpt 2 mul 0 V
+ hpt neg vpt -1.62 mul V closepath stroke } def
+/PentE { stroke [] 0 setdash gsave
+ translate 0 hpt M 4 {72 rotate 0 hpt L} repeat
+ closepath stroke grestore } def
+/CircE { stroke [] 0 setdash
+ hpt 0 360 arc stroke } def
+/Opaque { gsave closepath 1 setgray fill grestore 0 setgray closepath } def
+/DiaW { stroke [] 0 setdash vpt add M
+ hpt neg vpt neg V hpt vpt neg V
+ hpt vpt V hpt neg vpt V Opaque stroke } def
+/BoxW { stroke [] 0 setdash exch hpt sub exch vpt add M
+ 0 vpt2 neg V hpt2 0 V 0 vpt2 V
+ hpt2 neg 0 V Opaque stroke } def
+/TriUW { stroke [] 0 setdash vpt 1.12 mul add M
+ hpt neg vpt -1.62 mul V
+ hpt 2 mul 0 V
+ hpt neg vpt 1.62 mul V Opaque stroke } def
+/TriDW { stroke [] 0 setdash vpt 1.12 mul sub M
+ hpt neg vpt 1.62 mul V
+ hpt 2 mul 0 V
+ hpt neg vpt -1.62 mul V Opaque stroke } def
+/PentW { stroke [] 0 setdash gsave
+ translate 0 hpt M 4 {72 rotate 0 hpt L} repeat
+ Opaque stroke grestore } def
+/CircW { stroke [] 0 setdash
+ hpt 0 360 arc Opaque stroke } def
+/BoxFill { gsave Rec 1 setgray fill grestore } def
+end
+%%EndProlog
+%%Page: 1 1
+gnudict begin
+gsave
+50 50 translate
+0.100 0.100 scale
+90 rotate
+0 -5040 translate
+0 setgray
+newpath
+(Helvetica) findfont 140 scalefont setfont
+1.000 UL
+LTb
+560 420 M
+63 0 V
+6409 0 R
+-63 0 V
+476 420 M
+(0) Rshow
+560 1056 M
+63 0 V
+6409 0 R
+-63 0 V
+-6493 0 R
+(100) Rshow
+560 1692 M
+63 0 V
+6409 0 R
+-63 0 V
+-6493 0 R
+(200) Rshow
+560 2328 M
+63 0 V
+6409 0 R
+-63 0 V
+-6493 0 R
+(300) Rshow
+560 2964 M
+63 0 V
+6409 0 R
+-63 0 V
+-6493 0 R
+(400) Rshow
+560 3600 M
+63 0 V
+6409 0 R
+-63 0 V
+-6493 0 R
+(500) Rshow
+560 4236 M
+63 0 V
+6409 0 R
+-63 0 V
+-6493 0 R
+(600) Rshow
+560 4872 M
+63 0 V
+6409 0 R
+-63 0 V
+-6493 0 R
+(700) Rshow
+1531 420 M
+0 63 V
+0 4389 R
+0 -63 V
+0 -4529 R
+(400) Cshow
+2825 420 M
+0 63 V
+0 4389 R
+0 -63 V
+0 -4529 R
+(600) Cshow
+4120 420 M
+0 63 V
+0 4389 R
+0 -63 V
+0 -4529 R
+(800) Cshow
+5414 420 M
+0 63 V
+0 4389 R
+0 -63 V
+0 -4529 R
+(1000) Cshow
+6708 420 M
+0 63 V
+0 4389 R
+0 -63 V
+0 -4529 R
+(1200) Cshow
+1.000 UL
+LTb
+560 420 M
+6472 0 V
+0 4452 V
+-6472 0 V
+560 420 L
+0 2646 M
+currentpoint gsave translate 90 rotate 0 0 M
+(tar.gz size \(Kb\)) Cshow
+grestore
+3796 140 M
+(time \(days since Jan 1, 1998\)) Cshow
+1.000 UL
+LT0
+696 420 M
+0 593 V
+1255 0 V
+0 15 V
+214 0 V
+0 6 V
+958 0 V
+0 1 V
+-84 0 V
+0 37 V
+168 0 V
+0 262 V
+13 0 V
+0 56 V
+91 0 V
+0 33 V
+6 0 V
+0 1 V
+19 0 V
+0 11 V
+20 0 V
+0 13 V
+32 0 V
+0 104 V
+52 0 V
+0 27 V
+65 0 V
+0 15 V
+39 0 V
+0 126 V
+174 0 V
+0 103 V
+52 0 V
+0 49 V
+175 0 V
+0 56 V
+433 0 V
+0 661 V
+415 0 V
+0 857 V
+123 0 V
+0 -291 V
+498 0 V
+0 208 V
+505 0 V
+0 66 V
+291 0 V
+0 115 V
+311 0 V
+0 449 V
+162 0 V
+0 309 V
+stroke
+grestore
+end
+showpage
+%%Trailer
+%%DocumentFonts: Helvetica
+%%Pages: 1
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/copyright.txt b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/copyright.txt
new file mode 100644
index 0000000000..397475632e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/copyright.txt
@@ -0,0 +1,30 @@
+
+The code and graphics on this website (and it's mirror sites, if any) are
+Copyright (c) 1999-2004 by Erik Andersen. All rights reserved.
+Copyright (c) 2005-2006 Rob Landley.
+
+Documents on this Web site including their graphical elements, design, and
+layout are protected by trade dress and other laws and MAY BE COPIED OR
+IMITATED IN WHOLE OR IN PART. THIS WEBSITE IS LICENSED FREE OF CHARGE, THERE
+IS NO WARRANTY FOR THE WEBSITE TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+SHOULD THIS WEBSITE PROVE DEFECTIVE, YOU MAY ASSUME THAT SOMEONE MIGHT GET
+AROUND TO SERVICING, REPAIRING OR CORRECTING IT SOMETIME WHEN THEY HAVE NOTHING
+BETTER TO DO. REGARDLESS, YOU GET TO KEEP BOTH PIECES.
+
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY
+COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THIS
+WEBSITE AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
+INABILITY TO USE THIS WEBSITE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
+LOSS OF HAIR, LOSS OF LIFE, LOSS OF MEMORY, LOSS OF YOUR CARKEYS, MISPLACEMENT
+OF YOUR PAYCHECK, OR COMMANDER DATA BEING RENDERED UNABLE TO ASSIST THE
+STARFLEET OFFICERS ABORD THE STARSHIP ENTERPRISE TO RECALIBRATE THE MAIN
+DEFLECTOR ARRAY, LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
+WEBSITE TO OPERATE WITH YOUR WEBBROWSER), EVEN IF SUCH HOLDER OR OTHER PARTY
+HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+You have been warned.
+
+You can contact the webmaster at <rob@landley.net> if you have some sort
+of problem with this.
+
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/developer.html b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/developer.html
new file mode 100644
index 0000000000..cdb68b78c0
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/developer.html
@@ -0,0 +1,69 @@
+<!--#include file="header.html" -->
+
+<h3>Morris Dancing</h3>
+
+<p>Subversion commit access requires an account on Morris. The server
+behind busybox.net and uclibc.org. If you want to be able to commit things to
+Subversion, first contribute some stuff to show you are serious, can handle
+some responsibility, and that your patches don't generally need a lot of
+cleanup. Then, very nicely ask one of us (<a href="mailto:rob@landley.net">Rob
+Landley</a> for BusyBox, or <a href="mailto:andersen@codepoet.org">Erik
+Andersen</a> for uClibc) for an account.</p>
+
+<p>If you're approved for an account, you'll need to send an email from your
+preferred contact email address with the username you'd like to use when
+committing changes to SVN, and attach a public ssh key to access your account
+with.</p>
+
+<p>If you don't currently have an ssh version 2 DSA key at least 1024 bits
+long (the default), you can generate a key using the
+command <b>ssh-keygen -t dsa</b> and hitting enter at the prompts. This
+will create the files <b>~/.ssh/id_dsa</b> and <b>~/.ssh/id_dsa.pub</b>
+You must then send the content of 'id_dsa.pub' to me so I can set up your
+account. (The content of 'id_dsa' should of course be kept secret, anyone
+who has that can access any account that's installed your public key in
+its <b>.ssh/authorized_keys</b> file.)</p>
+
+<p>Note that if you would prefer to keep your communications with us
+private, you can encrypt your email using
+<a href="http://landley.net/pubkey.gpg">Rob's public key</a> or
+<a href="http://www.codepoet.org/andersen/erik/gpg.asc">Erik's public
+key</a>.</p>
+
+<p>Once you are setup with an account, you will need to use your account to
+checkout a copy of BusyBox from Subversion:</p>
+
+<p><b>svn checkout svn+ssh://username@busybox.net/svn/trunk/busybox</b></p>
+<p>or</p>
+<p><b>svn checkout svn+ssh://username@uclibc.org/svn/trunk/uclibc</b></p>
+
+<p>You must change <em>username</em> to your own username, or omit
+it if it's the same as your local username.</p>
+
+<p>You can then enter the newly checked out project directory, make changes,
+check your changes, diff your changes, revert your changes, and and commit your
+changes using commands such as:</p>
+
+<b><pre>
+svn diff
+svn status
+svn revert
+EDITOR=vi svn commit
+svn log -v -r PREV:HEAD
+svn help
+</pre></b>
+
+<p>For additional detail on how to use Subversion, please visit the
+<a href="http://subversion.tigris.org/">the Subversion website</a>.
+You might also want to read online or buy a copy of <a
+href="http://svnbook.red-bean.com/">the Subversion Book</a>...</p>
+
+<p>A morris account also gives you a personal web page
+(http://busybox.net/~username comes from ~/public_html on morris), and of
+course a shell prompt you can ssh into (as a regular user, root access is
+reserved for Erik and Rob). But keep in mind an account on Morris is a
+priviledge, not a requirement. Most contributors to busybox and uClibc
+haven't got one, and accounts are handed out to make the project maintainers'
+lives easier, not because "you deserve it".</p>
+
+<!--#include file="footer.html" -->
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/download.html b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/download.html
new file mode 100644
index 0000000000..b0bd6e3715
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/download.html
@@ -0,0 +1,60 @@
+<!--#include file="header.html" -->
+
+
+
+<h3>Download</h3>
+
+<p>
+Source for the latest release can always be
+downloaded from <a href="downloads/">http://www.busybox.net/downloads/</a>.
+
+<p>
+Each 1.x branch has bug fix releases after initial 1.x.0 release.
+Also there are patches on top of latest bug fix release.
+<p>
+Latest releases and patch directories for each branch:
+<br>
+<a href=http://busybox.net/downloads/busybox-1.10.1.tar.bz2>1.10.1</a>,
+<a href=http://busybox.net/downloads/fixes-1.10.1/>patches</a>,
+<br>
+<a href=http://busybox.net/downloads/busybox-1.9.2.tar.bz2>1.9.2</a>,
+<a href=http://busybox.net/downloads/fixes-1.9.2/>patches</a>,
+<br>
+<a href=http://busybox.net/downloads/busybox-1.8.3.tar.bz2>1.8.3</a>,
+<a href=http://busybox.net/downloads/fixes-1.8.3/>patches</a>,
+<br>
+<a href=http://busybox.net/downloads/busybox-1.7.5.tar.bz2>1.7.5</a>,
+<a href=http://busybox.net/downloads/fixes-1.7.5/>patches</a>,
+<br>
+<a href=http://busybox.net/downloads/busybox-1.6.2.tar.bz2>1.6.2</a>,
+<a href=http://busybox.net/downloads/fixes-1.6.2/>patches</a>,
+<br>
+<a href=http://busybox.net/downloads/busybox-1.5.2.tar.bz2>1.5.2</a>,
+<a href=http://busybox.net/downloads/fixes-1.5.2/>patches</a>,
+<br>
+<a href=http://busybox.net/downloads/busybox-1.4.2.tar.bz2>1.4.2</a>,
+<a href=http://busybox.net/downloads/fixes-1.4.2/>patches</a>,
+<br>
+<a href=http://busybox.net/downloads/busybox-1.3.2.tar.bz2>1.3.2</a>,
+<a href=http://busybox.net/downloads/fixes-1.3.2/>patches</a>.
+
+<p>
+You can also obtain <a href="downloads/snapshots/">Daily Snapshots</a> of
+the latest development source tree for those wishing to follow BusyBox development,
+but cannot or do not wish to use Subversion (svn).
+
+<ul>
+ <li> Click here to <a href="/cgi-bin/viewcvs.cgi/trunk/busybox/">browse the source tree</a>.
+ </li>
+
+ <li>Anonymous <a href="subversion.html">Subversion access</a> is available.
+ </li>
+
+ <li>For those that are actively contributing obtaining
+ <a href="developer.html">Subversion read/write access</a> is also possible.
+ </li>
+
+</ul>
+
+<!--#include file="footer.html" -->
+
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/fix.html b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/fix.html
new file mode 100644
index 0000000000..45621cde7f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/fix.html
@@ -0,0 +1,15 @@
+<!--#include file="header.html" -->
+
+<h3>How to get your patch added to "hot fixes"</h3>
+
+<p> If you found a regression or severe bug in busybox, and you have a patch
+ for it, and you want to see it added to "hot fixes", please rediff your
+ patch against corresponding unmodified busybox source and send it to
+ <a href=mailto:busybox@busybox.net>the mailing list</a>.
+</p>
+
+<br>
+<br>
+<br>
+
+<!--#include file="footer.html" -->
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/footer.html b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/footer.html
new file mode 100644
index 0000000000..7f39ccb01a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/footer.html
@@ -0,0 +1,47 @@
+<!-- Footer -->
+
+
+ </td>
+ </tr>
+ </table>
+
+<hr />
+
+
+ <table width="100%">
+ <tr>
+ <td width="60%">
+ <font face="arial, helvetica, sans-serif" size="-1">
+ <a href="/copyright.txt">Copyright &copy; 1999-2005 Erik Andersen</a>
+ <br>
+ Mail all comments, insults, suggestions and bribes to
+ <br>
+ Denys Vlasenko <a href="mailto:vda.linux@googlemail.com">vda.linux@googlemail.com</a><br>
+ </font>
+ </td>
+
+ <td>
+ <a href="http://www.vim.org/"><img border=0 width=88 height=31
+ src="images/written.in.vi.png"
+ alt="This site created with the vi editor"></a>
+ </td>
+
+ <td>
+ <a href="http://osuosl.org/"><img border=0 width=114 height=63
+ src="images/osuosl.png"
+ alt="This site is kindly hosted by OSL"></a>
+ </td>
+<!--
+ <td>
+ <a href="http://validator.w3.org/check?uri=referer"><img
+ border="0" height="31" width="88"
+ src="images/valid-html401.png"
+ alt="Valid HTML"></a>
+ </td>
+-->
+ </TR>
+ </table>
+
+ </body>
+</html>
+
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/header.html b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/header.html
new file mode 100644
index 0000000000..b83fdcb6a7
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/header.html
@@ -0,0 +1,102 @@
+<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'>
+
+<html>
+ <head>
+ <meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'>
+ <title>BusyBox</title>
+ <style type="text/css">
+ body {
+ background-color: #DEE2DE;
+ color: #000000;
+ }
+ :link { color: #660000 }
+ :visited { color: #660000 }
+ :active { color: #660000 }
+ td.c2 {font-family: arial, helvetica, sans-serif; font-size: 80%}
+ td.c1 {font-family: lucida, helvetica; font-size: 248%}
+ </style>
+ </head>
+
+ <body>
+ <basefont face="lucida, helvetica, arial" size="3">
+
+
+
+
+<table border="0" cellpadding="0" cellspacing="0">
+
+
+<tr>
+<td>
+ <div class="c3">
+ <table border="0" cellspacing="1" cellpadding="2">
+ <tr>
+ <td class="c1">BUSYBOX</td>
+ </tr>
+ </table>
+ </div>
+
+ <a href="/"><IMG SRC="images/busybox1.png" alt="BusyBox" border="0"></a><BR>
+</td>
+</tr>
+
+<tr>
+
+<td valign="TOP">
+ <b>About</b>
+ <ul>
+ <li><a href="about.html">About BusyBox</a></li>
+ <li><a href="screenshot.html">Screenshot</a></li>
+ <li><a href="news.html">Announcements</a></li>
+ </ul>
+ <b>Documentation</b>
+ <ul>
+ <li><a href="FAQ.html">FAQ</a></li>
+ <li><a href="downloads/BusyBox.html">Command Help</a></li>
+ <li><a href="downloads/README">README</a></li>
+ </ul>
+ <b>Get BusyBox</b>
+ <ul>
+ <li><a href="download.html">Download Source</a></li>
+ <li><a href="license.html">License</a></li>
+ <li><a href="products.html">Products</a></li>
+ </ul>
+ <b>Development</b>
+ <ul>
+ <li><a href="/cgi-bin/viewcvs.cgi/trunk/busybox/">Browse Source</a></li>
+ <li><a href="subversion.html">Source Control</a></li>
+ <!--li><a href="/downloads/patches/recent.html">Recent Changes</a></li-->
+ <li><a href="lists.html">Mailing Lists</a></li>
+ <li><a href="http://bugs.busybox.net/">Bug Tracking</a></li>
+ </ul>
+ <p><b>Links</b>
+ <ul>
+ <li><a href="links.html">Related Sites</a></li>
+ <li><a href="tinyutils.html">Tiny Utilities</a></li>
+ <li><a href="sponsors.html">Sponsors</a></li>
+ </ul>
+ <p><b>Developer Pages</b>
+ <ul>
+ <li><a href="http://busybox.net/~landley">Rob</a></li>
+ <li><a href="http://busybox.net/~aldot">Bernhard</a></li>
+ <li><a href="http://busybox.net/~vda">Denys</a>
+ <br>- <a href=http://busybox.net/~vda/resume/denys_vlasenko.htm>resume</a>
+ <br>- <a href=http://busybox.net/~vda/mboot/>mboot</a>
+ <br>- <a href=http://busybox.net/~vda/linld/>linld</a>
+ <br>- <a href=http://busybox.net/~vda/init_vs_runsv.html>init must die</a>
+ <br>- <a href=http://busybox.net/~vda/no_ifup.txt>no ifup</a>
+ <br>- <a href=http://busybox.net/~vda/unscd/>unscd</a>
+ </li>
+ </ul>
+
+<!--
+ <a href="http://validator.w3.org/check/referer"><img
+ src="/images/vh40.gif" height=31 width=88
+ align=left border=0 alt="Valid HTML 4.0!"></a>
+-->
+
+</td>
+
+
+<td Valign="TOP">
+
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/back.png b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/back.png
new file mode 100644
index 0000000000..79923869bf
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/back.png
Binary files differ
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/busybox.jpeg b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/busybox.jpeg
new file mode 100644
index 0000000000..37edc96146
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/busybox.jpeg
Binary files differ
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/busybox.png b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/busybox.png
new file mode 100644
index 0000000000..b1eb92f381
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/busybox.png
Binary files differ
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/busybox1.png b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/busybox1.png
new file mode 100644
index 0000000000..4d3126a529
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/busybox1.png
Binary files differ
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/busybox2.jpg b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/busybox2.jpg
new file mode 100644
index 0000000000..abf8f0610b
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/busybox2.jpg
Binary files differ
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/busybox3.jpg b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/busybox3.jpg
new file mode 100644
index 0000000000..0fab84cf9d
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/busybox3.jpg
Binary files differ
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/dir.png b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/dir.png
new file mode 100644
index 0000000000..1d633ce4a6
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/dir.png
Binary files differ
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/donate.png b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/donate.png
new file mode 100644
index 0000000000..b55621bb90
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/donate.png
Binary files differ
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/fm.mini.png b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/fm.mini.png
new file mode 100644
index 0000000000..c0883cd34c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/fm.mini.png
Binary files differ
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/gfx_by_gimp.png b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/gfx_by_gimp.png
new file mode 100644
index 0000000000..d583140348
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/gfx_by_gimp.png
Binary files differ
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/ltbutton2.png b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/ltbutton2.png
new file mode 100644
index 0000000000..9bad9496ae
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/ltbutton2.png
Binary files differ
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/osuosl.png b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/osuosl.png
new file mode 100644
index 0000000000..b00b5007d3
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/osuosl.png
Binary files differ
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/sdsmall.png b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/sdsmall.png
new file mode 100644
index 0000000000..b1024501b6
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/sdsmall.png
Binary files differ
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/text.png b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/text.png
new file mode 100644
index 0000000000..6034f899f9
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/text.png
Binary files differ
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/valid-html401.png b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/valid-html401.png
new file mode 100644
index 0000000000..ec9bc0ce00
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/valid-html401.png
Binary files differ
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/vh40.gif b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/vh40.gif
new file mode 100644
index 0000000000..c5e9402e73
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/vh40.gif
Binary files differ
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/written.in.vi.png b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/written.in.vi.png
new file mode 100644
index 0000000000..84f59bc151
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/images/written.in.vi.png
Binary files differ
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/index.html b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/index.html
new file mode 100644
index 0000000000..1bab6b0693
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/index.html
@@ -0,0 +1 @@
+<!--#include file="news.html" -->
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/license.html b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/license.html
new file mode 100644
index 0000000000..76358bc65b
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/license.html
@@ -0,0 +1,97 @@
+<!--#include file="header.html" -->
+
+<p>
+<h3>BusyBox is licensed under the GNU General Public License, version 2</h3>
+
+<p>BusyBox is licensed under <a href="http://www.gnu.org/licenses/gpl.html#SEC1">the
+GNU General Public License</a> version 2, which is often abbreviated as GPLv2.
+(This is the same license the Linux kernel is under, so you may be somewhat
+familiar with it by now.)</p>
+
+<p>A complete copy of the license text is included in the file LICENSE in
+the BusyBox source code.</p>
+
+<p><a href="/products.html">Anyone thinking of shipping BusyBox as part of a
+product</a> should be familiar with the licensing terms under which they are
+allowed to use and distribute BusyBox. Read the full test of the GPL (either
+through the above link, or in the file LICENSE in the busybox tarball), and
+also read the <a href="http://www.gnu.org/licenses/gpl-faq.html">Frequently
+Asked Questions about the GPL</a>.</p>
+
+<p>Basically, if you distribute GPL software the license requires that you also
+distribute the source code to that GPL-licensed software. So if you distribute
+BusyBox without making the source code to the version you distribute available,
+you violate the license terms, and thus infringe on the copyrights of BusyBox.
+(This requirement applies whether or not you modified BusyBox; either way the
+license terms still apply to you.) Read the license text for the details.</p>
+
+<h3>A note on GPL versions</h3>
+
+<p>Version 2 of the GPL is the only version of the GPL which current versions
+of BusyBox may be distributed under. New code added to the tree is licensed
+GPL version 2, and the project's license is GPL version 2.</p>
+
+<p>Older versions of BusyBox (versions 1.2.2 and earlier, up through about svn
+16112) included variants of the recommended "GPL version 2 or (at your option)
+later versions" boilerplate permission grant. Ancient versions of BusyBox
+(before svn 49) did not specify any version at all, and section 9 of GPLv2
+(the most recent version at the time) says those old versions may be
+redistributed under any version of GPL (including the obsolete V1). This was
+conceptually similar to a dual license, except that the different licenses were
+different versions of the GPL.</p>
+
+<p>However, BusyBox has apparently always contained chunks of code that were
+licensed under GPL version 2 only. Examples include applets written by Linus
+Torvalds (util-linux/mkfs_minix.c and util_linux/mkswap.c) which stated they
+"may be redistributed as per the Linux copyright" (which Linus clarified in the
+2.4.0-pre8 release announcement in 2000 was GPLv2 only), and Linux kernel code
+copied into libbb/loop.c (after Linus's announcement). There are probably
+more, because all we used to check was that the code was GPL, not which
+version. (Before the GPLv3 draft proceedings in 2006, it was a purely
+theoretical issue that didn't come up much.)</p>
+
+<p>To summarize: every version of BusyBox may be distributed under the terms of
+GPL version 2. New versions (after 1.2.2) may <b>only</b> be distributed under
+GPLv2, not under other versions of the GPL. Older versions of BusyBox might
+(or might not) be distributable under other versions of the GPL. If you
+want to use a GPL version other than 2, you should start with one of the old
+versions such as release 1.2.2 or SVN 16112, and do your own homework to
+identify and remove any code that can't be licensed under the GPL version you
+want to use. New development is all GPLv2.</p>
+
+<h3>License enforcement</h3>
+
+<p>BusyBox's copyrights are enforced by the <a
+href="http://www.softwarefreedom.org">Software Freedom Law Center</a>
+(you can contact them at gpl@busybox.net), which
+"accepts primary responsibility for enforcement of US copyrights on the
+software... and coordinates international copyright enforcement efforts for
+such works as necessary." If you distribute BusyBox in a way that doesn't
+comply with the terms of the license BusyBox is distributed under, expect to
+hear from these guys. Their entire reason for existing is to do pro-bono
+legal work for free/open source software projects. (We used to list people who
+violate the BusyBox license in <a href="/shame.html">The Hall of Shame</a>,
+but these days we find it much more effective to hand them over to the
+lawyers.)</p>
+
+<p>Our enforcement efforts are aimed at bringing people into compliance with
+the BusyBox license. Open source software is under a different license from
+proprietary software, but if you violate that license you're still a software
+pirate and the law gives the vendor (us) some big sticks to play with. We
+don't want monetary awards, injunctions, or to generate bad PR for a company,
+unless that's the only way to get somebody that repeatedly ignores us to comply
+with the license on our code.</p>
+
+<h3>A Good Example</h3>
+
+<p>These days, <a href="http://www.linksys.com/">Linksys</a> is
+doing a good job at complying with the GPL, they get to be an
+example of how to do things right. Please take a moment and
+check out what they do with
+<a href="http://www.linksys.com/servlet/Satellite?c=L_Content_C1&childpagename=US%2FLayout&cid=1115416836002&pagename=Linksys%2FCommon%2FVisitorWrapper">
+distributing the firmware for their WRT54G Router.</a>
+Following their example would be a fine way to ensure that you
+have also fulfilled your licensing obligations.</p>
+
+<!--#include file="footer.html" -->
+
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/links.html b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/links.html
new file mode 100644
index 0000000000..9cdbd7c8ce
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/links.html
@@ -0,0 +1,19 @@
+<!--#include file="header.html" -->
+
+<h3>Related Sites</h3>
+
+<br><a href="http://uclibc.org/">uClibc.org</a>
+<br><a href="http://cxx.uclibc.org/">uClibc++</a>
+<br><a href="http://udhcp.busybox.net/">udhcp</a>
+<br><a href="http://buildroot.uclibc.org/">buildroot</a>
+<br><a href="http://www.scratchbox.org/">Scratchbox</a>
+<br><a href="http://openembedded.org/">OpenEmbedded</a>
+<br><a href="http://www.ucdot.org/">uCdot</a>
+<br><a href="http://www.linuxdevices.com">LinuxDevices</a>
+<br><a href="http://slashdot.org/">Slashdot</a>
+<br><a href="http://freshmeat.net/">Freshmeat</a>
+<br><a href="http://linuxtoday.com/">Linux Today</a>
+<br><a href="http://lwn.net/">Linux Weekly News</a>
+<br><a href="http://www.tldp.org/HOWTO">Linux HOWTOs</a>
+
+<!--#include file="footer.html" -->
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/lists.html b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/lists.html
new file mode 100644
index 0000000000..3a28cc07e7
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/lists.html
@@ -0,0 +1,46 @@
+<!--#include file="header.html" -->
+
+
+<!-- Begin Introduction section -->
+
+<h3>Mailing List Information</h3>
+BusyBox has a <a href="/lists/busybox/">mailing list</a> for discussion and
+development. You can subscribe by visiting
+<a href="http://busybox.net/mailman/listinfo/busybox">this page</a>.
+Only subscribers to the BusyBox mailing list are allowed to post
+to this list.
+
+<p>
+There is also a mailing list for <a href="/lists/busybox-cvs/">active developers</a>
+wishing to read the complete diff of each and every change to busybox -- not for the
+faint of heart. Active developers can subscribe by visiting
+<a href="http://busybox.net/mailman/listinfo/busybox-cvs">this page</a>.
+The Subversion server is the only one permtted to post to this list. And yes,
+this list name uses the word 'cvs' even though we don't use that anymore...
+
+<p>
+
+
+<h3>Search the List Archives</h3>
+Please search the mailing list archives before asking questions on the mailing
+list, since there is a good chance someone else has asked the same question
+before. Checking the archives is a great way to avoid annoying everyone on the
+list with frequently asked questions...
+<p>
+
+<center>
+<form method="GET" action="http://www.google.com/custom">
+<input type="hidden" name="domains" value="busybox.net">
+<input type="hidden" name="sitesearch" value="busybox.net">
+<input type="text" name="q" size="31" maxlength="255" value="">
+<br>
+<input type="submit" name="sa" value="search the mailing list archives">
+<br>
+<a href="http://www.google.com"><img src="http://www.google.com/logos/Logo_25wht.gif" border="0" alt="Google" height="32" width="75" align="middle"></a>
+<br>
+</form>
+</center>
+
+
+
+<!--#include file="footer.html" -->
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/news.html b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/news.html
new file mode 100644
index 0000000000..47e61f21a8
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/news.html
@@ -0,0 +1,248 @@
+<!--#include file="header.html" -->
+
+<ul>
+ <li><b>12 June 2008 -- Sponsors!</b>
+ <p>We want to thank the following companies which are providing support
+ for BusyBox project:
+ <ul>
+ <li>AOE media, a <a href=http://www.aoemedia.com/typo3-development.html>
+ TYPO3 development agency</a> contributes financially.
+ <p>
+ <li><a href=http://www.analog.com/en/>Analog Devices, Inc.</a> provided
+ a <a href=http://docs.blackfin.uclinux.org/doku.php?id=bf537_quick_start>
+ Blackfin development board</a> free of charge.
+ <a href=http://www.analog.com/blackfin>Blackfin<a>
+ is a NOMMU processor, and its availability for testing is invaluable.
+ If you are an embedded device developer,
+ please note that Analog Devices has entire Linux distribution available
+ for download for this board. Visit
+ <a href=http://blackfin.uclinux.org/>http://blackfin.uclinux.org/</a>
+ for more information.
+ </ul>
+ </p>
+
+ <li><b>5 June 2008 -- BusyBox 1.10.3 (stable)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.10.3.tar.bz2>BusyBox 1.10.3</a>.
+ (<a href=http://busybox.net/cgi-bin/viewcvs.cgi/branches/busybox_1_10_stable/>svn</a>,
+ <a href=http://busybox.net/downloads/fixes-1.10.3/>patches</a>,
+ <a href=http://busybox.net/fix.html>how to add a patch</a>)</p>
+ <p>
+ Bugfix-only release for 1.10.x branch. It contains fixes for dnsd, fuser, hush,
+ ip, mdev and syslogd.
+ <p>
+ <a href=http://busybox.net/~vda/HOWTO/i486-linux-uclibc/HOWTO.txt>
+ How to build static busybox for i486-linux-uclibc</a>
+ <p>
+ The email address gpl@busybox.net is the recommended way to contact
+ the Software Freedom Law Center to report BusyBox license violations.
+ </p>
+
+ <li><b>8 May 2008 -- BusyBox 1.10.2 (stable)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.10.2.tar.bz2>BusyBox 1.10.2</a>.
+ (<a href=http://busybox.net/cgi-bin/viewcvs.cgi/branches/busybox_1_10_stable/>svn</a>,
+ <a href=http://busybox.net/downloads/fixes-1.10.2/>patches</a>,
+ <a href=http://busybox.net/fix.html>how to add a patch</a>)</p>
+ <p>
+ Bugfix-only release for 1.10.x branch. It contains fixes for echo, httpd, pidof,
+ start-stop-daemon, tar, taskset, tab completion in shells, build system.
+ <p>Please note that mdev was backported from current svn trunk. Please
+ report if you encounter any problems with it.
+ </p>
+
+ <li><b>19 April 2008 -- BusyBox 1.10.1 (stable)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.10.1.tar.bz2>BusyBox 1.10.1</a>.
+ (<a href=http://busybox.net/cgi-bin/viewcvs.cgi/branches/busybox_1_10_stable/>svn</a>,
+ <a href=http://busybox.net/downloads/fixes-1.10.1/>patches</a>,
+ <a href=http://busybox.net/fix.html>how to add a patch</a>)</p>
+ <p>
+ Bugfix-only release for 1.10.x branch. It contains fixes for
+ fuser, init, less, nameif, tail, taskset, tcpudp, top, udhcp.
+
+ <li><b>21 March 2008 -- BusyBox 1.10.0 (unstable)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.10.0.tar.bz2>BusyBox 1.10.0</a>.
+ (<a href=http://busybox.net/cgi-bin/viewcvs.cgi/branches/busybox_1_10_stable/>svn</a>,
+ <a href=http://busybox.net/downloads/fixes-1.10.0/>patches</a>,
+ <a href=http://busybox.net/fix.html>how to add a patch</a>)</p>
+
+ <p>Sizes of busybox-1.9.2 and busybox-1.10.0 (with almost full config, static uclibc build):<pre>
+ text data bss dec hex filename
+ 781405 679 7500 789584 c0c50 busybox-1.9.2
+ 773551 640 7372 781563 becfb busybox-1.10.0
+</pre>
+ <p>Top 10 stack users:<pre>
+busybox-1.9.2: busybox-1.10.0:
+echo_dg 4116 bb_full_fd_action 4112
+bb_full_fd_action 4112 find_list_entry2 4096
+discard_dg 4108 readlink_main 4096
+discard_dg 4096 ipaddr_list_or_flush 3900
+echo_stream 4096 iproute_list_or_flush 3680
+discard_stream 4096 insmod_main 3152
+find_list_entry2 4096 fallbackSort 2952
+readlink_main 4096 do_iproute 2492
+ipaddr_list_or_flush 3900 cal_main 2464
+iproute_list_or_flush 3680 readhere 2308
+</pre>
+
+ <p>New applets: brctl, chat (by Vladimir Dronnikov &lt;dronnikov AT gmail.com&gt;),
+ findfs, ifenslave (closes bug 115), lpd (by Vladimir Dronnikov &lt;dronnikov AT gmail.com&gt;),
+ lpr+lpq (by Walter Harms), script (by Pascal Bellard &lt;pascal.bellard AT ads-lu.com&gt;),
+ sendmail (Vladimir Dronnikov &lt;dronnikov AT gmail.com&gt;), tac, tftpd.
+
+ <p>Made NOMMU-compatible: crond, crontab, ifupdown, inetd, init, runsv, svlogd, tcpsvd, udpsvd.
+
+ <p>Changes since previous release:
+ <ul>
+ <li>globally: add -Wunused-parameter
+ <li>globally: add optimization barrier to all "G trick" locations
+ <li>adduser/addgroup: check username for invalid chars (by Tito &lt;farmatito AT tiscali.it&gt;)
+ <li>adduser: optional support for long options. Closes bug 2134
+ <li>ash: handle "A=1 A=2 B=$A; echo $B". Closes bug 947
+ <li>ash: make ash -c "if set -o barfoo 2&gt;/dev/null; then echo foo; else echo bar; fi" work. Closes bug 1142
+ <li>build system: don't use "gcc -o /dev/null", old gcc can delete /dev/null in this case
+ <li>build system: fixes for cross-compiling on an OS X host
+ <li>build system: make it do without "od -t"
+ <li>build system: pass CFLAGS to link stage too. Closes bug 1376
+ <li>build system: add CONFIG_NOMMU
+ <li>cp: add ENABLE_FEATURE_VERBOSE_CP_MESSAGE. Closes bug 1470
+ <li>crontab: almost complete rewrite
+ <li>dnsd: properly set _src_ IP:port on outgoing UDP packets
+ <li>dpkg: fix bug where existence check was reversed
+ <li>eject: add -s for SCSI- and USB-devices (Nico Erfurth)
+ <li>fdisk: fix a case where break was reached only for DOS labels
+ <li>fsck: don't kill pid -1! (Roy Marples &lt;roy at marples.name&gt;)
+ <li>fsck_minix: fix bug in map_block2: s/(blknr &gt;= 256 * 256)/(blknr &lt; 256 * 256)/
+ <li>fuser: substantial rewrite
+ <li>getopt: add support for "a+" specifier for nonnegative int parameters. By Vladimir Dronnikov &lt;dronnikov at gmail.com&gt;
+ <li>getty: don't try to detect parity on local lines (Joakim Tjernlund &lt;Joakim.Tjernlund at transmode.se&gt;)
+ <li>halt: write wtmp entry if wtmp support is enabled
+ <li>httpd: "HEAD" support. Closes bug 1530
+ <li>httpd: fix bug 2004: wrong argv when interpreter is invoked
+ <li>httpd: fix bug where we did chdir("") if CGI path had only one "/"
+ <li>httpd: fix for POST upload
+ <li>httpd: support for "I:index.xml" syntax (Peter Korsgaard &lt;jacmet AT uclibc.org&gt;)
+ <li>hush: fix a case where none of pipe members could be started because of fork failure
+ <li>hush: more correct handling of piping
+ <li>hush: reinstate `cmd` handling for NOMMU
+ <li>hush: report [v]fork failures
+ <li>hush: set CLOEXEC on script file being executed
+ <li>hush: try to add a bit more of vfork-friendliness
+ <li>inetd: make "udp nowait" work
+ <li>inetd: make inetd IPv6-capable
+ <li>init: add FEATURE_KILL_REMOVED (Eugene Bordenkircher &lt;eugebo AT gmail.com&gt;)
+ <li>init: allow last line of config file to be not terminated by "\n"
+ <li>init: do not die if "/dev/null" is missing
+ <li>init: fix bug 1111: restart actions were not splitting words
+ <li>init: wait for orphaned children too while waiting for sysinit-like processes (harald-tuxbox AT arcor.de)
+ <li>ip route: "ip route" was misbehaving (extra argv+1 ate 1st env var)
+ <li>last: do not go into endless loop on read error
+ <li>less,klogd,syslogd,nc,tcpudp: exit on signal by killing itself, not exit(1)
+ <li>less: "examine" command will not bomb out on bad file name now
+ <li>less: fix bug where backspace wasn't actually deleting chars
+ <li>less: make it a bit more resistant against status line corruption
+ <li>less: improve search when data is not supplied fast enough by stdin - now will try reading for 1-2 seconds before declaring that there is no match. This fixes a very common annoyance with long manpages
+ <li>less: update line input so that it doesn't interfere with screen update. Makes "man bash", [enter], [/], &lt;enter search pattern&gt;, [enter] more usable - manpage now draws even as you enter the pattern!
+ <li>libbb: filename completion matches dangling symlinks too
+ <li>libbb: fix getopt state corruption for NOFORK applets
+ <li>libbb: full_read/write now will report partial data counts prior to error
+ <li>libbb: intrduce and use safe_gethostname. By Tito &lt;farmatito AT tiscali.it&gt;
+ <li>libbb: introduce and use nonblock_safe_read(). Yay! Our shells are immune from this nasty O_NONBLOCK now!
+ <li>login,su: avoid clearing environment with some options, as was intended
+ <li>microcom: read more than 1 byte from device, if possible
+ <li>microcom: split -d (delay) option away from -t
+ <li>mktemp: support -p DIR (Timo Teras &lt;timo.teras at iki.fi&gt;)
+ <li>mount: #ifdef out MOUNT_LABEL code parts if it is not selected
+ <li>mount: add another mount helper call method
+ <li>mount: allow and ignore _netdev option
+ <li>mount: make -f work even without mtab support (Cristian Ionescu-Idbohrn &lt;cristian.ionescu-idbohrn at axis.com&gt;)
+ <li>mount: optional support for -vv verbosity
+ <li>mount: plug a hole where FEATURE_MOUNT_HELPERS could allow execution of arbitrary command
+ <li>mount: recognize "dirsync" (closes bug 835)
+ <li>mount: sanitize environment if called by non-root
+ <li>mount: support for mount by label. Closes bug 1143
+ <li>mount: with -vv -f, say what mount() calls we were going to make
+ <li>msh: create testsuite (based on hush one)
+ <li>msh: don't use floating point in "times" builtin
+ <li>msh: fix Ctrl-C handling with line editing
+ <li>msh: fix for bug 846 ("break" didn't work second time)
+ <li>msh: glob0/glob1/glob2/glob3 were just a sorting routine, removed
+ <li>msh: instead of fixing "ls | cd", "cd | ls" etc disallow builtins in pipes. They make no sense there anyway
+ <li>msh: stop trying to parse variables in "msh SCRIPT VAR=val param". They are passed as ordinary parameters
+ <li>netstat: print control chars as "^C" etc
+ <li>nmeter: fix bug where %[mf] behaves as %[mt]
+ <li>nohup: compat patch by Christoph Gysin &lt;mailinglist.cache at gmail.com&gt;
+ <li>od: handle /proc files (which have filesize 0) correctly
+ <li>patch: don't trash permissions of patched file
+ <li>ps: add conditional support for -o [e]time
+ <li>ps: fix COMMAND column adjustment; overflow in USER and VSZ columns
+ <li>reset: call "stty sane". Closes bug 1414
+ <li>rmdir: optional long options support for Debian users. By Roberto Gordo Saez &lt;roberto.gordo AT gmail.com&gt;
+ <li>run-parts: add --reverse
+ <li>script: correctly handle buffered "tail" of output
+ <li>sed: "n" command must reset "we had successful subst" flag. Closes bug 1214
+ <li>sort: -z outputs NUL terminated lines. Closes bug 1591
+ <li>stty: fix mishandling of control keywords (Ralf Friedl &lt;Ralf.Friedl AT online.de&gt;)
+ <li>switch_root: stop at first non-option. Closes bug 1425
+ <li>syslogd: avoid excessive time() system calls
+ <li>syslogd: don't die if remote host's IP cannot be resolved. Retry resolutions every two minutes instead
+ <li>syslogd: fix shmat error check
+ <li>syslogd: optional support for dropping dups. Closes bug 436
+ <li>syslogd: send "\n"-terminated messages over the network. Fully closes bug 1574
+ <li>syslogd: tighten up hostname handling
+ <li>tail: fix "tail -c 20 /dev/huge_disk" (was taking ages)
+ <li>tar: compat: handle tarballs with only one zero block at the end
+ <li>tar: autodetection of gz/bz2 compressed tarballs. Closes bug 992
+ <li>tar: real support for -p. By Natanael Copa &lt;natanael.copa at gmail.com&gt;
+ <li>tcpudp: narrow down time window where we have no wildcard socket
+ <li>telnetd: use login always, not "sometimes login, sometimes shell"
+ <li>test: fix mishandling of "test ! arg1 op arg2 more args"
+ <li>trylink: instead of build error, disable --gc-sections if GLIBC and STATIC are selected
+ <li>udhcp: make file paths configurable
+ <li>udhcp: optional support for non-standard DHCP ports
+ <li>udhcp: set correct op byte in the packet for DHCPDECLINE
+ <li>udhcpc: filter unwanted packets in kernel (Cristian Ionescu-Idbohrn &lt;cristian.ionescu-idbohrn AT axis.com&gt;)
+ <li>udhcpc: fix wrong options in decline and release packets (Jonas Danielsson &lt;jonas.danielsson AT axis.com&gt;)
+ <li>umount: do not complain several times about the same mountpoint
+ <li>umount: do not try to free loop device or erase mtab if remounted ro
+ <li>umount: instead of non-standard -D, use -d with opposite meaning. Closes bug 1604
+ <li>unlzma: shrink by Pascal Bellard &lt;pascal.bellard AT ads-lu.com&gt;
+ <li>unzip: do not try to read entire compressed stream at once (it can be huge)
+ <li>unzip: handle short reads correctly
+ <li>vi: many fixes
+ <li>zcip: don't chdir to root
+ <li>zcip: open ARP socket before openlog (else we can trash syslog socket)
+ </ul>
+ </p>
+
+ <li><b>21 March 2008 -- BusyBox old stable releases</b>
+ <p>
+ Bugfix-only releases for four past branches. Links to locations
+ for future hot patches are in parentheses.
+ <p>
+ <a href=http://busybox.net/downloads/busybox-1.9.2.tar.bz2>1.9.2</a>
+ (<a href=http://busybox.net/downloads/fixes-1.9.2/>patches</a>),
+ <a href=http://busybox.net/downloads/busybox-1.8.3.tar.bz2>1.8.3</a>
+ (<a href=http://busybox.net/downloads/fixes-1.8.3/>patches</a>),
+ <a href=http://busybox.net/downloads/busybox-1.7.5.tar.bz2>1.7.5</a>
+ (<a href=http://busybox.net/downloads/fixes-1.7.5/>patches</a>),
+ <a href=http://busybox.net/downloads/busybox-1.5.2.tar.bz2>1.5.2</a>
+ (<a href=http://busybox.net/downloads/fixes-1.5.2/>patches</a>).
+ <p>
+ <a href=http://busybox.net/fix.html>How to add a patch.</a>
+ <p>
+ <a href=http://busybox.net/~vda/HOWTO_bbox_with_uclibc.txt>How to build static busybox against uclibc</a>
+ <p>
+ The email address gpl@busybox.net is the recommended way to contact
+ the Software Freedom Law Center to report BusyBox license violations.
+ </p>
+
+
+ <li><b>Old News</b><p>
+ <a href="/oldnews.html">Click here to read older news</a>
+ </p>
+ </li>
+
+
+</ul>
+
+<!--#include file="footer.html" -->
+
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/oldnews.html b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/oldnews.html
new file mode 100644
index 0000000000..d6bd581f71
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/oldnews.html
@@ -0,0 +1,1939 @@
+<!--#include file="header.html" -->
+
+
+<ul>
+ <li><b>12 February 2008 -- BusyBox 1.9.1 (stable)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.9.1.tar.bz2>BusyBox 1.9.1</a>.
+ (<a href=http://busybox.net/cgi-bin/viewcvs.cgi/branches/busybox_1_9_stable/>svn</a>,
+ <a href=http://busybox.net/downloads/fixes-1.9.1/>patches</a>,
+ <a href=http://busybox.net/fix.html>how to add a patch</a>)</p>
+
+ <p>This is a bugfix-only release, with fixes to fsck,
+ iproute, mdev, mkswap, msh, nameif, stty, test, zcip.</p>
+ <p>hush has `command` expansion re-enabled for NOMMU, although it is
+ inherently unsafe (by virtue of NOMMU's use of vfork instead of fork).
+ The plan is to make this less likely to bite people in future versions.</p>
+ </li>
+
+ <li><b>24 December 2007 -- BusyBox 1.9.0 (unstable)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.9.0.tar.bz2>BusyBox 1.9.0</a>.
+ (<a href=http://busybox.net/cgi-bin/viewcvs.cgi/branches/busybox_1_9_stable/>svn</a>,
+ <a href=http://busybox.net/downloads/fixes-1.9.0/>patches</a>,
+ <a href=http://busybox.net/fix.html>how to add a patch</a>)</p>
+
+ <p>Sizes of busybox-1.8.2 and busybox-1.9.0 (with almost full config, static uclibc build):<pre>
+ text data bss dec hex filename
+ 792796 978 9724 803498 c42aa busybox-1.8.2
+ 783803 683 7508 791994 c15ba busybox-1.9.0
+</pre>
+ <p>Top 10 stack users:<pre>
+busybox-1.8.2: busybox-1.9.0:
+input_tab 10428 echo_dg 4116
+umount_main 8252 bb_full_fd_action 4112
+rtnl_talk 8240 discard_dg 4096
+xrtnl_dump_filter 8240 echo_stream 4096
+sendMTFValues 5316 discard_stream 4096
+mainSort 4700 find_list_entry2 4096
+mkfs_minix_main 4288 readlink_main 4096
+grave 4260 ipaddr_list_or_flush 3900
+unix_do_one 4156 iproute_list_or_flush 3680
+parse_prompt 4132 insmod_main 3152
+</pre>
+
+ <p>lash is deleted from this release. hush can be configured down to almost
+ the same size, but it is significantly less buggy. It even works
+ on NOMMU machines (interactive mode and backticks are not working on NOMMU,
+ though). "lash" applet is still available, but it runs hush.
+
+ <p>init has some changes in this release, please report if it causes
+ problems for you.
+
+ <p>Changes since previous release:
+ <ul>
+ <li>Build system improvements
+ <li>Testsuite additions
+ <li>Stack size reductions, code size reductions, data/bss reductions
+ <li>An option to prefer IPv4 address if host has both
+ <li>New applets: hd, sestatus
+ <li>Removed applets: lash
+ <li>hush: fixed a few bugs, wired up echo and test to be builtins
+ <li>init: simplify forking of children
+ <li>getty: special handling of '#' and '@' is removed
+ <li>[su]login: sanitize environment if called by non-root
+ <li>udhcpc: support "bad" servers which send oversized packets
+ (Cristian Ionescu-Idbohrn &lt;cristian.ionescu-idbohrn at axis.com&gt;)
+ <li>udhcpc: -O option allows to specify which options to ask for
+ (Stefan Hellermann &lt;stefan at the2masters.de&gt;)
+ <li>udhcpc: optionally check whether given IP is really free (by ARP ping)
+ (Jonas Danielsson &lt;jonas.danielsson at axis.com&gt;)
+ <li>vi: now handles files with unlimited line length
+ <li>vi: speedup for huge line lengths
+ <li>vi: Del key works
+ <li>sed: support GNUism '\t'
+ <li>cp/mv/install: optionally use bigger buffer for bulk copying
+ <li>line editing: don't eat stack like crazy
+ <li>passwd: follows symlinked /etc/passwd
+ <li>renice: accepts priority with +N too
+ <li>netstat: wide output mode
+ <li>nameif: extended matching (Nico Erfurth &lt;masta at perlgolf.de&gt;)
+ <li>test: become NOFORK applet
+ <li>find: -iname (Alexander Griesser &lt;alexander.griesser at lkh-vil.or.at&gt;)
+ <li>df: -i option (show inode info) (Pascal Bellard &lt;pascal.bellard at ads-lu.com&gt;)
+ <li>hexdump: -R option (Pascal Bellard &lt;pascal.bellard at ads-lu.com&gt;)
+ </ul>
+ </p>
+
+ <li><b>23 November 2007 -- BusyBox 1.8.2 (stable), BusyBox 1.7.4 (stable)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.8.2.tar.bz2>BusyBox 1.8.2</a>.
+ (<a href=http://busybox.net/cgi-bin/viewcvs.cgi/branches/busybox_1_8_stable/>svn</a>,
+ <a href=http://busybox.net/downloads/fixes-1.8.2/>patches</a>,
+ <a href=http://busybox.net/fix.html>how to add a patch</a>)</p>
+ <p><a href=http://busybox.net/downloads/busybox-1.7.4.tar.bz2>BusyBox 1.7.4</a>.
+ (<a href=http://busybox.net/cgi-bin/viewcvs.cgi/branches/busybox_1_7_stable/>svn</a>,
+ <a href=http://busybox.net/downloads/fixes-1.7.4/>patches</a>,
+ <a href=http://busybox.net/fix.html>how to add a patch</a>)</p>
+
+ <p>These are bugfix-only releases.
+ 1.8.2 contains fixes for inetd, lash, tar, tr, and build system.
+ 1.7.4 contains a fix for inetd.</p>
+ </li>
+
+ <li><b>9 November 2007 -- BusyBox 1.8.1 (stable)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.8.1.tar.bz2>BusyBox 1.8.1</a>.
+ (<a href=http://busybox.net/cgi-bin/viewcvs.cgi/branches/busybox_1_8_stable/>svn</a>,
+ <a href=http://busybox.net/downloads/fixes-1.8.1/>patches</a>,
+ <a href=http://busybox.net/fix.html>how to add a patch</a>)</p>
+
+ <p>This is a bugfix-only release, with fixes to login (PAM), modprobe, syslogd, telnetd, unzip.</p>
+ </li>
+
+ <li><b>4 November 2007 -- BusyBox 1.8.0 (unstable)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.8.0.tar.bz2>BusyBox 1.8.0</a>.
+ (<a href=http://busybox.net/cgi-bin/viewcvs.cgi/branches/busybox_1_8_stable/>svn</a>,
+ <a href=http://busybox.net/downloads/fixes-1.8.0/>patches</a>,
+ <a href=http://busybox.net/fix.html>how to add a patch</a>)</p>
+
+ <p>Note: this is probably the very last release with lash. It will be dropped. Please migrate to hush.
+
+ <p>Applets which had many changes since 1.7.x:
+ <p>httpd:
+ <ul>
+ <li>does not clear environment, CGIs will see all environment variables which were set for httpd
+ <li>fix bug where we were trying to read more POSTDATA than content-length
+ <li>fix trivial bug (spotted by Alex Landau)
+ <li>optional support for partial downloads
+ <li>simplified CGI i/o loop (now it looks good to me)
+ <li>small auth and IPv6 fixes (Kim B. Heino &lt;Kim.Heino at bluegiga.com>)
+ <li>support for proxying connection to other http server (by Alex Landau &lt;landau_alex at yahoo.com>)
+ </ul>
+
+ <p>top:
+ <ul>
+ <li>TOPMEM feature - 's(how sizes)' command
+ <li>don't wait before final bailout (try top -b -n1)
+ <li>fix for command line wrapping
+ </ul>
+
+ <p>Build system improvements: libbusybox mode restored (it was lost in transition to new makefiles).
+
+ <p>Code and data size in comparison with 1.7.3:<pre>
+Equivalent .config, i386 uclibc static builds:
+ text data bss dec hex filename
+ 768123 1055 10768 779946 be6aa busybox-1.7.3/busybox
+ 759693 974 9420 770087 bc027 busybox-1.8.0/busybox</pre>
+
+ <p>New applets:
+ <ul>
+ <li>microcom: new applet by Vladimir Dronnikov &lt;dronnikov at gmail.ru&gt;
+ <li>kbd_mode: new applet by Loic Grenie &lt;loic.grenie at gmail.com&gt;
+ <li>bzip2: port bzip2 1.0.4 to busybox, 9 kb of code
+ <li>pgrep, pkill: new applets by Loic Grenie &lt;loic.grenie at gmail.com&gt;
+ <li>setsebool: new applet (Yuichi Nakamura &lt;ynakam at hitachisoft.jp&gt;)
+ </ul>
+
+ <p>Other changes since previous release (abridged):
+ <ul>
+ <li>cp: -r and -R imply -d (coreutils compat)
+ <li>cp: detect and prevent infinite recursion
+ <li>cp: make it a bit closer to POSIX, but still refuse to open and overwrite symbolic link
+ <li>hdparm: reduce possibility of numeric overflow in -T
+ <li>hdparm: simplify timing measurement
+ <li>wget: -O FILE is allowed to overwrite existing file (compat)
+ <li>wget: allow dots in header field names
+ <li>telnetd: add -K option to close sessions as soon as child exits
+ <li>telnetd: don't SIGKILL child when closing the session, kernel will send SIGHUP for us
+ <li>ed: large cleanup, add line editing
+ <li>hush: feeble attempt at making it more NOMMU-friendly
+ <li>hush: fix glob()
+ <li>hush: stop doing manual accounting of open fd's, kernel can do it for us
+ <li>adduser: implement -S and fix uid selection
+ <li>ash: fix prompt expansion (Natanael Copa &lt;natanael.copa at gmail.com&gt;)
+ <li>ash: revert "cat | jobs" fix, it causes more problems than good
+ <li>find: fix -xdev behavior in the presence of two or more nested mount points
+ <li>grep: fix grep -F -e str1 -e str2 (was matching str2 only)
+ <li>grep: optimization: stop on first -e match
+ <li>gunzip: support concatenated gz files
+ <li>inetd: fix bug 1562 "inetd does not set argv[0] properly" (fix by Ilya Panfilov)
+ <li>install: 'support' (by ignoring) -v and -b
+ <li>install: fix bug in "install -c file dir" (tried to copy dir into dir too)
+ <li>ip: tunnel parameter parsing fix by Jean Wolter &lt;jw5 at os.inf.tu-dresden.de&gt;
+ <li>isrv: use monotonic_sec
+ <li>less: make 'f' key page forward
+ <li>libiproute: add missing break statements
+ <li>load_policy: update (Yuichi Nakamura &lt;ynakam at hitachisoft.jp&gt;)
+ <li>logger: fix a problem of losing all argv except first
+ <li>login: do reject wrong passwords with PAM auth
+ <li>losetup: support -f (Loic Grenie &lt;loic.grenie at gmail.com&gt;)
+ <li>fdisk: make fdisk compile on libc without llseek64
+ <li>libbb: by popular request allow PATH to be customized at build time
+ <li>mkswap: selinux support by KaiGai Kohei &lt;kaigai at ak.jp.nec.com&gt;
+ <li>mount: allow (and ignore) -i
+ <li>mount: ignore NFS bg option on NOMMU machines
+ <li>mount: mount helpers support (by Vladimir Dronnikov &lt;dronnikov at gmail.ru&gt;)
+ <li>passwd: handle Ctrl-C, restore termios on Ctrl-C
+ <li>passwd: SELinux support by KaiGai Kohei &lt;kaigai at ak.jp.nec.com&gt;
+ <li>ping: make -I ethN work too (-I addr already worked)
+ <li>ps: fix RSS parsing (rss field in /proc/PID/stat is in pages, not bytes)
+ <li>read_line_input: fix it to not do any fancy editing if echoing is disabled
+ <li>run_parts: make it sort executables by name (required by API)
+ <li>runsv: do not use clock_gettime if !MONOTONIC_CLOCK
+ <li>runsvdir: fix "linear wait time" bug
+ <li>sulogin: remove alarm handling, it is redundant there
+ <li>svlogd: compat: svlogd -tt should timestamp stderr too
+ <li>syslogd: bail out if you see null read from Unix socket
+ <li>syslogd: do not need to poll(), we can just block in read()
+ <li>tail: work correctly on /proc files (Kazuo TAKADA &lt;kztakada at sm.sony.co.jp&gt;)
+ <li>tar + gzip/bzip2/etc: support NOMMU machines (by Alex Landau &lt;landau_alex at yahoo.com&gt;)
+ <li>tar: strip leading '/' BEFORE memorizing hardlink's name
+ <li>tftp: fix infinite retry bug
+ <li>umount: support (by ignoring) -i; style fixes
+ <li>unzip: fix endianness bugs
+ <li>vi: don't wait 50 ms before reading ESC sequences
+ <li>watchdog: allow millisecond spec (-t 250ms)
+ <li>zcip: fix unaligned trap on ARM
+ </ul>
+ </p>
+
+ </li>
+
+ <li><b>4 November 2007 -- BusyBox 1.7.3 (stable)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.7.3.tar.bz2>BusyBox 1.7.3</a>.
+ (<a href=http://busybox.net/cgi-bin/viewcvs.cgi/branches/busybox_1_7_stable/>svn</a>,
+ <a href=http://busybox.net/downloads/fixes-1.7.3/>patches</a>,
+ <a href=http://busybox.net/fix.html>how to add a patch</a>)</p>
+
+ <p>This is a bugfix-only release, with fixes to ash, httpd, inetd, iptun, logger, login, tail.</p>
+ </li>
+
+ <li><b>30 September 2007 -- BusyBox 1.7.2 (stable)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.7.2.tar.bz2>BusyBox 1.7.2</a>.
+ (<a href=http://busybox.net/cgi-bin/viewcvs.cgi/branches/busybox_1_7_stable/>svn</a>,
+ <a href=http://busybox.net/downloads/fixes-1.7.2/>patches</a>,
+ <a href=http://busybox.net/fix.html>how to add a patch</a>)</p>
+
+ <p>This is a bugfix-only release, with fixes to install, find, login, httpd, runsvdir, chcon, setfiles, fdisk and line editing.</p>
+ </li>
+
+ <li><b>16 September 2007 -- BusyBox 1.7.1 (stable)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.7.1.tar.bz2>BusyBox 1.7.1</a>.
+ (<a href=http://busybox.net/cgi-bin/viewcvs.cgi/branches/busybox_1_7_stable/>svn</a>,
+ <a href=http://busybox.net/downloads/fixes-1.7.1/>patches</a>,
+ <a href=http://busybox.net/fix.html>how to add a patch</a>)</p>
+
+ <p>This is a bugfix-only release, with fixes to cp, runsv, tar, busybox --install and build system.</p>
+ </li>
+
+ <li><b>24 August 2007 -- BusyBox 1.7.0 (unstable)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.7.0.tar.bz2>BusyBox 1.7.0</a>.
+ (<a href=http://busybox.net/cgi-bin/viewcvs.cgi/branches/busybox_1_7_stable/>svn</a>,
+ <a href=http://busybox.net/downloads/fixes-1.7.0/>patches</a>,
+ <a href=http://busybox.net/fix.html>how to add a patch</a>)</p>
+
+ <p>Applets which had many changes since 1.6.x:
+ <p>httpd:
+ <ul>
+ <li>works in standalone mode on NOMMU machines now (partly by Alex Landau &lt;landau_alex at yahoo.com&gt;)
+ <li>indexer example is rewritten in C
+ <li>optional support for error pages (by Pierre Metras &lt;genepi at sympatico.ca&gt;)
+ <li>stop reading headers using 1-byte reads
+ <li>new option -v[v]: prints client addresses, HTTP codes returned, URLs
+ <li>extended -p PORT to -p [IP[v6]:]PORT
+ <li>sendfile support (by Pierre Metras &lt;genepi at sympatico.ca&gt;)
+ <li>add support for Status: CGI header
+ <li>fix CGI handling bug (we were closing wrong fd)
+ <li>CGI I/O loop still doesn't look 100% ok to me...
+ </ul>
+
+ <p>udhcp[cd]:
+ <ul>
+ <li>add -f "foreground" and -S "syslog" options
+ <li>fixed "ifupdown + udhcpc_without_pidfile_creation" bug
+ <li>new config option "Rewrite the lease file at every new acknowledge" (Mats Erik Andersson &lt;mats at blue2net.com&gt; (Blue2Net AB))
+ <li>consistently treat server_config.start/end IPs as host-order
+ <li>fix IP parsing for 64bit machines
+ <li>fix unsafe hton macro usage in read_opt()
+ <li>do not chdir to / when daemonizing
+ </ul>
+
+ <p>top, ps, killall, pidof:
+ <ul>
+ <li>simpler loadavg processing
+ <li>truncate usernames to 8 chars
+ <li>fix non-CONFIG_DESKTOP ps -ww (by rockeychu)
+ <li>improve /proc/PID/cmdinfo reading code
+ <li>use cmdline, not comm field (fixes problems with re-execed applets showing as processes with name "exe", and not being found by pidof/killall by applet name)
+ <li>reduce CPU usage in decimal conversion (optional) (corresponding speedup on kernel side is accepted in mainline Linux kernel, yay!)
+ <li>make percentile (0.1%) calculations configurable
+ <li>add config option and code for global CPU% display
+ <li>reorder columns, so that [P]PIDs are together and VSZ/%MEM are together - makes more sense
+ </ul>
+
+ <p>Build system improvements: doesn't link against libraries we don't need,
+ generates verbose link output and map file, allows for custom link
+ scripts (useful for removing extra padding, among other things).
+
+ <p>Code and data size in comparison with 1.6.1:<pre>
+Equivalent .config, i386 glibc dynamic builds:
+ text data bss dec hex filename
+ 672671 2768 16808 692247 a9017 busybox-1.6.1/busybox
+ 662948 2660 13528 679136 a5ce0 busybox-1.7.0/busybox
+ 662783 2631 13416 678830 a5bae busybox-1.7.0/busybox.customld
+
+Same .config built against static uclibc:
+ 765021 1059 11020 777100 bdb8c busybox-1.7.0/busybox_uc</pre>
+
+ <p>Code/data shrink done in applets: crond, hdparm, dd, cal, od, nc, expr, uuencode,
+ test, slattach, diff, ping, tr, syslogd, hwclock, zcip, find, pidof, ash, uudecode,
+ runit/*, in libbb.
+
+ <p>New applets:
+ <ul>
+ <li>pscan, expand, unexpand (from Tito &lt;farmatito at tiscali.it&gt;)
+ <li>setfiles, restorecon (by Yuichi Nakamura &lt;ynakam at hitachisoft.jp&gt;)
+ <li>chpasswd (by Alexander Shishkin &lt;virtuoso at slind.org&gt;)
+ <li>slattach, ttysize
+ </ul>
+
+ <p>Unfortunately, not much work is done on shells. This was mostly stalled
+ by lack of time (read: laziness) on my part to learn how to adapt existing
+ qemu-runnable image for a NOMMU architechture (available on qemu website)
+ for local testing of cross-compiled busybox on my machine.
+
+ <p>Other changes since previous release (abridged):
+ <ul>
+ <li>addgroup: disallow addgroup -g num user group; make -g 0 work (Tito &lt;farmatito at tiscali.it&gt;)
+ <li>adduser: close /etc/{passwd,shadow} before calling passwd etc. Spotted by Natanael Copa &lt;natanael.copa at gmail.com&gt;
+ <li>arping: -i should be -I, fixed
+ <li>ash: make "jobs | cat" work like in bash (was giving empty output)
+ <li>ash: recognize -l as --login equivalent; do not recognize +-login
+ <li>ash: fix buglet in DEBUG code (Nguyen Thai Ngoc Duy &lt;pclouds at gmail.com&gt;)
+ <li>ash: fix SEGV if type has zero parameters
+ <li>awk: fix -F 'regex' bug (miscounted fields if last field is empty)
+ <li>catv: catv without arguments was trying to use environ as argv (Alex Landau &lt;landau_alex at yahoo.com&gt;)
+ <li>catv: don't die on open error (emit warning)
+ <li>chown/chgrp: completely match coreutils 6.8 wrt symlink handling
+ <li>correct_password: do not print "no shadow passwd..." message
+ <li>crond: don't start sendmail with absolute path, don't report obsolete version (report true bbox version)
+ <li>dd: fix bug where we assume count=INT_MAX when count is unspecified
+ <li>devfsd: sanitization by Tito &lt;farmatito at tiscali.it&gt;
+ <li>echo: fix non-fancy echo
+ <li>fdisk: make it work with big disks (read: typical today's disks) even if CONFIG_LFS is unset
+ <li>find: -context support for SELinux (KaiGai Kohei &lt;kaigai at kaigai.gr.jp&gt;)
+ <li>find: add conditional support for -maxdepth and -regex, make -size match GNU find
+ <li>find: fix build failure on certain configs (found by Cristian Ionescu-Idbohrn &lt;cristian.ionescu-idbohrn at axis.com&gt;)
+ <li>fsck_minix: make it print bb version, not it's own (outdated/irrelevant) one
+ <li>grep: implement -m MAX_MATCHES, fix buglets with context printing
+ <li>grep: fix selection done by FEATURE_GREP_EGREP_ALIAS (Maxime Bizon &lt;mbizon at freebox.fr&gt; (Freebox))
+ <li>hush: add missing dependencies (Maxime Bizon &lt;mbizon at freebox.fr&gt; (Freebox))
+ <li>hush: fix read builtin to not read ahead past EOL and to not use insane amounts of stack
+ <li>ifconfig: make it work with ifaces with interface no. &gt; 255
+ <li>ifup/ifdown: make location of ifstate configurable
+ <li>ifupdown: make netmask parsing smaller and more strict (was accepting 255.0.255.0, 255.1234.0.0 etc...)
+ <li>install: fix -s (strip) option, fix install a b /a/link/to/dir
+ <li>libbb: consolidate ARRAY_SIZE macro (Walter Harms &lt;wharms at bfs.de&gt;)
+ <li>libbb: make /etc/network parsing configurable. -200 bytes when off
+ <li>libbb: nuke BB_GETOPT_ERROR, always die if there are mutually exclusive options
+ <li>libbb: xioctl and friends by Tito &lt;farmatito at tiscali.it&gt;
+ <li>login: optional support for PAM
+ <li>login: make /etc/nologin support configurable (-240 bytes)
+ <li>login: ask passwords even for wrong usernames
+ <li>md5_sha1_sum: fix mishandling when run as /bin/md5sum
+ <li>mdev: add support for firmware loading
+ <li>mdev: work even when CONFIG_SYSFS_DEPRECATED in kernel is off
+ <li>modprobe: add scanning of /lib/modules/`uname -r`/modules.symbols (by Yann E. MORIN &lt;yann.morin.1998 at anciens.enib.fr&gt;)
+ <li>more: fixes by Tristan Schmelcher &lt;tpkschme at engmail.uwaterloo.ca&gt;
+ <li>nc: make connecting to IPv4 from IPv6-enabled hosts easier (was requiring -s local_addr)
+ <li>passwd: fix bug "updating shadow even if user's record is in passwd"
+ <li>patch: fix -p -1 handling
+ <li>patch: fix bad line ending handling (Nguyen Thai Ngoc Duy &lt;pclouds at gmail.com&gt;)
+ <li>ping: display roundtrip times with 1/1000th of ms, not 1/10 ms precision.
+ <li>ping: fix incorrect handling of -I (Iouri Kharon &lt;bc-info at styx.cabel.net&gt;)
+ <li>ping: fix non-fancy ping6
+ <li>printenv: fix "printenv VAR1 VAR2" bug (spotted by Kalyanatejaswi Balabhadrapatruni &lt;kalyanatejaswi at yahoo.co.in&gt;)
+ <li>ps: fix -Z (by Yuichi Nakamura &lt;ynakam at hitachisoft.jp&gt;)
+ <li>rpm: add optional support for bz2 data. +50 bytes of code
+ <li>rpm: fix bogus "package is not installed" case
+ <li>sed: fix 'q' command handling (by Nguyen Thai Ngoc Duy &lt;pclouds at gmail.com&gt;)
+ <li>start_stop_daemon: NOMMU fixes by Alex Landau &lt;landau_alex at yahoo.com&gt;
+ <li>stat: fix option -Z SEGV
+ <li>strings: strings a b was processing a twice, fix that
+ <li>svlogd: fix timestamping, do not warn if config is missing
+ <li>syslogd, logread: get rid of head pointer, fix logread bug in the process
+ <li>syslogd: do not convert tabs to ^I, set syslog IPC buffer to mode 0644
+ <li>tar: improve OLDGNU compat, make old SUN compat configurable
+ <li>test: fix testing primary expressions like '"-u" = "-u"'
+ <li>uudecode: fix to base64 decode by Jorgen Cederlof &lt;jcz at google.com&gt;
+ <li>vi: multiple fixes by Natanael Copa &lt;natanael.copa at gmail.com&gt;
+ <li>wget: fix bug in base64 encoding (bug 1404). +10 bytes
+ <li>wget: lift 256 chars limitation on terminal width
+ <li>wget, zcip: use monotonic_sec instead of gettimeofday
+ </ul>
+ </p>
+ </li>
+
+ <li><b>30 June 2007 -- BusyBox 1.6.1 (stable)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.6.1.tar.bz2>BusyBox 1.6.1</a>.
+ (<a href=http://busybox.net/cgi-bin/viewcvs.cgi/branches/busybox_1_6_stable/>svn</a>,
+ <a href=http://busybox.net/downloads/fixes-1.6.1/>patches</a>,
+ <a href=http://busybox.net/fix.html>how to add a patch</a>)</p>
+
+ <p>This is a bugfix-only release, with fixes to echo, hush, and wget.</p>
+ </li>
+
+ <li><b>1 June 2007 -- BusyBox 1.6.0 (unstable)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.6.0.tar.bz2>BusyBox 1.6.0</a>.
+ (<a href=http://busybox.net/cgi-bin/viewcvs.cgi/branches/busybox_1_6_stable/>svn</a>,
+ <a href=http://busybox.net/downloads/fixes-1.6.0/>patches</a>,
+ <a href=http://busybox.net/fix.html>how to add a patch</a>)</p>
+
+ <p>Since this is a x.x.0 release, it probably does not deserve "stable"
+ label. Please help making 1.6.1 stable by testing 1.6.0.</p>
+ <p>Note that hush shell had many changes and (hopefully) is much improved now,
+ but there is a possibility that it regressed in some obscure cases. Please
+ report any such cases.</p>
+ <p>lash users please note: lash is going to be deprecated in busybox 1.7.0
+ and removed in the more distant future. Please migrate to hush.</p>
+ <p><a href=http://busybox.net/~vda/mem_usage-1.6.0.txt>Memory usage has decreased, but we can do better still</a></p>
+ <p>Other changes since previous release:
+ <ul>
+<li>NOFORK: audit small applets and mark some of them as NOFORK. Put big scary warnings in relevant places
+<li>NOFORK: factor out NOFORK/NOEXEC code from find. Use NOFORK/NOEXEC in find and xargs
+<li>NOFORK: remove potential xmalloc from NOFORK path in bb_full_fd_action
+<li>NOMMU: random fixes; compressed --help now works for NOMMU
+<li>SELinux: load_policy applet
+<li>[u]mount: extend -t option (Roy Marples &lt;uberlord at gentoo.org&gt;)
+<li>addgroup: clean up, fix adding users to existing groups and make it optional (Tito)
+<li>adduser: don't bomb out if shadow password file doesn't exist (from Tito &lt;farmatito at tiscali.it&gt;)
+<li>applet.c: do not even try to read config if run by real root; fix suid config handling
+<li>ash: fix infinite loop on exit if tty is not there anymore
+<li>ash: fix kill -l (by Mats Erik Andersson &lt;mats.andersson64 at comhem.se&gt;)
+<li>ash: implement type -p, costs less than 10 bytes (patch by Mats Erik Andersson &lt;mats.andersson64 at comhem.se&gt;)
+<li>awk: don't segfault on printf(%*s). Closes bug 1337
+<li>awk: guard against empty environment
+<li>awk: some 'lineno' vars were shorts, made them ints (code got smaller)
+<li>cat: stop using stdio.h opens
+<li>config system: clarify PREFER_APPLETS/SH_STANDALONE effects in help text
+<li>cryptpw: new applet (by Thomas Lundquist &lt;lists at zelow.no&gt;)
+<li>cttyhack: new applet
+<li>dd: NOEXEC fix; fix skip= parse error (spotted by Dirk Clemens &lt;develop at cle-mens.de&gt;)
+<li>deluser: add optional support for removing users from groups (by Tito &lt;farmatito at tiscali.it&gt;)
+<li>diff: fix SEGV (NULL deref) in diff -N
+<li>diff: fix segfault on empty dirs (Peter Korsgaard &lt;peter.korsgaard at barco.com&gt;)
+<li>dnsd: fix several buglets, make smaller; openlog(), so that applet's name is logged
+<li>dpkg: run_package_script() returns 0 if all ok and non-zero if failure. The result code was checked incorrectly in two places. (from Kim B. Heino &lt;Kim.Heino at bluegiga.com&gt;)
+<li>dpkg: use bitfields which are a bit closer to typical short/char. Code size -800 bytes
+<li>dumpleases: getopt32()-ization (from Mats Erik Andersson &lt;mats.andersson64 at comhem.se&gt;)
+<li>e2fsprogs: stop using statics in chattr. Minor code shrinkage (-130 bytes)
+<li>ether-wake: close bug 1317. Reorder fuctions to avoid forward refs while at it
+<li>ether-wake: save a few more bytes of code
+<li>find: -group, -depth (Natanael Copa &lt;natanael.copa at gmail.com&gt;)
+<li>find: add support for -delete, -path (by Natanael Copa)
+<li>find: fix -prune. Add big comment about it
+<li>find: improve usage text (Natanael Copa &lt;natanael.copa at gmail.com&gt;)
+<li>find: missed 'static' on const data; size and prune were mixed up; use index_in_str_array
+<li>find: un-DESKTOPize (Kai Schwenzfeier &lt;niteblade at gmx.net&gt;)
+<li>find_root_device: teach to deal with /dev/ subdirs (by Kirill K. Smirnov &lt;lich at math.spbu.ru&gt;)
+<li>find_root_device: use lstat - don't follow links
+<li>getopt32: fix llist_t options ordering. llist_rev is now unused
+<li>getopt: use getopt32 for option parsing - inspired by patch by Mats Erik Andersson &lt;mats.andersson64 at comhem.se&gt;
+<li>hdparm: fix multisector mode setting (from Toni Mirabete &lt;amirabete at catix.cat&gt;)
+<li>hdparm: make -T -t code smaller (-194 bytes), and output prettier
+<li>ifupdown: make it possible to use DHCP clients different from udhcp
+<li>ifupdown: reread state file before rewriting it. Fixes "ifup started another ifup" state corruption bug. Patch by Natanael Copa &lt;natanael.copa at gmail.com&gt;
+<li>ifupdown: small optimization (avoid doing useless work if we are not going to update state file)
+<li>ip: fix compilation if FEATURE_TR_CLASSES is off
+<li>ip: mv ip*_main into ip.c; use a dispatcher to save on needless duplication. Saves a minor 12b
+<li>ip: rewrite the ip applet to be less bloaty. Convert to index_in_(sub)str_array()
+<li>ip: set the scope properly. Thanks to Jean Wolter
+<li>iplink: shrink iplink; sanitize libiproute a bit (-916 bytes)
+<li>iproute: shrink a bit (-200 bytes)
+<li>kill: know much more signals; make code smaller; use common code for kill applet and ash kill builtin
+<li>klogd: remove dependency on syslogd
+<li>lash: "forking" applets are actually can be treated the same way as "non-forked". Also save a bit of space on trailing NULL array elements.
+<li>lash: fix kill buglet (didn't properly recognize ESRCH)
+<li>lash: make -c work; crush buffer overrun and free of non-malloced ptr (from Mats Erik Andersson &lt;mats.andersson64 at comhem.se&gt;)
+<li>lash: recognize and use NOFORK applets
+<li>less: fix case when regex search finds nothing; fix very obscure memory corruption bug; fix less &lt;HUGEFILE + [End] busy loop
+<li>libbb: add xsendto, xunlink, xpipe
+<li>libbb: fix segfault in reset_ino_dev_hashtable() when *hashtable was NULL
+<li>libbb: make pidfile writing configurable
+<li>libbb: make xsocket die with address family printed (if VERBOSE_RESOLUTION_ERRORS=y)
+<li>libbb: rework NOMMU helper API so that it makes more sense and easier to use
+<li>libiproute: audit callgraph, shortcut error paths into die() functions
+<li>lineedit: do not try to open NULL history file
+<li>lineedit: nuke two unused variables and code which sets them
+<li>login: remove setpgrp call (makes it work from shell prompt again); sanitize stdio descriptors (we are suid, need to be careful!)
+<li>login: shrink login and set_environment by ~100 bytes
+<li>mount: fix incorrect usage of strtok (inadvertently used NULL sometimes)
+<li>mount: fix mounting of symlinks (mount from util-linux allows that)
+<li>msh: data/bss reduction (more than 9k of it); fix "underscore bug" (a_b=1111 didn't work); fix obscure case with backticks and closed fd 1
+<li>nc: port nc 1.10 to busybox
+<li>netstat: fix for bogus state value for raw sockets
+<li>netstat: introduce -W: wide, ipv6-friendly output; shrink by ~500 bytes
+<li>nmeter: should die if stdout doesn't like him anymore
+<li>patch: do not try to delete same file twice
+<li>ping: fix wrong sign extension of packet id (bug 1373)
+<li>ps: add -o tty and -o rss support; make a bit smaller; work around libc bug: printf("%.*s\n", MAX_INT, buffer)
+<li>run_parts: rewrite
+<li>run_parts: do not check path portion of a name for "bad chars". Needed for ifupdown. Patch by Gabriel L. Somlo &lt;somlo at cmu.edu&gt;
+<li>sed: fix escaped newlines in -f
+<li>split: new applet
+<li>stat: remove superfluous bss user (flags) and manually unswitch some areas
+<li>stty: fix option parsing bug (spotted by Sascha Hauer &lt;s.hauer at pengutronix.de&gt;)
+<li>svlogd: fix 'SEGV on uninitialized data' and make it honor TERM
+<li>tail: fix SEGV on "tail -N"
+<li>ipsvd: tcpsvd,udpsvd are new applets, GPL-ed 'clones' of Dan Bernstein's tcpserver. Author: Gerrit Pape &lt;pape at smarden.org&gt;, http://smarden.sunsite.dk/ipsvd/
+<li>test: close bug 1371; plug a memory leak; code size reduction
+<li>tftp: code diet, and I think retransmits were broken
+<li>tr: fix bug where we did not reject invalid classes like '[[:alpha'. debloat while at it
+<li>udhcp: MAC_BCAST_ADDR and blank_chaddr are in fact constant, move to rodata; use pipe instead of socketpair
+<li>udhcp[cd]: stop using atexit magic fir pidfile removal; stop deleting our own pidfile if we daemonize
+<li>xargs: shrink code, ~80 bytes; simplify word list management
+<li>zcip: make it work on NOMMU (+ improve NOMMU support machinery)
+ </ul>
+ </p>
+ </li>
+
+ <li><b>20 May 2007 -- BusyBox 1.5.1 (stable)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.5.1.tar.bz2>BusyBox 1.5.1</a>.
+ (<a href=http://busybox.net/downloads/fixes-1.5.1/>patches</a>,
+ <a href=http://busybox.net/fix.html>how to add a patch</a>)</p>
+
+ <p>This is a bugfix-only release, with fixes to hdparm, hush, ifupdown, ps
+ and sed.</p>
+ </li>
+
+ <li><b>23 March 2007 -- BusyBox 1.5.0 (unstable)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.5.0.tar.bz2>BusyBox 1.5.0</a>.
+ (<a href=http://busybox.net/downloads/fixes-1.5.0/>patches</a>,
+ <a href=http://busybox.net/fix.html>how to add a patch</a>)</p>
+
+ <p>Since this is a x.x.0 release, it probably does not deserve "stable"
+ label. Please help making 1.5.1 stable by testing 1.5.0.</p>
+ <p>Notable changes since previous release:
+ <ul>
+ <li>find: added support for -user, -not, fixed -mtime, -mmin, -perm
+ <li>[de]archivers: merge common logic into one module
+ <li>ping[6]: unified code for both
+ <li>less: regex search improved
+ <li>ash: more readable code, testsuite added
+ <li>sed: several very obscure bugs fixed
+ <li>chown: -H, -L, -P support (required by POSIX)
+ <li>tar: handle (broken) checksums a-la Sun; tar restores mode again
+ <li>grep: implement -w, "implement" -a and -I by ignoring them
+ <li>cp: more sane behavior when overwriting existing files
+ <li>init: stop doing silly things with the console (-400 bytes)
+ <li>httpd: make httpd usable for NOMMU CPUs; fix POSTDATA handling bugs
+ <li>httpd: run interpreter for configured file extensions in any dir,
+ not only in /cgi-bin/
+ <li>chrt: new applet
+ <li>SELinux: SELinux-related code and -Z option added to several applets,
+ new SELinux-specific applets: chcon, runcon.
+ <li>Build system: produces link map, uses -Wwrite-strings to catch
+ improper usage of string constants.
+ <li>Data and bss section usage audited and reduced - should help NOMMU
+ targets.
+ <li>Applets with bug fixes: gunzip, vi, syslogd, dpkg, ls, adjtimex, resize,
+ sv, printf, diff, awk, sort, dpkg, diff, tftp
+ <li>Applets with usability improvements: swapon, more, ifup/ifdown, hwclock,
+ udhcpd, start_stop_daemon, cmp
+ <li>Applets with code cleaned up: telnet, fdisk, fsck_minix, mkfs_minix,
+ syslogd, swapon, runsv, svlogd, klogd
+ </ul>
+ </p>
+ </li>
+
+ <li><b>18 March 2007 -- BusyBox 1.4.2 (stable)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.4.2.tar.bz2>BusyBox 1.4.2</a>.
+ </p>
+
+ <p>This release includes only trivial fixes accumulated since 1.4.1.
+ </p>
+ </li>
+
+ <li><b>25 January 2007 -- BusyBox 1.4.1 (stable)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.4.1.tar.bz2>BusyBox 1.4.1</a>.
+ (<a href=http://busybox.net/downloads/fixes-1.4.1/>patches</a>)</p>
+
+ <p>This release includes only trivial fixes accumulated since 1.4.0.
+ </p>
+ </li>
+
+ <li><b>20 January 2007 -- BusyBox 1.4.0 (stable)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.4.0.tar.bz2>BusyBox 1.4.0</a>.
+ (<a href=http://busybox.net/downloads/fixes-1.4.0/>patches</a>)</p>
+
+ <p>Since this is a x.x.0 release, it probably is a bit less "stable"
+ than usual.</p>
+ <p>Changes since previous release:
+ <ul>
+ <li>e2fsprogs are mostly removed from busybox. Some smaller parts remain,
+ the rest of it sits disabled in e2fsprogs/old_e2fsprogs/*, because
+ it's too bloated. Really. I'm afraid it's about the only way we can
+ ever get e2fsprogs cleaned up.
+ <li>less: many improvements. Now can display binary files
+ (although I expect it to have trouble with displays where 8bit chars
+ don't have 1-to-1 char/glyph relationship). Regexp search is not buggy
+ anymore. Less does not read entire input up-front. Reads input
+ as it appears (yay!). Works rather nice as man pager. I recommend it
+ for general use now.
+ <li>IPv6: generic support is in place, many networking applets are
+ upgraded to be IPv6 capable. Probably some work remains, but it is
+ already much better than what we had previously.
+ <li>arp: new applet (thanks to Eric Spakman).
+ <li>fakeidentd: non-forking standalone server part was taking ~90%
+ of the applet. Factored it out (in fact, rewrote it).
+ <li>syslogd: mostly rewritten.
+ <li>decompress_unzip, gzip: sanitized a bit.
+ <li>sed: better hadling of NULs
+ <li>httpd: stop adding our own "Content-type:" to CGI output
+ <li>chown: user.grp works again.
+ <li>minor bugfixes to: passwd, date, tftp, start_stop_daemon, tar,
+ ps, ifupdown, time, su, stty, awk, ping[6], sort,...
+ </ul>
+ </p>
+ </li>
+
+ <li><b>20 January 2007 -- BusyBox 1.3.2 (stable)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.3.2.tar.bz2>BusyBox 1.3.2</a>.</p>
+
+ <p>This release includes only one trivial fix accumulated since 1.3.1
+ </p>
+ </li>
+
+ <li><b>27 December 2006 -- BusyBox 1.3.1 (stable)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.3.1.tar.bz2>BusyBox 1.3.1</a>.
+ (<a href=http://busybox.net/downloads/fixes-1.3.1/>patches</a>)</p>
+
+ <p>Closing 2006 with new release. It includes only trivial fixes accumulated since 1.3.0
+ </p>
+ </li>
+
+ <li><b>14 December 2006 -- BusyBox 1.3.0 (stable)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.3.0.tar.bz2>BusyBox 1.3.0</a>.
+ (<a href=http://busybox.net/downloads/fixes-1.3.0/>patches</a>)</p>
+
+ <p>This release has CONFIG_DESKTOP option which enables features
+ needed for busybox usage on desktop machine. For example, find, chmod
+ and chown get several less frequently used options, od is significantly
+ bigger but matches GNU coreutils, etc. Intended to eventually make
+ busybox a viable alternative for "standard" utilities for slightly
+ adventurous desktop users.
+ <p>Changes since previous release:
+ <ul>
+ <li>find: taking many more of standard options
+ <li>ps: POSIX-compliant -o implemented
+ <li>cp: added -s, -l
+ <li>grep: added -r, fixed -h
+ <li>watch: make it exec child like standard one does (was totally
+ incompatible)
+ <li>tar: fix limitations which were preventing bbox tar usage
+ on big directories: long names and linknames, pax headers
+ (Linux kernel tarballs have that). Fixed a number of obscure bugs.
+ Raised max file limit (now 64Gb). Security fixes (/../ attacks).
+ <li>httpd: added -i (inetd), -f (foreground), support for
+ directory indexer CGI (example is included), bugfixes.
+ <li>telnetd: fixed/improved IPv6 support, inetd+standalone support,
+ other fixes. Useful IPv6 stuff factored out into libbb.
+ <li>runit/*: new applets adapted from http://smarden.sunsite.dk/runit/
+ (these are my personal favorite small-and-beautiful toys)
+ <li>minor bugfixes to: login, dd, mount, umount, chmod, chown, ln, udhcp,
+ fdisk, ifconfig, sort, tee, mkswap, wget, insmod.
+ </ul>
+ <p>Note that GnuPG key used to sign this release is different.
+ 1.2.2.1 is also signed post-factum now. Sorry for the mess.
+ </p>
+ </li>
+
+ <li><b>29 October 2006 -- BusyBox 1.2.2.1 (fix)</b>
+ <p><a href=http://busybox.net/downloads/busybox-1.2.2.1.tar.bz2>BusyBox 1.2.2.1</a>.</p>
+
+ <p>Added compile-time warning that static linking against glibc
+ produces buggy executables.
+ </li>
+
+ <li><b>24 October 2006 -- BusyBox 1.2.2 (stable)</b>
+ <p>It's a bit overdue, but
+ <a href=http://busybox.net/downloads/busybox-1.2.2.tar.bz2>here is
+ BusyBox 1.2.2</a>.</p>
+
+ <p>This release has dozens of fixes backported from the ongoing development
+ branch. There are a couple of bugfixes to sed, two fixes to documentation
+ generation (BusyBox.html shouldn't have USE() macros in it anymore), fix
+ umount to report the right errno on failure and to umount block devices by
+ name with newer kernels, fix mount to handle symlinks properly, make mdev
+ delete device nodes when called for hotplug remove, fix a segfault
+ in traceroute, a minor portability fix to md5sum option parsing, a build
+ fix for httpd with old gccs, an options parsing tweak to hdparm, make test
+ fail gracefully when getgroups() returns -1, fix a race condition in
+ modprobe when two instances run at once (hotplug does this), make "tar xf
+ foo.tar dir/dir" extract all subdirectories, make our getty initialize the
+ terminal more like mingetty, an selinux build fix, an endianness fix in
+ ping6, fix for zcip defending addresses, clean up some global variables in
+ gzip to save memory, fix sulogin -tNNN, a help text tweak, several warning
+ fixes and build fixes, fixup dnsd a bit, and a partridge in a pear tree.</p>
+
+ <p>As <a href=http://lwn.net/Articles/202106/>Linux Weekly News noted</a>,
+ this is my (Rob's) last release of BusyBox. The new maintainer is Denis
+ Vlasenko, I'm off to do <a href=http://landley.net/code>other things</a>.
+ </p>
+ </li>
+
+ <li><b>29 September 2006 -- New license email address.</b>
+ <p>The email address gpl@busybox.net is now the recommended way to contact
+ the Software Freedom Law Center to report BusyBox license violations.</p>
+
+ <li><b>31 July 2006 -- BusyBox 1.2.1 (stable)</b>
+ <p>Since nobody seems to have objected too loudly over the weekend, I
+ might as well point you all at
+ <a href="http://busybox.net/downloads/busybox-1.2.1.tar.bz2">Busybox
+ 1.2.1</a>, a bugfix-only release with no new features.</p>
+
+ <p>It has three shell fixes (two to lash: going "var=value" without
+ saying "export" should now work, plus a missing null pointer check, and
+ one to ash when redirecting output to a file that fills up.) Fix three
+ embarassing thinkos in the new dmesg command. Two build tweaks
+ (dependencies for the compressed usage messages and running make in the
+ libbb subdirectory). One fix to tar so it can extract git-generated
+ tarballs (rather than barfing on the pax extensions). And a partridge
+ in a pear... Ahem.</p>
+
+ <p>But wait, there's more! A passwd changing fix so an empty
+ gecos field doesn't trigger a false objection that the new passwd contains
+ the gecos field. Make all our setuid() and setgid() calls check the return
+ value in case somebody's using per-process resource limits that prevent
+ a user from having too many processes (and thus prevent a process from
+ switching away from root, in which case the process will now _die_ rather
+ than continue with root privileges). A fix to adduser to make sure that
+ /etc/group gets updated. And a fix to modprobe to look for modules.conf
+ in the right place on 2.6 kernels.</p>
+
+ <li><b>30 June 2006 -- BusyBox 1.2.0</b>
+ <p>The -devel branch has been stabilized and the result is
+ <a href="http://busybox.net/downloads/busybox-1.2.0.tar.bz2">Busybox
+ 1.2.0</a>. Lots of stuff changed, I need to work up a decent changelog
+ over the weekend.</p>
+
+ <p>I'm still experimenting with how long is best for the development
+ cycle, and since we've got some largeish projects queued up I'm going to
+ try a longer one. Expect 1.3.0 in December. (Expect 1.2.1 any time
+ we fix enough bugs. :)</p>
+
+ <p>Update: Here are <a href="http://busybox.net/downloads/busybox-1.2.0.fixes.patch">the first few bug fixes</a> that will go into 1.2.1.</p>
+
+ <li><b>17 May 2006 -- BusyBox 1.1.3 (stable)</b>
+ <p><a href="http://busybox.net/downloads/busybox-1.1.3.tar.bz2">BusyBox
+ 1.1.3</a> is another bugfix release. It makes passwd use salt, fixes a
+ memory freeing bug in ls, fixes "build all sources at once" mode, makes
+ mount -a not abort on the first failure, fixes msh so ctrl-c doesn't kill
+ background processes, makes patch work with patch hunks that don't have a
+ timestamp, make less's text search a lot more robust (the old one could
+ segfault), and fixes readlink -f when built against uClibc.</p>
+
+ <p>Expect 1.2.0 sometime next month, which won't be a bugfix release.</p>
+
+ <li><b>10 April 2006 -- BusyBox 1.1.2 (stable)</b>
+ <p>You can now download <a href="http://busybox.net/downloads/busybox-1.1.2.tar.bz2">BusyBox 1.1.2</a>, a bug fix release consisting of 11 patches
+ backported from the development branch: Some build fixes, several fixes
+ for mount and nfsmount, a fix for insmod on big endian systems, a fix for
+ find -xdev, and a fix for comm. Check the file "changelog" in the tarball
+ for more info.</p>
+
+ <p>The next new development release (1.2.0) is slated for June. A 1.1.3
+ will be released before then if more bug fixes crop up. (The new plan is
+ to have a 1.x.0 new development release every 3 months, with 1.x.y stable
+ bugfix only releases based on that as appropriate.)</p>
+
+ <li><b>27 March 2006 -- Software Freedom Law Center representing BusyBox and uClibc</b>
+ <p>One issue Erik Andersen wanted to resolve when handing off BusyBox
+ maintainership to Rob Landley was license enforcement. BusyBox and
+ uClibc's existing license enforcement efforts (pro-bono representation
+ by Erik's father's law firm, and the
+ <a href="http://www.busybox.net/shame.html">Hall of Shame</a>), haven't
+ scaled to match the popularity of the projects. So we put our heads
+ together and did the obvious thing: ask Pamela Jones of
+ <a href="http://www.groklaw.net">Groklaw</a> for suggestions. She
+ referred us to the fine folks at softwarefreedom.org.</p>
+
+ <p>As a result, we're pleased to announce that the
+ <a href="http://www.softwarefreedom.org">Software Freedom Law Center</a>
+ has agreed to represent BusyBox and uClibc. We join a number of other
+ free and open source software projects (such as
+ <a href="http://lwn.net/Articles/141806/">X.org</a>,
+ <a href="http://lwn.net/Articles/135413/">Wine</a>, and
+ <a href="http://plone.org/foundation/newsitems/software-freedom-law-center-support/">Plone</a>
+ in being represented by a fairly cool bunch of lawyers, which is not a
+ phrase you get to use every day.</p>
+
+ <li><b>22 March 2006 -- BusyBox 1.1.1</b>
+ <p>The new maintainer is Rob Landley, and the new release is <a href="http://busybox.net/downloads/busybox-1.1.1.tar.bz2">BusyBox 1.1.1</a>. Expect a "what's new" document in a few days. (Also, Erik and I have have another announcement pending...)</p>
+ <p>Update: Rather than put out an endless stream of 1.1.1.x releases,
+ the various small fixes have been collected together into a
+ <a href="http://busybox.net/downloads/busybox-1.1.1.fixes.patch">patch</a>,
+ and new fixes will be appended to that as needed. Expect 1.1.2 around
+ June.</p>
+ </li>
+ <li><b>11 January 2006 -- 1.1.0 is out</b>
+ <p>The new stable release is
+ <a href="http://www.busybox.net/downloads/busybox-1.1.0.tar.bz2">BusyBox
+ 1.1.0</a>. It has a number of improvements, including several new applets.
+ (It also has <a href="http://www.busybox.net/lists/busybox/2006-January/017733.html">a few rough spots</a>,
+ but we're trying out a "release early, release often" strategy to see how
+ that works. Expect 1.1.1 sometime in March.)</p>
+
+ <li><b>31 October 2005 -- 1.1.0-pre1</b>
+ <p>The development branch of busybox is stable enough for wider testing, so
+ you can now
+ <a href="http://www.busybox.net/downloads/busybox-1.1.0-pre1.tar.bz2">download</a>,
+ the first prerelease of 1.1.0. This prerelease includes a lot of
+ <a href="http://www.busybox.net/downloads/BusyBox.html">new
+ functionality</a>: new applets, new features, and extensive rewrites of
+ several existing applets. This prerelease should be noticeably more
+ <a href="http://www.opengroup.org/onlinepubs/009695399/">standards
+ compliant</a> than earlier versions of busybox, although we're
+ still working out the <a href="http://bugs.busybox.net">bugs</a>.</p>
+
+ <li><b>16 August 2005 -- 1.01 is out</b>
+
+ <p>A new stable release (<a href="http://www.busybox.net/downloads/busybox-1.01.tar.bz2">BusyBox
+ 1.01</a>) is now available for download, containing over a hundred
+ <a href="http://www.busybox.net/lists/busybox/2005-August/015424.html">small
+ fixes</a> that have cropped up since the 1.00 release.</p>
+
+ <li><b>13 January 2005 -- Bug and Patch Tracking</b><p>
+
+ Bug reports sometimes get lost when posted to the mailing list. The
+ developers of BusyBox are busy people, and have only so much they can keep
+ in their brains at a time. In my case, I'm lucky if I can remember my own
+ name, much less a bug report posted last week... To prevent your bug report
+ from getting lost, if you find a bug in BusyBox, please use the
+ <a href="http://bugs.busybox.net/">shiny new Bug and Patch Tracking System</a>
+ to post all the gory details.
+
+ <p>
+
+ The same applies to patches... Regardless of whether your patch
+ is a bug fix or adds spiffy new features, please post your patch
+ to the Bug and Patch Tracking System to make certain it is
+ properly considered.
+
+
+ <p>
+ <li><b>13 October 2004 -- BusyBox 1.00 released</b><p>
+
+ When you take a careful look at nearly every embedded Linux device or
+ software distribution shipping today, you will find a copy of BusyBox.
+ With countless routers, set top boxes, wireless access points, PDAs, and
+ who knows what else, the future for Linux and BusyBox on embedded devices
+ is looking very bright.
+
+ <p>
+
+ It is therefore with great satisfaction that I declare each and every
+ device already shipping with BusyBox is now officially out of date.
+ The highly anticipated release of BusyBox 1.00 has arrived!
+
+ <p>
+
+ Over three years in development, BusyBox 1.00 represents a tremendous
+ improvement over the old 0.60.x stable series. Now featuring a Linux
+ KernelConf based configuration system (as used by the Linux kernel),
+ Linux 2.6 kernel support, many many new applets, and the development
+ work and testing of thousands of people from around the world.
+
+ <p>
+
+ If you are already using BusyBox, you are strongly encouraged to upgrade to
+ BusyBox 1.00. If you are considering developing an embedded Linux device
+ or software distribution, you may wish to investigate if using BusyBox is
+ right for your application. If you need help getting started using
+ BusyBox, if you wish to donate to help cover expenses, or if you find a bug
+ and need help reporting it, you are invited to visit the <a
+ href="FAQ.html">BusyBox FAQ</a>.
+
+ <p>
+
+ As usual you can <a href="downloads">download busybox here</a>.
+
+ <p>Have Fun!
+
+ <p>
+ <li><b>Old News</b><p>
+ <a href="/oldnews.html">Click here to read older news</a>
+
+
+ <li><b>16 August 2004 -- BusyBox 1.0.0-rc3 released</b><p>
+
+ Here goes release candidate 3...
+ <p>
+ The <a href="downloads/Changelog">changelog</a> has all the details.
+ And as usual you can <a href="downloads">download busybox here</a>.
+
+ <p>Have Fun!
+
+ <p>
+ <li><b>26 July 2004 -- BusyBox 1.0.0-rc2 released</b><p>
+
+ Here goes release candidate 2...
+ <p>
+ The <a href="downloads/Changelog">changelog</a> has all the details.
+ And as usual you can <a href="downloads">download busybox here</a>.
+
+ <p>Have Fun!
+
+ <p>
+ <li><b>20 July 2004 -- BusyBox 1.0.0-rc1 released</b><p>
+
+ Here goes release candidate 1... This fixes all (most?) of the problems
+ that have turned up since -pre10. In particular, loading and unloading of
+ kernel modules with 2.6.x kernels should be working much better.
+ <p>
+
+ I <b>really</b> want to get BusyBox 1.0.0 released soon and I see no real
+ reason why the 1.0.0 release shouldn't happen with things pretty much as
+ is. BusyBox is in good shape at the moment, and it works nicely for
+ everything that I'm doing with it. And from the reports I've been getting,
+ it works nicely for what most everyone else is doing with it as well.
+ There will eventually be a 1.0.1 anyway, so we might as well get on with
+ it. No, BusyBox is not perfect. No piece of software ever is. And while
+ there is still plenty that can be done to improve things, most of that work
+ is waiting till we can get a solid 1.0.0 release out the door....
+ <p>
+
+ Please do not bother to send in patches adding cool new features at this
+ time. Only bug-fix patches will be accepted. If you have submitted a
+ bug-fixing patch to the busybox mailing list and no one has emailed you
+ explaining why your patch was rejected, it is safe to say that your patch
+ has been lost or forgotten. That happens sometimes. Please re-submit your
+ bug-fixing patch to the BusyBox mailing list, and be sure to put "[PATCH]"
+ at the beginning of the email subject line!
+
+ <p>
+ The <a href="downloads/Changelog">changelog</a> has all the details.
+ And as usual you can <a href="downloads">download busybox here</a>.
+
+ <p>Have Fun!
+
+ <p>
+ On a less happy note, My 92 year old grandmother (my dad's mom) passed away
+ yesterday (June 19th). The funeral will be Thursday in a little town about
+ 2 hours south of my home. I've checked and there is absolutely no way I
+ could be back in time for the funeral if I attend <a
+ href="http://www.linuxsymposium.org/2004/">OLS</a> and give my presentation
+ as scheduled.
+ <p>
+ As such, it is with great reluctance and sadness that I have come
+ to the conclusion I will have to make my appologies and skip OLS
+ this year.
+ <p>
+
+
+ <p>
+ <li><b>13 April 2004 -- BusyBox 1.0.0-pre10 released</b><p>
+
+ Ok, I lied. It turns out that -pre9 will not be the final BusyBox
+ pre-release. With any luck however -pre10 will be, since I <b>really</b>
+ want to get BusyBox 1.0.0 released very soon. As usual, please do not
+ bother to send in patches adding cool new features at this time. Only
+ bug-fix patches will be accepted. It would also be <b>very</b> helpful if
+ people could continue to review the BusyBox documentation and submit
+ improvements.
+
+ <p>
+ The <a href="downloads/Changelog">changelog</a> has all the details.
+ And as usual you can <a href="downloads">download busybox here</a>.
+
+ <p>Have Fun!
+ <p>
+
+
+ <p>
+ <li><b>6 April 2004 -- BusyBox 1.0.0-pre9 released</b><p>
+
+ Here goes the final BusyBox pre-release... This is your last chance for
+ bug fixes. With luck this will be released as BusyBox 1.0.0 later this
+ week. Please do not bother to send in patches adding cool new features at
+ this time. Only bug-fix patches will be accepted. It would also be
+ <b>very</b> helpful if people could help review the BusyBox documentation
+ and submit improvements. I've spent a lot of time updating the
+ documentation to make it better match reality, but I could really use some
+ assistance in checking that the features supported by the various applets
+ match the features listed in the documentation.
+
+ <p>
+ I had hoped to get this released a month ago, but
+ <a href="http://codepoet.org/gallery/baby_peter/img_1796">
+ another release on 1 March 2004</a> has kept me busy...
+
+ <p>
+ The <a href="downloads/Changelog">changelog</a> has all the details.
+ And as usual you can <a href="downloads">download busybox here</a>.
+
+ <p>Have Fun!
+ <p>
+
+
+ <p>
+ <li><b>23 February 2004 -- BusyBox 1.0.0-pre8 released</b><p>
+
+ Here goes yet another BusyBox pre-release... Please do not bother to send
+ in patches supplying new features at this time. Only bug-fix patches will
+ be accepted. If you have a cool new feature you would like to see
+ supported, or if you have an amazing new applet you would like to submit,
+ please wait and submit such things later. We really want to get a release
+ out we can all be proud of. We are still aiming to finish off the -pre
+ series in February and move on to the final 1.0.0 release... So if you
+ spot any bugs, now would be an excellent time to send in a fix to the
+ busybox mailing list. It would also be <b>very</b> helpful if people could
+ help review the BusyBox documentation and submit improvements. It would be
+ especially helpful if people could check that the features supported by the
+ various applets match the features listed in the documentation.
+
+ <p>
+
+ The <a href="downloads/Changelog">changelog</a> has all the details.
+ And as usual you can <a href="downloads">download busybox here</a>.
+
+ <p>Have Fun!
+ <p>
+
+
+ <li><b>4 February 2004 -- BusyBox 1.0.0-pre7 released</b><p>
+
+ There was a bug in -pre6 that broke argument parsing for a
+ number of applets, since a variable was not being zeroed out
+ properly. This release is primarily intended to fix that one
+ problem. In addition, this release fixes several other
+ problems, including a rewrite by mjn3 of the code for parsing
+ the busybox.conf file used for suid handling, some shell updates
+ from vodz, and a scattering of other small fixes. We are still
+ aiming to finish off the -pre series in February and move on to
+ the final 1.0.0 release... If you see any problems, of have
+ suggestions to make, as always, please feel free to email the
+ busybox mailing list.
+
+ <p>
+
+ The <a href="downloads/Changelog">changelog</a> has all
+ the details. And as usual you can
+ <a href="downloads">download busybox here</a>.
+
+ <p>Have Fun!
+ <p>
+
+
+ <p>
+ <li><b>30 January 2004 -- BusyBox 1.0.0-pre6 released</b><p>
+
+ Here goes the next pre-release for the new BusyBox stable
+ series. This release adds a number of size optimizations,
+ updates udhcp, fixes up 2.6 modutils support, updates ash
+ and the shell command line editing, and the usual pile of
+ bug fixes both large and small. Things appear to be
+ settling down now, so with a bit of luck and some testing
+ perhaps we can finish off the -pre series in February and
+ move on to the final 1.0.0 release... If you see any
+ problems, of have suggestions to make, as always, please
+ feel free to email the busybox mailing list.
+
+ <p>
+
+ People who rely on the <a href= "downloads/snapshots/">daily BusyBox snapshots</a>
+ should be aware that snapshots of the old busybox 0.60.x
+ series are no longer available. Daily snapshots are now
+ only available for the BusyBox 1.0.0 series and now use
+ the naming scheme "busybox-&lt;date&gt;.tar.bz2". Please
+ adjust any build scripts using the old naming scheme accordingly.
+
+ <p>
+
+ The <a href="downloads/Changelog">changelog</a> has all
+ the details. And as usual you can
+ <a href="downloads">download busybox here</a>.
+
+ <p>Have Fun!
+ <p>
+
+
+ <p>
+ <li><b>23 December 2003 -- BusyBox 1.0.0-pre5 released</b><p>
+
+ Here goes the next pre-release for the new BusyBox stable
+ series. The most obvious thing in this release is a fix for
+ a terribly stupid bug in mount that prevented it from working
+ properly unless you specified the filesystem type. This
+ release also fixes a few compile problems, updates udhcp,
+ fixes a silly bug in fdisk, fixes ifup/ifdown to behave like
+ the Debian version, updates devfsd, updates the 2.6.x
+ modutils support, add a new 'rx' applet, removes the obsolete
+ 'loadacm' applet, fixes a few tar bugs, fixes a sed bug, and
+ a few other odd fixes.
+
+ <p>
+
+ If you see any problems, of have suggestions to make, as
+ always, please feel free to send an email to the busybox
+ mailing list.
+
+ <p>
+
+ The <a href="downloads/Changelog">changelog</a> has all
+ the details. And as usual you can
+ <a href="downloads">download busybox here</a>.
+
+ <p>Have Fun!
+ <p>
+
+
+
+ <li><b>10 December 2003 -- BusyBox 1.0.0-pre4 released</b><p>
+
+ Here goes the fourth pre-release for the new BusyBox stable
+ series. This release includes major rework to sed, lots of
+ rework on tar, a new tiny implementation of bunzip2, a new
+ devfsd applet, support for 2.6.x kernel modules, updates to
+ the ash shell, sha1sum and md5sum have been merged into a
+ common applet, the dpkg applets has been cleaned up, and tons
+ of random bugs have been fixed. Thanks everyone for all the
+ testing, bug reports, and patches! Once again, a big
+ thank-you goes to Glenn McGrath (bug1) for stepping in and
+ helping get patches merged!
+
+ <p>
+
+ And of course, if you are reading this, you might have noticed
+ the busybox website has been completely reworked. Hopefully
+ things are now somewhat easier to navigate... If you see any
+ problems, of have suggestions to make, as always, please feel
+ free to send an email to the busybox mailing list.
+
+ <p>
+
+ The <a href="downloads/Changelog">changelog</a> has all
+ the details. And as usual you can
+ <a href="downloads">download busybox here</a>.
+
+ <p>Have Fun!
+
+
+
+ <p>
+ <li><b>12 Sept 2003 -- BusyBox 1.0.0-pre3 released</b><p>
+
+ Here goes the third pre-release for the new BusyBox stable
+ series. The last prerelease has held up quite well under
+ testing, but a number of problems have turned up as the number
+ of people using it has increased. Thanks everyone for all
+ the testing, bug reports, and patches!
+
+ <p>
+
+ If you have submitted a patch or a bug report to the busybox
+ mailing list and no one has emailed you explaining why your
+ patch was rejected, it is safe to say that your patch has
+ somehow gotten lost or forgotten. That happens sometimes.
+ Please re-submit your patch or bug report to the BusyBox
+ mailing list!
+
+ <p>
+
+ The point of the "-preX" versions is to get a larger group of
+ people and vendors testing, so any problems that turn up can be
+ fixed prior to the final 1.0.0 release. The main feature
+ (besides additional testing) that is still still on the TODO
+ list before the final BusyBox 1.0.0 release is sorting out the
+ modutils issues. For the new 2.6.x kernels, we already have
+ patches adding insmod and rmmod support and those need to be
+ integrated. For 2.4.x kernels, for which busybox only supports
+ a limited number of architectures, we may want to invest a bit
+ more work before we cut 1.0.0. Or we may just leave 2.4.x
+ module loading alone.
+
+ <p>
+
+ I had hoped this release would be out a month ago. And of
+ course, it wasn't since Erik became busy getting a release of
+ <a href="http://www.uclibc.org/">uClibc</a>
+ out the door. Many thanks to Glenn McGrath (bug1) for
+ stepping in and helping get a bunch of patches merged! I am
+ not even going to state a date for releasing BusyBox 1.0.0
+ -pre4 (or the final 1.0.0). We're aiming for late September...
+ But if this release proves as to be exceptionally stable (or
+ exceptionally unstable!), the next release may be very soon
+ indeed.
+
+ <p>
+
+ The <a href="downloads/Changelog">changelog</a> has all
+ the details. And as usual you can
+ <a href="downloads">download busybox here</a>.
+
+ <p>Have Fun!
+
+
+ <p>
+ <li><b>30 July 2003 -- BusyBox 1.0.0-pre2 released</b><p>
+
+ Here goes another pre release for the new BusyBox stable
+ series. The last prerelease (pre1) was given quite a lot of
+ testing (thanks everyone!) which has helped turn up a number of
+ bugs, and these problems have now been fixed.
+
+ <p>
+
+ Highlights of -pre2 include updating the 'ash' shell to sync up
+ with the Debian 'dash' shell, a new 'hdparm' applet was added,
+ init again supports pivot_root, The 'reboot' 'halt' and
+ 'poweroff' applets can now be used without using busybox init.
+ an ifconfig buffer overflow was fixed, losetup now allows
+ read-write loop devices, uClinux daemon support was added, the
+ 'watchdog', 'fdisk', and 'kill' applets were rewritten, there were
+ tons of doc updates, and there were many other bugs fixed.
+ <p>
+
+ If you have submitted a patch and it is not included in this
+ release and Erik has not emailed you explaining why your patch
+ was rejected, it is safe to say that he has lost your patch.
+ That happens sometimes. Please re-submit your patch to the
+ BusyBox mailing list.
+ <p>
+
+ The point of the "-preX" versions is to get a larger group of
+ people and vendors testing, so any problems that turn up can be
+ fixed prior to the final 1.0.0 release. The main feature that
+ is still still on the TODO list before the final BusyBox 1.0.0
+ release is adding module support for the new 2.6.x kernels. If
+ necessary, a -pre3 BusyBox release will happen on August 6th.
+ Hopefully (i.e. unless some horrible catastrophic problem
+ turns up) the final BusyBox 1.0.0 release will be ready by
+ then...
+ <p>
+
+ The <a href="downloads/Changelog">changelog</a> has all
+ the details. As usual you can <a href="downloads">download busybox here</a>.
+
+ <p>Have Fun!
+ <p>
+
+ <p>
+ <li><b>15 July 2003 -- BusyBox 1.0.0-pre1 released</b><p>
+
+ The busybox development series has been under construction for
+ nearly two years now. Which is just entirely too long... So
+ it is with great pleasure that I announce the imminent release
+ of a new stable series. Due to the huge number of changes
+ since the last stable release (and the usual mindless version
+ number inflation) I am branding this new stable series verison
+ 1.0.x...
+ <p>
+
+ The point of "-preX" versions is to get a larger group of
+ people and vendors testing, so any problems that turn up can be
+ fixed prior to the magic 1.0.0 release (which should happen
+ later this month)... I plan to release BusyBox 1.0.0-pre2 next
+ Monday (July 21st), and, if necessary, -pre3 on July 28th.
+ Hopefully (i.e. unless some horrible catastrophic problem turns
+ up) the final BusyBox 1.0.0 release should be ready by the end
+ of July.
+ <p>
+
+ If you have submitted patches, and they are not in this release
+ and I have not emailed you explaining why your patch was
+ rejected, it is safe to say that I have lost your patch. That
+ happens sometimes. Please do <B>NOT</b> send all your patches,
+ support questions, etc, directly to Erik. I get hundreds of
+ emails every day (which is why I end up losing patches
+ sometimes in the flood)... The busybox mailing list is the
+ right place to send your patches, support questions, etc.
+ <p>
+
+ I would like to especially thank Vladimir Oleynik (vodz), Glenn
+ McGrath (bug1), Robert Griebl (sandman), and Manuel Novoa III
+ (mjn3) for their significant efforts and contributions that
+ have made this release possible.
+ <p>
+
+ As usual you can <a href="downloads">download busybox here</a>.
+ You don't really need to bother with the
+ <a href="downloads/Changelog">changelog</a>, as the changes
+ vs the stable version are way too extensive to easily enumerate.
+ But you can take a look if you really want too.
+
+ <p>Have Fun!
+ <p>
+
+
+
+ <p>
+ <li><b>26 October 2002 -- BusyBox 0.60.5 released</b><p>
+
+ I am very pleased to announce that the BusyBox 0.60.5 (stable)
+ is now available for download. This is a bugfix release for
+ the stable series to address all the problems that have turned
+ up since the last release. Unfortunately, the previous release
+ had a few nasty bugs (i.e. init could deadlock, gunzip -c tried
+ to delete source files, cp -a wouldn't copy symlinks, and init
+ was not always providing controlling ttys when it should have).
+ I know I said that the previous release would be the end of the
+ 0.60.x series. Well, it turns out I'm a liar. But this time I
+ mean it (just like last time ;-). This will be the last
+ release for the 0.60.x series -- all further development work
+ will be done for the development busybox tree. Expect the development
+ version to have its first real release very very soon now...
+
+ <p>
+ The <a href="downloads/Changelog.full">changelog</a> has all
+ the details. As usual you can <a href="downloads">download busybox here</a>.
+ <p>Have Fun!
+ <p>
+
+ <p>
+ <li><b>18 September 2002 -- BusyBox 0.60.4 released</b><p>
+
+ I am very pleased to announce that the BusyBox 0.60.4
+ (stable) is now available for download. This is primarily
+ a bugfix release for the stable series to address all
+ the problems that have turned up since the last
+ release. This will be the last release for the 0.60.x series.
+ I mean it this time -- all further development work will be done
+ on the development busybox tree, which is quite solid now and
+ should soon be getting its first real release.
+
+ <p>
+ The <a href="downloads/Changelog.full">changelog</a> has all
+ the details. As usual you can <a href="downloads">download busybox here</a>.
+ <p>Have Fun!
+ <p>
+
+
+ <p>
+ <li><b>27 April 2002 -- BusyBox 0.60.3 released</b><p>
+
+ I am very pleased to announce that the BusyBox 0.60.3 (stable) is
+ now available for download. This is primarily a bugfix release
+ for the stable series. A number of problems have turned up since
+ the last release, and this should address most of those problems.
+ This should be the last release for the 0.60.x series. The
+ development busybox tree has been progressing nicely, and will
+ hopefully be ready to become the next stable release.
+
+ <p>
+ The <a href="downloads/Changelog">changelog</a> has all
+ the details. As usual you can <a href="downloads">download busybox here</a>.
+ <p>Have Fun!
+ <p>
+
+
+ <p>
+ <li><b>6 March 2002 -- busybox.net now has mirrors!</b><p>
+
+ Busybox.net is now much more available, thanks to
+ the fine folks at <a href= "http://i-netinnovations.com/">http://i-netinnovations.com/</a>
+ who are providing hosting for busybox.net and
+ uclibc.org. In addition, we now have two mirrors:
+ <a href= "http://busybox.linuxmagic.com/">http://busybox.linuxmagic.com/</a>
+ in Canada and
+ <a href= "http://busybox.csservers.de/">http://busybox.csservers.de/</a>
+ in Germany. I hope this makes things much more
+ accessible for everyone!
+
+
+<li>
+<b>3 January 2002 -- Welcome to busybox.net!</b>
+
+<p>Thanks to the generosity of a number of busybox
+users, we have been able to purchase busybox.net
+(which is where you are probably reading this).
+Right now, busybox.net and uclibc.org are both
+living on my home system (at the end of my DSL
+line). I apologize for the abrupt move off of
+busybox.lineo.com. Unfortunately, I no longer have
+the access needed to keep that system updated (for
+example, you might notice the daily snapshots there
+stopped some time ago).</p>
+
+<p>Busybox.net is currently hosted on my home
+server, at the end of a DSL line. Unfortunately,
+the load on them is quite heavy. To address this,
+I'm trying to make arrangements to get busybox.net
+co-located directly at an ISP. To assist in the
+co-location effort, <a href=
+"http://www.codepoet.org/~markw">Mark Whitley</a>
+(author of busybox sed, cut, and grep) has donated
+his <a href=
+"http://www.netwinder.org/">NetWinder</a> computer
+for hosting busybox.net and uclibc.org. Once this
+system is co-located, the current speed problems
+should be completely eliminated. Hopefully, too,
+some of you will volunteer to set up some mirror
+sites, to help to distribute the load a bit.</p>
+
+<p><!--
+ <center>
+ Click here to help support busybox.net!
+ <form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+ <input type="hidden" name="cmd" value="_xclick">
+ <input type="hidden" name="business" value="andersen@codepoet.org">
+ <input type="hidden" name="item_name" value="Support Busybox">
+ <input type="hidden" name="image_url" value="https://codepoet-consulting.com/images/busybox2.jpg">
+ <input type="hidden" name="no_shipping" value="1">
+ <input type="image" src="images/donate.png" border="0" name="submit" alt="Make donation using PayPal">
+ </form>
+ </center>
+ -->
+ Since some people expressed concern over BusyBox
+donations, let me assure you that no one is getting
+rich here. All BusyBox and uClibc donations will be
+spent paying for bandwidth and needed hardware
+upgrades. For example, Mark's NetWinder currently
+has just 64Meg of memory. As demonstrated when
+google spidered the site the other day, 64 Megs in
+not enough, so I'm going to be ordering 256Megs of
+ram and a larger hard drive for the box today. So
+far, donations received have been sufficient to
+cover almost all expenses. In the future, we may
+have co-location fees to worry about, but for now
+we are ok. A <b>HUGE thank-you</b> goes out to
+everyone that has contributed!<br>
+ -Erik</p>
+</li>
+
+<li>
+<b>20 November 2001 -- BusyBox 0.60.2 released</b>
+
+<p>We am very pleased to announce that the BusyBox
+0.60.2 (stable) is now released to the world. This
+one is primarily a bugfix release for the stable
+series, and it should take care of most everyone's
+needs till we can get the nice new stuff we have
+been working on in CVS ready to release (with the
+wonderful new buildsystem). The biggest change in
+this release (beyond bugfixes) is the fact that msh
+(the minix shell) has been re-worked by Vladimir N.
+Oleynik (vodz) and so it no longer crashes when
+told to do complex things with backticks.</p>
+
+<p>This release has been tested on x86, ARM, and
+powerpc using glibc 2.2.4, libc5, and uClibc, so it
+should work with just about any Linux system you
+throw it at. See the <a href=
+"downloads/Changelog">changelog</a> for <small>most
+of</small> the details. The last release was
+<em>very</em> solid for people, and this one should
+be even better.</p>
+
+<p>As usual BusyBox 0.60.2 can be downloaded from
+<a href=
+"downloads">http://www.busybox.net/downloads</a>.</p>
+
+<p>Have Fun.<br>
+ -Erik</p>
+</li>
+
+<li> <b>18 November 2001 -- Help us buy busybox.net!</b>
+
+<!-- Begin PayPal Logo -->
+<center>
+Click here to help buy busybox.net!
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_xclick">
+<input type="hidden" name="business" value="andersen@codepoet.org">
+<input type="hidden" name="item_name" value="Support Busybox">
+<input type="hidden" name="image_url" value="https://busybox.net/images/busybox2.jpg">
+<input type="hidden" name="no_shipping" value="1">
+<input type="image" src="images/donate.png" border="0" name="submit" alt="Make donation using PayPal">
+</form>
+</center>
+<!-- End PayPal Logo -->
+
+I've contacted the current owner of busybox.net and he is willing
+to sell the domain name -- for $250. He also owns busybox.org but
+will not part with it... I will then need to pay the registry fee
+for a couple of years and start paying for bandwidth, so this will
+initially cost about $300. I would like to host busybox.net on my
+home machine (codepoet.org) so I have full control over the system,
+but to do that would require that I increase the level of bandwidth
+I am paying for. Did you know that so far this month, there
+have been over 1.4 Gigabytes of busybox ftp downloads? I don't
+even <em>know</em> how much CVS bandwidth it requires. For the
+time being, Lineo has continued to graciously provide this
+bandwidth, despite the fact that I no longer work for them. If I
+start running this all on my home machine, paying for the needed bandwidth
+will start costing some money.
+<p>
+
+I was going to pay it all myself, but my wife didn't like that
+idea at all (big surprise). It turns out &lt;insert argument
+where she wins and I don't&gt; she has better ideas
+about what we should spend our money on that don't involve
+busybox. She suggested I should ask for contributions on the
+mailing list and web page. So...
+<p>
+
+I am hoping that if everyone could contribute a bit, we could pick
+up the busybox.net domain name and cover the bandwidth costs. I
+know that busybox is being used by a lot of companies as well as
+individuals -- hopefully people and companies that are willing to
+contribute back a bit. So if everyone could please help out, that
+would be wonderful!
+<p>
+
+
+<li> <b>23 August 2001 -- BusyBox 0.60.1 released</b>
+<br>
+
+ This is a relatively minor bug fixing release that fixes
+ up the bugs that have shown up in the stable release in
+ the last few weeks. Fortunately, nothing <em>too</em>
+ serious has shown up. This release only fixes bugs -- no
+ new features, no new applets. So without further ado,
+ here it is. Come and get it.
+ <p>
+ The
+ <a href="downloads/Changelog">changelog</a> has all
+ the details. As usual BusyBox 0.60.1 can be downloaded from
+ <a href="downloads">http://busybox.net/downloads</a>.
+ <p>Have Fun!
+ <p>
+
+
+<li> <b>2 August 2001 -- BusyBox 0.60.0 released</b>
+<br>
+ I am very pleased to announce the immediate availability of
+ BusyBox 0.60.0. I have personally tested this release with libc5, glibc,
+ and <a href="http://uclibc.org/">uClibc</a> on
+ x86, ARM, and powerpc using linux 2.2 and 2.4, and I know a number
+ of people using it on everything from ia64 to m68k with great success.
+ Everything seems to be working very nicely now, so getting a nice
+ stable bug-free(tm) release out seems to be in order. This releases fixes
+ a memory leak in syslogd, a number of bugs in the ash and msh shells, and
+ cleans up a number of things.
+
+ <p>
+
+ Those wanting an easy way to test the 0.60.0 release with uClibc can
+ use <a href="http://user-mode-linux.sourceforge.net/">User-Mode Linux</a>
+ to give it a try by downloading and compiling
+ <a href="ftp://busybox.net/buildroot.tar.gz">buildroot.tar.gz</a>.
+ You don't have to be root or reboot your machine to run test this way.
+ Preconfigured User-Mode Linux kernel source is also on busybox.net.
+ <p>
+ Another cool thing is the nifty <a href="downloads/tutorial/index.html">
+ BusyBox Tutorial</a> contributed by K Computing. This requires
+ a ShockWave plugin (or standalone viewer), so you may want to grab the
+ the GPLed shockwave viewer from <a href="http://www.swift-tools.com/Flash/flash-0.4.10.tgz">here</a>
+ to view the tutorial.
+ <p>
+
+ Finally, In case you didn't notice anything odd about the
+ version number of this release, let me point out that this release
+ is <em>not</em> 0.53, because I bumped the version number up a
+ bit. This reflects the fact that this release is intended to form
+ a new stable BusyBox release series. If you need to rely on a
+ stable version of BusyBox, you should plan on using the stable
+ 0.60.x series. If bugs show up then I will release 0.60.1, then
+ 0.60.2, etc... This is also intended to deal with the fact that
+ the BusyBox build system will be getting a major overhaul for the
+ next release and I don't want that to break products that people
+ are shipping. To avoid that, the new build system will be
+ released as part of a new BusyBox development series that will
+ have some not-yet-decided-on odd version number. Once things
+ stabilize and the new build system is working for everyone, then
+ I will release that as a new stable release series.
+
+ <p>
+ The
+ <a href="downloads/Changelog">changelog</a> has all
+ the details. As usual BusyBox 0.60.0 can be downloaded from
+ <a href="downloads">http://busybox.net/downloads</a>.
+ <p>Have Fun!
+ <p>
+
+
+<li> <b>7 July 2001 -- BusyBox 0.52 released</b>
+<br>
+
+ I am very pleased to announce the immediate availability of
+ BusyBox 0.52 (the "new-and-improved rock-solid release"). This
+ release is the result of <em>many</em> hours of work and has tons
+ of bugfixes, optimizations, and cleanups. This release adds
+ several new applets, including several new shells (such as hush, msh,
+ and ash).
+
+ <p>
+ The
+ <a href="downloads/Changelog">changelog</a> covers
+ some of the more obvious details, but there are many many things that
+ are not mentioned, but have been improved in subtle ways. As usual,
+ BusyBox 0.52 can be downloaded from
+ <a href="downloads">http://busybox.net/downloads</a>.
+ <p>Have Fun!
+ <p>
+
+
+<li> <b>10 April 2001 - Graph of Busybox Growth </b>
+<br>
+The illustrious Larry Doolittle has made a PostScript chart of the growth
+of the Busybox tarball size over time. It is available for downloading /
+viewing <a href= "busybox-growth.ps"> right here</a>.
+
+<p> (Note that while the number of applets in Busybox has increased, you
+can still configure Busybox to be as small as you want by selectively
+turning off whichever applets you don't need.)
+<p>
+
+
+<li> <b>10 April 2001 -- BusyBox 0.51 released</b>
+<br>
+
+ BusyBox 0.51 (the "rock-solid release") is now out there. This
+ release adds only 2 new applets: env and vi. The vi applet,
+ contributed by Sterling Huxley, is very functional, and is only
+ 22k. This release fixes 3 critical bugs in the 0.50 release.
+ There were 2 potential segfaults in lash (the busybox shell) in
+ the 0.50 release which are now fixed. Another critical bug in
+ 0.50 which is now fixed: syslogd from 0.50 could potentially
+ deadlock the init process and thereby break your entire system.
+ <p>
+
+ There are a number of improvements in this release as well. For
+ one thing, the wget applet is greatly improved. Dmitry Zakharov
+ added FTP support, and Laurence Anderson make wget fully RFC
+ compliant for HTTP 1.1. The mechanism for including utility
+ functions in previous releases was clumsy and error prone. Now
+ all utility functions are part of a new libbb library, which makes
+ maintaining utility functions much simpler. And BusyBox now
+ compiles on itanium systems (thanks to the Debian itanium porters
+ for letting me use their system!).
+ <p>
+ You can read the
+ <a href="downloads/Changelog">changelog</a> for
+ complete details. BusyBox 0.51 can be downloaded from
+ <a href="downloads">http://busybox.net/downloads</a>.
+ <p>Have Fun!
+ <p>
+
+<li> <b>Busybox Boot-Floppy Image</b>
+
+<p>Because you asked for it, we have made available a <a href=
+"downloads/busybox.floppy.img"> Busybox boot floppy
+image</a>. Here's how you use it:
+
+<ol>
+
+ <li> <a href= "downloads/busybox.floppy.img">
+ Download the image</a>
+
+ <li> dd it onto a floppy like so: <tt> dd if=busybox.floppy.img
+ of=/dev/fd0 ; sync </tt>
+
+ <li> Pop it in a machine and boot up.
+
+</ol>
+
+<p> If you want to look at the contents of the initrd image, do this:
+
+<pre>
+ mount ./busybox.floppy.img /mnt -o loop -t msdos
+ cp /mnt/initrd.gz /tmp
+ umount /mnt
+ gunzip /tmp/initrd.gz
+ mount /tmp/initrd /mnt -o loop -t minix
+</pre>
+
+
+<li> <b>15 March 2001 -- BusyBox 0.50 released</b>
+<br>
+
+ This release adds several new applets including ifconfig, route, pivot_root, stty,
+ and tftp, and also fixes tons of bugs. Tab completion in the
+ shell is now working very well, and the shell's environment variable
+ expansion was fixed. Tons of other things were fixed or made
+ smaller. For a fairly complete overview, see the
+ <a href="downloads/Changelog">changelog</a>.
+ <p>
+ lash (the busybox shell) is still with us, fixed up a bit so it
+ now behaves itself quite nicely. It really is quite usable as
+ long as you don't expect it to provide Bourne shell grammer.
+ Standard things like pipes, redirects, command line editing, and
+ environment variable expansion work great. But we have found that
+ this shell, while very usable, does not provide an extensible
+ framework for adding in full Bourne shell behavior. So the first order of
+ business as we begin working on the next BusyBox release will be to merge in the new shell
+ currently in progress at
+ <a href="http://doolittle.faludi.com/~larry/parser.html">Larry Doolittle's website</a>.
+ <p>
+
+
+<li> <b>27 January 2001 -- BusyBox 0.49 released</b>
+<br>
+
+ Several new applets, lots of bug fixes, cleanups, and many smaller
+ things made nicer. Several cleanups and improvements to the shell.
+ For a list of the most interesting changes
+ you might want to look at the <a href="downloads/Changelog">changelog</a>.
+ <p>
+ Special thanks go out to Matt Kraai and Larry Doolittle for all their
+ work on this release, and for keeping on top of things while I've been
+ out of town.
+ <p>
+ <em>Special Note</em><br>
+
+ BusyBox 0.49 was supposed to have replaced lash, the BusyBox
+ shell, with a new shell that understands full Bourne shell/Posix shell grammer.
+ Well, that simply didn't happen in time for this release. A new
+ shell that will eventually replace lash is already under
+ construction. This new shell is being developed by Larry
+ Doolittle, and could use all of our help. Please see the work in
+ progress on <a href="http://doolittle.faludi.com/~larry/parser.html">Larry's website</a>
+ and help out if you can. This shell will be included in the next
+ release of BusyBox.
+ <p>
+
+<li> <b>13 December 2000 -- BusyBox 0.48 released</b>
+<br>
+
+ This release fixes lots and lots of bugs. This has had some very
+ rigorous testing, and looks very, very clean. The usual tar
+ update of course: tar no longer breaks hardlinks, tar -xzf is
+ optionally supported, and the LRP folks will be pleased to know
+ that 'tar -X' and 'tar --exclude' are both now in. Applets are
+ now looked up using a binary search making lash (the busybox
+ shell) much faster. For the new debian-installer (for Debian
+ woody) a .udeb can now be generated.
+ <p>
+ The curious can get a list of some of the more interesting changes by reading
+ the <a href="downloads/Changelog">changelog</a>.
+ <p>
+ Many thanks go out to the many many people that have contributed to
+ this release, especially Matt Kraai, Larry Doolittle, and Kent Robotti.
+ <p>
+<p> <li> <b>26 September 2000 -- BusyBox 0.47 released</b>
+<br>
+
+ This release fixes lots of bugs (including an ugly bug in 0.46
+ syslogd that could fork-bomb your system). Added several new
+ apps: rdate, wget, getopt, dos2unix, unix2dos, reset, unrpm,
+ renice, xargs, and expr. syslogd now supports network logging.
+ There are the usual tar updates. Most apps now use getopt for
+ more correct option parsing.
+ See the <a href="downloads/Changelog">changelog</a>
+ for complete details.
+
+
+<p> <li> <b>11 July 2000 -- BusyBox 0.46 released</b>
+<br>
+
+ This release fixes several bugs (including a ugly bug in tar,
+ and fixes for NFSv3 mount support). Added a dumpkmap to allow
+ people to dump a binary keymaps for use with 'loadkmap', and a
+ completely reworked 'grep' and 'sed' which should behave better.
+ BusyBox shell can now also be used as a login shell.
+ See the <a href="downloads/Changelog">changelog</a>
+ for complete details.
+
+
+<p> <li> <b>21 June 2000 -- BusyBox 0.45 released</b>
+<br>
+
+ This release has been slow in coming, but is very solid at this
+ point. BusyBox now supports libc5 as well as GNU libc. This
+ release provides the following new apps: cut, tr, insmod, ar,
+ mktemp, setkeycodes, md5sum, uuencode, uudecode, which, and
+ telnet. There are bug fixes for just about every app as well (see
+ the <a href="downloads/Changelog">changelog</a> for
+ details).
+ <p>
+ Also, some exciting infrastructure news! Busybox now has its own
+ <a href="lists/busybox/">mailing list</a>,
+ publically browsable
+ <a href="/cgi-bin/viewcvs.cgi/trunk/busybox/">CVS tree</a>,
+ anonymous
+ <a href="cvs_anon.html">CVS access</a>, and
+ for those that are actively contributing there is even
+ <a href="cvs_write.html">CVS write access</a>.
+ I think this will be a huge help to the ongoing development of BusyBox.
+ <p>
+ Also, for the curious, there is no 0.44 release. Somehow 0.44 got announced
+ a few weeks ago prior to its actually being released. To avoid any confusion
+ we are just skipping 0.44.
+ <p>
+ Many thanks go out to the many people that have contributed to this release
+ of BusyBox (esp. Pavel Roskin)!
+
+
+<p> <li> <b>19 April 2000 -- syslogd bugfix</b>
+<br>
+Turns out that there was still a bug in busybox syslogd.
+For example, with the following test app:
+<pre>
+#include &lt;syslog.h&gt;
+
+int do_log(char* msg, int delay)
+{
+ openlog("testlog", LOG_PID, LOG_DAEMON);
+ while(1) {
+ syslog(LOG_ERR, "%s: testing one, two, three\n", msg);
+ sleep(delay);
+ }
+ closelog();
+ return(0);
+};
+
+int main(void)
+{
+ if (fork()==0)
+ do_log("A", 2);
+ do_log("B", 3);
+}
+</pre>
+it should be logging stuff from both "A" and "B". As released in 0.43 only stuff
+from "A" would have been logged. This means that if init tries to log something
+while say ppp has the syslog open, init would block (which is bad, bad, bad).
+<p>
+Karl M. Hegbloom has created a fix for the problem.
+Thanks Karl!
+
+
+<p> <li> <b>18 April 2000 -- BusyBox 0.43 released (finally!)</b>
+<br>
+I have finally gotten everything into a state where I feel pretty
+good about things. This is definitely the most stable, solid release
+so far. A lot of bugs have been fixed, and the following new apps
+have been added: sh, basename, dirname, killall, uptime,
+freeramdisk, tr, echo, test, and usleep. Tar has been completely
+rewritten from scratch. Bss size has also been greatly reduced.
+More details are available in the
+<a href="downloads/Changelog">changelog</a>.
+Oh, and as a special bonus, I wrote some fairly comprehensive
+<em>documentation</em>, complete with examples and full usage information.
+
+<p>
+Many thanks go out to the fine people that have helped by submitting patches
+and bug reports; particularly instrumental in helping for this release were
+Karl Hegbloom, Pavel Roskin, Friedrich Vedder, Emanuele Caratti,
+Bob Tinsley, Nicolas Pitre, Avery Pennarun, Arne Bernin, John Beppu, and Jim Gleason.
+There were others so if I somehow forgot to mention you, I'm very sorry.
+<p>
+
+You can grab BusyBox 0.43 tarballs <a href="downloads">here</a>.
+
+<p> <li> <b>9 April 2000 -- BusyBox 0.43 pre release</b>
+<br>
+Unfortunately, I have not yet finished all the things I want to
+do for BusyBox 0.43, so I am posting this pre-release for people
+to poke at. This contains my complete rewrite of tar, which now weighs in at
+5k (7k with all options turned on) and works for reading and writing
+tarballs (which it does correctly for everything I have been able to throw
+at it). Tar also (optionally) supports the "--exclude" option (mainly because
+the Linux Router Project folks asked for it). This also has a pre-release
+of the micro shell I have been writing. This pre-release should be stable
+enough for production use -- it just isn't a release since I have some structural
+changes I still want to make.
+<p>
+The pre-release can be found <a href="downloads">here</a>.
+Please let me know ASAP if you find <em>any</em> bugs.
+
+<p> <li> <b>28 March 2000 -- Andersen Baby Boy release</b>
+<br>
+I am pleased to announce that on Tuesday March 28th at 5:48pm, weighing in at 7
+lbs. 12 oz, Micah Erik Andersen was born at LDS Hospital here in Salt Lake City.
+He was born in the emergency room less then 5 minutes after we arrived -- and
+it was such a relief that we even made it to the hospital at all. Despite the
+fact that I was driving at an amazingly unlawful speed and honking at everybody
+and thinking decidedly unkind thoughts about the people in our way, my wife
+(inconsiderate of my feelings and complete lack of medical training) was lying
+down in the back seat saying things like "I think I need to start pushing now"
+(which she then proceeded to do despite my best encouraging statements to the
+contrary).
+<p>
+Anyway, I'm glad to note that despite the much-faster-than-we-were-expecting
+labor, both Shaunalei and our new baby boy are doing wonderfully.
+<p>
+So now that I am done with my excuse for the slow release cycle...
+Progress on the next release of BusyBox has been slow but steady. I expect
+to have a release sometime during the first week of April. This release will
+include a number of important changes, including the addition of a shell, a
+re-write of tar (to accommodate the Linux Router Project), and syslogd can now
+accept multiple concurrent connections, fixing lots of unexpected blocking
+problems.
+
+
+<p> <li> <b>11 February 2000 -- BusyBox 0.42 released</b>
+<br>
+
+ This is the most solid BusyBox release so far. Many, many
+ bugs have been fixed. See the
+ <a href="downloads/Changelog">changelog</a> for details.
+
+ Of particular interest, init will now cleanly unmount
+ filesystems on reboot, cp and mv have been rewritten and
+ behave much better, and mount and umount no longer leak
+ loop devices. Many thanks go out to Randolph Chung,
+ Karl M. Hegbloom, Taketoshi Sano, and Pavel Roskin for
+ their hard work on this release of BusyBox. Please pound
+ on it and let me know if you find any bugs.
+
+<p> <li> <b>19 January 2000 -- BusyBox 0.41 released</b>
+<br>
+
+ This release includes bugfixes to cp, mv, logger, true, false,
+ mkdir, syslogd, and init. New apps include wc, hostid,
+ logname, tty, whoami, and yes. New features include loop device
+ support in mount and umount, and better TERM handling by init.
+ The changelog can be found <a href="downloads/Changelog">here</a>.
+
+<p> <li> <b>7 January 2000 -- BusyBox 0.40 released</b>
+<br>
+
+ This release includes bugfixes to init (now includes inittab support),
+ syslogd, head, logger, du, grep, cp, mv, sed, dmesg, ls, kill, gunzip, and mknod.
+ New apps include sort, uniq, lsmod, rmmod, fbset, and loadacm.
+ In particular, this release fixes an important bug in tar which
+ in some cases produced serious security problems.
+ As always, the changelog can be found <a href="downloads/Changelog">here</a>.
+
+<p> <li> <b>11 December 1999 -- BusyBox Website</b>
+<br>
+ I have received permission from Bruce Perens (the original author of BusyBox)
+ to set up this site as the new primary website for BusyBox. This website
+ will always contain pointers to the latest and greatest, and will also
+ contain the latest documentation on how to use BusyBox, what it can do,
+ what arguments its apps support, etc.
+
+<p> <li> <b>10 December 1999 -- BusyBox 0.39 released</b>
+<br>
+ This release includes fixes to init, reboot, halt, kill, and ls, and contains
+ the new apps ping, hostname, mkfifo, free, tail, du, tee, and head. A full
+ changelog can be found <a href="downloads/Changelog">here</a>.
+<p> <li> <b>5 December 1999 -- BusyBox 0.38 released</b>
+<br>
+ This release includes fixes to tar, cat, ls, dd, rm, umount, find, df,
+ and make install, and includes new apps syslogd/klogd and logger.
+
+
+</ul>
+
+
+<!--#include file="footer.html" -->
+
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/products.html b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/products.html
new file mode 100644
index 0000000000..a727d9f9a1
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/products.html
@@ -0,0 +1,170 @@
+<!--#include file="header.html" -->
+
+
+<h3>Products/Projects Using BusyBox</h3>
+
+Do you use BusyBox? I'd love to know about it and
+I'd be happy to link to you.
+
+<p>
+I know of the following products and/or projects that use BusyBox --
+listed in the order I happen to add them to the web page:
+
+<ul>
+
+<li><a href="http://buildroot.uclibc.org/">buildroot</a><br>A configurable
+means for building your own busybox/uClibc based system systems, maintained
+by the uClibc developers.
+
+<li><a href="http://openwrt.org">OpenWrt</a> a Linux distribution for embedded
+devices, based on buildroot.
+
+<li><a href="http://www.pengutronix.de/software/ptxdist_en.html">PTXdist</a><br>another
+configurable means for building your own busybox based system systems.
+
+</li><li><a href=
+"http://cvs.debian.org/boot-floppies/">
+Debian installer (boot floppies) project</a>
+
+</li><li><a href="http://redhat.com/">Red Hat installer</a>
+
+</li><li><a href=
+"http://distro.ibiblio.org/pub/Linux/distributions/slackware/slackware-current/source/rootdisks/">
+Slackware Installer</a>
+
+</li><li><a href="http://www.gentoo.org/">Gentoo Linux install/boot CDs</a>
+</li><li><a href="http://www.mandriva.com/">The Mandriva installer</a>
+
+</li><li><a href="http://Leaf.SourceForge.net">Linux Embedded Appliance Firewall</a><br>The sucessor of the Linux Router Project, supporting all sorts of embedded Linux gateways, routers, wireless routers, and firewalls.
+
+</li><li><a href=
+"http://www.toms.net/rb/">tomsrtbt</a>
+
+</li><li><a href="http://www.stormix.com/">Stormix
+Installer</a>
+
+</li><li><a href=
+"http://www.emacinc.com/linux2_sbc.htm">EMAC Linux
+2.0 SBC</a>
+
+</li><li><a href="http://www.trinux.org/">Trinux</a>
+
+</li><li><a href="http://oddas.sourceforge.net/">ODDAS
+project</a>
+
+</li><li><a href="http://byld.sourceforge.net/">Build Your
+Linux Disk</a>
+
+</li><li><a href=
+"http://ibiblio.org/pub/Linux/system/recovery">Zdisk</a>
+
+</li><li><a href="http://www.adtran.com">AdTran -
+VPN/firewall VPN Linux Distribution</a>
+
+</li><li><a href="http://mkcdrec.ota.be/">mkCDrec - make
+CD-ROM recovery</a>
+
+</li><li><a href=
+"http://recycle.lbl.gov/~ldoolitt/bse/">Linux on
+nanoEngine</a>
+
+</li><li><a href=
+"http://www.zelow.no/floppyfw/">Floppyfw</a>
+
+</li><li><a href="http://www.ltsp.org/">Linux Terminal
+Server Project</a>
+
+</li><li><a href="http://www.devil-linux.org/">Devil-Linux</a>
+
+</li><li><a href="http://dutnux.sourceforge.net/">DutNux</a>
+
+</li><li><a href="http://www.microwerks.net/~hugo/mindi/">Mindi</a>
+
+</li><li><a href="http://www.minimalinux.org/ttylinux/">ttylinux</a>
+
+</li><li><a href="http://www.coyotelinux.com/">Coyote Linux</a>
+
+</li><li><a href="http://www.partimage.org/">Partition
+Image</a>
+
+</li><li><a href="http://www.fli4l.de/">fli4l the on(e)-disk-router</a>
+
+</li><li><a href="http://tinfoilhat.cultists.net/">Tinfoil
+Hat Linux</a>
+
+</li><li><a href="http://sourceforge.net/projects/gp32linux/">gp32linux</a>
+</li><li><a href="http://familiar.handhelds.org/">Familiar Linux</a><br>A linux distribution for handheld computers
+</li><li><a href="http://rescuecd.sourceforge.net/">Timo's Rescue CD Set</a>
+</li><li><a href="http://sf.net/projects/netstation/">Netstation</a>
+</li><li><a href="http://www.fiwix.org/">GNU/Fiwix Operating System</a>
+</li><li><a href="http://www.softcraft.com/">Generations Linux</a>
+</li><li><a href="http://systemimager.org/relatedprojects/">SystemImager / System Installation Suite</a>
+</li><li><a href="http://www.bablokb.de/gendist/">GENDIST distribution generator</a>
+</li><li><a href="http://diet-pc.sourceforge.net/">DIET-PC embedded Linux thin client distribution</a>
+</li><li><a href="http://byzgl.sourceforge.net/">BYZantine Gnu/Linux</a>
+</li><li><a href="http://dban.sourceforge.net/">Darik's Boot and Nuke</a>
+</li><li><a href="http://www.timesys.com/">TimeSys real-time Linux</a>
+</li><li><a href="http://movix.sf.net/">MoviX</a><br>Boots from CD and automatically plays every video file on the CD
+</li><li><a href="http://katamaran.sourceforge.net">katamaran</a><br>Linux, X11, xfce windowmanager, based on BusyBox
+</li><li><a href="http://www.sourceforge.net/projects/simplygnustep">Prometheus SimplyGNUstep</a>
+</li><li><a href="http://www.renyi.hu/~ekho/lowlife/">lowlife</a><br>A documentation project on how to make your own uClibc-based systems and floppy.
+</li><li><a href="http://metadistros.hispalinux.es/">Metadistros</a><br>a project to allow you easily make Live-CD distributions.
+</li><li><a href="http://salvare.sourceforge.net/">Salvare</a><br>More Linux than tomsrtbt but less than Knoppix, aims to provide a useful workstation as well as a rescue disk.
+</li><li><a href="http://www.stresslinux.org/">stresslinux</a><br>minimal linux distribution running from a bootable cdrom or via PXE.
+</li><li><a href="http://thinstation.sourceforge.net/">thinstation</a><br>convert standard PCs into full-featured diskless thinclients.
+</li><li><a href="http://www.uhulinux.hu/">UHU-Linux Hungary</a>
+</li><li><a href="http://deep-water.berlios.de/">Deep-Water Linux</a>
+</li><li><a href="http://www.freesco.org/">Freesco router</a>
+</li><li><a href="http://Sentry.SourceForge.net/">Sentry Firewall CD</a>
+
+
+
+</li><li><a href="http://tuxscreen.net">Tuxscreen Linux Phone</a>
+</li><li><a href="http://www.kerbango.com/">The Kerbango Internet Radio</a>
+</li><li><a href="http://www.linuxmagic.com/vpn/">LinuxMagic VPN Firewall</a>
+</li><li><a href="http://www.isilver-inc.com/">I-Silver Linux appliance servers</a>
+</li><li><a href="http://zaurus.sourceforge.net/">Sharp Zaurus PDA</a>
+</li><li><a href="http://www.cyclades.com/">Cyclades-TS and other Cyclades products</a>
+</li><li><a href="http://www.linksys.com/products/product.asp?prid=508">Linksys WRT54G - Wireless-G Broadband Router</a>
+</li><li><a href="http://www.dell.com/us/en/biz/topics/sbtopic_005_truemobile.htm">Dell TrueMobile 1184</a>
+</li><li><a href="http://actiontec.com/products/modems/dual_pcmodem/dpm_overview.html">Actiontec Dual PC Modem</a>
+</li><li><a href="http://www.kiss-technology.com/">Kiss DP Series DVD players</a>
+</li><li><a href="http://www.netgear.com/products/prod_details.asp?prodID=170">NetGear WG602 wireless router</a>
+ <br>with sources <a href="http://www.netgear.com/support/support_details.asp?dnldID=453">here</a>
+</li><li><a href="http://www.trendware.com/products/TEW-411BRP.htm">TRENDnet TEW-411BRP 802.11g Wireless AP/Router/Switch</a>
+ <br>Source for busybox and udhcp <a href="http://www.trendware.com/asp/download/fileinfo.asp?file_id=277&amp;B1=Search">here</a> though no kernel source is provided.
+</li><li><a href="http://www.buffalo-technology.com/webcontent/products/wireless/wbr-g54.htm">Buffalo WBR-G54 wireless router</a>
+ </li><li><a href="http://www.asus.com/products/communication/wireless/wl-300g/overview.htm">ASUS WL-300g Wireless LAN Access Point</a>
+ <br>with source<a href="http://www.asus.com.tw/support/download/item.aspx?ModelName=WL-300G">here</a>
+ </li><li><a href="http://catalog.belkin.com/IWCatProductPage.process?Merchant_Id=&amp;Section_Id=201522&amp;pcount=&amp;Product_Id=136493">Belkin 54g Wireless DSL/Cable Gateway Router</a>
+ <br>with source<a href="http://web.belkin.com/support/gpl.asp">here</a>
+ <li><a href="http://www.acronis.com/products/partitionexpert/">Acronis PartitionExpert 2003</a>
+ <br>includes a heavily modified BusyBox v0.60.5 with built in
+ cardmgr, device detection, gpm, lspci, etc. Also includes udhcp,
+ uClibc 0.9.26, a heavily patched up linux kernel, etc. Source
+ can only be obtained <a href="http://www.acronis.com/files/gpl/linux.tar.bz2">here</a>
+
+</li><li><a href="http://www.usr.com/">U.S. Robotics Sureconnect 4-port ADSL router</a><br>
+ with source <a href="http://www.usr.com/support/s-gpl-code.asp">here</a>
+</li><li><a href="http://www.actiontec.com/products/broadband/54mbps_wireless_gateway_1p/index.html">
+ ActionTec GT701-WG Wireless Gateway/DSL Modem</a>
+ with source <a href="http://128.121.226.214/gtproducts/index.html">here</a>
+</li><li><a href="http://smartlinux.sourceforge.net/">S.M.A.R.T. Linux</a>
+</li><li><a href="http://www.dlink.com/">DLink - Model GSL-G604T, DSL-300T, and possibly other models</a>
+ with source <a href="ftp://ftp.dlink.co.uk/dsl_routers_modems/">here,</a>
+ with source <a href="ftp://ftp.dlink.de/dsl-products/">and here,</a>
+ and quite possibly other places as well. You may need to dig down a bit
+ to find the source, but it does seem to be there.
+</li><li><a href="http://www.siemens-mobile.de/cds/frontdoor/0,2241,de_de_0_42931_rArNrNrNrN,00.html">Siemens SE515 DSL router</a>
+ with source <a href="http://now-portal.c-lab.de/projects/gigaset/">here, I think...</a>
+ with some details <a href="http://heinz.hippenstiel.org/familie/hp/hobby/gigaset_se515dsl.html">here.</a>
+</li><li><a href="http://freeterm.spb.ru/frwt/">Free Remote Windows Terminal</a>
+
+</li><li><a href="http://www.zyxel.com/">ZyXEL Routers</a>
+
+</li>
+</ul>
+
+
+<!--#include file="footer.html" -->
+
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/screenshot.html b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/screenshot.html
new file mode 100644
index 0000000000..c5ef18bc74
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/screenshot.html
@@ -0,0 +1,75 @@
+<!--#include file="header.html" -->
+
+
+<!-- Begin Screenshot -->
+
+<h3> Busybox Screenshot! </h3>
+
+
+Everybody loves to look at screenshots, so here is a live action screenshot of BusyBox.
+
+<pre style="background-color: black; color: lightgreen; padding: 5px;
+font-family: monospace; font-size: smaller;" width="100">
+
+$ busybox
+BusyBox v1.10.1 (2008-04-24 11:30:07 CEST) multi-call binary
+Copyright (C) 1998-2007 Erik Andersen, Rob Landley, Denys Vlasenko
+and others. Licensed under GPLv2.
+See source distribution for full notice.
+
+Usage: busybox [function] [arguments]...
+ or: function [arguments]...
+
+ BusyBox is a multi-call binary that combines many common Unix
+ utilities into a single executable. Most people will create a
+ link to busybox for each function they wish to use and BusyBox
+ will act like whatever it was invoked as!
+
+Currently defined functions:
+ [, [[, addgroup, adduser, adjtimex, ar, arp, arping, ash,
+ awk, basename, bbconfig, brctl, bunzip2, bzcat, bzip2,
+ cal, cat, catv, chat, chattr, chcon, chgrp, chmod, chown,
+ chpasswd, chpst, chroot, chrt, chvt, cksum, clear, cmp,
+ comm, cp, cpio, crond, crontab, cryptpw, cttyhack, cut,
+ date, dc, dd, deallocvt, delgroup, deluser, devfsd, df,
+ dhcprelay, diff, dirname, dmesg, dnsd, dos2unix, dpkg,
+ dpkg-deb, du, dumpkmap, dumpleases, echo, ed, egrep, eject,
+ env, envdir, envuidgid, ether-wake, expand, expr, fakeidentd,
+ false, fbset, fdflush, fdformat, fdisk, fetchmail, fgrep,
+ find, findfs, fold, free, freeramdisk, fsck, fsck.minix,
+ ftpget, ftpput, fuser, getenforce, getopt, getsebool,
+ getty, grep, gunzip, gzip, halt, hd, hdparm, head, hexdump,
+ hostid, hostname, httpd, hush, hwclock, id, ifconfig,
+ ifdown, ifenslave, ifup, inetd, init, insmod, install,
+ ip, ipaddr, ipcalc, ipcrm, ipcs, iplink, iproute, iprule,
+ iptunnel, kbd_mode, kill, killall, killall5, klogd, lash,
+ last, length, less, linux32, linux64, linuxrc, ln, load_policy,
+ loadfont, loadkmap, logger, login, logname, logread, losetup,
+ lpd, lpq, lpr, ls, lsattr, lsmod, lzmacat, makedevs, matchpathcon,
+ md5sum, mdev, mesg, microcom, mkdir, mkfifo, mkfs.minix,
+ mknod, mkswap, mktemp, modprobe, more, mount, mountpoint,
+ msh, mt, mv, nameif, nc, netstat, nice, nmeter, nohup,
+ nslookup, od, openvt, passwd, patch, pgrep, pidof, ping,
+ ping6, pipe_progress, pivot_root, pkill, poweroff, printenv,
+ printf, ps, pscan, pwd, raidautorun, rdate, readahead,
+ readlink, readprofile, realpath, reboot, renice, reset,
+ resize, restorecon, rm, rmdir, rmmod, route, rpm, rpm2cpio,
+ rtcwake, run-parts, runcon, runlevel, runsv, runsvdir,
+ rx, script, sed, selinuxenabled, sendmail, seq, sestatus,
+ setarch, setconsole, setenforce, setfiles, setkeycodes,
+ setlogcons, setsebool, setsid, setuidgid, sha1sum, slattach,
+ sleep, softlimit, sort, split, start-stop-daemon, stat,
+ strings, stty, su, sulogin, sum, sv, svlogd, swapoff,
+ swapon, switch_root, sync, sysctl, syslogd, tac, tail,
+ tar, taskset, tcpsvd, tee, telnet, telnetd, test, tftp,
+ tftpd, time, top, touch, tr, traceroute, true, tty, ttysize,
+ udhcpc, udhcpd, udpsvd, umount, uname, uncompress, unexpand,
+ uniq, unix2dos, unlzma, unzip, uptime, usleep, uudecode,
+ uuencode, vconfig, vi, vlock, watch, watchdog, wc, wget,
+ which, who, whoami, xargs, yes, zcat, zcip
+
+$ <span style="text-decoration:blink;">_</span>
+
+</pre>
+
+<!--#include file="footer.html" -->
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/shame.html b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/shame.html
new file mode 100644
index 0000000000..d9da44b697
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/shame.html
@@ -0,0 +1,82 @@
+<!--#include file="header.html" -->
+
+
+<h3>Hall of Shame!!!</h3>
+
+<p>This page is no longer updated, these days we forward this sort of
+thing to the <a href="http://www.softwarefreedom.org">Software Freedom Law
+Center</a> instead.</p>
+
+<p>The following products and/or projects appear to use BusyBox, but do not
+appear to release source code as required by the <a
+href="/license.html">BusyBox license</a>. This is a violation of the law!
+The distributors of these products are invited to contact <a href=
+"mailto:andersen@codepoet.org">Erik Andersen</a> if they have any confusion
+as to what is needed to bring their products into compliance, or if they have
+already brought their product into compliance and wish to be removed from the
+Hall of Shame.
+
+<p>
+
+Here are the details of <a href="/license.html">exactly how to comply
+with the BusyBox license</a>, so there should be no question as to
+exactly what is expected.
+Complying with the Busybox license is easy and completely free, so the
+companies listed below should be ashamed of themselves. Furthermore, each
+product listed here is subject to being legally ordered to cease and desist
+distribution for violation of copyright law, and the distributor of each
+product is subject to being sued for statutory copyright infringement damages
+of up to $150,000 per work plus legal fees. Nobody wants to be sued, and <a
+href="mailto:andersen@codepoet.org">Erik</a> certainly would prefer to spend
+his time doing better things than sue people. But he will sue if forced to
+do so to maintain compliance.
+
+<p>
+
+Do everyone a favor and don't break the law -- if you use busybox, comply with
+the busybox license by releasing the source code with your product.
+
+<p>
+
+<ul>
+
+ <li><a href="http://www.trittontechnologies.com/products.html">Tritton Technologies NAS120</a>
+ <br>see <a href="http://www.ussg.iu.edu/hypermail/linux/kernel/0404.0/1611.html">here for details</a>
+ <li><a href="http://www.macsense.com/product/homepod/">Macsense HomePod</a>
+ <br>with details
+ <a href="http://developer.gloolabs.com/modules.php?op=modload&amp;name=Forums&amp;file=viewtopic&amp;topic=123&amp;forum=7">here</a>
+ <li><a href="http://www.cpx.com/products.asp?c=Wireless+Products">Compex Wireless Products</a>
+ <br>appears to be running v0.60.5 with Linux version 2.4.20-uc0 on ColdFire,
+ but no source code is mentioned or offered.
+ <li><a href="http://www.inventel.com/en/product/datasheet/10/">Inventel DW 200 wireless/ADSL router</a>
+ <li><a href="http://www.sweex.com/product.asp">Sweex DSL router</a>
+ <br>appears to be running BusyBox v1.00-pre2 and udhcpd, but no source
+ code is mentioned or offered.
+ <li><a href="http://www.trendware.com/products/TEW-410APB.htm">TRENDnet TEW-410APB</a>
+ </li><li><a href="http://www.hauppauge.com/Pages/products/data_mediamvp.html">Hauppauge Media MVP</a>
+ <br>Hauppauge contacted me on 16 Dec 2003, and claims to be working on resolving this problem.
+ </li><li><a href="http://www.hitex.com/download/adescom/data/">TriCore</a>
+ </li><li><a href="http://www.allnet.de/">ALLNET 0186 wireless router</a>
+ </li><li><a href="http://www.dmmtv.com/">Dreambox DM7000S DVB Satellite Receiver</a>
+ <br> Dream Multimedia contacted me on 22 Dec 2003 and is working on resolving this problem.
+ <br> Source _may_ be here: http://cvs.tuxbox.org/cgi-bin/viewcvs.cgi/tuxbox/cdk/
+ </li><li><a href="http://testing.lkml.org/slashdot.php?mid=331690">Sigma Designs EM8500 based DVD players</a>
+ <br>Source for the Sigma Designs reference platform is found here<br>
+ <a href="http://www.uclinux.org/pub/uClinux/ports/arm/EM8500/uClinux-2.4-sigma.tar.gz">uClinux-2.4-sigma.tar.gz</a>, so while Sigma Designs itself appears to be in compliance, as far as I can tell,
+ no vendors of Sigma Designs EM8500 based devices actually comply with the GPL....
+ </li><li><a href="http://testing.lkml.org/slashdot.php?mid=433790">Liteon LVD2001 DVD player using the Sigma Designs EM8500</a>
+ </li><li><a href="http://www.rimax.net/">Rimax DVD players using the Sigma Designs EM8500</a>
+ </li><li><a href="http://www.vinc.us/">Bravo DVD players using the Sigma Designs EM8500</a>
+ </li><li><a href="http://www.hb-direct.com/">H&amp;B DX3110 Divx player based on Sigma Designs EM8500</a>
+ </li><li><a href="http://www.recospa.it/mdpro1/index.php">United *DVX4066 mpeg4 capable DVD players</a>
+ </li><li><a href="http://www.a-link.com/RR64AP.html">Avaks alink Roadrunner 64</a>
+ <br> Partial source available, based on source distributed under NDA from <a href="http://www.lsilogic.com/products/dsl_platform_solutions/hb_linuxr2_2.html"> LSILogic</a>. Why the NDA LSILogic, what are you hiding ?
+ <br>To verify the Avaks infrigment see my slashdot <a href="http://slashdot.org/~bug1/journal/">journal</a>.
+ <br>The ZipIt wireless IM device appears to be using Busybox-1.00-pre1 in the ramdisk, however no source has been made available.
+ </li><li>Undoubtedly there are others... Please report them so we can shame them (or if necessary sue them) into compliance.
+
+</ul>
+
+
+<!--#include file="footer.html" -->
+
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/sponsors.html b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/sponsors.html
new file mode 100644
index 0000000000..2488647d3e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/sponsors.html
@@ -0,0 +1,52 @@
+<!--#include file="header.html" -->
+
+<h3>Sponsors</h3>
+
+<p>Please visit our sponsors and thank them for their support! They have
+provided money for equipment and bandwidth. Next time you need help with a
+project, consider these fine companies!</p>
+
+
+<ul>
+ <li><a href="http://osuosl.org/">OSU OSL</a><br>
+ OSU OSL kindly provides hosting for BusyBox and uClibc.
+ </li>
+
+ <li><a href="http://www.codepoet-consulting.com">Codepoet Consulting</a><br>
+ Custom Linux, embedded Linux, BusyBox, and uClibc development.
+ </li>
+
+ <li>AOE media, a <a href=http://www.aoemedia.com/typo3-development.html>
+ TYPO3 development agency</a> contributes financially.
+ </li>
+
+ <li><a href=http://www.analog.com/en/>Analog Devices, Inc.</a> provided
+ a <a href=http://docs.blackfin.uclinux.org/doku.php?id=bf537_quick_start>
+ Blackfin development board</a> free of charge.
+ <a href=http://www.analog.com/blackfin>Blackfin<a>
+ is a NOMMU processor, and its availability for testing is invaluable.
+ If you are an embedded device developer,
+ please note that Analog Devices has entire Linux distribution available
+ for download for this board. Visit
+ <a href=http://blackfin.uclinux.org/>http://blackfin.uclinux.org/</a>
+ for more information.
+ </li>
+
+ <li><a href="http://www.timesys.com">TimeSys</a><br>
+ Embedded Linux development, cross-compilers, real-time, KGDB, tsrpm and cygwin.
+ </li>
+
+ <li><a href="http://www.penguru.net">Penguru Consulting</a><br>
+ Custom development for embedded Linux systems and multimedia platforms.
+ </li>
+
+ <li><a href="http://opensource.se/">opensource.se</a><br>
+ Embedded open source consulting in Europe.
+ </li>
+
+</ul>
+
+<p>If you wish to be a sponsor, or if you have already contributed and would
+like your name added here, email <a href="mailto:vda.linux@gmail.com">Denys</a>.</p>
+
+<!--#include file="footer.html" -->
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/subversion.html b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/subversion.html
new file mode 100644
index 0000000000..561a5b80b7
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/subversion.html
@@ -0,0 +1,51 @@
+<!--#include file="header.html" -->
+
+<h3>Accessing Source</h3>
+
+
+
+<h3>Patches</h3>
+
+<p>You can <a href="/downloads/">download</a> fixes for particular releases
+of busybox, e.g. downloads/fixes-<em>major</em>-<em>minor</em>-<em>patch</em>/
+
+<h3>Anonymous Subversion Access</h3>
+
+We allow anonymous (read-only) Subversion (svn) access to everyone. To
+grab a copy of the latest version of BusyBox using anonymous svn access:
+
+<pre>
+svn co svn://busybox.net/trunk/busybox</pre>
+
+<p>
+The current <em>stable branch</em> can be obtained with
+<pre>
+svn co svn://busybox.net/branches/busybox_1_9_stable
+</pre>
+
+<p>
+
+If you are not already familiar with using Subversion, I recommend you visit <a
+href="http://subversion.tigris.org/">the Subversion website</a>. You might
+also want to read online or buy a copy of <a
+href="http://svnbook.red-bean.com/">the Subversion Book</a>. If you are
+already comfortable with using CVS, you may want to skip ahead to the <a
+href="http://svnbook.red-bean.com/en/1.1/apa.html">Subversion for CVS Users</a>
+part of the Subversion Book.
+
+<p>
+
+Once you've checked out a copy of the source tree, you can update your source
+tree at any time so it is in sync with the latest and greatest by entering your
+BusyBox directory and running the command:
+
+<pre>
+svn update</pre>
+
+Because you've only been granted anonymous access to the tree, you won't be
+able to commit any changes. Changes can be submitted for inclusion by posting
+them to the BusyBox mailing list. For those that are actively contributing
+<a href="developer.html">Subversion commit access</a> can be made available.
+
+<!--#include file="footer.html" -->
+
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/tinyutils.html b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/tinyutils.html
new file mode 100644
index 0000000000..9122d6e352
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox.net/tinyutils.html
@@ -0,0 +1,86 @@
+<!--#include file="header.html" -->
+
+
+<h3>External Tiny Utilities</h3>
+
+This is a list of tiny utilities whose functionality is not provided by
+busybox. If you have additional suggestions, please send an e-mail to our
+dev mailing list.
+
+<br><br>
+
+<table border=1>
+<tr>
+ <th>Feature</th>
+ <th>Utilities</th>
+</tr>
+
+<tr>
+ <td>SSH</td>
+ <td><a href="http://matt.ucc.asn.au/dropbear/">Dropbear</a> has both an ssh server and an ssh client that together come in around 100k. It has no external
+dependencies (I.E. it does not depend on OpenSSL, using a built-in copy of
+LibTomCrypt instead). It's actively maintained, with a quiet but responsive
+mailing list.</td>
+</tr>
+
+<tr>
+ <td>SMTP</td>
+ <td><a href="ftp://ftp.debian.org/debian/pool/main/s/ssmtp/">ssmtp</a> is an extremely simple Mail Transfer Agent.</td>
+</tr>
+
+<tr>
+ <td>ntp</td>
+ <td><a href="http://doolittle.icarus.com/ntpclient/">ntpclient</a> is a
+tiny ntp client. BusyBox has rdate to set the date from a remote server, but
+if you want a daemon to repeatedly adjust the clock over time, try that.</td>
+</table>
+
+<p>In a gui environment, you'll probably want a web browser.
+<a href="http://www.konqueror.org/embedded/">Konqueror Embedded</a> requires QT
+(or QT Embedded), but not KDE. The <a href="http://www.dillo.org/">Dillo</a>
+requires GTK+, but not Gnome. Or you can try the <a href="http://links.twibright.com/">graphical
+version of links</a>.</p>
+
+<h3>SCRIPTING LANGUAGES</h3>
+<p>Although busybox has built-in support for shell scripts, plenty of other
+small scripting languages are available on the net. A few examples:</p>
+<table border=1>
+<tr>
+<th><language></th>
+<th><description></th>
+</tr>
+<tr>
+<td> <a href=http://www.foo.be/docs/tpj/issues/vol5_3/tpj0503-0003.html>microperl</a> </td>
+<td> A small standalone perl interpreter that can be built from the perl source
+s via "make -f Makefile.micro". If you really feel the need for perl on an embe
+dded system, this is where to start.
+</tr>
+<tr>
+
+<td><a href=http://www.lua.org/pil/>Lua</a></td>
+<td>If you just want a small embedded scripting language to write <em>new</en>
+code in, this Brazilian import is lightweight, fairly popular, and has
+a complete book about it online.</td>
+</tr>
+
+<tr>
+<td><a href= http://www.star.le.ac.uk/%7Etjg/rc/>rc</a></td>
+<td>The PLAN9 shell. Not compatible with conventional bourne shell syntax,
+but fairly lightweight and small.</td>
+</tr>
+
+</tr>
+<tr>
+<td><a href=http://www.forth.org>forth</a></td>
+<td>A well known language for fast and small programs, decades old but still
+in use for everything from OpenBIOS to computer controlled engine timing.</td>
+</tr>
+</table>
+
+<p>For more information, you probably want to look at
+<a href=http://buildroot.uclibc.org>buildroot</a> and
+<a href=http://gentoo-wiki.com/TinyGentoo>TinyGentoo</a>, which
+build and use tiny utilities for all sorts of things.</p>
+
+<!--#include file="footer.html" -->
+
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox_footer.pod b/cleopatre/busybox-1.11.1-spc300/docs/busybox_footer.pod
new file mode 100644
index 0000000000..74575bdac3
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox_footer.pod
@@ -0,0 +1,256 @@
+=back
+
+=head1 LIBC NSS
+
+GNU Libc (glibc) uses the Name Service Switch (NSS) to configure the behavior
+of the C library for the local environment, and to configure how it reads
+system data, such as passwords and group information. This is implemented
+using an /etc/nsswitch.conf configuration file, and using one or more of the
+/lib/libnss_* libraries. BusyBox tries to avoid using any libc calls that make
+use of NSS. Some applets however, such as login and su, will use libc functions
+that require NSS.
+
+If you enable CONFIG_USE_BB_PWD_GRP, BusyBox will use internal functions to
+directly access the /etc/passwd, /etc/group, and /etc/shadow files without
+using NSS. This may allow you to run your system without the need for
+installing any of the NSS configuration files and libraries.
+
+When used with glibc, the BusyBox 'networking' applets will similarly require
+that you install at least some of the glibc NSS stuff (in particular,
+/etc/nsswitch.conf, /lib/libnss_dns*, /lib/libnss_files*, and /lib/libresolv*).
+
+Shameless Plug: As an alternative, one could use a C library such as uClibc. In
+addition to making your system significantly smaller, uClibc does not require the
+use of any NSS support files or libraries.
+
+=head1 MAINTAINER
+
+Denis Vlasenko <vda.linux@googlemail.com>
+
+=head1 AUTHORS
+
+The following people have contributed code to BusyBox whether they know it or
+not. If you have written code included in BusyBox, you should probably be
+listed here so you can obtain your bit of eternal glory. If you should be
+listed here, or the description of what you have done needs more detail, or is
+incorect, please send in an update.
+
+
+=for html <br>
+
+Emanuele Aina <emanuele.aina@tiscali.it>
+ run-parts
+
+=for html <br>
+
+Erik Andersen <andersen@codepoet.org>
+
+ Tons of new stuff, major rewrite of most of the
+ core apps, tons of new apps as noted in header files.
+ Lots of tedious effort writing these boring docs that
+ nobody is going to actually read.
+
+=for html <br>
+
+Laurence Anderson <l.d.anderson@warwick.ac.uk>
+
+ rpm2cpio, unzip, get_header_cpio, read_gz interface, rpm
+
+=for html <br>
+
+Jeff Angielski <jeff@theptrgroup.com>
+
+ ftpput, ftpget
+
+=for html <br>
+
+Edward Betts <edward@debian.org>
+
+ expr, hostid, logname, whoami
+
+=for html <br>
+
+John Beppu <beppu@codepoet.org>
+
+ du, nslookup, sort
+
+=for html <br>
+
+Brian Candler <B.Candler@pobox.com>
+
+ tiny-ls(ls)
+
+=for html <br>
+
+Randolph Chung <tausq@debian.org>
+
+ fbset, ping, hostname
+
+=for html <br>
+
+Dave Cinege <dcinege@psychosis.com>
+
+ more(v2), makedevs, dutmp, modularization, auto links file,
+ various fixes, Linux Router Project maintenance
+
+=for html <br>
+
+Jordan Crouse <jordan@cosmicpenguin.net>
+
+ ipcalc
+
+=for html <br>
+
+Magnus Damm <damm@opensource.se>
+
+ tftp client insmod powerpc support
+
+=for html <br>
+
+Larry Doolittle <ldoolitt@recycle.lbl.gov>
+
+ pristine source directory compilation, lots of patches and fixes.
+
+=for html <br>
+
+Glenn Engel <glenne@engel.org>
+
+ httpd
+
+=for html <br>
+
+Gennady Feldman <gfeldman@gena01.com>
+
+ Sysklogd (single threaded syslogd, IPC Circular buffer support,
+ logread), various fixes.
+
+=for html <br>
+
+Karl M. Hegbloom <karlheg@debian.org>
+
+ cp_mv.c, the test suite, various fixes to utility.c, &c.
+
+=for html <br>
+
+Daniel Jacobowitz <dan@debian.org>
+
+ mktemp.c
+
+=for html <br>
+
+Matt Kraai <kraai@alumni.cmu.edu>
+
+ documentation, bugfixes, test suite
+
+=for html <br>
+
+Stephan Linz <linz@li-pro.net>
+
+ ipcalc, Red Hat equivalence
+
+=for html <br>
+
+John Lombardo <john@deltanet.com>
+
+ tr
+
+=for html <br>
+
+Glenn McGrath <bug1@iinet.net.au>
+
+ Common unarchving code and unarchiving applets, ifupdown, ftpgetput,
+ nameif, sed, patch, fold, install, uudecode.
+ Various bugfixes, review and apply numerous patches.
+
+=for html <br>
+
+Manuel Novoa III <mjn3@codepoet.org>
+
+ cat, head, mkfifo, mknod, rmdir, sleep, tee, tty, uniq, usleep, wc, yes,
+ mesg, vconfig, make_directory, parse_mode, dirname, mode_string,
+ get_last_path_component, simplify_path, and a number trivial libbb routines
+
+ also bug fixes, partial rewrites, and size optimizations in
+ ash, basename, cal, cmp, cp, df, du, echo, env, ln, logname, md5sum, mkdir,
+ mv, realpath, rm, sort, tail, touch, uname, watch, arith, human_readable,
+ interface, dutmp, ifconfig, route
+
+=for html <br>
+
+Vladimir Oleynik <dzo@simtreas.ru>
+
+ cmdedit; xargs(current), httpd(current);
+ ports: ash, crond, fdisk, inetd, stty, traceroute, top;
+ locale, various fixes
+ and irreconcilable critic of everything not perfect.
+
+=for html <br>
+
+Bruce Perens <bruce@pixar.com>
+
+ Original author of BusyBox in 1995, 1996. Some of his code can
+ still be found hiding here and there...
+
+=for html <br>
+
+Tim Riker <Tim@Rikers.org>
+
+ bug fixes, member of fan club
+
+=for html <br>
+
+Kent Robotti <robotti@metconnect.com>
+
+ reset, tons and tons of bug reports and patches.
+
+=for html <br>
+
+Chip Rosenthal <chip@unicom.com>, <crosenth@covad.com>
+
+ wget - Contributed by permission of Covad Communications
+
+=for html <br>
+
+Pavel Roskin <proski@gnu.org>
+
+ Lots of bugs fixes and patches.
+
+=for html <br>
+
+Gyepi Sam <gyepi@praxis-sw.com>
+
+ Remote logging feature for syslogd
+
+=for html <br>
+
+Linus Torvalds <torvalds@transmeta.com>
+
+ mkswap, fsck.minix, mkfs.minix
+
+=for html <br>
+
+Mark Whitley <markw@codepoet.org>
+
+ grep, sed, cut, xargs(previous),
+ style-guide, new-applet-HOWTO, bug fixes, etc.
+
+=for html <br>
+
+Charles P. Wright <cpwright@villagenet.com>
+
+ gzip, mini-netcat(nc)
+
+=for html <br>
+
+Enrique Zanardi <ezanardi@ull.es>
+
+ tarcat (since removed), loadkmap, various fixes, Debian maintenance
+
+=for html <br>
+
+Tito Ragusa <farmatito@tiscali.it>
+
+ devfsd and size optimizations in strings, openvt and deallocvt.
+
+=cut
+
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/busybox_header.pod b/cleopatre/busybox-1.11.1-spc300/docs/busybox_header.pod
new file mode 100644
index 0000000000..804b839703
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/busybox_header.pod
@@ -0,0 +1,82 @@
+# vi: set sw=4 ts=4:
+
+=head1 NAME
+
+BusyBox - The Swiss Army Knife of Embedded Linux
+
+=head1 SYNTAX
+
+ BusyBox <function> [arguments...] # or
+
+ <function> [arguments...] # if symlinked
+
+=head1 DESCRIPTION
+
+BusyBox combines tiny versions of many common UNIX utilities into a single
+small executable. It provides minimalist replacements for most of the utilities
+you usually find in GNU coreutils, util-linux, etc. The utilities in BusyBox
+generally have fewer options than their full-featured GNU cousins; however, the
+options that are included provide the expected functionality and behave very
+much like their GNU counterparts.
+
+BusyBox has been written with size-optimization and limited resources in mind.
+It is also extremely modular so you can easily include or exclude commands (or
+features) at compile time. This makes it easy to customize your embedded
+systems. To create a working system, just add /dev, /etc, and a Linux kernel.
+BusyBox provides a fairly complete POSIX environment for any small or embedded
+system.
+
+BusyBox is extremely configurable. This allows you to include only the
+components you need, thereby reducing binary size. Run 'make config' or 'make
+menuconfig' to select the functionality that you wish to enable. Then run
+'make' to compile BusyBox using your configuration.
+
+After the compile has finished, you should use 'make install' to install
+BusyBox. This will install the 'bin/busybox' binary, in the target directory
+specified by CONFIG_PREFIX. CONFIG_PREFIX can be set when configuring BusyBox,
+or you can specify an alternative location at install time (i.e., with a
+command line like 'make CONFIG_PREFIX=/tmp/foo install'). If you enabled
+any applet installation scheme (either as symlinks or hardlinks), these will
+also be installed in the location pointed to by CONFIG_PREFIX.
+
+=head1 USAGE
+
+BusyBox is a multi-call binary. A multi-call binary is an executable program
+that performs the same job as more than one utility program. That means there
+is just a single BusyBox binary, but that single binary acts like a large
+number of utilities. This allows BusyBox to be smaller since all the built-in
+utility programs (we call them applets) can share code for many common operations.
+
+You can also invoke BusyBox by issuing a command as an argument on the
+command line. For example, entering
+
+ /bin/busybox ls
+
+will also cause BusyBox to behave as 'ls'.
+
+Of course, adding '/bin/busybox' into every command would be painful. So most
+people will invoke BusyBox using links to the BusyBox binary.
+
+For example, entering
+
+ ln -s /bin/busybox ls
+ ./ls
+
+will cause BusyBox to behave as 'ls' (if the 'ls' command has been compiled
+into BusyBox). Generally speaking, you should never need to make all these
+links yourself, as the BusyBox build system will do this for you when you run
+the 'make install' command.
+
+If you invoke BusyBox with no arguments, it will provide you with a list of the
+applets that have been compiled into your BusyBox binary.
+
+=head1 COMMON OPTIONS
+
+Most BusyBox commands support the B<--help> argument to provide a terse runtime
+description of their behavior. If the CONFIG_FEATURE_VERBOSE_USAGE option has
+been enabled, more detailed usage information will also be available.
+
+=head1 COMMANDS
+
+Currently defined functions include:
+
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/cgi/cl.html b/cleopatre/busybox-1.11.1-spc300/docs/cgi/cl.html
new file mode 100644
index 0000000000..5779d623ec
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/cgi/cl.html
@@ -0,0 +1,46 @@
+<html><head><title>CGI Command line options</title></head><body><h1><img alt="" src="cl_files/CGIlogo.gif"> CGI Command line options</h1>
+<hr> <p>
+
+</p><h2>Specification</h2>
+
+The command line is only used in the case of an ISINDEX query. It is
+not used in the case of an HTML form or any as yet undefined query
+type. The server should search the query information (the <code>QUERY_STRING</code> environment variable) for a non-encoded
+= character to determine if the command line is to be used, if it
+finds one, the command line is not to be used. This trusts the clients
+to encode the = sign in ISINDEX queries, a practice which was
+considered safe at the time of the design of this specification. <p>
+
+For example, use the <a href="http://hoohoo.ncsa.uiuc.edu/cgi-bin/finger">finger script</a> and the ISINDEX interface to look up "httpd". You will see that the script will call itself with <code>/cgi-bin/finger?httpd</code> and will actually execute "finger httpd" on the command line and output the results to you.
+</p><p>
+If the server does find a "=" in the <code>QUERY_STRING</code>,
+then the command line will not be used, and no decoding will be
+performed. The query then remains intact for processing by an
+appropriate FORM submission decoder.
+Again, as an example, use <a href="http://hoohoo.ncsa.uiuc.edu/cgi-bin/finger?httpd=name">this hyperlink</a> to submit <code>"httpd=name"</code> to the finger script. Since this <code>QUERY_STRING</code>
+contained an unencoded "=", nothing was decoded, the script didn't know
+it was being submitted a valid query, and just gave you the default
+finger form.
+</p><p>
+If the server finds that it cannot send the string due to internal
+limitations (such as exec() or /bin/sh command line restrictions) the
+server should include NO command line information and provide the
+non-decoded query information in the environment
+variable <a href="http://hoohoo.ncsa.uiuc.edu/cgi/env.html#query"><code>QUERY_STRING</code></a>. </p><p>
+</p><hr>
+<h2>Examples</h2>
+
+Examples of the command line usage are much better <a href="http://hoohoo.ncsa.uiuc.edu/cgi/examples.html">demonstrated</a> than explained. For these
+examples, pay close attention to the script output which says what
+argc and argv are. <p>
+
+</p><hr>
+
+<a href="http://hoohoo.ncsa.uiuc.edu/cgi/interface.html"><img alt="[Back]" src="cl_files/back.gif">Return to the
+interface specification</a> <p>
+
+CGI - Common Gateway Interface
+</p><address><a href="http://hoohoo.ncsa.uiuc.edu/cgi/mailtocgi.html">cgi@ncsa.uiuc.edu</a></address>
+
+
+</body></html> \ No newline at end of file
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/cgi/env.html b/cleopatre/busybox-1.11.1-spc300/docs/cgi/env.html
new file mode 100644
index 0000000000..924026b3ee
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/cgi/env.html
@@ -0,0 +1,149 @@
+<html><head><title>CGI Environment Variables</title></head><body><h1><img alt="" src="env_files/CGIlogo.gif"> CGI Environment Variables</h1>
+<hr>
+
+<p>
+
+In order to pass data about the information request from the server to
+the script, the server uses command line arguments as well as
+environment variables. These environment variables are set when the
+server executes the gateway program. </p><p>
+
+</p><hr>
+<h2>Specification</h2>
+
+ <p>
+The following environment variables are not request-specific and are
+set for all requests: </p><p>
+
+</p><ul>
+<li> <code>SERVER_SOFTWARE</code> <p>
+
+ The name and version of the information server software answering
+ the request (and running the gateway). Format: name/version </p><p>
+
+</p></li><li> <code>SERVER_NAME</code> <p>
+ The server's hostname, DNS alias, or IP address as it would appear
+ in self-referencing URLs. </p><p>
+
+</p></li><li> <code>GATEWAY_INTERFACE</code> <p>
+ The revision of the CGI specification to which this server
+ complies. Format: CGI/revision</p><p>
+
+</p></li></ul>
+
+<hr>
+
+The following environment variables are specific to the request being
+fulfilled by the gateway program: <p>
+
+</p><ul>
+<li> <a name="protocol"><code>SERVER_PROTOCOL</code></a> <p>
+ The name and revision of the information protcol this request came
+ in with. Format: protocol/revision </p><p>
+
+</p></li><li> <code>SERVER_PORT</code> <p>
+ The port number to which the request was sent. </p><p>
+
+</p></li><li> <code>REQUEST_METHOD</code> <p>
+ The method with which the request was made. For HTTP, this is
+ "GET", "HEAD", "POST", etc. </p><p>
+
+</p></li><li> <code>PATH_INFO</code> <p>
+ The extra path information, as given by the client. In other
+ words, scripts can be accessed by their virtual pathname, followed
+ by extra information at the end of this path. The extra
+ information is sent as PATH_INFO. This information should be
+ decoded by the server if it comes from a URL before it is passed
+ to the CGI script.</p><p>
+
+</p></li><li> <code>PATH_TRANSLATED</code> <p>
+ The server provides a translated version of PATH_INFO, which takes
+ the path and does any virtual-to-physical mapping to it. </p><p>
+
+</p></li><li> <code>SCRIPT_NAME</code> <p>
+ A virtual path to the script being executed, used for
+ self-referencing URLs. </p><p>
+
+</p></li><li> <a name="query"><code>QUERY_STRING</code></a> <p>
+ The information which follows the ? in the <a href="http://www.ncsa.uiuc.edu/demoweb/url-primer.html">URL</a>
+ which referenced this script. This is the query information. It
+ should not be decoded in any fashion. This variable should always
+ be set when there is query information, regardless of <a href="http://hoohoo.ncsa.uiuc.edu/cgi/cl.html">command line decoding</a>. </p><p>
+
+</p></li><li> <code>REMOTE_HOST</code> <p>
+ The hostname making the request. If the server does not have this
+ information, it should set REMOTE_ADDR and leave this unset.</p><p>
+
+</p></li><li> <code>REMOTE_ADDR</code> <p>
+ The IP address of the remote host making the request. </p><p>
+
+</p></li><li> <code>AUTH_TYPE</code> <p>
+ If the server supports user authentication, and the script is
+ protects, this is the protocol-specific authentication method used
+ to validate the user. </p><p>
+
+</p></li><li> <code>REMOTE_USER</code> <p>
+ If the server supports user authentication, and the script is
+ protected, this is the username they have authenticated as. </p><p>
+</p></li><li> <code>REMOTE_IDENT</code> <p>
+ If the HTTP server supports RFC 931 identification, then this
+ variable will be set to the remote user name retrieved from the
+ server. Usage of this variable should be limited to logging only.
+ </p><p>
+
+</p></li><li> <a name="ct"><code>CONTENT_TYPE</code></a> <p>
+ For queries which have attached information, such as HTTP POST and
+ PUT, this is the content type of the data. </p><p>
+
+</p></li><li> <a name="cl"><code>CONTENT_LENGTH</code></a> <p>
+ The length of the said content as given by the client. </p><p>
+
+</p></li></ul>
+
+
+<a name="headers"><hr></a>
+
+In addition to these, the header lines received from the client, if
+any, are placed into the environment with the prefix HTTP_ followed by
+the header name. Any - characters in the header name are changed to _
+characters. The server may exclude any headers which it has already
+processed, such as Authorization, Content-type, and Content-length. If
+necessary, the server may choose to exclude any or all of these
+headers if including them would exceed any system environment
+limits. <p>
+
+An example of this is the HTTP_ACCEPT variable which was defined in
+CGI/1.0. Another example is the header User-Agent.</p><p>
+
+</p><ul>
+<li> <code>HTTP_ACCEPT</code> <p>
+ The MIME types which the client will accept, as given by HTTP
+ headers. Other protocols may need to get this information from
+ elsewhere. Each item in this list should be separated by commas as
+ per the HTTP spec. </p><p>
+
+ Format: type/subtype, type/subtype </p><p>
+
+
+</p></li><li> <code>HTTP_USER_AGENT</code><p>
+
+ The browser the client is using to send the request. General
+format: <code>software/version library/version</code>.</p><p>
+
+</p></li></ul>
+
+<hr>
+<h2>Examples</h2>
+
+Examples of the setting of environment variables are really much better
+<a href="http://hoohoo.ncsa.uiuc.edu/cgi/examples.html">demonstrated</a> than explained. <p>
+
+</p><hr>
+
+<a href="http://hoohoo.ncsa.uiuc.edu/cgi/interface.html"><img alt="[Back]" src="env_files/back.gif">Return to the
+interface specification</a> <p>
+
+CGI - Common Gateway Interface
+</p><address><a href="http://hoohoo.ncsa.uiuc.edu/cgi/mailtocgi.html">cgi@ncsa.uiuc.edu</a></address>
+
+</body></html> \ No newline at end of file
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/cgi/in.html b/cleopatre/busybox-1.11.1-spc300/docs/cgi/in.html
new file mode 100644
index 0000000000..679306aaa0
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/cgi/in.html
@@ -0,0 +1,33 @@
+<html><head><title>CGI Script input</title></head><body><h1><img alt="" src="in_files/CGIlogo.gif"> CGI Script Input</h1>
+<hr>
+
+<h2>Specification</h2>
+
+For requests which have information attached after the header, such as
+HTTP POST or PUT, the information will be sent to the script on stdin.
+<p>
+
+The server will send <a href="http://hoohoo.ncsa.uiuc.edu/cgi/env.html#cl">CONTENT_LENGTH</a> bytes on
+this file descriptor. Remember that it will give the <a href="http://hoohoo.ncsa.uiuc.edu/cgi/env.html#ct">CONTENT_TYPE</a> of the data as well. The server is
+in no way obligated to send end-of-file after the script reads
+<code>CONTENT_LENGTH</code> bytes. </p><p>
+</p><hr>
+<h2>Example</h2>
+
+Let's take a form with METHOD="POST" as an example. Let's say the form
+results are 7 bytes encoded, and look like <code>a=b&amp;b=c</code>.
+<p>
+
+In this case, the server will set CONTENT_LENGTH to 7 and CONTENT_TYPE
+to application/x-www-form-urlencoded. The first byte on the script's
+standard input will be "a", followed by the rest of the encoded string.</p><p>
+
+</p><hr>
+
+<a href="http://hoohoo.ncsa.uiuc.edu/cgi/interface.html"><img alt="[Back]" src="in_files/back.gif">Return to the
+interface specification</a> <p>
+
+CGI - Common Gateway Interface
+</p><address><a href="http://hoohoo.ncsa.uiuc.edu/cgi/mailtocgi.html">cgi@ncsa.uiuc.edu</a></address>
+
+</body></html> \ No newline at end of file
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/cgi/interface.html b/cleopatre/busybox-1.11.1-spc300/docs/cgi/interface.html
new file mode 100644
index 0000000000..ea73ce3a24
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/cgi/interface.html
@@ -0,0 +1,29 @@
+<html><head><title>The Common Gateway Interface Specification
+[http://hoohoo.ncsa.uiuc.edu/cgi/interface.html]
+</title></head><body><h1><img alt="" src="interface_files/CGIlogo.gif"> The CGI Specification</h1>
+
+<hr>
+
+This is the specification for CGI version 1.1, or CGI/1.1. Further
+revisions of this protocol are guaranteed to be backward compatible.
+<p>
+
+The server and the CGI script communicate in four major ways. Each of
+the following is a hotlink to graphic detail.</p><p>
+
+</p><ul>
+<li> <a href="env.html">Environment variables</a>
+</li><li> <a href="cl.html">The command line</a>
+</li><li> <a href="in.html">Standard input</a>
+</li><li> <a href="out.html">Standard output</a>
+</li></ul>
+<hr>
+
+
+<a href="http://hoohoo.ncsa.uiuc.edu/cgi/overview.html"><img alt="[Back]" src="interface_files/back.gif">Return to the overview</a> <p>
+
+
+
+CGI - Common Gateway Interface
+</p><address><a href="http://hoohoo.ncsa.uiuc.edu/cgi/mailtocgi.html">cgi@ncsa.uiuc.edu</a></address>
+</body></html> \ No newline at end of file
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/cgi/out.html b/cleopatre/busybox-1.11.1-spc300/docs/cgi/out.html
new file mode 100644
index 0000000000..2203ee5a0a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/cgi/out.html
@@ -0,0 +1,126 @@
+<html><head><title>CGI Script output</title></head><body><h1><img alt="" src="out_files/CGIlogo.gif"> CGI Script Output</h1>
+<hr>
+
+<h2>Script output</h2>
+
+The script sends its output to stdout. This output can either be a
+document generated by the script, or instructions to the server for
+retrieving the desired output. <p>
+</p><hr>
+
+<h2>Script naming conventions</h2>
+
+Normally, scripts produce output which is interpreted and sent back to
+the client. An advantage of this is that the scripts do not need to
+send a full HTTP/1.0 header for every request. <p>
+<a name="nph">
+Some scripts may want to avoid the extra overhead of the server
+parsing their output, and talk directly to the client. In order to
+distinguish these scripts from the other scripts, CGI requires that
+the script name begins with nph- if a script does not want the server
+to parse its header. In this case, it is the script's responsibility
+to return a valid HTTP/1.0 (or HTTP/0.9) response to the client. </a></p><p>
+
+</p><hr>
+<h2><a name="nph">Parsed headers</a></h2>
+
+<a name="nph">The output of scripts begins with a small header. This header consists
+of text lines, in the same format as an </a><a href="http://www.w3.org/hypertext/WWW/Protocols/HTTP/Object_Headers.html">
+HTTP header</a>, terminated by a blank line (a line with only a
+linefeed or CR/LF). <p>
+
+Any headers which are not server directives are sent directly back to
+the client. Currently, this specification defines three server
+directives:</p><p>
+
+</p><ul>
+<li> <code>Content-type</code> <p>
+
+ This is the MIME type of the document you are returning. </p><p>
+
+</p></li><li> <code>Location</code> <p>
+
+ This is used to specify to the server that you are returning a
+ reference to a document rather than an actual document. </p><p>
+
+ If the argument to this is a URL, the server will issue a redirect
+ to the client. </p><p>
+
+ If the argument to this is a virtual path, the server will
+ retrieve the document specified as if the client had requested
+ that document originally. ? directives will work in here, but #
+ directives must be redirected back to the client.</p><p>
+
+
+</p></li><li> <a name="status"><code>Status</code></a><p>
+
+ This is used to give the server an HTTP/1.0 <a href="http://www.w3.org/hypertext/WWW/Protocols/HTTP/HTRESP.html">status
+line</a> to send to the client. The format is <code>nnn xxxxx</code>,
+where <code>nnn</code> is the 3-digit status code, and
+<code>xxxxx</code> is the reason string, such as "Forbidden".</p><p>
+
+</p></li></ul>
+
+<hr>
+<h2>Examples</h2>
+
+Let's say I have a fromgratz to HTML converter. When my converter is
+finished with its work, it will output the following on stdout (note
+that the lines beginning and ending with --- are just for illustration
+and would not be output): <p>
+
+</p><pre>--- start of output ---
+Content-type: text/html
+
+--- end of output ---
+</pre>
+
+Note the blank line after Content-type. <p>
+
+Now, let's say I have a script which, in certain instances, wants to
+return the document <code>/path/doc.txt</code> from this server just
+as if the user had actually requested
+<code>http://server:port/path/doc.txt</code> to begin with. In this
+case, the script would output: </p><p>
+</p><pre>--- start of output ---
+Location: /path/doc.txt
+
+--- end of output ---
+</pre>
+
+The server would then perform the request and send it to the client.
+<p>
+
+Let's say that I have a script which wants to reference our gopher
+server. In this case, if the script wanted to refer the user to
+<code>gopher://gopher.ncsa.uiuc.edu/</code>, it would output: </p><p>
+
+</p><pre>--- start of output ---
+Location: gopher://gopher.ncsa.uiuc.edu/
+
+--- end of output ---
+</pre>
+
+Finally, I have a script which wants to talk to the client directly.
+In this case, if the script is referenced with <a href="http://hoohoo.ncsa.uiuc.edu/cgi/env.html#protocol"><code>SERVER_PROTOCOL</code></a> of HTTP/1.0,
+the script would output the following HTTP/1.0 response: <p>
+
+</p><pre>--- start of output ---
+HTTP/1.0 200 OK
+Server: NCSA/1.0a6
+Content-type: text/plain
+
+This is a plaintext document generated on the fly just for you.
+
+--- end of output ---
+</pre>
+
+
+<hr>
+
+<a href="http://hoohoo.ncsa.uiuc.edu/cgi/interface.html"><img alt="[Back]" src="out_files/back.gif">Return to the
+interface specification</a> <p>
+
+CGI - Common Gateway Interface
+</p><address><a href="http://hoohoo.ncsa.uiuc.edu/cgi/mailtocgi.html">cgi@ncsa.uiuc.edu</a></address>
+</body></html> \ No newline at end of file
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/contributing.txt b/cleopatre/busybox-1.11.1-spc300/docs/contributing.txt
new file mode 100644
index 0000000000..aad43035c6
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/contributing.txt
@@ -0,0 +1,449 @@
+Contributing To Busybox
+=======================
+
+This document describes what you need to do to contribute to Busybox, where
+you can help, guidelines on testing, and how to submit a well-formed patch
+that is more likely to be accepted.
+
+The Busybox home page is at: http://busybox.net/
+
+
+
+Pre-Contribution Checklist
+--------------------------
+
+So you want to contribute to Busybox, eh? Great, wonderful, glad you want to
+help. However, before you dive in, headlong and hotfoot, there are some things
+you need to do:
+
+
+Checkout the Latest Code from CVS
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is a necessary first step. Please do not try to work with the last
+released version, as there is a good chance that somebody has already fixed
+the bug you found. Somebody might have even added the feature you had in mind.
+Don't make your work obsolete before you start!
+
+For information on how to check out Busybox from CVS, please look at the
+following links:
+
+ http://busybox.net/cvs_anon.html
+ http://busybox.net/cvs_howto.html
+
+
+Read the Mailing List
+~~~~~~~~~~~~~~~~~~~~~
+
+No one is required to read the entire archives of the mailing list, but you
+should at least read up on what people have been talking about lately. If
+you've recently discovered a problem, chances are somebody else has too. If
+you're the first to discover a problem, post a message and let the rest of us
+know.
+
+Archives can be found here:
+
+ http://busybox.net/lists/busybox/
+
+If you have a serious interest in Busybox, i.e., you are using it day-to-day or
+as part of an embedded project, it would be a good idea to join the mailing
+list.
+
+A web-based sign-up form can be found here:
+
+ http://busybox.net/mailman/listinfo/busybox
+
+
+Coordinate with the Applet Maintainer
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Some (not all) of the applets in Busybox are "owned" by a maintainer who has
+put significant effort into it and is probably more familiar with it than
+others. To find the maintainer of an applet, look at the top of the .c file
+for a name following the word 'Copyright' or 'Written by' or 'Maintainer'.
+
+Before plunging ahead, it's a good idea to send a message to the mailing list
+that says: "Hey, I was thinking about adding the 'transmogrify' feature to the
+'foo' applet. Would this be useful? Is anyone else working on it?" You might
+want to CC the maintainer (if any) with your question.
+
+
+
+Areas Where You Can Help
+------------------------
+
+Busybox can always use improvement! If you're looking for ways to help, there
+are a variety of areas where you could help.
+
+
+What Busybox Doesn't Need
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Before listing the areas where you _can_ help, it's worthwhile to mention the
+areas where you shouldn't bother. While Busybox strives to be the "Swiss Army
+Knife" of embedded Linux, there are some applets that will not be accepted:
+
+ - Any filesystem manipulation tools: Busybox is filesystem independent and
+ we do not want to start adding mkfs/fsck tools for every (or any)
+ filesystem under the sun. (fsck_minix.c and mkfs_minix.c are living on
+ borrowed time.) There are far too many of these tools out there. Use
+ the upstream version. Not everything has to be part of Busybox.
+
+ - Any partitioning tools: Partitioning a device is typically done once and
+ only once, and tools which do this generally do not need to reside on the
+ target device (esp a flash device). If you need a partitioning tool, grab
+ one (such as fdisk, sfdisk, or cfdisk from util-linux) and use that, but
+ don't try to merge it into busybox. These are nasty and complex and we
+ don't want to maintain them.
+
+ - Any disk, device, or media-specific tools: Use the -utils or -tools package
+ that was designed for your device; don't try to shoehorn them into Busybox.
+
+ - Any architecture specific tools: Busybox is (or should be) architecture
+ independent. Do not send us tools that cannot be used across multiple
+ platforms / arches.
+
+ - Any daemons that are not essential to basic system operation. To date, only
+ syslogd and klogd meet this requirement. We do not need a web server, an
+ ftp daemon, a dhcp server, a mail transport agent or a dns resolver. If you
+ need one of those, you are welcome to ask the folks on the mailing list for
+ recommendations, but please don't bloat up Busybox with any of these.
+
+
+Bug Reporting
+~~~~~~~~~~~~~
+
+If you find bugs, please submit a detailed bug report to the busybox mailing
+list at busybox@busybox.net. A well-written bug report should include a
+transcript of a shell session that demonstrates the bad behavior and enables
+anyone else to duplicate the bug on their own machine. The following is such
+an example:
+
+ To: busybox@busybox.net
+ From: diligent@testing.linux.org
+ Subject: /bin/date doesn't work
+
+ Package: busybox
+ Version: 1.00
+
+ When I execute Busybox 'date' it produces unexpected results.
+ With GNU date I get the following output:
+
+ $ date
+ Wed Mar 21 14:19:41 MST 2001
+
+ But when I use BusyBox date I get this instead:
+
+ $ date
+ llegal instruction
+
+ I am using Debian unstable, kernel version 2.4.19-rmk1 on an Netwinder,
+ and the latest uClibc from CVS. Thanks for the wonderful program!
+
+ -Diligent
+
+Note the careful description and use of examples showing not only what BusyBox
+does, but also a counter example showing what an equivalent GNU app does. Bug
+reports lacking such detail may never be fixed... Thanks for understanding.
+
+
+
+Write Documentation
+~~~~~~~~~~~~~~~~~~~
+
+Chances are, documentation in Busybox is either missing or needs improvement.
+Either way, help is welcome.
+
+Work is being done to automatically generate documentation from sources,
+especially from the usage.h file. If you want to correct the documentation,
+please make changes to the pre-generation parts, rather than the generated
+documentation. [More to come on this later...]
+
+It is preferred that modifications to documentation be submitted in patch
+format (more on this below), but we're a little more lenient when it comes to
+docs. You could, for example, just say "after the listing of the mount
+options, the following example would be helpful..."
+
+
+Consult Existing Sources
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+For a quick listing of "needs work" spots in the sources, cd into the Busybox
+directory and run the following:
+
+ for i in TODO FIXME XXX; do find -name '*.[ch]'|xargs grep $i; done
+
+This will show all of the trouble spots or 'questionable' code. Pick a spot,
+any spot, these are all invitations for you to contribute.
+
+
+Add a New Applet
+~~~~~~~~~~~~~~~~
+
+If you want to add a new applet to Busybox, we'd love to see it. However,
+before you write any code, please ask beforehand on the mailing list something
+like "Do you think applet 'foo' would be useful in Busybox?" or "Would you
+guys accept applet 'foo' into Busybox if I were to write it?" If the answer is
+"no" by the folks on the mailing list, then you've saved yourself some time.
+Conversely, you could get some positive responses from folks who might be
+interested in helping you implement it, or can recommend the best approach.
+Perhaps most importantly, this is your way of calling "dibs" on something and
+avoiding duplication of effort.
+
+Also, before you write a line of code, please read the 'new-applet-HOWTO.txt'
+file in the docs/ directory.
+
+
+Janitorial Work
+~~~~~~~~~~~~~~~
+
+These are dirty jobs, but somebody's gotta do 'em.
+
+ - Converting applets to use getopt() for option processing. Type 'find -name
+ '*.c'|grep -L getopt' to get a listing of the applets that currently don't
+ use getopt. If a .c file processes no options, it should have a line that
+ reads: /* no options, no getopt */ somewhere in the file.
+
+ - Replace any "naked" calls to malloc, calloc, realloc, str[n]dup, fopen with
+ the x* equivalents found in libbb/xfuncs.c.
+
+ - Security audits:
+ http://www.securityfocus.com/popups/forums/secprog/intro.shtml
+
+ - Synthetic code removal: http://www.perl.com/pub/2000/06/commify.html - This
+ is very Perl-specific, but the advice given in here applies equally well to
+ C.
+
+ - C library function use audits: Verifying that functions are being used
+ properly (called with the right args), replacing unsafe library functions
+ with safer versions, making sure return codes are being checked, etc.
+
+ - Where appropriate, replace preprocessor defined macros and values with
+ compile-time equivalents.
+
+ - Style guide compliance. See: docs/style-guide.txt
+
+ - Add testcases to tests/testcases.
+
+ - Makefile improvements:
+ http://www.canb.auug.org.au/~millerp/rmch/recu-make-cons-harm.html
+ (I think the recursive problems are pretty much taken care of at this point, non?)
+
+ - "Ten Commandments" compliance: (this is a "maybe", certainly not as
+ important as any of the previous items.)
+ http://www.lysator.liu.se/c/ten-commandments.html
+
+Other useful links:
+
+ - the comp.lang.c FAQ: http://web.onetelnet.ch/~twolf/tw/c/index.html#Sources
+
+
+
+Submitting Patches To Busybox
+-----------------------------
+
+Here are some guidelines on how to submit a patch to Busybox.
+
+
+Making A Patch
+~~~~~~~~~~~~~~
+
+If you've got anonymous CVS access set up, making a patch is simple. Just make
+sure you're in the busybox/ directory and type 'cvs diff -bwu > mychanges.patch'.
+You can send the resulting .patch file to the mailing list with a description
+of what it does. (But not before you test it! See the next section for some
+guidelines.) It is preferred that patches be sent as attachments, but it is
+not required.
+
+Also, feel free to help test other people's patches and reply to them with
+comments. You can apply a patch by saving it into your busybox/ directory and
+typing 'patch < mychanges.patch'. Then you can recompile, see if it runs, test
+if it works as advertised, and post your findings to the mailing list.
+
+NOTE: Please do not include extraneous or irrelevant changes in your patches.
+Please do not try to "bundle" two patches together into one. Make single,
+discreet changes on a per-patch basis. Sometimes you need to make a patch that
+touches code in many places, but these kind of patches are rare and should be
+coordinated with a maintainer.
+
+
+Testing Guidelines
+~~~~~~~~~~~~~~~~~~
+
+It's considered good form to test your new feature before you submit a patch
+to the mailing list, and especially before you commit a change to CVS. Here
+are some guidelines on how to test your changes.
+
+ - Always test Busybox applets against GNU counterparts and make sure the
+ behavior / output is identical between the two.
+
+ - Try several different permutations and combinations of the features you're
+ adding (i.e., different combinations of command-line switches) and make sure
+ they all work; make sure one feature does not interfere with another.
+
+ - Make sure you test compiling against the source both with the feature
+ turned on and turned off in Config.h and make sure Busybox compiles cleanly
+ both ways.
+
+ - Run the multibuild.pl script in the tests directory and make sure
+ everything checks out OK. (Do this from within the busybox/ directory by
+ typing: 'tests/multibuild.pl'.)
+
+
+Making Sure Your Patch Doesn't Get Lost
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you don't want your patch to be lost or forgotten, send it to the busybox
+mailing list with a subject line something like this:
+
+ [PATCH] - Adds "transmogrify" feature to "foo"
+
+In the body, you should have a pseudo-header that looks like the following:
+
+ Package: busybox
+ Version: v1.01pre (or whatever the current version is)
+ Severity: wishlist
+
+The remainder of the body should read along these lines:
+
+ This patch adds the "transmogrify" feature to the "foo" applet. I have
+ tested this on [arch] system(s) and it works. I have tested it against the
+ GNU counterparts and the outputs are identical. I have run the scripts in
+ the 'tests' directory and nothing breaks.
+
+
+
+Improving Your Chances of Patch Acceptance
+------------------------------------------
+
+Even after you send a brilliant patch to the mailing list, sometimes it can go
+unnoticed, un-replied-to, and sometimes (sigh) even lost. This is an
+unfortunate fact of life, but there are steps you can take to help your patch
+get noticed and convince a maintainer that it should be added:
+
+
+Be Succinct
+~~~~~~~~~~~
+
+A patch that includes small, isolated, obvious changes is more likely to be
+accepted than a patch that touches code in lots of different places or makes
+sweeping, dubious changes.
+
+
+Back It Up
+~~~~~~~~~~
+
+Hard facts on why your patch is better than the existing code will go a long
+way toward convincing maintainers that your patch should be included.
+Specifically, patches are more likely to be accepted if they are provably more
+correct, smaller, faster, simpler, or more maintainable than the existing
+code.
+
+Conversely, any patch that is supported with nothing more than "I think this
+would be cool" or "this patch is good because I say it is and I've got a Phd
+in Computer Science" will likely be ignored.
+
+
+Follow The Style Guide
+~~~~~~~~~~~~~~~~~~~~~~
+
+It's considered good form to abide by the established coding style used in a
+project; Busybox is no exception. We have gone so far as to delineate the
+"elements of Busybox style" in the file docs/style-guide.txt. Please follow
+them.
+
+
+Work With Someone Else
+~~~~~~~~~~~~~~~~~~~~~~
+
+Working on a patch in isolation is less effective than working with someone
+else for a variety of reasons. If another Busybox user is interested in what
+you're doing, then it's two (or more) voices instead of one that can petition
+for inclusion of the patch. You'll also have more people that can test your
+changes, or even offer suggestions on better approaches you could take.
+
+Getting other folks interested follows as a natural course if you've received
+responses from queries to applet maintainer or positive responses from folks
+on the mailing list.
+
+We've made strident efforts to put a useful "collaboration" infrastructure in
+place in the form of mailing lists, the bug tracking system, and CVS. Please
+use these resources.
+
+
+Send Patches to the Bug Tracking System
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This was mentioned above in the "Making Sure Your Patch Doesn't Get Lost"
+section, but it is worth mentioning again. A patch sent to the mailing list
+might be unnoticed and forgotten. A patch sent to the bug tracking system will
+be stored and closely connected to the bug it fixes.
+
+
+Be Polite
+~~~~~~~~~
+
+The old saying "You'll catch more flies with honey than you will with vinegar"
+applies when submitting patches to the mailing list for approval. The way you
+present your patch is sometimes just as important as the actual patch itself
+(if not more so). Being rude to the maintainers is not an effective way to
+convince them that your patch should be included; it will likely have the
+opposite effect.
+
+
+
+Committing Changes to CVS
+-------------------------
+
+If you submit several patches that demonstrate that you are a skilled and wise
+coder, you may be invited to become a committer, thus enabling you to commit
+changes directly to CVS. This is nice because you don't have to wait for
+someone else to commit your change for you, you can just do it yourself.
+
+But note that this is a privilege that comes with some responsibilities. You
+should test your changes before you commit them. You should also talk to an
+applet maintainer before you make any kind of sweeping changes to somebody
+else's code. Big changes should still go to the mailing list first. Remember,
+being wise, polite, and discreet is more important than being clever.
+
+
+When To Commit
+~~~~~~~~~~~~~~
+
+Generally, you should feel free to commit a change if:
+
+ - Your changes are small and don't touch many files
+ - You are fixing a bug
+ - Somebody has told you that it's okay
+ - It's obviously the Right Thing
+
+The more of the above are true, the better it is to just commit a change
+directly to CVS.
+
+
+When Not To Commit
+~~~~~~~~~~~~~~~~~~
+
+Even if you have commit rights, you should probably still post a patch to the
+mailing list if:
+
+ - Your changes are broad and touch many different files
+ - You are adding a feature
+ - Your changes are speculative or experimental (i.e., trying a new algorithm)
+ - You are not the maintainer and your changes make the maintainer cringe
+
+The more of the above are true, the better it is to post a patch to the
+mailing list instead of committing.
+
+
+
+Final Words
+-----------
+
+If all of this seems complicated, don't panic, it's really not that tough. If
+you're having difficulty following some of the steps outlined in this
+document don't worry, the folks on the Busybox mailing list are a fairly
+good-natured bunch and will work with you to help get your patches into shape
+or help you make contributions.
+
+
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/ctty.htm b/cleopatre/busybox-1.11.1-spc300/docs/ctty.htm
new file mode 100644
index 0000000000..8f466cdde6
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/ctty.htm
@@ -0,0 +1,476 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html><head>
+ <!-- saved from http://www.win.tue.nl/~aeb/linux/lk/lk-10.html -->
+ <meta name="GENERATOR" content="SGML-Tools 1.0.9"><title>The Linux kernel: Processes</title>
+</head>
+<body>
+<hr>
+<h2><a name="s10">10. Processes</a></h2>
+
+<p>Before looking at the Linux implementation, first a general Unix
+description of threads, processes, process groups and sessions.
+</p><p>A session contains a number of process groups, and a process group
+contains a number of processes, and a process contains a number
+of threads.
+</p><p>A session can have a controlling tty.
+At most one process group in a session can be a foreground process group.
+An interrupt character typed on a tty ("Teletype", i.e., terminal)
+causes a signal to be sent to all members of the foreground process group
+in the session (if any) that has that tty as controlling tty.
+</p><p>All these objects have numbers, and we have thread IDs, process IDs,
+process group IDs and session IDs.
+</p><p>
+</p><h2><a name="ss10.1">10.1 Processes</a>
+</h2>
+
+<p>
+</p><h3>Creation</h3>
+
+<p>A new process is traditionally started using the <code>fork()</code>
+system call:
+</p><blockquote>
+<pre>pid_t p;
+
+p = fork();
+if (p == (pid_t) -1)
+ /* ERROR */
+else if (p == 0)
+ /* CHILD */
+else
+ /* PARENT */
+</pre>
+</blockquote>
+<p>This creates a child as a duplicate of its parent.
+Parent and child are identical in almost all respects.
+In the code they are distinguished by the fact that the parent
+learns the process ID of its child, while <code>fork()</code>
+returns 0 in the child. (It can find the process ID of its
+parent using the <code>getppid()</code> system call.)
+</p><p>
+</p><h3>Termination</h3>
+
+<p>Normal termination is when the process does
+</p><blockquote>
+<pre>exit(n);
+</pre>
+</blockquote>
+
+or
+<blockquote>
+<pre>return n;
+</pre>
+</blockquote>
+
+from its <code>main()</code> procedure. It returns the single byte <code>n</code>
+to its parent.
+<p>Abnormal termination is usually caused by a signal.
+</p><p>
+</p><h3>Collecting the exit code. Zombies</h3>
+
+<p>The parent does
+</p><blockquote>
+<pre>pid_t p;
+int status;
+
+p = wait(&amp;status);
+</pre>
+</blockquote>
+
+and collects two bytes:
+<p>
+<figure>
+<eps file="absent">
+<img src="ctty_files/exit_status.png">
+</eps>
+</figure></p><p>A process that has terminated but has not yet been waited for
+is a <i>zombie</i>. It need only store these two bytes:
+exit code and reason for termination.
+</p><p>On the other hand, if the parent dies first, <code>init</code> (process 1)
+inherits the child and becomes its parent.
+</p><p>
+</p><h3>Signals</h3>
+
+<p>
+</p><h3>Stopping</h3>
+
+<p>Some signals cause a process to stop:
+<code>SIGSTOP</code> (stop!),
+<code>SIGTSTP</code> (stop from tty: probably ^Z was typed),
+<code>SIGTTIN</code> (tty input asked by background process),
+<code>SIGTTOU</code> (tty output sent by background process, and this was
+disallowed by <code>stty tostop</code>).
+</p><p>Apart from ^Z there also is ^Y. The former stops the process
+when it is typed, the latter stops it when it is read.
+</p><p>Signals generated by typing the corresponding character on some tty
+are sent to all processes that are in the foreground process group
+of the session that has that tty as controlling tty. (Details below.)
+</p><p>If a process is being traced, every signal will stop it.
+</p><p>
+</p><h3>Continuing</h3>
+
+<p><code>SIGCONT</code>: continue a stopped process.
+</p><p>
+</p><h3>Terminating</h3>
+
+<p><code>SIGKILL</code> (die! now!),
+<code>SIGTERM</code> (please, go away),
+<code>SIGHUP</code> (modem hangup),
+<code>SIGINT</code> (^C),
+<code>SIGQUIT</code> (^\), etc.
+Many signals have as default action to kill the target.
+(Sometimes with an additional core dump, when such is
+allowed by rlimit.)
+The signals <code>SIGCHLD</code> and <code>SIGWINCH</code>
+are ignored by default.
+All except <code>SIGKILL</code> and <code>SIGSTOP</code> can be
+caught or ignored or blocked.
+For details, see <code>signal(7)</code>.
+</p><p>
+</p><h2><a name="ss10.2">10.2 Process groups</a>
+</h2>
+
+<p>Every process is member of a unique <i>process group</i>,
+identified by its <i>process group ID</i>.
+(When the process is created, it becomes a member of the process group
+of its parent.)
+By convention, the process group ID of a process group
+equals the process ID of the first member of the process group,
+called the <i>process group leader</i>.
+A process finds the ID of its process group using the system call
+<code>getpgrp()</code>, or, equivalently, <code>getpgid(0)</code>.
+One finds the process group ID of process <code>p</code> using
+<code>getpgid(p)</code>.
+</p><p>One may use the command <code>ps j</code> to see PPID (parent process ID),
+PID (process ID), PGID (process group ID) and SID (session ID)
+of processes. With a shell that does not know about job control,
+like <code>ash</code>, each of its children will be in the same session
+and have the same process group as the shell. With a shell that knows
+about job control, like <code>bash</code>, the processes of one pipeline, like
+</p><blockquote>
+<pre>% cat paper | ideal | pic | tbl | eqn | ditroff &gt; out
+</pre>
+</blockquote>
+
+form a single process group.
+<p>
+</p><h3>Creation</h3>
+
+<p>A process <code>pid</code> is put into the process group <code>pgid</code> by
+</p><blockquote>
+<pre>setpgid(pid, pgid);
+</pre>
+</blockquote>
+
+If <code>pgid == pid</code> or <code>pgid == 0</code> then this creates
+a new process group with process group leader <code>pid</code>.
+Otherwise, this puts <code>pid</code> into the already existing
+process group <code>pgid</code>.
+A zero <code>pid</code> refers to the current process.
+The call <code>setpgrp()</code> is equivalent to <code>setpgid(0,0)</code>.
+<p>
+</p><h3>Restrictions on setpgid()</h3>
+
+<p>The calling process must be <code>pid</code> itself, or its parent,
+and the parent can only do this before <code>pid</code> has done
+<code>exec()</code>, and only when both belong to the same session.
+It is an error if process <code>pid</code> is a session leader
+(and this call would change its <code>pgid</code>).
+</p><p>
+</p><h3>Typical sequence</h3>
+
+<p>
+</p><blockquote>
+<pre>p = fork();
+if (p == (pid_t) -1) {
+ /* ERROR */
+} else if (p == 0) { /* CHILD */
+ setpgid(0, pgid);
+ ...
+} else { /* PARENT */
+ setpgid(p, pgid);
+ ...
+}
+</pre>
+</blockquote>
+
+This ensures that regardless of whether parent or child is scheduled
+first, the process group setting is as expected by both.
+<p>
+</p><h3>Signalling and waiting</h3>
+
+<p>One can signal all members of a process group:
+</p><blockquote>
+<pre>killpg(pgrp, sig);
+</pre>
+</blockquote>
+<p>One can wait for children in ones own process group:
+</p><blockquote>
+<pre>waitpid(0, &amp;status, ...);
+</pre>
+</blockquote>
+
+or in a specified process group:
+<blockquote>
+<pre>waitpid(-pgrp, &amp;status, ...);
+</pre>
+</blockquote>
+<p>
+</p><h3>Foreground process group</h3>
+
+<p>Among the process groups in a session at most one can be
+the <i>foreground process group</i> of that session.
+The tty input and tty signals (signals generated by ^C, ^Z, etc.)
+go to processes in this foreground process group.
+</p><p>A process can determine the foreground process group in its session
+using <code>tcgetpgrp(fd)</code>, where <code>fd</code> refers to its
+controlling tty. If there is none, this returns a random value
+larger than 1 that is not a process group ID.
+</p><p>A process can set the foreground process group in its session
+using <code>tcsetpgrp(fd,pgrp)</code>, where <code>fd</code> refers to its
+controlling tty, and <code>pgrp</code> is a process group in
+its session, and this session still is associated to the controlling
+tty of the calling process.
+</p><p>How does one get <code>fd</code>? By definition, <code>/dev/tty</code>
+refers to the controlling tty, entirely independent of redirects
+of standard input and output. (There is also the function
+<code>ctermid()</code> to get the name of the controlling terminal.
+On a POSIX standard system it will return <code>/dev/tty</code>.)
+Opening the name of the
+controlling tty gives a file descriptor <code>fd</code>.
+</p><p>
+</p><h3>Background process groups</h3>
+
+<p>All process groups in a session that are not foreground
+process group are <i>background process groups</i>.
+Since the user at the keyboard is interacting with foreground
+processes, background processes should stay away from it.
+When a background process reads from the terminal it gets
+a SIGTTIN signal. Normally, that will stop it, the job control shell
+notices and tells the user, who can say <code>fg</code> to continue
+this background process as a foreground process, and then this
+process can read from the terminal. But if the background process
+ignores or blocks the SIGTTIN signal, or if its process group
+is orphaned (see below), then the read() returns an EIO error,
+and no signal is sent. (Indeed, the idea is to tell the process
+that reading from the terminal is not allowed right now.
+If it wouldn't see the signal, then it will see the error return.)
+</p><p>When a background process writes to the terminal, it may get
+a SIGTTOU signal. May: namely, when the flag that this must happen
+is set (it is off by default). One can set the flag by
+</p><blockquote>
+<pre>% stty tostop
+</pre>
+</blockquote>
+
+and clear it again by
+<blockquote>
+<pre>% stty -tostop
+</pre>
+</blockquote>
+
+and inspect it by
+<blockquote>
+<pre>% stty -a
+</pre>
+</blockquote>
+
+Again, if TOSTOP is set but the background process ignores or blocks
+the SIGTTOU signal, or if its process group is orphaned (see below),
+then the write() returns an EIO error, and no signal is sent.
+<p>
+</p><h3>Orphaned process groups</h3>
+
+<p>The process group leader is the first member of the process group.
+It may terminate before the others, and then the process group is
+without leader.
+</p><p>A process group is called <i>orphaned</i> when <i>the
+parent of every member is either in the process group
+or outside the session</i>.
+In particular, the process group of the session leader
+is always orphaned.
+</p><p>If termination of a process causes a process group to become
+orphaned, and some member is stopped, then all are sent first SIGHUP
+and then SIGCONT.
+</p><p>The idea is that perhaps the parent of the process group leader
+is a job control shell. (In the same session but a different
+process group.) As long as this parent is alive, it can
+handle the stopping and starting of members in the process group.
+When it dies, there may be nobody to continue stopped processes.
+Therefore, these stopped processes are sent SIGHUP, so that they
+die unless they catch or ignore it, and then SIGCONT to continue them.
+</p><p>Note that the process group of the session leader is already
+orphaned, so no signals are sent when the session leader dies.
+</p><p>Note also that a process group can become orphaned in two ways
+by termination of a process: either it was a parent and not itself
+in the process group, or it was the last element of the process group
+with a parent outside but in the same session.
+Furthermore, that a process group can become orphaned
+other than by termination of a process, namely when some
+member is moved to a different process group.
+</p><p>
+</p><h2><a name="ss10.3">10.3 Sessions</a>
+</h2>
+
+<p>Every process group is in a unique <i>session</i>.
+(When the process is created, it becomes a member of the session
+of its parent.)
+By convention, the session ID of a session
+equals the process ID of the first member of the session,
+called the <i>session leader</i>.
+A process finds the ID of its session using the system call
+<code>getsid()</code>.
+</p><p>Every session may have a <i>controlling tty</i>,
+that then also is called the controlling tty of each of
+its member processes.
+A file descriptor for the controlling tty is obtained by
+opening <code>/dev/tty</code>. (And when that fails, there was no
+controlling tty.) Given a file descriptor for the controlling tty,
+one may obtain the SID using <code>tcgetsid(fd)</code>.
+</p><p>A session is often set up by a login process. The terminal
+on which one is logged in then becomes the controlling tty
+of the session. All processes that are descendants of the
+login process will in general be members of the session.
+</p><p>
+</p><h3>Creation</h3>
+
+<p>A new session is created by
+</p><blockquote>
+<pre>pid = setsid();
+</pre>
+</blockquote>
+
+This is allowed only when the current process is not a process group leader.
+In order to be sure of that we fork first:
+<blockquote>
+<pre>p = fork();
+if (p) exit(0);
+pid = setsid();
+</pre>
+</blockquote>
+
+The result is that the current process (with process ID <code>pid</code>)
+becomes session leader of a new session with session ID <code>pid</code>.
+Moreover, it becomes process group leader of a new process group.
+Both session and process group contain only the single process <code>pid</code>.
+Furthermore, this process has no controlling tty.
+<p>The restriction that the current process must not be a process group leader
+is needed: otherwise its PID serves as PGID of some existing process group
+and cannot be used as the PGID of a new process group.
+</p><p>
+</p><h3>Getting a controlling tty</h3>
+
+<p>How does one get a controlling terminal? Nobody knows,
+this is a great mystery.
+</p><p>The System V approach is that the first tty opened by the process
+becomes its controlling tty.
+</p><p>The BSD approach is that one has to explicitly call
+</p><blockquote>
+<pre>ioctl(fd, TIOCSCTTY, 0/1);
+</pre>
+</blockquote>
+
+to get a controlling tty.
+<p>Linux tries to be compatible with both, as always, and this
+results in a very obscure complex of conditions. Roughly:
+</p><p>The <code>TIOCSCTTY</code> ioctl will give us a controlling tty,
+provided that (i) the current process is a session leader,
+and (ii) it does not yet have a controlling tty, and
+(iii) maybe the tty should not already control some other session;
+if it does it is an error if we aren't root, or we steal the tty
+if we are all-powerful.
+[vda: correction: third parameter controls this: if 1, we steal tty from
+any such session, if 0, we don't steal]
+</p><p>Opening some terminal will give us a controlling tty,
+provided that (i) the current process is a session leader, and
+(ii) it does not yet have a controlling tty, and
+(iii) the tty does not already control some other session, and
+(iv) the open did not have the <code>O_NOCTTY</code> flag, and
+(v) the tty is not the foreground VT, and
+(vi) the tty is not the console, and
+(vii) maybe the tty should not be master or slave pty.
+</p><p>
+</p><h3>Getting rid of a controlling tty</h3>
+
+<p>If a process wants to continue as a daemon, it must detach itself
+from its controlling tty. Above we saw that <code>setsid()</code>
+will remove the controlling tty. Also the ioctl TIOCNOTTY does this.
+Moreover, in order not to get a controlling tty again as soon as it
+opens a tty, the process has to fork once more, to assure that it
+is not a session leader. Typical code fragment:
+</p><p>
+</p><pre> if ((fork()) != 0)
+ exit(0);
+ setsid();
+ if ((fork()) != 0)
+ exit(0);
+</pre>
+<p>See also <code>daemon(3)</code>.
+</p><p>
+</p><h3>Disconnect</h3>
+
+<p>If the terminal goes away by modem hangup, and the line was not local,
+then a SIGHUP is sent to the session leader.
+Any further reads from the gone terminal return EOF.
+(Or possibly -1 with <code>errno</code> set to EIO.)
+</p><p>If the terminal is the slave side of a pseudotty, and the master side
+is closed (for the last time), then a SIGHUP is sent to the foreground
+process group of the slave side.
+</p><p>When the session leader dies, a SIGHUP is sent to all processes
+in the foreground process group. Moreover, the terminal stops being
+the controlling terminal of this session (so that it can become
+the controlling terminal of another session).
+</p><p>Thus, if the terminal goes away and the session leader is
+a job control shell, then it can handle things for its descendants,
+e.g. by sending them again a SIGHUP.
+If on the other hand the session leader is an innocent process
+that does not catch SIGHUP, it will die, and all foreground processes
+get a SIGHUP.
+</p><p>
+</p><h2><a name="ss10.4">10.4 Threads</a>
+</h2>
+
+<p>A process can have several threads. New threads (with the same PID
+as the parent thread) are started using the <code>clone</code> system
+call using the <code>CLONE_THREAD</code> flag. Threads are distinguished
+by a <i>thread ID</i> (TID). An ordinary process has a single thread
+with TID equal to PID. The system call <code>gettid()</code> returns the
+TID. The system call <code>tkill()</code> sends a signal to a single thread.
+</p><p>Example: a process with two threads. Both only print PID and TID and exit.
+(Linux 2.4.19 or later.)
+</p><pre>% cat &lt;&lt; EOF &gt; gettid-demo.c
+#include &lt;unistd.h&gt;
+#include &lt;sys/types.h&gt;
+#define CLONE_SIGHAND 0x00000800
+#define CLONE_THREAD 0x00010000
+#include &lt;linux/unistd.h&gt;
+#include &lt;errno.h&gt;
+_syscall0(pid_t,gettid)
+
+int thread(void *p) {
+ printf("thread: %d %d\n", gettid(), getpid());
+}
+
+main() {
+ unsigned char stack[4096];
+ int i;
+
+ i = clone(thread, stack+2048, CLONE_THREAD | CLONE_SIGHAND, NULL);
+ if (i == -1)
+ perror("clone");
+ else
+ printf("clone returns %d\n", i);
+ printf("parent: %d %d\n", gettid(), getpid());
+}
+EOF
+% cc -o gettid-demo gettid-demo.c
+% ./gettid-demo
+clone returns 21826
+parent: 21825 21825
+thread: 21826 21825
+%
+</pre>
+<p>
+</p><p>
+</p><hr>
+
+</body></html>
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/draft-coar-cgi-v11-03-clean.html b/cleopatre/busybox-1.11.1-spc300/docs/draft-coar-cgi-v11-03-clean.html
new file mode 100644
index 0000000000..d52c9b842c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/draft-coar-cgi-v11-03-clean.html
@@ -0,0 +1,2674 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
+ "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+ <HEAD>
+ <TITLE>Common Gateway Interface - 1.1 *Draft 03* [http://cgi-spec.golux.com/draft-coar-cgi-v11-03-clean.html]
+ </TITLE>
+<!--#if expr="$HTTP_USER_AGENT != /Lynx/" -->
+ <!--#set var="GUI" value="1" -->
+<!--#endif -->
+ <LINK HREF="mailto:Ken.Coar@Golux.Com" rev="revised">
+ <LINK REL="STYLESHEET" HREF="cgip-style-rfc.css" TYPE="text/css">
+ <META name="latexstyle" content="rfc">
+ <META name="author" content="Ken A L Coar">
+ <META name="institute" content="IBM Corporation">
+ <META name="date" content="25 June 1999">
+ <META name="expires" content="Expires 31 December 1999">
+ <META name="document" content="INTERNET-DRAFT">
+ <META name="file" content="&lt;draft-coar-cgi-v11-03.txt&gt;">
+ <META name="group" content="INTERNET-DRAFT">
+<!--
+ There are a lot of BNF fragments in this document. To make it work
+ in all possible browsers (including Lynx, which is used to turn it
+ into text/plain), we handle these by using PREformatted blocks with
+ a universal internal margin of 2, inside one-level DL blocks.
+ -->
+ </HEAD>
+ <BODY>
+ <!--
+ HTML doesn't do paper pagination, so we need to fake it out. Basing
+ our formatting upon RFC2068, there are four (4) lines of header and
+ four (4) lines of footer for each page.
+
+<DIV ALIGN="CENTER">
+ <PRE>
+
+
+
+
+Coar, et al. CGI/1.1 Specification May, 1998
+INTERNET-DRAFT Expires 1 December 1998 [Page 2]
+
+
+ </PRE>
+</DIV>
+ -->
+ <!--
+ The following weirdness wrt non-breaking spaces is to get Lynx
+ (which is barely TABLE-aware) to line the left/right justified
+ text up properly.
+ -->
+ <DIV ALIGN="CENTER">
+ <TABLE WIDTH="100%" CELLPADDING=0 CELLSPACING=0>
+ <TR VALIGN="TOP">
+ <TD ALIGN="LEFT">
+ INTERNET-DRAFT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ </TD>
+ <TD ALIGN="RIGHT">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Ken A L Coar
+ </TD>
+ </TR>
+ <TR VALIGN="TOP">
+ <TD ALIGN="LEFT">
+ draft-coar-cgi-v11-03.{html,txt}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ </TD>
+ <TD ALIGN="RIGHT">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IBM Corporation
+ </TD>
+ </TR>
+ <TR VALIGN="TOP">
+ <TD ALIGN="LEFT">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ </TD>
+ <TD ALIGN="RIGHT">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.R.T. Robinson
+ </TD>
+ </TR>
+ <TR VALIGN="TOP">
+ <TD ALIGN="LEFT">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ </TD>
+ <TD ALIGN="RIGHT">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;E*TRADE&nbsp;UK&nbsp;Ltd.
+ </TD>
+ </TR>
+ <TR VALIGN="TOP">
+ <TD ALIGN="LEFT">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ </TD>
+ <TD ALIGN="RIGHT">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;25 June 1999
+ </TD>
+ </TR>
+ </TABLE>
+ </DIV>
+
+ <H1 ALIGN="CENTER">
+ The WWW Common Gateway Interface
+ <BR>
+ Version 1.1
+ </H1>
+
+<!--#include virtual="I-D-statement" -->
+
+ <H2>
+ <A NAME="Abstract">
+ Abstract
+ </A>
+ </H2>
+ <P>
+ The Common Gateway Interface (CGI) is a simple interface for running
+ external programs, software or gateways under an information server
+ in a platform-independent manner. Currently, the supported information
+ servers are HTTP servers.
+ </P>
+ <P>
+ The interface has been in use by the World-Wide Web since 1993. This
+ specification defines the
+ "current practice" parameters of the
+ 'CGI/1.1' interface developed and documented at the U.S. National
+ Centre for Supercomputing Applications [NCSA-CGI].
+ This document also defines the use of the CGI/1.1 interface
+ on the Unix and AmigaDOS(tm) systems.
+ </P>
+ <P>
+ Discussion of this draft occurs on the CGI-WG mailing list; see the
+ project Web page at
+ <SAMP>&lt;URL:<A HREF="http://CGI-Spec.Golux.Com/"
+ >http://CGI-Spec.Golux.Com/</A>&gt;</SAMP>
+ for details on the mailing list and the status of the project.
+ </P>
+
+<!--#if expr="$GUI" -->
+ <H2>
+ Revision History
+ </H2>
+ <P>
+ The revision history of this draft is being maintained using Web-based
+ GUI notation, such as struck-through characters and colour-coded
+ sections. The following legend describes how to determine the origin
+ of a particular revision according to the colour of the text:
+ </P>
+ <DL COMPACT>
+ <DT>Black
+ </DT>
+ <DD>Revision 00, released 28 May 1998
+ </DD>
+ <DT>Green
+ </DT>
+ <DD>Revision 01, released 28 December 1998
+ <BR>
+ Major structure change: Section 4, "Request Metadata (Meta-Variables)"
+ was moved entirely under <A HREF="#7.0">Section 7</A>, "Data Input to the
+ CGI Script."
+ Due to the size of this change, it is noted here and the text in its
+ former location does <EM>not</EM> appear as struckthrough. This has
+ caused major <A HREF="#6.0">sections 5</A> and following to decrement
+ by one. Other
+ large text movements are likewise not marked up. References to RFC
+ 1738 were changed to 2396 (1738's replacement).
+ </DD>
+ <DT>Red
+ </DT>
+ <DD>Revision 02, released 2 April, 1999
+ <BR>
+ Added text to <A HREF="#8.3">section 8.3</A> defining correct handling
+ of HTTP/1.1
+ requests using "chunked" Transfer-Encoding. Labelled metavariable
+ names in <A HREF="#8.0">section 8</A> with the appropriate detail section
+ numbers.
+ Clarified allowed usage of <SAMP>Status</SAMP> and
+ <SAMP>Location</SAMP> response header fields. Included new
+ Internet-Draft language.
+ </DD>
+ <DT>Fuchsia
+ </DT>
+ <DD>Revision 03, released 25 June 1999
+ <BR>
+ Changed references from "HTTP" to "Protocol-Specific" for the listing of
+ things like HTTP_ACCEPT. Changed 'entity-body' and 'content-body' to
+ 'message-body.' Added a note that response headers must comply with
+ requirements of the protocol level in use. Added a lot of stuff about
+ security (section 11). Clarified a bunch of productions. Pointed out
+ that zero-length and omitted values are indistinguishable in this
+ specification. Clarified production describing order of fields in
+ script response header. Clarified issues surrounding encoding of
+ data. Acknowledged additional contributors, and changed one of
+ the authors' addresses.
+ </DD>
+ </DL>
+<!--#endif -->
+
+ <H2>
+ <A NAME="Contents">
+ Table of Contents
+ </A>
+ </H2>
+ <DIV ALIGN="CENTER">
+ <PRE>
+ 1 Introduction..............................................<A
+ HREF="#1.0"
+ >TBD</A>
+ 1.1 Purpose................................................<A
+ HREF="#1.1"
+ >TBD</A>
+ 1.2 Requirements...........................................<A
+ HREF="#1.2"
+ >TBD</A>
+ 1.3 Specifications.........................................<A
+ HREF="#1.3"
+ >TBD</A>
+ 1.4 Terminology............................................<A
+ HREF="#1.4"
+ >TBD</A>
+ 2 Notational Conventions and Generic Grammar................<A
+ HREF="#2.0"
+ >TBD</A>
+ 2.1 Augmented BNF..........................................<A
+ HREF="#2.1"
+ >TBD</A>
+ 2.2 Basic Rules............................................<A
+ HREF="#2.2"
+ >TBD</A>
+ 3 Protocol Parameters.......................................<A
+ HREF="#3.0"
+ >TBD</A>
+ 3.1 URL Encoding...........................................<A
+ HREF="#3.1"
+ >TBD</A>
+ 3.2 The Script-URI.........................................<A
+ HREF="#3.2"
+ >TBD</A>
+ 4 Invoking the Script.......................................<A
+ HREF="#4.0"
+ >TBD</A>
+ 5 The CGI Script Command Line...............................<A
+ HREF="#5.0"
+ >TBD</A>
+ 6 Data Input to the CGI Script..............................<A
+ HREF="#6.0"
+ >TBD</A>
+ 6.1 Request Metadata (Metavariables).......................<A
+ HREF="#6.1"
+ >TBD</A>
+ 6.1.1 AUTH_TYPE...........................................<A
+ HREF="#6.1.1"
+ >TBD</A>
+ 6.1.2 CONTENT_LENGTH......................................<A
+ HREF="#6.1.2"
+ >TBD</A>
+ 6.1.3 CONTENT_TYPE........................................<A
+ HREF="#6.1.3"
+ >TBD</A>
+ 6.1.4 GATEWAY_INTERFACE...................................<A
+ HREF="#6.1.4"
+ >TBD</A>
+ 6.1.5 Protocol-Specific Metavariables.....................<A
+ HREF="#6.1.5"
+ >TBD</A>
+ 6.1.6 PATH_INFO...........................................<A
+ HREF="#6.1.6"
+ >TBD</A>
+ 6.1.7 PATH_TRANSLATED.....................................<A
+ HREF="#6.1.7"
+ >TBD</A>
+ 6.1.8 QUERY_STRING........................................<A
+ HREF="#6.1.8"
+ >TBD</A>
+ 6.1.9 REMOTE_ADDR.........................................<A
+ HREF="#6.1.9"
+ >TBD</A>
+ 6.1.10 REMOTE_HOST........................................<A
+ HREF="#6.1.10"
+ >TBD</A>
+ 6.1.11 REMOTE_IDENT.......................................<A
+ HREF="#6.1.11"
+ >TBD</A>
+ 6.1.12 REMOTE_USER........................................<A
+ HREF="#6.1.12"
+ >TBD</A>
+ 6.1.13 REQUEST_METHOD.....................................<A
+ HREF="#6.1.13"
+ >TBD</A>
+ 6.1.14 SCRIPT_NAME........................................<A
+ HREF="#6.1.14"
+ >TBD</A>
+ 6.1.15 SERVER_NAME........................................<A
+ HREF="#6.1.15"
+ >TBD</A>
+ 6.1.16 SERVER_PORT........................................<A
+ HREF="#6.1.16"
+ >TBD</A>
+ 6.1.17 SERVER_PROTOCOL....................................<A
+ HREF="#6.1.17"
+ >TBD</A>
+ 6.1.18 SERVER_SOFTWARE....................................<A
+ HREF="#6.1.18"
+ >TBD</A>
+ 6.2 Request Message-Bodies................................<A
+ HREF="#6.2"
+ >TBD</A>
+ 7 Data Output from the CGI Script...........................<A
+ HREF="#7.0"
+ >TBD</A>
+ 7.1 Non-Parsed Header Output...............................<A
+ HREF="#7.1"
+ >TBD</A>
+ 7.2 Parsed Header Output...................................<A
+ HREF="#7.2"
+ >TBD</A>
+ 7.2.1 CGI header fields...................................<A
+ HREF="#7.2.1"
+ >TBD</A>
+ 7.2.1.1 Content-Type.....................................<A
+ HREF="#7.2.1.1"
+ >TBD</A>
+ 7.2.1.2 Location.........................................<A
+ HREF="#7.2.1.2"
+ >TBD</A>
+ 7.2.1.3 Status...........................................<A
+ HREF="#7.2.1.3"
+ >TBD</A>
+ 7.2.1.4 Extension header fields..........................<A
+ HREF="#7.2.1.3"
+ >TBD</A>
+ 7.2.2 HTTP header fields..................................<A
+ HREF="#7.2.2"
+ >TBD</A>
+ 8 Server Implementation.....................................<A
+ HREF="#8.0"
+ >TBD</A>
+ 8.1 Requirements for Servers...............................<A
+ HREF="#8.1"
+ >TBD</A>
+ 8.1.1 Script-URI..........................................<A
+ HREF="#8.1"
+ >TBD</A>
+ 8.1.2 Request Message-body Handling.......................<A
+ HREF="#8.1.2"
+ >TBD</A>
+ 8.1.3 Required Metavariables..............................<A
+ HREF="#8.1.3"
+ >TBD</A>
+ 8.1.4 Response Compliance.................................<A
+ HREF="#8.1.4"
+ >TBD</A>
+ 8.2 Recommendations for Servers............................<A
+ HREF="#8.2"
+ >TBD</A>
+ 8.3 Summary of Metavariables...............................<A
+ HREF="#8.3"
+ >TBD</A>
+ 9 Script Implementation.....................................<A
+ HREF="#9.0"
+ >TBD</A>
+ 9.1 Requirements for Scripts...............................<A
+ HREF="#9.1"
+ >TBD</A>
+ 9.2 Recommendations for Scripts............................<A
+ HREF="#9.2"
+ >TBD</A>
+ 10 System Specifications....................................<A
+ HREF="#10.0"
+ >TBD</A>
+ 10.1 AmigaDOS..............................................<A
+ HREF="#10.1"
+ >TBD</A>
+ 10.2 Unix..................................................<A
+ HREF="#10.2"
+ >TBD</A>
+ 11 Security Considerations..................................<A
+ HREF="#11.0"
+ >TBD</A>
+ 11.1 Safe Methods..........................................<A
+ HREF="#11.1"
+ >TBD</A>
+ 11.2 HTTP Header Fields Containing Sensitive Information...<A
+ HREF="#11.2"
+ >TBD</A>
+ 11.3 Script Interference with the Server...................<A
+ HREF="#11.3"
+ >TBD</A>
+ 11.4 Data Length and Buffering Considerations..............<A
+ HREF="#11.4"
+ >TBD</A>
+ 11.5 Stateless Processing..................................<A
+ HREF="#11.5"
+ >TBD</A>
+ 12 Acknowledgments..........................................<A
+ HREF="#12.0"
+ >TBD</A>
+ 13 References...............................................<A
+ HREF="#13.0"
+ >TBD</A>
+ 14 Authors' Addresses.......................................<A
+ HREF="#14.0"
+ >TBD</A>
+ </PRE>
+ </DIV>
+
+ <H2>
+ <A NAME="1.0">
+ 1. Introduction
+ </A>
+ </H2>
+
+ <H3>
+ <A NAME="1.1">
+ 1.1. Purpose
+ </A>
+ </H3>
+ <P>
+ Together the HTTP [<A HREF="#[3]">3</A>,<A HREF="#[8]">8</A>] server
+ and the CGI script are responsible
+ for servicing a client
+ request by sending back responses. The client
+ request comprises a Universal Resource Identifier (URI)
+ [<A HREF="#[1]">1</A>], a
+ request method, and various ancillary
+ information about the request
+ provided by the transport mechanism.
+ </P>
+ <P>
+ The CGI defines the abstract parameters, known as
+ metavariables,
+ which describe the client's
+ request. Together with a
+ concrete programmer interface this specifies a platform-independent
+ interface between the script and the HTTP server.
+ </P>
+
+ <H3>
+ <A NAME="1.2">
+ 1.2. Requirements
+ </A>
+ </H3>
+ <P>
+ This specification uses the same words as RFC 1123
+ [<A HREF="#[5]">5</A>] to define the
+ significance of each particular requirement. These are:
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <DL>
+ <DT><EM>MUST</EM>
+ </DT>
+ <DD>
+ <P>
+ This word or the adjective 'required' means that the item is an
+ absolute requirement of the specification.
+ </P>
+ </DD>
+ <DT><EM>SHOULD</EM>
+ </DT>
+ <DD>
+ <P>
+ This word or the adjective 'recommended' means that there may
+ exist valid reasons in particular circumstances to ignore this
+ item, but the full implications should be understood and the case
+ carefully weighed before choosing a different course.
+ </P>
+ </DD>
+ <DT><EM>MAY</EM>
+ </DT>
+ <DD>
+ <P>
+ This word or the adjective 'optional' means that this item is
+ truly optional. One vendor may choose to include the item because
+ a particular marketplace requires it or because it enhances the
+ product, for example; another vendor may omit the same item.
+ </P>
+ </DD>
+ </DL>
+ <P>
+ An implementation is not compliant if it fails to satisfy one or more
+ of the 'must' requirements for the protocols it implements. An
+ implementation that satisfies all of the 'must' and all of the
+ 'should' requirements for its features is said to be 'unconditionally
+ compliant'; one that satisfies all of the 'must' requirements but not
+ all of the 'should' requirements for its features is said to be
+ 'conditionally compliant.'
+ </P>
+
+ <H3>
+ <A NAME="1.3">
+ 1.3. Specifications
+ </A>
+ </H3>
+ <P>
+ Not all of the functions and features of the CGI are defined in the
+ main part of this specification. The following phrases are used to
+ describe the features which are not specified:
+ </P>
+ <DL>
+ <DT><EM>system defined</EM>
+ </DT>
+ <DD>
+ <P>
+ The feature may differ between systems, but must be the same for
+ different implementations using the same system. A system will
+ usually identify a class of operating-systems. Some systems are
+ defined in
+ <A HREF="#10.0"
+ >section 10</A> of this document.
+ New systems may be defined
+ by new specifications without revision of this document.
+ </P>
+ </DD>
+ <DT><EM>implementation defined</EM>
+ </DT>
+ <DD>
+ <P>
+ The behaviour of the feature may vary from implementation to
+ implementation, but a particular implementation must document its
+ behaviour.
+ </P>
+ </DD>
+ </DL>
+
+ <H3>
+ <A NAME="1.4">
+ 1.4. Terminology
+ </A>
+ </H3>
+ <P>
+ This specification uses many terms defined in the HTTP/1.1
+ specification [<A HREF="#[8]">8</A>]; however, the following terms are
+ used here in a
+ sense which may not accord with their definitions in that document,
+ or with their common meaning.
+ </P>
+
+ <DL>
+ <DT><EM>metavariable</EM>
+ </DT>
+ <DD>
+ <P>
+ A named parameter that carries information from the server to the
+ script. It is not necessarily a variable in the operating-system's
+ environment, although that is the most common implementation.
+ </P>
+ </DD>
+
+ <DT><EM>script</EM>
+ </DT>
+ <DD>
+ <P>
+ The software which is invoked by the server <EM>via</EM> this
+ interface. It
+ need not be a standalone program, but could be a
+ dynamically-loaded or shared library, or even a subroutine in the
+ server. It <EM>may</EM> be a set of statements
+ interpreted at run-time, as the term 'script' is frequently
+ understood, but that is not a requirement and within the context
+ of this specification the term has the broader definition stated.
+ </P>
+ </DD>
+ <DT><EM>server</EM>
+ </DT>
+ <DD>
+ <P>
+ The application program which invokes the script in order to service
+ requests.
+ </P>
+ </DD>
+ </DL>
+
+ <H2>
+ <A NAME="2.0">
+ 2. Notational Conventions and Generic Grammar
+ </A>
+ </H2>
+
+ <H3>
+ <A NAME="2.1">
+ 2.1. Augmented BNF
+ </A>
+ </H3>
+ <P>
+ All of the mechanisms specified in this document are described in
+ both prose and an augmented Backus-Naur Form (BNF) similar to that
+ used by RFC 822 [<A HREF="#[6]">6</A>]. This augmented BNF contains
+ the following constructs:
+ </P>
+ <DL>
+ <DT>name = definition
+ </DT>
+ <DD>
+ <P>
+ The
+ definition by the equal character ("="). Whitespace is only
+ significant in that continuation lines of a definition are
+ indented.
+ </P>
+ </DD>
+ <DT>"literal"
+ </DT>
+ <DD>
+ <P>
+ Quotation marks (") surround literal text, except for a literal
+ quotation mark, which is surrounded by angle-brackets ("&lt;" and "&gt;").
+ Unless stated otherwise, the text is case-sensitive.
+ </P>
+ </DD>
+ <DT>rule1 | rule2
+ </DT>
+ <DD>
+ <P>
+ Alternative rules are separated by a vertical bar ("|").
+ </P>
+ </DD>
+ <DT>(rule1 rule2 rule3)
+ </DT>
+ <DD>
+ <P>
+ Elements enclosed in parentheses are treated as a single element.
+ </P>
+ </DD>
+ <DT>*rule
+ </DT>
+ <DD>
+ <P>
+ A rule preceded by an asterisk ("*") may have zero or more
+ occurrences. A rule preceded by an integer followed by an asterisk
+ must occur at least the specified number of times.
+ </P>
+ </DD>
+ <DT>[rule]
+ </DT>
+ <DD>
+ <P>
+ An element enclosed in square
+ brackets ("[" and "]") is optional.
+ </P>
+ </DD>
+ </DL>
+
+ <H3>
+ <A NAME="2.2">
+ 2.2. Basic Rules
+ </A>
+ </H3>
+ <P>
+ The following rules are used throughout this specification to
+ describe basic parsing constructs.
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ alpha = lowalpha | hialpha
+ alphanum = alpha | digit
+ lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h"
+ | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p"
+ | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x"
+ | "y" | "z"
+ hialpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H"
+ | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P"
+ | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X"
+ | "Y" | "Z"
+ digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7"
+ | "8" | "9"
+ hex = digit | "A" | "B" | "C" | "D" | "E" | "F" | "a"
+ | "b" | "c" | "d" | "e" | "f"
+ escaped = "%" hex hex
+ OCTET = &lt;any 8-bit sequence of data&gt;
+ CHAR = &lt;any US-ASCII character (octets 0 - 127)&gt;
+ CTL = &lt;any US-ASCII control character
+ (octets 0 - 31) and DEL (127)&gt;
+ CR = &lt;US-ASCII CR, carriage return (13)&gt;
+ LF = &lt;US-ASCII LF, linefeed (10)&gt;
+ SP = &lt;US-ASCII SP, space (32)&gt;
+ HT = &lt;US-ASCII HT, horizontal tab (9)&gt;
+ NL = CR | LF
+ LWSP = SP | HT | NL
+ tspecial = "(" | ")" | "@" | "," | ";" | ":" | "\" | &lt;"&gt;
+ | "/" | "[" | "]" | "?" | "&lt;" | "&gt;" | "{" | "}"
+ | SP | HT | NL
+ token = 1*&lt;any CHAR except CTLs or tspecials&gt;
+ quoted-string = ( &lt;"&gt; *qdtext &lt;"&gt; ) | ( "&lt;" *qatext "&gt;")
+ qdtext = &lt;any CHAR except &lt;"&gt; and CTLs but including LWSP&gt;
+ qatext = &lt;any CHAR except "&lt;", "&gt;" and CTLs but
+ including LWSP&gt;
+ mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
+ unreserved = alphanum | mark
+ reserved = ";" | "/" | "?" | ":" | "@" | "&amp;" | "=" |
+ "$" | ","
+ uric = reserved | unreserved | escaped
+ </PRE>
+ <P>
+ Note that newline (NL) need not be a single character, but can be a
+ character sequence.
+ </P>
+
+ <H2>
+ <A NAME="3.0">
+ 3. Protocol Parameters
+ </A>
+ </H2>
+
+ <H3>
+ <A NAME="3.1">
+ 3.1. URL Encoding
+ </A>
+ </H3>
+ <P>
+ Some variables and constructs used here are described as being
+ 'URL-encoded'. This encoding is described in section
+ 2 of RFC
+ 2396
+ [<A HREF="#[4]">4</A>].
+ </P>
+ <P>
+ An alternate "shortcut" encoding for representing the space
+ character exists and is in common use. Scripts MUST be prepared to
+ recognise both '+' and '%20' as an encoded space in a
+ URL-encoded value.
+ </P>
+ <P>
+ Note that some unsafe characters may have different semantics if
+ they are encoded. The definition of which characters are unsafe
+ depends on the context.
+ For example, the following two URLs do not
+ necessarily refer to the same resource:
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ http://somehost.com/somedir%2Fvalue
+ http://somehost.com/somedir/value
+ </PRE>
+ <P>
+ See section
+ 2 of RFC
+ 2396 [<A HREF="#[4]">4</A>]
+ for authoritative treatment of this issue.
+ </P>
+
+ <H3>
+ <A NAME="3.2">
+ 3.2. The Script-URI
+ </A>
+ </H3>
+ <P>
+ The 'Script-URI' is defined as the URI of the resource identified
+ by the metavariables. Often,
+ this URI will be the same as
+ the URI requested by the client (the 'Client-URI'); however, it need
+ not be. Instead, it could be a URI invented by the server, and so it
+ can only be used in the context of the server and its CGI interface.
+ </P>
+ <P>
+ The Script-URI has the syntax of generic-RL as defined in section 2.1
+ of RFC 1808 [<A HREF="#[7]">7</A>], with the exception that object
+ parameters and
+ fragment identifiers are not permitted:
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ &lt;scheme&gt;://&lt;host&gt;&lt;port&gt;/&lt;path&gt;?&lt;query&gt;
+ </PRE>
+ <P>
+ The various components of the
+ Script-URI
+ are defined by some of the
+ metavariables (see
+ <A HREF="#4.0">section 4</A>
+ below);
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ script-uri = protocol "://" SERVER_NAME ":" SERVER_PORT enc-script
+ enc-path-info "?" QUERY_STRING
+ </PRE>
+ <P>
+ where 'protocol' is obtained
+ from SERVER_PROTOCOL, 'enc-script' is a
+ URL-encoded version of SCRIPT_NAME and 'enc-path-info' is a
+ URL-encoded version of PATH_INFO. See
+ <A HREF="#4.6">section 4.6</A> for more information about the PATH_INFO
+ metavariable.
+ </P>
+ <P>
+ Note that the scheme and the protocol are <EM>not</EM> identical;
+ for instance, a resource accessed <EM>via</EM> an SSL mechanism
+ may have a Client-URI with a scheme of "<SAMP>https</SAMP>"
+ rather than "<SAMP>http</SAMP>". CGI/1.1 provides no means
+ for the script to reconstruct this, and therefore
+ the Script-URI includes the base protocol used.
+ </P>
+
+ <H2>
+ <A NAME="4.0">
+ 4. Invoking the Script
+ </A>
+ </H2>
+ <P>
+ The
+ script is invoked in a system defined manner. Unless specified
+ otherwise, the file containing the script will be invoked as an
+ executable program.
+ </P>
+
+ <H2>
+ <A NAME="5.0">
+ 5. The CGI Script Command Line
+ </A>
+ </H2>
+ <P>
+ Some systems support a method for supplying an array of strings to
+ the CGI script. This is only used in the case of an 'indexed' query.
+ This is identified by a "GET" or "HEAD" HTTP request with a URL
+ query
+ string not containing any unencoded "=" characters. For such a
+ request,
+ servers SHOULD parse the search string
+ into words, using the following rules:
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ search-string = search-word *( "+" search-word )
+ search-word = 1*schar
+ schar = xunreserved | escaped | xreserved
+ xunreserved = alpha | digit | xsafe | extra
+ xsafe = "$" | "-" | "_" | "."
+ xreserved = ";" | "/" | "?" | ":" | "@" | "&"
+ </PRE>
+ <P>
+ After parsing, each word is URL-decoded, optionally encoded in a
+ system defined manner,
+ and then the argument list is set to the list
+ of words.
+ </P>
+ <P>
+ If the server cannot create any part of the argument list, then the
+ server SHOULD NOT generate any command line information. For example, the
+ number of arguments may be greater than operating system or server
+ limitations permit, or one of the words may not be representable as an
+ argument.
+ </P>
+ <P>
+ Scripts SHOULD check to see if the QUERY_STRING value contains an
+ unencoded "=" character, and SHOULD NOT use the command line arguments
+ if it does.
+ </P>
+
+ <H2>
+ <A NAME="6.0">
+ 6. Data Input to the CGI Script
+ </A>
+ </H2>
+ <P>
+ Information about a request comes from two different sources: the
+ request header, and any associated
+ message-body.
+ Servers MUST
+ make portions of this information available to
+ scripts.
+ </P>
+
+ <H3>
+ <A NAME="6.1">
+ 6.1. Request Metadata
+ (Metavariables)
+ </A>
+ </H3>
+ <P>
+ Each CGI server
+ implementation MUST define a mechanism
+ to pass data about the request from
+ the server to the script.
+ The metavariables containing these
+ data
+ are accessed by the script in a system
+ defined manner.
+ The
+ representation of the characters in the
+ metavariables is
+ system defined.
+ </P>
+ <P>
+ This specification does not distinguish between the representation of
+ null values and missing ones. Whether null or missing values
+ (such as a query component of "?" or "", respectively) are represented
+ by undefined metavariables or by metavariables with values of "" is
+ implementation-defined.
+ </P>
+ <P>
+ Case is not significant in the
+ metavariable
+ names, in that there cannot be two
+ different variables
+ whose names differ in case only. Here they are
+ shown using a canonical representation of capitals plus underscore
+ ("_"). The actual representation of the names is system defined; for
+ a particular system the representation MAY be defined differently
+ than this.
+ </P>
+ <P>
+ Metavariable
+ values MUST be
+ considered case-sensitive except as noted
+ otherwise.
+ </P>
+ <P>
+ The canonical
+ metavariables
+ defined by this specification are:
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ AUTH_TYPE
+ CONTENT_LENGTH
+ CONTENT_TYPE
+ GATEWAY_INTERFACE
+ PATH_INFO
+ PATH_TRANSLATED
+ QUERY_STRING
+ REMOTE_ADDR
+ REMOTE_HOST
+ REMOTE_IDENT
+ REMOTE_USER
+ REQUEST_METHOD
+ SCRIPT_NAME
+ SERVER_NAME
+ SERVER_PORT
+ SERVER_PROTOCOL
+ SERVER_SOFTWARE
+ </PRE>
+ <P>
+ Metavariables with names beginning with the protocol name (<EM>e.g.</EM>,
+ "HTTP_ACCEPT") are also canonical in their description of request header
+ fields. The number and meaning of these fields may change independently
+ of this specification. (See also <A HREF="#6.1.5">section 6.1.5</A>.)
+ </P>
+
+ <H4>
+ <A NAME="6.1.1">
+ 6.1.1. AUTH_TYPE
+ </A>
+ </H4>
+ <P>
+ This variable is specific to requests made
+ <EM>via</EM> the
+ "<CODE>http</CODE>"
+ scheme.
+ </P>
+ <P>
+ If the Script-URI
+ required access authentication for external
+ access, then the server
+ MUST set
+ the value of
+ this variable
+ from the '<SAMP>auth-scheme</SAMP>' token in
+ the request's "<SAMP>Authorization</SAMP>" header
+ field.
+ Otherwise
+ it is
+ set to NULL.
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ AUTH_TYPE = "" | auth-scheme
+ auth-scheme = "Basic" | "Digest" | token
+ </PRE>
+ <P>
+ HTTP access authentication schemes are described in section 11 of the
+ HTTP/1.1 specification [<A HREF="#[8]">8</A>]. The auth-scheme is
+ not case-sensitive.
+ </P>
+ <P>
+ Servers
+ MUST
+ provide this metavariable
+ to scripts if the request
+ header included an "<SAMP>Authorization</SAMP>" field
+ that was authenticated.
+ </P>
+
+ <H4>
+ <A NAME="6.1.2">
+ 6.1.2. CONTENT_LENGTH
+ </A>
+ </H4>
+ <P>
+ This
+ metavariable
+ is set to the
+ size of the message-body
+ entity attached to the request, if any, in decimal
+ number of octets. If no data are attached, then this
+ metavariable
+ is either NULL or not
+ defined. The syntax is
+ the same as for
+ the HTTP "<SAMP>Content-Length</SAMP>" header field (section 14.14, HTTP/1.1
+ specification [<A HREF="#[8]">8</A>]).
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ CONTENT_LENGTH = "" | 1*digit
+ </PRE>
+ <P>
+ Servers MUST provide this metavariable
+ to scripts if the request
+ was accompanied by a
+ message-body entity.
+ </P>
+
+ <H4>
+ <A NAME="6.1.3">
+ 6.1.3. CONTENT_TYPE
+ </A>
+ </H4>
+ <P>
+ If the request includes a
+ message-body,
+ CONTENT_TYPE is set
+ to
+ the Internet Media Type
+ [<A HREF="#[9]">9</A>] of the attached
+ entity if the type was provided <EM>via</EM>
+ a "<SAMP>Content-type</SAMP>" field in the
+ request header, or if the server can determine it in the absence
+ of a supplied "<SAMP>Content-type</SAMP>" field. The syntax is the
+ same as for the HTTP
+ "<SAMP>Content-Type</SAMP>" header field.
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ CONTENT_TYPE = "" | media-type
+ media-type = type "/" subtype *( ";" parameter)
+ type = token
+ subtype = token
+ parameter = attribute "=" value
+ attribute = token
+ value = token | quoted-string
+ </PRE>
+ <P>
+ The type, subtype,
+ and parameter attribute names are not
+ case-sensitive. Parameter values MAY be case sensitive.
+ Media types and their use in HTTP are described
+ in section 3.7 of the
+ HTTP/1.1 specification [<A HREF="#[8]">8</A>].
+ </P>
+ <P>
+ Example:
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ application/x-www-form-urlencoded
+ </PRE>
+ <P>
+ There is no default value for this variable. If and only if it is
+ unset, then the script MAY attempt to determine the media type from
+ the data received. If the type remains unknown, then
+ the script MAY choose to either assume a
+ content-type of
+ <SAMP>application/octet-stream</SAMP>
+ or reject the request with a 415 ("Unsupported Media Type")
+ error. See <A HREF="#7.2.1.3">section 7.2.1.3</A>
+ for more information about returning error status values.
+ </P>
+ <P>
+ Servers MUST provide this metavariable
+ to scripts if
+ a "<SAMP>Content-Type</SAMP>" field was present
+ in the original request header. If the server receives a request
+ with an attached entity but no "<SAMP>Content-Type</SAMP>"
+ header field, it MAY attempt to
+ determine the correct datatype, or it MAY omit this
+ metavariable when
+ communicating the request information to the script.
+ </P>
+
+ <H4>
+ <A NAME="6.1.4">
+ 6.1.4. GATEWAY_INTERFACE
+ </A>
+ </H4>
+ <P>
+ This
+ metavariable
+ is set to
+ the dialect of CGI being used
+ by the server to communicate with the script.
+ Syntax:
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ GATEWAY_INTERFACE = "CGI" "/" major "." minor
+ major = 1*digit
+ minor = 1*digit
+ </PRE>
+ <P>
+ Note that the major and minor numbers are treated as separate
+ integers and hence each may be
+ more than a single
+ digit. Thus CGI/2.4 is a lower version than CGI/2.13 which in turn
+ is lower than CGI/12.3. Leading zeros in either
+ the major or the minor number MUST be ignored by scripts and
+ SHOULD NOT be generated by servers.
+ </P>
+ <P>
+ This document defines the 1.1 version of the CGI interface
+ ("CGI/1.1").
+ </P>
+ <P>
+ Servers MUST provide this metavariable
+ to scripts.
+ </P>
+
+ <H4>
+ <A NAME="6.1.5">
+ 6.1.5. Protocol-Specific Metavariables
+ </A>
+ </H4>
+ <P>
+ These metavariables are specific to
+ the protocol
+ <EM>via</EM> which the request is made.
+ Interpretation of these variables depends on the value of
+ the
+ SERVER_PROTOCOL
+ metavariable
+ (see
+ <A HREF="#6.1.17">section 6.1.17</A>).
+ </P>
+ <P>
+ Metavariables
+ with names beginning with "HTTP_" contain
+ values from the request header, if the
+ scheme used was HTTP.
+ Each
+ HTTP header field name is converted to upper case, has all occurrences of
+ "-" replaced with "_",
+ and has "HTTP_" prepended to form
+ the metavariable name.
+ Similar transformations are applied for other
+ protocols.
+ The header data MAY be presented as sent
+ by the client, or MAY be rewritten in ways which do not change its
+ semantics. If multiple header fields with the same field-name are received
+ then the server
+ MUST rewrite them as though they
+ had been received as a single header field having the same
+ semantics before being represented in a
+ metavariable.
+ Similarly, a header field that is received on more than one line
+ MUST be merged into a single line. The server MUST, if necessary,
+ change the representation of the data (for example, the character
+ set) to be appropriate for a CGI
+ metavariable.
+ <!-- ###NOTE: See if 2068 describes this thoroughly, and
+ point there if so. -->
+ </P>
+ <P>
+ Servers are
+ not required to create
+ metavariables for all
+ the request
+ header fields that they
+ receive. In particular,
+ they MAY
+ decline to make available any
+ header fields carrying authentication information, such as
+ "<SAMP>Authorization</SAMP>", or
+ which are available to the script
+ <EM>via</EM> other metavariables,
+ such as "<SAMP>Content-Length</SAMP>" and "<SAMP>Content-Type</SAMP>".
+ </P>
+
+ <H4>
+ <A NAME="6.1.6">
+ 6.1.6. PATH_INFO
+ </A>
+ </H4>
+ <P>
+ The PATH_INFO
+ metavariable
+ specifies
+ a path to be interpreted by the CGI script. It identifies the
+ resource or sub-resource to be returned
+ by the CGI
+ script, and it is derived from the portion
+ of the URI path following the script name but preceding
+ any query data.
+ The syntax
+ and semantics are similar to a decoded HTTP URL
+ 'path' token
+ (defined in
+ RFC 2396
+ [<A HREF="#[4]">4</A>]), with the exception
+ that a PATH_INFO of "/"
+ represents a single void path segment.
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ PATH_INFO = "" | ( "/" path )
+ path = segment *( "/" segment )
+ segment = *pchar
+ pchar = &lt;any CHAR except "/"&gt;
+ </PRE>
+ <P>
+ The PATH_INFO string is the trailing part of the &lt;path&gt; component of
+ the Script-URI
+ (see <A HREF="#3.2">section 3.2</A>)
+ that follows the SCRIPT_NAME
+ portion of the path.
+ </P>
+ <P>
+ Servers MAY impose their own restrictions and
+ limitations on what values they will accept for PATH_INFO, and MAY
+ reject or edit any values they
+ consider objectionable before passing
+ them to the script.
+ </P>
+ <P>
+ Servers MUST make this URI component available
+ to CGI scripts. The PATH_INFO
+ value is case-sensitive, and the
+ server MUST preserve the case of the PATH_INFO element of the URI
+ when making it available to scripts.
+ </P>
+
+ <H4>
+ <A NAME="6.1.7">
+ 6.1.7. PATH_TRANSLATED
+ </A>
+ </H4>
+ <P>
+ PATH_TRANSLATED is derived by taking any path-info component of the
+ request URI (see
+ <A HREF="#6.1.6">section 6.1.6</A>), decoding it
+ (see <A HREF="#3.1">section 3.1</A>), parsing it as a URI in its own
+ right, and performing any virtual-to-physical
+ translation appropriate to map it onto the
+ server's document repository structure.
+ If the request URI includes no path-info
+ component, the PATH_TRANSLATED metavariable SHOULD NOT be defined.
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ PATH_TRANSLATED = *CHAR
+ </PRE>
+ <P>
+ For a request such as the following:
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ http://somehost.com/cgi-bin/somescript/this%2eis%2epath%2einfo
+ </PRE>
+ <P>
+ the PATH_INFO component would be decoded, and the result
+ parsed as though it were a request for the following:
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ http://somehost.com/this.is.the.path.info
+ </PRE>
+ <P>
+ This would then be translated to a
+ location in the server's document repository,
+ perhaps a filesystem path something
+ like this:
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ /usr/local/www/htdocs/this.is.the.path.info
+ </PRE>
+ <P>
+ The result of the translation is the value of PATH_TRANSLATED.
+ </P>
+ <P>
+ The value of PATH_TRANSLATED may or may not map to a valid
+ repository
+ location.
+ Servers MUST preserve the case of the path-info
+ segment if and only if the underlying
+ repository
+ supports case-sensitive
+ names. If the
+ repository
+ is only case-aware, case-preserving, or case-blind
+ with regard to
+ document names,
+ servers are not required to preserve the
+ case of the original segment through the translation.
+ </P>
+ <P>
+ The
+ translation
+ algorithm the server uses to derive PATH_TRANSLATED is
+ implementation defined; CGI scripts which use this variable may
+ suffer limited portability.
+ </P>
+ <P>
+ Servers SHOULD provide this metavariable
+ to scripts if and only if the request URI includes a
+ path-info component.
+ </P>
+
+ <H4>
+ <A NAME="6.1.8">
+ 6.1.8. QUERY_STRING
+ </A>
+ </H4>
+ <P>
+ A URL-encoded
+ string; the &lt;query&gt; part of the
+ Script-URI.
+ (See
+ <A HREF="#3.2">section 3.2</A>.)
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ QUERY_STRING = query-string
+ query-string = *uric
+ </PRE>
+ <P>
+ The URL syntax for a query
+ string is described in
+ section 3 of
+ RFC 2396
+ [<A HREF="#[4]">4</A>].
+ </P>
+ <P>
+ Servers MUST supply this value to scripts.
+ The QUERY_STRING value is case-sensitive.
+ If the Script-URI does not include a query component,
+ the QUERY_STRING metavariable MUST be defined as an empty string ("").
+ </P>
+
+ <H4>
+ <A NAME="6.1.9">
+ 6.1.9. REMOTE_ADDR
+ </A>
+ </H4>
+ <P>
+ The IP address of the client
+ sending the request to the server. This
+ is not necessarily that of the user
+ agent
+ (such as if the request came through a proxy).
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ REMOTE_ADDR = hostnumber
+ hostnumber = ipv4-address | ipv6-address
+ </PRE>
+ <P>
+ The definitions of <SAMP>ipv4-address</SAMP> and <SAMP>ipv6-address</SAMP>
+ are provided in Appendix B of RFC 2373 [<A HREF="#[13]">13</A>].
+ </P>
+ <P>
+ Servers MUST supply this value to scripts.
+ </P>
+
+ <H4>
+ <A NAME="6.1.10">
+ 6.1.10. REMOTE_HOST
+ </A>
+ </H4>
+ <P>
+ The fully qualified domain name of the
+ client sending the request to
+ the server, if available, otherwise NULL.
+ (See <A HREF="#6.1.9">section 6.1.9</A>.)
+ Fully qualified domain names take the form as described in
+ section 3.5 of RFC 1034 [<A HREF="#[10]">10</A>] and section 2.1 of
+ RFC 1123 [<A HREF="#[5]">5</A>]. Domain names are not case sensitive.
+ </P>
+ <P>
+ Servers SHOULD provide this information to
+ scripts.
+ </P>
+
+ <H4>
+ <A NAME="6.1.11">
+ 6.1.11. REMOTE_IDENT
+ </A>
+ </H4>
+ <P>
+ The identity information reported about the connection by a
+ RFC 1413 [<A HREF="#[11]">11</A>] request to the remote agent, if
+ available. Servers
+ MAY choose not
+ to support this feature, or not to request the data
+ for efficiency reasons.
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ REMOTE_IDENT = *CHAR
+ </PRE>
+ <P>
+ The data returned
+ may be used for authentication purposes, but the level
+ of trust reposed in them should be minimal.
+ </P>
+ <P>
+ Servers MAY supply this information to scripts if the
+ RFC1413 [<A HREF="#[11]">11</A>] lookup is performed.
+ </P>
+
+ <H4>
+ <A NAME="6.1.12">
+ 6.1.12. REMOTE_USER
+ </A>
+ </H4>
+ <P>
+ If the request required authentication using the "Basic"
+ mechanism (<EM>i.e.</EM>, the AUTH_TYPE
+ metavariable is set
+ to "Basic"), then the value of the REMOTE_USER
+ metavariable is set to the
+ user-ID supplied. In all other cases
+ the value of this metavariable
+ is undefined.
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ REMOTE_USER = *OCTET
+ </PRE>
+ <P>
+ This variable is specific to requests made <EM>via</EM> the
+ HTTP protocol.
+ </P>
+ <P>
+ Servers SHOULD provide this metavariable
+ to scripts.
+ </P>
+
+ <H4>
+ <A NAME="6.1.13">
+ 6.1.13. REQUEST_METHOD
+ </A>
+ </H4>
+ <P>
+ The REQUEST_METHOD
+ metavariable
+ is set to the
+ method with which the request was made, as described in section
+ 5.1.1 of the HTTP/1.0 specification [<A HREF="#[3]">3</A>] and
+ section 5.1.1 of the
+ HTTP/1.1 specification [<A HREF="#[8]">8</A>].
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ REQUEST_METHOD = http-method
+ http-method = "GET" | "HEAD" | "POST" | "PUT" | "DELETE"
+ | "OPTIONS" | "TRACE" | extension-method
+ extension-method = token
+ </PRE>
+ <P>
+ The method is case sensitive.
+ CGI/1.1 servers MAY choose to process some methods
+ directly rather than passing them to scripts.
+ </P>
+ <P>
+ This variable is specific to requests made with HTTP.
+ </P>
+ <P>
+ Servers MUST provide this metavariable
+ to scripts.
+ </P>
+
+ <H4>
+ <A NAME="6.1.14">
+ 6.1.14. SCRIPT_NAME
+ </A>
+ </H4>
+ <P>
+ The SCRIPT_NAME
+ metavariable
+ is
+ set to a URL path that could identify the CGI script (rather than the
+ script's
+ output). The syntax and semantics are identical to a
+ decoded HTTP URL 'path' token
+ (see RFC 2396
+ [<A HREF="#[4]">4</A>]).
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ SCRIPT_NAME = "" | ( "/" [ path ] )
+ </PRE>
+ <P>
+ The SCRIPT_NAME string is some leading part of the &lt;path&gt; component
+ of the Script-URI derived in some
+ implementation defined manner.
+ No PATH_INFO or QUERY_STRING segments
+ (see sections <A HREF="#6.1.6">6.1.6</A> and
+ <A HREF="#6.1.8">6.1.8</A>) are included
+ in the SCRIPT_NAME value.
+ </P>
+ <P>
+ Servers MUST provide this metavariable
+ to scripts.
+ </P>
+
+ <H4>
+ <A NAME="6.1.15">
+ 6.1.15. SERVER_NAME
+ </A>
+ </H4>
+ <P>
+ The SERVER_NAME
+ metavariable
+ is set to the
+ name of the
+ server, as
+ derived from the &lt;host&gt; part of the
+ Script-URI
+ (see <A HREF="#3.2">section 3.2</A>).
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ SERVER_NAME = hostname | hostnumber
+ </PRE>
+ <P>
+ Servers MUST provide this metavariable
+ to scripts.
+ </P>
+
+ <H4>
+ <A NAME="6.1.16">
+ 6.1.16. SERVER_PORT
+ </A>
+ </H4>
+ <P>
+ The SERVER_PORT
+ metavariable
+ is set to the
+ port on which the
+ request was received, as used in the &lt;port&gt;
+ part of the Script-URI.
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ SERVER_PORT = 1*digit
+ </PRE>
+ <P>
+ If the &lt;port&gt; portion of the script-URI is blank, the actual
+ port number upon which the request was received MUST be supplied.
+ </P>
+ <P>
+ Servers MUST provide this metavariable
+ to scripts.
+ </P>
+
+ <H4>
+ <A NAME="6.1.17">
+ 6.1.17. SERVER_PROTOCOL
+ </A>
+ </H4>
+ <P>
+ The SERVER_PROTOCOL
+ metavariable
+ is set to
+ the
+ name and revision of the information protocol with which
+ the
+ request
+ arrived. This is not necessarily the same as the protocol version used by
+ the server in its response to the client.
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ SERVER_PROTOCOL = HTTP-Version | extension-version
+ | extension-token
+ HTTP-Version = "HTTP" "/" 1*digit "." 1*digit
+ extension-version = protocol "/" 1*digit "." 1*digit
+ protocol = 1*( alpha | digit | "+" | "-" | "." )
+ extension-token = token
+ </PRE>
+ <P>
+ 'protocol' is a version of the &lt;scheme&gt; part of the
+ Script-URI, but is
+ not identical to it. For example, the scheme of a request may be
+ "<SAMP>https</SAMP>" while the protocol remains "<SAMP>http</SAMP>".
+ The protocol is not case sensitive, but
+ by convention, 'protocol' is in
+ upper case.
+ </P>
+ <P>
+ A well-known extension token value is "INCLUDED",
+ which signals that the current document is being included as part of
+ a composite document, rather than being the direct target of the
+ client request.
+ </P>
+ <P>
+ Servers MUST provide this metavariable
+ to scripts.
+ </P>
+
+ <H4>
+ <A NAME="6.1.18">
+ 6.1.18. SERVER_SOFTWARE
+ </A>
+ </H4>
+ <P>
+ The SERVER_SOFTWARE
+ metavariable
+ is set to the
+ name and version of the information server software answering the
+ request (and running the gateway).
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ SERVER_SOFTWARE = 1*product
+ product = token [ "/" product-version ]
+ product-version = token
+ </PRE>
+ <P>
+ Servers MUST provide this metavariable
+ to scripts.
+ </P>
+
+ <H3>
+ <A NAME="6.2">
+ 6.2. Request Message-Bodies
+ </A>
+ </H3>
+ <P>
+ As there may be a data entity attached to the request, there MUST be
+ a system defined method for the script to read
+ these data. Unless
+ defined otherwise, this will be <EM>via</EM> the 'standard input' file
+ descriptor.
+ </P>
+ <P>
+ If the CONTENT_LENGTH value (see <A HREF="#6.1.2">section 6.1.2</A>)
+ is non-NULL, the server MUST supply at least that many bytes to
+ scripts on the standard input stream.
+ Scripts are
+ not obliged to read the data.
+ Servers MAY signal an EOF condition after CONTENT_LENGTH bytes have been
+ read, but are
+ not obligated to do so. Therefore, scripts
+ MUST NOT
+ attempt to read more than CONTENT_LENGTH bytes, even if more data
+ are available.
+ </P>
+ <P>
+ For non-parsed header (NPH) scripts (see
+ <A HREF="#7.1">section 7.1</A>
+ below),
+ servers SHOULD
+ attempt to ensure that the data
+ supplied to the script are precisely
+ as supplied by the client and unaltered by
+ the server.
+ </P>
+ <P>
+ <A HREF="#8.1.2">Section 8.1.2</A> describes the requirements of
+ servers with regard to requests that include
+ message-bodies.
+ </P>
+
+ <H2>
+ <A NAME="7.0">
+ 7. Data Output from the CGI Script
+ </A>
+ </H2>
+ <P>
+ There MUST be a system defined method for the script to send data
+ back to the server or client; a script MUST always return some data.
+ Unless defined otherwise, this will be <EM>via</EM> the 'standard
+ output' file descriptor.
+ </P>
+ <P>
+ There are two forms of output that scripts can supply to servers: non-parsed
+ header (NPH) output, and parsed header output.
+ Servers MUST support parsed header
+ output and MAY support NPH output. The method of
+ distinguishing between the two
+ types of output (or scripts) is implementation defined.
+ </P>
+ <P>
+ Servers MAY implement a timeout period within which data must be
+ received from scripts. If a server implementation defines such
+ a timeout and receives no data from a script within the timeout
+ period, the server MAY terminate the script process and SHOULD
+ abort the client request with
+ either a
+ '504 Gateway Timed Out' or a
+ '500 Internal Server Error' response.
+ </P>
+
+ <H3>
+ <A NAME="7.1">
+ 7.1. Non-Parsed Header Output
+ </A>
+ </H3>
+ <P>
+ Scripts using the NPH output form
+ MUST return a complete HTTP response message, as described
+ in Section 6 of the HTTP specifications
+ [<A HREF="#[3]">3</A>,<A HREF="#[8]">8</A>].
+ NPH scripts
+ MUST use the SERVER_PROTOCOL variable to determine the appropriate format
+ for a response.
+ </P>
+ <P>
+ Servers
+ SHOULD attempt to ensure that the script output is sent
+ directly to the client, with minimal
+ internal and no transport-visible
+ buffering.
+ </P>
+
+ <H3>
+ <A NAME="7.2">
+ 7.2. Parsed Header Output
+ </A>
+ </H3>
+ <P>
+ Scripts using the parsed header output form MUST supply
+ a CGI response message to the server
+ as follows:
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ CGI-Response = *optional-field CGI-Field *optional-field NL [ Message-Body ]
+ optional-field = ( CGI-Field | HTTP-Field )
+ CGI-Field = Content-type
+ | Location
+ | Status
+ | extension-header
+ </PRE>
+ <P><!-- ##### If HTTP defines x-headers, remove ours except x-cgi- -->
+ The response comprises a header and a body, separated by a blank line.
+ The body may be NULL.
+ The header fields are either CGI header fields to be interpreted by
+ the server, or HTTP header fields
+ to be included in the response returned
+ to the client
+ if the request method is HTTP. At least one
+ CGI-Field MUST be
+ supplied, but no CGI field name may be used more than once
+ in a response.
+ If a body is supplied, then a "<SAMP>Content-type</SAMP>"
+ header field MUST be
+ supplied by the script,
+ otherwise the script MUST send a "<SAMP>Location</SAMP>"
+ or "<SAMP>Status</SAMP>" header field. If a
+ <SAMP>Location</SAMP> CGI-Field
+ is returned, then the script MUST NOT supply
+ any HTTP-Fields.
+ </P>
+ <P>
+ Each header field in a CGI-Response MUST be specified on a single line;
+ CGI/1.1 does not support continuation lines.
+ </P>
+
+ <H4>
+ <A NAME="7.2.1">
+ 7.2.1. CGI header fields
+ </A>
+ </H4>
+ <P>
+ The CGI header fields have the generic syntax:
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ generic-field = field-name ":" [ field-value ] NL
+ field-name = token
+ field-value = *( field-content | LWSP )
+ field-content = *( token | tspecial | quoted-string )
+ </PRE>
+ <P>
+ The field-name is not case sensitive; a NULL field value is
+ equivalent to the header field not being sent.
+ </P>
+
+ <H4>
+ <A NAME="7.2.1.1">
+ 7.2.1.1. Content-Type
+ </A>
+ </H4>
+ <P>
+ The Internet Media Type [<A HREF="#[9]">9</A>] of the entity
+ body, which is to be sent unmodified to the client.
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ Content-Type = "Content-Type" ":" media-type NL
+ </PRE>
+ <P>
+ This is actually an HTTP-Field
+ rather than a CGI-Field, but
+ it is listed here because of its importance in the CGI dialogue as
+ a member of the "one of these is required" set of header
+ fields.
+ </P>
+
+ <H4>
+ <A NAME="7.2.1.2">
+ 7.2.1.2. Location
+ </A>
+ </H4>
+ <P>
+ This is used to specify to the server that the script is returning a
+ reference to a document rather than an actual document.
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ Location = "Location" ":"
+ ( fragment-URI | rel-URL-abs-path ) NL
+ fragment-URI = URI [ # fragmentid ]
+ URI = scheme ":" *qchar
+ fragmentid = *qchar
+ rel-URL-abs-path = "/" [ hpath ] [ "?" query-string ]
+ hpath = fpsegment *( "/" psegment )
+ fpsegment = 1*hchar
+ psegment = *hchar
+ hchar = alpha | digit | safe | extra
+ | ":" | "@" | "& | "="
+ </PRE>
+ <P>
+ The Location
+ value is either an absolute URI with optional fragment,
+ as defined in RFC 1630 [<A HREF="#[1]">1</A>], or an absolute path
+ within the server's URI space (<EM>i.e.</EM>,
+ omitting the scheme and network-related fields) and optional
+ query-string. If an absolute URI is returned by the script,
+ then the
+ server MUST generate a
+ '302 redirect' HTTP response
+ message unless the script has supplied an
+ explicit Status response header field.
+ Scripts returning an absolute URI MAY choose to
+ provide a message-body. Servers MUST make any appropriate modifications
+ to the script's output to ensure the response to the user-agent complies
+ with the response protocol version.
+ If the Location value is a path, then the server
+ MUST generate
+ the response that it would have produced in response to a request
+ containing the URL
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ scheme "://" SERVER_NAME ":" SERVER_PORT rel-URL-abs-path
+ </PRE>
+ <P>
+ Note: If the request was accompanied by a
+ message-body
+ (such as for a POST request), and the script
+ redirects the request with a Location field, the
+ message-body
+ may not be
+ available to the resource that is the target of the redirect.
+ </P>
+
+ <H4>
+ <A NAME="7.2.1.3">
+ 7.2.1.3. Status
+ </A>
+ </H4>
+ <P>
+ The "<SAMP>Status</SAMP>" header field is used to indicate to the server what
+ status code the server MUST use in the response message.
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ Status = "Status" ":" digit digit digit SP reason-phrase NL
+ reason-phrase = *&lt;CHAR, excluding CTLs, NL&gt;
+ </PRE>
+ <P>
+ The valid status codes are listed in section 6.1.1 of the HTTP/1.0
+ specifications [<A HREF="#[3]">3</A>]. If the SERVER_PROTOCOL is
+ "HTTP/1.1", then the status codes defined in the HTTP/1.1
+ specification [<A HREF="#[8]">8</A>] may
+ be used. If the script does not return a "<SAMP>Status</SAMP>" header
+ field, then "200 OK" SHOULD be assumed by the server.
+ </P>
+ <P>
+ If a script is being used to handle a particular error or condition
+ encountered by the server, such as a '404 Not Found' error, the script
+ SHOULD use the "<SAMP>Status</SAMP>" CGI header field to propagate the error
+ condition back to the client. <EM>E.g.</EM>, in the example mentioned it
+ SHOULD include a "Status:&nbsp;404&nbsp;Not&nbsp;Found" in the
+ header data returned to the server.
+ </P>
+
+ <H4>
+ <A NAME="7.2.1.4">
+ 7.2.1.4. Extension header fields
+ </A>
+ </H4>
+ <P>
+ Scripts MAY include in their CGI response header additional fields
+ not defined in this or the HTTP specification.
+ These are called "extension" fields,
+ and have the syntax of a <SAMP>generic-field</SAMP> as defined in
+ <A HREF="#7.2.1">section 7.2.1</A>. The name of an extension field
+ MUST NOT conflict with a field name defined in this or any other
+ specification; extension field names SHOULD begin with "X-CGI-"
+ to ensure uniqueness.
+ </P>
+
+ <H4>
+ <A NAME="7.2.2">
+ 7.2.2. HTTP header fields
+ </A>
+ </H4>
+ <P>
+ The script MAY return any other header fields defined by the
+ specification
+ for the SERVER_PROTOCOL (HTTP/1.0 [<A HREF="#[3]">3</A>] or HTTP/1.1
+ [<A HREF="#[8]">8</A>]).
+ Servers MUST resolve conflicts beteen CGI header
+ and HTTP header formats or names (see <A HREF="#8.0">section 8</A>).
+ </P>
+
+ <H2>
+ <A NAME="8.0">
+ 8. Server Implementation
+ </A>
+ </H2>
+ <P>
+ This section defines the requirements that must be met by HTTP
+ servers in order to provide a coherent and correct CGI/1.1
+ environment in which scripts may function. It is intended
+ primarily for server implementors, but it is useful for
+ script authors to be familiar with the information as well.
+ </P>
+
+ <H3>
+ <A NAME="8.1">
+ 8.1. Requirements for Servers
+ </A>
+ </H3>
+ <P>
+ In order to be considered CGI/1.1-compliant, a server must meet
+ certain basic criteria and provide certain minimal functionality.
+ The details of these requirements are described in the following sections.
+ </P>
+
+ <H3>
+ <A NAME="8.1.1">
+ 8.1.1. Script-URI
+ </A>
+ </H3>
+ <P>
+ Servers MUST support the standard mechanism (described below) which
+ allows
+ script authors to determine
+ what URL to use in documents
+ which reference the script;
+ specifically, what URL to use in order to
+ achieve particular settings of the
+ metavariables. This
+ mechanism is as follows:
+ </P>
+ <P>
+ The server
+ MUST translate the header data from the CGI header field syntax to
+ the HTTP
+ header field syntax if these differ. For example, the character
+ sequence for
+ newline (such as Unix's ASCII NL) used by CGI scripts may not be the
+ same as that used by HTTP (ASCII CR followed by LF). The server MUST
+ also resolve any conflicts between header fields returned by the script
+ and header fields that it would otherwise send itself.
+ </P>
+
+ <H3>
+ <A NAME="8.1.2">
+ 8.1.2. Request Message-body Handling
+ </A>
+ </H3>
+ <P>
+ These are the requirements for server handling of message-bodies directed
+ to CGI/1.1 resources:
+ </P>
+ <OL>
+ <LI>The message-body the server provides to the CGI script MUST
+ have any transfer encodings removed.
+ </LI>
+ <LI>The server MUST derive and provide a value for the CONTENT_LENGTH
+ metavariable that reflects the length of the message-body after any
+ transfer decoding.
+ </LI>
+ <LI>The server MUST leave intact any content-encodings of the message-body.
+ </LI>
+ </OL>
+
+ <H3>
+ <A NAME="8.1.3">
+ 8.1.3. Required Metavariables
+ </A>
+ </H3>
+ <P>
+ Servers MUST provide scripts with certain information and
+ metavariables
+ as described in <A HREF="#8.3">section 8.3</A>.
+ </P>
+
+ <H3>
+ <A NAME="8.1.4">
+ 8.1.4. Response Compliance
+ </A>
+ </H3>
+ <P>
+ Servers MUST ensure that responses sent to the user-agent meet all
+ requirements of the protocol level in effect. This may involve
+ modifying, deleting, or augmenting any header
+ fields and/or message-body supplied by the script.
+ </P>
+
+ <H3>
+ <A NAME="8.2">
+ 8.2. Recommendations for Servers
+ </A>
+ </H3>
+ <P>
+ Servers SHOULD provide the "<SAMP>query</SAMP>" component of the script-URI
+ as command-line arguments to scripts if it does not
+ contain any unencoded '=' characters and the command-line arguments can
+ be generated in an unambiguous manner.
+ (See <A HREF="#5.0">section 5</A>.)
+ </P>
+ <P>
+ Servers SHOULD set the AUTH_TYPE
+ metavariable to the value of the
+ '<SAMP>auth-scheme</SAMP>' token of the "<SAMP>Authorization</SAMP>"
+ field if it was supplied as part of the request header.
+ (See <A HREF="#6.1.1">section 6.1.1</A>.)
+ </P>
+ <P>
+ Where applicable, servers SHOULD set the current working directory
+ to the directory in which the script is located before invoking
+ it.
+ </P>
+ <P>
+ Servers MAY reject with error '404 Not Found'
+ any requests that would result in
+ an encoded "/" being decoded into PATH_INFO or SCRIPT_NAME, as this
+ might represent a loss of information to the script.
+ </P>
+ <P>
+ Although the server and the CGI script need not be consistent in
+ their handling of URL paths (client URLs and the PATH_INFO data,
+ respectively), server authors may wish to impose consistency.
+ So the server implementation SHOULD define its behaviour for the
+ following cases:
+ </P>
+ <OL>
+ <LI>define any restrictions on allowed characters, in particular
+ whether ASCII NUL is permitted;
+ </LI>
+ <LI>define any restrictions on allowed path segments, in particular
+ whether non-terminal NULL segments are permitted;
+ </LI>
+ <LI>define the behaviour for <SAMP>"."</SAMP> or <SAMP>".."</SAMP> path
+ segments; <EM>i.e.</EM>, whether they are prohibited, treated as
+ ordinary path
+ segments or interpreted in accordance with the relative URL
+ specification [<A HREF="#[7]">7</A>];
+ </LI>
+ <LI>define any limits of the implementation, including limits on path or
+ search string lengths, and limits on the volume of header data the server
+ will parse.
+ </LI><!-- ##### Move the field resolution/translation para below here -->
+ </OL>
+ <P>
+ Servers MAY generate the
+ Script-URI in
+ any way from the client URI,
+ or from any other data (but the behaviour SHOULD be documented).
+ </P>
+ <P>
+ For non-parsed header (NPH) scripts (see
+ <A HREF="#7.1">section 7.1</A>), servers SHOULD
+ attempt to ensure that the script input comes directly from the
+ client, with minimal buffering. For all scripts the data will be
+ as supplied by the client.
+ </P>
+
+ <H3>
+ <A NAME="8.3">
+ 8.3. Summary of
+ MetaVariables
+ </A>
+ </H3>
+ <P>
+ Servers MUST provide the following
+ metavariables to
+ scripts. See the individual descriptions for exceptions and semantics.
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ CONTENT_LENGTH (section <A HREF="#6.1.2">6.1.2</A>)
+ CONTENT_TYPE (section <A HREF="#6.1.3">6.1.3</A>)
+ GATEWAY_INTERFACE (section <A HREF="#6.1.4">6.1.4</A>)
+ PATH_INFO (section <A HREF="#6.1.6">6.1.6</A>)
+ QUERY_STRING (section <A HREF="#6.1.8">6.1.8</A>)
+ REMOTE_ADDR (section <A HREF="#6.1.9">6.1.9</A>)
+ REQUEST_METHOD (section <A HREF="#6.1.13">6.1.13</A>)
+ SCRIPT_NAME (section <A HREF="#6.1.14">6.1.14</A>)
+ SERVER_NAME (section <A HREF="#6.1.15">6.1.15</A>)
+ SERVER_PORT (section <A HREF="#6.1.16">6.1.16</A>)
+ SERVER_PROTOCOL (section <A HREF="#6.1.17">6.1.17</A>)
+ SERVER_SOFTWARE (section <A HREF="#6.1.18">6.1.18</A>)
+ </PRE>
+ <P>
+ Servers SHOULD define the following
+ metavariables for scripts.
+ See the individual descriptions for exceptions and semantics.
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ AUTH_TYPE (section <A HREF="#6.1.1">6.1.1</A>)
+ REMOTE_HOST (section <A HREF="#6.1.10">6.1.10</A>)
+ </PRE>
+ <P>
+ In addition, servers SHOULD provide
+ metavariables for all fields present
+ in the HTTP request header, with the exception of those involved with
+ access control. Servers MAY at their discretion provide
+ metavariables
+ for access control fields.
+ </P>
+ <P>
+ Servers MAY define the following
+ metavariables. See the individual
+ descriptions for exceptions and semantics.
+ </P><!--#if expr="! $GUI" -->
+ <P></P><!--#endif -->
+ <PRE>
+ PATH_TRANSLATED (section <A HREF="#6.1.7">6.1.7</A>)
+ REMOTE_IDENT (section <A HREF="#6.1.11">6.1.11</A>)
+ REMOTE_USER (section <A HREF="#6.1.12">6.1.12</A>)
+ </PRE>
+ <P>
+ Servers MAY
+ at their discretion define additional implementation-specific
+ extension metavariables
+ provided their names do not
+ conflict with defined header field names. Implementation-specific
+ metavariable names SHOULD
+ be prefixed with "X_" (<EM>e.g.</EM>,
+ "X_DBA") to avoid the potential for such conflicts.
+ </P>
+
+ <H2>
+ <A NAME="9.0">
+ 9.
+ Script Implementation
+ </A>
+ </H2>
+ <P>
+ This section defines the requirements and recommendations for scripts
+ that are intended to function in a CGI/1.1 environment. It is intended
+ primarily as a reference for script authors, but server implementors
+ should be familiar with these issues as well.
+ </P>
+
+ <H3>
+ <A NAME="9.1">
+ 9.1. Requirements for Scripts
+ </A>
+ </H3>
+ <P>
+ Scripts using the parsed-header method to communicate with servers
+ MUST supply a response header to the server.
+ (See <A HREF="#7.0">section 7</A>.)
+ </P>
+ <P>
+ Scripts using the NPH method to communicate with servers MUST
+ provide complete HTTP responses, and MUST use the value of the
+ SERVER_PROTOCOL metavariable
+ to determine the appropriate format.
+ (See <A HREF="#7.1">section 7.1</A>.)
+ </P>
+ <P>
+ Scripts MUST check the value of the REQUEST_METHOD
+ metavariable in order
+ to provide an appropriate response.
+ (See <A HREF="#6.1.13">section 6.1.13</A>.)
+ </P>
+ <P>
+ Scripts MUST be prepared to handled URL-encoded values in
+ metavariables.
+ In addition, they MUST recognise both "+" and "%20" in URL-encoded
+ quantities as representing the space character.
+ (See <A HREF="#3.1">section 3.1</A>.)
+ </P>
+ <P>
+ Scripts MUST ignore leading zeros in the major and minor version numbers
+ in the GATEWAY_INTERFACE
+ metavariable value. (See
+ <A HREF="#6.1.4">section 6.1.4</A>.)
+ </P>
+ <P>
+ When processing requests that include a
+ message-body, scripts
+ MUST NOT read more than CONTENT_LENGTH bytes from the input stream.
+ (See sections <A HREF="#6.1.2">6.1.2</A> and <A HREF="#6.2">6.2</A>.)
+ </P>
+
+ <H3>
+ <A NAME="9.2">
+ 9.2. Recommendations for Scripts
+ </A>
+ </H3>
+ <P>
+ Servers may interrupt or terminate script execution at any time
+ and without warning, so scripts SHOULD be prepared to deal with
+ abnormal termination.
+ </P>
+ <P>
+ Scripts MUST
+ reject with
+ error '405 Method Not
+ Allowed' requests
+ made using methods that they do not support. If the script does
+ not intend
+ processing the PATH_INFO data, then it SHOULD reject the request with
+ '404 Not
+ Found' if PATH_INFO is not NULL.
+ </P>
+ <P>
+ If a script is processing the output of a form, it SHOULD
+ verify that the CONTENT_TYPE
+ is "<SAMP>application/x-www-form-urlencoded</SAMP>" [<A HREF="#[2]">2</A>]
+ or whatever other media type is expected.
+ </P>
+ <P>
+ Scripts parsing PATH_INFO,
+ PATH_TRANSLATED, or SCRIPT_NAME
+ SHOULD be careful
+ of void path segments ("<SAMP>//</SAMP>") and special path segments
+ (<SAMP>"."</SAMP> and
+ <SAMP>".."</SAMP>). They SHOULD either be removed from the path before
+ use in OS
+ system calls, or the request SHOULD be rejected with
+ '404 Not Found'.
+ </P>
+ <P>
+ As it is impossible for
+ scripts to determine the client URI that
+ initiated a
+ request without knowledge of the specific server in
+ use, the script SHOULD NOT return "<SAMP>text/html</SAMP>"
+ documents containing
+ relative URL links without including a "<SAMP>&lt;BASE&gt;</SAMP>"
+ tag in the document.
+ </P>
+ <P>
+ When returning header fields,
+ scripts SHOULD try to send the CGI
+ header fields (see section
+ <A HREF="#7.2">7.2</A>) as soon as possible, and
+ SHOULD send them
+ before any HTTP header fields. This may
+ help reduce the server's memory requirements.
+ </P>
+
+ <H2>
+ <A NAME="10.0">
+ 10. System Specifications
+ </A>
+ </H2>
+
+ <H3>
+ <A NAME="10.1">
+ 10.1. AmigaDOS
+ </A>
+ </H3>
+ <P>
+ The implementation of the CGI on an AmigaDOS operating system platform
+ SHOULD use environment variables as the mechanism of providing
+ request metadata to CGI scripts.
+ </P>
+ <DL>
+ <DT><STRONG>Environment variables</STRONG>
+ </DT>
+ <DD>
+ <P>
+ These are accessed by the DOS library routine <SAMP>GetVar</SAMP>. The
+ flags argument SHOULD be 0. Case is ignored, but upper case is
+ recommended for compatibility with case-sensitive systems.
+ </P>
+ </DD>
+ <DT><STRONG>The current working directory</STRONG>
+ </DT>
+ <DD>
+ <P>
+ The current working directory for the script is set to the directory
+ containing the script.
+ </P>
+ </DD>
+ <DT><STRONG>Character set</STRONG>
+ </DT>
+ <DD>
+ <P>
+ The US-ASCII character set is used for the definition of environment
+ variable names and header
+ field names; the newline (NL) sequence is LF;
+ servers SHOULD also accept CR LF as a newline.
+ </P>
+ </DD>
+ </DL>
+
+ <H3>
+ <A NAME="10.2">
+ 10.2. Unix
+ </A>
+ </H3>
+ <P>
+ The implementation of the CGI on a UNIX operating system platform
+ SHOULD use environment variables as the mechanism of providing
+ request metadata to CGI scripts.
+ </P>
+ <P>
+ For Unix compatible operating systems, the following are defined:
+ </P>
+ <DL>
+ <DT><STRONG>Environment variables</STRONG>
+ </DT>
+ <DD>
+ <P>
+ These are accessed by the C library routine <SAMP>getenv</SAMP>.
+ </P>
+ </DD>
+ <DT><STRONG>The command line</STRONG>
+ </DT>
+ <DD>
+ <P>
+ This is accessed using the
+ <SAMP>argc</SAMP> and <SAMP>argv</SAMP>
+ arguments to <SAMP>main()</SAMP>. The words have any characters
+ that
+ are 'active' in the Bourne shell escaped with a backslash.
+ If the value of the QUERY_STRING
+ metavariable
+ contains an unencoded equals-sign '=', then the command line
+ SHOULD NOT be used by the script.
+ </P>
+ </DD>
+ <DT><STRONG>The current working directory</STRONG>
+ </DT>
+ <DD>
+ <P>
+ The current working directory for the script
+ SHOULD be set to the directory
+ containing the script.
+ </P>
+ </DD>
+ <DT><STRONG>Character set</STRONG>
+ </DT>
+ <DD>
+ <P>
+ The US-ASCII character set is used for the definition of environment
+ variable names and header field names; the newline (NL) sequence is LF;
+ servers SHOULD also accept CR LF as a newline.
+ </P>
+ </DD>
+ </DL>
+
+ <H2>
+ <A NAME="11.0">
+ 11. Security Considerations
+ </A>
+ </H2>
+
+ <H3>
+ <A NAME="11.1">
+ 11.1. Safe Methods
+ </A>
+ </H3>
+ <P>
+ As discussed in the security considerations of the HTTP
+ specifications [<A HREF="#[3]">3</A>,<A HREF="#[8]">8</A>], the
+ convention has been established that the
+ GET and HEAD methods should be 'safe'; they should cause no
+ side-effects and only have the significance of resource retrieval.
+ </P>
+ <P>
+ CGI scripts are responsible for enforcing any HTTP security considerations
+ [<A HREF="#[3]">3</A>,<A HREF="#[8]">8</A>]
+ with respect to the protocol version level of the request and
+ any side effects generated by the scripts on behalf of
+ the server. Primary
+ among these
+ are the considerations of safe and idempotent methods. Idempotent
+ requests are those that may be repeated an arbitrary number of times
+ and produce side effects identical to a single request.
+ </P>
+
+ <H3>
+ <A NAME="11.2">
+ 11.2. HTTP Header
+ Fields Containing Sensitive Information
+ </A>
+ </H3>
+ <P>
+ Some HTTP header fields may carry sensitive information which the server
+ SHOULD NOT pass on to the script unless explicitly configured to do
+ so. For example, if the server protects the script using the
+ "<SAMP>Basic</SAMP>"
+ authentication scheme, then the client will send an
+ "<SAMP>Authorization</SAMP>"
+ header field containing a username and password. If the server, rather
+ than the script, validates this information then the password SHOULD
+ NOT be passed on to the script <EM>via</EM> the HTTP_AUTHORIZATION
+ metavariable
+ without careful consideration.
+ This also applies to the
+ Proxy-Authorization header field and the corresponding
+ HTTP_PROXY_AUTHORIZATION
+ metavariable.
+ </P>
+
+ <H3>
+ <A NAME="11.3">
+ 11.3. Script
+ Interference with the Server
+ </A>
+ </H3>
+ <P>
+ The most common implementation of CGI invokes the script as a child
+ process using the same user and group as the server process. It
+ SHOULD therefore be ensured that the script cannot interfere with the
+ server process, its configuration, or documents.
+ </P>
+ <P>
+ If the script is executed by calling a function linked in to the
+ server software (either at compile-time or run-time) then precautions
+ SHOULD be taken to protect the core memory of the server, or to
+ ensure that untrusted code cannot be executed.
+ </P>
+
+ <H3>
+ <A NAME="11.4">
+ 11.4. Data Length and Buffering Considerations
+ </A>
+ </H3>
+ <P>
+ This specification places no limits on the length of message-bodies
+ presented to the script. Scripts should not assume that statically
+ allocated buffers of any size are sufficient to contain the entire
+ submission at one time. Use of a fixed length buffer without careful
+ overflow checking may result in an attacker exploiting 'stack-smashing'
+ or 'stack-overflow' vulnerabilities of the operating system.
+ Scripts may spool large submissions to disk or other buffering media,
+ but a rapid succession of large submissions may result in denial of
+ service conditions. If the CONTENT_LENGTH of a message-body is larger
+ than resource considerations allow, scripts should respond with an
+ error status appropriate for the protocol version; potentially applicable
+ status codes include '503 Service Unavailable' (HTTP/1.0 and HTTP/1.1),
+ '413 Request Entity Too Large' (HTTP/1.1), and
+ '414 Request-URI Too Long' (HTTP/1.1).
+ </P>
+
+ <H3>
+ <A NAME="11.5">
+ 11.5. Stateless Processing
+ </A>
+ </H3>
+ <P>
+ The stateless nature of the Web makes each script execution and resource
+ retrieval independent of all others even when multiple requests constitute a
+ single conceptual Web transaction. Because of this, a script should not
+ make any assumptions about the context of the user-agent submitting a
+ request. In particular, scripts should examine data obtained from the client
+ and verify that they are valid, both in form and content, before allowing
+ them to be used for sensitive purposes such as input to other
+ applications, commands, or operating system services. These uses
+ include, but are not
+ limited to: system call arguments, database writes, dynamically evaluated
+ source code, and input to billing or other secure processes. It is important
+ that applications be protected from invalid input regardless of whether
+ the invalidity is the result of user error, logic error, or malicious action.
+ </P>
+ <P>
+ Authors of scripts involved in multi-request transactions should be
+ particularly cautios about validating the state information;
+ undesirable effects may result from the substitution of dangerous
+ values for portions of the submission which might otherwise be
+ presumed safe. Subversion of this type occurs when alterations
+ are made to data from a prior stage of the transaction that were
+ not meant to be controlled by the client (<EM>e.g.</EM>, hidden
+ HTML form elements, cookies, embedded URLs, <EM>etc.</EM>).
+ </P>
+
+ <H2>
+ <A NAME="12.0">
+ 12. Acknowledgements
+ </A>
+ </H2>
+ <P>
+ This work is based on a draft published in 1997 by David R. Robinson,
+ which in turn was based on the original CGI interface that arose out of
+ discussions on the <EM>www-talk</EM> mailing list. In particular,
+ Rob McCool, John Franks, Ari Luotonen,
+ George Phillips and
+ Tony Sanders deserve special recognition for their efforts in
+ defining and implementing the early versions of this interface.
+ </P>
+ <P>
+ This document has also greatly benefited from the comments and
+ suggestions made by Chris Adie, Dave Kristol,
+ Mike Meyer, David Morris, Jeremy Madea,
+ Patrick M<SUP>c</SUP>Manus, Adam Donahue,
+ Ross Patterson, and Harald Alvestrand.
+ </P>
+
+ <H2>
+ <A NAME="13.0">
+ 13. References
+ </A>
+ </H2>
+ <DL COMPACT>
+ <DT><A NAME="[1]">[1]</A>
+ </DT>
+ <DD>Berners-Lee, T., 'Universal Resource Identifiers in WWW: A
+ Unifying Syntax for the Expression of Names and Addresses of
+ Objects on the Network as used in the World-Wide Web', RFC 1630,
+ CERN, June 1994.
+ <P>
+ </P>
+ </DD>
+ <DT><A NAME="[2]">[2]</A>
+ </DT>
+ <DD>Berners-Lee, T. and Connolly, D., 'Hypertext Markup Language -
+ 2.0', RFC 1866, MIT/W3C, November 1995.
+ <P>
+ </P>
+ </DD>
+ <DT><A NAME="[3]">[3]</A>
+ </DT>
+ <DD>Berners-Lee, T., Fielding, R. T. and Frystyk, H.,
+ 'Hypertext Transfer Protocol -- HTTP/1.0', RFC 1945, MIT/LCS,
+ UC Irvine, May 1996.
+ <P>
+ </P>
+ </DD>
+
+ <DT><A NAME="[4]">[4]</A>
+ </DT>
+ <DD>Berners-Lee, T., Fielding, R., and Masinter, L., Editors,
+ 'Uniform Resource Identifiers (URI): Generic Syntax', RFC 2396,
+ MIT, U.C. Irvine, Xerox Corporation, August 1996.
+ <P>
+ </P>
+ </DD>
+
+ <DT><A NAME="[5]">[5]</A>
+ </DT>
+ <DD>Braden, R., Editor, 'Requirements for Internet Hosts --
+ Application and Support', STD 3, RFC 1123, IETF, October 1989.
+ <P>
+ </P>
+ </DD>
+ <DT><A NAME="[6]">[6]</A>
+ </DT>
+ <DD>Crocker, D.H., 'Standard for the Format of ARPA Internet Text
+ Messages', STD 11, RFC 822, University of Delaware, August 1982.
+ <P>
+ </P>
+ </DD>
+ <DT><A NAME="[7]">[7]</A>
+ </DT>
+ <DD>Fielding, R., 'Relative Uniform Resource Locators', RFC 1808,
+ UC Irvine, June 1995.
+ <P>
+ </P>
+ </DD>
+ <DT><A NAME="[8]">[8]</A>
+ </DT>
+ <DD>Fielding, R., Gettys, J., Mogul, J., Frystyk, H. and
+ Berners-Lee, T., 'Hypertext Transfer Protocol -- HTTP/1.1',
+ RFC 2068, UC Irvine, DEC,
+ MIT/LCS, January 1997.
+ <P>
+ </P>
+ </DD>
+ <DT><A NAME="[9]">[9]</A>
+ </DT>
+ <DD>Freed, N. and Borenstein N., 'Multipurpose Internet Mail
+ Extensions (MIME) Part Two: Media Types', RFC 2046, Innosoft,
+ First Virtual, November 1996.
+ <P>
+ </P>
+ </DD>
+ <DT><A NAME="[10]">[10]</A>
+ </DT>
+ <DD>Mockapetris, P., 'Domain Names - Concepts and Facilities',
+ STD 13, RFC 1034, ISI, November 1987.
+ <P>
+ </P>
+ </DD>
+ <DT><A NAME="[11]">[11]</A>
+ </DT>
+ <DD>St. Johns, M., 'Identification Protocol', RFC 1431, US
+ Department of Defense, February 1993.
+ <P>
+ </P>
+ </DD>
+ <DT><A NAME="[12]">[12]</A>
+ </DT>
+ <DD>'Coded Character Set -- 7-bit American Standard Code for
+ Information Interchange', ANSI X3.4-1986.
+ <P>
+ </P>
+ </DD>
+ <DT><A NAME="[13]">[13]</A>
+ </DT>
+ <DD>Hinden, R. and Deering, S.,
+ 'IP Version 6 Addressing Architecture', RFC 2373,
+ Nokia, Cisco Systems,
+ July 1998.
+ <P>
+ </P>
+ </DD>
+ </DL>
+
+ <H2>
+ <A NAME="14.0">
+ 14. Authors' Addresses
+ </A>
+ </H2>
+ <ADDRESS>
+ <P>
+ Ken A L Coar
+ <BR>
+ MeepZor Consulting
+ <BR>
+ 7824 Mayfaire Crest Lane, Suite 202
+ <BR>
+ Raleigh, NC 27615-4875
+ <BR>
+ U.S.A.
+ </P>
+ <P>
+ Tel: +1 (919) 254.4237
+ <BR>
+ Fax: +1 (919) 254.5250
+ <BR>
+ Email:
+ <A
+ HREF="mailto:Ken.Coar@Golux.Com"
+ ><SAMP>Ken.Coar@Golux.Com</SAMP></A>
+ </P>
+ </ADDRESS>
+ <ADDRESS>
+ <P>
+ David Robinson
+ <BR>
+ E*TRADE UK Ltd
+ <BR>
+ Mount Pleasant House
+ <BR>
+ 2 Mount Pleasant
+ <BR>
+ Huntingdon Road
+ <BR>
+ Cambridge CB3 0RN
+ <BR>
+ UK
+ </P>
+ <P>
+ Tel: +44 (1223) 566926
+ <BR>
+ Fax: +44 (1223) 506288
+ <BR>
+ Email:
+ <A
+ HREF="mailto:drtr@etrade.co.uk"
+ ><SAMP>drtr@etrade.co.uk</SAMP></A>
+ </ADDRESS>
+
+ </BODY>
+</HTML>
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/ifupdown_design.txt b/cleopatre/busybox-1.11.1-spc300/docs/ifupdown_design.txt
new file mode 100644
index 0000000000..9df579289f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/ifupdown_design.txt
@@ -0,0 +1,44 @@
+This document is meant to convince you to not use ifup/ifdown.
+
+
+The general problem with ifupdown is that it is "copulated in vertical
+fashion" by design. It tries to do the job of shell script in C,
+and this is invariably doomed to fail. You need ifup/ifdown
+to be adaptable by local admins, and C is an extremely poor choice
+for that.
+
+We are doomed to have problems with ifup/ifdown. Just look as this code:
+
+static const struct dhcp_client_t ext_dhcp_clients[] = {
+ { "dhcpcd", "<up cmd>", "<down cmd>" },
+ { "dhclient", ........ },
+ { "pump", ........ },
+ { "udhcpc", ........ },
+};
+
+static int dhcp_down(struct interface_defn_t *ifd, execfn *exec)
+{
+#if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
+ int i ;
+ for (i = 0; i < ARRAY_SIZE(ext_dhcp_clients); i++) {
+ if (exists_execable(ext_dhcp_clients[i].name))
+ return execute(ext_dhcp_clients[i].stopcmd, ifd, exec);
+ }
+ bb_error_msg("no dhcp clients found, using static interface shutdown");
+ return static_down(ifd, exec);
+#elif ENABLE_APP_UDHCPC
+ return execute("kill "
+ "`cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", ifd, exec);
+#else
+ return 0; /* no dhcp support */
+#endif
+}
+
+How the hell it is supposed to work reliably this way? Just imagine that
+admin is using pump and ifup/ifdown. It works. Then, for whatever reason,
+admin installs dhclient, but does NOT use it. ifdown will STOP WORKING,
+just because it will see installed dhclient binary in e.g. /usr/bin/dhclient!
+This is stupid.
+
+I seriously urge people to not use ifup/ifdown.
+Use something less brain damaged.
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/keep_data_small.txt b/cleopatre/busybox-1.11.1-spc300/docs/keep_data_small.txt
new file mode 100644
index 0000000000..2ddbefa10a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/keep_data_small.txt
@@ -0,0 +1,216 @@
+ Keeping data small
+
+When many applets are compiled into busybox, all rw data and
+bss for each applet are concatenated. Including those from libc,
+if static busybox is built. When busybox is started, _all_ this data
+is allocated, not just that one part for selected applet.
+
+What "allocated" exactly means, depends on arch.
+On NOMMU it's probably bites the most, actually using real
+RAM for rwdata and bss. On i386, bss is lazily allocated
+by COWed zero pages. Not sure about rwdata - also COW?
+
+In order to keep busybox NOMMU and small-mem systems friendly
+we should avoid large global data in our applets, and should
+minimize usage of libc functions which implicitly use
+such structures.
+
+Small experiment to measure "parasitic" bbox memory consumption:
+here we start 1000 "busybox sleep 10" in parallel.
+busybox binary is practically allyesconfig static one,
+built against uclibc. Run on x86-64 machine with 64-bit kernel:
+
+bash-3.2# nmeter '%t %c %m %p %[pn]'
+23:17:28 .......... 168M 0 147
+23:17:29 .......... 168M 0 147
+23:17:30 U......... 168M 1 147
+23:17:31 SU........ 181M 244 391
+23:17:32 SSSSUUU... 223M 757 1147
+23:17:33 UUU....... 223M 0 1147
+23:17:34 U......... 223M 1 1147
+23:17:35 .......... 223M 0 1147
+23:17:36 .......... 223M 0 1147
+23:17:37 S......... 223M 0 1147
+23:17:38 .......... 223M 1 1147
+23:17:39 .......... 223M 0 1147
+23:17:40 .......... 223M 0 1147
+23:17:41 .......... 210M 0 906
+23:17:42 .......... 168M 1 147
+23:17:43 .......... 168M 0 147
+
+This requires 55M of memory. Thus 1 trivial busybox applet
+takes 55k of memory on 64-bit x86 kernel.
+
+On 32-bit kernel we need ~26k per applet.
+
+Script:
+
+i=1000; while test $i != 0; do
+ echo -n .
+ busybox sleep 30 &
+ i=$((i - 1))
+done
+echo
+wait
+
+(Data from NOMMU arches are sought. Provide 'size busybox' output too)
+
+
+ Example 1
+
+One example how to reduce global data usage is in
+archival/libunarchive/decompress_unzip.c:
+
+/* This is somewhat complex-looking arrangement, but it allows
+ * to place decompressor state either in bss or in
+ * malloc'ed space simply by changing #defines below.
+ * Sizes on i386:
+ * text data bss dec hex
+ * 5256 0 108 5364 14f4 - bss
+ * 4915 0 0 4915 1333 - malloc
+ */
+#define STATE_IN_BSS 0
+#define STATE_IN_MALLOC 1
+
+(see the rest of the file to get the idea)
+
+This example completely eliminates globals in that module.
+Required memory is allocated in unpack_gz_stream() [its main module]
+and then passed down to all subroutines which need to access 'globals'
+as a parameter.
+
+
+ Example 2
+
+In case you don't want to pass this additional parameter everywhere,
+take a look at archival/gzip.c. Here all global data is replaced by
+single global pointer (ptr_to_globals) to allocated storage.
+
+In order to not duplicate ptr_to_globals in every applet, you can
+reuse single common one. It is defined in libbb/messages.c
+as struct globals *const ptr_to_globals, but the struct globals is
+NOT defined in libbb.h. You first define your own struct:
+
+struct globals { int a; char buf[1000]; };
+
+and then declare that ptr_to_globals is a pointer to it:
+
+#define G (*ptr_to_globals)
+
+ptr_to_globals is declared as constant pointer.
+This helps gcc understand that it won't change, resulting in noticeably
+smaller code. In order to assign it, use SET_PTR_TO_GLOBALS macro:
+
+ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G)));
+
+Typically it is done in <applet>_main().
+
+Now you can reference "globals" by G.a, G.buf and so on, in any function.
+
+
+ bb_common_bufsiz1
+
+There is one big common buffer in bss - bb_common_bufsiz1. It is a much
+earlier mechanism to reduce bss usage. Each applet can use it for
+its needs. Library functions are prohibited from using it.
+
+'G.' trick can be done using bb_common_bufsiz1 instead of malloced buffer:
+
+#define G (*(struct globals*)&bb_common_bufsiz1)
+
+Be careful, though, and use it only if globals fit into bb_common_bufsiz1.
+Since bb_common_bufsiz1 is BUFSIZ + 1 bytes long and BUFSIZ can change
+from one libc to another, you have to add compile-time check for it:
+
+if (sizeof(struct globals) > sizeof(bb_common_bufsiz1))
+ BUG_<applet>_globals_too_big();
+
+
+ Drawbacks
+
+You have to initialize it by hand. xzalloc() can be helpful in clearing
+allocated storage to 0, but anything more must be done by hand.
+
+All global variables are prefixed by 'G.' now. If this makes code
+less readable, use #defines:
+
+#define dev_fd (G.dev_fd)
+#define sector (G.sector)
+
+
+ Word of caution
+
+If applet doesn't use much of global data, converting it to use
+one of above methods is not worth the resulting code obfuscation.
+If you have less than ~300 bytes of global data - don't bother.
+
+
+ gcc's data alignment problem
+
+The following attribute added in vi.c:
+
+static int tabstop;
+static struct termios term_orig __attribute__ ((aligned (4)));
+static struct termios term_vi __attribute__ ((aligned (4)));
+
+reduces bss size by 32 bytes, because gcc sometimes aligns structures to
+ridiculously large values. asm output diff for above example:
+
+ tabstop:
+ .zero 4
+ .section .bss.term_orig,"aw",@nobits
+- .align 32
++ .align 4
+ .type term_orig, @object
+ .size term_orig, 60
+ term_orig:
+ .zero 60
+ .section .bss.term_vi,"aw",@nobits
+- .align 32
++ .align 4
+ .type term_vi, @object
+ .size term_vi, 60
+
+gcc doesn't seem to have options for altering this behaviour.
+
+gcc 3.4.3 and 4.1.1 tested:
+char c = 1;
+// gcc aligns to 32 bytes if sizeof(struct) >= 32
+struct {
+ int a,b,c,d;
+ int i1,i2,i3;
+} s28 = { 1 }; // struct will be aligned to 4 bytes
+struct {
+ int a,b,c,d;
+ int i1,i2,i3,i4;
+} s32 = { 1 }; // struct will be aligned to 32 bytes
+// same for arrays
+char vc31[31] = { 1 }; // unaligned
+char vc32[32] = { 1 }; // aligned to 32 bytes
+
+-fpack-struct=1 reduces alignment of s28 to 1 (but probably
+will break layout of many libc structs) but s32 and vc32
+are still aligned to 32 bytes.
+
+I will try to cook up a patch to add a gcc option for disabling it.
+Meanwhile, this is where it can be disabled in gcc source:
+
+gcc/config/i386/i386.c
+int
+ix86_data_alignment (tree type, int align)
+{
+#if 0
+ if (AGGREGATE_TYPE_P (type)
+ && TYPE_SIZE (type)
+ && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
+ && (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 256
+ || TREE_INT_CST_HIGH (TYPE_SIZE (type))) && align < 256)
+ return 256;
+#endif
+
+Result (non-static busybox built against glibc):
+
+# size /usr/srcdevel/bbox/fix/busybox.t0/busybox busybox
+ text data bss dec hex filename
+ 634416 2736 23856 661008 a1610 busybox
+ 632580 2672 22944 658196 a0b14 busybox_noalign
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/mdev.txt b/cleopatre/busybox-1.11.1-spc300/docs/mdev.txt
new file mode 100644
index 0000000000..1a97be4ce2
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/mdev.txt
@@ -0,0 +1,97 @@
+-------------
+ MDEV Primer
+-------------
+
+For those of us who know how to use mdev, a primer might seem lame. For
+everyone else, mdev is a weird black box that they hear is awesome, but can't
+seem to get their head around how it works. Thus, a primer.
+
+-----------
+ Basic Use
+-----------
+
+Mdev has two primary uses: initial population and dynamic updates. Both
+require sysfs support in the kernel and have it mounted at /sys. For dynamic
+updates, you also need to have hotplugging enabled in your kernel.
+
+Here's a typical code snippet from the init script:
+[0] mount -t proc proc /proc
+[1] mount -t sysfs sysfs /sys
+[2] echo /bin/mdev > /proc/sys/kernel/hotplug
+[3] mdev -s
+
+Alternatively, without procfs the above becomes:
+[1] mount -t sysfs sysfs /sys
+[2] sysctl -w kernel.hotplug=/bin/mdev
+[3] mdev -s
+
+
+Of course, a more "full" setup would entail executing this before the previous
+code snippet:
+[4] mount -t tmpfs -o size=64k,mode=0755 tmpfs /dev
+[5] mkdir /dev/pts
+[6] mount -t devpts devpts /dev/pts
+
+The simple explanation here is that [1] you need to have /sys mounted before
+executing mdev. Then you [2] instruct the kernel to execute /bin/mdev whenever
+a device is added or removed so that the device node can be created or
+destroyed. Then you [3] seed /dev with all the device nodes that were created
+while the system was booting.
+
+For the "full" setup, you want to [4] make sure /dev is a tmpfs filesystem
+(assuming you're running out of flash). Then you want to [5] create the
+/dev/pts mount point and finally [6] mount the devpts filesystem on it.
+
+-------------
+ MDEV Config (/etc/mdev.conf)
+-------------
+
+Mdev has an optional config file for controlling ownership/permissions of
+device nodes if your system needs something more than the default root/root
+660 permissions.
+
+The file has the format:
+ <device regex> <uid>:<gid> <octal permissions>
+For example:
+ hd[a-z][0-9]* 0:3 660
+
+The config file parsing stops at the first matching line. If no line is
+matched, then the default of 0:0 660 is used. To set your own default, simply
+create your own total match like so:
+ .* 1:1 777
+
+You can rename/relocate device nodes by using the next optional field.
+ <device regex> <uid>:<gid> <octal permissions> [>path]
+So if you want to place the device node into a subdirectory, make sure the path
+has a trailing /. If you want to rename the device node, just place the name.
+ hda 0:3 660 >drives/
+This will relocate "hda" into the drives/ subdirectory.
+ hdb 0:3 660 >cdrom
+This will rename "hdb" to "cdrom".
+
+If you also enable support for executing your own commands, then the file has
+the format:
+ <device regex> <uid>:<gid> <octal permissions> [<@|$|*> <command>]
+The special characters have the meaning:
+ @ Run after creating the device.
+ $ Run before removing the device.
+ * Run both after creating and before removing the device.
+
+The command is executed via the system() function (which means you're giving a
+command to the shell), so make sure you have a shell installed at /bin/sh. You
+should also keep in mind that the kernel executes hotplug helpers with stdin,
+stdout, and stderr connected to /dev/null.
+
+For your convenience, the shell env var $MDEV is set to the device name. So if
+the device "hdc" was matched, MDEV would be set to "hdc".
+
+----------
+ FIRMWARE
+----------
+
+Some kernel device drivers need to request firmware at runtime in order to
+properly initialize a device. Place all such firmware files into the
+/lib/firmware/ directory. At runtime, the kernel will invoke mdev with the
+filename of the firmware which mdev will load out of /lib/firmware/ and into
+the kernel via the sysfs interface. The exact filename is hardcoded in the
+kernel, so look there if you need to know how to name the file in userspace.
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/new-applet-HOWTO.txt b/cleopatre/busybox-1.11.1-spc300/docs/new-applet-HOWTO.txt
new file mode 100644
index 0000000000..6f89cbe1d3
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/new-applet-HOWTO.txt
@@ -0,0 +1,182 @@
+How to Add a New Applet to BusyBox
+==================================
+
+This document details the steps you must take to add a new applet to BusyBox.
+
+Credits:
+Matt Kraai - initial writeup
+Mark Whitley - the remix
+Thomas Lundquist - Trying to keep it updated.
+
+When doing this you should consider using the latest svn trunk.
+This is a good thing if you plan to getting it commited into mainline.
+
+Initial Write
+-------------
+
+First, write your applet. Be sure to include copyright information at the top,
+such as who you stole the code from and so forth. Also include the mini-GPL
+boilerplate. Be sure to name the main function <applet>_main instead of main.
+And be sure to put it in <applet>.c. Usage does not have to be taken care of by
+your applet.
+Make sure to #include "libbb.h" as the first include file in your applet so
+the bb_config.h and appropriate platform specific files are included properly.
+
+For a new applet mu, here is the code that would go in mu.c:
+
+(busybox.h already includes most usual header files. You do not need
+#include <stdio.h> etc...)
+
+
+----begin example code------
+
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini mu implementation for busybox
+ *
+ * Copyright (C) [YEAR] by [YOUR NAME] <YOUR EMAIL>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "other.h"
+
+int mu_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int mu_main(int argc, char **argv)
+{
+ int fd;
+ ssize_t n;
+ char mu;
+
+ fd = xopen("/dev/random", O_RDONLY);
+
+ if ((n = safe_read(fd, &mu, 1)) < 1)
+ bb_perror_msg_and_die("/dev/random");
+
+ return mu;
+}
+
+----end example code------
+
+
+Coding Style
+------------
+
+Before you submit your applet for inclusion in BusyBox, (or better yet, before
+you _write_ your applet) please read through the style guide in the docs
+directory and make your program compliant.
+
+
+Some Words on libbb
+-------------------
+
+As you are writing your applet, please be aware of the body of pre-existing
+useful functions in libbb. Use these instead of reinventing the wheel.
+
+Additionally, if you have any useful, general-purpose functions in your
+applet that could be useful in other applets, consider putting them in libbb.
+
+And it may be possible that some of the other applets uses functions you
+could use. If so, you have to rip the function out of the applet and make
+a libbb function out of it.
+
+Adding a libbb function:
+------------------------
+
+Make a new file named <function_name>.c
+
+----start example code------
+
+#include "libbb.h"
+#include "other.h"
+
+int function(char *a)
+{
+ return *a;
+}
+
+----end example code------
+
+Add <function_name>.o in the right alphabetically sorted place
+in libbb/Kbuild. You should look at the conditional part of
+libbb/Kbuild aswell.
+
+You should also try to find a suitable place in include/libbb.h for
+the function declaration. If not, add it somewhere anyway, with or without
+ifdefs to include or not.
+
+You can look at libbb/Config.in and try to find out if the function is
+tuneable and add it there if it is.
+
+
+Placement / Directory
+---------------------
+
+Find the appropriate directory for your new applet.
+
+Make sure you find the appropriate places in the files, the applets are
+sorted alphabetically.
+
+Add the applet to Kbuild in the chosen directory:
+
+lib-$(CONFIG_MU) += mu.o
+
+Add the applet to Config.in in the chosen directory:
+
+config MU
+ bool "MU"
+ default n
+ help
+ Returns an indeterminate value.
+
+
+Usage String(s)
+---------------
+
+Next, add usage information for you applet to include/usage.h.
+This should look like the following:
+
+ #define mu_trivial_usage \
+ "-[abcde] FILES"
+ #define mu_full_usage \
+ "Returns an indeterminate value.\n\n" \
+ "Options:\n" \
+ "\t-a\t\tfirst function\n" \
+ "\t-b\t\tsecond function\n" \
+ ...
+
+If your program supports flags, the flags should be mentioned on the first
+line (-[abcde]) and a detailed description of each flag should go in the
+mu_full_usage section, one flag per line. (Numerous examples of this
+currently exist in usage.h.)
+
+
+Header Files
+------------
+
+Next, add an entry to include/applets.h. Be *sure* to keep the list
+in alphabetical order, or else it will break the binary-search lookup
+algorithm in busybox.c and the Gods of BusyBox smite you. Yea, verily:
+
+Be sure to read the top of applets.h before adding your applet.
+
+ /* all programs above here are alphabetically "less than" 'mu' */
+ USE_MU(APPLET(mu, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+ /* all programs below here are alphabetically "greater than" 'mu' */
+
+
+The Grand Announcement
+----------------------
+
+Then create a diff by adding the new files with svn (remember your libbb files)
+ svn add <where you put it>/mu.c
+eventually also:
+ svn add libbb/function.c
+then
+ svn diff
+and send it to the mailing list:
+ busybox@busybox.net
+ http://busybox.net/mailman/listinfo/busybox
+
+Sending patches as attachments is preferred, but not required.
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/nofork_noexec.txt b/cleopatre/busybox-1.11.1-spc300/docs/nofork_noexec.txt
new file mode 100644
index 0000000000..06c789affd
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/nofork_noexec.txt
@@ -0,0 +1,79 @@
+ NOEXEC and NOFORK applets.
+
+Unix shells traditionally execute some commands internally in the attempt
+to dramatically speed up execution. It will be slow as hell if for every
+"echo blah" shell will fork and exec /bin/echo. To this end, shells
+have to _reimplement_ these commands internally.
+
+Busybox is unique in this regard because it already is a collection
+of reimplemented Unix commands, and we can do the same trick
+for speeding up busybox shells, and more. NOEXEC and NOFORK applets
+are exactly those applets which are eligible for these tricks.
+
+Applet will be subject to NOFORK/NOEXEC tricks if it is marked as such
+in applets.h. FEATURE_PREFER_APPLETS is a config option which
+globally enables usage of NOFORK/NOEXEC tricks.
+If it is enabled, FEATURE_SH_STANDALONE can be enabled too,
+and then shells will use NOFORK/NOEXEC tricks for ordinary commands.
+NB: shell builtins use these tricks regardless of FEATURE_SH_STANDALONE
+or FEATURE_PREFER_APPLETS.
+
+In C, if you want to call a program and wait for it, use
+spawn_and_wait(argv), BB_EXECVP(prog,argv) or BB_EXECLP(prog,argv0,...).
+They check whether program name is an applet name and optionally
+do NOFORK/NOEXEC thing depending on configuration.
+
+
+ NOEXEC
+
+NOEXEC applet should work correctly if another applet forks and then
+executes exit(<applet>_main(argc,argv)) in the child. The rules
+roughly are:
+
+* do not expect shared global variables/buffers to be in their
+ "initialized" state. Examples: xfunc_error_retval can be != 1,
+ bb_common_bufsiz1 can be scribbled over, ...
+* do not expect that stdio wasn't used before. Calling set[v]buf()
+ can be disastrous.
+* ...
+
+NOEXEC applets save only one half of fork+exec overhead.
+NOEXEC trick is disabled for NOMMU build.
+
+
+ NOFORK
+
+NOFORK applet should work correctly if another applet simply runs
+<applet>_main(argc,argv) and then continues with its business (xargs,
+find, shells can do it). This poses much more serious limitations
+on what applet can/cannot do:
+
+* all NOEXEC limitations apply.
+* do not ever exit() or exec().
+ - xfuncs are okay. They are using special trick to return
+ to the caller applet instead of dying when they detect "x" condition.
+ - you may "exit" to caller applet by calling xfunc_die(). Return value
+ is taken from xfunc_error_retval.
+ - fflush_stdout_and_exit(n) is ok to use.
+* do not use shared global data, or save/restore shared global data
+ prior to returning. (e.g. bb_common_bufsiz1 is off-limits).
+ - getopt32() is ok to use. You do not need to save/restore option_mask32,
+ it is already done by core code.
+* if you allocate memory, you can use xmalloc() only on the very first
+ allocation. All other allocations should use malloc[_or_warn]().
+ After first allocation, you cannot use any xfuncs.
+ Otherwise, failing xfunc will return to caller applet
+ without freeing malloced data!
+* All allocated data, opened files, signal handlers, termios settings,
+ O_NONBLOCK flags etc should be freed/closed/restored prior to return.
+* ...
+
+NOFORK applets give the most of speed advantage, but are trickiest
+to implement. In order to minimize amount of bugs and maintenance,
+prime candidates for NOFORK-ification are those applets which
+are small and easy to audit, and those which are more likely to be
+frequently executed from shell/find/xargs, particularly in shell
+script loops. Applets which mess with signal handlers, termios etc
+are probably not worth the effort.
+
+Any NOFORK applet is also a NOEXEC applet.
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/sigint.htm b/cleopatre/busybox-1.11.1-spc300/docs/sigint.htm
new file mode 100644
index 0000000000..e230f4df79
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/sigint.htm
@@ -0,0 +1,627 @@
+<HTML>
+<HEAD>
+<link rel="SHORTCUT ICON" href="http://www.cons.org/favicon.ico">
+<TITLE>Proper handling of SIGINT/SIGQUIT [http://www.cons.org/cracauer/sigint.html]</TITLE>
+<!-- Created by: GNU m4 using $Revision: 1.20 $ of crawww.m4lib on 11-Feb-2005 -->
+<BODY BGCOLOR="#fff8e1">
+<CENTER><H2>Proper handling of SIGINT/SIGQUIT</H2></CENTER>
+<img src=linie.png width="100%" alt=" ">
+<P>
+
+<table border=1 cellpadding=4>
+<tr><th valign=top align=left>Abstract: </th>
+<td valign=top align=left>
+In UNIX terminal sessions, you usually have a key like
+<code>C-c</code> (Control-C) to immediately end whatever program you
+have running in the foreground. This should work even when the program
+you called has called other programs in turn. Everything should be
+aborted, giving you your command prompt back, no matter how deep the
+call stack is.
+
+<p>Basically, it's trivial. But the existence of interactive
+applications that use SIGINT and/or SIGQUIT for other purposes than a
+complete immediate abort make matters complicated, and - as was to
+expect - left us with several ways to solve the problems. Of course,
+existing shells and applications follow different ways.
+
+<P>This Web pages outlines different ways to solve the problem and
+argues that only one of them can do everything right, although it
+means that we have to fix some existing software.
+
+
+
+</td></tr><tr><th valign=top align=left>Intended audience: </th>
+<td valign=top align=left>Programmers who implement programs that catch SIGINT/SIGQUIT.
+<BR>Programmers who implements shells or shell-like programs that
+execute batches of programs.
+
+<p>Users who have problems problems getting rid of runaway shell
+scripts using <code>Control-C</code>. Or have interactive applications
+that don't behave right when sending SIGINT. Examples are emacs'es
+that die on Control-g or shellscript statements that sometimes are
+executed and sometimes not, apparently not determined by the user's
+intention.
+
+
+</td></tr><tr><th valign=top align=left>Required knowledge: </th>
+<td valign=top align=left>You have to know what it means to catch SIGINT or SIGQUIT and how
+processes are waiting for other processes (childs) they spawned.
+
+
+</td></tr></table>
+<img src=linie.png width="100%" alt=" ">
+
+
+<H3>Basic concepts</H3>
+
+What technically happens when you press Control-C is that all programs
+running in the foreground in your current terminal (or virtual
+terminal) get the signal SIGINT sent.
+
+<p>You may change the key that triggers the signal using
+<code>stty</code> and running programs may remap the SIGINT-sending
+key at any time they like, without your intervention and without
+asking you first.
+
+<p>The usual reaction of a running program to SIGINT is to exit.
+However, not all program do an exit on SIGINT, programs are free to
+use the signal for other actions or to ignore it at all.
+
+<p>All programs running in the foreground receive the signal. This may
+be a nested "stack" of programs: You started a program that started
+another and the outer is waiting for the inner to exit. This nesting
+may be arbitrarily deep.
+
+<p>The innermost program is the one that decides what to do on SIGINT.
+It may exit, do something else or do nothing. Still, when the user hit
+SIGINT, all the outer programs are awaken, get the signal and may
+react on it.
+
+<H3>What we try to achieve</H3>
+
+The problem is with shell scripts (or similar programs that call
+several subprograms one after another).
+
+<p>Let us consider the most basic script:
+<PRE>
+#! /bin/sh
+program1
+program2
+</PRE>
+and the usual run looks like this:
+<PRE>
+$ sh myscript
+[output of program1]
+[output of program2]
+$
+</PRE>
+
+<p>Let us assume that both programs do nothing special on SIGINT, they
+just exit.
+
+<p>Now imagine the user hits C-c while a shellscript is executing its
+first program. The following programs receive SIGINT: program1 and
+also the shell executing the script. program1 exits.
+
+<p>But what should the shell do? If we say that it is only the
+innermost's programs business to react on SIGINT, the shell will do
+nothing special (not exit) and it will continue the execution of the
+script and run program2. But this is wrong: The user's intention in
+hitting C-c is to abort the whole script, to get his prompt back. If
+he hits C-c while the first program is running, he does not want
+program2 to be even started.
+
+<p>here is what would happen if the shell doesn't do anything:
+<PRE>
+$ sh myscript
+[first half of program1's output]
+C-c [users presses C-c]
+[second half of program1's output will not be displayed]
+[output of program2 will appear]
+</PRE>
+
+
+<p>Consider a more annoying example:
+<pre>
+#! /bin/sh
+# let's assume there are 300 *.dat files
+for file in *.dat ; do
+ dat2ascii $dat
+done
+</pre>
+
+If your shell wouldn't end if the user hits <code>C-c</code>,
+<code>C-c</code> would just end <strong>one</strong> dat2ascii run and
+the script would continue. Thus, you had to hit <code>C-c</code> up to
+300 times to end this script.
+
+<H3>Alternatives to do so</H3>
+
+<p>There are several ways to handle abortion of shell scripts when
+SIGINT is received while a foreground child runs:
+
+<menu>
+
+<li>As just outlined, the shellscript may just continue, ignoring the
+fact that the user hit <code>C-c</code>. That way, your shellscript -
+including any loops - would continue and you had no chance of aborting
+it except using the kill command after finding out the outermost
+shell's PID. This "solution" will not be discussed further, as it is
+obviously not desirable.
+
+<p><li>The shell itself exits immediately when it receives SIGINT. Not
+only the program called will exit, but the calling (the
+script-executing) shell. The first variant is to exit the shell (and
+therefore discontinuing execution of the script) immediately, while
+the background program may still be executing (remember that although
+the shell is just waiting for the called program to exit, it is woken
+up and may act). I will call the way of doing things the "IUE" (for
+"immediate unconditional exit") for the rest of this document.
+
+<p><li>As a variant of the former, when the shell receives SIGINT
+while it is waiting for a child to exit, the shell does not exit
+immediately. but it remembers the fact that a SIGINT happened. After
+the called program exits and the shell's wait ends, the shell will
+exit itself and hence discontinue the script. I will call the way of
+doing things the "WUE" (for "wait and unconditional exit") for the
+rest of this document.
+
+<p><li>There is also a way that the calling shell can tell whether the
+called program exited on SIGINT and if it ignored SIGINT (or used it
+for other purposes). As in the <sl>WUE</sl> way, the shell waits for
+the child to complete. It figures whether the program was ended on
+SIGINT and if so, it discontinue the script. If the program did any
+other exit, the script will be continued. I will call the way of doing
+things the "WCE" (for "wait and cooperative exit") for the rest of
+this document.
+
+</menu>
+
+<H3>The problem</H3>
+
+On first sight, all three solutions (IUE, WUE and WCE) all seem to do
+what we want: If C-c is hit while the first program of the shell
+script runs, the script is discontinued. The user gets his prompt back
+immediately. So what are the difference between these way of handling
+SIGINT?
+
+<p>There are programs that use the signal SIGINT for other purposes
+than exiting. They use it as a normal keystroke. The user is expected
+to use the key that sends SIGINT during a perfectly normal program
+run. As a result, the user sends SIGINT in situations where he/she
+does not want the program or the script to end.
+
+<p>The primary example is the emacs editor: C-g does what ESC does in
+other applications: It cancels a partially executed or prepared
+operation. Technically, emacs remaps the key that sends SIGINT from
+C-c to C-g and catches SIGINT.
+
+<p>Remember that the SIGINT is sent to all programs running in the
+foreground. If emacs is executing from a shell script, both emacs and
+the shell get SIGINT. emacs is the program that decides what to do:
+Exit on SIGINT or not. emacs decides not to exit. The problem arises
+when the shell draws its own conclusions from receiving SIGINT without
+consulting emacs for its opinion.
+
+<p>Consider this script:
+<PRE>
+#! /bin/sh
+emacs /tmp/foo
+cp /tmp/foo /home/user/mail/sent
+</PRE>
+
+<p>If C-g is used in emacs, both the shell and emacs will received
+SIGINT. Emacs will not exit, the user used C-g as a normal editing
+keystroke, he/she does not want the script to be aborted on C-g.
+
+<p>The central problem is that the second command (cp) may
+unintentionally be killed when the shell draws its own conclusion
+about the user's intention. The innermost program is the only one to
+judge.
+
+<H3>One more example</H3>
+
+<p>Imagine a mail session using a curses mailer in a tty. You called
+your mailer and started to compose a message. Your mailer calls emacs.
+<code>C-g</code> is a normal editing key in emacs. Technically it
+sends SIGINT (it was <code>C-c</code>, but emacs remapped the key) to
+<menu>
+<li>emacs
+<li>the shell between your mailer and emacs, the one from your mailers
+ system("emacs /tmp/bla.44") command
+<li>the mailer itself
+<li>possibly another shell if your mailer was called by a shell script
+or from another application using system(3)
+<li>your interactive shell (which ignores it since it is interactive
+and hence is not relevant to this discussion)
+</menu>
+
+<p>If everyone just exits on SIGINT, you will be left with nothing but
+your login shell, without asking.
+
+<p>But for sure you don't want to be dropped out of your editor and
+out of your mailer back to the commandline, having your edited data
+and mailer status deleted.
+
+<p>Understand the difference: While <code>C-g</code> is used an a kind
+of abort key in emacs, it isn't the major "abort everything" key. When
+you use <code>C-g</code> in emacs, you want to end some internal emacs
+command. You don't want your whole emacs and mailer session to end.
+
+<p>So, if the shell exits immediately if the user sends SIGINT (the
+second of the four ways shown above), the parent of emacs would die,
+leaving emacs without the controlling tty. The user will lose it's
+editing session immediately and unrecoverable. If the "main" shell of
+the operating system defaults to this behavior, every editor session
+that is spawned from a mailer or such will break (because it is
+usually executed by system(3), which calls /bin/sh). This was the case
+in FreeBSD before I and Bruce Evans changed it in 1998.
+
+<p>If the shell recognized that SIGINT was sent and exits after the
+current foreground process exited (the third way of the four), the
+editor session will not be disturbed, but things will still not work
+right.
+
+<H3>A further look at the alternatives</H3>
+
+<p>Still considering this script to examine the shell's actions in the
+IUE, WUE and ICE way of handling SIGINT:
+<PRE>
+#! /bin/sh
+emacs /tmp/foo
+cp /tmp/foo /home/user/mail/sent
+</PRE>
+
+<p>The IUE ("immediate unconditional exit") way does not work at all:
+emacs wants to survive the SIGINT (it's a normal editing key for
+emacs), but its parent shell unconditionally thinks "We received
+SIGINT. Abort everything. Now.". The shell will exit even before emacs
+exits. But this will leave emacs in an unusable state, since the death
+of its calling shell will leave it without required resources (file
+descriptors). This way does not work at all for shellscripts that call
+programs that use SIGINT for other purposes than immediate exit. Even
+for programs that exit on SIGINT, but want to do some cleanup between
+the signal and the exit, may fail before they complete their cleanup.
+
+<p>It should be noted that this way has one advantage: If a child
+blocks SIGINT and does not exit at all, this way will get control back
+to the user's terminal. Since such programs should be banned from your
+system anyway, I don't think that weighs against the disadvantages.
+
+<p>WUE ("wait and unconditional exit") is a little more clever: If C-g
+was used in emacs, the shell will get SIGINT. It will not immediately
+exit, but remember the fact that a SIGINT happened. When emacs ends
+(maybe a long time after the SIGINT), it will say "Ok, a SIGINT
+happened sometime while the child was executing, the user wants the
+script to be discontinued". It will then exit. The cp will not be
+executed. But that's bad. The "cp" will be executed when the emacs
+session ended without the C-g key ever used, but it will not be
+executed when the user used C-g at least one time. That is clearly not
+desired. Since C-g is a normal editing key in emacs, the user expects
+the rest of the script to behave identically no matter what keys he
+used.
+
+<p>As a result, the "WUE" way is better than the "IUE" way in that it
+does not break SIGINT-using programs completely. The emacs session
+will end undisturbed. But it still does not support scripts where
+other actions should be performed after a program that use SIGINT for
+non-exit purposes. Since the behavior is basically undeterminable for
+the user, this can lead to nasty surprises.
+
+<p>The "WCE" way fixes this by "asking" the called program whether it
+exited on SIGINT or not. While emacs receives SIGINT, it does not exit
+on it and a calling shell waiting for its exit will not be told that
+it exited on SIGINT. (Although it receives SIGINT at some point in
+time, the system does not enforce that emacs will exit with
+"I-exited-on-SIGINT" status. This is under emacs' control, see below).
+
+<p>this still work for the normal script without SIGINT-using
+programs:</p>
+<PRE>
+#! /bin/sh
+program1
+program2
+</PRE>
+
+Unless program1 and program2 mess around with signal handling, the
+system will tell the calling shell whether the programs exited
+normally or as a result of SIGINT.
+
+<p>The "WCE" way then has an easy way to things right: When one called
+program exited with "I-exited-on-SIGINT" status, it will discontinue
+the script after this program. If the program ends without this
+status, the next command in the script is started.
+
+<p>It is important to understand that a shell in "WCE" modus does not
+need to listen to the SIGINT signal at all. Both in the
+"emacs-then-cp" script and in the "several-normal-programs" script, it
+will be woken up and receive SIGINT when the user hits the
+corresponding key. But the shell does not need to react on this event
+and it doesn't need to remember the event of any SIGINT, either.
+Telling whether the user wants to end a script is done by asking that
+program that has to decide, that program that interprets keystrokes
+from the user, the innermost program.
+
+<H3>So everything is well with WCE?</H3>
+
+Well, almost.
+
+<p>The problem with the "WCE" modus is that there are broken programs
+that do not properly communicate the required information up to the
+calling program.
+
+<p>Unless a program messes with signal handling, the system does this
+automatically.
+
+<p>There are programs that want to exit on SIGINT, but they don't let
+the system do the automatic exit, because they want to do some
+cleanup. To do so, they catch SIGINT, do the cleanup and then exit by
+themselves.
+
+<p>And here is where the problem arises: Once they catch the signal,
+the system will no longer communicate the "I-exited-on-SIGINT" status
+to the calling program automatically. Even if the program exit
+immediately in the signal handler of SIGINT. Once it catches the
+signal, it has to take care of communicating the signal status
+itself.
+
+<p>Some programs don't do this. On SIGINT, they do cleanup and exit
+immediatly, but the calling shell isn't told about the non-normal exit
+and it will call the next program in the script.
+
+<p>As a result, the user hits SIGINT and while one program exits, the
+shellscript continues. To him/her it looks like the shell fails to
+obey to his abortion command.
+
+<p>Both IUE or WUE shell would not have this problem, since they
+discontinue the script on their own. But as I said, they don't support
+programs using SIGINT for non-exiting purposes, no matter whether
+these programs properly communicate their signal status to the calling
+shell or not.
+
+<p>Since some shell in wide use implement the WUE way (and some even
+IUE), there is a considerable number of broken programs out there that
+break WCE shells. The programmers just don't recognize it if their
+shell isn't WCE.
+
+<H3>How to be a proper program</H3>
+
+<p>(Short note in advance: What you need to achieve is that
+WIFSIGNALED(status) is true in the calling program and that
+WTERMSIG(status) returns SIGINT.)
+
+<p>If you don't catch SIGINT, the system automatically does the right
+thing for you: Your program exits and the calling program gets the
+right "I-exited-on-SIGINT" status after waiting for your exit.
+
+<p>But once you catch SIGINT, you have to act.
+
+<p>Decide whether the SIGINT is used for exit/abort purposes and hence
+a shellscript calling this program should discontinue. This is
+hopefully obvious. If you just need to do some cleanup on SIGINT, but
+then exit immediately, the answer is "yes".
+
+<p>If so, you have to tell the calling program about it by exiting
+with the "I-exited-on-SIGINT" status.
+
+<p>There is no other way of doing this than to kill yourself with a
+SIGINT signal. Do it by resetting the SIGINT handler to SIG_DFL, then
+send yourself the signal.
+
+<PRE>
+void sigint_handler(int sig)
+{
+ <do some cleanup>
+ signal(SIGINT, SIG_DFL);
+ kill(getpid(), SIGINT);
+}
+</PRE>
+
+Notes:
+
+<MENU>
+
+<LI>You cannot "fake" the proper exit status by an exit(3) with a
+special numeric value. People often assume this since the manuals for
+shells often list some return value for exactly this. But this is just
+a convention for your shell script. It does not work from one UNIX API
+program to another.
+
+<P>All that happens is that the shell sets the "$?" variable to a
+special numeric value for the convenience of your script, because your
+script does not have access to the lower-lever UNIX status evaluation
+functions. This is just an agreement between your script and the
+executing shell, it does not have any meaning in other contexts.
+
+<P><LI>Do not use kill(0, SIGINT) without consulting the manul for
+your OS implementation. I.e. on BSD, this would not send the signal to
+the current process, but to all processes in the group.
+
+<P><LI>POSIX 1003.1 allows all these calls to appear in signal
+handlers, so it is portable.
+
+</MENU>
+
+<p>In a bourne shell script, you can catch signals using the
+<code>trap</code> command. Here, the same as for C programs apply. If
+the intention of SIGINT is to end your program, you have to exit in a
+way that the calling programs "sees" that you have been killed. If
+you don't catch SIGINT, this happend automatically, but of you catch
+SIGINT, i.e. to do cleanup work, you have to end the program by
+killing yourself, not by calling exit.
+
+<p>Consider this example from FreeBSD's <code>mkdep</code>, which is a
+bourne shell script.
+
+<pre>
+TMP=_mkdep$$
+trap 'rm -f $TMP ; trap 2 ; kill -2 $$' 1 2 3 13 15
+</pre>
+
+Yes, you have to do it the hard way. It's even more annoying in shell
+scripts than in C programs since you can't "pre-delete" temporary
+files (which isn't really portable in C, though).
+
+<P>All this applies to programs in all languages, not only C and
+bourne shell. Every language implementation that lets you catch SIGINT
+should also give you the option to reset the signal and kill yourself.
+
+<P>It is always desireable to exit the right way, even if you don't
+expect your usual callers to depend on it, some unusual one will come
+along. This proper exit status will be needed for WCE and will not
+hurt when the calling shell uses IUE or WUE.
+
+<H3>How to be a proper shell</H3>
+
+All this applies only for the script-executing case. Most shells will
+also have interactive modes where things are different.
+
+<MENU>
+
+<LI>Do nothing special when SIGINT appears while you wait for a child.
+You don't even have to remember that one happened.
+
+<P><LI>Wait for child to exit, get the exit status. Do not truncate it
+to type char.
+
+<P><LI>Look at WIFSIGNALED(status) and WTERMSIG(status) to tell
+whether the child says "I exited on SIGINT: in my opinion the user
+wants the shellscript to be discontinued".
+
+<P><LI>If the latter applies, discontinue the script.
+
+<P><LI>Exit. But since a shellscript may in turn be called by a
+shellscript, you need to make sure that you properly communicate the
+discontinue intention to the calling program. As in any other program
+(see above), do
+
+<PRE>
+ signal(SIGINT, SIG_DFL);
+ kill(getpid(), SIGINT);
+</PRE>
+
+</MENU>
+
+<H3>Other remarks</H3>
+
+Although this web page talks about SIGINT only, almost the same issues
+apply to SIGQUIT, including proper exiting by killing yourself after
+catching the signal and proper reaction on the WIFSIGNALED(status)
+value. One notable difference for SIGQUIT is that you have to make
+sure that not the whole call tree dumps core.
+
+<H3>What to fight</H3>
+
+Make sure all programs <em>really</em> kill themselves if they react
+to SIGINT or SIGQUIT and intend to abort their operation as a result
+of this signal. Programs that don't use SIGINT/SIGQUIT as a
+termination trigger - but as part of normal operation - don't kill
+themselves, but do a normal exit instead.
+
+<p>Make sure people understand why you can't fake an exit-on-signal by
+doing exit(...) using any numerical status.
+
+<p>Make sure you use a shell that behaves right. Especially if you
+develop programs, since it will help seeing problems.
+
+<H3>Concrete examples how to fix programs:</H3>
+<ul>
+
+<li>The fix for FreeBSD's
+<A HREF="http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/time/time.c.diff?r1=1.10&r2=1.11">time(1)</A>. This fix is the best example, it's quite short and clear and
+it fixes a case where someone tried to fake signal exit status by a
+numerical value. And the complete program is small.
+
+<p><li>Fix for FreeBSD's
+<A HREF="http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/truss/main.c.diff?r1=1.9&r2=1.10">truss(1)</A>.
+
+<p><li>The fix for FreeBSD's
+<A HREF="http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/mkdep/mkdep.gcc.sh.diff?r1=1.8.2.1&r2=1.8.2.2">mkdep(1)</A>, a shell script.
+
+
+<p><li>Fix for FreeBSD's make(1), <A HREF="http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/make/job.c.diff?r1=1.9&r2=1.10">part 1</A>,
+<A HREF="http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/make/compat.c.diff?r1=1.10&r2=1.11">part 2</A>.
+
+</ul>
+
+<H3>Testsuite for shells</H3>
+
+I have a collection of shellscripts that test shells for the
+behavior. See my <A HREF="download/">download dir</A> to get the newest
+"sh-interrupt" files, either as a tarfile or as individual file for
+online browsing. This isn't really documented, besides from the
+comments the scripts echo.
+
+<H3>Appendix 1 - table of implementation choices</H3>
+
+<table border cellpadding=2>
+
+<tr valign=top>
+<th>Method sign</th>
+<th>Does what?</th>
+<th>Example shells that implement it:</th>
+<th>What happens when a shellscript called emacs, the user used
+<code>C-g</code> and the script has additional commands in it?</th>
+<th>What happens when a shellscript called emacs, the user did not use
+<code>C-c</code> and the script has additional commands in it?</th>
+<th>What happens if a non-interactive child catches SIGINT?</th>
+<th>To behave properly, childs must do what?</th>
+</tr>
+
+<tr valign=top align=left>
+<td>IUE</td>
+<td>The shell executing a script exits immediately if it receives
+SIGINT.</td>
+<td>4.4BSD ash (ash), NetBSD, FreeBSD prior to 3.0/22.8</td>
+<td>The editor session is lost and subsequent commands are not
+executed.</td>
+<td>The editor continues as normal and the subsequent commands are
+executed. </td>
+<td>The scripts ends immediately, returning to the caller even before
+the current foreground child of the shell exits. </td>
+<td>It doesn't matter what the child does or how it exits, even if the
+child continues to operate, the shell returns. </td>
+</tr>
+
+<tr valign=top align=left>
+<td>WUE</td>
+<td>If the shell executing a script received SIGINT while a foreground
+process was running, it will exit after that child's exit.</td>
+<td>pdksh (OpenBSD /bin/sh)</td>
+<td>The editor continues as normal, but subsequent commands from the
+script are not executed.</td>
+<td>The editor continues as normal and subsequent commands are
+executed. </td>
+<td>The scripts returns to its caller after the current foreground
+child exits, no matter how the child exited. </td>
+<td>It doesn't matter how the child exits (signal status or not), but
+if it doesn't return at all, the shell will not return. In no case
+will further commands from the script be executed. </td>
+</tr>
+
+<tr valign=top align=left>
+<td>WCE</td>
+<td>The shell exits if a child signaled that it was killed on a
+signal (either it had the default handler for SIGINT or it killed
+itself). </td>
+<td>bash (Linux /bin/sh), most commercial /bin/sh, FreeBSD /bin/sh
+from 3.0/2.2.8.</td>
+<td>The editor continues as normal and subsequent commands are
+executed. </td>
+<td>The editor continues as normal and subsequent commands are
+executed. </td>
+<td>The scripts returns to its caller after the current foreground
+child exits, but only if the child exited with signal status. If
+the child did a normal exit (even if it received SIGINT, but catches
+it), the script will continue. </td>
+<td>The child must be implemented right, or the user will not be able
+to break shell scripts reliably.</td>
+</tr>
+
+</table>
+
+<P><img src=linie.png width="100%" alt=" ">
+<BR>&copy;2005 Martin Cracauer &lt;cracauer @ cons.org&gt;
+<A HREF="http://www.cons.org/cracauer/">http://www.cons.org/cracauer/</A>
+<BR>Last changed: $Date: 2005/02/11 21:44:43 $
+</BODY></HTML>
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/style-guide.txt b/cleopatre/busybox-1.11.1-spc300/docs/style-guide.txt
new file mode 100644
index 0000000000..7560d69862
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/style-guide.txt
@@ -0,0 +1,714 @@
+Busybox Style Guide
+===================
+
+This document describes the coding style conventions used in Busybox. If you
+add a new file to Busybox or are editing an existing file, please format your
+code according to this style. If you are the maintainer of a file that does
+not follow these guidelines, please -- at your own convenience -- modify the
+file(s) you maintain to bring them into conformance with this style guide.
+Please note that this is a low priority task.
+
+To help you format the whitespace of your programs, an ".indent.pro" file is
+included in the main Busybox source directory that contains option flags to
+format code as per this style guide. This way you can run GNU indent on your
+files by typing 'indent myfile.c myfile.h' and it will magically apply all the
+right formatting rules to your file. Please _do_not_ run this on all the files
+in the directory, just your own.
+
+
+
+Declaration Order
+-----------------
+
+Here is the preferred order in which code should be laid out in a file:
+
+ - commented program name and one-line description
+ - commented author name and email address(es)
+ - commented GPL boilerplate
+ - commented longer description / notes for the program (if needed)
+ - #includes of .h files with angle brackets (<>) around them
+ - #includes of .h files with quotes ("") around them
+ - #defines (if any, note the section below titled "Avoid the Preprocessor")
+ - const and global variables
+ - function declarations (if necessary)
+ - function implementations
+
+
+
+Whitespace and Formatting
+-------------------------
+
+This is everybody's favorite flame topic so let's get it out of the way right
+up front.
+
+
+Tabs vs. Spaces in Line Indentation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The preference in Busybox is to indent lines with tabs. Do not indent lines
+with spaces and do not indents lines using a mixture of tabs and spaces. (The
+indentation style in the Apache and Postfix source does this sort of thing:
+\s\s\s\sif (expr) {\n\tstmt; --ick.) The only exception to this rule is
+multi-line comments that use an asterisk at the beginning of each line, i.e.:
+
+ \t/*
+ \t * This is a block comment.
+ \t * Note that it has multiple lines
+ \t * and that the beginning of each line has a tab plus a space
+ \t * except for the opening '/*' line where the slash
+ \t * is used instead of a space.
+ \t */
+
+Furthermore, The preference is that tabs be set to display at four spaces
+wide, but the beauty of using only tabs (and not spaces) at the beginning of
+lines is that you can set your editor to display tabs at *whatever* number of
+spaces is desired and the code will still look fine.
+
+
+Operator Spacing
+~~~~~~~~~~~~~~~~
+
+Put spaces between terms and operators. Example:
+
+ Don't do this:
+
+ for(i=0;i<num_items;i++){
+
+ Do this instead:
+
+ for (i = 0; i < num_items; i++) {
+
+ While it extends the line a bit longer, the spaced version is more
+ readable. An allowable exception to this rule is the situation where
+ excluding the spacing makes it more obvious that we are dealing with a
+ single term (even if it is a compound term) such as:
+
+ if (str[idx] == '/' && str[idx-1] != '\\')
+
+ or
+
+ if ((argc-1) - (optind+1) > 0)
+
+
+Bracket Spacing
+~~~~~~~~~~~~~~~
+
+If an opening bracket starts a function, it should be on the
+next line with no spacing before it. However, if a bracket follows an opening
+control block, it should be on the same line with a single space (not a tab)
+between it and the opening control block statement. Examples:
+
+ Don't do this:
+
+ while (!done)
+ {
+
+ do
+ {
+
+ Don't do this either:
+
+ while (!done){
+
+ do{
+
+ And for heaven's sake, don't do this:
+
+ while (!done)
+ {
+
+ do
+ {
+
+ Do this instead:
+
+ while (!done) {
+
+ do {
+
+If you have long logic statements that need to be wrapped, then uncuddling
+the bracket to improve readability is allowed. Generally, this style makes
+it easier for reader to notice that 2nd and following lines are still
+inside 'if':
+
+ if (some_really_long_checks && some_other_really_long_checks
+ && some_more_really_long_checks
+ && even_more_of_long_checks
+ ) {
+ do_foo_now;
+
+Spacing around Parentheses
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Put a space between C keywords and left parens, but not between function names
+and the left paren that starts it's parameter list (whether it is being
+declared or called). Examples:
+
+ Don't do this:
+
+ while(foo) {
+ for(i = 0; i < n; i++) {
+
+ Do this instead:
+
+ while (foo) {
+ for (i = 0; i < n; i++) {
+
+ But do functions like this:
+
+ static int my_func(int foo, char bar)
+ ...
+ baz = my_func(1, 2);
+
+Also, don't put a space between the left paren and the first term, nor between
+the last arg and the right paren.
+
+ Don't do this:
+
+ if ( x < 1 )
+ strcmp( thisstr, thatstr )
+
+ Do this instead:
+
+ if (x < 1)
+ strcmp(thisstr, thatstr)
+
+
+Cuddled Elses
+~~~~~~~~~~~~~
+
+Also, please "cuddle" your else statements by putting the else keyword on the
+same line after the right bracket that closes an 'if' statement.
+
+ Don't do this:
+
+ if (foo) {
+ stmt;
+ }
+ else {
+ stmt;
+ }
+
+ Do this instead:
+
+ if (foo) {
+ stmt;
+ } else {
+ stmt;
+ }
+
+The exception to this rule is if you want to include a comment before the else
+block. Example:
+
+ if (foo) {
+ stmts...
+ }
+ /* otherwise, we're just kidding ourselves, so re-frob the input */
+ else {
+ other_stmts...
+ }
+
+
+Labels
+~~~~~~
+
+Labels should start at the beginning of the line, not indented to the block
+level (because they do not "belong" to block scope, only to whole function).
+
+ if (foo) {
+ stmt;
+ label:
+ stmt2;
+ stmt;
+ }
+
+(Putting label at position 1 prevents diff -p from confusing label for function
+name, but it's not a policy of busybox project to enforce such a minor detail).
+
+
+
+Variable and Function Names
+---------------------------
+
+Use the K&R style with names in all lower-case and underscores occasionally
+used to separate words (e.g., "variable_name" and "numchars" are both
+acceptable). Using underscores makes variable and function names more readable
+because it looks like whitespace; using lower-case is easy on the eyes.
+
+ Frowned upon:
+
+ hitList
+ TotalChars
+ szFileName
+ pf_Nfol_TriState
+
+ Preferred:
+
+ hit_list
+ total_chars
+ file_name
+ sensible_name
+
+Exceptions:
+
+ - Enums, macros, and constant variables are occasionally written in all
+ upper-case with words optionally seperatedy by underscores (i.e. FIFO_TYPE,
+ ISBLKDEV()).
+
+ - Nobody is going to get mad at you for using 'pvar' as the name of a
+ variable that is a pointer to 'var'.
+
+
+Converting to K&R
+~~~~~~~~~~~~~~~~~
+
+The Busybox codebase is very much a mixture of code gathered from a variety of
+sources. This explains why the current codebase contains such a hodge-podge of
+different naming styles (Java, Pascal, K&R, just-plain-weird, etc.). The K&R
+guideline explained above should therefore be used on new files that are added
+to the repository. Furthermore, the maintainer of an existing file that uses
+alternate naming conventions should, at his own convenience, convert those
+names over to K&R style. Converting variable names is a very low priority
+task.
+
+If you want to do a search-and-replace of a single variable name in different
+files, you can do the following in the busybox directory:
+
+ $ perl -pi -e 's/\bOldVar\b/new_var/g' *.[ch]
+
+If you want to convert all the non-K&R vars in your file all at once, follow
+these steps:
+
+ - In the busybox directory type 'examples/mk2knr.pl files-to-convert'. This
+ does not do the actual conversion, rather, it generates a script called
+ 'convertme.pl' that shows what will be converted, giving you a chance to
+ review the changes beforehand.
+
+ - Review the 'convertme.pl' script that gets generated in the busybox
+ directory and remove / edit any of the substitutions in there. Please
+ especially check for false positives (strings that should not be
+ converted).
+
+ - Type './convertme.pl same-files-as-before' to perform the actual
+ conversion.
+
+ - Compile and see if everything still works.
+
+Please be aware of changes that have cascading effects into other files. For
+example, if you're changing the name of something in, say utility.c, you
+should probably run 'examples/mk2knr.pl utility.c' at first, but when you run
+the 'convertme.pl' script you should run it on _all_ files like so:
+'./convertme.pl *.[ch]'.
+
+
+
+Avoid The Preprocessor
+----------------------
+
+At best, the preprocessor is a necessary evil, helping us account for platform
+and architecture differences. Using the preprocessor unnecessarily is just
+plain evil.
+
+
+The Folly of #define
+~~~~~~~~~~~~~~~~~~~~
+
+Use 'const <type> var' for declaring constants.
+
+ Don't do this:
+
+ #define CONST 80
+
+ Do this instead, when the variable is in a header file and will be used in
+ several source files:
+
+ enum { CONST = 80 };
+
+Although enum may look ugly to some people, it is better for code size.
+With "const int" compiler may fail to optimize it out and will reserve
+a real storage in rodata for it! (Hopefully, newer gcc will get better
+at it...). With "define", you have slight risk of polluting namespace
+(#define doesn't allow you to redefine the name in the inner scopes),
+and complex "define" are evaluated each time they uesd, not once
+at declarations like enums. Also, the preprocessor does _no_ type checking
+whatsoever, making it much more error prone.
+
+
+The Folly of Macros
+~~~~~~~~~~~~~~~~~~~
+
+Use 'static inline' instead of a macro.
+
+ Don't do this:
+
+ #define mini_func(param1, param2) (param1 << param2)
+
+ Do this instead:
+
+ static inline int mini_func(int param1, param2)
+ {
+ return (param1 << param2);
+ }
+
+Static inline functions are greatly preferred over macros. They provide type
+safety, have no length limitations, no formatting limitations, have an actual
+return value, and under gcc they are as cheap as macros. Besides, really long
+macros with backslashes at the end of each line are ugly as sin.
+
+
+The Folly of #ifdef
+~~~~~~~~~~~~~~~~~~~
+
+Code cluttered with ifdefs is difficult to read and maintain. Don't do it.
+Instead, put your ifdefs at the top of your .c file (or in a header), and
+conditionally define 'static inline' functions, (or *maybe* macros), which are
+used in the code.
+
+ Don't do this:
+
+ ret = my_func(bar, baz);
+ if (!ret)
+ return -1;
+ #ifdef CONFIG_FEATURE_FUNKY
+ maybe_do_funky_stuff(bar, baz);
+ #endif
+
+ Do this instead:
+
+ (in .h header file)
+
+ #if ENABLE_FEATURE_FUNKY
+ static inline void maybe_do_funky_stuff(int bar, int baz)
+ {
+ /* lotsa code in here */
+ }
+ #else
+ static inline void maybe_do_funky_stuff(int bar, int baz) {}
+ #endif
+
+ (in the .c source file)
+
+ ret = my_func(bar, baz);
+ if (!ret)
+ return -1;
+ maybe_do_funky_stuff(bar, baz);
+
+The great thing about this approach is that the compiler will optimize away
+the "no-op" case (the empty function) when the feature is turned off.
+
+Note also the use of the word 'maybe' in the function name to indicate
+conditional execution.
+
+
+
+Notes on Strings
+----------------
+
+Strings in C can get a little thorny. Here's some guidelines for dealing with
+strings in Busybox. (There is surely more that could be added to this
+section.)
+
+
+String Files
+~~~~~~~~~~~~
+
+Put all help/usage messages in usage.c. Put other strings in messages.c.
+Putting these strings into their own file is a calculated decision designed to
+confine spelling errors to a single place and aid internationalization
+efforts, if needed. (Side Note: we might want to use a single file - maybe
+called 'strings.c' - instead of two, food for thought).
+
+
+Testing String Equivalence
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+There's a right way and a wrong way to test for sting equivalence with
+strcmp():
+
+ The wrong way:
+
+ if (!strcmp(string, "foo")) {
+ ...
+
+ The right way:
+
+ if (strcmp(string, "foo") == 0){
+ ...
+
+The use of the "equals" (==) operator in the latter example makes it much more
+obvious that you are testing for equivalence. The former example with the
+"not" (!) operator makes it look like you are testing for an error. In a more
+perfect world, we would have a streq() function in the string library, but
+that ain't the world we're living in.
+
+
+Avoid Dangerous String Functions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Unfortunately, the way C handles strings makes them prone to overruns when
+certain library functions are (mis)used. The following table offers a summary
+of some of the more notorious troublemakers:
+
+function overflows preferred
+-------------------------------------------------
+strcpy dest string safe_strncpy
+strncpy may fail to 0-terminate dst safe_strncpy
+strcat dest string strncat
+gets string it gets fgets
+getwd buf string getcwd
+[v]sprintf str buffer [v]snprintf
+realpath path buffer use with pathconf
+[vf]scanf its arguments just avoid it
+
+
+The above is by no means a complete list. Be careful out there.
+
+
+
+Avoid Big Static Buffers
+------------------------
+
+First, some background to put this discussion in context: static buffers look
+like this in code:
+
+ /* in a .c file outside any functions */
+ static char buffer[BUFSIZ]; /* happily used by any function in this file,
+ but ick! big! */
+
+The problem with these is that any time any busybox app is run, you pay a
+memory penalty for this buffer, even if the applet that uses said buffer is
+not run. This can be fixed, thusly:
+
+ static char *buffer;
+ ...
+ other_func()
+ {
+ strcpy(buffer, lotsa_chars); /* happily uses global *buffer */
+ ...
+ foo_main()
+ {
+ buffer = xmalloc(sizeof(char)*BUFSIZ);
+ ...
+
+However, this approach trades bss segment for text segment. Rather than
+mallocing the buffers (and thus growing the text size), buffers can be
+declared on the stack in the *_main() function and made available globally by
+assigning them to a global pointer thusly:
+
+ static char *pbuffer;
+ ...
+ other_func()
+ {
+ strcpy(pbuffer, lotsa_chars); /* happily uses global *pbuffer */
+ ...
+ foo_main()
+ {
+ char *buffer[BUFSIZ]; /* declared locally, on stack */
+ pbuffer = buffer; /* but available globally */
+ ...
+
+This last approach has some advantages (low code size, space not used until
+it's needed), but can be a problem in some low resource machines that have
+very limited stack space (e.g., uCLinux).
+
+A macro is declared in busybox.h that implements compile-time selection
+between xmalloc() and stack creation, so you can code the line in question as
+
+ RESERVE_CONFIG_BUFFER(buffer, BUFSIZ);
+
+and the right thing will happen, based on your configuration.
+
+Another relatively new trick of similar nature is explained
+in keep_data_small.txt.
+
+
+
+Miscellaneous Coding Guidelines
+-------------------------------
+
+The following are important items that don't fit into any of the above
+sections.
+
+
+Model Busybox Applets After GNU Counterparts
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When in doubt about the proper behavior of a Busybox program (output,
+formatting, options, etc.), model it after the equivalent GNU program.
+Doesn't matter how that program behaves on some other flavor of *NIX; doesn't
+matter what the POSIX standard says or doesn't say, just model Busybox
+programs after their GNU counterparts and it will make life easier on (nearly)
+everyone.
+
+The only time we deviate from emulating the GNU behavior is when:
+
+ - We are deliberately not supporting a feature (such as a command line
+ switch)
+ - Emulating the GNU behavior is prohibitively expensive (lots more code
+ would be required, lots more memory would be used, etc.)
+ - The difference is minor or cosmetic
+
+A note on the 'cosmetic' case: output differences might be considered
+cosmetic, but if the output is significant enough to break other scripts that
+use the output, it should really be fixed.
+
+
+Scope
+~~~~~
+
+If a const variable is used only in a single source file, put it in the source
+file and not in a header file. Likewise, if a const variable is used in only
+one function, do not make it global to the file. Instead, declare it inside
+the function body. Bottom line: Make a conscious effort to limit declarations
+to the smallest scope possible.
+
+Inside applet files, all functions should be declared static so as to keep the
+global name space clean. The only exception to this rule is the "applet_main"
+function which must be declared extern.
+
+If you write a function that performs a task that could be useful outside the
+immediate file, turn it into a general-purpose function with no ties to any
+applet and put it in the utility.c file instead.
+
+
+Brackets Are Your Friends
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Please use brackets on all if and else statements, even if it is only one
+line. Example:
+
+ Don't do this:
+
+ if (foo)
+ stmt1;
+ stmt2
+ stmt3;
+
+ Do this instead:
+
+ if (foo) {
+ stmt1;
+ }
+ stmt2
+ stmt3;
+
+The "bracketless" approach is error prone because someday you might add a line
+like this:
+
+ if (foo)
+ stmt1;
+ new_line();
+ stmt2;
+ stmt3;
+
+And the resulting behavior of your program would totally bewilder you. (Don't
+laugh, it happens to us all.) Remember folks, this is C, not Python.
+
+
+Function Declarations
+~~~~~~~~~~~~~~~~~~~~~
+
+Do not use old-style function declarations that declare variable types between
+the parameter list and opening bracket. Example:
+
+ Don't do this:
+
+ int foo(parm1, parm2)
+ char parm1;
+ float parm2;
+ {
+ ....
+
+ Do this instead:
+
+ int foo(char parm1, float parm2)
+ {
+ ....
+
+The only time you would ever need to use the old declaration syntax is to
+support ancient, antediluvian compilers. To our good fortune, we have access
+to more modern compilers and the old declaration syntax is neither necessary
+nor desired.
+
+
+Emphasizing Logical Blocks
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Organization and readability are improved by putting extra newlines around
+blocks of code that perform a single task. These are typically blocks that
+begin with a C keyword, but not always.
+
+Furthermore, you should put a single comment (not necessarily one line, just
+one comment) before the block, rather than commenting each and every line.
+There is an optimal amount of commenting that a program can have; you can
+comment too much as well as too little.
+
+A picture is really worth a thousand words here, the following example
+illustrates how to emphasize logical blocks:
+
+ while (line = xmalloc_fgets(fp)) {
+
+ /* eat the newline, if any */
+ chomp(line);
+
+ /* ignore blank lines */
+ if (strlen(file_to_act_on) == 0) {
+ continue;
+ }
+
+ /* if the search string is in this line, print it,
+ * unless we were told to be quiet */
+ if (strstr(line, search) && !be_quiet) {
+ puts(line);
+ }
+
+ /* clean up */
+ free(line);
+ }
+
+
+Processing Options with getopt
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If your applet needs to process command-line switches, please use getopt32() to
+do so. Numerous examples can be seen in many of the existing applets, but
+basically it boils down to two things: at the top of the .c file, have this
+line in the midst of your #includes, if you need to parse long options:
+
+ #include <getopt.h>
+
+Then have long options defined:
+
+ static const struct option <applet>_long_options[] = {
+ { "list", 0, NULL, 't' },
+ { "extract", 0, NULL, 'x' },
+ { NULL, 0, NULL, 0 }
+ };
+
+And a code block similar to the following near the top of your applet_main()
+routine:
+
+ char *str_b;
+
+ opt_complementary = "cryptic_string";
+ applet_long_options = <applet>_long_options; /* if you have them */
+ opt = getopt32(argc, argv, "ab:c", &str_b);
+ if (opt & 1) {
+ handle_option_a();
+ }
+ if (opt & 2) {
+ handle_option_b(str_b);
+ }
+ if (opt & 4) {
+ handle_option_c();
+ }
+
+If your applet takes no options (such as 'init'), there should be a line
+somewhere in the file reads:
+
+ /* no options, no getopt */
+
+That way, when people go grepping to see which applets need to be converted to
+use getopt, they won't get false positives.
+
+For more info and examples, examine getopt32.c, tar.c, wget.c etc.
diff --git a/cleopatre/busybox-1.11.1-spc300/docs/tar_pax.txt b/cleopatre/busybox-1.11.1-spc300/docs/tar_pax.txt
new file mode 100644
index 0000000000..e56c27b165
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/docs/tar_pax.txt
@@ -0,0 +1,239 @@
+'pax headers' is POSIX 2003 (iirc) addition designed to fix
+tar format limitations - older tar format has fixed fields
+for everything (filename, uid, filesize etc) which can overflow.
+
+pax Header Block
+
+The pax header block shall be identical to the ustar header block
+described in ustar Interchange Format, except that two additional
+typeflag values are defined:
+
+x
+ Represents extended header records for the following file in
+the archive (which shall have its own ustar header block).
+
+g
+ Represents global extended header records for the following
+files in the archive. Each value shall affect all subsequent files
+that do not override that value in their own extended header
+record and until another global extended header record is reached
+that provides another value for the same field. The typeflag g
+global headers should not be used with interchange media that
+could suffer partial data loss in transporting the archive.
+
+For both of these types, the size field shall be the size of the
+extended header records in octets. The other fields in the header
+block are not meaningful to this version of the pax utility.
+However, if this archive is read by a pax utility conforming to
+the ISO POSIX-2:1993 standard, the header block fields are used to
+create a regular file that contains the extended header records as
+data. Therefore, header block field values should be selected to
+provide reasonable file access to this regular file.
+
+A further difference from the ustar header block is that data
+blocks for files of typeflag 1 (the digit one) (hard link) may be
+included, which means that the size field may be greater than
+zero.
+
+pax Extended Header
+
+An extended header shall consist of one or more records, each
+constructed as follows:
+
+"%d %s=%s\n", <length>, <keyword>, <value>
+
+The <length> field shall be the decimal length of the extended
+header record in octets, including length string itself and the
+trailing <newline>.
+
+[skip]
+
+atime
+ The file access time for the following file(s), equivalent to
+the value of the st_atime member of the stat structure for a file,
+as described by the stat() function. The access time shall be
+restored if the process has the appropriate privilege required to
+do so. The format of the <value> shall be as described in pax
+Extended Header File Times.
+
+charset
+ The name of the character set used to encode the data in the
+following file(s).
+
+ The encoding is included in an extended header for information
+only; when pax is used as described in IEEE Std 1003.1-2001, it
+shall not translate the file data into any other encoding. The
+BINARY entry indicates unencoded binary data.
+
+ When used in write or copy mode, it is implementation-defined
+whether pax includes a charset extended header record for a file.
+
+comment
+ A series of characters used as a comment. All characters in
+the <value> field shall be ignored by pax.
+
+gid
+ The group ID of the group that owns the file, expressed as a
+decimal number using digits from the ISO/IEC 646:1991 standard.
+This record shall override the gid field in the following header
+block(s). When used in write or copy mode, pax shall include a gid
+extended header record for each file whose group ID is greater
+than 2097151 (octal 7777777).
+
+gname
+ The group of the file(s), formatted as a group name in the
+group database. This record shall override the gid and gname
+fields in the following header block(s), and any gid extended
+header record. When used in read, copy, or list mode, pax shall
+translate the name from the UTF-8 encoding in the header record to
+the character set appropriate for the group database on the
+receiving system. If any of the UTF-8 characters cannot be
+translated, and if the -o invalid= UTF-8 option is not specified,
+the results are implementation-defined. When used in write or copy
+mode, pax shall include a gname extended header record for each
+file whose group name cannot be represented entirely with the
+letters and digits of the portable character set.
+
+linkpath
+ The pathname of a link being created to another file, of any
+type, previously archived. This record shall override the linkname
+field in the following ustar header block(s). The following ustar
+header block shall determine the type of link created. If typeflag
+of the following header block is 1, it shall be a hard link. If
+typeflag is 2, it shall be a symbolic link and the linkpath value
+shall be the contents of the symbolic link. The pax utility shall
+translate the name of the link (contents of the symbolic link)
+from the UTF-8 encoding to the character set appropriate for the
+local file system. When used in write or copy mode, pax shall
+include a linkpath extended header record for each link whose
+pathname cannot be represented entirely with the members of the
+portable character set other than NUL.
+
+mtime
+ The file modification time of the following file(s),
+equivalent to the value of the st_mtime member of the stat
+structure for a file, as described in the stat() function. This
+record shall override the mtime field in the following header
+block(s). The modification time shall be restored if the process
+has the appropriate privilege required to do so. The format of the
+<value> shall be as described in pax Extended Header File Times.
+
+path
+ The pathname of the following file(s). This record shall
+override the name and prefix fields in the following header
+block(s). The pax utility shall translate the pathname of the file
+from the UTF-8 encoding to the character set appropriate for the
+local file system.
+
+ When used in write or copy mode, pax shall include a path
+extended header record for each file whose pathname cannot be
+represented entirely with the members of the portable character
+set other than NUL.
+
+realtime.any
+ The keywords prefixed by "realtime." are reserved for future
+standardization.
+
+security.any
+ The keywords prefixed by "security." are reserved for future
+standardization.
+
+size
+ The size of the file in octets, expressed as a decimal number
+using digits from the ISO/IEC 646:1991 standard. This record shall
+override the size field in the following header block(s). When
+used in write or copy mode, pax shall include a size extended
+header record for each file with a size value greater than
+8589934591 (octal 77777777777).
+
+uid
+ The user ID of the file owner, expressed as a decimal number
+using digits from the ISO/IEC 646:1991 standard. This record shall
+override the uid field in the following header block(s). When used
+in write or copy mode, pax shall include a uid extended header
+record for each file whose owner ID is greater than 2097151 (octal
+7777777).
+
+uname
+ The owner of the following file(s), formatted as a user name
+in the user database. This record shall override the uid and uname
+fields in the following header block(s), and any uid extended
+header record. When used in read, copy, or list mode, pax shall
+translate the name from the UTF-8 encoding in the header record to
+the character set appropriate for the user database on the
+receiving system. If any of the UTF-8 characters cannot be
+translated, and if the -o invalid= UTF-8 option is not specified,
+the results are implementation-defined. When used in write or copy
+mode, pax shall include a uname extended header record for each
+file whose user name cannot be represented entirely with the
+letters and digits of the portable character set.
+
+If the <value> field is zero length, it shall delete any header
+block field, previously entered extended header value, or global
+extended header value of the same name.
+
+If a keyword in an extended header record (or in a -o
+option-argument) overrides or deletes a corresponding field in the
+ustar header block, pax shall ignore the contents of that header
+block field.
+
+Unlike the ustar header block fields, NULs shall not delimit
+<value>s; all characters within the <value> field shall be
+considered data for the field. None of the length limitations of
+the ustar header block fields in ustar Header Block shall apply to
+the extended header records.
+
+pax Extended Header File Times
+
+Time records shall be formatted as a decimal representation of the
+time in seconds since the Epoch. If a period ( '.' ) decimal point
+character is present, the digits to the right of the point shall
+represent the units of a subsecond timing granularity. In read or
+copy mode, the pax utility shall truncate the time of a file to
+the greatest value that is not greater than the input header
+file time. In write or copy mode, the pax utility shall output a
+time exactly if it can be represented exactly as a decimal number,
+and otherwise shall generate only enough digits so that the same
+time shall be recovered if the file is extracted on a system whose
+underlying implementation supports the same time granularity.
+
+Example from Linux kernel archive tarball:
+
+00000000 70 61 78 5f 67 6c 6f 62 61 6c 5f 68 65 61 64 65 |pax_global_heade|
+00000010 72 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |r...............|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 00 00 00 00 30 30 30 30 36 36 36 00 30 30 30 30 |....0000666.0000|
+00000070 30 30 30 00 30 30 30 30 30 30 30 00 30 30 30 30 |000.0000000.0000|
+00000080 30 30 30 30 30 36 34 00 30 30 30 30 30 30 30 30 |0000064.00000000|
+00000090 30 30 30 00 30 30 31 34 30 35 33 00 67 00 00 00 |000.0014053.g...|
+000000a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+000000b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+000000c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+000000d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+000000e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+000000f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000100 00 75 73 74 61 72 00 30 30 67 69 74 00 00 00 00 |.ustar.00git....|
+00000110 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000120 00 00 00 00 00 00 00 00 00 67 69 74 00 00 00 00 |.........git....|
+00000130 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000140 00 00 00 00 00 00 00 00 00 30 30 30 30 30 30 30 |.........0000000|
+00000150 00 30 30 30 30 30 30 30 00 00 00 00 00 00 00 00 |.0000000........|
+00000160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+000001a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+000001b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+000001c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+000001d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+000001e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000200 35 32 20 63 6f 6d 6d 65 6e 74 3d 62 31 30 35 30 |52 comment=b1050|
+00000210 32 62 32 32 61 31 32 30 39 64 36 62 34 37 36 33 |2b22a1209d6b4763|
+00000220 39 64 38 38 62 38 31 32 62 32 31 66 62 35 39 34 |9d88b812b21fb594|
+00000230 39 65 34 0a 00 00 00 00 00 00 00 00 00 00 00 00 |9e4.............|
+00000240 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+...
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/Config.in b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/Config.in
new file mode 100644
index 0000000000..fe8d031507
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/Config.in
@@ -0,0 +1,68 @@
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Linux Ext2 FS Progs"
+
+config CHATTR
+ bool "chattr"
+ default n
+ help
+ chattr changes the file attributes on a second extended file system.
+
+### config E2FSCK
+### bool "e2fsck"
+### default n
+### help
+### e2fsck is used to check Linux second extended file systems (ext2fs).
+### e2fsck also supports ext2 filesystems countaining a journal (ext3).
+### The normal compat symlinks 'fsck.ext2' and 'fsck.ext3' are also
+### provided.
+
+config FSCK
+ bool "fsck"
+ default n
+ help
+ fsck is used to check and optionally repair one or more filesystems.
+ In actuality, fsck is simply a front-end for the various file system
+ checkers (fsck.fstype) available under Linux.
+
+config LSATTR
+ bool "lsattr"
+ default n
+ help
+ lsattr lists the file attributes on a second extended file system.
+
+### config MKE2FS
+### bool "mke2fs"
+### default n
+### help
+### mke2fs is used to create an ext2/ext3 filesystem. The normal compat
+### symlinks 'mkfs.ext2' and 'mkfs.ext3' are also provided.
+
+### config TUNE2FS
+### bool "tune2fs"
+### default n
+### help
+### tune2fs allows the system administrator to adjust various tunable
+### filesystem parameters on Linux ext2/ext3 filesystems.
+
+### config E2LABEL
+### bool "e2label"
+### default n
+### depends on TUNE2FS
+### help
+### e2label will display or change the filesystem label on the ext2
+### filesystem located on device.
+
+### NB: this one is now provided by util-linux/volume_id/*
+### config FINDFS
+### bool "findfs"
+### default n
+### depends on TUNE2FS
+### help
+### findfs will search the disks in the system looking for a filesystem
+### which has a label matching label or a UUID equal to uuid.
+
+endmenu
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/Kbuild b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/Kbuild
new file mode 100644
index 0000000000..9f58ce0925
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/Kbuild
@@ -0,0 +1,12 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+lib-y:=
+
+lib-$(CONFIG_CHATTR) += chattr.o e2fs_lib.o
+lib-$(CONFIG_LSATTR) += lsattr.o e2fs_lib.o
+
+lib-$(CONFIG_FSCK) += fsck.o
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/README b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/README
new file mode 100644
index 0000000000..eb158e5881
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/README
@@ -0,0 +1,12 @@
+Authors and contributors of original e2fsprogs:
+
+Remy Card <card@masi.ibp.fr>
+Theodore Ts'o <tytso@mit.edu>
+Stephen C. Tweedie <sct@redhat.com>
+Andreas Gruenbacher, <a.gruenbacher@computer.org>
+Kaz Kylheku <kaz@ashi.footprints.net>
+F.W. ten Wolde <franky@duteca.et.tudelft.nl>
+Jeremy Fitzhardinge <jeremy@zip.com.au>
+M.J.E. Mol <marcel@duteca.et.tudelft.nl>
+Miquel van Smoorenburg <miquels@drinkel.ow.org>
+Uwe Ohse <uwe@tirka.gun.de>
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/chattr.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/chattr.c
new file mode 100644
index 0000000000..e783d3e894
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/chattr.c
@@ -0,0 +1,172 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * chattr.c - Change file attributes on an ext2 file system
+ *
+ * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
+ * Laboratoire MASI, Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * This file can be redistributed under the terms of the GNU General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/10/30 - Creation
+ * 93/11/13 - Replace stat() calls by lstat() to avoid loops
+ * 94/02/27 - Integrated in Ted's distribution
+ * 98/12/29 - Ignore symlinks when working recursively (G M Sipe)
+ * 98/12/29 - Display version info only when -V specified (G M Sipe)
+ */
+
+#include "libbb.h"
+#include "e2fs_lib.h"
+
+#define OPT_ADD 1
+#define OPT_REM 2
+#define OPT_SET 4
+#define OPT_SET_VER 8
+
+struct globals {
+ unsigned long version;
+ unsigned long af;
+ unsigned long rf;
+ smallint flags;
+ smallint recursive;
+};
+
+static unsigned long get_flag(char c)
+{
+ const char *fp = strchr(e2attr_flags_sname_chattr, c);
+ if (fp)
+ return e2attr_flags_value_chattr[fp - e2attr_flags_sname_chattr];
+ bb_show_usage();
+}
+
+static int decode_arg(const char *arg, struct globals *gp)
+{
+ unsigned long *fl;
+ char opt = *arg++;
+
+ fl = &gp->af;
+ if (opt == '-') {
+ gp->flags |= OPT_REM;
+ fl = &gp->rf;
+ } else if (opt == '+') {
+ gp->flags |= OPT_ADD;
+ } else if (opt == '=') {
+ gp->flags |= OPT_SET;
+ } else
+ return 0;
+
+ while (*arg)
+ *fl |= get_flag(*arg++);
+
+ return 1;
+}
+
+static void change_attributes(const char *name, struct globals *gp);
+
+static int chattr_dir_proc(const char *dir_name, struct dirent *de, void *gp)
+{
+ char *path = concat_subpath_file(dir_name, de->d_name);
+ /* path is NULL if de->d_name is "." or "..", else... */
+ if (path) {
+ change_attributes(path, gp);
+ free(path);
+ }
+ return 0;
+}
+
+static void change_attributes(const char *name, struct globals *gp)
+{
+ unsigned long fsflags;
+ struct stat st;
+
+ if (lstat(name, &st) != 0) {
+ bb_perror_msg("stat %s", name);
+ return;
+ }
+ if (S_ISLNK(st.st_mode) && gp->recursive)
+ return;
+
+ /* Don't try to open device files, fifos etc. We probably
+ * ought to display an error if the file was explicitly given
+ * on the command line (whether or not recursive was
+ * requested). */
+ if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode))
+ return;
+
+ if (gp->flags & OPT_SET_VER)
+ if (fsetversion(name, gp->version) != 0)
+ bb_perror_msg("setting version on %s", name);
+
+ if (gp->flags & OPT_SET) {
+ fsflags = gp->af;
+ } else {
+ if (fgetflags(name, &fsflags) != 0) {
+ bb_perror_msg("reading flags on %s", name);
+ goto skip_setflags;
+ }
+ /*if (gp->flags & OPT_REM) - not needed, rf is zero otherwise */
+ fsflags &= ~gp->rf;
+ /*if (gp->flags & OPT_ADD) - not needed, af is zero otherwise */
+ fsflags |= gp->af;
+ /* What is this? And why it's not done for SET case? */
+ if (!S_ISDIR(st.st_mode))
+ fsflags &= ~EXT2_DIRSYNC_FL;
+ }
+ if (fsetflags(name, fsflags) != 0)
+ bb_perror_msg("setting flags on %s", name);
+
+ skip_setflags:
+ if (gp->recursive && S_ISDIR(st.st_mode))
+ iterate_on_dir(name, chattr_dir_proc, gp);
+}
+
+int chattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int chattr_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ struct globals g;
+ char *arg;
+
+ memset(&g, 0, sizeof(g));
+
+ /* parse the args */
+ while ((arg = *++argv)) {
+ /* take care of -R and -v <version> */
+ if (arg[0] == '-'
+ && (arg[1] == 'R' || arg[1] == 'v')
+ && !arg[2]
+ ) {
+ if (arg[1] == 'R') {
+ g.recursive = 1;
+ continue;
+ }
+ /* arg[1] == 'v' */
+ if (!*++argv)
+ bb_show_usage();
+ g.version = xatoul(*argv);
+ g.flags |= OPT_SET_VER;
+ continue;
+ }
+
+ if (!decode_arg(arg, &g))
+ break;
+ }
+
+ /* run sanity checks on all the arguments given us */
+ if (!*argv)
+ bb_show_usage();
+ if ((g.flags & OPT_SET) && (g.flags & (OPT_ADD|OPT_REM)))
+ bb_error_msg_and_die("= is incompatible with - and +");
+ if (g.rf & g.af)
+ bb_error_msg_and_die("can't set and unset a flag");
+ if (!g.flags)
+ bb_error_msg_and_die("must use '-v', =, - or +");
+
+ /* now run chattr on all the files passed to us */
+ do change_attributes(*argv, &g); while (*++argv);
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/e2fs_defs.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/e2fs_defs.h
new file mode 100644
index 0000000000..b3ea3ae344
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/e2fs_defs.h
@@ -0,0 +1,561 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * linux/include/linux/ext2_fs.h
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#ifndef _LINUX_EXT2_FS_H
+#define _LINUX_EXT2_FS_H
+
+/*
+ * Special inode numbers
+ */
+#define EXT2_BAD_INO 1 /* Bad blocks inode */
+#define EXT2_ROOT_INO 2 /* Root inode */
+#define EXT2_ACL_IDX_INO 3 /* ACL inode */
+#define EXT2_ACL_DATA_INO 4 /* ACL inode */
+#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */
+#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */
+#define EXT2_RESIZE_INO 7 /* Reserved group descriptors inode */
+#define EXT2_JOURNAL_INO 8 /* Journal inode */
+
+/* First non-reserved inode for old ext2 filesystems */
+#define EXT2_GOOD_OLD_FIRST_INO 11
+
+/*
+ * The second extended file system magic number
+ */
+#define EXT2_SUPER_MAGIC 0xEF53
+
+/* Assume that user mode programs are passing in an ext2fs superblock, not
+ * a kernel struct super_block. This will allow us to call the feature-test
+ * macros from user land. */
+#define EXT2_SB(sb) (sb)
+
+/*
+ * Maximal count of links to a file
+ */
+#define EXT2_LINK_MAX 32000
+
+/*
+ * Macro-instructions used to manage several block sizes
+ */
+#define EXT2_MIN_BLOCK_LOG_SIZE 10 /* 1024 */
+#define EXT2_MAX_BLOCK_LOG_SIZE 16 /* 65536 */
+#define EXT2_MIN_BLOCK_SIZE (1 << EXT2_MIN_BLOCK_LOG_SIZE)
+#define EXT2_MAX_BLOCK_SIZE (1 << EXT2_MAX_BLOCK_LOG_SIZE)
+#define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
+#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
+#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+ EXT2_GOOD_OLD_INODE_SIZE : (s)->s_inode_size)
+#define EXT2_FIRST_INO(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+ EXT2_GOOD_OLD_FIRST_INO : (s)->s_first_ino)
+#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof(uint32_t))
+
+/*
+ * Macro-instructions used to manage fragments
+ */
+#define EXT2_MIN_FRAG_SIZE EXT2_MIN_BLOCK_SIZE
+#define EXT2_MAX_FRAG_SIZE EXT2_MAX_BLOCK_SIZE
+#define EXT2_MIN_FRAG_LOG_SIZE EXT2_MIN_BLOCK_LOG_SIZE
+#define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size)
+#define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s))
+
+/*
+ * ACL structures
+ */
+struct ext2_acl_header { /* Header of Access Control Lists */
+ uint32_t aclh_size;
+ uint32_t aclh_file_count;
+ uint32_t aclh_acle_count;
+ uint32_t aclh_first_acle;
+};
+
+struct ext2_acl_entry { /* Access Control List Entry */
+ uint32_t acle_size;
+ uint16_t acle_perms; /* Access permissions */
+ uint16_t acle_type; /* Type of entry */
+ uint16_t acle_tag; /* User or group identity */
+ uint16_t acle_pad1;
+ uint32_t acle_next; /* Pointer on next entry for the */
+ /* same inode or on next free entry */
+};
+
+/*
+ * Structure of a blocks group descriptor
+ */
+struct ext2_group_desc {
+ uint32_t bg_block_bitmap; /* Blocks bitmap block */
+ uint32_t bg_inode_bitmap; /* Inodes bitmap block */
+ uint32_t bg_inode_table; /* Inodes table block */
+ uint16_t bg_free_blocks_count; /* Free blocks count */
+ uint16_t bg_free_inodes_count; /* Free inodes count */
+ uint16_t bg_used_dirs_count; /* Directories count */
+ uint16_t bg_pad;
+ uint32_t bg_reserved[3];
+};
+
+/*
+ * Data structures used by the directory indexing feature
+ *
+ * Note: all of the multibyte integer fields are little endian.
+ */
+
+/*
+ * Note: dx_root_info is laid out so that if it should somehow get
+ * overlaid by a dirent the two low bits of the hash version will be
+ * zero. Therefore, the hash version mod 4 should never be 0.
+ * Sincerely, the paranoia department.
+ */
+struct ext2_dx_root_info {
+ uint32_t reserved_zero;
+ uint8_t hash_version; /* 0 now, 1 at release */
+ uint8_t info_length; /* 8 */
+ uint8_t indirect_levels;
+ uint8_t unused_flags;
+};
+
+#define EXT2_HASH_LEGACY 0
+#define EXT2_HASH_HALF_MD4 1
+#define EXT2_HASH_TEA 2
+
+#define EXT2_HASH_FLAG_INCOMPAT 0x1
+
+struct ext2_dx_entry {
+ uint32_t hash;
+ uint32_t block;
+};
+
+struct ext2_dx_countlimit {
+ uint16_t limit;
+ uint16_t count;
+};
+
+
+/*
+ * Macro-instructions used to manage group descriptors
+ */
+#define EXT2_BLOCKS_PER_GROUP(s) (EXT2_SB(s)->s_blocks_per_group)
+#define EXT2_INODES_PER_GROUP(s) (EXT2_SB(s)->s_inodes_per_group)
+#define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s)/EXT2_INODE_SIZE(s))
+/* limits imposed by 16-bit value gd_free_{blocks,inode}_count */
+#define EXT2_MAX_BLOCKS_PER_GROUP(s) ((1 << 16) - 8)
+#define EXT2_MAX_INODES_PER_GROUP(s) ((1 << 16) - EXT2_INODES_PER_BLOCK(s))
+#define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
+
+/*
+ * Constants relative to the data blocks
+ */
+#define EXT2_NDIR_BLOCKS 12
+#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
+#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
+#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
+#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
+
+/*
+ * Inode flags
+ */
+#define EXT2_SECRM_FL 0x00000001 /* Secure deletion */
+#define EXT2_UNRM_FL 0x00000002 /* Undelete */
+#define EXT2_COMPR_FL 0x00000004 /* Compress file */
+#define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */
+#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */
+#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */
+#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */
+#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */
+/* Reserved for compression usage... */
+#define EXT2_DIRTY_FL 0x00000100
+#define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
+#define EXT2_NOCOMPR_FL 0x00000400 /* Access raw compressed data */
+#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */
+/* End compression flags --- maybe not all used */
+#define EXT2_BTREE_FL 0x00001000 /* btree format dir */
+#define EXT2_INDEX_FL 0x00001000 /* hash-indexed directory */
+#define EXT2_IMAGIC_FL 0x00002000
+#define EXT3_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */
+#define EXT2_NOTAIL_FL 0x00008000 /* file tail should not be merged */
+#define EXT2_DIRSYNC_FL 0x00010000 /* Synchronous directory modifications */
+#define EXT2_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
+#define EXT3_EXTENTS_FL 0x00080000 /* Inode uses extents */
+#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
+
+#define EXT2_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */
+#define EXT2_FL_USER_MODIFIABLE 0x000080FF /* User modifiable flags */
+
+/*
+ * ioctl commands
+ */
+#define EXT2_IOC_GETFLAGS _IOR('f', 1, long)
+#define EXT2_IOC_SETFLAGS _IOW('f', 2, long)
+#define EXT2_IOC_GETVERSION _IOR('v', 1, long)
+#define EXT2_IOC_SETVERSION _IOW('v', 2, long)
+
+/*
+ * Structure of an inode on the disk
+ */
+struct ext2_inode {
+ uint16_t i_mode; /* File mode */
+ uint16_t i_uid; /* Low 16 bits of Owner Uid */
+ uint32_t i_size; /* Size in bytes */
+ uint32_t i_atime; /* Access time */
+ uint32_t i_ctime; /* Creation time */
+ uint32_t i_mtime; /* Modification time */
+ uint32_t i_dtime; /* Deletion Time */
+ uint16_t i_gid; /* Low 16 bits of Group Id */
+ uint16_t i_links_count; /* Links count */
+ uint32_t i_blocks; /* Blocks count */
+ uint32_t i_flags; /* File flags */
+ union {
+ struct {
+ uint32_t l_i_reserved1;
+ } linux1;
+ struct {
+ uint32_t h_i_translator;
+ } hurd1;
+ struct {
+ uint32_t m_i_reserved1;
+ } masix1;
+ } osd1; /* OS dependent 1 */
+ uint32_t i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
+ uint32_t i_generation; /* File version (for NFS) */
+ uint32_t i_file_acl; /* File ACL */
+ uint32_t i_dir_acl; /* Directory ACL */
+ uint32_t i_faddr; /* Fragment address */
+ union {
+ struct {
+ uint8_t l_i_frag; /* Fragment number */
+ uint8_t l_i_fsize; /* Fragment size */
+ uint16_t i_pad1;
+ uint16_t l_i_uid_high; /* these 2 fields */
+ uint16_t l_i_gid_high; /* were reserved2[0] */
+ uint32_t l_i_reserved2;
+ } linux2;
+ struct {
+ uint8_t h_i_frag; /* Fragment number */
+ uint8_t h_i_fsize; /* Fragment size */
+ uint16_t h_i_mode_high;
+ uint16_t h_i_uid_high;
+ uint16_t h_i_gid_high;
+ uint32_t h_i_author;
+ } hurd2;
+ struct {
+ uint8_t m_i_frag; /* Fragment number */
+ uint8_t m_i_fsize; /* Fragment size */
+ uint16_t m_pad1;
+ uint32_t m_i_reserved2[2];
+ } masix2;
+ } osd2; /* OS dependent 2 */
+};
+
+/*
+ * Permanent part of an large inode on the disk
+ */
+struct ext2_inode_large {
+ uint16_t i_mode; /* File mode */
+ uint16_t i_uid; /* Low 16 bits of Owner Uid */
+ uint32_t i_size; /* Size in bytes */
+ uint32_t i_atime; /* Access time */
+ uint32_t i_ctime; /* Creation time */
+ uint32_t i_mtime; /* Modification time */
+ uint32_t i_dtime; /* Deletion Time */
+ uint16_t i_gid; /* Low 16 bits of Group Id */
+ uint16_t i_links_count; /* Links count */
+ uint32_t i_blocks; /* Blocks count */
+ uint32_t i_flags; /* File flags */
+ union {
+ struct {
+ uint32_t l_i_reserved1;
+ } linux1;
+ struct {
+ uint32_t h_i_translator;
+ } hurd1;
+ struct {
+ uint32_t m_i_reserved1;
+ } masix1;
+ } osd1; /* OS dependent 1 */
+ uint32_t i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
+ uint32_t i_generation; /* File version (for NFS) */
+ uint32_t i_file_acl; /* File ACL */
+ uint32_t i_dir_acl; /* Directory ACL */
+ uint32_t i_faddr; /* Fragment address */
+ union {
+ struct {
+ uint8_t l_i_frag; /* Fragment number */
+ uint8_t l_i_fsize; /* Fragment size */
+ uint16_t i_pad1;
+ uint16_t l_i_uid_high; /* these 2 fields */
+ uint16_t l_i_gid_high; /* were reserved2[0] */
+ uint32_t l_i_reserved2;
+ } linux2;
+ struct {
+ uint8_t h_i_frag; /* Fragment number */
+ uint8_t h_i_fsize; /* Fragment size */
+ uint16_t h_i_mode_high;
+ uint16_t h_i_uid_high;
+ uint16_t h_i_gid_high;
+ uint32_t h_i_author;
+ } hurd2;
+ struct {
+ uint8_t m_i_frag; /* Fragment number */
+ uint8_t m_i_fsize; /* Fragment size */
+ uint16_t m_pad1;
+ uint32_t m_i_reserved2[2];
+ } masix2;
+ } osd2; /* OS dependent 2 */
+ uint16_t i_extra_isize;
+ uint16_t i_pad1;
+};
+
+#define i_size_high i_dir_acl
+
+/*
+ * File system states
+ */
+#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */
+#define EXT2_ERROR_FS 0x0002 /* Errors detected */
+
+/*
+ * Mount flags
+ */
+#define EXT2_MOUNT_CHECK 0x0001 /* Do mount-time checks */
+#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */
+#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */
+#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */
+#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */
+#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */
+#define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */
+#define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */
+
+#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt
+#define set_opt(o, opt) o |= EXT2_MOUNT_##opt
+#define test_opt(sb, opt) (EXT2_SB(sb)->s_mount_opt & \
+ EXT2_MOUNT_##opt)
+/*
+ * Maximal mount counts between two filesystem checks
+ */
+#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */
+#define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */
+
+/*
+ * Behaviour when detecting errors
+ */
+#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */
+#define EXT2_ERRORS_RO 2 /* Remount fs read-only */
+#define EXT2_ERRORS_PANIC 3 /* Panic */
+#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE
+
+/*
+ * Structure of the super block
+ */
+struct ext2_super_block {
+ uint32_t s_inodes_count; /* Inodes count */
+ uint32_t s_blocks_count; /* Blocks count */
+ uint32_t s_r_blocks_count; /* Reserved blocks count */
+ uint32_t s_free_blocks_count; /* Free blocks count */
+ uint32_t s_free_inodes_count; /* Free inodes count */
+ uint32_t s_first_data_block; /* First Data Block */
+ uint32_t s_log_block_size; /* Block size */
+ int32_t s_log_frag_size; /* Fragment size */
+ uint32_t s_blocks_per_group; /* # Blocks per group */
+ uint32_t s_frags_per_group; /* # Fragments per group */
+ uint32_t s_inodes_per_group; /* # Inodes per group */
+ uint32_t s_mtime; /* Mount time */
+ uint32_t s_wtime; /* Write time */
+ uint16_t s_mnt_count; /* Mount count */
+ int16_t s_max_mnt_count; /* Maximal mount count */
+ uint16_t s_magic; /* Magic signature */
+ uint16_t s_state; /* File system state */
+ uint16_t s_errors; /* Behaviour when detecting errors */
+ uint16_t s_minor_rev_level; /* minor revision level */
+ uint32_t s_lastcheck; /* time of last check */
+ uint32_t s_checkinterval; /* max. time between checks */
+ uint32_t s_creator_os; /* OS */
+ uint32_t s_rev_level; /* Revision level */
+ uint16_t s_def_resuid; /* Default uid for reserved blocks */
+ uint16_t s_def_resgid; /* Default gid for reserved blocks */
+ /*
+ * These fields are for EXT2_DYNAMIC_REV superblocks only.
+ *
+ * Note: the difference between the compatible feature set and
+ * the incompatible feature set is that if there is a bit set
+ * in the incompatible feature set that the kernel doesn't
+ * know about, it should refuse to mount the filesystem.
+ *
+ * e2fsck's requirements are more strict; if it doesn't know
+ * about a feature in either the compatible or incompatible
+ * feature set, it must abort and not try to meddle with
+ * things it doesn't understand...
+ */
+ uint32_t s_first_ino; /* First non-reserved inode */
+ uint16_t s_inode_size; /* size of inode structure */
+ uint16_t s_block_group_nr; /* block group # of this superblock */
+ uint32_t s_feature_compat; /* compatible feature set */
+ uint32_t s_feature_incompat; /* incompatible feature set */
+ uint32_t s_feature_ro_compat; /* readonly-compatible feature set */
+ uint8_t s_uuid[16]; /* 128-bit uuid for volume */
+ char s_volume_name[16]; /* volume name */
+ char s_last_mounted[64]; /* directory where last mounted */
+ uint32_t s_algorithm_usage_bitmap; /* For compression */
+ /*
+ * Performance hints. Directory preallocation should only
+ * happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on.
+ */
+ uint8_t s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
+ uint8_t s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
+ uint16_t s_reserved_gdt_blocks; /* Per group table for online growth */
+ /*
+ * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set.
+ */
+ uint8_t s_journal_uuid[16]; /* uuid of journal superblock */
+ uint32_t s_journal_inum; /* inode number of journal file */
+ uint32_t s_journal_dev; /* device number of journal file */
+ uint32_t s_last_orphan; /* start of list of inodes to delete */
+ uint32_t s_hash_seed[4]; /* HTREE hash seed */
+ uint8_t s_def_hash_version; /* Default hash version to use */
+ uint8_t s_jnl_backup_type; /* Default type of journal backup */
+ uint16_t s_reserved_word_pad;
+ uint32_t s_default_mount_opts;
+ uint32_t s_first_meta_bg; /* First metablock group */
+ uint32_t s_mkfs_time; /* When the filesystem was created */
+ uint32_t s_jnl_blocks[17]; /* Backup of the journal inode */
+ uint32_t s_reserved[172]; /* Padding to the end of the block */
+};
+
+/*
+ * Codes for operating systems
+ */
+#define EXT2_OS_LINUX 0
+#define EXT2_OS_HURD 1
+#define EXT2_OS_MASIX 2
+#define EXT2_OS_FREEBSD 3
+#define EXT2_OS_LITES 4
+
+/*
+ * Revision levels
+ */
+#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */
+#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */
+
+#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV
+#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV
+
+#define EXT2_GOOD_OLD_INODE_SIZE 128
+
+/*
+ * Journal inode backup types
+ */
+#define EXT3_JNL_BACKUP_BLOCKS 1
+
+/*
+ * Feature set definitions
+ */
+
+#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_feature_compat & (mask) )
+#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_feature_ro_compat & (mask) )
+#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_feature_incompat & (mask) )
+
+#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
+#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
+#define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008
+#define EXT2_FEATURE_COMPAT_RESIZE_INODE 0x0010
+#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020
+
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
+#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
+/* #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 not used */
+
+#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
+#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
+#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */
+#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
+#define EXT3_FEATURE_INCOMPAT_EXTENTS 0x0040
+
+
+#define EXT2_FEATURE_COMPAT_SUPP 0
+#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE)
+#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
+ EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
+
+/*
+ * Default values for user and/or group using reserved blocks
+ */
+#define EXT2_DEF_RESUID 0
+#define EXT2_DEF_RESGID 0
+
+/*
+ * Default mount options
+ */
+#define EXT2_DEFM_DEBUG 0x0001
+#define EXT2_DEFM_BSDGROUPS 0x0002
+#define EXT2_DEFM_XATTR_USER 0x0004
+#define EXT2_DEFM_ACL 0x0008
+#define EXT2_DEFM_UID16 0x0010
+#define EXT3_DEFM_JMODE 0x0060
+#define EXT3_DEFM_JMODE_DATA 0x0020
+#define EXT3_DEFM_JMODE_ORDERED 0x0040
+#define EXT3_DEFM_JMODE_WBACK 0x0060
+
+/*
+ * Structure of a directory entry
+ */
+#define EXT2_NAME_LEN 255
+
+struct ext2_dir_entry {
+ uint32_t inode; /* Inode number */
+ uint16_t rec_len; /* Directory entry length */
+ uint16_t name_len; /* Name length */
+ char name[EXT2_NAME_LEN]; /* File name */
+};
+
+/*
+ * The new version of the directory entry. Since EXT2 structures are
+ * stored in intel byte order, and the name_len field could never be
+ * bigger than 255 chars, it's safe to reclaim the extra byte for the
+ * file_type field.
+ */
+struct ext2_dir_entry_2 {
+ uint32_t inode; /* Inode number */
+ uint16_t rec_len; /* Directory entry length */
+ uint8_t name_len; /* Name length */
+ uint8_t file_type;
+ char name[EXT2_NAME_LEN]; /* File name */
+};
+
+/*
+ * Ext2 directory file types. Only the low 3 bits are used. The
+ * other bits are reserved for now.
+ */
+#define EXT2_FT_UNKNOWN 0
+#define EXT2_FT_REG_FILE 1
+#define EXT2_FT_DIR 2
+#define EXT2_FT_CHRDEV 3
+#define EXT2_FT_BLKDEV 4
+#define EXT2_FT_FIFO 5
+#define EXT2_FT_SOCK 6
+#define EXT2_FT_SYMLINK 7
+
+#define EXT2_FT_MAX 8
+
+/*
+ * EXT2_DIR_PAD defines the directory entries boundaries
+ *
+ * NOTE: It must be a multiple of 4
+ */
+#define EXT2_DIR_PAD 4
+#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
+#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
+ ~EXT2_DIR_ROUND)
+
+#endif /* _LINUX_EXT2_FS_H */
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/e2fs_lib.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/e2fs_lib.c
new file mode 100644
index 0000000000..839109e3f7
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/e2fs_lib.c
@@ -0,0 +1,227 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * See README for additional information
+ *
+ * This file can be redistributed under the terms of the GNU Library General
+ * Public License
+ */
+
+#include "libbb.h"
+#include "e2fs_lib.h"
+
+#define HAVE_EXT2_IOCTLS 1
+
+#if INT_MAX == LONG_MAX
+#define IF_LONG_IS_SAME(...) __VA_ARGS__
+#define IF_LONG_IS_WIDER(...)
+#else
+#define IF_LONG_IS_SAME(...)
+#define IF_LONG_IS_WIDER(...) __VA_ARGS__
+#endif
+
+static void close_silently(int fd)
+{
+ int e = errno;
+ close(fd);
+ errno = e;
+}
+
+
+/* Iterate a function on each entry of a directory */
+int iterate_on_dir(const char *dir_name,
+ int (*func)(const char *, struct dirent *, void *),
+ void * private)
+{
+ DIR *dir;
+ struct dirent *de, *dep;
+ int max_len, len;
+
+ max_len = PATH_MAX + sizeof(struct dirent);
+ de = xmalloc(max_len+1);
+ memset(de, 0, max_len+1);
+
+ dir = opendir(dir_name);
+ if (dir == NULL) {
+ free(de);
+ return -1;
+ }
+ while ((dep = readdir(dir))) {
+ len = sizeof(struct dirent);
+ if (len < dep->d_reclen)
+ len = dep->d_reclen;
+ if (len > max_len)
+ len = max_len;
+ memcpy(de, dep, len);
+ func(dir_name, de, private);
+ }
+ closedir(dir);
+ free(de);
+ return 0;
+}
+
+
+/* Get/set a file version on an ext2 file system */
+int fgetsetversion(const char *name, unsigned long *get_version, unsigned long set_version)
+{
+#if HAVE_EXT2_IOCTLS
+ int fd, r;
+ IF_LONG_IS_WIDER(int ver;)
+
+ fd = open(name, O_NONBLOCK);
+ if (fd == -1)
+ return -1;
+ if (!get_version) {
+ IF_LONG_IS_WIDER(
+ ver = (int) set_version;
+ r = ioctl(fd, EXT2_IOC_SETVERSION, &ver);
+ )
+ IF_LONG_IS_SAME(
+ r = ioctl(fd, EXT2_IOC_SETVERSION, (void*)&set_version);
+ )
+ } else {
+ IF_LONG_IS_WIDER(
+ r = ioctl(fd, EXT2_IOC_GETVERSION, &ver);
+ *get_version = ver;
+ )
+ IF_LONG_IS_SAME(
+ r = ioctl(fd, EXT2_IOC_GETVERSION, (void*)get_version);
+ )
+ }
+ close_silently(fd);
+ return r;
+#else /* ! HAVE_EXT2_IOCTLS */
+ errno = EOPNOTSUPP;
+ return -1;
+#endif /* ! HAVE_EXT2_IOCTLS */
+}
+
+
+/* Get/set a file flags on an ext2 file system */
+int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_flags)
+{
+#if HAVE_EXT2_IOCTLS
+ struct stat buf;
+ int fd, r;
+ IF_LONG_IS_WIDER(int f;)
+
+ if (stat(name, &buf) == 0 /* stat is ok */
+ && !S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)
+ ) {
+ goto notsupp;
+ }
+ fd = open(name, O_NONBLOCK); /* neither read nor write asked for */
+ if (fd == -1)
+ return -1;
+
+ if (!get_flags) {
+ IF_LONG_IS_WIDER(
+ f = (int) set_flags;
+ r = ioctl(fd, EXT2_IOC_SETFLAGS, &f);
+ )
+ IF_LONG_IS_SAME(
+ r = ioctl(fd, EXT2_IOC_SETFLAGS, (void*)&set_flags);
+ )
+ } else {
+ IF_LONG_IS_WIDER(
+ r = ioctl(fd, EXT2_IOC_GETFLAGS, &f);
+ *get_flags = f;
+ )
+ IF_LONG_IS_SAME(
+ r = ioctl(fd, EXT2_IOC_GETFLAGS, (void*)get_flags);
+ )
+ }
+
+ close_silently(fd);
+ return r;
+ notsupp:
+#endif /* HAVE_EXT2_IOCTLS */
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+
+/* Print file attributes on an ext2 file system */
+const uint32_t e2attr_flags_value[] = {
+#ifdef ENABLE_COMPRESSION
+ EXT2_COMPRBLK_FL,
+ EXT2_DIRTY_FL,
+ EXT2_NOCOMPR_FL,
+ EXT2_ECOMPR_FL,
+#endif
+ EXT2_INDEX_FL,
+ EXT2_SECRM_FL,
+ EXT2_UNRM_FL,
+ EXT2_SYNC_FL,
+ EXT2_DIRSYNC_FL,
+ EXT2_IMMUTABLE_FL,
+ EXT2_APPEND_FL,
+ EXT2_NODUMP_FL,
+ EXT2_NOATIME_FL,
+ EXT2_COMPR_FL,
+ EXT3_JOURNAL_DATA_FL,
+ EXT2_NOTAIL_FL,
+ EXT2_TOPDIR_FL
+};
+
+const char e2attr_flags_sname[] =
+#ifdef ENABLE_COMPRESSION
+ "BZXE"
+#endif
+ "I"
+ "suSDiadAcjtT";
+
+static const char e2attr_flags_lname[] =
+#ifdef ENABLE_COMPRESSION
+ "Compressed_File" "\0"
+ "Compressed_Dirty_File" "\0"
+ "Compression_Raw_Access" "\0"
+ "Compression_Error" "\0"
+#endif
+ "Indexed_directory" "\0"
+ "Secure_Deletion" "\0"
+ "Undelete" "\0"
+ "Synchronous_Updates" "\0"
+ "Synchronous_Directory_Updates" "\0"
+ "Immutable" "\0"
+ "Append_Only" "\0"
+ "No_Dump" "\0"
+ "No_Atime" "\0"
+ "Compression_Requested" "\0"
+ "Journaled_Data" "\0"
+ "No_Tailmerging" "\0"
+ "Top_of_Directory_Hierarchies" "\0"
+ /* Another trailing NUL is added by compiler */;
+
+void print_e2flags(FILE *f, unsigned long flags, unsigned options)
+{
+ const uint32_t *fv;
+ const char *fn;
+
+ fv = e2attr_flags_value;
+ if (options & PFOPT_LONG) {
+ int first = 1;
+ fn = e2attr_flags_lname;
+ do {
+ if (flags & *fv) {
+ if (!first)
+ fputs(", ", f);
+ fputs(fn, f);
+ first = 0;
+ }
+ fv++;
+ fn += strlen(fn) + 1;
+ } while (*fn);
+ if (first)
+ fputs("---", f);
+ } else {
+ fn = e2attr_flags_sname;
+ do {
+ char c = '-';
+ if (flags & *fv)
+ c = *fn;
+ fputc(c, f);
+ fv++;
+ fn++;
+ } while (*fn);
+ }
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/e2fs_lib.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/e2fs_lib.h
new file mode 100644
index 0000000000..e21a0f917e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/e2fs_lib.h
@@ -0,0 +1,51 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * See README for additional information
+ *
+ * This file can be redistributed under the terms of the GNU Library General
+ * Public License
+ */
+
+/* Constants and structures */
+#include "e2fs_defs.h"
+
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility push(hidden)
+#endif
+
+/* Iterate a function on each entry of a directory */
+int iterate_on_dir(const char *dir_name,
+ int (*func)(const char *, struct dirent *, void *),
+ void *private);
+
+/* Get/set a file version on an ext2 file system */
+int fgetsetversion(const char *name, unsigned long *get_version, unsigned long set_version);
+#define fgetversion(name, version) fgetsetversion(name, version, 0)
+#define fsetversion(name, version) fgetsetversion(name, NULL, version)
+
+/* Get/set a file flags on an ext2 file system */
+int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_flags);
+#define fgetflags(name, flags) fgetsetflags(name, flags, 0)
+#define fsetflags(name, flags) fgetsetflags(name, NULL, flags)
+
+/* Must be 1 for compatibility with `int long_format'. */
+#define PFOPT_LONG 1
+/* Print file attributes on an ext2 file system */
+void print_e2flags(FILE *f, unsigned long flags, unsigned options);
+
+extern const uint32_t e2attr_flags_value[];
+extern const char e2attr_flags_sname[];
+
+/* If you plan to ENABLE_COMPRESSION, see e2fs_lib.c and chattr.c - */
+/* make sure that chattr doesn't accept bad options! */
+#ifdef ENABLE_COMPRESSION
+#define e2attr_flags_value_chattr (&e2attr_flags_value[5])
+#define e2attr_flags_sname_chattr (&e2attr_flags_sname[5])
+#else
+#define e2attr_flags_value_chattr (&e2attr_flags_value[1])
+#define e2attr_flags_sname_chattr (&e2attr_flags_sname[1])
+#endif
+
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility pop
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/fsck.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/fsck.c
new file mode 100644
index 0000000000..0707d295dd
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/fsck.c
@@ -0,0 +1,1187 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * fsck --- A generic, parallelizing front-end for the fsck program.
+ * It will automatically try to run fsck programs in parallel if the
+ * devices are on separate spindles. It is based on the same ideas as
+ * the generic front end for fsck by David Engel and Fred van Kempen,
+ * but it has been completely rewritten from scratch to support
+ * parallel execution.
+ *
+ * Written by Theodore Ts'o, <tytso@mit.edu>
+ *
+ * Miquel van Smoorenburg (miquels@drinkel.ow.org) 20-Oct-1994:
+ * o Changed -t fstype to behave like with mount when -A (all file
+ * systems) or -M (like mount) is specified.
+ * o fsck looks if it can find the fsck.type program to decide
+ * if it should ignore the fs type. This way more fsck programs
+ * can be added without changing this front-end.
+ * o -R flag skip root file system.
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+ * 2001, 2002, 2003, 2004, 2005 by Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+/* All filesystem specific hooks have been removed.
+ * If filesystem cannot be determined, we will execute
+ * "fsck.auto". Currently this also happens if you specify
+ * UUID=xxx or LABEL=xxx as an object to check.
+ * Detection code for that is also probably has to be in fsck.auto.
+ *
+ * In other words, this is _really_ is just a driver program which
+ * spawns actual fsck.something for each filesystem to check.
+ * It doesn't guess filesystem types from on-disk format.
+ */
+
+#include "libbb.h"
+
+/* "progress indicator" code is somewhat buggy and ext[23] specific.
+ * We should be filesystem agnostic. IOW: there should be a well-defined
+ * API for fsck.something, NOT ad-hoc hacks in generic fsck. */
+#define DO_PROGRESS_INDICATOR 0
+
+#define EXIT_OK 0
+#define EXIT_NONDESTRUCT 1
+#define EXIT_DESTRUCT 2
+#define EXIT_UNCORRECTED 4
+#define EXIT_ERROR 8
+#define EXIT_USAGE 16
+#define FSCK_CANCELED 32 /* Aborted with a signal or ^C */
+
+/*
+ * Internal structure for mount table entries.
+ */
+
+struct fs_info {
+ struct fs_info *next;
+ char *device;
+ char *mountpt;
+ char *type;
+ char *opts;
+ int passno;
+ int flags;
+};
+
+#define FLAG_DONE 1
+#define FLAG_PROGRESS 2
+/*
+ * Structure to allow exit codes to be stored
+ */
+struct fsck_instance {
+ struct fsck_instance *next;
+ int pid;
+ int flags;
+#if DO_PROGRESS_INDICATOR
+ time_t start_time;
+#endif
+ char *prog;
+ char *device;
+ char *base_device; /* /dev/hda for /dev/hdaN etc */
+};
+
+static const char ignored_types[] ALIGN1 =
+ "ignore\0"
+ "iso9660\0"
+ "nfs\0"
+ "proc\0"
+ "sw\0"
+ "swap\0"
+ "tmpfs\0"
+ "devpts\0";
+
+#if 0
+static const char really_wanted[] ALIGN1 =
+ "minix\0"
+ "ext2\0"
+ "ext3\0"
+ "jfs\0"
+ "reiserfs\0"
+ "xiafs\0"
+ "xfs\0";
+#endif
+
+#define BASE_MD "/dev/md"
+
+static char **devices;
+static char **args;
+static int num_devices;
+static int num_args;
+static int verbose;
+
+#define FS_TYPE_FLAG_NORMAL 0
+#define FS_TYPE_FLAG_OPT 1
+#define FS_TYPE_FLAG_NEGOPT 2
+static char **fs_type_list;
+static uint8_t *fs_type_flag;
+static smallint fs_type_negated;
+
+static volatile smallint cancel_requested;
+static smallint doall;
+static smallint noexecute;
+static smallint serialize;
+static smallint skip_root;
+/* static smallint like_mount; */
+static smallint notitle;
+static smallint parallel_root;
+static smallint force_all_parallel;
+
+#if DO_PROGRESS_INDICATOR
+static smallint progress;
+static int progress_fd;
+#endif
+
+static int num_running;
+static int max_running;
+static char *fstype;
+static struct fs_info *filesys_info;
+static struct fs_info *filesys_last;
+static struct fsck_instance *instance_list;
+
+/*
+ * Return the "base device" given a particular device; this is used to
+ * assure that we only fsck one partition on a particular drive at any
+ * one time. Otherwise, the disk heads will be seeking all over the
+ * place. If the base device cannot be determined, return NULL.
+ *
+ * The base_device() function returns an allocated string which must
+ * be freed.
+ */
+#if ENABLE_FEATURE_DEVFS
+/*
+ * Required for the uber-silly devfs /dev/ide/host1/bus2/target3/lun3
+ * pathames.
+ */
+static const char *const devfs_hier[] = {
+ "host", "bus", "target", "lun", NULL
+};
+#endif
+
+static char *base_device(const char *device)
+{
+ char *str, *cp;
+#if ENABLE_FEATURE_DEVFS
+ const char *const *hier;
+ const char *disk;
+ int len;
+#endif
+ cp = str = xstrdup(device);
+
+ /* Skip over /dev/; if it's not present, give up. */
+ if (strncmp(cp, "/dev/", 5) != 0)
+ goto errout;
+ cp += 5;
+
+ /*
+ * For md devices, we treat them all as if they were all
+ * on one disk, since we don't know how to parallelize them.
+ */
+ if (cp[0] == 'm' && cp[1] == 'd') {
+ cp[2] = 0;
+ return str;
+ }
+
+ /* Handle DAC 960 devices */
+ if (strncmp(cp, "rd/", 3) == 0) {
+ cp += 3;
+ if (cp[0] != 'c' || !isdigit(cp[1])
+ || cp[2] != 'd' || !isdigit(cp[3]))
+ goto errout;
+ cp[4] = 0;
+ return str;
+ }
+
+ /* Now let's handle /dev/hd* and /dev/sd* devices.... */
+ if ((cp[0] == 'h' || cp[0] == 's') && cp[1] == 'd') {
+ cp += 2;
+ /* If there's a single number after /dev/hd, skip it */
+ if (isdigit(*cp))
+ cp++;
+ /* What follows must be an alpha char, or give up */
+ if (!isalpha(*cp))
+ goto errout;
+ cp[1] = 0;
+ return str;
+ }
+
+#if ENABLE_FEATURE_DEVFS
+ /* Now let's handle devfs (ugh) names */
+ len = 0;
+ if (strncmp(cp, "ide/", 4) == 0)
+ len = 4;
+ if (strncmp(cp, "scsi/", 5) == 0)
+ len = 5;
+ if (len) {
+ cp += len;
+ /*
+ * Now we proceed down the expected devfs hierarchy.
+ * i.e., .../host1/bus2/target3/lun4/...
+ * If we don't find the expected token, followed by
+ * some number of digits at each level, abort.
+ */
+ for (hier = devfs_hier; *hier; hier++) {
+ len = strlen(*hier);
+ if (strncmp(cp, *hier, len) != 0)
+ goto errout;
+ cp += len;
+ while (*cp != '/' && *cp != 0) {
+ if (!isdigit(*cp))
+ goto errout;
+ cp++;
+ }
+ cp++;
+ }
+ cp[-1] = 0;
+ return str;
+ }
+
+ /* Now handle devfs /dev/disc or /dev/disk names */
+ disk = 0;
+ if (strncmp(cp, "discs/", 6) == 0)
+ disk = "disc";
+ else if (strncmp(cp, "disks/", 6) == 0)
+ disk = "disk";
+ if (disk) {
+ cp += 6;
+ if (strncmp(cp, disk, 4) != 0)
+ goto errout;
+ cp += 4;
+ while (*cp != '/' && *cp != 0) {
+ if (!isdigit(*cp))
+ goto errout;
+ cp++;
+ }
+ *cp = 0;
+ return str;
+ }
+#endif
+ errout:
+ free(str);
+ return NULL;
+}
+
+static void free_instance(struct fsck_instance *p)
+{
+ free(p->prog);
+ free(p->device);
+ free(p->base_device);
+ free(p);
+}
+
+static struct fs_info *create_fs_device(const char *device, const char *mntpnt,
+ const char *type, const char *opts,
+ int passno)
+{
+ struct fs_info *fs;
+
+ fs = xzalloc(sizeof(*fs));
+ fs->device = xstrdup(device);
+ fs->mountpt = xstrdup(mntpnt);
+ fs->type = xstrdup(type);
+ fs->opts = xstrdup(opts ? opts : "");
+ fs->passno = passno;
+ /*fs->flags = 0; */
+ /*fs->next = NULL; */
+
+ if (!filesys_info)
+ filesys_info = fs;
+ else
+ filesys_last->next = fs;
+ filesys_last = fs;
+
+ return fs;
+}
+
+static void strip_line(char *line)
+{
+ char *p = line + strlen(line) - 1;
+
+ while (*line) {
+ if (*p != '\n' && *p != '\r')
+ break;
+ *p-- = '\0';
+ }
+}
+
+static char *parse_word(char **buf)
+{
+ char *word, *next;
+
+ word = *buf;
+ if (*word == '\0')
+ return NULL;
+
+ word = skip_whitespace(word);
+ next = skip_non_whitespace(word);
+ if (*next)
+ *next++ = '\0';
+ *buf = next;
+ return word;
+}
+
+static void parse_escape(char *word)
+{
+ char *q, c;
+ const char *p;
+
+ if (!word)
+ return;
+
+ for (p = q = word; *p; q++) {
+ c = *p++;
+ if (c != '\\') {
+ *q = c;
+ } else {
+ *q = bb_process_escape_sequence(&p);
+ }
+ }
+ *q = '\0';
+}
+
+static int parse_fstab_line(char *line, struct fs_info **ret_fs)
+{
+ char *device, *mntpnt, *type, *opts, *passno, *cp;
+ struct fs_info *fs;
+
+ *ret_fs = NULL;
+ strip_line(line);
+ *strchrnul(line, '#') = '\0'; /* Ignore everything after comment */
+ cp = line;
+
+ device = parse_word(&cp);
+ if (!device) return 0; /* Allow blank lines */
+ mntpnt = parse_word(&cp);
+ type = parse_word(&cp);
+ opts = parse_word(&cp);
+ /*freq =*/ parse_word(&cp);
+ passno = parse_word(&cp);
+
+ if (!mntpnt || !type)
+ return -1;
+
+ parse_escape(device);
+ parse_escape(mntpnt);
+ parse_escape(type);
+ parse_escape(opts);
+ parse_escape(passno);
+
+ if (strchr(type, ','))
+ type = NULL;
+
+ fs = create_fs_device(device, mntpnt, type ? type : "auto", opts,
+ (passno ? atoi(passno) : -1));
+ *ret_fs = fs;
+ return 0;
+}
+
+/* Load the filesystem database from /etc/fstab */
+static void load_fs_info(const char *filename)
+{
+ FILE *f;
+ int lineno = 0;
+ int old_fstab = 1;
+ struct fs_info *fs;
+
+ f = fopen_or_warn(filename, "r");
+ if (f == NULL) {
+ return;
+ }
+ while (1) {
+ int r;
+ char *buf = xmalloc_fgetline(f);
+ if (!buf) break;
+ r = parse_fstab_line(buf, &fs);
+ free(buf);
+ lineno++;
+ if (r < 0) {
+ bb_error_msg("WARNING: bad format "
+ "on line %d of %s", lineno, filename);
+ continue;
+ }
+ if (!fs)
+ continue;
+ if (fs->passno < 0)
+ fs->passno = 0;
+ else
+ old_fstab = 0;
+ }
+ fclose(f);
+
+ if (old_fstab) {
+ fputs("\007"
+"WARNING: Your /etc/fstab does not contain the fsck passno field.\n"
+"I will kludge around things for you, but you should fix\n"
+"your /etc/fstab file as soon as you can.\n\n", stderr);
+ for (fs = filesys_info; fs; fs = fs->next) {
+ fs->passno = 1;
+ }
+ }
+}
+
+/* Lookup filesys in /etc/fstab and return the corresponding entry. */
+static struct fs_info *lookup(char *filesys)
+{
+ struct fs_info *fs;
+
+ for (fs = filesys_info; fs; fs = fs->next) {
+ if (strcmp(filesys, fs->device) == 0
+ || (fs->mountpt && strcmp(filesys, fs->mountpt) == 0)
+ )
+ break;
+ }
+
+ return fs;
+}
+
+#if DO_PROGRESS_INDICATOR
+static int progress_active(void)
+{
+ struct fsck_instance *inst;
+
+ for (inst = instance_list; inst; inst = inst->next) {
+ if (inst->flags & FLAG_DONE)
+ continue;
+ if (inst->flags & FLAG_PROGRESS)
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+
+/*
+ * Send a signal to all outstanding fsck child processes
+ */
+static void kill_all_if_cancel_requested(void)
+{
+ static smallint kill_sent;
+
+ struct fsck_instance *inst;
+
+ if (!cancel_requested || kill_sent)
+ return;
+
+ for (inst = instance_list; inst; inst = inst->next) {
+ if (inst->flags & FLAG_DONE)
+ continue;
+ kill(inst->pid, SIGTERM);
+ }
+ kill_sent = 1;
+}
+
+/*
+ * Wait for one child process to exit; when it does, unlink it from
+ * the list of executing child processes, free, and return its exit status.
+ * If there is no exited child, return -1.
+ */
+static int wait_one(int flags)
+{
+ int status;
+ int sig;
+ struct fsck_instance *inst, *prev;
+ pid_t pid;
+
+ if (!instance_list)
+ return -1;
+ /* if (noexecute) { already returned -1; } */
+
+ while (1) {
+ pid = waitpid(-1, &status, flags);
+ kill_all_if_cancel_requested();
+ if (pid == 0) /* flags == WNOHANG and no children exited */
+ return -1;
+ if (pid < 0) {
+ if (errno == EINTR)
+ continue;
+ if (errno == ECHILD) { /* paranoia */
+ bb_error_msg("wait: no more children");
+ return -1;
+ }
+ bb_perror_msg("wait");
+ continue;
+ }
+ prev = NULL;
+ inst = instance_list;
+ do {
+ if (inst->pid == pid)
+ goto child_died;
+ prev = inst;
+ inst = inst->next;
+ } while (inst);
+ }
+ child_died:
+
+ if (WIFEXITED(status))
+ status = WEXITSTATUS(status);
+ else if (WIFSIGNALED(status)) {
+ sig = WTERMSIG(status);
+ status = EXIT_UNCORRECTED;
+ if (sig != SIGINT) {
+ printf("Warning: %s %s terminated "
+ "by signal %d\n",
+ inst->prog, inst->device, sig);
+ status = EXIT_ERROR;
+ }
+ } else {
+ printf("%s %s: status is %x, should never happen\n",
+ inst->prog, inst->device, status);
+ status = EXIT_ERROR;
+ }
+
+#if DO_PROGRESS_INDICATOR
+ if (progress && (inst->flags & FLAG_PROGRESS) && !progress_active()) {
+ struct fsck_instance *inst2;
+ for (inst2 = instance_list; inst2; inst2 = inst2->next) {
+ if (inst2->flags & FLAG_DONE)
+ continue;
+ if (strcmp(inst2->type, "ext2") != 0
+ && strcmp(inst2->type, "ext3") != 0
+ ) {
+ continue;
+ }
+ /* ext[23], we will send USR1
+ * (request to start displaying progress bar)
+ *
+ * If we've just started the fsck, wait a tiny
+ * bit before sending the kill, to give it
+ * time to set up the signal handler
+ */
+ if (inst2->start_time >= time(NULL) - 1)
+ sleep(1);
+ kill(inst2->pid, SIGUSR1);
+ inst2->flags |= FLAG_PROGRESS;
+ break;
+ }
+ }
+#endif
+
+ if (prev)
+ prev->next = inst->next;
+ else
+ instance_list = inst->next;
+ if (verbose > 1)
+ printf("Finished with %s (exit status %d)\n",
+ inst->device, status);
+ num_running--;
+ free_instance(inst);
+
+ return status;
+}
+
+/*
+ * Wait until all executing child processes have exited; return the
+ * logical OR of all of their exit code values.
+ */
+#define FLAG_WAIT_ALL 0
+#define FLAG_WAIT_ATLEAST_ONE WNOHANG
+static int wait_many(int flags)
+{
+ int exit_status;
+ int global_status = 0;
+ int wait_flags = 0;
+
+ while ((exit_status = wait_one(wait_flags)) != -1) {
+ global_status |= exit_status;
+ wait_flags |= flags;
+ }
+ return global_status;
+}
+
+/*
+ * Execute a particular fsck program, and link it into the list of
+ * child processes we are waiting for.
+ */
+static void execute(const char *type, const char *device,
+ const char *mntpt /*, int interactive */)
+{
+ char *argv[num_args + 4]; /* see count below: */
+ int argc;
+ int i;
+ struct fsck_instance *inst;
+ pid_t pid;
+
+ argv[0] = xasprintf("fsck.%s", type); /* 1 */
+ for (i = 0; i < num_args; i++)
+ argv[i+1] = args[i]; /* num_args */
+ argc = num_args + 1;
+
+#if DO_PROGRESS_INDICATOR
+ if (progress && !progress_active()) {
+ if (strcmp(type, "ext2") == 0
+ || strcmp(type, "ext3") == 0
+ ) {
+ argv[argc++] = xasprintf("-C%d", progress_fd); /* 1 */
+ inst->flags |= FLAG_PROGRESS;
+ }
+ }
+#endif
+
+ argv[argc++] = (char*)device; /* 1 */
+ argv[argc] = NULL; /* 1 */
+
+ if (verbose || noexecute) {
+ printf("[%s (%d) -- %s]", argv[0], num_running,
+ mntpt ? mntpt : device);
+ for (i = 0; i < argc; i++)
+ printf(" %s", argv[i]);
+ bb_putchar('\n');
+ }
+
+ /* Fork and execute the correct program. */
+ pid = -1;
+ if (!noexecute) {
+ pid = spawn(argv);
+ if (pid < 0)
+ bb_simple_perror_msg(argv[0]);
+ }
+
+#if DO_PROGRESS_INDICATOR
+ free(argv[num_args + 1]);
+#endif
+
+ /* No child, so don't record an instance */
+ if (pid <= 0) {
+ free(argv[0]);
+ return;
+ }
+
+ inst = xzalloc(sizeof(*inst));
+ inst->pid = pid;
+ inst->prog = argv[0];
+ inst->device = xstrdup(device);
+ inst->base_device = base_device(device);
+#if DO_PROGRESS_INDICATOR
+ inst->start_time = time(NULL);
+#endif
+
+ /* Add to the list of running fsck's.
+ * (was adding to the end, but adding to the front is simpler...) */
+ inst->next = instance_list;
+ instance_list = inst;
+}
+
+/*
+ * Run the fsck program on a particular device
+ *
+ * If the type is specified using -t, and it isn't prefixed with "no"
+ * (as in "noext2") and only one filesystem type is specified, then
+ * use that type regardless of what is specified in /etc/fstab.
+ *
+ * If the type isn't specified by the user, then use either the type
+ * specified in /etc/fstab, or "auto".
+ */
+static void fsck_device(struct fs_info *fs /*, int interactive */)
+{
+ const char *type;
+
+ if (strcmp(fs->type, "auto") != 0) {
+ type = fs->type;
+ if (verbose > 2)
+ bb_info_msg("using filesystem type '%s' %s",
+ type, "from fstab");
+ } else if (fstype
+ && (fstype[0] != 'n' || fstype[1] != 'o') /* != "no" */
+ && strncmp(fstype, "opts=", 5) != 0
+ && strncmp(fstype, "loop", 4) != 0
+ && !strchr(fstype, ',')
+ ) {
+ type = fstype;
+ if (verbose > 2)
+ bb_info_msg("using filesystem type '%s' %s",
+ type, "from -t");
+ } else {
+ type = "auto";
+ if (verbose > 2)
+ bb_info_msg("using filesystem type '%s' %s",
+ type, "(default)");
+ }
+
+ num_running++;
+ execute(type, fs->device, fs->mountpt /*, interactive */);
+}
+
+/*
+ * Returns TRUE if a partition on the same disk is already being
+ * checked.
+ */
+static int device_already_active(char *device)
+{
+ struct fsck_instance *inst;
+ char *base;
+
+ if (force_all_parallel)
+ return 0;
+
+#ifdef BASE_MD
+ /* Don't check a soft raid disk with any other disk */
+ if (instance_list
+ && (!strncmp(instance_list->device, BASE_MD, sizeof(BASE_MD)-1)
+ || !strncmp(device, BASE_MD, sizeof(BASE_MD)-1))
+ ) {
+ return 1;
+ }
+#endif
+
+ base = base_device(device);
+ /*
+ * If we don't know the base device, assume that the device is
+ * already active if there are any fsck instances running.
+ */
+ if (!base)
+ return (instance_list != NULL);
+
+ for (inst = instance_list; inst; inst = inst->next) {
+ if (!inst->base_device || !strcmp(base, inst->base_device)) {
+ free(base);
+ return 1;
+ }
+ }
+
+ free(base);
+ return 0;
+}
+
+/*
+ * This function returns true if a particular option appears in a
+ * comma-delimited options list
+ */
+static int opt_in_list(char *opt, char *optlist)
+{
+ char *s;
+ int len;
+
+ if (!optlist)
+ return 0;
+
+ len = strlen(opt);
+ s = optlist - 1;
+ while (1) {
+ s = strstr(s + 1, opt);
+ if (!s)
+ return 0;
+ /* neither "opt.." nor "xxx,opt.."? */
+ if (s != optlist && s[-1] != ',')
+ continue;
+ /* neither "..opt" nor "..opt,xxx"? */
+ if (s[len] != '\0' && s[len] != ',')
+ continue;
+ return 1;
+ }
+}
+
+/* See if the filesystem matches the criteria given by the -t option */
+static int fs_match(struct fs_info *fs)
+{
+ int n, ret, checked_type;
+ char *cp;
+
+ if (!fs_type_list)
+ return 1;
+
+ ret = 0;
+ checked_type = 0;
+ n = 0;
+ while (1) {
+ cp = fs_type_list[n];
+ if (!cp)
+ break;
+ switch (fs_type_flag[n]) {
+ case FS_TYPE_FLAG_NORMAL:
+ checked_type++;
+ if (strcmp(cp, fs->type) == 0)
+ ret = 1;
+ break;
+ case FS_TYPE_FLAG_NEGOPT:
+ if (opt_in_list(cp, fs->opts))
+ return 0;
+ break;
+ case FS_TYPE_FLAG_OPT:
+ if (!opt_in_list(cp, fs->opts))
+ return 0;
+ break;
+ }
+ n++;
+ }
+ if (checked_type == 0)
+ return 1;
+
+ return (fs_type_negated ? !ret : ret);
+}
+
+/* Check if we should ignore this filesystem. */
+static int ignore(struct fs_info *fs)
+{
+ /*
+ * If the pass number is 0, ignore it.
+ */
+ if (fs->passno == 0)
+ return 1;
+
+ /*
+ * If a specific fstype is specified, and it doesn't match,
+ * ignore it.
+ */
+ if (!fs_match(fs))
+ return 1;
+
+ /* Are we ignoring this type? */
+ if (index_in_strings(ignored_types, fs->type) >= 0)
+ return 1;
+
+ /* We can and want to check this file system type. */
+ return 0;
+}
+
+/* Check all file systems, using the /etc/fstab table. */
+static int check_all(void)
+{
+ struct fs_info *fs;
+ int status = EXIT_OK;
+ smallint not_done_yet;
+ smallint pass_done;
+ int passno;
+
+ if (verbose)
+ puts("Checking all filesystems");
+
+ /*
+ * Do an initial scan over the filesystem; mark filesystems
+ * which should be ignored as done, and resolve any "auto"
+ * filesystem types (done as a side-effect of calling ignore()).
+ */
+ for (fs = filesys_info; fs; fs = fs->next)
+ if (ignore(fs))
+ fs->flags |= FLAG_DONE;
+
+ /*
+ * Find and check the root filesystem.
+ */
+ if (!parallel_root) {
+ for (fs = filesys_info; fs; fs = fs->next) {
+ if (LONE_CHAR(fs->mountpt, '/')) {
+ if (!skip_root && !ignore(fs)) {
+ fsck_device(fs /*, 1*/);
+ status |= wait_many(FLAG_WAIT_ALL);
+ if (status > EXIT_NONDESTRUCT)
+ return status;
+ }
+ fs->flags |= FLAG_DONE;
+ break;
+ }
+ }
+ }
+ /*
+ * This is for the bone-headed user who has root
+ * filesystem listed twice.
+ * "Skip root" will skip _all_ root entries.
+ */
+ if (skip_root)
+ for (fs = filesys_info; fs; fs = fs->next)
+ if (LONE_CHAR(fs->mountpt, '/'))
+ fs->flags |= FLAG_DONE;
+
+ not_done_yet = 1;
+ passno = 1;
+ while (not_done_yet) {
+ not_done_yet = 0;
+ pass_done = 1;
+
+ for (fs = filesys_info; fs; fs = fs->next) {
+ if (cancel_requested)
+ break;
+ if (fs->flags & FLAG_DONE)
+ continue;
+ /*
+ * If the filesystem's pass number is higher
+ * than the current pass number, then we didn't
+ * do it yet.
+ */
+ if (fs->passno > passno) {
+ not_done_yet = 1;
+ continue;
+ }
+ /*
+ * If a filesystem on a particular device has
+ * already been spawned, then we need to defer
+ * this to another pass.
+ */
+ if (device_already_active(fs->device)) {
+ pass_done = 0;
+ continue;
+ }
+ /*
+ * Spawn off the fsck process
+ */
+ fsck_device(fs /*, serialize*/);
+ fs->flags |= FLAG_DONE;
+
+ /*
+ * Only do one filesystem at a time, or if we
+ * have a limit on the number of fsck's extant
+ * at one time, apply that limit.
+ */
+ if (serialize
+ || (max_running && (num_running >= max_running))
+ ) {
+ pass_done = 0;
+ break;
+ }
+ }
+ if (cancel_requested)
+ break;
+ if (verbose > 1)
+ printf("--waiting-- (pass %d)\n", passno);
+ status |= wait_many(pass_done ? FLAG_WAIT_ALL :
+ FLAG_WAIT_ATLEAST_ONE);
+ if (pass_done) {
+ if (verbose > 1)
+ puts("----------------------------------");
+ passno++;
+ } else
+ not_done_yet = 1;
+ }
+ kill_all_if_cancel_requested();
+ status |= wait_many(FLAG_WAIT_ATLEAST_ONE);
+ return status;
+}
+
+/*
+ * Deal with the fsck -t argument.
+ * Huh, for mount "-t novfat,nfs" means "neither vfat nor nfs"!
+ * Why here we require "-t novfat,nonfs" ??
+ */
+static void compile_fs_type(char *fs_type)
+{
+ char *s;
+ int num = 2;
+ smallint negate;
+
+ s = fs_type;
+ while ((s = strchr(s, ','))) {
+ num++;
+ s++;
+ }
+
+ fs_type_list = xzalloc(num * sizeof(fs_type_list[0]));
+ fs_type_flag = xzalloc(num * sizeof(fs_type_flag[0]));
+ fs_type_negated = -1; /* not yet known is it negated or not */
+
+ num = 0;
+ s = fs_type;
+ while (1) {
+ char *comma;
+
+ negate = 0;
+ if (s[0] == 'n' && s[1] == 'o') { /* "no.." */
+ s += 2;
+ negate = 1;
+ } else if (s[0] == '!') {
+ s++;
+ negate = 1;
+ }
+
+ if (strcmp(s, "loop") == 0)
+ /* loop is really short-hand for opts=loop */
+ goto loop_special_case;
+ if (strncmp(s, "opts=", 5) == 0) {
+ s += 5;
+ loop_special_case:
+ fs_type_flag[num] = negate ? FS_TYPE_FLAG_NEGOPT : FS_TYPE_FLAG_OPT;
+ } else {
+ if (fs_type_negated == -1)
+ fs_type_negated = negate;
+ if (fs_type_negated != negate)
+ bb_error_msg_and_die(
+"either all or none of the filesystem types passed to -t must be prefixed "
+"with 'no' or '!'");
+ }
+ comma = strchr(s, ',');
+ fs_type_list[num++] = comma ? xstrndup(s, comma-s) : xstrdup(s);
+ if (!comma)
+ break;
+ s = comma + 1;
+ }
+}
+
+static void parse_args(char **argv)
+{
+ int i, j;
+ char *arg, *tmp;
+ char *options;
+ int optpos;
+ int opts_for_fsck = 0;
+
+ /* in bss, so already zeroed
+ num_devices = 0;
+ num_args = 0;
+ instance_list = NULL;
+ */
+
+ for (i = 1; argv[i]; i++) {
+ arg = argv[i];
+
+ /* "/dev/blk" or "/path" or "UUID=xxx" or "LABEL=xxx" */
+ if ((arg[0] == '/' && !opts_for_fsck) || strchr(arg, '=')) {
+// FIXME: must check that arg is a blkdev, or resolve
+// "/path", "UUID=xxx" or "LABEL=xxx" into block device name
+// ("UUID=xxx"/"LABEL=xxx" can probably shifted to fsck.auto duties)
+ devices = xrealloc(devices, (num_devices+1) * sizeof(devices[0]));
+ devices[num_devices++] = xstrdup(arg);
+ continue;
+ }
+
+ if (arg[0] != '-' || opts_for_fsck) {
+ args = xrealloc(args, (num_args+1) * sizeof(args[0]));
+ args[num_args++] = xstrdup(arg);
+ continue;
+ }
+
+ if (LONE_CHAR(arg + 1, '-')) { /* "--" ? */
+ opts_for_fsck = 1;
+ continue;
+ }
+
+ optpos = 0;
+ options = NULL;
+ for (j = 1; arg[j]; j++) {
+ switch (arg[j]) {
+ case 'A':
+ doall = 1;
+ break;
+#if DO_PROGRESS_INDICATOR
+ case 'C':
+ progress = 1;
+ if (arg[++j]) { /* -Cn */
+ progress_fd = xatoi_u(&arg[j]);
+ goto next_arg;
+ }
+ /* -C n */
+ if (!argv[++i]) bb_show_usage();
+ progress_fd = xatoi_u(argv[i]);
+ goto next_arg;
+#endif
+ case 'V':
+ verbose++;
+ break;
+ case 'N':
+ noexecute = 1;
+ break;
+ case 'R':
+ skip_root = 1;
+ break;
+ case 'T':
+ notitle = 1;
+ break;
+/* case 'M':
+ like_mount = 1;
+ break; */
+ case 'P':
+ parallel_root = 1;
+ break;
+ case 's':
+ serialize = 1;
+ break;
+ case 't':
+ if (fstype)
+ bb_show_usage();
+ if (arg[++j])
+ tmp = &arg[j];
+ else if (argv[++i])
+ tmp = argv[i];
+ else
+ bb_show_usage();
+ fstype = xstrdup(tmp);
+ compile_fs_type(fstype);
+ goto next_arg;
+ case '?':
+ bb_show_usage();
+ break;
+ default:
+ optpos++;
+ /* one extra for '\0' */
+ options = xrealloc(options, optpos + 2);
+ options[optpos] = arg[j];
+ break;
+ }
+ }
+ next_arg:
+ if (optpos) {
+ options[0] = '-';
+ options[optpos + 1] = '\0';
+ args = xrealloc(args, (num_args+1) * sizeof(args[0]));
+ args[num_args++] = options;
+ }
+ }
+ if (getenv("FSCK_FORCE_ALL_PARALLEL"))
+ force_all_parallel = 1;
+ tmp = getenv("FSCK_MAX_INST");
+ if (tmp)
+ max_running = xatoi(tmp);
+}
+
+static void signal_cancel(int sig ATTRIBUTE_UNUSED)
+{
+ cancel_requested = 1;
+}
+
+int fsck_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int fsck_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ int i, status;
+ /*int interactive;*/
+ const char *fstab;
+ struct fs_info *fs;
+
+ /* we want wait() to be interruptible */
+ signal_no_SA_RESTART_empty_mask(SIGINT, signal_cancel);
+ signal_no_SA_RESTART_empty_mask(SIGTERM, signal_cancel);
+
+ setbuf(stdout, NULL);
+
+ parse_args(argv);
+
+ if (!notitle)
+ puts("fsck (busybox "BB_VER", "BB_BT")");
+
+ /* Even plain "fsck /dev/hda1" needs fstab to get fs type,
+ * so we are scanning it anyway */
+ fstab = getenv("FSTAB_FILE");
+ if (!fstab)
+ fstab = "/etc/fstab";
+ load_fs_info(fstab);
+
+ /*interactive = (num_devices == 1) | serialize;*/
+
+ if (num_devices == 0)
+ /*interactive =*/ serialize = doall = 1;
+ if (doall)
+ return check_all();
+
+ status = 0;
+ for (i = 0; i < num_devices; i++) {
+ if (cancel_requested) {
+ kill_all_if_cancel_requested();
+ break;
+ }
+
+ fs = lookup(devices[i]);
+ if (!fs)
+ fs = create_fs_device(devices[i], "", "auto", NULL, -1);
+ fsck_device(fs /*, interactive */);
+
+ if (serialize
+ || (max_running && (num_running >= max_running))
+ ) {
+ int exit_status = wait_one(0);
+ if (exit_status >= 0)
+ status |= exit_status;
+ if (verbose > 1)
+ puts("----------------------------------");
+ }
+ }
+ status |= wait_many(FLAG_WAIT_ALL);
+ return status;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/lsattr.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/lsattr.c
new file mode 100644
index 0000000000..066af86c77
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/lsattr.c
@@ -0,0 +1,109 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * lsattr.c - List file attributes on an ext2 file system
+ *
+ * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
+ * Laboratoire MASI, Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * This file can be redistributed under the terms of the GNU General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/10/30 - Creation
+ * 93/11/13 - Replace stat() calls by lstat() to avoid loops
+ * 94/02/27 - Integrated in Ted's distribution
+ * 98/12/29 - Display version info only when -V specified (G M Sipe)
+ */
+
+#include "libbb.h"
+#include "e2fs_lib.h"
+
+enum {
+ OPT_RECUR = 0x1,
+ OPT_ALL = 0x2,
+ OPT_DIRS_OPT = 0x4,
+ OPT_PF_LONG = 0x8,
+ OPT_GENERATION = 0x10,
+};
+
+static void list_attributes(const char *name)
+{
+ unsigned long fsflags;
+ unsigned long generation;
+
+ if (fgetflags(name, &fsflags) != 0)
+ goto read_err;
+
+ if (option_mask32 & OPT_GENERATION) {
+ if (fgetversion(name, &generation) != 0)
+ goto read_err;
+ printf("%5lu ", generation);
+ }
+
+ if (option_mask32 & OPT_PF_LONG) {
+ printf("%-28s ", name);
+ print_e2flags(stdout, fsflags, PFOPT_LONG);
+ bb_putchar('\n');
+ } else {
+ print_e2flags(stdout, fsflags, 0);
+ printf(" %s\n", name);
+ }
+
+ return;
+ read_err:
+ bb_perror_msg("reading %s", name);
+}
+
+static int lsattr_dir_proc(const char *dir_name, struct dirent *de,
+ void *private ATTRIBUTE_UNUSED)
+{
+ struct stat st;
+ char *path;
+
+ path = concat_path_file(dir_name, de->d_name);
+
+ if (lstat(path, &st) != 0)
+ bb_perror_msg("stat %s", path);
+ else if (de->d_name[0] != '.' || (option_mask32 & OPT_ALL)) {
+ list_attributes(path);
+ if (S_ISDIR(st.st_mode) && (option_mask32 & OPT_RECUR)
+ && !DOT_OR_DOTDOT(de->d_name)
+ ) {
+ printf("\n%s:\n", path);
+ iterate_on_dir(path, lsattr_dir_proc, NULL);
+ bb_putchar('\n');
+ }
+ }
+
+ free(path);
+ return 0;
+}
+
+static void lsattr_args(const char *name)
+{
+ struct stat st;
+
+ if (lstat(name, &st) == -1) {
+ bb_perror_msg("stat %s", name);
+ } else if (S_ISDIR(st.st_mode) && !(option_mask32 & OPT_DIRS_OPT)) {
+ iterate_on_dir(name, lsattr_dir_proc, NULL);
+ } else {
+ list_attributes(name);
+ }
+}
+
+int lsattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int lsattr_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ getopt32(argv, "Radlv");
+ argv += optind;
+
+ if (!*argv)
+ *--argv = (char*)".";
+ do lsattr_args(*argv++); while (*argv);
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/Config.in b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/Config.in
new file mode 100644
index 0000000000..0062b2fe30
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/Config.in
@@ -0,0 +1,67 @@
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Linux Ext2 FS Progs"
+
+config CHATTR
+ bool "chattr"
+ default n
+ help
+ chattr changes the file attributes on a second extended file system.
+
+config E2FSCK
+ bool "e2fsck"
+ default n
+ help
+ e2fsck is used to check Linux second extended file systems (ext2fs).
+ e2fsck also supports ext2 filesystems countaining a journal (ext3).
+ The normal compat symlinks 'fsck.ext2' and 'fsck.ext3' are also
+ provided.
+
+config FSCK
+ bool "fsck"
+ default n
+ help
+ fsck is used to check and optionally repair one or more filesystems.
+ In actuality, fsck is simply a front-end for the various file system
+ checkers (fsck.fstype) available under Linux.
+
+config LSATTR
+ bool "lsattr"
+ default n
+ help
+ lsattr lists the file attributes on a second extended file system.
+
+config MKE2FS
+ bool "mke2fs"
+ default n
+ help
+ mke2fs is used to create an ext2/ext3 filesystem. The normal compat
+ symlinks 'mkfs.ext2' and 'mkfs.ext3' are also provided.
+
+config TUNE2FS
+ bool "tune2fs"
+ default n
+ help
+ tune2fs allows the system administrator to adjust various tunable
+ filesystem parameters on Linux ext2/ext3 filesystems.
+
+config E2LABEL
+ bool "e2label"
+ default n
+ depends on TUNE2FS
+ help
+ e2label will display or change the filesystem label on the ext2
+ filesystem located on device.
+
+config FINDFS
+ bool "findfs"
+ default n
+ depends on TUNE2FS
+ help
+ findfs will search the disks in the system looking for a filesystem
+ which has a label matching label or a UUID equal to uuid.
+
+endmenu
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/Kbuild b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/Kbuild
new file mode 100644
index 0000000000..b05bb92e18
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/Kbuild
@@ -0,0 +1,16 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+lib-y:=
+
+lib-$(CONFIG_CHATTR) += chattr.o
+lib-$(CONFIG_E2FSCK) += e2fsck.o util.o
+lib-$(CONFIG_FSCK) += fsck.o util.o
+lib-$(CONFIG_LSATTR) += lsattr.o
+lib-$(CONFIG_MKE2FS) += mke2fs.o util.o
+lib-$(CONFIG_TUNE2FS) += tune2fs.o util.o
+
+CFLAGS += -include $(srctree)/e2fsprogs/e2fsbb.h
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/README b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/README
new file mode 100644
index 0000000000..fac0901931
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/README
@@ -0,0 +1,3 @@
+This is a pretty straight rip from the e2fsprogs pkg.
+
+See README's in subdirs for specific info.
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/Kbuild b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/Kbuild
new file mode 100644
index 0000000000..ddcfdfd9ae
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/Kbuild
@@ -0,0 +1,23 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+NEEDED-$(CONFIG_E2FSCK) = y
+NEEDED-$(CONFIG_FSCK) = y
+NEEDED-$(CONFIG_MKE2FS) = y
+NEEDED-$(CONFIG_TUNE2FS) = y
+
+lib-y:=
+lib-$(NEEDED-y) += cache.o dev.o devname.o devno.o blkid_getsize.o \
+ probe.o read.o resolve.o save.o tag.o list.o
+
+CFLAGS_dev.o := -include $(srctree)/include/busybox.h
+CFLAGS_devname.o := -include $(srctree)/include/busybox.h
+CFLAGS_devno.o := -include $(srctree)/include/busybox.h
+CFLAGS_blkid_getsize.o := -include $(srctree)/include/busybox.h
+CFLAGS_probe.o := -include $(srctree)/include/busybox.h
+CFLAGS_save.o := -include $(srctree)/include/busybox.h
+CFLAGS_tag.o := -include $(srctree)/include/busybox.h
+CFLAGS_list.o := -include $(srctree)/include/busybox.h
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/blkid.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/blkid.h
new file mode 100644
index 0000000000..4fa9f6fdf8
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/blkid.h
@@ -0,0 +1,105 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * blkid.h - Interface for libblkid, a library to identify block devices
+ *
+ * Copyright (C) 2001 Andreas Dilger
+ * Copyright (C) 2003 Theodore Ts'o
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#ifndef _BLKID_BLKID_H
+#define _BLKID_BLKID_H
+
+#include <sys/types.h>
+#include <linux/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BLKID_VERSION "1.0.0"
+#define BLKID_DATE "12-Feb-2003"
+
+typedef struct blkid_struct_dev *blkid_dev;
+typedef struct blkid_struct_cache *blkid_cache;
+typedef __s64 blkid_loff_t;
+
+typedef struct blkid_struct_tag_iterate *blkid_tag_iterate;
+typedef struct blkid_struct_dev_iterate *blkid_dev_iterate;
+
+/*
+ * Flags for blkid_get_dev
+ *
+ * BLKID_DEV_CREATE Create an empty device structure if not found
+ * in the cache.
+ * BLKID_DEV_VERIFY Make sure the device structure corresponds
+ * with reality.
+ * BLKID_DEV_FIND Just look up a device entry, and return NULL
+ * if it is not found.
+ * BLKID_DEV_NORMAL Get a valid device structure, either from the
+ * cache or by probing the device.
+ */
+#define BLKID_DEV_FIND 0x0000
+#define BLKID_DEV_CREATE 0x0001
+#define BLKID_DEV_VERIFY 0x0002
+#define BLKID_DEV_NORMAL (BLKID_DEV_CREATE | BLKID_DEV_VERIFY)
+
+/* cache.c */
+extern void blkid_put_cache(blkid_cache cache);
+extern int blkid_get_cache(blkid_cache *cache, const char *filename);
+
+/* dev.c */
+extern const char *blkid_dev_devname(blkid_dev dev);
+
+extern blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache);
+extern int blkid_dev_set_search(blkid_dev_iterate iter,
+ char *search_type, char *search_value);
+extern int blkid_dev_next(blkid_dev_iterate iterate, blkid_dev *dev);
+extern void blkid_dev_iterate_end(blkid_dev_iterate iterate);
+
+/* devno.c */
+extern char *blkid_devno_to_devname(dev_t devno);
+
+/* devname.c */
+extern int blkid_probe_all(blkid_cache cache);
+extern int blkid_probe_all_new(blkid_cache cache);
+extern blkid_dev blkid_get_dev(blkid_cache cache, const char *devname,
+ int flags);
+
+/* getsize.c */
+extern blkid_loff_t blkid_get_dev_size(int fd);
+
+/* probe.c */
+int blkid_known_fstype(const char *fstype);
+extern blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev);
+
+/* read.c */
+
+/* resolve.c */
+extern char *blkid_get_tag_value(blkid_cache cache, const char *tagname,
+ const char *devname);
+extern char *blkid_get_devname(blkid_cache cache, const char *token,
+ const char *value);
+
+/* tag.c */
+extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev);
+extern int blkid_tag_next(blkid_tag_iterate iterate,
+ const char **type, const char **value);
+extern void blkid_tag_iterate_end(blkid_tag_iterate iterate);
+extern int blkid_dev_has_tag(blkid_dev dev, const char *type,
+ const char *value);
+extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache,
+ const char *type,
+ const char *value);
+extern int blkid_parse_tag_string(const char *token, char **ret_type,
+ char **ret_val);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BLKID_BLKID_H */
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/blkidP.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/blkidP.h
new file mode 100644
index 0000000000..c7cb8abe94
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/blkidP.h
@@ -0,0 +1,187 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * blkidP.h - Internal interfaces for libblkid
+ *
+ * Copyright (C) 2001 Andreas Dilger
+ * Copyright (C) 2003 Theodore Ts'o
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#ifndef _BLKID_BLKIDP_H
+#define _BLKID_BLKIDP_H
+
+#include <sys/types.h>
+#include <stdio.h>
+
+#include "blkid.h"
+#include "list.h"
+
+#ifdef __GNUC__
+#define __BLKID_ATTR(x) __attribute__(x)
+#else
+#define __BLKID_ATTR(x)
+#endif
+
+
+/*
+ * This describes the attributes of a specific device.
+ * We can traverse all of the tags by bid_tags (linking to the tag bit_names).
+ * The bid_label and bid_uuid fields are shortcuts to the LABEL and UUID tag
+ * values, if they exist.
+ */
+struct blkid_struct_dev
+{
+ struct list_head bid_devs; /* All devices in the cache */
+ struct list_head bid_tags; /* All tags for this device */
+ blkid_cache bid_cache; /* Dev belongs to this cache */
+ char *bid_name; /* Device inode pathname */
+ char *bid_type; /* Preferred device TYPE */
+ int bid_pri; /* Device priority */
+ dev_t bid_devno; /* Device major/minor number */
+ time_t bid_time; /* Last update time of device */
+ unsigned int bid_flags; /* Device status bitflags */
+ char *bid_label; /* Shortcut to device LABEL */
+ char *bid_uuid; /* Shortcut to binary UUID */
+};
+
+#define BLKID_BID_FL_VERIFIED 0x0001 /* Device data validated from disk */
+#define BLKID_BID_FL_INVALID 0x0004 /* Device is invalid */
+
+/*
+ * Each tag defines a NAME=value pair for a particular device. The tags
+ * are linked via bit_names for a single device, so that traversing the
+ * names list will get you a list of all tags associated with a device.
+ * They are also linked via bit_values for all devices, so one can easily
+ * search all tags with a given NAME for a specific value.
+ */
+struct blkid_struct_tag
+{
+ struct list_head bit_tags; /* All tags for this device */
+ struct list_head bit_names; /* All tags with given NAME */
+ char *bit_name; /* NAME of tag (shared) */
+ char *bit_val; /* value of tag */
+ blkid_dev bit_dev; /* pointer to device */
+};
+typedef struct blkid_struct_tag *blkid_tag;
+
+/*
+ * Minimum number of seconds between device probes, even when reading
+ * from the cache. This is to avoid re-probing all devices which were
+ * just probed by another program that does not share the cache.
+ */
+#define BLKID_PROBE_MIN 2
+
+/*
+ * Time in seconds an entry remains verified in the in-memory cache
+ * before being reverified (in case of long-running processes that
+ * keep a cache in memory and continue to use it for a long time).
+ */
+#define BLKID_PROBE_INTERVAL 200
+
+/* This describes an entire blkid cache file and probed devices.
+ * We can traverse all of the found devices via bic_list.
+ * We can traverse all of the tag types by bic_tags, which hold empty tags
+ * for each tag type. Those tags can be used as list_heads for iterating
+ * through all devices with a specific tag type (e.g. LABEL).
+ */
+struct blkid_struct_cache
+{
+ struct list_head bic_devs; /* List head of all devices */
+ struct list_head bic_tags; /* List head of all tag types */
+ time_t bic_time; /* Last probe time */
+ time_t bic_ftime; /* Mod time of the cachefile */
+ unsigned int bic_flags; /* Status flags of the cache */
+ char *bic_filename; /* filename of cache */
+};
+
+#define BLKID_BIC_FL_PROBED 0x0002 /* We probed /proc/partition devices */
+#define BLKID_BIC_FL_CHANGED 0x0004 /* Cache has changed from disk */
+
+extern char *blkid_strdup(const char *s);
+extern char *blkid_strndup(const char *s, const int length);
+
+#define BLKID_CACHE_FILE "/etc/blkid.tab"
+extern const char *blkid_devdirs[];
+
+#define BLKID_ERR_IO 5
+#define BLKID_ERR_PROC 9
+#define BLKID_ERR_MEM 12
+#define BLKID_ERR_CACHE 14
+#define BLKID_ERR_DEV 19
+#define BLKID_ERR_PARAM 22
+#define BLKID_ERR_BIG 27
+
+/*
+ * Priority settings for different types of devices
+ */
+#define BLKID_PRI_EVMS 30
+#define BLKID_PRI_LVM 20
+#define BLKID_PRI_MD 10
+
+#if defined(TEST_PROGRAM) && !defined(CONFIG_BLKID_DEBUG)
+#define CONFIG_BLKID_DEBUG
+#endif
+
+#define DEBUG_CACHE 0x0001
+#define DEBUG_DUMP 0x0002
+#define DEBUG_DEV 0x0004
+#define DEBUG_DEVNAME 0x0008
+#define DEBUG_DEVNO 0x0010
+#define DEBUG_PROBE 0x0020
+#define DEBUG_READ 0x0040
+#define DEBUG_RESOLVE 0x0080
+#define DEBUG_SAVE 0x0100
+#define DEBUG_TAG 0x0200
+#define DEBUG_INIT 0x8000
+#define DEBUG_ALL 0xFFFF
+
+#ifdef CONFIG_BLKID_DEBUG
+#include <stdio.h>
+extern int blkid_debug_mask;
+#define DBG(m,x) if ((m) & blkid_debug_mask) x;
+#else
+#define DBG(m,x)
+#endif
+
+#ifdef CONFIG_BLKID_DEBUG
+extern void blkid_debug_dump_dev(blkid_dev dev);
+extern void blkid_debug_dump_tag(blkid_tag tag);
+#endif
+
+/* lseek.c */
+/* extern blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int whence); */
+#ifdef CONFIG_LFS
+# define blkid_llseek lseek64
+#else
+# define blkid_llseek lseek
+#endif
+
+/* read.c */
+extern void blkid_read_cache(blkid_cache cache);
+
+/* save.c */
+extern int blkid_flush_cache(blkid_cache cache);
+
+/*
+ * Functions to create and find a specific tag type: tag.c
+ */
+extern void blkid_free_tag(blkid_tag tag);
+extern blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type);
+extern int blkid_set_tag(blkid_dev dev, const char *name,
+ const char *value, const int vlength);
+
+/*
+ * Functions to create and find a specific tag type: dev.c
+ */
+extern blkid_dev blkid_new_dev(void);
+extern void blkid_free_dev(blkid_dev dev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BLKID_BLKIDP_H */
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/blkid_getsize.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/blkid_getsize.c
new file mode 100644
index 0000000000..941efa42cd
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/blkid_getsize.c
@@ -0,0 +1,179 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * getsize.c --- get the size of a partition.
+ *
+ * Copyright (C) 1995, 1995 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+/* include this before sys/queues.h! */
+#include "blkidP.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <fcntl.h>
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_LINUX_FD_H
+#include <linux/fd.h>
+#endif
+#ifdef HAVE_SYS_DISKLABEL_H
+#include <sys/disklabel.h>
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_DISK_H
+#ifdef HAVE_SYS_QUEUE_H
+#include <sys/queue.h> /* for LIST_HEAD */
+#endif
+#include <sys/disk.h>
+#endif
+#ifdef __linux__
+#include <sys/utsname.h>
+#endif
+
+#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)
+#define BLKGETSIZE _IO(0x12,96) /* return device size */
+#endif
+
+#if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64)
+#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */
+#endif
+
+#ifdef APPLE_DARWIN
+#define BLKGETSIZE DKIOCGETBLOCKCOUNT32
+#endif /* APPLE_DARWIN */
+
+static int valid_offset(int fd, blkid_loff_t offset)
+{
+ char ch;
+
+ if (blkid_llseek(fd, offset, 0) < 0)
+ return 0;
+ if (read(fd, &ch, 1) < 1)
+ return 0;
+ return 1;
+}
+
+/*
+ * Returns the number of blocks in a partition
+ */
+blkid_loff_t blkid_get_dev_size(int fd)
+{
+ int valid_blkgetsize64 = 1;
+#ifdef __linux__
+ struct utsname ut;
+#endif
+ unsigned long long size64;
+ unsigned long size;
+ blkid_loff_t high, low;
+#ifdef FDGETPRM
+ struct floppy_struct this_floppy;
+#endif
+#ifdef HAVE_SYS_DISKLABEL_H
+ int part = -1;
+ struct disklabel lab;
+ struct partition *pp;
+ char ch;
+ struct stat st;
+#endif /* HAVE_SYS_DISKLABEL_H */
+
+#ifdef DKIOCGETBLOCKCOUNT /* For Apple Darwin */
+ if (ioctl(fd, DKIOCGETBLOCKCOUNT, &size64) >= 0) {
+ if ((sizeof(blkid_loff_t) < sizeof(unsigned long long))
+ && (size64 << 9 > 0xFFFFFFFF))
+ return 0; /* EFBIG */
+ return (blkid_loff_t) size64 << 9;
+ }
+#endif
+
+#ifdef BLKGETSIZE64
+#ifdef __linux__
+ if ((uname(&ut) == 0) &&
+ ((ut.release[0] == '2') && (ut.release[1] == '.') &&
+ (ut.release[2] < '6') && (ut.release[3] == '.')))
+ valid_blkgetsize64 = 0;
+#endif
+ if (valid_blkgetsize64 &&
+ ioctl(fd, BLKGETSIZE64, &size64) >= 0) {
+ if ((sizeof(blkid_loff_t) < sizeof(unsigned long long))
+ && ((size64) > 0xFFFFFFFF))
+ return 0; /* EFBIG */
+ return size64;
+ }
+#endif
+
+#ifdef BLKGETSIZE
+ if (ioctl(fd, BLKGETSIZE, &size) >= 0)
+ return (blkid_loff_t)size << 9;
+#endif
+
+#ifdef FDGETPRM
+ if (ioctl(fd, FDGETPRM, &this_floppy) >= 0)
+ return (blkid_loff_t)this_floppy.size << 9;
+#endif
+#ifdef HAVE_SYS_DISKLABEL_H
+#if 0
+ /*
+ * This should work in theory but I haven't tested it. Anyone
+ * on a BSD system want to test this for me? In the meantime,
+ * binary search mechanism should work just fine.
+ */
+ if ((fstat(fd, &st) >= 0) && S_ISBLK(st.st_mode))
+ part = st.st_rdev & 7;
+ if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) {
+ pp = &lab.d_partitions[part];
+ if (pp->p_size)
+ return pp->p_size << 9;
+ }
+#endif
+#endif /* HAVE_SYS_DISKLABEL_H */
+
+ /*
+ * OK, we couldn't figure it out by using a specialized ioctl,
+ * which is generally the best way. So do binary search to
+ * find the size of the partition.
+ */
+ low = 0;
+ for (high = 1024; valid_offset(fd, high); high *= 2)
+ low = high;
+ while (low < high - 1)
+ {
+ const blkid_loff_t mid = (low + high) / 2;
+
+ if (valid_offset(fd, mid))
+ low = mid;
+ else
+ high = mid;
+ }
+ return low + 1;
+}
+
+#ifdef TEST_PROGRAM
+int main(int argc, char **argv)
+{
+ blkid_loff_t bytes;
+ int fd;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s device\n"
+ "Determine the size of a device\n", argv[0]);
+ return 1;
+ }
+
+ if ((fd = open(argv[1], O_RDONLY)) < 0)
+ perror(argv[0]);
+
+ bytes = blkid_get_dev_size(fd);
+ printf("Device %s has %lld 1k blocks.\n", argv[1], bytes >> 10);
+
+ return 0;
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/cache.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/cache.c
new file mode 100644
index 0000000000..d1d29146b3
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/cache.c
@@ -0,0 +1,125 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * cache.c - allocation/initialization/free routines for cache
+ *
+ * Copyright (C) 2001 Andreas Dilger
+ * Copyright (C) 2003 Theodore Ts'o
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "blkidP.h"
+
+int blkid_debug_mask = 0;
+
+int blkid_get_cache(blkid_cache *ret_cache, const char *filename)
+{
+ blkid_cache cache;
+
+#ifdef CONFIG_BLKID_DEBUG
+ if (!(blkid_debug_mask & DEBUG_INIT)) {
+ char *dstr = getenv("BLKID_DEBUG");
+
+ if (dstr)
+ blkid_debug_mask = strtoul(dstr, 0, 0);
+ blkid_debug_mask |= DEBUG_INIT;
+ }
+#endif
+
+ DBG(DEBUG_CACHE, printf("creating blkid cache (using %s)\n",
+ filename ? filename : "default cache"));
+
+ cache = xzalloc(sizeof(struct blkid_struct_cache));
+
+ INIT_LIST_HEAD(&cache->bic_devs);
+ INIT_LIST_HEAD(&cache->bic_tags);
+
+ if (filename && !strlen(filename))
+ filename = 0;
+ if (!filename && (getuid() == geteuid()))
+ filename = getenv("BLKID_FILE");
+ if (!filename)
+ filename = BLKID_CACHE_FILE;
+ cache->bic_filename = blkid_strdup(filename);
+
+ blkid_read_cache(cache);
+
+ *ret_cache = cache;
+ return 0;
+}
+
+void blkid_put_cache(blkid_cache cache)
+{
+ if (!cache)
+ return;
+
+ (void) blkid_flush_cache(cache);
+
+ DBG(DEBUG_CACHE, printf("freeing cache struct\n"));
+
+ /* DBG(DEBUG_CACHE, blkid_debug_dump_cache(cache)); */
+
+ while (!list_empty(&cache->bic_devs)) {
+ blkid_dev dev = list_entry(cache->bic_devs.next,
+ struct blkid_struct_dev,
+ bid_devs);
+ blkid_free_dev(dev);
+ }
+
+ while (!list_empty(&cache->bic_tags)) {
+ blkid_tag tag = list_entry(cache->bic_tags.next,
+ struct blkid_struct_tag,
+ bit_tags);
+
+ while (!list_empty(&tag->bit_names)) {
+ blkid_tag bad = list_entry(tag->bit_names.next,
+ struct blkid_struct_tag,
+ bit_names);
+
+ DBG(DEBUG_CACHE, printf("warning: unfreed tag %s=%s\n",
+ bad->bit_name, bad->bit_val));
+ blkid_free_tag(bad);
+ }
+ blkid_free_tag(tag);
+ }
+ free(cache->bic_filename);
+
+ free(cache);
+}
+
+#ifdef TEST_PROGRAM
+int main(int argc, char** argv)
+{
+ blkid_cache cache = NULL;
+ int ret;
+
+ blkid_debug_mask = DEBUG_ALL;
+ if ((argc > 2)) {
+ fprintf(stderr, "Usage: %s [filename]\n", argv[0]);
+ exit(1);
+ }
+
+ if ((ret = blkid_get_cache(&cache, argv[1])) < 0) {
+ fprintf(stderr, "error %d parsing cache file %s\n", ret,
+ argv[1] ? argv[1] : BLKID_CACHE_FILE);
+ exit(1);
+ }
+ if ((ret = blkid_get_cache(&cache, bb_dev_null)) != 0) {
+ fprintf(stderr, "%s: error creating cache (%d)\n",
+ argv[0], ret);
+ exit(1);
+ }
+ if ((ret = blkid_probe_all(cache) < 0))
+ fprintf(stderr, "error probing devices\n");
+
+ blkid_put_cache(cache);
+
+ return ret;
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/dev.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/dev.c
new file mode 100644
index 0000000000..bb0cc914a0
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/dev.c
@@ -0,0 +1,213 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * dev.c - allocation/initialization/free routines for dev
+ *
+ * Copyright (C) 2001 Andreas Dilger
+ * Copyright (C) 2003 Theodore Ts'o
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "blkidP.h"
+
+blkid_dev blkid_new_dev(void)
+{
+ blkid_dev dev;
+
+ dev = xzalloc(sizeof(struct blkid_struct_dev));
+
+ INIT_LIST_HEAD(&dev->bid_devs);
+ INIT_LIST_HEAD(&dev->bid_tags);
+
+ return dev;
+}
+
+void blkid_free_dev(blkid_dev dev)
+{
+ if (!dev)
+ return;
+
+ DBG(DEBUG_DEV,
+ printf(" freeing dev %s (%s)\n", dev->bid_name, dev->bid_type));
+ DBG(DEBUG_DEV, blkid_debug_dump_dev(dev));
+
+ list_del(&dev->bid_devs);
+ while (!list_empty(&dev->bid_tags)) {
+ blkid_tag tag = list_entry(dev->bid_tags.next,
+ struct blkid_struct_tag,
+ bit_tags);
+ blkid_free_tag(tag);
+ }
+ if (dev->bid_name)
+ free(dev->bid_name);
+ free(dev);
+}
+
+/*
+ * Given a blkid device, return its name
+ */
+const char *blkid_dev_devname(blkid_dev dev)
+{
+ return dev->bid_name;
+}
+
+#ifdef CONFIG_BLKID_DEBUG
+void blkid_debug_dump_dev(blkid_dev dev)
+{
+ struct list_head *p;
+
+ if (!dev) {
+ printf(" dev: NULL\n");
+ return;
+ }
+
+ printf(" dev: name = %s\n", dev->bid_name);
+ printf(" dev: DEVNO=\"0x%0llx\"\n", dev->bid_devno);
+ printf(" dev: TIME=\"%lu\"\n", dev->bid_time);
+ printf(" dev: PRI=\"%d\"\n", dev->bid_pri);
+ printf(" dev: flags = 0x%08X\n", dev->bid_flags);
+
+ list_for_each(p, &dev->bid_tags) {
+ blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags);
+ if (tag)
+ printf(" tag: %s=\"%s\"\n", tag->bit_name,
+ tag->bit_val);
+ else
+ printf(" tag: NULL\n");
+ }
+ bb_putchar('\n');
+}
+#endif
+
+/*
+ * dev iteration routines for the public libblkid interface.
+ *
+ * These routines do not expose the list.h implementation, which are a
+ * contamination of the namespace, and which force us to reveal far, far
+ * too much of our internal implemenation. I'm not convinced I want
+ * to keep list.h in the long term, anyway. It's fine for kernel
+ * programming, but performance is not the #1 priority for this
+ * library, and I really don't like the tradeoff of type-safety for
+ * performance for this application. [tytso:20030125.2007EST]
+ */
+
+/*
+ * This series of functions iterate over all devices in a blkid cache
+ */
+#define DEV_ITERATE_MAGIC 0x01a5284c
+
+struct blkid_struct_dev_iterate {
+ int magic;
+ blkid_cache cache;
+ struct list_head *p;
+};
+
+blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache)
+{
+ blkid_dev_iterate iter;
+
+ iter = xmalloc(sizeof(struct blkid_struct_dev_iterate));
+ iter->magic = DEV_ITERATE_MAGIC;
+ iter->cache = cache;
+ iter->p = cache->bic_devs.next;
+ return iter;
+}
+
+/*
+ * Return 0 on success, -1 on error
+ */
+extern int blkid_dev_next(blkid_dev_iterate iter,
+ blkid_dev *dev)
+{
+ *dev = 0;
+ if (!iter || iter->magic != DEV_ITERATE_MAGIC ||
+ iter->p == &iter->cache->bic_devs)
+ return -1;
+ *dev = list_entry(iter->p, struct blkid_struct_dev, bid_devs);
+ iter->p = iter->p->next;
+ return 0;
+}
+
+void blkid_dev_iterate_end(blkid_dev_iterate iter)
+{
+ if (!iter || iter->magic != DEV_ITERATE_MAGIC)
+ return;
+ iter->magic = 0;
+ free(iter);
+}
+
+#ifdef TEST_PROGRAM
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern char *optarg;
+extern int optind;
+#endif
+
+void usage(char *prog)
+{
+ fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask]\n", prog);
+ fprintf(stderr, "\tList all devices and exit\n", prog);
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ blkid_dev_iterate iter;
+ blkid_cache cache = NULL;
+ blkid_dev dev;
+ int c, ret;
+ char *tmp;
+ char *file = NULL;
+ char *search_type = NULL;
+ char *search_value = NULL;
+
+ while ((c = getopt (argc, argv, "m:f:")) != EOF)
+ switch (c) {
+ case 'f':
+ file = optarg;
+ break;
+ case 'm':
+ blkid_debug_mask = strtoul (optarg, &tmp, 0);
+ if (*tmp) {
+ fprintf(stderr, "Invalid debug mask: %d\n",
+ optarg);
+ exit(1);
+ }
+ break;
+ case '?':
+ usage(argv[0]);
+ }
+ if (argc >= optind+2) {
+ search_type = argv[optind];
+ search_value = argv[optind+1];
+ optind += 2;
+ }
+ if (argc != optind)
+ usage(argv[0]);
+
+ if ((ret = blkid_get_cache(&cache, file)) != 0) {
+ fprintf(stderr, "%s: error creating cache (%d)\n",
+ argv[0], ret);
+ exit(1);
+ }
+
+ iter = blkid_dev_iterate_begin(cache);
+ if (search_type)
+ blkid_dev_set_search(iter, search_type, search_value);
+ while (blkid_dev_next(iter, &dev) == 0) {
+ printf("Device: %s\n", blkid_dev_devname(dev));
+ }
+ blkid_dev_iterate_end(iter);
+
+
+ blkid_put_cache(cache);
+ return 0;
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/devname.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/devname.c
new file mode 100644
index 0000000000..071aa5a12f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/devname.c
@@ -0,0 +1,367 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * devname.c - get a dev by its device inode name
+ *
+ * Copyright (C) Andries Brouwer
+ * Copyright (C) 1999, 2000, 2001, 2002, 2003 Theodore Ts'o
+ * Copyright (C) 2001 Andreas Dilger
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <sys/stat.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_SYS_MKDEV_H
+#include <sys/mkdev.h>
+#endif
+#include <time.h>
+
+#include "blkidP.h"
+
+/*
+ * Find a dev struct in the cache by device name, if available.
+ *
+ * If there is no entry with the specified device name, and the create
+ * flag is set, then create an empty device entry.
+ */
+blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags)
+{
+ blkid_dev dev = NULL, tmp;
+ struct list_head *p;
+
+ if (!cache || !devname)
+ return NULL;
+
+ list_for_each(p, &cache->bic_devs) {
+ tmp = list_entry(p, struct blkid_struct_dev, bid_devs);
+ if (strcmp(tmp->bid_name, devname))
+ continue;
+
+ DBG(DEBUG_DEVNAME,
+ printf("found devname %s in cache\n", tmp->bid_name));
+ dev = tmp;
+ break;
+ }
+
+ if (!dev && (flags & BLKID_DEV_CREATE)) {
+ dev = blkid_new_dev();
+ if (!dev)
+ return NULL;
+ dev->bid_name = blkid_strdup(devname);
+ dev->bid_cache = cache;
+ list_add_tail(&dev->bid_devs, &cache->bic_devs);
+ cache->bic_flags |= BLKID_BIC_FL_CHANGED;
+ }
+
+ if (flags & BLKID_DEV_VERIFY)
+ dev = blkid_verify(cache, dev);
+ return dev;
+}
+
+/*
+ * Probe a single block device to add to the device cache.
+ */
+static void probe_one(blkid_cache cache, const char *ptname,
+ dev_t devno, int pri)
+{
+ blkid_dev dev = NULL;
+ struct list_head *p;
+ const char **dir;
+ char *devname = NULL;
+
+ /* See if we already have this device number in the cache. */
+ list_for_each(p, &cache->bic_devs) {
+ blkid_dev tmp = list_entry(p, struct blkid_struct_dev,
+ bid_devs);
+ if (tmp->bid_devno == devno) {
+ dev = blkid_verify(cache, tmp);
+ break;
+ }
+ }
+ if (dev && dev->bid_devno == devno)
+ goto set_pri;
+
+ /*
+ * Take a quick look at /dev/ptname for the device number. We check
+ * all of the likely device directories. If we don't find it, or if
+ * the stat information doesn't check out, use blkid_devno_to_devname()
+ * to find it via an exhaustive search for the device major/minor.
+ */
+ for (dir = blkid_devdirs; *dir; dir++) {
+ struct stat st;
+ char device[256];
+
+ sprintf(device, "%s/%s", *dir, ptname);
+ if ((dev = blkid_get_dev(cache, device, BLKID_DEV_FIND)) &&
+ dev->bid_devno == devno)
+ goto set_pri;
+
+ if (stat(device, &st) == 0 && S_ISBLK(st.st_mode) &&
+ st.st_rdev == devno) {
+ devname = blkid_strdup(device);
+ break;
+ }
+ }
+ if (!devname) {
+ devname = blkid_devno_to_devname(devno);
+ if (!devname)
+ return;
+ }
+ dev = blkid_get_dev(cache, devname, BLKID_DEV_NORMAL);
+ free(devname);
+
+set_pri:
+ if (!pri && !strncmp(ptname, "md", 2))
+ pri = BLKID_PRI_MD;
+ if (dev)
+ dev->bid_pri = pri;
+}
+
+#define PROC_PARTITIONS "/proc/partitions"
+#define VG_DIR "/proc/lvm/VGs"
+
+/*
+ * This function initializes the UUID cache with devices from the LVM
+ * proc hierarchy. We currently depend on the names of the LVM
+ * hierarchy giving us the device structure in /dev. (XXX is this a
+ * safe thing to do?)
+ */
+#ifdef VG_DIR
+#include <dirent.h>
+static dev_t lvm_get_devno(const char *lvm_device)
+{
+ FILE *lvf;
+ char buf[1024];
+ int ma, mi;
+ dev_t ret = 0;
+
+ DBG(DEBUG_DEVNAME, printf("opening %s\n", lvm_device));
+ if ((lvf = fopen(lvm_device, "r")) == NULL) {
+ DBG(DEBUG_DEVNAME, printf("%s: (%d) %s\n", lvm_device, errno,
+ strerror(errno)));
+ return 0;
+ }
+
+ while (fgets(buf, sizeof(buf), lvf)) {
+ if (sscanf(buf, "device: %d:%d", &ma, &mi) == 2) {
+ ret = makedev(ma, mi);
+ break;
+ }
+ }
+ fclose(lvf);
+
+ return ret;
+}
+
+static void lvm_probe_all(blkid_cache cache)
+{
+ DIR *vg_list;
+ struct dirent *vg_iter;
+ int vg_len = strlen(VG_DIR);
+ dev_t dev;
+
+ if ((vg_list = opendir(VG_DIR)) == NULL)
+ return;
+
+ DBG(DEBUG_DEVNAME, printf("probing LVM devices under %s\n", VG_DIR));
+
+ while ((vg_iter = readdir(vg_list)) != NULL) {
+ DIR *lv_list;
+ char *vdirname;
+ char *vg_name;
+ struct dirent *lv_iter;
+
+ vg_name = vg_iter->d_name;
+ if (LONE_CHAR(vg_name, '.') || !strcmp(vg_name, ".."))
+ continue;
+ vdirname = xmalloc(vg_len + strlen(vg_name) + 8);
+ sprintf(vdirname, "%s/%s/LVs", VG_DIR, vg_name);
+
+ lv_list = opendir(vdirname);
+ free(vdirname);
+ if (lv_list == NULL)
+ continue;
+
+ while ((lv_iter = readdir(lv_list)) != NULL) {
+ char *lv_name, *lvm_device;
+
+ lv_name = lv_iter->d_name;
+ if (LONE_CHAR(lv_name, '.') || !strcmp(lv_name, ".."))
+ continue;
+
+ lvm_device = xmalloc(vg_len + strlen(vg_name) +
+ strlen(lv_name) + 8);
+ sprintf(lvm_device, "%s/%s/LVs/%s", VG_DIR, vg_name,
+ lv_name);
+ dev = lvm_get_devno(lvm_device);
+ sprintf(lvm_device, "%s/%s", vg_name, lv_name);
+ DBG(DEBUG_DEVNAME, printf("LVM dev %s: devno 0x%04X\n",
+ lvm_device,
+ (unsigned int) dev));
+ probe_one(cache, lvm_device, dev, BLKID_PRI_LVM);
+ free(lvm_device);
+ }
+ closedir(lv_list);
+ }
+ closedir(vg_list);
+}
+#endif
+
+#define PROC_EVMS_VOLUMES "/proc/evms/volumes"
+
+static int
+evms_probe_all(blkid_cache cache)
+{
+ char line[100];
+ int ma, mi, sz, num = 0;
+ FILE *procpt;
+ char device[110];
+
+ procpt = fopen(PROC_EVMS_VOLUMES, "r");
+ if (!procpt)
+ return 0;
+ while (fgets(line, sizeof(line), procpt)) {
+ if (sscanf (line, " %d %d %d %*s %*s %[^\n ]",
+ &ma, &mi, &sz, device) != 4)
+ continue;
+
+ DBG(DEBUG_DEVNAME, printf("Checking partition %s (%d, %d)\n",
+ device, ma, mi));
+
+ probe_one(cache, device, makedev(ma, mi), BLKID_PRI_EVMS);
+ num++;
+ }
+ fclose(procpt);
+ return num;
+}
+
+/*
+ * Read the device data for all available block devices in the system.
+ */
+int blkid_probe_all(blkid_cache cache)
+{
+ FILE *proc;
+ char line[1024];
+ char ptname0[128], ptname1[128], *ptname = 0;
+ char *ptnames[2];
+ dev_t devs[2];
+ int ma, mi;
+ unsigned long long sz;
+ int lens[2] = { 0, 0 };
+ int which = 0, last = 0;
+
+ ptnames[0] = ptname0;
+ ptnames[1] = ptname1;
+
+ if (!cache)
+ return -BLKID_ERR_PARAM;
+
+ if (cache->bic_flags & BLKID_BIC_FL_PROBED &&
+ time(0) - cache->bic_time < BLKID_PROBE_INTERVAL)
+ return 0;
+
+ blkid_read_cache(cache);
+ evms_probe_all(cache);
+#ifdef VG_DIR
+ lvm_probe_all(cache);
+#endif
+
+ proc = fopen(PROC_PARTITIONS, "r");
+ if (!proc)
+ return -BLKID_ERR_PROC;
+
+ while (fgets(line, sizeof(line), proc)) {
+ last = which;
+ which ^= 1;
+ ptname = ptnames[which];
+
+ if (sscanf(line, " %d %d %llu %128[^\n ]",
+ &ma, &mi, &sz, ptname) != 4)
+ continue;
+ devs[which] = makedev(ma, mi);
+
+ DBG(DEBUG_DEVNAME, printf("read partition name %s\n", ptname));
+
+ /* Skip whole disk devs unless they have no partitions
+ * If we don't have a partition on this dev, also
+ * check previous dev to see if it didn't have a partn.
+ * heuristic: partition name ends in a digit.
+ *
+ * Skip extended partitions.
+ * heuristic: size is 1
+ *
+ * FIXME: skip /dev/{ida,cciss,rd} whole-disk devs
+ */
+
+ lens[which] = strlen(ptname);
+ if (isdigit(ptname[lens[which] - 1])) {
+ DBG(DEBUG_DEVNAME,
+ printf("partition dev %s, devno 0x%04X\n",
+ ptname, (unsigned int) devs[which]));
+
+ if (sz > 1)
+ probe_one(cache, ptname, devs[which], 0);
+ lens[which] = 0;
+ lens[last] = 0;
+ } else if (lens[last] && strncmp(ptnames[last], ptname,
+ lens[last])) {
+ DBG(DEBUG_DEVNAME,
+ printf("whole dev %s, devno 0x%04X\n",
+ ptnames[last], (unsigned int) devs[last]));
+ probe_one(cache, ptnames[last], devs[last], 0);
+ lens[last] = 0;
+ }
+ }
+
+ /* Handle the last device if it wasn't partitioned */
+ if (lens[which])
+ probe_one(cache, ptname, devs[which], 0);
+
+ fclose(proc);
+
+ cache->bic_time = time(0);
+ cache->bic_flags |= BLKID_BIC_FL_PROBED;
+ blkid_flush_cache(cache);
+ return 0;
+}
+
+#ifdef TEST_PROGRAM
+int main(int argc, char **argv)
+{
+ blkid_cache cache = NULL;
+ int ret;
+
+ blkid_debug_mask = DEBUG_ALL;
+ if (argc != 1) {
+ fprintf(stderr, "Usage: %s\n"
+ "Probe all devices and exit\n", argv[0]);
+ exit(1);
+ }
+ if ((ret = blkid_get_cache(&cache, bb_dev_null)) != 0) {
+ fprintf(stderr, "%s: error creating cache (%d)\n",
+ argv[0], ret);
+ exit(1);
+ }
+ if (blkid_probe_all(cache) < 0)
+ printf("%s: error probing devices\n", argv[0]);
+
+ blkid_put_cache(cache);
+ return 0;
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/devno.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/devno.c
new file mode 100644
index 0000000000..ae326f81a0
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/devno.c
@@ -0,0 +1,222 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * devno.c - find a particular device by its device number (major/minor)
+ *
+ * Copyright (C) 2000, 2001, 2003 Theodore Ts'o
+ * Copyright (C) 2001 Andreas Dilger
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <sys/stat.h>
+#include <dirent.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_SYS_MKDEV_H
+#include <sys/mkdev.h>
+#endif
+
+#include "blkidP.h"
+
+struct dir_list {
+ char *name;
+ struct dir_list *next;
+};
+
+char *blkid_strndup(const char *s, int length)
+{
+ char *ret;
+
+ if (!s)
+ return NULL;
+
+ if (!length)
+ length = strlen(s);
+
+ ret = xmalloc(length + 1);
+ strncpy(ret, s, length);
+ ret[length] = '\0';
+ return ret;
+}
+
+char *blkid_strdup(const char *s)
+{
+ return blkid_strndup(s, 0);
+}
+
+/*
+ * This function adds an entry to the directory list
+ */
+static void add_to_dirlist(const char *name, struct dir_list **list)
+{
+ struct dir_list *dp;
+
+ dp = xmalloc(sizeof(struct dir_list));
+ dp->name = blkid_strdup(name);
+ dp->next = *list;
+ *list = dp;
+}
+
+/*
+ * This function frees a directory list
+ */
+static void free_dirlist(struct dir_list **list)
+{
+ struct dir_list *dp, *next;
+
+ for (dp = *list; dp; dp = next) {
+ next = dp->next;
+ free(dp->name);
+ free(dp);
+ }
+ *list = NULL;
+}
+
+static void scan_dir(char *dir_name, dev_t devno, struct dir_list **list,
+ char **devname)
+{
+ DIR *dir;
+ struct dirent *dp;
+ char path[1024];
+ int dirlen;
+ struct stat st;
+
+ if ((dir = opendir(dir_name)) == NULL)
+ return;
+ dirlen = strlen(dir_name) + 2;
+ while ((dp = readdir(dir)) != 0) {
+ if (dirlen + strlen(dp->d_name) >= sizeof(path))
+ continue;
+
+ if (dp->d_name[0] == '.' &&
+ ((dp->d_name[1] == 0) ||
+ ((dp->d_name[1] == '.') && (dp->d_name[2] == 0))))
+ continue;
+
+ sprintf(path, "%s/%s", dir_name, dp->d_name);
+ if (stat(path, &st) < 0)
+ continue;
+
+ if (S_ISDIR(st.st_mode))
+ add_to_dirlist(path, list);
+ else if (S_ISBLK(st.st_mode) && st.st_rdev == devno) {
+ *devname = blkid_strdup(path);
+ DBG(DEBUG_DEVNO,
+ printf("found 0x%llx at %s (%p)\n", devno,
+ path, *devname));
+ break;
+ }
+ }
+ closedir(dir);
+}
+
+/* Directories where we will try to search for device numbers */
+const char *blkid_devdirs[] = { "/devices", "/devfs", "/dev", NULL };
+
+/*
+ * This function finds the pathname to a block device with a given
+ * device number. It returns a pointer to allocated memory to the
+ * pathname on success, and NULL on failure.
+ */
+char *blkid_devno_to_devname(dev_t devno)
+{
+ struct dir_list *list = NULL, *new_list = NULL;
+ char *devname = NULL;
+ const char **dir;
+
+ /*
+ * Add the starting directories to search in reverse order of
+ * importance, since we are using a stack...
+ */
+ for (dir = blkid_devdirs; *dir; dir++)
+ add_to_dirlist(*dir, &list);
+
+ while (list) {
+ struct dir_list *current = list;
+
+ list = list->next;
+ DBG(DEBUG_DEVNO, printf("directory %s\n", current->name));
+ scan_dir(current->name, devno, &new_list, &devname);
+ free(current->name);
+ free(current);
+ if (devname)
+ break;
+ /*
+ * If we're done checking at this level, descend to
+ * the next level of subdirectories. (breadth-first)
+ */
+ if (list == NULL) {
+ list = new_list;
+ new_list = NULL;
+ }
+ }
+ free_dirlist(&list);
+ free_dirlist(&new_list);
+
+ if (!devname) {
+ DBG(DEBUG_DEVNO,
+ printf("blkid: cannot find devno 0x%04lx\n",
+ (unsigned long) devno));
+ } else {
+ DBG(DEBUG_DEVNO,
+ printf("found devno 0x%04llx as %s\n", devno, devname));
+ }
+
+
+ return devname;
+}
+
+#ifdef TEST_PROGRAM
+int main(int argc, char** argv)
+{
+ char *devname, *tmp;
+ int major, minor;
+ dev_t devno;
+ const char *errmsg = "Cannot parse %s: %s\n";
+
+ blkid_debug_mask = DEBUG_ALL;
+ if ((argc != 2) && (argc != 3)) {
+ fprintf(stderr, "Usage:\t%s device_number\n\t%s major minor\n"
+ "Resolve a device number to a device name\n",
+ argv[0], argv[0]);
+ exit(1);
+ }
+ if (argc == 2) {
+ devno = strtoul(argv[1], &tmp, 0);
+ if (*tmp) {
+ fprintf(stderr, errmsg, "device number", argv[1]);
+ exit(1);
+ }
+ } else {
+ major = strtoul(argv[1], &tmp, 0);
+ if (*tmp) {
+ fprintf(stderr, errmsg, "major number", argv[1]);
+ exit(1);
+ }
+ minor = strtoul(argv[2], &tmp, 0);
+ if (*tmp) {
+ fprintf(stderr, errmsg, "minor number", argv[2]);
+ exit(1);
+ }
+ devno = makedev(major, minor);
+ }
+ printf("Looking for device 0x%04Lx\n", devno);
+ devname = blkid_devno_to_devname(devno);
+ free(devname);
+ return 0;
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/list.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/list.c
new file mode 100644
index 0000000000..04d61a19ba
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/list.c
@@ -0,0 +1,110 @@
+/* vi: set sw=4 ts=4: */
+
+#include "list.h"
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+void __list_add(struct list_head * add,
+ struct list_head * prev,
+ struct list_head * next)
+{
+ next->prev = add;
+ add->next = next;
+ add->prev = prev;
+ prev->next = add;
+}
+
+/*
+ * list_add - add a new entry
+ * @add: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+void list_add(struct list_head *add, struct list_head *head)
+{
+ __list_add(add, head, head->next);
+}
+
+/*
+ * list_add_tail - add a new entry
+ * @add: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+void list_add_tail(struct list_head *add, struct list_head *head)
+{
+ __list_add(add, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+void __list_del(struct list_head * prev, struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/*
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ *
+ * list_empty() on @entry does not return true after this, @entry is
+ * in an undefined state.
+ */
+void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+}
+
+/*
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/*
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+int list_empty(struct list_head *head)
+{
+ return head->next == head;
+}
+
+/*
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+void list_splice(struct list_head *list, struct list_head *head)
+{
+ struct list_head *first = list->next;
+
+ if (first != list) {
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+ }
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/list.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/list.h
new file mode 100644
index 0000000000..8b06d853bb
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/list.h
@@ -0,0 +1,73 @@
+/* vi: set sw=4 ts=4: */
+#if !defined(_BLKID_LIST_H) && !defined(LIST_HEAD)
+#define _BLKID_LIST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+void __list_add(struct list_head * add, struct list_head * prev, struct list_head * next);
+void list_add(struct list_head *add, struct list_head *head);
+void list_add_tail(struct list_head *add, struct list_head *head);
+void __list_del(struct list_head * prev, struct list_head * next);
+void list_del(struct list_head *entry);
+void list_del_init(struct list_head *entry);
+int list_empty(struct list_head *head);
+void list_splice(struct list_head *list, struct list_head *head);
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+/**
+ * list_for_each - iterate over elements in a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_safe - iterate over elements in a list, but don't dereference
+ * pos after the body is done (in case it is freed)
+ * @pos: the &struct list_head to use as a loop counter.
+ * @pnext: the &struct list_head to use as a pointer to the next item.
+ * @head: the head for your list (not included in iteration).
+ */
+#define list_for_each_safe(pos, pnext, head) \
+ for (pos = (head)->next, pnext = pos->next; pos != (head); \
+ pos = pnext, pnext = pos->next)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BLKID_LIST_H */
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/probe.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/probe.c
new file mode 100644
index 0000000000..453b4d04a2
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/probe.c
@@ -0,0 +1,721 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * probe.c - identify a block device by its contents, and return a dev
+ * struct with the details
+ *
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_MKDEV_H
+#include <sys/mkdev.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include "blkidP.h"
+#include "../uuid/uuid.h"
+#include "probe.h"
+
+/*
+ * This is a special case code to check for an MDRAID device. We do
+ * this special since it requires checking for a superblock at the end
+ * of the device.
+ */
+static int check_mdraid(int fd, unsigned char *ret_uuid)
+{
+ struct mdp_superblock_s *md;
+ blkid_loff_t offset;
+ char buf[4096];
+
+ if (fd < 0)
+ return -BLKID_ERR_PARAM;
+
+ offset = (blkid_get_dev_size(fd) & ~((blkid_loff_t)65535)) - 65536;
+
+ if (blkid_llseek(fd, offset, 0) < 0 ||
+ read(fd, buf, 4096) != 4096)
+ return -BLKID_ERR_IO;
+
+ /* Check for magic number */
+ if (memcmp("\251+N\374", buf, 4))
+ return -BLKID_ERR_PARAM;
+
+ if (!ret_uuid)
+ return 0;
+ *ret_uuid = 0;
+
+ /* The MD UUID is not contiguous in the superblock, make it so */
+ md = (struct mdp_superblock_s *)buf;
+ if (md->set_uuid0 || md->set_uuid1 || md->set_uuid2 || md->set_uuid3) {
+ memcpy(ret_uuid, &md->set_uuid0, 4);
+ memcpy(ret_uuid, &md->set_uuid1, 12);
+ }
+ return 0;
+}
+
+static void set_uuid(blkid_dev dev, uuid_t uuid)
+{
+ char str[37];
+
+ if (!uuid_is_null(uuid)) {
+ uuid_unparse(uuid, str);
+ blkid_set_tag(dev, "UUID", str, sizeof(str));
+ }
+}
+
+static void get_ext2_info(blkid_dev dev, unsigned char *buf)
+{
+ struct ext2_super_block *es = (struct ext2_super_block *) buf;
+ const char *label = 0;
+
+ DBG(DEBUG_PROBE, printf("ext2_sb.compat = %08X:%08X:%08X\n",
+ blkid_le32(es->s_feature_compat),
+ blkid_le32(es->s_feature_incompat),
+ blkid_le32(es->s_feature_ro_compat)));
+
+ if (strlen(es->s_volume_name))
+ label = es->s_volume_name;
+ blkid_set_tag(dev, "LABEL", label, sizeof(es->s_volume_name));
+
+ set_uuid(dev, es->s_uuid);
+}
+
+static int probe_ext3(int fd __BLKID_ATTR((unused)),
+ blkid_cache cache __BLKID_ATTR((unused)),
+ blkid_dev dev,
+ const struct blkid_magic *id __BLKID_ATTR((unused)),
+ unsigned char *buf)
+{
+ struct ext2_super_block *es;
+
+ es = (struct ext2_super_block *)buf;
+
+ /* Distinguish between jbd and ext2/3 fs */
+ if (blkid_le32(es->s_feature_incompat) &
+ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
+ return -BLKID_ERR_PARAM;
+
+ /* Distinguish between ext3 and ext2 */
+ if (!(blkid_le32(es->s_feature_compat) &
+ EXT3_FEATURE_COMPAT_HAS_JOURNAL))
+ return -BLKID_ERR_PARAM;
+
+ get_ext2_info(dev, buf);
+
+ blkid_set_tag(dev, "SEC_TYPE", "ext2", sizeof("ext2"));
+
+ return 0;
+}
+
+static int probe_ext2(int fd __BLKID_ATTR((unused)),
+ blkid_cache cache __BLKID_ATTR((unused)),
+ blkid_dev dev,
+ const struct blkid_magic *id __BLKID_ATTR((unused)),
+ unsigned char *buf)
+{
+ struct ext2_super_block *es;
+
+ es = (struct ext2_super_block *)buf;
+
+ /* Distinguish between jbd and ext2/3 fs */
+ if (blkid_le32(es->s_feature_incompat) &
+ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
+ return -BLKID_ERR_PARAM;
+
+ get_ext2_info(dev, buf);
+
+ return 0;
+}
+
+static int probe_jbd(int fd __BLKID_ATTR((unused)),
+ blkid_cache cache __BLKID_ATTR((unused)),
+ blkid_dev dev,
+ const struct blkid_magic *id __BLKID_ATTR((unused)),
+ unsigned char *buf)
+{
+ struct ext2_super_block *es = (struct ext2_super_block *) buf;
+
+ if (!(blkid_le32(es->s_feature_incompat) &
+ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV))
+ return -BLKID_ERR_PARAM;
+
+ get_ext2_info(dev, buf);
+
+ return 0;
+}
+
+static int probe_vfat(int fd __BLKID_ATTR((unused)),
+ blkid_cache cache __BLKID_ATTR((unused)),
+ blkid_dev dev,
+ const struct blkid_magic *id __BLKID_ATTR((unused)),
+ unsigned char *buf)
+{
+ struct vfat_super_block *vs;
+ char serno[10];
+ const char *label = 0;
+ int label_len = 0;
+
+ vs = (struct vfat_super_block *)buf;
+
+ if (strncmp(vs->vs_label, "NO NAME", 7)) {
+ char *end = vs->vs_label + sizeof(vs->vs_label) - 1;
+
+ while (*end == ' ' && end >= vs->vs_label)
+ --end;
+ if (end >= vs->vs_label) {
+ label = vs->vs_label;
+ label_len = end - vs->vs_label + 1;
+ }
+ }
+
+ /* We can't just print them as %04X, because they are unaligned */
+ sprintf(serno, "%02X%02X-%02X%02X", vs->vs_serno[3], vs->vs_serno[2],
+ vs->vs_serno[1], vs->vs_serno[0]);
+ blkid_set_tag(dev, "LABEL", label, label_len);
+ blkid_set_tag(dev, "UUID", serno, sizeof(serno));
+
+ return 0;
+}
+
+static int probe_msdos(int fd __BLKID_ATTR((unused)),
+ blkid_cache cache __BLKID_ATTR((unused)),
+ blkid_dev dev,
+ const struct blkid_magic *id __BLKID_ATTR((unused)),
+ unsigned char *buf)
+{
+ struct msdos_super_block *ms = (struct msdos_super_block *) buf;
+ char serno[10];
+ const char *label = 0;
+ int label_len = 0;
+
+ if (strncmp(ms->ms_label, "NO NAME", 7)) {
+ char *end = ms->ms_label + sizeof(ms->ms_label) - 1;
+
+ while (*end == ' ' && end >= ms->ms_label)
+ --end;
+ if (end >= ms->ms_label) {
+ label = ms->ms_label;
+ label_len = end - ms->ms_label + 1;
+ }
+ }
+
+ /* We can't just print them as %04X, because they are unaligned */
+ sprintf(serno, "%02X%02X-%02X%02X", ms->ms_serno[3], ms->ms_serno[2],
+ ms->ms_serno[1], ms->ms_serno[0]);
+ blkid_set_tag(dev, "UUID", serno, 0);
+ blkid_set_tag(dev, "LABEL", label, label_len);
+ blkid_set_tag(dev, "SEC_TYPE", "msdos", sizeof("msdos"));
+
+ return 0;
+}
+
+static int probe_xfs(int fd __BLKID_ATTR((unused)),
+ blkid_cache cache __BLKID_ATTR((unused)),
+ blkid_dev dev,
+ const struct blkid_magic *id __BLKID_ATTR((unused)),
+ unsigned char *buf)
+{
+ struct xfs_super_block *xs;
+ const char *label = 0;
+
+ xs = (struct xfs_super_block *)buf;
+
+ if (strlen(xs->xs_fname))
+ label = xs->xs_fname;
+ blkid_set_tag(dev, "LABEL", label, sizeof(xs->xs_fname));
+ set_uuid(dev, xs->xs_uuid);
+ return 0;
+}
+
+static int probe_reiserfs(int fd __BLKID_ATTR((unused)),
+ blkid_cache cache __BLKID_ATTR((unused)),
+ blkid_dev dev,
+ const struct blkid_magic *id, unsigned char *buf)
+{
+ struct reiserfs_super_block *rs = (struct reiserfs_super_block *) buf;
+ unsigned int blocksize;
+ const char *label = 0;
+
+ blocksize = blkid_le16(rs->rs_blocksize);
+
+ /* If the superblock is inside the journal, we have the wrong one */
+ if (id->bim_kboff/(blocksize>>10) > blkid_le32(rs->rs_journal_block))
+ return -BLKID_ERR_BIG;
+
+ /* LABEL/UUID are only valid for later versions of Reiserfs v3.6. */
+ if (!strcmp(id->bim_magic, "ReIsEr2Fs") ||
+ !strcmp(id->bim_magic, "ReIsEr3Fs")) {
+ if (strlen(rs->rs_label))
+ label = rs->rs_label;
+ set_uuid(dev, rs->rs_uuid);
+ }
+ blkid_set_tag(dev, "LABEL", label, sizeof(rs->rs_label));
+
+ return 0;
+}
+
+static int probe_jfs(int fd __BLKID_ATTR((unused)),
+ blkid_cache cache __BLKID_ATTR((unused)),
+ blkid_dev dev,
+ const struct blkid_magic *id __BLKID_ATTR((unused)),
+ unsigned char *buf)
+{
+ struct jfs_super_block *js;
+ const char *label = 0;
+
+ js = (struct jfs_super_block *)buf;
+
+ if (strlen((char *) js->js_label))
+ label = (char *) js->js_label;
+ blkid_set_tag(dev, "LABEL", label, sizeof(js->js_label));
+ set_uuid(dev, js->js_uuid);
+ return 0;
+}
+
+static int probe_romfs(int fd __BLKID_ATTR((unused)),
+ blkid_cache cache __BLKID_ATTR((unused)),
+ blkid_dev dev,
+ const struct blkid_magic *id __BLKID_ATTR((unused)),
+ unsigned char *buf)
+{
+ struct romfs_super_block *ros;
+ const char *label = 0;
+
+ ros = (struct romfs_super_block *)buf;
+
+ if (strlen((char *) ros->ros_volume))
+ label = (char *) ros->ros_volume;
+ blkid_set_tag(dev, "LABEL", label, 0);
+ return 0;
+}
+
+static int probe_cramfs(int fd __BLKID_ATTR((unused)),
+ blkid_cache cache __BLKID_ATTR((unused)),
+ blkid_dev dev,
+ const struct blkid_magic *id __BLKID_ATTR((unused)),
+ unsigned char *buf)
+{
+ struct cramfs_super_block *csb;
+ const char *label = 0;
+
+ csb = (struct cramfs_super_block *)buf;
+
+ if (strlen((char *) csb->name))
+ label = (char *) csb->name;
+ blkid_set_tag(dev, "LABEL", label, 0);
+ return 0;
+}
+
+static int probe_swap0(int fd __BLKID_ATTR((unused)),
+ blkid_cache cache __BLKID_ATTR((unused)),
+ blkid_dev dev,
+ const struct blkid_magic *id __BLKID_ATTR((unused)),
+ unsigned char *buf __BLKID_ATTR((unused)))
+{
+ blkid_set_tag(dev, "UUID", 0, 0);
+ blkid_set_tag(dev, "LABEL", 0, 0);
+ return 0;
+}
+
+static int probe_swap1(int fd,
+ blkid_cache cache __BLKID_ATTR((unused)),
+ blkid_dev dev,
+ const struct blkid_magic *id __BLKID_ATTR((unused)),
+ unsigned char *buf __BLKID_ATTR((unused)))
+{
+ struct swap_id_block *sws;
+
+ probe_swap0(fd, cache, dev, id, buf);
+ /*
+ * Version 1 swap headers are always located at offset of 1024
+ * bytes, although the swap signature itself is located at the
+ * end of the page (which may vary depending on hardware
+ * pagesize).
+ */
+ if (lseek(fd, 1024, SEEK_SET) < 0) return 1;
+ sws = xmalloc(1024);
+ if (read(fd, sws, 1024) != 1024) {
+ free(sws);
+ return 1;
+ }
+
+ /* arbitrary sanity check.. is there any garbage down there? */
+ if (sws->sws_pad[32] == 0 && sws->sws_pad[33] == 0) {
+ if (sws->sws_volume[0])
+ blkid_set_tag(dev, "LABEL", (const char*)sws->sws_volume,
+ sizeof(sws->sws_volume));
+ if (sws->sws_uuid[0])
+ set_uuid(dev, sws->sws_uuid);
+ }
+ free(sws);
+
+ return 0;
+}
+
+static const char
+* const udf_magic[] = { "BEA01", "BOOT2", "CD001", "CDW02", "NSR02",
+ "NSR03", "TEA01", 0 };
+
+static int probe_udf(int fd, blkid_cache cache __BLKID_ATTR((unused)),
+ blkid_dev dev __BLKID_ATTR((unused)),
+ const struct blkid_magic *id __BLKID_ATTR((unused)),
+ unsigned char *buf __BLKID_ATTR((unused)))
+{
+ int j, bs;
+ struct iso_volume_descriptor isosb;
+ const char *const *m;
+
+ /* determine the block size by scanning in 2K increments
+ (block sizes larger than 2K will be null padded) */
+ for (bs = 1; bs < 16; bs++) {
+ lseek(fd, bs*2048+32768, SEEK_SET);
+ if (read(fd, (char *)&isosb, sizeof(isosb)) != sizeof(isosb))
+ return 1;
+ if (isosb.id[0])
+ break;
+ }
+
+ /* Scan up to another 64 blocks looking for additional VSD's */
+ for (j = 1; j < 64; j++) {
+ if (j > 1) {
+ lseek(fd, j*bs*2048+32768, SEEK_SET);
+ if (read(fd, (char *)&isosb, sizeof(isosb))
+ != sizeof(isosb))
+ return 1;
+ }
+ /* If we find NSR0x then call it udf:
+ NSR01 for UDF 1.00
+ NSR02 for UDF 1.50
+ NSR03 for UDF 2.00 */
+ if (!strncmp(isosb.id, "NSR0", 4))
+ return 0;
+ for (m = udf_magic; *m; m++)
+ if (!strncmp(*m, isosb.id, 5))
+ break;
+ if (*m == 0)
+ return 1;
+ }
+ return 1;
+}
+
+static int probe_ocfs(int fd __BLKID_ATTR((unused)),
+ blkid_cache cache __BLKID_ATTR((unused)),
+ blkid_dev dev,
+ const struct blkid_magic *id __BLKID_ATTR((unused)),
+ unsigned char *buf)
+{
+ struct ocfs_volume_header ovh;
+ struct ocfs_volume_label ovl;
+ __u32 major;
+
+ memcpy(&ovh, buf, sizeof(ovh));
+ memcpy(&ovl, buf+512, sizeof(ovl));
+
+ major = ocfsmajor(ovh);
+ if (major == 1)
+ blkid_set_tag(dev,"SEC_TYPE","ocfs1",sizeof("ocfs1"));
+ else if (major >= 9)
+ blkid_set_tag(dev,"SEC_TYPE","ntocfs",sizeof("ntocfs"));
+
+ blkid_set_tag(dev, "LABEL", (const char*)ovl.label, ocfslabellen(ovl));
+ blkid_set_tag(dev, "MOUNT", (const char*)ovh.mount, ocfsmountlen(ovh));
+ set_uuid(dev, ovl.vol_id);
+ return 0;
+}
+
+static int probe_ocfs2(int fd __BLKID_ATTR((unused)),
+ blkid_cache cache __BLKID_ATTR((unused)),
+ blkid_dev dev,
+ const struct blkid_magic *id __BLKID_ATTR((unused)),
+ unsigned char *buf)
+{
+ struct ocfs2_super_block *osb;
+
+ osb = (struct ocfs2_super_block *)buf;
+
+ blkid_set_tag(dev, "LABEL", (const char*)osb->s_label, sizeof(osb->s_label));
+ set_uuid(dev, osb->s_uuid);
+ return 0;
+}
+
+static int probe_oracleasm(int fd __BLKID_ATTR((unused)),
+ blkid_cache cache __BLKID_ATTR((unused)),
+ blkid_dev dev,
+ const struct blkid_magic *id __BLKID_ATTR((unused)),
+ unsigned char *buf)
+{
+ struct oracle_asm_disk_label *dl;
+
+ dl = (struct oracle_asm_disk_label *)buf;
+
+ blkid_set_tag(dev, "LABEL", dl->dl_id, sizeof(dl->dl_id));
+ return 0;
+}
+
+/*
+ * BLKID_BLK_OFFS is at least as large as the highest bim_kboff defined
+ * in the type_array table below + bim_kbalign.
+ *
+ * When probing for a lot of magics, we handle everything in 1kB buffers so
+ * that we don't have to worry about reading each combination of block sizes.
+ */
+#define BLKID_BLK_OFFS 64 /* currently reiserfs */
+
+/*
+ * Various filesystem magics that we can check for. Note that kboff and
+ * sboff are in kilobytes and bytes respectively. All magics are in
+ * byte strings so we don't worry about endian issues.
+ */
+static const struct blkid_magic type_array[] = {
+/* type kboff sboff len magic probe */
+ { "oracleasm", 0, 32, 8, "ORCLDISK", probe_oracleasm },
+ { "ntfs", 0, 3, 8, "NTFS ", 0 },
+ { "jbd", 1, 0x38, 2, "\123\357", probe_jbd },
+ { "ext3", 1, 0x38, 2, "\123\357", probe_ext3 },
+ { "ext2", 1, 0x38, 2, "\123\357", probe_ext2 },
+ { "reiserfs", 8, 0x34, 8, "ReIsErFs", probe_reiserfs },
+ { "reiserfs", 64, 0x34, 9, "ReIsEr2Fs", probe_reiserfs },
+ { "reiserfs", 64, 0x34, 9, "ReIsEr3Fs", probe_reiserfs },
+ { "reiserfs", 64, 0x34, 8, "ReIsErFs", probe_reiserfs },
+ { "reiserfs", 8, 20, 8, "ReIsErFs", probe_reiserfs },
+ { "vfat", 0, 0x52, 5, "MSWIN", probe_vfat },
+ { "vfat", 0, 0x52, 8, "FAT32 ", probe_vfat },
+ { "vfat", 0, 0x36, 5, "MSDOS", probe_msdos },
+ { "vfat", 0, 0x36, 8, "FAT16 ", probe_msdos },
+ { "vfat", 0, 0x36, 8, "FAT12 ", probe_msdos },
+ { "minix", 1, 0x10, 2, "\177\023", 0 },
+ { "minix", 1, 0x10, 2, "\217\023", 0 },
+ { "minix", 1, 0x10, 2, "\150\044", 0 },
+ { "minix", 1, 0x10, 2, "\170\044", 0 },
+ { "vxfs", 1, 0, 4, "\365\374\001\245", 0 },
+ { "xfs", 0, 0, 4, "XFSB", probe_xfs },
+ { "romfs", 0, 0, 8, "-rom1fs-", probe_romfs },
+ { "bfs", 0, 0, 4, "\316\372\173\033", 0 },
+ { "cramfs", 0, 0, 4, "E=\315\050", probe_cramfs },
+ { "qnx4", 0, 4, 6, "QNX4FS", 0 },
+ { "udf", 32, 1, 5, "BEA01", probe_udf },
+ { "udf", 32, 1, 5, "BOOT2", probe_udf },
+ { "udf", 32, 1, 5, "CD001", probe_udf },
+ { "udf", 32, 1, 5, "CDW02", probe_udf },
+ { "udf", 32, 1, 5, "NSR02", probe_udf },
+ { "udf", 32, 1, 5, "NSR03", probe_udf },
+ { "udf", 32, 1, 5, "TEA01", probe_udf },
+ { "iso9660", 32, 1, 5, "CD001", 0 },
+ { "iso9660", 32, 9, 5, "CDROM", 0 },
+ { "jfs", 32, 0, 4, "JFS1", probe_jfs },
+ { "hfs", 1, 0, 2, "BD", 0 },
+ { "ufs", 8, 0x55c, 4, "T\031\001\000", 0 },
+ { "hpfs", 8, 0, 4, "I\350\225\371", 0 },
+ { "sysv", 0, 0x3f8, 4, "\020~\030\375", 0 },
+ { "swap", 0, 0xff6, 10, "SWAP-SPACE", probe_swap0 },
+ { "swap", 0, 0xff6, 10, "SWAPSPACE2", probe_swap1 },
+ { "swap", 0, 0x1ff6, 10, "SWAP-SPACE", probe_swap0 },
+ { "swap", 0, 0x1ff6, 10, "SWAPSPACE2", probe_swap1 },
+ { "swap", 0, 0x3ff6, 10, "SWAP-SPACE", probe_swap0 },
+ { "swap", 0, 0x3ff6, 10, "SWAPSPACE2", probe_swap1 },
+ { "swap", 0, 0x7ff6, 10, "SWAP-SPACE", probe_swap0 },
+ { "swap", 0, 0x7ff6, 10, "SWAPSPACE2", probe_swap1 },
+ { "swap", 0, 0xfff6, 10, "SWAP-SPACE", probe_swap0 },
+ { "swap", 0, 0xfff6, 10, "SWAPSPACE2", probe_swap1 },
+ { "ocfs", 0, 8, 9, "OracleCFS", probe_ocfs },
+ { "ocfs2", 1, 0, 6, "OCFSV2", probe_ocfs2 },
+ { "ocfs2", 2, 0, 6, "OCFSV2", probe_ocfs2 },
+ { "ocfs2", 4, 0, 6, "OCFSV2", probe_ocfs2 },
+ { "ocfs2", 8, 0, 6, "OCFSV2", probe_ocfs2 },
+ { NULL, 0, 0, 0, NULL, NULL }
+};
+
+/*
+ * Verify that the data in dev is consistent with what is on the actual
+ * block device (using the devname field only). Normally this will be
+ * called when finding items in the cache, but for long running processes
+ * is also desirable to revalidate an item before use.
+ *
+ * If we are unable to revalidate the data, we return the old data and
+ * do not set the BLKID_BID_FL_VERIFIED flag on it.
+ */
+blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev)
+{
+ const struct blkid_magic *id;
+ unsigned char *bufs[BLKID_BLK_OFFS + 1], *buf;
+ const char *type;
+ struct stat st;
+ time_t diff, now;
+ int fd, idx;
+
+ if (!dev)
+ return NULL;
+
+ now = time(0);
+ diff = now - dev->bid_time;
+
+ if ((now < dev->bid_time) ||
+ (diff < BLKID_PROBE_MIN) ||
+ (dev->bid_flags & BLKID_BID_FL_VERIFIED &&
+ diff < BLKID_PROBE_INTERVAL))
+ return dev;
+
+ DBG(DEBUG_PROBE,
+ printf("need to revalidate %s (time since last check %lu)\n",
+ dev->bid_name, diff));
+
+ if (((fd = open(dev->bid_name, O_RDONLY)) < 0) ||
+ (fstat(fd, &st) < 0)) {
+ if (errno == ENXIO || errno == ENODEV || errno == ENOENT) {
+ blkid_free_dev(dev);
+ return NULL;
+ }
+ /* We don't have read permission, just return cache data. */
+ DBG(DEBUG_PROBE,
+ printf("returning unverified data for %s\n",
+ dev->bid_name));
+ return dev;
+ }
+
+ memset(bufs, 0, sizeof(bufs));
+
+ /*
+ * Iterate over the type array. If we already know the type,
+ * then try that first. If it doesn't work, then blow away
+ * the type information, and try again.
+ *
+ */
+try_again:
+ type = 0;
+ if (!dev->bid_type || !strcmp(dev->bid_type, "mdraid")) {
+ uuid_t uuid;
+
+ if (check_mdraid(fd, uuid) == 0) {
+ set_uuid(dev, uuid);
+ type = "mdraid";
+ goto found_type;
+ }
+ }
+ for (id = type_array; id->bim_type; id++) {
+ if (dev->bid_type &&
+ strcmp(id->bim_type, dev->bid_type))
+ continue;
+
+ idx = id->bim_kboff + (id->bim_sboff >> 10);
+ if (idx > BLKID_BLK_OFFS || idx < 0)
+ continue;
+ buf = bufs[idx];
+ if (!buf) {
+ if (lseek(fd, idx << 10, SEEK_SET) < 0)
+ continue;
+
+ buf = xmalloc(1024);
+
+ if (read(fd, buf, 1024) != 1024) {
+ free(buf);
+ continue;
+ }
+ bufs[idx] = buf;
+ }
+
+ if (memcmp(id->bim_magic, buf + (id->bim_sboff&0x3ff),
+ id->bim_len))
+ continue;
+
+ if ((id->bim_probe == NULL) ||
+ (id->bim_probe(fd, cache, dev, id, buf) == 0)) {
+ type = id->bim_type;
+ goto found_type;
+ }
+ }
+
+ if (!id->bim_type && dev->bid_type) {
+ /*
+ * Zap the device filesystem type and try again
+ */
+ blkid_set_tag(dev, "TYPE", 0, 0);
+ blkid_set_tag(dev, "SEC_TYPE", 0, 0);
+ blkid_set_tag(dev, "LABEL", 0, 0);
+ blkid_set_tag(dev, "UUID", 0, 0);
+ goto try_again;
+ }
+
+ if (!dev->bid_type) {
+ blkid_free_dev(dev);
+ return NULL;
+ }
+
+found_type:
+ if (dev && type) {
+ dev->bid_devno = st.st_rdev;
+ dev->bid_time = time(0);
+ dev->bid_flags |= BLKID_BID_FL_VERIFIED;
+ cache->bic_flags |= BLKID_BIC_FL_CHANGED;
+
+ blkid_set_tag(dev, "TYPE", type, 0);
+
+ DBG(DEBUG_PROBE, printf("%s: devno 0x%04llx, type %s\n",
+ dev->bid_name, st.st_rdev, type));
+ }
+
+ close(fd);
+
+ return dev;
+}
+
+int blkid_known_fstype(const char *fstype)
+{
+ const struct blkid_magic *id;
+
+ for (id = type_array; id->bim_type; id++) {
+ if (strcmp(fstype, id->bim_type) == 0)
+ return 1;
+ }
+ return 0;
+}
+
+#ifdef TEST_PROGRAM
+int main(int argc, char **argv)
+{
+ blkid_dev dev;
+ blkid_cache cache;
+ int ret;
+
+ blkid_debug_mask = DEBUG_ALL;
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s device\n"
+ "Probe a single device to determine type\n", argv[0]);
+ exit(1);
+ }
+ if ((ret = blkid_get_cache(&cache, bb_dev_null)) != 0) {
+ fprintf(stderr, "%s: error creating cache (%d)\n",
+ argv[0], ret);
+ exit(1);
+ }
+ dev = blkid_get_dev(cache, argv[1], BLKID_DEV_NORMAL);
+ if (!dev) {
+ printf("%s: %s has an unsupported type\n", argv[0], argv[1]);
+ return 1;
+ }
+ printf("%s is type %s\n", argv[1], dev->bid_type ?
+ dev->bid_type : "(null)");
+ if (dev->bid_label)
+ printf("\tlabel is '%s'\n", dev->bid_label);
+ if (dev->bid_uuid)
+ printf("\tuuid is %s\n", dev->bid_uuid);
+
+ blkid_free_dev(dev);
+ return 0;
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/probe.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/probe.h
new file mode 100644
index 0000000000..0fd16a7716
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/probe.h
@@ -0,0 +1,375 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * probe.h - constants and on-disk structures for extracting device data
+ *
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#ifndef _BLKID_PROBE_H
+#define _BLKID_PROBE_H
+
+#include <linux/types.h>
+
+struct blkid_magic;
+
+typedef int (*blkid_probe_t)(int fd, blkid_cache cache, blkid_dev dev,
+ const struct blkid_magic *id, unsigned char *buf);
+
+struct blkid_magic {
+ const char *bim_type; /* type name for this magic */
+ long bim_kboff; /* kilobyte offset of superblock */
+ unsigned bim_sboff; /* byte offset within superblock */
+ unsigned bim_len; /* length of magic */
+ const char *bim_magic; /* magic string */
+ blkid_probe_t bim_probe; /* probe function */
+};
+
+/*
+ * Structures for each of the content types we want to extract information
+ * from. We do not necessarily need the magic field here, because we have
+ * already identified the content type before we get this far. It may still
+ * be useful if there are probe functions which handle multiple content types.
+ */
+struct ext2_super_block {
+ __u32 s_inodes_count;
+ __u32 s_blocks_count;
+ __u32 s_r_blocks_count;
+ __u32 s_free_blocks_count;
+ __u32 s_free_inodes_count;
+ __u32 s_first_data_block;
+ __u32 s_log_block_size;
+ __u32 s_dummy3[7];
+ unsigned char s_magic[2];
+ __u16 s_state;
+ __u32 s_dummy5[8];
+ __u32 s_feature_compat;
+ __u32 s_feature_incompat;
+ __u32 s_feature_ro_compat;
+ unsigned char s_uuid[16];
+ char s_volume_name[16];
+};
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x00000004
+#define EXT3_FEATURE_INCOMPAT_RECOVER 0x00000004
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x00000008
+
+struct xfs_super_block {
+ unsigned char xs_magic[4];
+ __u32 xs_blocksize;
+ __u64 xs_dblocks;
+ __u64 xs_rblocks;
+ __u32 xs_dummy1[2];
+ unsigned char xs_uuid[16];
+ __u32 xs_dummy2[15];
+ char xs_fname[12];
+ __u32 xs_dummy3[2];
+ __u64 xs_icount;
+ __u64 xs_ifree;
+ __u64 xs_fdblocks;
+};
+
+struct reiserfs_super_block {
+ __u32 rs_blocks_count;
+ __u32 rs_free_blocks;
+ __u32 rs_root_block;
+ __u32 rs_journal_block;
+ __u32 rs_journal_dev;
+ __u32 rs_orig_journal_size;
+ __u32 rs_dummy2[5];
+ __u16 rs_blocksize;
+ __u16 rs_dummy3[3];
+ unsigned char rs_magic[12];
+ __u32 rs_dummy4[5];
+ unsigned char rs_uuid[16];
+ char rs_label[16];
+};
+
+struct jfs_super_block {
+ unsigned char js_magic[4];
+ __u32 js_version;
+ __u64 js_size;
+ __u32 js_bsize;
+ __u32 js_dummy1;
+ __u32 js_pbsize;
+ __u32 js_dummy2[27];
+ unsigned char js_uuid[16];
+ unsigned char js_label[16];
+ unsigned char js_loguuid[16];
+};
+
+struct romfs_super_block {
+ unsigned char ros_magic[8];
+ __u32 ros_dummy1[2];
+ unsigned char ros_volume[16];
+};
+
+struct cramfs_super_block {
+ __u8 magic[4];
+ __u32 size;
+ __u32 flags;
+ __u32 future;
+ __u8 signature[16];
+ struct cramfs_info {
+ __u32 crc;
+ __u32 edition;
+ __u32 blocks;
+ __u32 files;
+ } info;
+ __u8 name[16];
+};
+
+struct swap_id_block {
+/* unsigned char sws_boot[1024]; */
+ __u32 sws_version;
+ __u32 sws_lastpage;
+ __u32 sws_nrbad;
+ unsigned char sws_uuid[16];
+ char sws_volume[16];
+ unsigned char sws_pad[117];
+ __u32 sws_badpg;
+};
+
+/* Yucky misaligned values */
+struct vfat_super_block {
+/* 00*/ unsigned char vs_ignored[3];
+/* 03*/ unsigned char vs_sysid[8];
+/* 0b*/ unsigned char vs_sector_size[2];
+/* 0d*/ __u8 vs_cluster_size;
+/* 0e*/ __u16 vs_reserved;
+/* 10*/ __u8 vs_fats;
+/* 11*/ unsigned char vs_dir_entries[2];
+/* 13*/ unsigned char vs_sectors[2];
+/* 15*/ unsigned char vs_media;
+/* 16*/ __u16 vs_fat_length;
+/* 18*/ __u16 vs_secs_track;
+/* 1a*/ __u16 vs_heads;
+/* 1c*/ __u32 vs_hidden;
+/* 20*/ __u32 vs_total_sect;
+/* 24*/ __u32 vs_fat32_length;
+/* 28*/ __u16 vs_flags;
+/* 2a*/ __u8 vs_version[2];
+/* 2c*/ __u32 vs_root_cluster;
+/* 30*/ __u16 vs_insfo_sector;
+/* 32*/ __u16 vs_backup_boot;
+/* 34*/ __u16 vs_reserved2[6];
+/* 40*/ unsigned char vs_unknown[3];
+/* 43*/ unsigned char vs_serno[4];
+/* 47*/ char vs_label[11];
+/* 52*/ unsigned char vs_magic[8];
+/* 5a*/ unsigned char vs_dummy2[164];
+/*1fe*/ unsigned char vs_pmagic[2];
+};
+
+/* Yucky misaligned values */
+struct msdos_super_block {
+/* 00*/ unsigned char ms_ignored[3];
+/* 03*/ unsigned char ms_sysid[8];
+/* 0b*/ unsigned char ms_sector_size[2];
+/* 0d*/ __u8 ms_cluster_size;
+/* 0e*/ __u16 ms_reserved;
+/* 10*/ __u8 ms_fats;
+/* 11*/ unsigned char ms_dir_entries[2];
+/* 13*/ unsigned char ms_sectors[2];
+/* 15*/ unsigned char ms_media;
+/* 16*/ __u16 ms_fat_length;
+/* 18*/ __u16 ms_secs_track;
+/* 1a*/ __u16 ms_heads;
+/* 1c*/ __u32 ms_hidden;
+/* 20*/ __u32 ms_total_sect;
+/* 24*/ unsigned char ms_unknown[3];
+/* 27*/ unsigned char ms_serno[4];
+/* 2b*/ char ms_label[11];
+/* 36*/ unsigned char ms_magic[8];
+/* 3d*/ unsigned char ms_dummy2[192];
+/*1fe*/ unsigned char ms_pmagic[2];
+};
+
+struct minix_super_block {
+ __u16 ms_ninodes;
+ __u16 ms_nzones;
+ __u16 ms_imap_blocks;
+ __u16 ms_zmap_blocks;
+ __u16 ms_firstdatazone;
+ __u16 ms_log_zone_size;
+ __u32 ms_max_size;
+ unsigned char ms_magic[2];
+ __u16 ms_state;
+ __u32 ms_zones;
+};
+
+struct mdp_superblock_s {
+ __u32 md_magic;
+ __u32 major_version;
+ __u32 minor_version;
+ __u32 patch_version;
+ __u32 gvalid_words;
+ __u32 set_uuid0;
+ __u32 ctime;
+ __u32 level;
+ __u32 size;
+ __u32 nr_disks;
+ __u32 raid_disks;
+ __u32 md_minor;
+ __u32 not_persistent;
+ __u32 set_uuid1;
+ __u32 set_uuid2;
+ __u32 set_uuid3;
+};
+
+struct hfs_super_block {
+ char h_magic[2];
+ char h_dummy[18];
+ __u32 h_blksize;
+};
+
+struct ocfs_volume_header {
+ unsigned char minor_version[4];
+ unsigned char major_version[4];
+ unsigned char signature[128];
+ char mount[128];
+ unsigned char mount_len[2];
+};
+
+struct ocfs_volume_label {
+ unsigned char disk_lock[48];
+ char label[64];
+ unsigned char label_len[2];
+ unsigned char vol_id[16];
+ unsigned char vol_id_len[2];
+};
+
+#define ocfsmajor(o) ((__u32)o.major_version[0] \
+ + (((__u32) o.major_version[1]) << 8) \
+ + (((__u32) o.major_version[2]) << 16) \
+ + (((__u32) o.major_version[3]) << 24))
+#define ocfslabellen(o) ((__u32)o.label_len[0] + (((__u32) o.label_len[1]) << 8))
+#define ocfsmountlen(o) ((__u32)o.mount_len[0] + (((__u32) o.mount_len[1])<<8))
+
+#define OCFS_MAGIC "OracleCFS"
+
+struct ocfs2_super_block {
+ unsigned char signature[8];
+ unsigned char s_dummy1[184];
+ unsigned char s_dummy2[80];
+ char s_label[64];
+ unsigned char s_uuid[16];
+};
+
+#define OCFS2_MIN_BLOCKSIZE 512
+#define OCFS2_MAX_BLOCKSIZE 4096
+
+#define OCFS2_SUPER_BLOCK_BLKNO 2
+
+#define OCFS2_SUPER_BLOCK_SIGNATURE "OCFSV2"
+
+struct oracle_asm_disk_label {
+ char dummy[32];
+ char dl_tag[8];
+ char dl_id[24];
+};
+
+#define ORACLE_ASM_DISK_LABEL_MARKED "ORCLDISK"
+#define ORACLE_ASM_DISK_LABEL_OFFSET 32
+
+#define ISODCL(from, to) (to - from + 1)
+struct iso_volume_descriptor {
+ char type[ISODCL(1,1)]; /* 711 */
+ char id[ISODCL(2,6)];
+ char version[ISODCL(7,7)];
+ char data[ISODCL(8,2048)];
+};
+
+/*
+ * Byte swap functions
+ */
+#ifdef __GNUC__
+#define _INLINE_ static __inline__
+#else /* For Watcom C */
+#define _INLINE_ static inline
+#endif
+
+static __u16 blkid_swab16(__u16 val);
+static __u32 blkid_swab32(__u32 val);
+static __u64 blkid_swab64(__u64 val);
+
+#if ((defined __GNUC__) && \
+ (defined(__i386__) || defined(__i486__) || defined(__i586__)))
+
+#define _BLKID_HAVE_ASM_BITOPS_
+
+_INLINE_ __u32 blkid_swab32(__u32 val)
+{
+#ifdef EXT2FS_REQUIRE_486
+ __asm__("bswap %0" : "=r" (val) : "0" (val));
+#else
+ __asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */
+ "rorl $16,%0\n\t" /* swap words */
+ "xchgb %b0,%h0" /* swap higher bytes */
+ :"=q" (val)
+ : "0" (val));
+#endif
+ return val;
+}
+
+_INLINE_ __u16 blkid_swab16(__u16 val)
+{
+ __asm__("xchgb %b0,%h0" /* swap bytes */ \
+ : "=q" (val) \
+ : "0" (val)); \
+ return val;
+}
+
+_INLINE_ __u64 blkid_swab64(__u64 val)
+{
+ return blkid_swab32(val >> 32) |
+ ( ((__u64)blkid_swab32((__u32)val)) << 32 );
+}
+#endif
+
+#if !defined(_BLKID_HAVE_ASM_BITOPS_)
+
+_INLINE_ __u16 blkid_swab16(__u16 val)
+{
+ return (val >> 8) | (val << 8);
+}
+
+_INLINE_ __u32 blkid_swab32(__u32 val)
+{
+ return (val>>24) | ((val>>8) & 0xFF00) |
+ ((val<<8) & 0xFF0000) | (val<<24);
+}
+
+_INLINE_ __u64 blkid_swab64(__u64 val)
+{
+ return blkid_swab32(val >> 32) |
+ ( ((__u64)blkid_swab32((__u32)val)) << 32 );
+}
+#endif
+
+
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define blkid_le16(x) blkid_swab16(x)
+#define blkid_le32(x) blkid_swab32(x)
+#define blkid_le64(x) blkid_swab64(x)
+#define blkid_be16(x) (x)
+#define blkid_be32(x) (x)
+#define blkid_be64(x) (x)
+#else
+#define blkid_le16(x) (x)
+#define blkid_le32(x) (x)
+#define blkid_le64(x) (x)
+#define blkid_be16(x) blkid_swab16(x)
+#define blkid_be32(x) blkid_swab32(x)
+#define blkid_be64(x) blkid_swab64(x)
+#endif
+
+#undef _INLINE_
+
+#endif /* _BLKID_PROBE_H */
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/read.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/read.c
new file mode 100644
index 0000000000..67bc8ee442
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/read.c
@@ -0,0 +1,461 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * read.c - read the blkid cache from disk, to avoid scanning all devices
+ *
+ * Copyright (C) 2001, 2003 Theodore Y. Ts'o
+ * Copyright (C) 2001 Andreas Dilger
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "blkidP.h"
+#include "../uuid/uuid.h"
+
+#ifdef HAVE_STRTOULL
+#define __USE_ISOC9X
+#define STRTOULL strtoull /* defined in stdlib.h if you try hard enough */
+#else
+/* FIXME: need to support real strtoull here */
+#define STRTOULL strtoul
+#endif
+
+#include <stdlib.h>
+
+#ifdef TEST_PROGRAM
+#define blkid_debug_dump_dev(dev) (debug_dump_dev(dev))
+static void debug_dump_dev(blkid_dev dev);
+#endif
+
+/*
+ * File format:
+ *
+ * <device [<NAME="value"> ...]>device_name</device>
+ *
+ * The following tags are required for each entry:
+ * <ID="id"> unique (within this file) ID number of this device
+ * <TIME="time"> (ascii time_t) time this entry was last read from disk
+ * <TYPE="type"> (detected) type of filesystem/data for this partition
+ *
+ * The following tags may be present, depending on the device contents
+ * <LABEL="label"> (user supplied) label (volume name, etc)
+ * <UUID="uuid"> (generated) universally unique identifier (serial no)
+ */
+
+static char *skip_over_blank(char *cp)
+{
+ while (*cp && isspace(*cp))
+ cp++;
+ return cp;
+}
+
+static char *skip_over_word(char *cp)
+{
+ char ch;
+
+ while ((ch = *cp)) {
+ /* If we see a backslash, skip the next character */
+ if (ch == '\\') {
+ cp++;
+ if (*cp == '\0')
+ break;
+ cp++;
+ continue;
+ }
+ if (isspace(ch) || ch == '<' || ch == '>')
+ break;
+ cp++;
+ }
+ return cp;
+}
+
+static char *strip_line(char *line)
+{
+ char *p;
+
+ line = skip_over_blank(line);
+
+ p = line + strlen(line) - 1;
+
+ while (*line) {
+ if (isspace(*p))
+ *p-- = '\0';
+ else
+ break;
+ }
+
+ return line;
+}
+
+/*
+ * Start parsing a new line from the cache.
+ *
+ * line starts with "<device" return 1 -> continue parsing line
+ * line starts with "<foo", empty, or # return 0 -> skip line
+ * line starts with other, return -BLKID_ERR_CACHE -> error
+ */
+static int parse_start(char **cp)
+{
+ char *p;
+
+ p = strip_line(*cp);
+
+ /* Skip comment or blank lines. We can't just NUL the first '#' char,
+ * in case it is inside quotes, or escaped.
+ */
+ if (*p == '\0' || *p == '#')
+ return 0;
+
+ if (!strncmp(p, "<device", 7)) {
+ DBG(DEBUG_READ, printf("found device header: %8s\n", p));
+ p += 7;
+
+ *cp = p;
+ return 1;
+ }
+
+ if (*p == '<')
+ return 0;
+
+ return -BLKID_ERR_CACHE;
+}
+
+/* Consume the remaining XML on the line (cosmetic only) */
+static int parse_end(char **cp)
+{
+ *cp = skip_over_blank(*cp);
+
+ if (!strncmp(*cp, "</device>", 9)) {
+ DBG(DEBUG_READ, printf("found device trailer %9s\n", *cp));
+ *cp += 9;
+ return 0;
+ }
+
+ return -BLKID_ERR_CACHE;
+}
+
+/*
+ * Allocate a new device struct with device name filled in. Will handle
+ * finding the device on lines of the form:
+ * <device foo=bar>devname</device>
+ * <device>devname<foo>bar</foo></device>
+ */
+static int parse_dev(blkid_cache cache, blkid_dev *dev, char **cp)
+{
+ char *start, *tmp, *end, *name;
+ int ret;
+
+ if ((ret = parse_start(cp)) <= 0)
+ return ret;
+
+ start = tmp = strchr(*cp, '>');
+ if (!start) {
+ DBG(DEBUG_READ,
+ printf("blkid: short line parsing dev: %s\n", *cp));
+ return -BLKID_ERR_CACHE;
+ }
+ start = skip_over_blank(start + 1);
+ end = skip_over_word(start);
+
+ DBG(DEBUG_READ, printf("device should be %*s\n", end - start, start));
+
+ if (**cp == '>')
+ *cp = end;
+ else
+ (*cp)++;
+
+ *tmp = '\0';
+
+ if (!(tmp = strrchr(end, '<')) || parse_end(&tmp) < 0) {
+ DBG(DEBUG_READ,
+ printf("blkid: missing </device> ending: %s\n", end));
+ } else if (tmp)
+ *tmp = '\0';
+
+ if (end - start <= 1) {
+ DBG(DEBUG_READ, printf("blkid: empty device name: %s\n", *cp));
+ return -BLKID_ERR_CACHE;
+ }
+
+ name = blkid_strndup(start, end-start);
+ if (name == NULL)
+ return -BLKID_ERR_MEM;
+
+ DBG(DEBUG_READ, printf("found dev %s\n", name));
+
+ if (!(*dev = blkid_get_dev(cache, name, BLKID_DEV_CREATE)))
+ return -BLKID_ERR_MEM;
+
+ free(name);
+ return 1;
+}
+
+/*
+ * Extract a tag of the form NAME="value" from the line.
+ */
+static int parse_token(char **name, char **value, char **cp)
+{
+ char *end;
+
+ if (!name || !value || !cp)
+ return -BLKID_ERR_PARAM;
+
+ if (!(*value = strchr(*cp, '=')))
+ return 0;
+
+ **value = '\0';
+ *name = strip_line(*cp);
+ *value = skip_over_blank(*value + 1);
+
+ if (**value == '"') {
+ end = strchr(*value + 1, '"');
+ if (!end) {
+ DBG(DEBUG_READ,
+ printf("unbalanced quotes at: %s\n", *value));
+ *cp = *value;
+ return -BLKID_ERR_CACHE;
+ }
+ (*value)++;
+ *end = '\0';
+ end++;
+ } else {
+ end = skip_over_word(*value);
+ if (*end) {
+ *end = '\0';
+ end++;
+ }
+ }
+ *cp = end;
+
+ return 1;
+}
+
+/*
+ * Extract a tag of the form <NAME>value</NAME> from the line.
+ */
+/*
+static int parse_xml(char **name, char **value, char **cp)
+{
+ char *end;
+
+ if (!name || !value || !cp)
+ return -BLKID_ERR_PARAM;
+
+ *name = strip_line(*cp);
+
+ if ((*name)[0] != '<' || (*name)[1] == '/')
+ return 0;
+
+ FIXME: finish this.
+}
+*/
+
+/*
+ * Extract a tag from the line.
+ *
+ * Return 1 if a valid tag was found.
+ * Return 0 if no tag found.
+ * Return -ve error code.
+ */
+static int parse_tag(blkid_cache cache, blkid_dev dev, char **cp)
+{
+ char *name;
+ char *value;
+ int ret;
+
+ if (!cache || !dev)
+ return -BLKID_ERR_PARAM;
+
+ if ((ret = parse_token(&name, &value, cp)) <= 0 /* &&
+ (ret = parse_xml(&name, &value, cp)) <= 0 */)
+ return ret;
+
+ /* Some tags are stored directly in the device struct */
+ if (!strcmp(name, "DEVNO"))
+ dev->bid_devno = STRTOULL(value, 0, 0);
+ else if (!strcmp(name, "PRI"))
+ dev->bid_pri = strtol(value, 0, 0);
+ else if (!strcmp(name, "TIME"))
+ /* FIXME: need to parse a long long eventually */
+ dev->bid_time = strtol(value, 0, 0);
+ else
+ ret = blkid_set_tag(dev, name, value, strlen(value));
+
+ DBG(DEBUG_READ, printf(" tag: %s=\"%s\"\n", name, value));
+
+ return ret < 0 ? ret : 1;
+}
+
+/*
+ * Parse a single line of data, and return a newly allocated dev struct.
+ * Add the new device to the cache struct, if one was read.
+ *
+ * Lines are of the form <device [TAG="value" ...]>/dev/foo</device>
+ *
+ * Returns -ve value on error.
+ * Returns 0 otherwise.
+ * If a valid device was read, *dev_p is non-NULL, otherwise it is NULL
+ * (e.g. comment lines, unknown XML content, etc).
+ */
+static int blkid_parse_line(blkid_cache cache, blkid_dev *dev_p, char *cp)
+{
+ blkid_dev dev;
+ int ret;
+
+ if (!cache || !dev_p)
+ return -BLKID_ERR_PARAM;
+
+ *dev_p = NULL;
+
+ DBG(DEBUG_READ, printf("line: %s\n", cp));
+
+ if ((ret = parse_dev(cache, dev_p, &cp)) <= 0)
+ return ret;
+
+ dev = *dev_p;
+
+ while ((ret = parse_tag(cache, dev, &cp)) > 0) {
+ ;
+ }
+
+ if (dev->bid_type == NULL) {
+ DBG(DEBUG_READ,
+ printf("blkid: device %s has no TYPE\n",dev->bid_name));
+ blkid_free_dev(dev);
+ }
+
+ DBG(DEBUG_READ, blkid_debug_dump_dev(dev));
+
+ return ret;
+}
+
+/*
+ * Parse the specified filename, and return the data in the supplied or
+ * a newly allocated cache struct. If the file doesn't exist, return a
+ * new empty cache struct.
+ */
+void blkid_read_cache(blkid_cache cache)
+{
+ FILE *file;
+ char buf[4096];
+ int fd, lineno = 0;
+ struct stat st;
+
+ if (!cache)
+ return;
+
+ /*
+ * If the file doesn't exist, then we just return an empty
+ * struct so that the cache can be populated.
+ */
+ if ((fd = open(cache->bic_filename, O_RDONLY)) < 0)
+ return;
+ if (fstat(fd, &st) < 0)
+ goto errout;
+ if ((st.st_mtime == cache->bic_ftime) ||
+ (cache->bic_flags & BLKID_BIC_FL_CHANGED)) {
+ DBG(DEBUG_CACHE, printf("skipping re-read of %s\n",
+ cache->bic_filename));
+ goto errout;
+ }
+
+ DBG(DEBUG_CACHE, printf("reading cache file %s\n",
+ cache->bic_filename));
+
+ file = fdopen(fd, "r");
+ if (!file)
+ goto errout;
+
+ while (fgets(buf, sizeof(buf), file)) {
+ blkid_dev dev;
+ unsigned int end;
+
+ lineno++;
+ if (buf[0] == 0)
+ continue;
+ end = strlen(buf) - 1;
+ /* Continue reading next line if it ends with a backslash */
+ while (buf[end] == '\\' && end < sizeof(buf) - 2 &&
+ fgets(buf + end, sizeof(buf) - end, file)) {
+ end = strlen(buf) - 1;
+ lineno++;
+ }
+
+ if (blkid_parse_line(cache, &dev, buf) < 0) {
+ DBG(DEBUG_READ,
+ printf("blkid: bad format on line %d\n", lineno));
+ continue;
+ }
+ }
+ fclose(file);
+
+ /*
+ * Initially we do not need to write out the cache file.
+ */
+ cache->bic_flags &= ~BLKID_BIC_FL_CHANGED;
+ cache->bic_ftime = st.st_mtime;
+
+ return;
+errout:
+ close(fd);
+}
+
+#ifdef TEST_PROGRAM
+static void debug_dump_dev(blkid_dev dev)
+{
+ struct list_head *p;
+
+ if (!dev) {
+ printf(" dev: NULL\n");
+ return;
+ }
+
+ printf(" dev: name = %s\n", dev->bid_name);
+ printf(" dev: DEVNO=\"0x%0llx\"\n", dev->bid_devno);
+ printf(" dev: TIME=\"%lu\"\n", dev->bid_time);
+ printf(" dev: PRI=\"%d\"\n", dev->bid_pri);
+ printf(" dev: flags = 0x%08X\n", dev->bid_flags);
+
+ list_for_each(p, &dev->bid_tags) {
+ blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags);
+ if (tag)
+ printf(" tag: %s=\"%s\"\n", tag->bit_name,
+ tag->bit_val);
+ else
+ printf(" tag: NULL\n");
+ }
+ bb_putchar('\n');
+}
+
+int main(int argc, char**argv)
+{
+ blkid_cache cache = NULL;
+ int ret;
+
+ blkid_debug_mask = DEBUG_ALL;
+ if (argc > 2) {
+ fprintf(stderr, "Usage: %s [filename]\n"
+ "Test parsing of the cache (filename)\n", argv[0]);
+ exit(1);
+ }
+ if ((ret = blkid_get_cache(&cache, argv[1])) < 0)
+ fprintf(stderr, "error %d reading cache file %s\n", ret,
+ argv[1] ? argv[1] : BLKID_CACHE_FILE);
+
+ blkid_put_cache(cache);
+
+ return ret;
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/resolve.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/resolve.c
new file mode 100644
index 0000000000..7942de2cd1
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/resolve.c
@@ -0,0 +1,139 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * resolve.c - resolve names and tags into specific devices
+ *
+ * Copyright (C) 2001, 2003 Theodore Ts'o.
+ * Copyright (C) 2001 Andreas Dilger
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "blkidP.h"
+#include "probe.h"
+
+/*
+ * Find a tagname (e.g. LABEL or UUID) on a specific device.
+ */
+char *blkid_get_tag_value(blkid_cache cache, const char *tagname,
+ const char *devname)
+{
+ blkid_tag found;
+ blkid_dev dev;
+ blkid_cache c = cache;
+ char *ret = NULL;
+
+ DBG(DEBUG_RESOLVE, printf("looking for %s on %s\n", tagname, devname));
+
+ if (!devname)
+ return NULL;
+
+ if (!cache) {
+ if (blkid_get_cache(&c, NULL) < 0)
+ return NULL;
+ }
+
+ if ((dev = blkid_get_dev(c, devname, BLKID_DEV_NORMAL)) &&
+ (found = blkid_find_tag_dev(dev, tagname)))
+ ret = blkid_strdup(found->bit_val);
+
+ if (!cache)
+ blkid_put_cache(c);
+
+ return ret;
+}
+
+/*
+ * Locate a device name from a token (NAME=value string), or (name, value)
+ * pair. In the case of a token, value is ignored. If the "token" is not
+ * of the form "NAME=value" and there is no value given, then it is assumed
+ * to be the actual devname and a copy is returned.
+ */
+char *blkid_get_devname(blkid_cache cache, const char *token,
+ const char *value)
+{
+ blkid_dev dev;
+ blkid_cache c = cache;
+ char *t = 0, *v = 0;
+ char *ret = NULL;
+
+ if (!token)
+ return NULL;
+
+ if (!cache) {
+ if (blkid_get_cache(&c, NULL) < 0)
+ return NULL;
+ }
+
+ DBG(DEBUG_RESOLVE,
+ printf("looking for %s%s%s %s\n", token, value ? "=" : "",
+ value ? value : "", cache ? "in cache" : "from disk"));
+
+ if (!value) {
+ if (!strchr(token, '='))
+ return blkid_strdup(token);
+ blkid_parse_tag_string(token, &t, &v);
+ if (!t || !v)
+ goto errout;
+ token = t;
+ value = v;
+ }
+
+ dev = blkid_find_dev_with_tag(c, token, value);
+ if (!dev)
+ goto errout;
+
+ ret = blkid_strdup(blkid_dev_devname(dev));
+
+errout:
+ free(t);
+ free(v);
+ if (!cache) {
+ blkid_put_cache(c);
+ }
+ return ret;
+}
+
+#ifdef TEST_PROGRAM
+int main(int argc, char **argv)
+{
+ char *value;
+ blkid_cache cache;
+
+ blkid_debug_mask = DEBUG_ALL;
+ if (argc != 2 && argc != 3) {
+ fprintf(stderr, "Usage:\t%s tagname=value\n"
+ "\t%s tagname devname\n"
+ "Find which device holds a given token or\n"
+ "Find what the value of a tag is in a device\n",
+ argv[0], argv[0]);
+ exit(1);
+ }
+ if (blkid_get_cache(&cache, bb_dev_null) < 0) {
+ fprintf(stderr, "cannot get blkid cache\n");
+ exit(1);
+ }
+
+ if (argv[2]) {
+ value = blkid_get_tag_value(cache, argv[1], argv[2]);
+ printf("%s has tag %s=%s\n", argv[2], argv[1],
+ value ? value : "<missing>");
+ } else {
+ value = blkid_get_devname(cache, argv[1], NULL);
+ printf("%s has tag %s\n", value ? value : "<none>", argv[1]);
+ }
+ blkid_put_cache(cache);
+ return value ? 0 : 1;
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/save.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/save.c
new file mode 100644
index 0000000000..cdbaabcb12
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/save.c
@@ -0,0 +1,189 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * save.c - write the cache struct to disk
+ *
+ * Copyright (C) 2001 by Andreas Dilger
+ * Copyright (C) 2003 Theodore Ts'o
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_MKDEV_H
+#include <sys/mkdev.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include "blkidP.h"
+
+static int save_dev(blkid_dev dev, FILE *file)
+{
+ struct list_head *p;
+
+ if (!dev || dev->bid_name[0] != '/')
+ return 0;
+
+ DBG(DEBUG_SAVE,
+ printf("device %s, type %s\n", dev->bid_name, dev->bid_type));
+
+ fprintf(file,
+ "<device DEVNO=\"0x%04lx\" TIME=\"%lu\"",
+ (unsigned long) dev->bid_devno, dev->bid_time);
+ if (dev->bid_pri)
+ fprintf(file, " PRI=\"%d\"", dev->bid_pri);
+ list_for_each(p, &dev->bid_tags) {
+ blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags);
+ fprintf(file, " %s=\"%s\"", tag->bit_name,tag->bit_val);
+ }
+ fprintf(file, ">%s</device>\n", dev->bid_name);
+
+ return 0;
+}
+
+/*
+ * Write out the cache struct to the cache file on disk.
+ */
+int blkid_flush_cache(blkid_cache cache)
+{
+ struct list_head *p;
+ char *tmp = NULL;
+ const char *opened = NULL;
+ const char *filename;
+ FILE *file = NULL;
+ int fd, ret = 0;
+ struct stat st;
+
+ if (!cache)
+ return -BLKID_ERR_PARAM;
+
+ if (list_empty(&cache->bic_devs) ||
+ !(cache->bic_flags & BLKID_BIC_FL_CHANGED)) {
+ DBG(DEBUG_SAVE, printf("skipping cache file write\n"));
+ return 0;
+ }
+
+ filename = cache->bic_filename ? cache->bic_filename: BLKID_CACHE_FILE;
+
+ /* If we can't write to the cache file, then don't even try */
+ if (((ret = stat(filename, &st)) < 0 && errno != ENOENT) ||
+ (ret == 0 && access(filename, W_OK) < 0)) {
+ DBG(DEBUG_SAVE,
+ printf("can't write to cache file %s\n", filename));
+ return 0;
+ }
+
+ /*
+ * Try and create a temporary file in the same directory so
+ * that in case of error we don't overwrite the cache file.
+ * If the cache file doesn't yet exist, it isn't a regular
+ * file (e.g. /dev/null or a socket), or we couldn't create
+ * a temporary file then we open it directly.
+ */
+ if (ret == 0 && S_ISREG(st.st_mode)) {
+ tmp = xmalloc(strlen(filename) + 8);
+ sprintf(tmp, "%s-XXXXXX", filename);
+ fd = mkstemp(tmp);
+ if (fd >= 0) {
+ file = fdopen(fd, "w");
+ opened = tmp;
+ }
+ fchmod(fd, 0644);
+ }
+
+ if (!file) {
+ file = fopen(filename, "w");
+ opened = filename;
+ }
+
+ DBG(DEBUG_SAVE,
+ printf("writing cache file %s (really %s)\n",
+ filename, opened));
+
+ if (!file) {
+ ret = errno;
+ goto errout;
+ }
+
+ list_for_each(p, &cache->bic_devs) {
+ blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs);
+ if (!dev->bid_type)
+ continue;
+ if ((ret = save_dev(dev, file)) < 0)
+ break;
+ }
+
+ if (ret >= 0) {
+ cache->bic_flags &= ~BLKID_BIC_FL_CHANGED;
+ ret = 1;
+ }
+
+ fclose(file);
+ if (opened != filename) {
+ if (ret < 0) {
+ unlink(opened);
+ DBG(DEBUG_SAVE,
+ printf("unlinked temp cache %s\n", opened));
+ } else {
+ char *backup;
+
+ backup = xmalloc(strlen(filename) + 5);
+ sprintf(backup, "%s.old", filename);
+ unlink(backup);
+ link(filename, backup);
+ free(backup);
+ rename(opened, filename);
+ DBG(DEBUG_SAVE,
+ printf("moved temp cache %s\n", opened));
+ }
+ }
+
+errout:
+ free(tmp);
+ return ret;
+}
+
+#ifdef TEST_PROGRAM
+int main(int argc, char **argv)
+{
+ blkid_cache cache = NULL;
+ int ret;
+
+ blkid_debug_mask = DEBUG_ALL;
+ if (argc > 2) {
+ fprintf(stderr, "Usage: %s [filename]\n"
+ "Test loading/saving a cache (filename)\n", argv[0]);
+ exit(1);
+ }
+
+ if ((ret = blkid_get_cache(&cache, bb_dev_null)) != 0) {
+ fprintf(stderr, "%s: error creating cache (%d)\n",
+ argv[0], ret);
+ exit(1);
+ }
+ if ((ret = blkid_probe_all(cache)) < 0) {
+ fprintf(stderr, "error (%d) probing devices\n", ret);
+ exit(1);
+ }
+ cache->bic_filename = blkid_strdup(argv[1]);
+
+ if ((ret = blkid_flush_cache(cache)) < 0) {
+ fprintf(stderr, "error (%d) saving cache\n", ret);
+ exit(1);
+ }
+
+ blkid_put_cache(cache);
+
+ return ret;
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/tag.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/tag.c
new file mode 100644
index 0000000000..c0a93df98f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/blkid/tag.c
@@ -0,0 +1,431 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * tag.c - allocation/initialization/free routines for tag structs
+ *
+ * Copyright (C) 2001 Andreas Dilger
+ * Copyright (C) 2003 Theodore Ts'o
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "blkidP.h"
+
+static blkid_tag blkid_new_tag(void)
+{
+ blkid_tag tag;
+
+ tag = xzalloc(sizeof(struct blkid_struct_tag));
+
+ INIT_LIST_HEAD(&tag->bit_tags);
+ INIT_LIST_HEAD(&tag->bit_names);
+
+ return tag;
+}
+
+#ifdef CONFIG_BLKID_DEBUG
+void blkid_debug_dump_tag(blkid_tag tag)
+{
+ if (!tag) {
+ printf(" tag: NULL\n");
+ return;
+ }
+
+ printf(" tag: %s=\"%s\"\n", tag->bit_name, tag->bit_val);
+}
+#endif
+
+void blkid_free_tag(blkid_tag tag)
+{
+ if (!tag)
+ return;
+
+ DBG(DEBUG_TAG, printf(" freeing tag %s=%s\n", tag->bit_name,
+ tag->bit_val ? tag->bit_val : "(NULL)"));
+ DBG(DEBUG_TAG, blkid_debug_dump_tag(tag));
+
+ list_del(&tag->bit_tags); /* list of tags for this device */
+ list_del(&tag->bit_names); /* list of tags with this type */
+
+ free(tag->bit_name);
+ free(tag->bit_val);
+ free(tag);
+}
+
+/*
+ * Find the desired tag on a device. If value is NULL, then the
+ * first such tag is returned, otherwise return only exact tag if found.
+ */
+blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type)
+{
+ struct list_head *p;
+
+ if (!dev || !type)
+ return NULL;
+
+ list_for_each(p, &dev->bid_tags) {
+ blkid_tag tmp = list_entry(p, struct blkid_struct_tag,
+ bit_tags);
+
+ if (!strcmp(tmp->bit_name, type))
+ return tmp;
+ }
+ return NULL;
+}
+
+/*
+ * Find the desired tag type in the cache.
+ * We return the head tag for this tag type.
+ */
+static blkid_tag blkid_find_head_cache(blkid_cache cache, const char *type)
+{
+ blkid_tag head = NULL, tmp;
+ struct list_head *p;
+
+ if (!cache || !type)
+ return NULL;
+
+ list_for_each(p, &cache->bic_tags) {
+ tmp = list_entry(p, struct blkid_struct_tag, bit_tags);
+ if (!strcmp(tmp->bit_name, type)) {
+ DBG(DEBUG_TAG,
+ printf(" found cache tag head %s\n", type));
+ head = tmp;
+ break;
+ }
+ }
+ return head;
+}
+
+/*
+ * Set a tag on an existing device.
+ *
+ * If value is NULL, then delete the tagsfrom the device.
+ */
+int blkid_set_tag(blkid_dev dev, const char *name,
+ const char *value, const int vlength)
+{
+ blkid_tag t = 0, head = 0;
+ char *val = 0;
+
+ if (!dev || !name)
+ return -BLKID_ERR_PARAM;
+
+ if (!(val = blkid_strndup(value, vlength)) && value)
+ return -BLKID_ERR_MEM;
+ t = blkid_find_tag_dev(dev, name);
+ if (!value) {
+ blkid_free_tag(t);
+ } else if (t) {
+ if (!strcmp(t->bit_val, val)) {
+ /* Same thing, exit */
+ free(val);
+ return 0;
+ }
+ free(t->bit_val);
+ t->bit_val = val;
+ } else {
+ /* Existing tag not present, add to device */
+ if (!(t = blkid_new_tag()))
+ goto errout;
+ t->bit_name = blkid_strdup(name);
+ t->bit_val = val;
+ t->bit_dev = dev;
+
+ list_add_tail(&t->bit_tags, &dev->bid_tags);
+
+ if (dev->bid_cache) {
+ head = blkid_find_head_cache(dev->bid_cache,
+ t->bit_name);
+ if (!head) {
+ head = blkid_new_tag();
+ if (!head)
+ goto errout;
+
+ DBG(DEBUG_TAG,
+ printf(" creating new cache tag head %s\n", name));
+ head->bit_name = blkid_strdup(name);
+ if (!head->bit_name)
+ goto errout;
+ list_add_tail(&head->bit_tags,
+ &dev->bid_cache->bic_tags);
+ }
+ list_add_tail(&t->bit_names, &head->bit_names);
+ }
+ }
+
+ /* Link common tags directly to the device struct */
+ if (!strcmp(name, "TYPE"))
+ dev->bid_type = val;
+ else if (!strcmp(name, "LABEL"))
+ dev->bid_label = val;
+ else if (!strcmp(name, "UUID"))
+ dev->bid_uuid = val;
+
+ if (dev->bid_cache)
+ dev->bid_cache->bic_flags |= BLKID_BIC_FL_CHANGED;
+ return 0;
+
+errout:
+ blkid_free_tag(t);
+ if (!t)
+ free(val);
+ blkid_free_tag(head);
+ return -BLKID_ERR_MEM;
+}
+
+
+/*
+ * Parse a "NAME=value" string. This is slightly different than
+ * parse_token, because that will end an unquoted value at a space, while
+ * this will assume that an unquoted value is the rest of the token (e.g.
+ * if we are passed an already quoted string from the command-line we don't
+ * have to both quote and escape quote so that the quotes make it to
+ * us).
+ *
+ * Returns 0 on success, and -1 on failure.
+ */
+int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val)
+{
+ char *name, *value, *cp;
+
+ DBG(DEBUG_TAG, printf("trying to parse '%s' as a tag\n", token));
+
+ if (!token || !(cp = strchr(token, '=')))
+ return -1;
+
+ name = blkid_strdup(token);
+ if (!name)
+ return -1;
+ value = name + (cp - token);
+ *value++ = '\0';
+ if (*value == '"' || *value == '\'') {
+ char c = *value++;
+ if (!(cp = strrchr(value, c)))
+ goto errout; /* missing closing quote */
+ *cp = '\0';
+ }
+ value = blkid_strdup(value);
+ if (!value)
+ goto errout;
+
+ *ret_type = name;
+ *ret_val = value;
+
+ return 0;
+
+errout:
+ free(name);
+ return -1;
+}
+
+/*
+ * Tag iteration routines for the public libblkid interface.
+ *
+ * These routines do not expose the list.h implementation, which are a
+ * contamination of the namespace, and which force us to reveal far, far
+ * too much of our internal implemenation. I'm not convinced I want
+ * to keep list.h in the long term, anyway. It's fine for kernel
+ * programming, but performance is not the #1 priority for this
+ * library, and I really don't like the tradeoff of type-safety for
+ * performance for this application. [tytso:20030125.2007EST]
+ */
+
+/*
+ * This series of functions iterate over all tags in a device
+ */
+#define TAG_ITERATE_MAGIC 0x01a5284c
+
+struct blkid_struct_tag_iterate {
+ int magic;
+ blkid_dev dev;
+ struct list_head *p;
+};
+
+blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev)
+{
+ blkid_tag_iterate iter;
+
+ iter = xmalloc(sizeof(struct blkid_struct_tag_iterate));
+ iter->magic = TAG_ITERATE_MAGIC;
+ iter->dev = dev;
+ iter->p = dev->bid_tags.next;
+ return iter;
+}
+
+/*
+ * Return 0 on success, -1 on error
+ */
+extern int blkid_tag_next(blkid_tag_iterate iter,
+ const char **type, const char **value)
+{
+ blkid_tag tag;
+
+ *type = 0;
+ *value = 0;
+ if (!iter || iter->magic != TAG_ITERATE_MAGIC ||
+ iter->p == &iter->dev->bid_tags)
+ return -1;
+ tag = list_entry(iter->p, struct blkid_struct_tag, bit_tags);
+ *type = tag->bit_name;
+ *value = tag->bit_val;
+ iter->p = iter->p->next;
+ return 0;
+}
+
+void blkid_tag_iterate_end(blkid_tag_iterate iter)
+{
+ if (!iter || iter->magic != TAG_ITERATE_MAGIC)
+ return;
+ iter->magic = 0;
+ free(iter);
+}
+
+/*
+ * This function returns a device which matches a particular
+ * type/value pair. If there is more than one device that matches the
+ * search specification, it returns the one with the highest priority
+ * value. This allows us to give preference to EVMS or LVM devices.
+ *
+ * XXX there should also be an interface which uses an iterator so we
+ * can get all of the devices which match a type/value search parameter.
+ */
+extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache,
+ const char *type,
+ const char *value)
+{
+ blkid_tag head;
+ blkid_dev dev;
+ int pri;
+ struct list_head *p;
+
+ if (!cache || !type || !value)
+ return NULL;
+
+ blkid_read_cache(cache);
+
+ DBG(DEBUG_TAG, printf("looking for %s=%s in cache\n", type, value));
+
+try_again:
+ pri = -1;
+ dev = 0;
+ head = blkid_find_head_cache(cache, type);
+
+ if (head) {
+ list_for_each(p, &head->bit_names) {
+ blkid_tag tmp = list_entry(p, struct blkid_struct_tag,
+ bit_names);
+
+ if (!strcmp(tmp->bit_val, value) &&
+ tmp->bit_dev->bid_pri > pri) {
+ dev = tmp->bit_dev;
+ pri = dev->bid_pri;
+ }
+ }
+ }
+ if (dev && !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) {
+ dev = blkid_verify(cache, dev);
+ if (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED))
+ goto try_again;
+ }
+
+ if (!dev && !(cache->bic_flags & BLKID_BIC_FL_PROBED)) {
+ if (blkid_probe_all(cache) < 0)
+ return NULL;
+ goto try_again;
+ }
+ return dev;
+}
+
+#ifdef TEST_PROGRAM
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern char *optarg;
+extern int optind;
+#endif
+
+void usage(char *prog)
+{
+ fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask] device "
+ "[type value]\n",
+ prog);
+ fprintf(stderr, "\tList all tags for a device and exit\n", prog);
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ blkid_tag_iterate iter;
+ blkid_cache cache = NULL;
+ blkid_dev dev;
+ int c, ret, found;
+ int flags = BLKID_DEV_FIND;
+ char *tmp;
+ char *file = NULL;
+ char *devname = NULL;
+ char *search_type = NULL;
+ char *search_value = NULL;
+ const char *type, *value;
+
+ while ((c = getopt (argc, argv, "m:f:")) != EOF)
+ switch (c) {
+ case 'f':
+ file = optarg;
+ break;
+ case 'm':
+ blkid_debug_mask = strtoul (optarg, &tmp, 0);
+ if (*tmp) {
+ fprintf(stderr, "Invalid debug mask: %d\n",
+ optarg);
+ exit(1);
+ }
+ break;
+ case '?':
+ usage(argv[0]);
+ }
+ if (argc > optind)
+ devname = argv[optind++];
+ if (argc > optind)
+ search_type = argv[optind++];
+ if (argc > optind)
+ search_value = argv[optind++];
+ if (!devname || (argc != optind))
+ usage(argv[0]);
+
+ if ((ret = blkid_get_cache(&cache, file)) != 0) {
+ fprintf(stderr, "%s: error creating cache (%d)\n",
+ argv[0], ret);
+ exit(1);
+ }
+
+ dev = blkid_get_dev(cache, devname, flags);
+ if (!dev) {
+ fprintf(stderr, "%s: cannot find device in blkid cache\n");
+ exit(1);
+ }
+ if (search_type) {
+ found = blkid_dev_has_tag(dev, search_type, search_value);
+ printf("Device %s: (%s, %s) %s\n", blkid_dev_devname(dev),
+ search_type, search_value ? search_value : "NULL",
+ found ? "FOUND" : "NOT FOUND");
+ return !found;
+ }
+ printf("Device %s...\n", blkid_dev_devname(dev));
+
+ iter = blkid_tag_iterate_begin(dev);
+ while (blkid_tag_next(iter, &type, &value) == 0) {
+ printf("\tTag %s has value %s\n", type, value);
+ }
+ blkid_tag_iterate_end(iter);
+
+ blkid_put_cache(cache);
+ return 0;
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/chattr.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/chattr.c
new file mode 100644
index 0000000000..ae39d92245
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/chattr.c
@@ -0,0 +1,220 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * chattr.c - Change file attributes on an ext2 file system
+ *
+ * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
+ * Laboratoire MASI, Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * This file can be redistributed under the terms of the GNU General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/10/30 - Creation
+ * 93/11/13 - Replace stat() calls by lstat() to avoid loops
+ * 94/02/27 - Integrated in Ted's distribution
+ * 98/12/29 - Ignore symlinks when working recursively (G M Sipe)
+ * 98/12/29 - Display version info only when -V specified (G M Sipe)
+ */
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include "ext2fs/ext2_fs.h"
+
+#ifdef __GNUC__
+# define EXT2FS_ATTR(x) __attribute__(x)
+#else
+# define EXT2FS_ATTR(x)
+#endif
+
+#include "e2fsbb.h"
+#include "e2p/e2p.h"
+
+#define OPT_ADD 1
+#define OPT_REM 2
+#define OPT_SET 4
+#define OPT_SET_VER 8
+static int flags;
+static int recursive;
+
+static unsigned long version;
+
+static unsigned long af;
+static unsigned long rf;
+static unsigned long sf;
+
+struct flags_char {
+ unsigned long flag;
+ char optchar;
+};
+
+static const struct flags_char flags_array[] = {
+ { EXT2_NOATIME_FL, 'A' },
+ { EXT2_SYNC_FL, 'S' },
+ { EXT2_DIRSYNC_FL, 'D' },
+ { EXT2_APPEND_FL, 'a' },
+ { EXT2_COMPR_FL, 'c' },
+ { EXT2_NODUMP_FL, 'd' },
+ { EXT2_IMMUTABLE_FL, 'i' },
+ { EXT3_JOURNAL_DATA_FL, 'j' },
+ { EXT2_SECRM_FL, 's' },
+ { EXT2_UNRM_FL, 'u' },
+ { EXT2_NOTAIL_FL, 't' },
+ { EXT2_TOPDIR_FL, 'T' },
+ { 0, 0 }
+};
+
+static unsigned long get_flag(char c)
+{
+ const struct flags_char *fp;
+ for (fp = flags_array; fp->flag; fp++)
+ if (fp->optchar == c)
+ return fp->flag;
+ bb_show_usage();
+ return 0;
+}
+
+static int decode_arg(char *arg)
+{
+ unsigned long *fl;
+ char opt = *arg++;
+
+ if (opt == '-') {
+ flags |= OPT_REM;
+ fl = &rf;
+ } else if (opt == '+') {
+ flags |= OPT_ADD;
+ fl = &af;
+ } else if (opt == '=') {
+ flags |= OPT_SET;
+ fl = &sf;
+ } else
+ return EOF;
+
+ for (; *arg; ++arg)
+ (*fl) |= get_flag(*arg);
+
+ return 1;
+}
+
+static int chattr_dir_proc(const char *, struct dirent *, void *);
+
+static void change_attributes(const char * name)
+{
+ unsigned long fsflags;
+ struct stat st;
+
+ if (lstat(name, &st) == -1) {
+ bb_error_msg("stat %s failed", name);
+ return;
+ }
+ if (S_ISLNK(st.st_mode) && recursive)
+ return;
+
+ /* Don't try to open device files, fifos etc. We probably
+ * ought to display an error if the file was explicitly given
+ * on the command line (whether or not recursive was
+ * requested). */
+ if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode))
+ return;
+
+ if (flags & OPT_SET_VER)
+ if (fsetversion(name, version) == -1)
+ bb_error_msg("setting version on %s", name);
+
+ if (flags & OPT_SET) {
+ fsflags = sf;
+ } else {
+ if (fgetflags(name, &fsflags) == -1) {
+ bb_error_msg("reading flags on %s", name);
+ goto skip_setflags;
+ }
+ if (flags & OPT_REM)
+ fsflags &= ~rf;
+ if (flags & OPT_ADD)
+ fsflags |= af;
+ if (!S_ISDIR(st.st_mode))
+ fsflags &= ~EXT2_DIRSYNC_FL;
+ }
+ if (fsetflags(name, fsflags) == -1)
+ bb_error_msg("setting flags on %s", name);
+
+skip_setflags:
+ if (S_ISDIR(st.st_mode) && recursive)
+ iterate_on_dir(name, chattr_dir_proc, NULL);
+}
+
+static int chattr_dir_proc(const char *dir_name, struct dirent *de,
+ void *private EXT2FS_ATTR((unused)))
+{
+ /*if (strcmp(de->d_name, ".") || strcmp(de->d_name, "..")) {*/
+ if (de->d_name[0] == '.'
+ && (!de->d_name[1] || (de->d_name[1] == '.' && !de->d_name[2]))
+ ) {
+ char *path = concat_subpath_file(dir_name, de->d_name);
+ if (path) {
+ change_attributes(path);
+ free(path);
+ }
+ }
+ return 0;
+}
+
+int chattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int chattr_main(int argc, char **argv)
+{
+ int i;
+ char *arg;
+
+ /* parse the args */
+ for (i = 1; i < argc; ++i) {
+ arg = argv[i];
+
+ /* take care of -R and -v <version> */
+ if (arg[0] == '-') {
+ if (arg[1] == 'R' && arg[2] == '\0') {
+ recursive = 1;
+ continue;
+ } else if (arg[1] == 'v' && arg[2] == '\0') {
+ char *tmp;
+ ++i;
+ if (i >= argc)
+ bb_show_usage();
+ version = strtol(argv[i], &tmp, 0);
+ if (*tmp)
+ bb_error_msg_and_die("bad version '%s'", arg);
+ flags |= OPT_SET_VER;
+ continue;
+ }
+ }
+
+ if (decode_arg(arg) == EOF)
+ break;
+ }
+
+ /* run sanity checks on all the arguments given us */
+ if (i >= argc)
+ bb_show_usage();
+ if ((flags & OPT_SET) && ((flags & OPT_ADD) || (flags & OPT_REM)))
+ bb_error_msg_and_die("= is incompatible with - and +");
+ if ((rf & af) != 0)
+ bb_error_msg_and_die("Can't set and unset a flag");
+ if (!flags)
+ bb_error_msg_and_die("Must use '-v', =, - or +");
+
+ /* now run chattr on all the files passed to us */
+ while (i < argc)
+ change_attributes(argv[i++]);
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2fsbb.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2fsbb.h
new file mode 100644
index 0000000000..78e7cbd04c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2fsbb.h
@@ -0,0 +1,43 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * File: e2fsbb.h
+ *
+ * Redefine a bunch of e2fsprogs stuff to use busybox routines
+ * instead. This makes upgrade between e2fsprogs versions easy.
+ */
+
+#ifndef __E2FSBB_H__
+#define __E2FSBB_H__ 1
+
+#include "libbb.h"
+
+/* version we've last synced against */
+#define E2FSPROGS_VERSION "1.38"
+#define E2FSPROGS_DATE "30-Jun-2005"
+
+typedef long errcode_t;
+#define ERRCODE_RANGE 8
+#define error_message(code) strerror((int) (code & ((1<<ERRCODE_RANGE)-1)))
+
+/* header defines */
+#define ENABLE_HTREE 1
+#define HAVE_ERRNO_H 1
+#define HAVE_EXT2_IOCTLS 1
+#define HAVE_LINUX_FD_H 1
+#define HAVE_MNTENT_H 1
+#define HAVE_NETINET_IN_H 1
+#define HAVE_NET_IF_H 1
+#define HAVE_SYS_IOCTL_H 1
+#define HAVE_SYS_MOUNT_H 1
+#define HAVE_SYS_QUEUE_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_UNISTD_H 1
+
+/* Endianness */
+#if BB_BIG_ENDIAN
+#define ENABLE_SWAPFS 1
+#define WORDS_BIGENDIAN 1
+#endif
+
+#endif /* __E2FSBB_H__ */
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2fsck.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2fsck.c
new file mode 100644
index 0000000000..4887a57d72
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2fsck.c
@@ -0,0 +1,13548 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * e2fsck
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
+ * Copyright (C) 2006 Garrett Kajmowicz
+ *
+ * Dictionary Abstract Data Type
+ * Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
+ * Free Software License:
+ * All rights are reserved by the author, with the following exceptions:
+ * Permission is granted to freely reproduce and distribute this software,
+ * possibly in exchange for a fee, provided that this copyright notice appears
+ * intact. Permission is also granted to adapt this software to produce
+ * derivative works, as long as the modified versions carry this copyright
+ * notice and additional notices stating that the work has been modified.
+ * This source code may be translated into executable form and incorporated
+ * into proprietary software; there is no requirement for such software to
+ * contain a copyright notice related to this source.
+ *
+ * linux/fs/recovery and linux/fs/revoke
+ * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
+ *
+ * Copyright 1999-2000 Red Hat Software --- All Rights Reserved
+ *
+ * Journal recovery routines for the generic filesystem journaling code;
+ * part of the ext2fs journaling system.
+ *
+ * Licensed under GPLv2 or later, see file License in this tarball for details.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1 /* get strnlen() */
+#endif
+
+#include "e2fsck.h" /*Put all of our defines here to clean things up*/
+
+#define _(x) x
+#define N_(x) x
+
+/*
+ * Procedure declarations
+ */
+
+static void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf);
+
+/* pass1.c */
+static void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool);
+
+/* pass2.c */
+static int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
+ ext2_ino_t ino, char *buf);
+
+/* pass3.c */
+static int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t inode);
+static errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
+ int num, int gauranteed_size);
+static ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix);
+static errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino,
+ int adj);
+
+/* rehash.c */
+static void e2fsck_rehash_directories(e2fsck_t ctx);
+
+/* util.c */
+static void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
+ const char *description);
+static int ask(e2fsck_t ctx, const char * string, int def);
+static void e2fsck_read_bitmaps(e2fsck_t ctx);
+static void preenhalt(e2fsck_t ctx);
+static void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
+ struct ext2_inode * inode, const char * proc);
+static void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
+ struct ext2_inode * inode, const char * proc);
+static blk_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs,
+ const char *name, io_manager manager);
+
+/* unix.c */
+static void e2fsck_clear_progbar(e2fsck_t ctx);
+static int e2fsck_simple_progress(e2fsck_t ctx, const char *label,
+ float percent, unsigned int dpynum);
+
+
+/*
+ * problem.h --- e2fsck problem error codes
+ */
+
+typedef __u32 problem_t;
+
+struct problem_context {
+ errcode_t errcode;
+ ext2_ino_t ino, ino2, dir;
+ struct ext2_inode *inode;
+ struct ext2_dir_entry *dirent;
+ blk_t blk, blk2;
+ e2_blkcnt_t blkcount;
+ int group;
+ __u64 num;
+ const char *str;
+};
+
+
+/*
+ * Function declarations
+ */
+static int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx);
+static int end_problem_latch(e2fsck_t ctx, int mask);
+static int set_latch_flags(int mask, int setflags, int clearflags);
+static void clear_problem_context(struct problem_context *ctx);
+
+/*
+ * Dictionary Abstract Data Type
+ * Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
+ *
+ * dict.h v 1.22.2.6 2000/11/13 01:36:44 kaz
+ * kazlib_1_20
+ */
+
+#ifndef DICT_H
+#define DICT_H
+
+/*
+ * Blurb for inclusion into C++ translation units
+ */
+
+typedef unsigned long dictcount_t;
+#define DICTCOUNT_T_MAX ULONG_MAX
+
+/*
+ * The dictionary is implemented as a red-black tree
+ */
+
+typedef enum { dnode_red, dnode_black } dnode_color_t;
+
+typedef struct dnode_t {
+ struct dnode_t *dict_left;
+ struct dnode_t *dict_right;
+ struct dnode_t *dict_parent;
+ dnode_color_t dict_color;
+ const void *dict_key;
+ void *dict_data;
+} dnode_t;
+
+typedef int (*dict_comp_t)(const void *, const void *);
+typedef void (*dnode_free_t)(dnode_t *);
+
+typedef struct dict_t {
+ dnode_t dict_nilnode;
+ dictcount_t dict_nodecount;
+ dictcount_t dict_maxcount;
+ dict_comp_t dict_compare;
+ dnode_free_t dict_freenode;
+ int dict_dupes;
+} dict_t;
+
+typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *);
+
+typedef struct dict_load_t {
+ dict_t *dict_dictptr;
+ dnode_t dict_nilnode;
+} dict_load_t;
+
+#define dict_count(D) ((D)->dict_nodecount)
+#define dnode_get(N) ((N)->dict_data)
+#define dnode_getkey(N) ((N)->dict_key)
+
+#endif
+
+/*
+ * Compatibility header file for e2fsck which should be included
+ * instead of linux/jfs.h
+ *
+ * Copyright (C) 2000 Stephen C. Tweedie
+ */
+
+/*
+ * Pull in the definition of the e2fsck context structure
+ */
+
+struct buffer_head {
+ char b_data[8192];
+ e2fsck_t b_ctx;
+ io_channel b_io;
+ int b_size;
+ blk_t b_blocknr;
+ int b_dirty;
+ int b_uptodate;
+ int b_err;
+};
+
+
+#define K_DEV_FS 1
+#define K_DEV_JOURNAL 2
+
+#define lock_buffer(bh) do {} while(0)
+#define unlock_buffer(bh) do {} while(0)
+#define buffer_req(bh) 1
+#define do_readahead(journal, start) do {} while(0)
+
+static e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */
+
+typedef struct {
+ int object_length;
+} kmem_cache_t;
+
+#define kmem_cache_alloc(cache,flags) malloc((cache)->object_length)
+
+/*
+ * We use the standard libext2fs portability tricks for inline
+ * functions.
+ */
+
+static kmem_cache_t * do_cache_create(int len)
+{
+ kmem_cache_t *new_cache;
+
+ new_cache = malloc(sizeof(*new_cache));
+ if (new_cache)
+ new_cache->object_length = len;
+ return new_cache;
+}
+
+static void do_cache_destroy(kmem_cache_t *cache)
+{
+ free(cache);
+}
+
+
+/*
+ * Dictionary Abstract Data Type
+ */
+
+
+/*
+ * These macros provide short convenient names for structure members,
+ * which are embellished with dict_ prefixes so that they are
+ * properly confined to the documented namespace. It's legal for a
+ * program which uses dict to define, for instance, a macro called ``parent''.
+ * Such a macro would interfere with the dnode_t struct definition.
+ * In general, highly portable and reusable C modules which expose their
+ * structures need to confine structure member names to well-defined spaces.
+ * The resulting identifiers aren't necessarily convenient to use, nor
+ * readable, in the implementation, however!
+ */
+
+#define left dict_left
+#define right dict_right
+#define parent dict_parent
+#define color dict_color
+#define key dict_key
+#define data dict_data
+
+#define nilnode dict_nilnode
+#define maxcount dict_maxcount
+#define compare dict_compare
+#define dupes dict_dupes
+
+#define dict_root(D) ((D)->nilnode.left)
+#define dict_nil(D) (&(D)->nilnode)
+
+static void dnode_free(dnode_t *node);
+
+/*
+ * Perform a ``left rotation'' adjustment on the tree. The given node P and
+ * its right child C are rearranged so that the P instead becomes the left
+ * child of C. The left subtree of C is inherited as the new right subtree
+ * for P. The ordering of the keys within the tree is thus preserved.
+ */
+
+static void rotate_left(dnode_t *upper)
+{
+ dnode_t *lower, *lowleft, *upparent;
+
+ lower = upper->right;
+ upper->right = lowleft = lower->left;
+ lowleft->parent = upper;
+
+ lower->parent = upparent = upper->parent;
+
+ /* don't need to check for root node here because root->parent is
+ the sentinel nil node, and root->parent->left points back to root */
+
+ if (upper == upparent->left) {
+ upparent->left = lower;
+ } else {
+ assert (upper == upparent->right);
+ upparent->right = lower;
+ }
+
+ lower->left = upper;
+ upper->parent = lower;
+}
+
+/*
+ * This operation is the ``mirror'' image of rotate_left. It is
+ * the same procedure, but with left and right interchanged.
+ */
+
+static void rotate_right(dnode_t *upper)
+{
+ dnode_t *lower, *lowright, *upparent;
+
+ lower = upper->left;
+ upper->left = lowright = lower->right;
+ lowright->parent = upper;
+
+ lower->parent = upparent = upper->parent;
+
+ if (upper == upparent->right) {
+ upparent->right = lower;
+ } else {
+ assert (upper == upparent->left);
+ upparent->left = lower;
+ }
+
+ lower->right = upper;
+ upper->parent = lower;
+}
+
+/*
+ * Do a postorder traversal of the tree rooted at the specified
+ * node and free everything under it. Used by dict_free().
+ */
+
+static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil)
+{
+ if (node == nil)
+ return;
+ free_nodes(dict, node->left, nil);
+ free_nodes(dict, node->right, nil);
+ dict->dict_freenode(node);
+}
+
+/*
+ * Verify that the tree contains the given node. This is done by
+ * traversing all of the nodes and comparing their pointers to the
+ * given pointer. Returns 1 if the node is found, otherwise
+ * returns zero. It is intended for debugging purposes.
+ */
+
+static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node)
+{
+ if (root != nil) {
+ return root == node
+ || verify_dict_has_node(nil, root->left, node)
+ || verify_dict_has_node(nil, root->right, node);
+ }
+ return 0;
+}
+
+
+/*
+ * Select a different set of node allocator routines.
+ */
+
+static void dict_set_allocator(dict_t *dict, dnode_free_t fr)
+{
+ assert (dict_count(dict) == 0);
+ dict->dict_freenode = fr;
+}
+
+/*
+ * Free all the nodes in the dictionary by using the dictionary's
+ * installed free routine. The dictionary is emptied.
+ */
+
+static void dict_free_nodes(dict_t *dict)
+{
+ dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
+ free_nodes(dict, root, nil);
+ dict->dict_nodecount = 0;
+ dict->nilnode.left = &dict->nilnode;
+ dict->nilnode.right = &dict->nilnode;
+}
+
+/*
+ * Initialize a user-supplied dictionary object.
+ */
+
+static dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp)
+{
+ dict->compare = comp;
+ dict->dict_freenode = dnode_free;
+ dict->dict_nodecount = 0;
+ dict->maxcount = maxcount;
+ dict->nilnode.left = &dict->nilnode;
+ dict->nilnode.right = &dict->nilnode;
+ dict->nilnode.parent = &dict->nilnode;
+ dict->nilnode.color = dnode_black;
+ dict->dupes = 0;
+ return dict;
+}
+
+/*
+ * Locate a node in the dictionary having the given key.
+ * If the node is not found, a null a pointer is returned (rather than
+ * a pointer that dictionary's nil sentinel node), otherwise a pointer to the
+ * located node is returned.
+ */
+
+static dnode_t *dict_lookup(dict_t *dict, const void *key)
+{
+ dnode_t *root = dict_root(dict);
+ dnode_t *nil = dict_nil(dict);
+ dnode_t *saved;
+ int result;
+
+ /* simple binary search adapted for trees that contain duplicate keys */
+
+ while (root != nil) {
+ result = dict->compare(key, root->key);
+ if (result < 0)
+ root = root->left;
+ else if (result > 0)
+ root = root->right;
+ else {
+ if (!dict->dupes) { /* no duplicates, return match */
+ return root;
+ } else { /* could be dupes, find leftmost one */
+ do {
+ saved = root;
+ root = root->left;
+ while (root != nil && dict->compare(key, root->key))
+ root = root->right;
+ } while (root != nil);
+ return saved;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Insert a node into the dictionary. The node should have been
+ * initialized with a data field. All other fields are ignored.
+ * The behavior is undefined if the user attempts to insert into
+ * a dictionary that is already full (for which the dict_isfull()
+ * function returns true).
+ */
+
+static void dict_insert(dict_t *dict, dnode_t *node, const void *key)
+{
+ dnode_t *where = dict_root(dict), *nil = dict_nil(dict);
+ dnode_t *parent = nil, *uncle, *grandpa;
+ int result = -1;
+
+ node->key = key;
+
+ /* basic binary tree insert */
+
+ while (where != nil) {
+ parent = where;
+ result = dict->compare(key, where->key);
+ /* trap attempts at duplicate key insertion unless it's explicitly allowed */
+ assert (dict->dupes || result != 0);
+ if (result < 0)
+ where = where->left;
+ else
+ where = where->right;
+ }
+
+ assert (where == nil);
+
+ if (result < 0)
+ parent->left = node;
+ else
+ parent->right = node;
+
+ node->parent = parent;
+ node->left = nil;
+ node->right = nil;
+
+ dict->dict_nodecount++;
+
+ /* red black adjustments */
+
+ node->color = dnode_red;
+
+ while (parent->color == dnode_red) {
+ grandpa = parent->parent;
+ if (parent == grandpa->left) {
+ uncle = grandpa->right;
+ if (uncle->color == dnode_red) { /* red parent, red uncle */
+ parent->color = dnode_black;
+ uncle->color = dnode_black;
+ grandpa->color = dnode_red;
+ node = grandpa;
+ parent = grandpa->parent;
+ } else { /* red parent, black uncle */
+ if (node == parent->right) {
+ rotate_left(parent);
+ parent = node;
+ assert (grandpa == parent->parent);
+ /* rotation between parent and child preserves grandpa */
+ }
+ parent->color = dnode_black;
+ grandpa->color = dnode_red;
+ rotate_right(grandpa);
+ break;
+ }
+ } else { /* symmetric cases: parent == parent->parent->right */
+ uncle = grandpa->left;
+ if (uncle->color == dnode_red) {
+ parent->color = dnode_black;
+ uncle->color = dnode_black;
+ grandpa->color = dnode_red;
+ node = grandpa;
+ parent = grandpa->parent;
+ } else {
+ if (node == parent->left) {
+ rotate_right(parent);
+ parent = node;
+ assert (grandpa == parent->parent);
+ }
+ parent->color = dnode_black;
+ grandpa->color = dnode_red;
+ rotate_left(grandpa);
+ break;
+ }
+ }
+ }
+
+ dict_root(dict)->color = dnode_black;
+
+}
+
+/*
+ * Allocate a node using the dictionary's allocator routine, give it
+ * the data item.
+ */
+
+static dnode_t *dnode_init(dnode_t *dnode, void *data)
+{
+ dnode->data = data;
+ dnode->parent = NULL;
+ dnode->left = NULL;
+ dnode->right = NULL;
+ return dnode;
+}
+
+static int dict_alloc_insert(dict_t *dict, const void *key, void *data)
+{
+ dnode_t *node = malloc(sizeof(dnode_t));
+
+ if (node) {
+ dnode_init(node, data);
+ dict_insert(dict, node, key);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Return the node with the lowest (leftmost) key. If the dictionary is empty
+ * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
+ */
+
+static dnode_t *dict_first(dict_t *dict)
+{
+ dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left;
+
+ if (root != nil)
+ while ((left = root->left) != nil)
+ root = left;
+
+ return (root == nil) ? NULL : root;
+}
+
+/*
+ * Return the given node's successor node---the node which has the
+ * next key in the the left to right ordering. If the node has
+ * no successor, a null pointer is returned rather than a pointer to
+ * the nil node.
+ */
+
+static dnode_t *dict_next(dict_t *dict, dnode_t *curr)
+{
+ dnode_t *nil = dict_nil(dict), *parent, *left;
+
+ if (curr->right != nil) {
+ curr = curr->right;
+ while ((left = curr->left) != nil)
+ curr = left;
+ return curr;
+ }
+
+ parent = curr->parent;
+
+ while (parent != nil && curr == parent->right) {
+ curr = parent;
+ parent = curr->parent;
+ }
+
+ return (parent == nil) ? NULL : parent;
+}
+
+
+static void dnode_free(dnode_t *node)
+{
+ free(node);
+}
+
+
+#undef left
+#undef right
+#undef parent
+#undef color
+#undef key
+#undef data
+
+#undef nilnode
+#undef maxcount
+#undef compare
+#undef dupes
+
+
+/*
+ * dirinfo.c --- maintains the directory information table for e2fsck.
+ */
+
+/*
+ * This subroutine is called during pass1 to create a directory info
+ * entry. During pass1, the passed-in parent is 0; it will get filled
+ * in during pass2.
+ */
+static void e2fsck_add_dir_info(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent)
+{
+ struct dir_info *dir;
+ int i, j;
+ ext2_ino_t num_dirs;
+ errcode_t retval;
+ unsigned long old_size;
+
+ if (!ctx->dir_info) {
+ ctx->dir_info_count = 0;
+ retval = ext2fs_get_num_dirs(ctx->fs, &num_dirs);
+ if (retval)
+ num_dirs = 1024; /* Guess */
+ ctx->dir_info_size = num_dirs + 10;
+ ctx->dir_info = (struct dir_info *)
+ e2fsck_allocate_memory(ctx, ctx->dir_info_size
+ * sizeof (struct dir_info),
+ "directory map");
+ }
+
+ if (ctx->dir_info_count >= ctx->dir_info_size) {
+ old_size = ctx->dir_info_size * sizeof(struct dir_info);
+ ctx->dir_info_size += 10;
+ retval = ext2fs_resize_mem(old_size, ctx->dir_info_size *
+ sizeof(struct dir_info),
+ &ctx->dir_info);
+ if (retval) {
+ ctx->dir_info_size -= 10;
+ return;
+ }
+ }
+
+ /*
+ * Normally, add_dir_info is called with each inode in
+ * sequential order; but once in a while (like when pass 3
+ * needs to recreate the root directory or lost+found
+ * directory) it is called out of order. In those cases, we
+ * need to move the dir_info entries down to make room, since
+ * the dir_info array needs to be sorted by inode number for
+ * get_dir_info()'s sake.
+ */
+ if (ctx->dir_info_count &&
+ ctx->dir_info[ctx->dir_info_count-1].ino >= ino) {
+ for (i = ctx->dir_info_count-1; i > 0; i--)
+ if (ctx->dir_info[i-1].ino < ino)
+ break;
+ dir = &ctx->dir_info[i];
+ if (dir->ino != ino)
+ for (j = ctx->dir_info_count++; j > i; j--)
+ ctx->dir_info[j] = ctx->dir_info[j-1];
+ } else
+ dir = &ctx->dir_info[ctx->dir_info_count++];
+
+ dir->ino = ino;
+ dir->dotdot = parent;
+ dir->parent = parent;
+}
+
+/*
+ * get_dir_info() --- given an inode number, try to find the directory
+ * information entry for it.
+ */
+static struct dir_info *e2fsck_get_dir_info(e2fsck_t ctx, ext2_ino_t ino)
+{
+ int low, high, mid;
+
+ low = 0;
+ high = ctx->dir_info_count-1;
+ if (!ctx->dir_info)
+ return 0;
+ if (ino == ctx->dir_info[low].ino)
+ return &ctx->dir_info[low];
+ if (ino == ctx->dir_info[high].ino)
+ return &ctx->dir_info[high];
+
+ while (low < high) {
+ mid = (low+high)/2;
+ if (mid == low || mid == high)
+ break;
+ if (ino == ctx->dir_info[mid].ino)
+ return &ctx->dir_info[mid];
+ if (ino < ctx->dir_info[mid].ino)
+ high = mid;
+ else
+ low = mid;
+ }
+ return 0;
+}
+
+/*
+ * Free the dir_info structure when it isn't needed any more.
+ */
+static void e2fsck_free_dir_info(e2fsck_t ctx)
+{
+ ext2fs_free_mem(&ctx->dir_info);
+ ctx->dir_info_size = 0;
+ ctx->dir_info_count = 0;
+}
+
+/*
+ * Return the count of number of directories in the dir_info structure
+ */
+static int e2fsck_get_num_dirinfo(e2fsck_t ctx)
+{
+ return ctx->dir_info_count;
+}
+
+/*
+ * A simple interator function
+ */
+static struct dir_info *e2fsck_dir_info_iter(e2fsck_t ctx, int *control)
+{
+ if (*control >= ctx->dir_info_count)
+ return 0;
+
+ return ctx->dir_info + (*control)++;
+}
+
+/*
+ * dirinfo.c --- maintains the directory information table for e2fsck.
+ *
+ */
+
+#ifdef ENABLE_HTREE
+
+/*
+ * This subroutine is called during pass1 to create a directory info
+ * entry. During pass1, the passed-in parent is 0; it will get filled
+ * in during pass2.
+ */
+static void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino, int num_blocks)
+{
+ struct dx_dir_info *dir;
+ int i, j;
+ errcode_t retval;
+ unsigned long old_size;
+
+ if (!ctx->dx_dir_info) {
+ ctx->dx_dir_info_count = 0;
+ ctx->dx_dir_info_size = 100; /* Guess */
+ ctx->dx_dir_info = (struct dx_dir_info *)
+ e2fsck_allocate_memory(ctx, ctx->dx_dir_info_size
+ * sizeof (struct dx_dir_info),
+ "directory map");
+ }
+
+ if (ctx->dx_dir_info_count >= ctx->dx_dir_info_size) {
+ old_size = ctx->dx_dir_info_size * sizeof(struct dx_dir_info);
+ ctx->dx_dir_info_size += 10;
+ retval = ext2fs_resize_mem(old_size, ctx->dx_dir_info_size *
+ sizeof(struct dx_dir_info),
+ &ctx->dx_dir_info);
+ if (retval) {
+ ctx->dx_dir_info_size -= 10;
+ return;
+ }
+ }
+
+ /*
+ * Normally, add_dx_dir_info is called with each inode in
+ * sequential order; but once in a while (like when pass 3
+ * needs to recreate the root directory or lost+found
+ * directory) it is called out of order. In those cases, we
+ * need to move the dx_dir_info entries down to make room, since
+ * the dx_dir_info array needs to be sorted by inode number for
+ * get_dx_dir_info()'s sake.
+ */
+ if (ctx->dx_dir_info_count &&
+ ctx->dx_dir_info[ctx->dx_dir_info_count-1].ino >= ino) {
+ for (i = ctx->dx_dir_info_count-1; i > 0; i--)
+ if (ctx->dx_dir_info[i-1].ino < ino)
+ break;
+ dir = &ctx->dx_dir_info[i];
+ if (dir->ino != ino)
+ for (j = ctx->dx_dir_info_count++; j > i; j--)
+ ctx->dx_dir_info[j] = ctx->dx_dir_info[j-1];
+ } else
+ dir = &ctx->dx_dir_info[ctx->dx_dir_info_count++];
+
+ dir->ino = ino;
+ dir->numblocks = num_blocks;
+ dir->hashversion = 0;
+ dir->dx_block = e2fsck_allocate_memory(ctx, num_blocks
+ * sizeof (struct dx_dirblock_info),
+ "dx_block info array");
+
+}
+
+/*
+ * get_dx_dir_info() --- given an inode number, try to find the directory
+ * information entry for it.
+ */
+static struct dx_dir_info *e2fsck_get_dx_dir_info(e2fsck_t ctx, ext2_ino_t ino)
+{
+ int low, high, mid;
+
+ low = 0;
+ high = ctx->dx_dir_info_count-1;
+ if (!ctx->dx_dir_info)
+ return 0;
+ if (ino == ctx->dx_dir_info[low].ino)
+ return &ctx->dx_dir_info[low];
+ if (ino == ctx->dx_dir_info[high].ino)
+ return &ctx->dx_dir_info[high];
+
+ while (low < high) {
+ mid = (low+high)/2;
+ if (mid == low || mid == high)
+ break;
+ if (ino == ctx->dx_dir_info[mid].ino)
+ return &ctx->dx_dir_info[mid];
+ if (ino < ctx->dx_dir_info[mid].ino)
+ high = mid;
+ else
+ low = mid;
+ }
+ return 0;
+}
+
+/*
+ * Free the dx_dir_info structure when it isn't needed any more.
+ */
+static void e2fsck_free_dx_dir_info(e2fsck_t ctx)
+{
+ int i;
+ struct dx_dir_info *dir;
+
+ if (ctx->dx_dir_info) {
+ dir = ctx->dx_dir_info;
+ for (i=0; i < ctx->dx_dir_info_count; i++) {
+ ext2fs_free_mem(&dir->dx_block);
+ }
+ ext2fs_free_mem(&ctx->dx_dir_info);
+ }
+ ctx->dx_dir_info_size = 0;
+ ctx->dx_dir_info_count = 0;
+}
+
+/*
+ * A simple interator function
+ */
+static struct dx_dir_info *e2fsck_dx_dir_info_iter(e2fsck_t ctx, int *control)
+{
+ if (*control >= ctx->dx_dir_info_count)
+ return 0;
+
+ return ctx->dx_dir_info + (*control)++;
+}
+
+#endif /* ENABLE_HTREE */
+/*
+ * e2fsck.c - a consistency checker for the new extended file system.
+ *
+ */
+
+/*
+ * This function allocates an e2fsck context
+ */
+static errcode_t e2fsck_allocate_context(e2fsck_t *ret)
+{
+ e2fsck_t context;
+ errcode_t retval;
+
+ retval = ext2fs_get_mem(sizeof(struct e2fsck_struct), &context);
+ if (retval)
+ return retval;
+
+ memset(context, 0, sizeof(struct e2fsck_struct));
+
+ context->process_inode_size = 256;
+ context->ext_attr_ver = 2;
+
+ *ret = context;
+ return 0;
+}
+
+struct ea_refcount_el {
+ blk_t ea_blk;
+ int ea_count;
+};
+
+struct ea_refcount {
+ blk_t count;
+ blk_t size;
+ blk_t cursor;
+ struct ea_refcount_el *list;
+};
+
+static void ea_refcount_free(ext2_refcount_t refcount)
+{
+ if (!refcount)
+ return;
+
+ ext2fs_free_mem(&refcount->list);
+ ext2fs_free_mem(&refcount);
+}
+
+/*
+ * This function resets an e2fsck context; it is called when e2fsck
+ * needs to be restarted.
+ */
+static errcode_t e2fsck_reset_context(e2fsck_t ctx)
+{
+ ctx->flags = 0;
+ ctx->lost_and_found = 0;
+ ctx->bad_lost_and_found = 0;
+ ext2fs_free_inode_bitmap(ctx->inode_used_map);
+ ctx->inode_used_map = 0;
+ ext2fs_free_inode_bitmap(ctx->inode_dir_map);
+ ctx->inode_dir_map = 0;
+ ext2fs_free_inode_bitmap(ctx->inode_reg_map);
+ ctx->inode_reg_map = 0;
+ ext2fs_free_block_bitmap(ctx->block_found_map);
+ ctx->block_found_map = 0;
+ ext2fs_free_icount(ctx->inode_link_info);
+ ctx->inode_link_info = 0;
+ if (ctx->journal_io) {
+ if (ctx->fs && ctx->fs->io != ctx->journal_io)
+ io_channel_close(ctx->journal_io);
+ ctx->journal_io = 0;
+ }
+ if (ctx->fs) {
+ ext2fs_free_dblist(ctx->fs->dblist);
+ ctx->fs->dblist = 0;
+ }
+ e2fsck_free_dir_info(ctx);
+#ifdef ENABLE_HTREE
+ e2fsck_free_dx_dir_info(ctx);
+#endif
+ ea_refcount_free(ctx->refcount);
+ ctx->refcount = 0;
+ ea_refcount_free(ctx->refcount_extra);
+ ctx->refcount_extra = 0;
+ ext2fs_free_block_bitmap(ctx->block_dup_map);
+ ctx->block_dup_map = 0;
+ ext2fs_free_block_bitmap(ctx->block_ea_map);
+ ctx->block_ea_map = 0;
+ ext2fs_free_inode_bitmap(ctx->inode_bad_map);
+ ctx->inode_bad_map = 0;
+ ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
+ ctx->inode_imagic_map = 0;
+ ext2fs_u32_list_free(ctx->dirs_to_hash);
+ ctx->dirs_to_hash = 0;
+
+ /*
+ * Clear the array of invalid meta-data flags
+ */
+ ext2fs_free_mem(&ctx->invalid_inode_bitmap_flag);
+ ext2fs_free_mem(&ctx->invalid_block_bitmap_flag);
+ ext2fs_free_mem(&ctx->invalid_inode_table_flag);
+
+ /* Clear statistic counters */
+ ctx->fs_directory_count = 0;
+ ctx->fs_regular_count = 0;
+ ctx->fs_blockdev_count = 0;
+ ctx->fs_chardev_count = 0;
+ ctx->fs_links_count = 0;
+ ctx->fs_symlinks_count = 0;
+ ctx->fs_fast_symlinks_count = 0;
+ ctx->fs_fifo_count = 0;
+ ctx->fs_total_count = 0;
+ ctx->fs_sockets_count = 0;
+ ctx->fs_ind_count = 0;
+ ctx->fs_dind_count = 0;
+ ctx->fs_tind_count = 0;
+ ctx->fs_fragmented = 0;
+ ctx->large_files = 0;
+
+ /* Reset the superblock to the user's requested value */
+ ctx->superblock = ctx->use_superblock;
+
+ return 0;
+}
+
+static void e2fsck_free_context(e2fsck_t ctx)
+{
+ if (!ctx)
+ return;
+
+ e2fsck_reset_context(ctx);
+ if (ctx->blkid)
+ blkid_put_cache(ctx->blkid);
+
+ ext2fs_free_mem(&ctx);
+}
+
+/*
+ * ea_refcount.c
+ */
+
+/*
+ * The strategy we use for keeping track of EA refcounts is as
+ * follows. We keep a sorted array of first EA blocks and its
+ * reference counts. Once the refcount has dropped to zero, it is
+ * removed from the array to save memory space. Once the EA block is
+ * checked, its bit is set in the block_ea_map bitmap.
+ */
+
+
+static errcode_t ea_refcount_create(int size, ext2_refcount_t *ret)
+{
+ ext2_refcount_t refcount;
+ errcode_t retval;
+ size_t bytes;
+
+ retval = ext2fs_get_mem(sizeof(struct ea_refcount), &refcount);
+ if (retval)
+ return retval;
+ memset(refcount, 0, sizeof(struct ea_refcount));
+
+ if (!size)
+ size = 500;
+ refcount->size = size;
+ bytes = (size_t) (size * sizeof(struct ea_refcount_el));
+#ifdef DEBUG
+ printf("Refcount allocated %d entries, %d bytes.\n",
+ refcount->size, bytes);
+#endif
+ retval = ext2fs_get_mem(bytes, &refcount->list);
+ if (retval)
+ goto errout;
+ memset(refcount->list, 0, bytes);
+
+ refcount->count = 0;
+ refcount->cursor = 0;
+
+ *ret = refcount;
+ return 0;
+
+errout:
+ ea_refcount_free(refcount);
+ return retval;
+}
+
+/*
+ * collapse_refcount() --- go through the refcount array, and get rid
+ * of any count == zero entries
+ */
+static void refcount_collapse(ext2_refcount_t refcount)
+{
+ unsigned int i, j;
+ struct ea_refcount_el *list;
+
+ list = refcount->list;
+ for (i = 0, j = 0; i < refcount->count; i++) {
+ if (list[i].ea_count) {
+ if (i != j)
+ list[j] = list[i];
+ j++;
+ }
+ }
+#if defined(DEBUG) || defined(TEST_PROGRAM)
+ printf("Refcount_collapse: size was %d, now %d\n",
+ refcount->count, j);
+#endif
+ refcount->count = j;
+}
+
+
+/*
+ * insert_refcount_el() --- Insert a new entry into the sorted list at a
+ * specified position.
+ */
+static struct ea_refcount_el *insert_refcount_el(ext2_refcount_t refcount,
+ blk_t blk, int pos)
+{
+ struct ea_refcount_el *el;
+ errcode_t retval;
+ blk_t new_size = 0;
+ int num;
+
+ if (refcount->count >= refcount->size) {
+ new_size = refcount->size + 100;
+#ifdef DEBUG
+ printf("Reallocating refcount %d entries...\n", new_size);
+#endif
+ retval = ext2fs_resize_mem((size_t) refcount->size *
+ sizeof(struct ea_refcount_el),
+ (size_t) new_size *
+ sizeof(struct ea_refcount_el),
+ &refcount->list);
+ if (retval)
+ return 0;
+ refcount->size = new_size;
+ }
+ num = (int) refcount->count - pos;
+ if (num < 0)
+ return 0; /* should never happen */
+ if (num) {
+ memmove(&refcount->list[pos+1], &refcount->list[pos],
+ sizeof(struct ea_refcount_el) * num);
+ }
+ refcount->count++;
+ el = &refcount->list[pos];
+ el->ea_count = 0;
+ el->ea_blk = blk;
+ return el;
+}
+
+
+/*
+ * get_refcount_el() --- given an block number, try to find refcount
+ * information in the sorted list. If the create flag is set,
+ * and we can't find an entry, create one in the sorted list.
+ */
+static struct ea_refcount_el *get_refcount_el(ext2_refcount_t refcount,
+ blk_t blk, int create)
+{
+ float range;
+ int low, high, mid;
+ blk_t lowval, highval;
+
+ if (!refcount || !refcount->list)
+ return 0;
+retry:
+ low = 0;
+ high = (int) refcount->count-1;
+ if (create && ((refcount->count == 0) ||
+ (blk > refcount->list[high].ea_blk))) {
+ if (refcount->count >= refcount->size)
+ refcount_collapse(refcount);
+
+ return insert_refcount_el(refcount, blk,
+ (unsigned) refcount->count);
+ }
+ if (refcount->count == 0)
+ return 0;
+
+ if (refcount->cursor >= refcount->count)
+ refcount->cursor = 0;
+ if (blk == refcount->list[refcount->cursor].ea_blk)
+ return &refcount->list[refcount->cursor++];
+#ifdef DEBUG
+ printf("Non-cursor get_refcount_el: %u\n", blk);
+#endif
+ while (low <= high) {
+ if (low == high)
+ mid = low;
+ else {
+ /* Interpolate for efficiency */
+ lowval = refcount->list[low].ea_blk;
+ highval = refcount->list[high].ea_blk;
+
+ if (blk < lowval)
+ range = 0;
+ else if (blk > highval)
+ range = 1;
+ else
+ range = ((float) (blk - lowval)) /
+ (highval - lowval);
+ mid = low + ((int) (range * (high-low)));
+ }
+
+ if (blk == refcount->list[mid].ea_blk) {
+ refcount->cursor = mid+1;
+ return &refcount->list[mid];
+ }
+ if (blk < refcount->list[mid].ea_blk)
+ high = mid-1;
+ else
+ low = mid+1;
+ }
+ /*
+ * If we need to create a new entry, it should be right at
+ * low (where high will be left at low-1).
+ */
+ if (create) {
+ if (refcount->count >= refcount->size) {
+ refcount_collapse(refcount);
+ if (refcount->count < refcount->size)
+ goto retry;
+ }
+ return insert_refcount_el(refcount, blk, low);
+ }
+ return 0;
+}
+
+static errcode_t
+ea_refcount_increment(ext2_refcount_t refcount, blk_t blk, int *ret)
+{
+ struct ea_refcount_el *el;
+
+ el = get_refcount_el(refcount, blk, 1);
+ if (!el)
+ return EXT2_ET_NO_MEMORY;
+ el->ea_count++;
+
+ if (ret)
+ *ret = el->ea_count;
+ return 0;
+}
+
+static errcode_t
+ea_refcount_decrement(ext2_refcount_t refcount, blk_t blk, int *ret)
+{
+ struct ea_refcount_el *el;
+
+ el = get_refcount_el(refcount, blk, 0);
+ if (!el || el->ea_count == 0)
+ return EXT2_ET_INVALID_ARGUMENT;
+
+ el->ea_count--;
+
+ if (ret)
+ *ret = el->ea_count;
+ return 0;
+}
+
+static errcode_t
+ea_refcount_store(ext2_refcount_t refcount, blk_t blk, int count)
+{
+ struct ea_refcount_el *el;
+
+ /*
+ * Get the refcount element
+ */
+ el = get_refcount_el(refcount, blk, count ? 1 : 0);
+ if (!el)
+ return count ? EXT2_ET_NO_MEMORY : 0;
+ el->ea_count = count;
+ return 0;
+}
+
+static inline void ea_refcount_intr_begin(ext2_refcount_t refcount)
+{
+ refcount->cursor = 0;
+}
+
+
+static blk_t ea_refcount_intr_next(ext2_refcount_t refcount, int *ret)
+{
+ struct ea_refcount_el *list;
+
+ while (1) {
+ if (refcount->cursor >= refcount->count)
+ return 0;
+ list = refcount->list;
+ if (list[refcount->cursor].ea_count) {
+ if (ret)
+ *ret = list[refcount->cursor].ea_count;
+ return list[refcount->cursor++].ea_blk;
+ }
+ refcount->cursor++;
+ }
+}
+
+
+/*
+ * ehandler.c --- handle bad block errors which come up during the
+ * course of an e2fsck session.
+ */
+
+
+static const char *operation;
+
+static errcode_t
+e2fsck_handle_read_error(io_channel channel, unsigned long block, int count,
+ void *data, size_t size FSCK_ATTR((unused)),
+ int actual FSCK_ATTR((unused)), errcode_t error)
+{
+ int i;
+ char *p;
+ ext2_filsys fs = (ext2_filsys) channel->app_data;
+ e2fsck_t ctx;
+
+ ctx = (e2fsck_t) fs->priv_data;
+
+ /*
+ * If more than one block was read, try reading each block
+ * separately. We could use the actual bytes read to figure
+ * out where to start, but we don't bother.
+ */
+ if (count > 1) {
+ p = (char *) data;
+ for (i=0; i < count; i++, p += channel->block_size, block++) {
+ error = io_channel_read_blk(channel, block,
+ 1, p);
+ if (error)
+ return error;
+ }
+ return 0;
+ }
+ if (operation)
+ printf(_("Error reading block %lu (%s) while %s. "), block,
+ error_message(error), operation);
+ else
+ printf(_("Error reading block %lu (%s). "), block,
+ error_message(error));
+ preenhalt(ctx);
+ if (ask(ctx, _("Ignore error"), 1)) {
+ if (ask(ctx, _("Force rewrite"), 1))
+ io_channel_write_blk(channel, block, 1, data);
+ return 0;
+ }
+
+ return error;
+}
+
+static errcode_t
+e2fsck_handle_write_error(io_channel channel, unsigned long block, int count,
+ const void *data, size_t size FSCK_ATTR((unused)),
+ int actual FSCK_ATTR((unused)), errcode_t error)
+{
+ int i;
+ const char *p;
+ ext2_filsys fs = (ext2_filsys) channel->app_data;
+ e2fsck_t ctx;
+
+ ctx = (e2fsck_t) fs->priv_data;
+
+ /*
+ * If more than one block was written, try writing each block
+ * separately. We could use the actual bytes read to figure
+ * out where to start, but we don't bother.
+ */
+ if (count > 1) {
+ p = (const char *) data;
+ for (i=0; i < count; i++, p += channel->block_size, block++) {
+ error = io_channel_write_blk(channel, block,
+ 1, p);
+ if (error)
+ return error;
+ }
+ return 0;
+ }
+
+ if (operation)
+ printf(_("Error writing block %lu (%s) while %s. "), block,
+ error_message(error), operation);
+ else
+ printf(_("Error writing block %lu (%s). "), block,
+ error_message(error));
+ preenhalt(ctx);
+ if (ask(ctx, _("Ignore error"), 1))
+ return 0;
+
+ return error;
+}
+
+static const char *ehandler_operation(const char *op)
+{
+ const char *ret = operation;
+
+ operation = op;
+ return ret;
+}
+
+static void ehandler_init(io_channel channel)
+{
+ channel->read_error = e2fsck_handle_read_error;
+ channel->write_error = e2fsck_handle_write_error;
+}
+
+/*
+ * journal.c --- code for handling the "ext3" journal
+ *
+ * Copyright (C) 2000 Andreas Dilger
+ * Copyright (C) 2000 Theodore Ts'o
+ *
+ * Parts of the code are based on fs/jfs/journal.c by Stephen C. Tweedie
+ * Copyright (C) 1999 Red Hat Software
+ *
+ * This file may be redistributed under the terms of the
+ * GNU General Public License version 2 or at your discretion
+ * any later version.
+ */
+
+/*
+ * Define USE_INODE_IO to use the inode_io.c / fileio.c codepaths.
+ * This creates a larger static binary, and a smaller binary using
+ * shared libraries. It's also probably slightly less CPU-efficient,
+ * which is why it's not on by default. But, it's a good way of
+ * testing the functions in inode_io.c and fileio.c.
+ */
+#undef USE_INODE_IO
+
+/* Kernel compatibility functions for handling the journal. These allow us
+ * to use the recovery.c file virtually unchanged from the kernel, so we
+ * don't have to do much to keep kernel and user recovery in sync.
+ */
+static int journal_bmap(journal_t *journal, blk_t block, unsigned long *phys)
+{
+#ifdef USE_INODE_IO
+ *phys = block;
+ return 0;
+#else
+ struct inode *inode = journal->j_inode;
+ errcode_t retval;
+ blk_t pblk;
+
+ if (!inode) {
+ *phys = block;
+ return 0;
+ }
+
+ retval= ext2fs_bmap(inode->i_ctx->fs, inode->i_ino,
+ &inode->i_ext2, NULL, 0, block, &pblk);
+ *phys = pblk;
+ return retval;
+#endif
+}
+
+static struct buffer_head *getblk(kdev_t kdev, blk_t blocknr, int blocksize)
+{
+ struct buffer_head *bh;
+
+ bh = e2fsck_allocate_memory(kdev->k_ctx, sizeof(*bh), "block buffer");
+ if (!bh)
+ return NULL;
+
+ bh->b_ctx = kdev->k_ctx;
+ if (kdev->k_dev == K_DEV_FS)
+ bh->b_io = kdev->k_ctx->fs->io;
+ else
+ bh->b_io = kdev->k_ctx->journal_io;
+ bh->b_size = blocksize;
+ bh->b_blocknr = blocknr;
+
+ return bh;
+}
+
+static void sync_blockdev(kdev_t kdev)
+{
+ io_channel io;
+
+ if (kdev->k_dev == K_DEV_FS)
+ io = kdev->k_ctx->fs->io;
+ else
+ io = kdev->k_ctx->journal_io;
+
+ io_channel_flush(io);
+}
+
+static void ll_rw_block(int rw, int nr, struct buffer_head *bhp[])
+{
+ int retval;
+ struct buffer_head *bh;
+
+ for (; nr > 0; --nr) {
+ bh = *bhp++;
+ if (rw == READ && !bh->b_uptodate) {
+ retval = io_channel_read_blk(bh->b_io,
+ bh->b_blocknr,
+ 1, bh->b_data);
+ if (retval) {
+ bb_error_msg("while reading block %lu",
+ (unsigned long) bh->b_blocknr);
+ bh->b_err = retval;
+ continue;
+ }
+ bh->b_uptodate = 1;
+ } else if (rw == WRITE && bh->b_dirty) {
+ retval = io_channel_write_blk(bh->b_io,
+ bh->b_blocknr,
+ 1, bh->b_data);
+ if (retval) {
+ bb_error_msg("while writing block %lu",
+ (unsigned long) bh->b_blocknr);
+ bh->b_err = retval;
+ continue;
+ }
+ bh->b_dirty = 0;
+ bh->b_uptodate = 1;
+ }
+ }
+}
+
+static void mark_buffer_dirty(struct buffer_head *bh)
+{
+ bh->b_dirty = 1;
+}
+
+static inline void mark_buffer_clean(struct buffer_head * bh)
+{
+ bh->b_dirty = 0;
+}
+
+static void brelse(struct buffer_head *bh)
+{
+ if (bh->b_dirty)
+ ll_rw_block(WRITE, 1, &bh);
+ ext2fs_free_mem(&bh);
+}
+
+static int buffer_uptodate(struct buffer_head *bh)
+{
+ return bh->b_uptodate;
+}
+
+static inline void mark_buffer_uptodate(struct buffer_head *bh, int val)
+{
+ bh->b_uptodate = val;
+}
+
+static void wait_on_buffer(struct buffer_head *bh)
+{
+ if (!bh->b_uptodate)
+ ll_rw_block(READ, 1, &bh);
+}
+
+
+static void e2fsck_clear_recover(e2fsck_t ctx, int error)
+{
+ ctx->fs->super->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
+
+ /* if we had an error doing journal recovery, we need a full fsck */
+ if (error)
+ ctx->fs->super->s_state &= ~EXT2_VALID_FS;
+ ext2fs_mark_super_dirty(ctx->fs);
+}
+
+static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal)
+{
+ struct ext2_super_block *sb = ctx->fs->super;
+ struct ext2_super_block jsuper;
+ struct problem_context pctx;
+ struct buffer_head *bh;
+ struct inode *j_inode = NULL;
+ struct kdev_s *dev_fs = NULL, *dev_journal;
+ const char *journal_name = 0;
+ journal_t *journal = NULL;
+ errcode_t retval = 0;
+ io_manager io_ptr = 0;
+ unsigned long start = 0;
+ blk_t blk;
+ int ext_journal = 0;
+ int tried_backup_jnl = 0;
+ int i;
+
+ clear_problem_context(&pctx);
+
+ journal = e2fsck_allocate_memory(ctx, sizeof(journal_t), "journal");
+ if (!journal) {
+ return EXT2_ET_NO_MEMORY;
+ }
+
+ dev_fs = e2fsck_allocate_memory(ctx, 2*sizeof(struct kdev_s), "kdev");
+ if (!dev_fs) {
+ retval = EXT2_ET_NO_MEMORY;
+ goto errout;
+ }
+ dev_journal = dev_fs+1;
+
+ dev_fs->k_ctx = dev_journal->k_ctx = ctx;
+ dev_fs->k_dev = K_DEV_FS;
+ dev_journal->k_dev = K_DEV_JOURNAL;
+
+ journal->j_dev = dev_journal;
+ journal->j_fs_dev = dev_fs;
+ journal->j_inode = NULL;
+ journal->j_blocksize = ctx->fs->blocksize;
+
+ if (uuid_is_null(sb->s_journal_uuid)) {
+ if (!sb->s_journal_inum)
+ return EXT2_ET_BAD_INODE_NUM;
+ j_inode = e2fsck_allocate_memory(ctx, sizeof(*j_inode),
+ "journal inode");
+ if (!j_inode) {
+ retval = EXT2_ET_NO_MEMORY;
+ goto errout;
+ }
+
+ j_inode->i_ctx = ctx;
+ j_inode->i_ino = sb->s_journal_inum;
+
+ if ((retval = ext2fs_read_inode(ctx->fs,
+ sb->s_journal_inum,
+ &j_inode->i_ext2))) {
+ try_backup_journal:
+ if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS ||
+ tried_backup_jnl)
+ goto errout;
+ memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode));
+ memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks,
+ EXT2_N_BLOCKS*4);
+ j_inode->i_ext2.i_size = sb->s_jnl_blocks[16];
+ j_inode->i_ext2.i_links_count = 1;
+ j_inode->i_ext2.i_mode = LINUX_S_IFREG | 0600;
+ tried_backup_jnl++;
+ }
+ if (!j_inode->i_ext2.i_links_count ||
+ !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) {
+ retval = EXT2_ET_NO_JOURNAL;
+ goto try_backup_journal;
+ }
+ if (j_inode->i_ext2.i_size / journal->j_blocksize <
+ JFS_MIN_JOURNAL_BLOCKS) {
+ retval = EXT2_ET_JOURNAL_TOO_SMALL;
+ goto try_backup_journal;
+ }
+ for (i=0; i < EXT2_N_BLOCKS; i++) {
+ blk = j_inode->i_ext2.i_block[i];
+ if (!blk) {
+ if (i < EXT2_NDIR_BLOCKS) {
+ retval = EXT2_ET_JOURNAL_TOO_SMALL;
+ goto try_backup_journal;
+ }
+ continue;
+ }
+ if (blk < sb->s_first_data_block ||
+ blk >= sb->s_blocks_count) {
+ retval = EXT2_ET_BAD_BLOCK_NUM;
+ goto try_backup_journal;
+ }
+ }
+ journal->j_maxlen = j_inode->i_ext2.i_size / journal->j_blocksize;
+
+#ifdef USE_INODE_IO
+ retval = ext2fs_inode_io_intern2(ctx->fs, sb->s_journal_inum,
+ &j_inode->i_ext2,
+ &journal_name);
+ if (retval)
+ goto errout;
+
+ io_ptr = inode_io_manager;
+#else
+ journal->j_inode = j_inode;
+ ctx->journal_io = ctx->fs->io;
+ if ((retval = journal_bmap(journal, 0, &start)) != 0)
+ goto errout;
+#endif
+ } else {
+ ext_journal = 1;
+ if (!ctx->journal_name) {
+ char uuid[37];
+
+ uuid_unparse(sb->s_journal_uuid, uuid);
+ ctx->journal_name = blkid_get_devname(ctx->blkid,
+ "UUID", uuid);
+ if (!ctx->journal_name)
+ ctx->journal_name = blkid_devno_to_devname(sb->s_journal_dev);
+ }
+ journal_name = ctx->journal_name;
+
+ if (!journal_name) {
+ fix_problem(ctx, PR_0_CANT_FIND_JOURNAL, &pctx);
+ return EXT2_ET_LOAD_EXT_JOURNAL;
+ }
+
+ io_ptr = unix_io_manager;
+ }
+
+#ifndef USE_INODE_IO
+ if (ext_journal)
+#endif
+ retval = io_ptr->open(journal_name, IO_FLAG_RW,
+ &ctx->journal_io);
+ if (retval)
+ goto errout;
+
+ io_channel_set_blksize(ctx->journal_io, ctx->fs->blocksize);
+
+ if (ext_journal) {
+ if (ctx->fs->blocksize == 1024)
+ start = 1;
+ bh = getblk(dev_journal, start, ctx->fs->blocksize);
+ if (!bh) {
+ retval = EXT2_ET_NO_MEMORY;
+ goto errout;
+ }
+ ll_rw_block(READ, 1, &bh);
+ if ((retval = bh->b_err) != 0)
+ goto errout;
+ memcpy(&jsuper, start ? bh->b_data : bh->b_data + 1024,
+ sizeof(jsuper));
+ brelse(bh);
+#if BB_BIG_ENDIAN
+ if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
+ ext2fs_swap_super(&jsuper);
+#endif
+ if (jsuper.s_magic != EXT2_SUPER_MAGIC ||
+ !(jsuper.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
+ fix_problem(ctx, PR_0_EXT_JOURNAL_BAD_SUPER, &pctx);
+ retval = EXT2_ET_LOAD_EXT_JOURNAL;
+ goto errout;
+ }
+ /* Make sure the journal UUID is correct */
+ if (memcmp(jsuper.s_uuid, ctx->fs->super->s_journal_uuid,
+ sizeof(jsuper.s_uuid))) {
+ fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx);
+ retval = EXT2_ET_LOAD_EXT_JOURNAL;
+ goto errout;
+ }
+
+ journal->j_maxlen = jsuper.s_blocks_count;
+ start++;
+ }
+
+ if (!(bh = getblk(dev_journal, start, journal->j_blocksize))) {
+ retval = EXT2_ET_NO_MEMORY;
+ goto errout;
+ }
+
+ journal->j_sb_buffer = bh;
+ journal->j_superblock = (journal_superblock_t *)bh->b_data;
+
+#ifdef USE_INODE_IO
+ ext2fs_free_mem(&j_inode);
+#endif
+
+ *ret_journal = journal;
+ return 0;
+
+errout:
+ ext2fs_free_mem(&dev_fs);
+ ext2fs_free_mem(&j_inode);
+ ext2fs_free_mem(&journal);
+ return retval;
+
+}
+
+static errcode_t e2fsck_journal_fix_bad_inode(e2fsck_t ctx,
+ struct problem_context *pctx)
+{
+ struct ext2_super_block *sb = ctx->fs->super;
+ int recover = ctx->fs->super->s_feature_incompat &
+ EXT3_FEATURE_INCOMPAT_RECOVER;
+ int has_journal = ctx->fs->super->s_feature_compat &
+ EXT3_FEATURE_COMPAT_HAS_JOURNAL;
+
+ if (has_journal || sb->s_journal_inum) {
+ /* The journal inode is bogus, remove and force full fsck */
+ pctx->ino = sb->s_journal_inum;
+ if (fix_problem(ctx, PR_0_JOURNAL_BAD_INODE, pctx)) {
+ if (has_journal && sb->s_journal_inum)
+ printf("*** ext3 journal has been deleted - "
+ "filesystem is now ext2 only ***\n\n");
+ sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
+ sb->s_journal_inum = 0;
+ ctx->flags |= E2F_FLAG_JOURNAL_INODE; /* FIXME: todo */
+ e2fsck_clear_recover(ctx, 1);
+ return 0;
+ }
+ return EXT2_ET_BAD_INODE_NUM;
+ } else if (recover) {
+ if (fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, pctx)) {
+ e2fsck_clear_recover(ctx, 1);
+ return 0;
+ }
+ return EXT2_ET_UNSUPP_FEATURE;
+ }
+ return 0;
+}
+
+#define V1_SB_SIZE 0x0024
+static void clear_v2_journal_fields(journal_t *journal)
+{
+ e2fsck_t ctx = journal->j_dev->k_ctx;
+ struct problem_context pctx;
+
+ clear_problem_context(&pctx);
+
+ if (!fix_problem(ctx, PR_0_CLEAR_V2_JOURNAL, &pctx))
+ return;
+
+ memset(((char *) journal->j_superblock) + V1_SB_SIZE, 0,
+ ctx->fs->blocksize-V1_SB_SIZE);
+ mark_buffer_dirty(journal->j_sb_buffer);
+}
+
+
+static errcode_t e2fsck_journal_load(journal_t *journal)
+{
+ e2fsck_t ctx = journal->j_dev->k_ctx;
+ journal_superblock_t *jsb;
+ struct buffer_head *jbh = journal->j_sb_buffer;
+ struct problem_context pctx;
+
+ clear_problem_context(&pctx);
+
+ ll_rw_block(READ, 1, &jbh);
+ if (jbh->b_err) {
+ bb_error_msg(_("reading journal superblock"));
+ return jbh->b_err;
+ }
+
+ jsb = journal->j_superblock;
+ /* If we don't even have JFS_MAGIC, we probably have a wrong inode */
+ if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER))
+ return e2fsck_journal_fix_bad_inode(ctx, &pctx);
+
+ switch (ntohl(jsb->s_header.h_blocktype)) {
+ case JFS_SUPERBLOCK_V1:
+ journal->j_format_version = 1;
+ if (jsb->s_feature_compat ||
+ jsb->s_feature_incompat ||
+ jsb->s_feature_ro_compat ||
+ jsb->s_nr_users)
+ clear_v2_journal_fields(journal);
+ break;
+
+ case JFS_SUPERBLOCK_V2:
+ journal->j_format_version = 2;
+ if (ntohl(jsb->s_nr_users) > 1 &&
+ uuid_is_null(ctx->fs->super->s_journal_uuid))
+ clear_v2_journal_fields(journal);
+ if (ntohl(jsb->s_nr_users) > 1) {
+ fix_problem(ctx, PR_0_JOURNAL_UNSUPP_MULTIFS, &pctx);
+ return EXT2_ET_JOURNAL_UNSUPP_VERSION;
+ }
+ break;
+
+ /*
+ * These should never appear in a journal super block, so if
+ * they do, the journal is badly corrupted.
+ */
+ case JFS_DESCRIPTOR_BLOCK:
+ case JFS_COMMIT_BLOCK:
+ case JFS_REVOKE_BLOCK:
+ return EXT2_ET_CORRUPT_SUPERBLOCK;
+
+ /* If we don't understand the superblock major type, but there
+ * is a magic number, then it is likely to be a new format we
+ * just don't understand, so leave it alone. */
+ default:
+ return EXT2_ET_JOURNAL_UNSUPP_VERSION;
+ }
+
+ if (JFS_HAS_INCOMPAT_FEATURE(journal, ~JFS_KNOWN_INCOMPAT_FEATURES))
+ return EXT2_ET_UNSUPP_FEATURE;
+
+ if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES))
+ return EXT2_ET_RO_UNSUPP_FEATURE;
+
+ /* We have now checked whether we know enough about the journal
+ * format to be able to proceed safely, so any other checks that
+ * fail we should attempt to recover from. */
+ if (jsb->s_blocksize != htonl(journal->j_blocksize)) {
+ bb_error_msg(_("%s: no valid journal superblock found"),
+ ctx->device_name);
+ return EXT2_ET_CORRUPT_SUPERBLOCK;
+ }
+
+ if (ntohl(jsb->s_maxlen) < journal->j_maxlen)
+ journal->j_maxlen = ntohl(jsb->s_maxlen);
+ else if (ntohl(jsb->s_maxlen) > journal->j_maxlen) {
+ bb_error_msg(_("%s: journal too short"),
+ ctx->device_name);
+ return EXT2_ET_CORRUPT_SUPERBLOCK;
+ }
+
+ journal->j_tail_sequence = ntohl(jsb->s_sequence);
+ journal->j_transaction_sequence = journal->j_tail_sequence;
+ journal->j_tail = ntohl(jsb->s_start);
+ journal->j_first = ntohl(jsb->s_first);
+ journal->j_last = ntohl(jsb->s_maxlen);
+
+ return 0;
+}
+
+static void e2fsck_journal_reset_super(e2fsck_t ctx, journal_superblock_t *jsb,
+ journal_t *journal)
+{
+ char *p;
+ union {
+ uuid_t uuid;
+ __u32 val[4];
+ } u;
+ __u32 new_seq = 0;
+ int i;
+
+ /* Leave a valid existing V1 superblock signature alone.
+ * Anything unrecognisable we overwrite with a new V2
+ * signature. */
+
+ if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) ||
+ jsb->s_header.h_blocktype != htonl(JFS_SUPERBLOCK_V1)) {
+ jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
+ jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
+ }
+
+ /* Zero out everything else beyond the superblock header */
+
+ p = ((char *) jsb) + sizeof(journal_header_t);
+ memset (p, 0, ctx->fs->blocksize-sizeof(journal_header_t));
+
+ jsb->s_blocksize = htonl(ctx->fs->blocksize);
+ jsb->s_maxlen = htonl(journal->j_maxlen);
+ jsb->s_first = htonl(1);
+
+ /* Initialize the journal sequence number so that there is "no"
+ * chance we will find old "valid" transactions in the journal.
+ * This avoids the need to zero the whole journal (slow to do,
+ * and risky when we are just recovering the filesystem).
+ */
+ uuid_generate(u.uuid);
+ for (i = 0; i < 4; i ++)
+ new_seq ^= u.val[i];
+ jsb->s_sequence = htonl(new_seq);
+
+ mark_buffer_dirty(journal->j_sb_buffer);
+ ll_rw_block(WRITE, 1, &journal->j_sb_buffer);
+}
+
+static errcode_t e2fsck_journal_fix_corrupt_super(e2fsck_t ctx,
+ journal_t *journal,
+ struct problem_context *pctx)
+{
+ struct ext2_super_block *sb = ctx->fs->super;
+ int recover = ctx->fs->super->s_feature_incompat &
+ EXT3_FEATURE_INCOMPAT_RECOVER;
+
+ if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
+ if (fix_problem(ctx, PR_0_JOURNAL_BAD_SUPER, pctx)) {
+ e2fsck_journal_reset_super(ctx, journal->j_superblock,
+ journal);
+ journal->j_transaction_sequence = 1;
+ e2fsck_clear_recover(ctx, recover);
+ return 0;
+ }
+ return EXT2_ET_CORRUPT_SUPERBLOCK;
+ } else if (e2fsck_journal_fix_bad_inode(ctx, pctx))
+ return EXT2_ET_CORRUPT_SUPERBLOCK;
+
+ return 0;
+}
+
+static void e2fsck_journal_release(e2fsck_t ctx, journal_t *journal,
+ int reset, int drop)
+{
+ journal_superblock_t *jsb;
+
+ if (drop)
+ mark_buffer_clean(journal->j_sb_buffer);
+ else if (!(ctx->options & E2F_OPT_READONLY)) {
+ jsb = journal->j_superblock;
+ jsb->s_sequence = htonl(journal->j_transaction_sequence);
+ if (reset)
+ jsb->s_start = 0; /* this marks the journal as empty */
+ mark_buffer_dirty(journal->j_sb_buffer);
+ }
+ brelse(journal->j_sb_buffer);
+
+ if (ctx->journal_io) {
+ if (ctx->fs && ctx->fs->io != ctx->journal_io)
+ io_channel_close(ctx->journal_io);
+ ctx->journal_io = 0;
+ }
+
+#ifndef USE_INODE_IO
+ ext2fs_free_mem(&journal->j_inode);
+#endif
+ ext2fs_free_mem(&journal->j_fs_dev);
+ ext2fs_free_mem(&journal);
+}
+
+/*
+ * This function makes sure that the superblock fields regarding the
+ * journal are consistent.
+ */
+static int e2fsck_check_ext3_journal(e2fsck_t ctx)
+{
+ struct ext2_super_block *sb = ctx->fs->super;
+ journal_t *journal;
+ int recover = ctx->fs->super->s_feature_incompat &
+ EXT3_FEATURE_INCOMPAT_RECOVER;
+ struct problem_context pctx;
+ problem_t problem;
+ int reset = 0, force_fsck = 0;
+ int retval;
+
+ /* If we don't have any journal features, don't do anything more */
+ if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
+ !recover && sb->s_journal_inum == 0 && sb->s_journal_dev == 0 &&
+ uuid_is_null(sb->s_journal_uuid))
+ return 0;
+
+ clear_problem_context(&pctx);
+ pctx.num = sb->s_journal_inum;
+
+ retval = e2fsck_get_journal(ctx, &journal);
+ if (retval) {
+ if ((retval == EXT2_ET_BAD_INODE_NUM) ||
+ (retval == EXT2_ET_BAD_BLOCK_NUM) ||
+ (retval == EXT2_ET_JOURNAL_TOO_SMALL) ||
+ (retval == EXT2_ET_NO_JOURNAL))
+ return e2fsck_journal_fix_bad_inode(ctx, &pctx);
+ return retval;
+ }
+
+ retval = e2fsck_journal_load(journal);
+ if (retval) {
+ if ((retval == EXT2_ET_CORRUPT_SUPERBLOCK) ||
+ ((retval == EXT2_ET_UNSUPP_FEATURE) &&
+ (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_INCOMPAT,
+ &pctx))) ||
+ ((retval == EXT2_ET_RO_UNSUPP_FEATURE) &&
+ (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_ROCOMPAT,
+ &pctx))) ||
+ ((retval == EXT2_ET_JOURNAL_UNSUPP_VERSION) &&
+ (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_VERSION, &pctx))))
+ retval = e2fsck_journal_fix_corrupt_super(ctx, journal,
+ &pctx);
+ e2fsck_journal_release(ctx, journal, 0, 1);
+ return retval;
+ }
+
+ /*
+ * We want to make the flags consistent here. We will not leave with
+ * needs_recovery set but has_journal clear. We can't get in a loop
+ * with -y, -n, or -p, only if a user isn't making up their mind.
+ */
+no_has_journal:
+ if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
+ recover = sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER;
+ pctx.str = "inode";
+ if (fix_problem(ctx, PR_0_JOURNAL_HAS_JOURNAL, &pctx)) {
+ if (recover &&
+ !fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, &pctx))
+ goto no_has_journal;
+ /*
+ * Need a full fsck if we are releasing a
+ * journal stored on a reserved inode.
+ */
+ force_fsck = recover ||
+ (sb->s_journal_inum < EXT2_FIRST_INODE(sb));
+ /* Clear all of the journal fields */
+ sb->s_journal_inum = 0;
+ sb->s_journal_dev = 0;
+ memset(sb->s_journal_uuid, 0,
+ sizeof(sb->s_journal_uuid));
+ e2fsck_clear_recover(ctx, force_fsck);
+ } else if (!(ctx->options & E2F_OPT_READONLY)) {
+ sb->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
+ ext2fs_mark_super_dirty(ctx->fs);
+ }
+ }
+
+ if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL &&
+ !(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) &&
+ journal->j_superblock->s_start != 0) {
+ /* Print status information */
+ fix_problem(ctx, PR_0_JOURNAL_RECOVERY_CLEAR, &pctx);
+ if (ctx->superblock)
+ problem = PR_0_JOURNAL_RUN_DEFAULT;
+ else
+ problem = PR_0_JOURNAL_RUN;
+ if (fix_problem(ctx, problem, &pctx)) {
+ ctx->options |= E2F_OPT_FORCE;
+ sb->s_feature_incompat |=
+ EXT3_FEATURE_INCOMPAT_RECOVER;
+ ext2fs_mark_super_dirty(ctx->fs);
+ } else if (fix_problem(ctx,
+ PR_0_JOURNAL_RESET_JOURNAL, &pctx)) {
+ reset = 1;
+ sb->s_state &= ~EXT2_VALID_FS;
+ ext2fs_mark_super_dirty(ctx->fs);
+ }
+ /*
+ * If the user answers no to the above question, we
+ * ignore the fact that journal apparently has data;
+ * accidentally replaying over valid data would be far
+ * worse than skipping a questionable recovery.
+ *
+ * XXX should we abort with a fatal error here? What
+ * will the ext3 kernel code do if a filesystem with
+ * !NEEDS_RECOVERY but with a non-zero
+ * journal->j_superblock->s_start is mounted?
+ */
+ }
+
+ e2fsck_journal_release(ctx, journal, reset, 0);
+ return retval;
+}
+
+static errcode_t recover_ext3_journal(e2fsck_t ctx)
+{
+ journal_t *journal;
+ int retval;
+
+ journal_init_revoke_caches();
+ retval = e2fsck_get_journal(ctx, &journal);
+ if (retval)
+ return retval;
+
+ retval = e2fsck_journal_load(journal);
+ if (retval)
+ goto errout;
+
+ retval = journal_init_revoke(journal, 1024);
+ if (retval)
+ goto errout;
+
+ retval = -journal_recover(journal);
+ if (retval)
+ goto errout;
+
+ if (journal->j_superblock->s_errno) {
+ ctx->fs->super->s_state |= EXT2_ERROR_FS;
+ ext2fs_mark_super_dirty(ctx->fs);
+ journal->j_superblock->s_errno = 0;
+ mark_buffer_dirty(journal->j_sb_buffer);
+ }
+
+errout:
+ journal_destroy_revoke(journal);
+ journal_destroy_revoke_caches();
+ e2fsck_journal_release(ctx, journal, 1, 0);
+ return retval;
+}
+
+static int e2fsck_run_ext3_journal(e2fsck_t ctx)
+{
+ io_manager io_ptr = ctx->fs->io->manager;
+ int blocksize = ctx->fs->blocksize;
+ errcode_t retval, recover_retval;
+
+ printf(_("%s: recovering journal\n"), ctx->device_name);
+ if (ctx->options & E2F_OPT_READONLY) {
+ printf(_("%s: won't do journal recovery while read-only\n"),
+ ctx->device_name);
+ return EXT2_ET_FILE_RO;
+ }
+
+ if (ctx->fs->flags & EXT2_FLAG_DIRTY)
+ ext2fs_flush(ctx->fs); /* Force out any modifications */
+
+ recover_retval = recover_ext3_journal(ctx);
+
+ /*
+ * Reload the filesystem context to get up-to-date data from disk
+ * because journal recovery will change the filesystem under us.
+ */
+ ext2fs_close(ctx->fs);
+ retval = ext2fs_open(ctx->filesystem_name, EXT2_FLAG_RW,
+ ctx->superblock, blocksize, io_ptr,
+ &ctx->fs);
+
+ if (retval) {
+ bb_error_msg(_("while trying to re-open %s"),
+ ctx->device_name);
+ bb_error_msg_and_die(0);
+ }
+ ctx->fs->priv_data = ctx;
+
+ /* Set the superblock flags */
+ e2fsck_clear_recover(ctx, recover_retval);
+ return recover_retval;
+}
+
+/*
+ * This function will move the journal inode from a visible file in
+ * the filesystem directory hierarchy to the reserved inode if necessary.
+ */
+static const char *const journal_names[] = {
+ ".journal", "journal", ".journal.dat", "journal.dat", 0 };
+
+static void e2fsck_move_ext3_journal(e2fsck_t ctx)
+{
+ struct ext2_super_block *sb = ctx->fs->super;
+ struct problem_context pctx;
+ struct ext2_inode inode;
+ ext2_filsys fs = ctx->fs;
+ ext2_ino_t ino;
+ errcode_t retval;
+ const char *const * cpp;
+ int group, mount_flags;
+
+ clear_problem_context(&pctx);
+
+ /*
+ * If the filesystem is opened read-only, or there is no
+ * journal, then do nothing.
+ */
+ if ((ctx->options & E2F_OPT_READONLY) ||
+ (sb->s_journal_inum == 0) ||
+ !(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
+ return;
+
+ /*
+ * Read in the journal inode
+ */
+ if (ext2fs_read_inode(fs, sb->s_journal_inum, &inode) != 0)
+ return;
+
+ /*
+ * If it's necessary to backup the journal inode, do so.
+ */
+ if ((sb->s_jnl_backup_type == 0) ||
+ ((sb->s_jnl_backup_type == EXT3_JNL_BACKUP_BLOCKS) &&
+ memcmp(inode.i_block, sb->s_jnl_blocks, EXT2_N_BLOCKS*4))) {
+ if (fix_problem(ctx, PR_0_BACKUP_JNL, &pctx)) {
+ memcpy(sb->s_jnl_blocks, inode.i_block,
+ EXT2_N_BLOCKS*4);
+ sb->s_jnl_blocks[16] = inode.i_size;
+ sb->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
+ ext2fs_mark_super_dirty(fs);
+ fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
+ }
+ }
+
+ /*
+ * If the journal is already the hidden inode, then do nothing
+ */
+ if (sb->s_journal_inum == EXT2_JOURNAL_INO)
+ return;
+
+ /*
+ * The journal inode had better have only one link and not be readable.
+ */
+ if (inode.i_links_count != 1)
+ return;
+
+ /*
+ * If the filesystem is mounted, or we can't tell whether
+ * or not it's mounted, do nothing.
+ */
+ retval = ext2fs_check_if_mounted(ctx->filesystem_name, &mount_flags);
+ if (retval || (mount_flags & EXT2_MF_MOUNTED))
+ return;
+
+ /*
+ * If we can't find the name of the journal inode, then do
+ * nothing.
+ */
+ for (cpp = journal_names; *cpp; cpp++) {
+ retval = ext2fs_lookup(fs, EXT2_ROOT_INO, *cpp,
+ strlen(*cpp), 0, &ino);
+ if ((retval == 0) && (ino == sb->s_journal_inum))
+ break;
+ }
+ if (*cpp == 0)
+ return;
+
+ /* We need the inode bitmap to be loaded */
+ retval = ext2fs_read_bitmaps(fs);
+ if (retval)
+ return;
+
+ pctx.str = *cpp;
+ if (!fix_problem(ctx, PR_0_MOVE_JOURNAL, &pctx))
+ return;
+
+ /*
+ * OK, we've done all the checks, let's actually move the
+ * journal inode. Errors at this point mean we need to force
+ * an ext2 filesystem check.
+ */
+ if ((retval = ext2fs_unlink(fs, EXT2_ROOT_INO, *cpp, ino, 0)) != 0)
+ goto err_out;
+ if ((retval = ext2fs_write_inode(fs, EXT2_JOURNAL_INO, &inode)) != 0)
+ goto err_out;
+ sb->s_journal_inum = EXT2_JOURNAL_INO;
+ ext2fs_mark_super_dirty(fs);
+ fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
+ inode.i_links_count = 0;
+ inode.i_dtime = time(0);
+ if ((retval = ext2fs_write_inode(fs, ino, &inode)) != 0)
+ goto err_out;
+
+ group = ext2fs_group_of_ino(fs, ino);
+ ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
+ ext2fs_mark_ib_dirty(fs);
+ fs->group_desc[group].bg_free_inodes_count++;
+ fs->super->s_free_inodes_count++;
+ return;
+
+err_out:
+ pctx.errcode = retval;
+ fix_problem(ctx, PR_0_ERR_MOVE_JOURNAL, &pctx);
+ fs->super->s_state &= ~EXT2_VALID_FS;
+ ext2fs_mark_super_dirty(fs);
+}
+
+/*
+ * message.c --- print e2fsck messages (with compression)
+ *
+ * print_e2fsck_message() prints a message to the user, using
+ * compression techniques and expansions of abbreviations.
+ *
+ * The following % expansions are supported:
+ *
+ * %b <blk> block number
+ * %B <blkcount> integer
+ * %c <blk2> block number
+ * %Di <dirent>->ino inode number
+ * %Dn <dirent>->name string
+ * %Dr <dirent>->rec_len
+ * %Dl <dirent>->name_len
+ * %Dt <dirent>->filetype
+ * %d <dir> inode number
+ * %g <group> integer
+ * %i <ino> inode number
+ * %Is <inode> -> i_size
+ * %IS <inode> -> i_extra_isize
+ * %Ib <inode> -> i_blocks
+ * %Il <inode> -> i_links_count
+ * %Im <inode> -> i_mode
+ * %IM <inode> -> i_mtime
+ * %IF <inode> -> i_faddr
+ * %If <inode> -> i_file_acl
+ * %Id <inode> -> i_dir_acl
+ * %Iu <inode> -> i_uid
+ * %Ig <inode> -> i_gid
+ * %j <ino2> inode number
+ * %m <com_err error message>
+ * %N <num>
+ * %p ext2fs_get_pathname of directory <ino>
+ * %P ext2fs_get_pathname of <dirent>->ino with <ino2> as
+ * the containing directory. (If dirent is NULL
+ * then return the pathname of directory <ino2>)
+ * %q ext2fs_get_pathname of directory <dir>
+ * %Q ext2fs_get_pathname of directory <ino> with <dir> as
+ * the containing directory.
+ * %s <str> miscellaneous string
+ * %S backup superblock
+ * %X <num> hexadecimal format
+ *
+ * The following '@' expansions are supported:
+ *
+ * @a extended attribute
+ * @A error allocating
+ * @b block
+ * @B bitmap
+ * @c compress
+ * @C conflicts with some other fs block
+ * @D deleted
+ * @d directory
+ * @e entry
+ * @E Entry '%Dn' in %p (%i)
+ * @f filesystem
+ * @F for @i %i (%Q) is
+ * @g group
+ * @h HTREE directory inode
+ * @i inode
+ * @I illegal
+ * @j journal
+ * @l lost+found
+ * @L is a link
+ * @m multiply-claimed
+ * @n invalid
+ * @o orphaned
+ * @p problem in
+ * @r root inode
+ * @s should be
+ * @S superblock
+ * @u unattached
+ * @v device
+ * @z zero-length
+ */
+
+
+/*
+ * This structure defines the abbreviations used by the text strings
+ * below. The first character in the string is the index letter. An
+ * abbreviation of the form '@<i>' is expanded by looking up the index
+ * letter <i> in the table below.
+ */
+static const char *const abbrevs[] = {
+ N_("aextended attribute"),
+ N_("Aerror allocating"),
+ N_("bblock"),
+ N_("Bbitmap"),
+ N_("ccompress"),
+ N_("Cconflicts with some other fs @b"),
+ N_("iinode"),
+ N_("Iillegal"),
+ N_("jjournal"),
+ N_("Ddeleted"),
+ N_("ddirectory"),
+ N_("eentry"),
+ N_("E@e '%Dn' in %p (%i)"),
+ N_("ffilesystem"),
+ N_("Ffor @i %i (%Q) is"),
+ N_("ggroup"),
+ N_("hHTREE @d @i"),
+ N_("llost+found"),
+ N_("Lis a link"),
+ N_("mmultiply-claimed"),
+ N_("ninvalid"),
+ N_("oorphaned"),
+ N_("pproblem in"),
+ N_("rroot @i"),
+ N_("sshould be"),
+ N_("Ssuper@b"),
+ N_("uunattached"),
+ N_("vdevice"),
+ N_("zzero-length"),
+ "@@",
+ 0
+ };
+
+/*
+ * Give more user friendly names to the "special" inodes.
+ */
+#define num_special_inodes 11
+static const char *const special_inode_name[] =
+{
+ N_("<The NULL inode>"), /* 0 */
+ N_("<The bad blocks inode>"), /* 1 */
+ "/", /* 2 */
+ N_("<The ACL index inode>"), /* 3 */
+ N_("<The ACL data inode>"), /* 4 */
+ N_("<The boot loader inode>"), /* 5 */
+ N_("<The undelete directory inode>"), /* 6 */
+ N_("<The group descriptor inode>"), /* 7 */
+ N_("<The journal inode>"), /* 8 */
+ N_("<Reserved inode 9>"), /* 9 */
+ N_("<Reserved inode 10>"), /* 10 */
+};
+
+/*
+ * This function does "safe" printing. It will convert non-printable
+ * ASCII characters using '^' and M- notation.
+ */
+static void safe_print(const char *cp, int len)
+{
+ unsigned char ch;
+
+ if (len < 0)
+ len = strlen(cp);
+
+ while (len--) {
+ ch = *cp++;
+ if (ch > 128) {
+ fputs("M-", stdout);
+ ch -= 128;
+ }
+ if ((ch < 32) || (ch == 0x7f)) {
+ bb_putchar('^');
+ ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
+ }
+ bb_putchar(ch);
+ }
+}
+
+
+/*
+ * This function prints a pathname, using the ext2fs_get_pathname
+ * function
+ */
+static void print_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino)
+{
+ errcode_t retval;
+ char *path;
+
+ if (!dir && (ino < num_special_inodes)) {
+ fputs(_(special_inode_name[ino]), stdout);
+ return;
+ }
+
+ retval = ext2fs_get_pathname(fs, dir, ino, &path);
+ if (retval)
+ fputs("???", stdout);
+ else {
+ safe_print(path, -1);
+ ext2fs_free_mem(&path);
+ }
+}
+
+static void print_e2fsck_message(e2fsck_t ctx, const char *msg,
+ struct problem_context *pctx, int first);
+/*
+ * This function handles the '@' expansion. We allow recursive
+ * expansion; an @ expression can contain further '@' and '%'
+ * expressions.
+ */
+static void expand_at_expression(e2fsck_t ctx, char ch,
+ struct problem_context *pctx,
+ int *first)
+{
+ const char *const *cpp;
+ const char *str;
+
+ /* Search for the abbreviation */
+ for (cpp = abbrevs; *cpp; cpp++) {
+ if (ch == *cpp[0])
+ break;
+ }
+ if (*cpp) {
+ str = _(*cpp) + 1;
+ if (*first && islower(*str)) {
+ *first = 0;
+ bb_putchar(toupper(*str++));
+ }
+ print_e2fsck_message(ctx, str, pctx, *first);
+ } else
+ printf("@%c", ch);
+}
+
+/*
+ * This function expands '%IX' expressions
+ */
+static void expand_inode_expression(char ch,
+ struct problem_context *ctx)
+{
+ struct ext2_inode *inode;
+ struct ext2_inode_large *large_inode;
+ char * time_str;
+ time_t t;
+ int do_gmt = -1;
+
+ if (!ctx || !ctx->inode)
+ goto no_inode;
+
+ inode = ctx->inode;
+ large_inode = (struct ext2_inode_large *) inode;
+
+ switch (ch) {
+ case 's':
+ if (LINUX_S_ISDIR(inode->i_mode))
+ printf("%u", inode->i_size);
+ else {
+ printf("%"PRIu64, (inode->i_size |
+ ((uint64_t) inode->i_size_high << 32)));
+ }
+ break;
+ case 'S':
+ printf("%u", large_inode->i_extra_isize);
+ break;
+ case 'b':
+ printf("%u", inode->i_blocks);
+ break;
+ case 'l':
+ printf("%d", inode->i_links_count);
+ break;
+ case 'm':
+ printf("0%o", inode->i_mode);
+ break;
+ case 'M':
+ /* The diet libc doesn't respect the TZ environemnt variable */
+ if (do_gmt == -1) {
+ time_str = getenv("TZ");
+ if (!time_str)
+ time_str = "";
+ do_gmt = !strcmp(time_str, "GMT");
+ }
+ t = inode->i_mtime;
+ time_str = asctime(do_gmt ? gmtime(&t) : localtime(&t));
+ printf("%.24s", time_str);
+ break;
+ case 'F':
+ printf("%u", inode->i_faddr);
+ break;
+ case 'f':
+ printf("%u", inode->i_file_acl);
+ break;
+ case 'd':
+ printf("%u", (LINUX_S_ISDIR(inode->i_mode) ?
+ inode->i_dir_acl : 0));
+ break;
+ case 'u':
+ printf("%d", (inode->i_uid |
+ (inode->osd2.linux2.l_i_uid_high << 16)));
+ break;
+ case 'g':
+ printf("%d", (inode->i_gid |
+ (inode->osd2.linux2.l_i_gid_high << 16)));
+ break;
+ default:
+ no_inode:
+ printf("%%I%c", ch);
+ break;
+ }
+}
+
+/*
+ * This function expands '%dX' expressions
+ */
+static void expand_dirent_expression(char ch,
+ struct problem_context *ctx)
+{
+ struct ext2_dir_entry *dirent;
+ int len;
+
+ if (!ctx || !ctx->dirent)
+ goto no_dirent;
+
+ dirent = ctx->dirent;
+
+ switch (ch) {
+ case 'i':
+ printf("%u", dirent->inode);
+ break;
+ case 'n':
+ len = dirent->name_len & 0xFF;
+ if (len > EXT2_NAME_LEN)
+ len = EXT2_NAME_LEN;
+ if (len > dirent->rec_len)
+ len = dirent->rec_len;
+ safe_print(dirent->name, len);
+ break;
+ case 'r':
+ printf("%u", dirent->rec_len);
+ break;
+ case 'l':
+ printf("%u", dirent->name_len & 0xFF);
+ break;
+ case 't':
+ printf("%u", dirent->name_len >> 8);
+ break;
+ default:
+ no_dirent:
+ printf("%%D%c", ch);
+ break;
+ }
+}
+
+static void expand_percent_expression(ext2_filsys fs, char ch,
+ struct problem_context *ctx)
+{
+ if (!ctx)
+ goto no_context;
+
+ switch (ch) {
+ case '%':
+ bb_putchar('%');
+ break;
+ case 'b':
+ printf("%u", ctx->blk);
+ break;
+ case 'B':
+ printf("%"PRIi64, ctx->blkcount);
+ break;
+ case 'c':
+ printf("%u", ctx->blk2);
+ break;
+ case 'd':
+ printf("%u", ctx->dir);
+ break;
+ case 'g':
+ printf("%d", ctx->group);
+ break;
+ case 'i':
+ printf("%u", ctx->ino);
+ break;
+ case 'j':
+ printf("%u", ctx->ino2);
+ break;
+ case 'm':
+ fputs(error_message(ctx->errcode), stdout);
+ break;
+ case 'N':
+ printf("%"PRIi64, ctx->num);
+ break;
+ case 'p':
+ print_pathname(fs, ctx->ino, 0);
+ break;
+ case 'P':
+ print_pathname(fs, ctx->ino2,
+ ctx->dirent ? ctx->dirent->inode : 0);
+ break;
+ case 'q':
+ print_pathname(fs, ctx->dir, 0);
+ break;
+ case 'Q':
+ print_pathname(fs, ctx->dir, ctx->ino);
+ break;
+ case 'S':
+ printf("%d", get_backup_sb(NULL, fs, NULL, NULL));
+ break;
+ case 's':
+ fputs((ctx->str ? ctx->str : "NULL"), stdout);
+ break;
+ case 'X':
+ printf("0x%"PRIi64, ctx->num);
+ break;
+ default:
+ no_context:
+ printf("%%%c", ch);
+ break;
+ }
+}
+
+
+static void print_e2fsck_message(e2fsck_t ctx, const char *msg,
+ struct problem_context *pctx, int first)
+{
+ ext2_filsys fs = ctx->fs;
+ const char * cp;
+ int i;
+
+ e2fsck_clear_progbar(ctx);
+ for (cp = msg; *cp; cp++) {
+ if (cp[0] == '@') {
+ cp++;
+ expand_at_expression(ctx, *cp, pctx, &first);
+ } else if (cp[0] == '%' && cp[1] == 'I') {
+ cp += 2;
+ expand_inode_expression(*cp, pctx);
+ } else if (cp[0] == '%' && cp[1] == 'D') {
+ cp += 2;
+ expand_dirent_expression(*cp, pctx);
+ } else if ((cp[0] == '%')) {
+ cp++;
+ expand_percent_expression(fs, *cp, pctx);
+ } else {
+ for (i=0; cp[i]; i++)
+ if ((cp[i] == '@') || cp[i] == '%')
+ break;
+ printf("%.*s", i, cp);
+ cp += i-1;
+ }
+ first = 0;
+ }
+}
+
+
+/*
+ * region.c --- code which manages allocations within a region.
+ */
+
+struct region_el {
+ region_addr_t start;
+ region_addr_t end;
+ struct region_el *next;
+};
+
+struct region_struct {
+ region_addr_t min;
+ region_addr_t max;
+ struct region_el *allocated;
+};
+
+static region_t region_create(region_addr_t min, region_addr_t max)
+{
+ region_t region;
+
+ region = malloc(sizeof(struct region_struct));
+ if (!region)
+ return NULL;
+ memset(region, 0, sizeof(struct region_struct));
+ region->min = min;
+ region->max = max;
+ return region;
+}
+
+static void region_free(region_t region)
+{
+ struct region_el *r, *next;
+
+ for (r = region->allocated; r; r = next) {
+ next = r->next;
+ free(r);
+ }
+ memset(region, 0, sizeof(struct region_struct));
+ free(region);
+}
+
+static int region_allocate(region_t region, region_addr_t start, int n)
+{
+ struct region_el *r, *new_region, *prev, *next;
+ region_addr_t end;
+
+ end = start+n;
+ if ((start < region->min) || (end > region->max))
+ return -1;
+ if (n == 0)
+ return 1;
+
+ /*
+ * Search through the linked list. If we find that it
+ * conflicts witih something that's already allocated, return
+ * 1; if we can find an existing region which we can grow, do
+ * so. Otherwise, stop when we find the appropriate place
+ * insert a new region element into the linked list.
+ */
+ for (r = region->allocated, prev=NULL; r; prev = r, r = r->next) {
+ if (((start >= r->start) && (start < r->end)) ||
+ ((end > r->start) && (end <= r->end)) ||
+ ((start <= r->start) && (end >= r->end)))
+ return 1;
+ if (end == r->start) {
+ r->start = start;
+ return 0;
+ }
+ if (start == r->end) {
+ if ((next = r->next)) {
+ if (end > next->start)
+ return 1;
+ if (end == next->start) {
+ r->end = next->end;
+ r->next = next->next;
+ free(next);
+ return 0;
+ }
+ }
+ r->end = end;
+ return 0;
+ }
+ if (start < r->start)
+ break;
+ }
+ /*
+ * Insert a new region element structure into the linked list
+ */
+ new_region = malloc(sizeof(struct region_el));
+ if (!new_region)
+ return -1;
+ new_region->start = start;
+ new_region->end = start + n;
+ new_region->next = r;
+ if (prev)
+ prev->next = new_region;
+ else
+ region->allocated = new_region;
+ return 0;
+}
+
+/*
+ * pass1.c -- pass #1 of e2fsck: sequential scan of the inode table
+ *
+ * Pass 1 of e2fsck iterates over all the inodes in the filesystems,
+ * and applies the following tests to each inode:
+ *
+ * - The mode field of the inode must be legal.
+ * - The size and block count fields of the inode are correct.
+ * - A data block must not be used by another inode
+ *
+ * Pass 1 also gathers the collects the following information:
+ *
+ * - A bitmap of which inodes are in use. (inode_used_map)
+ * - A bitmap of which inodes are directories. (inode_dir_map)
+ * - A bitmap of which inodes are regular files. (inode_reg_map)
+ * - A bitmap of which inodes have bad fields. (inode_bad_map)
+ * - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
+ * - A bitmap of which blocks are in use. (block_found_map)
+ * - A bitmap of which blocks are in use by two inodes (block_dup_map)
+ * - The data blocks of the directory inodes. (dir_map)
+ *
+ * Pass 1 is designed to stash away enough information so that the
+ * other passes should not need to read in the inode information
+ * during the normal course of a filesystem check. (Althogh if an
+ * inconsistency is detected, other passes may need to read in an
+ * inode to fix it.)
+ *
+ * Note that pass 1B will be invoked if there are any duplicate blocks
+ * found.
+ */
+
+
+static int process_block(ext2_filsys fs, blk_t *blocknr,
+ e2_blkcnt_t blockcnt, blk_t ref_blk,
+ int ref_offset, void *priv_data);
+static int process_bad_block(ext2_filsys fs, blk_t *block_nr,
+ e2_blkcnt_t blockcnt, blk_t ref_blk,
+ int ref_offset, void *priv_data);
+static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
+ char *block_buf);
+static void mark_table_blocks(e2fsck_t ctx);
+static void alloc_imagic_map(e2fsck_t ctx);
+static void mark_inode_bad(e2fsck_t ctx, ino_t ino);
+static void handle_fs_bad_blocks(e2fsck_t ctx);
+static void process_inodes(e2fsck_t ctx, char *block_buf);
+static int process_inode_cmp(const void *a, const void *b);
+static errcode_t scan_callback(ext2_filsys fs,
+ dgrp_t group, void * priv_data);
+static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
+ char *block_buf, int adjust_sign);
+/* static char *describe_illegal_block(ext2_filsys fs, blk_t block); */
+
+static void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
+ struct ext2_inode * inode, int bufsize,
+ const char *proc);
+
+struct process_block_struct_1 {
+ ext2_ino_t ino;
+ unsigned is_dir:1, is_reg:1, clear:1, suppress:1,
+ fragmented:1, compressed:1, bbcheck:1;
+ blk_t num_blocks;
+ blk_t max_blocks;
+ e2_blkcnt_t last_block;
+ int num_illegal_blocks;
+ blk_t previous_block;
+ struct ext2_inode *inode;
+ struct problem_context *pctx;
+ ext2fs_block_bitmap fs_meta_blocks;
+ e2fsck_t ctx;
+};
+
+struct process_inode_block {
+ ext2_ino_t ino;
+ struct ext2_inode inode;
+};
+
+struct scan_callback_struct {
+ e2fsck_t ctx;
+ char *block_buf;
+};
+
+/*
+ * For the inodes to process list.
+ */
+static struct process_inode_block *inodes_to_process;
+static int process_inode_count;
+
+static __u64 ext2_max_sizes[EXT2_MAX_BLOCK_LOG_SIZE -
+ EXT2_MIN_BLOCK_LOG_SIZE + 1];
+
+/*
+ * Free all memory allocated by pass1 in preparation for restarting
+ * things.
+ */
+static void unwind_pass1(void)
+{
+ ext2fs_free_mem(&inodes_to_process);
+}
+
+/*
+ * Check to make sure a device inode is real. Returns 1 if the device
+ * checks out, 0 if not.
+ *
+ * Note: this routine is now also used to check FIFO's and Sockets,
+ * since they have the same requirement; the i_block fields should be
+ * zero.
+ */
+static int
+e2fsck_pass1_check_device_inode(ext2_filsys fs, struct ext2_inode *inode)
+{
+ int i;
+
+ /*
+ * If i_blocks is non-zero, or the index flag is set, then
+ * this is a bogus device/fifo/socket
+ */
+ if ((ext2fs_inode_data_blocks(fs, inode) != 0) ||
+ (inode->i_flags & EXT2_INDEX_FL))
+ return 0;
+
+ /*
+ * We should be able to do the test below all the time, but
+ * because the kernel doesn't forcibly clear the device
+ * inode's additional i_block fields, there are some rare
+ * occasions when a legitimate device inode will have non-zero
+ * additional i_block fields. So for now, we only complain
+ * when the immutable flag is set, which should never happen
+ * for devices. (And that's when the problem is caused, since
+ * you can't set or clear immutable flags for devices.) Once
+ * the kernel has been fixed we can change this...
+ */
+ if (inode->i_flags & (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)) {
+ for (i=4; i < EXT2_N_BLOCKS; i++)
+ if (inode->i_block[i])
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Check to make sure a symlink inode is real. Returns 1 if the symlink
+ * checks out, 0 if not.
+ */
+static int
+e2fsck_pass1_check_symlink(ext2_filsys fs, struct ext2_inode *inode, char *buf)
+{
+ unsigned int len;
+ int i;
+ blk_t blocks;
+
+ if ((inode->i_size_high || inode->i_size == 0) ||
+ (inode->i_flags & EXT2_INDEX_FL))
+ return 0;
+
+ blocks = ext2fs_inode_data_blocks(fs, inode);
+ if (blocks) {
+ if ((inode->i_size >= fs->blocksize) ||
+ (blocks != fs->blocksize >> 9) ||
+ (inode->i_block[0] < fs->super->s_first_data_block) ||
+ (inode->i_block[0] >= fs->super->s_blocks_count))
+ return 0;
+
+ for (i = 1; i < EXT2_N_BLOCKS; i++)
+ if (inode->i_block[i])
+ return 0;
+
+ if (io_channel_read_blk(fs->io, inode->i_block[0], 1, buf))
+ return 0;
+
+ len = strnlen(buf, fs->blocksize);
+ if (len == fs->blocksize)
+ return 0;
+ } else {
+ if (inode->i_size >= sizeof(inode->i_block))
+ return 0;
+
+ len = strnlen((char *)inode->i_block, sizeof(inode->i_block));
+ if (len == sizeof(inode->i_block))
+ return 0;
+ }
+ if (len != inode->i_size)
+ return 0;
+ return 1;
+}
+
+/*
+ * If the immutable (or append-only) flag is set on the inode, offer
+ * to clear it.
+ */
+#define BAD_SPECIAL_FLAGS (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)
+static void check_immutable(e2fsck_t ctx, struct problem_context *pctx)
+{
+ if (!(pctx->inode->i_flags & BAD_SPECIAL_FLAGS))
+ return;
+
+ if (!fix_problem(ctx, PR_1_SET_IMMUTABLE, pctx))
+ return;
+
+ pctx->inode->i_flags &= ~BAD_SPECIAL_FLAGS;
+ e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
+}
+
+/*
+ * If device, fifo or socket, check size is zero -- if not offer to
+ * clear it
+ */
+static void check_size(e2fsck_t ctx, struct problem_context *pctx)
+{
+ struct ext2_inode *inode = pctx->inode;
+
+ if ((inode->i_size == 0) && (inode->i_size_high == 0))
+ return;
+
+ if (!fix_problem(ctx, PR_1_SET_NONZSIZE, pctx))
+ return;
+
+ inode->i_size = 0;
+ inode->i_size_high = 0;
+ e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
+}
+
+static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
+{
+ struct ext2_super_block *sb = ctx->fs->super;
+ struct ext2_inode_large *inode;
+ struct ext2_ext_attr_entry *entry;
+ char *start, *end;
+ int storage_size, remain, offs;
+ int problem = 0;
+
+ inode = (struct ext2_inode_large *) pctx->inode;
+ storage_size = EXT2_INODE_SIZE(ctx->fs->super) - EXT2_GOOD_OLD_INODE_SIZE -
+ inode->i_extra_isize;
+ start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
+ inode->i_extra_isize + sizeof(__u32);
+ end = (char *) inode + EXT2_INODE_SIZE(ctx->fs->super);
+ entry = (struct ext2_ext_attr_entry *) start;
+
+ /* scan all entry's headers first */
+
+ /* take finish entry 0UL into account */
+ remain = storage_size - sizeof(__u32);
+ offs = end - start;
+
+ while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
+
+ /* header eats this space */
+ remain -= sizeof(struct ext2_ext_attr_entry);
+
+ /* is attribute name valid? */
+ if (EXT2_EXT_ATTR_SIZE(entry->e_name_len) > remain) {
+ pctx->num = entry->e_name_len;
+ problem = PR_1_ATTR_NAME_LEN;
+ goto fix;
+ }
+
+ /* attribute len eats this space */
+ remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
+
+ /* check value size */
+ if (entry->e_value_size == 0 || entry->e_value_size > remain) {
+ pctx->num = entry->e_value_size;
+ problem = PR_1_ATTR_VALUE_SIZE;
+ goto fix;
+ }
+
+ /* check value placement */
+ if (entry->e_value_offs +
+ EXT2_XATTR_SIZE(entry->e_value_size) != offs) {
+ printf("(entry->e_value_offs + entry->e_value_size: %d, offs: %d)\n", entry->e_value_offs + entry->e_value_size, offs);
+ pctx->num = entry->e_value_offs;
+ problem = PR_1_ATTR_VALUE_OFFSET;
+ goto fix;
+ }
+
+ /* e_value_block must be 0 in inode's ea */
+ if (entry->e_value_block != 0) {
+ pctx->num = entry->e_value_block;
+ problem = PR_1_ATTR_VALUE_BLOCK;
+ goto fix;
+ }
+
+ /* e_hash must be 0 in inode's ea */
+ if (entry->e_hash != 0) {
+ pctx->num = entry->e_hash;
+ problem = PR_1_ATTR_HASH;
+ goto fix;
+ }
+
+ remain -= entry->e_value_size;
+ offs -= EXT2_XATTR_SIZE(entry->e_value_size);
+
+ entry = EXT2_EXT_ATTR_NEXT(entry);
+ }
+fix:
+ /*
+ * it seems like a corruption. it's very unlikely we could repair
+ * EA(s) in automatic fashion -bzzz
+ */
+ if (problem == 0 || !fix_problem(ctx, problem, pctx))
+ return;
+
+ /* simple remove all possible EA(s) */
+ *((__u32 *)start) = 0UL;
+ e2fsck_write_inode_full(ctx, pctx->ino, (struct ext2_inode *)inode,
+ EXT2_INODE_SIZE(sb), "pass1");
+}
+
+static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx)
+{
+ struct ext2_super_block *sb = ctx->fs->super;
+ struct ext2_inode_large *inode;
+ __u32 *eamagic;
+ int min, max;
+
+ inode = (struct ext2_inode_large *) pctx->inode;
+ if (EXT2_INODE_SIZE(sb) == EXT2_GOOD_OLD_INODE_SIZE) {
+ /* this isn't large inode. so, nothing to check */
+ return;
+ }
+
+ /* i_extra_isize must cover i_extra_isize + i_pad1 at least */
+ min = sizeof(inode->i_extra_isize) + sizeof(inode->i_pad1);
+ max = EXT2_INODE_SIZE(sb) - EXT2_GOOD_OLD_INODE_SIZE;
+ /*
+ * For now we will allow i_extra_isize to be 0, but really
+ * implementations should never allow i_extra_isize to be 0
+ */
+ if (inode->i_extra_isize &&
+ (inode->i_extra_isize < min || inode->i_extra_isize > max)) {
+ if (!fix_problem(ctx, PR_1_EXTRA_ISIZE, pctx))
+ return;
+ inode->i_extra_isize = min;
+ e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode,
+ EXT2_INODE_SIZE(sb), "pass1");
+ return;
+ }
+
+ eamagic = (__u32 *) (((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
+ inode->i_extra_isize);
+ if (*eamagic == EXT2_EXT_ATTR_MAGIC) {
+ /* it seems inode has an extended attribute(s) in body */
+ check_ea_in_inode(ctx, pctx);
+ }
+}
+
+static void e2fsck_pass1(e2fsck_t ctx)
+{
+ int i;
+ __u64 max_sizes;
+ ext2_filsys fs = ctx->fs;
+ ext2_ino_t ino;
+ struct ext2_inode *inode;
+ ext2_inode_scan scan;
+ char *block_buf;
+ unsigned char frag, fsize;
+ struct problem_context pctx;
+ struct scan_callback_struct scan_struct;
+ struct ext2_super_block *sb = ctx->fs->super;
+ int imagic_fs;
+ int busted_fs_time = 0;
+ int inode_size;
+
+ clear_problem_context(&pctx);
+
+ if (!(ctx->options & E2F_OPT_PREEN))
+ fix_problem(ctx, PR_1_PASS_HEADER, &pctx);
+
+ if ((fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
+ !(ctx->options & E2F_OPT_NO)) {
+ if (ext2fs_u32_list_create(&ctx->dirs_to_hash, 50))
+ ctx->dirs_to_hash = 0;
+ }
+
+ /* Pass 1 */
+
+#define EXT2_BPP(bits) (1ULL << ((bits) - 2))
+
+ for (i = EXT2_MIN_BLOCK_LOG_SIZE; i <= EXT2_MAX_BLOCK_LOG_SIZE; i++) {
+ max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(i);
+ max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i);
+ max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i) * EXT2_BPP(i);
+ max_sizes = (max_sizes * (1UL << i)) - 1;
+ ext2_max_sizes[i - EXT2_MIN_BLOCK_LOG_SIZE] = max_sizes;
+ }
+#undef EXT2_BPP
+
+ imagic_fs = (sb->s_feature_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES);
+
+ /*
+ * Allocate bitmaps structures
+ */
+ pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("in-use inode map"),
+ &ctx->inode_used_map);
+ if (pctx.errcode) {
+ pctx.num = 1;
+ fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
+ _("directory inode map"), &ctx->inode_dir_map);
+ if (pctx.errcode) {
+ pctx.num = 2;
+ fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
+ _("regular file inode map"), &ctx->inode_reg_map);
+ if (pctx.errcode) {
+ pctx.num = 6;
+ fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ pctx.errcode = ext2fs_allocate_block_bitmap(fs, _("in-use block map"),
+ &ctx->block_found_map);
+ if (pctx.errcode) {
+ pctx.num = 1;
+ fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ pctx.errcode = ext2fs_create_icount2(fs, 0, 0, 0,
+ &ctx->inode_link_info);
+ if (pctx.errcode) {
+ fix_problem(ctx, PR_1_ALLOCATE_ICOUNT, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ inode_size = EXT2_INODE_SIZE(fs->super);
+ inode = (struct ext2_inode *)
+ e2fsck_allocate_memory(ctx, inode_size, "scratch inode");
+
+ inodes_to_process = (struct process_inode_block *)
+ e2fsck_allocate_memory(ctx,
+ (ctx->process_inode_size *
+ sizeof(struct process_inode_block)),
+ "array of inodes to process");
+ process_inode_count = 0;
+
+ pctx.errcode = ext2fs_init_dblist(fs, 0);
+ if (pctx.errcode) {
+ fix_problem(ctx, PR_1_ALLOCATE_DBCOUNT, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+
+ /*
+ * If the last orphan field is set, clear it, since the pass1
+ * processing will automatically find and clear the orphans.
+ * In the future, we may want to try using the last_orphan
+ * linked list ourselves, but for now, we clear it so that the
+ * ext3 mount code won't get confused.
+ */
+ if (!(ctx->options & E2F_OPT_READONLY)) {
+ if (fs->super->s_last_orphan) {
+ fs->super->s_last_orphan = 0;
+ ext2fs_mark_super_dirty(fs);
+ }
+ }
+
+ mark_table_blocks(ctx);
+ block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3,
+ "block interate buffer");
+ e2fsck_use_inode_shortcuts(ctx, 1);
+ ehandler_operation(_("doing inode scan"));
+ pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
+ &scan);
+ if (pctx.errcode) {
+ fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE, 0);
+ ctx->stashed_inode = inode;
+ scan_struct.ctx = ctx;
+ scan_struct.block_buf = block_buf;
+ ext2fs_set_inode_callback(scan, scan_callback, &scan_struct);
+ if (ctx->progress)
+ if ((ctx->progress)(ctx, 1, 0, ctx->fs->group_desc_count))
+ return;
+ if ((fs->super->s_wtime < fs->super->s_inodes_count) ||
+ (fs->super->s_mtime < fs->super->s_inodes_count))
+ busted_fs_time = 1;
+
+ while (1) {
+ pctx.errcode = ext2fs_get_next_inode_full(scan, &ino,
+ inode, inode_size);
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ return;
+ if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) {
+ continue;
+ }
+ if (pctx.errcode) {
+ fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ if (!ino)
+ break;
+ pctx.ino = ino;
+ pctx.inode = inode;
+ ctx->stashed_ino = ino;
+ if (inode->i_links_count) {
+ pctx.errcode = ext2fs_icount_store(ctx->inode_link_info,
+ ino, inode->i_links_count);
+ if (pctx.errcode) {
+ pctx.num = inode->i_links_count;
+ fix_problem(ctx, PR_1_ICOUNT_STORE, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ }
+ if (ino == EXT2_BAD_INO) {
+ struct process_block_struct_1 pb;
+
+ pctx.errcode = ext2fs_copy_bitmap(ctx->block_found_map,
+ &pb.fs_meta_blocks);
+ if (pctx.errcode) {
+ pctx.num = 4;
+ fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ pb.ino = EXT2_BAD_INO;
+ pb.num_blocks = pb.last_block = 0;
+ pb.num_illegal_blocks = 0;
+ pb.suppress = 0; pb.clear = 0; pb.is_dir = 0;
+ pb.is_reg = 0; pb.fragmented = 0; pb.bbcheck = 0;
+ pb.inode = inode;
+ pb.pctx = &pctx;
+ pb.ctx = ctx;
+ pctx.errcode = ext2fs_block_iterate2(fs, ino, 0,
+ block_buf, process_bad_block, &pb);
+ ext2fs_free_block_bitmap(pb.fs_meta_blocks);
+ if (pctx.errcode) {
+ fix_problem(ctx, PR_1_BLOCK_ITERATE, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ if (pb.bbcheck)
+ if (!fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK_PROMPT, &pctx)) {
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
+ clear_problem_context(&pctx);
+ continue;
+ } else if (ino == EXT2_ROOT_INO) {
+ /*
+ * Make sure the root inode is a directory; if
+ * not, offer to clear it. It will be
+ * regnerated in pass #3.
+ */
+ if (!LINUX_S_ISDIR(inode->i_mode)) {
+ if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx)) {
+ inode->i_dtime = time(0);
+ inode->i_links_count = 0;
+ ext2fs_icount_store(ctx->inode_link_info,
+ ino, 0);
+ e2fsck_write_inode(ctx, ino, inode,
+ "pass1");
+ }
+
+ }
+ /*
+ * If dtime is set, offer to clear it. mke2fs
+ * version 0.2b created filesystems with the
+ * dtime field set for the root and lost+found
+ * directories. We won't worry about
+ * /lost+found, since that can be regenerated
+ * easily. But we will fix the root directory
+ * as a special case.
+ */
+ if (inode->i_dtime && inode->i_links_count) {
+ if (fix_problem(ctx, PR_1_ROOT_DTIME, &pctx)) {
+ inode->i_dtime = 0;
+ e2fsck_write_inode(ctx, ino, inode,
+ "pass1");
+ }
+ }
+ } else if (ino == EXT2_JOURNAL_INO) {
+ ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
+ if (fs->super->s_journal_inum == EXT2_JOURNAL_INO) {
+ if (!LINUX_S_ISREG(inode->i_mode) &&
+ fix_problem(ctx, PR_1_JOURNAL_BAD_MODE,
+ &pctx)) {
+ inode->i_mode = LINUX_S_IFREG;
+ e2fsck_write_inode(ctx, ino, inode,
+ "pass1");
+ }
+ check_blocks(ctx, &pctx, block_buf);
+ continue;
+ }
+ if ((inode->i_links_count || inode->i_blocks ||
+ inode->i_blocks || inode->i_block[0]) &&
+ fix_problem(ctx, PR_1_JOURNAL_INODE_NOT_CLEAR,
+ &pctx)) {
+ memset(inode, 0, inode_size);
+ ext2fs_icount_store(ctx->inode_link_info,
+ ino, 0);
+ e2fsck_write_inode_full(ctx, ino, inode,
+ inode_size, "pass1");
+ }
+ } else if (ino < EXT2_FIRST_INODE(fs->super)) {
+ int problem = 0;
+
+ ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
+ if (ino == EXT2_BOOT_LOADER_INO) {
+ if (LINUX_S_ISDIR(inode->i_mode))
+ problem = PR_1_RESERVED_BAD_MODE;
+ } else if (ino == EXT2_RESIZE_INO) {
+ if (inode->i_mode &&
+ !LINUX_S_ISREG(inode->i_mode))
+ problem = PR_1_RESERVED_BAD_MODE;
+ } else {
+ if (inode->i_mode != 0)
+ problem = PR_1_RESERVED_BAD_MODE;
+ }
+ if (problem) {
+ if (fix_problem(ctx, problem, &pctx)) {
+ inode->i_mode = 0;
+ e2fsck_write_inode(ctx, ino, inode,
+ "pass1");
+ }
+ }
+ check_blocks(ctx, &pctx, block_buf);
+ continue;
+ }
+ /*
+ * Check for inodes who might have been part of the
+ * orphaned list linked list. They should have gotten
+ * dealt with by now, unless the list had somehow been
+ * corrupted.
+ *
+ * FIXME: In the future, inodes which are still in use
+ * (and which are therefore) pending truncation should
+ * be handled specially. Right now we just clear the
+ * dtime field, and the normal e2fsck handling of
+ * inodes where i_size and the inode blocks are
+ * inconsistent is to fix i_size, instead of releasing
+ * the extra blocks. This won't catch the inodes that
+ * was at the end of the orphan list, but it's better
+ * than nothing. The right answer is that there
+ * shouldn't be any bugs in the orphan list handling. :-)
+ */
+ if (inode->i_dtime && !busted_fs_time &&
+ inode->i_dtime < ctx->fs->super->s_inodes_count) {
+ if (fix_problem(ctx, PR_1_LOW_DTIME, &pctx)) {
+ inode->i_dtime = inode->i_links_count ?
+ 0 : time(0);
+ e2fsck_write_inode(ctx, ino, inode,
+ "pass1");
+ }
+ }
+
+ /*
+ * This code assumes that deleted inodes have
+ * i_links_count set to 0.
+ */
+ if (!inode->i_links_count) {
+ if (!inode->i_dtime && inode->i_mode) {
+ if (fix_problem(ctx,
+ PR_1_ZERO_DTIME, &pctx)) {
+ inode->i_dtime = time(0);
+ e2fsck_write_inode(ctx, ino, inode,
+ "pass1");
+ }
+ }
+ continue;
+ }
+ /*
+ * n.b. 0.3c ext2fs code didn't clear i_links_count for
+ * deleted files. Oops.
+ *
+ * Since all new ext2 implementations get this right,
+ * we now assume that the case of non-zero
+ * i_links_count and non-zero dtime means that we
+ * should keep the file, not delete it.
+ *
+ */
+ if (inode->i_dtime) {
+ if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) {
+ inode->i_dtime = 0;
+ e2fsck_write_inode(ctx, ino, inode, "pass1");
+ }
+ }
+
+ ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
+ switch (fs->super->s_creator_os) {
+ case EXT2_OS_LINUX:
+ frag = inode->osd2.linux2.l_i_frag;
+ fsize = inode->osd2.linux2.l_i_fsize;
+ break;
+ case EXT2_OS_HURD:
+ frag = inode->osd2.hurd2.h_i_frag;
+ fsize = inode->osd2.hurd2.h_i_fsize;
+ break;
+ case EXT2_OS_MASIX:
+ frag = inode->osd2.masix2.m_i_frag;
+ fsize = inode->osd2.masix2.m_i_fsize;
+ break;
+ default:
+ frag = fsize = 0;
+ }
+
+ if (inode->i_faddr || frag || fsize ||
+ (LINUX_S_ISDIR(inode->i_mode) && inode->i_dir_acl))
+ mark_inode_bad(ctx, ino);
+ if (inode->i_flags & EXT2_IMAGIC_FL) {
+ if (imagic_fs) {
+ if (!ctx->inode_imagic_map)
+ alloc_imagic_map(ctx);
+ ext2fs_mark_inode_bitmap(ctx->inode_imagic_map,
+ ino);
+ } else {
+ if (fix_problem(ctx, PR_1_SET_IMAGIC, &pctx)) {
+ inode->i_flags &= ~EXT2_IMAGIC_FL;
+ e2fsck_write_inode(ctx, ino,
+ inode, "pass1");
+ }
+ }
+ }
+
+ check_inode_extra_space(ctx, &pctx);
+
+ if (LINUX_S_ISDIR(inode->i_mode)) {
+ ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
+ e2fsck_add_dir_info(ctx, ino, 0);
+ ctx->fs_directory_count++;
+ } else if (LINUX_S_ISREG (inode->i_mode)) {
+ ext2fs_mark_inode_bitmap(ctx->inode_reg_map, ino);
+ ctx->fs_regular_count++;
+ } else if (LINUX_S_ISCHR (inode->i_mode) &&
+ e2fsck_pass1_check_device_inode(fs, inode)) {
+ check_immutable(ctx, &pctx);
+ check_size(ctx, &pctx);
+ ctx->fs_chardev_count++;
+ } else if (LINUX_S_ISBLK (inode->i_mode) &&
+ e2fsck_pass1_check_device_inode(fs, inode)) {
+ check_immutable(ctx, &pctx);
+ check_size(ctx, &pctx);
+ ctx->fs_blockdev_count++;
+ } else if (LINUX_S_ISLNK (inode->i_mode) &&
+ e2fsck_pass1_check_symlink(fs, inode, block_buf)) {
+ check_immutable(ctx, &pctx);
+ ctx->fs_symlinks_count++;
+ if (ext2fs_inode_data_blocks(fs, inode) == 0) {
+ ctx->fs_fast_symlinks_count++;
+ check_blocks(ctx, &pctx, block_buf);
+ continue;
+ }
+ }
+ else if (LINUX_S_ISFIFO (inode->i_mode) &&
+ e2fsck_pass1_check_device_inode(fs, inode)) {
+ check_immutable(ctx, &pctx);
+ check_size(ctx, &pctx);
+ ctx->fs_fifo_count++;
+ } else if ((LINUX_S_ISSOCK (inode->i_mode)) &&
+ e2fsck_pass1_check_device_inode(fs, inode)) {
+ check_immutable(ctx, &pctx);
+ check_size(ctx, &pctx);
+ ctx->fs_sockets_count++;
+ } else
+ mark_inode_bad(ctx, ino);
+ if (inode->i_block[EXT2_IND_BLOCK])
+ ctx->fs_ind_count++;
+ if (inode->i_block[EXT2_DIND_BLOCK])
+ ctx->fs_dind_count++;
+ if (inode->i_block[EXT2_TIND_BLOCK])
+ ctx->fs_tind_count++;
+ if (inode->i_block[EXT2_IND_BLOCK] ||
+ inode->i_block[EXT2_DIND_BLOCK] ||
+ inode->i_block[EXT2_TIND_BLOCK] ||
+ inode->i_file_acl) {
+ inodes_to_process[process_inode_count].ino = ino;
+ inodes_to_process[process_inode_count].inode = *inode;
+ process_inode_count++;
+ } else
+ check_blocks(ctx, &pctx, block_buf);
+
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ return;
+
+ if (process_inode_count >= ctx->process_inode_size) {
+ process_inodes(ctx, block_buf);
+
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ return;
+ }
+ }
+ process_inodes(ctx, block_buf);
+ ext2fs_close_inode_scan(scan);
+ ehandler_operation(0);
+
+ /*
+ * If any extended attribute blocks' reference counts need to
+ * be adjusted, either up (ctx->refcount_extra), or down
+ * (ctx->refcount), then fix them.
+ */
+ if (ctx->refcount) {
+ adjust_extattr_refcount(ctx, ctx->refcount, block_buf, -1);
+ ea_refcount_free(ctx->refcount);
+ ctx->refcount = 0;
+ }
+ if (ctx->refcount_extra) {
+ adjust_extattr_refcount(ctx, ctx->refcount_extra,
+ block_buf, +1);
+ ea_refcount_free(ctx->refcount_extra);
+ ctx->refcount_extra = 0;
+ }
+
+ if (ctx->invalid_bitmaps)
+ handle_fs_bad_blocks(ctx);
+
+ /* We don't need the block_ea_map any more */
+ ext2fs_free_block_bitmap(ctx->block_ea_map);
+ ctx->block_ea_map = 0;
+
+ if (ctx->flags & E2F_FLAG_RESIZE_INODE) {
+ ext2fs_block_bitmap save_bmap;
+
+ save_bmap = fs->block_map;
+ fs->block_map = ctx->block_found_map;
+ clear_problem_context(&pctx);
+ pctx.errcode = ext2fs_create_resize_inode(fs);
+ if (pctx.errcode) {
+ fix_problem(ctx, PR_1_RESIZE_INODE_CREATE, &pctx);
+ /* Should never get here */
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ e2fsck_read_inode(ctx, EXT2_RESIZE_INO, inode,
+ "recreate inode");
+ inode->i_mtime = time(0);
+ e2fsck_write_inode(ctx, EXT2_RESIZE_INO, inode,
+ "recreate inode");
+ fs->block_map = save_bmap;
+ ctx->flags &= ~E2F_FLAG_RESIZE_INODE;
+ }
+
+ if (ctx->flags & E2F_FLAG_RESTART) {
+ /*
+ * Only the master copy of the superblock and block
+ * group descriptors are going to be written during a
+ * restart, so set the superblock to be used to be the
+ * master superblock.
+ */
+ ctx->use_superblock = 0;
+ unwind_pass1();
+ goto endit;
+ }
+
+ if (ctx->block_dup_map) {
+ if (ctx->options & E2F_OPT_PREEN) {
+ clear_problem_context(&pctx);
+ fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx);
+ }
+ e2fsck_pass1_dupblocks(ctx, block_buf);
+ }
+ ext2fs_free_mem(&inodes_to_process);
+endit:
+ e2fsck_use_inode_shortcuts(ctx, 0);
+
+ ext2fs_free_mem(&block_buf);
+ ext2fs_free_mem(&inode);
+
+}
+
+/*
+ * When the inode_scan routines call this callback at the end of the
+ * glock group, call process_inodes.
+ */
+static errcode_t scan_callback(ext2_filsys fs,
+ dgrp_t group, void * priv_data)
+{
+ struct scan_callback_struct *scan_struct;
+ e2fsck_t ctx;
+
+ scan_struct = (struct scan_callback_struct *) priv_data;
+ ctx = scan_struct->ctx;
+
+ process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf);
+
+ if (ctx->progress)
+ if ((ctx->progress)(ctx, 1, group+1,
+ ctx->fs->group_desc_count))
+ return EXT2_ET_CANCEL_REQUESTED;
+
+ return 0;
+}
+
+/*
+ * Process the inodes in the "inodes to process" list.
+ */
+static void process_inodes(e2fsck_t ctx, char *block_buf)
+{
+ int i;
+ struct ext2_inode *old_stashed_inode;
+ ext2_ino_t old_stashed_ino;
+ const char *old_operation;
+ char buf[80];
+ struct problem_context pctx;
+
+ /* begin process_inodes */
+ if (process_inode_count == 0)
+ return;
+ old_operation = ehandler_operation(0);
+ old_stashed_inode = ctx->stashed_inode;
+ old_stashed_ino = ctx->stashed_ino;
+ qsort(inodes_to_process, process_inode_count,
+ sizeof(struct process_inode_block), process_inode_cmp);
+ clear_problem_context(&pctx);
+ for (i=0; i < process_inode_count; i++) {
+ pctx.inode = ctx->stashed_inode = &inodes_to_process[i].inode;
+ pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino;
+ sprintf(buf, _("reading indirect blocks of inode %u"),
+ pctx.ino);
+ ehandler_operation(buf);
+ check_blocks(ctx, &pctx, block_buf);
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ break;
+ }
+ ctx->stashed_inode = old_stashed_inode;
+ ctx->stashed_ino = old_stashed_ino;
+ process_inode_count = 0;
+ /* end process inodes */
+
+ ehandler_operation(old_operation);
+}
+
+static int process_inode_cmp(const void *a, const void *b)
+{
+ const struct process_inode_block *ib_a =
+ (const struct process_inode_block *) a;
+ const struct process_inode_block *ib_b =
+ (const struct process_inode_block *) b;
+ int ret;
+
+ ret = (ib_a->inode.i_block[EXT2_IND_BLOCK] -
+ ib_b->inode.i_block[EXT2_IND_BLOCK]);
+ if (ret == 0)
+ ret = ib_a->inode.i_file_acl - ib_b->inode.i_file_acl;
+ return ret;
+}
+
+/*
+ * Mark an inode as being bad in some what
+ */
+static void mark_inode_bad(e2fsck_t ctx, ino_t ino)
+{
+ struct problem_context pctx;
+
+ if (!ctx->inode_bad_map) {
+ clear_problem_context(&pctx);
+
+ pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
+ _("bad inode map"), &ctx->inode_bad_map);
+ if (pctx.errcode) {
+ pctx.num = 3;
+ fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
+ /* Should never get here */
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ }
+ ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino);
+}
+
+
+/*
+ * This procedure will allocate the inode imagic table
+ */
+static void alloc_imagic_map(e2fsck_t ctx)
+{
+ struct problem_context pctx;
+
+ clear_problem_context(&pctx);
+ pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
+ _("imagic inode map"),
+ &ctx->inode_imagic_map);
+ if (pctx.errcode) {
+ pctx.num = 5;
+ fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
+ /* Should never get here */
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+}
+
+/*
+ * Marks a block as in use, setting the dup_map if it's been set
+ * already. Called by process_block and process_bad_block.
+ *
+ * WARNING: Assumes checks have already been done to make sure block
+ * is valid. This is true in both process_block and process_bad_block.
+ */
+static void mark_block_used(e2fsck_t ctx, blk_t block)
+{
+ struct problem_context pctx;
+
+ clear_problem_context(&pctx);
+
+ if (ext2fs_fast_test_block_bitmap(ctx->block_found_map, block)) {
+ if (!ctx->block_dup_map) {
+ pctx.errcode = ext2fs_allocate_block_bitmap(ctx->fs,
+ _("multiply claimed block map"),
+ &ctx->block_dup_map);
+ if (pctx.errcode) {
+ pctx.num = 3;
+ fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR,
+ &pctx);
+ /* Should never get here */
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ }
+ ext2fs_fast_mark_block_bitmap(ctx->block_dup_map, block);
+ } else {
+ ext2fs_fast_mark_block_bitmap(ctx->block_found_map, block);
+ }
+}
+
+/*
+ * Adjust the extended attribute block's reference counts at the end
+ * of pass 1, either by subtracting out references for EA blocks that
+ * are still referenced in ctx->refcount, or by adding references for
+ * EA blocks that had extra references as accounted for in
+ * ctx->refcount_extra.
+ */
+static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
+ char *block_buf, int adjust_sign)
+{
+ struct ext2_ext_attr_header *header;
+ struct problem_context pctx;
+ ext2_filsys fs = ctx->fs;
+ blk_t blk;
+ __u32 should_be;
+ int count;
+
+ clear_problem_context(&pctx);
+
+ ea_refcount_intr_begin(refcount);
+ while (1) {
+ if ((blk = ea_refcount_intr_next(refcount, &count)) == 0)
+ break;
+ pctx.blk = blk;
+ pctx.errcode = ext2fs_read_ext_attr(fs, blk, block_buf);
+ if (pctx.errcode) {
+ fix_problem(ctx, PR_1_EXTATTR_READ_ABORT, &pctx);
+ return;
+ }
+ header = (struct ext2_ext_attr_header *) block_buf;
+ pctx.blkcount = header->h_refcount;
+ should_be = header->h_refcount + adjust_sign * count;
+ pctx.num = should_be;
+ if (fix_problem(ctx, PR_1_EXTATTR_REFCOUNT, &pctx)) {
+ header->h_refcount = should_be;
+ pctx.errcode = ext2fs_write_ext_attr(fs, blk,
+ block_buf);
+ if (pctx.errcode) {
+ fix_problem(ctx, PR_1_EXTATTR_WRITE, &pctx);
+ continue;
+ }
+ }
+ }
+}
+
+/*
+ * Handle processing the extended attribute blocks
+ */
+static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
+ char *block_buf)
+{
+ ext2_filsys fs = ctx->fs;
+ ext2_ino_t ino = pctx->ino;
+ struct ext2_inode *inode = pctx->inode;
+ blk_t blk;
+ char * end;
+ struct ext2_ext_attr_header *header;
+ struct ext2_ext_attr_entry *entry;
+ int count;
+ region_t region;
+
+ blk = inode->i_file_acl;
+ if (blk == 0)
+ return 0;
+
+ /*
+ * If the Extended attribute flag isn't set, then a non-zero
+ * file acl means that the inode is corrupted.
+ *
+ * Or if the extended attribute block is an invalid block,
+ * then the inode is also corrupted.
+ */
+ if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) ||
+ (blk < fs->super->s_first_data_block) ||
+ (blk >= fs->super->s_blocks_count)) {
+ mark_inode_bad(ctx, ino);
+ return 0;
+ }
+
+ /* If ea bitmap hasn't been allocated, create it */
+ if (!ctx->block_ea_map) {
+ pctx->errcode = ext2fs_allocate_block_bitmap(fs,
+ _("ext attr block map"),
+ &ctx->block_ea_map);
+ if (pctx->errcode) {
+ pctx->num = 2;
+ fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return 0;
+ }
+ }
+
+ /* Create the EA refcount structure if necessary */
+ if (!ctx->refcount) {
+ pctx->errcode = ea_refcount_create(0, &ctx->refcount);
+ if (pctx->errcode) {
+ pctx->num = 1;
+ fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return 0;
+ }
+ }
+
+ /* Have we seen this EA block before? */
+ if (ext2fs_fast_test_block_bitmap(ctx->block_ea_map, blk)) {
+ if (ea_refcount_decrement(ctx->refcount, blk, 0) == 0)
+ return 1;
+ /* Ooops, this EA was referenced more than it stated */
+ if (!ctx->refcount_extra) {
+ pctx->errcode = ea_refcount_create(0,
+ &ctx->refcount_extra);
+ if (pctx->errcode) {
+ pctx->num = 2;
+ fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return 0;
+ }
+ }
+ ea_refcount_increment(ctx->refcount_extra, blk, 0);
+ return 1;
+ }
+
+ /*
+ * OK, we haven't seen this EA block yet. So we need to
+ * validate it
+ */
+ pctx->blk = blk;
+ pctx->errcode = ext2fs_read_ext_attr(fs, blk, block_buf);
+ if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx))
+ goto clear_extattr;
+ header = (struct ext2_ext_attr_header *) block_buf;
+ pctx->blk = inode->i_file_acl;
+ if (((ctx->ext_attr_ver == 1) &&
+ (header->h_magic != EXT2_EXT_ATTR_MAGIC_v1)) ||
+ ((ctx->ext_attr_ver == 2) &&
+ (header->h_magic != EXT2_EXT_ATTR_MAGIC))) {
+ if (fix_problem(ctx, PR_1_BAD_EA_BLOCK, pctx))
+ goto clear_extattr;
+ }
+
+ if (header->h_blocks != 1) {
+ if (fix_problem(ctx, PR_1_EA_MULTI_BLOCK, pctx))
+ goto clear_extattr;
+ }
+
+ region = region_create(0, fs->blocksize);
+ if (!region) {
+ fix_problem(ctx, PR_1_EA_ALLOC_REGION, pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return 0;
+ }
+ if (region_allocate(region, 0, sizeof(struct ext2_ext_attr_header))) {
+ if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
+ goto clear_extattr;
+ }
+
+ entry = (struct ext2_ext_attr_entry *)(header+1);
+ end = block_buf + fs->blocksize;
+ while ((char *)entry < end && *(__u32 *)entry) {
+ if (region_allocate(region, (char *)entry - (char *)header,
+ EXT2_EXT_ATTR_LEN(entry->e_name_len))) {
+ if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
+ goto clear_extattr;
+ }
+ if ((ctx->ext_attr_ver == 1 &&
+ (entry->e_name_len == 0 || entry->e_name_index != 0)) ||
+ (ctx->ext_attr_ver == 2 &&
+ entry->e_name_index == 0)) {
+ if (fix_problem(ctx, PR_1_EA_BAD_NAME, pctx))
+ goto clear_extattr;
+ }
+ if (entry->e_value_block != 0) {
+ if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx))
+ goto clear_extattr;
+ }
+ if (entry->e_value_size &&
+ region_allocate(region, entry->e_value_offs,
+ EXT2_EXT_ATTR_SIZE(entry->e_value_size))) {
+ if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
+ goto clear_extattr;
+ }
+ entry = EXT2_EXT_ATTR_NEXT(entry);
+ }
+ if (region_allocate(region, (char *)entry - (char *)header, 4)) {
+ if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
+ goto clear_extattr;
+ }
+ region_free(region);
+
+ count = header->h_refcount - 1;
+ if (count)
+ ea_refcount_store(ctx->refcount, blk, count);
+ mark_block_used(ctx, blk);
+ ext2fs_fast_mark_block_bitmap(ctx->block_ea_map, blk);
+
+ return 1;
+
+clear_extattr:
+ inode->i_file_acl = 0;
+ e2fsck_write_inode(ctx, ino, inode, "check_ext_attr");
+ return 0;
+}
+
+/* Returns 1 if bad htree, 0 if OK */
+static int handle_htree(e2fsck_t ctx, struct problem_context *pctx,
+ ext2_ino_t ino FSCK_ATTR((unused)),
+ struct ext2_inode *inode,
+ char *block_buf)
+{
+ struct ext2_dx_root_info *root;
+ ext2_filsys fs = ctx->fs;
+ errcode_t retval;
+ blk_t blk;
+
+ if ((!LINUX_S_ISDIR(inode->i_mode) &&
+ fix_problem(ctx, PR_1_HTREE_NODIR, pctx)) ||
+ (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
+ fix_problem(ctx, PR_1_HTREE_SET, pctx)))
+ return 1;
+
+ blk = inode->i_block[0];
+ if (((blk == 0) ||
+ (blk < fs->super->s_first_data_block) ||
+ (blk >= fs->super->s_blocks_count)) &&
+ fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
+ return 1;
+
+ retval = io_channel_read_blk(fs->io, blk, 1, block_buf);
+ if (retval && fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
+ return 1;
+
+ /* XXX should check that beginning matches a directory */
+ root = (struct ext2_dx_root_info *) (block_buf + 24);
+
+ if ((root->reserved_zero || root->info_length < 8) &&
+ fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
+ return 1;
+
+ pctx->num = root->hash_version;
+ if ((root->hash_version != EXT2_HASH_LEGACY) &&
+ (root->hash_version != EXT2_HASH_HALF_MD4) &&
+ (root->hash_version != EXT2_HASH_TEA) &&
+ fix_problem(ctx, PR_1_HTREE_HASHV, pctx))
+ return 1;
+
+ if ((root->unused_flags & EXT2_HASH_FLAG_INCOMPAT) &&
+ fix_problem(ctx, PR_1_HTREE_INCOMPAT, pctx))
+ return 1;
+
+ pctx->num = root->indirect_levels;
+ if ((root->indirect_levels > 1) &&
+ fix_problem(ctx, PR_1_HTREE_DEPTH, pctx))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * This subroutine is called on each inode to account for all of the
+ * blocks used by that inode.
+ */
+static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
+ char *block_buf)
+{
+ ext2_filsys fs = ctx->fs;
+ struct process_block_struct_1 pb;
+ ext2_ino_t ino = pctx->ino;
+ struct ext2_inode *inode = pctx->inode;
+ int bad_size = 0;
+ int dirty_inode = 0;
+ __u64 size;
+
+ pb.ino = ino;
+ pb.num_blocks = 0;
+ pb.last_block = -1;
+ pb.num_illegal_blocks = 0;
+ pb.suppress = 0; pb.clear = 0;
+ pb.fragmented = 0;
+ pb.compressed = 0;
+ pb.previous_block = 0;
+ pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
+ pb.is_reg = LINUX_S_ISREG(inode->i_mode);
+ pb.max_blocks = 1 << (31 - fs->super->s_log_block_size);
+ pb.inode = inode;
+ pb.pctx = pctx;
+ pb.ctx = ctx;
+ pctx->ino = ino;
+ pctx->errcode = 0;
+
+ if (inode->i_flags & EXT2_COMPRBLK_FL) {
+ if (fs->super->s_feature_incompat &
+ EXT2_FEATURE_INCOMPAT_COMPRESSION)
+ pb.compressed = 1;
+ else {
+ if (fix_problem(ctx, PR_1_COMPR_SET, pctx)) {
+ inode->i_flags &= ~EXT2_COMPRBLK_FL;
+ dirty_inode++;
+ }
+ }
+ }
+
+ if (inode->i_file_acl && check_ext_attr(ctx, pctx, block_buf))
+ pb.num_blocks++;
+
+ if (ext2fs_inode_has_valid_blocks(inode))
+ pctx->errcode = ext2fs_block_iterate2(fs, ino,
+ pb.is_dir ? BLOCK_FLAG_HOLE : 0,
+ block_buf, process_block, &pb);
+ end_problem_latch(ctx, PR_LATCH_BLOCK);
+ end_problem_latch(ctx, PR_LATCH_TOOBIG);
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ goto out;
+ if (pctx->errcode)
+ fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx);
+
+ if (pb.fragmented && pb.num_blocks < fs->super->s_blocks_per_group)
+ ctx->fs_fragmented++;
+
+ if (pb.clear) {
+ inode->i_links_count = 0;
+ ext2fs_icount_store(ctx->inode_link_info, ino, 0);
+ inode->i_dtime = time(0);
+ dirty_inode++;
+ ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
+ ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
+ ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
+ /*
+ * The inode was probably partially accounted for
+ * before processing was aborted, so we need to
+ * restart the pass 1 scan.
+ */
+ ctx->flags |= E2F_FLAG_RESTART;
+ goto out;
+ }
+
+ if (inode->i_flags & EXT2_INDEX_FL) {
+ if (handle_htree(ctx, pctx, ino, inode, block_buf)) {
+ inode->i_flags &= ~EXT2_INDEX_FL;
+ dirty_inode++;
+ } else {
+#ifdef ENABLE_HTREE
+ e2fsck_add_dx_dir(ctx, ino, pb.last_block+1);
+#endif
+ }
+ }
+ if (ctx->dirs_to_hash && pb.is_dir &&
+ !(inode->i_flags & EXT2_INDEX_FL) &&
+ ((inode->i_size / fs->blocksize) >= 3))
+ ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
+
+ if (!pb.num_blocks && pb.is_dir) {
+ if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) {
+ inode->i_links_count = 0;
+ ext2fs_icount_store(ctx->inode_link_info, ino, 0);
+ inode->i_dtime = time(0);
+ dirty_inode++;
+ ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
+ ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
+ ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
+ ctx->fs_directory_count--;
+ goto out;
+ }
+ }
+
+ pb.num_blocks *= (fs->blocksize / 512);
+
+ if (pb.is_dir) {
+ int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super);
+ if (nblock > (pb.last_block + 1))
+ bad_size = 1;
+ else if (nblock < (pb.last_block + 1)) {
+ if (((pb.last_block + 1) - nblock) >
+ fs->super->s_prealloc_dir_blocks)
+ bad_size = 2;
+ }
+ } else {
+ size = EXT2_I_SIZE(inode);
+ if ((pb.last_block >= 0) &&
+ (size < (__u64) pb.last_block * fs->blocksize))
+ bad_size = 3;
+ else if (size > ext2_max_sizes[fs->super->s_log_block_size])
+ bad_size = 4;
+ }
+ /* i_size for symlinks is checked elsewhere */
+ if (bad_size && !LINUX_S_ISLNK(inode->i_mode)) {
+ pctx->num = (pb.last_block+1) * fs->blocksize;
+ if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) {
+ inode->i_size = pctx->num;
+ if (!LINUX_S_ISDIR(inode->i_mode))
+ inode->i_size_high = pctx->num >> 32;
+ dirty_inode++;
+ }
+ pctx->num = 0;
+ }
+ if (LINUX_S_ISREG(inode->i_mode) &&
+ (inode->i_size_high || inode->i_size & 0x80000000UL))
+ ctx->large_files++;
+ if (pb.num_blocks != inode->i_blocks) {
+ pctx->num = pb.num_blocks;
+ if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) {
+ inode->i_blocks = pb.num_blocks;
+ dirty_inode++;
+ }
+ pctx->num = 0;
+ }
+out:
+ if (dirty_inode)
+ e2fsck_write_inode(ctx, ino, inode, "check_blocks");
+}
+
+
+/*
+ * This is a helper function for check_blocks().
+ */
+static int process_block(ext2_filsys fs,
+ blk_t *block_nr,
+ e2_blkcnt_t blockcnt,
+ blk_t ref_block FSCK_ATTR((unused)),
+ int ref_offset FSCK_ATTR((unused)),
+ void *priv_data)
+{
+ struct process_block_struct_1 *p;
+ struct problem_context *pctx;
+ blk_t blk = *block_nr;
+ int ret_code = 0;
+ int problem = 0;
+ e2fsck_t ctx;
+
+ p = (struct process_block_struct_1 *) priv_data;
+ pctx = p->pctx;
+ ctx = p->ctx;
+
+ if (p->compressed && (blk == EXT2FS_COMPRESSED_BLKADDR)) {
+ /* todo: Check that the comprblk_fl is high, that the
+ blkaddr pattern looks right (all non-holes up to
+ first EXT2FS_COMPRESSED_BLKADDR, then all
+ EXT2FS_COMPRESSED_BLKADDR up to end of cluster),
+ that the feature_incompat bit is high, and that the
+ inode is a regular file. If we're doing a "full
+ check" (a concept introduced to e2fsck by e2compr,
+ meaning that we look at data blocks as well as
+ metadata) then call some library routine that
+ checks the compressed data. I'll have to think
+ about this, because one particularly important
+ problem to be able to fix is to recalculate the
+ cluster size if necessary. I think that perhaps
+ we'd better do most/all e2compr-specific checks
+ separately, after the non-e2compr checks. If not
+ doing a full check, it may be useful to test that
+ the personality is linux; e.g. if it isn't then
+ perhaps this really is just an illegal block. */
+ return 0;
+ }
+
+ if (blk == 0) {
+ if (p->is_dir == 0) {
+ /*
+ * Should never happen, since only directories
+ * get called with BLOCK_FLAG_HOLE
+ */
+#ifdef DEBUG_E2FSCK
+ printf("process_block() called with blk == 0, "
+ "blockcnt=%d, inode %lu???\n",
+ blockcnt, p->ino);
+#endif
+ return 0;
+ }
+ if (blockcnt < 0)
+ return 0;
+ if (blockcnt * fs->blocksize < p->inode->i_size) {
+ goto mark_dir;
+ }
+ return 0;
+ }
+
+ /*
+ * Simplistic fragmentation check. We merely require that the
+ * file be contiguous. (Which can never be true for really
+ * big files that are greater than a block group.)
+ */
+ if (!HOLE_BLKADDR(p->previous_block)) {
+ if (p->previous_block+1 != blk)
+ p->fragmented = 1;
+ }
+ p->previous_block = blk;
+
+ if (p->is_dir && blockcnt > (1 << (21 - fs->super->s_log_block_size)))
+ problem = PR_1_TOOBIG_DIR;
+ if (p->is_reg && p->num_blocks+1 >= p->max_blocks)
+ problem = PR_1_TOOBIG_REG;
+ if (!p->is_dir && !p->is_reg && blockcnt > 0)
+ problem = PR_1_TOOBIG_SYMLINK;
+
+ if (blk < fs->super->s_first_data_block ||
+ blk >= fs->super->s_blocks_count)
+ problem = PR_1_ILLEGAL_BLOCK_NUM;
+
+ if (problem) {
+ p->num_illegal_blocks++;
+ if (!p->suppress && (p->num_illegal_blocks % 12) == 0) {
+ if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) {
+ p->clear = 1;
+ return BLOCK_ABORT;
+ }
+ if (fix_problem(ctx, PR_1_SUPPRESS_MESSAGES, pctx)) {
+ p->suppress = 1;
+ set_latch_flags(PR_LATCH_BLOCK,
+ PRL_SUPPRESS, 0);
+ }
+ }
+ pctx->blk = blk;
+ pctx->blkcount = blockcnt;
+ if (fix_problem(ctx, problem, pctx)) {
+ blk = *block_nr = 0;
+ ret_code = BLOCK_CHANGED;
+ goto mark_dir;
+ } else
+ return 0;
+ }
+
+ if (p->ino == EXT2_RESIZE_INO) {
+ /*
+ * The resize inode has already be sanity checked
+ * during pass #0 (the superblock checks). All we
+ * have to do is mark the double indirect block as
+ * being in use; all of the other blocks are handled
+ * by mark_table_blocks()).
+ */
+ if (blockcnt == BLOCK_COUNT_DIND)
+ mark_block_used(ctx, blk);
+ } else
+ mark_block_used(ctx, blk);
+ p->num_blocks++;
+ if (blockcnt >= 0)
+ p->last_block = blockcnt;
+mark_dir:
+ if (p->is_dir && (blockcnt >= 0)) {
+ pctx->errcode = ext2fs_add_dir_block(fs->dblist, p->ino,
+ blk, blockcnt);
+ if (pctx->errcode) {
+ pctx->blk = blk;
+ pctx->num = blockcnt;
+ fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
+ /* Should never get here */
+ ctx->flags |= E2F_FLAG_ABORT;
+ return BLOCK_ABORT;
+ }
+ }
+ return ret_code;
+}
+
+static int process_bad_block(ext2_filsys fs FSCK_ATTR((unused)),
+ blk_t *block_nr,
+ e2_blkcnt_t blockcnt,
+ blk_t ref_block FSCK_ATTR((unused)),
+ int ref_offset FSCK_ATTR((unused)),
+ void *priv_data EXT2FS_ATTR((unused)))
+{
+ /*
+ * Note: This function processes blocks for the bad blocks
+ * inode, which is never compressed. So we don't use HOLE_BLKADDR().
+ */
+
+ printf("Unrecoverable Error: Found %"PRIi64" bad blocks starting at block number: %u\n", blockcnt, *block_nr);
+ return BLOCK_ERROR;
+}
+
+/*
+ * This routine gets called at the end of pass 1 if bad blocks are
+ * detected in the superblock, group descriptors, inode_bitmaps, or
+ * block bitmaps. At this point, all of the blocks have been mapped
+ * out, so we can try to allocate new block(s) to replace the bad
+ * blocks.
+ */
+static void handle_fs_bad_blocks(e2fsck_t ctx)
+{
+ printf("Bad blocks detected on your filesystem\n"
+ "You should get your data off as the device will soon die\n");
+}
+
+/*
+ * This routine marks all blocks which are used by the superblock,
+ * group descriptors, inode bitmaps, and block bitmaps.
+ */
+static void mark_table_blocks(e2fsck_t ctx)
+{
+ ext2_filsys fs = ctx->fs;
+ blk_t block, b;
+ dgrp_t i;
+ int j;
+ struct problem_context pctx;
+
+ clear_problem_context(&pctx);
+
+ block = fs->super->s_first_data_block;
+ for (i = 0; i < fs->group_desc_count; i++) {
+ pctx.group = i;
+
+ ext2fs_reserve_super_and_bgd(fs, i, ctx->block_found_map);
+
+ /*
+ * Mark the blocks used for the inode table
+ */
+ if (fs->group_desc[i].bg_inode_table) {
+ for (j = 0, b = fs->group_desc[i].bg_inode_table;
+ j < fs->inode_blocks_per_group;
+ j++, b++) {
+ if (ext2fs_test_block_bitmap(ctx->block_found_map,
+ b)) {
+ pctx.blk = b;
+ if (fix_problem(ctx,
+ PR_1_ITABLE_CONFLICT, &pctx)) {
+ ctx->invalid_inode_table_flag[i]++;
+ ctx->invalid_bitmaps++;
+ }
+ } else {
+ ext2fs_mark_block_bitmap(ctx->block_found_map,
+ b);
+ }
+ }
+ }
+
+ /*
+ * Mark block used for the block bitmap
+ */
+ if (fs->group_desc[i].bg_block_bitmap) {
+ if (ext2fs_test_block_bitmap(ctx->block_found_map,
+ fs->group_desc[i].bg_block_bitmap)) {
+ pctx.blk = fs->group_desc[i].bg_block_bitmap;
+ if (fix_problem(ctx, PR_1_BB_CONFLICT, &pctx)) {
+ ctx->invalid_block_bitmap_flag[i]++;
+ ctx->invalid_bitmaps++;
+ }
+ } else {
+ ext2fs_mark_block_bitmap(ctx->block_found_map,
+ fs->group_desc[i].bg_block_bitmap);
+ }
+
+ }
+ /*
+ * Mark block used for the inode bitmap
+ */
+ if (fs->group_desc[i].bg_inode_bitmap) {
+ if (ext2fs_test_block_bitmap(ctx->block_found_map,
+ fs->group_desc[i].bg_inode_bitmap)) {
+ pctx.blk = fs->group_desc[i].bg_inode_bitmap;
+ if (fix_problem(ctx, PR_1_IB_CONFLICT, &pctx)) {
+ ctx->invalid_inode_bitmap_flag[i]++;
+ ctx->invalid_bitmaps++;
+ }
+ } else {
+ ext2fs_mark_block_bitmap(ctx->block_found_map,
+ fs->group_desc[i].bg_inode_bitmap);
+ }
+ }
+ block += fs->super->s_blocks_per_group;
+ }
+}
+
+/*
+ * Thes subroutines short circuits ext2fs_get_blocks and
+ * ext2fs_check_directory; we use them since we already have the inode
+ * structure, so there's no point in letting the ext2fs library read
+ * the inode again.
+ */
+static errcode_t pass1_get_blocks(ext2_filsys fs, ext2_ino_t ino,
+ blk_t *blocks)
+{
+ e2fsck_t ctx = (e2fsck_t) fs->priv_data;
+ int i;
+
+ if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
+ return EXT2_ET_CALLBACK_NOTHANDLED;
+
+ for (i=0; i < EXT2_N_BLOCKS; i++)
+ blocks[i] = ctx->stashed_inode->i_block[i];
+ return 0;
+}
+
+static errcode_t pass1_read_inode(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode *inode)
+{
+ e2fsck_t ctx = (e2fsck_t) fs->priv_data;
+
+ if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
+ return EXT2_ET_CALLBACK_NOTHANDLED;
+ *inode = *ctx->stashed_inode;
+ return 0;
+}
+
+static errcode_t pass1_write_inode(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode *inode)
+{
+ e2fsck_t ctx = (e2fsck_t) fs->priv_data;
+
+ if ((ino == ctx->stashed_ino) && ctx->stashed_inode)
+ *ctx->stashed_inode = *inode;
+ return EXT2_ET_CALLBACK_NOTHANDLED;
+}
+
+static errcode_t pass1_check_directory(ext2_filsys fs, ext2_ino_t ino)
+{
+ e2fsck_t ctx = (e2fsck_t) fs->priv_data;
+
+ if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
+ return EXT2_ET_CALLBACK_NOTHANDLED;
+
+ if (!LINUX_S_ISDIR(ctx->stashed_inode->i_mode))
+ return EXT2_ET_NO_DIRECTORY;
+ return 0;
+}
+
+void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool)
+{
+ ext2_filsys fs = ctx->fs;
+
+ if (bool) {
+ fs->get_blocks = pass1_get_blocks;
+ fs->check_directory = pass1_check_directory;
+ fs->read_inode = pass1_read_inode;
+ fs->write_inode = pass1_write_inode;
+ ctx->stashed_ino = 0;
+ } else {
+ fs->get_blocks = 0;
+ fs->check_directory = 0;
+ fs->read_inode = 0;
+ fs->write_inode = 0;
+ }
+}
+
+/*
+ * pass1b.c --- Pass #1b of e2fsck
+ *
+ * This file contains pass1B, pass1C, and pass1D of e2fsck. They are
+ * only invoked if pass 1 discovered blocks which are in use by more
+ * than one inode.
+ *
+ * Pass1B scans the data blocks of all the inodes again, generating a
+ * complete list of duplicate blocks and which inodes have claimed
+ * them.
+ *
+ * Pass1C does a tree-traversal of the filesystem, to determine the
+ * parent directories of these inodes. This step is necessary so that
+ * e2fsck can print out the pathnames of affected inodes.
+ *
+ * Pass1D is a reconciliation pass. For each inode with duplicate
+ * blocks, the user is prompted if s/he would like to clone the file
+ * (so that the file gets a fresh copy of the duplicated blocks) or
+ * simply to delete the file.
+ *
+ */
+
+
+/* Needed for architectures where sizeof(int) != sizeof(void *) */
+#define INT_TO_VOIDPTR(val) ((void *)(intptr_t)(val))
+#define VOIDPTR_TO_INT(ptr) ((int)(intptr_t)(ptr))
+
+/* Define an extension to the ext2 library's block count information */
+#define BLOCK_COUNT_EXTATTR (-5)
+
+struct block_el {
+ blk_t block;
+ struct block_el *next;
+};
+
+struct inode_el {
+ ext2_ino_t inode;
+ struct inode_el *next;
+};
+
+struct dup_block {
+ int num_bad;
+ struct inode_el *inode_list;
+};
+
+/*
+ * This structure stores information about a particular inode which
+ * is sharing blocks with other inodes. This information is collected
+ * to display to the user, so that the user knows what files he or she
+ * is dealing with, when trying to decide how to resolve the conflict
+ * of multiply-claimed blocks.
+ */
+struct dup_inode {
+ ext2_ino_t dir;
+ int num_dupblocks;
+ struct ext2_inode inode;
+ struct block_el *block_list;
+};
+
+static int process_pass1b_block(ext2_filsys fs, blk_t *blocknr,
+ e2_blkcnt_t blockcnt, blk_t ref_blk,
+ int ref_offset, void *priv_data);
+static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
+ struct dup_inode *dp, char *block_buf);
+static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
+ struct dup_inode *dp, char* block_buf);
+static int check_if_fs_block(e2fsck_t ctx, blk_t test_blk);
+
+static void pass1b(e2fsck_t ctx, char *block_buf);
+static void pass1c(e2fsck_t ctx, char *block_buf);
+static void pass1d(e2fsck_t ctx, char *block_buf);
+
+static int dup_inode_count = 0;
+
+static dict_t blk_dict, ino_dict;
+
+static ext2fs_inode_bitmap inode_dup_map;
+
+static int dict_int_cmp(const void *a, const void *b)
+{
+ intptr_t ia, ib;
+
+ ia = (intptr_t)a;
+ ib = (intptr_t)b;
+
+ return (ia-ib);
+}
+
+/*
+ * Add a duplicate block record
+ */
+static void add_dupe(e2fsck_t ctx, ext2_ino_t ino, blk_t blk,
+ struct ext2_inode *inode)
+{
+ dnode_t *n;
+ struct dup_block *db;
+ struct dup_inode *di;
+ struct block_el *blk_el;
+ struct inode_el *ino_el;
+
+ n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk));
+ if (n)
+ db = (struct dup_block *) dnode_get(n);
+ else {
+ db = (struct dup_block *) e2fsck_allocate_memory(ctx,
+ sizeof(struct dup_block), "duplicate block header");
+ db->num_bad = 0;
+ db->inode_list = 0;
+ dict_alloc_insert(&blk_dict, INT_TO_VOIDPTR(blk), db);
+ }
+ ino_el = (struct inode_el *) e2fsck_allocate_memory(ctx,
+ sizeof(struct inode_el), "inode element");
+ ino_el->inode = ino;
+ ino_el->next = db->inode_list;
+ db->inode_list = ino_el;
+ db->num_bad++;
+
+ n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino));
+ if (n)
+ di = (struct dup_inode *) dnode_get(n);
+ else {
+ di = (struct dup_inode *) e2fsck_allocate_memory(ctx,
+ sizeof(struct dup_inode), "duplicate inode header");
+ di->dir = (ino == EXT2_ROOT_INO) ? EXT2_ROOT_INO : 0;
+ di->num_dupblocks = 0;
+ di->block_list = 0;
+ di->inode = *inode;
+ dict_alloc_insert(&ino_dict, INT_TO_VOIDPTR(ino), di);
+ }
+ blk_el = (struct block_el *) e2fsck_allocate_memory(ctx,
+ sizeof(struct block_el), "block element");
+ blk_el->block = blk;
+ blk_el->next = di->block_list;
+ di->block_list = blk_el;
+ di->num_dupblocks++;
+}
+
+/*
+ * Free a duplicate inode record
+ */
+static void inode_dnode_free(dnode_t *node)
+{
+ struct dup_inode *di;
+ struct block_el *p, *next;
+
+ di = (struct dup_inode *) dnode_get(node);
+ for (p = di->block_list; p; p = next) {
+ next = p->next;
+ free(p);
+ }
+ free(node);
+}
+
+/*
+ * Free a duplicate block record
+ */
+static void block_dnode_free(dnode_t *node)
+{
+ struct dup_block *db;
+ struct inode_el *p, *next;
+
+ db = (struct dup_block *) dnode_get(node);
+ for (p = db->inode_list; p; p = next) {
+ next = p->next;
+ free(p);
+ }
+ free(node);
+}
+
+
+/*
+ * Main procedure for handling duplicate blocks
+ */
+void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf)
+{
+ ext2_filsys fs = ctx->fs;
+ struct problem_context pctx;
+
+ clear_problem_context(&pctx);
+
+ pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
+ _("multiply claimed inode map"), &inode_dup_map);
+ if (pctx.errcode) {
+ fix_problem(ctx, PR_1B_ALLOCATE_IBITMAP_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+
+ dict_init(&ino_dict, DICTCOUNT_T_MAX, dict_int_cmp);
+ dict_init(&blk_dict, DICTCOUNT_T_MAX, dict_int_cmp);
+ dict_set_allocator(&ino_dict, inode_dnode_free);
+ dict_set_allocator(&blk_dict, block_dnode_free);
+
+ pass1b(ctx, block_buf);
+ pass1c(ctx, block_buf);
+ pass1d(ctx, block_buf);
+
+ /*
+ * Time to free all of the accumulated data structures that we
+ * don't need anymore.
+ */
+ dict_free_nodes(&ino_dict);
+ dict_free_nodes(&blk_dict);
+}
+
+/*
+ * Scan the inodes looking for inodes that contain duplicate blocks.
+ */
+struct process_block_struct_1b {
+ e2fsck_t ctx;
+ ext2_ino_t ino;
+ int dup_blocks;
+ struct ext2_inode *inode;
+ struct problem_context *pctx;
+};
+
+static void pass1b(e2fsck_t ctx, char *block_buf)
+{
+ ext2_filsys fs = ctx->fs;
+ ext2_ino_t ino;
+ struct ext2_inode inode;
+ ext2_inode_scan scan;
+ struct process_block_struct_1b pb;
+ struct problem_context pctx;
+
+ clear_problem_context(&pctx);
+
+ if (!(ctx->options & E2F_OPT_PREEN))
+ fix_problem(ctx, PR_1B_PASS_HEADER, &pctx);
+ pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
+ &scan);
+ if (pctx.errcode) {
+ fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ ctx->stashed_inode = &inode;
+ pb.ctx = ctx;
+ pb.pctx = &pctx;
+ pctx.str = "pass1b";
+ while (1) {
+ pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode);
+ if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
+ continue;
+ if (pctx.errcode) {
+ fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ if (!ino)
+ break;
+ pctx.ino = ctx->stashed_ino = ino;
+ if ((ino != EXT2_BAD_INO) &&
+ !ext2fs_test_inode_bitmap(ctx->inode_used_map, ino))
+ continue;
+
+ pb.ino = ino;
+ pb.dup_blocks = 0;
+ pb.inode = &inode;
+
+ if (ext2fs_inode_has_valid_blocks(&inode) ||
+ (ino == EXT2_BAD_INO))
+ pctx.errcode = ext2fs_block_iterate2(fs, ino,
+ 0, block_buf, process_pass1b_block, &pb);
+ if (inode.i_file_acl)
+ process_pass1b_block(fs, &inode.i_file_acl,
+ BLOCK_COUNT_EXTATTR, 0, 0, &pb);
+ if (pb.dup_blocks) {
+ end_problem_latch(ctx, PR_LATCH_DBLOCK);
+ if (ino >= EXT2_FIRST_INODE(fs->super) ||
+ ino == EXT2_ROOT_INO)
+ dup_inode_count++;
+ }
+ if (pctx.errcode)
+ fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
+ }
+ ext2fs_close_inode_scan(scan);
+ e2fsck_use_inode_shortcuts(ctx, 0);
+}
+
+static int process_pass1b_block(ext2_filsys fs FSCK_ATTR((unused)),
+ blk_t *block_nr,
+ e2_blkcnt_t blockcnt FSCK_ATTR((unused)),
+ blk_t ref_blk FSCK_ATTR((unused)),
+ int ref_offset FSCK_ATTR((unused)),
+ void *priv_data)
+{
+ struct process_block_struct_1b *p;
+ e2fsck_t ctx;
+
+ if (HOLE_BLKADDR(*block_nr))
+ return 0;
+ p = (struct process_block_struct_1b *) priv_data;
+ ctx = p->ctx;
+
+ if (!ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr))
+ return 0;
+
+ /* OK, this is a duplicate block */
+ if (p->ino != EXT2_BAD_INO) {
+ p->pctx->blk = *block_nr;
+ fix_problem(ctx, PR_1B_DUP_BLOCK, p->pctx);
+ }
+ p->dup_blocks++;
+ ext2fs_mark_inode_bitmap(inode_dup_map, p->ino);
+
+ add_dupe(ctx, p->ino, *block_nr, p->inode);
+
+ return 0;
+}
+
+/*
+ * Pass 1c: Scan directories for inodes with duplicate blocks. This
+ * is used so that we can print pathnames when prompting the user for
+ * what to do.
+ */
+struct search_dir_struct {
+ int count;
+ ext2_ino_t first_inode;
+ ext2_ino_t max_inode;
+};
+
+static int search_dirent_proc(ext2_ino_t dir, int entry,
+ struct ext2_dir_entry *dirent,
+ int offset FSCK_ATTR((unused)),
+ int blocksize FSCK_ATTR((unused)),
+ char *buf FSCK_ATTR((unused)),
+ void *priv_data)
+{
+ struct search_dir_struct *sd;
+ struct dup_inode *p;
+ dnode_t *n;
+
+ sd = (struct search_dir_struct *) priv_data;
+
+ if (dirent->inode > sd->max_inode)
+ /* Should abort this inode, but not everything */
+ return 0;
+
+ if ((dirent->inode < sd->first_inode) || (entry < DIRENT_OTHER_FILE) ||
+ !ext2fs_test_inode_bitmap(inode_dup_map, dirent->inode))
+ return 0;
+
+ n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(dirent->inode));
+ if (!n)
+ return 0;
+ p = (struct dup_inode *) dnode_get(n);
+ p->dir = dir;
+ sd->count--;
+
+ return sd->count ? 0 : DIRENT_ABORT;
+}
+
+
+static void pass1c(e2fsck_t ctx, char *block_buf)
+{
+ ext2_filsys fs = ctx->fs;
+ struct search_dir_struct sd;
+ struct problem_context pctx;
+
+ clear_problem_context(&pctx);
+
+ if (!(ctx->options & E2F_OPT_PREEN))
+ fix_problem(ctx, PR_1C_PASS_HEADER, &pctx);
+
+ /*
+ * Search through all directories to translate inodes to names
+ * (by searching for the containing directory for that inode.)
+ */
+ sd.count = dup_inode_count;
+ sd.first_inode = EXT2_FIRST_INODE(fs->super);
+ sd.max_inode = fs->super->s_inodes_count;
+ ext2fs_dblist_dir_iterate(fs->dblist, 0, block_buf,
+ search_dirent_proc, &sd);
+}
+
+static void pass1d(e2fsck_t ctx, char *block_buf)
+{
+ ext2_filsys fs = ctx->fs;
+ struct dup_inode *p, *t;
+ struct dup_block *q;
+ ext2_ino_t *shared, ino;
+ int shared_len;
+ int i;
+ int file_ok;
+ int meta_data = 0;
+ struct problem_context pctx;
+ dnode_t *n, *m;
+ struct block_el *s;
+ struct inode_el *r;
+
+ clear_problem_context(&pctx);
+
+ if (!(ctx->options & E2F_OPT_PREEN))
+ fix_problem(ctx, PR_1D_PASS_HEADER, &pctx);
+ e2fsck_read_bitmaps(ctx);
+
+ pctx.num = dup_inode_count; /* dict_count(&ino_dict); */
+ fix_problem(ctx, PR_1D_NUM_DUP_INODES, &pctx);
+ shared = (ext2_ino_t *) e2fsck_allocate_memory(ctx,
+ sizeof(ext2_ino_t) * dict_count(&ino_dict),
+ "Shared inode list");
+ for (n = dict_first(&ino_dict); n; n = dict_next(&ino_dict, n)) {
+ p = (struct dup_inode *) dnode_get(n);
+ shared_len = 0;
+ file_ok = 1;
+ ino = (ext2_ino_t)VOIDPTR_TO_INT(dnode_getkey(n));
+ if (ino == EXT2_BAD_INO || ino == EXT2_RESIZE_INO)
+ continue;
+
+ /*
+ * Find all of the inodes which share blocks with this
+ * one. First we find all of the duplicate blocks
+ * belonging to this inode, and then search each block
+ * get the list of inodes, and merge them together.
+ */
+ for (s = p->block_list; s; s = s->next) {
+ m = dict_lookup(&blk_dict, INT_TO_VOIDPTR(s->block));
+ if (!m)
+ continue; /* Should never happen... */
+ q = (struct dup_block *) dnode_get(m);
+ if (q->num_bad > 1)
+ file_ok = 0;
+ if (check_if_fs_block(ctx, s->block)) {
+ file_ok = 0;
+ meta_data = 1;
+ }
+
+ /*
+ * Add all inodes used by this block to the
+ * shared[] --- which is a unique list, so
+ * if an inode is already in shared[], don't
+ * add it again.
+ */
+ for (r = q->inode_list; r; r = r->next) {
+ if (r->inode == ino)
+ continue;
+ for (i = 0; i < shared_len; i++)
+ if (shared[i] == r->inode)
+ break;
+ if (i == shared_len) {
+ shared[shared_len++] = r->inode;
+ }
+ }
+ }
+
+ /*
+ * Report the inode that we are working on
+ */
+ pctx.inode = &p->inode;
+ pctx.ino = ino;
+ pctx.dir = p->dir;
+ pctx.blkcount = p->num_dupblocks;
+ pctx.num = meta_data ? shared_len+1 : shared_len;
+ fix_problem(ctx, PR_1D_DUP_FILE, &pctx);
+ pctx.blkcount = 0;
+ pctx.num = 0;
+
+ if (meta_data)
+ fix_problem(ctx, PR_1D_SHARE_METADATA, &pctx);
+
+ for (i = 0; i < shared_len; i++) {
+ m = dict_lookup(&ino_dict, INT_TO_VOIDPTR(shared[i]));
+ if (!m)
+ continue; /* should never happen */
+ t = (struct dup_inode *) dnode_get(m);
+ /*
+ * Report the inode that we are sharing with
+ */
+ pctx.inode = &t->inode;
+ pctx.ino = shared[i];
+ pctx.dir = t->dir;
+ fix_problem(ctx, PR_1D_DUP_FILE_LIST, &pctx);
+ }
+ if (file_ok) {
+ fix_problem(ctx, PR_1D_DUP_BLOCKS_DEALT, &pctx);
+ continue;
+ }
+ if (fix_problem(ctx, PR_1D_CLONE_QUESTION, &pctx)) {
+ pctx.errcode = clone_file(ctx, ino, p, block_buf);
+ if (pctx.errcode)
+ fix_problem(ctx, PR_1D_CLONE_ERROR, &pctx);
+ else
+ continue;
+ }
+ if (fix_problem(ctx, PR_1D_DELETE_QUESTION, &pctx))
+ delete_file(ctx, ino, p, block_buf);
+ else
+ ext2fs_unmark_valid(fs);
+ }
+ ext2fs_free_mem(&shared);
+}
+
+/*
+ * Drop the refcount on the dup_block structure, and clear the entry
+ * in the block_dup_map if appropriate.
+ */
+static void decrement_badcount(e2fsck_t ctx, blk_t block, struct dup_block *p)
+{
+ p->num_bad--;
+ if (p->num_bad <= 0 ||
+ (p->num_bad == 1 && !check_if_fs_block(ctx, block)))
+ ext2fs_unmark_block_bitmap(ctx->block_dup_map, block);
+}
+
+static int delete_file_block(ext2_filsys fs,
+ blk_t *block_nr,
+ e2_blkcnt_t blockcnt FSCK_ATTR((unused)),
+ blk_t ref_block FSCK_ATTR((unused)),
+ int ref_offset FSCK_ATTR((unused)),
+ void *priv_data)
+{
+ struct process_block_struct_1b *pb;
+ struct dup_block *p;
+ dnode_t *n;
+ e2fsck_t ctx;
+
+ pb = (struct process_block_struct_1b *) priv_data;
+ ctx = pb->ctx;
+
+ if (HOLE_BLKADDR(*block_nr))
+ return 0;
+
+ if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
+ n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr));
+ if (n) {
+ p = (struct dup_block *) dnode_get(n);
+ decrement_badcount(ctx, *block_nr, p);
+ } else
+ bb_error_msg(_("internal error; can't find dup_blk for %d"),
+ *block_nr);
+ } else {
+ ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
+ ext2fs_block_alloc_stats(fs, *block_nr, -1);
+ }
+
+ return 0;
+}
+
+static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
+ struct dup_inode *dp, char* block_buf)
+{
+ ext2_filsys fs = ctx->fs;
+ struct process_block_struct_1b pb;
+ struct ext2_inode inode;
+ struct problem_context pctx;
+ unsigned int count;
+
+ clear_problem_context(&pctx);
+ pctx.ino = pb.ino = ino;
+ pb.dup_blocks = dp->num_dupblocks;
+ pb.ctx = ctx;
+ pctx.str = "delete_file";
+
+ e2fsck_read_inode(ctx, ino, &inode, "delete_file");
+ if (ext2fs_inode_has_valid_blocks(&inode))
+ pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
+ delete_file_block, &pb);
+ if (pctx.errcode)
+ fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
+ ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
+ ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
+ if (ctx->inode_bad_map)
+ ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
+ ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
+
+ /* Inode may have changed by block_iterate, so reread it */
+ e2fsck_read_inode(ctx, ino, &inode, "delete_file");
+ inode.i_links_count = 0;
+ inode.i_dtime = time(0);
+ if (inode.i_file_acl &&
+ (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
+ count = 1;
+ pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
+ block_buf, -1, &count);
+ if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
+ pctx.errcode = 0;
+ count = 1;
+ }
+ if (pctx.errcode) {
+ pctx.blk = inode.i_file_acl;
+ fix_problem(ctx, PR_1B_ADJ_EA_REFCOUNT, &pctx);
+ }
+ /*
+ * If the count is zero, then arrange to have the
+ * block deleted. If the block is in the block_dup_map,
+ * also call delete_file_block since it will take care
+ * of keeping the accounting straight.
+ */
+ if ((count == 0) ||
+ ext2fs_test_block_bitmap(ctx->block_dup_map,
+ inode.i_file_acl))
+ delete_file_block(fs, &inode.i_file_acl,
+ BLOCK_COUNT_EXTATTR, 0, 0, &pb);
+ }
+ e2fsck_write_inode(ctx, ino, &inode, "delete_file");
+}
+
+struct clone_struct {
+ errcode_t errcode;
+ ext2_ino_t dir;
+ char *buf;
+ e2fsck_t ctx;
+};
+
+static int clone_file_block(ext2_filsys fs,
+ blk_t *block_nr,
+ e2_blkcnt_t blockcnt,
+ blk_t ref_block FSCK_ATTR((unused)),
+ int ref_offset FSCK_ATTR((unused)),
+ void *priv_data)
+{
+ struct dup_block *p;
+ blk_t new_block;
+ errcode_t retval;
+ struct clone_struct *cs = (struct clone_struct *) priv_data;
+ dnode_t *n;
+ e2fsck_t ctx;
+
+ ctx = cs->ctx;
+
+ if (HOLE_BLKADDR(*block_nr))
+ return 0;
+
+ if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
+ n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr));
+ if (n) {
+ p = (struct dup_block *) dnode_get(n);
+ retval = ext2fs_new_block(fs, 0, ctx->block_found_map,
+ &new_block);
+ if (retval) {
+ cs->errcode = retval;
+ return BLOCK_ABORT;
+ }
+ if (cs->dir && (blockcnt >= 0)) {
+ retval = ext2fs_set_dir_block(fs->dblist,
+ cs->dir, new_block, blockcnt);
+ if (retval) {
+ cs->errcode = retval;
+ return BLOCK_ABORT;
+ }
+ }
+
+ retval = io_channel_read_blk(fs->io, *block_nr, 1,
+ cs->buf);
+ if (retval) {
+ cs->errcode = retval;
+ return BLOCK_ABORT;
+ }
+ retval = io_channel_write_blk(fs->io, new_block, 1,
+ cs->buf);
+ if (retval) {
+ cs->errcode = retval;
+ return BLOCK_ABORT;
+ }
+ decrement_badcount(ctx, *block_nr, p);
+ *block_nr = new_block;
+ ext2fs_mark_block_bitmap(ctx->block_found_map,
+ new_block);
+ ext2fs_mark_block_bitmap(fs->block_map, new_block);
+ return BLOCK_CHANGED;
+ } else
+ bb_error_msg(_("internal error; can't find dup_blk for %d"),
+ *block_nr);
+ }
+ return 0;
+}
+
+static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
+ struct dup_inode *dp, char* block_buf)
+{
+ ext2_filsys fs = ctx->fs;
+ errcode_t retval;
+ struct clone_struct cs;
+ struct problem_context pctx;
+ blk_t blk;
+ dnode_t *n;
+ struct inode_el *ino_el;
+ struct dup_block *db;
+ struct dup_inode *di;
+
+ clear_problem_context(&pctx);
+ cs.errcode = 0;
+ cs.dir = 0;
+ cs.ctx = ctx;
+ retval = ext2fs_get_mem(fs->blocksize, &cs.buf);
+ if (retval)
+ return retval;
+
+ if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino))
+ cs.dir = ino;
+
+ pctx.ino = ino;
+ pctx.str = "clone_file";
+ if (ext2fs_inode_has_valid_blocks(&dp->inode))
+ pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
+ clone_file_block, &cs);
+ ext2fs_mark_bb_dirty(fs);
+ if (pctx.errcode) {
+ fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
+ retval = pctx.errcode;
+ goto errout;
+ }
+ if (cs.errcode) {
+ bb_error_msg(_("returned from clone_file_block"));
+ retval = cs.errcode;
+ goto errout;
+ }
+ /* The inode may have changed on disk, so we have to re-read it */
+ e2fsck_read_inode(ctx, ino, &dp->inode, "clone file EA");
+ blk = dp->inode.i_file_acl;
+ if (blk && (clone_file_block(fs, &dp->inode.i_file_acl,
+ BLOCK_COUNT_EXTATTR, 0, 0, &cs) ==
+ BLOCK_CHANGED)) {
+ e2fsck_write_inode(ctx, ino, &dp->inode, "clone file EA");
+ /*
+ * If we cloned the EA block, find all other inodes
+ * which refered to that EA block, and modify
+ * them to point to the new EA block.
+ */
+ n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk));
+ db = (struct dup_block *) dnode_get(n);
+ for (ino_el = db->inode_list; ino_el; ino_el = ino_el->next) {
+ if (ino_el->inode == ino)
+ continue;
+ n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino_el->inode));
+ di = (struct dup_inode *) dnode_get(n);
+ if (di->inode.i_file_acl == blk) {
+ di->inode.i_file_acl = dp->inode.i_file_acl;
+ e2fsck_write_inode(ctx, ino_el->inode,
+ &di->inode, "clone file EA");
+ decrement_badcount(ctx, blk, db);
+ }
+ }
+ }
+ retval = 0;
+errout:
+ ext2fs_free_mem(&cs.buf);
+ return retval;
+}
+
+/*
+ * This routine returns 1 if a block overlaps with one of the superblocks,
+ * group descriptors, inode bitmaps, or block bitmaps.
+ */
+static int check_if_fs_block(e2fsck_t ctx, blk_t test_block)
+{
+ ext2_filsys fs = ctx->fs;
+ blk_t block;
+ dgrp_t i;
+
+ block = fs->super->s_first_data_block;
+ for (i = 0; i < fs->group_desc_count; i++) {
+
+ /* Check superblocks/block group descriptros */
+ if (ext2fs_bg_has_super(fs, i)) {
+ if (test_block >= block &&
+ (test_block <= block + fs->desc_blocks))
+ return 1;
+ }
+
+ /* Check the inode table */
+ if ((fs->group_desc[i].bg_inode_table) &&
+ (test_block >= fs->group_desc[i].bg_inode_table) &&
+ (test_block < (fs->group_desc[i].bg_inode_table +
+ fs->inode_blocks_per_group)))
+ return 1;
+
+ /* Check the bitmap blocks */
+ if ((test_block == fs->group_desc[i].bg_block_bitmap) ||
+ (test_block == fs->group_desc[i].bg_inode_bitmap))
+ return 1;
+
+ block += fs->super->s_blocks_per_group;
+ }
+ return 0;
+}
+/*
+ * pass2.c --- check directory structure
+ *
+ * Pass 2 of e2fsck iterates through all active directory inodes, and
+ * applies to following tests to each directory entry in the directory
+ * blocks in the inodes:
+ *
+ * - The length of the directory entry (rec_len) should be at
+ * least 8 bytes, and no more than the remaining space
+ * left in the directory block.
+ * - The length of the name in the directory entry (name_len)
+ * should be less than (rec_len - 8).
+ * - The inode number in the directory entry should be within
+ * legal bounds.
+ * - The inode number should refer to a in-use inode.
+ * - The first entry should be '.', and its inode should be
+ * the inode of the directory.
+ * - The second entry should be '..'.
+ *
+ * To minimize disk seek time, the directory blocks are processed in
+ * sorted order of block numbers.
+ *
+ * Pass 2 also collects the following information:
+ * - The inode numbers of the subdirectories for each directory.
+ *
+ * Pass 2 relies on the following information from previous passes:
+ * - The directory information collected in pass 1.
+ * - The inode_used_map bitmap
+ * - The inode_bad_map bitmap
+ * - The inode_dir_map bitmap
+ *
+ * Pass 2 frees the following data structures
+ * - The inode_bad_map bitmap
+ * - The inode_reg_map bitmap
+ */
+
+/*
+ * Keeps track of how many times an inode is referenced.
+ */
+static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf);
+static int check_dir_block(ext2_filsys fs,
+ struct ext2_db_entry *dir_blocks_info,
+ void *priv_data);
+static int allocate_dir_block(e2fsck_t ctx, struct ext2_db_entry *dir_blocks_info,
+ struct problem_context *pctx);
+static int update_dir_block(ext2_filsys fs,
+ blk_t *block_nr,
+ e2_blkcnt_t blockcnt,
+ blk_t ref_block,
+ int ref_offset,
+ void *priv_data);
+static void clear_htree(e2fsck_t ctx, ext2_ino_t ino);
+static int htree_depth(struct dx_dir_info *dx_dir,
+ struct dx_dirblock_info *dx_db);
+static int special_dir_block_cmp(const void *a, const void *b);
+
+struct check_dir_struct {
+ char *buf;
+ struct problem_context pctx;
+ int count, max;
+ e2fsck_t ctx;
+};
+
+static void e2fsck_pass2(e2fsck_t ctx)
+{
+ struct ext2_super_block *sb = ctx->fs->super;
+ struct problem_context pctx;
+ ext2_filsys fs = ctx->fs;
+ char *buf;
+ struct dir_info *dir;
+ struct check_dir_struct cd;
+ struct dx_dir_info *dx_dir;
+ struct dx_dirblock_info *dx_db, *dx_parent;
+ int b;
+ int i, depth;
+ problem_t code;
+ int bad_dir;
+
+ clear_problem_context(&cd.pctx);
+
+ /* Pass 2 */
+
+ if (!(ctx->options & E2F_OPT_PREEN))
+ fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx);
+
+ cd.pctx.errcode = ext2fs_create_icount2(fs, EXT2_ICOUNT_OPT_INCREMENT,
+ 0, ctx->inode_link_info,
+ &ctx->inode_count);
+ if (cd.pctx.errcode) {
+ fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ buf = (char *) e2fsck_allocate_memory(ctx, 2*fs->blocksize,
+ "directory scan buffer");
+
+ /*
+ * Set up the parent pointer for the root directory, if
+ * present. (If the root directory is not present, we will
+ * create it in pass 3.)
+ */
+ dir = e2fsck_get_dir_info(ctx, EXT2_ROOT_INO);
+ if (dir)
+ dir->parent = EXT2_ROOT_INO;
+
+ cd.buf = buf;
+ cd.ctx = ctx;
+ cd.count = 1;
+ cd.max = ext2fs_dblist_count(fs->dblist);
+
+ if (ctx->progress)
+ (void) (ctx->progress)(ctx, 2, 0, cd.max);
+
+ if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX)
+ ext2fs_dblist_sort(fs->dblist, special_dir_block_cmp);
+
+ cd.pctx.errcode = ext2fs_dblist_iterate(fs->dblist, check_dir_block,
+ &cd);
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ return;
+ if (cd.pctx.errcode) {
+ fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+
+#ifdef ENABLE_HTREE
+ for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) {
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ return;
+ if (dx_dir->numblocks == 0)
+ continue;
+ clear_problem_context(&pctx);
+ bad_dir = 0;
+ pctx.dir = dx_dir->ino;
+ dx_db = dx_dir->dx_block;
+ if (dx_db->flags & DX_FLAG_REFERENCED)
+ dx_db->flags |= DX_FLAG_DUP_REF;
+ else
+ dx_db->flags |= DX_FLAG_REFERENCED;
+ /*
+ * Find all of the first and last leaf blocks, and
+ * update their parent's min and max hash values
+ */
+ for (b=0, dx_db = dx_dir->dx_block;
+ b < dx_dir->numblocks;
+ b++, dx_db++) {
+ if ((dx_db->type != DX_DIRBLOCK_LEAF) ||
+ !(dx_db->flags & (DX_FLAG_FIRST | DX_FLAG_LAST)))
+ continue;
+ dx_parent = &dx_dir->dx_block[dx_db->parent];
+ /*
+ * XXX Make sure dx_parent->min_hash > dx_db->min_hash
+ */
+ if (dx_db->flags & DX_FLAG_FIRST)
+ dx_parent->min_hash = dx_db->min_hash;
+ /*
+ * XXX Make sure dx_parent->max_hash < dx_db->max_hash
+ */
+ if (dx_db->flags & DX_FLAG_LAST)
+ dx_parent->max_hash = dx_db->max_hash;
+ }
+
+ for (b=0, dx_db = dx_dir->dx_block;
+ b < dx_dir->numblocks;
+ b++, dx_db++) {
+ pctx.blkcount = b;
+ pctx.group = dx_db->parent;
+ code = 0;
+ if (!(dx_db->flags & DX_FLAG_FIRST) &&
+ (dx_db->min_hash < dx_db->node_min_hash)) {
+ pctx.blk = dx_db->min_hash;
+ pctx.blk2 = dx_db->node_min_hash;
+ code = PR_2_HTREE_MIN_HASH;
+ fix_problem(ctx, code, &pctx);
+ bad_dir++;
+ }
+ if (dx_db->type == DX_DIRBLOCK_LEAF) {
+ depth = htree_depth(dx_dir, dx_db);
+ if (depth != dx_dir->depth) {
+ code = PR_2_HTREE_BAD_DEPTH;
+ fix_problem(ctx, code, &pctx);
+ bad_dir++;
+ }
+ }
+ /*
+ * This test doesn't apply for the root block
+ * at block #0
+ */
+ if (b &&
+ (dx_db->max_hash > dx_db->node_max_hash)) {
+ pctx.blk = dx_db->max_hash;
+ pctx.blk2 = dx_db->node_max_hash;
+ code = PR_2_HTREE_MAX_HASH;
+ fix_problem(ctx, code, &pctx);
+ bad_dir++;
+ }
+ if (!(dx_db->flags & DX_FLAG_REFERENCED)) {
+ code = PR_2_HTREE_NOTREF;
+ fix_problem(ctx, code, &pctx);
+ bad_dir++;
+ } else if (dx_db->flags & DX_FLAG_DUP_REF) {
+ code = PR_2_HTREE_DUPREF;
+ fix_problem(ctx, code, &pctx);
+ bad_dir++;
+ }
+ if (code == 0)
+ continue;
+ }
+ if (bad_dir && fix_problem(ctx, PR_2_HTREE_CLEAR, &pctx)) {
+ clear_htree(ctx, dx_dir->ino);
+ dx_dir->numblocks = 0;
+ }
+ }
+#endif
+ ext2fs_free_mem(&buf);
+ ext2fs_free_dblist(fs->dblist);
+
+ ext2fs_free_inode_bitmap(ctx->inode_bad_map);
+ ctx->inode_bad_map = 0;
+ ext2fs_free_inode_bitmap(ctx->inode_reg_map);
+ ctx->inode_reg_map = 0;
+
+ clear_problem_context(&pctx);
+ if (ctx->large_files) {
+ if (!(sb->s_feature_ro_compat &
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE) &&
+ fix_problem(ctx, PR_2_FEATURE_LARGE_FILES, &pctx)) {
+ sb->s_feature_ro_compat |=
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
+ ext2fs_mark_super_dirty(fs);
+ }
+ if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
+ fix_problem(ctx, PR_1_FS_REV_LEVEL, &pctx)) {
+ ext2fs_update_dynamic_rev(fs);
+ ext2fs_mark_super_dirty(fs);
+ }
+ } else if (!ctx->large_files &&
+ (sb->s_feature_ro_compat &
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) {
+ if (fs->flags & EXT2_FLAG_RW) {
+ sb->s_feature_ro_compat &=
+ ~EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
+ ext2fs_mark_super_dirty(fs);
+ }
+ }
+
+}
+
+#define MAX_DEPTH 32000
+static int htree_depth(struct dx_dir_info *dx_dir,
+ struct dx_dirblock_info *dx_db)
+{
+ int depth = 0;
+
+ while (dx_db->type != DX_DIRBLOCK_ROOT && depth < MAX_DEPTH) {
+ dx_db = &dx_dir->dx_block[dx_db->parent];
+ depth++;
+ }
+ return depth;
+}
+
+static int dict_de_cmp(const void *a, const void *b)
+{
+ const struct ext2_dir_entry *de_a, *de_b;
+ int a_len, b_len;
+
+ de_a = (const struct ext2_dir_entry *) a;
+ a_len = de_a->name_len & 0xFF;
+ de_b = (const struct ext2_dir_entry *) b;
+ b_len = de_b->name_len & 0xFF;
+
+ if (a_len != b_len)
+ return (a_len - b_len);
+
+ return strncmp(de_a->name, de_b->name, a_len);
+}
+
+/*
+ * This is special sort function that makes sure that directory blocks
+ * with a dirblock of zero are sorted to the beginning of the list.
+ * This guarantees that the root node of the htree directories are
+ * processed first, so we know what hash version to use.
+ */
+static int special_dir_block_cmp(const void *a, const void *b)
+{
+ const struct ext2_db_entry *db_a =
+ (const struct ext2_db_entry *) a;
+ const struct ext2_db_entry *db_b =
+ (const struct ext2_db_entry *) b;
+
+ if (db_a->blockcnt && !db_b->blockcnt)
+ return 1;
+
+ if (!db_a->blockcnt && db_b->blockcnt)
+ return -1;
+
+ if (db_a->blk != db_b->blk)
+ return (int) (db_a->blk - db_b->blk);
+
+ if (db_a->ino != db_b->ino)
+ return (int) (db_a->ino - db_b->ino);
+
+ return (int) (db_a->blockcnt - db_b->blockcnt);
+}
+
+
+/*
+ * Make sure the first entry in the directory is '.', and that the
+ * directory entry is sane.
+ */
+static int check_dot(e2fsck_t ctx,
+ struct ext2_dir_entry *dirent,
+ ext2_ino_t ino, struct problem_context *pctx)
+{
+ struct ext2_dir_entry *nextdir;
+ int status = 0;
+ int created = 0;
+ int new_len;
+ int problem = 0;
+
+ if (!dirent->inode)
+ problem = PR_2_MISSING_DOT;
+ else if (((dirent->name_len & 0xFF) != 1) ||
+ (dirent->name[0] != '.'))
+ problem = PR_2_1ST_NOT_DOT;
+ else if (dirent->name[1] != '\0')
+ problem = PR_2_DOT_NULL_TERM;
+
+ if (problem) {
+ if (fix_problem(ctx, problem, pctx)) {
+ if (dirent->rec_len < 12)
+ dirent->rec_len = 12;
+ dirent->inode = ino;
+ dirent->name_len = 1;
+ dirent->name[0] = '.';
+ dirent->name[1] = '\0';
+ status = 1;
+ created = 1;
+ }
+ }
+ if (dirent->inode != ino) {
+ if (fix_problem(ctx, PR_2_BAD_INODE_DOT, pctx)) {
+ dirent->inode = ino;
+ status = 1;
+ }
+ }
+ if (dirent->rec_len > 12) {
+ new_len = dirent->rec_len - 12;
+ if (new_len > 12) {
+ if (created ||
+ fix_problem(ctx, PR_2_SPLIT_DOT, pctx)) {
+ nextdir = (struct ext2_dir_entry *)
+ ((char *) dirent + 12);
+ dirent->rec_len = 12;
+ nextdir->rec_len = new_len;
+ nextdir->inode = 0;
+ nextdir->name_len = 0;
+ status = 1;
+ }
+ }
+ }
+ return status;
+}
+
+/*
+ * Make sure the second entry in the directory is '..', and that the
+ * directory entry is sane. We do not check the inode number of '..'
+ * here; this gets done in pass 3.
+ */
+static int check_dotdot(e2fsck_t ctx,
+ struct ext2_dir_entry *dirent,
+ struct dir_info *dir, struct problem_context *pctx)
+{
+ int problem = 0;
+
+ if (!dirent->inode)
+ problem = PR_2_MISSING_DOT_DOT;
+ else if (((dirent->name_len & 0xFF) != 2) ||
+ (dirent->name[0] != '.') ||
+ (dirent->name[1] != '.'))
+ problem = PR_2_2ND_NOT_DOT_DOT;
+ else if (dirent->name[2] != '\0')
+ problem = PR_2_DOT_DOT_NULL_TERM;
+
+ if (problem) {
+ if (fix_problem(ctx, problem, pctx)) {
+ if (dirent->rec_len < 12)
+ dirent->rec_len = 12;
+ /*
+ * Note: we don't have the parent inode just
+ * yet, so we will fill it in with the root
+ * inode. This will get fixed in pass 3.
+ */
+ dirent->inode = EXT2_ROOT_INO;
+ dirent->name_len = 2;
+ dirent->name[0] = '.';
+ dirent->name[1] = '.';
+ dirent->name[2] = '\0';
+ return 1;
+ }
+ return 0;
+ }
+ dir->dotdot = dirent->inode;
+ return 0;
+}
+
+/*
+ * Check to make sure a directory entry doesn't contain any illegal
+ * characters.
+ */
+static int check_name(e2fsck_t ctx,
+ struct ext2_dir_entry *dirent,
+ struct problem_context *pctx)
+{
+ int i;
+ int fixup = -1;
+ int ret = 0;
+
+ for ( i = 0; i < (dirent->name_len & 0xFF); i++) {
+ if (dirent->name[i] == '/' || dirent->name[i] == '\0') {
+ if (fixup < 0) {
+ fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx);
+ }
+ if (fixup) {
+ dirent->name[i] = '.';
+ ret = 1;
+ }
+ }
+ }
+ return ret;
+}
+
+/*
+ * Check the directory filetype (if present)
+ */
+
+/*
+ * Given a mode, return the ext2 file type
+ */
+static int ext2_file_type(unsigned int mode)
+{
+ if (LINUX_S_ISREG(mode))
+ return EXT2_FT_REG_FILE;
+
+ if (LINUX_S_ISDIR(mode))
+ return EXT2_FT_DIR;
+
+ if (LINUX_S_ISCHR(mode))
+ return EXT2_FT_CHRDEV;
+
+ if (LINUX_S_ISBLK(mode))
+ return EXT2_FT_BLKDEV;
+
+ if (LINUX_S_ISLNK(mode))
+ return EXT2_FT_SYMLINK;
+
+ if (LINUX_S_ISFIFO(mode))
+ return EXT2_FT_FIFO;
+
+ if (LINUX_S_ISSOCK(mode))
+ return EXT2_FT_SOCK;
+
+ return 0;
+}
+
+static int check_filetype(e2fsck_t ctx,
+ struct ext2_dir_entry *dirent,
+ struct problem_context *pctx)
+{
+ int filetype = dirent->name_len >> 8;
+ int should_be = EXT2_FT_UNKNOWN;
+ struct ext2_inode inode;
+
+ if (!(ctx->fs->super->s_feature_incompat &
+ EXT2_FEATURE_INCOMPAT_FILETYPE)) {
+ if (filetype == 0 ||
+ !fix_problem(ctx, PR_2_CLEAR_FILETYPE, pctx))
+ return 0;
+ dirent->name_len = dirent->name_len & 0xFF;
+ return 1;
+ }
+
+ if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dirent->inode)) {
+ should_be = EXT2_FT_DIR;
+ } else if (ext2fs_test_inode_bitmap(ctx->inode_reg_map,
+ dirent->inode)) {
+ should_be = EXT2_FT_REG_FILE;
+ } else if (ctx->inode_bad_map &&
+ ext2fs_test_inode_bitmap(ctx->inode_bad_map,
+ dirent->inode))
+ should_be = 0;
+ else {
+ e2fsck_read_inode(ctx, dirent->inode, &inode,
+ "check_filetype");
+ should_be = ext2_file_type(inode.i_mode);
+ }
+ if (filetype == should_be)
+ return 0;
+ pctx->num = should_be;
+
+ if (fix_problem(ctx, filetype ? PR_2_BAD_FILETYPE : PR_2_SET_FILETYPE,
+ pctx) == 0)
+ return 0;
+
+ dirent->name_len = (dirent->name_len & 0xFF) | should_be << 8;
+ return 1;
+}
+
+#ifdef ENABLE_HTREE
+static void parse_int_node(ext2_filsys fs,
+ struct ext2_db_entry *db,
+ struct check_dir_struct *cd,
+ struct dx_dir_info *dx_dir,
+ char *block_buf)
+{
+ struct ext2_dx_root_info *root;
+ struct ext2_dx_entry *ent;
+ struct ext2_dx_countlimit *limit;
+ struct dx_dirblock_info *dx_db;
+ int i, expect_limit, count;
+ blk_t blk;
+ ext2_dirhash_t min_hash = 0xffffffff;
+ ext2_dirhash_t max_hash = 0;
+ ext2_dirhash_t hash = 0, prev_hash;
+
+ if (db->blockcnt == 0) {
+ root = (struct ext2_dx_root_info *) (block_buf + 24);
+ ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length);
+ } else {
+ ent = (struct ext2_dx_entry *) (block_buf+8);
+ }
+ limit = (struct ext2_dx_countlimit *) ent;
+
+ count = ext2fs_le16_to_cpu(limit->count);
+ expect_limit = (fs->blocksize - ((char *) ent - block_buf)) /
+ sizeof(struct ext2_dx_entry);
+ if (ext2fs_le16_to_cpu(limit->limit) != expect_limit) {
+ cd->pctx.num = ext2fs_le16_to_cpu(limit->limit);
+ if (fix_problem(cd->ctx, PR_2_HTREE_BAD_LIMIT, &cd->pctx))
+ goto clear_and_exit;
+ }
+ if (count > expect_limit) {
+ cd->pctx.num = count;
+ if (fix_problem(cd->ctx, PR_2_HTREE_BAD_COUNT, &cd->pctx))
+ goto clear_and_exit;
+ count = expect_limit;
+ }
+
+ for (i=0; i < count; i++) {
+ prev_hash = hash;
+ hash = i ? (ext2fs_le32_to_cpu(ent[i].hash) & ~1) : 0;
+ blk = ext2fs_le32_to_cpu(ent[i].block) & 0x0ffffff;
+ /* Check to make sure the block is valid */
+ if (blk > (blk_t) dx_dir->numblocks) {
+ cd->pctx.blk = blk;
+ if (fix_problem(cd->ctx, PR_2_HTREE_BADBLK,
+ &cd->pctx))
+ goto clear_and_exit;
+ }
+ if (hash < prev_hash &&
+ fix_problem(cd->ctx, PR_2_HTREE_HASH_ORDER, &cd->pctx))
+ goto clear_and_exit;
+ dx_db = &dx_dir->dx_block[blk];
+ if (dx_db->flags & DX_FLAG_REFERENCED) {
+ dx_db->flags |= DX_FLAG_DUP_REF;
+ } else {
+ dx_db->flags |= DX_FLAG_REFERENCED;
+ dx_db->parent = db->blockcnt;
+ }
+ if (hash < min_hash)
+ min_hash = hash;
+ if (hash > max_hash)
+ max_hash = hash;
+ dx_db->node_min_hash = hash;
+ if ((i+1) < count)
+ dx_db->node_max_hash =
+ ext2fs_le32_to_cpu(ent[i+1].hash) & ~1;
+ else {
+ dx_db->node_max_hash = 0xfffffffe;
+ dx_db->flags |= DX_FLAG_LAST;
+ }
+ if (i == 0)
+ dx_db->flags |= DX_FLAG_FIRST;
+ }
+ dx_db = &dx_dir->dx_block[db->blockcnt];
+ dx_db->min_hash = min_hash;
+ dx_db->max_hash = max_hash;
+ return;
+
+clear_and_exit:
+ clear_htree(cd->ctx, cd->pctx.ino);
+ dx_dir->numblocks = 0;
+}
+#endif /* ENABLE_HTREE */
+
+/*
+ * Given a busted directory, try to salvage it somehow.
+ *
+ */
+static void salvage_directory(ext2_filsys fs,
+ struct ext2_dir_entry *dirent,
+ struct ext2_dir_entry *prev,
+ unsigned int *offset)
+{
+ char *cp = (char *) dirent;
+ int left = fs->blocksize - *offset - dirent->rec_len;
+ int name_len = dirent->name_len & 0xFF;
+
+ /*
+ * Special case of directory entry of size 8: copy what's left
+ * of the directory block up to cover up the invalid hole.
+ */
+ if ((left >= 12) && (dirent->rec_len == 8)) {
+ memmove(cp, cp+8, left);
+ memset(cp + left, 0, 8);
+ return;
+ }
+ /*
+ * If the directory entry overruns the end of the directory
+ * block, and the name is small enough to fit, then adjust the
+ * record length.
+ */
+ if ((left < 0) &&
+ (name_len + 8 <= dirent->rec_len + left) &&
+ dirent->inode <= fs->super->s_inodes_count &&
+ strnlen(dirent->name, name_len) == name_len) {
+ dirent->rec_len += left;
+ return;
+ }
+ /*
+ * If the directory entry is a multiple of four, so it is
+ * valid, let the previous directory entry absorb the invalid
+ * one.
+ */
+ if (prev && dirent->rec_len && (dirent->rec_len % 4) == 0) {
+ prev->rec_len += dirent->rec_len;
+ *offset += dirent->rec_len;
+ return;
+ }
+ /*
+ * Default salvage method --- kill all of the directory
+ * entries for the rest of the block. We will either try to
+ * absorb it into the previous directory entry, or create a
+ * new empty directory entry the rest of the directory block.
+ */
+ if (prev) {
+ prev->rec_len += fs->blocksize - *offset;
+ *offset = fs->blocksize;
+ } else {
+ dirent->rec_len = fs->blocksize - *offset;
+ dirent->name_len = 0;
+ dirent->inode = 0;
+ }
+}
+
+static int check_dir_block(ext2_filsys fs,
+ struct ext2_db_entry *db,
+ void *priv_data)
+{
+ struct dir_info *subdir, *dir;
+ struct dx_dir_info *dx_dir;
+#ifdef ENABLE_HTREE
+ struct dx_dirblock_info *dx_db = 0;
+#endif /* ENABLE_HTREE */
+ struct ext2_dir_entry *dirent, *prev;
+ ext2_dirhash_t hash;
+ unsigned int offset = 0;
+ int dir_modified = 0;
+ int dot_state;
+ blk_t block_nr = db->blk;
+ ext2_ino_t ino = db->ino;
+ __u16 links;
+ struct check_dir_struct *cd;
+ char *buf;
+ e2fsck_t ctx;
+ int problem;
+ struct ext2_dx_root_info *root;
+ struct ext2_dx_countlimit *limit;
+ static dict_t de_dict;
+ struct problem_context pctx;
+ int dups_found = 0;
+
+ cd = (struct check_dir_struct *) priv_data;
+ buf = cd->buf;
+ ctx = cd->ctx;
+
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ return DIRENT_ABORT;
+
+ if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
+ return DIRENT_ABORT;
+
+ /*
+ * Make sure the inode is still in use (could have been
+ * deleted in the duplicate/bad blocks pass.
+ */
+ if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, ino)))
+ return 0;
+
+ cd->pctx.ino = ino;
+ cd->pctx.blk = block_nr;
+ cd->pctx.blkcount = db->blockcnt;
+ cd->pctx.ino2 = 0;
+ cd->pctx.dirent = 0;
+ cd->pctx.num = 0;
+
+ if (db->blk == 0) {
+ if (allocate_dir_block(ctx, db, &cd->pctx))
+ return 0;
+ block_nr = db->blk;
+ }
+
+ if (db->blockcnt)
+ dot_state = 2;
+ else
+ dot_state = 0;
+
+ if (ctx->dirs_to_hash &&
+ ext2fs_u32_list_test(ctx->dirs_to_hash, ino))
+ dups_found++;
+
+ cd->pctx.errcode = ext2fs_read_dir_block(fs, block_nr, buf);
+ if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
+ cd->pctx.errcode = 0; /* We'll handle this ourselves */
+ if (cd->pctx.errcode) {
+ if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) {
+ ctx->flags |= E2F_FLAG_ABORT;
+ return DIRENT_ABORT;
+ }
+ memset(buf, 0, fs->blocksize);
+ }
+#ifdef ENABLE_HTREE
+ dx_dir = e2fsck_get_dx_dir_info(ctx, ino);
+ if (dx_dir && dx_dir->numblocks) {
+ if (db->blockcnt >= dx_dir->numblocks) {
+ printf("XXX should never happen!!!\n");
+ abort();
+ }
+ dx_db = &dx_dir->dx_block[db->blockcnt];
+ dx_db->type = DX_DIRBLOCK_LEAF;
+ dx_db->phys = block_nr;
+ dx_db->min_hash = ~0;
+ dx_db->max_hash = 0;
+
+ dirent = (struct ext2_dir_entry *) buf;
+ limit = (struct ext2_dx_countlimit *) (buf+8);
+ if (db->blockcnt == 0) {
+ root = (struct ext2_dx_root_info *) (buf + 24);
+ dx_db->type = DX_DIRBLOCK_ROOT;
+ dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST;
+ if ((root->reserved_zero ||
+ root->info_length < 8 ||
+ root->indirect_levels > 1) &&
+ fix_problem(ctx, PR_2_HTREE_BAD_ROOT, &cd->pctx)) {
+ clear_htree(ctx, ino);
+ dx_dir->numblocks = 0;
+ dx_db = 0;
+ }
+ dx_dir->hashversion = root->hash_version;
+ dx_dir->depth = root->indirect_levels + 1;
+ } else if ((dirent->inode == 0) &&
+ (dirent->rec_len == fs->blocksize) &&
+ (dirent->name_len == 0) &&
+ (ext2fs_le16_to_cpu(limit->limit) ==
+ ((fs->blocksize-8) /
+ sizeof(struct ext2_dx_entry))))
+ dx_db->type = DX_DIRBLOCK_NODE;
+ }
+#endif /* ENABLE_HTREE */
+
+ dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
+ prev = 0;
+ do {
+ problem = 0;
+ dirent = (struct ext2_dir_entry *) (buf + offset);
+ cd->pctx.dirent = dirent;
+ cd->pctx.num = offset;
+ if (((offset + dirent->rec_len) > fs->blocksize) ||
+ (dirent->rec_len < 12) ||
+ ((dirent->rec_len % 4) != 0) ||
+ (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
+ if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) {
+ salvage_directory(fs, dirent, prev, &offset);
+ dir_modified++;
+ continue;
+ } else
+ goto abort_free_dict;
+ }
+ if ((dirent->name_len & 0xFF) > EXT2_NAME_LEN) {
+ if (fix_problem(ctx, PR_2_FILENAME_LONG, &cd->pctx)) {
+ dirent->name_len = EXT2_NAME_LEN;
+ dir_modified++;
+ }
+ }
+
+ if (dot_state == 0) {
+ if (check_dot(ctx, dirent, ino, &cd->pctx))
+ dir_modified++;
+ } else if (dot_state == 1) {
+ dir = e2fsck_get_dir_info(ctx, ino);
+ if (!dir) {
+ fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
+ goto abort_free_dict;
+ }
+ if (check_dotdot(ctx, dirent, dir, &cd->pctx))
+ dir_modified++;
+ } else if (dirent->inode == ino) {
+ problem = PR_2_LINK_DOT;
+ if (fix_problem(ctx, PR_2_LINK_DOT, &cd->pctx)) {
+ dirent->inode = 0;
+ dir_modified++;
+ goto next;
+ }
+ }
+ if (!dirent->inode)
+ goto next;
+
+ /*
+ * Make sure the inode listed is a legal one.
+ */
+ if (((dirent->inode != EXT2_ROOT_INO) &&
+ (dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
+ (dirent->inode > fs->super->s_inodes_count)) {
+ problem = PR_2_BAD_INO;
+ } else if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map,
+ dirent->inode))) {
+ /*
+ * If the inode is unused, offer to clear it.
+ */
+ problem = PR_2_UNUSED_INODE;
+ } else if ((dot_state > 1) &&
+ ((dirent->name_len & 0xFF) == 1) &&
+ (dirent->name[0] == '.')) {
+ /*
+ * If there's a '.' entry in anything other
+ * than the first directory entry, it's a
+ * duplicate entry that should be removed.
+ */
+ problem = PR_2_DUP_DOT;
+ } else if ((dot_state > 1) &&
+ ((dirent->name_len & 0xFF) == 2) &&
+ (dirent->name[0] == '.') &&
+ (dirent->name[1] == '.')) {
+ /*
+ * If there's a '..' entry in anything other
+ * than the second directory entry, it's a
+ * duplicate entry that should be removed.
+ */
+ problem = PR_2_DUP_DOT_DOT;
+ } else if ((dot_state > 1) &&
+ (dirent->inode == EXT2_ROOT_INO)) {
+ /*
+ * Don't allow links to the root directory.
+ * We check this specially to make sure we
+ * catch this error case even if the root
+ * directory hasn't been created yet.
+ */
+ problem = PR_2_LINK_ROOT;
+ } else if ((dot_state > 1) &&
+ (dirent->name_len & 0xFF) == 0) {
+ /*
+ * Don't allow zero-length directory names.
+ */
+ problem = PR_2_NULL_NAME;
+ }
+
+ if (problem) {
+ if (fix_problem(ctx, problem, &cd->pctx)) {
+ dirent->inode = 0;
+ dir_modified++;
+ goto next;
+ } else {
+ ext2fs_unmark_valid(fs);
+ if (problem == PR_2_BAD_INO)
+ goto next;
+ }
+ }
+
+ /*
+ * If the inode was marked as having bad fields in
+ * pass1, process it and offer to fix/clear it.
+ * (We wait until now so that we can display the
+ * pathname to the user.)
+ */
+ if (ctx->inode_bad_map &&
+ ext2fs_test_inode_bitmap(ctx->inode_bad_map,
+ dirent->inode)) {
+ if (e2fsck_process_bad_inode(ctx, ino,
+ dirent->inode,
+ buf + fs->blocksize)) {
+ dirent->inode = 0;
+ dir_modified++;
+ goto next;
+ }
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ return DIRENT_ABORT;
+ }
+
+ if (check_name(ctx, dirent, &cd->pctx))
+ dir_modified++;
+
+ if (check_filetype(ctx, dirent, &cd->pctx))
+ dir_modified++;
+
+#ifdef ENABLE_HTREE
+ if (dx_db) {
+ ext2fs_dirhash(dx_dir->hashversion, dirent->name,
+ (dirent->name_len & 0xFF),
+ fs->super->s_hash_seed, &hash, 0);
+ if (hash < dx_db->min_hash)
+ dx_db->min_hash = hash;
+ if (hash > dx_db->max_hash)
+ dx_db->max_hash = hash;
+ }
+#endif
+
+ /*
+ * If this is a directory, then mark its parent in its
+ * dir_info structure. If the parent field is already
+ * filled in, then this directory has more than one
+ * hard link. We assume the first link is correct,
+ * and ask the user if he/she wants to clear this one.
+ */
+ if ((dot_state > 1) &&
+ (ext2fs_test_inode_bitmap(ctx->inode_dir_map,
+ dirent->inode))) {
+ subdir = e2fsck_get_dir_info(ctx, dirent->inode);
+ if (!subdir) {
+ cd->pctx.ino = dirent->inode;
+ fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
+ goto abort_free_dict;
+ }
+ if (subdir->parent) {
+ cd->pctx.ino2 = subdir->parent;
+ if (fix_problem(ctx, PR_2_LINK_DIR,
+ &cd->pctx)) {
+ dirent->inode = 0;
+ dir_modified++;
+ goto next;
+ }
+ cd->pctx.ino2 = 0;
+ } else
+ subdir->parent = ino;
+ }
+
+ if (dups_found) {
+ ;
+ } else if (dict_lookup(&de_dict, dirent)) {
+ clear_problem_context(&pctx);
+ pctx.ino = ino;
+ pctx.dirent = dirent;
+ fix_problem(ctx, PR_2_REPORT_DUP_DIRENT, &pctx);
+ if (!ctx->dirs_to_hash)
+ ext2fs_u32_list_create(&ctx->dirs_to_hash, 50);
+ if (ctx->dirs_to_hash)
+ ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
+ dups_found++;
+ } else
+ dict_alloc_insert(&de_dict, dirent, dirent);
+
+ ext2fs_icount_increment(ctx->inode_count, dirent->inode,
+ &links);
+ if (links > 1)
+ ctx->fs_links_count++;
+ ctx->fs_total_count++;
+ next:
+ prev = dirent;
+ offset += dirent->rec_len;
+ dot_state++;
+ } while (offset < fs->blocksize);
+#ifdef ENABLE_HTREE
+ if (dx_db) {
+ cd->pctx.dir = cd->pctx.ino;
+ if ((dx_db->type == DX_DIRBLOCK_ROOT) ||
+ (dx_db->type == DX_DIRBLOCK_NODE))
+ parse_int_node(fs, db, cd, dx_dir, buf);
+ }
+#endif /* ENABLE_HTREE */
+ if (offset != fs->blocksize) {
+ cd->pctx.num = dirent->rec_len - fs->blocksize + offset;
+ if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
+ dirent->rec_len = cd->pctx.num;
+ dir_modified++;
+ }
+ }
+ if (dir_modified) {
+ cd->pctx.errcode = ext2fs_write_dir_block(fs, block_nr, buf);
+ if (cd->pctx.errcode) {
+ if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
+ &cd->pctx))
+ goto abort_free_dict;
+ }
+ ext2fs_mark_changed(fs);
+ }
+ dict_free_nodes(&de_dict);
+ return 0;
+abort_free_dict:
+ dict_free_nodes(&de_dict);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return DIRENT_ABORT;
+}
+
+/*
+ * This function is called to deallocate a block, and is an interator
+ * functioned called by deallocate inode via ext2fs_iterate_block().
+ */
+static int deallocate_inode_block(ext2_filsys fs, blk_t *block_nr,
+ e2_blkcnt_t blockcnt FSCK_ATTR((unused)),
+ blk_t ref_block FSCK_ATTR((unused)),
+ int ref_offset FSCK_ATTR((unused)),
+ void *priv_data)
+{
+ e2fsck_t ctx = (e2fsck_t) priv_data;
+
+ if (HOLE_BLKADDR(*block_nr))
+ return 0;
+ if ((*block_nr < fs->super->s_first_data_block) ||
+ (*block_nr >= fs->super->s_blocks_count))
+ return 0;
+ ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
+ ext2fs_block_alloc_stats(fs, *block_nr, -1);
+ return 0;
+}
+
+/*
+ * This fuction deallocates an inode
+ */
+static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
+{
+ ext2_filsys fs = ctx->fs;
+ struct ext2_inode inode;
+ struct problem_context pctx;
+ __u32 count;
+
+ ext2fs_icount_store(ctx->inode_link_info, ino, 0);
+ e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
+ inode.i_links_count = 0;
+ inode.i_dtime = time(0);
+ e2fsck_write_inode(ctx, ino, &inode, "deallocate_inode");
+ clear_problem_context(&pctx);
+ pctx.ino = ino;
+
+ /*
+ * Fix up the bitmaps...
+ */
+ e2fsck_read_bitmaps(ctx);
+ ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
+ ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
+ if (ctx->inode_bad_map)
+ ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
+ ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
+
+ if (inode.i_file_acl &&
+ (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
+ pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
+ block_buf, -1, &count);
+ if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
+ pctx.errcode = 0;
+ count = 1;
+ }
+ if (pctx.errcode) {
+ pctx.blk = inode.i_file_acl;
+ fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ if (count == 0) {
+ ext2fs_unmark_block_bitmap(ctx->block_found_map,
+ inode.i_file_acl);
+ ext2fs_block_alloc_stats(fs, inode.i_file_acl, -1);
+ }
+ inode.i_file_acl = 0;
+ }
+
+ if (!ext2fs_inode_has_valid_blocks(&inode))
+ return;
+
+ if (LINUX_S_ISREG(inode.i_mode) &&
+ (inode.i_size_high || inode.i_size & 0x80000000UL))
+ ctx->large_files--;
+
+ pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
+ deallocate_inode_block, ctx);
+ if (pctx.errcode) {
+ fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+}
+
+/*
+ * This fuction clears the htree flag on an inode
+ */
+static void clear_htree(e2fsck_t ctx, ext2_ino_t ino)
+{
+ struct ext2_inode inode;
+
+ e2fsck_read_inode(ctx, ino, &inode, "clear_htree");
+ inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL;
+ e2fsck_write_inode(ctx, ino, &inode, "clear_htree");
+ if (ctx->dirs_to_hash)
+ ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
+}
+
+
+static int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
+ ext2_ino_t ino, char *buf)
+{
+ ext2_filsys fs = ctx->fs;
+ struct ext2_inode inode;
+ int inode_modified = 0;
+ int not_fixed = 0;
+ unsigned char *frag, *fsize;
+ struct problem_context pctx;
+ int problem = 0;
+
+ e2fsck_read_inode(ctx, ino, &inode, "process_bad_inode");
+
+ clear_problem_context(&pctx);
+ pctx.ino = ino;
+ pctx.dir = dir;
+ pctx.inode = &inode;
+
+ if (inode.i_file_acl &&
+ !(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) &&
+ fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) {
+ inode.i_file_acl = 0;
+#if BB_BIG_ENDIAN
+ /*
+ * This is a special kludge to deal with long symlinks
+ * on big endian systems. i_blocks had already been
+ * decremented earlier in pass 1, but since i_file_acl
+ * hadn't yet been cleared, ext2fs_read_inode()
+ * assumed that the file was short symlink and would
+ * not have byte swapped i_block[0]. Hence, we have
+ * to byte-swap it here.
+ */
+ if (LINUX_S_ISLNK(inode.i_mode) &&
+ (fs->flags & EXT2_FLAG_SWAP_BYTES) &&
+ (inode.i_blocks == fs->blocksize >> 9))
+ inode.i_block[0] = ext2fs_swab32(inode.i_block[0]);
+#endif
+ inode_modified++;
+ } else
+ not_fixed++;
+
+ if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) &&
+ !LINUX_S_ISCHR(inode.i_mode) && !LINUX_S_ISBLK(inode.i_mode) &&
+ !LINUX_S_ISLNK(inode.i_mode) && !LINUX_S_ISFIFO(inode.i_mode) &&
+ !(LINUX_S_ISSOCK(inode.i_mode)))
+ problem = PR_2_BAD_MODE;
+ else if (LINUX_S_ISCHR(inode.i_mode)
+ && !e2fsck_pass1_check_device_inode(fs, &inode))
+ problem = PR_2_BAD_CHAR_DEV;
+ else if (LINUX_S_ISBLK(inode.i_mode)
+ && !e2fsck_pass1_check_device_inode(fs, &inode))
+ problem = PR_2_BAD_BLOCK_DEV;
+ else if (LINUX_S_ISFIFO(inode.i_mode)
+ && !e2fsck_pass1_check_device_inode(fs, &inode))
+ problem = PR_2_BAD_FIFO;
+ else if (LINUX_S_ISSOCK(inode.i_mode)
+ && !e2fsck_pass1_check_device_inode(fs, &inode))
+ problem = PR_2_BAD_SOCKET;
+ else if (LINUX_S_ISLNK(inode.i_mode)
+ && !e2fsck_pass1_check_symlink(fs, &inode, buf)) {
+ problem = PR_2_INVALID_SYMLINK;
+ }
+
+ if (problem) {
+ if (fix_problem(ctx, problem, &pctx)) {
+ deallocate_inode(ctx, ino, 0);
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ return 0;
+ return 1;
+ } else
+ not_fixed++;
+ problem = 0;
+ }
+
+ if (inode.i_faddr) {
+ if (fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) {
+ inode.i_faddr = 0;
+ inode_modified++;
+ } else
+ not_fixed++;
+ }
+
+ switch (fs->super->s_creator_os) {
+ case EXT2_OS_LINUX:
+ frag = &inode.osd2.linux2.l_i_frag;
+ fsize = &inode.osd2.linux2.l_i_fsize;
+ break;
+ case EXT2_OS_HURD:
+ frag = &inode.osd2.hurd2.h_i_frag;
+ fsize = &inode.osd2.hurd2.h_i_fsize;
+ break;
+ case EXT2_OS_MASIX:
+ frag = &inode.osd2.masix2.m_i_frag;
+ fsize = &inode.osd2.masix2.m_i_fsize;
+ break;
+ default:
+ frag = fsize = 0;
+ }
+ if (frag && *frag) {
+ pctx.num = *frag;
+ if (fix_problem(ctx, PR_2_FRAG_ZERO, &pctx)) {
+ *frag = 0;
+ inode_modified++;
+ } else
+ not_fixed++;
+ pctx.num = 0;
+ }
+ if (fsize && *fsize) {
+ pctx.num = *fsize;
+ if (fix_problem(ctx, PR_2_FSIZE_ZERO, &pctx)) {
+ *fsize = 0;
+ inode_modified++;
+ } else
+ not_fixed++;
+ pctx.num = 0;
+ }
+
+ if (inode.i_file_acl &&
+ ((inode.i_file_acl < fs->super->s_first_data_block) ||
+ (inode.i_file_acl >= fs->super->s_blocks_count))) {
+ if (fix_problem(ctx, PR_2_FILE_ACL_BAD, &pctx)) {
+ inode.i_file_acl = 0;
+ inode_modified++;
+ } else
+ not_fixed++;
+ }
+ if (inode.i_dir_acl &&
+ LINUX_S_ISDIR(inode.i_mode)) {
+ if (fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) {
+ inode.i_dir_acl = 0;
+ inode_modified++;
+ } else
+ not_fixed++;
+ }
+
+ if (inode_modified)
+ e2fsck_write_inode(ctx, ino, &inode, "process_bad_inode");
+ if (!not_fixed)
+ ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
+ return 0;
+}
+
+
+/*
+ * allocate_dir_block --- this function allocates a new directory
+ * block for a particular inode; this is done if a directory has
+ * a "hole" in it, or if a directory has a illegal block number
+ * that was zeroed out and now needs to be replaced.
+ */
+static int allocate_dir_block(e2fsck_t ctx, struct ext2_db_entry *db,
+ struct problem_context *pctx)
+{
+ ext2_filsys fs = ctx->fs;
+ blk_t blk;
+ char *block;
+ struct ext2_inode inode;
+
+ if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0)
+ return 1;
+
+ /*
+ * Read the inode and block bitmaps in; we'll be messing with
+ * them.
+ */
+ e2fsck_read_bitmaps(ctx);
+
+ /*
+ * First, find a free block
+ */
+ pctx->errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
+ if (pctx->errcode) {
+ pctx->str = "ext2fs_new_block";
+ fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
+ return 1;
+ }
+ ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
+ ext2fs_mark_block_bitmap(fs->block_map, blk);
+ ext2fs_mark_bb_dirty(fs);
+
+ /*
+ * Now let's create the actual data block for the inode
+ */
+ if (db->blockcnt)
+ pctx->errcode = ext2fs_new_dir_block(fs, 0, 0, &block);
+ else
+ pctx->errcode = ext2fs_new_dir_block(fs, db->ino,
+ EXT2_ROOT_INO, &block);
+
+ if (pctx->errcode) {
+ pctx->str = "ext2fs_new_dir_block";
+ fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
+ return 1;
+ }
+
+ pctx->errcode = ext2fs_write_dir_block(fs, blk, block);
+ ext2fs_free_mem(&block);
+ if (pctx->errcode) {
+ pctx->str = "ext2fs_write_dir_block";
+ fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
+ return 1;
+ }
+
+ /*
+ * Update the inode block count
+ */
+ e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block");
+ inode.i_blocks += fs->blocksize / 512;
+ if (inode.i_size < (db->blockcnt+1) * fs->blocksize)
+ inode.i_size = (db->blockcnt+1) * fs->blocksize;
+ e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block");
+
+ /*
+ * Finally, update the block pointers for the inode
+ */
+ db->blk = blk;
+ pctx->errcode = ext2fs_block_iterate2(fs, db->ino, BLOCK_FLAG_HOLE,
+ 0, update_dir_block, db);
+ if (pctx->errcode) {
+ pctx->str = "ext2fs_block_iterate";
+ fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * This is a helper function for allocate_dir_block().
+ */
+static int update_dir_block(ext2_filsys fs FSCK_ATTR((unused)),
+ blk_t *block_nr,
+ e2_blkcnt_t blockcnt,
+ blk_t ref_block FSCK_ATTR((unused)),
+ int ref_offset FSCK_ATTR((unused)),
+ void *priv_data)
+{
+ struct ext2_db_entry *db;
+
+ db = (struct ext2_db_entry *) priv_data;
+ if (db->blockcnt == (int) blockcnt) {
+ *block_nr = db->blk;
+ return BLOCK_CHANGED;
+ }
+ return 0;
+}
+
+/*
+ * pass3.c -- pass #3 of e2fsck: Check for directory connectivity
+ *
+ * Pass #3 assures that all directories are connected to the
+ * filesystem tree, using the following algorithm:
+ *
+ * First, the root directory is checked to make sure it exists; if
+ * not, e2fsck will offer to create a new one. It is then marked as
+ * "done".
+ *
+ * Then, pass3 interates over all directory inodes; for each directory
+ * it attempts to trace up the filesystem tree, using dirinfo.parent
+ * until it reaches a directory which has been marked "done". If it
+ * cannot do so, then the directory must be disconnected, and e2fsck
+ * will offer to reconnect it to /lost+found. While it is chasing
+ * parent pointers up the filesystem tree, if pass3 sees a directory
+ * twice, then it has detected a filesystem loop, and it will again
+ * offer to reconnect the directory to /lost+found in to break the
+ * filesystem loop.
+ *
+ * Pass 3 also contains the subroutine, e2fsck_reconnect_file() to
+ * reconnect inodes to /lost+found; this subroutine is also used by
+ * pass 4. e2fsck_reconnect_file() calls get_lost_and_found(), which
+ * is responsible for creating /lost+found if it does not exist.
+ *
+ * Pass 3 frees the following data structures:
+ * - The dirinfo directory information cache.
+ */
+
+static void check_root(e2fsck_t ctx);
+static int check_directory(e2fsck_t ctx, struct dir_info *dir,
+ struct problem_context *pctx);
+static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent);
+
+static ext2fs_inode_bitmap inode_loop_detect;
+static ext2fs_inode_bitmap inode_done_map;
+
+static void e2fsck_pass3(e2fsck_t ctx)
+{
+ ext2_filsys fs = ctx->fs;
+ int i;
+ struct problem_context pctx;
+ struct dir_info *dir;
+ unsigned long maxdirs, count;
+
+ clear_problem_context(&pctx);
+
+ /* Pass 3 */
+
+ if (!(ctx->options & E2F_OPT_PREEN))
+ fix_problem(ctx, PR_3_PASS_HEADER, &pctx);
+
+ /*
+ * Allocate some bitmaps to do loop detection.
+ */
+ pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("inode done bitmap"),
+ &inode_done_map);
+ if (pctx.errcode) {
+ pctx.num = 2;
+ fix_problem(ctx, PR_3_ALLOCATE_IBITMAP_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ goto abort_exit;
+ }
+ check_root(ctx);
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ goto abort_exit;
+
+ ext2fs_mark_inode_bitmap(inode_done_map, EXT2_ROOT_INO);
+
+ maxdirs = e2fsck_get_num_dirinfo(ctx);
+ count = 1;
+
+ if (ctx->progress)
+ if ((ctx->progress)(ctx, 3, 0, maxdirs))
+ goto abort_exit;
+
+ for (i=0; (dir = e2fsck_dir_info_iter(ctx, &i)) != 0;) {
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ goto abort_exit;
+ if (ctx->progress && (ctx->progress)(ctx, 3, count++, maxdirs))
+ goto abort_exit;
+ if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dir->ino))
+ if (check_directory(ctx, dir, &pctx))
+ goto abort_exit;
+ }
+
+ /*
+ * Force the creation of /lost+found if not present
+ */
+ if ((ctx->flags & E2F_OPT_READONLY) == 0)
+ e2fsck_get_lost_and_found(ctx, 1);
+
+ /*
+ * If there are any directories that need to be indexed or
+ * optimized, do it here.
+ */
+ e2fsck_rehash_directories(ctx);
+
+abort_exit:
+ e2fsck_free_dir_info(ctx);
+ ext2fs_free_inode_bitmap(inode_loop_detect);
+ inode_loop_detect = 0;
+ ext2fs_free_inode_bitmap(inode_done_map);
+ inode_done_map = 0;
+}
+
+/*
+ * This makes sure the root inode is present; if not, we ask if the
+ * user wants us to create it. Not creating it is a fatal error.
+ */
+static void check_root(e2fsck_t ctx)
+{
+ ext2_filsys fs = ctx->fs;
+ blk_t blk;
+ struct ext2_inode inode;
+ char * block;
+ struct problem_context pctx;
+
+ clear_problem_context(&pctx);
+
+ if (ext2fs_test_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO)) {
+ /*
+ * If the root inode is not a directory, die here. The
+ * user must have answered 'no' in pass1 when we
+ * offered to clear it.
+ */
+ if (!(ext2fs_test_inode_bitmap(ctx->inode_dir_map,
+ EXT2_ROOT_INO))) {
+ fix_problem(ctx, PR_3_ROOT_NOT_DIR_ABORT, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ }
+ return;
+ }
+
+ if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) {
+ fix_problem(ctx, PR_3_NO_ROOT_INODE_ABORT, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+
+ e2fsck_read_bitmaps(ctx);
+
+ /*
+ * First, find a free block
+ */
+ pctx.errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
+ if (pctx.errcode) {
+ pctx.str = "ext2fs_new_block";
+ fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
+ ext2fs_mark_block_bitmap(fs->block_map, blk);
+ ext2fs_mark_bb_dirty(fs);
+
+ /*
+ * Now let's create the actual data block for the inode
+ */
+ pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
+ &block);
+ if (pctx.errcode) {
+ pctx.str = "ext2fs_new_dir_block";
+ fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+
+ pctx.errcode = ext2fs_write_dir_block(fs, blk, block);
+ if (pctx.errcode) {
+ pctx.str = "ext2fs_write_dir_block";
+ fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ ext2fs_free_mem(&block);
+
+ /*
+ * Set up the inode structure
+ */
+ memset(&inode, 0, sizeof(inode));
+ inode.i_mode = 040755;
+ inode.i_size = fs->blocksize;
+ inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
+ inode.i_links_count = 2;
+ inode.i_blocks = fs->blocksize / 512;
+ inode.i_block[0] = blk;
+
+ /*
+ * Write out the inode.
+ */
+ pctx.errcode = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode);
+ if (pctx.errcode) {
+ pctx.str = "ext2fs_write_inode";
+ fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+
+ /*
+ * Miscellaneous bookkeeping...
+ */
+ e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO);
+ ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2);
+ ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2);
+
+ ext2fs_mark_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO);
+ ext2fs_mark_inode_bitmap(ctx->inode_dir_map, EXT2_ROOT_INO);
+ ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_ROOT_INO);
+ ext2fs_mark_ib_dirty(fs);
+}
+
+/*
+ * This subroutine is responsible for making sure that a particular
+ * directory is connected to the root; if it isn't we trace it up as
+ * far as we can go, and then offer to connect the resulting parent to
+ * the lost+found. We have to do loop detection; if we ever discover
+ * a loop, we treat that as a disconnected directory and offer to
+ * reparent it to lost+found.
+ *
+ * However, loop detection is expensive, because for very large
+ * filesystems, the inode_loop_detect bitmap is huge, and clearing it
+ * is non-trivial. Loops in filesystems are also a rare error case,
+ * and we shouldn't optimize for error cases. So we try two passes of
+ * the algorithm. The first time, we ignore loop detection and merely
+ * increment a counter; if the counter exceeds some extreme threshold,
+ * then we try again with the loop detection bitmap enabled.
+ */
+static int check_directory(e2fsck_t ctx, struct dir_info *dir,
+ struct problem_context *pctx)
+{
+ ext2_filsys fs = ctx->fs;
+ struct dir_info *p = dir;
+ int loop_pass = 0, parent_count = 0;
+
+ if (!p)
+ return 0;
+
+ while (1) {
+ /*
+ * Mark this inode as being "done"; by the time we
+ * return from this function, the inode we either be
+ * verified as being connected to the directory tree,
+ * or we will have offered to reconnect this to
+ * lost+found.
+ *
+ * If it was marked done already, then we've reached a
+ * parent we've already checked.
+ */
+ if (ext2fs_mark_inode_bitmap(inode_done_map, p->ino))
+ break;
+
+ /*
+ * If this directory doesn't have a parent, or we've
+ * seen the parent once already, then offer to
+ * reparent it to lost+found
+ */
+ if (!p->parent ||
+ (loop_pass &&
+ (ext2fs_test_inode_bitmap(inode_loop_detect,
+ p->parent)))) {
+ pctx->ino = p->ino;
+ if (fix_problem(ctx, PR_3_UNCONNECTED_DIR, pctx)) {
+ if (e2fsck_reconnect_file(ctx, pctx->ino))
+ ext2fs_unmark_valid(fs);
+ else {
+ p = e2fsck_get_dir_info(ctx, pctx->ino);
+ p->parent = ctx->lost_and_found;
+ fix_dotdot(ctx, p, ctx->lost_and_found);
+ }
+ }
+ break;
+ }
+ p = e2fsck_get_dir_info(ctx, p->parent);
+ if (!p) {
+ fix_problem(ctx, PR_3_NO_DIRINFO, pctx);
+ return 0;
+ }
+ if (loop_pass) {
+ ext2fs_mark_inode_bitmap(inode_loop_detect,
+ p->ino);
+ } else if (parent_count++ > 2048) {
+ /*
+ * If we've run into a path depth that's
+ * greater than 2048, try again with the inode
+ * loop bitmap turned on and start from the
+ * top.
+ */
+ loop_pass = 1;
+ if (inode_loop_detect)
+ ext2fs_clear_inode_bitmap(inode_loop_detect);
+ else {
+ pctx->errcode = ext2fs_allocate_inode_bitmap(fs, _("inode loop detection bitmap"), &inode_loop_detect);
+ if (pctx->errcode) {
+ pctx->num = 1;
+ fix_problem(ctx,
+ PR_3_ALLOCATE_IBITMAP_ERROR, pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return -1;
+ }
+ }
+ p = dir;
+ }
+ }
+
+ /*
+ * Make sure that .. and the parent directory are the same;
+ * offer to fix it if not.
+ */
+ if (dir->parent != dir->dotdot) {
+ pctx->ino = dir->ino;
+ pctx->ino2 = dir->dotdot;
+ pctx->dir = dir->parent;
+ if (fix_problem(ctx, PR_3_BAD_DOT_DOT, pctx))
+ fix_dotdot(ctx, dir, dir->parent);
+ }
+ return 0;
+}
+
+/*
+ * This routine gets the lost_and_found inode, making it a directory
+ * if necessary
+ */
+ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
+{
+ ext2_filsys fs = ctx->fs;
+ ext2_ino_t ino;
+ blk_t blk;
+ errcode_t retval;
+ struct ext2_inode inode;
+ char * block;
+ static const char name[] = "lost+found";
+ struct problem_context pctx;
+ struct dir_info *dirinfo;
+
+ if (ctx->lost_and_found)
+ return ctx->lost_and_found;
+
+ clear_problem_context(&pctx);
+
+ retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name,
+ sizeof(name)-1, 0, &ino);
+ if (retval && !fix)
+ return 0;
+ if (!retval) {
+ if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino)) {
+ ctx->lost_and_found = ino;
+ return ino;
+ }
+
+ /* Lost+found isn't a directory! */
+ if (!fix)
+ return 0;
+ pctx.ino = ino;
+ if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx))
+ return 0;
+
+ /* OK, unlink the old /lost+found file. */
+ pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0);
+ if (pctx.errcode) {
+ pctx.str = "ext2fs_unlink";
+ fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
+ return 0;
+ }
+ dirinfo = e2fsck_get_dir_info(ctx, ino);
+ if (dirinfo)
+ dirinfo->parent = 0;
+ e2fsck_adjust_inode_count(ctx, ino, -1);
+ } else if (retval != EXT2_ET_FILE_NOT_FOUND) {
+ pctx.errcode = retval;
+ fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx);
+ }
+ if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0))
+ return 0;
+
+ /*
+ * Read the inode and block bitmaps in; we'll be messing with
+ * them.
+ */
+ e2fsck_read_bitmaps(ctx);
+
+ /*
+ * First, find a free block
+ */
+ retval = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
+ if (retval) {
+ pctx.errcode = retval;
+ fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx);
+ return 0;
+ }
+ ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
+ ext2fs_block_alloc_stats(fs, blk, +1);
+
+ /*
+ * Next find a free inode.
+ */
+ retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700,
+ ctx->inode_used_map, &ino);
+ if (retval) {
+ pctx.errcode = retval;
+ fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx);
+ return 0;
+ }
+ ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
+ ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
+ ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
+
+ /*
+ * Now let's create the actual data block for the inode
+ */
+ retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block);
+ if (retval) {
+ pctx.errcode = retval;
+ fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx);
+ return 0;
+ }
+
+ retval = ext2fs_write_dir_block(fs, blk, block);
+ ext2fs_free_mem(&block);
+ if (retval) {
+ pctx.errcode = retval;
+ fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx);
+ return 0;
+ }
+
+ /*
+ * Set up the inode structure
+ */
+ memset(&inode, 0, sizeof(inode));
+ inode.i_mode = 040700;
+ inode.i_size = fs->blocksize;
+ inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
+ inode.i_links_count = 2;
+ inode.i_blocks = fs->blocksize / 512;
+ inode.i_block[0] = blk;
+
+ /*
+ * Next, write out the inode.
+ */
+ pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode);
+ if (pctx.errcode) {
+ pctx.str = "ext2fs_write_inode";
+ fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
+ return 0;
+ }
+ /*
+ * Finally, create the directory link
+ */
+ pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR);
+ if (pctx.errcode) {
+ pctx.str = "ext2fs_link";
+ fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
+ return 0;
+ }
+
+ /*
+ * Miscellaneous bookkeeping that needs to be kept straight.
+ */
+ e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO);
+ e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1);
+ ext2fs_icount_store(ctx->inode_count, ino, 2);
+ ext2fs_icount_store(ctx->inode_link_info, ino, 2);
+ ctx->lost_and_found = ino;
+ return ino;
+}
+
+/*
+ * This routine will connect a file to lost+found
+ */
+int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t ino)
+{
+ ext2_filsys fs = ctx->fs;
+ errcode_t retval;
+ char name[80];
+ struct problem_context pctx;
+ struct ext2_inode inode;
+ int file_type = 0;
+
+ clear_problem_context(&pctx);
+ pctx.ino = ino;
+
+ if (!ctx->bad_lost_and_found && !ctx->lost_and_found) {
+ if (e2fsck_get_lost_and_found(ctx, 1) == 0)
+ ctx->bad_lost_and_found++;
+ }
+ if (ctx->bad_lost_and_found) {
+ fix_problem(ctx, PR_3_NO_LPF, &pctx);
+ return 1;
+ }
+
+ sprintf(name, "#%u", ino);
+ if (ext2fs_read_inode(fs, ino, &inode) == 0)
+ file_type = ext2_file_type(inode.i_mode);
+ retval = ext2fs_link(fs, ctx->lost_and_found, name, ino, file_type);
+ if (retval == EXT2_ET_DIR_NO_SPACE) {
+ if (!fix_problem(ctx, PR_3_EXPAND_LF_DIR, &pctx))
+ return 1;
+ retval = e2fsck_expand_directory(ctx, ctx->lost_and_found,
+ 1, 0);
+ if (retval) {
+ pctx.errcode = retval;
+ fix_problem(ctx, PR_3_CANT_EXPAND_LPF, &pctx);
+ return 1;
+ }
+ retval = ext2fs_link(fs, ctx->lost_and_found, name,
+ ino, file_type);
+ }
+ if (retval) {
+ pctx.errcode = retval;
+ fix_problem(ctx, PR_3_CANT_RECONNECT, &pctx);
+ return 1;
+ }
+ e2fsck_adjust_inode_count(ctx, ino, 1);
+
+ return 0;
+}
+
+/*
+ * Utility routine to adjust the inode counts on an inode.
+ */
+errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj)
+{
+ ext2_filsys fs = ctx->fs;
+ errcode_t retval;
+ struct ext2_inode inode;
+
+ if (!ino)
+ return 0;
+
+ retval = ext2fs_read_inode(fs, ino, &inode);
+ if (retval)
+ return retval;
+
+ if (adj == 1) {
+ ext2fs_icount_increment(ctx->inode_count, ino, 0);
+ if (inode.i_links_count == (__u16) ~0)
+ return 0;
+ ext2fs_icount_increment(ctx->inode_link_info, ino, 0);
+ inode.i_links_count++;
+ } else if (adj == -1) {
+ ext2fs_icount_decrement(ctx->inode_count, ino, 0);
+ if (inode.i_links_count == 0)
+ return 0;
+ ext2fs_icount_decrement(ctx->inode_link_info, ino, 0);
+ inode.i_links_count--;
+ }
+
+ retval = ext2fs_write_inode(fs, ino, &inode);
+ if (retval)
+ return retval;
+
+ return 0;
+}
+
+/*
+ * Fix parent --- this routine fixes up the parent of a directory.
+ */
+struct fix_dotdot_struct {
+ ext2_filsys fs;
+ ext2_ino_t parent;
+ int done;
+ e2fsck_t ctx;
+};
+
+static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
+ int offset FSCK_ATTR((unused)),
+ int blocksize FSCK_ATTR((unused)),
+ char *buf FSCK_ATTR((unused)),
+ void *priv_data)
+{
+ struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) priv_data;
+ errcode_t retval;
+ struct problem_context pctx;
+
+ if ((dirent->name_len & 0xFF) != 2)
+ return 0;
+ if (strncmp(dirent->name, "..", 2))
+ return 0;
+
+ clear_problem_context(&pctx);
+
+ retval = e2fsck_adjust_inode_count(fp->ctx, dirent->inode, -1);
+ if (retval) {
+ pctx.errcode = retval;
+ fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
+ }
+ retval = e2fsck_adjust_inode_count(fp->ctx, fp->parent, 1);
+ if (retval) {
+ pctx.errcode = retval;
+ fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
+ }
+ dirent->inode = fp->parent;
+
+ fp->done++;
+ return DIRENT_ABORT | DIRENT_CHANGED;
+}
+
+static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent)
+{
+ ext2_filsys fs = ctx->fs;
+ errcode_t retval;
+ struct fix_dotdot_struct fp;
+ struct problem_context pctx;
+
+ fp.fs = fs;
+ fp.parent = parent;
+ fp.done = 0;
+ fp.ctx = ctx;
+
+ retval = ext2fs_dir_iterate(fs, dir->ino, DIRENT_FLAG_INCLUDE_EMPTY,
+ 0, fix_dotdot_proc, &fp);
+ if (retval || !fp.done) {
+ clear_problem_context(&pctx);
+ pctx.ino = dir->ino;
+ pctx.errcode = retval;
+ fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR :
+ PR_3_FIX_PARENT_NOFIND, &pctx);
+ ext2fs_unmark_valid(fs);
+ }
+ dir->dotdot = parent;
+}
+
+/*
+ * These routines are responsible for expanding a /lost+found if it is
+ * too small.
+ */
+
+struct expand_dir_struct {
+ int num;
+ int guaranteed_size;
+ int newblocks;
+ int last_block;
+ errcode_t err;
+ e2fsck_t ctx;
+};
+
+static int expand_dir_proc(ext2_filsys fs,
+ blk_t *blocknr,
+ e2_blkcnt_t blockcnt,
+ blk_t ref_block FSCK_ATTR((unused)),
+ int ref_offset FSCK_ATTR((unused)),
+ void *priv_data)
+{
+ struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
+ blk_t new_blk;
+ static blk_t last_blk = 0;
+ char *block;
+ errcode_t retval;
+ e2fsck_t ctx;
+
+ ctx = es->ctx;
+
+ if (es->guaranteed_size && blockcnt >= es->guaranteed_size)
+ return BLOCK_ABORT;
+
+ if (blockcnt > 0)
+ es->last_block = blockcnt;
+ if (*blocknr) {
+ last_blk = *blocknr;
+ return 0;
+ }
+ retval = ext2fs_new_block(fs, last_blk, ctx->block_found_map,
+ &new_blk);
+ if (retval) {
+ es->err = retval;
+ return BLOCK_ABORT;
+ }
+ if (blockcnt > 0) {
+ retval = ext2fs_new_dir_block(fs, 0, 0, &block);
+ if (retval) {
+ es->err = retval;
+ return BLOCK_ABORT;
+ }
+ es->num--;
+ retval = ext2fs_write_dir_block(fs, new_blk, block);
+ } else {
+ retval = ext2fs_get_mem(fs->blocksize, &block);
+ if (retval) {
+ es->err = retval;
+ return BLOCK_ABORT;
+ }
+ memset(block, 0, fs->blocksize);
+ retval = io_channel_write_blk(fs->io, new_blk, 1, block);
+ }
+ if (retval) {
+ es->err = retval;
+ return BLOCK_ABORT;
+ }
+ ext2fs_free_mem(&block);
+ *blocknr = new_blk;
+ ext2fs_mark_block_bitmap(ctx->block_found_map, new_blk);
+ ext2fs_block_alloc_stats(fs, new_blk, +1);
+ es->newblocks++;
+
+ if (es->num == 0)
+ return (BLOCK_CHANGED | BLOCK_ABORT);
+ else
+ return BLOCK_CHANGED;
+}
+
+errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
+ int num, int guaranteed_size)
+{
+ ext2_filsys fs = ctx->fs;
+ errcode_t retval;
+ struct expand_dir_struct es;
+ struct ext2_inode inode;
+
+ if (!(fs->flags & EXT2_FLAG_RW))
+ return EXT2_ET_RO_FILSYS;
+
+ /*
+ * Read the inode and block bitmaps in; we'll be messing with
+ * them.
+ */
+ e2fsck_read_bitmaps(ctx);
+
+ retval = ext2fs_check_directory(fs, dir);
+ if (retval)
+ return retval;
+
+ es.num = num;
+ es.guaranteed_size = guaranteed_size;
+ es.last_block = 0;
+ es.err = 0;
+ es.newblocks = 0;
+ es.ctx = ctx;
+
+ retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_APPEND,
+ 0, expand_dir_proc, &es);
+
+ if (es.err)
+ return es.err;
+
+ /*
+ * Update the size and block count fields in the inode.
+ */
+ retval = ext2fs_read_inode(fs, dir, &inode);
+ if (retval)
+ return retval;
+
+ inode.i_size = (es.last_block + 1) * fs->blocksize;
+ inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
+
+ e2fsck_write_inode(ctx, dir, &inode, "expand_directory");
+
+ return 0;
+}
+
+/*
+ * pass4.c -- pass #4 of e2fsck: Check reference counts
+ *
+ * Pass 4 frees the following data structures:
+ * - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
+ */
+
+/*
+ * This routine is called when an inode is not connected to the
+ * directory tree.
+ *
+ * This subroutine returns 1 then the caller shouldn't bother with the
+ * rest of the pass 4 tests.
+ */
+static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i)
+{
+ ext2_filsys fs = ctx->fs;
+ struct ext2_inode inode;
+ struct problem_context pctx;
+
+ e2fsck_read_inode(ctx, i, &inode, "pass4: disconnect_inode");
+ clear_problem_context(&pctx);
+ pctx.ino = i;
+ pctx.inode = &inode;
+
+ /*
+ * Offer to delete any zero-length files that does not have
+ * blocks. If there is an EA block, it might have useful
+ * information, so we won't prompt to delete it, but let it be
+ * reconnected to lost+found.
+ */
+ if (!inode.i_blocks && (LINUX_S_ISREG(inode.i_mode) ||
+ LINUX_S_ISDIR(inode.i_mode))) {
+ if (fix_problem(ctx, PR_4_ZERO_LEN_INODE, &pctx)) {
+ ext2fs_icount_store(ctx->inode_link_info, i, 0);
+ inode.i_links_count = 0;
+ inode.i_dtime = time(0);
+ e2fsck_write_inode(ctx, i, &inode,
+ "disconnect_inode");
+ /*
+ * Fix up the bitmaps...
+ */
+ e2fsck_read_bitmaps(ctx);
+ ext2fs_unmark_inode_bitmap(ctx->inode_used_map, i);
+ ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, i);
+ ext2fs_inode_alloc_stats2(fs, i, -1,
+ LINUX_S_ISDIR(inode.i_mode));
+ return 0;
+ }
+ }
+
+ /*
+ * Prompt to reconnect.
+ */
+ if (fix_problem(ctx, PR_4_UNATTACHED_INODE, &pctx)) {
+ if (e2fsck_reconnect_file(ctx, i))
+ ext2fs_unmark_valid(fs);
+ } else {
+ /*
+ * If we don't attach the inode, then skip the
+ * i_links_test since there's no point in trying to
+ * force i_links_count to zero.
+ */
+ ext2fs_unmark_valid(fs);
+ return 1;
+ }
+ return 0;
+}
+
+
+static void e2fsck_pass4(e2fsck_t ctx)
+{
+ ext2_filsys fs = ctx->fs;
+ ext2_ino_t i;
+ struct ext2_inode inode;
+ struct problem_context pctx;
+ __u16 link_count, link_counted;
+ char *buf = 0;
+ int group, maxgroup;
+
+ /* Pass 4 */
+
+ clear_problem_context(&pctx);
+
+ if (!(ctx->options & E2F_OPT_PREEN))
+ fix_problem(ctx, PR_4_PASS_HEADER, &pctx);
+
+ group = 0;
+ maxgroup = fs->group_desc_count;
+ if (ctx->progress)
+ if ((ctx->progress)(ctx, 4, 0, maxgroup))
+ return;
+
+ for (i=1; i <= fs->super->s_inodes_count; i++) {
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ return;
+ if ((i % fs->super->s_inodes_per_group) == 0) {
+ group++;
+ if (ctx->progress)
+ if ((ctx->progress)(ctx, 4, group, maxgroup))
+ return;
+ }
+ if (i == EXT2_BAD_INO ||
+ (i > EXT2_ROOT_INO && i < EXT2_FIRST_INODE(fs->super)))
+ continue;
+ if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, i)) ||
+ (ctx->inode_imagic_map &&
+ ext2fs_test_inode_bitmap(ctx->inode_imagic_map, i)))
+ continue;
+ ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count);
+ ext2fs_icount_fetch(ctx->inode_count, i, &link_counted);
+ if (link_counted == 0) {
+ if (!buf)
+ buf = e2fsck_allocate_memory(ctx,
+ fs->blocksize, "bad_inode buffer");
+ if (e2fsck_process_bad_inode(ctx, 0, i, buf))
+ continue;
+ if (disconnect_inode(ctx, i))
+ continue;
+ ext2fs_icount_fetch(ctx->inode_link_info, i,
+ &link_count);
+ ext2fs_icount_fetch(ctx->inode_count, i,
+ &link_counted);
+ }
+ if (link_counted != link_count) {
+ e2fsck_read_inode(ctx, i, &inode, "pass4");
+ pctx.ino = i;
+ pctx.inode = &inode;
+ if (link_count != inode.i_links_count) {
+ pctx.num = link_count;
+ fix_problem(ctx,
+ PR_4_INCONSISTENT_COUNT, &pctx);
+ }
+ pctx.num = link_counted;
+ if (fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx)) {
+ inode.i_links_count = link_counted;
+ e2fsck_write_inode(ctx, i, &inode, "pass4");
+ }
+ }
+ }
+ ext2fs_free_icount(ctx->inode_link_info); ctx->inode_link_info = 0;
+ ext2fs_free_icount(ctx->inode_count); ctx->inode_count = 0;
+ ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
+ ctx->inode_imagic_map = 0;
+ ext2fs_free_mem(&buf);
+}
+
+/*
+ * pass5.c --- check block and inode bitmaps against on-disk bitmaps
+ */
+
+#define NO_BLK ((blk_t) -1)
+
+static void print_bitmap_problem(e2fsck_t ctx, int problem,
+ struct problem_context *pctx)
+{
+ switch (problem) {
+ case PR_5_BLOCK_UNUSED:
+ if (pctx->blk == pctx->blk2)
+ pctx->blk2 = 0;
+ else
+ problem = PR_5_BLOCK_RANGE_UNUSED;
+ break;
+ case PR_5_BLOCK_USED:
+ if (pctx->blk == pctx->blk2)
+ pctx->blk2 = 0;
+ else
+ problem = PR_5_BLOCK_RANGE_USED;
+ break;
+ case PR_5_INODE_UNUSED:
+ if (pctx->ino == pctx->ino2)
+ pctx->ino2 = 0;
+ else
+ problem = PR_5_INODE_RANGE_UNUSED;
+ break;
+ case PR_5_INODE_USED:
+ if (pctx->ino == pctx->ino2)
+ pctx->ino2 = 0;
+ else
+ problem = PR_5_INODE_RANGE_USED;
+ break;
+ }
+ fix_problem(ctx, problem, pctx);
+ pctx->blk = pctx->blk2 = NO_BLK;
+ pctx->ino = pctx->ino2 = 0;
+}
+
+static void check_block_bitmaps(e2fsck_t ctx)
+{
+ ext2_filsys fs = ctx->fs;
+ blk_t i;
+ int *free_array;
+ int group = 0;
+ unsigned int blocks = 0;
+ unsigned int free_blocks = 0;
+ int group_free = 0;
+ int actual, bitmap;
+ struct problem_context pctx;
+ int problem, save_problem, fixit, had_problem;
+ errcode_t retval;
+
+ clear_problem_context(&pctx);
+ free_array = (int *) e2fsck_allocate_memory(ctx,
+ fs->group_desc_count * sizeof(int), "free block count array");
+
+ if ((fs->super->s_first_data_block <
+ ext2fs_get_block_bitmap_start(ctx->block_found_map)) ||
+ (fs->super->s_blocks_count-1 >
+ ext2fs_get_block_bitmap_end(ctx->block_found_map))) {
+ pctx.num = 1;
+ pctx.blk = fs->super->s_first_data_block;
+ pctx.blk2 = fs->super->s_blocks_count -1;
+ pctx.ino = ext2fs_get_block_bitmap_start(ctx->block_found_map);
+ pctx.ino2 = ext2fs_get_block_bitmap_end(ctx->block_found_map);
+ fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
+
+ ctx->flags |= E2F_FLAG_ABORT; /* fatal */
+ return;
+ }
+
+ if ((fs->super->s_first_data_block <
+ ext2fs_get_block_bitmap_start(fs->block_map)) ||
+ (fs->super->s_blocks_count-1 >
+ ext2fs_get_block_bitmap_end(fs->block_map))) {
+ pctx.num = 2;
+ pctx.blk = fs->super->s_first_data_block;
+ pctx.blk2 = fs->super->s_blocks_count -1;
+ pctx.ino = ext2fs_get_block_bitmap_start(fs->block_map);
+ pctx.ino2 = ext2fs_get_block_bitmap_end(fs->block_map);
+ fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
+
+ ctx->flags |= E2F_FLAG_ABORT; /* fatal */
+ return;
+ }
+
+redo_counts:
+ had_problem = 0;
+ save_problem = 0;
+ pctx.blk = pctx.blk2 = NO_BLK;
+ for (i = fs->super->s_first_data_block;
+ i < fs->super->s_blocks_count;
+ i++) {
+ actual = ext2fs_fast_test_block_bitmap(ctx->block_found_map, i);
+ bitmap = ext2fs_fast_test_block_bitmap(fs->block_map, i);
+
+ if (actual == bitmap)
+ goto do_counts;
+
+ if (!actual && bitmap) {
+ /*
+ * Block not used, but marked in use in the bitmap.
+ */
+ problem = PR_5_BLOCK_UNUSED;
+ } else {
+ /*
+ * Block used, but not marked in use in the bitmap.
+ */
+ problem = PR_5_BLOCK_USED;
+ }
+ if (pctx.blk == NO_BLK) {
+ pctx.blk = pctx.blk2 = i;
+ save_problem = problem;
+ } else {
+ if ((problem == save_problem) &&
+ (pctx.blk2 == i-1))
+ pctx.blk2++;
+ else {
+ print_bitmap_problem(ctx, save_problem, &pctx);
+ pctx.blk = pctx.blk2 = i;
+ save_problem = problem;
+ }
+ }
+ ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
+ had_problem++;
+
+ do_counts:
+ if (!bitmap) {
+ group_free++;
+ free_blocks++;
+ }
+ blocks ++;
+ if ((blocks == fs->super->s_blocks_per_group) ||
+ (i == fs->super->s_blocks_count-1)) {
+ free_array[group] = group_free;
+ group ++;
+ blocks = 0;
+ group_free = 0;
+ if (ctx->progress)
+ if ((ctx->progress)(ctx, 5, group,
+ fs->group_desc_count*2))
+ return;
+ }
+ }
+ if (pctx.blk != NO_BLK)
+ print_bitmap_problem(ctx, save_problem, &pctx);
+ if (had_problem)
+ fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP);
+ else
+ fixit = -1;
+ ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
+
+ if (fixit == 1) {
+ ext2fs_free_block_bitmap(fs->block_map);
+ retval = ext2fs_copy_bitmap(ctx->block_found_map,
+ &fs->block_map);
+ if (retval) {
+ clear_problem_context(&pctx);
+ fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ ext2fs_set_bitmap_padding(fs->block_map);
+ ext2fs_mark_bb_dirty(fs);
+
+ /* Redo the counts */
+ blocks = 0; free_blocks = 0; group_free = 0; group = 0;
+ memset(free_array, 0, fs->group_desc_count * sizeof(int));
+ goto redo_counts;
+ } else if (fixit == 0)
+ ext2fs_unmark_valid(fs);
+
+ for (i = 0; i < fs->group_desc_count; i++) {
+ if (free_array[i] != fs->group_desc[i].bg_free_blocks_count) {
+ pctx.group = i;
+ pctx.blk = fs->group_desc[i].bg_free_blocks_count;
+ pctx.blk2 = free_array[i];
+
+ if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
+ &pctx)) {
+ fs->group_desc[i].bg_free_blocks_count =
+ free_array[i];
+ ext2fs_mark_super_dirty(fs);
+ } else
+ ext2fs_unmark_valid(fs);
+ }
+ }
+ if (free_blocks != fs->super->s_free_blocks_count) {
+ pctx.group = 0;
+ pctx.blk = fs->super->s_free_blocks_count;
+ pctx.blk2 = free_blocks;
+
+ if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
+ fs->super->s_free_blocks_count = free_blocks;
+ ext2fs_mark_super_dirty(fs);
+ } else
+ ext2fs_unmark_valid(fs);
+ }
+ ext2fs_free_mem(&free_array);
+}
+
+static void check_inode_bitmaps(e2fsck_t ctx)
+{
+ ext2_filsys fs = ctx->fs;
+ ext2_ino_t i;
+ unsigned int free_inodes = 0;
+ int group_free = 0;
+ int dirs_count = 0;
+ int group = 0;
+ unsigned int inodes = 0;
+ int *free_array;
+ int *dir_array;
+ int actual, bitmap;
+ errcode_t retval;
+ struct problem_context pctx;
+ int problem, save_problem, fixit, had_problem;
+
+ clear_problem_context(&pctx);
+ free_array = (int *) e2fsck_allocate_memory(ctx,
+ fs->group_desc_count * sizeof(int), "free inode count array");
+
+ dir_array = (int *) e2fsck_allocate_memory(ctx,
+ fs->group_desc_count * sizeof(int), "directory count array");
+
+ if ((1 < ext2fs_get_inode_bitmap_start(ctx->inode_used_map)) ||
+ (fs->super->s_inodes_count >
+ ext2fs_get_inode_bitmap_end(ctx->inode_used_map))) {
+ pctx.num = 3;
+ pctx.blk = 1;
+ pctx.blk2 = fs->super->s_inodes_count;
+ pctx.ino = ext2fs_get_inode_bitmap_start(ctx->inode_used_map);
+ pctx.ino2 = ext2fs_get_inode_bitmap_end(ctx->inode_used_map);
+ fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
+
+ ctx->flags |= E2F_FLAG_ABORT; /* fatal */
+ return;
+ }
+ if ((1 < ext2fs_get_inode_bitmap_start(fs->inode_map)) ||
+ (fs->super->s_inodes_count >
+ ext2fs_get_inode_bitmap_end(fs->inode_map))) {
+ pctx.num = 4;
+ pctx.blk = 1;
+ pctx.blk2 = fs->super->s_inodes_count;
+ pctx.ino = ext2fs_get_inode_bitmap_start(fs->inode_map);
+ pctx.ino2 = ext2fs_get_inode_bitmap_end(fs->inode_map);
+ fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
+
+ ctx->flags |= E2F_FLAG_ABORT; /* fatal */
+ return;
+ }
+
+redo_counts:
+ had_problem = 0;
+ save_problem = 0;
+ pctx.ino = pctx.ino2 = 0;
+ for (i = 1; i <= fs->super->s_inodes_count; i++) {
+ actual = ext2fs_fast_test_inode_bitmap(ctx->inode_used_map, i);
+ bitmap = ext2fs_fast_test_inode_bitmap(fs->inode_map, i);
+
+ if (actual == bitmap)
+ goto do_counts;
+
+ if (!actual && bitmap) {
+ /*
+ * Inode wasn't used, but marked in bitmap
+ */
+ problem = PR_5_INODE_UNUSED;
+ } else /* if (actual && !bitmap) */ {
+ /*
+ * Inode used, but not in bitmap
+ */
+ problem = PR_5_INODE_USED;
+ }
+ if (pctx.ino == 0) {
+ pctx.ino = pctx.ino2 = i;
+ save_problem = problem;
+ } else {
+ if ((problem == save_problem) &&
+ (pctx.ino2 == i-1))
+ pctx.ino2++;
+ else {
+ print_bitmap_problem(ctx, save_problem, &pctx);
+ pctx.ino = pctx.ino2 = i;
+ save_problem = problem;
+ }
+ }
+ ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
+ had_problem++;
+
+do_counts:
+ if (!bitmap) {
+ group_free++;
+ free_inodes++;
+ } else {
+ if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, i))
+ dirs_count++;
+ }
+ inodes++;
+ if ((inodes == fs->super->s_inodes_per_group) ||
+ (i == fs->super->s_inodes_count)) {
+ free_array[group] = group_free;
+ dir_array[group] = dirs_count;
+ group ++;
+ inodes = 0;
+ group_free = 0;
+ dirs_count = 0;
+ if (ctx->progress)
+ if ((ctx->progress)(ctx, 5,
+ group + fs->group_desc_count,
+ fs->group_desc_count*2))
+ return;
+ }
+ }
+ if (pctx.ino)
+ print_bitmap_problem(ctx, save_problem, &pctx);
+
+ if (had_problem)
+ fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP);
+ else
+ fixit = -1;
+ ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
+
+ if (fixit == 1) {
+ ext2fs_free_inode_bitmap(fs->inode_map);
+ retval = ext2fs_copy_bitmap(ctx->inode_used_map,
+ &fs->inode_map);
+ if (retval) {
+ clear_problem_context(&pctx);
+ fix_problem(ctx, PR_5_COPY_IBITMAP_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ ext2fs_set_bitmap_padding(fs->inode_map);
+ ext2fs_mark_ib_dirty(fs);
+
+ /* redo counts */
+ inodes = 0; free_inodes = 0; group_free = 0;
+ dirs_count = 0; group = 0;
+ memset(free_array, 0, fs->group_desc_count * sizeof(int));
+ memset(dir_array, 0, fs->group_desc_count * sizeof(int));
+ goto redo_counts;
+ } else if (fixit == 0)
+ ext2fs_unmark_valid(fs);
+
+ for (i = 0; i < fs->group_desc_count; i++) {
+ if (free_array[i] != fs->group_desc[i].bg_free_inodes_count) {
+ pctx.group = i;
+ pctx.ino = fs->group_desc[i].bg_free_inodes_count;
+ pctx.ino2 = free_array[i];
+ if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP,
+ &pctx)) {
+ fs->group_desc[i].bg_free_inodes_count =
+ free_array[i];
+ ext2fs_mark_super_dirty(fs);
+ } else
+ ext2fs_unmark_valid(fs);
+ }
+ if (dir_array[i] != fs->group_desc[i].bg_used_dirs_count) {
+ pctx.group = i;
+ pctx.ino = fs->group_desc[i].bg_used_dirs_count;
+ pctx.ino2 = dir_array[i];
+
+ if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP,
+ &pctx)) {
+ fs->group_desc[i].bg_used_dirs_count =
+ dir_array[i];
+ ext2fs_mark_super_dirty(fs);
+ } else
+ ext2fs_unmark_valid(fs);
+ }
+ }
+ if (free_inodes != fs->super->s_free_inodes_count) {
+ pctx.group = -1;
+ pctx.ino = fs->super->s_free_inodes_count;
+ pctx.ino2 = free_inodes;
+
+ if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) {
+ fs->super->s_free_inodes_count = free_inodes;
+ ext2fs_mark_super_dirty(fs);
+ } else
+ ext2fs_unmark_valid(fs);
+ }
+ ext2fs_free_mem(&free_array);
+ ext2fs_free_mem(&dir_array);
+}
+
+static void check_inode_end(e2fsck_t ctx)
+{
+ ext2_filsys fs = ctx->fs;
+ ext2_ino_t end, save_inodes_count, i;
+ struct problem_context pctx;
+
+ clear_problem_context(&pctx);
+
+ end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
+ pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end,
+ &save_inodes_count);
+ if (pctx.errcode) {
+ pctx.num = 1;
+ fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT; /* fatal */
+ return;
+ }
+ if (save_inodes_count == end)
+ return;
+
+ for (i = save_inodes_count + 1; i <= end; i++) {
+ if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) {
+ if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) {
+ for (i = save_inodes_count + 1; i <= end; i++)
+ ext2fs_mark_inode_bitmap(fs->inode_map,
+ i);
+ ext2fs_mark_ib_dirty(fs);
+ } else
+ ext2fs_unmark_valid(fs);
+ break;
+ }
+ }
+
+ pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map,
+ save_inodes_count, 0);
+ if (pctx.errcode) {
+ pctx.num = 2;
+ fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT; /* fatal */
+ return;
+ }
+}
+
+static void check_block_end(e2fsck_t ctx)
+{
+ ext2_filsys fs = ctx->fs;
+ blk_t end, save_blocks_count, i;
+ struct problem_context pctx;
+
+ clear_problem_context(&pctx);
+
+ end = fs->block_map->start +
+ (EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count) - 1;
+ pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, end,
+ &save_blocks_count);
+ if (pctx.errcode) {
+ pctx.num = 3;
+ fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT; /* fatal */
+ return;
+ }
+ if (save_blocks_count == end)
+ return;
+
+ for (i = save_blocks_count + 1; i <= end; i++) {
+ if (!ext2fs_test_block_bitmap(fs->block_map, i)) {
+ if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) {
+ for (i = save_blocks_count + 1; i <= end; i++)
+ ext2fs_mark_block_bitmap(fs->block_map,
+ i);
+ ext2fs_mark_bb_dirty(fs);
+ } else
+ ext2fs_unmark_valid(fs);
+ break;
+ }
+ }
+
+ pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map,
+ save_blocks_count, 0);
+ if (pctx.errcode) {
+ pctx.num = 4;
+ fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT; /* fatal */
+ return;
+ }
+}
+
+static void e2fsck_pass5(e2fsck_t ctx)
+{
+ struct problem_context pctx;
+
+ /* Pass 5 */
+
+ clear_problem_context(&pctx);
+
+ if (!(ctx->options & E2F_OPT_PREEN))
+ fix_problem(ctx, PR_5_PASS_HEADER, &pctx);
+
+ if (ctx->progress)
+ if ((ctx->progress)(ctx, 5, 0, ctx->fs->group_desc_count*2))
+ return;
+
+ e2fsck_read_bitmaps(ctx);
+
+ check_block_bitmaps(ctx);
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ return;
+ check_inode_bitmaps(ctx);
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ return;
+ check_inode_end(ctx);
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ return;
+ check_block_end(ctx);
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ return;
+
+ ext2fs_free_inode_bitmap(ctx->inode_used_map);
+ ctx->inode_used_map = 0;
+ ext2fs_free_inode_bitmap(ctx->inode_dir_map);
+ ctx->inode_dir_map = 0;
+ ext2fs_free_block_bitmap(ctx->block_found_map);
+ ctx->block_found_map = 0;
+}
+
+/*
+ * problem.c --- report filesystem problems to the user
+ */
+
+#define PR_PREEN_OK 0x000001 /* Don't need to do preenhalt */
+#define PR_NO_OK 0x000002 /* If user answers no, don't make fs invalid */
+#define PR_NO_DEFAULT 0x000004 /* Default to no */
+#define PR_MSG_ONLY 0x000008 /* Print message only */
+
+/* Bit positions 0x000ff0 are reserved for the PR_LATCH flags */
+
+#define PR_FATAL 0x001000 /* Fatal error */
+#define PR_AFTER_CODE 0x002000 /* After asking the first question, */
+ /* ask another */
+#define PR_PREEN_NOMSG 0x004000 /* Don't print a message if we're preening */
+#define PR_NOCOLLATE 0x008000 /* Don't collate answers for this latch */
+#define PR_NO_NOMSG 0x010000 /* Don't print a message if e2fsck -n */
+#define PR_PREEN_NO 0x020000 /* Use No as an answer if preening */
+#define PR_PREEN_NOHDR 0x040000 /* Don't print the preen header */
+
+
+#define PROMPT_NONE 0
+#define PROMPT_FIX 1
+#define PROMPT_CLEAR 2
+#define PROMPT_RELOCATE 3
+#define PROMPT_ALLOCATE 4
+#define PROMPT_EXPAND 5
+#define PROMPT_CONNECT 6
+#define PROMPT_CREATE 7
+#define PROMPT_SALVAGE 8
+#define PROMPT_TRUNCATE 9
+#define PROMPT_CLEAR_INODE 10
+#define PROMPT_ABORT 11
+#define PROMPT_SPLIT 12
+#define PROMPT_CONTINUE 13
+#define PROMPT_CLONE 14
+#define PROMPT_DELETE 15
+#define PROMPT_SUPPRESS 16
+#define PROMPT_UNLINK 17
+#define PROMPT_CLEAR_HTREE 18
+#define PROMPT_RECREATE 19
+#define PROMPT_NULL 20
+
+struct e2fsck_problem {
+ problem_t e2p_code;
+ const char * e2p_description;
+ char prompt;
+ int flags;
+ problem_t second_code;
+};
+
+struct latch_descr {
+ int latch_code;
+ problem_t question;
+ problem_t end_message;
+ int flags;
+};
+
+/*
+ * These are the prompts which are used to ask the user if they want
+ * to fix a problem.
+ */
+static const char *const prompt[] = {
+ N_("(no prompt)"), /* 0 */
+ N_("Fix"), /* 1 */
+ N_("Clear"), /* 2 */
+ N_("Relocate"), /* 3 */
+ N_("Allocate"), /* 4 */
+ N_("Expand"), /* 5 */
+ N_("Connect to /lost+found"), /* 6 */
+ N_("Create"), /* 7 */
+ N_("Salvage"), /* 8 */
+ N_("Truncate"), /* 9 */
+ N_("Clear inode"), /* 10 */
+ N_("Abort"), /* 11 */
+ N_("Split"), /* 12 */
+ N_("Continue"), /* 13 */
+ N_("Clone multiply-claimed blocks"), /* 14 */
+ N_("Delete file"), /* 15 */
+ N_("Suppress messages"),/* 16 */
+ N_("Unlink"), /* 17 */
+ N_("Clear HTree index"),/* 18 */
+ N_("Recreate"), /* 19 */
+ "", /* 20 */
+};
+
+/*
+ * These messages are printed when we are preen mode and we will be
+ * automatically fixing the problem.
+ */
+static const char *const preen_msg[] = {
+ N_("(NONE)"), /* 0 */
+ N_("FIXED"), /* 1 */
+ N_("CLEARED"), /* 2 */
+ N_("RELOCATED"), /* 3 */
+ N_("ALLOCATED"), /* 4 */
+ N_("EXPANDED"), /* 5 */
+ N_("RECONNECTED"), /* 6 */
+ N_("CREATED"), /* 7 */
+ N_("SALVAGED"), /* 8 */
+ N_("TRUNCATED"), /* 9 */
+ N_("INODE CLEARED"), /* 10 */
+ N_("ABORTED"), /* 11 */
+ N_("SPLIT"), /* 12 */
+ N_("CONTINUING"), /* 13 */
+ N_("MULTIPLY-CLAIMED BLOCKS CLONED"), /* 14 */
+ N_("FILE DELETED"), /* 15 */
+ N_("SUPPRESSED"), /* 16 */
+ N_("UNLINKED"), /* 17 */
+ N_("HTREE INDEX CLEARED"),/* 18 */
+ N_("WILL RECREATE"), /* 19 */
+ "", /* 20 */
+};
+
+static const struct e2fsck_problem problem_table[] = {
+
+ /* Pre-Pass 1 errors */
+
+ /* Block bitmap not in group */
+ { PR_0_BB_NOT_GROUP, N_("@b @B for @g %g is not in @g. (@b %b)\n"),
+ PROMPT_RELOCATE, PR_LATCH_RELOC },
+
+ /* Inode bitmap not in group */
+ { PR_0_IB_NOT_GROUP, N_("@i @B for @g %g is not in @g. (@b %b)\n"),
+ PROMPT_RELOCATE, PR_LATCH_RELOC },
+
+ /* Inode table not in group */
+ { PR_0_ITABLE_NOT_GROUP,
+ N_("@i table for @g %g is not in @g. (@b %b)\n"
+ "WARNING: SEVERE DATA LOSS POSSIBLE.\n"),
+ PROMPT_RELOCATE, PR_LATCH_RELOC },
+
+ /* Superblock corrupt */
+ { PR_0_SB_CORRUPT,
+ N_("\nThe @S could not be read or does not describe a correct ext2\n"
+ "@f. If the @v is valid and it really contains an ext2\n"
+ "@f (and not swap or ufs or something else), then the @S\n"
+ "is corrupt, and you might try running e2fsck with an alternate @S:\n"
+ " e2fsck -b %S <@v>\n\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Filesystem size is wrong */
+ { PR_0_FS_SIZE_WRONG,
+ N_("The @f size (according to the @S) is %b @bs\n"
+ "The physical size of the @v is %c @bs\n"
+ "Either the @S or the partition table is likely to be corrupt!\n"),
+ PROMPT_ABORT, 0 },
+
+ /* Fragments not supported */
+ { PR_0_NO_FRAGMENTS,
+ N_("@S @b_size = %b, fragsize = %c.\n"
+ "This version of e2fsck does not support fragment sizes different\n"
+ "from the @b size.\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Bad blocks_per_group */
+ { PR_0_BLOCKS_PER_GROUP,
+ N_("@S @bs_per_group = %b, should have been %c\n"),
+ PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
+
+ /* Bad first_data_block */
+ { PR_0_FIRST_DATA_BLOCK,
+ N_("@S first_data_@b = %b, should have been %c\n"),
+ PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
+
+ /* Adding UUID to filesystem */
+ { PR_0_ADD_UUID,
+ N_("@f did not have a UUID; generating one.\n\n"),
+ PROMPT_NONE, 0 },
+
+ /* Relocate hint */
+ { PR_0_RELOCATE_HINT,
+ N_("Note: if several inode or block bitmap blocks or part\n"
+ "of the inode table require relocation, you may wish to try\n"
+ "running e2fsck with the '-b %S' option first. The problem\n"
+ "may lie only with the primary block group descriptors, and\n"
+ "the backup block group descriptors may be OK.\n\n"),
+ PROMPT_NONE, PR_PREEN_OK | PR_NOCOLLATE },
+
+ /* Miscellaneous superblock corruption */
+ { PR_0_MISC_CORRUPT_SUPER,
+ N_("Corruption found in @S. (%s = %N).\n"),
+ PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
+
+ /* Error determing physical device size of filesystem */
+ { PR_0_GETSIZE_ERROR,
+ N_("Error determining size of the physical @v: %m\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Inode count in superblock is incorrect */
+ { PR_0_INODE_COUNT_WRONG,
+ N_("@i count in @S is %i, @s %j.\n"),
+ PROMPT_FIX, 0 },
+
+ { PR_0_HURD_CLEAR_FILETYPE,
+ N_("The Hurd does not support the filetype feature.\n"),
+ PROMPT_CLEAR, 0 },
+
+ /* Journal inode is invalid */
+ { PR_0_JOURNAL_BAD_INODE,
+ N_("@S has an @n ext3 @j (@i %i).\n"),
+ PROMPT_CLEAR, PR_PREEN_OK },
+
+ /* The external journal has (unsupported) multiple filesystems */
+ { PR_0_JOURNAL_UNSUPP_MULTIFS,
+ N_("External @j has multiple @f users (unsupported).\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Can't find external journal */
+ { PR_0_CANT_FIND_JOURNAL,
+ N_("Can't find external @j\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* External journal has bad superblock */
+ { PR_0_EXT_JOURNAL_BAD_SUPER,
+ N_("External @j has bad @S\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Superblock has a bad journal UUID */
+ { PR_0_JOURNAL_BAD_UUID,
+ N_("External @j does not support this @f\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Journal has an unknown superblock type */
+ { PR_0_JOURNAL_UNSUPP_SUPER,
+ N_("Ext3 @j @S is unknown type %N (unsupported).\n"
+ "It is likely that your copy of e2fsck is old and/or doesn't "
+ "support this @j format.\n"
+ "It is also possible the @j @S is corrupt.\n"),
+ PROMPT_ABORT, PR_NO_OK | PR_AFTER_CODE, PR_0_JOURNAL_BAD_SUPER },
+
+ /* Journal superblock is corrupt */
+ { PR_0_JOURNAL_BAD_SUPER,
+ N_("Ext3 @j @S is corrupt.\n"),
+ PROMPT_FIX, PR_PREEN_OK },
+
+ /* Superblock flag should be cleared */
+ { PR_0_JOURNAL_HAS_JOURNAL,
+ N_("@S doesn't have has_@j flag, but has ext3 @j %s.\n"),
+ PROMPT_CLEAR, PR_PREEN_OK },
+
+ /* Superblock flag is incorrect */
+ { PR_0_JOURNAL_RECOVER_SET,
+ N_("@S has ext3 needs_recovery flag set, but no @j.\n"),
+ PROMPT_CLEAR, PR_PREEN_OK },
+
+ /* Journal has data, but recovery flag is clear */
+ { PR_0_JOURNAL_RECOVERY_CLEAR,
+ N_("ext3 recovery flag is clear, but @j has data.\n"),
+ PROMPT_NONE, 0 },
+
+ /* Ask if we should clear the journal */
+ { PR_0_JOURNAL_RESET_JOURNAL,
+ N_("Clear @j"),
+ PROMPT_NULL, PR_PREEN_NOMSG },
+
+ /* Ask if we should run the journal anyway */
+ { PR_0_JOURNAL_RUN,
+ N_("Run @j anyway"),
+ PROMPT_NULL, 0 },
+
+ /* Run the journal by default */
+ { PR_0_JOURNAL_RUN_DEFAULT,
+ N_("Recovery flag not set in backup @S, so running @j anyway.\n"),
+ PROMPT_NONE, 0 },
+
+ /* Clearing orphan inode */
+ { PR_0_ORPHAN_CLEAR_INODE,
+ N_("%s @o @i %i (uid=%Iu, gid=%Ig, mode=%Im, size=%Is)\n"),
+ PROMPT_NONE, 0 },
+
+ /* Illegal block found in orphaned inode */
+ { PR_0_ORPHAN_ILLEGAL_BLOCK_NUM,
+ N_("@I @b #%B (%b) found in @o @i %i.\n"),
+ PROMPT_NONE, 0 },
+
+ /* Already cleared block found in orphaned inode */
+ { PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
+ N_("Already cleared @b #%B (%b) found in @o @i %i.\n"),
+ PROMPT_NONE, 0 },
+
+ /* Illegal orphan inode in superblock */
+ { PR_0_ORPHAN_ILLEGAL_HEAD_INODE,
+ N_("@I @o @i %i in @S.\n"),
+ PROMPT_NONE, 0 },
+
+ /* Illegal inode in orphaned inode list */
+ { PR_0_ORPHAN_ILLEGAL_INODE,
+ N_("@I @i %i in @o @i list.\n"),
+ PROMPT_NONE, 0 },
+
+ /* Filesystem revision is 0, but feature flags are set */
+ { PR_0_FS_REV_LEVEL,
+ N_("@f has feature flag(s) set, but is a revision 0 @f. "),
+ PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
+
+ /* Journal superblock has an unknown read-only feature flag set */
+ { PR_0_JOURNAL_UNSUPP_ROCOMPAT,
+ N_("Ext3 @j @S has an unknown read-only feature flag set.\n"),
+ PROMPT_ABORT, 0 },
+
+ /* Journal superblock has an unknown incompatible feature flag set */
+ { PR_0_JOURNAL_UNSUPP_INCOMPAT,
+ N_("Ext3 @j @S has an unknown incompatible feature flag set.\n"),
+ PROMPT_ABORT, 0 },
+
+ /* Journal has unsupported version number */
+ { PR_0_JOURNAL_UNSUPP_VERSION,
+ N_("@j version not supported by this e2fsck.\n"),
+ PROMPT_ABORT, 0 },
+
+ /* Moving journal to hidden file */
+ { PR_0_MOVE_JOURNAL,
+ N_("Moving @j from /%s to hidden @i.\n\n"),
+ PROMPT_NONE, 0 },
+
+ /* Error moving journal to hidden file */
+ { PR_0_ERR_MOVE_JOURNAL,
+ N_("Error moving @j: %m\n\n"),
+ PROMPT_NONE, 0 },
+
+ /* Clearing V2 journal superblock */
+ { PR_0_CLEAR_V2_JOURNAL,
+ N_("Found @n V2 @j @S fields (from V1 @j).\n"
+ "Clearing fields beyond the V1 @j @S...\n\n"),
+ PROMPT_NONE, 0 },
+
+ /* Backup journal inode blocks */
+ { PR_0_BACKUP_JNL,
+ N_("Backing up @j @i @b information.\n\n"),
+ PROMPT_NONE, 0 },
+
+ /* Reserved blocks w/o resize_inode */
+ { PR_0_NONZERO_RESERVED_GDT_BLOCKS,
+ N_("@f does not have resize_@i enabled, but s_reserved_gdt_@bs\n"
+ "is %N; @s zero. "),
+ PROMPT_FIX, 0 },
+
+ /* Resize_inode not enabled, but resize inode is non-zero */
+ { PR_0_CLEAR_RESIZE_INODE,
+ N_("Resize_@i not enabled, but the resize @i is non-zero. "),
+ PROMPT_CLEAR, 0 },
+
+ /* Resize inode invalid */
+ { PR_0_RESIZE_INODE_INVALID,
+ N_("Resize @i not valid. "),
+ PROMPT_RECREATE, 0 },
+
+ /* Pass 1 errors */
+
+ /* Pass 1: Checking inodes, blocks, and sizes */
+ { PR_1_PASS_HEADER,
+ N_("Pass 1: Checking @is, @bs, and sizes\n"),
+ PROMPT_NONE, 0 },
+
+ /* Root directory is not an inode */
+ { PR_1_ROOT_NO_DIR, N_("@r is not a @d. "),
+ PROMPT_CLEAR, 0 },
+
+ /* Root directory has dtime set */
+ { PR_1_ROOT_DTIME,
+ N_("@r has dtime set (probably due to old mke2fs). "),
+ PROMPT_FIX, PR_PREEN_OK },
+
+ /* Reserved inode has bad mode */
+ { PR_1_RESERVED_BAD_MODE,
+ N_("Reserved @i %i (%Q) has @n mode. "),
+ PROMPT_CLEAR, PR_PREEN_OK },
+
+ /* Deleted inode has zero dtime */
+ { PR_1_ZERO_DTIME,
+ N_("@D @i %i has zero dtime. "),
+ PROMPT_FIX, PR_PREEN_OK },
+
+ /* Inode in use, but dtime set */
+ { PR_1_SET_DTIME,
+ N_("@i %i is in use, but has dtime set. "),
+ PROMPT_FIX, PR_PREEN_OK },
+
+ /* Zero-length directory */
+ { PR_1_ZERO_LENGTH_DIR,
+ N_("@i %i is a @z @d. "),
+ PROMPT_CLEAR, PR_PREEN_OK },
+
+ /* Block bitmap conflicts with some other fs block */
+ { PR_1_BB_CONFLICT,
+ N_("@g %g's @b @B at %b @C.\n"),
+ PROMPT_RELOCATE, 0 },
+
+ /* Inode bitmap conflicts with some other fs block */
+ { PR_1_IB_CONFLICT,
+ N_("@g %g's @i @B at %b @C.\n"),
+ PROMPT_RELOCATE, 0 },
+
+ /* Inode table conflicts with some other fs block */
+ { PR_1_ITABLE_CONFLICT,
+ N_("@g %g's @i table at %b @C.\n"),
+ PROMPT_RELOCATE, 0 },
+
+ /* Block bitmap is on a bad block */
+ { PR_1_BB_BAD_BLOCK,
+ N_("@g %g's @b @B (%b) is bad. "),
+ PROMPT_RELOCATE, 0 },
+
+ /* Inode bitmap is on a bad block */
+ { PR_1_IB_BAD_BLOCK,
+ N_("@g %g's @i @B (%b) is bad. "),
+ PROMPT_RELOCATE, 0 },
+
+ /* Inode has incorrect i_size */
+ { PR_1_BAD_I_SIZE,
+ N_("@i %i, i_size is %Is, @s %N. "),
+ PROMPT_FIX, PR_PREEN_OK },
+
+ /* Inode has incorrect i_blocks */
+ { PR_1_BAD_I_BLOCKS,
+ N_("@i %i, i_@bs is %Ib, @s %N. "),
+ PROMPT_FIX, PR_PREEN_OK },
+
+ /* Illegal blocknumber in inode */
+ { PR_1_ILLEGAL_BLOCK_NUM,
+ N_("@I @b #%B (%b) in @i %i. "),
+ PROMPT_CLEAR, PR_LATCH_BLOCK },
+
+ /* Block number overlaps fs metadata */
+ { PR_1_BLOCK_OVERLAPS_METADATA,
+ N_("@b #%B (%b) overlaps @f metadata in @i %i. "),
+ PROMPT_CLEAR, PR_LATCH_BLOCK },
+
+ /* Inode has illegal blocks (latch question) */
+ { PR_1_INODE_BLOCK_LATCH,
+ N_("@i %i has illegal @b(s). "),
+ PROMPT_CLEAR, 0 },
+
+ /* Too many bad blocks in inode */
+ { PR_1_TOO_MANY_BAD_BLOCKS,
+ N_("Too many illegal @bs in @i %i.\n"),
+ PROMPT_CLEAR_INODE, PR_NO_OK },
+
+ /* Illegal block number in bad block inode */
+ { PR_1_BB_ILLEGAL_BLOCK_NUM,
+ N_("@I @b #%B (%b) in bad @b @i. "),
+ PROMPT_CLEAR, PR_LATCH_BBLOCK },
+
+ /* Bad block inode has illegal blocks (latch question) */
+ { PR_1_INODE_BBLOCK_LATCH,
+ N_("Bad @b @i has illegal @b(s). "),
+ PROMPT_CLEAR, 0 },
+
+ /* Duplicate or bad blocks in use! */
+ { PR_1_DUP_BLOCKS_PREENSTOP,
+ N_("Duplicate or bad @b in use!\n"),
+ PROMPT_NONE, 0 },
+
+ /* Bad block used as bad block indirect block */
+ { PR_1_BBINODE_BAD_METABLOCK,
+ N_("Bad @b %b used as bad @b @i indirect @b. "),
+ PROMPT_CLEAR, PR_LATCH_BBLOCK },
+
+ /* Inconsistency can't be fixed prompt */
+ { PR_1_BBINODE_BAD_METABLOCK_PROMPT,
+ N_("\nThe bad @b @i has probably been corrupted. You probably\n"
+ "should stop now and run ""e2fsck -c"" to scan for bad blocks\n"
+ "in the @f.\n"),
+ PROMPT_CONTINUE, PR_PREEN_NOMSG },
+
+ /* Bad primary block */
+ { PR_1_BAD_PRIMARY_BLOCK,
+ N_("\nIf the @b is really bad, the @f cannot be fixed.\n"),
+ PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK_PROMPT },
+
+ /* Bad primary block prompt */
+ { PR_1_BAD_PRIMARY_BLOCK_PROMPT,
+ N_("You can remove this @b from the bad @b list and hope\n"
+ "that the @b is really OK. But there are no guarantees.\n\n"),
+ PROMPT_CLEAR, PR_PREEN_NOMSG },
+
+ /* Bad primary superblock */
+ { PR_1_BAD_PRIMARY_SUPERBLOCK,
+ N_("The primary @S (%b) is on the bad @b list.\n"),
+ PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
+
+ /* Bad primary block group descriptors */
+ { PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR,
+ N_("Block %b in the primary @g descriptors "
+ "is on the bad @b list\n"),
+ PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
+
+ /* Bad superblock in group */
+ { PR_1_BAD_SUPERBLOCK,
+ N_("Warning: Group %g's @S (%b) is bad.\n"),
+ PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
+
+ /* Bad block group descriptors in group */
+ { PR_1_BAD_GROUP_DESCRIPTORS,
+ N_("Warning: Group %g's copy of the @g descriptors has a bad "
+ "@b (%b).\n"),
+ PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
+
+ /* Block claimed for no reason */
+ { PR_1_PROGERR_CLAIMED_BLOCK,
+ N_("Programming error? @b #%b claimed for no reason in "
+ "process_bad_@b.\n"),
+ PROMPT_NONE, PR_PREEN_OK },
+
+ /* Error allocating blocks for relocating metadata */
+ { PR_1_RELOC_BLOCK_ALLOCATE,
+ N_("@A %N contiguous @b(s) in @b @g %g for %s: %m\n"),
+ PROMPT_NONE, PR_PREEN_OK },
+
+ /* Error allocating block buffer during relocation process */
+ { PR_1_RELOC_MEMORY_ALLOCATE,
+ N_("@A @b buffer for relocating %s\n"),
+ PROMPT_NONE, PR_PREEN_OK },
+
+ /* Relocating metadata group information from X to Y */
+ { PR_1_RELOC_FROM_TO,
+ N_("Relocating @g %g's %s from %b to %c...\n"),
+ PROMPT_NONE, PR_PREEN_OK },
+
+ /* Relocating metatdata group information to X */
+ { PR_1_RELOC_TO,
+ N_("Relocating @g %g's %s to %c...\n"), /* xgettext:no-c-format */
+ PROMPT_NONE, PR_PREEN_OK },
+
+ /* Block read error during relocation process */
+ { PR_1_RELOC_READ_ERR,
+ N_("Warning: could not read @b %b of %s: %m\n"),
+ PROMPT_NONE, PR_PREEN_OK },
+
+ /* Block write error during relocation process */
+ { PR_1_RELOC_WRITE_ERR,
+ N_("Warning: could not write @b %b for %s: %m\n"),
+ PROMPT_NONE, PR_PREEN_OK },
+
+ /* Error allocating inode bitmap */
+ { PR_1_ALLOCATE_IBITMAP_ERROR,
+ N_("@A @i @B (%N): %m\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Error allocating block bitmap */
+ { PR_1_ALLOCATE_BBITMAP_ERROR,
+ N_("@A @b @B (%N): %m\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Error allocating icount structure */
+ { PR_1_ALLOCATE_ICOUNT,
+ N_("@A icount link information: %m\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Error allocating dbcount */
+ { PR_1_ALLOCATE_DBCOUNT,
+ N_("@A @d @b array: %m\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Error while scanning inodes */
+ { PR_1_ISCAN_ERROR,
+ N_("Error while scanning @is (%i): %m\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Error while iterating over blocks */
+ { PR_1_BLOCK_ITERATE,
+ N_("Error while iterating over @bs in @i %i: %m\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Error while storing inode count information */
+ { PR_1_ICOUNT_STORE,
+ N_("Error storing @i count information (@i=%i, count=%N): %m\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Error while storing directory block information */
+ { PR_1_ADD_DBLOCK,
+ N_("Error storing @d @b information "
+ "(@i=%i, @b=%b, num=%N): %m\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Error while reading inode (for clearing) */
+ { PR_1_READ_INODE,
+ N_("Error reading @i %i: %m\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Suppress messages prompt */
+ { PR_1_SUPPRESS_MESSAGES, "", PROMPT_SUPPRESS, PR_NO_OK },
+
+ /* Imagic flag set on an inode when filesystem doesn't support it */
+ { PR_1_SET_IMAGIC,
+ N_("@i %i has imagic flag set. "),
+ PROMPT_CLEAR, 0 },
+
+ /* Immutable flag set on a device or socket inode */
+ { PR_1_SET_IMMUTABLE,
+ N_("Special (@v/socket/fifo/symlink) file (@i %i) has immutable\n"
+ "or append-only flag set. "),
+ PROMPT_CLEAR, PR_PREEN_OK | PR_PREEN_NO | PR_NO_OK },
+
+ /* Compression flag set on an inode when filesystem doesn't support it */
+ { PR_1_COMPR_SET,
+ N_("@i %i has @cion flag set on @f without @cion support. "),
+ PROMPT_CLEAR, 0 },
+
+ /* Non-zero size for device, fifo or socket inode */
+ { PR_1_SET_NONZSIZE,
+ N_("Special (@v/socket/fifo) @i %i has non-zero size. "),
+ PROMPT_FIX, PR_PREEN_OK },
+
+ /* Filesystem revision is 0, but feature flags are set */
+ { PR_1_FS_REV_LEVEL,
+ N_("@f has feature flag(s) set, but is a revision 0 @f. "),
+ PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
+
+ /* Journal inode is not in use, but contains data */
+ { PR_1_JOURNAL_INODE_NOT_CLEAR,
+ N_("@j @i is not in use, but contains data. "),
+ PROMPT_CLEAR, PR_PREEN_OK },
+
+ /* Journal has bad mode */
+ { PR_1_JOURNAL_BAD_MODE,
+ N_("@j is not regular file. "),
+ PROMPT_FIX, PR_PREEN_OK },
+
+ /* Deal with inodes that were part of orphan linked list */
+ { PR_1_LOW_DTIME,
+ N_("@i %i was part of the @o @i list. "),
+ PROMPT_FIX, PR_LATCH_LOW_DTIME, 0 },
+
+ /* Deal with inodes that were part of corrupted orphan linked
+ list (latch question) */
+ { PR_1_ORPHAN_LIST_REFUGEES,
+ N_("@is that were part of a corrupted orphan linked list found. "),
+ PROMPT_FIX, 0 },
+
+ /* Error allocating refcount structure */
+ { PR_1_ALLOCATE_REFCOUNT,
+ N_("@A refcount structure (%N): %m\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Error reading extended attribute block */
+ { PR_1_READ_EA_BLOCK,
+ N_("Error reading @a @b %b for @i %i. "),
+ PROMPT_CLEAR, 0 },
+
+ /* Invalid extended attribute block */
+ { PR_1_BAD_EA_BLOCK,
+ N_("@i %i has a bad @a @b %b. "),
+ PROMPT_CLEAR, 0 },
+
+ /* Error reading Extended Attribute block while fixing refcount */
+ { PR_1_EXTATTR_READ_ABORT,
+ N_("Error reading @a @b %b (%m). "),
+ PROMPT_ABORT, 0 },
+
+ /* Extended attribute reference count incorrect */
+ { PR_1_EXTATTR_REFCOUNT,
+ N_("@a @b %b has reference count %B, @s %N. "),
+ PROMPT_FIX, 0 },
+
+ /* Error writing Extended Attribute block while fixing refcount */
+ { PR_1_EXTATTR_WRITE,
+ N_("Error writing @a @b %b (%m). "),
+ PROMPT_ABORT, 0 },
+
+ /* Multiple EA blocks not supported */
+ { PR_1_EA_MULTI_BLOCK,
+ N_("@a @b %b has h_@bs > 1. "),
+ PROMPT_CLEAR, 0},
+
+ /* Error allocating EA region allocation structure */
+ { PR_1_EA_ALLOC_REGION,
+ N_("@A @a @b %b. "),
+ PROMPT_ABORT, 0},
+
+ /* Error EA allocation collision */
+ { PR_1_EA_ALLOC_COLLISION,
+ N_("@a @b %b is corrupt (allocation collision). "),
+ PROMPT_CLEAR, 0},
+
+ /* Bad extended attribute name */
+ { PR_1_EA_BAD_NAME,
+ N_("@a @b %b is corrupt (@n name). "),
+ PROMPT_CLEAR, 0},
+
+ /* Bad extended attribute value */
+ { PR_1_EA_BAD_VALUE,
+ N_("@a @b %b is corrupt (@n value). "),
+ PROMPT_CLEAR, 0},
+
+ /* Inode too big (latch question) */
+ { PR_1_INODE_TOOBIG,
+ N_("@i %i is too big. "), PROMPT_TRUNCATE, 0 },
+
+ /* Directory too big */
+ { PR_1_TOOBIG_DIR,
+ N_("@b #%B (%b) causes @d to be too big. "),
+ PROMPT_CLEAR, PR_LATCH_TOOBIG },
+
+ /* Regular file too big */
+ { PR_1_TOOBIG_REG,
+ N_("@b #%B (%b) causes file to be too big. "),
+ PROMPT_CLEAR, PR_LATCH_TOOBIG },
+
+ /* Symlink too big */
+ { PR_1_TOOBIG_SYMLINK,
+ N_("@b #%B (%b) causes symlink to be too big. "),
+ PROMPT_CLEAR, PR_LATCH_TOOBIG },
+
+ /* INDEX_FL flag set on a non-HTREE filesystem */
+ { PR_1_HTREE_SET,
+ N_("@i %i has INDEX_FL flag set on @f without htree support.\n"),
+ PROMPT_CLEAR_HTREE, PR_PREEN_OK },
+
+ /* INDEX_FL flag set on a non-directory */
+ { PR_1_HTREE_NODIR,
+ N_("@i %i has INDEX_FL flag set but is not a @d.\n"),
+ PROMPT_CLEAR_HTREE, PR_PREEN_OK },
+
+ /* Invalid root node in HTREE directory */
+ { PR_1_HTREE_BADROOT,
+ N_("@h %i has an @n root node.\n"),
+ PROMPT_CLEAR_HTREE, PR_PREEN_OK },
+
+ /* Unsupported hash version in HTREE directory */
+ { PR_1_HTREE_HASHV,
+ N_("@h %i has an unsupported hash version (%N)\n"),
+ PROMPT_CLEAR_HTREE, PR_PREEN_OK },
+
+ /* Incompatible flag in HTREE root node */
+ { PR_1_HTREE_INCOMPAT,
+ N_("@h %i uses an incompatible htree root node flag.\n"),
+ PROMPT_CLEAR_HTREE, PR_PREEN_OK },
+
+ /* HTREE too deep */
+ { PR_1_HTREE_DEPTH,
+ N_("@h %i has a tree depth (%N) which is too big\n"),
+ PROMPT_CLEAR_HTREE, PR_PREEN_OK },
+
+ /* Bad block has indirect block that conflicts with filesystem block */
+ { PR_1_BB_FS_BLOCK,
+ N_("Bad @b @i has an indirect @b (%b) that conflicts with\n"
+ "@f metadata. "),
+ PROMPT_CLEAR, PR_LATCH_BBLOCK },
+
+ /* Resize inode failed */
+ { PR_1_RESIZE_INODE_CREATE,
+ N_("Resize @i (re)creation failed: %m."),
+ PROMPT_ABORT, 0 },
+
+ /* invalid inode->i_extra_isize */
+ { PR_1_EXTRA_ISIZE,
+ N_("@i %i has a extra size (%IS) which is @n\n"),
+ PROMPT_FIX, PR_PREEN_OK },
+
+ /* invalid ea entry->e_name_len */
+ { PR_1_ATTR_NAME_LEN,
+ N_("@a in @i %i has a namelen (%N) which is @n\n"),
+ PROMPT_CLEAR, PR_PREEN_OK },
+
+ /* invalid ea entry->e_value_size */
+ { PR_1_ATTR_VALUE_SIZE,
+ N_("@a in @i %i has a value size (%N) which is @n\n"),
+ PROMPT_CLEAR, PR_PREEN_OK },
+
+ /* invalid ea entry->e_value_offs */
+ { PR_1_ATTR_VALUE_OFFSET,
+ N_("@a in @i %i has a value offset (%N) which is @n\n"),
+ PROMPT_CLEAR, PR_PREEN_OK },
+
+ /* invalid ea entry->e_value_block */
+ { PR_1_ATTR_VALUE_BLOCK,
+ N_("@a in @i %i has a value @b (%N) which is @n (must be 0)\n"),
+ PROMPT_CLEAR, PR_PREEN_OK },
+
+ /* invalid ea entry->e_hash */
+ { PR_1_ATTR_HASH,
+ N_("@a in @i %i has a hash (%N) which is @n (must be 0)\n"),
+ PROMPT_CLEAR, PR_PREEN_OK },
+
+ /* Pass 1b errors */
+
+ /* Pass 1B: Rescan for duplicate/bad blocks */
+ { PR_1B_PASS_HEADER,
+ N_("\nRunning additional passes to resolve @bs claimed by more than one @i...\n"
+ "Pass 1B: Rescanning for @m @bs\n"),
+ PROMPT_NONE, 0 },
+
+ /* Duplicate/bad block(s) header */
+ { PR_1B_DUP_BLOCK_HEADER,
+ N_("@m @b(s) in @i %i:"),
+ PROMPT_NONE, 0 },
+
+ /* Duplicate/bad block(s) in inode */
+ { PR_1B_DUP_BLOCK,
+ " %b",
+ PROMPT_NONE, PR_LATCH_DBLOCK | PR_PREEN_NOHDR },
+
+ /* Duplicate/bad block(s) end */
+ { PR_1B_DUP_BLOCK_END,
+ "\n",
+ PROMPT_NONE, PR_PREEN_NOHDR },
+
+ /* Error while scanning inodes */
+ { PR_1B_ISCAN_ERROR,
+ N_("Error while scanning inodes (%i): %m\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Error allocating inode bitmap */
+ { PR_1B_ALLOCATE_IBITMAP_ERROR,
+ N_("@A @i @B (@i_dup_map): %m\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Error while iterating over blocks */
+ { PR_1B_BLOCK_ITERATE,
+ N_("Error while iterating over @bs in @i %i (%s): %m\n"),
+ PROMPT_NONE, 0 },
+
+ /* Error adjusting EA refcount */
+ { PR_1B_ADJ_EA_REFCOUNT,
+ N_("Error adjusting refcount for @a @b %b (@i %i): %m\n"),
+ PROMPT_NONE, 0 },
+
+
+ /* Pass 1C: Scan directories for inodes with multiply-claimed blocks. */
+ { PR_1C_PASS_HEADER,
+ N_("Pass 1C: Scanning directories for @is with @m @bs.\n"),
+ PROMPT_NONE, 0 },
+
+
+ /* Pass 1D: Reconciling multiply-claimed blocks */
+ { PR_1D_PASS_HEADER,
+ N_("Pass 1D: Reconciling @m @bs\n"),
+ PROMPT_NONE, 0 },
+
+ /* File has duplicate blocks */
+ { PR_1D_DUP_FILE,
+ N_("File %Q (@i #%i, mod time %IM)\n"
+ " has %B @m @b(s), shared with %N file(s):\n"),
+ PROMPT_NONE, 0 },
+
+ /* List of files sharing duplicate blocks */
+ { PR_1D_DUP_FILE_LIST,
+ N_("\t%Q (@i #%i, mod time %IM)\n"),
+ PROMPT_NONE, 0 },
+
+ /* File sharing blocks with filesystem metadata */
+ { PR_1D_SHARE_METADATA,
+ N_("\t<@f metadata>\n"),
+ PROMPT_NONE, 0 },
+
+ /* Report of how many duplicate/bad inodes */
+ { PR_1D_NUM_DUP_INODES,
+ N_("(There are %N @is containing @m @bs.)\n\n"),
+ PROMPT_NONE, 0 },
+
+ /* Duplicated blocks already reassigned or cloned. */
+ { PR_1D_DUP_BLOCKS_DEALT,
+ N_("@m @bs already reassigned or cloned.\n\n"),
+ PROMPT_NONE, 0 },
+
+ /* Clone duplicate/bad blocks? */
+ { PR_1D_CLONE_QUESTION,
+ "", PROMPT_CLONE, PR_NO_OK },
+
+ /* Delete file? */
+ { PR_1D_DELETE_QUESTION,
+ "", PROMPT_DELETE, 0 },
+
+ /* Couldn't clone file (error) */
+ { PR_1D_CLONE_ERROR,
+ N_("Couldn't clone file: %m\n"), PROMPT_NONE, 0 },
+
+ /* Pass 2 errors */
+
+ /* Pass 2: Checking directory structure */
+ { PR_2_PASS_HEADER,
+ N_("Pass 2: Checking @d structure\n"),
+ PROMPT_NONE, 0 },
+
+ /* Bad inode number for '.' */
+ { PR_2_BAD_INODE_DOT,
+ N_("@n @i number for '.' in @d @i %i.\n"),
+ PROMPT_FIX, 0 },
+
+ /* Directory entry has bad inode number */
+ { PR_2_BAD_INO,
+ N_("@E has @n @i #: %Di.\n"),
+ PROMPT_CLEAR, 0 },
+
+ /* Directory entry has deleted or unused inode */
+ { PR_2_UNUSED_INODE,
+ N_("@E has @D/unused @i %Di. "),
+ PROMPT_CLEAR, PR_PREEN_OK },
+
+ /* Directry entry is link to '.' */
+ { PR_2_LINK_DOT,
+ N_("@E @L to '.' "),
+ PROMPT_CLEAR, 0 },
+
+ /* Directory entry points to inode now located in a bad block */
+ { PR_2_BB_INODE,
+ N_("@E points to @i (%Di) located in a bad @b.\n"),
+ PROMPT_CLEAR, 0 },
+
+ /* Directory entry contains a link to a directory */
+ { PR_2_LINK_DIR,
+ N_("@E @L to @d %P (%Di).\n"),
+ PROMPT_CLEAR, 0 },
+
+ /* Directory entry contains a link to the root directry */
+ { PR_2_LINK_ROOT,
+ N_("@E @L to the @r.\n"),
+ PROMPT_CLEAR, 0 },
+
+ /* Directory entry has illegal characters in its name */
+ { PR_2_BAD_NAME,
+ N_("@E has illegal characters in its name.\n"),
+ PROMPT_FIX, 0 },
+
+ /* Missing '.' in directory inode */
+ { PR_2_MISSING_DOT,
+ N_("Missing '.' in @d @i %i.\n"),
+ PROMPT_FIX, 0 },
+
+ /* Missing '..' in directory inode */
+ { PR_2_MISSING_DOT_DOT,
+ N_("Missing '..' in @d @i %i.\n"),
+ PROMPT_FIX, 0 },
+
+ /* First entry in directory inode doesn't contain '.' */
+ { PR_2_1ST_NOT_DOT,
+ N_("First @e '%Dn' (@i=%Di) in @d @i %i (%p) @s '.'\n"),
+ PROMPT_FIX, 0 },
+
+ /* Second entry in directory inode doesn't contain '..' */
+ { PR_2_2ND_NOT_DOT_DOT,
+ N_("Second @e '%Dn' (@i=%Di) in @d @i %i @s '..'\n"),
+ PROMPT_FIX, 0 },
+
+ /* i_faddr should be zero */
+ { PR_2_FADDR_ZERO,
+ N_("i_faddr @F %IF, @s zero.\n"),
+ PROMPT_CLEAR, 0 },
+
+ /* i_file_acl should be zero */
+ { PR_2_FILE_ACL_ZERO,
+ N_("i_file_acl @F %If, @s zero.\n"),
+ PROMPT_CLEAR, 0 },
+
+ /* i_dir_acl should be zero */
+ { PR_2_DIR_ACL_ZERO,
+ N_("i_dir_acl @F %Id, @s zero.\n"),
+ PROMPT_CLEAR, 0 },
+
+ /* i_frag should be zero */
+ { PR_2_FRAG_ZERO,
+ N_("i_frag @F %N, @s zero.\n"),
+ PROMPT_CLEAR, 0 },
+
+ /* i_fsize should be zero */
+ { PR_2_FSIZE_ZERO,
+ N_("i_fsize @F %N, @s zero.\n"),
+ PROMPT_CLEAR, 0 },
+
+ /* inode has bad mode */
+ { PR_2_BAD_MODE,
+ N_("@i %i (%Q) has @n mode (%Im).\n"),
+ PROMPT_CLEAR, 0 },
+
+ /* directory corrupted */
+ { PR_2_DIR_CORRUPTED,
+ N_("@d @i %i, @b %B, offset %N: @d corrupted\n"),
+ PROMPT_SALVAGE, 0 },
+
+ /* filename too long */
+ { PR_2_FILENAME_LONG,
+ N_("@d @i %i, @b %B, offset %N: filename too long\n"),
+ PROMPT_TRUNCATE, 0 },
+
+ /* Directory inode has a missing block (hole) */
+ { PR_2_DIRECTORY_HOLE,
+ N_("@d @i %i has an unallocated @b #%B. "),
+ PROMPT_ALLOCATE, 0 },
+
+ /* '.' is not NULL terminated */
+ { PR_2_DOT_NULL_TERM,
+ N_("'.' @d @e in @d @i %i is not NULL terminated\n"),
+ PROMPT_FIX, 0 },
+
+ /* '..' is not NULL terminated */
+ { PR_2_DOT_DOT_NULL_TERM,
+ N_("'..' @d @e in @d @i %i is not NULL terminated\n"),
+ PROMPT_FIX, 0 },
+
+ /* Illegal character device inode */
+ { PR_2_BAD_CHAR_DEV,
+ N_("@i %i (%Q) is an @I character @v.\n"),
+ PROMPT_CLEAR, 0 },
+
+ /* Illegal block device inode */
+ { PR_2_BAD_BLOCK_DEV,
+ N_("@i %i (%Q) is an @I @b @v.\n"),
+ PROMPT_CLEAR, 0 },
+
+ /* Duplicate '.' entry */
+ { PR_2_DUP_DOT,
+ N_("@E is duplicate '.' @e.\n"),
+ PROMPT_FIX, 0 },
+
+ /* Duplicate '..' entry */
+ { PR_2_DUP_DOT_DOT,
+ N_("@E is duplicate '..' @e.\n"),
+ PROMPT_FIX, 0 },
+
+ /* Internal error: couldn't find dir_info */
+ { PR_2_NO_DIRINFO,
+ N_("Internal error: cannot find dir_info for %i.\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Final rec_len is wrong */
+ { PR_2_FINAL_RECLEN,
+ N_("@E has rec_len of %Dr, @s %N.\n"),
+ PROMPT_FIX, 0 },
+
+ /* Error allocating icount structure */
+ { PR_2_ALLOCATE_ICOUNT,
+ N_("@A icount structure: %m\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Error iterating over directory blocks */
+ { PR_2_DBLIST_ITERATE,
+ N_("Error iterating over @d @bs: %m\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Error reading directory block */
+ { PR_2_READ_DIRBLOCK,
+ N_("Error reading @d @b %b (@i %i): %m\n"),
+ PROMPT_CONTINUE, 0 },
+
+ /* Error writing directory block */
+ { PR_2_WRITE_DIRBLOCK,
+ N_("Error writing @d @b %b (@i %i): %m\n"),
+ PROMPT_CONTINUE, 0 },
+
+ /* Error allocating new directory block */
+ { PR_2_ALLOC_DIRBOCK,
+ N_("@A new @d @b for @i %i (%s): %m\n"),
+ PROMPT_NONE, 0 },
+
+ /* Error deallocating inode */
+ { PR_2_DEALLOC_INODE,
+ N_("Error deallocating @i %i: %m\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Directory entry for '.' is big. Split? */
+ { PR_2_SPLIT_DOT,
+ N_("@d @e for '.' is big. "),
+ PROMPT_SPLIT, PR_NO_OK },
+
+ /* Illegal FIFO inode */
+ { PR_2_BAD_FIFO,
+ N_("@i %i (%Q) is an @I FIFO.\n"),
+ PROMPT_CLEAR, 0 },
+
+ /* Illegal socket inode */
+ { PR_2_BAD_SOCKET,
+ N_("@i %i (%Q) is an @I socket.\n"),
+ PROMPT_CLEAR, 0 },
+
+ /* Directory filetype not set */
+ { PR_2_SET_FILETYPE,
+ N_("Setting filetype for @E to %N.\n"),
+ PROMPT_NONE, PR_PREEN_OK | PR_NO_OK | PR_NO_NOMSG },
+
+ /* Directory filetype incorrect */
+ { PR_2_BAD_FILETYPE,
+ N_("@E has an incorrect filetype (was %Dt, @s %N).\n"),
+ PROMPT_FIX, 0 },
+
+ /* Directory filetype set on filesystem */
+ { PR_2_CLEAR_FILETYPE,
+ N_("@E has filetype set.\n"),
+ PROMPT_CLEAR, PR_PREEN_OK },
+
+ /* Directory filename is null */
+ { PR_2_NULL_NAME,
+ N_("@E has a @z name.\n"),
+ PROMPT_CLEAR, 0 },
+
+ /* Invalid symlink */
+ { PR_2_INVALID_SYMLINK,
+ N_("Symlink %Q (@i #%i) is @n.\n"),
+ PROMPT_CLEAR, 0 },
+
+ /* i_file_acl (extended attribute block) is bad */
+ { PR_2_FILE_ACL_BAD,
+ N_("@a @b @F @n (%If).\n"),
+ PROMPT_CLEAR, 0 },
+
+ /* Filesystem contains large files, but has no such flag in sb */
+ { PR_2_FEATURE_LARGE_FILES,
+ N_("@f contains large files, but lacks LARGE_FILE flag in @S.\n"),
+ PROMPT_FIX, 0 },
+
+ /* Node in HTREE directory not referenced */
+ { PR_2_HTREE_NOTREF,
+ N_("@p @h %d: node (%B) not referenced\n"),
+ PROMPT_NONE, 0 },
+
+ /* Node in HTREE directory referenced twice */
+ { PR_2_HTREE_DUPREF,
+ N_("@p @h %d: node (%B) referenced twice\n"),
+ PROMPT_NONE, 0 },
+
+ /* Node in HTREE directory has bad min hash */
+ { PR_2_HTREE_MIN_HASH,
+ N_("@p @h %d: node (%B) has bad min hash\n"),
+ PROMPT_NONE, 0 },
+
+ /* Node in HTREE directory has bad max hash */
+ { PR_2_HTREE_MAX_HASH,
+ N_("@p @h %d: node (%B) has bad max hash\n"),
+ PROMPT_NONE, 0 },
+
+ /* Clear invalid HTREE directory */
+ { PR_2_HTREE_CLEAR,
+ N_("@n @h %d (%q). "), PROMPT_CLEAR, 0 },
+
+ /* Bad block in htree interior node */
+ { PR_2_HTREE_BADBLK,
+ N_("@p @h %d (%q): bad @b number %b.\n"),
+ PROMPT_CLEAR_HTREE, 0 },
+
+ /* Error adjusting EA refcount */
+ { PR_2_ADJ_EA_REFCOUNT,
+ N_("Error adjusting refcount for @a @b %b (@i %i): %m\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Invalid HTREE root node */
+ { PR_2_HTREE_BAD_ROOT,
+ N_("@p @h %d: root node is @n\n"),
+ PROMPT_CLEAR_HTREE, PR_PREEN_OK },
+
+ /* Invalid HTREE limit */
+ { PR_2_HTREE_BAD_LIMIT,
+ N_("@p @h %d: node (%B) has @n limit (%N)\n"),
+ PROMPT_CLEAR_HTREE, PR_PREEN_OK },
+
+ /* Invalid HTREE count */
+ { PR_2_HTREE_BAD_COUNT,
+ N_("@p @h %d: node (%B) has @n count (%N)\n"),
+ PROMPT_CLEAR_HTREE, PR_PREEN_OK },
+
+ /* HTREE interior node has out-of-order hashes in table */
+ { PR_2_HTREE_HASH_ORDER,
+ N_("@p @h %d: node (%B) has an unordered hash table\n"),
+ PROMPT_CLEAR_HTREE, PR_PREEN_OK },
+
+ /* Node in HTREE directory has invalid depth */
+ { PR_2_HTREE_BAD_DEPTH,
+ N_("@p @h %d: node (%B) has @n depth\n"),
+ PROMPT_NONE, 0 },
+
+ /* Duplicate directory entry found */
+ { PR_2_DUPLICATE_DIRENT,
+ N_("Duplicate @E found. "),
+ PROMPT_CLEAR, 0 },
+
+ /* Non-unique filename found */
+ { PR_2_NON_UNIQUE_FILE, /* xgettext: no-c-format */
+ N_("@E has a non-unique filename.\nRename to %s"),
+ PROMPT_NULL, 0 },
+
+ /* Duplicate directory entry found */
+ { PR_2_REPORT_DUP_DIRENT,
+ N_("Duplicate @e '%Dn' found.\n\tMarking %p (%i) to be rebuilt.\n\n"),
+ PROMPT_NONE, 0 },
+
+ /* Pass 3 errors */
+
+ /* Pass 3: Checking directory connectivity */
+ { PR_3_PASS_HEADER,
+ N_("Pass 3: Checking @d connectivity\n"),
+ PROMPT_NONE, 0 },
+
+ /* Root inode not allocated */
+ { PR_3_NO_ROOT_INODE,
+ N_("@r not allocated. "),
+ PROMPT_ALLOCATE, 0 },
+
+ /* No room in lost+found */
+ { PR_3_EXPAND_LF_DIR,
+ N_("No room in @l @d. "),
+ PROMPT_EXPAND, 0 },
+
+ /* Unconnected directory inode */
+ { PR_3_UNCONNECTED_DIR,
+ N_("Unconnected @d @i %i (%p)\n"),
+ PROMPT_CONNECT, 0 },
+
+ /* /lost+found not found */
+ { PR_3_NO_LF_DIR,
+ N_("/@l not found. "),
+ PROMPT_CREATE, PR_PREEN_OK },
+
+ /* .. entry is incorrect */
+ { PR_3_BAD_DOT_DOT,
+ N_("'..' in %Q (%i) is %P (%j), @s %q (%d).\n"),
+ PROMPT_FIX, 0 },
+
+ /* Bad or non-existent /lost+found. Cannot reconnect */
+ { PR_3_NO_LPF,
+ N_("Bad or non-existent /@l. Cannot reconnect.\n"),
+ PROMPT_NONE, 0 },
+
+ /* Could not expand /lost+found */
+ { PR_3_CANT_EXPAND_LPF,
+ N_("Could not expand /@l: %m\n"),
+ PROMPT_NONE, 0 },
+
+ /* Could not reconnect inode */
+ { PR_3_CANT_RECONNECT,
+ N_("Could not reconnect %i: %m\n"),
+ PROMPT_NONE, 0 },
+
+ /* Error while trying to find /lost+found */
+ { PR_3_ERR_FIND_LPF,
+ N_("Error while trying to find /@l: %m\n"),
+ PROMPT_NONE, 0 },
+
+ /* Error in ext2fs_new_block while creating /lost+found */
+ { PR_3_ERR_LPF_NEW_BLOCK,
+ N_("ext2fs_new_@b: %m while trying to create /@l @d\n"),
+ PROMPT_NONE, 0 },
+
+ /* Error in ext2fs_new_inode while creating /lost+found */
+ { PR_3_ERR_LPF_NEW_INODE,
+ N_("ext2fs_new_@i: %m while trying to create /@l @d\n"),
+ PROMPT_NONE, 0 },
+
+ /* Error in ext2fs_new_dir_block while creating /lost+found */
+ { PR_3_ERR_LPF_NEW_DIR_BLOCK,
+ N_("ext2fs_new_dir_@b: %m while creating new @d @b\n"),
+ PROMPT_NONE, 0 },
+
+ /* Error while writing directory block for /lost+found */
+ { PR_3_ERR_LPF_WRITE_BLOCK,
+ N_("ext2fs_write_dir_@b: %m while writing the @d @b for /@l\n"),
+ PROMPT_NONE, 0 },
+
+ /* Error while adjusting inode count */
+ { PR_3_ADJUST_INODE,
+ N_("Error while adjusting @i count on @i %i\n"),
+ PROMPT_NONE, 0 },
+
+ /* Couldn't fix parent directory -- error */
+ { PR_3_FIX_PARENT_ERR,
+ N_("Couldn't fix parent of @i %i: %m\n\n"),
+ PROMPT_NONE, 0 },
+
+ /* Couldn't fix parent directory -- couldn't find it */
+ { PR_3_FIX_PARENT_NOFIND,
+ N_("Couldn't fix parent of @i %i: Couldn't find parent @d @e\n\n"),
+ PROMPT_NONE, 0 },
+
+ /* Error allocating inode bitmap */
+ { PR_3_ALLOCATE_IBITMAP_ERROR,
+ N_("@A @i @B (%N): %m\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Error creating root directory */
+ { PR_3_CREATE_ROOT_ERROR,
+ N_("Error creating root @d (%s): %m\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Error creating lost and found directory */
+ { PR_3_CREATE_LPF_ERROR,
+ N_("Error creating /@l @d (%s): %m\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Root inode is not directory; aborting */
+ { PR_3_ROOT_NOT_DIR_ABORT,
+ N_("@r is not a @d; aborting.\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Cannot proceed without a root inode. */
+ { PR_3_NO_ROOT_INODE_ABORT,
+ N_("Cannot proceed without a @r.\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Internal error: couldn't find dir_info */
+ { PR_3_NO_DIRINFO,
+ N_("Internal error: cannot find dir_info for %i.\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Lost+found not a directory */
+ { PR_3_LPF_NOTDIR,
+ N_("/@l is not a @d (ino=%i)\n"),
+ PROMPT_UNLINK, 0 },
+
+ /* Pass 3A Directory Optimization */
+
+ /* Pass 3A: Optimizing directories */
+ { PR_3A_PASS_HEADER,
+ N_("Pass 3A: Optimizing directories\n"),
+ PROMPT_NONE, PR_PREEN_NOMSG },
+
+ /* Error iterating over directories */
+ { PR_3A_OPTIMIZE_ITER,
+ N_("Failed to create dirs_to_hash iterator: %m"),
+ PROMPT_NONE, 0 },
+
+ /* Error rehash directory */
+ { PR_3A_OPTIMIZE_DIR_ERR,
+ N_("Failed to optimize directory %q (%d): %m"),
+ PROMPT_NONE, 0 },
+
+ /* Rehashing dir header */
+ { PR_3A_OPTIMIZE_DIR_HEADER,
+ N_("Optimizing directories: "),
+ PROMPT_NONE, PR_MSG_ONLY },
+
+ /* Rehashing directory %d */
+ { PR_3A_OPTIMIZE_DIR,
+ " %d",
+ PROMPT_NONE, PR_LATCH_OPTIMIZE_DIR | PR_PREEN_NOHDR},
+
+ /* Rehashing dir end */
+ { PR_3A_OPTIMIZE_DIR_END,
+ "\n",
+ PROMPT_NONE, PR_PREEN_NOHDR },
+
+ /* Pass 4 errors */
+
+ /* Pass 4: Checking reference counts */
+ { PR_4_PASS_HEADER,
+ N_("Pass 4: Checking reference counts\n"),
+ PROMPT_NONE, 0 },
+
+ /* Unattached zero-length inode */
+ { PR_4_ZERO_LEN_INODE,
+ N_("@u @z @i %i. "),
+ PROMPT_CLEAR, PR_PREEN_OK|PR_NO_OK },
+
+ /* Unattached inode */
+ { PR_4_UNATTACHED_INODE,
+ N_("@u @i %i\n"),
+ PROMPT_CONNECT, 0 },
+
+ /* Inode ref count wrong */
+ { PR_4_BAD_REF_COUNT,
+ N_("@i %i ref count is %Il, @s %N. "),
+ PROMPT_FIX, PR_PREEN_OK },
+
+ { PR_4_INCONSISTENT_COUNT,
+ N_("WARNING: PROGRAMMING BUG IN E2FSCK!\n"
+ "\tOR SOME BONEHEAD (YOU) IS CHECKING A MOUNTED (LIVE) FILESYSTEM.\n"
+ "@i_link_info[%i] is %N, @i.i_links_count is %Il. "
+ "They @s the same!\n"),
+ PROMPT_NONE, 0 },
+
+ /* Pass 5 errors */
+
+ /* Pass 5: Checking group summary information */
+ { PR_5_PASS_HEADER,
+ N_("Pass 5: Checking @g summary information\n"),
+ PROMPT_NONE, 0 },
+
+ /* Padding at end of inode bitmap is not set. */
+ { PR_5_INODE_BMAP_PADDING,
+ N_("Padding at end of @i @B is not set. "),
+ PROMPT_FIX, PR_PREEN_OK },
+
+ /* Padding at end of block bitmap is not set. */
+ { PR_5_BLOCK_BMAP_PADDING,
+ N_("Padding at end of @b @B is not set. "),
+ PROMPT_FIX, PR_PREEN_OK },
+
+ /* Block bitmap differences header */
+ { PR_5_BLOCK_BITMAP_HEADER,
+ N_("@b @B differences: "),
+ PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG},
+
+ /* Block not used, but marked in bitmap */
+ { PR_5_BLOCK_UNUSED,
+ " -%b",
+ PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
+
+ /* Block used, but not marked used in bitmap */
+ { PR_5_BLOCK_USED,
+ " +%b",
+ PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
+
+ /* Block bitmap differences end */
+ { PR_5_BLOCK_BITMAP_END,
+ "\n",
+ PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
+
+ /* Inode bitmap differences header */
+ { PR_5_INODE_BITMAP_HEADER,
+ N_("@i @B differences: "),
+ PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
+
+ /* Inode not used, but marked in bitmap */
+ { PR_5_INODE_UNUSED,
+ " -%i",
+ PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
+
+ /* Inode used, but not marked used in bitmap */
+ { PR_5_INODE_USED,
+ " +%i",
+ PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
+
+ /* Inode bitmap differences end */
+ { PR_5_INODE_BITMAP_END,
+ "\n",
+ PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
+
+ /* Free inodes count for group wrong */
+ { PR_5_FREE_INODE_COUNT_GROUP,
+ N_("Free @is count wrong for @g #%g (%i, counted=%j).\n"),
+ PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
+
+ /* Directories count for group wrong */
+ { PR_5_FREE_DIR_COUNT_GROUP,
+ N_("Directories count wrong for @g #%g (%i, counted=%j).\n"),
+ PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
+
+ /* Free inodes count wrong */
+ { PR_5_FREE_INODE_COUNT,
+ N_("Free @is count wrong (%i, counted=%j).\n"),
+ PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
+
+ /* Free blocks count for group wrong */
+ { PR_5_FREE_BLOCK_COUNT_GROUP,
+ N_("Free @bs count wrong for @g #%g (%b, counted=%c).\n"),
+ PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
+
+ /* Free blocks count wrong */
+ { PR_5_FREE_BLOCK_COUNT,
+ N_("Free @bs count wrong (%b, counted=%c).\n"),
+ PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
+
+ /* Programming error: bitmap endpoints don't match */
+ { PR_5_BMAP_ENDPOINTS,
+ N_("PROGRAMMING ERROR: @f (#%N) @B endpoints (%b, %c) don't "
+ "match calculated @B endpoints (%i, %j)\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Internal error: fudging end of bitmap */
+ { PR_5_FUDGE_BITMAP_ERROR,
+ N_("Internal error: fudging end of bitmap (%N)\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Error copying in replacement inode bitmap */
+ { PR_5_COPY_IBITMAP_ERROR,
+ N_("Error copying in replacement @i @B: %m\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Error copying in replacement block bitmap */
+ { PR_5_COPY_BBITMAP_ERROR,
+ N_("Error copying in replacement @b @B: %m\n"),
+ PROMPT_NONE, PR_FATAL },
+
+ /* Block range not used, but marked in bitmap */
+ { PR_5_BLOCK_RANGE_UNUSED,
+ " -(%b--%c)",
+ PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
+
+ /* Block range used, but not marked used in bitmap */
+ { PR_5_BLOCK_RANGE_USED,
+ " +(%b--%c)",
+ PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
+
+ /* Inode range not used, but marked in bitmap */
+ { PR_5_INODE_RANGE_UNUSED,
+ " -(%i--%j)",
+ PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
+
+ /* Inode range used, but not marked used in bitmap */
+ { PR_5_INODE_RANGE_USED,
+ " +(%i--%j)",
+ PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
+
+ { 0 }
+};
+
+/*
+ * This is the latch flags register. It allows several problems to be
+ * "latched" together. This means that the user has to answer but one
+ * question for the set of problems, and all of the associated
+ * problems will be either fixed or not fixed.
+ */
+static struct latch_descr pr_latch_info[] = {
+ { PR_LATCH_BLOCK, PR_1_INODE_BLOCK_LATCH, 0 },
+ { PR_LATCH_BBLOCK, PR_1_INODE_BBLOCK_LATCH, 0 },
+ { PR_LATCH_IBITMAP, PR_5_INODE_BITMAP_HEADER, PR_5_INODE_BITMAP_END },
+ { PR_LATCH_BBITMAP, PR_5_BLOCK_BITMAP_HEADER, PR_5_BLOCK_BITMAP_END },
+ { PR_LATCH_RELOC, PR_0_RELOCATE_HINT, 0 },
+ { PR_LATCH_DBLOCK, PR_1B_DUP_BLOCK_HEADER, PR_1B_DUP_BLOCK_END },
+ { PR_LATCH_LOW_DTIME, PR_1_ORPHAN_LIST_REFUGEES, 0 },
+ { PR_LATCH_TOOBIG, PR_1_INODE_TOOBIG, 0 },
+ { PR_LATCH_OPTIMIZE_DIR, PR_3A_OPTIMIZE_DIR_HEADER, PR_3A_OPTIMIZE_DIR_END },
+ { -1, 0, 0 },
+};
+
+static const struct e2fsck_problem *find_problem(problem_t code)
+{
+ int i;
+
+ for (i=0; problem_table[i].e2p_code; i++) {
+ if (problem_table[i].e2p_code == code)
+ return &problem_table[i];
+ }
+ return 0;
+}
+
+static struct latch_descr *find_latch(int code)
+{
+ int i;
+
+ for (i=0; pr_latch_info[i].latch_code >= 0; i++) {
+ if (pr_latch_info[i].latch_code == code)
+ return &pr_latch_info[i];
+ }
+ return 0;
+}
+
+int end_problem_latch(e2fsck_t ctx, int mask)
+{
+ struct latch_descr *ldesc;
+ struct problem_context pctx;
+ int answer = -1;
+
+ ldesc = find_latch(mask);
+ if (ldesc->end_message && (ldesc->flags & PRL_LATCHED)) {
+ clear_problem_context(&pctx);
+ answer = fix_problem(ctx, ldesc->end_message, &pctx);
+ }
+ ldesc->flags &= ~(PRL_VARIABLE);
+ return answer;
+}
+
+int set_latch_flags(int mask, int setflags, int clearflags)
+{
+ struct latch_descr *ldesc;
+
+ ldesc = find_latch(mask);
+ if (!ldesc)
+ return -1;
+ ldesc->flags |= setflags;
+ ldesc->flags &= ~clearflags;
+ return 0;
+}
+
+void clear_problem_context(struct problem_context *ctx)
+{
+ memset(ctx, 0, sizeof(struct problem_context));
+ ctx->blkcount = -1;
+ ctx->group = -1;
+}
+
+int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx)
+{
+ ext2_filsys fs = ctx->fs;
+ const struct e2fsck_problem *ptr;
+ struct latch_descr *ldesc = 0;
+ const char *message;
+ int def_yn, answer, ans;
+ int print_answer = 0;
+ int suppress = 0;
+
+ ptr = find_problem(code);
+ if (!ptr) {
+ printf(_("Unhandled error code (0x%x)!\n"), code);
+ return 0;
+ }
+ def_yn = 1;
+ if ((ptr->flags & PR_NO_DEFAULT) ||
+ ((ptr->flags & PR_PREEN_NO) && (ctx->options & E2F_OPT_PREEN)) ||
+ (ctx->options & E2F_OPT_NO))
+ def_yn= 0;
+
+ /*
+ * Do special latch processing. This is where we ask the
+ * latch question, if it exists
+ */
+ if (ptr->flags & PR_LATCH_MASK) {
+ ldesc = find_latch(ptr->flags & PR_LATCH_MASK);
+ if (ldesc->question && !(ldesc->flags & PRL_LATCHED)) {
+ ans = fix_problem(ctx, ldesc->question, pctx);
+ if (ans == 1)
+ ldesc->flags |= PRL_YES;
+ if (ans == 0)
+ ldesc->flags |= PRL_NO;
+ ldesc->flags |= PRL_LATCHED;
+ }
+ if (ldesc->flags & PRL_SUPPRESS)
+ suppress++;
+ }
+ if ((ptr->flags & PR_PREEN_NOMSG) &&
+ (ctx->options & E2F_OPT_PREEN))
+ suppress++;
+ if ((ptr->flags & PR_NO_NOMSG) &&
+ (ctx->options & E2F_OPT_NO))
+ suppress++;
+ if (!suppress) {
+ message = ptr->e2p_description;
+ if ((ctx->options & E2F_OPT_PREEN) &&
+ !(ptr->flags & PR_PREEN_NOHDR)) {
+ printf("%s: ", ctx->device_name ?
+ ctx->device_name : ctx->filesystem_name);
+ }
+ if (*message)
+ print_e2fsck_message(ctx, _(message), pctx, 1);
+ }
+ if (!(ptr->flags & PR_PREEN_OK) && (ptr->prompt != PROMPT_NONE))
+ preenhalt(ctx);
+
+ if (ptr->flags & PR_FATAL)
+ bb_error_msg_and_die(0);
+
+ if (ptr->prompt == PROMPT_NONE) {
+ if (ptr->flags & PR_NOCOLLATE)
+ answer = -1;
+ else
+ answer = def_yn;
+ } else {
+ if (ctx->options & E2F_OPT_PREEN) {
+ answer = def_yn;
+ if (!(ptr->flags & PR_PREEN_NOMSG))
+ print_answer = 1;
+ } else if ((ptr->flags & PR_LATCH_MASK) &&
+ (ldesc->flags & (PRL_YES | PRL_NO))) {
+ if (!suppress)
+ print_answer = 1;
+ if (ldesc->flags & PRL_YES)
+ answer = 1;
+ else
+ answer = 0;
+ } else
+ answer = ask(ctx, _(prompt[(int) ptr->prompt]), def_yn);
+ if (!answer && !(ptr->flags & PR_NO_OK))
+ ext2fs_unmark_valid(fs);
+
+ if (print_answer)
+ printf("%s.\n", answer ?
+ _(preen_msg[(int) ptr->prompt]) : _("IGNORED"));
+
+ }
+
+ if ((ptr->prompt == PROMPT_ABORT) && answer)
+ bb_error_msg_and_die(0);
+
+ if (ptr->flags & PR_AFTER_CODE)
+ answer = fix_problem(ctx, ptr->second_code, pctx);
+
+ return answer;
+}
+
+/*
+ * linux/fs/recovery.c
+ *
+ * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
+ */
+
+/*
+ * Maintain information about the progress of the recovery job, so that
+ * the different passes can carry information between them.
+ */
+struct recovery_info
+{
+ tid_t start_transaction;
+ tid_t end_transaction;
+
+ int nr_replays;
+ int nr_revokes;
+ int nr_revoke_hits;
+};
+
+enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY};
+static int do_one_pass(journal_t *journal,
+ struct recovery_info *info, enum passtype pass);
+static int scan_revoke_records(journal_t *, struct buffer_head *,
+ tid_t, struct recovery_info *);
+
+/*
+ * Read a block from the journal
+ */
+
+static int jread(struct buffer_head **bhp, journal_t *journal,
+ unsigned int offset)
+{
+ int err;
+ unsigned long blocknr;
+ struct buffer_head *bh;
+
+ *bhp = NULL;
+
+ err = journal_bmap(journal, offset, &blocknr);
+
+ if (err) {
+ printf("JBD: bad block at offset %u\n", offset);
+ return err;
+ }
+
+ bh = getblk(journal->j_dev, blocknr, journal->j_blocksize);
+ if (!bh)
+ return -ENOMEM;
+
+ if (!buffer_uptodate(bh)) {
+ /* If this is a brand new buffer, start readahead.
+ Otherwise, we assume we are already reading it. */
+ if (!buffer_req(bh))
+ do_readahead(journal, offset);
+ wait_on_buffer(bh);
+ }
+
+ if (!buffer_uptodate(bh)) {
+ printf("JBD: Failed to read block at offset %u\n", offset);
+ brelse(bh);
+ return -EIO;
+ }
+
+ *bhp = bh;
+ return 0;
+}
+
+
+/*
+ * Count the number of in-use tags in a journal descriptor block.
+ */
+
+static int count_tags(struct buffer_head *bh, int size)
+{
+ char * tagp;
+ journal_block_tag_t * tag;
+ int nr = 0;
+
+ tagp = &bh->b_data[sizeof(journal_header_t)];
+
+ while ((tagp - bh->b_data + sizeof(journal_block_tag_t)) <= size) {
+ tag = (journal_block_tag_t *) tagp;
+
+ nr++;
+ tagp += sizeof(journal_block_tag_t);
+ if (!(tag->t_flags & htonl(JFS_FLAG_SAME_UUID)))
+ tagp += 16;
+
+ if (tag->t_flags & htonl(JFS_FLAG_LAST_TAG))
+ break;
+ }
+
+ return nr;
+}
+
+
+/* Make sure we wrap around the log correctly! */
+#define wrap(journal, var) \
+do { \
+ if (var >= (journal)->j_last) \
+ var -= ((journal)->j_last - (journal)->j_first); \
+} while (0)
+
+/**
+ * int journal_recover(journal_t *journal) - recovers a on-disk journal
+ * @journal: the journal to recover
+ *
+ * The primary function for recovering the log contents when mounting a
+ * journaled device.
+ *
+ * Recovery is done in three passes. In the first pass, we look for the
+ * end of the log. In the second, we assemble the list of revoke
+ * blocks. In the third and final pass, we replay any un-revoked blocks
+ * in the log.
+ */
+int journal_recover(journal_t *journal)
+{
+ int err;
+ journal_superblock_t * sb;
+
+ struct recovery_info info;
+
+ memset(&info, 0, sizeof(info));
+ sb = journal->j_superblock;
+
+ /*
+ * The journal superblock's s_start field (the current log head)
+ * is always zero if, and only if, the journal was cleanly
+ * unmounted.
+ */
+
+ if (!sb->s_start) {
+ journal->j_transaction_sequence = ntohl(sb->s_sequence) + 1;
+ return 0;
+ }
+
+ err = do_one_pass(journal, &info, PASS_SCAN);
+ if (!err)
+ err = do_one_pass(journal, &info, PASS_REVOKE);
+ if (!err)
+ err = do_one_pass(journal, &info, PASS_REPLAY);
+
+ /* Restart the log at the next transaction ID, thus invalidating
+ * any existing commit records in the log. */
+ journal->j_transaction_sequence = ++info.end_transaction;
+
+ journal_clear_revoke(journal);
+ sync_blockdev(journal->j_fs_dev);
+ return err;
+}
+
+static int do_one_pass(journal_t *journal,
+ struct recovery_info *info, enum passtype pass)
+{
+ unsigned int first_commit_ID, next_commit_ID;
+ unsigned long next_log_block;
+ int err, success = 0;
+ journal_superblock_t * sb;
+ journal_header_t * tmp;
+ struct buffer_head * bh;
+ unsigned int sequence;
+ int blocktype;
+
+ /* Precompute the maximum metadata descriptors in a descriptor block */
+ int MAX_BLOCKS_PER_DESC;
+ MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t))
+ / sizeof(journal_block_tag_t));
+
+ /*
+ * First thing is to establish what we expect to find in the log
+ * (in terms of transaction IDs), and where (in terms of log
+ * block offsets): query the superblock.
+ */
+
+ sb = journal->j_superblock;
+ next_commit_ID = ntohl(sb->s_sequence);
+ next_log_block = ntohl(sb->s_start);
+
+ first_commit_ID = next_commit_ID;
+ if (pass == PASS_SCAN)
+ info->start_transaction = first_commit_ID;
+
+ /*
+ * Now we walk through the log, transaction by transaction,
+ * making sure that each transaction has a commit block in the
+ * expected place. Each complete transaction gets replayed back
+ * into the main filesystem.
+ */
+
+ while (1) {
+ int flags;
+ char * tagp;
+ journal_block_tag_t * tag;
+ struct buffer_head * obh;
+ struct buffer_head * nbh;
+
+ /* If we already know where to stop the log traversal,
+ * check right now that we haven't gone past the end of
+ * the log. */
+
+ if (pass != PASS_SCAN)
+ if (tid_geq(next_commit_ID, info->end_transaction))
+ break;
+
+ /* Skip over each chunk of the transaction looking
+ * either the next descriptor block or the final commit
+ * record. */
+
+ err = jread(&bh, journal, next_log_block);
+ if (err)
+ goto failed;
+
+ next_log_block++;
+ wrap(journal, next_log_block);
+
+ /* What kind of buffer is it?
+ *
+ * If it is a descriptor block, check that it has the
+ * expected sequence number. Otherwise, we're all done
+ * here. */
+
+ tmp = (journal_header_t *)bh->b_data;
+
+ if (tmp->h_magic != htonl(JFS_MAGIC_NUMBER)) {
+ brelse(bh);
+ break;
+ }
+
+ blocktype = ntohl(tmp->h_blocktype);
+ sequence = ntohl(tmp->h_sequence);
+
+ if (sequence != next_commit_ID) {
+ brelse(bh);
+ break;
+ }
+
+ /* OK, we have a valid descriptor block which matches
+ * all of the sequence number checks. What are we going
+ * to do with it? That depends on the pass... */
+
+ switch(blocktype) {
+ case JFS_DESCRIPTOR_BLOCK:
+ /* If it is a valid descriptor block, replay it
+ * in pass REPLAY; otherwise, just skip over the
+ * blocks it describes. */
+ if (pass != PASS_REPLAY) {
+ next_log_block +=
+ count_tags(bh, journal->j_blocksize);
+ wrap(journal, next_log_block);
+ brelse(bh);
+ continue;
+ }
+
+ /* A descriptor block: we can now write all of
+ * the data blocks. Yay, useful work is finally
+ * getting done here! */
+
+ tagp = &bh->b_data[sizeof(journal_header_t)];
+ while ((tagp - bh->b_data +sizeof(journal_block_tag_t))
+ <= journal->j_blocksize) {
+ unsigned long io_block;
+
+ tag = (journal_block_tag_t *) tagp;
+ flags = ntohl(tag->t_flags);
+
+ io_block = next_log_block++;
+ wrap(journal, next_log_block);
+ err = jread(&obh, journal, io_block);
+ if (err) {
+ /* Recover what we can, but
+ * report failure at the end. */
+ success = err;
+ printf("JBD: IO error %d recovering "
+ "block %ld in log\n",
+ err, io_block);
+ } else {
+ unsigned long blocknr;
+
+ blocknr = ntohl(tag->t_blocknr);
+
+ /* If the block has been
+ * revoked, then we're all done
+ * here. */
+ if (journal_test_revoke
+ (journal, blocknr,
+ next_commit_ID)) {
+ brelse(obh);
+ ++info->nr_revoke_hits;
+ goto skip_write;
+ }
+
+ /* Find a buffer for the new
+ * data being restored */
+ nbh = getblk(journal->j_fs_dev,
+ blocknr,
+ journal->j_blocksize);
+ if (nbh == NULL) {
+ printf("JBD: Out of memory "
+ "during recovery.\n");
+ err = -ENOMEM;
+ brelse(bh);
+ brelse(obh);
+ goto failed;
+ }
+
+ lock_buffer(nbh);
+ memcpy(nbh->b_data, obh->b_data,
+ journal->j_blocksize);
+ if (flags & JFS_FLAG_ESCAPE) {
+ *((unsigned int *)bh->b_data) =
+ htonl(JFS_MAGIC_NUMBER);
+ }
+
+ mark_buffer_uptodate(nbh, 1);
+ mark_buffer_dirty(nbh);
+ ++info->nr_replays;
+ /* ll_rw_block(WRITE, 1, &nbh); */
+ unlock_buffer(nbh);
+ brelse(obh);
+ brelse(nbh);
+ }
+
+ skip_write:
+ tagp += sizeof(journal_block_tag_t);
+ if (!(flags & JFS_FLAG_SAME_UUID))
+ tagp += 16;
+
+ if (flags & JFS_FLAG_LAST_TAG)
+ break;
+ }
+
+ brelse(bh);
+ continue;
+
+ case JFS_COMMIT_BLOCK:
+ /* Found an expected commit block: not much to
+ * do other than move on to the next sequence
+ * number. */
+ brelse(bh);
+ next_commit_ID++;
+ continue;
+
+ case JFS_REVOKE_BLOCK:
+ /* If we aren't in the REVOKE pass, then we can
+ * just skip over this block. */
+ if (pass != PASS_REVOKE) {
+ brelse(bh);
+ continue;
+ }
+
+ err = scan_revoke_records(journal, bh,
+ next_commit_ID, info);
+ brelse(bh);
+ if (err)
+ goto failed;
+ continue;
+
+ default:
+ goto done;
+ }
+ }
+
+ done:
+ /*
+ * We broke out of the log scan loop: either we came to the
+ * known end of the log or we found an unexpected block in the
+ * log. If the latter happened, then we know that the "current"
+ * transaction marks the end of the valid log.
+ */
+
+ if (pass == PASS_SCAN)
+ info->end_transaction = next_commit_ID;
+ else {
+ /* It's really bad news if different passes end up at
+ * different places (but possible due to IO errors). */
+ if (info->end_transaction != next_commit_ID) {
+ printf("JBD: recovery pass %d ended at "
+ "transaction %u, expected %u\n",
+ pass, next_commit_ID, info->end_transaction);
+ if (!success)
+ success = -EIO;
+ }
+ }
+
+ return success;
+
+ failed:
+ return err;
+}
+
+
+/* Scan a revoke record, marking all blocks mentioned as revoked. */
+
+static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
+ tid_t sequence, struct recovery_info *info)
+{
+ journal_revoke_header_t *header;
+ int offset, max;
+
+ header = (journal_revoke_header_t *) bh->b_data;
+ offset = sizeof(journal_revoke_header_t);
+ max = ntohl(header->r_count);
+
+ while (offset < max) {
+ unsigned long blocknr;
+ int err;
+
+ blocknr = ntohl(* ((unsigned int *) (bh->b_data+offset)));
+ offset += 4;
+ err = journal_set_revoke(journal, blocknr, sequence);
+ if (err)
+ return err;
+ ++info->nr_revokes;
+ }
+ return 0;
+}
+
+
+/*
+ * rehash.c --- rebuild hash tree directories
+ *
+ * This algorithm is designed for simplicity of implementation and to
+ * pack the directory as much as possible. It however requires twice
+ * as much memory as the size of the directory. The maximum size
+ * directory supported using a 4k blocksize is roughly a gigabyte, and
+ * so there may very well be problems with machines that don't have
+ * virtual memory, and obscenely large directories.
+ *
+ * An alternate algorithm which is much more disk intensive could be
+ * written, and probably will need to be written in the future. The
+ * design goals of such an algorithm are: (a) use (roughly) constant
+ * amounts of memory, no matter how large the directory, (b) the
+ * directory must be safe at all times, even if e2fsck is interrupted
+ * in the middle, (c) we must use minimal amounts of extra disk
+ * blocks. This pretty much requires an incremental approach, where
+ * we are reading from one part of the directory, and inserting into
+ * the front half. So the algorithm will have to keep track of a
+ * moving block boundary between the new tree and the old tree, and
+ * files will need to be moved from the old directory and inserted
+ * into the new tree. If the new directory requires space which isn't
+ * yet available, blocks from the beginning part of the old directory
+ * may need to be moved to the end of the directory to make room for
+ * the new tree:
+ *
+ * --------------------------------------------------------
+ * | new tree | | old tree |
+ * --------------------------------------------------------
+ * ^ ptr ^ptr
+ * tail new head old
+ *
+ * This is going to be a pain in the tuckus to implement, and will
+ * require a lot more disk accesses. So I'm going to skip it for now;
+ * it's only really going to be an issue for really, really big
+ * filesystems (when we reach the level of tens of millions of files
+ * in a single directory). It will probably be easier to simply
+ * require that e2fsck use VM first.
+ */
+
+struct fill_dir_struct {
+ char *buf;
+ struct ext2_inode *inode;
+ int err;
+ e2fsck_t ctx;
+ struct hash_entry *harray;
+ int max_array, num_array;
+ int dir_size;
+ int compress;
+ ino_t parent;
+};
+
+struct hash_entry {
+ ext2_dirhash_t hash;
+ ext2_dirhash_t minor_hash;
+ struct ext2_dir_entry *dir;
+};
+
+struct out_dir {
+ int num;
+ int max;
+ char *buf;
+ ext2_dirhash_t *hashes;
+};
+
+static int fill_dir_block(ext2_filsys fs,
+ blk_t *block_nr,
+ e2_blkcnt_t blockcnt,
+ blk_t ref_block FSCK_ATTR((unused)),
+ int ref_offset FSCK_ATTR((unused)),
+ void *priv_data)
+{
+ struct fill_dir_struct *fd = (struct fill_dir_struct *) priv_data;
+ struct hash_entry *new_array, *ent;
+ struct ext2_dir_entry *dirent;
+ char *dir;
+ unsigned int offset, dir_offset;
+
+ if (blockcnt < 0)
+ return 0;
+
+ offset = blockcnt * fs->blocksize;
+ if (offset + fs->blocksize > fd->inode->i_size) {
+ fd->err = EXT2_ET_DIR_CORRUPTED;
+ return BLOCK_ABORT;
+ }
+ dir = (fd->buf+offset);
+ if (HOLE_BLKADDR(*block_nr)) {
+ memset(dir, 0, fs->blocksize);
+ dirent = (struct ext2_dir_entry *) dir;
+ dirent->rec_len = fs->blocksize;
+ } else {
+ fd->err = ext2fs_read_dir_block(fs, *block_nr, dir);
+ if (fd->err)
+ return BLOCK_ABORT;
+ }
+ /* While the directory block is "hot", index it. */
+ dir_offset = 0;
+ while (dir_offset < fs->blocksize) {
+ dirent = (struct ext2_dir_entry *) (dir + dir_offset);
+ if (((dir_offset + dirent->rec_len) > fs->blocksize) ||
+ (dirent->rec_len < 8) ||
+ ((dirent->rec_len % 4) != 0) ||
+ (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
+ fd->err = EXT2_ET_DIR_CORRUPTED;
+ return BLOCK_ABORT;
+ }
+ dir_offset += dirent->rec_len;
+ if (dirent->inode == 0)
+ continue;
+ if (!fd->compress && ((dirent->name_len&0xFF) == 1) &&
+ (dirent->name[0] == '.'))
+ continue;
+ if (!fd->compress && ((dirent->name_len&0xFF) == 2) &&
+ (dirent->name[0] == '.') && (dirent->name[1] == '.')) {
+ fd->parent = dirent->inode;
+ continue;
+ }
+ if (fd->num_array >= fd->max_array) {
+ new_array = realloc(fd->harray,
+ sizeof(struct hash_entry) * (fd->max_array+500));
+ if (!new_array) {
+ fd->err = ENOMEM;
+ return BLOCK_ABORT;
+ }
+ fd->harray = new_array;
+ fd->max_array += 500;
+ }
+ ent = fd->harray + fd->num_array++;
+ ent->dir = dirent;
+ fd->dir_size += EXT2_DIR_REC_LEN(dirent->name_len & 0xFF);
+ if (fd->compress)
+ ent->hash = ent->minor_hash = 0;
+ else {
+ fd->err = ext2fs_dirhash(fs->super->s_def_hash_version,
+ dirent->name,
+ dirent->name_len & 0xFF,
+ fs->super->s_hash_seed,
+ &ent->hash, &ent->minor_hash);
+ if (fd->err)
+ return BLOCK_ABORT;
+ }
+ }
+
+ return 0;
+}
+
+/* Used for sorting the hash entry */
+static int name_cmp(const void *a, const void *b)
+{
+ const struct hash_entry *he_a = (const struct hash_entry *) a;
+ const struct hash_entry *he_b = (const struct hash_entry *) b;
+ int ret;
+ int min_len;
+
+ min_len = he_a->dir->name_len;
+ if (min_len > he_b->dir->name_len)
+ min_len = he_b->dir->name_len;
+
+ ret = strncmp(he_a->dir->name, he_b->dir->name, min_len);
+ if (ret == 0) {
+ if (he_a->dir->name_len > he_b->dir->name_len)
+ ret = 1;
+ else if (he_a->dir->name_len < he_b->dir->name_len)
+ ret = -1;
+ else
+ ret = he_b->dir->inode - he_a->dir->inode;
+ }
+ return ret;
+}
+
+/* Used for sorting the hash entry */
+static int hash_cmp(const void *a, const void *b)
+{
+ const struct hash_entry *he_a = (const struct hash_entry *) a;
+ const struct hash_entry *he_b = (const struct hash_entry *) b;
+ int ret;
+
+ if (he_a->hash > he_b->hash)
+ ret = 1;
+ else if (he_a->hash < he_b->hash)
+ ret = -1;
+ else {
+ if (he_a->minor_hash > he_b->minor_hash)
+ ret = 1;
+ else if (he_a->minor_hash < he_b->minor_hash)
+ ret = -1;
+ else
+ ret = name_cmp(a, b);
+ }
+ return ret;
+}
+
+static errcode_t alloc_size_dir(ext2_filsys fs, struct out_dir *outdir,
+ int blocks)
+{
+ void *new_mem;
+
+ if (outdir->max) {
+ new_mem = realloc(outdir->buf, blocks * fs->blocksize);
+ if (!new_mem)
+ return ENOMEM;
+ outdir->buf = new_mem;
+ new_mem = realloc(outdir->hashes,
+ blocks * sizeof(ext2_dirhash_t));
+ if (!new_mem)
+ return ENOMEM;
+ outdir->hashes = new_mem;
+ } else {
+ outdir->buf = malloc(blocks * fs->blocksize);
+ outdir->hashes = malloc(blocks * sizeof(ext2_dirhash_t));
+ outdir->num = 0;
+ }
+ outdir->max = blocks;
+ return 0;
+}
+
+static void free_out_dir(struct out_dir *outdir)
+{
+ free(outdir->buf);
+ free(outdir->hashes);
+ outdir->max = 0;
+ outdir->num =0;
+}
+
+static errcode_t get_next_block(ext2_filsys fs, struct out_dir *outdir,
+ char ** ret)
+{
+ errcode_t retval;
+
+ if (outdir->num >= outdir->max) {
+ retval = alloc_size_dir(fs, outdir, outdir->max + 50);
+ if (retval)
+ return retval;
+ }
+ *ret = outdir->buf + (outdir->num++ * fs->blocksize);
+ memset(*ret, 0, fs->blocksize);
+ return 0;
+}
+
+/*
+ * This function is used to make a unique filename. We do this by
+ * appending ~0, and then incrementing the number. However, we cannot
+ * expand the length of the filename beyond the padding available in
+ * the directory entry.
+ */
+static void mutate_name(char *str, __u16 *len)
+{
+ int i;
+ __u16 l = *len & 0xFF, h = *len & 0xff00;
+
+ /*
+ * First check to see if it looks the name has been mutated
+ * already
+ */
+ for (i = l-1; i > 0; i--) {
+ if (!isdigit(str[i]))
+ break;
+ }
+ if ((i == l-1) || (str[i] != '~')) {
+ if (((l-1) & 3) < 2)
+ l += 2;
+ else
+ l = (l+3) & ~3;
+ str[l-2] = '~';
+ str[l-1] = '0';
+ *len = l | h;
+ return;
+ }
+ for (i = l-1; i >= 0; i--) {
+ if (isdigit(str[i])) {
+ if (str[i] == '9')
+ str[i] = '0';
+ else {
+ str[i]++;
+ return;
+ }
+ continue;
+ }
+ if (i == 1) {
+ if (str[0] == 'z')
+ str[0] = 'A';
+ else if (str[0] == 'Z') {
+ str[0] = '~';
+ str[1] = '0';
+ } else
+ str[0]++;
+ } else if (i > 0) {
+ str[i] = '1';
+ str[i-1] = '~';
+ } else {
+ if (str[0] == '~')
+ str[0] = 'a';
+ else
+ str[0]++;
+ }
+ break;
+ }
+}
+
+static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs,
+ ext2_ino_t ino,
+ struct fill_dir_struct *fd)
+{
+ struct problem_context pctx;
+ struct hash_entry *ent, *prev;
+ int i, j;
+ int fixed = 0;
+ char new_name[256];
+ __u16 new_len;
+
+ clear_problem_context(&pctx);
+ pctx.ino = ino;
+
+ for (i=1; i < fd->num_array; i++) {
+ ent = fd->harray + i;
+ prev = ent - 1;
+ if (!ent->dir->inode ||
+ ((ent->dir->name_len & 0xFF) !=
+ (prev->dir->name_len & 0xFF)) ||
+ (strncmp(ent->dir->name, prev->dir->name,
+ ent->dir->name_len & 0xFF)))
+ continue;
+ pctx.dirent = ent->dir;
+ if ((ent->dir->inode == prev->dir->inode) &&
+ fix_problem(ctx, PR_2_DUPLICATE_DIRENT, &pctx)) {
+ e2fsck_adjust_inode_count(ctx, ent->dir->inode, -1);
+ ent->dir->inode = 0;
+ fixed++;
+ continue;
+ }
+ memcpy(new_name, ent->dir->name, ent->dir->name_len & 0xFF);
+ new_len = ent->dir->name_len;
+ mutate_name(new_name, &new_len);
+ for (j=0; j < fd->num_array; j++) {
+ if ((i==j) ||
+ ((ent->dir->name_len & 0xFF) !=
+ (fd->harray[j].dir->name_len & 0xFF)) ||
+ (strncmp(new_name, fd->harray[j].dir->name,
+ new_len & 0xFF)))
+ continue;
+ mutate_name(new_name, &new_len);
+
+ j = -1;
+ }
+ new_name[new_len & 0xFF] = 0;
+ pctx.str = new_name;
+ if (fix_problem(ctx, PR_2_NON_UNIQUE_FILE, &pctx)) {
+ memcpy(ent->dir->name, new_name, new_len & 0xFF);
+ ent->dir->name_len = new_len;
+ ext2fs_dirhash(fs->super->s_def_hash_version,
+ ent->dir->name,
+ ent->dir->name_len & 0xFF,
+ fs->super->s_hash_seed,
+ &ent->hash, &ent->minor_hash);
+ fixed++;
+ }
+ }
+ return fixed;
+}
+
+
+static errcode_t copy_dir_entries(ext2_filsys fs,
+ struct fill_dir_struct *fd,
+ struct out_dir *outdir)
+{
+ errcode_t retval;
+ char *block_start;
+ struct hash_entry *ent;
+ struct ext2_dir_entry *dirent;
+ int i, rec_len, left;
+ ext2_dirhash_t prev_hash;
+ int offset;
+
+ outdir->max = 0;
+ retval = alloc_size_dir(fs, outdir,
+ (fd->dir_size / fs->blocksize) + 2);
+ if (retval)
+ return retval;
+ outdir->num = fd->compress ? 0 : 1;
+ offset = 0;
+ outdir->hashes[0] = 0;
+ prev_hash = 1;
+ if ((retval = get_next_block(fs, outdir, &block_start)))
+ return retval;
+ dirent = (struct ext2_dir_entry *) block_start;
+ left = fs->blocksize;
+ for (i=0; i < fd->num_array; i++) {
+ ent = fd->harray + i;
+ if (ent->dir->inode == 0)
+ continue;
+ rec_len = EXT2_DIR_REC_LEN(ent->dir->name_len & 0xFF);
+ if (rec_len > left) {
+ if (left)
+ dirent->rec_len += left;
+ if ((retval = get_next_block(fs, outdir,
+ &block_start)))
+ return retval;
+ offset = 0;
+ }
+ left = fs->blocksize - offset;
+ dirent = (struct ext2_dir_entry *) (block_start + offset);
+ if (offset == 0) {
+ if (ent->hash == prev_hash)
+ outdir->hashes[outdir->num-1] = ent->hash | 1;
+ else
+ outdir->hashes[outdir->num-1] = ent->hash;
+ }
+ dirent->inode = ent->dir->inode;
+ dirent->name_len = ent->dir->name_len;
+ dirent->rec_len = rec_len;
+ memcpy(dirent->name, ent->dir->name, dirent->name_len & 0xFF);
+ offset += rec_len;
+ left -= rec_len;
+ if (left < 12) {
+ dirent->rec_len += left;
+ offset += left;
+ left = 0;
+ }
+ prev_hash = ent->hash;
+ }
+ if (left)
+ dirent->rec_len += left;
+
+ return 0;
+}
+
+
+static struct ext2_dx_root_info *set_root_node(ext2_filsys fs, char *buf,
+ ext2_ino_t ino, ext2_ino_t parent)
+{
+ struct ext2_dir_entry *dir;
+ struct ext2_dx_root_info *root;
+ struct ext2_dx_countlimit *limits;
+ int filetype = 0;
+
+ if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
+ filetype = EXT2_FT_DIR << 8;
+
+ memset(buf, 0, fs->blocksize);
+ dir = (struct ext2_dir_entry *) buf;
+ dir->inode = ino;
+ dir->name[0] = '.';
+ dir->name_len = 1 | filetype;
+ dir->rec_len = 12;
+ dir = (struct ext2_dir_entry *) (buf + 12);
+ dir->inode = parent;
+ dir->name[0] = '.';
+ dir->name[1] = '.';
+ dir->name_len = 2 | filetype;
+ dir->rec_len = fs->blocksize - 12;
+
+ root = (struct ext2_dx_root_info *) (buf+24);
+ root->reserved_zero = 0;
+ root->hash_version = fs->super->s_def_hash_version;
+ root->info_length = 8;
+ root->indirect_levels = 0;
+ root->unused_flags = 0;
+
+ limits = (struct ext2_dx_countlimit *) (buf+32);
+ limits->limit = (fs->blocksize - 32) / sizeof(struct ext2_dx_entry);
+ limits->count = 0;
+
+ return root;
+}
+
+
+static struct ext2_dx_entry *set_int_node(ext2_filsys fs, char *buf)
+{
+ struct ext2_dir_entry *dir;
+ struct ext2_dx_countlimit *limits;
+
+ memset(buf, 0, fs->blocksize);
+ dir = (struct ext2_dir_entry *) buf;
+ dir->inode = 0;
+ dir->rec_len = fs->blocksize;
+
+ limits = (struct ext2_dx_countlimit *) (buf+8);
+ limits->limit = (fs->blocksize - 8) / sizeof(struct ext2_dx_entry);
+ limits->count = 0;
+
+ return (struct ext2_dx_entry *) limits;
+}
+
+/*
+ * This function takes the leaf nodes which have been written in
+ * outdir, and populates the root node and any necessary interior nodes.
+ */
+static errcode_t calculate_tree(ext2_filsys fs,
+ struct out_dir *outdir,
+ ext2_ino_t ino,
+ ext2_ino_t parent)
+{
+ struct ext2_dx_root_info *root_info;
+ struct ext2_dx_entry *root, *dx_ent = 0;
+ struct ext2_dx_countlimit *root_limit, *limit;
+ errcode_t retval;
+ char * block_start;
+ int i, c1, c2, nblks;
+ int limit_offset, root_offset;
+
+ root_info = set_root_node(fs, outdir->buf, ino, parent);
+ root_offset = limit_offset = ((char *) root_info - outdir->buf) +
+ root_info->info_length;
+ root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
+ c1 = root_limit->limit;
+ nblks = outdir->num;
+
+ /* Write out the pointer blocks */
+ if (nblks-1 <= c1) {
+ /* Just write out the root block, and we're done */
+ root = (struct ext2_dx_entry *) (outdir->buf + root_offset);
+ for (i=1; i < nblks; i++) {
+ root->block = ext2fs_cpu_to_le32(i);
+ if (i != 1)
+ root->hash =
+ ext2fs_cpu_to_le32(outdir->hashes[i]);
+ root++;
+ c1--;
+ }
+ } else {
+ c2 = 0;
+ limit = 0;
+ root_info->indirect_levels = 1;
+ for (i=1; i < nblks; i++) {
+ if (c1 == 0)
+ return ENOSPC;
+ if (c2 == 0) {
+ if (limit)
+ limit->limit = limit->count =
+ ext2fs_cpu_to_le16(limit->limit);
+ root = (struct ext2_dx_entry *)
+ (outdir->buf + root_offset);
+ root->block = ext2fs_cpu_to_le32(outdir->num);
+ if (i != 1)
+ root->hash =
+ ext2fs_cpu_to_le32(outdir->hashes[i]);
+ if ((retval = get_next_block(fs, outdir,
+ &block_start)))
+ return retval;
+ dx_ent = set_int_node(fs, block_start);
+ limit = (struct ext2_dx_countlimit *) dx_ent;
+ c2 = limit->limit;
+ root_offset += sizeof(struct ext2_dx_entry);
+ c1--;
+ }
+ dx_ent->block = ext2fs_cpu_to_le32(i);
+ if (c2 != limit->limit)
+ dx_ent->hash =
+ ext2fs_cpu_to_le32(outdir->hashes[i]);
+ dx_ent++;
+ c2--;
+ }
+ limit->count = ext2fs_cpu_to_le16(limit->limit - c2);
+ limit->limit = ext2fs_cpu_to_le16(limit->limit);
+ }
+ root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
+ root_limit->count = ext2fs_cpu_to_le16(root_limit->limit - c1);
+ root_limit->limit = ext2fs_cpu_to_le16(root_limit->limit);
+
+ return 0;
+}
+
+struct write_dir_struct {
+ struct out_dir *outdir;
+ errcode_t err;
+ e2fsck_t ctx;
+ int cleared;
+};
+
+/*
+ * Helper function which writes out a directory block.
+ */
+static int write_dir_block(ext2_filsys fs,
+ blk_t *block_nr,
+ e2_blkcnt_t blockcnt,
+ blk_t ref_block FSCK_ATTR((unused)),
+ int ref_offset FSCK_ATTR((unused)),
+ void *priv_data)
+{
+ struct write_dir_struct *wd = (struct write_dir_struct *) priv_data;
+ blk_t blk;
+ char *dir;
+
+ if (*block_nr == 0)
+ return 0;
+ if (blockcnt >= wd->outdir->num) {
+ e2fsck_read_bitmaps(wd->ctx);
+ blk = *block_nr;
+ ext2fs_unmark_block_bitmap(wd->ctx->block_found_map, blk);
+ ext2fs_block_alloc_stats(fs, blk, -1);
+ *block_nr = 0;
+ wd->cleared++;
+ return BLOCK_CHANGED;
+ }
+ if (blockcnt < 0)
+ return 0;
+
+ dir = wd->outdir->buf + (blockcnt * fs->blocksize);
+ wd->err = ext2fs_write_dir_block(fs, *block_nr, dir);
+ if (wd->err)
+ return BLOCK_ABORT;
+ return 0;
+}
+
+static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs,
+ struct out_dir *outdir,
+ ext2_ino_t ino, int compress)
+{
+ struct write_dir_struct wd;
+ errcode_t retval;
+ struct ext2_inode inode;
+
+ retval = e2fsck_expand_directory(ctx, ino, -1, outdir->num);
+ if (retval)
+ return retval;
+
+ wd.outdir = outdir;
+ wd.err = 0;
+ wd.ctx = ctx;
+ wd.cleared = 0;
+
+ retval = ext2fs_block_iterate2(fs, ino, 0, 0,
+ write_dir_block, &wd);
+ if (retval)
+ return retval;
+ if (wd.err)
+ return wd.err;
+
+ e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
+ if (compress)
+ inode.i_flags &= ~EXT2_INDEX_FL;
+ else
+ inode.i_flags |= EXT2_INDEX_FL;
+ inode.i_size = outdir->num * fs->blocksize;
+ inode.i_blocks -= (fs->blocksize / 512) * wd.cleared;
+ e2fsck_write_inode(ctx, ino, &inode, "rehash_dir");
+
+ return 0;
+}
+
+static errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino)
+{
+ ext2_filsys fs = ctx->fs;
+ errcode_t retval;
+ struct ext2_inode inode;
+ char *dir_buf = 0;
+ struct fill_dir_struct fd;
+ struct out_dir outdir;
+
+ outdir.max = outdir.num = 0;
+ outdir.buf = 0;
+ outdir.hashes = 0;
+ e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
+
+ retval = ENOMEM;
+ fd.harray = 0;
+ dir_buf = malloc(inode.i_size);
+ if (!dir_buf)
+ goto errout;
+
+ fd.max_array = inode.i_size / 32;
+ fd.num_array = 0;
+ fd.harray = malloc(fd.max_array * sizeof(struct hash_entry));
+ if (!fd.harray)
+ goto errout;
+
+ fd.ctx = ctx;
+ fd.buf = dir_buf;
+ fd.inode = &inode;
+ fd.err = 0;
+ fd.dir_size = 0;
+ fd.compress = 0;
+ if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) ||
+ (inode.i_size / fs->blocksize) < 2)
+ fd.compress = 1;
+ fd.parent = 0;
+
+ /* Read in the entire directory into memory */
+ retval = ext2fs_block_iterate2(fs, ino, 0, 0,
+ fill_dir_block, &fd);
+ if (fd.err) {
+ retval = fd.err;
+ goto errout;
+ }
+
+ /* Sort the list */
+resort:
+ if (fd.compress)
+ qsort(fd.harray+2, fd.num_array-2,
+ sizeof(struct hash_entry), name_cmp);
+ else
+ qsort(fd.harray, fd.num_array,
+ sizeof(struct hash_entry), hash_cmp);
+
+ /*
+ * Look for duplicates
+ */
+ if (duplicate_search_and_fix(ctx, fs, ino, &fd))
+ goto resort;
+
+ if (ctx->options & E2F_OPT_NO) {
+ retval = 0;
+ goto errout;
+ }
+
+ /*
+ * Copy the directory entries. In a htree directory these
+ * will become the leaf nodes.
+ */
+ retval = copy_dir_entries(fs, &fd, &outdir);
+ if (retval)
+ goto errout;
+
+ free(dir_buf); dir_buf = 0;
+
+ if (!fd.compress) {
+ /* Calculate the interior nodes */
+ retval = calculate_tree(fs, &outdir, ino, fd.parent);
+ if (retval)
+ goto errout;
+ }
+
+ retval = write_directory(ctx, fs, &outdir, ino, fd.compress);
+
+errout:
+ free(dir_buf);
+ free(fd.harray);
+
+ free_out_dir(&outdir);
+ return retval;
+}
+
+void e2fsck_rehash_directories(e2fsck_t ctx)
+{
+ struct problem_context pctx;
+ struct dir_info *dir;
+ ext2_u32_iterate iter;
+ ext2_ino_t ino;
+ errcode_t retval;
+ int i, cur, max, all_dirs, dir_index, first = 1;
+
+ all_dirs = ctx->options & E2F_OPT_COMPRESS_DIRS;
+
+ if (!ctx->dirs_to_hash && !all_dirs)
+ return;
+
+ e2fsck_get_lost_and_found(ctx, 0);
+
+ clear_problem_context(&pctx);
+
+ dir_index = ctx->fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX;
+ cur = 0;
+ if (all_dirs) {
+ i = 0;
+ max = e2fsck_get_num_dirinfo(ctx);
+ } else {
+ retval = ext2fs_u32_list_iterate_begin(ctx->dirs_to_hash,
+ &iter);
+ if (retval) {
+ pctx.errcode = retval;
+ fix_problem(ctx, PR_3A_OPTIMIZE_ITER, &pctx);
+ return;
+ }
+ max = ext2fs_u32_list_count(ctx->dirs_to_hash);
+ }
+ while (1) {
+ if (all_dirs) {
+ if ((dir = e2fsck_dir_info_iter(ctx, &i)) == 0)
+ break;
+ ino = dir->ino;
+ } else {
+ if (!ext2fs_u32_list_iterate(iter, &ino))
+ break;
+ }
+ if (ino == ctx->lost_and_found)
+ continue;
+ pctx.dir = ino;
+ if (first) {
+ fix_problem(ctx, PR_3A_PASS_HEADER, &pctx);
+ first = 0;
+ }
+ pctx.errcode = e2fsck_rehash_dir(ctx, ino);
+ if (pctx.errcode) {
+ end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR);
+ fix_problem(ctx, PR_3A_OPTIMIZE_DIR_ERR, &pctx);
+ }
+ if (ctx->progress && !ctx->progress_fd)
+ e2fsck_simple_progress(ctx, "Rebuilding directory",
+ 100.0 * (float) (++cur) / (float) max, ino);
+ }
+ end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR);
+ if (!all_dirs)
+ ext2fs_u32_list_iterate_end(iter);
+
+ ext2fs_u32_list_free(ctx->dirs_to_hash);
+ ctx->dirs_to_hash = 0;
+}
+
+/*
+ * linux/fs/revoke.c
+ *
+ * Journal revoke routines for the generic filesystem journaling code;
+ * part of the ext2fs journaling system.
+ *
+ * Revoke is the mechanism used to prevent old log records for deleted
+ * metadata from being replayed on top of newer data using the same
+ * blocks. The revoke mechanism is used in two separate places:
+ *
+ * + Commit: during commit we write the entire list of the current
+ * transaction's revoked blocks to the journal
+ *
+ * + Recovery: during recovery we record the transaction ID of all
+ * revoked blocks. If there are multiple revoke records in the log
+ * for a single block, only the last one counts, and if there is a log
+ * entry for a block beyond the last revoke, then that log entry still
+ * gets replayed.
+ *
+ * We can get interactions between revokes and new log data within a
+ * single transaction:
+ *
+ * Block is revoked and then journaled:
+ * The desired end result is the journaling of the new block, so we
+ * cancel the revoke before the transaction commits.
+ *
+ * Block is journaled and then revoked:
+ * The revoke must take precedence over the write of the block, so we
+ * need either to cancel the journal entry or to write the revoke
+ * later in the log than the log block. In this case, we choose the
+ * latter: journaling a block cancels any revoke record for that block
+ * in the current transaction, so any revoke for that block in the
+ * transaction must have happened after the block was journaled and so
+ * the revoke must take precedence.
+ *
+ * Block is revoked and then written as data:
+ * The data write is allowed to succeed, but the revoke is _not_
+ * cancelled. We still need to prevent old log records from
+ * overwriting the new data. We don't even need to clear the revoke
+ * bit here.
+ *
+ * Revoke information on buffers is a tri-state value:
+ *
+ * RevokeValid clear: no cached revoke status, need to look it up
+ * RevokeValid set, Revoked clear:
+ * buffer has not been revoked, and cancel_revoke
+ * need do nothing.
+ * RevokeValid set, Revoked set:
+ * buffer has been revoked.
+ */
+
+static kmem_cache_t *revoke_record_cache;
+static kmem_cache_t *revoke_table_cache;
+
+/* Each revoke record represents one single revoked block. During
+ journal replay, this involves recording the transaction ID of the
+ last transaction to revoke this block. */
+
+struct jbd_revoke_record_s
+{
+ struct list_head hash;
+ tid_t sequence; /* Used for recovery only */
+ unsigned long blocknr;
+};
+
+
+/* The revoke table is just a simple hash table of revoke records. */
+struct jbd_revoke_table_s
+{
+ /* It is conceivable that we might want a larger hash table
+ * for recovery. Must be a power of two. */
+ int hash_size;
+ int hash_shift;
+ struct list_head *hash_table;
+};
+
+
+/* Utility functions to maintain the revoke table */
+
+/* Borrowed from buffer.c: this is a tried and tested block hash function */
+static int hash(journal_t *journal, unsigned long block)
+{
+ struct jbd_revoke_table_s *table = journal->j_revoke;
+ int hash_shift = table->hash_shift;
+
+ return ((block << (hash_shift - 6)) ^
+ (block >> 13) ^
+ (block << (hash_shift - 12))) & (table->hash_size - 1);
+}
+
+static int insert_revoke_hash(journal_t *journal, unsigned long blocknr,
+ tid_t seq)
+{
+ struct list_head *hash_list;
+ struct jbd_revoke_record_s *record;
+
+ record = kmem_cache_alloc(revoke_record_cache, GFP_NOFS);
+ if (!record)
+ goto oom;
+
+ record->sequence = seq;
+ record->blocknr = blocknr;
+ hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
+ list_add(&record->hash, hash_list);
+ return 0;
+
+oom:
+ return -ENOMEM;
+}
+
+/* Find a revoke record in the journal's hash table. */
+
+static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal,
+ unsigned long blocknr)
+{
+ struct list_head *hash_list;
+ struct jbd_revoke_record_s *record;
+
+ hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
+
+ record = (struct jbd_revoke_record_s *) hash_list->next;
+ while (&(record->hash) != hash_list) {
+ if (record->blocknr == blocknr)
+ return record;
+ record = (struct jbd_revoke_record_s *) record->hash.next;
+ }
+ return NULL;
+}
+
+int journal_init_revoke_caches(void)
+{
+ revoke_record_cache = do_cache_create(sizeof(struct jbd_revoke_record_s));
+ if (revoke_record_cache == 0)
+ return -ENOMEM;
+
+ revoke_table_cache = do_cache_create(sizeof(struct jbd_revoke_table_s));
+ if (revoke_table_cache == 0) {
+ do_cache_destroy(revoke_record_cache);
+ revoke_record_cache = NULL;
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+void journal_destroy_revoke_caches(void)
+{
+ do_cache_destroy(revoke_record_cache);
+ revoke_record_cache = 0;
+ do_cache_destroy(revoke_table_cache);
+ revoke_table_cache = 0;
+}
+
+/* Initialise the revoke table for a given journal to a given size. */
+
+int journal_init_revoke(journal_t *journal, int hash_size)
+{
+ int shift, tmp;
+
+ journal->j_revoke = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL);
+ if (!journal->j_revoke)
+ return -ENOMEM;
+
+ /* Check that the hash_size is a power of two */
+ journal->j_revoke->hash_size = hash_size;
+
+ shift = 0;
+ tmp = hash_size;
+ while((tmp >>= 1UL) != 0UL)
+ shift++;
+ journal->j_revoke->hash_shift = shift;
+
+ journal->j_revoke->hash_table = malloc(hash_size * sizeof(struct list_head));
+ if (!journal->j_revoke->hash_table) {
+ free(journal->j_revoke);
+ journal->j_revoke = NULL;
+ return -ENOMEM;
+ }
+
+ for (tmp = 0; tmp < hash_size; tmp++)
+ INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
+
+ return 0;
+}
+
+/* Destoy a journal's revoke table. The table must already be empty! */
+
+void journal_destroy_revoke(journal_t *journal)
+{
+ struct jbd_revoke_table_s *table;
+ struct list_head *hash_list;
+ int i;
+
+ table = journal->j_revoke;
+ if (!table)
+ return;
+
+ for (i=0; i<table->hash_size; i++) {
+ hash_list = &table->hash_table[i];
+ }
+
+ free(table->hash_table);
+ free(table);
+ journal->j_revoke = NULL;
+}
+
+/*
+ * Revoke support for recovery.
+ *
+ * Recovery needs to be able to:
+ *
+ * record all revoke records, including the tid of the latest instance
+ * of each revoke in the journal
+ *
+ * check whether a given block in a given transaction should be replayed
+ * (ie. has not been revoked by a revoke record in that or a subsequent
+ * transaction)
+ *
+ * empty the revoke table after recovery.
+ */
+
+/*
+ * First, setting revoke records. We create a new revoke record for
+ * every block ever revoked in the log as we scan it for recovery, and
+ * we update the existing records if we find multiple revokes for a
+ * single block.
+ */
+
+int journal_set_revoke(journal_t *journal, unsigned long blocknr,
+ tid_t sequence)
+{
+ struct jbd_revoke_record_s *record;
+
+ record = find_revoke_record(journal, blocknr);
+ if (record) {
+ /* If we have multiple occurences, only record the
+ * latest sequence number in the hashed record */
+ if (tid_gt(sequence, record->sequence))
+ record->sequence = sequence;
+ return 0;
+ }
+ return insert_revoke_hash(journal, blocknr, sequence);
+}
+
+/*
+ * Test revoke records. For a given block referenced in the log, has
+ * that block been revoked? A revoke record with a given transaction
+ * sequence number revokes all blocks in that transaction and earlier
+ * ones, but later transactions still need replayed.
+ */
+
+int journal_test_revoke(journal_t *journal, unsigned long blocknr,
+ tid_t sequence)
+{
+ struct jbd_revoke_record_s *record;
+
+ record = find_revoke_record(journal, blocknr);
+ if (!record)
+ return 0;
+ if (tid_gt(sequence, record->sequence))
+ return 0;
+ return 1;
+}
+
+/*
+ * Finally, once recovery is over, we need to clear the revoke table so
+ * that it can be reused by the running filesystem.
+ */
+
+void journal_clear_revoke(journal_t *journal)
+{
+ int i;
+ struct list_head *hash_list;
+ struct jbd_revoke_record_s *record;
+ struct jbd_revoke_table_s *revoke_var;
+
+ revoke_var = journal->j_revoke;
+
+ for (i = 0; i < revoke_var->hash_size; i++) {
+ hash_list = &revoke_var->hash_table[i];
+ while (!list_empty(hash_list)) {
+ record = (struct jbd_revoke_record_s*) hash_list->next;
+ list_del(&record->hash);
+ free(record);
+ }
+ }
+}
+
+/*
+ * e2fsck.c - superblock checks
+ */
+
+#define MIN_CHECK 1
+#define MAX_CHECK 2
+
+static void check_super_value(e2fsck_t ctx, const char *descr,
+ unsigned long value, int flags,
+ unsigned long min_val, unsigned long max_val)
+{
+ struct problem_context pctx;
+
+ if (((flags & MIN_CHECK) && (value < min_val)) ||
+ ((flags & MAX_CHECK) && (value > max_val))) {
+ clear_problem_context(&pctx);
+ pctx.num = value;
+ pctx.str = descr;
+ fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT; /* never get here! */
+ }
+}
+
+/*
+ * This routine may get stubbed out in special compilations of the
+ * e2fsck code..
+ */
+#ifndef EXT2_SPECIAL_DEVICE_SIZE
+static errcode_t e2fsck_get_device_size(e2fsck_t ctx)
+{
+ return (ext2fs_get_device_size(ctx->filesystem_name,
+ EXT2_BLOCK_SIZE(ctx->fs->super),
+ &ctx->num_blocks));
+}
+#endif
+
+/*
+ * helper function to release an inode
+ */
+struct process_block_struct {
+ e2fsck_t ctx;
+ char *buf;
+ struct problem_context *pctx;
+ int truncating;
+ int truncate_offset;
+ e2_blkcnt_t truncate_block;
+ int truncated_blocks;
+ int abort;
+ errcode_t errcode;
+};
+
+static int release_inode_block(ext2_filsys fs, blk_t *block_nr,
+ e2_blkcnt_t blockcnt,
+ blk_t ref_blk FSCK_ATTR((unused)),
+ int ref_offset FSCK_ATTR((unused)),
+ void *priv_data)
+{
+ struct process_block_struct *pb;
+ e2fsck_t ctx;
+ struct problem_context *pctx;
+ blk_t blk = *block_nr;
+ int retval = 0;
+
+ pb = (struct process_block_struct *) priv_data;
+ ctx = pb->ctx;
+ pctx = pb->pctx;
+
+ pctx->blk = blk;
+ pctx->blkcount = blockcnt;
+
+ if (HOLE_BLKADDR(blk))
+ return 0;
+
+ if ((blk < fs->super->s_first_data_block) ||
+ (blk >= fs->super->s_blocks_count)) {
+ fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, pctx);
+ return_abort:
+ pb->abort = 1;
+ return BLOCK_ABORT;
+ }
+
+ if (!ext2fs_test_block_bitmap(fs->block_map, blk)) {
+ fix_problem(ctx, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK, pctx);
+ goto return_abort;
+ }
+
+ /*
+ * If we are deleting an orphan, then we leave the fields alone.
+ * If we are truncating an orphan, then update the inode fields
+ * and clean up any partial block data.
+ */
+ if (pb->truncating) {
+ /*
+ * We only remove indirect blocks if they are
+ * completely empty.
+ */
+ if (blockcnt < 0) {
+ int i, limit;
+ blk_t *bp;
+
+ pb->errcode = io_channel_read_blk(fs->io, blk, 1,
+ pb->buf);
+ if (pb->errcode)
+ goto return_abort;
+
+ limit = fs->blocksize >> 2;
+ for (i = 0, bp = (blk_t *) pb->buf;
+ i < limit; i++, bp++)
+ if (*bp)
+ return 0;
+ }
+ /*
+ * We don't remove direct blocks until we've reached
+ * the truncation block.
+ */
+ if (blockcnt >= 0 && blockcnt < pb->truncate_block)
+ return 0;
+ /*
+ * If part of the last block needs truncating, we do
+ * it here.
+ */
+ if ((blockcnt == pb->truncate_block) && pb->truncate_offset) {
+ pb->errcode = io_channel_read_blk(fs->io, blk, 1,
+ pb->buf);
+ if (pb->errcode)
+ goto return_abort;
+ memset(pb->buf + pb->truncate_offset, 0,
+ fs->blocksize - pb->truncate_offset);
+ pb->errcode = io_channel_write_blk(fs->io, blk, 1,
+ pb->buf);
+ if (pb->errcode)
+ goto return_abort;
+ }
+ pb->truncated_blocks++;
+ *block_nr = 0;
+ retval |= BLOCK_CHANGED;
+ }
+
+ ext2fs_block_alloc_stats(fs, blk, -1);
+ return retval;
+}
+
+/*
+ * This function releases an inode. Returns 1 if an inconsistency was
+ * found. If the inode has a link count, then it is being truncated and
+ * not deleted.
+ */
+static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino,
+ struct ext2_inode *inode, char *block_buf,
+ struct problem_context *pctx)
+{
+ struct process_block_struct pb;
+ ext2_filsys fs = ctx->fs;
+ errcode_t retval;
+ __u32 count;
+
+ if (!ext2fs_inode_has_valid_blocks(inode))
+ return 0;
+
+ pb.buf = block_buf + 3 * ctx->fs->blocksize;
+ pb.ctx = ctx;
+ pb.abort = 0;
+ pb.errcode = 0;
+ pb.pctx = pctx;
+ if (inode->i_links_count) {
+ pb.truncating = 1;
+ pb.truncate_block = (e2_blkcnt_t)
+ ((((long long)inode->i_size_high << 32) +
+ inode->i_size + fs->blocksize - 1) /
+ fs->blocksize);
+ pb.truncate_offset = inode->i_size % fs->blocksize;
+ } else {
+ pb.truncating = 0;
+ pb.truncate_block = 0;
+ pb.truncate_offset = 0;
+ }
+ pb.truncated_blocks = 0;
+ retval = ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_DEPTH_TRAVERSE,
+ block_buf, release_inode_block, &pb);
+ if (retval) {
+ bb_error_msg(_("while calling ext2fs_block_iterate for inode %d"),
+ ino);
+ return 1;
+ }
+ if (pb.abort)
+ return 1;
+
+ /* Refresh the inode since ext2fs_block_iterate may have changed it */
+ e2fsck_read_inode(ctx, ino, inode, "release_inode_blocks");
+
+ if (pb.truncated_blocks)
+ inode->i_blocks -= pb.truncated_blocks *
+ (fs->blocksize / 512);
+
+ if (inode->i_file_acl) {
+ retval = ext2fs_adjust_ea_refcount(fs, inode->i_file_acl,
+ block_buf, -1, &count);
+ if (retval == EXT2_ET_BAD_EA_BLOCK_NUM) {
+ retval = 0;
+ count = 1;
+ }
+ if (retval) {
+ bb_error_msg(_("while calling ext2fs_adjust_ea_refocunt for inode %d"),
+ ino);
+ return 1;
+ }
+ if (count == 0)
+ ext2fs_block_alloc_stats(fs, inode->i_file_acl, -1);
+ inode->i_file_acl = 0;
+ }
+ return 0;
+}
+
+/*
+ * This function releases all of the orphan inodes. It returns 1 if
+ * it hit some error, and 0 on success.
+ */
+static int release_orphan_inodes(e2fsck_t ctx)
+{
+ ext2_filsys fs = ctx->fs;
+ ext2_ino_t ino, next_ino;
+ struct ext2_inode inode;
+ struct problem_context pctx;
+ char *block_buf;
+
+ if ((ino = fs->super->s_last_orphan) == 0)
+ return 0;
+
+ /*
+ * Win or lose, we won't be using the head of the orphan inode
+ * list again.
+ */
+ fs->super->s_last_orphan = 0;
+ ext2fs_mark_super_dirty(fs);
+
+ /*
+ * If the filesystem contains errors, don't run the orphan
+ * list, since the orphan list can't be trusted; and we're
+ * going to be running a full e2fsck run anyway...
+ */
+ if (fs->super->s_state & EXT2_ERROR_FS)
+ return 0;
+
+ if ((ino < EXT2_FIRST_INODE(fs->super)) ||
+ (ino > fs->super->s_inodes_count)) {
+ clear_problem_context(&pctx);
+ pctx.ino = ino;
+ fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_HEAD_INODE, &pctx);
+ return 1;
+ }
+
+ block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
+ "block iterate buffer");
+ e2fsck_read_bitmaps(ctx);
+
+ while (ino) {
+ e2fsck_read_inode(ctx, ino, &inode, "release_orphan_inodes");
+ clear_problem_context(&pctx);
+ pctx.ino = ino;
+ pctx.inode = &inode;
+ pctx.str = inode.i_links_count ? _("Truncating") :
+ _("Clearing");
+
+ fix_problem(ctx, PR_0_ORPHAN_CLEAR_INODE, &pctx);
+
+ next_ino = inode.i_dtime;
+ if (next_ino &&
+ ((next_ino < EXT2_FIRST_INODE(fs->super)) ||
+ (next_ino > fs->super->s_inodes_count))) {
+ pctx.ino = next_ino;
+ fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_INODE, &pctx);
+ goto return_abort;
+ }
+
+ if (release_inode_blocks(ctx, ino, &inode, block_buf, &pctx))
+ goto return_abort;
+
+ if (!inode.i_links_count) {
+ ext2fs_inode_alloc_stats2(fs, ino, -1,
+ LINUX_S_ISDIR(inode.i_mode));
+ inode.i_dtime = time(0);
+ } else {
+ inode.i_dtime = 0;
+ }
+ e2fsck_write_inode(ctx, ino, &inode, "delete_file");
+ ino = next_ino;
+ }
+ ext2fs_free_mem(&block_buf);
+ return 0;
+return_abort:
+ ext2fs_free_mem(&block_buf);
+ return 1;
+}
+
+/*
+ * Check the resize inode to make sure it is sane. We check both for
+ * the case where on-line resizing is not enabled (in which case the
+ * resize inode should be cleared) as well as the case where on-line
+ * resizing is enabled.
+ */
+static void check_resize_inode(e2fsck_t ctx)
+{
+ ext2_filsys fs = ctx->fs;
+ struct ext2_inode inode;
+ struct problem_context pctx;
+ int i, j, gdt_off, ind_off;
+ blk_t blk, pblk, expect;
+ __u32 *dind_buf = 0, *ind_buf;
+ errcode_t retval;
+
+ clear_problem_context(&pctx);
+
+ /*
+ * If the resize inode feature isn't set, then
+ * s_reserved_gdt_blocks must be zero.
+ */
+ if (!(fs->super->s_feature_compat &
+ EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
+ if (fs->super->s_reserved_gdt_blocks) {
+ pctx.num = fs->super->s_reserved_gdt_blocks;
+ if (fix_problem(ctx, PR_0_NONZERO_RESERVED_GDT_BLOCKS,
+ &pctx)) {
+ fs->super->s_reserved_gdt_blocks = 0;
+ ext2fs_mark_super_dirty(fs);
+ }
+ }
+ }
+
+ /* Read the resize inode */
+ pctx.ino = EXT2_RESIZE_INO;
+ retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
+ if (retval) {
+ if (fs->super->s_feature_compat &
+ EXT2_FEATURE_COMPAT_RESIZE_INODE)
+ ctx->flags |= E2F_FLAG_RESIZE_INODE;
+ return;
+ }
+
+ /*
+ * If the resize inode feature isn't set, check to make sure
+ * the resize inode is cleared; then we're done.
+ */
+ if (!(fs->super->s_feature_compat &
+ EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
+ for (i=0; i < EXT2_N_BLOCKS; i++) {
+ if (inode.i_block[i])
+ break;
+ }
+ if ((i < EXT2_N_BLOCKS) &&
+ fix_problem(ctx, PR_0_CLEAR_RESIZE_INODE, &pctx)) {
+ memset(&inode, 0, sizeof(inode));
+ e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode,
+ "clear_resize");
+ }
+ return;
+ }
+
+ /*
+ * The resize inode feature is enabled; check to make sure the
+ * only block in use is the double indirect block
+ */
+ blk = inode.i_block[EXT2_DIND_BLOCK];
+ for (i=0; i < EXT2_N_BLOCKS; i++) {
+ if (i != EXT2_DIND_BLOCK && inode.i_block[i])
+ break;
+ }
+ if ((i < EXT2_N_BLOCKS) || !blk || !inode.i_links_count ||
+ !(inode.i_mode & LINUX_S_IFREG) ||
+ (blk < fs->super->s_first_data_block ||
+ blk >= fs->super->s_blocks_count)) {
+ resize_inode_invalid:
+ if (fix_problem(ctx, PR_0_RESIZE_INODE_INVALID, &pctx)) {
+ memset(&inode, 0, sizeof(inode));
+ e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode,
+ "clear_resize");
+ ctx->flags |= E2F_FLAG_RESIZE_INODE;
+ }
+ if (!(ctx->options & E2F_OPT_READONLY)) {
+ fs->super->s_state &= ~EXT2_VALID_FS;
+ ext2fs_mark_super_dirty(fs);
+ }
+ goto cleanup;
+ }
+ dind_buf = (__u32 *) e2fsck_allocate_memory(ctx, fs->blocksize * 2,
+ "resize dind buffer");
+ ind_buf = (__u32 *) ((char *) dind_buf + fs->blocksize);
+
+ retval = ext2fs_read_ind_block(fs, blk, dind_buf);
+ if (retval)
+ goto resize_inode_invalid;
+
+ gdt_off = fs->desc_blocks;
+ pblk = fs->super->s_first_data_block + 1 + fs->desc_blocks;
+ for (i = 0; i < fs->super->s_reserved_gdt_blocks / 4;
+ i++, gdt_off++, pblk++) {
+ gdt_off %= fs->blocksize/4;
+ if (dind_buf[gdt_off] != pblk)
+ goto resize_inode_invalid;
+ retval = ext2fs_read_ind_block(fs, pblk, ind_buf);
+ if (retval)
+ goto resize_inode_invalid;
+ ind_off = 0;
+ for (j = 1; j < fs->group_desc_count; j++) {
+ if (!ext2fs_bg_has_super(fs, j))
+ continue;
+ expect = pblk + (j * fs->super->s_blocks_per_group);
+ if (ind_buf[ind_off] != expect)
+ goto resize_inode_invalid;
+ ind_off++;
+ }
+ }
+
+cleanup:
+ ext2fs_free_mem(&dind_buf);
+
+ }
+
+static void check_super_block(e2fsck_t ctx)
+{
+ ext2_filsys fs = ctx->fs;
+ blk_t first_block, last_block;
+ struct ext2_super_block *sb = fs->super;
+ struct ext2_group_desc *gd;
+ blk_t blocks_per_group = fs->super->s_blocks_per_group;
+ blk_t bpg_max;
+ int inodes_per_block;
+ int ipg_max;
+ int inode_size;
+ dgrp_t i;
+ blk_t should_be;
+ struct problem_context pctx;
+ __u32 free_blocks = 0, free_inodes = 0;
+
+ inodes_per_block = EXT2_INODES_PER_BLOCK(fs->super);
+ ipg_max = inodes_per_block * (blocks_per_group - 4);
+ if (ipg_max > EXT2_MAX_INODES_PER_GROUP(sb))
+ ipg_max = EXT2_MAX_INODES_PER_GROUP(sb);
+ bpg_max = 8 * EXT2_BLOCK_SIZE(sb);
+ if (bpg_max > EXT2_MAX_BLOCKS_PER_GROUP(sb))
+ bpg_max = EXT2_MAX_BLOCKS_PER_GROUP(sb);
+
+ ctx->invalid_inode_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
+ sizeof(int) * fs->group_desc_count, "invalid_inode_bitmap");
+ ctx->invalid_block_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
+ sizeof(int) * fs->group_desc_count, "invalid_block_bitmap");
+ ctx->invalid_inode_table_flag = (int *) e2fsck_allocate_memory(ctx,
+ sizeof(int) * fs->group_desc_count, "invalid_inode_table");
+
+ clear_problem_context(&pctx);
+
+ /*
+ * Verify the super block constants...
+ */
+ check_super_value(ctx, "inodes_count", sb->s_inodes_count,
+ MIN_CHECK, 1, 0);
+ check_super_value(ctx, "blocks_count", sb->s_blocks_count,
+ MIN_CHECK, 1, 0);
+ check_super_value(ctx, "first_data_block", sb->s_first_data_block,
+ MAX_CHECK, 0, sb->s_blocks_count);
+ check_super_value(ctx, "log_block_size", sb->s_log_block_size,
+ MIN_CHECK | MAX_CHECK, 0,
+ EXT2_MAX_BLOCK_LOG_SIZE - EXT2_MIN_BLOCK_LOG_SIZE);
+ check_super_value(ctx, "log_frag_size", sb->s_log_frag_size,
+ MIN_CHECK | MAX_CHECK, 0, sb->s_log_block_size);
+ check_super_value(ctx, "frags_per_group", sb->s_frags_per_group,
+ MIN_CHECK | MAX_CHECK, sb->s_blocks_per_group,
+ bpg_max);
+ check_super_value(ctx, "blocks_per_group", sb->s_blocks_per_group,
+ MIN_CHECK | MAX_CHECK, 8, bpg_max);
+ check_super_value(ctx, "inodes_per_group", sb->s_inodes_per_group,
+ MIN_CHECK | MAX_CHECK, inodes_per_block, ipg_max);
+ check_super_value(ctx, "r_blocks_count", sb->s_r_blocks_count,
+ MAX_CHECK, 0, sb->s_blocks_count / 2);
+ check_super_value(ctx, "reserved_gdt_blocks",
+ sb->s_reserved_gdt_blocks, MAX_CHECK, 0,
+ fs->blocksize/4);
+ inode_size = EXT2_INODE_SIZE(sb);
+ check_super_value(ctx, "inode_size",
+ inode_size, MIN_CHECK | MAX_CHECK,
+ EXT2_GOOD_OLD_INODE_SIZE, fs->blocksize);
+ if (inode_size & (inode_size - 1)) {
+ pctx.num = inode_size;
+ pctx.str = "inode_size";
+ fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT; /* never get here! */
+ return;
+ }
+
+ if (!ctx->num_blocks) {
+ pctx.errcode = e2fsck_get_device_size(ctx);
+ if (pctx.errcode && pctx.errcode != EXT2_ET_UNIMPLEMENTED) {
+ fix_problem(ctx, PR_0_GETSIZE_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ if ((pctx.errcode != EXT2_ET_UNIMPLEMENTED) &&
+ (ctx->num_blocks < sb->s_blocks_count)) {
+ pctx.blk = sb->s_blocks_count;
+ pctx.blk2 = ctx->num_blocks;
+ if (fix_problem(ctx, PR_0_FS_SIZE_WRONG, &pctx)) {
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ }
+ }
+
+ if (sb->s_log_block_size != (__u32) sb->s_log_frag_size) {
+ pctx.blk = EXT2_BLOCK_SIZE(sb);
+ pctx.blk2 = EXT2_FRAG_SIZE(sb);
+ fix_problem(ctx, PR_0_NO_FRAGMENTS, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+
+ should_be = sb->s_frags_per_group >>
+ (sb->s_log_block_size - sb->s_log_frag_size);
+ if (sb->s_blocks_per_group != should_be) {
+ pctx.blk = sb->s_blocks_per_group;
+ pctx.blk2 = should_be;
+ fix_problem(ctx, PR_0_BLOCKS_PER_GROUP, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+
+ should_be = (sb->s_log_block_size == 0) ? 1 : 0;
+ if (sb->s_first_data_block != should_be) {
+ pctx.blk = sb->s_first_data_block;
+ pctx.blk2 = should_be;
+ fix_problem(ctx, PR_0_FIRST_DATA_BLOCK, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+
+ should_be = sb->s_inodes_per_group * fs->group_desc_count;
+ if (sb->s_inodes_count != should_be) {
+ pctx.ino = sb->s_inodes_count;
+ pctx.ino2 = should_be;
+ if (fix_problem(ctx, PR_0_INODE_COUNT_WRONG, &pctx)) {
+ sb->s_inodes_count = should_be;
+ ext2fs_mark_super_dirty(fs);
+ }
+ }
+
+ /*
+ * Verify the group descriptors....
+ */
+ first_block = sb->s_first_data_block;
+ last_block = first_block + blocks_per_group;
+
+ for (i = 0, gd=fs->group_desc; i < fs->group_desc_count; i++, gd++) {
+ pctx.group = i;
+
+ if (i == fs->group_desc_count - 1)
+ last_block = sb->s_blocks_count;
+ if ((gd->bg_block_bitmap < first_block) ||
+ (gd->bg_block_bitmap >= last_block)) {
+ pctx.blk = gd->bg_block_bitmap;
+ if (fix_problem(ctx, PR_0_BB_NOT_GROUP, &pctx))
+ gd->bg_block_bitmap = 0;
+ }
+ if (gd->bg_block_bitmap == 0) {
+ ctx->invalid_block_bitmap_flag[i]++;
+ ctx->invalid_bitmaps++;
+ }
+ if ((gd->bg_inode_bitmap < first_block) ||
+ (gd->bg_inode_bitmap >= last_block)) {
+ pctx.blk = gd->bg_inode_bitmap;
+ if (fix_problem(ctx, PR_0_IB_NOT_GROUP, &pctx))
+ gd->bg_inode_bitmap = 0;
+ }
+ if (gd->bg_inode_bitmap == 0) {
+ ctx->invalid_inode_bitmap_flag[i]++;
+ ctx->invalid_bitmaps++;
+ }
+ if ((gd->bg_inode_table < first_block) ||
+ ((gd->bg_inode_table +
+ fs->inode_blocks_per_group - 1) >= last_block)) {
+ pctx.blk = gd->bg_inode_table;
+ if (fix_problem(ctx, PR_0_ITABLE_NOT_GROUP, &pctx))
+ gd->bg_inode_table = 0;
+ }
+ if (gd->bg_inode_table == 0) {
+ ctx->invalid_inode_table_flag[i]++;
+ ctx->invalid_bitmaps++;
+ }
+ free_blocks += gd->bg_free_blocks_count;
+ free_inodes += gd->bg_free_inodes_count;
+ first_block += sb->s_blocks_per_group;
+ last_block += sb->s_blocks_per_group;
+
+ if ((gd->bg_free_blocks_count > sb->s_blocks_per_group) ||
+ (gd->bg_free_inodes_count > sb->s_inodes_per_group) ||
+ (gd->bg_used_dirs_count > sb->s_inodes_per_group))
+ ext2fs_unmark_valid(fs);
+
+ }
+
+ /*
+ * Update the global counts from the block group counts. This
+ * is needed for an experimental patch which eliminates
+ * locking the entire filesystem when allocating blocks or
+ * inodes; if the filesystem is not unmounted cleanly, the
+ * global counts may not be accurate.
+ */
+ if ((free_blocks != sb->s_free_blocks_count) ||
+ (free_inodes != sb->s_free_inodes_count)) {
+ if (ctx->options & E2F_OPT_READONLY)
+ ext2fs_unmark_valid(fs);
+ else {
+ sb->s_free_blocks_count = free_blocks;
+ sb->s_free_inodes_count = free_inodes;
+ ext2fs_mark_super_dirty(fs);
+ }
+ }
+
+ if ((sb->s_free_blocks_count > sb->s_blocks_count) ||
+ (sb->s_free_inodes_count > sb->s_inodes_count))
+ ext2fs_unmark_valid(fs);
+
+
+ /*
+ * If we have invalid bitmaps, set the error state of the
+ * filesystem.
+ */
+ if (ctx->invalid_bitmaps && !(ctx->options & E2F_OPT_READONLY)) {
+ sb->s_state &= ~EXT2_VALID_FS;
+ ext2fs_mark_super_dirty(fs);
+ }
+
+ clear_problem_context(&pctx);
+
+ /*
+ * If the UUID field isn't assigned, assign it.
+ */
+ if (!(ctx->options & E2F_OPT_READONLY) && uuid_is_null(sb->s_uuid)) {
+ if (fix_problem(ctx, PR_0_ADD_UUID, &pctx)) {
+ uuid_generate(sb->s_uuid);
+ ext2fs_mark_super_dirty(fs);
+ fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
+ }
+ }
+
+ /* FIXME - HURD support?
+ * For the Hurd, check to see if the filetype option is set,
+ * since it doesn't support it.
+ */
+ if (!(ctx->options & E2F_OPT_READONLY) &&
+ fs->super->s_creator_os == EXT2_OS_HURD &&
+ (fs->super->s_feature_incompat &
+ EXT2_FEATURE_INCOMPAT_FILETYPE)) {
+ if (fix_problem(ctx, PR_0_HURD_CLEAR_FILETYPE, &pctx)) {
+ fs->super->s_feature_incompat &=
+ ~EXT2_FEATURE_INCOMPAT_FILETYPE;
+ ext2fs_mark_super_dirty(fs);
+
+ }
+ }
+
+ /*
+ * If we have any of the compatibility flags set, we need to have a
+ * revision 1 filesystem. Most kernels will not check the flags on
+ * a rev 0 filesystem and we may have corruption issues because of
+ * the incompatible changes to the filesystem.
+ */
+ if (!(ctx->options & E2F_OPT_READONLY) &&
+ fs->super->s_rev_level == EXT2_GOOD_OLD_REV &&
+ (fs->super->s_feature_compat ||
+ fs->super->s_feature_ro_compat ||
+ fs->super->s_feature_incompat) &&
+ fix_problem(ctx, PR_0_FS_REV_LEVEL, &pctx)) {
+ ext2fs_update_dynamic_rev(fs);
+ ext2fs_mark_super_dirty(fs);
+ }
+
+ check_resize_inode(ctx);
+
+ /*
+ * Clean up any orphan inodes, if present.
+ */
+ if (!(ctx->options & E2F_OPT_READONLY) && release_orphan_inodes(ctx)) {
+ fs->super->s_state &= ~EXT2_VALID_FS;
+ ext2fs_mark_super_dirty(fs);
+ }
+
+ /*
+ * Move the ext3 journal file, if necessary.
+ */
+ e2fsck_move_ext3_journal(ctx);
+}
+
+/*
+ * swapfs.c --- byte-swap an ext2 filesystem
+ */
+
+#ifdef ENABLE_SWAPFS
+
+struct swap_block_struct {
+ ext2_ino_t ino;
+ int isdir;
+ errcode_t errcode;
+ char *dir_buf;
+ struct ext2_inode *inode;
+};
+
+/*
+ * This is a helper function for block_iterate. We mark all of the
+ * indirect and direct blocks as changed, so that block_iterate will
+ * write them out.
+ */
+static int swap_block(ext2_filsys fs, blk_t *block_nr, int blockcnt,
+ void *priv_data)
+{
+ errcode_t retval;
+
+ struct swap_block_struct *sb = (struct swap_block_struct *) priv_data;
+
+ if (sb->isdir && (blockcnt >= 0) && *block_nr) {
+ retval = ext2fs_read_dir_block(fs, *block_nr, sb->dir_buf);
+ if (retval) {
+ sb->errcode = retval;
+ return BLOCK_ABORT;
+ }
+ retval = ext2fs_write_dir_block(fs, *block_nr, sb->dir_buf);
+ if (retval) {
+ sb->errcode = retval;
+ return BLOCK_ABORT;
+ }
+ }
+ if (blockcnt >= 0) {
+ if (blockcnt < EXT2_NDIR_BLOCKS)
+ return 0;
+ return BLOCK_CHANGED;
+ }
+ if (blockcnt == BLOCK_COUNT_IND) {
+ if (*block_nr == sb->inode->i_block[EXT2_IND_BLOCK])
+ return 0;
+ return BLOCK_CHANGED;
+ }
+ if (blockcnt == BLOCK_COUNT_DIND) {
+ if (*block_nr == sb->inode->i_block[EXT2_DIND_BLOCK])
+ return 0;
+ return BLOCK_CHANGED;
+ }
+ if (blockcnt == BLOCK_COUNT_TIND) {
+ if (*block_nr == sb->inode->i_block[EXT2_TIND_BLOCK])
+ return 0;
+ return BLOCK_CHANGED;
+ }
+ return BLOCK_CHANGED;
+}
+
+/*
+ * This function is responsible for byte-swapping all of the indirect,
+ * block pointers. It is also responsible for byte-swapping directories.
+ */
+static void swap_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, char *block_buf,
+ struct ext2_inode *inode)
+{
+ errcode_t retval;
+ struct swap_block_struct sb;
+
+ sb.ino = ino;
+ sb.inode = inode;
+ sb.dir_buf = block_buf + ctx->fs->blocksize*3;
+ sb.errcode = 0;
+ sb.isdir = 0;
+ if (LINUX_S_ISDIR(inode->i_mode))
+ sb.isdir = 1;
+
+ retval = ext2fs_block_iterate(ctx->fs, ino, 0, block_buf,
+ swap_block, &sb);
+ if (retval) {
+ bb_error_msg(_("while calling ext2fs_block_iterate"));
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ if (sb.errcode) {
+ bb_error_msg(_("while calling iterator function"));
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+}
+
+static void swap_inodes(e2fsck_t ctx)
+{
+ ext2_filsys fs = ctx->fs;
+ dgrp_t group;
+ unsigned int i;
+ ext2_ino_t ino = 1;
+ char *buf, *block_buf;
+ errcode_t retval;
+ struct ext2_inode * inode;
+
+ e2fsck_use_inode_shortcuts(ctx, 1);
+
+ retval = ext2fs_get_mem(fs->blocksize * fs->inode_blocks_per_group,
+ &buf);
+ if (retval) {
+ bb_error_msg(_("while allocating inode buffer"));
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
+ "block interate buffer");
+ for (group = 0; group < fs->group_desc_count; group++) {
+ retval = io_channel_read_blk(fs->io,
+ fs->group_desc[group].bg_inode_table,
+ fs->inode_blocks_per_group, buf);
+ if (retval) {
+ bb_error_msg(_("while reading inode table (group %d)"),
+ group);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ inode = (struct ext2_inode *) buf;
+ for (i=0; i < fs->super->s_inodes_per_group;
+ i++, ino++, inode++) {
+ ctx->stashed_ino = ino;
+ ctx->stashed_inode = inode;
+
+ if (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)
+ ext2fs_swap_inode(fs, inode, inode, 0);
+
+ /*
+ * Skip deleted files.
+ */
+ if (inode->i_links_count == 0)
+ continue;
+
+ if (LINUX_S_ISDIR(inode->i_mode) ||
+ ((inode->i_block[EXT2_IND_BLOCK] ||
+ inode->i_block[EXT2_DIND_BLOCK] ||
+ inode->i_block[EXT2_TIND_BLOCK]) &&
+ ext2fs_inode_has_valid_blocks(inode)))
+ swap_inode_blocks(ctx, ino, block_buf, inode);
+
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ return;
+
+ if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
+ ext2fs_swap_inode(fs, inode, inode, 1);
+ }
+ retval = io_channel_write_blk(fs->io,
+ fs->group_desc[group].bg_inode_table,
+ fs->inode_blocks_per_group, buf);
+ if (retval) {
+ bb_error_msg(_("while writing inode table (group %d)"),
+ group);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ }
+ ext2fs_free_mem(&buf);
+ ext2fs_free_mem(&block_buf);
+ e2fsck_use_inode_shortcuts(ctx, 0);
+ ext2fs_flush_icache(fs);
+}
+
+#if defined(__powerpc__) && BB_BIG_ENDIAN
+/*
+ * On the PowerPC, the big-endian variant of the ext2 filesystem
+ * has its bitmaps stored as 32-bit words with bit 0 as the LSB
+ * of each word. Thus a bitmap with only bit 0 set would be, as
+ * a string of bytes, 00 00 00 01 00 ...
+ * To cope with this, we byte-reverse each word of a bitmap if
+ * we have a big-endian filesystem, that is, if we are *not*
+ * byte-swapping other word-sized numbers.
+ */
+#define EXT2_BIG_ENDIAN_BITMAPS
+#endif
+
+#ifdef EXT2_BIG_ENDIAN_BITMAPS
+static void ext2fs_swap_bitmap(ext2fs_generic_bitmap bmap)
+{
+ __u32 *p = (__u32 *) bmap->bitmap;
+ int n, nbytes = (bmap->end - bmap->start + 7) / 8;
+
+ for (n = nbytes / sizeof(__u32); n > 0; --n, ++p)
+ *p = ext2fs_swab32(*p);
+}
+#endif
+
+
+#ifdef ENABLE_SWAPFS
+static void swap_filesys(e2fsck_t ctx)
+{
+ ext2_filsys fs = ctx->fs;
+ if (!(ctx->options & E2F_OPT_PREEN))
+ printf(_("Pass 0: Doing byte-swap of filesystem\n"));
+
+ /* Byte swap */
+
+ if (fs->super->s_mnt_count) {
+ fprintf(stderr, _("%s: the filesystem must be freshly "
+ "checked using fsck\n"
+ "and not mounted before trying to "
+ "byte-swap it.\n"), ctx->device_name);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
+ fs->flags &= ~(EXT2_FLAG_SWAP_BYTES|
+ EXT2_FLAG_SWAP_BYTES_WRITE);
+ fs->flags |= EXT2_FLAG_SWAP_BYTES_READ;
+ } else {
+ fs->flags &= ~EXT2_FLAG_SWAP_BYTES_READ;
+ fs->flags |= EXT2_FLAG_SWAP_BYTES_WRITE;
+ }
+ swap_inodes(ctx);
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ return;
+ if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
+ fs->flags |= EXT2_FLAG_SWAP_BYTES;
+ fs->flags &= ~(EXT2_FLAG_SWAP_BYTES_READ|
+ EXT2_FLAG_SWAP_BYTES_WRITE);
+
+#ifdef EXT2_BIG_ENDIAN_BITMAPS
+ e2fsck_read_bitmaps(ctx);
+ ext2fs_swap_bitmap(fs->inode_map);
+ ext2fs_swap_bitmap(fs->block_map);
+ fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
+#endif
+ fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
+ ext2fs_flush(fs);
+ fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
+}
+#endif /* ENABLE_SWAPFS */
+
+#endif
+
+/*
+ * util.c --- miscellaneous utilities
+ */
+
+
+void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
+ const char *description)
+{
+ void *ret;
+ char buf[256];
+
+ ret = malloc(size);
+ if (!ret) {
+ sprintf(buf, "Can't allocate %s\n", description);
+ bb_error_msg_and_die(buf);
+ }
+ memset(ret, 0, size);
+ return ret;
+}
+
+static char *string_copy(const char *str, int len)
+{
+ char *ret;
+
+ if (!str)
+ return NULL;
+ if (!len)
+ len = strlen(str);
+ ret = malloc(len+1);
+ if (ret) {
+ strncpy(ret, str, len);
+ ret[len] = 0;
+ }
+ return ret;
+}
+
+#ifndef HAVE_CONIO_H
+static int read_a_char(void)
+{
+ char c;
+ int r;
+ int fail = 0;
+
+ while(1) {
+ if (e2fsck_global_ctx &&
+ (e2fsck_global_ctx->flags & E2F_FLAG_CANCEL)) {
+ return 3;
+ }
+ r = read(0, &c, 1);
+ if (r == 1)
+ return c;
+ if (fail++ > 100)
+ break;
+ }
+ return EOF;
+}
+#endif
+
+static int ask_yn(const char * string, int def)
+{
+ int c;
+ const char *defstr;
+ static const char short_yes[] = "yY";
+ static const char short_no[] = "nN";
+
+#ifdef HAVE_TERMIOS_H
+ struct termios termios, tmp;
+
+ tcgetattr (0, &termios);
+ tmp = termios;
+ tmp.c_lflag &= ~(ICANON | ECHO);
+ tmp.c_cc[VMIN] = 1;
+ tmp.c_cc[VTIME] = 0;
+ tcsetattr (0, TCSANOW, &tmp);
+#endif
+
+ if (def == 1)
+ defstr = "<y>";
+ else if (def == 0)
+ defstr = "<n>";
+ else
+ defstr = " (y/n)";
+ printf("%s%s? ", string, defstr);
+ while (1) {
+ fflush (stdout);
+ if ((c = read_a_char()) == EOF)
+ break;
+ if (c == 3) {
+#ifdef HAVE_TERMIOS_H
+ tcsetattr (0, TCSANOW, &termios);
+#endif
+ if (e2fsck_global_ctx &&
+ e2fsck_global_ctx->flags & E2F_FLAG_SETJMP_OK) {
+ puts("\n");
+ longjmp(e2fsck_global_ctx->abort_loc, 1);
+ }
+ puts(_("cancelled!\n"));
+ return 0;
+ }
+ if (strchr(short_yes, (char) c)) {
+ def = 1;
+ break;
+ }
+ else if (strchr(short_no, (char) c)) {
+ def = 0;
+ break;
+ }
+ else if ((c == ' ' || c == '\n') && (def != -1))
+ break;
+ }
+ if (def)
+ puts("yes\n");
+ else
+ puts ("no\n");
+#ifdef HAVE_TERMIOS_H
+ tcsetattr (0, TCSANOW, &termios);
+#endif
+ return def;
+}
+
+int ask (e2fsck_t ctx, const char * string, int def)
+{
+ if (ctx->options & E2F_OPT_NO) {
+ printf(_("%s? no\n\n"), string);
+ return 0;
+ }
+ if (ctx->options & E2F_OPT_YES) {
+ printf(_("%s? yes\n\n"), string);
+ return 1;
+ }
+ if (ctx->options & E2F_OPT_PREEN) {
+ printf("%s? %s\n\n", string, def ? _("yes") : _("no"));
+ return def;
+ }
+ return ask_yn(string, def);
+}
+
+void e2fsck_read_bitmaps(e2fsck_t ctx)
+{
+ ext2_filsys fs = ctx->fs;
+ errcode_t retval;
+
+ if (ctx->invalid_bitmaps) {
+ bb_error_msg(_("e2fsck_read_bitmaps: illegal bitmap block(s) for %s"),
+ ctx->device_name);
+ bb_error_msg_and_die(0);
+ }
+
+ ehandler_operation(_("reading inode and block bitmaps"));
+ retval = ext2fs_read_bitmaps(fs);
+ ehandler_operation(0);
+ if (retval) {
+ bb_error_msg(_("while retrying to read bitmaps for %s"),
+ ctx->device_name);
+ bb_error_msg_and_die(0);
+ }
+}
+
+static void e2fsck_write_bitmaps(e2fsck_t ctx)
+{
+ ext2_filsys fs = ctx->fs;
+ errcode_t retval;
+
+ if (ext2fs_test_bb_dirty(fs)) {
+ ehandler_operation(_("writing block bitmaps"));
+ retval = ext2fs_write_block_bitmap(fs);
+ ehandler_operation(0);
+ if (retval) {
+ bb_error_msg(_("while retrying to write block bitmaps for %s"),
+ ctx->device_name);
+ bb_error_msg_and_die(0);
+ }
+ }
+
+ if (ext2fs_test_ib_dirty(fs)) {
+ ehandler_operation(_("writing inode bitmaps"));
+ retval = ext2fs_write_inode_bitmap(fs);
+ ehandler_operation(0);
+ if (retval) {
+ bb_error_msg(_("while retrying to write inode bitmaps for %s"),
+ ctx->device_name);
+ bb_error_msg_and_die(0);
+ }
+ }
+}
+
+void preenhalt(e2fsck_t ctx)
+{
+ ext2_filsys fs = ctx->fs;
+
+ if (!(ctx->options & E2F_OPT_PREEN))
+ return;
+ fprintf(stderr, _("\n\n%s: UNEXPECTED INCONSISTENCY; "
+ "RUN fsck MANUALLY.\n\t(i.e., without -a or -p options)\n"),
+ ctx->device_name);
+ if (fs != NULL) {
+ fs->super->s_state |= EXT2_ERROR_FS;
+ ext2fs_mark_super_dirty(fs);
+ ext2fs_close(fs);
+ }
+ exit(EXIT_UNCORRECTED);
+}
+
+void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
+ struct ext2_inode * inode, const char *proc)
+{
+ int retval;
+
+ retval = ext2fs_read_inode(ctx->fs, ino, inode);
+ if (retval) {
+ bb_error_msg(_("while reading inode %ld in %s"), ino, proc);
+ bb_error_msg_and_die(0);
+ }
+}
+
+extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
+ struct ext2_inode * inode, int bufsize,
+ const char *proc)
+{
+ int retval;
+
+ retval = ext2fs_write_inode_full(ctx->fs, ino, inode, bufsize);
+ if (retval) {
+ bb_error_msg(_("while writing inode %ld in %s"), ino, proc);
+ bb_error_msg_and_die(0);
+ }
+}
+
+extern void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
+ struct ext2_inode * inode, const char *proc)
+{
+ int retval;
+
+ retval = ext2fs_write_inode(ctx->fs, ino, inode);
+ if (retval) {
+ bb_error_msg(_("while writing inode %ld in %s"), ino, proc);
+ bb_error_msg_and_die(0);
+ }
+}
+
+blk_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs, const char *name,
+ io_manager manager)
+{
+ struct ext2_super_block *sb;
+ io_channel io = NULL;
+ void *buf = NULL;
+ int blocksize;
+ blk_t superblock, ret_sb = 8193;
+
+ if (fs && fs->super) {
+ ret_sb = (fs->super->s_blocks_per_group +
+ fs->super->s_first_data_block);
+ if (ctx) {
+ ctx->superblock = ret_sb;
+ ctx->blocksize = fs->blocksize;
+ }
+ return ret_sb;
+ }
+
+ if (ctx) {
+ if (ctx->blocksize) {
+ ret_sb = ctx->blocksize * 8;
+ if (ctx->blocksize == 1024)
+ ret_sb++;
+ ctx->superblock = ret_sb;
+ return ret_sb;
+ }
+ ctx->superblock = ret_sb;
+ ctx->blocksize = 1024;
+ }
+
+ if (!name || !manager)
+ goto cleanup;
+
+ if (manager->open(name, 0, &io) != 0)
+ goto cleanup;
+
+ if (ext2fs_get_mem(SUPERBLOCK_SIZE, &buf))
+ goto cleanup;
+ sb = (struct ext2_super_block *) buf;
+
+ for (blocksize = EXT2_MIN_BLOCK_SIZE;
+ blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) {
+ superblock = blocksize*8;
+ if (blocksize == 1024)
+ superblock++;
+ io_channel_set_blksize(io, blocksize);
+ if (io_channel_read_blk(io, superblock,
+ -SUPERBLOCK_SIZE, buf))
+ continue;
+#if BB_BIG_ENDIAN
+ if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
+ ext2fs_swap_super(sb);
+#endif
+ if (sb->s_magic == EXT2_SUPER_MAGIC) {
+ ret_sb = superblock;
+ if (ctx) {
+ ctx->superblock = superblock;
+ ctx->blocksize = blocksize;
+ }
+ break;
+ }
+ }
+
+cleanup:
+ if (io)
+ io_channel_close(io);
+ ext2fs_free_mem(&buf);
+ return ret_sb;
+}
+
+
+/*
+ * This function runs through the e2fsck passes and calls them all,
+ * returning restart, abort, or cancel as necessary...
+ */
+typedef void (*pass_t)(e2fsck_t ctx);
+
+static const pass_t e2fsck_passes[] = {
+ e2fsck_pass1, e2fsck_pass2, e2fsck_pass3, e2fsck_pass4,
+ e2fsck_pass5, 0 };
+
+#define E2F_FLAG_RUN_RETURN (E2F_FLAG_SIGNAL_MASK|E2F_FLAG_RESTART)
+
+static int e2fsck_run(e2fsck_t ctx)
+{
+ int i;
+ pass_t e2fsck_pass;
+
+ if (setjmp(ctx->abort_loc)) {
+ ctx->flags &= ~E2F_FLAG_SETJMP_OK;
+ return (ctx->flags & E2F_FLAG_RUN_RETURN);
+ }
+ ctx->flags |= E2F_FLAG_SETJMP_OK;
+
+ for (i=0; (e2fsck_pass = e2fsck_passes[i]); i++) {
+ if (ctx->flags & E2F_FLAG_RUN_RETURN)
+ break;
+ e2fsck_pass(ctx);
+ if (ctx->progress)
+ (void) (ctx->progress)(ctx, 0, 0, 0);
+ }
+ ctx->flags &= ~E2F_FLAG_SETJMP_OK;
+
+ if (ctx->flags & E2F_FLAG_RUN_RETURN)
+ return (ctx->flags & E2F_FLAG_RUN_RETURN);
+ return 0;
+}
+
+
+/*
+ * unix.c - The unix-specific code for e2fsck
+ */
+
+
+/* Command line options */
+static int swapfs;
+#ifdef ENABLE_SWAPFS
+static int normalize_swapfs;
+#endif
+static int cflag; /* check disk */
+static int show_version_only;
+static int verbose;
+
+#define P_E2(singular, plural, n) n, ((n) == 1 ? singular : plural)
+
+static void show_stats(e2fsck_t ctx)
+{
+ ext2_filsys fs = ctx->fs;
+ int inodes, inodes_used, blocks, blocks_used;
+ int dir_links;
+ int num_files, num_links;
+ int frag_percent;
+
+ dir_links = 2 * ctx->fs_directory_count - 1;
+ num_files = ctx->fs_total_count - dir_links;
+ num_links = ctx->fs_links_count - dir_links;
+ inodes = fs->super->s_inodes_count;
+ inodes_used = (fs->super->s_inodes_count -
+ fs->super->s_free_inodes_count);
+ blocks = fs->super->s_blocks_count;
+ blocks_used = (fs->super->s_blocks_count -
+ fs->super->s_free_blocks_count);
+
+ frag_percent = (10000 * ctx->fs_fragmented) / inodes_used;
+ frag_percent = (frag_percent + 5) / 10;
+
+ if (!verbose) {
+ printf("%s: %d/%d files (%0d.%d%% non-contiguous), %d/%d blocks\n",
+ ctx->device_name, inodes_used, inodes,
+ frag_percent / 10, frag_percent % 10,
+ blocks_used, blocks);
+ return;
+ }
+ printf("\n%8d inode%s used (%d%%)\n", P_E2("", "s", inodes_used),
+ 100 * inodes_used / inodes);
+ printf("%8d non-contiguous inode%s (%0d.%d%%)\n",
+ P_E2("", "s", ctx->fs_fragmented),
+ frag_percent / 10, frag_percent % 10);
+ printf(_(" # of inodes with ind/dind/tind blocks: %d/%d/%d\n"),
+ ctx->fs_ind_count, ctx->fs_dind_count, ctx->fs_tind_count);
+ printf("%8d block%s used (%d%%)\n", P_E2("", "s", blocks_used),
+ (int) ((long long) 100 * blocks_used / blocks));
+ printf("%8d large file%s\n", P_E2("", "s", ctx->large_files));
+ printf("\n%8d regular file%s\n", P_E2("", "s", ctx->fs_regular_count));
+ printf("%8d director%s\n", P_E2("y", "ies", ctx->fs_directory_count));
+ printf("%8d character device file%s\n", P_E2("", "s", ctx->fs_chardev_count));
+ printf("%8d block device file%s\n", P_E2("", "s", ctx->fs_blockdev_count));
+ printf("%8d fifo%s\n", P_E2("", "s", ctx->fs_fifo_count));
+ printf("%8d link%s\n", P_E2("", "s", ctx->fs_links_count - dir_links));
+ printf("%8d symbolic link%s", P_E2("", "s", ctx->fs_symlinks_count));
+ printf(" (%d fast symbolic link%s)\n", P_E2("", "s", ctx->fs_fast_symlinks_count));
+ printf("%8d socket%s--------\n\n", P_E2("", "s", ctx->fs_sockets_count));
+ printf("%8d file%s\n", P_E2("", "s", ctx->fs_total_count - dir_links));
+}
+
+static void check_mount(e2fsck_t ctx)
+{
+ errcode_t retval;
+ int cont;
+
+ retval = ext2fs_check_if_mounted(ctx->filesystem_name,
+ &ctx->mount_flags);
+ if (retval) {
+ bb_error_msg(_("while determining whether %s is mounted."),
+ ctx->filesystem_name);
+ return;
+ }
+
+ /*
+ * If the filesystem isn't mounted, or it's the root filesystem
+ * and it's mounted read-only, then everything's fine.
+ */
+ if ((!(ctx->mount_flags & EXT2_MF_MOUNTED)) ||
+ ((ctx->mount_flags & EXT2_MF_ISROOT) &&
+ (ctx->mount_flags & EXT2_MF_READONLY)))
+ return;
+
+ if (ctx->options & E2F_OPT_READONLY) {
+ printf(_("Warning! %s is mounted.\n"), ctx->filesystem_name);
+ return;
+ }
+
+ printf(_("%s is mounted. "), ctx->filesystem_name);
+ if (!ctx->interactive)
+ bb_error_msg_and_die(_("Cannot continue, aborting."));
+ printf(_("\n\n\007\007\007\007WARNING!!! "
+ "Running e2fsck on a mounted filesystem may cause\n"
+ "SEVERE filesystem damage.\007\007\007\n\n"));
+ cont = ask_yn(_("Do you really want to continue"), -1);
+ if (!cont) {
+ printf(_("check aborted.\n"));
+ exit(0);
+ }
+}
+
+static int is_on_batt(void)
+{
+ FILE *f;
+ DIR *d;
+ char tmp[80], tmp2[80], fname[80];
+ unsigned int acflag;
+ struct dirent* de;
+
+ f = fopen("/proc/apm", "r");
+ if (f) {
+ if (fscanf(f, "%s %s %s %x", tmp, tmp, tmp, &acflag) != 4)
+ acflag = 1;
+ fclose(f);
+ return (acflag != 1);
+ }
+ d = opendir("/proc/acpi/ac_adapter");
+ if (d) {
+ while ((de=readdir(d)) != NULL) {
+ if (!strncmp(".", de->d_name, 1))
+ continue;
+ snprintf(fname, 80, "/proc/acpi/ac_adapter/%s/state",
+ de->d_name);
+ f = fopen(fname, "r");
+ if (!f)
+ continue;
+ if (fscanf(f, "%s %s", tmp2, tmp) != 2)
+ tmp[0] = 0;
+ fclose(f);
+ if (strncmp(tmp, "off-line", 8) == 0) {
+ closedir(d);
+ return 1;
+ }
+ }
+ closedir(d);
+ }
+ return 0;
+}
+
+/*
+ * This routine checks to see if a filesystem can be skipped; if so,
+ * it will exit with EXIT_OK. Under some conditions it will print a
+ * message explaining why a check is being forced.
+ */
+static void check_if_skip(e2fsck_t ctx)
+{
+ ext2_filsys fs = ctx->fs;
+ const char *reason = NULL;
+ unsigned int reason_arg = 0;
+ long next_check;
+ int batt = is_on_batt();
+ time_t now = time(0);
+
+ if ((ctx->options & E2F_OPT_FORCE) || cflag || swapfs)
+ return;
+
+ if ((fs->super->s_state & EXT2_ERROR_FS) ||
+ !ext2fs_test_valid(fs))
+ reason = _(" contains a file system with errors");
+ else if ((fs->super->s_state & EXT2_VALID_FS) == 0)
+ reason = _(" was not cleanly unmounted");
+ else if ((fs->super->s_max_mnt_count > 0) &&
+ (fs->super->s_mnt_count >=
+ (unsigned) fs->super->s_max_mnt_count)) {
+ reason = _(" has been mounted %u times without being checked");
+ reason_arg = fs->super->s_mnt_count;
+ if (batt && (fs->super->s_mnt_count <
+ (unsigned) fs->super->s_max_mnt_count*2))
+ reason = 0;
+ } else if (fs->super->s_checkinterval &&
+ ((now - fs->super->s_lastcheck) >=
+ fs->super->s_checkinterval)) {
+ reason = _(" has gone %u days without being checked");
+ reason_arg = (now - fs->super->s_lastcheck)/(3600*24);
+ if (batt && ((now - fs->super->s_lastcheck) <
+ fs->super->s_checkinterval*2))
+ reason = 0;
+ }
+ if (reason) {
+ fputs(ctx->device_name, stdout);
+ printf(reason, reason_arg);
+ fputs(_(", check forced.\n"), stdout);
+ return;
+ }
+ printf(_("%s: clean, %d/%d files, %d/%d blocks"), ctx->device_name,
+ fs->super->s_inodes_count - fs->super->s_free_inodes_count,
+ fs->super->s_inodes_count,
+ fs->super->s_blocks_count - fs->super->s_free_blocks_count,
+ fs->super->s_blocks_count);
+ next_check = 100000;
+ if (fs->super->s_max_mnt_count > 0) {
+ next_check = fs->super->s_max_mnt_count - fs->super->s_mnt_count;
+ if (next_check <= 0)
+ next_check = 1;
+ }
+ if (fs->super->s_checkinterval &&
+ ((now - fs->super->s_lastcheck) >= fs->super->s_checkinterval))
+ next_check = 1;
+ if (next_check <= 5) {
+ if (next_check == 1)
+ fputs(_(" (check after next mount)"), stdout);
+ else
+ printf(_(" (check in %ld mounts)"), next_check);
+ }
+ bb_putchar('\n');
+ ext2fs_close(fs);
+ ctx->fs = NULL;
+ e2fsck_free_context(ctx);
+ exit(EXIT_OK);
+}
+
+/*
+ * For completion notice
+ */
+struct percent_tbl {
+ int max_pass;
+ int table[32];
+};
+static const struct percent_tbl e2fsck_tbl = {
+ 5, { 0, 70, 90, 92, 95, 100 }
+};
+
+static char bar[128], spaces[128];
+
+static float calc_percent(const struct percent_tbl *tbl, int pass, int curr,
+ int max)
+{
+ float percent;
+
+ if (pass <= 0)
+ return 0.0;
+ if (pass > tbl->max_pass || max == 0)
+ return 100.0;
+ percent = ((float) curr) / ((float) max);
+ return ((percent * (tbl->table[pass] - tbl->table[pass-1]))
+ + tbl->table[pass-1]);
+}
+
+void e2fsck_clear_progbar(e2fsck_t ctx)
+{
+ if (!(ctx->flags & E2F_FLAG_PROG_BAR))
+ return;
+
+ printf("%s%s\r%s", ctx->start_meta, spaces + (sizeof(spaces) - 80),
+ ctx->stop_meta);
+ fflush(stdout);
+ ctx->flags &= ~E2F_FLAG_PROG_BAR;
+}
+
+int e2fsck_simple_progress(e2fsck_t ctx, const char *label, float percent,
+ unsigned int dpynum)
+{
+ static const char spinner[] = "\\|/-";
+ int i;
+ unsigned int tick;
+ struct timeval tv;
+ int dpywidth;
+ int fixed_percent;
+
+ if (ctx->flags & E2F_FLAG_PROG_SUPPRESS)
+ return 0;
+
+ /*
+ * Calculate the new progress position. If the
+ * percentage hasn't changed, then we skip out right
+ * away.
+ */
+ fixed_percent = (int) ((10 * percent) + 0.5);
+ if (ctx->progress_last_percent == fixed_percent)
+ return 0;
+ ctx->progress_last_percent = fixed_percent;
+
+ /*
+ * If we've already updated the spinner once within
+ * the last 1/8th of a second, no point doing it
+ * again.
+ */
+ gettimeofday(&tv, NULL);
+ tick = (tv.tv_sec << 3) + (tv.tv_usec / (1000000 / 8));
+ if ((tick == ctx->progress_last_time) &&
+ (fixed_percent != 0) && (fixed_percent != 1000))
+ return 0;
+ ctx->progress_last_time = tick;
+
+ /*
+ * Advance the spinner, and note that the progress bar
+ * will be on the screen
+ */
+ ctx->progress_pos = (ctx->progress_pos+1) & 3;
+ ctx->flags |= E2F_FLAG_PROG_BAR;
+
+ dpywidth = 66 - strlen(label);
+ dpywidth = 8 * (dpywidth / 8);
+ if (dpynum)
+ dpywidth -= 8;
+
+ i = ((percent * dpywidth) + 50) / 100;
+ printf("%s%s: |%s%s", ctx->start_meta, label,
+ bar + (sizeof(bar) - (i+1)),
+ spaces + (sizeof(spaces) - (dpywidth - i + 1)));
+ if (fixed_percent == 1000)
+ bb_putchar('|');
+ else
+ bb_putchar(spinner[ctx->progress_pos & 3]);
+ printf(" %4.1f%% ", percent);
+ if (dpynum)
+ printf("%u\r", dpynum);
+ else
+ fputs(" \r", stdout);
+ fputs(ctx->stop_meta, stdout);
+
+ if (fixed_percent == 1000)
+ e2fsck_clear_progbar(ctx);
+ fflush(stdout);
+
+ return 0;
+}
+
+static int e2fsck_update_progress(e2fsck_t ctx, int pass,
+ unsigned long cur, unsigned long max)
+{
+ char buf[80];
+ float percent;
+
+ if (pass == 0)
+ return 0;
+
+ if (ctx->progress_fd) {
+ sprintf(buf, "%d %lu %lu\n", pass, cur, max);
+ write(ctx->progress_fd, buf, strlen(buf));
+ } else {
+ percent = calc_percent(&e2fsck_tbl, pass, cur, max);
+ e2fsck_simple_progress(ctx, ctx->device_name,
+ percent, 0);
+ }
+ return 0;
+}
+
+static void reserve_stdio_fds(void)
+{
+ int fd;
+
+ while (1) {
+ fd = open(bb_dev_null, O_RDWR);
+ if (fd > 2)
+ break;
+ if (fd < 0) {
+ fprintf(stderr, _("ERROR: Cannot open "
+ "/dev/null (%s)\n"),
+ strerror(errno));
+ break;
+ }
+ }
+ close(fd);
+}
+
+static void signal_progress_on(int sig FSCK_ATTR((unused)))
+{
+ e2fsck_t ctx = e2fsck_global_ctx;
+
+ if (!ctx)
+ return;
+
+ ctx->progress = e2fsck_update_progress;
+ ctx->progress_fd = 0;
+}
+
+static void signal_progress_off(int sig FSCK_ATTR((unused)))
+{
+ e2fsck_t ctx = e2fsck_global_ctx;
+
+ if (!ctx)
+ return;
+
+ e2fsck_clear_progbar(ctx);
+ ctx->progress = 0;
+}
+
+static void signal_cancel(int sig FSCK_ATTR((unused)))
+{
+ e2fsck_t ctx = e2fsck_global_ctx;
+
+ if (!ctx)
+ exit(FSCK_CANCELED);
+
+ ctx->flags |= E2F_FLAG_CANCEL;
+}
+
+static void parse_extended_opts(e2fsck_t ctx, const char *opts)
+{
+ char *buf, *token, *next, *p, *arg;
+ int ea_ver;
+ int extended_usage = 0;
+
+ buf = string_copy(opts, 0);
+ for (token = buf; token && *token; token = next) {
+ p = strchr(token, ',');
+ next = 0;
+ if (p) {
+ *p = 0;
+ next = p+1;
+ }
+ arg = strchr(token, '=');
+ if (arg) {
+ *arg = 0;
+ arg++;
+ }
+ if (strcmp(token, "ea_ver") == 0) {
+ if (!arg) {
+ extended_usage++;
+ continue;
+ }
+ ea_ver = strtoul(arg, &p, 0);
+ if (*p ||
+ ((ea_ver != 1) && (ea_ver != 2))) {
+ fprintf(stderr,
+ _("Invalid EA version.\n"));
+ extended_usage++;
+ continue;
+ }
+ ctx->ext_attr_ver = ea_ver;
+ } else {
+ fprintf(stderr, _("Unknown extended option: %s\n"),
+ token);
+ extended_usage++;
+ }
+ }
+ if (extended_usage) {
+ bb_error_msg_and_die(
+ "Extended options are separated by commas, "
+ "and may take an argument which\n"
+ "is set off by an equals ('=') sign. "
+ "Valid extended options are:\n"
+ "\tea_ver=<ea_version (1 or 2)>\n\n");
+ }
+}
+
+
+static errcode_t PRS(int argc, char **argv, e2fsck_t *ret_ctx)
+{
+ int flush = 0;
+ int c, fd;
+ e2fsck_t ctx;
+ errcode_t retval;
+ struct sigaction sa;
+ char *extended_opts = 0;
+
+ retval = e2fsck_allocate_context(&ctx);
+ if (retval)
+ return retval;
+
+ *ret_ctx = ctx;
+
+ setvbuf(stdout, NULL, _IONBF, BUFSIZ);
+ setvbuf(stderr, NULL, _IONBF, BUFSIZ);
+ if (isatty(0) && isatty(1)) {
+ ctx->interactive = 1;
+ } else {
+ ctx->start_meta[0] = '\001';
+ ctx->stop_meta[0] = '\002';
+ }
+ memset(bar, '=', sizeof(bar)-1);
+ memset(spaces, ' ', sizeof(spaces)-1);
+ blkid_get_cache(&ctx->blkid, NULL);
+
+ if (argc && *argv)
+ ctx->program_name = *argv;
+ else
+ ctx->program_name = "e2fsck";
+ while ((c = getopt (argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDk")) != EOF)
+ switch (c) {
+ case 'C':
+ ctx->progress = e2fsck_update_progress;
+ ctx->progress_fd = atoi(optarg);
+ if (!ctx->progress_fd)
+ break;
+ /* Validate the file descriptor to avoid disasters */
+ fd = dup(ctx->progress_fd);
+ if (fd < 0) {
+ fprintf(stderr,
+ _("Error validating file descriptor %d: %s\n"),
+ ctx->progress_fd,
+ error_message(errno));
+ bb_error_msg_and_die(_("Invalid completion information file descriptor"));
+ } else
+ close(fd);
+ break;
+ case 'D':
+ ctx->options |= E2F_OPT_COMPRESS_DIRS;
+ break;
+ case 'E':
+ extended_opts = optarg;
+ break;
+ case 'p':
+ case 'a':
+ if (ctx->options & (E2F_OPT_YES|E2F_OPT_NO)) {
+ conflict_opt:
+ bb_error_msg_and_die(_("Only one the options -p/-a, -n or -y may be specified."));
+ }
+ ctx->options |= E2F_OPT_PREEN;
+ break;
+ case 'n':
+ if (ctx->options & (E2F_OPT_YES|E2F_OPT_PREEN))
+ goto conflict_opt;
+ ctx->options |= E2F_OPT_NO;
+ break;
+ case 'y':
+ if (ctx->options & (E2F_OPT_PREEN|E2F_OPT_NO))
+ goto conflict_opt;
+ ctx->options |= E2F_OPT_YES;
+ break;
+ case 't':
+ /* FIXME - This needs to go away in a future path - will change binary */
+ fprintf(stderr, _("The -t option is not "
+ "supported on this version of e2fsck.\n"));
+ break;
+ case 'c':
+ if (cflag++)
+ ctx->options |= E2F_OPT_WRITECHECK;
+ ctx->options |= E2F_OPT_CHECKBLOCKS;
+ break;
+ case 'r':
+ /* What we do by default, anyway! */
+ break;
+ case 'b':
+ ctx->use_superblock = atoi(optarg);
+ ctx->flags |= E2F_FLAG_SB_SPECIFIED;
+ break;
+ case 'B':
+ ctx->blocksize = atoi(optarg);
+ break;
+ case 'I':
+ ctx->inode_buffer_blocks = atoi(optarg);
+ break;
+ case 'j':
+ ctx->journal_name = string_copy(optarg, 0);
+ break;
+ case 'P':
+ ctx->process_inode_size = atoi(optarg);
+ break;
+ case 'd':
+ ctx->options |= E2F_OPT_DEBUG;
+ break;
+ case 'f':
+ ctx->options |= E2F_OPT_FORCE;
+ break;
+ case 'F':
+ flush = 1;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'V':
+ show_version_only = 1;
+ break;
+ case 'N':
+ ctx->device_name = optarg;
+ break;
+#ifdef ENABLE_SWAPFS
+ case 's':
+ normalize_swapfs = 1;
+ case 'S':
+ swapfs = 1;
+ break;
+#else
+ case 's':
+ case 'S':
+ fprintf(stderr, _("Byte-swapping filesystems "
+ "not compiled in this version "
+ "of e2fsck\n"));
+ exit(1);
+#endif
+ default:
+ bb_show_usage();
+ }
+ if (show_version_only)
+ return 0;
+ if (optind != argc - 1)
+ bb_show_usage();
+ if ((ctx->options & E2F_OPT_NO) &&
+ !cflag && !swapfs && !(ctx->options & E2F_OPT_COMPRESS_DIRS))
+ ctx->options |= E2F_OPT_READONLY;
+ ctx->io_options = strchr(argv[optind], '?');
+ if (ctx->io_options)
+ *ctx->io_options++ = 0;
+ ctx->filesystem_name = blkid_get_devname(ctx->blkid, argv[optind], 0);
+ if (!ctx->filesystem_name) {
+ bb_error_msg(_("Unable to resolve '%s'"), argv[optind]);
+ bb_error_msg_and_die(0);
+ }
+ if (extended_opts)
+ parse_extended_opts(ctx, extended_opts);
+
+ if (flush) {
+ fd = open(ctx->filesystem_name, O_RDONLY, 0);
+ if (fd < 0) {
+ bb_error_msg(_("while opening %s for flushing"),
+ ctx->filesystem_name);
+ bb_error_msg_and_die(0);
+ }
+ if ((retval = ext2fs_sync_device(fd, 1))) {
+ bb_error_msg(_("while trying to flush %s"),
+ ctx->filesystem_name);
+ bb_error_msg_and_die(0);
+ }
+ close(fd);
+ }
+#ifdef ENABLE_SWAPFS
+ if (swapfs && cflag) {
+ fprintf(stderr, _("Incompatible options not "
+ "allowed when byte-swapping.\n"));
+ exit(EXIT_USAGE);
+ }
+#endif
+ /*
+ * Set up signal action
+ */
+ memset(&sa, 0, sizeof(struct sigaction));
+ sa.sa_handler = signal_cancel;
+ sigaction(SIGINT, &sa, 0);
+ sigaction(SIGTERM, &sa, 0);
+#ifdef SA_RESTART
+ sa.sa_flags = SA_RESTART;
+#endif
+ e2fsck_global_ctx = ctx;
+ sa.sa_handler = signal_progress_on;
+ sigaction(SIGUSR1, &sa, 0);
+ sa.sa_handler = signal_progress_off;
+ sigaction(SIGUSR2, &sa, 0);
+
+ /* Update our PATH to include /sbin if we need to run badblocks */
+ if (cflag)
+ e2fs_set_sbin_path();
+ return 0;
+}
+
+static const char my_ver_string[] = E2FSPROGS_VERSION;
+static const char my_ver_date[] = E2FSPROGS_DATE;
+
+int e2fsck_main (int argc, char **argv);
+int e2fsck_main (int argc, char **argv)
+{
+ errcode_t retval;
+ int exit_value = EXIT_OK;
+ ext2_filsys fs = 0;
+ io_manager io_ptr;
+ struct ext2_super_block *sb;
+ const char *lib_ver_date;
+ int my_ver, lib_ver;
+ e2fsck_t ctx;
+ struct problem_context pctx;
+ int flags, run_result;
+
+ clear_problem_context(&pctx);
+
+ my_ver = ext2fs_parse_version_string(my_ver_string);
+ lib_ver = ext2fs_get_library_version(0, &lib_ver_date);
+ if (my_ver > lib_ver) {
+ fprintf( stderr, _("Error: ext2fs library version "
+ "out of date!\n"));
+ show_version_only++;
+ }
+
+ retval = PRS(argc, argv, &ctx);
+ if (retval) {
+ bb_error_msg(_("while trying to initialize program"));
+ exit(EXIT_ERROR);
+ }
+ reserve_stdio_fds();
+
+ if (!(ctx->options & E2F_OPT_PREEN) || show_version_only)
+ fprintf(stderr, "e2fsck %s (%s)\n", my_ver_string,
+ my_ver_date);
+
+ if (show_version_only) {
+ fprintf(stderr, _("\tUsing %s, %s\n"),
+ error_message(EXT2_ET_BASE), lib_ver_date);
+ exit(EXIT_OK);
+ }
+
+ check_mount(ctx);
+
+ if (!(ctx->options & E2F_OPT_PREEN) &&
+ !(ctx->options & E2F_OPT_NO) &&
+ !(ctx->options & E2F_OPT_YES)) {
+ if (!ctx->interactive)
+ bb_error_msg_and_die(_("need terminal for interactive repairs"));
+ }
+ ctx->superblock = ctx->use_superblock;
+restart:
+#ifdef CONFIG_TESTIO_DEBUG
+ io_ptr = test_io_manager;
+ test_io_backing_manager = unix_io_manager;
+#else
+ io_ptr = unix_io_manager;
+#endif
+ flags = 0;
+ if ((ctx->options & E2F_OPT_READONLY) == 0)
+ flags |= EXT2_FLAG_RW;
+
+ if (ctx->superblock && ctx->blocksize) {
+ retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options,
+ flags, ctx->superblock, ctx->blocksize,
+ io_ptr, &fs);
+ } else if (ctx->superblock) {
+ int blocksize;
+ for (blocksize = EXT2_MIN_BLOCK_SIZE;
+ blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) {
+ retval = ext2fs_open2(ctx->filesystem_name,
+ ctx->io_options, flags,
+ ctx->superblock, blocksize,
+ io_ptr, &fs);
+ if (!retval)
+ break;
+ }
+ } else
+ retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options,
+ flags, 0, 0, io_ptr, &fs);
+ if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) &&
+ !(ctx->flags & E2F_FLAG_SB_SPECIFIED) &&
+ ((retval == EXT2_ET_BAD_MAGIC) ||
+ ((retval == 0) && ext2fs_check_desc(fs)))) {
+ if (!fs || (fs->group_desc_count > 1)) {
+ printf(_("%s trying backup blocks...\n"),
+ retval ? _("Couldn't find ext2 superblock,") :
+ _("Group descriptors look bad..."));
+ get_backup_sb(ctx, fs, ctx->filesystem_name, io_ptr);
+ if (fs)
+ ext2fs_close(fs);
+ goto restart;
+ }
+ }
+ if (retval) {
+ bb_error_msg(_("while trying to open %s"),
+ ctx->filesystem_name);
+ if (retval == EXT2_ET_REV_TOO_HIGH) {
+ printf(_("The filesystem revision is apparently "
+ "too high for this version of e2fsck.\n"
+ "(Or the filesystem superblock "
+ "is corrupt)\n\n"));
+ fix_problem(ctx, PR_0_SB_CORRUPT, &pctx);
+ } else if (retval == EXT2_ET_SHORT_READ)
+ printf(_("Could this be a zero-length partition?\n"));
+ else if ((retval == EPERM) || (retval == EACCES))
+ printf(_("You must have %s access to the "
+ "filesystem or be root\n"),
+ (ctx->options & E2F_OPT_READONLY) ?
+ "r/o" : "r/w");
+ else if (retval == ENXIO)
+ printf(_("Possibly non-existent or swap device?\n"));
+#ifdef EROFS
+ else if (retval == EROFS)
+ printf(_("Disk write-protected; use the -n option "
+ "to do a read-only\n"
+ "check of the device.\n"));
+#endif
+ else
+ fix_problem(ctx, PR_0_SB_CORRUPT, &pctx);
+ bb_error_msg_and_die(0);
+ }
+ ctx->fs = fs;
+ fs->priv_data = ctx;
+ sb = fs->super;
+ if (sb->s_rev_level > E2FSCK_CURRENT_REV) {
+ bb_error_msg(_("while trying to open %s"),
+ ctx->filesystem_name);
+ get_newer:
+ bb_error_msg_and_die(_("Get a newer version of e2fsck!"));
+ }
+
+ /*
+ * Set the device name, which is used whenever we print error
+ * or informational messages to the user.
+ */
+ if (ctx->device_name == 0 &&
+ (sb->s_volume_name[0] != 0)) {
+ ctx->device_name = string_copy(sb->s_volume_name,
+ sizeof(sb->s_volume_name));
+ }
+ if (ctx->device_name == 0)
+ ctx->device_name = ctx->filesystem_name;
+
+ /*
+ * Make sure the ext3 superblock fields are consistent.
+ */
+ retval = e2fsck_check_ext3_journal(ctx);
+ if (retval) {
+ bb_error_msg(_("while checking ext3 journal for %s"),
+ ctx->device_name);
+ bb_error_msg_and_die(0);
+ }
+
+ /*
+ * Check to see if we need to do ext3-style recovery. If so,
+ * do it, and then restart the fsck.
+ */
+ if (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) {
+ if (ctx->options & E2F_OPT_READONLY) {
+ printf(_("Warning: skipping journal recovery "
+ "because doing a read-only filesystem "
+ "check.\n"));
+ io_channel_flush(ctx->fs->io);
+ } else {
+ if (ctx->flags & E2F_FLAG_RESTARTED) {
+ /*
+ * Whoops, we attempted to run the
+ * journal twice. This should never
+ * happen, unless the hardware or
+ * device driver is being bogus.
+ */
+ bb_error_msg(_("cannot set superblock flags on %s"), ctx->device_name);
+ bb_error_msg_and_die(0);
+ }
+ retval = e2fsck_run_ext3_journal(ctx);
+ if (retval) {
+ bb_error_msg(_("while recovering ext3 journal of %s"),
+ ctx->device_name);
+ bb_error_msg_and_die(0);
+ }
+ ext2fs_close(ctx->fs);
+ ctx->fs = 0;
+ ctx->flags |= E2F_FLAG_RESTARTED;
+ goto restart;
+ }
+ }
+
+ /*
+ * Check for compatibility with the feature sets. We need to
+ * be more stringent than ext2fs_open().
+ */
+ if ((sb->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) ||
+ (sb->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP)) {
+ bb_error_msg("(%s)", ctx->device_name);
+ goto get_newer;
+ }
+ if (sb->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
+ bb_error_msg("(%s)", ctx->device_name);
+ goto get_newer;
+ }
+#ifdef ENABLE_COMPRESSION
+ /* FIXME - do we support this at all? */
+ if (sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_COMPRESSION)
+ bb_error_msg(_("Warning: compression support is experimental."));
+#endif
+#ifndef ENABLE_HTREE
+ if (sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) {
+ bb_error_msg(_("E2fsck not compiled with HTREE support,\n\t"
+ "but filesystem %s has HTREE directories."),
+ ctx->device_name);
+ goto get_newer;
+ }
+#endif
+
+ /*
+ * If the user specified a specific superblock, presumably the
+ * master superblock has been trashed. So we mark the
+ * superblock as dirty, so it can be written out.
+ */
+ if (ctx->superblock &&
+ !(ctx->options & E2F_OPT_READONLY))
+ ext2fs_mark_super_dirty(fs);
+
+ /*
+ * We only update the master superblock because (a) paranoia;
+ * we don't want to corrupt the backup superblocks, and (b) we
+ * don't need to update the mount count and last checked
+ * fields in the backup superblock (the kernel doesn't
+ * update the backup superblocks anyway).
+ */
+ fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
+
+ ehandler_init(fs->io);
+
+ if (ctx->superblock)
+ set_latch_flags(PR_LATCH_RELOC, PRL_LATCHED, 0);
+ ext2fs_mark_valid(fs);
+ check_super_block(ctx);
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ bb_error_msg_and_die(0);
+ check_if_skip(ctx);
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ bb_error_msg_and_die(0);
+#ifdef ENABLE_SWAPFS
+
+#ifdef WORDS_BIGENDIAN
+#define NATIVE_FLAG EXT2_FLAG_SWAP_BYTES
+#else
+#define NATIVE_FLAG 0
+#endif
+
+
+ if (normalize_swapfs) {
+ if ((fs->flags & EXT2_FLAG_SWAP_BYTES) == NATIVE_FLAG) {
+ fprintf(stderr, _("%s: Filesystem byte order "
+ "already normalized.\n"), ctx->device_name);
+ bb_error_msg_and_die(0);
+ }
+ }
+ if (swapfs) {
+ swap_filesys(ctx);
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ bb_error_msg_and_die(0);
+ }
+#endif
+
+ /*
+ * Mark the system as valid, 'til proven otherwise
+ */
+ ext2fs_mark_valid(fs);
+
+ retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
+ if (retval) {
+ bb_error_msg(_("while reading bad blocks inode"));
+ preenhalt(ctx);
+ printf(_("This doesn't bode well,"
+ " but we'll try to go on...\n"));
+ }
+
+ run_result = e2fsck_run(ctx);
+ e2fsck_clear_progbar(ctx);
+ if (run_result == E2F_FLAG_RESTART) {
+ printf(_("Restarting e2fsck from the beginning...\n"));
+ retval = e2fsck_reset_context(ctx);
+ if (retval) {
+ bb_error_msg(_("while resetting context"));
+ bb_error_msg_and_die(0);
+ }
+ ext2fs_close(fs);
+ goto restart;
+ }
+ if (run_result & E2F_FLAG_CANCEL) {
+ printf(_("%s: e2fsck canceled.\n"), ctx->device_name ?
+ ctx->device_name : ctx->filesystem_name);
+ exit_value |= FSCK_CANCELED;
+ }
+ if (run_result & E2F_FLAG_ABORT)
+ bb_error_msg_and_die(_("aborted"));
+
+ /* Cleanup */
+ if (ext2fs_test_changed(fs)) {
+ exit_value |= EXIT_NONDESTRUCT;
+ if (!(ctx->options & E2F_OPT_PREEN))
+ printf(_("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n"),
+ ctx->device_name);
+ if (ctx->mount_flags & EXT2_MF_ISROOT) {
+ printf(_("%s: ***** REBOOT LINUX *****\n"),
+ ctx->device_name);
+ exit_value |= EXIT_DESTRUCT;
+ }
+ }
+ if (!ext2fs_test_valid(fs)) {
+ printf(_("\n%s: ********** WARNING: Filesystem still has "
+ "errors **********\n\n"), ctx->device_name);
+ exit_value |= EXIT_UNCORRECTED;
+ exit_value &= ~EXIT_NONDESTRUCT;
+ }
+ if (exit_value & FSCK_CANCELED)
+ exit_value &= ~EXIT_NONDESTRUCT;
+ else {
+ show_stats(ctx);
+ if (!(ctx->options & E2F_OPT_READONLY)) {
+ if (ext2fs_test_valid(fs)) {
+ if (!(sb->s_state & EXT2_VALID_FS))
+ exit_value |= EXIT_NONDESTRUCT;
+ sb->s_state = EXT2_VALID_FS;
+ } else
+ sb->s_state &= ~EXT2_VALID_FS;
+ sb->s_mnt_count = 0;
+ sb->s_lastcheck = time(NULL);
+ ext2fs_mark_super_dirty(fs);
+ }
+ }
+
+ e2fsck_write_bitmaps(ctx);
+
+ ext2fs_close(fs);
+ ctx->fs = NULL;
+ free(ctx->filesystem_name);
+ free(ctx->journal_name);
+ e2fsck_free_context(ctx);
+
+ return exit_value;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2fsck.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2fsck.h
new file mode 100644
index 0000000000..73d398ff46
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2fsck.h
@@ -0,0 +1,640 @@
+/* vi: set sw=4 ts=4: */
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <setjmp.h>
+#include <errno.h>
+#include <getopt.h>
+#include <limits.h>
+#include <stddef.h>
+#include <assert.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <mntent.h>
+#include <dirent.h>
+#include "ext2fs/kernel-list.h"
+#include <sys/types.h>
+#include <linux/types.h>
+
+/*
+ * Now pull in the real linux/jfs.h definitions.
+ */
+#include "ext2fs/kernel-jbd.h"
+
+
+
+#include "fsck.h"
+
+#include "ext2fs/ext2_fs.h"
+#include "blkid/blkid.h"
+#include "ext2fs/ext2_ext_attr.h"
+#include "uuid/uuid.h"
+#include "libbb.h"
+
+#ifdef HAVE_CONIO_H
+#undef HAVE_TERMIOS_H
+#include <conio.h>
+#define read_a_char() getch()
+#else
+#ifdef HAVE_TERMIOS_H
+#include <termios.h>
+#endif
+#endif
+
+
+/*
+ * The last ext2fs revision level that this version of e2fsck is able to
+ * support
+ */
+#define E2FSCK_CURRENT_REV 1
+
+/* Used by the region allocation code */
+typedef __u32 region_addr_t;
+typedef struct region_struct *region_t;
+
+struct dx_dirblock_info {
+ int type;
+ blk_t phys;
+ int flags;
+ blk_t parent;
+ ext2_dirhash_t min_hash;
+ ext2_dirhash_t max_hash;
+ ext2_dirhash_t node_min_hash;
+ ext2_dirhash_t node_max_hash;
+};
+
+/*
+These defines are used in the type field of dx_dirblock_info
+*/
+
+#define DX_DIRBLOCK_ROOT 1
+#define DX_DIRBLOCK_LEAF 2
+#define DX_DIRBLOCK_NODE 3
+
+
+/*
+The following defines are used in the 'flags' field of a dx_dirblock_info
+*/
+#define DX_FLAG_REFERENCED 1
+#define DX_FLAG_DUP_REF 2
+#define DX_FLAG_FIRST 4
+#define DX_FLAG_LAST 8
+
+/*
+ * E2fsck options
+ */
+#define E2F_OPT_READONLY 0x0001
+#define E2F_OPT_PREEN 0x0002
+#define E2F_OPT_YES 0x0004
+#define E2F_OPT_NO 0x0008
+#define E2F_OPT_TIME 0x0010
+#define E2F_OPT_CHECKBLOCKS 0x0040
+#define E2F_OPT_DEBUG 0x0080
+#define E2F_OPT_FORCE 0x0100
+#define E2F_OPT_WRITECHECK 0x0200
+#define E2F_OPT_COMPRESS_DIRS 0x0400
+
+/*
+ * E2fsck flags
+ */
+#define E2F_FLAG_ABORT 0x0001 /* Abort signaled */
+#define E2F_FLAG_CANCEL 0x0002 /* Cancel signaled */
+#define E2F_FLAG_SIGNAL_MASK 0x0003
+#define E2F_FLAG_RESTART 0x0004 /* Restart signaled */
+
+#define E2F_FLAG_SETJMP_OK 0x0010 /* Setjmp valid for abort */
+
+#define E2F_FLAG_PROG_BAR 0x0020 /* Progress bar on screen */
+#define E2F_FLAG_PROG_SUPPRESS 0x0040 /* Progress suspended */
+#define E2F_FLAG_JOURNAL_INODE 0x0080 /* Create a new ext3 journal inode */
+#define E2F_FLAG_SB_SPECIFIED 0x0100 /* The superblock was explicitly
+ * specified by the user */
+#define E2F_FLAG_RESTARTED 0x0200 /* E2fsck has been restarted */
+#define E2F_FLAG_RESIZE_INODE 0x0400 /* Request to recreate resize inode */
+
+
+/*Don't know where these come from*/
+#define READ 0
+#define WRITE 1
+#define cpu_to_be32(n) htonl(n)
+#define be32_to_cpu(n) ntohl(n)
+
+/*
+ * We define a set of "latch groups"; these are problems which are
+ * handled as a set. The user answers once for a particular latch
+ * group.
+ */
+#define PR_LATCH_MASK 0x0ff0 /* Latch mask */
+#define PR_LATCH_BLOCK 0x0010 /* Latch for illegal blocks (pass 1) */
+#define PR_LATCH_BBLOCK 0x0020 /* Latch for bad block inode blocks (pass 1) */
+#define PR_LATCH_IBITMAP 0x0030 /* Latch for pass 5 inode bitmap proc. */
+#define PR_LATCH_BBITMAP 0x0040 /* Latch for pass 5 inode bitmap proc. */
+#define PR_LATCH_RELOC 0x0050 /* Latch for superblock relocate hint */
+#define PR_LATCH_DBLOCK 0x0060 /* Latch for pass 1b dup block headers */
+#define PR_LATCH_LOW_DTIME 0x0070 /* Latch for pass1 orphaned list refugees */
+#define PR_LATCH_TOOBIG 0x0080 /* Latch for file to big errors */
+#define PR_LATCH_OPTIMIZE_DIR 0x0090 /* Latch for optimize directories */
+
+#define PR_LATCH(x) ((((x) & PR_LATCH_MASK) >> 4) - 1)
+
+/*
+ * Latch group descriptor flags
+ */
+#define PRL_YES 0x0001 /* Answer yes */
+#define PRL_NO 0x0002 /* Answer no */
+#define PRL_LATCHED 0x0004 /* The latch group is latched */
+#define PRL_SUPPRESS 0x0008 /* Suppress all latch group questions */
+
+#define PRL_VARIABLE 0x000f /* All the flags that need to be reset */
+
+/*
+ * Pre-Pass 1 errors
+ */
+
+#define PR_0_BB_NOT_GROUP 0x000001 /* Block bitmap not in group */
+#define PR_0_IB_NOT_GROUP 0x000002 /* Inode bitmap not in group */
+#define PR_0_ITABLE_NOT_GROUP 0x000003 /* Inode table not in group */
+#define PR_0_SB_CORRUPT 0x000004 /* Superblock corrupt */
+#define PR_0_FS_SIZE_WRONG 0x000005 /* Filesystem size is wrong */
+#define PR_0_NO_FRAGMENTS 0x000006 /* Fragments not supported */
+#define PR_0_BLOCKS_PER_GROUP 0x000007 /* Bad blocks_per_group */
+#define PR_0_FIRST_DATA_BLOCK 0x000008 /* Bad first_data_block */
+#define PR_0_ADD_UUID 0x000009 /* Adding UUID to filesystem */
+#define PR_0_RELOCATE_HINT 0x00000A /* Relocate hint */
+#define PR_0_MISC_CORRUPT_SUPER 0x00000B /* Miscellaneous superblock corruption */
+#define PR_0_GETSIZE_ERROR 0x00000C /* Error determing physical device size of filesystem */
+#define PR_0_INODE_COUNT_WRONG 0x00000D /* Inode count in the superblock incorrect */
+#define PR_0_HURD_CLEAR_FILETYPE 0x00000E /* The Hurd does not support the filetype feature */
+#define PR_0_JOURNAL_BAD_INODE 0x00000F /* The Hurd does not support the filetype feature */
+#define PR_0_JOURNAL_UNSUPP_MULTIFS 0x000010 /* The external journal has multiple filesystems (which we can't handle yet) */
+#define PR_0_CANT_FIND_JOURNAL 0x000011 /* Can't find external journal */
+#define PR_0_EXT_JOURNAL_BAD_SUPER 0x000012/* External journal has bad superblock */
+#define PR_0_JOURNAL_BAD_UUID 0x000013 /* Superblock has a bad journal UUID */
+#define PR_0_JOURNAL_UNSUPP_SUPER 0x000014 /* Journal has an unknown superblock type */
+#define PR_0_JOURNAL_BAD_SUPER 0x000015 /* Journal superblock is corrupt */
+#define PR_0_JOURNAL_HAS_JOURNAL 0x000016 /* Journal superblock is corrupt */
+#define PR_0_JOURNAL_RECOVER_SET 0x000017 /* Superblock has recovery flag set but no journal */
+#define PR_0_JOURNAL_RECOVERY_CLEAR 0x000018 /* Journal has data, but recovery flag is clear */
+#define PR_0_JOURNAL_RESET_JOURNAL 0x000019 /* Ask if we should clear the journal */
+#define PR_0_FS_REV_LEVEL 0x00001A /* Filesystem revision is 0, but feature flags are set */
+#define PR_0_ORPHAN_CLEAR_INODE 0x000020 /* Clearing orphan inode */
+#define PR_0_ORPHAN_ILLEGAL_BLOCK_NUM 0x000021 /* Illegal block found in orphaned inode */
+#define PR_0_ORPHAN_ALREADY_CLEARED_BLOCK 0x000022 /* Already cleared block found in orphaned inode */
+#define PR_0_ORPHAN_ILLEGAL_HEAD_INODE 0x000023 /* Illegal orphan inode in superblock */
+#define PR_0_ORPHAN_ILLEGAL_INODE 0x000024 /* Illegal inode in orphaned inode list */
+#define PR_0_JOURNAL_UNSUPP_ROCOMPAT 0x000025 /* Journal has unsupported read-only feature - abort */
+#define PR_0_JOURNAL_UNSUPP_INCOMPAT 0x000026 /* Journal has unsupported incompatible feature - abort */
+#define PR_0_JOURNAL_UNSUPP_VERSION 0x000027 /* Journal has unsupported version number */
+#define PR_0_MOVE_JOURNAL 0x000028 /* Moving journal to hidden file */
+#define PR_0_ERR_MOVE_JOURNAL 0x000029 /* Error moving journal */
+#define PR_0_CLEAR_V2_JOURNAL 0x00002A /* Clearing V2 journal superblock */
+#define PR_0_JOURNAL_RUN 0x00002B /* Run journal anyway */
+#define PR_0_JOURNAL_RUN_DEFAULT 0x00002C /* Run journal anyway by default */
+#define PR_0_BACKUP_JNL 0x00002D /* Backup journal inode blocks */
+#define PR_0_NONZERO_RESERVED_GDT_BLOCKS 0x00002E /* Reserved blocks w/o resize_inode */
+#define PR_0_CLEAR_RESIZE_INODE 0x00002F /* Resize_inode not enabled, but resize inode is non-zero */
+#define PR_0_RESIZE_INODE_INVALID 0x000030 /* Resize inode invalid */
+
+/*
+ * Pass 1 errors
+ */
+
+#define PR_1_PASS_HEADER 0x010000 /* Pass 1: Checking inodes, blocks, and sizes */
+#define PR_1_ROOT_NO_DIR 0x010001 /* Root directory is not an inode */
+#define PR_1_ROOT_DTIME 0x010002 /* Root directory has dtime set */
+#define PR_1_RESERVED_BAD_MODE 0x010003 /* Reserved inode has bad mode */
+#define PR_1_ZERO_DTIME 0x010004 /* Deleted inode has zero dtime */
+#define PR_1_SET_DTIME 0x010005 /* Inode in use, but dtime set */
+#define PR_1_ZERO_LENGTH_DIR 0x010006 /* Zero-length directory */
+#define PR_1_BB_CONFLICT 0x010007 /* Block bitmap conflicts with some other fs block */
+#define PR_1_IB_CONFLICT 0x010008 /* Inode bitmap conflicts with some other fs block */
+#define PR_1_ITABLE_CONFLICT 0x010009 /* Inode table conflicts with some other fs block */
+#define PR_1_BB_BAD_BLOCK 0x01000A /* Block bitmap is on a bad block */
+#define PR_1_IB_BAD_BLOCK 0x01000B /* Inode bitmap is on a bad block */
+#define PR_1_BAD_I_SIZE 0x01000C /* Inode has incorrect i_size */
+#define PR_1_BAD_I_BLOCKS 0x01000D /* Inode has incorrect i_blocks */
+#define PR_1_ILLEGAL_BLOCK_NUM 0x01000E /* Illegal block number in inode */
+#define PR_1_BLOCK_OVERLAPS_METADATA 0x01000F /* Block number overlaps fs metadata */
+#define PR_1_INODE_BLOCK_LATCH 0x010010 /* Inode has illegal blocks (latch question) */
+#define PR_1_TOO_MANY_BAD_BLOCKS 0x010011 /* Too many bad blocks in inode */
+#define PR_1_BB_ILLEGAL_BLOCK_NUM 0x010012 /* Illegal block number in bad block inode */
+#define PR_1_INODE_BBLOCK_LATCH 0x010013 /* Bad block inode has illegal blocks (latch question) */
+#define PR_1_DUP_BLOCKS_PREENSTOP 0x010014 /* Duplicate or bad blocks in use! */
+#define PR_1_BBINODE_BAD_METABLOCK 0x010015 /* Bad block used as bad block indirect block */
+#define PR_1_BBINODE_BAD_METABLOCK_PROMPT 0x010016 /* Inconsistency can't be fixed prompt */
+#define PR_1_BAD_PRIMARY_BLOCK 0x010017 /* Bad primary block */
+#define PR_1_BAD_PRIMARY_BLOCK_PROMPT 0x010018 /* Bad primary block prompt */
+#define PR_1_BAD_PRIMARY_SUPERBLOCK 0x010019 /* Bad primary superblock */
+#define PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR 0x01001A /* Bad primary block group descriptors */
+#define PR_1_BAD_SUPERBLOCK 0x01001B /* Bad superblock in group */
+#define PR_1_BAD_GROUP_DESCRIPTORS 0x01001C /* Bad block group descriptors in group */
+#define PR_1_PROGERR_CLAIMED_BLOCK 0x01001D /* Block claimed for no reason */
+#define PR_1_RELOC_BLOCK_ALLOCATE 0x01001E /* Error allocating blocks for relocating metadata */
+#define PR_1_RELOC_MEMORY_ALLOCATE 0x01001F /* Error allocating block buffer during relocation process */
+#define PR_1_RELOC_FROM_TO 0x010020 /* Relocating metadata group information from X to Y */
+#define PR_1_RELOC_TO 0x010021 /* Relocating metatdata group information to X */
+#define PR_1_RELOC_READ_ERR 0x010022 /* Block read error during relocation process */
+#define PR_1_RELOC_WRITE_ERR 0x010023 /* Block write error during relocation process */
+#define PR_1_ALLOCATE_IBITMAP_ERROR 0x010024 /* Error allocating inode bitmap */
+#define PR_1_ALLOCATE_BBITMAP_ERROR 0x010025 /* Error allocating block bitmap */
+#define PR_1_ALLOCATE_ICOUNT 0x010026 /* Error allocating icount structure */
+#define PR_1_ALLOCATE_DBCOUNT 0x010027 /* Error allocating dbcount */
+#define PR_1_ISCAN_ERROR 0x010028 /* Error while scanning inodes */
+#define PR_1_BLOCK_ITERATE 0x010029 /* Error while iterating over blocks */
+#define PR_1_ICOUNT_STORE 0x01002A /* Error while storing inode count information */
+#define PR_1_ADD_DBLOCK 0x01002B /* Error while storing directory block information */
+#define PR_1_READ_INODE 0x01002C /* Error while reading inode (for clearing) */
+#define PR_1_SUPPRESS_MESSAGES 0x01002D /* Suppress messages prompt */
+#define PR_1_SET_IMAGIC 0x01002F /* Imagic flag set on an inode when filesystem doesn't support it */
+#define PR_1_SET_IMMUTABLE 0x010030 /* Immutable flag set on a device or socket inode */
+#define PR_1_COMPR_SET 0x010031 /* Compression flag set on a non-compressed filesystem */
+#define PR_1_SET_NONZSIZE 0x010032 /* Non-zero size on on device, fifo or socket inode */
+#define PR_1_FS_REV_LEVEL 0x010033 /* Filesystem revision is 0, but feature flags are set */
+#define PR_1_JOURNAL_INODE_NOT_CLEAR 0x010034 /* Journal inode not in use, needs clearing */
+#define PR_1_JOURNAL_BAD_MODE 0x010035 /* Journal inode has wrong mode */
+#define PR_1_LOW_DTIME 0x010036 /* Inode that was part of orphan linked list */
+#define PR_1_ORPHAN_LIST_REFUGEES 0x010037 /* Latch question which asks how to deal with low dtime inodes */
+#define PR_1_ALLOCATE_REFCOUNT 0x010038 /* Error allocating refcount structure */
+#define PR_1_READ_EA_BLOCK 0x010039 /* Error reading Extended Attribute block */
+#define PR_1_BAD_EA_BLOCK 0x01003A /* Invalid Extended Attribute block */
+#define PR_1_EXTATTR_READ_ABORT 0x01003B /* Error reading Extended Attribute block while fixing refcount -- abort */
+#define PR_1_EXTATTR_REFCOUNT 0x01003C /* Extended attribute reference count incorrect */
+#define PR_1_EXTATTR_WRITE 0x01003D /* Error writing Extended Attribute block while fixing refcount */
+#define PR_1_EA_MULTI_BLOCK 0x01003E /* Multiple EA blocks not supported */
+#define PR_1_EA_ALLOC_REGION 0x01003F /* Error allocating EA region allocation structure */
+#define PR_1_EA_ALLOC_COLLISION 0x010040 /* Error EA allocation collision */
+#define PR_1_EA_BAD_NAME 0x010041 /* Bad extended attribute name */
+#define PR_1_EA_BAD_VALUE 0x010042 /* Bad extended attribute value */
+#define PR_1_INODE_TOOBIG 0x010043 /* Inode too big (latch question) */
+#define PR_1_TOOBIG_DIR 0x010044 /* Directory too big */
+#define PR_1_TOOBIG_REG 0x010045 /* Regular file too big */
+#define PR_1_TOOBIG_SYMLINK 0x010046 /* Symlink too big */
+#define PR_1_HTREE_SET 0x010047 /* INDEX_FL flag set on a non-HTREE filesystem */
+#define PR_1_HTREE_NODIR 0x010048 /* INDEX_FL flag set on a non-directory */
+#define PR_1_HTREE_BADROOT 0x010049 /* Invalid root node in HTREE directory */
+#define PR_1_HTREE_HASHV 0x01004A /* Unsupported hash version in HTREE directory */
+#define PR_1_HTREE_INCOMPAT 0x01004B /* Incompatible flag in HTREE root node */
+#define PR_1_HTREE_DEPTH 0x01004C /* HTREE too deep */
+#define PR_1_BB_FS_BLOCK 0x01004D /* Bad block has indirect block that conflicts with filesystem block */
+#define PR_1_RESIZE_INODE_CREATE 0x01004E /* Resize inode failed */
+#define PR_1_EXTRA_ISIZE 0x01004F /* inode->i_size is too long */
+#define PR_1_ATTR_NAME_LEN 0x010050 /* attribute name is too long */
+#define PR_1_ATTR_VALUE_OFFSET 0x010051 /* wrong EA value offset */
+#define PR_1_ATTR_VALUE_BLOCK 0x010052 /* wrong EA blocknumber */
+#define PR_1_ATTR_VALUE_SIZE 0x010053 /* wrong EA value size */
+#define PR_1_ATTR_HASH 0x010054 /* wrong EA hash value */
+
+/*
+ * Pass 1b errors
+ */
+
+#define PR_1B_PASS_HEADER 0x011000 /* Pass 1B: Rescan for duplicate/bad blocks */
+#define PR_1B_DUP_BLOCK_HEADER 0x011001 /* Duplicate/bad block(s) header */
+#define PR_1B_DUP_BLOCK 0x011002 /* Duplicate/bad block(s) in inode */
+#define PR_1B_DUP_BLOCK_END 0x011003 /* Duplicate/bad block(s) end */
+#define PR_1B_ISCAN_ERROR 0x011004 /* Error while scanning inodes */
+#define PR_1B_ALLOCATE_IBITMAP_ERROR 0x011005 /* Error allocating inode bitmap */
+#define PR_1B_BLOCK_ITERATE 0x0110006 /* Error while iterating over blocks */
+#define PR_1B_ADJ_EA_REFCOUNT 0x0110007 /* Error adjusting EA refcount */
+#define PR_1C_PASS_HEADER 0x012000 /* Pass 1C: Scan directories for inodes with dup blocks. */
+#define PR_1D_PASS_HEADER 0x013000 /* Pass 1D: Reconciling duplicate blocks */
+#define PR_1D_DUP_FILE 0x013001 /* File has duplicate blocks */
+#define PR_1D_DUP_FILE_LIST 0x013002 /* List of files sharing duplicate blocks */
+#define PR_1D_SHARE_METADATA 0x013003 /* File sharing blocks with filesystem metadata */
+#define PR_1D_NUM_DUP_INODES 0x013004 /* Report of how many duplicate/bad inodes */
+#define PR_1D_DUP_BLOCKS_DEALT 0x013005 /* Duplicated blocks already reassigned or cloned. */
+#define PR_1D_CLONE_QUESTION 0x013006 /* Clone duplicate/bad blocks? */
+#define PR_1D_DELETE_QUESTION 0x013007 /* Delete file? */
+#define PR_1D_CLONE_ERROR 0x013008 /* Couldn't clone file (error) */
+
+/*
+ * Pass 2 errors
+ */
+
+#define PR_2_PASS_HEADER 0x020000 /* Pass 2: Checking directory structure */
+#define PR_2_BAD_INODE_DOT 0x020001 /* Bad inode number for '.' */
+#define PR_2_BAD_INO 0x020002 /* Directory entry has bad inode number */
+#define PR_2_UNUSED_INODE 0x020003 /* Directory entry has deleted or unused inode */
+#define PR_2_LINK_DOT 0x020004 /* Directry entry is link to '.' */
+#define PR_2_BB_INODE 0x020005 /* Directory entry points to inode now located in a bad block */
+#define PR_2_LINK_DIR 0x020006 /* Directory entry contains a link to a directory */
+#define PR_2_LINK_ROOT 0x020007 /* Directory entry contains a link to the root directry */
+#define PR_2_BAD_NAME 0x020008 /* Directory entry has illegal characters in its name */
+#define PR_2_MISSING_DOT 0x020009 /* Missing '.' in directory inode */
+#define PR_2_MISSING_DOT_DOT 0x02000A /* Missing '..' in directory inode */
+#define PR_2_1ST_NOT_DOT 0x02000B /* First entry in directory inode doesn't contain '.' */
+#define PR_2_2ND_NOT_DOT_DOT 0x02000C /* Second entry in directory inode doesn't contain '..' */
+#define PR_2_FADDR_ZERO 0x02000D /* i_faddr should be zero */
+#define PR_2_FILE_ACL_ZERO 0x02000E /* i_file_acl should be zero */
+#define PR_2_DIR_ACL_ZERO 0x02000F /* i_dir_acl should be zero */
+#define PR_2_FRAG_ZERO 0x020010 /* i_frag should be zero */
+#define PR_2_FSIZE_ZERO 0x020011 /* i_fsize should be zero */
+#define PR_2_BAD_MODE 0x020012 /* inode has bad mode */
+#define PR_2_DIR_CORRUPTED 0x020013 /* directory corrupted */
+#define PR_2_FILENAME_LONG 0x020014 /* filename too long */
+#define PR_2_DIRECTORY_HOLE 0x020015 /* Directory inode has a missing block (hole) */
+#define PR_2_DOT_NULL_TERM 0x020016 /* '.' is not NULL terminated */
+#define PR_2_DOT_DOT_NULL_TERM 0x020017 /* '..' is not NULL terminated */
+#define PR_2_BAD_CHAR_DEV 0x020018 /* Illegal character device in inode */
+#define PR_2_BAD_BLOCK_DEV 0x020019 /* Illegal block device in inode */
+#define PR_2_DUP_DOT 0x02001A /* Duplicate '.' entry */
+#define PR_2_DUP_DOT_DOT 0x02001B /* Duplicate '..' entry */
+#define PR_2_NO_DIRINFO 0x02001C /* Internal error: couldn't find dir_info */
+#define PR_2_FINAL_RECLEN 0x02001D /* Final rec_len is wrong */
+#define PR_2_ALLOCATE_ICOUNT 0x02001E /* Error allocating icount structure */
+#define PR_2_DBLIST_ITERATE 0x02001F /* Error iterating over directory blocks */
+#define PR_2_READ_DIRBLOCK 0x020020 /* Error reading directory block */
+#define PR_2_WRITE_DIRBLOCK 0x020021 /* Error writing directory block */
+#define PR_2_ALLOC_DIRBOCK 0x020022 /* Error allocating new directory block */
+#define PR_2_DEALLOC_INODE 0x020023 /* Error deallocating inode */
+#define PR_2_SPLIT_DOT 0x020024 /* Directory entry for '.' is big. Split? */
+#define PR_2_BAD_FIFO 0x020025 /* Illegal FIFO */
+#define PR_2_BAD_SOCKET 0x020026 /* Illegal socket */
+#define PR_2_SET_FILETYPE 0x020027 /* Directory filetype not set */
+#define PR_2_BAD_FILETYPE 0x020028 /* Directory filetype incorrect */
+#define PR_2_CLEAR_FILETYPE 0x020029 /* Directory filetype set when it shouldn't be */
+#define PR_2_NULL_NAME 0x020030 /* Directory filename can't be zero-length */
+#define PR_2_INVALID_SYMLINK 0x020031 /* Invalid symlink */
+#define PR_2_FILE_ACL_BAD 0x020032 /* i_file_acl (extended attribute) is bad */
+#define PR_2_FEATURE_LARGE_FILES 0x020033 /* Filesystem contains large files, but has no such flag in sb */
+#define PR_2_HTREE_NOTREF 0x020034 /* Node in HTREE directory not referenced */
+#define PR_2_HTREE_DUPREF 0x020035 /* Node in HTREE directory referenced twice */
+#define PR_2_HTREE_MIN_HASH 0x020036 /* Node in HTREE directory has bad min hash */
+#define PR_2_HTREE_MAX_HASH 0x020037 /* Node in HTREE directory has bad max hash */
+#define PR_2_HTREE_CLEAR 0x020038 /* Clear invalid HTREE directory */
+#define PR_2_HTREE_BADBLK 0x02003A /* Bad block in htree interior node */
+#define PR_2_ADJ_EA_REFCOUNT 0x02003B /* Error adjusting EA refcount */
+#define PR_2_HTREE_BAD_ROOT 0x02003C /* Invalid HTREE root node */
+#define PR_2_HTREE_BAD_LIMIT 0x02003D /* Invalid HTREE limit */
+#define PR_2_HTREE_BAD_COUNT 0x02003E /* Invalid HTREE count */
+#define PR_2_HTREE_HASH_ORDER 0x02003F /* HTREE interior node has out-of-order hashes in table */
+#define PR_2_HTREE_BAD_DEPTH 0x020040 /* Node in HTREE directory has bad depth */
+#define PR_2_DUPLICATE_DIRENT 0x020041 /* Duplicate directory entry found */
+#define PR_2_NON_UNIQUE_FILE 0x020042 /* Non-unique filename found */
+#define PR_2_REPORT_DUP_DIRENT 0x020043 /* Duplicate directory entry found */
+
+/*
+ * Pass 3 errors
+ */
+
+#define PR_3_PASS_HEADER 0x030000 /* Pass 3: Checking directory connectivity */
+#define PR_3_NO_ROOT_INODE 0x030001 /* Root inode not allocated */
+#define PR_3_EXPAND_LF_DIR 0x030002 /* No room in lost+found */
+#define PR_3_UNCONNECTED_DIR 0x030003 /* Unconnected directory inode */
+#define PR_3_NO_LF_DIR 0x030004 /* /lost+found not found */
+#define PR_3_BAD_DOT_DOT 0x030005 /* .. entry is incorrect */
+#define PR_3_NO_LPF 0x030006 /* Bad or non-existent /lost+found. Cannot reconnect */
+#define PR_3_CANT_EXPAND_LPF 0x030007 /* Could not expand /lost+found */
+#define PR_3_CANT_RECONNECT 0x030008 /* Could not reconnect inode */
+#define PR_3_ERR_FIND_LPF 0x030009 /* Error while trying to find /lost+found */
+#define PR_3_ERR_LPF_NEW_BLOCK 0x03000A /* Error in ext2fs_new_block while creating /lost+found */
+#define PR_3_ERR_LPF_NEW_INODE 0x03000B /* Error in ext2fs_new_inode while creating /lost+found */
+#define PR_3_ERR_LPF_NEW_DIR_BLOCK 0x03000C /* Error in ext2fs_new_dir_block while creating /lost+found */
+#define PR_3_ERR_LPF_WRITE_BLOCK 0x03000D /* Error while writing directory block for /lost+found */
+#define PR_3_ADJUST_INODE 0x03000E /* Error while adjusting inode count */
+#define PR_3_FIX_PARENT_ERR 0x03000F /* Couldn't fix parent directory -- error */
+#define PR_3_FIX_PARENT_NOFIND 0x030010 /* Couldn't fix parent directory -- couldn't find it */
+#define PR_3_ALLOCATE_IBITMAP_ERROR 0x030011 /* Error allocating inode bitmap */
+#define PR_3_CREATE_ROOT_ERROR 0x030012 /* Error creating root directory */
+#define PR_3_CREATE_LPF_ERROR 0x030013 /* Error creating lost and found directory */
+#define PR_3_ROOT_NOT_DIR_ABORT 0x030014 /* Root inode is not directory; aborting */
+#define PR_3_NO_ROOT_INODE_ABORT 0x030015 /* Cannot proceed without a root inode. */
+#define PR_3_NO_DIRINFO 0x030016 /* Internal error: couldn't find dir_info */
+#define PR_3_LPF_NOTDIR 0x030017 /* Lost+found is not a directory */
+
+/*
+ * Pass 3a --- rehashing diretories
+ */
+#define PR_3A_PASS_HEADER 0x031000 /* Pass 3a: Reindexing directories */
+#define PR_3A_OPTIMIZE_ITER 0x031001 /* Error iterating over directories */
+#define PR_3A_OPTIMIZE_DIR_ERR 0x031002 /* Error rehash directory */
+#define PR_3A_OPTIMIZE_DIR_HEADER 0x031003 /* Rehashing dir header */
+#define PR_3A_OPTIMIZE_DIR 0x031004 /* Rehashing directory %d */
+#define PR_3A_OPTIMIZE_DIR_END 0x031005 /* Rehashing dir end */
+
+/*
+ * Pass 4 errors
+ */
+
+#define PR_4_PASS_HEADER 0x040000 /* Pass 4: Checking reference counts */
+#define PR_4_ZERO_LEN_INODE 0x040001 /* Unattached zero-length inode */
+#define PR_4_UNATTACHED_INODE 0x040002 /* Unattached inode */
+#define PR_4_BAD_REF_COUNT 0x040003 /* Inode ref count wrong */
+#define PR_4_INCONSISTENT_COUNT 0x040004 /* Inconsistent inode count information cached */
+
+/*
+ * Pass 5 errors
+ */
+
+#define PR_5_PASS_HEADER 0x050000 /* Pass 5: Checking group summary information */
+#define PR_5_INODE_BMAP_PADDING 0x050001 /* Padding at end of inode bitmap is not set. */
+#define PR_5_BLOCK_BMAP_PADDING 0x050002 /* Padding at end of block bitmap is not set. */
+#define PR_5_BLOCK_BITMAP_HEADER 0x050003 /* Block bitmap differences header */
+#define PR_5_BLOCK_UNUSED 0x050004 /* Block not used, but marked in bitmap */
+#define PR_5_BLOCK_USED 0x050005 /* Block used, but not marked used in bitmap */
+#define PR_5_BLOCK_BITMAP_END 0x050006 /* Block bitmap differences end */
+#define PR_5_INODE_BITMAP_HEADER 0x050007 /* Inode bitmap differences header */
+#define PR_5_INODE_UNUSED 0x050008 /* Inode not used, but marked in bitmap */
+#define PR_5_INODE_USED 0x050009 /* Inode used, but not marked used in bitmap */
+#define PR_5_INODE_BITMAP_END 0x05000A /* Inode bitmap differences end */
+#define PR_5_FREE_INODE_COUNT_GROUP 0x05000B /* Free inodes count for group wrong */
+#define PR_5_FREE_DIR_COUNT_GROUP 0x05000C /* Directories count for group wrong */
+#define PR_5_FREE_INODE_COUNT 0x05000D /* Free inodes count wrong */
+#define PR_5_FREE_BLOCK_COUNT_GROUP 0x05000E /* Free blocks count for group wrong */
+#define PR_5_FREE_BLOCK_COUNT 0x05000F /* Free blocks count wrong */
+#define PR_5_BMAP_ENDPOINTS 0x050010 /* Programming error: bitmap endpoints don't match */
+#define PR_5_FUDGE_BITMAP_ERROR 0x050011 /* Internal error: fudging end of bitmap */
+#define PR_5_COPY_IBITMAP_ERROR 0x050012 /* Error copying in replacement inode bitmap */
+#define PR_5_COPY_BBITMAP_ERROR 0x050013 /* Error copying in replacement block bitmap */
+#define PR_5_BLOCK_RANGE_UNUSED 0x050014 /* Block range not used, but marked in bitmap */
+#define PR_5_BLOCK_RANGE_USED 0x050015 /* Block range used, but not marked used in bitmap */
+#define PR_5_INODE_RANGE_UNUSED 0x050016 /* Inode range not used, but marked in bitmap */
+#define PR_5_INODE_RANGE_USED 0x050017 /* Inode rangeused, but not marked used in bitmap */
+
+
+/*
+ * The directory information structure; stores directory information
+ * collected in earlier passes, to avoid disk i/o in fetching the
+ * directory information.
+ */
+struct dir_info {
+ ext2_ino_t ino; /* Inode number */
+ ext2_ino_t dotdot; /* Parent according to '..' */
+ ext2_ino_t parent; /* Parent according to treewalk */
+};
+
+
+
+/*
+ * The indexed directory information structure; stores information for
+ * directories which contain a hash tree index.
+ */
+struct dx_dir_info {
+ ext2_ino_t ino; /* Inode number */
+ int numblocks; /* number of blocks */
+ int hashversion;
+ short depth; /* depth of tree */
+ struct dx_dirblock_info *dx_block; /* Array of size numblocks */
+};
+
+/*
+ * Define the extended attribute refcount structure
+ */
+typedef struct ea_refcount *ext2_refcount_t;
+
+struct e2fsck_struct {
+ ext2_filsys fs;
+ const char *program_name;
+ char *filesystem_name;
+ char *device_name;
+ char *io_options;
+ int flags; /* E2fsck internal flags */
+ int options;
+ blk_t use_superblock; /* sb requested by user */
+ blk_t superblock; /* sb used to open fs */
+ int blocksize; /* blocksize */
+ blk_t num_blocks; /* Total number of blocks */
+ int mount_flags;
+ blkid_cache blkid; /* blkid cache */
+
+ jmp_buf abort_loc;
+
+ unsigned long abort_code;
+
+ int (*progress)(e2fsck_t ctx, int pass, unsigned long cur,
+ unsigned long max);
+
+ ext2fs_inode_bitmap inode_used_map; /* Inodes which are in use */
+ ext2fs_inode_bitmap inode_bad_map; /* Inodes which are bad somehow */
+ ext2fs_inode_bitmap inode_dir_map; /* Inodes which are directories */
+ ext2fs_inode_bitmap inode_imagic_map; /* AFS inodes */
+ ext2fs_inode_bitmap inode_reg_map; /* Inodes which are regular files*/
+
+ ext2fs_block_bitmap block_found_map; /* Blocks which are in use */
+ ext2fs_block_bitmap block_dup_map; /* Blks referenced more than once */
+ ext2fs_block_bitmap block_ea_map; /* Blocks which are used by EA's */
+
+ /*
+ * Inode count arrays
+ */
+ ext2_icount_t inode_count;
+ ext2_icount_t inode_link_info;
+
+ ext2_refcount_t refcount;
+ ext2_refcount_t refcount_extra;
+
+ /*
+ * Array of flags indicating whether an inode bitmap, block
+ * bitmap, or inode table is invalid
+ */
+ int *invalid_inode_bitmap_flag;
+ int *invalid_block_bitmap_flag;
+ int *invalid_inode_table_flag;
+ int invalid_bitmaps; /* There are invalid bitmaps/itable */
+
+ /*
+ * Block buffer
+ */
+ char *block_buf;
+
+ /*
+ * For pass1_check_directory and pass1_get_blocks
+ */
+ ext2_ino_t stashed_ino;
+ struct ext2_inode *stashed_inode;
+
+ /*
+ * Location of the lost and found directory
+ */
+ ext2_ino_t lost_and_found;
+ int bad_lost_and_found;
+
+ /*
+ * Directory information
+ */
+ int dir_info_count;
+ int dir_info_size;
+ struct dir_info *dir_info;
+
+ /*
+ * Indexed directory information
+ */
+ int dx_dir_info_count;
+ int dx_dir_info_size;
+ struct dx_dir_info *dx_dir_info;
+
+ /*
+ * Directories to hash
+ */
+ ext2_u32_list dirs_to_hash;
+
+ /*
+ * Tuning parameters
+ */
+ int process_inode_size;
+ int inode_buffer_blocks;
+
+ /*
+ * ext3 journal support
+ */
+ io_channel journal_io;
+ char *journal_name;
+
+ /*
+ * How we display the progress update (for unix)
+ */
+ int progress_fd;
+ int progress_pos;
+ int progress_last_percent;
+ unsigned int progress_last_time;
+ int interactive; /* Are we connected directly to a tty? */
+ char start_meta[2], stop_meta[2];
+
+ /* File counts */
+ int fs_directory_count;
+ int fs_regular_count;
+ int fs_blockdev_count;
+ int fs_chardev_count;
+ int fs_links_count;
+ int fs_symlinks_count;
+ int fs_fast_symlinks_count;
+ int fs_fifo_count;
+ int fs_total_count;
+ int fs_sockets_count;
+ int fs_ind_count;
+ int fs_dind_count;
+ int fs_tind_count;
+ int fs_fragmented;
+ int large_files;
+ int fs_ext_attr_inodes;
+ int fs_ext_attr_blocks;
+
+ int ext_attr_ver;
+
+ /*
+ * For the use of callers of the e2fsck functions; not used by
+ * e2fsck functions themselves.
+ */
+ void *priv_data;
+};
+
+
+#define tid_gt(x, y) ((x - y) > 0)
+
+static inline int tid_geq(tid_t x, tid_t y)
+{
+ int difference = (x - y);
+ return (difference >= 0);
+}
+
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/Kbuild b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/Kbuild
new file mode 100644
index 0000000000..c0ff824e3c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/Kbuild
@@ -0,0 +1,15 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+NEEDED-$(CONFIG_CHATTR) = y
+NEEDED-$(CONFIG_LSATTR) = y
+NEEDED-$(CONFIG_MKE2FS) = y
+NEEDED-$(CONFIG_TUNE2FS) = y
+
+lib-y:=
+lib-$(NEEDED-y) += fgetsetflags.o fgetsetversion.o pf.o iod.o mntopts.o \
+ feature.o ls.o uuid.o pe.o ostype.o ps.o hashstr.o \
+ parse_num.o
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/e2p.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/e2p.h
new file mode 100644
index 0000000000..4524700473
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/e2p.h
@@ -0,0 +1,64 @@
+/* vi: set sw=4 ts=4: */
+#include "libbb.h"
+#include <sys/types.h> /* Needed by dirent.h on netbsd */
+#include <stdio.h>
+#include <dirent.h>
+
+#include "../ext2fs/ext2_fs.h"
+
+#define E2P_FEATURE_COMPAT 0
+#define E2P_FEATURE_INCOMPAT 1
+#define E2P_FEATURE_RO_INCOMPAT 2
+#ifndef EXT3_FEATURE_INCOMPAT_EXTENTS
+#define EXT3_FEATURE_INCOMPAT_EXTENTS 0x0040
+#endif
+
+/* `options' for print_e2flags() */
+
+#define PFOPT_LONG 1 /* Must be 1 for compatibility with `int long_format'. */
+
+/*int fgetversion (const char * name, unsigned long * version);*/
+/*int fsetversion (const char * name, unsigned long version);*/
+int fgetsetversion(const char * name, unsigned long * get_version, unsigned long set_version);
+#define fgetversion(name, version) fgetsetversion(name, version, 0)
+#define fsetversion(name, version) fgetsetversion(name, NULL, version)
+
+/*int fgetflags (const char * name, unsigned long * flags);*/
+/*int fsetflags (const char * name, unsigned long flags);*/
+int fgetsetflags(const char * name, unsigned long * get_flags, unsigned long set_flags);
+#define fgetflags(name, flags) fgetsetflags(name, flags, 0)
+#define fsetflags(name, flags) fgetsetflags(name, NULL, flags)
+
+int getflags (int fd, unsigned long * flags);
+int getversion (int fd, unsigned long * version);
+int iterate_on_dir (const char * dir_name,
+ int (*func) (const char *, struct dirent *, void *),
+ void * private);
+/*void list_super(struct ext2_super_block * s);*/
+void list_super2(struct ext2_super_block * s, FILE *f);
+#define list_super(s) list_super2(s, stdout)
+void print_fs_errors (FILE * f, unsigned short errors);
+void print_flags (FILE * f, unsigned long flags, unsigned options);
+void print_fs_state (FILE * f, unsigned short state);
+int setflags (int fd, unsigned long flags);
+int setversion (int fd, unsigned long version);
+
+const char *e2p_feature2string(int compat, unsigned int mask);
+int e2p_string2feature(char *string, int *compat, unsigned int *mask);
+int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array);
+
+int e2p_is_null_uuid(void *uu);
+void e2p_uuid_to_str(void *uu, char *out);
+const char *e2p_uuid2str(void *uu);
+
+const char *e2p_hash2string(int num);
+int e2p_string2hash(char *string);
+
+const char *e2p_mntopt2string(unsigned int mask);
+int e2p_string2mntopt(char *string, unsigned int *mask);
+int e2p_edit_mntopts(const char *str, __u32 *mntopts, __u32 ok);
+
+unsigned long parse_num_blocks(const char *arg, int log_block_size);
+
+char *e2p_os2string(int os_type);
+int e2p_string2os(char *str);
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/feature.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/feature.c
new file mode 100644
index 0000000000..b45754f971
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/feature.c
@@ -0,0 +1,187 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * feature.c --- convert between features and strings
+ *
+ * Copyright (C) 1999 Theodore Ts'o <tytso@mit.edu>
+ *
+ * This file can be redistributed under the terms of the GNU Library General
+ * Public License
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "e2p.h"
+
+struct feature {
+ int compat;
+ unsigned int mask;
+ const char *string;
+};
+
+static const struct feature feature_list[] = {
+ { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_PREALLOC,
+ "dir_prealloc" },
+ { E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL,
+ "has_journal" },
+ { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_IMAGIC_INODES,
+ "imagic_inodes" },
+ { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_EXT_ATTR,
+ "ext_attr" },
+ { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX,
+ "dir_index" },
+ { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_RESIZE_INODE,
+ "resize_inode" },
+ { E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER,
+ "sparse_super" },
+ { E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_LARGE_FILE,
+ "large_file" },
+ { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION,
+ "compression" },
+ { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_FILETYPE,
+ "filetype" },
+ { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_RECOVER,
+ "needs_recovery" },
+ { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_JOURNAL_DEV,
+ "journal_dev" },
+ { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS,
+ "extents" },
+ { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_META_BG,
+ "meta_bg" },
+ { 0, 0, 0 },
+};
+
+const char *e2p_feature2string(int compat, unsigned int mask)
+{
+ const struct feature *f;
+ static char buf[20];
+ char fchar;
+ int fnum;
+
+ for (f = feature_list; f->string; f++) {
+ if ((compat == f->compat) &&
+ (mask == f->mask))
+ return f->string;
+ }
+ switch (compat) {
+ case E2P_FEATURE_COMPAT:
+ fchar = 'C';
+ break;
+ case E2P_FEATURE_INCOMPAT:
+ fchar = 'I';
+ break;
+ case E2P_FEATURE_RO_INCOMPAT:
+ fchar = 'R';
+ break;
+ default:
+ fchar = '?';
+ break;
+ }
+ for (fnum = 0; mask >>= 1; fnum++);
+ sprintf(buf, "FEATURE_%c%d", fchar, fnum);
+ return buf;
+}
+
+int e2p_string2feature(char *string, int *compat_type, unsigned int *mask)
+{
+ const struct feature *f;
+ char *eptr;
+ int num;
+
+ for (f = feature_list; f->string; f++) {
+ if (!strcasecmp(string, f->string)) {
+ *compat_type = f->compat;
+ *mask = f->mask;
+ return 0;
+ }
+ }
+ if (strncasecmp(string, "FEATURE_", 8))
+ return 1;
+
+ switch (string[8]) {
+ case 'c':
+ case 'C':
+ *compat_type = E2P_FEATURE_COMPAT;
+ break;
+ case 'i':
+ case 'I':
+ *compat_type = E2P_FEATURE_INCOMPAT;
+ break;
+ case 'r':
+ case 'R':
+ *compat_type = E2P_FEATURE_RO_INCOMPAT;
+ break;
+ default:
+ return 1;
+ }
+ if (string[9] == 0)
+ return 1;
+ num = strtol(string+9, &eptr, 10);
+ if (num > 32 || num < 0)
+ return 1;
+ if (*eptr)
+ return 1;
+ *mask = 1 << num;
+ return 0;
+}
+
+static inline char *skip_over_blanks(char *cp)
+{
+ while (*cp && isspace(*cp))
+ cp++;
+ return cp;
+}
+
+static inline char *skip_over_word(char *cp)
+{
+ while (*cp && !isspace(*cp) && *cp != ',')
+ cp++;
+ return cp;
+}
+
+/*
+ * Edit a feature set array as requested by the user. The ok_array,
+ * if set, allows the application to limit what features the user is
+ * allowed to set or clear using this function.
+ */
+int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array)
+{
+ char *cp, *buf, *next;
+ int neg;
+ unsigned int mask;
+ int compat_type;
+
+ buf = xstrdup(str);
+ cp = buf;
+ while (cp && *cp) {
+ neg = 0;
+ cp = skip_over_blanks(cp);
+ next = skip_over_word(cp);
+ if (*next == 0)
+ next = 0;
+ else
+ *next = 0;
+ switch (*cp) {
+ case '-':
+ case '^':
+ neg++;
+ case '+':
+ cp++;
+ break;
+ }
+ if (e2p_string2feature(cp, &compat_type, &mask))
+ return 1;
+ if (ok_array && !(ok_array[compat_type] & mask))
+ return 1;
+ if (neg)
+ compat_array[compat_type] &= ~mask;
+ else
+ compat_array[compat_type] |= mask;
+ cp = next ? next+1 : 0;
+ }
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/fgetsetflags.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/fgetsetflags.c
new file mode 100644
index 0000000000..008b798504
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/fgetsetflags.c
@@ -0,0 +1,70 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * fgetflags.c - Get a file flags on an ext2 file system
+ * fsetflags.c - Set a file flags on an ext2 file system
+ *
+ * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
+ * Laboratoire MASI, Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * This file can be redistributed under the terms of the GNU Library General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/10/30 - Creation
+ */
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_EXT2_IOCTLS
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#endif
+
+#include "e2p.h"
+
+#ifdef O_LARGEFILE
+#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK|O_LARGEFILE)
+#else
+#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK)
+#endif
+
+int fgetsetflags (const char * name, unsigned long * get_flags, unsigned long set_flags)
+{
+#ifdef HAVE_EXT2_IOCTLS
+ struct stat buf;
+ int fd, r, f, save_errno = 0;
+
+ if (!stat(name, &buf) &&
+ !S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) {
+ goto notsupp;
+ }
+ fd = open (name, OPEN_FLAGS);
+ if (fd == -1)
+ return -1;
+ if (!get_flags) {
+ f = (int) set_flags;
+ r = ioctl (fd, EXT2_IOC_SETFLAGS, &f);
+ } else {
+ r = ioctl (fd, EXT2_IOC_GETFLAGS, &f);
+ *get_flags = f;
+ }
+ if (r == -1)
+ save_errno = errno;
+ close (fd);
+ if (save_errno)
+ errno = save_errno;
+ return r;
+notsupp:
+#endif /* HAVE_EXT2_IOCTLS */
+ errno = EOPNOTSUPP;
+ return -1;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/fgetsetversion.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/fgetsetversion.c
new file mode 100644
index 0000000000..8d79054d6a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/fgetsetversion.c
@@ -0,0 +1,70 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * fgetversion.c - Get a file version on an ext2 file system
+ * fsetversion.c - Set a file version on an ext2 file system
+ *
+ *
+ * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
+ * Laboratoire MASI, Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * This file can be redistributed under the terms of the GNU Library General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/10/30 - Creation
+ */
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include "e2p.h"
+
+#ifdef O_LARGEFILE
+#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK|O_LARGEFILE)
+#else
+#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK)
+#endif
+
+/*
+ To do fsetversion: unsigned long *ptr_version must be set to NULL.
+ and unsigned long version must be set to a value
+ To do fgetversion: unsigned long *ptr_version must NOT be set to NULL
+ and unsigned long version is ignored.
+ TITO.
+*/
+
+int fgetsetversion (const char * name, unsigned long * get_version, unsigned long set_version)
+{
+#ifdef HAVE_EXT2_IOCTLS
+ int fd, r, ver, save_errno = 0;
+
+ fd = open (name, OPEN_FLAGS);
+ if (fd == -1)
+ return -1;
+ if (!get_version) {
+ ver = (int) set_version;
+ r = ioctl (fd, EXT2_IOC_SETVERSION, &ver);
+ } else {
+ r = ioctl (fd, EXT2_IOC_GETVERSION, &ver);
+ *get_version = ver;
+ }
+ if (r == -1)
+ save_errno = errno;
+ close (fd);
+ if (save_errno)
+ errno = save_errno;
+ return r;
+#else /* ! HAVE_EXT2_IOCTLS */
+ errno = EOPNOTSUPP;
+ return -1;
+#endif /* ! HAVE_EXT2_IOCTLS */
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/hashstr.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/hashstr.c
new file mode 100644
index 0000000000..697ffadc37
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/hashstr.c
@@ -0,0 +1,70 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * feature.c --- convert between features and strings
+ *
+ * Copyright (C) 1999 Theodore Ts'o <tytso@mit.edu>
+ *
+ * This file can be redistributed under the terms of the GNU Library General
+ * Public License
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "e2p.h"
+
+struct hash {
+ int num;
+ const char *string;
+};
+
+static const struct hash hash_list[] = {
+ { EXT2_HASH_LEGACY, "legacy" },
+ { EXT2_HASH_HALF_MD4, "half_md4" },
+ { EXT2_HASH_TEA, "tea" },
+ { 0, 0 },
+};
+
+const char *e2p_hash2string(int num)
+{
+ const struct hash *p;
+ static char buf[20];
+
+ for (p = hash_list; p->string; p++) {
+ if (num == p->num)
+ return p->string;
+ }
+ sprintf(buf, "HASHALG_%d", num);
+ return buf;
+}
+
+/*
+ * Returns the hash algorithm, or -1 on error
+ */
+int e2p_string2hash(char *string)
+{
+ const struct hash *p;
+ char *eptr;
+ int num;
+
+ for (p = hash_list; p->string; p++) {
+ if (!strcasecmp(string, p->string)) {
+ return p->num;
+ }
+ }
+ if (strncasecmp(string, "HASHALG_", 8))
+ return -1;
+
+ if (string[8] == 0)
+ return -1;
+ num = strtol(string+8, &eptr, 10);
+ if (num > 255 || num < 0)
+ return -1;
+ if (*eptr)
+ return -1;
+ return num;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/iod.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/iod.c
new file mode 100644
index 0000000000..23ab8d5b54
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/iod.c
@@ -0,0 +1,52 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * iod.c - Iterate a function on each entry of a directory
+ *
+ * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
+ * Laboratoire MASI, Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * This file can be redistributed under the terms of the GNU Library General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/10/30 - Creation
+ */
+
+#include "e2p.h"
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+int iterate_on_dir (const char * dir_name,
+ int (*func) (const char *, struct dirent *, void *),
+ void * private)
+{
+ DIR * dir;
+ struct dirent *de, *dep;
+ int max_len, len;
+
+ max_len = PATH_MAX + sizeof(struct dirent);
+ de = xmalloc(max_len+1);
+ memset(de, 0, max_len+1);
+
+ dir = opendir (dir_name);
+ if (dir == NULL) {
+ free(de);
+ return -1;
+ }
+ while ((dep = readdir (dir))) {
+ len = sizeof(struct dirent);
+ if (len < dep->d_reclen)
+ len = dep->d_reclen;
+ if (len > max_len)
+ len = max_len;
+ memcpy(de, dep, len);
+ (*func) (dir_name, de, private);
+ }
+ free(de);
+ closedir(dir);
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/ls.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/ls.c
new file mode 100644
index 0000000000..9d29db6af3
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/ls.c
@@ -0,0 +1,273 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * ls.c - List the contents of an ext2fs superblock
+ *
+ * Copyright (C) 1992, 1993, 1994 Remy Card <card@masi.ibp.fr>
+ * Laboratoire MASI, Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * Copyright (C) 1995, 1996, 1997 Theodore Ts'o <tytso@mit.edu>
+ *
+ * This file can be redistributed under the terms of the GNU Library General
+ * Public License
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <string.h>
+#include <grp.h>
+#include <pwd.h>
+#include <time.h>
+
+#include "e2p.h"
+
+static void print_user(unsigned short uid, FILE *f)
+{
+ struct passwd *pw = getpwuid(uid);
+ fprintf(f, "%u (user %s)\n", uid,
+ (pw == NULL ? "unknown" : pw->pw_name));
+}
+
+static void print_group(unsigned short gid, FILE *f)
+{
+ struct group *gr = getgrgid(gid);
+ fprintf(f, "%u (group %s)\n", gid,
+ (gr == NULL ? "unknown" : gr->gr_name));
+}
+
+#define MONTH_INT (86400 * 30)
+#define WEEK_INT (86400 * 7)
+#define DAY_INT (86400)
+#define HOUR_INT (60 * 60)
+#define MINUTE_INT (60)
+
+static const char *interval_string(unsigned int secs)
+{
+ static char buf[256], tmp[80];
+ int hr, min, num;
+
+ buf[0] = 0;
+
+ if (secs == 0)
+ return "<none>";
+
+ if (secs >= MONTH_INT) {
+ num = secs / MONTH_INT;
+ secs -= num*MONTH_INT;
+ sprintf(buf, "%d month%s", num, (num>1) ? "s" : "");
+ }
+ if (secs >= WEEK_INT) {
+ num = secs / WEEK_INT;
+ secs -= num*WEEK_INT;
+ sprintf(tmp, "%s%d week%s", buf[0] ? ", " : "",
+ num, (num>1) ? "s" : "");
+ strcat(buf, tmp);
+ }
+ if (secs >= DAY_INT) {
+ num = secs / DAY_INT;
+ secs -= num*DAY_INT;
+ sprintf(tmp, "%s%d day%s", buf[0] ? ", " : "",
+ num, (num>1) ? "s" : "");
+ strcat(buf, tmp);
+ }
+ if (secs > 0) {
+ hr = secs / HOUR_INT;
+ secs -= hr*HOUR_INT;
+ min = secs / MINUTE_INT;
+ secs -= min*MINUTE_INT;
+ sprintf(tmp, "%s%d:%02d:%02d", buf[0] ? ", " : "",
+ hr, min, secs);
+ strcat(buf, tmp);
+ }
+ return buf;
+}
+
+static void print_features(struct ext2_super_block * s, FILE *f)
+{
+#ifdef EXT2_DYNAMIC_REV
+ int i, j, printed=0;
+ __u32 *mask = &s->s_feature_compat, m;
+
+ fprintf(f, "Filesystem features: ");
+ for (i=0; i <3; i++,mask++) {
+ for (j=0,m=1; j < 32; j++, m<<=1) {
+ if (*mask & m) {
+ fprintf(f, " %s", e2p_feature2string(i, m));
+ printed++;
+ }
+ }
+ }
+ if (printed == 0)
+ fprintf(f, " (none)");
+ fprintf(f, "\n");
+#endif
+}
+
+static void print_mntopts(struct ext2_super_block * s, FILE *f)
+{
+#ifdef EXT2_DYNAMIC_REV
+ int i, printed=0;
+ __u32 mask = s->s_default_mount_opts, m;
+
+ fprintf(f, "Default mount options: ");
+ if (mask & EXT3_DEFM_JMODE) {
+ fprintf(f, " %s", e2p_mntopt2string(mask & EXT3_DEFM_JMODE));
+ printed++;
+ }
+ for (i=0,m=1; i < 32; i++, m<<=1) {
+ if (m & EXT3_DEFM_JMODE)
+ continue;
+ if (mask & m) {
+ fprintf(f, " %s", e2p_mntopt2string(m));
+ printed++;
+ }
+ }
+ if (printed == 0)
+ fprintf(f, " (none)");
+ fprintf(f, "\n");
+#endif
+}
+
+
+#ifndef EXT2_INODE_SIZE
+#define EXT2_INODE_SIZE(s) sizeof(struct ext2_inode)
+#endif
+
+#ifndef EXT2_GOOD_OLD_REV
+#define EXT2_GOOD_OLD_REV 0
+#endif
+
+void list_super2(struct ext2_super_block * sb, FILE *f)
+{
+ int inode_blocks_per_group;
+ char buf[80], *str;
+ time_t tm;
+
+ inode_blocks_per_group = (((sb->s_inodes_per_group *
+ EXT2_INODE_SIZE(sb)) +
+ EXT2_BLOCK_SIZE(sb) - 1) /
+ EXT2_BLOCK_SIZE(sb));
+ if (sb->s_volume_name[0]) {
+ memset(buf, 0, sizeof(buf));
+ strncpy(buf, sb->s_volume_name, sizeof(sb->s_volume_name));
+ } else
+ strcpy(buf, "<none>");
+ fprintf(f, "Filesystem volume name: %s\n", buf);
+ if (sb->s_last_mounted[0]) {
+ memset(buf, 0, sizeof(buf));
+ strncpy(buf, sb->s_last_mounted, sizeof(sb->s_last_mounted));
+ } else
+ strcpy(buf, "<not available>");
+ fprintf(f,
+ "Last mounted on: %s\n"
+ "Filesystem UUID: %s\n"
+ "Filesystem magic number: 0x%04X\n"
+ "Filesystem revision #: %d",
+ buf, e2p_uuid2str(sb->s_uuid), sb->s_magic, sb->s_rev_level);
+ if (sb->s_rev_level == EXT2_GOOD_OLD_REV) {
+ fprintf(f, " (original)\n");
+#ifdef EXT2_DYNAMIC_REV
+ } else if (sb->s_rev_level == EXT2_DYNAMIC_REV) {
+ fprintf(f, " (dynamic)\n");
+#endif
+ } else
+ fprintf(f, " (unknown)\n");
+ print_features(sb, f);
+ print_mntopts(sb, f);
+ fprintf(f, "Filesystem state: ");
+ print_fs_state (f, sb->s_state);
+ fprintf(f, "\nErrors behavior: ");
+ print_fs_errors(f, sb->s_errors);
+ str = e2p_os2string(sb->s_creator_os);
+ fprintf(f,
+ "\n"
+ "Filesystem OS type: %s\n"
+ "Inode count: %u\n"
+ "Block count: %u\n"
+ "Reserved block count: %u\n"
+ "Free blocks: %u\n"
+ "Free inodes: %u\n"
+ "First block: %u\n"
+ "Block size: %u\n"
+ "Fragment size: %u\n",
+ str, sb->s_inodes_count, sb->s_blocks_count, sb->s_r_blocks_count,
+ sb->s_free_blocks_count, sb->s_free_inodes_count,
+ sb->s_first_data_block, EXT2_BLOCK_SIZE(sb), EXT2_FRAG_SIZE(sb));
+ free(str);
+ if (sb->s_reserved_gdt_blocks)
+ fprintf(f, "Reserved GDT blocks: %u\n",
+ sb->s_reserved_gdt_blocks);
+ fprintf(f,
+ "Blocks per group: %u\n"
+ "Fragments per group: %u\n"
+ "Inodes per group: %u\n"
+ "Inode blocks per group: %u\n",
+ sb->s_blocks_per_group, sb->s_frags_per_group,
+ sb->s_inodes_per_group, inode_blocks_per_group);
+ if (sb->s_first_meta_bg)
+ fprintf(f, "First meta block group: %u\n",
+ sb->s_first_meta_bg);
+ if (sb->s_mkfs_time) {
+ tm = sb->s_mkfs_time;
+ fprintf(f, "Filesystem created: %s", ctime(&tm));
+ }
+ tm = sb->s_mtime;
+ fprintf(f, "Last mount time: %s",
+ sb->s_mtime ? ctime(&tm) : "n/a\n");
+ tm = sb->s_wtime;
+ fprintf(f,
+ "Last write time: %s"
+ "Mount count: %u\n"
+ "Maximum mount count: %d\n",
+ ctime(&tm), sb->s_mnt_count, sb->s_max_mnt_count);
+ tm = sb->s_lastcheck;
+ fprintf(f,
+ "Last checked: %s"
+ "Check interval: %u (%s)\n",
+ ctime(&tm),
+ sb->s_checkinterval, interval_string(sb->s_checkinterval));
+ if (sb->s_checkinterval)
+ {
+ time_t next;
+
+ next = sb->s_lastcheck + sb->s_checkinterval;
+ fprintf(f, "Next check after: %s", ctime(&next));
+ }
+ fprintf(f, "Reserved blocks uid: ");
+ print_user(sb->s_def_resuid, f);
+ fprintf(f, "Reserved blocks gid: ");
+ print_group(sb->s_def_resgid, f);
+ if (sb->s_rev_level >= EXT2_DYNAMIC_REV) {
+ fprintf(f,
+ "First inode: %d\n"
+ "Inode size: %d\n",
+ sb->s_first_ino, sb->s_inode_size);
+ }
+ if (!e2p_is_null_uuid(sb->s_journal_uuid))
+ fprintf(f, "Journal UUID: %s\n",
+ e2p_uuid2str(sb->s_journal_uuid));
+ if (sb->s_journal_inum)
+ fprintf(f, "Journal inode: %u\n",
+ sb->s_journal_inum);
+ if (sb->s_journal_dev)
+ fprintf(f, "Journal device: 0x%04x\n",
+ sb->s_journal_dev);
+ if (sb->s_last_orphan)
+ fprintf(f, "First orphan inode: %u\n",
+ sb->s_last_orphan);
+ if ((sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) ||
+ sb->s_def_hash_version)
+ fprintf(f, "Default directory hash: %s\n",
+ e2p_hash2string(sb->s_def_hash_version));
+ if (!e2p_is_null_uuid(sb->s_hash_seed))
+ fprintf(f, "Directory Hash Seed: %s\n",
+ e2p_uuid2str(sb->s_hash_seed));
+ if (sb->s_jnl_backup_type) {
+ fprintf(f, "Journal backup: ");
+ if (sb->s_jnl_backup_type == 1)
+ fprintf(f, "inode blocks\n");
+ else
+ fprintf(f, "type %u\n", sb->s_jnl_backup_type);
+ }
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/mntopts.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/mntopts.c
new file mode 100644
index 0000000000..17c26c480b
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/mntopts.c
@@ -0,0 +1,134 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * mountopts.c --- convert between default mount options and strings
+ *
+ * Copyright (C) 2002 Theodore Ts'o <tytso@mit.edu>
+ *
+ * This file can be redistributed under the terms of the GNU Library General
+ * Public License
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "e2p.h"
+
+struct mntopt {
+ unsigned int mask;
+ const char *string;
+};
+
+static const struct mntopt mntopt_list[] = {
+ { EXT2_DEFM_DEBUG, "debug" },
+ { EXT2_DEFM_BSDGROUPS, "bsdgroups" },
+ { EXT2_DEFM_XATTR_USER, "user_xattr" },
+ { EXT2_DEFM_ACL, "acl" },
+ { EXT2_DEFM_UID16, "uid16" },
+ { EXT3_DEFM_JMODE_DATA, "journal_data" },
+ { EXT3_DEFM_JMODE_ORDERED, "journal_data_ordered" },
+ { EXT3_DEFM_JMODE_WBACK, "journal_data_writeback" },
+ { 0, 0 },
+};
+
+const char *e2p_mntopt2string(unsigned int mask)
+{
+ const struct mntopt *f;
+ static char buf[20];
+ int fnum;
+
+ for (f = mntopt_list; f->string; f++) {
+ if (mask == f->mask)
+ return f->string;
+ }
+ for (fnum = 0; mask >>= 1; fnum++);
+ sprintf(buf, "MNTOPT_%d", fnum);
+ return buf;
+}
+
+int e2p_string2mntopt(char *string, unsigned int *mask)
+{
+ const struct mntopt *f;
+ char *eptr;
+ int num;
+
+ for (f = mntopt_list; f->string; f++) {
+ if (!strcasecmp(string, f->string)) {
+ *mask = f->mask;
+ return 0;
+ }
+ }
+ if (strncasecmp(string, "MNTOPT_", 8))
+ return 1;
+
+ if (string[8] == 0)
+ return 1;
+ num = strtol(string+8, &eptr, 10);
+ if (num > 32 || num < 0)
+ return 1;
+ if (*eptr)
+ return 1;
+ *mask = 1 << num;
+ return 0;
+}
+
+static char *skip_over_blanks(char *cp)
+{
+ while (*cp && isspace(*cp))
+ cp++;
+ return cp;
+}
+
+static char *skip_over_word(char *cp)
+{
+ while (*cp && !isspace(*cp) && *cp != ',')
+ cp++;
+ return cp;
+}
+
+/*
+ * Edit a mntopt set array as requested by the user. The ok
+ * parameter, if non-zero, allows the application to limit what
+ * mntopts the user is allowed to set or clear using this function.
+ */
+int e2p_edit_mntopts(const char *str, __u32 *mntopts, __u32 ok)
+{
+ char *cp, *buf, *next;
+ int neg;
+ unsigned int mask;
+
+ buf = xstrdup(str);
+ cp = buf;
+ while (cp && *cp) {
+ neg = 0;
+ cp = skip_over_blanks(cp);
+ next = skip_over_word(cp);
+ if (*next == 0)
+ next = 0;
+ else
+ *next = 0;
+ switch (*cp) {
+ case '-':
+ case '^':
+ neg++;
+ case '+':
+ cp++;
+ break;
+ }
+ if (e2p_string2mntopt(cp, &mask))
+ return 1;
+ if (ok && !(ok & mask))
+ return 1;
+ if (mask & EXT3_DEFM_JMODE)
+ *mntopts &= ~EXT3_DEFM_JMODE;
+ if (neg)
+ *mntopts &= ~mask;
+ else
+ *mntopts |= mask;
+ cp = next ? next+1 : 0;
+ }
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/ostype.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/ostype.c
new file mode 100644
index 0000000000..1abe2ba912
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/ostype.c
@@ -0,0 +1,74 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * getostype.c - Get the Filesystem OS type
+ *
+ * Copyright (C) 2004,2005 Theodore Ts'o <tytso@mit.edu>
+ *
+ * This file can be redistributed under the terms of the GNU Library General
+ * Public License
+ */
+
+#include "e2p.h"
+#include <string.h>
+#include <stdlib.h>
+
+static const char *const os_tab[] =
+ { "Linux",
+ "Hurd",
+ "Masix",
+ "FreeBSD",
+ "Lites",
+ 0 };
+
+/*
+ * Convert an os_type to a string
+ */
+char *e2p_os2string(int os_type)
+{
+ const char *os;
+ char *ret;
+
+ if (os_type <= EXT2_OS_LITES)
+ os = os_tab[os_type];
+ else
+ os = "(unknown os)";
+
+ ret = xstrdup(os);
+ return ret;
+}
+
+/*
+ * Convert an os_type to a string
+ */
+int e2p_string2os(char *str)
+{
+ const char *const *cpp;
+ int i = 0;
+
+ for (cpp = os_tab; *cpp; cpp++, i++) {
+ if (!strcasecmp(str, *cpp))
+ return i;
+ }
+ return -1;
+}
+
+#ifdef TEST_PROGRAM
+int main(int argc, char **argv)
+{
+ char *s;
+ int i, os;
+
+ for (i=0; i <= EXT2_OS_LITES; i++) {
+ s = e2p_os2string(i);
+ os = e2p_string2os(s);
+ printf("%d: %s (%d)\n", i, s, os);
+ if (i != os) {
+ fprintf(stderr, "Failure!\n");
+ exit(1);
+ }
+ }
+ exit(0);
+}
+#endif
+
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/parse_num.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/parse_num.c
new file mode 100644
index 0000000000..6db076f9cd
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/parse_num.c
@@ -0,0 +1,65 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * parse_num.c - Parse the number of blocks
+ *
+ * Copyright (C) 2004,2005 Theodore Ts'o <tytso@mit.edu>
+ *
+ * This file can be redistributed under the terms of the GNU Library General
+ * Public License
+ */
+
+#include "e2p.h"
+
+#include <stdlib.h>
+
+unsigned long parse_num_blocks(const char *arg, int log_block_size)
+{
+ char *p;
+ unsigned long long num;
+
+ num = strtoull(arg, &p, 0);
+
+ if (p[0] && p[1])
+ return 0;
+
+ switch (*p) { /* Using fall-through logic */
+ case 'T': case 't':
+ num <<= 10;
+ case 'G': case 'g':
+ num <<= 10;
+ case 'M': case 'm':
+ num <<= 10;
+ case 'K': case 'k':
+ num >>= log_block_size;
+ break;
+ case 's':
+ num >>= 1;
+ break;
+ case '\0':
+ break;
+ default:
+ return 0;
+ }
+ return num;
+}
+
+#ifdef DEBUG
+#include <unistd.h>
+#include <stdio.h>
+
+main(int argc, char **argv)
+{
+ unsigned long num;
+ int log_block_size = 0;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s arg\n", argv[0]);
+ exit(1);
+ }
+
+ num = parse_num_blocks(argv[1], log_block_size);
+
+ printf("Parsed number: %lu\n", num);
+ exit(0);
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/pe.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/pe.c
new file mode 100644
index 0000000000..835274b54a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/pe.c
@@ -0,0 +1,32 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * pe.c - Print a second extended filesystem errors behavior
+ *
+ * Copyright (C) 1992, 1993, 1994 Remy Card <card@masi.ibp.fr>
+ * Laboratoire MASI, Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * This file can be redistributed under the terms of the GNU Library General
+ * Public License
+ */
+
+/*
+ * History:
+ * 94/01/09 - Creation
+ */
+
+#include <stdio.h>
+
+#include "e2p.h"
+
+void print_fs_errors(FILE *f, unsigned short errors)
+{
+ char *disp = NULL;
+ switch (errors) {
+ case EXT2_ERRORS_CONTINUE: disp = "Continue"; break;
+ case EXT2_ERRORS_RO: disp = "Remount read-only"; break;
+ case EXT2_ERRORS_PANIC: disp = "Panic"; break;
+ default: disp = "Unknown (continue)";
+ }
+ fprintf(f, disp);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/pf.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/pf.c
new file mode 100644
index 0000000000..55d4bc487f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/pf.c
@@ -0,0 +1,74 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * pf.c - Print file attributes on an ext2 file system
+ *
+ * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
+ * Laboratoire MASI, Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * This file can be redistributed under the terms of the GNU Library General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/10/30 - Creation
+ */
+
+#include <stdio.h>
+
+#include "e2p.h"
+
+struct flags_name {
+ unsigned long flag;
+ const char *short_name;
+ const char *long_name;
+};
+
+static const struct flags_name flags_array[] = {
+ { EXT2_SECRM_FL, "s", "Secure_Deletion" },
+ { EXT2_UNRM_FL, "u" , "Undelete" },
+ { EXT2_SYNC_FL, "S", "Synchronous_Updates" },
+ { EXT2_DIRSYNC_FL, "D", "Synchronous_Directory_Updates" },
+ { EXT2_IMMUTABLE_FL, "i", "Immutable" },
+ { EXT2_APPEND_FL, "a", "Append_Only" },
+ { EXT2_NODUMP_FL, "d", "No_Dump" },
+ { EXT2_NOATIME_FL, "A", "No_Atime" },
+ { EXT2_COMPR_FL, "c", "Compression_Requested" },
+#ifdef ENABLE_COMPRESSION
+ { EXT2_COMPRBLK_FL, "B", "Compressed_File" },
+ { EXT2_DIRTY_FL, "Z", "Compressed_Dirty_File" },
+ { EXT2_NOCOMPR_FL, "X", "Compression_Raw_Access" },
+ { EXT2_ECOMPR_FL, "E", "Compression_Error" },
+#endif
+ { EXT3_JOURNAL_DATA_FL, "j", "Journaled_Data" },
+ { EXT2_INDEX_FL, "I", "Indexed_direcctory" },
+ { EXT2_NOTAIL_FL, "t", "No_Tailmerging" },
+ { EXT2_TOPDIR_FL, "T", "Top_of_Directory_Hierarchies" },
+ { 0, NULL, NULL }
+};
+
+void print_flags (FILE * f, unsigned long flags, unsigned options)
+{
+ int long_opt = (options & PFOPT_LONG);
+ const struct flags_name *fp;
+ int first = 1;
+
+ for (fp = flags_array; fp->flag != 0; fp++) {
+ if (flags & fp->flag) {
+ if (long_opt) {
+ if (first)
+ first = 0;
+ else
+ fputs(", ", f);
+ fputs(fp->long_name, f);
+ } else
+ fputs(fp->short_name, f);
+ } else {
+ if (!long_opt)
+ fputs("-", f);
+ }
+ }
+ if (long_opt && first)
+ fputs("---", f);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/ps.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/ps.c
new file mode 100644
index 0000000000..a6b4099db5
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/ps.c
@@ -0,0 +1,27 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * ps.c - Print filesystem state
+ *
+ * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
+ * Laboratoire MASI, Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * This file can be redistributed under the terms of the GNU Library General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/12/22 - Creation
+ */
+
+#include <stdio.h>
+
+#include "e2p.h"
+
+void print_fs_state(FILE *f, unsigned short state)
+{
+ fprintf(f, (state & EXT2_VALID_FS ? " clean" : " not clean"));
+ if (state & EXT2_ERROR_FS)
+ fprintf(f, " with errors");
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/uuid.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/uuid.c
new file mode 100644
index 0000000000..474d64a5a4
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/e2p/uuid.c
@@ -0,0 +1,78 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * uuid.c -- utility routines for manipulating UUID's.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "../ext2fs/ext2_types.h"
+
+#include "e2p.h"
+
+struct uuid {
+ __u32 time_low;
+ __u16 time_mid;
+ __u16 time_hi_and_version;
+ __u16 clock_seq;
+ __u8 node[6];
+};
+
+/* Returns 1 if the uuid is the NULL uuid */
+int e2p_is_null_uuid(void *uu)
+{
+ __u8 *cp;
+ int i;
+
+ for (i=0, cp = uu; i < 16; i++)
+ if (*cp)
+ return 0;
+ return 1;
+}
+
+static void e2p_unpack_uuid(void *in, struct uuid *uu)
+{
+ __u8 *ptr = in;
+ __u32 tmp;
+
+ tmp = *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ uu->time_low = tmp;
+
+ tmp = *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ uu->time_mid = tmp;
+
+ tmp = *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ uu->time_hi_and_version = tmp;
+
+ tmp = *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ uu->clock_seq = tmp;
+
+ memcpy(uu->node, ptr, 6);
+}
+
+void e2p_uuid_to_str(void *uu, char *out)
+{
+ struct uuid uuid;
+
+ e2p_unpack_uuid(uu, &uuid);
+ sprintf(out,
+ "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ uuid.time_low, uuid.time_mid, uuid.time_hi_and_version,
+ uuid.clock_seq >> 8, uuid.clock_seq & 0xFF,
+ uuid.node[0], uuid.node[1], uuid.node[2],
+ uuid.node[3], uuid.node[4], uuid.node[5]);
+}
+
+const char *e2p_uuid2str(void *uu)
+{
+ static char buf[80];
+ if (e2p_is_null_uuid(uu))
+ return "<none>";
+ e2p_uuid_to_str(uu, buf);
+ return buf;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/Kbuild b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/Kbuild
new file mode 100644
index 0000000000..185887a446
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/Kbuild
@@ -0,0 +1,23 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+NEEDED-$(CONFIG_E2FSCK) = y
+NEEDED-$(CONFIG_FSCK) = y
+NEEDED-$(CONFIG_MKE2FS) = y
+NEEDED-$(CONFIG_TUNE2FS) = y
+
+lib-y:=
+lib-$(NEEDED-y) += gen_bitmap.o bitops.o ismounted.o mkjournal.o unix_io.o \
+ rw_bitmaps.o initialize.o bitmaps.o block.o \
+ ind_block.o inode.o freefs.o alloc_stats.o closefs.o \
+ openfs.o io_manager.o finddev.o read_bb.o alloc.o badblocks.o \
+ getsize.o getsectsize.o alloc_tables.o read_bb_file.o mkdir.o \
+ bb_inode.o newdir.o alloc_sb.o lookup.o dirblock.o expanddir.o \
+ dir_iterate.o link.o res_gdt.o icount.o get_pathname.o dblist.o \
+ dirhash.o version.o flushb.o unlink.o check_desc.o valid_blk.o \
+ ext_attr.o bmap.o dblist_dir.o ext2fs_inline.o swapfs.o
+
+CFLAGS += -include $(srctree)/e2fsprogs/e2fsbb.h
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/alloc.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/alloc.c
new file mode 100644
index 0000000000..590f23a7ee
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/alloc.c
@@ -0,0 +1,174 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * alloc.c --- allocate new inodes, blocks for ext2fs
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ *
+ */
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <time.h>
+#include <string.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * Right now, just search forward from the parent directory's block
+ * group to find the next free inode.
+ *
+ * Should have a special policy for directories.
+ */
+errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir,
+ int mode EXT2FS_ATTR((unused)),
+ ext2fs_inode_bitmap map, ext2_ino_t *ret)
+{
+ ext2_ino_t dir_group = 0;
+ ext2_ino_t i;
+ ext2_ino_t start_inode;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ if (!map)
+ map = fs->inode_map;
+ if (!map)
+ return EXT2_ET_NO_INODE_BITMAP;
+
+ if (dir > 0)
+ dir_group = (dir - 1) / EXT2_INODES_PER_GROUP(fs->super);
+
+ start_inode = (dir_group * EXT2_INODES_PER_GROUP(fs->super)) + 1;
+ if (start_inode < EXT2_FIRST_INODE(fs->super))
+ start_inode = EXT2_FIRST_INODE(fs->super);
+ i = start_inode;
+
+ do {
+ if (!ext2fs_fast_test_inode_bitmap(map, i))
+ break;
+ i++;
+ if (i > fs->super->s_inodes_count)
+ i = EXT2_FIRST_INODE(fs->super);
+ } while (i != start_inode);
+
+ if (ext2fs_test_inode_bitmap(map, i))
+ return EXT2_ET_INODE_ALLOC_FAIL;
+ *ret = i;
+ return 0;
+}
+
+/*
+ * Stupid algorithm --- we now just search forward starting from the
+ * goal. Should put in a smarter one someday....
+ */
+errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal,
+ ext2fs_block_bitmap map, blk_t *ret)
+{
+ blk_t i;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ if (!map)
+ map = fs->block_map;
+ if (!map)
+ return EXT2_ET_NO_BLOCK_BITMAP;
+ if (!goal || (goal >= fs->super->s_blocks_count))
+ goal = fs->super->s_first_data_block;
+ i = goal;
+ do {
+ if (!ext2fs_fast_test_block_bitmap(map, i)) {
+ *ret = i;
+ return 0;
+ }
+ i++;
+ if (i >= fs->super->s_blocks_count)
+ i = fs->super->s_first_data_block;
+ } while (i != goal);
+ return EXT2_ET_BLOCK_ALLOC_FAIL;
+}
+
+/*
+ * This function zeros out the allocated block, and updates all of the
+ * appropriate filesystem records.
+ */
+errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal,
+ char *block_buf, blk_t *ret)
+{
+ errcode_t retval;
+ blk_t block;
+ char *buf = 0;
+
+ if (!block_buf) {
+ retval = ext2fs_get_mem(fs->blocksize, &buf);
+ if (retval)
+ return retval;
+ block_buf = buf;
+ }
+ memset(block_buf, 0, fs->blocksize);
+
+ if (!fs->block_map) {
+ retval = ext2fs_read_block_bitmap(fs);
+ if (retval)
+ goto fail;
+ }
+
+ retval = ext2fs_new_block(fs, goal, 0, &block);
+ if (retval)
+ goto fail;
+
+ retval = io_channel_write_blk(fs->io, block, 1, block_buf);
+ if (retval)
+ goto fail;
+
+ ext2fs_block_alloc_stats(fs, block, +1);
+ *ret = block;
+ return 0;
+
+fail:
+ if (buf)
+ ext2fs_free_mem(&buf);
+ return retval;
+}
+
+errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start, blk_t finish,
+ int num, ext2fs_block_bitmap map, blk_t *ret)
+{
+ blk_t b = start;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ if (!map)
+ map = fs->block_map;
+ if (!map)
+ return EXT2_ET_NO_BLOCK_BITMAP;
+ if (!b)
+ b = fs->super->s_first_data_block;
+ if (!finish)
+ finish = start;
+ if (!num)
+ num = 1;
+ do {
+ if (b+num-1 > fs->super->s_blocks_count)
+ b = fs->super->s_first_data_block;
+ if (ext2fs_fast_test_block_bitmap_range(map, b, num)) {
+ *ret = b;
+ return 0;
+ }
+ b++;
+ } while (b != finish);
+ return EXT2_ET_BLOCK_ALLOC_FAIL;
+}
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/alloc_sb.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/alloc_sb.c
new file mode 100644
index 0000000000..a7437c96f5
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/alloc_sb.c
@@ -0,0 +1,58 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * alloc_sb.c --- Allocate the superblock and block group descriptors for a
+ * newly initialized filesystem. Used by mke2fs when initializing a filesystem
+ *
+ * Copyright (C) 1994, 1995, 1996, 2003 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+int ext2fs_reserve_super_and_bgd(ext2_filsys fs,
+ dgrp_t group,
+ ext2fs_block_bitmap bmap)
+{
+ blk_t super_blk, old_desc_blk, new_desc_blk;
+ int j, old_desc_blocks, num_blocks;
+
+ num_blocks = ext2fs_super_and_bgd_loc(fs, group, &super_blk,
+ &old_desc_blk, &new_desc_blk, 0);
+
+ if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
+ old_desc_blocks = fs->super->s_first_meta_bg;
+ else
+ old_desc_blocks =
+ fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
+
+ if (super_blk || (group == 0))
+ ext2fs_mark_block_bitmap(bmap, super_blk);
+
+ if (old_desc_blk) {
+ for (j=0; j < old_desc_blocks; j++)
+ ext2fs_mark_block_bitmap(bmap, old_desc_blk + j);
+ }
+ if (new_desc_blk)
+ ext2fs_mark_block_bitmap(bmap, new_desc_blk);
+
+ return num_blocks;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/alloc_stats.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/alloc_stats.c
new file mode 100644
index 0000000000..f3ab06a237
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/alloc_stats.c
@@ -0,0 +1,53 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * alloc_stats.c --- Update allocation statistics for ext2fs
+ *
+ * Copyright (C) 2001 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ *
+ */
+
+#include <stdio.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino,
+ int inuse, int isdir)
+{
+ int group = ext2fs_group_of_ino(fs, ino);
+
+ if (inuse > 0)
+ ext2fs_mark_inode_bitmap(fs->inode_map, ino);
+ else
+ ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
+ fs->group_desc[group].bg_free_inodes_count -= inuse;
+ if (isdir)
+ fs->group_desc[group].bg_used_dirs_count += inuse;
+ fs->super->s_free_inodes_count -= inuse;
+ ext2fs_mark_super_dirty(fs);
+ ext2fs_mark_ib_dirty(fs);
+}
+
+void ext2fs_inode_alloc_stats(ext2_filsys fs, ext2_ino_t ino, int inuse)
+{
+ ext2fs_inode_alloc_stats2(fs, ino, inuse, 0);
+}
+
+void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse)
+{
+ int group = ext2fs_group_of_blk(fs, blk);
+
+ if (inuse > 0)
+ ext2fs_mark_block_bitmap(fs->block_map, blk);
+ else
+ ext2fs_unmark_block_bitmap(fs->block_map, blk);
+ fs->group_desc[group].bg_free_blocks_count -= inuse;
+ fs->super->s_free_blocks_count -= inuse;
+ ext2fs_mark_super_dirty(fs);
+ ext2fs_mark_bb_dirty(fs);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/alloc_tables.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/alloc_tables.c
new file mode 100644
index 0000000000..b2d786ed83
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/alloc_tables.c
@@ -0,0 +1,118 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * alloc_tables.c --- Allocate tables for a newly initialized
+ * filesystem. Used by mke2fs when initializing a filesystem
+ *
+ * Copyright (C) 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group,
+ ext2fs_block_bitmap bmap)
+{
+ errcode_t retval;
+ blk_t group_blk, start_blk, last_blk, new_blk, blk;
+ int j;
+
+ group_blk = fs->super->s_first_data_block +
+ (group * fs->super->s_blocks_per_group);
+
+ last_blk = group_blk + fs->super->s_blocks_per_group;
+ if (last_blk >= fs->super->s_blocks_count)
+ last_blk = fs->super->s_blocks_count - 1;
+
+ if (!bmap)
+ bmap = fs->block_map;
+
+ /*
+ * Allocate the block and inode bitmaps, if necessary
+ */
+ if (fs->stride) {
+ start_blk = group_blk + fs->inode_blocks_per_group;
+ start_blk += ((fs->stride * group) %
+ (last_blk - start_blk));
+ if (start_blk > last_blk)
+ start_blk = group_blk;
+ } else
+ start_blk = group_blk;
+
+ if (!fs->group_desc[group].bg_block_bitmap) {
+ retval = ext2fs_get_free_blocks(fs, start_blk, last_blk,
+ 1, bmap, &new_blk);
+ if (retval == EXT2_ET_BLOCK_ALLOC_FAIL)
+ retval = ext2fs_get_free_blocks(fs, group_blk,
+ last_blk, 1, bmap, &new_blk);
+ if (retval)
+ return retval;
+ ext2fs_mark_block_bitmap(bmap, new_blk);
+ fs->group_desc[group].bg_block_bitmap = new_blk;
+ }
+
+ if (!fs->group_desc[group].bg_inode_bitmap) {
+ retval = ext2fs_get_free_blocks(fs, start_blk, last_blk,
+ 1, bmap, &new_blk);
+ if (retval == EXT2_ET_BLOCK_ALLOC_FAIL)
+ retval = ext2fs_get_free_blocks(fs, group_blk,
+ last_blk, 1, bmap, &new_blk);
+ if (retval)
+ return retval;
+ ext2fs_mark_block_bitmap(bmap, new_blk);
+ fs->group_desc[group].bg_inode_bitmap = new_blk;
+ }
+
+ /*
+ * Allocate the inode table
+ */
+ if (!fs->group_desc[group].bg_inode_table) {
+ retval = ext2fs_get_free_blocks(fs, group_blk, last_blk,
+ fs->inode_blocks_per_group,
+ bmap, &new_blk);
+ if (retval)
+ return retval;
+ for (j=0, blk = new_blk;
+ j < fs->inode_blocks_per_group;
+ j++, blk++)
+ ext2fs_mark_block_bitmap(bmap, blk);
+ fs->group_desc[group].bg_inode_table = new_blk;
+ }
+
+
+ return 0;
+}
+
+
+
+errcode_t ext2fs_allocate_tables(ext2_filsys fs)
+{
+ errcode_t retval;
+ dgrp_t i;
+
+ for (i = 0; i < fs->group_desc_count; i++) {
+ retval = ext2fs_allocate_group_table(fs, i, fs->block_map);
+ if (retval)
+ return retval;
+ }
+ return 0;
+}
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/badblocks.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/badblocks.c
new file mode 100644
index 0000000000..6e5cc10b82
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/badblocks.c
@@ -0,0 +1,328 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * badblocks.c --- routines to manipulate the bad block structure
+ *
+ * Copyright (C) 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+
+/*
+ * Helper function for making a badblocks list
+ */
+static errcode_t make_u32_list(int size, int num, __u32 *list,
+ ext2_u32_list *ret)
+{
+ ext2_u32_list bb;
+ errcode_t retval;
+
+ retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_list), &bb);
+ if (retval)
+ return retval;
+ memset(bb, 0, sizeof(struct ext2_struct_u32_list));
+ bb->magic = EXT2_ET_MAGIC_BADBLOCKS_LIST;
+ bb->size = size ? size : 10;
+ bb->num = num;
+ retval = ext2fs_get_mem(bb->size * sizeof(blk_t), &bb->list);
+ if (!bb->list) {
+ ext2fs_free_mem(&bb);
+ return retval;
+ }
+ if (list)
+ memcpy(bb->list, list, bb->size * sizeof(blk_t));
+ else
+ memset(bb->list, 0, bb->size * sizeof(blk_t));
+ *ret = bb;
+ return 0;
+}
+
+
+/*
+ * This procedure creates an empty u32 list.
+ */
+errcode_t ext2fs_u32_list_create(ext2_u32_list *ret, int size)
+{
+ return make_u32_list(size, 0, 0, ret);
+}
+
+/*
+ * This procedure creates an empty badblocks list.
+ */
+errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret, int size)
+{
+ return make_u32_list(size, 0, 0, (ext2_badblocks_list *) ret);
+}
+
+
+/*
+ * This procedure copies a badblocks list
+ */
+errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest)
+{
+ errcode_t retval;
+
+ retval = make_u32_list(src->size, src->num, src->list, dest);
+ if (retval)
+ return retval;
+ (*dest)->badblocks_flags = src->badblocks_flags;
+ return 0;
+}
+
+errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src,
+ ext2_badblocks_list *dest)
+{
+ return ext2fs_u32_copy((ext2_u32_list) src,
+ (ext2_u32_list *) dest);
+}
+
+/*
+ * This procedure frees a badblocks list.
+ *
+ * (note: moved to closefs.c)
+ */
+
+
+/*
+ * This procedure adds a block to a badblocks list.
+ */
+errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk)
+{
+ errcode_t retval;
+ int i, j;
+ unsigned long old_size;
+
+ EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
+
+ if (bb->num >= bb->size) {
+ old_size = bb->size * sizeof(__u32);
+ bb->size += 100;
+ retval = ext2fs_resize_mem(old_size, bb->size * sizeof(__u32),
+ &bb->list);
+ if (retval) {
+ bb->size -= 100;
+ return retval;
+ }
+ }
+
+ /*
+ * Add special case code for appending to the end of the list
+ */
+ i = bb->num-1;
+ if ((bb->num != 0) && (bb->list[i] == blk))
+ return 0;
+ if ((bb->num == 0) || (bb->list[i] < blk)) {
+ bb->list[bb->num++] = blk;
+ return 0;
+ }
+
+ j = bb->num;
+ for (i=0; i < bb->num; i++) {
+ if (bb->list[i] == blk)
+ return 0;
+ if (bb->list[i] > blk) {
+ j = i;
+ break;
+ }
+ }
+ for (i=bb->num; i > j; i--)
+ bb->list[i] = bb->list[i-1];
+ bb->list[j] = blk;
+ bb->num++;
+ return 0;
+}
+
+errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, blk_t blk)
+{
+ return ext2fs_u32_list_add((ext2_u32_list) bb, (__u32) blk);
+}
+
+/*
+ * This procedure finds a particular block is on a badblocks
+ * list.
+ */
+int ext2fs_u32_list_find(ext2_u32_list bb, __u32 blk)
+{
+ int low, high, mid;
+
+ if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
+ return -1;
+
+ if (bb->num == 0)
+ return -1;
+
+ low = 0;
+ high = bb->num-1;
+ if (blk == bb->list[low])
+ return low;
+ if (blk == bb->list[high])
+ return high;
+
+ while (low < high) {
+ mid = (low+high)/2;
+ if (mid == low || mid == high)
+ break;
+ if (blk == bb->list[mid])
+ return mid;
+ if (blk < bb->list[mid])
+ high = mid;
+ else
+ low = mid;
+ }
+ return -1;
+}
+
+/*
+ * This procedure tests to see if a particular block is on a badblocks
+ * list.
+ */
+int ext2fs_u32_list_test(ext2_u32_list bb, __u32 blk)
+{
+ if (ext2fs_u32_list_find(bb, blk) < 0)
+ return 0;
+ else
+ return 1;
+}
+
+int ext2fs_badblocks_list_test(ext2_badblocks_list bb, blk_t blk)
+{
+ return ext2fs_u32_list_test((ext2_u32_list) bb, (__u32) blk);
+}
+
+
+/*
+ * Remove a block from the badblock list
+ */
+int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk)
+{
+ int remloc, i;
+
+ if (bb->num == 0)
+ return -1;
+
+ remloc = ext2fs_u32_list_find(bb, blk);
+ if (remloc < 0)
+ return -1;
+
+ for (i = remloc; i < bb->num - 1; i++)
+ bb->list[i] = bb->list[i+1];
+ bb->num--;
+ return 0;
+}
+
+void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk)
+{
+ ext2fs_u32_list_del(bb, blk);
+}
+
+errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb,
+ ext2_u32_iterate *ret)
+{
+ ext2_u32_iterate iter;
+ errcode_t retval;
+
+ EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
+
+ retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_iterate), &iter);
+ if (retval)
+ return retval;
+
+ iter->magic = EXT2_ET_MAGIC_BADBLOCKS_ITERATE;
+ iter->bb = bb;
+ iter->ptr = 0;
+ *ret = iter;
+ return 0;
+}
+
+errcode_t ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb,
+ ext2_badblocks_iterate *ret)
+{
+ return ext2fs_u32_list_iterate_begin((ext2_u32_list) bb,
+ (ext2_u32_iterate *) ret);
+}
+
+
+int ext2fs_u32_list_iterate(ext2_u32_iterate iter, __u32 *blk)
+{
+ ext2_u32_list bb;
+
+ if (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE)
+ return 0;
+
+ bb = iter->bb;
+
+ if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
+ return 0;
+
+ if (iter->ptr < bb->num) {
+ *blk = bb->list[iter->ptr++];
+ return 1;
+ }
+ *blk = 0;
+ return 0;
+}
+
+int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, blk_t *blk)
+{
+ return ext2fs_u32_list_iterate((ext2_u32_iterate) iter,
+ (__u32 *) blk);
+}
+
+
+void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter)
+{
+ if (!iter || (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE))
+ return;
+
+ iter->bb = 0;
+ ext2fs_free_mem(&iter);
+}
+
+void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter)
+{
+ ext2fs_u32_list_iterate_end((ext2_u32_iterate) iter);
+}
+
+
+int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2)
+{
+ EXT2_CHECK_MAGIC(bb1, EXT2_ET_MAGIC_BADBLOCKS_LIST);
+ EXT2_CHECK_MAGIC(bb2, EXT2_ET_MAGIC_BADBLOCKS_LIST);
+
+ if (bb1->num != bb2->num)
+ return 0;
+
+ if (memcmp(bb1->list, bb2->list, bb1->num * sizeof(blk_t)) != 0)
+ return 0;
+ return 1;
+}
+
+int ext2fs_badblocks_equal(ext2_badblocks_list bb1, ext2_badblocks_list bb2)
+{
+ return ext2fs_u32_list_equal((ext2_u32_list) bb1,
+ (ext2_u32_list) bb2);
+}
+
+int ext2fs_u32_list_count(ext2_u32_list bb)
+{
+ return bb->num;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bb_compat.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bb_compat.c
new file mode 100644
index 0000000000..419ac77859
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bb_compat.c
@@ -0,0 +1,64 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bb_compat.c --- compatibility badblocks routines
+ *
+ * Copyright (C) 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+
+errcode_t badblocks_list_create(badblocks_list *ret, int size)
+{
+ return ext2fs_badblocks_list_create(ret, size);
+}
+
+void badblocks_list_free(badblocks_list bb)
+{
+ ext2fs_badblocks_list_free(bb);
+}
+
+errcode_t badblocks_list_add(badblocks_list bb, blk_t blk)
+{
+ return ext2fs_badblocks_list_add(bb, blk);
+}
+
+int badblocks_list_test(badblocks_list bb, blk_t blk)
+{
+ return ext2fs_badblocks_list_test(bb, blk);
+}
+
+errcode_t badblocks_list_iterate_begin(badblocks_list bb,
+ badblocks_iterate *ret)
+{
+ return ext2fs_badblocks_list_iterate_begin(bb, ret);
+}
+
+int badblocks_list_iterate(badblocks_iterate iter, blk_t *blk)
+{
+ return ext2fs_badblocks_list_iterate(iter, blk);
+}
+
+void badblocks_list_iterate_end(badblocks_iterate iter)
+{
+ ext2fs_badblocks_list_iterate_end(iter);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bb_inode.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bb_inode.c
new file mode 100644
index 0000000000..855f86eac9
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bb_inode.c
@@ -0,0 +1,268 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bb_inode.c --- routines to update the bad block inode.
+ *
+ * WARNING: This routine modifies a lot of state in the filesystem; if
+ * this routine returns an error, the bad block inode may be in an
+ * inconsistent state.
+ *
+ * Copyright (C) 1994, 1995 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+struct set_badblock_record {
+ ext2_badblocks_iterate bb_iter;
+ int bad_block_count;
+ blk_t *ind_blocks;
+ int max_ind_blocks;
+ int ind_blocks_size;
+ int ind_blocks_ptr;
+ char *block_buf;
+ errcode_t err;
+};
+
+static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
+ e2_blkcnt_t blockcnt,
+ blk_t ref_block, int ref_offset,
+ void *priv_data);
+static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
+ e2_blkcnt_t blockcnt,
+ blk_t ref_block, int ref_offset,
+ void *priv_data);
+
+/*
+ * Given a bad blocks bitmap, update the bad blocks inode to reflect
+ * the map.
+ */
+errcode_t ext2fs_update_bb_inode(ext2_filsys fs, ext2_badblocks_list bb_list)
+{
+ errcode_t retval;
+ struct set_badblock_record rec;
+ struct ext2_inode inode;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ if (!fs->block_map)
+ return EXT2_ET_NO_BLOCK_BITMAP;
+
+ rec.bad_block_count = 0;
+ rec.ind_blocks_size = rec.ind_blocks_ptr = 0;
+ rec.max_ind_blocks = 10;
+ retval = ext2fs_get_mem(rec.max_ind_blocks * sizeof(blk_t),
+ &rec.ind_blocks);
+ if (retval)
+ return retval;
+ memset(rec.ind_blocks, 0, rec.max_ind_blocks * sizeof(blk_t));
+ retval = ext2fs_get_mem(fs->blocksize, &rec.block_buf);
+ if (retval)
+ goto cleanup;
+ memset(rec.block_buf, 0, fs->blocksize);
+ rec.err = 0;
+
+ /*
+ * First clear the old bad blocks (while saving the indirect blocks)
+ */
+ retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO,
+ BLOCK_FLAG_DEPTH_TRAVERSE, 0,
+ clear_bad_block_proc, &rec);
+ if (retval)
+ goto cleanup;
+ if (rec.err) {
+ retval = rec.err;
+ goto cleanup;
+ }
+
+ /*
+ * Now set the bad blocks!
+ *
+ * First, mark the bad blocks as used. This prevents a bad
+ * block from being used as an indirecto block for the bad
+ * block inode (!).
+ */
+ if (bb_list) {
+ retval = ext2fs_badblocks_list_iterate_begin(bb_list,
+ &rec.bb_iter);
+ if (retval)
+ goto cleanup;
+ retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO,
+ BLOCK_FLAG_APPEND, 0,
+ set_bad_block_proc, &rec);
+ ext2fs_badblocks_list_iterate_end(rec.bb_iter);
+ if (retval)
+ goto cleanup;
+ if (rec.err) {
+ retval = rec.err;
+ goto cleanup;
+ }
+ }
+
+ /*
+ * Update the bad block inode's mod time and block count
+ * field.
+ */
+ retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode);
+ if (retval)
+ goto cleanup;
+
+ inode.i_atime = inode.i_mtime = time(0);
+ if (!inode.i_ctime)
+ inode.i_ctime = time(0);
+ inode.i_blocks = rec.bad_block_count * (fs->blocksize / 512);
+ inode.i_size = rec.bad_block_count * fs->blocksize;
+
+ retval = ext2fs_write_inode(fs, EXT2_BAD_INO, &inode);
+ if (retval)
+ goto cleanup;
+
+cleanup:
+ ext2fs_free_mem(&rec.ind_blocks);
+ ext2fs_free_mem(&rec.block_buf);
+ return retval;
+}
+
+/*
+ * Helper function for update_bb_inode()
+ *
+ * Clear the bad blocks in the bad block inode, while saving the
+ * indirect blocks.
+ */
+#ifdef __TURBOC__
+# pragma argsused
+#endif
+static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
+ e2_blkcnt_t blockcnt,
+ blk_t ref_block EXT2FS_ATTR((unused)),
+ int ref_offset EXT2FS_ATTR((unused)),
+ void *priv_data)
+{
+ struct set_badblock_record *rec = (struct set_badblock_record *)
+ priv_data;
+ errcode_t retval;
+ unsigned long old_size;
+
+ if (!*block_nr)
+ return 0;
+
+ /*
+ * If the block number is outrageous, clear it and ignore it.
+ */
+ if (*block_nr >= fs->super->s_blocks_count ||
+ *block_nr < fs->super->s_first_data_block) {
+ *block_nr = 0;
+ return BLOCK_CHANGED;
+ }
+
+ if (blockcnt < 0) {
+ if (rec->ind_blocks_size >= rec->max_ind_blocks) {
+ old_size = rec->max_ind_blocks * sizeof(blk_t);
+ rec->max_ind_blocks += 10;
+ retval = ext2fs_resize_mem(old_size,
+ rec->max_ind_blocks * sizeof(blk_t),
+ &rec->ind_blocks);
+ if (retval) {
+ rec->max_ind_blocks -= 10;
+ rec->err = retval;
+ return BLOCK_ABORT;
+ }
+ }
+ rec->ind_blocks[rec->ind_blocks_size++] = *block_nr;
+ }
+
+ /*
+ * Mark the block as unused, and update accounting information
+ */
+ ext2fs_block_alloc_stats(fs, *block_nr, -1);
+
+ *block_nr = 0;
+ return BLOCK_CHANGED;
+}
+
+
+/*
+ * Helper function for update_bb_inode()
+ *
+ * Set the block list in the bad block inode, using the supplied bitmap.
+ */
+#ifdef __TURBOC__
+ #pragma argsused
+#endif
+static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
+ e2_blkcnt_t blockcnt,
+ blk_t ref_block EXT2FS_ATTR((unused)),
+ int ref_offset EXT2FS_ATTR((unused)),
+ void *priv_data)
+{
+ struct set_badblock_record *rec = (struct set_badblock_record *)
+ priv_data;
+ errcode_t retval;
+ blk_t blk;
+
+ if (blockcnt >= 0) {
+ /*
+ * Get the next bad block.
+ */
+ if (!ext2fs_badblocks_list_iterate(rec->bb_iter, &blk))
+ return BLOCK_ABORT;
+ rec->bad_block_count++;
+ } else {
+ /*
+ * An indirect block; fetch a block from the
+ * previously used indirect block list. The block
+ * most be not marked as used; if so, get another one.
+ * If we run out of reserved indirect blocks, allocate
+ * a new one.
+ */
+ retry:
+ if (rec->ind_blocks_ptr < rec->ind_blocks_size) {
+ blk = rec->ind_blocks[rec->ind_blocks_ptr++];
+ if (ext2fs_test_block_bitmap(fs->block_map, blk))
+ goto retry;
+ } else {
+ retval = ext2fs_new_block(fs, 0, 0, &blk);
+ if (retval) {
+ rec->err = retval;
+ return BLOCK_ABORT;
+ }
+ }
+ retval = io_channel_write_blk(fs->io, blk, 1, rec->block_buf);
+ if (retval) {
+ rec->err = retval;
+ return BLOCK_ABORT;
+ }
+ }
+
+ /*
+ * Update block counts
+ */
+ ext2fs_block_alloc_stats(fs, blk, +1);
+
+ *block_nr = blk;
+ return BLOCK_CHANGED;
+}
+
+
+
+
+
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bitmaps.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bitmaps.c
new file mode 100644
index 0000000000..637ed27af9
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bitmaps.c
@@ -0,0 +1,211 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bitmaps.c --- routines to read, write, and manipulate the inode and
+ * block bitmaps.
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+static errcode_t make_bitmap(__u32 start, __u32 end, __u32 real_end,
+ const char *descr, char *init_map,
+ ext2fs_generic_bitmap *ret)
+{
+ ext2fs_generic_bitmap bitmap;
+ errcode_t retval;
+ size_t size;
+
+ retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap),
+ &bitmap);
+ if (retval)
+ return retval;
+
+ bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
+ bitmap->fs = NULL;
+ bitmap->start = start;
+ bitmap->end = end;
+ bitmap->real_end = real_end;
+ bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK;
+ if (descr) {
+ retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description);
+ if (retval) {
+ ext2fs_free_mem(&bitmap);
+ return retval;
+ }
+ strcpy(bitmap->description, descr);
+ } else
+ bitmap->description = 0;
+
+ size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1);
+ retval = ext2fs_get_mem(size, &bitmap->bitmap);
+ if (retval) {
+ ext2fs_free_mem(&bitmap->description);
+ ext2fs_free_mem(&bitmap);
+ return retval;
+ }
+
+ if (init_map)
+ memcpy(bitmap->bitmap, init_map, size);
+ else
+ memset(bitmap->bitmap, 0, size);
+ *ret = bitmap;
+ return 0;
+}
+
+errcode_t ext2fs_allocate_generic_bitmap(__u32 start,
+ __u32 end,
+ __u32 real_end,
+ const char *descr,
+ ext2fs_generic_bitmap *ret)
+{
+ return make_bitmap(start, end, real_end, descr, 0, ret);
+}
+
+errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src,
+ ext2fs_generic_bitmap *dest)
+{
+ errcode_t retval;
+ ext2fs_generic_bitmap new_map;
+
+ retval = make_bitmap(src->start, src->end, src->real_end,
+ src->description, src->bitmap, &new_map);
+ if (retval)
+ return retval;
+ new_map->magic = src->magic;
+ new_map->fs = src->fs;
+ new_map->base_error_code = src->base_error_code;
+ *dest = new_map;
+ return 0;
+}
+
+void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map)
+{
+ __u32 i, j;
+
+ for (i=map->end+1, j = i - map->start; i <= map->real_end; i++, j++)
+ ext2fs_set_bit(j, map->bitmap);
+}
+
+errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs,
+ const char *descr,
+ ext2fs_inode_bitmap *ret)
+{
+ ext2fs_inode_bitmap bitmap;
+ errcode_t retval;
+ __u32 start, end, real_end;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ fs->write_bitmaps = ext2fs_write_bitmaps;
+
+ start = 1;
+ end = fs->super->s_inodes_count;
+ real_end = (EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count);
+
+ retval = ext2fs_allocate_generic_bitmap(start, end, real_end,
+ descr, &bitmap);
+ if (retval)
+ return retval;
+
+ bitmap->magic = EXT2_ET_MAGIC_INODE_BITMAP;
+ bitmap->fs = fs;
+ bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK;
+
+ *ret = bitmap;
+ return 0;
+}
+
+errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs,
+ const char *descr,
+ ext2fs_block_bitmap *ret)
+{
+ ext2fs_block_bitmap bitmap;
+ errcode_t retval;
+ __u32 start, end, real_end;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ fs->write_bitmaps = ext2fs_write_bitmaps;
+
+ start = fs->super->s_first_data_block;
+ end = fs->super->s_blocks_count-1;
+ real_end = (EXT2_BLOCKS_PER_GROUP(fs->super)
+ * fs->group_desc_count)-1 + start;
+
+ retval = ext2fs_allocate_generic_bitmap(start, end, real_end,
+ descr, &bitmap);
+ if (retval)
+ return retval;
+
+ bitmap->magic = EXT2_ET_MAGIC_BLOCK_BITMAP;
+ bitmap->fs = fs;
+ bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK;
+
+ *ret = bitmap;
+ return 0;
+}
+
+errcode_t ext2fs_fudge_inode_bitmap_end(ext2fs_inode_bitmap bitmap,
+ ext2_ino_t end, ext2_ino_t *oend)
+{
+ EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_INODE_BITMAP);
+
+ if (end > bitmap->real_end)
+ return EXT2_ET_FUDGE_INODE_BITMAP_END;
+ if (oend)
+ *oend = bitmap->end;
+ bitmap->end = end;
+ return 0;
+}
+
+errcode_t ext2fs_fudge_block_bitmap_end(ext2fs_block_bitmap bitmap,
+ blk_t end, blk_t *oend)
+{
+ EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_BLOCK_BITMAP);
+
+ if (end > bitmap->real_end)
+ return EXT2_ET_FUDGE_BLOCK_BITMAP_END;
+ if (oend)
+ *oend = bitmap->end;
+ bitmap->end = end;
+ return 0;
+}
+
+void ext2fs_clear_inode_bitmap(ext2fs_inode_bitmap bitmap)
+{
+ if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_INODE_BITMAP))
+ return;
+
+ memset(bitmap->bitmap, 0,
+ (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1));
+}
+
+void ext2fs_clear_block_bitmap(ext2fs_block_bitmap bitmap)
+{
+ if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_BLOCK_BITMAP))
+ return;
+
+ memset(bitmap->bitmap, 0,
+ (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1));
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bitops.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bitops.c
new file mode 100644
index 0000000000..9870611305
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bitops.c
@@ -0,0 +1,91 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bitops.c --- Bitmap frobbing code. See bitops.h for the inlined
+ * routines.
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+#ifndef _EXT2_HAVE_ASM_BITOPS_
+
+/*
+ * For the benefit of those who are trying to port Linux to another
+ * architecture, here are some C-language equivalents. You should
+ * recode these in the native assmebly language, if at all possible.
+ *
+ * C language equivalents written by Theodore Ts'o, 9/26/92.
+ * Modified by Pete A. Zaitcev 7/14/95 to be portable to big endian
+ * systems, as well as non-32 bit systems.
+ */
+
+int ext2fs_set_bit(unsigned int nr,void * addr)
+{
+ int mask, retval;
+ unsigned char *ADDR = (unsigned char *) addr;
+
+ ADDR += nr >> 3;
+ mask = 1 << (nr & 0x07);
+ retval = mask & *ADDR;
+ *ADDR |= mask;
+ return retval;
+}
+
+int ext2fs_clear_bit(unsigned int nr, void * addr)
+{
+ int mask, retval;
+ unsigned char *ADDR = (unsigned char *) addr;
+
+ ADDR += nr >> 3;
+ mask = 1 << (nr & 0x07);
+ retval = mask & *ADDR;
+ *ADDR &= ~mask;
+ return retval;
+}
+
+int ext2fs_test_bit(unsigned int nr, const void * addr)
+{
+ int mask;
+ const unsigned char *ADDR = (const unsigned char *) addr;
+
+ ADDR += nr >> 3;
+ mask = 1 << (nr & 0x07);
+ return (mask & *ADDR);
+}
+
+#endif /* !_EXT2_HAVE_ASM_BITOPS_ */
+
+void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg,
+ const char *description)
+{
+#ifndef OMIT_COM_ERR
+ if (description)
+ bb_error_msg("#%lu for %s", arg, description);
+ else
+ bb_error_msg("#%lu", arg);
+#endif
+}
+
+void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap,
+ int code, unsigned long arg)
+{
+#ifndef OMIT_COM_ERR
+ if (bitmap->description)
+ bb_error_msg("#%lu for %s", arg, bitmap->description);
+ else
+ bb_error_msg("#%lu", arg);
+#endif
+}
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bitops.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bitops.h
new file mode 100644
index 0000000000..b34bd98f76
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bitops.h
@@ -0,0 +1,107 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bitops.h --- Bitmap frobbing code. The byte swapping routines are
+ * also included here.
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ *
+ * i386 bitops operations taken from <asm/bitops.h>, Copyright 1992,
+ * Linus Torvalds.
+ */
+
+#include <string.h>
+//#include <strings.h>
+
+extern int ext2fs_set_bit(unsigned int nr,void * addr);
+extern int ext2fs_clear_bit(unsigned int nr, void * addr);
+extern int ext2fs_test_bit(unsigned int nr, const void * addr);
+extern __u16 ext2fs_swab16(__u16 val);
+extern __u32 ext2fs_swab32(__u32 val);
+
+#ifdef WORDS_BIGENDIAN
+#define ext2fs_cpu_to_le32(x) ext2fs_swab32((x))
+#define ext2fs_le32_to_cpu(x) ext2fs_swab32((x))
+#define ext2fs_cpu_to_le16(x) ext2fs_swab16((x))
+#define ext2fs_le16_to_cpu(x) ext2fs_swab16((x))
+#define ext2fs_cpu_to_be32(x) ((__u32)(x))
+#define ext2fs_be32_to_cpu(x) ((__u32)(x))
+#define ext2fs_cpu_to_be16(x) ((__u16)(x))
+#define ext2fs_be16_to_cpu(x) ((__u16)(x))
+#else
+#define ext2fs_cpu_to_le32(x) ((__u32)(x))
+#define ext2fs_le32_to_cpu(x) ((__u32)(x))
+#define ext2fs_cpu_to_le16(x) ((__u16)(x))
+#define ext2fs_le16_to_cpu(x) ((__u16)(x))
+#define ext2fs_cpu_to_be32(x) ext2fs_swab32((x))
+#define ext2fs_be32_to_cpu(x) ext2fs_swab32((x))
+#define ext2fs_cpu_to_be16(x) ext2fs_swab16((x))
+#define ext2fs_be16_to_cpu(x) ext2fs_swab16((x))
+#endif
+
+/*
+ * EXT2FS bitmap manipulation routines.
+ */
+
+/* Support for sending warning messages from the inline subroutines */
+extern const char *ext2fs_block_string;
+extern const char *ext2fs_inode_string;
+extern const char *ext2fs_mark_string;
+extern const char *ext2fs_unmark_string;
+extern const char *ext2fs_test_string;
+extern void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg,
+ const char *description);
+extern void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap,
+ int code, unsigned long arg);
+
+extern int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block);
+extern int ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
+ blk_t block);
+extern int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block);
+
+extern int ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap, ext2_ino_t inode);
+extern int ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
+ ext2_ino_t inode);
+extern int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap, ext2_ino_t inode);
+
+extern void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap,
+ blk_t block);
+extern void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
+ blk_t block);
+extern int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap,
+ blk_t block);
+
+extern void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
+ ext2_ino_t inode);
+extern void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
+ ext2_ino_t inode);
+extern int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
+ ext2_ino_t inode);
+extern blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap);
+extern ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap);
+extern blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap);
+extern ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap);
+
+extern void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
+ blk_t block, int num);
+extern void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
+ blk_t block, int num);
+extern int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
+ blk_t block, int num);
+extern void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
+ blk_t block, int num);
+extern void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
+ blk_t block, int num);
+extern int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
+ blk_t block, int num);
+extern void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map);
+
+/* These two routines moved to gen_bitmap.c */
+extern int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
+ __u32 bitno);
+extern int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap,
+ blk_t bitno);
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/block.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/block.c
new file mode 100644
index 0000000000..4980969955
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/block.c
@@ -0,0 +1,438 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * block.c --- iterate over all blocks in an inode
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+struct block_context {
+ ext2_filsys fs;
+ int (*func)(ext2_filsys fs,
+ blk_t *blocknr,
+ e2_blkcnt_t bcount,
+ blk_t ref_blk,
+ int ref_offset,
+ void *priv_data);
+ e2_blkcnt_t bcount;
+ int bsize;
+ int flags;
+ errcode_t errcode;
+ char *ind_buf;
+ char *dind_buf;
+ char *tind_buf;
+ void *priv_data;
+};
+
+static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
+ int ref_offset, struct block_context *ctx)
+{
+ int ret = 0, changed = 0;
+ int i, flags, limit, offset;
+ blk_t *block_nr;
+
+ limit = ctx->fs->blocksize >> 2;
+ if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
+ !(ctx->flags & BLOCK_FLAG_DATA_ONLY))
+ ret = (*ctx->func)(ctx->fs, ind_block,
+ BLOCK_COUNT_IND, ref_block,
+ ref_offset, ctx->priv_data);
+ if (!*ind_block || (ret & BLOCK_ABORT)) {
+ ctx->bcount += limit;
+ return ret;
+ }
+ if (*ind_block >= ctx->fs->super->s_blocks_count ||
+ *ind_block < ctx->fs->super->s_first_data_block) {
+ ctx->errcode = EXT2_ET_BAD_IND_BLOCK;
+ ret |= BLOCK_ERROR;
+ return ret;
+ }
+ ctx->errcode = ext2fs_read_ind_block(ctx->fs, *ind_block,
+ ctx->ind_buf);
+ if (ctx->errcode) {
+ ret |= BLOCK_ERROR;
+ return ret;
+ }
+
+ block_nr = (blk_t *) ctx->ind_buf;
+ offset = 0;
+ if (ctx->flags & BLOCK_FLAG_APPEND) {
+ for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
+ flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
+ *ind_block, offset,
+ ctx->priv_data);
+ changed |= flags;
+ if (flags & BLOCK_ABORT) {
+ ret |= BLOCK_ABORT;
+ break;
+ }
+ offset += sizeof(blk_t);
+ }
+ } else {
+ for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
+ if (*block_nr == 0)
+ continue;
+ flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
+ *ind_block, offset,
+ ctx->priv_data);
+ changed |= flags;
+ if (flags & BLOCK_ABORT) {
+ ret |= BLOCK_ABORT;
+ break;
+ }
+ offset += sizeof(blk_t);
+ }
+ }
+ if (changed & BLOCK_CHANGED) {
+ ctx->errcode = ext2fs_write_ind_block(ctx->fs, *ind_block,
+ ctx->ind_buf);
+ if (ctx->errcode)
+ ret |= BLOCK_ERROR | BLOCK_ABORT;
+ }
+ if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
+ !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
+ !(ret & BLOCK_ABORT))
+ ret |= (*ctx->func)(ctx->fs, ind_block,
+ BLOCK_COUNT_IND, ref_block,
+ ref_offset, ctx->priv_data);
+ return ret;
+}
+
+static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
+ int ref_offset, struct block_context *ctx)
+{
+ int ret = 0, changed = 0;
+ int i, flags, limit, offset;
+ blk_t *block_nr;
+
+ limit = ctx->fs->blocksize >> 2;
+ if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
+ BLOCK_FLAG_DATA_ONLY)))
+ ret = (*ctx->func)(ctx->fs, dind_block,
+ BLOCK_COUNT_DIND, ref_block,
+ ref_offset, ctx->priv_data);
+ if (!*dind_block || (ret & BLOCK_ABORT)) {
+ ctx->bcount += limit*limit;
+ return ret;
+ }
+ if (*dind_block >= ctx->fs->super->s_blocks_count ||
+ *dind_block < ctx->fs->super->s_first_data_block) {
+ ctx->errcode = EXT2_ET_BAD_DIND_BLOCK;
+ ret |= BLOCK_ERROR;
+ return ret;
+ }
+ ctx->errcode = ext2fs_read_ind_block(ctx->fs, *dind_block,
+ ctx->dind_buf);
+ if (ctx->errcode) {
+ ret |= BLOCK_ERROR;
+ return ret;
+ }
+
+ block_nr = (blk_t *) ctx->dind_buf;
+ offset = 0;
+ if (ctx->flags & BLOCK_FLAG_APPEND) {
+ for (i = 0; i < limit; i++, block_nr++) {
+ flags = block_iterate_ind(block_nr,
+ *dind_block, offset,
+ ctx);
+ changed |= flags;
+ if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
+ ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
+ break;
+ }
+ offset += sizeof(blk_t);
+ }
+ } else {
+ for (i = 0; i < limit; i++, block_nr++) {
+ if (*block_nr == 0) {
+ ctx->bcount += limit;
+ continue;
+ }
+ flags = block_iterate_ind(block_nr,
+ *dind_block, offset,
+ ctx);
+ changed |= flags;
+ if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
+ ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
+ break;
+ }
+ offset += sizeof(blk_t);
+ }
+ }
+ if (changed & BLOCK_CHANGED) {
+ ctx->errcode = ext2fs_write_ind_block(ctx->fs, *dind_block,
+ ctx->dind_buf);
+ if (ctx->errcode)
+ ret |= BLOCK_ERROR | BLOCK_ABORT;
+ }
+ if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
+ !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
+ !(ret & BLOCK_ABORT))
+ ret |= (*ctx->func)(ctx->fs, dind_block,
+ BLOCK_COUNT_DIND, ref_block,
+ ref_offset, ctx->priv_data);
+ return ret;
+}
+
+static int block_iterate_tind(blk_t *tind_block, blk_t ref_block,
+ int ref_offset, struct block_context *ctx)
+{
+ int ret = 0, changed = 0;
+ int i, flags, limit, offset;
+ blk_t *block_nr;
+
+ limit = ctx->fs->blocksize >> 2;
+ if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
+ BLOCK_FLAG_DATA_ONLY)))
+ ret = (*ctx->func)(ctx->fs, tind_block,
+ BLOCK_COUNT_TIND, ref_block,
+ ref_offset, ctx->priv_data);
+ if (!*tind_block || (ret & BLOCK_ABORT)) {
+ ctx->bcount += limit*limit*limit;
+ return ret;
+ }
+ if (*tind_block >= ctx->fs->super->s_blocks_count ||
+ *tind_block < ctx->fs->super->s_first_data_block) {
+ ctx->errcode = EXT2_ET_BAD_TIND_BLOCK;
+ ret |= BLOCK_ERROR;
+ return ret;
+ }
+ ctx->errcode = ext2fs_read_ind_block(ctx->fs, *tind_block,
+ ctx->tind_buf);
+ if (ctx->errcode) {
+ ret |= BLOCK_ERROR;
+ return ret;
+ }
+
+ block_nr = (blk_t *) ctx->tind_buf;
+ offset = 0;
+ if (ctx->flags & BLOCK_FLAG_APPEND) {
+ for (i = 0; i < limit; i++, block_nr++) {
+ flags = block_iterate_dind(block_nr,
+ *tind_block,
+ offset, ctx);
+ changed |= flags;
+ if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
+ ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
+ break;
+ }
+ offset += sizeof(blk_t);
+ }
+ } else {
+ for (i = 0; i < limit; i++, block_nr++) {
+ if (*block_nr == 0) {
+ ctx->bcount += limit*limit;
+ continue;
+ }
+ flags = block_iterate_dind(block_nr,
+ *tind_block,
+ offset, ctx);
+ changed |= flags;
+ if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
+ ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
+ break;
+ }
+ offset += sizeof(blk_t);
+ }
+ }
+ if (changed & BLOCK_CHANGED) {
+ ctx->errcode = ext2fs_write_ind_block(ctx->fs, *tind_block,
+ ctx->tind_buf);
+ if (ctx->errcode)
+ ret |= BLOCK_ERROR | BLOCK_ABORT;
+ }
+ if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
+ !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
+ !(ret & BLOCK_ABORT))
+ ret |= (*ctx->func)(ctx->fs, tind_block,
+ BLOCK_COUNT_TIND, ref_block,
+ ref_offset, ctx->priv_data);
+
+ return ret;
+}
+
+errcode_t ext2fs_block_iterate2(ext2_filsys fs,
+ ext2_ino_t ino,
+ int flags,
+ char *block_buf,
+ int (*func)(ext2_filsys fs,
+ blk_t *blocknr,
+ e2_blkcnt_t blockcnt,
+ blk_t ref_blk,
+ int ref_offset,
+ void *priv_data),
+ void *priv_data)
+{
+ int i;
+ int got_inode = 0;
+ int ret = 0;
+ blk_t blocks[EXT2_N_BLOCKS]; /* directory data blocks */
+ struct ext2_inode inode;
+ errcode_t retval;
+ struct block_context ctx;
+ int limit;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ /*
+ * Check to see if we need to limit large files
+ */
+ if (flags & BLOCK_FLAG_NO_LARGE) {
+ ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
+ if (ctx.errcode)
+ return ctx.errcode;
+ got_inode = 1;
+ if (!LINUX_S_ISDIR(inode.i_mode) &&
+ (inode.i_size_high != 0))
+ return EXT2_ET_FILE_TOO_BIG;
+ }
+
+ retval = ext2fs_get_blocks(fs, ino, blocks);
+ if (retval)
+ return retval;
+
+ limit = fs->blocksize >> 2;
+
+ ctx.fs = fs;
+ ctx.func = func;
+ ctx.priv_data = priv_data;
+ ctx.flags = flags;
+ ctx.bcount = 0;
+ if (block_buf) {
+ ctx.ind_buf = block_buf;
+ } else {
+ retval = ext2fs_get_mem(fs->blocksize * 3, &ctx.ind_buf);
+ if (retval)
+ return retval;
+ }
+ ctx.dind_buf = ctx.ind_buf + fs->blocksize;
+ ctx.tind_buf = ctx.dind_buf + fs->blocksize;
+
+ /*
+ * Iterate over the HURD translator block (if present)
+ */
+ if ((fs->super->s_creator_os == EXT2_OS_HURD) &&
+ !(flags & BLOCK_FLAG_DATA_ONLY)) {
+ ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
+ if (ctx.errcode)
+ goto abort_exit;
+ got_inode = 1;
+ if (inode.osd1.hurd1.h_i_translator) {
+ ret |= (*ctx.func)(fs,
+ &inode.osd1.hurd1.h_i_translator,
+ BLOCK_COUNT_TRANSLATOR,
+ 0, 0, priv_data);
+ if (ret & BLOCK_ABORT)
+ goto abort_exit;
+ }
+ }
+
+ /*
+ * Iterate over normal data blocks
+ */
+ for (i = 0; i < EXT2_NDIR_BLOCKS; i++, ctx.bcount++) {
+ if (blocks[i] || (flags & BLOCK_FLAG_APPEND)) {
+ ret |= (*ctx.func)(fs, &blocks[i],
+ ctx.bcount, 0, i, priv_data);
+ if (ret & BLOCK_ABORT)
+ goto abort_exit;
+ }
+ }
+ if (*(blocks + EXT2_IND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
+ ret |= block_iterate_ind(blocks + EXT2_IND_BLOCK,
+ 0, EXT2_IND_BLOCK, &ctx);
+ if (ret & BLOCK_ABORT)
+ goto abort_exit;
+ } else
+ ctx.bcount += limit;
+ if (*(blocks + EXT2_DIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
+ ret |= block_iterate_dind(blocks + EXT2_DIND_BLOCK,
+ 0, EXT2_DIND_BLOCK, &ctx);
+ if (ret & BLOCK_ABORT)
+ goto abort_exit;
+ } else
+ ctx.bcount += limit * limit;
+ if (*(blocks + EXT2_TIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
+ ret |= block_iterate_tind(blocks + EXT2_TIND_BLOCK,
+ 0, EXT2_TIND_BLOCK, &ctx);
+ if (ret & BLOCK_ABORT)
+ goto abort_exit;
+ }
+
+abort_exit:
+ if (ret & BLOCK_CHANGED) {
+ if (!got_inode) {
+ retval = ext2fs_read_inode(fs, ino, &inode);
+ if (retval)
+ return retval;
+ }
+ for (i=0; i < EXT2_N_BLOCKS; i++)
+ inode.i_block[i] = blocks[i];
+ retval = ext2fs_write_inode(fs, ino, &inode);
+ if (retval)
+ return retval;
+ }
+
+ if (!block_buf)
+ ext2fs_free_mem(&ctx.ind_buf);
+
+ return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
+}
+
+/*
+ * Emulate the old ext2fs_block_iterate function!
+ */
+
+struct xlate {
+ int (*func)(ext2_filsys fs,
+ blk_t *blocknr,
+ int bcount,
+ void *priv_data);
+ void *real_private;
+};
+
+#ifdef __TURBOC__
+# pragma argsused
+#endif
+static int xlate_func(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt,
+ blk_t ref_block EXT2FS_ATTR((unused)),
+ int ref_offset EXT2FS_ATTR((unused)),
+ void *priv_data)
+{
+ struct xlate *xl = (struct xlate *) priv_data;
+
+ return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private);
+}
+
+errcode_t ext2fs_block_iterate(ext2_filsys fs,
+ ext2_ino_t ino,
+ int flags,
+ char *block_buf,
+ int (*func)(ext2_filsys fs,
+ blk_t *blocknr,
+ int blockcnt,
+ void *priv_data),
+ void *priv_data)
+{
+ struct xlate xl;
+
+ xl.real_private = priv_data;
+ xl.func = func;
+
+ return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags,
+ block_buf, xlate_func, &xl);
+}
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bmap.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bmap.c
new file mode 100644
index 0000000000..b22fe3dbf6
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bmap.c
@@ -0,0 +1,264 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bmap.c --- logical to physical block mapping
+ *
+ * Copyright (C) 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode *inode,
+ char *block_buf, int bmap_flags,
+ blk_t block, blk_t *phys_blk);
+
+#define inode_bmap(inode, nr) ((inode)->i_block[(nr)])
+
+static errcode_t block_ind_bmap(ext2_filsys fs, int flags,
+ blk_t ind, char *block_buf,
+ int *blocks_alloc,
+ blk_t nr, blk_t *ret_blk)
+{
+ errcode_t retval;
+ blk_t b;
+
+ if (!ind) {
+ if (flags & BMAP_SET)
+ return EXT2_ET_SET_BMAP_NO_IND;
+ *ret_blk = 0;
+ return 0;
+ }
+ retval = io_channel_read_blk(fs->io, ind, 1, block_buf);
+ if (retval)
+ return retval;
+
+ if (flags & BMAP_SET) {
+ b = *ret_blk;
+#if BB_BIG_ENDIAN
+ if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+ (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
+ b = ext2fs_swab32(b);
+#endif
+ ((blk_t *) block_buf)[nr] = b;
+ return io_channel_write_blk(fs->io, ind, 1, block_buf);
+ }
+
+ b = ((blk_t *) block_buf)[nr];
+
+#if BB_BIG_ENDIAN
+ if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+ (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
+ b = ext2fs_swab32(b);
+#endif
+
+ if (!b && (flags & BMAP_ALLOC)) {
+ b = nr ? ((blk_t *) block_buf)[nr-1] : 0;
+ retval = ext2fs_alloc_block(fs, b,
+ block_buf + fs->blocksize, &b);
+ if (retval)
+ return retval;
+
+#if BB_BIG_ENDIAN
+ if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+ (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
+ ((blk_t *) block_buf)[nr] = ext2fs_swab32(b);
+ else
+#endif
+ ((blk_t *) block_buf)[nr] = b;
+
+ retval = io_channel_write_blk(fs->io, ind, 1, block_buf);
+ if (retval)
+ return retval;
+
+ (*blocks_alloc)++;
+ }
+
+ *ret_blk = b;
+ return 0;
+}
+
+static errcode_t block_dind_bmap(ext2_filsys fs, int flags,
+ blk_t dind, char *block_buf,
+ int *blocks_alloc,
+ blk_t nr, blk_t *ret_blk)
+{
+ blk_t b;
+ errcode_t retval;
+ blk_t addr_per_block;
+
+ addr_per_block = (blk_t) fs->blocksize >> 2;
+
+ retval = block_ind_bmap(fs, flags & ~BMAP_SET, dind, block_buf,
+ blocks_alloc, nr / addr_per_block, &b);
+ if (retval)
+ return retval;
+ retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
+ nr % addr_per_block, ret_blk);
+ return retval;
+}
+
+static errcode_t block_tind_bmap(ext2_filsys fs, int flags,
+ blk_t tind, char *block_buf,
+ int *blocks_alloc,
+ blk_t nr, blk_t *ret_blk)
+{
+ blk_t b;
+ errcode_t retval;
+ blk_t addr_per_block;
+
+ addr_per_block = (blk_t) fs->blocksize >> 2;
+
+ retval = block_dind_bmap(fs, flags & ~BMAP_SET, tind, block_buf,
+ blocks_alloc, nr / addr_per_block, &b);
+ if (retval)
+ return retval;
+ retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
+ nr % addr_per_block, ret_blk);
+ return retval;
+}
+
+errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
+ char *block_buf, int bmap_flags, blk_t block,
+ blk_t *phys_blk)
+{
+ struct ext2_inode inode_buf;
+ blk_t addr_per_block;
+ blk_t b;
+ char *buf = 0;
+ errcode_t retval = 0;
+ int blocks_alloc = 0, inode_dirty = 0;
+
+ if (!(bmap_flags & BMAP_SET))
+ *phys_blk = 0;
+
+ /* Read inode structure if necessary */
+ if (!inode) {
+ retval = ext2fs_read_inode(fs, ino, &inode_buf);
+ if (retval)
+ return retval;
+ inode = &inode_buf;
+ }
+ addr_per_block = (blk_t) fs->blocksize >> 2;
+
+ if (!block_buf) {
+ retval = ext2fs_get_mem(fs->blocksize * 2, &buf);
+ if (retval)
+ return retval;
+ block_buf = buf;
+ }
+
+ if (block < EXT2_NDIR_BLOCKS) {
+ if (bmap_flags & BMAP_SET) {
+ b = *phys_blk;
+#if BB_BIG_ENDIAN
+ if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+ (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
+ b = ext2fs_swab32(b);
+#endif
+ inode_bmap(inode, block) = b;
+ inode_dirty++;
+ goto done;
+ }
+
+ *phys_blk = inode_bmap(inode, block);
+ b = block ? inode_bmap(inode, block-1) : 0;
+
+ if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) {
+ retval = ext2fs_alloc_block(fs, b, block_buf, &b);
+ if (retval)
+ goto done;
+ inode_bmap(inode, block) = b;
+ blocks_alloc++;
+ *phys_blk = b;
+ }
+ goto done;
+ }
+
+ /* Indirect block */
+ block -= EXT2_NDIR_BLOCKS;
+ if (block < addr_per_block) {
+ b = inode_bmap(inode, EXT2_IND_BLOCK);
+ if (!b) {
+ if (!(bmap_flags & BMAP_ALLOC)) {
+ if (bmap_flags & BMAP_SET)
+ retval = EXT2_ET_SET_BMAP_NO_IND;
+ goto done;
+ }
+
+ b = inode_bmap(inode, EXT2_IND_BLOCK-1);
+ retval = ext2fs_alloc_block(fs, b, block_buf, &b);
+ if (retval)
+ goto done;
+ inode_bmap(inode, EXT2_IND_BLOCK) = b;
+ blocks_alloc++;
+ }
+ retval = block_ind_bmap(fs, bmap_flags, b, block_buf,
+ &blocks_alloc, block, phys_blk);
+ goto done;
+ }
+
+ /* Doubly indirect block */
+ block -= addr_per_block;
+ if (block < addr_per_block * addr_per_block) {
+ b = inode_bmap(inode, EXT2_DIND_BLOCK);
+ if (!b) {
+ if (!(bmap_flags & BMAP_ALLOC)) {
+ if (bmap_flags & BMAP_SET)
+ retval = EXT2_ET_SET_BMAP_NO_IND;
+ goto done;
+ }
+
+ b = inode_bmap(inode, EXT2_IND_BLOCK);
+ retval = ext2fs_alloc_block(fs, b, block_buf, &b);
+ if (retval)
+ goto done;
+ inode_bmap(inode, EXT2_DIND_BLOCK) = b;
+ blocks_alloc++;
+ }
+ retval = block_dind_bmap(fs, bmap_flags, b, block_buf,
+ &blocks_alloc, block, phys_blk);
+ goto done;
+ }
+
+ /* Triply indirect block */
+ block -= addr_per_block * addr_per_block;
+ b = inode_bmap(inode, EXT2_TIND_BLOCK);
+ if (!b) {
+ if (!(bmap_flags & BMAP_ALLOC)) {
+ if (bmap_flags & BMAP_SET)
+ retval = EXT2_ET_SET_BMAP_NO_IND;
+ goto done;
+ }
+
+ b = inode_bmap(inode, EXT2_DIND_BLOCK);
+ retval = ext2fs_alloc_block(fs, b, block_buf, &b);
+ if (retval)
+ goto done;
+ inode_bmap(inode, EXT2_TIND_BLOCK) = b;
+ blocks_alloc++;
+ }
+ retval = block_tind_bmap(fs, bmap_flags, b, block_buf,
+ &blocks_alloc, block, phys_blk);
+done:
+ ext2fs_free_mem(&buf);
+ if ((retval == 0) && (blocks_alloc || inode_dirty)) {
+ inode->i_blocks += (blocks_alloc * fs->blocksize) / 512;
+ retval = ext2fs_write_inode(fs, ino, inode);
+ }
+ return retval;
+}
+
+
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bmove.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bmove.c
new file mode 100644
index 0000000000..635410da53
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/bmove.c
@@ -0,0 +1,156 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bmove.c --- Move blocks around to make way for a particular
+ * filesystem structure.
+ *
+ * Copyright (C) 1997 Theodore Ts'o. This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+
+struct process_block_struct {
+ ext2_ino_t ino;
+ struct ext2_inode * inode;
+ ext2fs_block_bitmap reserve;
+ ext2fs_block_bitmap alloc_map;
+ errcode_t error;
+ char *buf;
+ int add_dir;
+ int flags;
+};
+
+static int process_block(ext2_filsys fs, blk_t *block_nr,
+ e2_blkcnt_t blockcnt, blk_t ref_block,
+ int ref_offset, void *priv_data)
+{
+ struct process_block_struct *pb;
+ errcode_t retval;
+ int ret;
+ blk_t block, orig;
+
+ pb = (struct process_block_struct *) priv_data;
+ block = orig = *block_nr;
+ ret = 0;
+
+ /*
+ * Let's see if this is one which we need to relocate
+ */
+ if (ext2fs_test_block_bitmap(pb->reserve, block)) {
+ do {
+ if (++block >= fs->super->s_blocks_count)
+ block = fs->super->s_first_data_block;
+ if (block == orig) {
+ pb->error = EXT2_ET_BLOCK_ALLOC_FAIL;
+ return BLOCK_ABORT;
+ }
+ } while (ext2fs_test_block_bitmap(pb->reserve, block) ||
+ ext2fs_test_block_bitmap(pb->alloc_map, block));
+
+ retval = io_channel_read_blk(fs->io, orig, 1, pb->buf);
+ if (retval) {
+ pb->error = retval;
+ return BLOCK_ABORT;
+ }
+ retval = io_channel_write_blk(fs->io, block, 1, pb->buf);
+ if (retval) {
+ pb->error = retval;
+ return BLOCK_ABORT;
+ }
+ *block_nr = block;
+ ext2fs_mark_block_bitmap(pb->alloc_map, block);
+ ret = BLOCK_CHANGED;
+ if (pb->flags & EXT2_BMOVE_DEBUG)
+ printf("ino=%ld, blockcnt=%lld, %d->%d\n", pb->ino,
+ blockcnt, orig, block);
+ }
+ if (pb->add_dir) {
+ retval = ext2fs_add_dir_block(fs->dblist, pb->ino,
+ block, (int) blockcnt);
+ if (retval) {
+ pb->error = retval;
+ ret |= BLOCK_ABORT;
+ }
+ }
+ return ret;
+}
+
+errcode_t ext2fs_move_blocks(ext2_filsys fs,
+ ext2fs_block_bitmap reserve,
+ ext2fs_block_bitmap alloc_map,
+ int flags)
+{
+ ext2_ino_t ino;
+ struct ext2_inode inode;
+ errcode_t retval;
+ struct process_block_struct pb;
+ ext2_inode_scan scan;
+ char *block_buf;
+
+ retval = ext2fs_open_inode_scan(fs, 0, &scan);
+ if (retval)
+ return retval;
+
+ pb.reserve = reserve;
+ pb.error = 0;
+ pb.alloc_map = alloc_map ? alloc_map : fs->block_map;
+ pb.flags = flags;
+
+ retval = ext2fs_get_mem(fs->blocksize * 4, &block_buf);
+ if (retval)
+ return retval;
+ pb.buf = block_buf + fs->blocksize * 3;
+
+ /*
+ * If GET_DBLIST is set in the flags field, then we should
+ * gather directory block information while we're doing the
+ * block move.
+ */
+ if (flags & EXT2_BMOVE_GET_DBLIST) {
+ ext2fs_free_dblist(fs->dblist);
+ fs->dblist = NULL;
+ retval = ext2fs_init_dblist(fs, 0);
+ if (retval)
+ return retval;
+ }
+
+ retval = ext2fs_get_next_inode(scan, &ino, &inode);
+ if (retval)
+ return retval;
+
+ while (ino) {
+ if ((inode.i_links_count == 0) ||
+ !ext2fs_inode_has_valid_blocks(&inode))
+ goto next;
+
+ pb.ino = ino;
+ pb.inode = &inode;
+
+ pb.add_dir = (LINUX_S_ISDIR(inode.i_mode) &&
+ flags & EXT2_BMOVE_GET_DBLIST);
+
+ retval = ext2fs_block_iterate2(fs, ino, 0, block_buf,
+ process_block, &pb);
+ if (retval)
+ return retval;
+ if (pb.error)
+ return pb.error;
+
+ next:
+ retval = ext2fs_get_next_inode(scan, &ino, &inode);
+ if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
+ goto next;
+ }
+ return 0;
+}
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/brel.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/brel.h
new file mode 100644
index 0000000000..216fd132cd
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/brel.h
@@ -0,0 +1,87 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * brel.h
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+struct ext2_block_relocate_entry {
+ blk_t new;
+ __s16 offset;
+ __u16 flags;
+ union {
+ blk_t block_ref;
+ ext2_ino_t inode_ref;
+ } owner;
+};
+
+#define RELOCATE_TYPE_REF 0x0007
+#define RELOCATE_BLOCK_REF 0x0001
+#define RELOCATE_INODE_REF 0x0002
+
+typedef struct ext2_block_relocation_table *ext2_brel;
+
+struct ext2_block_relocation_table {
+ __u32 magic;
+ char *name;
+ blk_t current;
+ void *priv_data;
+
+ /*
+ * Add a block relocation entry.
+ */
+ errcode_t (*put)(ext2_brel brel, blk_t old,
+ struct ext2_block_relocate_entry *ent);
+
+ /*
+ * Get a block relocation entry.
+ */
+ errcode_t (*get)(ext2_brel brel, blk_t old,
+ struct ext2_block_relocate_entry *ent);
+
+ /*
+ * Initialize for iterating over the block relocation entries.
+ */
+ errcode_t (*start_iter)(ext2_brel brel);
+
+ /*
+ * The iterator function for the inode relocation entries.
+ * Returns an inode number of 0 when out of entries.
+ */
+ errcode_t (*next)(ext2_brel brel, blk_t *old,
+ struct ext2_block_relocate_entry *ent);
+
+ /*
+ * Move the inode relocation table from one block number to
+ * another.
+ */
+ errcode_t (*move)(ext2_brel brel, blk_t old, blk_t new);
+
+ /*
+ * Remove a block relocation entry.
+ */
+ errcode_t (*delete)(ext2_brel brel, blk_t old);
+
+
+ /*
+ * Free the block relocation table.
+ */
+ errcode_t (*free)(ext2_brel brel);
+};
+
+errcode_t ext2fs_brel_memarray_create(char *name, blk_t max_block,
+ ext2_brel *brel);
+
+#define ext2fs_brel_put(brel, old, ent) ((brel)->put((brel), old, ent))
+#define ext2fs_brel_get(brel, old, ent) ((brel)->get((brel), old, ent))
+#define ext2fs_brel_start_iter(brel) ((brel)->start_iter((brel)))
+#define ext2fs_brel_next(brel, old, ent) ((brel)->next((brel), old, ent))
+#define ext2fs_brel_move(brel, old, new) ((brel)->move((brel), old, new))
+#define ext2fs_brel_delete(brel, old) ((brel)->delete((brel), old))
+#define ext2fs_brel_free(brel) ((brel)->free((brel)))
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/brel_ma.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/brel_ma.c
new file mode 100644
index 0000000000..652a3509cb
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/brel_ma.c
@@ -0,0 +1,196 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * brel_ma.c
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * TODO: rewrite to not use a direct array!!! (Fortunately this
+ * module isn't really used yet.)
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+#include "brel.h"
+
+static errcode_t bma_put(ext2_brel brel, blk_t old,
+ struct ext2_block_relocate_entry *ent);
+static errcode_t bma_get(ext2_brel brel, blk_t old,
+ struct ext2_block_relocate_entry *ent);
+static errcode_t bma_start_iter(ext2_brel brel);
+static errcode_t bma_next(ext2_brel brel, blk_t *old,
+ struct ext2_block_relocate_entry *ent);
+static errcode_t bma_move(ext2_brel brel, blk_t old, blk_t new);
+static errcode_t bma_delete(ext2_brel brel, blk_t old);
+static errcode_t bma_free(ext2_brel brel);
+
+struct brel_ma {
+ __u32 magic;
+ blk_t max_block;
+ struct ext2_block_relocate_entry *entries;
+};
+
+errcode_t ext2fs_brel_memarray_create(char *name, blk_t max_block,
+ ext2_brel *new_brel)
+{
+ ext2_brel brel = 0;
+ errcode_t retval;
+ struct brel_ma *ma = 0;
+ size_t size;
+
+ *new_brel = 0;
+
+ /*
+ * Allocate memory structures
+ */
+ retval = ext2fs_get_mem(sizeof(struct ext2_block_relocation_table),
+ &brel);
+ if (retval)
+ goto errout;
+ memset(brel, 0, sizeof(struct ext2_block_relocation_table));
+
+ retval = ext2fs_get_mem(strlen(name)+1, &brel->name);
+ if (retval)
+ goto errout;
+ strcpy(brel->name, name);
+
+ retval = ext2fs_get_mem(sizeof(struct brel_ma), &ma);
+ if (retval)
+ goto errout;
+ memset(ma, 0, sizeof(struct brel_ma));
+ brel->priv_data = ma;
+
+ size = (size_t) (sizeof(struct ext2_block_relocate_entry) *
+ (max_block+1));
+ retval = ext2fs_get_mem(size, &ma->entries);
+ if (retval)
+ goto errout;
+ memset(ma->entries, 0, size);
+ ma->max_block = max_block;
+
+ /*
+ * Fill in the brel data structure
+ */
+ brel->put = bma_put;
+ brel->get = bma_get;
+ brel->start_iter = bma_start_iter;
+ brel->next = bma_next;
+ brel->move = bma_move;
+ brel->delete = bma_delete;
+ brel->free = bma_free;
+
+ *new_brel = brel;
+ return 0;
+
+errout:
+ bma_free(brel);
+ return retval;
+}
+
+static errcode_t bma_put(ext2_brel brel, blk_t old,
+ struct ext2_block_relocate_entry *ent)
+{
+ struct brel_ma *ma;
+
+ ma = brel->priv_data;
+ if (old > ma->max_block)
+ return EXT2_ET_INVALID_ARGUMENT;
+ ma->entries[(unsigned)old] = *ent;
+ return 0;
+}
+
+static errcode_t bma_get(ext2_brel brel, blk_t old,
+ struct ext2_block_relocate_entry *ent)
+{
+ struct brel_ma *ma;
+
+ ma = brel->priv_data;
+ if (old > ma->max_block)
+ return EXT2_ET_INVALID_ARGUMENT;
+ if (ma->entries[(unsigned)old].new == 0)
+ return ENOENT;
+ *ent = ma->entries[old];
+ return 0;
+}
+
+static errcode_t bma_start_iter(ext2_brel brel)
+{
+ brel->current = 0;
+ return 0;
+}
+
+static errcode_t bma_next(ext2_brel brel, blk_t *old,
+ struct ext2_block_relocate_entry *ent)
+{
+ struct brel_ma *ma;
+
+ ma = brel->priv_data;
+ while (++brel->current < ma->max_block) {
+ if (ma->entries[(unsigned)brel->current].new == 0)
+ continue;
+ *old = brel->current;
+ *ent = ma->entries[(unsigned)brel->current];
+ return 0;
+ }
+ *old = 0;
+ return 0;
+}
+
+static errcode_t bma_move(ext2_brel brel, blk_t old, blk_t new)
+{
+ struct brel_ma *ma;
+
+ ma = brel->priv_data;
+ if ((old > ma->max_block) || (new > ma->max_block))
+ return EXT2_ET_INVALID_ARGUMENT;
+ if (ma->entries[(unsigned)old].new == 0)
+ return ENOENT;
+ ma->entries[(unsigned)new] = ma->entries[old];
+ ma->entries[(unsigned)old].new = 0;
+ return 0;
+}
+
+static errcode_t bma_delete(ext2_brel brel, blk_t old)
+{
+ struct brel_ma *ma;
+
+ ma = brel->priv_data;
+ if (old > ma->max_block)
+ return EXT2_ET_INVALID_ARGUMENT;
+ if (ma->entries[(unsigned)old].new == 0)
+ return ENOENT;
+ ma->entries[(unsigned)old].new = 0;
+ return 0;
+}
+
+static errcode_t bma_free(ext2_brel brel)
+{
+ struct brel_ma *ma;
+
+ if (!brel)
+ return 0;
+
+ ma = brel->priv_data;
+
+ if (ma) {
+ ext2fs_free_mem(&ma->entries);
+ ext2fs_free_mem(&ma);
+ }
+ ext2fs_free_mem(&brel->name);
+ ext2fs_free_mem(&brel);
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/check_desc.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/check_desc.c
new file mode 100644
index 0000000000..dd4b0e9cf5
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/check_desc.c
@@ -0,0 +1,69 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * check_desc.c --- Check the group descriptors of an ext2 filesystem
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * This routine sanity checks the group descriptors
+ */
+errcode_t ext2fs_check_desc(ext2_filsys fs)
+{
+ dgrp_t i;
+ blk_t block = fs->super->s_first_data_block;
+ blk_t next;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ for (i = 0; i < fs->group_desc_count; i++) {
+ next = block + fs->super->s_blocks_per_group;
+ /*
+ * Check to make sure block bitmap for group is
+ * located within the group.
+ */
+ if (fs->group_desc[i].bg_block_bitmap < block ||
+ fs->group_desc[i].bg_block_bitmap >= next)
+ return EXT2_ET_GDESC_BAD_BLOCK_MAP;
+ /*
+ * Check to make sure inode bitmap for group is
+ * located within the group
+ */
+ if (fs->group_desc[i].bg_inode_bitmap < block ||
+ fs->group_desc[i].bg_inode_bitmap >= next)
+ return EXT2_ET_GDESC_BAD_INODE_MAP;
+ /*
+ * Check to make sure inode table for group is located
+ * within the group
+ */
+ if (fs->group_desc[i].bg_inode_table < block ||
+ ((fs->group_desc[i].bg_inode_table +
+ fs->inode_blocks_per_group) >= next))
+ return EXT2_ET_GDESC_BAD_INODE_TABLE;
+
+ block = next;
+ }
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/closefs.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/closefs.c
new file mode 100644
index 0000000000..008d5f36eb
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/closefs.c
@@ -0,0 +1,381 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * closefs.c --- close an ext2 filesystem
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <time.h>
+#include <string.h>
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+
+static int test_root(int a, int b)
+{
+ if (a == 0)
+ return 1;
+ while (1) {
+ if (a == 1)
+ return 1;
+ if (a % b)
+ return 0;
+ a = a / b;
+ }
+}
+
+int ext2fs_bg_has_super(ext2_filsys fs, int group_block)
+{
+ if (!(fs->super->s_feature_ro_compat &
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
+ return 1;
+
+ if (test_root(group_block, 3) || (test_root(group_block, 5)) ||
+ test_root(group_block, 7))
+ return 1;
+
+ return 0;
+}
+
+int ext2fs_super_and_bgd_loc(ext2_filsys fs,
+ dgrp_t group,
+ blk_t *ret_super_blk,
+ blk_t *ret_old_desc_blk,
+ blk_t *ret_new_desc_blk,
+ int *ret_meta_bg)
+{
+ blk_t group_block, super_blk = 0, old_desc_blk = 0, new_desc_blk = 0;
+ unsigned int meta_bg, meta_bg_size;
+ int numblocks, has_super;
+ int old_desc_blocks;
+
+ group_block = fs->super->s_first_data_block +
+ (group * fs->super->s_blocks_per_group);
+
+ if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
+ old_desc_blocks = fs->super->s_first_meta_bg;
+ else
+ old_desc_blocks =
+ fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
+
+ if (group == fs->group_desc_count-1) {
+ numblocks = (fs->super->s_blocks_count -
+ fs->super->s_first_data_block) %
+ fs->super->s_blocks_per_group;
+ if (!numblocks)
+ numblocks = fs->super->s_blocks_per_group;
+ } else
+ numblocks = fs->super->s_blocks_per_group;
+
+ has_super = ext2fs_bg_has_super(fs, group);
+
+ if (has_super) {
+ super_blk = group_block;
+ numblocks--;
+ }
+ meta_bg_size = (fs->blocksize / sizeof (struct ext2_group_desc));
+ meta_bg = group / meta_bg_size;
+
+ if (!(fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) ||
+ (meta_bg < fs->super->s_first_meta_bg)) {
+ if (has_super) {
+ old_desc_blk = group_block + 1;
+ numblocks -= old_desc_blocks;
+ }
+ } else {
+ if (((group % meta_bg_size) == 0) ||
+ ((group % meta_bg_size) == 1) ||
+ ((group % meta_bg_size) == (meta_bg_size-1))) {
+ if (has_super)
+ has_super = 1;
+ new_desc_blk = group_block + has_super;
+ numblocks--;
+ }
+ }
+
+ numblocks -= 2 + fs->inode_blocks_per_group;
+
+ if (ret_super_blk)
+ *ret_super_blk = super_blk;
+ if (ret_old_desc_blk)
+ *ret_old_desc_blk = old_desc_blk;
+ if (ret_new_desc_blk)
+ *ret_new_desc_blk = new_desc_blk;
+ if (ret_meta_bg)
+ *ret_meta_bg = meta_bg;
+ return numblocks;
+}
+
+
+/*
+ * This function forces out the primary superblock. We need to only
+ * write out those fields which we have changed, since if the
+ * filesystem is mounted, it may have changed some of the other
+ * fields.
+ *
+ * It takes as input a superblock which has already been byte swapped
+ * (if necessary).
+ *
+ */
+static errcode_t write_primary_superblock(ext2_filsys fs,
+ struct ext2_super_block *super)
+{
+ __u16 *old_super, *new_super;
+ int check_idx, write_idx, size;
+ errcode_t retval;
+
+ if (!fs->io->manager->write_byte || !fs->orig_super) {
+ io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
+ retval = io_channel_write_blk(fs->io, 1, -SUPERBLOCK_SIZE,
+ super);
+ io_channel_set_blksize(fs->io, fs->blocksize);
+ return retval;
+ }
+
+ old_super = (__u16 *) fs->orig_super;
+ new_super = (__u16 *) super;
+
+ for (check_idx = 0; check_idx < SUPERBLOCK_SIZE/2; check_idx++) {
+ if (old_super[check_idx] == new_super[check_idx])
+ continue;
+ write_idx = check_idx;
+ for (check_idx++; check_idx < SUPERBLOCK_SIZE/2; check_idx++)
+ if (old_super[check_idx] == new_super[check_idx])
+ break;
+ size = 2 * (check_idx - write_idx);
+ retval = io_channel_write_byte(fs->io,
+ SUPERBLOCK_OFFSET + (2 * write_idx), size,
+ new_super + write_idx);
+ if (retval)
+ return retval;
+ }
+ memcpy(fs->orig_super, super, SUPERBLOCK_SIZE);
+ return 0;
+}
+
+
+/*
+ * Updates the revision to EXT2_DYNAMIC_REV
+ */
+void ext2fs_update_dynamic_rev(ext2_filsys fs)
+{
+ struct ext2_super_block *sb = fs->super;
+
+ if (sb->s_rev_level > EXT2_GOOD_OLD_REV)
+ return;
+
+ sb->s_rev_level = EXT2_DYNAMIC_REV;
+ sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
+ sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
+ /* s_uuid is handled by e2fsck already */
+ /* other fields should be left alone */
+}
+
+static errcode_t write_backup_super(ext2_filsys fs, dgrp_t group,
+ blk_t group_block,
+ struct ext2_super_block *super_shadow)
+{
+ dgrp_t sgrp = group;
+
+ if (sgrp > ((1 << 16) - 1))
+ sgrp = (1 << 16) - 1;
+#if BB_BIG_ENDIAN
+ if (fs->flags & EXT2_FLAG_SWAP_BYTES)
+ super_shadow->s_block_group_nr = ext2fs_swab16(sgrp);
+ else
+#endif
+ fs->super->s_block_group_nr = sgrp;
+
+ return io_channel_write_blk(fs->io, group_block, -SUPERBLOCK_SIZE,
+ super_shadow);
+}
+
+
+errcode_t ext2fs_flush(ext2_filsys fs)
+{
+ dgrp_t i;
+ blk_t group_block;
+ errcode_t retval;
+ unsigned long fs_state;
+ struct ext2_super_block *super_shadow = 0;
+ struct ext2_group_desc *group_shadow = 0;
+ char *group_ptr;
+ int old_desc_blocks;
+#if BB_BIG_ENDIAN
+ dgrp_t j;
+ struct ext2_group_desc *s, *t;
+#endif
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ fs_state = fs->super->s_state;
+
+ fs->super->s_wtime = time(NULL);
+ fs->super->s_block_group_nr = 0;
+#if BB_BIG_ENDIAN
+ if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
+ retval = EXT2_ET_NO_MEMORY;
+ retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super_shadow);
+ if (retval)
+ goto errout;
+ retval = ext2fs_get_mem((size_t)(fs->blocksize *
+ fs->desc_blocks),
+ &group_shadow);
+ if (retval)
+ goto errout;
+ memset(group_shadow, 0, (size_t) fs->blocksize *
+ fs->desc_blocks);
+
+ /* swap the group descriptors */
+ for (j=0, s=fs->group_desc, t=group_shadow;
+ j < fs->group_desc_count; j++, t++, s++) {
+ *t = *s;
+ ext2fs_swap_group_desc(t);
+ }
+ } else {
+ super_shadow = fs->super;
+ group_shadow = fs->group_desc;
+ }
+#else
+ super_shadow = fs->super;
+ group_shadow = fs->group_desc;
+#endif
+
+ /*
+ * If this is an external journal device, don't write out the
+ * block group descriptors or any of the backup superblocks
+ */
+ if (fs->super->s_feature_incompat &
+ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
+ goto write_primary_superblock_only;
+
+ /*
+ * Set the state of the FS to be non-valid. (The state has
+ * already been backed up earlier, and will be restored after
+ * we write out the backup superblocks.)
+ */
+ fs->super->s_state &= ~EXT2_VALID_FS;
+#if BB_BIG_ENDIAN
+ if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
+ *super_shadow = *fs->super;
+ ext2fs_swap_super(super_shadow);
+ }
+#endif
+
+ /*
+ * Write out the master group descriptors, and the backup
+ * superblocks and group descriptors.
+ */
+ group_block = fs->super->s_first_data_block;
+ group_ptr = (char *) group_shadow;
+ if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
+ old_desc_blocks = fs->super->s_first_meta_bg;
+ else
+ old_desc_blocks = fs->desc_blocks;
+
+ for (i = 0; i < fs->group_desc_count; i++) {
+ blk_t super_blk, old_desc_blk, new_desc_blk;
+ int meta_bg;
+
+ ext2fs_super_and_bgd_loc(fs, i, &super_blk, &old_desc_blk,
+ &new_desc_blk, &meta_bg);
+
+ if (!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) &&i && super_blk) {
+ retval = write_backup_super(fs, i, super_blk,
+ super_shadow);
+ if (retval)
+ goto errout;
+ }
+ if (fs->flags & EXT2_FLAG_SUPER_ONLY)
+ continue;
+ if ((old_desc_blk) &&
+ (!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) || (i == 0))) {
+ retval = io_channel_write_blk(fs->io,
+ old_desc_blk, old_desc_blocks, group_ptr);
+ if (retval)
+ goto errout;
+ }
+ if (new_desc_blk) {
+ retval = io_channel_write_blk(fs->io, new_desc_blk,
+ 1, group_ptr + (meta_bg*fs->blocksize));
+ if (retval)
+ goto errout;
+ }
+ }
+ fs->super->s_block_group_nr = 0;
+ fs->super->s_state = fs_state;
+#if BB_BIG_ENDIAN
+ if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
+ *super_shadow = *fs->super;
+ ext2fs_swap_super(super_shadow);
+ }
+#endif
+
+ /*
+ * If the write_bitmaps() function is present, call it to
+ * flush the bitmaps. This is done this way so that a simple
+ * program that doesn't mess with the bitmaps doesn't need to
+ * drag in the bitmaps.c code.
+ */
+ if (fs->write_bitmaps) {
+ retval = fs->write_bitmaps(fs);
+ if (retval)
+ goto errout;
+ }
+
+write_primary_superblock_only:
+ /*
+ * Write out master superblock. This has to be done
+ * separately, since it is located at a fixed location
+ * (SUPERBLOCK_OFFSET). We flush all other pending changes
+ * out to disk first, just to avoid a race condition with an
+ * insy-tinsy window....
+ */
+ retval = io_channel_flush(fs->io);
+ retval = write_primary_superblock(fs, super_shadow);
+ if (retval)
+ goto errout;
+
+ fs->flags &= ~EXT2_FLAG_DIRTY;
+
+ retval = io_channel_flush(fs->io);
+errout:
+ fs->super->s_state = fs_state;
+ if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
+ if (super_shadow)
+ ext2fs_free_mem(&super_shadow);
+ if (group_shadow)
+ ext2fs_free_mem(&group_shadow);
+ }
+ return retval;
+}
+
+errcode_t ext2fs_close(ext2_filsys fs)
+{
+ errcode_t retval;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ if (fs->flags & EXT2_FLAG_DIRTY) {
+ retval = ext2fs_flush(fs);
+ if (retval)
+ return retval;
+ }
+ if (fs->write_bitmaps) {
+ retval = fs->write_bitmaps(fs);
+ if (retval)
+ return retval;
+ }
+ ext2fs_free(fs);
+ return 0;
+}
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/cmp_bitmaps.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/cmp_bitmaps.c
new file mode 100644
index 0000000000..05b8eb8d78
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/cmp_bitmaps.c
@@ -0,0 +1,73 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * cmp_bitmaps.c --- routines to compare inode and block bitmaps.
+ *
+ * Copyright (C) 1995 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1,
+ ext2fs_block_bitmap bm2)
+{
+ blk_t i;
+
+ EXT2_CHECK_MAGIC(bm1, EXT2_ET_MAGIC_BLOCK_BITMAP);
+ EXT2_CHECK_MAGIC(bm2, EXT2_ET_MAGIC_BLOCK_BITMAP);
+
+ if ((bm1->start != bm2->start) ||
+ (bm1->end != bm2->end) ||
+ (memcmp(bm1->bitmap, bm2->bitmap,
+ (size_t) (bm1->end - bm1->start)/8)))
+ return EXT2_ET_NEQ_BLOCK_BITMAP;
+
+ for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
+ if (ext2fs_fast_test_block_bitmap(bm1, i) !=
+ ext2fs_fast_test_block_bitmap(bm2, i))
+ return EXT2_ET_NEQ_BLOCK_BITMAP;
+
+ return 0;
+}
+
+errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1,
+ ext2fs_inode_bitmap bm2)
+{
+ ext2_ino_t i;
+
+ EXT2_CHECK_MAGIC(bm1, EXT2_ET_MAGIC_INODE_BITMAP);
+ EXT2_CHECK_MAGIC(bm2, EXT2_ET_MAGIC_INODE_BITMAP);
+
+ if ((bm1->start != bm2->start) ||
+ (bm1->end != bm2->end) ||
+ (memcmp(bm1->bitmap, bm2->bitmap,
+ (size_t) (bm1->end - bm1->start)/8)))
+ return EXT2_ET_NEQ_INODE_BITMAP;
+
+ for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
+ if (ext2fs_fast_test_inode_bitmap(bm1, i) !=
+ ext2fs_fast_test_inode_bitmap(bm2, i))
+ return EXT2_ET_NEQ_INODE_BITMAP;
+
+ return 0;
+}
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dblist.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dblist.c
new file mode 100644
index 0000000000..06ff6d8079
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dblist.c
@@ -0,0 +1,260 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * dblist.c -- directory block list functions
+ *
+ * Copyright 1997 by Theodore Ts'o
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ *
+ */
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <time.h>
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+
+static int dir_block_cmp(const void *a, const void *b);
+
+/*
+ * Returns the number of directories in the filesystem as reported by
+ * the group descriptors. Of course, the group descriptors could be
+ * wrong!
+ */
+errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs)
+{
+ dgrp_t i;
+ ext2_ino_t num_dirs, max_dirs;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ num_dirs = 0;
+ max_dirs = fs->super->s_inodes_per_group;
+ for (i = 0; i < fs->group_desc_count; i++) {
+ if (fs->group_desc[i].bg_used_dirs_count > max_dirs)
+ num_dirs += max_dirs / 8;
+ else
+ num_dirs += fs->group_desc[i].bg_used_dirs_count;
+ }
+ if (num_dirs > fs->super->s_inodes_count)
+ num_dirs = fs->super->s_inodes_count;
+
+ *ret_num_dirs = num_dirs;
+
+ return 0;
+}
+
+/*
+ * helper function for making a new directory block list (for
+ * initialize and copy).
+ */
+static errcode_t make_dblist(ext2_filsys fs, ext2_ino_t size, ext2_ino_t count,
+ struct ext2_db_entry *list,
+ ext2_dblist *ret_dblist)
+{
+ ext2_dblist dblist;
+ errcode_t retval;
+ size_t len;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ if ((ret_dblist == 0) && fs->dblist &&
+ (fs->dblist->magic == EXT2_ET_MAGIC_DBLIST))
+ return 0;
+
+ retval = ext2fs_get_mem(sizeof(struct ext2_struct_dblist), &dblist);
+ if (retval)
+ return retval;
+ memset(dblist, 0, sizeof(struct ext2_struct_dblist));
+
+ dblist->magic = EXT2_ET_MAGIC_DBLIST;
+ dblist->fs = fs;
+ if (size)
+ dblist->size = size;
+ else {
+ retval = ext2fs_get_num_dirs(fs, &dblist->size);
+ if (retval)
+ goto cleanup;
+ dblist->size = (dblist->size * 2) + 12;
+ }
+ len = (size_t) sizeof(struct ext2_db_entry) * dblist->size;
+ dblist->count = count;
+ retval = ext2fs_get_mem(len, &dblist->list);
+ if (retval)
+ goto cleanup;
+
+ if (list)
+ memcpy(dblist->list, list, len);
+ else
+ memset(dblist->list, 0, len);
+ if (ret_dblist)
+ *ret_dblist = dblist;
+ else
+ fs->dblist = dblist;
+ return 0;
+cleanup:
+ ext2fs_free_mem(&dblist);
+ return retval;
+}
+
+/*
+ * Initialize a directory block list
+ */
+errcode_t ext2fs_init_dblist(ext2_filsys fs, ext2_dblist *ret_dblist)
+{
+ ext2_dblist dblist;
+ errcode_t retval;
+
+ retval = make_dblist(fs, 0, 0, 0, &dblist);
+ if (retval)
+ return retval;
+
+ dblist->sorted = 1;
+ if (ret_dblist)
+ *ret_dblist = dblist;
+ else
+ fs->dblist = dblist;
+
+ return 0;
+}
+
+/*
+ * Copy a directory block list
+ */
+errcode_t ext2fs_copy_dblist(ext2_dblist src, ext2_dblist *dest)
+{
+ ext2_dblist dblist;
+ errcode_t retval;
+
+ retval = make_dblist(src->fs, src->size, src->count, src->list,
+ &dblist);
+ if (retval)
+ return retval;
+ dblist->sorted = src->sorted;
+ *dest = dblist;
+ return 0;
+}
+
+/*
+ * Close a directory block list
+ *
+ * (moved to closefs.c)
+ */
+
+
+/*
+ * Add a directory block to the directory block list
+ */
+errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk,
+ int blockcnt)
+{
+ struct ext2_db_entry *new_entry;
+ errcode_t retval;
+ unsigned long old_size;
+
+ EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
+
+ if (dblist->count >= dblist->size) {
+ old_size = dblist->size * sizeof(struct ext2_db_entry);
+ dblist->size += 100;
+ retval = ext2fs_resize_mem(old_size, (size_t) dblist->size *
+ sizeof(struct ext2_db_entry),
+ &dblist->list);
+ if (retval) {
+ dblist->size -= 100;
+ return retval;
+ }
+ }
+ new_entry = dblist->list + ( (int) dblist->count++);
+ new_entry->blk = blk;
+ new_entry->ino = ino;
+ new_entry->blockcnt = blockcnt;
+
+ dblist->sorted = 0;
+
+ return 0;
+}
+
+/*
+ * Change the directory block to the directory block list
+ */
+errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk,
+ int blockcnt)
+{
+ dgrp_t i;
+
+ EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
+
+ for (i=0; i < dblist->count; i++) {
+ if ((dblist->list[i].ino != ino) ||
+ (dblist->list[i].blockcnt != blockcnt))
+ continue;
+ dblist->list[i].blk = blk;
+ dblist->sorted = 0;
+ return 0;
+ }
+ return EXT2_ET_DB_NOT_FOUND;
+}
+
+void ext2fs_dblist_sort(ext2_dblist dblist,
+ int (*sortfunc)(const void *,
+ const void *))
+{
+ if (!sortfunc)
+ sortfunc = dir_block_cmp;
+ qsort(dblist->list, (size_t) dblist->count,
+ sizeof(struct ext2_db_entry), sortfunc);
+ dblist->sorted = 1;
+}
+
+/*
+ * This function iterates over the directory block list
+ */
+errcode_t ext2fs_dblist_iterate(ext2_dblist dblist,
+ int (*func)(ext2_filsys fs,
+ struct ext2_db_entry *db_info,
+ void *priv_data),
+ void *priv_data)
+{
+ ext2_ino_t i;
+ int ret;
+
+ EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
+
+ if (!dblist->sorted)
+ ext2fs_dblist_sort(dblist, 0);
+ for (i=0; i < dblist->count; i++) {
+ ret = (*func)(dblist->fs, &dblist->list[(int)i], priv_data);
+ if (ret & DBLIST_ABORT)
+ return 0;
+ }
+ return 0;
+}
+
+static int dir_block_cmp(const void *a, const void *b)
+{
+ const struct ext2_db_entry *db_a =
+ (const struct ext2_db_entry *) a;
+ const struct ext2_db_entry *db_b =
+ (const struct ext2_db_entry *) b;
+
+ if (db_a->blk != db_b->blk)
+ return (int) (db_a->blk - db_b->blk);
+
+ if (db_a->ino != db_b->ino)
+ return (int) (db_a->ino - db_b->ino);
+
+ return (int) (db_a->blockcnt - db_b->blockcnt);
+}
+
+int ext2fs_dblist_count(ext2_dblist dblist)
+{
+ return (int) dblist->count;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dblist_dir.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dblist_dir.c
new file mode 100644
index 0000000000..b239204664
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dblist_dir.c
@@ -0,0 +1,76 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * dblist_dir.c --- iterate by directory entry
+ *
+ * Copyright 1997 by Theodore Ts'o
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ *
+ */
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <time.h>
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+
+static int db_dir_proc(ext2_filsys fs, struct ext2_db_entry *db_info,
+ void *priv_data);
+
+errcode_t ext2fs_dblist_dir_iterate(ext2_dblist dblist,
+ int flags,
+ char *block_buf,
+ int (*func)(ext2_ino_t dir,
+ int entry,
+ struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data),
+ void *priv_data)
+{
+ errcode_t retval;
+ struct dir_context ctx;
+
+ EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
+
+ ctx.dir = 0;
+ ctx.flags = flags;
+ if (block_buf)
+ ctx.buf = block_buf;
+ else {
+ retval = ext2fs_get_mem(dblist->fs->blocksize, &ctx.buf);
+ if (retval)
+ return retval;
+ }
+ ctx.func = func;
+ ctx.priv_data = priv_data;
+ ctx.errcode = 0;
+
+ retval = ext2fs_dblist_iterate(dblist, db_dir_proc, &ctx);
+
+ if (!block_buf)
+ ext2fs_free_mem(&ctx.buf);
+ if (retval)
+ return retval;
+ return ctx.errcode;
+}
+
+static int db_dir_proc(ext2_filsys fs, struct ext2_db_entry *db_info,
+ void *priv_data)
+{
+ struct dir_context *ctx;
+
+ ctx = (struct dir_context *) priv_data;
+ ctx->dir = db_info->ino;
+
+ return ext2fs_process_dir_block(fs, &db_info->blk,
+ db_info->blockcnt, 0, 0, priv_data);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dir_iterate.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dir_iterate.c
new file mode 100644
index 0000000000..b7d873595a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dir_iterate.c
@@ -0,0 +1,220 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * dir_iterate.c --- ext2fs directory iteration operations
+ *
+ * Copyright (C) 1993, 1994, 1994, 1995, 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+
+/*
+ * This function checks to see whether or not a potential deleted
+ * directory entry looks valid. What we do is check the deleted entry
+ * and each successive entry to make sure that they all look valid and
+ * that the last deleted entry ends at the beginning of the next
+ * undeleted entry. Returns 1 if the deleted entry looks valid, zero
+ * if not valid.
+ */
+static int ext2fs_validate_entry(char *buf, int offset, int final_offset)
+{
+ struct ext2_dir_entry *dirent;
+
+ while (offset < final_offset) {
+ dirent = (struct ext2_dir_entry *)(buf + offset);
+ offset += dirent->rec_len;
+ if ((dirent->rec_len < 8) ||
+ ((dirent->rec_len % 4) != 0) ||
+ (((dirent->name_len & 0xFF)+8) > dirent->rec_len))
+ return 0;
+ }
+ return (offset == final_offset);
+}
+
+errcode_t ext2fs_dir_iterate2(ext2_filsys fs,
+ ext2_ino_t dir,
+ int flags,
+ char *block_buf,
+ int (*func)(ext2_ino_t dir,
+ int entry,
+ struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data),
+ void *priv_data)
+{
+ struct dir_context ctx;
+ errcode_t retval;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ retval = ext2fs_check_directory(fs, dir);
+ if (retval)
+ return retval;
+
+ ctx.dir = dir;
+ ctx.flags = flags;
+ if (block_buf)
+ ctx.buf = block_buf;
+ else {
+ retval = ext2fs_get_mem(fs->blocksize, &ctx.buf);
+ if (retval)
+ return retval;
+ }
+ ctx.func = func;
+ ctx.priv_data = priv_data;
+ ctx.errcode = 0;
+ retval = ext2fs_block_iterate2(fs, dir, 0, 0,
+ ext2fs_process_dir_block, &ctx);
+ if (!block_buf)
+ ext2fs_free_mem(&ctx.buf);
+ if (retval)
+ return retval;
+ return ctx.errcode;
+}
+
+struct xlate {
+ int (*func)(struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data);
+ void *real_private;
+};
+
+static int xlate_func(ext2_ino_t dir EXT2FS_ATTR((unused)),
+ int entry EXT2FS_ATTR((unused)),
+ struct ext2_dir_entry *dirent, int offset,
+ int blocksize, char *buf, void *priv_data)
+{
+ struct xlate *xl = (struct xlate *) priv_data;
+
+ return (*xl->func)(dirent, offset, blocksize, buf, xl->real_private);
+}
+
+extern errcode_t ext2fs_dir_iterate(ext2_filsys fs,
+ ext2_ino_t dir,
+ int flags,
+ char *block_buf,
+ int (*func)(struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data),
+ void *priv_data)
+{
+ struct xlate xl;
+
+ xl.real_private = priv_data;
+ xl.func = func;
+
+ return ext2fs_dir_iterate2(fs, dir, flags, block_buf,
+ xlate_func, &xl);
+}
+
+
+/*
+ * Helper function which is private to this module. Used by
+ * ext2fs_dir_iterate() and ext2fs_dblist_dir_iterate()
+ */
+int ext2fs_process_dir_block(ext2_filsys fs,
+ blk_t *blocknr,
+ e2_blkcnt_t blockcnt,
+ blk_t ref_block EXT2FS_ATTR((unused)),
+ int ref_offset EXT2FS_ATTR((unused)),
+ void *priv_data)
+{
+ struct dir_context *ctx = (struct dir_context *) priv_data;
+ unsigned int offset = 0;
+ unsigned int next_real_entry = 0;
+ int ret = 0;
+ int changed = 0;
+ int do_abort = 0;
+ int entry, size;
+ struct ext2_dir_entry *dirent;
+
+ if (blockcnt < 0)
+ return 0;
+
+ entry = blockcnt ? DIRENT_OTHER_FILE : DIRENT_DOT_FILE;
+
+ ctx->errcode = ext2fs_read_dir_block(fs, *blocknr, ctx->buf);
+ if (ctx->errcode)
+ return BLOCK_ABORT;
+
+ while (offset < fs->blocksize) {
+ dirent = (struct ext2_dir_entry *) (ctx->buf + offset);
+ if (((offset + dirent->rec_len) > fs->blocksize) ||
+ (dirent->rec_len < 8) ||
+ ((dirent->rec_len % 4) != 0) ||
+ (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
+ ctx->errcode = EXT2_ET_DIR_CORRUPTED;
+ return BLOCK_ABORT;
+ }
+ if (!dirent->inode &&
+ !(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY))
+ goto next;
+
+ ret = (ctx->func)(ctx->dir,
+ (next_real_entry > offset) ?
+ DIRENT_DELETED_FILE : entry,
+ dirent, offset,
+ fs->blocksize, ctx->buf,
+ ctx->priv_data);
+ if (entry < DIRENT_OTHER_FILE)
+ entry++;
+
+ if (ret & DIRENT_CHANGED)
+ changed++;
+ if (ret & DIRENT_ABORT) {
+ do_abort++;
+ break;
+ }
+next:
+ if (next_real_entry == offset)
+ next_real_entry += dirent->rec_len;
+
+ if (ctx->flags & DIRENT_FLAG_INCLUDE_REMOVED) {
+ size = ((dirent->name_len & 0xFF) + 11) & ~3;
+
+ if (dirent->rec_len != size) {
+ unsigned int final_offset;
+
+ final_offset = offset + dirent->rec_len;
+ offset += size;
+ while (offset < final_offset &&
+ !ext2fs_validate_entry(ctx->buf,
+ offset,
+ final_offset))
+ offset += 4;
+ continue;
+ }
+ }
+ offset += dirent->rec_len;
+ }
+
+ if (changed) {
+ ctx->errcode = ext2fs_write_dir_block(fs, *blocknr, ctx->buf);
+ if (ctx->errcode)
+ return BLOCK_ABORT;
+ }
+ if (do_abort)
+ return BLOCK_ABORT;
+ return 0;
+}
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dirblock.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dirblock.c
new file mode 100644
index 0000000000..5d3f6a1bcf
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dirblock.c
@@ -0,0 +1,133 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * dirblock.c --- directory block routines.
+ *
+ * Copyright (C) 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <time.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
+ void *buf, int flags EXT2FS_ATTR((unused)))
+{
+ errcode_t retval;
+ char *p, *end;
+ struct ext2_dir_entry *dirent;
+ unsigned int name_len, rec_len;
+#if BB_BIG_ENDIAN
+ unsigned int do_swap;
+#endif
+
+ retval = io_channel_read_blk(fs->io, block, 1, buf);
+ if (retval)
+ return retval;
+#if BB_BIG_ENDIAN
+ do_swap = (fs->flags & (EXT2_FLAG_SWAP_BYTES|
+ EXT2_FLAG_SWAP_BYTES_READ)) != 0;
+#endif
+ p = (char *) buf;
+ end = (char *) buf + fs->blocksize;
+ while (p < end-8) {
+ dirent = (struct ext2_dir_entry *) p;
+#if BB_BIG_ENDIAN
+ if (do_swap) {
+ dirent->inode = ext2fs_swab32(dirent->inode);
+ dirent->rec_len = ext2fs_swab16(dirent->rec_len);
+ dirent->name_len = ext2fs_swab16(dirent->name_len);
+ }
+#endif
+ name_len = dirent->name_len;
+#ifdef WORDS_BIGENDIAN
+ if (flags & EXT2_DIRBLOCK_V2_STRUCT)
+ dirent->name_len = ext2fs_swab16(dirent->name_len);
+#endif
+ rec_len = dirent->rec_len;
+ if ((rec_len < 8) || (rec_len % 4)) {
+ rec_len = 8;
+ retval = EXT2_ET_DIR_CORRUPTED;
+ }
+ if (((name_len & 0xFF) + 8) > dirent->rec_len)
+ retval = EXT2_ET_DIR_CORRUPTED;
+ p += rec_len;
+ }
+ return retval;
+}
+
+errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block,
+ void *buf)
+{
+ return ext2fs_read_dir_block2(fs, block, buf, 0);
+}
+
+
+errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
+ void *inbuf, int flags EXT2FS_ATTR((unused)))
+{
+#if BB_BIG_ENDIAN
+ int do_swap = 0;
+ errcode_t retval;
+ char *p, *end;
+ char *buf = 0;
+ struct ext2_dir_entry *dirent;
+
+ if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+ (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
+ do_swap = 1;
+
+#ifndef WORDS_BIGENDIAN
+ if (!do_swap)
+ return io_channel_write_blk(fs->io, block, 1, (char *) inbuf);
+#endif
+
+ retval = ext2fs_get_mem(fs->blocksize, &buf);
+ if (retval)
+ return retval;
+ memcpy(buf, inbuf, fs->blocksize);
+ p = buf;
+ end = buf + fs->blocksize;
+ while (p < end) {
+ dirent = (struct ext2_dir_entry *) p;
+ if ((dirent->rec_len < 8) ||
+ (dirent->rec_len % 4)) {
+ ext2fs_free_mem(&buf);
+ return EXT2_ET_DIR_CORRUPTED;
+ }
+ p += dirent->rec_len;
+ if (do_swap) {
+ dirent->inode = ext2fs_swab32(dirent->inode);
+ dirent->rec_len = ext2fs_swab16(dirent->rec_len);
+ dirent->name_len = ext2fs_swab16(dirent->name_len);
+ }
+#ifdef WORDS_BIGENDIAN
+ if (flags & EXT2_DIRBLOCK_V2_STRUCT)
+ dirent->name_len = ext2fs_swab16(dirent->name_len);
+#endif
+ }
+ retval = io_channel_write_blk(fs->io, block, 1, buf);
+ ext2fs_free_mem(&buf);
+ return retval;
+#else
+ return io_channel_write_blk(fs->io, block, 1, (char *) inbuf);
+#endif
+}
+
+
+errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block,
+ void *inbuf)
+{
+ return ext2fs_write_dir_block2(fs, block, inbuf, 0);
+}
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dirhash.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dirhash.c
new file mode 100644
index 0000000000..ab3243fd77
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dirhash.c
@@ -0,0 +1,234 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * dirhash.c -- Calculate the hash of a directory entry
+ *
+ * Copyright (c) 2001 Daniel Phillips
+ *
+ * Copyright (c) 2002 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * Keyed 32-bit hash function using TEA in a Davis-Meyer function
+ * H0 = Key
+ * Hi = E Mi(Hi-1) + Hi-1
+ *
+ * (see Applied Cryptography, 2nd edition, p448).
+ *
+ * Jeremy Fitzhardinge <jeremy@zip.com.au> 1998
+ *
+ * This code is made available under the terms of the GPL
+ */
+#define DELTA 0x9E3779B9
+
+static void TEA_transform(__u32 buf[4], __u32 const in[])
+{
+ __u32 sum = 0;
+ __u32 b0 = buf[0], b1 = buf[1];
+ __u32 a = in[0], b = in[1], c = in[2], d = in[3];
+ int n = 16;
+
+ do {
+ sum += DELTA;
+ b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b);
+ b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d);
+ } while(--n);
+
+ buf[0] += b0;
+ buf[1] += b1;
+}
+
+/* F, G and H are basic MD4 functions: selection, majority, parity */
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/*
+ * The generic round function. The application is so specific that
+ * we don't bother protecting all the arguments with parens, as is generally
+ * good macro practice, in favor of extra legibility.
+ * Rotation is separate from addition to prevent recomputation
+ */
+#define ROUND(f, a, b, c, d, x, s) \
+ (a += f(b, c, d) + x, a = (a << s) | (a >> (32-s)))
+#define K1 0
+#define K2 013240474631UL
+#define K3 015666365641UL
+
+/*
+ * Basic cut-down MD4 transform. Returns only 32 bits of result.
+ */
+static void halfMD4Transform (__u32 buf[4], __u32 const in[])
+{
+ __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+ /* Round 1 */
+ ROUND(F, a, b, c, d, in[0] + K1, 3);
+ ROUND(F, d, a, b, c, in[1] + K1, 7);
+ ROUND(F, c, d, a, b, in[2] + K1, 11);
+ ROUND(F, b, c, d, a, in[3] + K1, 19);
+ ROUND(F, a, b, c, d, in[4] + K1, 3);
+ ROUND(F, d, a, b, c, in[5] + K1, 7);
+ ROUND(F, c, d, a, b, in[6] + K1, 11);
+ ROUND(F, b, c, d, a, in[7] + K1, 19);
+
+ /* Round 2 */
+ ROUND(G, a, b, c, d, in[1] + K2, 3);
+ ROUND(G, d, a, b, c, in[3] + K2, 5);
+ ROUND(G, c, d, a, b, in[5] + K2, 9);
+ ROUND(G, b, c, d, a, in[7] + K2, 13);
+ ROUND(G, a, b, c, d, in[0] + K2, 3);
+ ROUND(G, d, a, b, c, in[2] + K2, 5);
+ ROUND(G, c, d, a, b, in[4] + K2, 9);
+ ROUND(G, b, c, d, a, in[6] + K2, 13);
+
+ /* Round 3 */
+ ROUND(H, a, b, c, d, in[3] + K3, 3);
+ ROUND(H, d, a, b, c, in[7] + K3, 9);
+ ROUND(H, c, d, a, b, in[2] + K3, 11);
+ ROUND(H, b, c, d, a, in[6] + K3, 15);
+ ROUND(H, a, b, c, d, in[1] + K3, 3);
+ ROUND(H, d, a, b, c, in[5] + K3, 9);
+ ROUND(H, c, d, a, b, in[0] + K3, 11);
+ ROUND(H, b, c, d, a, in[4] + K3, 15);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+#undef ROUND
+#undef F
+#undef G
+#undef H
+#undef K1
+#undef K2
+#undef K3
+
+/* The old legacy hash */
+static ext2_dirhash_t dx_hack_hash (const char *name, int len)
+{
+ __u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
+ while (len--) {
+ __u32 hash = hash1 + (hash0 ^ (*name++ * 7152373));
+
+ if (hash & 0x80000000) hash -= 0x7fffffff;
+ hash1 = hash0;
+ hash0 = hash;
+ }
+ return (hash0 << 1);
+}
+
+static void str2hashbuf(const char *msg, int len, __u32 *buf, int num)
+{
+ __u32 pad, val;
+ int i;
+
+ pad = (__u32)len | ((__u32)len << 8);
+ pad |= pad << 16;
+
+ val = pad;
+ if (len > num*4)
+ len = num * 4;
+ for (i=0; i < len; i++) {
+ if ((i % 4) == 0)
+ val = pad;
+ val = msg[i] + (val << 8);
+ if ((i % 4) == 3) {
+ *buf++ = val;
+ val = pad;
+ num--;
+ }
+ }
+ if (--num >= 0)
+ *buf++ = val;
+ while (--num >= 0)
+ *buf++ = pad;
+}
+
+/*
+ * Returns the hash of a filename. If len is 0 and name is NULL, then
+ * this function can be used to test whether or not a hash version is
+ * supported.
+ *
+ * The seed is an 4 longword (32 bits) "secret" which can be used to
+ * uniquify a hash. If the seed is all zero's, then some default seed
+ * may be used.
+ *
+ * A particular hash version specifies whether or not the seed is
+ * represented, and whether or not the returned hash is 32 bits or 64
+ * bits. 32 bit hashes will return 0 for the minor hash.
+ */
+errcode_t ext2fs_dirhash(int version, const char *name, int len,
+ const __u32 *seed,
+ ext2_dirhash_t *ret_hash,
+ ext2_dirhash_t *ret_minor_hash)
+{
+ __u32 hash;
+ __u32 minor_hash = 0;
+ const char *p;
+ int i;
+ __u32 in[8], buf[4];
+
+ /* Initialize the default seed for the hash checksum functions */
+ buf[0] = 0x67452301;
+ buf[1] = 0xefcdab89;
+ buf[2] = 0x98badcfe;
+ buf[3] = 0x10325476;
+
+ /* Check to see if the seed is all zero's */
+ if (seed) {
+ for (i=0; i < 4; i++) {
+ if (seed[i])
+ break;
+ }
+ if (i < 4)
+ memcpy(buf, seed, sizeof(buf));
+ }
+
+ switch (version) {
+ case EXT2_HASH_LEGACY:
+ hash = dx_hack_hash(name, len);
+ break;
+ case EXT2_HASH_HALF_MD4:
+ p = name;
+ while (len > 0) {
+ str2hashbuf(p, len, in, 8);
+ halfMD4Transform(buf, in);
+ len -= 32;
+ p += 32;
+ }
+ minor_hash = buf[2];
+ hash = buf[1];
+ break;
+ case EXT2_HASH_TEA:
+ p = name;
+ while (len > 0) {
+ str2hashbuf(p, len, in, 4);
+ TEA_transform(buf, in);
+ len -= 16;
+ p += 16;
+ }
+ hash = buf[0];
+ minor_hash = buf[1];
+ break;
+ default:
+ *ret_hash = 0;
+ return EXT2_ET_DIRHASH_UNSUPP;
+ }
+ *ret_hash = hash & ~1;
+ if (ret_minor_hash)
+ *ret_minor_hash = minor_hash;
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dupfs.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dupfs.c
new file mode 100644
index 0000000000..203c29fe3e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/dupfs.c
@@ -0,0 +1,97 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * dupfs.c --- duplicate a ext2 filesystem handle
+ *
+ * Copyright (C) 1997, 1998, 2001, 2003, 2005 by Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <time.h>
+#include <string.h>
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+
+errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest)
+{
+ ext2_filsys fs;
+ errcode_t retval;
+
+ EXT2_CHECK_MAGIC(src, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
+ if (retval)
+ return retval;
+
+ *fs = *src;
+ fs->device_name = 0;
+ fs->super = 0;
+ fs->orig_super = 0;
+ fs->group_desc = 0;
+ fs->inode_map = 0;
+ fs->block_map = 0;
+ fs->badblocks = 0;
+ fs->dblist = 0;
+
+ io_channel_bumpcount(fs->io);
+ if (fs->icache)
+ fs->icache->refcount++;
+
+ retval = ext2fs_get_mem(strlen(src->device_name)+1, &fs->device_name);
+ if (retval)
+ goto errout;
+ strcpy(fs->device_name, src->device_name);
+
+ retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->super);
+ if (retval)
+ goto errout;
+ memcpy(fs->super, src->super, SUPERBLOCK_SIZE);
+
+ retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super);
+ if (retval)
+ goto errout;
+ memcpy(fs->orig_super, src->orig_super, SUPERBLOCK_SIZE);
+
+ retval = ext2fs_get_mem((size_t) fs->desc_blocks * fs->blocksize,
+ &fs->group_desc);
+ if (retval)
+ goto errout;
+ memcpy(fs->group_desc, src->group_desc,
+ (size_t) fs->desc_blocks * fs->blocksize);
+
+ if (src->inode_map) {
+ retval = ext2fs_copy_bitmap(src->inode_map, &fs->inode_map);
+ if (retval)
+ goto errout;
+ }
+ if (src->block_map) {
+ retval = ext2fs_copy_bitmap(src->block_map, &fs->block_map);
+ if (retval)
+ goto errout;
+ }
+ if (src->badblocks) {
+ retval = ext2fs_badblocks_copy(src->badblocks, &fs->badblocks);
+ if (retval)
+ goto errout;
+ }
+ if (src->dblist) {
+ retval = ext2fs_copy_dblist(src->dblist, &fs->dblist);
+ if (retval)
+ goto errout;
+ }
+ *dest = fs;
+ return 0;
+errout:
+ ext2fs_free(fs);
+ return retval;
+
+}
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/e2image.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/e2image.h
new file mode 100644
index 0000000000..8d38ecc13f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/e2image.h
@@ -0,0 +1,52 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * e2image.h --- header file describing the ext2 image format
+ *
+ * Copyright (C) 2000 Theodore Ts'o.
+ *
+ * Note: this uses the POSIX IO interfaces, unlike most of the other
+ * functions in this library. So sue me.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+
+struct ext2_image_hdr {
+ __u32 magic_number; /* This must be EXT2_ET_MAGIC_E2IMAGE */
+ char magic_descriptor[16]; /* "Ext2 Image 1.0", w/ null padding */
+ char fs_hostname[64];/* Hostname of machine of image */
+ char fs_netaddr[32]; /* Network address */
+ __u32 fs_netaddr_type;/* 0 = IPV4, 1 = IPV6, etc. */
+ __u32 fs_device; /* Device number of image */
+ char fs_device_name[64]; /* Device name */
+ char fs_uuid[16]; /* UUID of filesystem */
+ __u32 fs_blocksize; /* Block size of the filesystem */
+ __u32 fs_reserved[8];
+
+ __u32 image_device; /* Device number of image file */
+ __u32 image_inode; /* Inode number of image file */
+ __u32 image_time; /* Time of image creation */
+ __u32 image_reserved[8];
+
+ __u32 offset_super; /* Byte offset of the sb and descriptors */
+ __u32 offset_inode; /* Byte offset of the inode table */
+ __u32 offset_inodemap; /* Byte offset of the inode bitmaps */
+ __u32 offset_blockmap; /* Byte offset of the inode bitmaps */
+ __u32 offset_reserved[8];
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/expanddir.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/expanddir.c
new file mode 100644
index 0000000000..8a29ae5849
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/expanddir.c
@@ -0,0 +1,127 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * expand.c --- expand an ext2fs directory
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+struct expand_dir_struct {
+ int done;
+ int newblocks;
+ errcode_t err;
+};
+
+static int expand_dir_proc(ext2_filsys fs,
+ blk_t *blocknr,
+ e2_blkcnt_t blockcnt,
+ blk_t ref_block EXT2FS_ATTR((unused)),
+ int ref_offset EXT2FS_ATTR((unused)),
+ void *priv_data)
+{
+ struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
+ blk_t new_blk;
+ static blk_t last_blk = 0;
+ char *block;
+ errcode_t retval;
+
+ if (*blocknr) {
+ last_blk = *blocknr;
+ return 0;
+ }
+ retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
+ if (retval) {
+ es->err = retval;
+ return BLOCK_ABORT;
+ }
+ if (blockcnt > 0) {
+ retval = ext2fs_new_dir_block(fs, 0, 0, &block);
+ if (retval) {
+ es->err = retval;
+ return BLOCK_ABORT;
+ }
+ es->done = 1;
+ retval = ext2fs_write_dir_block(fs, new_blk, block);
+ } else {
+ retval = ext2fs_get_mem(fs->blocksize, &block);
+ if (retval) {
+ es->err = retval;
+ return BLOCK_ABORT;
+ }
+ memset(block, 0, fs->blocksize);
+ retval = io_channel_write_blk(fs->io, new_blk, 1, block);
+ }
+ if (retval) {
+ es->err = retval;
+ return BLOCK_ABORT;
+ }
+ ext2fs_free_mem(&block);
+ *blocknr = new_blk;
+ ext2fs_block_alloc_stats(fs, new_blk, +1);
+ es->newblocks++;
+
+ if (es->done)
+ return (BLOCK_CHANGED | BLOCK_ABORT);
+ else
+ return BLOCK_CHANGED;
+}
+
+errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir)
+{
+ errcode_t retval;
+ struct expand_dir_struct es;
+ struct ext2_inode inode;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ if (!(fs->flags & EXT2_FLAG_RW))
+ return EXT2_ET_RO_FILSYS;
+
+ if (!fs->block_map)
+ return EXT2_ET_NO_BLOCK_BITMAP;
+
+ retval = ext2fs_check_directory(fs, dir);
+ if (retval)
+ return retval;
+
+ es.done = 0;
+ es.err = 0;
+ es.newblocks = 0;
+
+ retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_APPEND,
+ 0, expand_dir_proc, &es);
+
+ if (es.err)
+ return es.err;
+ if (!es.done)
+ return EXT2_ET_EXPAND_DIR_ERR;
+
+ /*
+ * Update the size and block count fields in the inode.
+ */
+ retval = ext2fs_read_inode(fs, dir, &inode);
+ if (retval)
+ return retval;
+
+ inode.i_size += fs->blocksize;
+ inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
+
+ retval = ext2fs_write_inode(fs, dir, &inode);
+ if (retval)
+ return retval;
+
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2_err.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2_err.h
new file mode 100644
index 0000000000..ead352810a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2_err.h
@@ -0,0 +1,116 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * ext2_err.h:
+ * This file is automatically generated; please do not edit it.
+ */
+
+#define EXT2_ET_BASE (2133571328L)
+#define EXT2_ET_MAGIC_EXT2FS_FILSYS (2133571329L)
+#define EXT2_ET_MAGIC_BADBLOCKS_LIST (2133571330L)
+#define EXT2_ET_MAGIC_BADBLOCKS_ITERATE (2133571331L)
+#define EXT2_ET_MAGIC_INODE_SCAN (2133571332L)
+#define EXT2_ET_MAGIC_IO_CHANNEL (2133571333L)
+#define EXT2_ET_MAGIC_UNIX_IO_CHANNEL (2133571334L)
+#define EXT2_ET_MAGIC_IO_MANAGER (2133571335L)
+#define EXT2_ET_MAGIC_BLOCK_BITMAP (2133571336L)
+#define EXT2_ET_MAGIC_INODE_BITMAP (2133571337L)
+#define EXT2_ET_MAGIC_GENERIC_BITMAP (2133571338L)
+#define EXT2_ET_MAGIC_TEST_IO_CHANNEL (2133571339L)
+#define EXT2_ET_MAGIC_DBLIST (2133571340L)
+#define EXT2_ET_MAGIC_ICOUNT (2133571341L)
+#define EXT2_ET_MAGIC_PQ_IO_CHANNEL (2133571342L)
+#define EXT2_ET_MAGIC_EXT2_FILE (2133571343L)
+#define EXT2_ET_MAGIC_E2IMAGE (2133571344L)
+#define EXT2_ET_MAGIC_INODE_IO_CHANNEL (2133571345L)
+#define EXT2_ET_MAGIC_RESERVED_9 (2133571346L)
+#define EXT2_ET_BAD_MAGIC (2133571347L)
+#define EXT2_ET_REV_TOO_HIGH (2133571348L)
+#define EXT2_ET_RO_FILSYS (2133571349L)
+#define EXT2_ET_GDESC_READ (2133571350L)
+#define EXT2_ET_GDESC_WRITE (2133571351L)
+#define EXT2_ET_GDESC_BAD_BLOCK_MAP (2133571352L)
+#define EXT2_ET_GDESC_BAD_INODE_MAP (2133571353L)
+#define EXT2_ET_GDESC_BAD_INODE_TABLE (2133571354L)
+#define EXT2_ET_INODE_BITMAP_WRITE (2133571355L)
+#define EXT2_ET_INODE_BITMAP_READ (2133571356L)
+#define EXT2_ET_BLOCK_BITMAP_WRITE (2133571357L)
+#define EXT2_ET_BLOCK_BITMAP_READ (2133571358L)
+#define EXT2_ET_INODE_TABLE_WRITE (2133571359L)
+#define EXT2_ET_INODE_TABLE_READ (2133571360L)
+#define EXT2_ET_NEXT_INODE_READ (2133571361L)
+#define EXT2_ET_UNEXPECTED_BLOCK_SIZE (2133571362L)
+#define EXT2_ET_DIR_CORRUPTED (2133571363L)
+#define EXT2_ET_SHORT_READ (2133571364L)
+#define EXT2_ET_SHORT_WRITE (2133571365L)
+#define EXT2_ET_DIR_NO_SPACE (2133571366L)
+#define EXT2_ET_NO_INODE_BITMAP (2133571367L)
+#define EXT2_ET_NO_BLOCK_BITMAP (2133571368L)
+#define EXT2_ET_BAD_INODE_NUM (2133571369L)
+#define EXT2_ET_BAD_BLOCK_NUM (2133571370L)
+#define EXT2_ET_EXPAND_DIR_ERR (2133571371L)
+#define EXT2_ET_TOOSMALL (2133571372L)
+#define EXT2_ET_BAD_BLOCK_MARK (2133571373L)
+#define EXT2_ET_BAD_BLOCK_UNMARK (2133571374L)
+#define EXT2_ET_BAD_BLOCK_TEST (2133571375L)
+#define EXT2_ET_BAD_INODE_MARK (2133571376L)
+#define EXT2_ET_BAD_INODE_UNMARK (2133571377L)
+#define EXT2_ET_BAD_INODE_TEST (2133571378L)
+#define EXT2_ET_FUDGE_BLOCK_BITMAP_END (2133571379L)
+#define EXT2_ET_FUDGE_INODE_BITMAP_END (2133571380L)
+#define EXT2_ET_BAD_IND_BLOCK (2133571381L)
+#define EXT2_ET_BAD_DIND_BLOCK (2133571382L)
+#define EXT2_ET_BAD_TIND_BLOCK (2133571383L)
+#define EXT2_ET_NEQ_BLOCK_BITMAP (2133571384L)
+#define EXT2_ET_NEQ_INODE_BITMAP (2133571385L)
+#define EXT2_ET_BAD_DEVICE_NAME (2133571386L)
+#define EXT2_ET_MISSING_INODE_TABLE (2133571387L)
+#define EXT2_ET_CORRUPT_SUPERBLOCK (2133571388L)
+#define EXT2_ET_BAD_GENERIC_MARK (2133571389L)
+#define EXT2_ET_BAD_GENERIC_UNMARK (2133571390L)
+#define EXT2_ET_BAD_GENERIC_TEST (2133571391L)
+#define EXT2_ET_SYMLINK_LOOP (2133571392L)
+#define EXT2_ET_CALLBACK_NOTHANDLED (2133571393L)
+#define EXT2_ET_BAD_BLOCK_IN_INODE_TABLE (2133571394L)
+#define EXT2_ET_UNSUPP_FEATURE (2133571395L)
+#define EXT2_ET_RO_UNSUPP_FEATURE (2133571396L)
+#define EXT2_ET_LLSEEK_FAILED (2133571397L)
+#define EXT2_ET_NO_MEMORY (2133571398L)
+#define EXT2_ET_INVALID_ARGUMENT (2133571399L)
+#define EXT2_ET_BLOCK_ALLOC_FAIL (2133571400L)
+#define EXT2_ET_INODE_ALLOC_FAIL (2133571401L)
+#define EXT2_ET_NO_DIRECTORY (2133571402L)
+#define EXT2_ET_TOO_MANY_REFS (2133571403L)
+#define EXT2_ET_FILE_NOT_FOUND (2133571404L)
+#define EXT2_ET_FILE_RO (2133571405L)
+#define EXT2_ET_DB_NOT_FOUND (2133571406L)
+#define EXT2_ET_DIR_EXISTS (2133571407L)
+#define EXT2_ET_UNIMPLEMENTED (2133571408L)
+#define EXT2_ET_CANCEL_REQUESTED (2133571409L)
+#define EXT2_ET_FILE_TOO_BIG (2133571410L)
+#define EXT2_ET_JOURNAL_NOT_BLOCK (2133571411L)
+#define EXT2_ET_NO_JOURNAL_SB (2133571412L)
+#define EXT2_ET_JOURNAL_TOO_SMALL (2133571413L)
+#define EXT2_ET_JOURNAL_UNSUPP_VERSION (2133571414L)
+#define EXT2_ET_LOAD_EXT_JOURNAL (2133571415L)
+#define EXT2_ET_NO_JOURNAL (2133571416L)
+#define EXT2_ET_DIRHASH_UNSUPP (2133571417L)
+#define EXT2_ET_BAD_EA_BLOCK_NUM (2133571418L)
+#define EXT2_ET_TOO_MANY_INODES (2133571419L)
+#define EXT2_ET_NOT_IMAGE_FILE (2133571420L)
+#define EXT2_ET_RES_GDT_BLOCKS (2133571421L)
+#define EXT2_ET_RESIZE_INODE_CORRUPT (2133571422L)
+#define EXT2_ET_SET_BMAP_NO_IND (2133571423L)
+
+#if 0
+extern const struct error_table et_ext2_error_table;
+extern void initialize_ext2_error_table(void);
+
+/* For compatibility with Heimdal */
+extern void initialize_ext2_error_table_r(struct et_list **list);
+
+#define ERROR_TABLE_BASE_ext2 (2133571328L)
+
+/* for compatibility with older versions... */
+#define init_ext2_err_tbl initialize_ext2_error_table
+#define ext2_err_base ERROR_TABLE_BASE_ext2
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2_ext_attr.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2_ext_attr.h
new file mode 100644
index 0000000000..cc91bb8d67
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2_ext_attr.h
@@ -0,0 +1,53 @@
+/* vi: set sw=4 ts=4: */
+/*
+ File: linux/ext2_ext_attr.h
+
+ On-disk format of extended attributes for the ext2 filesystem.
+
+ (C) 2000 Andreas Gruenbacher, <a.gruenbacher@computer.org>
+*/
+
+/* Magic value in attribute blocks */
+#define EXT2_EXT_ATTR_MAGIC_v1 0xEA010000
+#define EXT2_EXT_ATTR_MAGIC 0xEA020000
+
+/* Maximum number of references to one attribute block */
+#define EXT2_EXT_ATTR_REFCOUNT_MAX 1024
+
+struct ext2_ext_attr_header {
+ __u32 h_magic; /* magic number for identification */
+ __u32 h_refcount; /* reference count */
+ __u32 h_blocks; /* number of disk blocks used */
+ __u32 h_hash; /* hash value of all attributes */
+ __u32 h_reserved[4]; /* zero right now */
+};
+
+struct ext2_ext_attr_entry {
+ __u8 e_name_len; /* length of name */
+ __u8 e_name_index; /* attribute name index */
+ __u16 e_value_offs; /* offset in disk block of value */
+ __u32 e_value_block; /* disk block attribute is stored on (n/i) */
+ __u32 e_value_size; /* size of attribute value */
+ __u32 e_hash; /* hash value of name and value */
+};
+
+#define EXT2_EXT_ATTR_PAD_BITS 2
+#define EXT2_EXT_ATTR_PAD (1<<EXT2_EXT_ATTR_PAD_BITS)
+#define EXT2_EXT_ATTR_ROUND (EXT2_EXT_ATTR_PAD-1)
+#define EXT2_EXT_ATTR_LEN(name_len) \
+ (((name_len) + EXT2_EXT_ATTR_ROUND + \
+ sizeof(struct ext2_ext_attr_entry)) & ~EXT2_EXT_ATTR_ROUND)
+#define EXT2_EXT_ATTR_NEXT(entry) \
+ ( (struct ext2_ext_attr_entry *)( \
+ (char *)(entry) + EXT2_EXT_ATTR_LEN((entry)->e_name_len)) )
+#define EXT2_EXT_ATTR_SIZE(size) \
+ (((size) + EXT2_EXT_ATTR_ROUND) & ~EXT2_EXT_ATTR_ROUND)
+#define EXT2_EXT_IS_LAST_ENTRY(entry) (*((__u32 *)(entry)) == 0UL)
+#define EXT2_EXT_ATTR_NAME(entry) \
+ (((char *) (entry)) + sizeof(struct ext2_ext_attr_entry))
+#define EXT2_XATTR_LEN(name_len) \
+ (((name_len) + EXT2_EXT_ATTR_ROUND + \
+ sizeof(struct ext2_xattr_entry)) & ~EXT2_EXT_ATTR_ROUND)
+#define EXT2_XATTR_SIZE(size) \
+ (((size) + EXT2_EXT_ATTR_ROUND) & ~EXT2_EXT_ATTR_ROUND)
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2_fs.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2_fs.h
new file mode 100644
index 0000000000..cb49d7a600
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2_fs.h
@@ -0,0 +1,570 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * linux/include/linux/ext2_fs.h
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/include/linux/minix_fs.h
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#ifndef _LINUX_EXT2_FS_H
+#define _LINUX_EXT2_FS_H
+
+#include "ext2_types.h" /* Changed from linux/types.h */
+
+/*
+ * Special inode numbers
+ */
+#define EXT2_BAD_INO 1 /* Bad blocks inode */
+#define EXT2_ROOT_INO 2 /* Root inode */
+#define EXT2_ACL_IDX_INO 3 /* ACL inode */
+#define EXT2_ACL_DATA_INO 4 /* ACL inode */
+#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */
+#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */
+#define EXT2_RESIZE_INO 7 /* Reserved group descriptors inode */
+#define EXT2_JOURNAL_INO 8 /* Journal inode */
+
+/* First non-reserved inode for old ext2 filesystems */
+#define EXT2_GOOD_OLD_FIRST_INO 11
+
+/*
+ * The second extended file system magic number
+ */
+#define EXT2_SUPER_MAGIC 0xEF53
+
+/* Assume that user mode programs are passing in an ext2fs superblock, not
+ * a kernel struct super_block. This will allow us to call the feature-test
+ * macros from user land. */
+#define EXT2_SB(sb) (sb)
+
+/*
+ * Maximal count of links to a file
+ */
+#define EXT2_LINK_MAX 32000
+
+/*
+ * Macro-instructions used to manage several block sizes
+ */
+#define EXT2_MIN_BLOCK_LOG_SIZE 10 /* 1024 */
+#define EXT2_MAX_BLOCK_LOG_SIZE 16 /* 65536 */
+#define EXT2_MIN_BLOCK_SIZE (1 << EXT2_MIN_BLOCK_LOG_SIZE)
+#define EXT2_MAX_BLOCK_SIZE (1 << EXT2_MAX_BLOCK_LOG_SIZE)
+#define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
+#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
+#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+ EXT2_GOOD_OLD_INODE_SIZE : (s)->s_inode_size)
+#define EXT2_FIRST_INO(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+ EXT2_GOOD_OLD_FIRST_INO : (s)->s_first_ino)
+#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof(__u32))
+
+/*
+ * Macro-instructions used to manage fragments
+ */
+#define EXT2_MIN_FRAG_SIZE EXT2_MIN_BLOCK_SIZE
+#define EXT2_MAX_FRAG_SIZE EXT2_MAX_BLOCK_SIZE
+#define EXT2_MIN_FRAG_LOG_SIZE EXT2_MIN_BLOCK_LOG_SIZE
+# define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size)
+# define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s))
+
+/*
+ * ACL structures
+ */
+struct ext2_acl_header /* Header of Access Control Lists */
+{
+ __u32 aclh_size;
+ __u32 aclh_file_count;
+ __u32 aclh_acle_count;
+ __u32 aclh_first_acle;
+};
+
+struct ext2_acl_entry /* Access Control List Entry */
+{
+ __u32 acle_size;
+ __u16 acle_perms; /* Access permissions */
+ __u16 acle_type; /* Type of entry */
+ __u16 acle_tag; /* User or group identity */
+ __u16 acle_pad1;
+ __u32 acle_next; /* Pointer on next entry for the */
+ /* same inode or on next free entry */
+};
+
+/*
+ * Structure of a blocks group descriptor
+ */
+struct ext2_group_desc
+{
+ __u32 bg_block_bitmap; /* Blocks bitmap block */
+ __u32 bg_inode_bitmap; /* Inodes bitmap block */
+ __u32 bg_inode_table; /* Inodes table block */
+ __u16 bg_free_blocks_count; /* Free blocks count */
+ __u16 bg_free_inodes_count; /* Free inodes count */
+ __u16 bg_used_dirs_count; /* Directories count */
+ __u16 bg_pad;
+ __u32 bg_reserved[3];
+};
+
+/*
+ * Data structures used by the directory indexing feature
+ *
+ * Note: all of the multibyte integer fields are little endian.
+ */
+
+/*
+ * Note: dx_root_info is laid out so that if it should somehow get
+ * overlaid by a dirent the two low bits of the hash version will be
+ * zero. Therefore, the hash version mod 4 should never be 0.
+ * Sincerely, the paranoia department.
+ */
+struct ext2_dx_root_info {
+ __u32 reserved_zero;
+ __u8 hash_version; /* 0 now, 1 at release */
+ __u8 info_length; /* 8 */
+ __u8 indirect_levels;
+ __u8 unused_flags;
+};
+
+#define EXT2_HASH_LEGACY 0
+#define EXT2_HASH_HALF_MD4 1
+#define EXT2_HASH_TEA 2
+
+#define EXT2_HASH_FLAG_INCOMPAT 0x1
+
+struct ext2_dx_entry {
+ __u32 hash;
+ __u32 block;
+};
+
+struct ext2_dx_countlimit {
+ __u16 limit;
+ __u16 count;
+};
+
+
+/*
+ * Macro-instructions used to manage group descriptors
+ */
+#define EXT2_BLOCKS_PER_GROUP(s) (EXT2_SB(s)->s_blocks_per_group)
+#define EXT2_INODES_PER_GROUP(s) (EXT2_SB(s)->s_inodes_per_group)
+#define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s)/EXT2_INODE_SIZE(s))
+/* limits imposed by 16-bit value gd_free_{blocks,inode}_count */
+#define EXT2_MAX_BLOCKS_PER_GROUP(s) ((1 << 16) - 8)
+#define EXT2_MAX_INODES_PER_GROUP(s) ((1 << 16) - EXT2_INODES_PER_BLOCK(s))
+#define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
+
+/*
+ * Constants relative to the data blocks
+ */
+#define EXT2_NDIR_BLOCKS 12
+#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
+#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
+#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
+#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
+
+/*
+ * Inode flags
+ */
+#define EXT2_SECRM_FL 0x00000001 /* Secure deletion */
+#define EXT2_UNRM_FL 0x00000002 /* Undelete */
+#define EXT2_COMPR_FL 0x00000004 /* Compress file */
+#define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */
+#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */
+#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */
+#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */
+#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */
+/* Reserved for compression usage... */
+#define EXT2_DIRTY_FL 0x00000100
+#define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
+#define EXT2_NOCOMPR_FL 0x00000400 /* Access raw compressed data */
+#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */
+/* End compression flags --- maybe not all used */
+#define EXT2_BTREE_FL 0x00001000 /* btree format dir */
+#define EXT2_INDEX_FL 0x00001000 /* hash-indexed directory */
+#define EXT2_IMAGIC_FL 0x00002000
+#define EXT3_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */
+#define EXT2_NOTAIL_FL 0x00008000 /* file tail should not be merged */
+#define EXT2_DIRSYNC_FL 0x00010000 /* Synchronous directory modifications */
+#define EXT2_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
+#define EXT3_EXTENTS_FL 0x00080000 /* Inode uses extents */
+#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
+
+#define EXT2_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */
+#define EXT2_FL_USER_MODIFIABLE 0x000080FF /* User modifiable flags */
+
+/*
+ * ioctl commands
+ */
+#define EXT2_IOC_GETFLAGS _IOR('f', 1, long)
+#define EXT2_IOC_SETFLAGS _IOW('f', 2, long)
+#define EXT2_IOC_GETVERSION _IOR('v', 1, long)
+#define EXT2_IOC_SETVERSION _IOW('v', 2, long)
+
+/*
+ * Structure of an inode on the disk
+ */
+struct ext2_inode {
+ __u16 i_mode; /* File mode */
+ __u16 i_uid; /* Low 16 bits of Owner Uid */
+ __u32 i_size; /* Size in bytes */
+ __u32 i_atime; /* Access time */
+ __u32 i_ctime; /* Creation time */
+ __u32 i_mtime; /* Modification time */
+ __u32 i_dtime; /* Deletion Time */
+ __u16 i_gid; /* Low 16 bits of Group Id */
+ __u16 i_links_count; /* Links count */
+ __u32 i_blocks; /* Blocks count */
+ __u32 i_flags; /* File flags */
+ union {
+ struct {
+ __u32 l_i_reserved1;
+ } linux1;
+ struct {
+ __u32 h_i_translator;
+ } hurd1;
+ struct {
+ __u32 m_i_reserved1;
+ } masix1;
+ } osd1; /* OS dependent 1 */
+ __u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
+ __u32 i_generation; /* File version (for NFS) */
+ __u32 i_file_acl; /* File ACL */
+ __u32 i_dir_acl; /* Directory ACL */
+ __u32 i_faddr; /* Fragment address */
+ union {
+ struct {
+ __u8 l_i_frag; /* Fragment number */
+ __u8 l_i_fsize; /* Fragment size */
+ __u16 i_pad1;
+ __u16 l_i_uid_high; /* these 2 fields */
+ __u16 l_i_gid_high; /* were reserved2[0] */
+ __u32 l_i_reserved2;
+ } linux2;
+ struct {
+ __u8 h_i_frag; /* Fragment number */
+ __u8 h_i_fsize; /* Fragment size */
+ __u16 h_i_mode_high;
+ __u16 h_i_uid_high;
+ __u16 h_i_gid_high;
+ __u32 h_i_author;
+ } hurd2;
+ struct {
+ __u8 m_i_frag; /* Fragment number */
+ __u8 m_i_fsize; /* Fragment size */
+ __u16 m_pad1;
+ __u32 m_i_reserved2[2];
+ } masix2;
+ } osd2; /* OS dependent 2 */
+};
+
+/*
+ * Permanent part of an large inode on the disk
+ */
+struct ext2_inode_large {
+ __u16 i_mode; /* File mode */
+ __u16 i_uid; /* Low 16 bits of Owner Uid */
+ __u32 i_size; /* Size in bytes */
+ __u32 i_atime; /* Access time */
+ __u32 i_ctime; /* Creation time */
+ __u32 i_mtime; /* Modification time */
+ __u32 i_dtime; /* Deletion Time */
+ __u16 i_gid; /* Low 16 bits of Group Id */
+ __u16 i_links_count; /* Links count */
+ __u32 i_blocks; /* Blocks count */
+ __u32 i_flags; /* File flags */
+ union {
+ struct {
+ __u32 l_i_reserved1;
+ } linux1;
+ struct {
+ __u32 h_i_translator;
+ } hurd1;
+ struct {
+ __u32 m_i_reserved1;
+ } masix1;
+ } osd1; /* OS dependent 1 */
+ __u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
+ __u32 i_generation; /* File version (for NFS) */
+ __u32 i_file_acl; /* File ACL */
+ __u32 i_dir_acl; /* Directory ACL */
+ __u32 i_faddr; /* Fragment address */
+ union {
+ struct {
+ __u8 l_i_frag; /* Fragment number */
+ __u8 l_i_fsize; /* Fragment size */
+ __u16 i_pad1;
+ __u16 l_i_uid_high; /* these 2 fields */
+ __u16 l_i_gid_high; /* were reserved2[0] */
+ __u32 l_i_reserved2;
+ } linux2;
+ struct {
+ __u8 h_i_frag; /* Fragment number */
+ __u8 h_i_fsize; /* Fragment size */
+ __u16 h_i_mode_high;
+ __u16 h_i_uid_high;
+ __u16 h_i_gid_high;
+ __u32 h_i_author;
+ } hurd2;
+ struct {
+ __u8 m_i_frag; /* Fragment number */
+ __u8 m_i_fsize; /* Fragment size */
+ __u16 m_pad1;
+ __u32 m_i_reserved2[2];
+ } masix2;
+ } osd2; /* OS dependent 2 */
+ __u16 i_extra_isize;
+ __u16 i_pad1;
+};
+
+#define i_size_high i_dir_acl
+
+/*
+ * File system states
+ */
+#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */
+#define EXT2_ERROR_FS 0x0002 /* Errors detected */
+
+/*
+ * Mount flags
+ */
+#define EXT2_MOUNT_CHECK 0x0001 /* Do mount-time checks */
+#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */
+#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */
+#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */
+#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */
+#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */
+#define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */
+#define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */
+
+#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt
+#define set_opt(o, opt) o |= EXT2_MOUNT_##opt
+#define test_opt(sb, opt) (EXT2_SB(sb)->s_mount_opt & \
+ EXT2_MOUNT_##opt)
+/*
+ * Maximal mount counts between two filesystem checks
+ */
+#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */
+#define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */
+
+/*
+ * Behaviour when detecting errors
+ */
+#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */
+#define EXT2_ERRORS_RO 2 /* Remount fs read-only */
+#define EXT2_ERRORS_PANIC 3 /* Panic */
+#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE
+
+/*
+ * Structure of the super block
+ */
+struct ext2_super_block {
+ __u32 s_inodes_count; /* Inodes count */
+ __u32 s_blocks_count; /* Blocks count */
+ __u32 s_r_blocks_count; /* Reserved blocks count */
+ __u32 s_free_blocks_count; /* Free blocks count */
+ __u32 s_free_inodes_count; /* Free inodes count */
+ __u32 s_first_data_block; /* First Data Block */
+ __u32 s_log_block_size; /* Block size */
+ __s32 s_log_frag_size; /* Fragment size */
+ __u32 s_blocks_per_group; /* # Blocks per group */
+ __u32 s_frags_per_group; /* # Fragments per group */
+ __u32 s_inodes_per_group; /* # Inodes per group */
+ __u32 s_mtime; /* Mount time */
+ __u32 s_wtime; /* Write time */
+ __u16 s_mnt_count; /* Mount count */
+ __s16 s_max_mnt_count; /* Maximal mount count */
+ __u16 s_magic; /* Magic signature */
+ __u16 s_state; /* File system state */
+ __u16 s_errors; /* Behaviour when detecting errors */
+ __u16 s_minor_rev_level; /* minor revision level */
+ __u32 s_lastcheck; /* time of last check */
+ __u32 s_checkinterval; /* max. time between checks */
+ __u32 s_creator_os; /* OS */
+ __u32 s_rev_level; /* Revision level */
+ __u16 s_def_resuid; /* Default uid for reserved blocks */
+ __u16 s_def_resgid; /* Default gid for reserved blocks */
+ /*
+ * These fields are for EXT2_DYNAMIC_REV superblocks only.
+ *
+ * Note: the difference between the compatible feature set and
+ * the incompatible feature set is that if there is a bit set
+ * in the incompatible feature set that the kernel doesn't
+ * know about, it should refuse to mount the filesystem.
+ *
+ * e2fsck's requirements are more strict; if it doesn't know
+ * about a feature in either the compatible or incompatible
+ * feature set, it must abort and not try to meddle with
+ * things it doesn't understand...
+ */
+ __u32 s_first_ino; /* First non-reserved inode */
+ __u16 s_inode_size; /* size of inode structure */
+ __u16 s_block_group_nr; /* block group # of this superblock */
+ __u32 s_feature_compat; /* compatible feature set */
+ __u32 s_feature_incompat; /* incompatible feature set */
+ __u32 s_feature_ro_compat; /* readonly-compatible feature set */
+ __u8 s_uuid[16]; /* 128-bit uuid for volume */
+ char s_volume_name[16]; /* volume name */
+ char s_last_mounted[64]; /* directory where last mounted */
+ __u32 s_algorithm_usage_bitmap; /* For compression */
+ /*
+ * Performance hints. Directory preallocation should only
+ * happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on.
+ */
+ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
+ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
+ __u16 s_reserved_gdt_blocks; /* Per group table for online growth */
+ /*
+ * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set.
+ */
+ __u8 s_journal_uuid[16]; /* uuid of journal superblock */
+ __u32 s_journal_inum; /* inode number of journal file */
+ __u32 s_journal_dev; /* device number of journal file */
+ __u32 s_last_orphan; /* start of list of inodes to delete */
+ __u32 s_hash_seed[4]; /* HTREE hash seed */
+ __u8 s_def_hash_version; /* Default hash version to use */
+ __u8 s_jnl_backup_type; /* Default type of journal backup */
+ __u16 s_reserved_word_pad;
+ __u32 s_default_mount_opts;
+ __u32 s_first_meta_bg; /* First metablock group */
+ __u32 s_mkfs_time; /* When the filesystem was created */
+ __u32 s_jnl_blocks[17]; /* Backup of the journal inode */
+ __u32 s_reserved[172]; /* Padding to the end of the block */
+};
+
+/*
+ * Codes for operating systems
+ */
+#define EXT2_OS_LINUX 0
+#define EXT2_OS_HURD 1
+#define EXT2_OS_MASIX 2
+#define EXT2_OS_FREEBSD 3
+#define EXT2_OS_LITES 4
+
+/*
+ * Revision levels
+ */
+#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */
+#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */
+
+#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV
+#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV
+
+#define EXT2_GOOD_OLD_INODE_SIZE 128
+
+/*
+ * Journal inode backup types
+ */
+#define EXT3_JNL_BACKUP_BLOCKS 1
+
+/*
+ * Feature set definitions
+ */
+
+#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_feature_compat & (mask) )
+#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_feature_ro_compat & (mask) )
+#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_feature_incompat & (mask) )
+
+#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
+#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
+#define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008
+#define EXT2_FEATURE_COMPAT_RESIZE_INODE 0x0010
+#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020
+
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
+#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
+/* #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 not used */
+
+#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
+#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
+#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */
+#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
+#define EXT3_FEATURE_INCOMPAT_EXTENTS 0x0040
+
+
+#define EXT2_FEATURE_COMPAT_SUPP 0
+#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE)
+#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
+ EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
+
+/*
+ * Default values for user and/or group using reserved blocks
+ */
+#define EXT2_DEF_RESUID 0
+#define EXT2_DEF_RESGID 0
+
+/*
+ * Default mount options
+ */
+#define EXT2_DEFM_DEBUG 0x0001
+#define EXT2_DEFM_BSDGROUPS 0x0002
+#define EXT2_DEFM_XATTR_USER 0x0004
+#define EXT2_DEFM_ACL 0x0008
+#define EXT2_DEFM_UID16 0x0010
+#define EXT3_DEFM_JMODE 0x0060
+#define EXT3_DEFM_JMODE_DATA 0x0020
+#define EXT3_DEFM_JMODE_ORDERED 0x0040
+#define EXT3_DEFM_JMODE_WBACK 0x0060
+
+/*
+ * Structure of a directory entry
+ */
+#define EXT2_NAME_LEN 255
+
+struct ext2_dir_entry {
+ __u32 inode; /* Inode number */
+ __u16 rec_len; /* Directory entry length */
+ __u16 name_len; /* Name length */
+ char name[EXT2_NAME_LEN]; /* File name */
+};
+
+/*
+ * The new version of the directory entry. Since EXT2 structures are
+ * stored in intel byte order, and the name_len field could never be
+ * bigger than 255 chars, it's safe to reclaim the extra byte for the
+ * file_type field.
+ */
+struct ext2_dir_entry_2 {
+ __u32 inode; /* Inode number */
+ __u16 rec_len; /* Directory entry length */
+ __u8 name_len; /* Name length */
+ __u8 file_type;
+ char name[EXT2_NAME_LEN]; /* File name */
+};
+
+/*
+ * Ext2 directory file types. Only the low 3 bits are used. The
+ * other bits are reserved for now.
+ */
+#define EXT2_FT_UNKNOWN 0
+#define EXT2_FT_REG_FILE 1
+#define EXT2_FT_DIR 2
+#define EXT2_FT_CHRDEV 3
+#define EXT2_FT_BLKDEV 4
+#define EXT2_FT_FIFO 5
+#define EXT2_FT_SOCK 6
+#define EXT2_FT_SYMLINK 7
+
+#define EXT2_FT_MAX 8
+
+/*
+ * EXT2_DIR_PAD defines the directory entries boundaries
+ *
+ * NOTE: It must be a multiple of 4
+ */
+#define EXT2_DIR_PAD 4
+#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
+#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
+ ~EXT2_DIR_ROUND)
+
+#endif /* _LINUX_EXT2_FS_H */
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2_io.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2_io.h
new file mode 100644
index 0000000000..e6c9630e2c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2_io.h
@@ -0,0 +1,114 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * io.h --- the I/O manager abstraction
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#ifndef _EXT2FS_EXT2_IO_H
+#define _EXT2FS_EXT2_IO_H
+
+/*
+ * ext2_loff_t is defined here since unix_io.c needs it.
+ */
+#if defined(__GNUC__) || defined(HAS_LONG_LONG)
+typedef long long ext2_loff_t;
+#else
+typedef long ext2_loff_t;
+#endif
+
+/* llseek.c */
+/* ext2_loff_t ext2fs_llseek (int, ext2_loff_t, int); */
+#ifdef CONFIG_LFS
+# define ext2fs_llseek lseek64
+#else
+# define ext2fs_llseek lseek
+#endif
+
+typedef struct struct_io_manager *io_manager;
+typedef struct struct_io_channel *io_channel;
+
+#define CHANNEL_FLAGS_WRITETHROUGH 0x01
+
+struct struct_io_channel {
+ errcode_t magic;
+ io_manager manager;
+ char *name;
+ int block_size;
+ errcode_t (*read_error)(io_channel channel,
+ unsigned long block,
+ int count,
+ void *data,
+ size_t size,
+ int actual_bytes_read,
+ errcode_t error);
+ errcode_t (*write_error)(io_channel channel,
+ unsigned long block,
+ int count,
+ const void *data,
+ size_t size,
+ int actual_bytes_written,
+ errcode_t error);
+ int refcount;
+ int flags;
+ int reserved[14];
+ void *private_data;
+ void *app_data;
+};
+
+struct struct_io_manager {
+ errcode_t magic;
+ const char *name;
+ errcode_t (*open)(const char *name, int flags, io_channel *channel);
+ errcode_t (*close)(io_channel channel);
+ errcode_t (*set_blksize)(io_channel channel, int blksize);
+ errcode_t (*read_blk)(io_channel channel, unsigned long block,
+ int count, void *data);
+ errcode_t (*write_blk)(io_channel channel, unsigned long block,
+ int count, const void *data);
+ errcode_t (*flush)(io_channel channel);
+ errcode_t (*write_byte)(io_channel channel, unsigned long offset,
+ int count, const void *data);
+ errcode_t (*set_option)(io_channel channel, const char *option,
+ const char *arg);
+ int reserved[14];
+};
+
+#define IO_FLAG_RW 1
+
+/*
+ * Convenience functions....
+ */
+#define io_channel_close(c) ((c)->manager->close((c)))
+#define io_channel_set_blksize(c,s) ((c)->manager->set_blksize((c),s))
+#define io_channel_read_blk(c,b,n,d) ((c)->manager->read_blk((c),b,n,d))
+#define io_channel_write_blk(c,b,n,d) ((c)->manager->write_blk((c),b,n,d))
+#define io_channel_flush(c) ((c)->manager->flush((c)))
+#define io_channel_bumpcount(c) ((c)->refcount++)
+
+/* io_manager.c */
+extern errcode_t io_channel_set_options(io_channel channel,
+ const char *options);
+extern errcode_t io_channel_write_byte(io_channel channel,
+ unsigned long offset,
+ int count, const void *data);
+
+/* unix_io.c */
+extern io_manager unix_io_manager;
+
+/* test_io.c */
+extern io_manager test_io_manager, test_io_backing_manager;
+extern void (*test_io_cb_read_blk)
+ (unsigned long block, int count, errcode_t err);
+extern void (*test_io_cb_write_blk)
+ (unsigned long block, int count, errcode_t err);
+extern void (*test_io_cb_set_blksize)
+ (int blksize, errcode_t err);
+
+#endif /* _EXT2FS_EXT2_IO_H */
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2_types.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2_types.h
new file mode 100644
index 0000000000..2c1196b8b7
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2_types.h
@@ -0,0 +1,2 @@
+/* vi: set sw=4 ts=4: */
+#include <linux/types.h>
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs.h
new file mode 100644
index 0000000000..133fb1f1b1
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs.h
@@ -0,0 +1,923 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * ext2fs.h --- ext2fs
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#ifndef _EXT2FS_EXT2FS_H
+#define _EXT2FS_EXT2FS_H
+
+
+#define EXT2FS_ATTR(x)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Where the master copy of the superblock is located, and how big
+ * superblocks are supposed to be. We define SUPERBLOCK_SIZE because
+ * the size of the superblock structure is not necessarily trustworthy
+ * (some versions have the padding set up so that the superblock is
+ * 1032 bytes long).
+ */
+#define SUPERBLOCK_OFFSET 1024
+#define SUPERBLOCK_SIZE 1024
+
+/*
+ * The last ext2fs revision level that this version of the library is
+ * able to support.
+ */
+#define EXT2_LIB_CURRENT_REV EXT2_DYNAMIC_REV
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ext2_types.h"
+#include "ext2_fs.h"
+
+typedef __u32 ext2_ino_t;
+typedef __u32 blk_t;
+typedef __u32 dgrp_t;
+typedef __u32 ext2_off_t;
+typedef __s64 e2_blkcnt_t;
+typedef __u32 ext2_dirhash_t;
+
+#include "ext2_io.h"
+#include "ext2_err.h"
+
+typedef struct struct_ext2_filsys *ext2_filsys;
+
+struct ext2fs_struct_generic_bitmap {
+ errcode_t magic;
+ ext2_filsys fs;
+ __u32 start, end;
+ __u32 real_end;
+ char * description;
+ char * bitmap;
+ errcode_t base_error_code;
+ __u32 reserved[7];
+};
+
+#define EXT2FS_MARK_ERROR 0
+#define EXT2FS_UNMARK_ERROR 1
+#define EXT2FS_TEST_ERROR 2
+
+typedef struct ext2fs_struct_generic_bitmap *ext2fs_generic_bitmap;
+typedef struct ext2fs_struct_generic_bitmap *ext2fs_inode_bitmap;
+typedef struct ext2fs_struct_generic_bitmap *ext2fs_block_bitmap;
+
+#define EXT2_FIRST_INODE(s) EXT2_FIRST_INO(s)
+
+/*
+ * badblocks list definitions
+ */
+
+typedef struct ext2_struct_u32_list *ext2_badblocks_list;
+typedef struct ext2_struct_u32_iterate *ext2_badblocks_iterate;
+
+typedef struct ext2_struct_u32_list *ext2_u32_list;
+typedef struct ext2_struct_u32_iterate *ext2_u32_iterate;
+
+/* old */
+typedef struct ext2_struct_u32_list *badblocks_list;
+typedef struct ext2_struct_u32_iterate *badblocks_iterate;
+
+#define BADBLOCKS_FLAG_DIRTY 1
+
+/*
+ * ext2_dblist structure and abstractions (see dblist.c)
+ */
+struct ext2_db_entry {
+ ext2_ino_t ino;
+ blk_t blk;
+ int blockcnt;
+};
+
+typedef struct ext2_struct_dblist *ext2_dblist;
+
+#define DBLIST_ABORT 1
+
+/*
+ * ext2_fileio definitions
+ */
+
+#define EXT2_FILE_WRITE 0x0001
+#define EXT2_FILE_CREATE 0x0002
+
+#define EXT2_FILE_MASK 0x00FF
+
+#define EXT2_FILE_BUF_DIRTY 0x4000
+#define EXT2_FILE_BUF_VALID 0x2000
+
+typedef struct ext2_file *ext2_file_t;
+
+#define EXT2_SEEK_SET 0
+#define EXT2_SEEK_CUR 1
+#define EXT2_SEEK_END 2
+
+/*
+ * Flags for the ext2_filsys structure and for ext2fs_open()
+ */
+#define EXT2_FLAG_RW 0x01
+#define EXT2_FLAG_CHANGED 0x02
+#define EXT2_FLAG_DIRTY 0x04
+#define EXT2_FLAG_VALID 0x08
+#define EXT2_FLAG_IB_DIRTY 0x10
+#define EXT2_FLAG_BB_DIRTY 0x20
+#define EXT2_FLAG_SWAP_BYTES 0x40
+#define EXT2_FLAG_SWAP_BYTES_READ 0x80
+#define EXT2_FLAG_SWAP_BYTES_WRITE 0x100
+#define EXT2_FLAG_MASTER_SB_ONLY 0x200
+#define EXT2_FLAG_FORCE 0x400
+#define EXT2_FLAG_SUPER_ONLY 0x800
+#define EXT2_FLAG_JOURNAL_DEV_OK 0x1000
+#define EXT2_FLAG_IMAGE_FILE 0x2000
+
+/*
+ * Special flag in the ext2 inode i_flag field that means that this is
+ * a new inode. (So that ext2_write_inode() can clear extra fields.)
+ */
+#define EXT2_NEW_INODE_FL 0x80000000
+
+/*
+ * Flags for mkjournal
+ *
+ * EXT2_MKJOURNAL_V1_SUPER Make a (deprecated) V1 journal superblock
+ */
+#define EXT2_MKJOURNAL_V1_SUPER 0x0000001
+
+struct struct_ext2_filsys {
+ errcode_t magic;
+ io_channel io;
+ int flags;
+ char * device_name;
+ struct ext2_super_block * super;
+ unsigned int blocksize;
+ int fragsize;
+ dgrp_t group_desc_count;
+ unsigned long desc_blocks;
+ struct ext2_group_desc * group_desc;
+ int inode_blocks_per_group;
+ ext2fs_inode_bitmap inode_map;
+ ext2fs_block_bitmap block_map;
+ errcode_t (*get_blocks)(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks);
+ errcode_t (*check_directory)(ext2_filsys fs, ext2_ino_t ino);
+ errcode_t (*write_bitmaps)(ext2_filsys fs);
+ errcode_t (*read_inode)(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode *inode);
+ errcode_t (*write_inode)(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode *inode);
+ ext2_badblocks_list badblocks;
+ ext2_dblist dblist;
+ __u32 stride; /* for mke2fs */
+ struct ext2_super_block * orig_super;
+ struct ext2_image_hdr * image_header;
+ __u32 umask;
+ /*
+ * Reserved for future expansion
+ */
+ __u32 reserved[8];
+
+ /*
+ * Reserved for the use of the calling application.
+ */
+ void * priv_data;
+
+ /*
+ * Inode cache
+ */
+ struct ext2_inode_cache *icache;
+ io_channel image_io;
+};
+
+#include "bitops.h"
+
+/*
+ * Return flags for the block iterator functions
+ */
+#define BLOCK_CHANGED 1
+#define BLOCK_ABORT 2
+#define BLOCK_ERROR 4
+
+/*
+ * Block interate flags
+ *
+ * BLOCK_FLAG_APPEND, or BLOCK_FLAG_HOLE, indicates that the interator
+ * function should be called on blocks where the block number is zero.
+ * This is used by ext2fs_expand_dir() to be able to add a new block
+ * to an inode. It can also be used for programs that want to be able
+ * to deal with files that contain "holes".
+ *
+ * BLOCK_FLAG_TRAVERSE indicates that the iterator function for the
+ * indirect, doubly indirect, etc. blocks should be called after all
+ * of the blocks containined in the indirect blocks are processed.
+ * This is useful if you are going to be deallocating blocks from an
+ * inode.
+ *
+ * BLOCK_FLAG_DATA_ONLY indicates that the iterator function should be
+ * called for data blocks only.
+ *
+ * BLOCK_FLAG_NO_LARGE is for internal use only. It informs
+ * ext2fs_block_iterate2 that large files won't be accepted.
+ */
+#define BLOCK_FLAG_APPEND 1
+#define BLOCK_FLAG_HOLE 1
+#define BLOCK_FLAG_DEPTH_TRAVERSE 2
+#define BLOCK_FLAG_DATA_ONLY 4
+
+#define BLOCK_FLAG_NO_LARGE 0x1000
+
+/*
+ * Magic "block count" return values for the block iterator function.
+ */
+#define BLOCK_COUNT_IND (-1)
+#define BLOCK_COUNT_DIND (-2)
+#define BLOCK_COUNT_TIND (-3)
+#define BLOCK_COUNT_TRANSLATOR (-4)
+
+#if 0
+/*
+ * Flags for ext2fs_move_blocks
+ */
+#define EXT2_BMOVE_GET_DBLIST 0x0001
+#define EXT2_BMOVE_DEBUG 0x0002
+#endif
+
+/*
+ * Flags for directory block reading and writing functions
+ */
+#define EXT2_DIRBLOCK_V2_STRUCT 0x0001
+
+/*
+ * Return flags for the directory iterator functions
+ */
+#define DIRENT_CHANGED 1
+#define DIRENT_ABORT 2
+#define DIRENT_ERROR 3
+
+/*
+ * Directory iterator flags
+ */
+
+#define DIRENT_FLAG_INCLUDE_EMPTY 1
+#define DIRENT_FLAG_INCLUDE_REMOVED 2
+
+#define DIRENT_DOT_FILE 1
+#define DIRENT_DOT_DOT_FILE 2
+#define DIRENT_OTHER_FILE 3
+#define DIRENT_DELETED_FILE 4
+
+/*
+ * Inode scan definitions
+ */
+typedef struct ext2_struct_inode_scan *ext2_inode_scan;
+
+/*
+ * ext2fs_scan flags
+ */
+#define EXT2_SF_CHK_BADBLOCKS 0x0001
+#define EXT2_SF_BAD_INODE_BLK 0x0002
+#define EXT2_SF_BAD_EXTRA_BYTES 0x0004
+#define EXT2_SF_SKIP_MISSING_ITABLE 0x0008
+
+/*
+ * ext2fs_check_if_mounted flags
+ */
+#define EXT2_MF_MOUNTED 1
+#define EXT2_MF_ISROOT 2
+#define EXT2_MF_READONLY 4
+#define EXT2_MF_SWAP 8
+#define EXT2_MF_BUSY 16
+
+/*
+ * Ext2/linux mode flags. We define them here so that we don't need
+ * to depend on the OS's sys/stat.h, since we may be compiling on a
+ * non-Linux system.
+ */
+#define LINUX_S_IFMT 00170000
+#define LINUX_S_IFSOCK 0140000
+#define LINUX_S_IFLNK 0120000
+#define LINUX_S_IFREG 0100000
+#define LINUX_S_IFBLK 0060000
+#define LINUX_S_IFDIR 0040000
+#define LINUX_S_IFCHR 0020000
+#define LINUX_S_IFIFO 0010000
+#define LINUX_S_ISUID 0004000
+#define LINUX_S_ISGID 0002000
+#define LINUX_S_ISVTX 0001000
+
+#define LINUX_S_IRWXU 00700
+#define LINUX_S_IRUSR 00400
+#define LINUX_S_IWUSR 00200
+#define LINUX_S_IXUSR 00100
+
+#define LINUX_S_IRWXG 00070
+#define LINUX_S_IRGRP 00040
+#define LINUX_S_IWGRP 00020
+#define LINUX_S_IXGRP 00010
+
+#define LINUX_S_IRWXO 00007
+#define LINUX_S_IROTH 00004
+#define LINUX_S_IWOTH 00002
+#define LINUX_S_IXOTH 00001
+
+#define LINUX_S_ISLNK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFLNK)
+#define LINUX_S_ISREG(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFREG)
+#define LINUX_S_ISDIR(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFDIR)
+#define LINUX_S_ISCHR(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFCHR)
+#define LINUX_S_ISBLK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFBLK)
+#define LINUX_S_ISFIFO(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFIFO)
+#define LINUX_S_ISSOCK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFSOCK)
+
+/*
+ * ext2 size of an inode
+ */
+#define EXT2_I_SIZE(i) ((i)->i_size | ((__u64) (i)->i_size_high << 32))
+
+/*
+ * ext2_icount_t abstraction
+ */
+#define EXT2_ICOUNT_OPT_INCREMENT 0x01
+
+typedef struct ext2_icount *ext2_icount_t;
+
+/*
+ * Flags for ext2fs_bmap
+ */
+#define BMAP_ALLOC 0x0001
+#define BMAP_SET 0x0002
+
+/*
+ * Flags for imager.c functions
+ */
+#define IMAGER_FLAG_INODEMAP 1
+#define IMAGER_FLAG_SPARSEWRITE 2
+
+/*
+ * For checking structure magic numbers...
+ */
+
+#define EXT2_CHECK_MAGIC(struct, code) \
+ if ((struct)->magic != (code)) return (code)
+
+
+/*
+ * For ext2 compression support
+ */
+#define EXT2FS_COMPRESSED_BLKADDR ((blk_t) 0xffffffff)
+#define HOLE_BLKADDR(_b) ((_b) == 0 || (_b) == EXT2FS_COMPRESSED_BLKADDR)
+
+/*
+ * Features supported by this version of the library
+ */
+#define EXT2_LIB_FEATURE_COMPAT_SUPP (EXT2_FEATURE_COMPAT_DIR_PREALLOC|\
+ EXT2_FEATURE_COMPAT_IMAGIC_INODES|\
+ EXT3_FEATURE_COMPAT_HAS_JOURNAL|\
+ EXT2_FEATURE_COMPAT_RESIZE_INODE|\
+ EXT2_FEATURE_COMPAT_DIR_INDEX|\
+ EXT2_FEATURE_COMPAT_EXT_ATTR)
+
+/* This #ifdef is temporary until compression is fully supported */
+#ifdef ENABLE_COMPRESSION
+#ifndef I_KNOW_THAT_COMPRESSION_IS_EXPERIMENTAL
+/* If the below warning bugs you, then have
+ `CPPFLAGS=-DI_KNOW_THAT_COMPRESSION_IS_EXPERIMENTAL' in your
+ environment at configure time. */
+ #warning "Compression support is experimental"
+#endif
+#define EXT2_LIB_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE|\
+ EXT2_FEATURE_INCOMPAT_COMPRESSION|\
+ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\
+ EXT2_FEATURE_INCOMPAT_META_BG|\
+ EXT3_FEATURE_INCOMPAT_RECOVER)
+#else
+#define EXT2_LIB_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE|\
+ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\
+ EXT2_FEATURE_INCOMPAT_META_BG|\
+ EXT3_FEATURE_INCOMPAT_RECOVER)
+#endif
+#define EXT2_LIB_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE)
+/*
+ * function prototypes
+ */
+
+/* alloc.c */
+extern errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir, int mode,
+ ext2fs_inode_bitmap map, ext2_ino_t *ret);
+extern errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal,
+ ext2fs_block_bitmap map, blk_t *ret);
+extern errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start,
+ blk_t finish, int num,
+ ext2fs_block_bitmap map,
+ blk_t *ret);
+extern errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal,
+ char *block_buf, blk_t *ret);
+
+/* alloc_sb.c */
+extern int ext2fs_reserve_super_and_bgd(ext2_filsys fs,
+ dgrp_t group,
+ ext2fs_block_bitmap bmap);
+
+/* alloc_stats.c */
+void ext2fs_inode_alloc_stats(ext2_filsys fs, ext2_ino_t ino, int inuse);
+void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino,
+ int inuse, int isdir);
+void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse);
+
+/* alloc_tables.c */
+extern errcode_t ext2fs_allocate_tables(ext2_filsys fs);
+extern errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group,
+ ext2fs_block_bitmap bmap);
+
+/* badblocks.c */
+extern errcode_t ext2fs_u32_list_create(ext2_u32_list *ret, int size);
+extern errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk);
+extern int ext2fs_u32_list_find(ext2_u32_list bb, __u32 blk);
+extern int ext2fs_u32_list_test(ext2_u32_list bb, blk_t blk);
+extern errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb,
+ ext2_u32_iterate *ret);
+extern int ext2fs_u32_list_iterate(ext2_u32_iterate iter, blk_t *blk);
+extern void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter);
+extern errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest);
+extern int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2);
+
+extern errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret,
+ int size);
+extern errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb,
+ blk_t blk);
+extern int ext2fs_badblocks_list_test(ext2_badblocks_list bb,
+ blk_t blk);
+extern int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk);
+extern void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk);
+extern errcode_t
+ ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb,
+ ext2_badblocks_iterate *ret);
+extern int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter,
+ blk_t *blk);
+extern void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter);
+extern errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src,
+ ext2_badblocks_list *dest);
+extern int ext2fs_badblocks_equal(ext2_badblocks_list bb1,
+ ext2_badblocks_list bb2);
+extern int ext2fs_u32_list_count(ext2_u32_list bb);
+
+/* bb_compat */
+extern errcode_t badblocks_list_create(badblocks_list *ret, int size);
+extern errcode_t badblocks_list_add(badblocks_list bb, blk_t blk);
+extern int badblocks_list_test(badblocks_list bb, blk_t blk);
+extern errcode_t badblocks_list_iterate_begin(badblocks_list bb,
+ badblocks_iterate *ret);
+extern int badblocks_list_iterate(badblocks_iterate iter, blk_t *blk);
+extern void badblocks_list_iterate_end(badblocks_iterate iter);
+extern void badblocks_list_free(badblocks_list bb);
+
+/* bb_inode.c */
+extern errcode_t ext2fs_update_bb_inode(ext2_filsys fs,
+ ext2_badblocks_list bb_list);
+
+/* bitmaps.c */
+extern errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs);
+extern errcode_t ext2fs_write_block_bitmap (ext2_filsys fs);
+extern errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs);
+extern errcode_t ext2fs_read_block_bitmap(ext2_filsys fs);
+extern errcode_t ext2fs_allocate_generic_bitmap(__u32 start,
+ __u32 end,
+ __u32 real_end,
+ const char *descr,
+ ext2fs_generic_bitmap *ret);
+extern errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs,
+ const char *descr,
+ ext2fs_block_bitmap *ret);
+extern errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs,
+ const char *descr,
+ ext2fs_inode_bitmap *ret);
+extern errcode_t ext2fs_fudge_inode_bitmap_end(ext2fs_inode_bitmap bitmap,
+ ext2_ino_t end, ext2_ino_t *oend);
+extern errcode_t ext2fs_fudge_block_bitmap_end(ext2fs_block_bitmap bitmap,
+ blk_t end, blk_t *oend);
+extern void ext2fs_clear_inode_bitmap(ext2fs_inode_bitmap bitmap);
+extern void ext2fs_clear_block_bitmap(ext2fs_block_bitmap bitmap);
+extern errcode_t ext2fs_read_bitmaps(ext2_filsys fs);
+extern errcode_t ext2fs_write_bitmaps(ext2_filsys fs);
+
+/* block.c */
+extern errcode_t ext2fs_block_iterate(ext2_filsys fs,
+ ext2_ino_t ino,
+ int flags,
+ char *block_buf,
+ int (*func)(ext2_filsys fs,
+ blk_t *blocknr,
+ int blockcnt,
+ void *priv_data),
+ void *priv_data);
+errcode_t ext2fs_block_iterate2(ext2_filsys fs,
+ ext2_ino_t ino,
+ int flags,
+ char *block_buf,
+ int (*func)(ext2_filsys fs,
+ blk_t *blocknr,
+ e2_blkcnt_t blockcnt,
+ blk_t ref_blk,
+ int ref_offset,
+ void *priv_data),
+ void *priv_data);
+
+/* bmap.c */
+extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode *inode,
+ char *block_buf, int bmap_flags,
+ blk_t block, blk_t *phys_blk);
+
+
+#if 0
+/* bmove.c */
+extern errcode_t ext2fs_move_blocks(ext2_filsys fs,
+ ext2fs_block_bitmap reserve,
+ ext2fs_block_bitmap alloc_map,
+ int flags);
+#endif
+
+/* check_desc.c */
+extern errcode_t ext2fs_check_desc(ext2_filsys fs);
+
+/* closefs.c */
+extern errcode_t ext2fs_close(ext2_filsys fs);
+extern errcode_t ext2fs_flush(ext2_filsys fs);
+extern int ext2fs_bg_has_super(ext2_filsys fs, int group_block);
+extern int ext2fs_super_and_bgd_loc(ext2_filsys fs,
+ dgrp_t group,
+ blk_t *ret_super_blk,
+ blk_t *ret_old_desc_blk,
+ blk_t *ret_new_desc_blk,
+ int *ret_meta_bg);
+extern void ext2fs_update_dynamic_rev(ext2_filsys fs);
+
+/* cmp_bitmaps.c */
+extern errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1,
+ ext2fs_block_bitmap bm2);
+extern errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1,
+ ext2fs_inode_bitmap bm2);
+
+/* dblist.c */
+
+extern errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs);
+extern errcode_t ext2fs_init_dblist(ext2_filsys fs, ext2_dblist *ret_dblist);
+extern errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino,
+ blk_t blk, int blockcnt);
+extern void ext2fs_dblist_sort(ext2_dblist dblist,
+ int (*sortfunc)(const void *,
+ const void *));
+extern errcode_t ext2fs_dblist_iterate(ext2_dblist dblist,
+ int (*func)(ext2_filsys fs, struct ext2_db_entry *db_info,
+ void *priv_data),
+ void *priv_data);
+extern errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ext2_ino_t ino,
+ blk_t blk, int blockcnt);
+extern errcode_t ext2fs_copy_dblist(ext2_dblist src,
+ ext2_dblist *dest);
+extern int ext2fs_dblist_count(ext2_dblist dblist);
+
+/* dblist_dir.c */
+extern errcode_t
+ ext2fs_dblist_dir_iterate(ext2_dblist dblist,
+ int flags,
+ char *block_buf,
+ int (*func)(ext2_ino_t dir,
+ int entry,
+ struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data),
+ void *priv_data);
+
+/* dirblock.c */
+extern errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block,
+ void *buf);
+extern errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
+ void *buf, int flags);
+extern errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block,
+ void *buf);
+extern errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
+ void *buf, int flags);
+
+/* dirhash.c */
+extern errcode_t ext2fs_dirhash(int version, const char *name, int len,
+ const __u32 *seed,
+ ext2_dirhash_t *ret_hash,
+ ext2_dirhash_t *ret_minor_hash);
+
+
+/* dir_iterate.c */
+extern errcode_t ext2fs_dir_iterate(ext2_filsys fs,
+ ext2_ino_t dir,
+ int flags,
+ char *block_buf,
+ int (*func)(struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data),
+ void *priv_data);
+extern errcode_t ext2fs_dir_iterate2(ext2_filsys fs,
+ ext2_ino_t dir,
+ int flags,
+ char *block_buf,
+ int (*func)(ext2_ino_t dir,
+ int entry,
+ struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data),
+ void *priv_data);
+
+/* dupfs.c */
+extern errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest);
+
+/* expanddir.c */
+extern errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir);
+
+/* ext_attr.c */
+extern errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf);
+extern errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block,
+ void *buf);
+extern errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
+ char *block_buf,
+ int adjust, __u32 *newcount);
+
+/* fileio.c */
+extern errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode *inode,
+ int flags, ext2_file_t *ret);
+extern errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino,
+ int flags, ext2_file_t *ret);
+extern ext2_filsys ext2fs_file_get_fs(ext2_file_t file);
+extern errcode_t ext2fs_file_close(ext2_file_t file);
+extern errcode_t ext2fs_file_flush(ext2_file_t file);
+extern errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
+ unsigned int wanted, unsigned int *got);
+extern errcode_t ext2fs_file_write(ext2_file_t file, const void *buf,
+ unsigned int nbytes, unsigned int *written);
+extern errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset,
+ int whence, __u64 *ret_pos);
+extern errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset,
+ int whence, ext2_off_t *ret_pos);
+errcode_t ext2fs_file_get_lsize(ext2_file_t file, __u64 *ret_size);
+extern ext2_off_t ext2fs_file_get_size(ext2_file_t file);
+extern errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size);
+
+/* finddev.c */
+extern char *ext2fs_find_block_device(dev_t device);
+
+/* flushb.c */
+extern errcode_t ext2fs_sync_device(int fd, int flushb);
+
+/* freefs.c */
+extern void ext2fs_free(ext2_filsys fs);
+extern void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap);
+extern void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap);
+extern void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap);
+extern void ext2fs_free_dblist(ext2_dblist dblist);
+extern void ext2fs_badblocks_list_free(ext2_badblocks_list bb);
+extern void ext2fs_u32_list_free(ext2_u32_list bb);
+
+/* getsize.c */
+extern errcode_t ext2fs_get_device_size(const char *file, int blocksize,
+ blk_t *retblocks);
+
+/* getsectsize.c */
+errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize);
+
+/* imager.c */
+extern errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags);
+extern errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd, int flags);
+extern errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, int flags);
+extern errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd, int flags);
+extern errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags);
+extern errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags);
+
+/* ind_block.c */
+errcode_t ext2fs_read_ind_block(ext2_filsys fs, blk_t blk, void *buf);
+errcode_t ext2fs_write_ind_block(ext2_filsys fs, blk_t blk, void *buf);
+
+/* initialize.c */
+extern errcode_t ext2fs_initialize(const char *name, int flags,
+ struct ext2_super_block *param,
+ io_manager manager, ext2_filsys *ret_fs);
+
+/* icount.c */
+extern void ext2fs_free_icount(ext2_icount_t icount);
+extern errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags,
+ unsigned int size,
+ ext2_icount_t hint, ext2_icount_t *ret);
+extern errcode_t ext2fs_create_icount(ext2_filsys fs, int flags,
+ unsigned int size,
+ ext2_icount_t *ret);
+extern errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino,
+ __u16 *ret);
+extern errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino,
+ __u16 *ret);
+extern errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino,
+ __u16 *ret);
+extern errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,
+ __u16 count);
+extern ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount);
+errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *);
+
+/* inode.c */
+extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
+extern errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan,
+ ext2_ino_t *ino,
+ struct ext2_inode *inode,
+ int bufsize);
+extern errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
+ ext2_inode_scan *ret_scan);
+extern void ext2fs_close_inode_scan(ext2_inode_scan scan);
+extern errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
+ struct ext2_inode *inode);
+extern errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,
+ int group);
+extern void ext2fs_set_inode_callback
+ (ext2_inode_scan scan,
+ errcode_t (*done_group)(ext2_filsys fs,
+ dgrp_t group,
+ void * priv_data),
+ void *done_group_data);
+extern int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags,
+ int clear_flags);
+extern errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode * inode,
+ int bufsize);
+extern errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode * inode);
+extern errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode * inode,
+ int bufsize);
+extern errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode * inode);
+extern errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode * inode);
+extern errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks);
+extern errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino);
+
+/* inode_io.c */
+extern io_manager inode_io_manager;
+extern errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino,
+ char **name);
+extern errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode *inode,
+ char **name);
+
+/* ismounted.c */
+extern errcode_t ext2fs_check_if_mounted(const char *file, int *mount_flags);
+extern errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags,
+ char *mtpt, int mtlen);
+
+/* namei.c */
+extern errcode_t ext2fs_lookup(ext2_filsys fs, ext2_ino_t dir, const char *name,
+ int namelen, char *buf, ext2_ino_t *inode);
+extern errcode_t ext2fs_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
+ const char *name, ext2_ino_t *inode);
+errcode_t ext2fs_namei_follow(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
+ const char *name, ext2_ino_t *inode);
+extern errcode_t ext2fs_follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
+ ext2_ino_t inode, ext2_ino_t *res_inode);
+
+/* native.c */
+int ext2fs_native_flag(void);
+
+/* newdir.c */
+extern errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
+ ext2_ino_t parent_ino, char **block);
+
+/* mkdir.c */
+extern errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
+ const char *name);
+
+/* mkjournal.c */
+extern errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
+ __u32 size, int flags,
+ char **ret_jsb);
+extern errcode_t ext2fs_add_journal_device(ext2_filsys fs,
+ ext2_filsys journal_dev);
+extern errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size,
+ int flags);
+
+/* openfs.c */
+extern errcode_t ext2fs_open(const char *name, int flags, int superblock,
+ unsigned int block_size, io_manager manager,
+ ext2_filsys *ret_fs);
+extern errcode_t ext2fs_open2(const char *name, const char *io_options,
+ int flags, int superblock,
+ unsigned int block_size, io_manager manager,
+ ext2_filsys *ret_fs);
+extern blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block,
+ dgrp_t i);
+errcode_t ext2fs_get_data_io(ext2_filsys fs, io_channel *old_io);
+errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io);
+errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io);
+
+/* get_pathname.c */
+extern errcode_t ext2fs_get_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino,
+ char **name);
+
+/* link.c */
+errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name,
+ ext2_ino_t ino, int flags);
+errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir, const char *name,
+ ext2_ino_t ino, int flags);
+
+/* read_bb.c */
+extern errcode_t ext2fs_read_bb_inode(ext2_filsys fs,
+ ext2_badblocks_list *bb_list);
+
+/* read_bb_file.c */
+extern errcode_t ext2fs_read_bb_FILE2(ext2_filsys fs, FILE *f,
+ ext2_badblocks_list *bb_list,
+ void *priv_data,
+ void (*invalid)(ext2_filsys fs,
+ blk_t blk,
+ char *badstr,
+ void *priv_data));
+extern errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f,
+ ext2_badblocks_list *bb_list,
+ void (*invalid)(ext2_filsys fs,
+ blk_t blk));
+
+/* res_gdt.c */
+extern errcode_t ext2fs_create_resize_inode(ext2_filsys fs);
+
+/* rs_bitmap.c */
+extern errcode_t ext2fs_resize_generic_bitmap(__u32 new_end,
+ __u32 new_real_end,
+ ext2fs_generic_bitmap bmap);
+extern errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end,
+ ext2fs_inode_bitmap bmap);
+extern errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end,
+ ext2fs_block_bitmap bmap);
+extern errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src,
+ ext2fs_generic_bitmap *dest);
+
+/* swapfs.c */
+extern void ext2fs_swap_ext_attr(char *to, char *from, int bufsize,
+ int has_header);
+extern void ext2fs_swap_super(struct ext2_super_block * super);
+extern void ext2fs_swap_group_desc(struct ext2_group_desc *gdp);
+extern void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
+ struct ext2_inode_large *f, int hostorder,
+ int bufsize);
+extern void ext2fs_swap_inode(ext2_filsys fs,struct ext2_inode *t,
+ struct ext2_inode *f, int hostorder);
+
+/* valid_blk.c */
+extern int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode);
+
+/* version.c */
+extern int ext2fs_parse_version_string(const char *ver_string);
+extern int ext2fs_get_library_version(const char **ver_string,
+ const char **date_string);
+
+/* write_bb_file.c */
+extern errcode_t ext2fs_write_bb_FILE(ext2_badblocks_list bb_list,
+ unsigned int flags,
+ FILE *f);
+
+
+/* inline functions */
+extern errcode_t ext2fs_get_mem(unsigned long size, void *ptr);
+extern errcode_t ext2fs_free_mem(void *ptr);
+extern errcode_t ext2fs_resize_mem(unsigned long old_size,
+ unsigned long size, void *ptr);
+extern void ext2fs_mark_super_dirty(ext2_filsys fs);
+extern void ext2fs_mark_changed(ext2_filsys fs);
+extern int ext2fs_test_changed(ext2_filsys fs);
+extern void ext2fs_mark_valid(ext2_filsys fs);
+extern void ext2fs_unmark_valid(ext2_filsys fs);
+extern int ext2fs_test_valid(ext2_filsys fs);
+extern void ext2fs_mark_ib_dirty(ext2_filsys fs);
+extern void ext2fs_mark_bb_dirty(ext2_filsys fs);
+extern int ext2fs_test_ib_dirty(ext2_filsys fs);
+extern int ext2fs_test_bb_dirty(ext2_filsys fs);
+extern int ext2fs_group_of_blk(ext2_filsys fs, blk_t blk);
+extern int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino);
+extern blk_t ext2fs_inode_data_blocks(ext2_filsys fs,
+ struct ext2_inode *inode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _EXT2FS_EXT2FS_H */
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2fsP.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2fsP.h
new file mode 100644
index 0000000000..908b5d9a4e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2fsP.h
@@ -0,0 +1,89 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * ext2fsP.h --- private header file for ext2 library
+ *
+ * Copyright (C) 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include "ext2fs.h"
+
+/*
+ * Badblocks list
+ */
+struct ext2_struct_u32_list {
+ int magic;
+ int num;
+ int size;
+ __u32 *list;
+ int badblocks_flags;
+};
+
+struct ext2_struct_u32_iterate {
+ int magic;
+ ext2_u32_list bb;
+ int ptr;
+};
+
+
+/*
+ * Directory block iterator definition
+ */
+struct ext2_struct_dblist {
+ int magic;
+ ext2_filsys fs;
+ ext2_ino_t size;
+ ext2_ino_t count;
+ int sorted;
+ struct ext2_db_entry * list;
+};
+
+/*
+ * For directory iterators
+ */
+struct dir_context {
+ ext2_ino_t dir;
+ int flags;
+ char *buf;
+ int (*func)(ext2_ino_t dir,
+ int entry,
+ struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data);
+ void *priv_data;
+ errcode_t errcode;
+};
+
+/*
+ * Inode cache structure
+ */
+struct ext2_inode_cache {
+ void * buffer;
+ blk_t buffer_blk;
+ int cache_last;
+ int cache_size;
+ int refcount;
+ struct ext2_inode_cache_ent *cache;
+};
+
+struct ext2_inode_cache_ent {
+ ext2_ino_t ino;
+ struct ext2_inode inode;
+};
+
+/* Function prototypes */
+
+extern int ext2fs_process_dir_block(ext2_filsys fs,
+ blk_t *blocknr,
+ e2_blkcnt_t blockcnt,
+ blk_t ref_block,
+ int ref_offset,
+ void *priv_data);
+
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c
new file mode 100644
index 0000000000..da1cf5be5d
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c
@@ -0,0 +1,367 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * ext2fs.h --- ext2fs
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include "ext2fs.h"
+#include "bitops.h"
+#include <string.h>
+
+/*
+ * Allocate memory
+ */
+errcode_t ext2fs_get_mem(unsigned long size, void *ptr)
+{
+ void **pp = (void **)ptr;
+
+ *pp = malloc(size);
+ if (!*pp)
+ return EXT2_ET_NO_MEMORY;
+ return 0;
+}
+
+/*
+ * Free memory
+ */
+errcode_t ext2fs_free_mem(void *ptr)
+{
+ void **pp = (void **)ptr;
+
+ free(*pp);
+ *pp = 0;
+ return 0;
+}
+
+/*
+ * Resize memory
+ */
+errcode_t ext2fs_resize_mem(unsigned long EXT2FS_ATTR((unused)) old_size,
+ unsigned long size, void *ptr)
+{
+ void *p;
+
+ /* Use "memcpy" for pointer assignments here to avoid problems
+ * with C99 strict type aliasing rules. */
+ memcpy(&p, ptr, sizeof (p));
+ p = realloc(p, size);
+ if (!p)
+ return EXT2_ET_NO_MEMORY;
+ memcpy(ptr, &p, sizeof (p));
+ return 0;
+}
+
+/*
+ * Mark a filesystem superblock as dirty
+ */
+void ext2fs_mark_super_dirty(ext2_filsys fs)
+{
+ fs->flags |= EXT2_FLAG_DIRTY | EXT2_FLAG_CHANGED;
+}
+
+/*
+ * Mark a filesystem as changed
+ */
+void ext2fs_mark_changed(ext2_filsys fs)
+{
+ fs->flags |= EXT2_FLAG_CHANGED;
+}
+
+/*
+ * Check to see if a filesystem has changed
+ */
+int ext2fs_test_changed(ext2_filsys fs)
+{
+ return (fs->flags & EXT2_FLAG_CHANGED);
+}
+
+/*
+ * Mark a filesystem as valid
+ */
+void ext2fs_mark_valid(ext2_filsys fs)
+{
+ fs->flags |= EXT2_FLAG_VALID;
+}
+
+/*
+ * Mark a filesystem as NOT valid
+ */
+void ext2fs_unmark_valid(ext2_filsys fs)
+{
+ fs->flags &= ~EXT2_FLAG_VALID;
+}
+
+/*
+ * Check to see if a filesystem is valid
+ */
+int ext2fs_test_valid(ext2_filsys fs)
+{
+ return (fs->flags & EXT2_FLAG_VALID);
+}
+
+/*
+ * Mark the inode bitmap as dirty
+ */
+void ext2fs_mark_ib_dirty(ext2_filsys fs)
+{
+ fs->flags |= EXT2_FLAG_IB_DIRTY | EXT2_FLAG_CHANGED;
+}
+
+/*
+ * Mark the block bitmap as dirty
+ */
+void ext2fs_mark_bb_dirty(ext2_filsys fs)
+{
+ fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_CHANGED;
+}
+
+/*
+ * Check to see if a filesystem's inode bitmap is dirty
+ */
+int ext2fs_test_ib_dirty(ext2_filsys fs)
+{
+ return (fs->flags & EXT2_FLAG_IB_DIRTY);
+}
+
+/*
+ * Check to see if a filesystem's block bitmap is dirty
+ */
+int ext2fs_test_bb_dirty(ext2_filsys fs)
+{
+ return (fs->flags & EXT2_FLAG_BB_DIRTY);
+}
+
+/*
+ * Return the group # of a block
+ */
+int ext2fs_group_of_blk(ext2_filsys fs, blk_t blk)
+{
+ return (blk - fs->super->s_first_data_block) /
+ fs->super->s_blocks_per_group;
+}
+
+/*
+ * Return the group # of an inode number
+ */
+int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino)
+{
+ return (ino - 1) / fs->super->s_inodes_per_group;
+}
+
+blk_t ext2fs_inode_data_blocks(ext2_filsys fs,
+ struct ext2_inode *inode)
+{
+ return inode->i_blocks -
+ (inode->i_file_acl ? fs->blocksize >> 9 : 0);
+}
+
+
+
+
+
+
+
+
+
+__u16 ext2fs_swab16(__u16 val)
+{
+ return (val >> 8) | (val << 8);
+}
+
+__u32 ext2fs_swab32(__u32 val)
+{
+ return ((val>>24) | ((val>>8)&0xFF00) |
+ ((val<<8)&0xFF0000) | (val<<24));
+}
+
+int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
+ blk_t bitno);
+
+int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
+ blk_t bitno)
+{
+ if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
+ ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, bitno);
+ return 0;
+ }
+ return ext2fs_test_bit(bitno - bitmap->start, bitmap->bitmap);
+}
+
+int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap,
+ blk_t block)
+{
+ return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap)
+ bitmap,
+ block);
+}
+
+int ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
+ blk_t block)
+{
+ return ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap,
+ block);
+}
+
+int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap,
+ blk_t block)
+{
+ return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap,
+ block);
+}
+
+int ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
+ ext2_ino_t inode)
+{
+ return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap,
+ inode);
+}
+
+int ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
+ ext2_ino_t inode)
+{
+ return ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap,
+ inode);
+}
+
+int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
+ ext2_ino_t inode)
+{
+ return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap,
+ inode);
+}
+
+void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap,
+ blk_t block)
+{
+ ext2fs_set_bit(block - bitmap->start, bitmap->bitmap);
+}
+
+void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
+ blk_t block)
+{
+ ext2fs_clear_bit(block - bitmap->start, bitmap->bitmap);
+}
+
+int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap,
+ blk_t block)
+{
+ return ext2fs_test_bit(block - bitmap->start, bitmap->bitmap);
+}
+
+void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
+ ext2_ino_t inode)
+{
+ ext2fs_set_bit(inode - bitmap->start, bitmap->bitmap);
+}
+
+void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
+ ext2_ino_t inode)
+{
+ ext2fs_clear_bit(inode - bitmap->start, bitmap->bitmap);
+}
+
+int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
+ ext2_ino_t inode)
+{
+ return ext2fs_test_bit(inode - bitmap->start, bitmap->bitmap);
+}
+
+blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap)
+{
+ return bitmap->start;
+}
+
+ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap)
+{
+ return bitmap->start;
+}
+
+blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap)
+{
+ return bitmap->end;
+}
+
+ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap)
+{
+ return bitmap->end;
+}
+
+int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
+ blk_t block, int num)
+{
+ int i;
+
+ if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
+ ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
+ block, bitmap->description);
+ return 0;
+ }
+ for (i=0; i < num; i++) {
+ if (ext2fs_fast_test_block_bitmap(bitmap, block+i))
+ return 0;
+ }
+ return 1;
+}
+
+int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
+ blk_t block, int num)
+{
+ int i;
+
+ for (i=0; i < num; i++) {
+ if (ext2fs_fast_test_block_bitmap(bitmap, block+i))
+ return 0;
+ }
+ return 1;
+}
+
+void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
+ blk_t block, int num)
+{
+ int i;
+
+ if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
+ ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
+ bitmap->description);
+ return;
+ }
+ for (i=0; i < num; i++)
+ ext2fs_set_bit(block + i - bitmap->start, bitmap->bitmap);
+}
+
+void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
+ blk_t block, int num)
+{
+ int i;
+
+ for (i=0; i < num; i++)
+ ext2fs_set_bit(block + i - bitmap->start, bitmap->bitmap);
+}
+
+void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
+ blk_t block, int num)
+{
+ int i;
+
+ if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
+ ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
+ bitmap->description);
+ return;
+ }
+ for (i=0; i < num; i++)
+ ext2fs_clear_bit(block + i - bitmap->start, bitmap->bitmap);
+}
+
+void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
+ blk_t block, int num)
+{
+ int i;
+ for (i=0; i < num; i++)
+ ext2fs_clear_bit(block + i - bitmap->start, bitmap->bitmap);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext_attr.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext_attr.c
new file mode 100644
index 0000000000..7ee41f234d
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ext_attr.c
@@ -0,0 +1,101 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * ext_attr.c --- extended attribute blocks
+ *
+ * Copyright (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
+ *
+ * Copyright (C) 2002 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+
+#include "ext2_fs.h"
+#include "ext2_ext_attr.h"
+#include "ext2fs.h"
+
+errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf)
+{
+ errcode_t retval;
+
+ retval = io_channel_read_blk(fs->io, block, 1, buf);
+ if (retval)
+ return retval;
+#if BB_BIG_ENDIAN
+ if ((fs->flags & (EXT2_FLAG_SWAP_BYTES|
+ EXT2_FLAG_SWAP_BYTES_READ)) != 0)
+ ext2fs_swap_ext_attr(buf, buf, fs->blocksize, 1);
+#endif
+ return 0;
+}
+
+errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, void *inbuf)
+{
+ errcode_t retval;
+ char *write_buf;
+ char *buf = NULL;
+
+ if (BB_BIG_ENDIAN && ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+ (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))) {
+ retval = ext2fs_get_mem(fs->blocksize, &buf);
+ if (retval)
+ return retval;
+ write_buf = buf;
+ ext2fs_swap_ext_attr(buf, inbuf, fs->blocksize, 1);
+ } else
+ write_buf = (char *) inbuf;
+ retval = io_channel_write_blk(fs->io, block, 1, write_buf);
+ if (buf)
+ ext2fs_free_mem(&buf);
+ if (!retval)
+ ext2fs_mark_changed(fs);
+ return retval;
+}
+
+/*
+ * This function adjusts the reference count of the EA block.
+ */
+errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
+ char *block_buf, int adjust,
+ __u32 *newcount)
+{
+ errcode_t retval;
+ struct ext2_ext_attr_header *header;
+ char *buf = 0;
+
+ if ((blk >= fs->super->s_blocks_count) ||
+ (blk < fs->super->s_first_data_block))
+ return EXT2_ET_BAD_EA_BLOCK_NUM;
+
+ if (!block_buf) {
+ retval = ext2fs_get_mem(fs->blocksize, &buf);
+ if (retval)
+ return retval;
+ block_buf = buf;
+ }
+
+ retval = ext2fs_read_ext_attr(fs, blk, block_buf);
+ if (retval)
+ goto errout;
+
+ header = (struct ext2_ext_attr_header *) block_buf;
+ header->h_refcount += adjust;
+ if (newcount)
+ *newcount = header->h_refcount;
+
+ retval = ext2fs_write_ext_attr(fs, blk, block_buf);
+ if (retval)
+ goto errout;
+
+errout:
+ if (buf)
+ ext2fs_free_mem(&buf);
+ return retval;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/fileio.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/fileio.c
new file mode 100644
index 0000000000..5a5ad3ef89
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/fileio.c
@@ -0,0 +1,377 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * fileio.c --- Simple file I/O routines
+ *
+ * Copyright (C) 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+struct ext2_file {
+ errcode_t magic;
+ ext2_filsys fs;
+ ext2_ino_t ino;
+ struct ext2_inode inode;
+ int flags;
+ __u64 pos;
+ blk_t blockno;
+ blk_t physblock;
+ char *buf;
+};
+
+#define BMAP_BUFFER (file->buf + fs->blocksize)
+
+errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode *inode,
+ int flags, ext2_file_t *ret)
+{
+ ext2_file_t file;
+ errcode_t retval;
+
+ /*
+ * Don't let caller create or open a file for writing if the
+ * filesystem is read-only.
+ */
+ if ((flags & (EXT2_FILE_WRITE | EXT2_FILE_CREATE)) &&
+ !(fs->flags & EXT2_FLAG_RW))
+ return EXT2_ET_RO_FILSYS;
+
+ retval = ext2fs_get_mem(sizeof(struct ext2_file), &file);
+ if (retval)
+ return retval;
+
+ memset(file, 0, sizeof(struct ext2_file));
+ file->magic = EXT2_ET_MAGIC_EXT2_FILE;
+ file->fs = fs;
+ file->ino = ino;
+ file->flags = flags & EXT2_FILE_MASK;
+
+ if (inode) {
+ memcpy(&file->inode, inode, sizeof(struct ext2_inode));
+ } else {
+ retval = ext2fs_read_inode(fs, ino, &file->inode);
+ if (retval)
+ goto fail;
+ }
+
+ retval = ext2fs_get_mem(fs->blocksize * 3, &file->buf);
+ if (retval)
+ goto fail;
+
+ *ret = file;
+ return 0;
+
+fail:
+ ext2fs_free_mem(&file->buf);
+ ext2fs_free_mem(&file);
+ return retval;
+}
+
+errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino,
+ int flags, ext2_file_t *ret)
+{
+ return ext2fs_file_open2(fs, ino, NULL, flags, ret);
+}
+
+/*
+ * This function returns the filesystem handle of a file from the structure
+ */
+ext2_filsys ext2fs_file_get_fs(ext2_file_t file)
+{
+ if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
+ return 0;
+ return file->fs;
+}
+
+/*
+ * This function flushes the dirty block buffer out to disk if
+ * necessary.
+ */
+errcode_t ext2fs_file_flush(ext2_file_t file)
+{
+ errcode_t retval;
+ ext2_filsys fs;
+
+ EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
+ fs = file->fs;
+
+ if (!(file->flags & EXT2_FILE_BUF_VALID) ||
+ !(file->flags & EXT2_FILE_BUF_DIRTY))
+ return 0;
+
+ /*
+ * OK, the physical block hasn't been allocated yet.
+ * Allocate it.
+ */
+ if (!file->physblock) {
+ retval = ext2fs_bmap(fs, file->ino, &file->inode,
+ BMAP_BUFFER, file->ino ? BMAP_ALLOC : 0,
+ file->blockno, &file->physblock);
+ if (retval)
+ return retval;
+ }
+
+ retval = io_channel_write_blk(fs->io, file->physblock,
+ 1, file->buf);
+ if (retval)
+ return retval;
+
+ file->flags &= ~EXT2_FILE_BUF_DIRTY;
+
+ return retval;
+}
+
+/*
+ * This function synchronizes the file's block buffer and the current
+ * file position, possibly invalidating block buffer if necessary
+ */
+static errcode_t sync_buffer_position(ext2_file_t file)
+{
+ blk_t b;
+ errcode_t retval;
+
+ b = file->pos / file->fs->blocksize;
+ if (b != file->blockno) {
+ retval = ext2fs_file_flush(file);
+ if (retval)
+ return retval;
+ file->flags &= ~EXT2_FILE_BUF_VALID;
+ }
+ file->blockno = b;
+ return 0;
+}
+
+/*
+ * This function loads the file's block buffer with valid data from
+ * the disk as necessary.
+ *
+ * If dontfill is true, then skip initializing the buffer since we're
+ * going to be replacing its entire contents anyway. If set, then the
+ * function basically only sets file->physblock and EXT2_FILE_BUF_VALID
+ */
+#define DONTFILL 1
+static errcode_t load_buffer(ext2_file_t file, int dontfill)
+{
+ ext2_filsys fs = file->fs;
+ errcode_t retval;
+
+ if (!(file->flags & EXT2_FILE_BUF_VALID)) {
+ retval = ext2fs_bmap(fs, file->ino, &file->inode,
+ BMAP_BUFFER, 0, file->blockno,
+ &file->physblock);
+ if (retval)
+ return retval;
+ if (!dontfill) {
+ if (file->physblock) {
+ retval = io_channel_read_blk(fs->io,
+ file->physblock,
+ 1, file->buf);
+ if (retval)
+ return retval;
+ } else
+ memset(file->buf, 0, fs->blocksize);
+ }
+ file->flags |= EXT2_FILE_BUF_VALID;
+ }
+ return 0;
+}
+
+
+errcode_t ext2fs_file_close(ext2_file_t file)
+{
+ errcode_t retval;
+
+ EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
+
+ retval = ext2fs_file_flush(file);
+
+ ext2fs_free_mem(&file->buf);
+ ext2fs_free_mem(&file);
+
+ return retval;
+}
+
+
+errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
+ unsigned int wanted, unsigned int *got)
+{
+ ext2_filsys fs;
+ errcode_t retval = 0;
+ unsigned int start, c, count = 0;
+ __u64 left;
+ char *ptr = (char *) buf;
+
+ EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
+ fs = file->fs;
+
+ while ((file->pos < EXT2_I_SIZE(&file->inode)) && (wanted > 0)) {
+ retval = sync_buffer_position(file);
+ if (retval)
+ goto fail;
+ retval = load_buffer(file, 0);
+ if (retval)
+ goto fail;
+
+ start = file->pos % fs->blocksize;
+ c = fs->blocksize - start;
+ if (c > wanted)
+ c = wanted;
+ left = EXT2_I_SIZE(&file->inode) - file->pos;
+ if (c > left)
+ c = left;
+
+ memcpy(ptr, file->buf+start, c);
+ file->pos += c;
+ ptr += c;
+ count += c;
+ wanted -= c;
+ }
+
+fail:
+ if (got)
+ *got = count;
+ return retval;
+}
+
+
+errcode_t ext2fs_file_write(ext2_file_t file, const void *buf,
+ unsigned int nbytes, unsigned int *written)
+{
+ ext2_filsys fs;
+ errcode_t retval = 0;
+ unsigned int start, c, count = 0;
+ const char *ptr = (const char *) buf;
+
+ EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
+ fs = file->fs;
+
+ if (!(file->flags & EXT2_FILE_WRITE))
+ return EXT2_ET_FILE_RO;
+
+ while (nbytes > 0) {
+ retval = sync_buffer_position(file);
+ if (retval)
+ goto fail;
+
+ start = file->pos % fs->blocksize;
+ c = fs->blocksize - start;
+ if (c > nbytes)
+ c = nbytes;
+
+ /*
+ * We only need to do a read-modify-update cycle if
+ * we're doing a partial write.
+ */
+ retval = load_buffer(file, (c == fs->blocksize));
+ if (retval)
+ goto fail;
+
+ file->flags |= EXT2_FILE_BUF_DIRTY;
+ memcpy(file->buf+start, ptr, c);
+ file->pos += c;
+ ptr += c;
+ count += c;
+ nbytes -= c;
+ }
+
+fail:
+ if (written)
+ *written = count;
+ return retval;
+}
+
+errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset,
+ int whence, __u64 *ret_pos)
+{
+ EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
+
+ if (whence == EXT2_SEEK_SET)
+ file->pos = offset;
+ else if (whence == EXT2_SEEK_CUR)
+ file->pos += offset;
+ else if (whence == EXT2_SEEK_END)
+ file->pos = EXT2_I_SIZE(&file->inode) + offset;
+ else
+ return EXT2_ET_INVALID_ARGUMENT;
+
+ if (ret_pos)
+ *ret_pos = file->pos;
+
+ return 0;
+}
+
+errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset,
+ int whence, ext2_off_t *ret_pos)
+{
+ __u64 loffset, ret_loffset;
+ errcode_t retval;
+
+ loffset = offset;
+ retval = ext2fs_file_llseek(file, loffset, whence, &ret_loffset);
+ if (ret_pos)
+ *ret_pos = (ext2_off_t) ret_loffset;
+ return retval;
+}
+
+
+/*
+ * This function returns the size of the file, according to the inode
+ */
+errcode_t ext2fs_file_get_lsize(ext2_file_t file, __u64 *ret_size)
+{
+ if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
+ return EXT2_ET_MAGIC_EXT2_FILE;
+ *ret_size = EXT2_I_SIZE(&file->inode);
+ return 0;
+}
+
+/*
+ * This function returns the size of the file, according to the inode
+ */
+ext2_off_t ext2fs_file_get_size(ext2_file_t file)
+{
+ __u64 size;
+
+ if (ext2fs_file_get_lsize(file, &size))
+ return 0;
+ if ((size >> 32) != 0)
+ return 0;
+ return size;
+}
+
+/*
+ * This function sets the size of the file, truncating it if necessary
+ *
+ * XXX still need to call truncate
+ */
+errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size)
+{
+ errcode_t retval;
+ EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
+
+ file->inode.i_size = size;
+ file->inode.i_size_high = 0;
+ if (file->ino) {
+ retval = ext2fs_write_inode(file->fs, file->ino, &file->inode);
+ if (retval)
+ return retval;
+ }
+
+ /*
+ * XXX truncate inode if necessary
+ */
+
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/finddev.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/finddev.c
new file mode 100644
index 0000000000..5e2cce940e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/finddev.c
@@ -0,0 +1,199 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * finddev.c -- this routine attempts to find a particular device in
+ * /dev
+ *
+ * Copyright (C) 2000 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include <dirent.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_SYS_MKDEV_H
+#include <sys/mkdev.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+struct dir_list {
+ char *name;
+ struct dir_list *next;
+};
+
+/*
+ * This function adds an entry to the directory list
+ */
+static void add_to_dirlist(const char *name, struct dir_list **list)
+{
+ struct dir_list *dp;
+
+ dp = xmalloc(sizeof(struct dir_list));
+ dp->name = xmalloc(strlen(name)+1);
+ strcpy(dp->name, name);
+ dp->next = *list;
+ *list = dp;
+}
+
+/*
+ * This function frees a directory list
+ */
+static void free_dirlist(struct dir_list **list)
+{
+ struct dir_list *dp, *next;
+
+ for (dp = *list; dp; dp = next) {
+ next = dp->next;
+ free(dp->name);
+ free(dp);
+ }
+ *list = 0;
+}
+
+static int scan_dir(char *dir_name, dev_t device, struct dir_list **list,
+ char **ret_path)
+{
+ DIR *dir;
+ struct dirent *dp;
+ char path[1024], *cp;
+ int dirlen;
+ struct stat st;
+
+ dirlen = strlen(dir_name);
+ if ((dir = opendir(dir_name)) == NULL)
+ return errno;
+ dp = readdir(dir);
+ while (dp) {
+ if (dirlen + strlen(dp->d_name) + 2 >= sizeof(path))
+ goto skip_to_next;
+ if (dp->d_name[0] == '.' &&
+ ((dp->d_name[1] == 0) ||
+ ((dp->d_name[1] == '.') && (dp->d_name[2] == 0))))
+ goto skip_to_next;
+ sprintf(path, "%s/%s", dir_name, dp->d_name);
+ if (stat(path, &st) < 0)
+ goto skip_to_next;
+ if (S_ISDIR(st.st_mode))
+ add_to_dirlist(path, list);
+ if (S_ISBLK(st.st_mode) && st.st_rdev == device) {
+ cp = xmalloc(strlen(path)+1);
+ strcpy(cp, path);
+ *ret_path = cp;
+ goto success;
+ }
+ skip_to_next:
+ dp = readdir(dir);
+ }
+success:
+ closedir(dir);
+ return 0;
+}
+
+/*
+ * This function finds the pathname to a block device with a given
+ * device number. It returns a pointer to allocated memory to the
+ * pathname on success, and NULL on failure.
+ */
+char *ext2fs_find_block_device(dev_t device)
+{
+ struct dir_list *list = 0, *new_list = 0;
+ struct dir_list *current;
+ char *ret_path = 0;
+
+ /*
+ * Add the starting directories to search...
+ */
+ add_to_dirlist("/devices", &list);
+ add_to_dirlist("/devfs", &list);
+ add_to_dirlist("/dev", &list);
+
+ while (list) {
+ current = list;
+ list = list->next;
+#ifdef DEBUG
+ printf("Scanning directory %s\n", current->name);
+#endif
+ scan_dir(current->name, device, &new_list, &ret_path);
+ free(current->name);
+ free(current);
+ if (ret_path)
+ break;
+ /*
+ * If we're done checking at this level, descend to
+ * the next level of subdirectories. (breadth-first)
+ */
+ if (list == 0) {
+ list = new_list;
+ new_list = 0;
+ }
+ }
+ free_dirlist(&list);
+ free_dirlist(&new_list);
+ return ret_path;
+}
+
+
+#ifdef DEBUG
+int main(int argc, char** argv)
+{
+ char *devname, *tmp;
+ int major, minor;
+ dev_t device;
+ const char *errmsg = "Cannot parse %s: %s\n";
+
+ if ((argc != 2) && (argc != 3)) {
+ fprintf(stderr, "Usage: %s device_number\n", argv[0]);
+ fprintf(stderr, "\t: %s major minor\n", argv[0]);
+ exit(1);
+ }
+ if (argc == 2) {
+ device = strtoul(argv[1], &tmp, 0);
+ if (*tmp) {
+ fprintf(stderr, errmsg, "device number", argv[1]);
+ exit(1);
+ }
+ } else {
+ major = strtoul(argv[1], &tmp, 0);
+ if (*tmp) {
+ fprintf(stderr, errmsg, "major number", argv[1]);
+ exit(1);
+ }
+ minor = strtoul(argv[2], &tmp, 0);
+ if (*tmp) {
+ fprintf(stderr, errmsg, "minor number", argv[2]);
+ exit(1);
+ }
+ device = makedev(major, minor);
+ printf("Looking for device 0x%04x (%d:%d)\n", device,
+ major, minor);
+ }
+ devname = ext2fs_find_block_device(device);
+ if (devname) {
+ printf("Found device! %s\n", devname);
+ free(devname);
+ } else {
+ printf("Cannot find device.\n");
+ }
+ return 0;
+}
+
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/flushb.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/flushb.c
new file mode 100644
index 0000000000..e42982653f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/flushb.c
@@ -0,0 +1,83 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * flushb.c --- Hides system-dependent information for both syncing a
+ * device to disk and to flush any buffers from disk cache.
+ *
+ * Copyright (C) 2000 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#if HAVE_SYS_MOUNT_H
+#include <sys/param.h>
+#include <sys/mount.h> /* This may define BLKFLSBUF */
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * For Linux, define BLKFLSBUF and FDFLUSH if necessary, since
+ * not all portable header file does so for us. This really should be
+ * fixed in the glibc header files. (Recent glibcs appear to define
+ * BLKFLSBUF in sys/mount.h, but FDFLUSH still doesn't seem to be
+ * defined anywhere portable.) Until then....
+ */
+#ifdef __linux__
+#ifndef BLKFLSBUF
+#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
+#endif
+#ifndef FDFLUSH
+#define FDFLUSH _IO(2,0x4b) /* flush floppy disk */
+#endif
+#endif
+
+/*
+ * This function will sync a device/file, and optionally attempt to
+ * flush the buffer cache. The latter is basically only useful for
+ * system benchmarks and for torturing systems in burn-in tests. :)
+ */
+errcode_t ext2fs_sync_device(int fd, int flushb)
+{
+ /*
+ * We always sync the device in case we're running on old
+ * kernels for which we can lose data if we don't. (There
+ * still is a race condition for those kernels, but this
+ * reduces it greatly.)
+ */
+ if (fsync (fd) == -1)
+ return errno;
+
+ if (flushb) {
+
+#ifdef BLKFLSBUF
+ if (ioctl (fd, BLKFLSBUF, 0) == 0)
+ return 0;
+#else
+#ifdef __GNUC__
+# warning BLKFLSBUF not defined
+#endif /* __GNUC__ */
+#endif
+#ifdef FDFLUSH
+ ioctl (fd, FDFLUSH, 0); /* In case this is a floppy */
+#else
+#ifdef __GNUC__
+# warning FDFLUSH not defined
+#endif /* __GNUC__ */
+#endif
+ }
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/freefs.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/freefs.c
new file mode 100644
index 0000000000..65c4ee7948
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/freefs.c
@@ -0,0 +1,128 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * freefs.c --- free an ext2 filesystem
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+
+static void ext2fs_free_inode_cache(struct ext2_inode_cache *icache);
+
+void ext2fs_free(ext2_filsys fs)
+{
+ if (!fs || (fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS))
+ return;
+ if (fs->image_io != fs->io) {
+ if (fs->image_io)
+ io_channel_close(fs->image_io);
+ }
+ if (fs->io) {
+ io_channel_close(fs->io);
+ }
+ ext2fs_free_mem(&fs->device_name);
+ ext2fs_free_mem(&fs->super);
+ ext2fs_free_mem(&fs->orig_super);
+ ext2fs_free_mem(&fs->group_desc);
+ ext2fs_free_block_bitmap(fs->block_map);
+ ext2fs_free_inode_bitmap(fs->inode_map);
+
+ ext2fs_badblocks_list_free(fs->badblocks);
+ fs->badblocks = 0;
+
+ ext2fs_free_dblist(fs->dblist);
+
+ if (fs->icache)
+ ext2fs_free_inode_cache(fs->icache);
+
+ fs->magic = 0;
+
+ ext2fs_free_mem(&fs);
+}
+
+void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap)
+{
+ if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_GENERIC_BITMAP))
+ return;
+
+ bitmap->magic = 0;
+ ext2fs_free_mem(&bitmap->description);
+ ext2fs_free_mem(&bitmap->bitmap);
+ ext2fs_free_mem(&bitmap);
+}
+
+void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap)
+{
+ if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_INODE_BITMAP))
+ return;
+
+ bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
+ ext2fs_free_generic_bitmap(bitmap);
+}
+
+void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap)
+{
+ if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_BLOCK_BITMAP))
+ return;
+
+ bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
+ ext2fs_free_generic_bitmap(bitmap);
+}
+
+/*
+ * Free the inode cache structure
+ */
+static void ext2fs_free_inode_cache(struct ext2_inode_cache *icache)
+{
+ if (--icache->refcount)
+ return;
+ ext2fs_free_mem(&icache->buffer);
+ ext2fs_free_mem(&icache->cache);
+ icache->buffer_blk = 0;
+ ext2fs_free_mem(&icache);
+}
+
+/*
+ * This procedure frees a badblocks list.
+ */
+void ext2fs_u32_list_free(ext2_u32_list bb)
+{
+ if (!bb || bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
+ return;
+
+ ext2fs_free_mem(&bb->list);
+ ext2fs_free_mem(&bb);
+}
+
+void ext2fs_badblocks_list_free(ext2_badblocks_list bb)
+{
+ ext2fs_u32_list_free((ext2_u32_list) bb);
+}
+
+
+/*
+ * Free a directory block list
+ */
+void ext2fs_free_dblist(ext2_dblist dblist)
+{
+ if (!dblist || (dblist->magic != EXT2_ET_MAGIC_DBLIST))
+ return;
+
+ ext2fs_free_mem(&dblist->list);
+ if (dblist->fs && dblist->fs->dblist == dblist)
+ dblist->fs->dblist = 0;
+ dblist->magic = 0;
+ ext2fs_free_mem(&dblist);
+}
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/gen_bitmap.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/gen_bitmap.c
new file mode 100644
index 0000000000..d0869c9191
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/gen_bitmap.c
@@ -0,0 +1,49 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * gen_bitmap.c --- Generic bitmap routines that used to be inlined.
+ *
+ * Copyright (C) 2001 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
+ __u32 bitno)
+{
+ if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
+ ext2fs_warn_bitmap2(bitmap, EXT2FS_MARK_ERROR, bitno);
+ return 0;
+ }
+ return ext2fs_set_bit(bitno - bitmap->start, bitmap->bitmap);
+}
+
+int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap,
+ blk_t bitno)
+{
+ if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
+ ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR, bitno);
+ return 0;
+ }
+ return ext2fs_clear_bit(bitno - bitmap->start, bitmap->bitmap);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/get_pathname.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/get_pathname.c
new file mode 100644
index 0000000000..a98b2b9e5a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/get_pathname.c
@@ -0,0 +1,157 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * get_pathname.c --- do directry/inode -> name translation
+ *
+ * Copyright (C) 1993, 1994, 1995 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ *
+ * ext2fs_get_pathname(fs, dir, ino, name)
+ *
+ * This function translates takes two inode numbers into a
+ * string, placing the result in <name>. <dir> is the containing
+ * directory inode, and <ino> is the inode number itself. If
+ * <ino> is zero, then ext2fs_get_pathname will return pathname
+ * of the the directory <dir>.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+struct get_pathname_struct {
+ ext2_ino_t search_ino;
+ ext2_ino_t parent;
+ char *name;
+ errcode_t errcode;
+};
+
+#ifdef __TURBOC__
+# pragma argsused
+#endif
+static int get_pathname_proc(struct ext2_dir_entry *dirent,
+ int offset EXT2FS_ATTR((unused)),
+ int blocksize EXT2FS_ATTR((unused)),
+ char *buf EXT2FS_ATTR((unused)),
+ void *priv_data)
+{
+ struct get_pathname_struct *gp;
+ errcode_t retval;
+
+ gp = (struct get_pathname_struct *) priv_data;
+
+ if (((dirent->name_len & 0xFF) == 2) &&
+ !strncmp(dirent->name, "..", 2))
+ gp->parent = dirent->inode;
+ if (dirent->inode == gp->search_ino) {
+ retval = ext2fs_get_mem((dirent->name_len & 0xFF) + 1,
+ &gp->name);
+ if (retval) {
+ gp->errcode = retval;
+ return DIRENT_ABORT;
+ }
+ strncpy(gp->name, dirent->name, (dirent->name_len & 0xFF));
+ gp->name[dirent->name_len & 0xFF] = '\0';
+ return DIRENT_ABORT;
+ }
+ return 0;
+}
+
+static errcode_t ext2fs_get_pathname_int(ext2_filsys fs, ext2_ino_t dir,
+ ext2_ino_t ino, int maxdepth,
+ char *buf, char **name)
+{
+ struct get_pathname_struct gp;
+ char *parent_name, *ret;
+ errcode_t retval;
+
+ if (dir == ino) {
+ retval = ext2fs_get_mem(2, name);
+ if (retval)
+ return retval;
+ strcpy(*name, (dir == EXT2_ROOT_INO) ? "/" : ".");
+ return 0;
+ }
+
+ if (!dir || (maxdepth < 0)) {
+ retval = ext2fs_get_mem(4, name);
+ if (retval)
+ return retval;
+ strcpy(*name, "...");
+ return 0;
+ }
+
+ gp.search_ino = ino;
+ gp.parent = 0;
+ gp.name = 0;
+ gp.errcode = 0;
+
+ retval = ext2fs_dir_iterate(fs, dir, 0, buf, get_pathname_proc, &gp);
+ if (retval)
+ goto cleanup;
+ if (gp.errcode) {
+ retval = gp.errcode;
+ goto cleanup;
+ }
+
+ retval = ext2fs_get_pathname_int(fs, gp.parent, dir, maxdepth-1,
+ buf, &parent_name);
+ if (retval)
+ goto cleanup;
+ if (!ino) {
+ *name = parent_name;
+ return 0;
+ }
+
+ if (gp.name)
+ retval = ext2fs_get_mem(strlen(parent_name)+strlen(gp.name)+2,
+ &ret);
+ else
+ retval = ext2fs_get_mem(strlen(parent_name)+5, &ret);
+ if (retval)
+ goto cleanup;
+
+ ret[0] = 0;
+ if (parent_name[1])
+ strcat(ret, parent_name);
+ strcat(ret, "/");
+ if (gp.name)
+ strcat(ret, gp.name);
+ else
+ strcat(ret, "???");
+ *name = ret;
+ ext2fs_free_mem(&parent_name);
+ retval = 0;
+
+cleanup:
+ ext2fs_free_mem(&gp.name);
+ return retval;
+}
+
+errcode_t ext2fs_get_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino,
+ char **name)
+{
+ char *buf;
+ errcode_t retval;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ retval = ext2fs_get_mem(fs->blocksize, &buf);
+ if (retval)
+ return retval;
+ if (dir == ino)
+ ino = 0;
+ retval = ext2fs_get_pathname_int(fs, dir, ino, 32, buf, name);
+ ext2fs_free_mem(&buf);
+ return retval;
+
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/getsectsize.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/getsectsize.c
new file mode 100644
index 0000000000..163ec65e5b
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/getsectsize.c
@@ -0,0 +1,58 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * getsectsize.c --- get the sector size of a device.
+ *
+ * Copyright (C) 1995, 1995 Theodore Ts'o.
+ * Copyright (C) 2003 VMware, Inc.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <fcntl.h>
+#ifdef HAVE_LINUX_FD_H
+#include <sys/ioctl.h>
+#include <linux/fd.h>
+#endif
+
+#if defined(__linux__) && defined(_IO) && !defined(BLKSSZGET)
+#define BLKSSZGET _IO(0x12,104)/* get block device sector size */
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * Returns the number of blocks in a partition
+ */
+errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize)
+{
+ int fd;
+
+#ifdef CONFIG_LFS
+ fd = open64(file, O_RDONLY);
+#else
+ fd = open(file, O_RDONLY);
+#endif
+ if (fd < 0)
+ return errno;
+
+#ifdef BLKSSZGET
+ if (ioctl(fd, BLKSSZGET, sectsize) >= 0) {
+ close(fd);
+ return 0;
+ }
+#endif
+ *sectsize = 0;
+ close(fd);
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/getsize.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/getsize.c
new file mode 100644
index 0000000000..63a0dcad9c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/getsize.c
@@ -0,0 +1,291 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * getsize.c --- get the size of a partition.
+ *
+ * Copyright (C) 1995, 1995 Theodore Ts'o.
+ * Copyright (C) 2003 VMware, Inc.
+ *
+ * Windows version of ext2fs_get_device_size by Chris Li, VMware.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <fcntl.h>
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_LINUX_FD_H
+#include <linux/fd.h>
+#endif
+#ifdef HAVE_SYS_DISKLABEL_H
+#include <sys/disklabel.h>
+#endif
+#ifdef HAVE_SYS_DISK_H
+#ifdef HAVE_SYS_QUEUE_H
+#include <sys/queue.h> /* for LIST_HEAD */
+#endif
+#include <sys/disk.h>
+#endif
+#ifdef __linux__
+#include <sys/utsname.h>
+#endif
+
+#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)
+#define BLKGETSIZE _IO(0x12,96) /* return device size */
+#endif
+
+#if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64)
+#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */
+#endif
+
+#ifdef APPLE_DARWIN
+#define BLKGETSIZE DKIOCGETBLOCKCOUNT32
+#endif /* APPLE_DARWIN */
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+#if defined(__CYGWIN__) || defined(WIN32)
+#include <windows.h>
+#include <winioctl.h>
+
+#if (_WIN32_WINNT >= 0x0500)
+#define HAVE_GET_FILE_SIZE_EX 1
+#endif
+
+errcode_t ext2fs_get_device_size(const char *file, int blocksize,
+ blk_t *retblocks)
+{
+ HANDLE dev;
+ PARTITION_INFORMATION pi;
+ DISK_GEOMETRY gi;
+ DWORD retbytes;
+#ifdef HAVE_GET_FILE_SIZE_EX
+ LARGE_INTEGER filesize;
+#else
+ DWORD filesize;
+#endif /* HAVE_GET_FILE_SIZE_EX */
+
+ dev = CreateFile(file, GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE ,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (dev == INVALID_HANDLE_VALUE)
+ return EBADF;
+ if (DeviceIoControl(dev, IOCTL_DISK_GET_PARTITION_INFO,
+ &pi, sizeof(PARTITION_INFORMATION),
+ &pi, sizeof(PARTITION_INFORMATION),
+ &retbytes, NULL)) {
+
+ *retblocks = pi.PartitionLength.QuadPart / blocksize;
+
+ } else if (DeviceIoControl(dev, IOCTL_DISK_GET_DRIVE_GEOMETRY,
+ &gi, sizeof(DISK_GEOMETRY),
+ &gi, sizeof(DISK_GEOMETRY),
+ &retbytes, NULL)) {
+
+ *retblocks = gi.BytesPerSector *
+ gi.SectorsPerTrack *
+ gi.TracksPerCylinder *
+ gi.Cylinders.QuadPart / blocksize;
+
+#ifdef HAVE_GET_FILE_SIZE_EX
+ } else if (GetFileSizeEx(dev, &filesize)) {
+ *retblocks = filesize.QuadPart / blocksize;
+ }
+#else
+ } else {
+ filesize = GetFileSize(dev, NULL);
+ if (INVALID_FILE_SIZE != filesize) {
+ *retblocks = filesize / blocksize;
+ }
+ }
+#endif /* HAVE_GET_FILE_SIZE_EX */
+
+ CloseHandle(dev);
+ return 0;
+}
+
+#else
+
+static int valid_offset (int fd, ext2_loff_t offset)
+{
+ char ch;
+
+ if (ext2fs_llseek (fd, offset, 0) < 0)
+ return 0;
+ if (read (fd, &ch, 1) < 1)
+ return 0;
+ return 1;
+}
+
+/*
+ * Returns the number of blocks in a partition
+ */
+errcode_t ext2fs_get_device_size(const char *file, int blocksize,
+ blk_t *retblocks)
+{
+ int fd;
+ int valid_blkgetsize64 = 1;
+#ifdef __linux__
+ struct utsname ut;
+#endif
+ unsigned long long size64;
+ unsigned long size;
+ ext2_loff_t high, low;
+#ifdef FDGETPRM
+ struct floppy_struct this_floppy;
+#endif
+#ifdef HAVE_SYS_DISKLABEL_H
+ int part;
+ struct disklabel lab;
+ struct partition *pp;
+ char ch;
+#endif /* HAVE_SYS_DISKLABEL_H */
+
+#ifdef CONFIG_LFS
+ fd = open64(file, O_RDONLY);
+#else
+ fd = open(file, O_RDONLY);
+#endif
+ if (fd < 0)
+ return errno;
+
+#ifdef DKIOCGETBLOCKCOUNT /* For Apple Darwin */
+ if (ioctl(fd, DKIOCGETBLOCKCOUNT, &size64) >= 0) {
+ if ((sizeof(*retblocks) < sizeof(unsigned long long))
+ && ((size64 / (blocksize / 512)) > 0xFFFFFFFF))
+ return EFBIG;
+ close(fd);
+ *retblocks = size64 / (blocksize / 512);
+ return 0;
+ }
+#endif
+
+#ifdef BLKGETSIZE64
+#ifdef __linux__
+ if ((uname(&ut) == 0) &&
+ ((ut.release[0] == '2') && (ut.release[1] == '.') &&
+ (ut.release[2] < '6') && (ut.release[3] == '.')))
+ valid_blkgetsize64 = 0;
+#endif
+ if (valid_blkgetsize64 &&
+ ioctl(fd, BLKGETSIZE64, &size64) >= 0) {
+ if ((sizeof(*retblocks) < sizeof(unsigned long long))
+ && ((size64 / blocksize) > 0xFFFFFFFF))
+ return EFBIG;
+ close(fd);
+ *retblocks = size64 / blocksize;
+ return 0;
+ }
+#endif
+
+#ifdef BLKGETSIZE
+ if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
+ close(fd);
+ *retblocks = size / (blocksize / 512);
+ return 0;
+ }
+#endif
+
+#ifdef FDGETPRM
+ if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) {
+ close(fd);
+ *retblocks = this_floppy.size / (blocksize / 512);
+ return 0;
+ }
+#endif
+
+#ifdef HAVE_SYS_DISKLABEL_H
+#if defined(DIOCGMEDIASIZE)
+ {
+ off_t ms;
+ u_int bs;
+ if (ioctl(fd, DIOCGMEDIASIZE, &ms) >= 0) {
+ *retblocks = ms / blocksize;
+ return 0;
+ }
+ }
+#elif defined(DIOCGDINFO)
+ /* old disklabel interface */
+ part = strlen(file) - 1;
+ if (part >= 0) {
+ ch = file[part];
+ if (isdigit(ch))
+ part = 0;
+ else if (ch >= 'a' && ch <= 'h')
+ part = ch - 'a';
+ else
+ part = -1;
+ }
+ if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) {
+ pp = &lab.d_partitions[part];
+ if (pp->p_size) {
+ close(fd);
+ *retblocks = pp->p_size / (blocksize / 512);
+ return 0;
+ }
+ }
+#endif /* defined(DIOCG*) */
+#endif /* HAVE_SYS_DISKLABEL_H */
+
+ /*
+ * OK, we couldn't figure it out by using a specialized ioctl,
+ * which is generally the best way. So do binary search to
+ * find the size of the partition.
+ */
+ low = 0;
+ for (high = 1024; valid_offset (fd, high); high *= 2)
+ low = high;
+ while (low < high - 1)
+ {
+ const ext2_loff_t mid = (low + high) / 2;
+
+ if (valid_offset (fd, mid))
+ low = mid;
+ else
+ high = mid;
+ }
+ valid_offset (fd, 0);
+ close(fd);
+ size64 = low + 1;
+ if ((sizeof(*retblocks) < sizeof(unsigned long long))
+ && ((size64 / blocksize) > 0xFFFFFFFF))
+ return EFBIG;
+ *retblocks = size64 / blocksize;
+ return 0;
+}
+
+#endif /* WIN32 */
+
+#ifdef DEBUG
+int main(int argc, char **argv)
+{
+ blk_t blocks;
+ int retval;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s device\n", argv[0]);
+ exit(1);
+ }
+
+ retval = ext2fs_get_device_size(argv[1], 1024, &blocks);
+ if (retval) {
+ com_err(argv[0], retval,
+ "while calling ext2fs_get_device_size");
+ exit(1);
+ }
+ printf("Device %s has %d 1k blocks.\n", argv[1], blocks);
+ exit(0);
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/icount.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/icount.c
new file mode 100644
index 0000000000..7ab5f51f48
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/icount.c
@@ -0,0 +1,467 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * icount.c --- an efficient inode count abstraction
+ *
+ * Copyright (C) 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * The data storage strategy used by icount relies on the observation
+ * that most inode counts are either zero (for non-allocated inodes),
+ * one (for most files), and only a few that are two or more
+ * (directories and files that are linked to more than one directory).
+ *
+ * Also, e2fsck tends to load the icount data sequentially.
+ *
+ * So, we use an inode bitmap to indicate which inodes have a count of
+ * one, and then use a sorted list to store the counts for inodes
+ * which are greater than one.
+ *
+ * We also use an optional bitmap to indicate which inodes are already
+ * in the sorted list, to speed up the use of this abstraction by
+ * e2fsck's pass 2. Pass 2 increments inode counts as it finds them,
+ * so this extra bitmap avoids searching the sorted list to see if a
+ * particular inode is on the sorted list already.
+ */
+
+struct ext2_icount_el {
+ ext2_ino_t ino;
+ __u16 count;
+};
+
+struct ext2_icount {
+ errcode_t magic;
+ ext2fs_inode_bitmap single;
+ ext2fs_inode_bitmap multiple;
+ ext2_ino_t count;
+ ext2_ino_t size;
+ ext2_ino_t num_inodes;
+ ext2_ino_t cursor;
+ struct ext2_icount_el *list;
+};
+
+void ext2fs_free_icount(ext2_icount_t icount)
+{
+ if (!icount)
+ return;
+
+ icount->magic = 0;
+ ext2fs_free_mem(&icount->list);
+ ext2fs_free_inode_bitmap(icount->single);
+ ext2fs_free_inode_bitmap(icount->multiple);
+ ext2fs_free_mem(&icount);
+}
+
+errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, unsigned int size,
+ ext2_icount_t hint, ext2_icount_t *ret)
+{
+ ext2_icount_t icount;
+ errcode_t retval;
+ size_t bytes;
+ ext2_ino_t i;
+
+ if (hint) {
+ EXT2_CHECK_MAGIC(hint, EXT2_ET_MAGIC_ICOUNT);
+ if (hint->size > size)
+ size = (size_t) hint->size;
+ }
+
+ retval = ext2fs_get_mem(sizeof(struct ext2_icount), &icount);
+ if (retval)
+ return retval;
+ memset(icount, 0, sizeof(struct ext2_icount));
+
+ retval = ext2fs_allocate_inode_bitmap(fs, 0,
+ &icount->single);
+ if (retval)
+ goto errout;
+
+ if (flags & EXT2_ICOUNT_OPT_INCREMENT) {
+ retval = ext2fs_allocate_inode_bitmap(fs, 0,
+ &icount->multiple);
+ if (retval)
+ goto errout;
+ } else
+ icount->multiple = 0;
+
+ if (size) {
+ icount->size = size;
+ } else {
+ /*
+ * Figure out how many special case inode counts we will
+ * have. We know we will need one for each directory;
+ * we also need to reserve some extra room for file links
+ */
+ retval = ext2fs_get_num_dirs(fs, &icount->size);
+ if (retval)
+ goto errout;
+ icount->size += fs->super->s_inodes_count / 50;
+ }
+
+ bytes = (size_t) (icount->size * sizeof(struct ext2_icount_el));
+ retval = ext2fs_get_mem(bytes, &icount->list);
+ if (retval)
+ goto errout;
+ memset(icount->list, 0, bytes);
+
+ icount->magic = EXT2_ET_MAGIC_ICOUNT;
+ icount->count = 0;
+ icount->cursor = 0;
+ icount->num_inodes = fs->super->s_inodes_count;
+
+ /*
+ * Populate the sorted list with those entries which were
+ * found in the hint icount (since those are ones which will
+ * likely need to be in the sorted list this time around).
+ */
+ if (hint) {
+ for (i=0; i < hint->count; i++)
+ icount->list[i].ino = hint->list[i].ino;
+ icount->count = hint->count;
+ }
+
+ *ret = icount;
+ return 0;
+
+errout:
+ ext2fs_free_icount(icount);
+ return retval;
+}
+
+errcode_t ext2fs_create_icount(ext2_filsys fs, int flags,
+ unsigned int size,
+ ext2_icount_t *ret)
+{
+ return ext2fs_create_icount2(fs, flags, size, 0, ret);
+}
+
+/*
+ * insert_icount_el() --- Insert a new entry into the sorted list at a
+ * specified position.
+ */
+static struct ext2_icount_el *insert_icount_el(ext2_icount_t icount,
+ ext2_ino_t ino, int pos)
+{
+ struct ext2_icount_el *el;
+ errcode_t retval;
+ ext2_ino_t new_size = 0;
+ int num;
+
+ if (icount->count >= icount->size) {
+ if (icount->count) {
+ new_size = icount->list[(unsigned)icount->count-1].ino;
+ new_size = (ext2_ino_t) (icount->count *
+ ((float) icount->num_inodes / new_size));
+ }
+ if (new_size < (icount->size + 100))
+ new_size = icount->size + 100;
+ retval = ext2fs_resize_mem((size_t) icount->size *
+ sizeof(struct ext2_icount_el),
+ (size_t) new_size *
+ sizeof(struct ext2_icount_el),
+ &icount->list);
+ if (retval)
+ return 0;
+ icount->size = new_size;
+ }
+ num = (int) icount->count - pos;
+ if (num < 0)
+ return 0; /* should never happen */
+ if (num) {
+ memmove(&icount->list[pos+1], &icount->list[pos],
+ sizeof(struct ext2_icount_el) * num);
+ }
+ icount->count++;
+ el = &icount->list[pos];
+ el->count = 0;
+ el->ino = ino;
+ return el;
+}
+
+/*
+ * get_icount_el() --- given an inode number, try to find icount
+ * information in the sorted list. If the create flag is set,
+ * and we can't find an entry, create one in the sorted list.
+ */
+static struct ext2_icount_el *get_icount_el(ext2_icount_t icount,
+ ext2_ino_t ino, int create)
+{
+ float range;
+ int low, high, mid;
+ ext2_ino_t lowval, highval;
+
+ if (!icount || !icount->list)
+ return 0;
+
+ if (create && ((icount->count == 0) ||
+ (ino > icount->list[(unsigned)icount->count-1].ino))) {
+ return insert_icount_el(icount, ino, (unsigned) icount->count);
+ }
+ if (icount->count == 0)
+ return 0;
+
+ if (icount->cursor >= icount->count)
+ icount->cursor = 0;
+ if (ino == icount->list[icount->cursor].ino)
+ return &icount->list[icount->cursor++];
+ low = 0;
+ high = (int) icount->count-1;
+ while (low <= high) {
+ if (low == high)
+ mid = low;
+ else {
+ /* Interpolate for efficiency */
+ lowval = icount->list[low].ino;
+ highval = icount->list[high].ino;
+
+ if (ino < lowval)
+ range = 0;
+ else if (ino > highval)
+ range = 1;
+ else
+ range = ((float) (ino - lowval)) /
+ (highval - lowval);
+ mid = low + ((int) (range * (high-low)));
+ }
+ if (ino == icount->list[mid].ino) {
+ icount->cursor = mid+1;
+ return &icount->list[mid];
+ }
+ if (ino < icount->list[mid].ino)
+ high = mid-1;
+ else
+ low = mid+1;
+ }
+ /*
+ * If we need to create a new entry, it should be right at
+ * low (where high will be left at low-1).
+ */
+ if (create)
+ return insert_icount_el(icount, ino, low);
+ return 0;
+}
+
+errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *out)
+{
+ errcode_t ret = 0;
+ unsigned int i;
+ const char *bad = "bad icount";
+
+ EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
+
+ if (icount->count > icount->size) {
+ fprintf(out, "%s: count > size\n", bad);
+ return EXT2_ET_INVALID_ARGUMENT;
+ }
+ for (i=1; i < icount->count; i++) {
+ if (icount->list[i-1].ino >= icount->list[i].ino) {
+ fprintf(out, "%s: list[%d].ino=%u, list[%d].ino=%u\n",
+ bad, i-1, icount->list[i-1].ino,
+ i, icount->list[i].ino);
+ ret = EXT2_ET_INVALID_ARGUMENT;
+ }
+ }
+ return ret;
+}
+
+errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret)
+{
+ struct ext2_icount_el *el;
+
+ EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
+
+ if (!ino || (ino > icount->num_inodes))
+ return EXT2_ET_INVALID_ARGUMENT;
+
+ if (ext2fs_test_inode_bitmap(icount->single, ino)) {
+ *ret = 1;
+ return 0;
+ }
+ if (icount->multiple &&
+ !ext2fs_test_inode_bitmap(icount->multiple, ino)) {
+ *ret = 0;
+ return 0;
+ }
+ el = get_icount_el(icount, ino, 0);
+ if (!el) {
+ *ret = 0;
+ return 0;
+ }
+ *ret = el->count;
+ return 0;
+}
+
+errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino,
+ __u16 *ret)
+{
+ struct ext2_icount_el *el;
+
+ EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
+
+ if (!ino || (ino > icount->num_inodes))
+ return EXT2_ET_INVALID_ARGUMENT;
+
+ if (ext2fs_test_inode_bitmap(icount->single, ino)) {
+ /*
+ * If the existing count is 1, then we know there is
+ * no entry in the list.
+ */
+ el = get_icount_el(icount, ino, 1);
+ if (!el)
+ return EXT2_ET_NO_MEMORY;
+ ext2fs_unmark_inode_bitmap(icount->single, ino);
+ el->count = 2;
+ } else if (icount->multiple) {
+ /*
+ * The count is either zero or greater than 1; if the
+ * inode is set in icount->multiple, then there should
+ * be an entry in the list, so find it using
+ * get_icount_el().
+ */
+ if (ext2fs_test_inode_bitmap(icount->multiple, ino)) {
+ el = get_icount_el(icount, ino, 1);
+ if (!el)
+ return EXT2_ET_NO_MEMORY;
+ el->count++;
+ } else {
+ /*
+ * The count was zero; mark the single bitmap
+ * and return.
+ */
+ zero_count:
+ ext2fs_mark_inode_bitmap(icount->single, ino);
+ if (ret)
+ *ret = 1;
+ return 0;
+ }
+ } else {
+ /*
+ * The count is either zero or greater than 1; try to
+ * find an entry in the list to determine which.
+ */
+ el = get_icount_el(icount, ino, 0);
+ if (!el) {
+ /* No entry means the count was zero */
+ goto zero_count;
+ }
+ el = get_icount_el(icount, ino, 1);
+ if (!el)
+ return EXT2_ET_NO_MEMORY;
+ el->count++;
+ }
+ if (icount->multiple)
+ ext2fs_mark_inode_bitmap(icount->multiple, ino);
+ if (ret)
+ *ret = el->count;
+ return 0;
+}
+
+errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino,
+ __u16 *ret)
+{
+ struct ext2_icount_el *el;
+
+ if (!ino || (ino > icount->num_inodes))
+ return EXT2_ET_INVALID_ARGUMENT;
+
+ EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
+
+ if (ext2fs_test_inode_bitmap(icount->single, ino)) {
+ ext2fs_unmark_inode_bitmap(icount->single, ino);
+ if (icount->multiple)
+ ext2fs_unmark_inode_bitmap(icount->multiple, ino);
+ else {
+ el = get_icount_el(icount, ino, 0);
+ if (el)
+ el->count = 0;
+ }
+ if (ret)
+ *ret = 0;
+ return 0;
+ }
+
+ if (icount->multiple &&
+ !ext2fs_test_inode_bitmap(icount->multiple, ino))
+ return EXT2_ET_INVALID_ARGUMENT;
+
+ el = get_icount_el(icount, ino, 0);
+ if (!el || el->count == 0)
+ return EXT2_ET_INVALID_ARGUMENT;
+
+ el->count--;
+ if (el->count == 1)
+ ext2fs_mark_inode_bitmap(icount->single, ino);
+ if ((el->count == 0) && icount->multiple)
+ ext2fs_unmark_inode_bitmap(icount->multiple, ino);
+
+ if (ret)
+ *ret = el->count;
+ return 0;
+}
+
+errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,
+ __u16 count)
+{
+ struct ext2_icount_el *el;
+
+ if (!ino || (ino > icount->num_inodes))
+ return EXT2_ET_INVALID_ARGUMENT;
+
+ EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
+
+ if (count == 1) {
+ ext2fs_mark_inode_bitmap(icount->single, ino);
+ if (icount->multiple)
+ ext2fs_unmark_inode_bitmap(icount->multiple, ino);
+ return 0;
+ }
+ if (count == 0) {
+ ext2fs_unmark_inode_bitmap(icount->single, ino);
+ if (icount->multiple) {
+ /*
+ * If the icount->multiple bitmap is enabled,
+ * we can just clear both bitmaps and we're done
+ */
+ ext2fs_unmark_inode_bitmap(icount->multiple, ino);
+ } else {
+ el = get_icount_el(icount, ino, 0);
+ if (el)
+ el->count = 0;
+ }
+ return 0;
+ }
+
+ /*
+ * Get the icount element
+ */
+ el = get_icount_el(icount, ino, 1);
+ if (!el)
+ return EXT2_ET_NO_MEMORY;
+ el->count = count;
+ ext2fs_unmark_inode_bitmap(icount->single, ino);
+ if (icount->multiple)
+ ext2fs_mark_inode_bitmap(icount->multiple, ino);
+ return 0;
+}
+
+ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount)
+{
+ if (!icount || icount->magic != EXT2_ET_MAGIC_ICOUNT)
+ return 0;
+
+ return icount->size;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/imager.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/imager.c
new file mode 100644
index 0000000000..e82321efac
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/imager.c
@@ -0,0 +1,377 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * image.c --- writes out the critical parts of the filesystem as a
+ * flat file.
+ *
+ * Copyright (C) 2000 Theodore Ts'o.
+ *
+ * Note: this uses the POSIX IO interfaces, unlike most of the other
+ * functions in this library. So sue me.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+#ifndef HAVE_TYPE_SSIZE_T
+typedef int ssize_t;
+#endif
+
+/*
+ * This function returns 1 if the specified block is all zeros
+ */
+static int check_zero_block(char *buf, int blocksize)
+{
+ char *cp = buf;
+ int left = blocksize;
+
+ while (left > 0) {
+ if (*cp++)
+ return 0;
+ left--;
+ }
+ return 1;
+}
+
+/*
+ * Write the inode table out as a single block.
+ */
+#define BUF_BLOCKS 32
+
+errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags)
+{
+ unsigned int group, left, c, d;
+ char *buf, *cp;
+ blk_t blk;
+ ssize_t actual;
+ errcode_t retval;
+
+ buf = xmalloc(fs->blocksize * BUF_BLOCKS);
+
+ for (group = 0; group < fs->group_desc_count; group++) {
+ blk = fs->group_desc[(unsigned)group].bg_inode_table;
+ if (!blk)
+ return EXT2_ET_MISSING_INODE_TABLE;
+ left = fs->inode_blocks_per_group;
+ while (left) {
+ c = BUF_BLOCKS;
+ if (c > left)
+ c = left;
+ retval = io_channel_read_blk(fs->io, blk, c, buf);
+ if (retval)
+ goto errout;
+ cp = buf;
+ while (c) {
+ if (!(flags & IMAGER_FLAG_SPARSEWRITE)) {
+ d = c;
+ goto skip_sparse;
+ }
+ /* Skip zero blocks */
+ if (check_zero_block(cp, fs->blocksize)) {
+ c--;
+ blk++;
+ left--;
+ cp += fs->blocksize;
+ lseek(fd, fs->blocksize, SEEK_CUR);
+ continue;
+ }
+ /* Find non-zero blocks */
+ for (d=1; d < c; d++) {
+ if (check_zero_block(cp + d*fs->blocksize, fs->blocksize))
+ break;
+ }
+ skip_sparse:
+ actual = write(fd, cp, fs->blocksize * d);
+ if (actual == -1) {
+ retval = errno;
+ goto errout;
+ }
+ if (actual != (ssize_t) (fs->blocksize * d)) {
+ retval = EXT2_ET_SHORT_WRITE;
+ goto errout;
+ }
+ blk += d;
+ left -= d;
+ cp += fs->blocksize * d;
+ c -= d;
+ }
+ }
+ }
+ retval = 0;
+
+errout:
+ free(buf);
+ return retval;
+}
+
+/*
+ * Read in the inode table and stuff it into place
+ */
+errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd,
+ int flags EXT2FS_ATTR((unused)))
+{
+ unsigned int group, c, left;
+ char *buf;
+ blk_t blk;
+ ssize_t actual;
+ errcode_t retval;
+
+ buf = xmalloc(fs->blocksize * BUF_BLOCKS);
+
+ for (group = 0; group < fs->group_desc_count; group++) {
+ blk = fs->group_desc[(unsigned)group].bg_inode_table;
+ if (!blk) {
+ retval = EXT2_ET_MISSING_INODE_TABLE;
+ goto errout;
+ }
+ left = fs->inode_blocks_per_group;
+ while (left) {
+ c = BUF_BLOCKS;
+ if (c > left)
+ c = left;
+ actual = read(fd, buf, fs->blocksize * c);
+ if (actual == -1) {
+ retval = errno;
+ goto errout;
+ }
+ if (actual != (ssize_t) (fs->blocksize * c)) {
+ retval = EXT2_ET_SHORT_READ;
+ goto errout;
+ }
+ retval = io_channel_write_blk(fs->io, blk, c, buf);
+ if (retval)
+ goto errout;
+
+ blk += c;
+ left -= c;
+ }
+ }
+ retval = ext2fs_flush_icache(fs);
+
+errout:
+ free(buf);
+ return retval;
+}
+
+/*
+ * Write out superblock and group descriptors
+ */
+errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd,
+ int flags EXT2FS_ATTR((unused)))
+{
+ char *buf, *cp;
+ ssize_t actual;
+ errcode_t retval;
+
+ buf = xmalloc(fs->blocksize);
+
+ /*
+ * Write out the superblock
+ */
+ memset(buf, 0, fs->blocksize);
+ memcpy(buf, fs->super, SUPERBLOCK_SIZE);
+ actual = write(fd, buf, fs->blocksize);
+ if (actual == -1) {
+ retval = errno;
+ goto errout;
+ }
+ if (actual != (ssize_t) fs->blocksize) {
+ retval = EXT2_ET_SHORT_WRITE;
+ goto errout;
+ }
+
+ /*
+ * Now write out the block group descriptors
+ */
+ cp = (char *) fs->group_desc;
+ actual = write(fd, cp, fs->blocksize * fs->desc_blocks);
+ if (actual == -1) {
+ retval = errno;
+ goto errout;
+ }
+ if (actual != (ssize_t) (fs->blocksize * fs->desc_blocks)) {
+ retval = EXT2_ET_SHORT_WRITE;
+ goto errout;
+ }
+
+ retval = 0;
+
+errout:
+ free(buf);
+ return retval;
+}
+
+/*
+ * Read the superblock and group descriptors and overwrite them.
+ */
+errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd,
+ int flags EXT2FS_ATTR((unused)))
+{
+ char *buf;
+ ssize_t actual, size;
+ errcode_t retval;
+
+ size = fs->blocksize * (fs->group_desc_count + 1);
+ buf = xmalloc(size);
+
+ /*
+ * Read it all in.
+ */
+ actual = read(fd, buf, size);
+ if (actual == -1) {
+ retval = errno;
+ goto errout;
+ }
+ if (actual != size) {
+ retval = EXT2_ET_SHORT_READ;
+ goto errout;
+ }
+
+ /*
+ * Now copy in the superblock and group descriptors
+ */
+ memcpy(fs->super, buf, SUPERBLOCK_SIZE);
+
+ memcpy(fs->group_desc, buf + fs->blocksize,
+ fs->blocksize * fs->group_desc_count);
+
+ retval = 0;
+
+errout:
+ free(buf);
+ return retval;
+}
+
+/*
+ * Write the block/inode bitmaps.
+ */
+errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
+{
+ char *ptr;
+ int c, size;
+ char zero_buf[1024];
+ ssize_t actual;
+ errcode_t retval;
+
+ if (flags & IMAGER_FLAG_INODEMAP) {
+ if (!fs->inode_map) {
+ retval = ext2fs_read_inode_bitmap(fs);
+ if (retval)
+ return retval;
+ }
+ ptr = fs->inode_map->bitmap;
+ size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
+ } else {
+ if (!fs->block_map) {
+ retval = ext2fs_read_block_bitmap(fs);
+ if (retval)
+ return retval;
+ }
+ ptr = fs->block_map->bitmap;
+ size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
+ }
+ size = size * fs->group_desc_count;
+
+ actual = write(fd, ptr, size);
+ if (actual == -1) {
+ retval = errno;
+ goto errout;
+ }
+ if (actual != size) {
+ retval = EXT2_ET_SHORT_WRITE;
+ goto errout;
+ }
+ size = size % fs->blocksize;
+ memset(zero_buf, 0, sizeof(zero_buf));
+ if (size) {
+ size = fs->blocksize - size;
+ while (size) {
+ c = size;
+ if (c > (int) sizeof(zero_buf))
+ c = sizeof(zero_buf);
+ actual = write(fd, zero_buf, c);
+ if (actual == -1) {
+ retval = errno;
+ goto errout;
+ }
+ if (actual != c) {
+ retval = EXT2_ET_SHORT_WRITE;
+ goto errout;
+ }
+ size -= c;
+ }
+ }
+ retval = 0;
+errout:
+ return retval;
+}
+
+
+/*
+ * Read the block/inode bitmaps.
+ */
+errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
+{
+ char *ptr, *buf = 0;
+ int size;
+ ssize_t actual;
+ errcode_t retval;
+
+ if (flags & IMAGER_FLAG_INODEMAP) {
+ if (!fs->inode_map) {
+ retval = ext2fs_read_inode_bitmap(fs);
+ if (retval)
+ return retval;
+ }
+ ptr = fs->inode_map->bitmap;
+ size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
+ } else {
+ if (!fs->block_map) {
+ retval = ext2fs_read_block_bitmap(fs);
+ if (retval)
+ return retval;
+ }
+ ptr = fs->block_map->bitmap;
+ size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
+ }
+ size = size * fs->group_desc_count;
+
+ buf = xmalloc(size);
+
+ actual = read(fd, buf, size);
+ if (actual == -1) {
+ retval = errno;
+ goto errout;
+ }
+ if (actual != size) {
+ retval = EXT2_ET_SHORT_WRITE;
+ goto errout;
+ }
+ memcpy(ptr, buf, size);
+
+ retval = 0;
+errout:
+ free(buf);
+ return retval;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ind_block.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ind_block.c
new file mode 100644
index 0000000000..c86a1c59a3
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ind_block.c
@@ -0,0 +1,71 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * ind_block.c --- indirect block I/O routines
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+ * 2001, 2002, 2003, 2004, 2005 by Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+errcode_t ext2fs_read_ind_block(ext2_filsys fs, blk_t blk, void *buf)
+{
+ errcode_t retval;
+#if BB_BIG_ENDIAN
+ blk_t *block_nr;
+ int i;
+ int limit = fs->blocksize >> 2;
+#endif
+
+ if ((fs->flags & EXT2_FLAG_IMAGE_FILE) &&
+ (fs->io != fs->image_io))
+ memset(buf, 0, fs->blocksize);
+ else {
+ retval = io_channel_read_blk(fs->io, blk, 1, buf);
+ if (retval)
+ return retval;
+ }
+#if BB_BIG_ENDIAN
+ if (fs->flags & (EXT2_FLAG_SWAP_BYTES | EXT2_FLAG_SWAP_BYTES_READ)) {
+ block_nr = (blk_t *) buf;
+ for (i = 0; i < limit; i++, block_nr++)
+ *block_nr = ext2fs_swab32(*block_nr);
+ }
+#endif
+ return 0;
+}
+
+errcode_t ext2fs_write_ind_block(ext2_filsys fs, blk_t blk, void *buf)
+{
+#if BB_BIG_ENDIAN
+ blk_t *block_nr;
+ int i;
+ int limit = fs->blocksize >> 2;
+#endif
+
+ if (fs->flags & EXT2_FLAG_IMAGE_FILE)
+ return 0;
+
+#if BB_BIG_ENDIAN
+ if (fs->flags & (EXT2_FLAG_SWAP_BYTES | EXT2_FLAG_SWAP_BYTES_WRITE)) {
+ block_nr = (blk_t *) buf;
+ for (i = 0; i < limit; i++, block_nr++)
+ *block_nr = ext2fs_swab32(*block_nr);
+ }
+#endif
+ return io_channel_write_blk(fs->io, blk, 1, buf);
+}
+
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/initialize.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/initialize.c
new file mode 100644
index 0000000000..ef1d343797
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/initialize.c
@@ -0,0 +1,388 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * initialize.c --- initialize a filesystem handle given superblock
+ * parameters. Used by mke2fs when initializing a filesystem.
+ *
+ * Copyright (C) 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+#if defined(__linux__) && defined(EXT2_OS_LINUX)
+#define CREATOR_OS EXT2_OS_LINUX
+#else
+#if defined(__GNU__) && defined(EXT2_OS_HURD)
+#define CREATOR_OS EXT2_OS_HURD
+#else
+#if defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD)
+#define CREATOR_OS EXT2_OS_FREEBSD
+#else
+#if defined(LITES) && defined(EXT2_OS_LITES)
+#define CREATOR_OS EXT2_OS_LITES
+#else
+#define CREATOR_OS EXT2_OS_LINUX /* by default */
+#endif /* defined(LITES) && defined(EXT2_OS_LITES) */
+#endif /* defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD) */
+#endif /* defined(__GNU__) && defined(EXT2_OS_HURD) */
+#endif /* defined(__linux__) && defined(EXT2_OS_LINUX) */
+
+/*
+ * Note we override the kernel include file's idea of what the default
+ * check interval (never) should be. It's a good idea to check at
+ * least *occasionally*, specially since servers will never rarely get
+ * to reboot, since Linux is so robust these days. :-)
+ *
+ * 180 days (six months) seems like a good value.
+ */
+#ifdef EXT2_DFL_CHECKINTERVAL
+#undef EXT2_DFL_CHECKINTERVAL
+#endif
+#define EXT2_DFL_CHECKINTERVAL (86400L * 180L)
+
+/*
+ * Calculate the number of GDT blocks to reserve for online filesystem growth.
+ * The absolute maximum number of GDT blocks we can reserve is determined by
+ * the number of block pointers that can fit into a single block.
+ */
+static int calc_reserved_gdt_blocks(ext2_filsys fs)
+{
+ struct ext2_super_block *sb = fs->super;
+ unsigned long bpg = sb->s_blocks_per_group;
+ unsigned int gdpb = fs->blocksize / sizeof(struct ext2_group_desc);
+ unsigned long max_blocks = 0xffffffff;
+ unsigned long rsv_groups;
+ int rsv_gdb;
+
+ /* We set it at 1024x the current filesystem size, or
+ * the upper block count limit (2^32), whichever is lower.
+ */
+ if (sb->s_blocks_count < max_blocks / 1024)
+ max_blocks = sb->s_blocks_count * 1024;
+ rsv_groups = (max_blocks - sb->s_first_data_block + bpg - 1) / bpg;
+ rsv_gdb = (rsv_groups + gdpb - 1) / gdpb - fs->desc_blocks;
+ if (rsv_gdb > EXT2_ADDR_PER_BLOCK(sb))
+ rsv_gdb = EXT2_ADDR_PER_BLOCK(sb);
+#ifdef RES_GDT_DEBUG
+ printf("max_blocks %lu, rsv_groups = %lu, rsv_gdb = %lu\n",
+ max_blocks, rsv_groups, rsv_gdb);
+#endif
+
+ return rsv_gdb;
+}
+
+errcode_t ext2fs_initialize(const char *name, int flags,
+ struct ext2_super_block *param,
+ io_manager manager, ext2_filsys *ret_fs)
+{
+ ext2_filsys fs;
+ errcode_t retval;
+ struct ext2_super_block *super;
+ int frags_per_block;
+ unsigned int rem;
+ unsigned int overhead = 0;
+ blk_t group_block;
+ unsigned int ipg;
+ dgrp_t i;
+ blk_t numblocks;
+ int rsv_gdt;
+ char *buf;
+
+ if (!param || !param->s_blocks_count)
+ return EXT2_ET_INVALID_ARGUMENT;
+
+ retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
+ if (retval)
+ return retval;
+
+ memset(fs, 0, sizeof(struct struct_ext2_filsys));
+ fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
+ fs->flags = flags | EXT2_FLAG_RW;
+ fs->umask = 022;
+#ifdef WORDS_BIGENDIAN
+ fs->flags |= EXT2_FLAG_SWAP_BYTES;
+#endif
+ retval = manager->open(name, IO_FLAG_RW, &fs->io);
+ if (retval)
+ goto cleanup;
+ fs->image_io = fs->io;
+ fs->io->app_data = fs;
+ retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name);
+ if (retval)
+ goto cleanup;
+
+ strcpy(fs->device_name, name);
+ retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super);
+ if (retval)
+ goto cleanup;
+ fs->super = super;
+
+ memset(super, 0, SUPERBLOCK_SIZE);
+
+#define set_field(field, default) (super->field = param->field ? \
+ param->field : (default))
+
+ super->s_magic = EXT2_SUPER_MAGIC;
+ super->s_state = EXT2_VALID_FS;
+
+ set_field(s_log_block_size, 0); /* default blocksize: 1024 bytes */
+ set_field(s_log_frag_size, 0); /* default fragsize: 1024 bytes */
+ set_field(s_first_data_block, super->s_log_block_size ? 0 : 1);
+ set_field(s_max_mnt_count, EXT2_DFL_MAX_MNT_COUNT);
+ set_field(s_errors, EXT2_ERRORS_DEFAULT);
+ set_field(s_feature_compat, 0);
+ set_field(s_feature_incompat, 0);
+ set_field(s_feature_ro_compat, 0);
+ set_field(s_first_meta_bg, 0);
+ if (super->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
+ retval = EXT2_ET_UNSUPP_FEATURE;
+ goto cleanup;
+ }
+ if (super->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
+ retval = EXT2_ET_RO_UNSUPP_FEATURE;
+ goto cleanup;
+ }
+
+ set_field(s_rev_level, EXT2_GOOD_OLD_REV);
+ if (super->s_rev_level >= EXT2_DYNAMIC_REV) {
+ set_field(s_first_ino, EXT2_GOOD_OLD_FIRST_INO);
+ set_field(s_inode_size, EXT2_GOOD_OLD_INODE_SIZE);
+ }
+
+ set_field(s_checkinterval, EXT2_DFL_CHECKINTERVAL);
+ super->s_mkfs_time = super->s_lastcheck = time(NULL);
+
+ super->s_creator_os = CREATOR_OS;
+
+ fs->blocksize = EXT2_BLOCK_SIZE(super);
+ fs->fragsize = EXT2_FRAG_SIZE(super);
+ frags_per_block = fs->blocksize / fs->fragsize;
+
+ /* default: (fs->blocksize*8) blocks/group, up to 2^16 (GDT limit) */
+ set_field(s_blocks_per_group, fs->blocksize * 8);
+ if (super->s_blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(super))
+ super->s_blocks_per_group = EXT2_MAX_BLOCKS_PER_GROUP(super);
+ super->s_frags_per_group = super->s_blocks_per_group * frags_per_block;
+
+ super->s_blocks_count = param->s_blocks_count;
+ super->s_r_blocks_count = param->s_r_blocks_count;
+ if (super->s_r_blocks_count >= param->s_blocks_count) {
+ retval = EXT2_ET_INVALID_ARGUMENT;
+ goto cleanup;
+ }
+
+ /*
+ * If we're creating an external journal device, we don't need
+ * to bother with the rest.
+ */
+ if (super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
+ fs->group_desc_count = 0;
+ ext2fs_mark_super_dirty(fs);
+ *ret_fs = fs;
+ return 0;
+ }
+
+retry:
+ fs->group_desc_count = (super->s_blocks_count -
+ super->s_first_data_block +
+ EXT2_BLOCKS_PER_GROUP(super) - 1)
+ / EXT2_BLOCKS_PER_GROUP(super);
+ if (fs->group_desc_count == 0) {
+ retval = EXT2_ET_TOOSMALL;
+ goto cleanup;
+ }
+ fs->desc_blocks = (fs->group_desc_count +
+ EXT2_DESC_PER_BLOCK(super) - 1)
+ / EXT2_DESC_PER_BLOCK(super);
+
+ i = fs->blocksize >= 4096 ? 1 : 4096 / fs->blocksize;
+ set_field(s_inodes_count, super->s_blocks_count / i);
+
+ /*
+ * Make sure we have at least EXT2_FIRST_INO + 1 inodes, so
+ * that we have enough inodes for the filesystem(!)
+ */
+ if (super->s_inodes_count < EXT2_FIRST_INODE(super)+1)
+ super->s_inodes_count = EXT2_FIRST_INODE(super)+1;
+
+ /*
+ * There should be at least as many inodes as the user
+ * requested. Figure out how many inodes per group that
+ * should be. But make sure that we don't allocate more than
+ * one bitmap's worth of inodes each group.
+ */
+ ipg = (super->s_inodes_count + fs->group_desc_count - 1) /
+ fs->group_desc_count;
+ if (ipg > fs->blocksize * 8) {
+ if (super->s_blocks_per_group >= 256) {
+ /* Try again with slightly different parameters */
+ super->s_blocks_per_group -= 8;
+ super->s_blocks_count = param->s_blocks_count;
+ super->s_frags_per_group = super->s_blocks_per_group *
+ frags_per_block;
+ goto retry;
+ } else
+ return EXT2_ET_TOO_MANY_INODES;
+ }
+
+ if (ipg > (unsigned) EXT2_MAX_INODES_PER_GROUP(super))
+ ipg = EXT2_MAX_INODES_PER_GROUP(super);
+
+ super->s_inodes_per_group = ipg;
+ if (super->s_inodes_count > ipg * fs->group_desc_count)
+ super->s_inodes_count = ipg * fs->group_desc_count;
+
+ /*
+ * Make sure the number of inodes per group completely fills
+ * the inode table blocks in the descriptor. If not, add some
+ * additional inodes/group. Waste not, want not...
+ */
+ fs->inode_blocks_per_group = (((super->s_inodes_per_group *
+ EXT2_INODE_SIZE(super)) +
+ EXT2_BLOCK_SIZE(super) - 1) /
+ EXT2_BLOCK_SIZE(super));
+ super->s_inodes_per_group = ((fs->inode_blocks_per_group *
+ EXT2_BLOCK_SIZE(super)) /
+ EXT2_INODE_SIZE(super));
+ /*
+ * Finally, make sure the number of inodes per group is a
+ * multiple of 8. This is needed to simplify the bitmap
+ * splicing code.
+ */
+ super->s_inodes_per_group &= ~7;
+ fs->inode_blocks_per_group = (((super->s_inodes_per_group *
+ EXT2_INODE_SIZE(super)) +
+ EXT2_BLOCK_SIZE(super) - 1) /
+ EXT2_BLOCK_SIZE(super));
+
+ /*
+ * adjust inode count to reflect the adjusted inodes_per_group
+ */
+ super->s_inodes_count = super->s_inodes_per_group *
+ fs->group_desc_count;
+ super->s_free_inodes_count = super->s_inodes_count;
+
+ /*
+ * check the number of reserved group descriptor table blocks
+ */
+ if (super->s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INODE)
+ rsv_gdt = calc_reserved_gdt_blocks(fs);
+ else
+ rsv_gdt = 0;
+ set_field(s_reserved_gdt_blocks, rsv_gdt);
+ if (super->s_reserved_gdt_blocks > EXT2_ADDR_PER_BLOCK(super)) {
+ retval = EXT2_ET_RES_GDT_BLOCKS;
+ goto cleanup;
+ }
+
+ /*
+ * Overhead is the number of bookkeeping blocks per group. It
+ * includes the superblock backup, the group descriptor
+ * backups, the inode bitmap, the block bitmap, and the inode
+ * table.
+ */
+
+ overhead = (int) (2 + fs->inode_blocks_per_group);
+
+ if (ext2fs_bg_has_super(fs, fs->group_desc_count - 1))
+ overhead += 1 + fs->desc_blocks + super->s_reserved_gdt_blocks;
+
+ /* This can only happen if the user requested too many inodes */
+ if (overhead > super->s_blocks_per_group)
+ return EXT2_ET_TOO_MANY_INODES;
+
+ /*
+ * See if the last group is big enough to support the
+ * necessary data structures. If not, we need to get rid of
+ * it.
+ */
+ rem = ((super->s_blocks_count - super->s_first_data_block) %
+ super->s_blocks_per_group);
+ if ((fs->group_desc_count == 1) && rem && (rem < overhead))
+ return EXT2_ET_TOOSMALL;
+ if (rem && (rem < overhead+50)) {
+ super->s_blocks_count -= rem;
+ goto retry;
+ }
+
+ /*
+ * At this point we know how big the filesystem will be. So
+ * we can do any and all allocations that depend on the block
+ * count.
+ */
+
+ retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
+ if (retval)
+ goto cleanup;
+
+ sprintf(buf, "block bitmap for %s", fs->device_name);
+ retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
+ if (retval)
+ goto cleanup;
+
+ sprintf(buf, "inode bitmap for %s", fs->device_name);
+ retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
+ if (retval)
+ goto cleanup;
+
+ ext2fs_free_mem(&buf);
+
+ retval = ext2fs_get_mem((size_t) fs->desc_blocks * fs->blocksize,
+ &fs->group_desc);
+ if (retval)
+ goto cleanup;
+
+ memset(fs->group_desc, 0, (size_t) fs->desc_blocks * fs->blocksize);
+
+ /*
+ * Reserve the superblock and group descriptors for each
+ * group, and fill in the correct group statistics for group.
+ * Note that although the block bitmap, inode bitmap, and
+ * inode table have not been allocated (and in fact won't be
+ * by this routine), they are accounted for nevertheless.
+ */
+ group_block = super->s_first_data_block;
+ super->s_free_blocks_count = 0;
+ for (i = 0; i < fs->group_desc_count; i++) {
+ numblocks = ext2fs_reserve_super_and_bgd(fs, i, fs->block_map);
+
+ super->s_free_blocks_count += numblocks;
+ fs->group_desc[i].bg_free_blocks_count = numblocks;
+ fs->group_desc[i].bg_free_inodes_count =
+ fs->super->s_inodes_per_group;
+ fs->group_desc[i].bg_used_dirs_count = 0;
+
+ group_block += super->s_blocks_per_group;
+ }
+
+ ext2fs_mark_super_dirty(fs);
+ ext2fs_mark_bb_dirty(fs);
+ ext2fs_mark_ib_dirty(fs);
+
+ io_channel_set_blksize(fs->io, fs->blocksize);
+
+ *ret_fs = fs;
+ return 0;
+cleanup:
+ ext2fs_free(fs);
+ return retval;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/inline.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/inline.c
new file mode 100644
index 0000000000..9b620a772d
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/inline.c
@@ -0,0 +1,33 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * inline.c --- Includes the inlined functions defined in the header
+ * files as standalone functions, in case the application program
+ * is compiled with inlining turned off.
+ *
+ * Copyright (C) 1993, 1994 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#define INCLUDE_INLINE_FUNCS
+#include "ext2fs.h"
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/inode.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/inode.c
new file mode 100644
index 0000000000..5e0d081bd5
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/inode.c
@@ -0,0 +1,767 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * inode.c --- utility routines to read and write inodes
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+#include "e2image.h"
+
+struct ext2_struct_inode_scan {
+ errcode_t magic;
+ ext2_filsys fs;
+ ext2_ino_t current_inode;
+ blk_t current_block;
+ dgrp_t current_group;
+ ext2_ino_t inodes_left;
+ blk_t blocks_left;
+ dgrp_t groups_left;
+ blk_t inode_buffer_blocks;
+ char * inode_buffer;
+ int inode_size;
+ char * ptr;
+ int bytes_left;
+ char *temp_buffer;
+ errcode_t (*done_group)(ext2_filsys fs,
+ dgrp_t group,
+ void * priv_data);
+ void * done_group_data;
+ int bad_block_ptr;
+ int scan_flags;
+ int reserved[6];
+};
+
+/*
+ * This routine flushes the icache, if it exists.
+ */
+errcode_t ext2fs_flush_icache(ext2_filsys fs)
+{
+ int i;
+
+ if (!fs->icache)
+ return 0;
+
+ for (i=0; i < fs->icache->cache_size; i++)
+ fs->icache->cache[i].ino = 0;
+
+ fs->icache->buffer_blk = 0;
+ return 0;
+}
+
+static errcode_t create_icache(ext2_filsys fs)
+{
+ errcode_t retval;
+
+ if (fs->icache)
+ return 0;
+ retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache), &fs->icache);
+ if (retval)
+ return retval;
+
+ memset(fs->icache, 0, sizeof(struct ext2_inode_cache));
+ retval = ext2fs_get_mem(fs->blocksize, &fs->icache->buffer);
+ if (retval) {
+ ext2fs_free_mem(&fs->icache);
+ return retval;
+ }
+ fs->icache->buffer_blk = 0;
+ fs->icache->cache_last = -1;
+ fs->icache->cache_size = 4;
+ fs->icache->refcount = 1;
+ retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache_ent)
+ * fs->icache->cache_size,
+ &fs->icache->cache);
+ if (retval) {
+ ext2fs_free_mem(&fs->icache->buffer);
+ ext2fs_free_mem(&fs->icache);
+ return retval;
+ }
+ ext2fs_flush_icache(fs);
+ return 0;
+}
+
+errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
+ ext2_inode_scan *ret_scan)
+{
+ ext2_inode_scan scan;
+ errcode_t retval;
+ errcode_t (*save_get_blocks)(ext2_filsys f, ext2_ino_t ino, blk_t *blocks);
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ /*
+ * If fs->badblocks isn't set, then set it --- since the inode
+ * scanning functions require it.
+ */
+ if (fs->badblocks == 0) {
+ /*
+ * Temporarly save fs->get_blocks and set it to zero,
+ * for compatibility with old e2fsck's.
+ */
+ save_get_blocks = fs->get_blocks;
+ fs->get_blocks = 0;
+ retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
+ if (retval) {
+ ext2fs_badblocks_list_free(fs->badblocks);
+ fs->badblocks = 0;
+ }
+ fs->get_blocks = save_get_blocks;
+ }
+
+ retval = ext2fs_get_mem(sizeof(struct ext2_struct_inode_scan), &scan);
+ if (retval)
+ return retval;
+ memset(scan, 0, sizeof(struct ext2_struct_inode_scan));
+
+ scan->magic = EXT2_ET_MAGIC_INODE_SCAN;
+ scan->fs = fs;
+ scan->inode_size = EXT2_INODE_SIZE(fs->super);
+ scan->bytes_left = 0;
+ scan->current_group = 0;
+ scan->groups_left = fs->group_desc_count - 1;
+ scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : 8;
+ scan->current_block = scan->fs->
+ group_desc[scan->current_group].bg_inode_table;
+ scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
+ scan->blocks_left = scan->fs->inode_blocks_per_group;
+ retval = ext2fs_get_mem((size_t) (scan->inode_buffer_blocks *
+ fs->blocksize),
+ &scan->inode_buffer);
+ scan->done_group = 0;
+ scan->done_group_data = 0;
+ scan->bad_block_ptr = 0;
+ if (retval) {
+ ext2fs_free_mem(&scan);
+ return retval;
+ }
+ retval = ext2fs_get_mem(scan->inode_size, &scan->temp_buffer);
+ if (retval) {
+ ext2fs_free_mem(&scan->inode_buffer);
+ ext2fs_free_mem(&scan);
+ return retval;
+ }
+ if (scan->fs->badblocks && scan->fs->badblocks->num)
+ scan->scan_flags |= EXT2_SF_CHK_BADBLOCKS;
+ *ret_scan = scan;
+ return 0;
+}
+
+void ext2fs_close_inode_scan(ext2_inode_scan scan)
+{
+ if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
+ return;
+
+ ext2fs_free_mem(&scan->inode_buffer);
+ scan->inode_buffer = NULL;
+ ext2fs_free_mem(&scan->temp_buffer);
+ scan->temp_buffer = NULL;
+ ext2fs_free_mem(&scan);
+}
+
+void ext2fs_set_inode_callback(ext2_inode_scan scan,
+ errcode_t (*done_group)(ext2_filsys fs,
+ dgrp_t group,
+ void * priv_data),
+ void *done_group_data)
+{
+ if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
+ return;
+
+ scan->done_group = done_group;
+ scan->done_group_data = done_group_data;
+}
+
+int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags,
+ int clear_flags)
+{
+ int old_flags;
+
+ if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
+ return 0;
+
+ old_flags = scan->scan_flags;
+ scan->scan_flags &= ~clear_flags;
+ scan->scan_flags |= set_flags;
+ return old_flags;
+}
+
+/*
+ * This function is called by ext2fs_get_next_inode when it needs to
+ * get ready to read in a new blockgroup.
+ */
+static errcode_t get_next_blockgroup(ext2_inode_scan scan)
+{
+ scan->current_group++;
+ scan->groups_left--;
+
+ scan->current_block = scan->fs->
+ group_desc[scan->current_group].bg_inode_table;
+
+ scan->current_inode = scan->current_group *
+ EXT2_INODES_PER_GROUP(scan->fs->super);
+
+ scan->bytes_left = 0;
+ scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
+ scan->blocks_left = scan->fs->inode_blocks_per_group;
+ return 0;
+}
+
+errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,
+ int group)
+{
+ scan->current_group = group - 1;
+ scan->groups_left = scan->fs->group_desc_count - group;
+ return get_next_blockgroup(scan);
+}
+
+/*
+ * This function is called by get_next_blocks() to check for bad
+ * blocks in the inode table.
+ *
+ * This function assumes that badblocks_list->list is sorted in
+ * increasing order.
+ */
+static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan,
+ blk_t *num_blocks)
+{
+ blk_t blk = scan->current_block;
+ badblocks_list bb = scan->fs->badblocks;
+
+ /*
+ * If the inode table is missing, then obviously there are no
+ * bad blocks. :-)
+ */
+ if (blk == 0)
+ return 0;
+
+ /*
+ * If the current block is greater than the bad block listed
+ * in the bad block list, then advance the pointer until this
+ * is no longer the case. If we run out of bad blocks, then
+ * we don't need to do any more checking!
+ */
+ while (blk > bb->list[scan->bad_block_ptr]) {
+ if (++scan->bad_block_ptr >= bb->num) {
+ scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
+ return 0;
+ }
+ }
+
+ /*
+ * If the current block is equal to the bad block listed in
+ * the bad block list, then handle that one block specially.
+ * (We could try to handle runs of bad blocks, but that
+ * only increases CPU efficiency by a small amount, at the
+ * expense of a huge expense of code complexity, and for an
+ * uncommon case at that.)
+ */
+ if (blk == bb->list[scan->bad_block_ptr]) {
+ scan->scan_flags |= EXT2_SF_BAD_INODE_BLK;
+ *num_blocks = 1;
+ if (++scan->bad_block_ptr >= bb->num)
+ scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
+ return 0;
+ }
+
+ /*
+ * If there is a bad block in the range that we're about to
+ * read in, adjust the number of blocks to read so that we we
+ * don't read in the bad block. (Then the next block to read
+ * will be the bad block, which is handled in the above case.)
+ */
+ if ((blk + *num_blocks) > bb->list[scan->bad_block_ptr])
+ *num_blocks = (int) (bb->list[scan->bad_block_ptr] - blk);
+
+ return 0;
+}
+
+/*
+ * This function is called by ext2fs_get_next_inode when it needs to
+ * read in more blocks from the current blockgroup's inode table.
+ */
+static errcode_t get_next_blocks(ext2_inode_scan scan)
+{
+ blk_t num_blocks;
+ errcode_t retval;
+
+ /*
+ * Figure out how many blocks to read; we read at most
+ * inode_buffer_blocks, and perhaps less if there aren't that
+ * many blocks left to read.
+ */
+ num_blocks = scan->inode_buffer_blocks;
+ if (num_blocks > scan->blocks_left)
+ num_blocks = scan->blocks_left;
+
+ /*
+ * If the past block "read" was a bad block, then mark the
+ * left-over extra bytes as also being bad.
+ */
+ if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) {
+ if (scan->bytes_left)
+ scan->scan_flags |= EXT2_SF_BAD_EXTRA_BYTES;
+ scan->scan_flags &= ~EXT2_SF_BAD_INODE_BLK;
+ }
+
+ /*
+ * Do inode bad block processing, if necessary.
+ */
+ if (scan->scan_flags & EXT2_SF_CHK_BADBLOCKS) {
+ retval = check_for_inode_bad_blocks(scan, &num_blocks);
+ if (retval)
+ return retval;
+ }
+
+ if ((scan->scan_flags & EXT2_SF_BAD_INODE_BLK) ||
+ (scan->current_block == 0)) {
+ memset(scan->inode_buffer, 0,
+ (size_t) num_blocks * scan->fs->blocksize);
+ } else {
+ retval = io_channel_read_blk(scan->fs->io,
+ scan->current_block,
+ (int) num_blocks,
+ scan->inode_buffer);
+ if (retval)
+ return EXT2_ET_NEXT_INODE_READ;
+ }
+ scan->ptr = scan->inode_buffer;
+ scan->bytes_left = num_blocks * scan->fs->blocksize;
+
+ scan->blocks_left -= num_blocks;
+ if (scan->current_block)
+ scan->current_block += num_blocks;
+ return 0;
+}
+
+errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
+ struct ext2_inode *inode, int bufsize)
+{
+ errcode_t retval;
+ int extra_bytes = 0;
+
+ EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN);
+
+ /*
+ * Do we need to start reading a new block group?
+ */
+ if (scan->inodes_left <= 0) {
+ force_new_group:
+ if (scan->done_group) {
+ retval = (scan->done_group)
+ (scan->fs, scan->current_group,
+ scan->done_group_data);
+ if (retval)
+ return retval;
+ }
+ if (scan->groups_left <= 0) {
+ *ino = 0;
+ return 0;
+ }
+ retval = get_next_blockgroup(scan);
+ if (retval)
+ return retval;
+ }
+ /*
+ * This is done outside the above if statement so that the
+ * check can be done for block group #0.
+ */
+ if (scan->current_block == 0) {
+ if (scan->scan_flags & EXT2_SF_SKIP_MISSING_ITABLE) {
+ goto force_new_group;
+ } else
+ return EXT2_ET_MISSING_INODE_TABLE;
+ }
+
+
+ /*
+ * Have we run out of space in the inode buffer? If so, we
+ * need to read in more blocks.
+ */
+ if (scan->bytes_left < scan->inode_size) {
+ memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left);
+ extra_bytes = scan->bytes_left;
+
+ retval = get_next_blocks(scan);
+ if (retval)
+ return retval;
+#if 0
+ /*
+ * XXX test Need check for used inode somehow.
+ * (Note: this is hard.)
+ */
+ if (is_empty_scan(scan))
+ goto force_new_group;
+#endif
+ }
+
+ retval = 0;
+ if (extra_bytes) {
+ memcpy(scan->temp_buffer+extra_bytes, scan->ptr,
+ scan->inode_size - extra_bytes);
+ scan->ptr += scan->inode_size - extra_bytes;
+ scan->bytes_left -= scan->inode_size - extra_bytes;
+
+#if BB_BIG_ENDIAN
+ if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+ (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
+ ext2fs_swap_inode_full(scan->fs,
+ (struct ext2_inode_large *) inode,
+ (struct ext2_inode_large *) scan->temp_buffer,
+ 0, bufsize);
+ else
+#endif
+ *inode = *((struct ext2_inode *) scan->temp_buffer);
+ if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES)
+ retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
+ scan->scan_flags &= ~EXT2_SF_BAD_EXTRA_BYTES;
+ } else {
+#if BB_BIG_ENDIAN
+ if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+ (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
+ ext2fs_swap_inode_full(scan->fs,
+ (struct ext2_inode_large *) inode,
+ (struct ext2_inode_large *) scan->ptr,
+ 0, bufsize);
+ else
+#endif
+ memcpy(inode, scan->ptr, bufsize);
+ scan->ptr += scan->inode_size;
+ scan->bytes_left -= scan->inode_size;
+ if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK)
+ retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
+ }
+
+ scan->inodes_left--;
+ scan->current_inode++;
+ *ino = scan->current_inode;
+ return retval;
+}
+
+errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
+ struct ext2_inode *inode)
+{
+ return ext2fs_get_next_inode_full(scan, ino, inode,
+ sizeof(struct ext2_inode));
+}
+
+/*
+ * Functions to read and write a single inode.
+ */
+errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode * inode, int bufsize)
+{
+ unsigned long group, block, block_nr, offset;
+ char *ptr;
+ errcode_t retval;
+ int clen, i, inodes_per_block, length;
+ io_channel io;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ /* Check to see if user has an override function */
+ if (fs->read_inode) {
+ retval = (fs->read_inode)(fs, ino, inode);
+ if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
+ return retval;
+ }
+ /* Create inode cache if not present */
+ if (!fs->icache) {
+ retval = create_icache(fs);
+ if (retval)
+ return retval;
+ }
+ /* Check to see if it's in the inode cache */
+ if (bufsize == sizeof(struct ext2_inode)) {
+ /* only old good inode can be retrieve from the cache */
+ for (i=0; i < fs->icache->cache_size; i++) {
+ if (fs->icache->cache[i].ino == ino) {
+ *inode = fs->icache->cache[i].inode;
+ return 0;
+ }
+ }
+ }
+ if ((ino == 0) || (ino > fs->super->s_inodes_count))
+ return EXT2_ET_BAD_INODE_NUM;
+ if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
+ inodes_per_block = fs->blocksize / EXT2_INODE_SIZE(fs->super);
+ block_nr = fs->image_header->offset_inode / fs->blocksize;
+ block_nr += (ino - 1) / inodes_per_block;
+ offset = ((ino - 1) % inodes_per_block) *
+ EXT2_INODE_SIZE(fs->super);
+ io = fs->image_io;
+ } else {
+ group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
+ offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
+ EXT2_INODE_SIZE(fs->super);
+ block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
+ if (!fs->group_desc[(unsigned)group].bg_inode_table)
+ return EXT2_ET_MISSING_INODE_TABLE;
+ block_nr = fs->group_desc[(unsigned)group].bg_inode_table +
+ block;
+ io = fs->io;
+ }
+ offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
+
+ length = EXT2_INODE_SIZE(fs->super);
+ if (bufsize < length)
+ length = bufsize;
+
+ ptr = (char *) inode;
+ while (length) {
+ clen = length;
+ if ((offset + length) > fs->blocksize)
+ clen = fs->blocksize - offset;
+
+ if (block_nr != fs->icache->buffer_blk) {
+ retval = io_channel_read_blk(io, block_nr, 1,
+ fs->icache->buffer);
+ if (retval)
+ return retval;
+ fs->icache->buffer_blk = block_nr;
+ }
+
+ memcpy(ptr, ((char *) fs->icache->buffer) + (unsigned) offset,
+ clen);
+
+ offset = 0;
+ length -= clen;
+ ptr += clen;
+ block_nr++;
+ }
+
+#if BB_BIG_ENDIAN
+ if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+ (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
+ ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) inode,
+ (struct ext2_inode_large *) inode,
+ 0, length);
+#endif
+
+ /* Update the inode cache */
+ fs->icache->cache_last = (fs->icache->cache_last + 1) %
+ fs->icache->cache_size;
+ fs->icache->cache[fs->icache->cache_last].ino = ino;
+ fs->icache->cache[fs->icache->cache_last].inode = *inode;
+
+ return 0;
+}
+
+errcode_t ext2fs_read_inode(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode * inode)
+{
+ return ext2fs_read_inode_full(fs, ino, inode,
+ sizeof(struct ext2_inode));
+}
+
+errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode * inode, int bufsize)
+{
+ unsigned long group, block, block_nr, offset;
+ errcode_t retval = 0;
+ struct ext2_inode_large temp_inode, *w_inode;
+ char *ptr;
+ int clen, i, length;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ /* Check to see if user provided an override function */
+ if (fs->write_inode) {
+ retval = (fs->write_inode)(fs, ino, inode);
+ if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
+ return retval;
+ }
+
+ /* Check to see if the inode cache needs to be updated */
+ if (fs->icache) {
+ for (i=0; i < fs->icache->cache_size; i++) {
+ if (fs->icache->cache[i].ino == ino) {
+ fs->icache->cache[i].inode = *inode;
+ break;
+ }
+ }
+ } else {
+ retval = create_icache(fs);
+ if (retval)
+ return retval;
+ }
+
+ if (!(fs->flags & EXT2_FLAG_RW))
+ return EXT2_ET_RO_FILSYS;
+
+ if ((ino == 0) || (ino > fs->super->s_inodes_count))
+ return EXT2_ET_BAD_INODE_NUM;
+
+ length = bufsize;
+ if (length < EXT2_INODE_SIZE(fs->super))
+ length = EXT2_INODE_SIZE(fs->super);
+
+ if (length > (int) sizeof(struct ext2_inode_large)) {
+ w_inode = xmalloc(length);
+ } else
+ w_inode = &temp_inode;
+ memset(w_inode, 0, length);
+
+#if BB_BIG_ENDIAN
+ if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+ (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
+ ext2fs_swap_inode_full(fs, w_inode,
+ (struct ext2_inode_large *) inode,
+ 1, bufsize);
+ else
+#endif
+ memcpy(w_inode, inode, bufsize);
+
+ group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
+ offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
+ EXT2_INODE_SIZE(fs->super);
+ block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
+ if (!fs->group_desc[(unsigned) group].bg_inode_table)
+ return EXT2_ET_MISSING_INODE_TABLE;
+ block_nr = fs->group_desc[(unsigned) group].bg_inode_table + block;
+
+ offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
+
+ length = EXT2_INODE_SIZE(fs->super);
+ if (length > bufsize)
+ length = bufsize;
+
+ ptr = (char *) w_inode;
+
+ while (length) {
+ clen = length;
+ if ((offset + length) > fs->blocksize)
+ clen = fs->blocksize - offset;
+
+ if (fs->icache->buffer_blk != block_nr) {
+ retval = io_channel_read_blk(fs->io, block_nr, 1,
+ fs->icache->buffer);
+ if (retval)
+ goto errout;
+ fs->icache->buffer_blk = block_nr;
+ }
+
+
+ memcpy((char *) fs->icache->buffer + (unsigned) offset,
+ ptr, clen);
+
+ retval = io_channel_write_blk(fs->io, block_nr, 1,
+ fs->icache->buffer);
+ if (retval)
+ goto errout;
+
+ offset = 0;
+ ptr += clen;
+ length -= clen;
+ block_nr++;
+ }
+
+ fs->flags |= EXT2_FLAG_CHANGED;
+errout:
+ if (w_inode && w_inode != &temp_inode)
+ free(w_inode);
+ return retval;
+}
+
+errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode *inode)
+{
+ return ext2fs_write_inode_full(fs, ino, inode,
+ sizeof(struct ext2_inode));
+}
+
+/*
+ * This function should be called when writing a new inode. It makes
+ * sure that extra part of large inodes is initialized properly.
+ */
+errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode *inode)
+{
+ struct ext2_inode *buf;
+ int size = EXT2_INODE_SIZE(fs->super);
+ struct ext2_inode_large *large_inode;
+
+ if (size == sizeof(struct ext2_inode))
+ return ext2fs_write_inode_full(fs, ino, inode,
+ sizeof(struct ext2_inode));
+
+ buf = xmalloc(size);
+
+ memset(buf, 0, size);
+ *buf = *inode;
+
+ large_inode = (struct ext2_inode_large *) buf;
+ large_inode->i_extra_isize = sizeof(struct ext2_inode_large) -
+ EXT2_GOOD_OLD_INODE_SIZE;
+
+ return ext2fs_write_inode_full(fs, ino, buf, size);
+}
+
+
+errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks)
+{
+ struct ext2_inode inode;
+ int i;
+ errcode_t retval;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ if (ino > fs->super->s_inodes_count)
+ return EXT2_ET_BAD_INODE_NUM;
+
+ if (fs->get_blocks) {
+ if (!(*fs->get_blocks)(fs, ino, blocks))
+ return 0;
+ }
+ retval = ext2fs_read_inode(fs, ino, &inode);
+ if (retval)
+ return retval;
+ for (i=0; i < EXT2_N_BLOCKS; i++)
+ blocks[i] = inode.i_block[i];
+ return 0;
+}
+
+errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino)
+{
+ struct ext2_inode inode;
+ errcode_t retval;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ if (ino > fs->super->s_inodes_count)
+ return EXT2_ET_BAD_INODE_NUM;
+
+ if (fs->check_directory) {
+ retval = (fs->check_directory)(fs, ino);
+ if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
+ return retval;
+ }
+ retval = ext2fs_read_inode(fs, ino, &inode);
+ if (retval)
+ return retval;
+ if (!LINUX_S_ISDIR(inode.i_mode))
+ return EXT2_ET_NO_DIRECTORY;
+ return 0;
+}
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/inode_io.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/inode_io.c
new file mode 100644
index 0000000000..4bfa93aef4
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/inode_io.c
@@ -0,0 +1,271 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * inode_io.c --- This is allows an inode in an ext2 filesystem image
+ * to be accessed via the I/O manager interface.
+ *
+ * Copyright (C) 2002 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <time.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * For checking structure magic numbers...
+ */
+
+#define EXT2_CHECK_MAGIC(struct, code) \
+ if ((struct)->magic != (code)) return (code)
+
+struct inode_private_data {
+ int magic;
+ char name[32];
+ ext2_file_t file;
+ ext2_filsys fs;
+ ext2_ino_t ino;
+ struct ext2_inode inode;
+ int flags;
+ struct inode_private_data *next;
+};
+
+#define CHANNEL_HAS_INODE 0x8000
+
+static struct inode_private_data *top_intern;
+static int ino_unique = 0;
+
+static errcode_t inode_open(const char *name, int flags, io_channel *channel);
+static errcode_t inode_close(io_channel channel);
+static errcode_t inode_set_blksize(io_channel channel, int blksize);
+static errcode_t inode_read_blk(io_channel channel, unsigned long block,
+ int count, void *data);
+static errcode_t inode_write_blk(io_channel channel, unsigned long block,
+ int count, const void *data);
+static errcode_t inode_flush(io_channel channel);
+static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
+ int size, const void *data);
+
+static struct struct_io_manager struct_inode_manager = {
+ EXT2_ET_MAGIC_IO_MANAGER,
+ "Inode I/O Manager",
+ inode_open,
+ inode_close,
+ inode_set_blksize,
+ inode_read_blk,
+ inode_write_blk,
+ inode_flush,
+ inode_write_byte
+};
+
+io_manager inode_io_manager = &struct_inode_manager;
+
+errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode *inode,
+ char **name)
+{
+ struct inode_private_data *data;
+ errcode_t retval;
+
+ if ((retval = ext2fs_get_mem(sizeof(struct inode_private_data),
+ &data)))
+ return retval;
+ data->magic = EXT2_ET_MAGIC_INODE_IO_CHANNEL;
+ sprintf(data->name, "%u:%d", ino, ino_unique++);
+ data->file = 0;
+ data->fs = fs;
+ data->ino = ino;
+ data->flags = 0;
+ if (inode) {
+ memcpy(&data->inode, inode, sizeof(struct ext2_inode));
+ data->flags |= CHANNEL_HAS_INODE;
+ }
+ data->next = top_intern;
+ top_intern = data;
+ *name = data->name;
+ return 0;
+}
+
+errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino,
+ char **name)
+{
+ return ext2fs_inode_io_intern2(fs, ino, NULL, name);
+}
+
+
+static errcode_t inode_open(const char *name, int flags, io_channel *channel)
+{
+ io_channel io = NULL;
+ struct inode_private_data *prev, *data = NULL;
+ errcode_t retval;
+ int open_flags;
+
+ if (name == 0)
+ return EXT2_ET_BAD_DEVICE_NAME;
+
+ for (data = top_intern, prev = NULL; data;
+ prev = data, data = data->next)
+ if (strcmp(name, data->name) == 0)
+ break;
+ if (!data)
+ return ENOENT;
+ if (prev)
+ prev->next = data->next;
+ else
+ top_intern = data->next;
+
+ retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
+ if (retval)
+ goto cleanup;
+ memset(io, 0, sizeof(struct struct_io_channel));
+
+ io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
+ io->manager = inode_io_manager;
+ retval = ext2fs_get_mem(strlen(name)+1, &io->name);
+ if (retval)
+ goto cleanup;
+
+ strcpy(io->name, name);
+ io->private_data = data;
+ io->block_size = 1024;
+ io->read_error = 0;
+ io->write_error = 0;
+ io->refcount = 1;
+
+ open_flags = (flags & IO_FLAG_RW) ? EXT2_FILE_WRITE : 0;
+ retval = ext2fs_file_open2(data->fs, data->ino,
+ (data->flags & CHANNEL_HAS_INODE) ?
+ &data->inode : 0, open_flags,
+ &data->file);
+ if (retval)
+ goto cleanup;
+
+ *channel = io;
+ return 0;
+
+cleanup:
+ if (data) {
+ ext2fs_free_mem(&data);
+ }
+ if (io)
+ ext2fs_free_mem(&io);
+ return retval;
+}
+
+static errcode_t inode_close(io_channel channel)
+{
+ struct inode_private_data *data;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct inode_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
+
+ if (--channel->refcount > 0)
+ return 0;
+
+ retval = ext2fs_file_close(data->file);
+
+ ext2fs_free_mem(&channel->private_data);
+ if (channel->name)
+ ext2fs_free_mem(&channel->name);
+ ext2fs_free_mem(&channel);
+ return retval;
+}
+
+static errcode_t inode_set_blksize(io_channel channel, int blksize)
+{
+ struct inode_private_data *data;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct inode_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
+
+ channel->block_size = blksize;
+ return 0;
+}
+
+
+static errcode_t inode_read_blk(io_channel channel, unsigned long block,
+ int count, void *buf)
+{
+ struct inode_private_data *data;
+ errcode_t retval;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct inode_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
+
+ if ((retval = ext2fs_file_lseek(data->file,
+ block * channel->block_size,
+ EXT2_SEEK_SET, 0)))
+ return retval;
+
+ count = (count < 0) ? -count : (count * channel->block_size);
+
+ return ext2fs_file_read(data->file, buf, count, 0);
+}
+
+static errcode_t inode_write_blk(io_channel channel, unsigned long block,
+ int count, const void *buf)
+{
+ struct inode_private_data *data;
+ errcode_t retval;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct inode_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
+
+ if ((retval = ext2fs_file_lseek(data->file,
+ block * channel->block_size,
+ EXT2_SEEK_SET, 0)))
+ return retval;
+
+ count = (count < 0) ? -count : (count * channel->block_size);
+
+ return ext2fs_file_write(data->file, buf, count, 0);
+}
+
+static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
+ int size, const void *buf)
+{
+ struct inode_private_data *data;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct inode_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
+
+ if ((retval = ext2fs_file_lseek(data->file, offset,
+ EXT2_SEEK_SET, 0)))
+ return retval;
+
+ return ext2fs_file_write(data->file, buf, size, 0);
+}
+
+/*
+ * Flush data buffers to disk.
+ */
+static errcode_t inode_flush(io_channel channel)
+{
+ struct inode_private_data *data;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct inode_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
+
+ return ext2fs_file_flush(data->file);
+}
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/io_manager.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/io_manager.c
new file mode 100644
index 0000000000..b47038602a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/io_manager.c
@@ -0,0 +1,70 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * io_manager.c --- the I/O manager abstraction
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+errcode_t io_channel_set_options(io_channel channel, const char *opts)
+{
+ errcode_t retval = 0;
+ char *next, *ptr, *options, *arg;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+
+ if (!opts)
+ return 0;
+
+ if (!channel->manager->set_option)
+ return EXT2_ET_INVALID_ARGUMENT;
+
+ options = malloc(strlen(opts)+1);
+ if (!options)
+ return EXT2_ET_NO_MEMORY;
+ strcpy(options, opts);
+ ptr = options;
+
+ while (ptr && *ptr) {
+ next = strchr(ptr, '&');
+ if (next)
+ *next++ = 0;
+
+ arg = strchr(ptr, '=');
+ if (arg)
+ *arg++ = 0;
+
+ retval = (channel->manager->set_option)(channel, ptr, arg);
+ if (retval)
+ break;
+ ptr = next;
+ }
+ free(options);
+ return retval;
+}
+
+errcode_t io_channel_write_byte(io_channel channel, unsigned long offset,
+ int count, const void *data)
+{
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+
+ if (channel->manager->write_byte)
+ return channel->manager->write_byte(channel, offset,
+ count, data);
+
+ return EXT2_ET_UNIMPLEMENTED;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/irel.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/irel.h
new file mode 100644
index 0000000000..91d1d89d5f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/irel.h
@@ -0,0 +1,115 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * irel.h
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+struct ext2_inode_reference {
+ blk_t block;
+ __u16 offset;
+};
+
+struct ext2_inode_relocate_entry {
+ ext2_ino_t new;
+ ext2_ino_t orig;
+ __u16 flags;
+ __u16 max_refs;
+};
+
+typedef struct ext2_inode_relocation_table *ext2_irel;
+
+struct ext2_inode_relocation_table {
+ __u32 magic;
+ char *name;
+ ext2_ino_t current;
+ void *priv_data;
+
+ /*
+ * Add an inode relocation entry.
+ */
+ errcode_t (*put)(ext2_irel irel, ext2_ino_t old,
+ struct ext2_inode_relocate_entry *ent);
+ /*
+ * Get an inode relocation entry.
+ */
+ errcode_t (*get)(ext2_irel irel, ext2_ino_t old,
+ struct ext2_inode_relocate_entry *ent);
+
+ /*
+ * Get an inode relocation entry by its original inode number
+ */
+ errcode_t (*get_by_orig)(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old,
+ struct ext2_inode_relocate_entry *ent);
+
+ /*
+ * Initialize for iterating over the inode relocation entries.
+ */
+ errcode_t (*start_iter)(ext2_irel irel);
+
+ /*
+ * The iterator function for the inode relocation entries.
+ * Returns an inode number of 0 when out of entries.
+ */
+ errcode_t (*next)(ext2_irel irel, ext2_ino_t *old,
+ struct ext2_inode_relocate_entry *ent);
+
+ /*
+ * Add an inode reference (i.e., note the fact that a
+ * particular block/offset contains a reference to an inode)
+ */
+ errcode_t (*add_ref)(ext2_irel irel, ext2_ino_t ino,
+ struct ext2_inode_reference *ref);
+
+ /*
+ * Initialize for iterating over the inode references for a
+ * particular inode.
+ */
+ errcode_t (*start_iter_ref)(ext2_irel irel, ext2_ino_t ino);
+
+ /*
+ * The iterator function for the inode references for an
+ * inode. The references for only one inode can be interator
+ * over at a time, as the iterator state is stored in ext2_irel.
+ */
+ errcode_t (*next_ref)(ext2_irel irel,
+ struct ext2_inode_reference *ref);
+
+ /*
+ * Move the inode relocation table from one inode number to
+ * another. Note that the inode references also must move.
+ */
+ errcode_t (*move)(ext2_irel irel, ext2_ino_t old, ext2_ino_t new);
+
+ /*
+ * Remove an inode relocation entry, along with all of the
+ * inode references.
+ */
+ errcode_t (*delete)(ext2_irel irel, ext2_ino_t old);
+
+ /*
+ * Free the inode relocation table.
+ */
+ errcode_t (*free)(ext2_irel irel);
+};
+
+errcode_t ext2fs_irel_memarray_create(char *name, ext2_ino_t max_inode,
+ ext2_irel *irel);
+
+#define ext2fs_irel_put(irel, old, ent) ((irel)->put((irel), old, ent))
+#define ext2fs_irel_get(irel, old, ent) ((irel)->get((irel), old, ent))
+#define ext2fs_irel_get_by_orig(irel, orig, old, ent) \
+ ((irel)->get_by_orig((irel), orig, old, ent))
+#define ext2fs_irel_start_iter(irel) ((irel)->start_iter((irel)))
+#define ext2fs_irel_next(irel, old, ent) ((irel)->next((irel), old, ent))
+#define ext2fs_irel_add_ref(irel, ino, ref) ((irel)->add_ref((irel), ino, ref))
+#define ext2fs_irel_start_iter_ref(irel, ino) ((irel)->start_iter_ref((irel), ino))
+#define ext2fs_irel_next_ref(irel, ref) ((irel)->next_ref((irel), ref))
+#define ext2fs_irel_move(irel, old, new) ((irel)->move((irel), old, new))
+#define ext2fs_irel_delete(irel, old) ((irel)->delete((irel), old))
+#define ext2fs_irel_free(irel) ((irel)->free((irel)))
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/irel_ma.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/irel_ma.c
new file mode 100644
index 0000000000..c871b18919
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/irel_ma.c
@@ -0,0 +1,367 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * irel_ma.c
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+#include "irel.h"
+
+static errcode_t ima_put(ext2_irel irel, ext2_ino_t old,
+ struct ext2_inode_relocate_entry *ent);
+static errcode_t ima_get(ext2_irel irel, ext2_ino_t old,
+ struct ext2_inode_relocate_entry *ent);
+static errcode_t ima_get_by_orig(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old,
+ struct ext2_inode_relocate_entry *ent);
+static errcode_t ima_start_iter(ext2_irel irel);
+static errcode_t ima_next(ext2_irel irel, ext2_ino_t *old,
+ struct ext2_inode_relocate_entry *ent);
+static errcode_t ima_add_ref(ext2_irel irel, ext2_ino_t ino,
+ struct ext2_inode_reference *ref);
+static errcode_t ima_start_iter_ref(ext2_irel irel, ext2_ino_t ino);
+static errcode_t ima_next_ref(ext2_irel irel, struct ext2_inode_reference *ref);
+static errcode_t ima_move(ext2_irel irel, ext2_ino_t old, ext2_ino_t new);
+static errcode_t ima_delete(ext2_irel irel, ext2_ino_t old);
+static errcode_t ima_free(ext2_irel irel);
+
+/*
+ * This data structure stores the array of inode references; there is
+ * a structure for each inode.
+ */
+struct inode_reference_entry {
+ __u16 num;
+ struct ext2_inode_reference *refs;
+};
+
+struct irel_ma {
+ __u32 magic;
+ ext2_ino_t max_inode;
+ ext2_ino_t ref_current;
+ int ref_iter;
+ ext2_ino_t *orig_map;
+ struct ext2_inode_relocate_entry *entries;
+ struct inode_reference_entry *ref_entries;
+};
+
+errcode_t ext2fs_irel_memarray_create(char *name, ext2_ino_t max_inode,
+ ext2_irel *new_irel)
+{
+ ext2_irel irel = 0;
+ errcode_t retval;
+ struct irel_ma *ma = 0;
+ size_t size;
+
+ *new_irel = 0;
+
+ /*
+ * Allocate memory structures
+ */
+ retval = ext2fs_get_mem(sizeof(struct ext2_inode_relocation_table),
+ &irel);
+ if (retval)
+ goto errout;
+ memset(irel, 0, sizeof(struct ext2_inode_relocation_table));
+
+ retval = ext2fs_get_mem(strlen(name)+1, &irel->name);
+ if (retval)
+ goto errout;
+ strcpy(irel->name, name);
+
+ retval = ext2fs_get_mem(sizeof(struct irel_ma), &ma);
+ if (retval)
+ goto errout;
+ memset(ma, 0, sizeof(struct irel_ma));
+ irel->priv_data = ma;
+
+ size = (size_t) (sizeof(ext2_ino_t) * (max_inode+1));
+ retval = ext2fs_get_mem(size, &ma->orig_map);
+ if (retval)
+ goto errout;
+ memset(ma->orig_map, 0, size);
+
+ size = (size_t) (sizeof(struct ext2_inode_relocate_entry) *
+ (max_inode+1));
+ retval = ext2fs_get_mem(size, &ma->entries);
+ if (retval)
+ goto errout;
+ memset(ma->entries, 0, size);
+
+ size = (size_t) (sizeof(struct inode_reference_entry) *
+ (max_inode+1));
+ retval = ext2fs_get_mem(size, &ma->ref_entries);
+ if (retval)
+ goto errout;
+ memset(ma->ref_entries, 0, size);
+ ma->max_inode = max_inode;
+
+ /*
+ * Fill in the irel data structure
+ */
+ irel->put = ima_put;
+ irel->get = ima_get;
+ irel->get_by_orig = ima_get_by_orig;
+ irel->start_iter = ima_start_iter;
+ irel->next = ima_next;
+ irel->add_ref = ima_add_ref;
+ irel->start_iter_ref = ima_start_iter_ref;
+ irel->next_ref = ima_next_ref;
+ irel->move = ima_move;
+ irel->delete = ima_delete;
+ irel->free = ima_free;
+
+ *new_irel = irel;
+ return 0;
+
+errout:
+ ima_free(irel);
+ return retval;
+}
+
+static errcode_t ima_put(ext2_irel irel, ext2_ino_t old,
+ struct ext2_inode_relocate_entry *ent)
+{
+ struct inode_reference_entry *ref_ent;
+ struct irel_ma *ma;
+ errcode_t retval;
+ size_t size, old_size;
+
+ ma = irel->priv_data;
+ if (old > ma->max_inode)
+ return EXT2_ET_INVALID_ARGUMENT;
+
+ /*
+ * Force the orig field to the correct value; the application
+ * program shouldn't be messing with this field.
+ */
+ if (ma->entries[(unsigned) old].new == 0)
+ ent->orig = old;
+ else
+ ent->orig = ma->entries[(unsigned) old].orig;
+
+ /*
+ * If max_refs has changed, reallocate the refs array
+ */
+ ref_ent = ma->ref_entries + (unsigned) old;
+ if (ref_ent->refs && ent->max_refs !=
+ ma->entries[(unsigned) old].max_refs) {
+ size = (sizeof(struct ext2_inode_reference) * ent->max_refs);
+ old_size = (sizeof(struct ext2_inode_reference) *
+ ma->entries[(unsigned) old].max_refs);
+ retval = ext2fs_resize_mem(old_size, size, &ref_ent->refs);
+ if (retval)
+ return retval;
+ }
+
+ ma->entries[(unsigned) old] = *ent;
+ ma->orig_map[(unsigned) ent->orig] = old;
+ return 0;
+}
+
+static errcode_t ima_get(ext2_irel irel, ext2_ino_t old,
+ struct ext2_inode_relocate_entry *ent)
+{
+ struct irel_ma *ma;
+
+ ma = irel->priv_data;
+ if (old > ma->max_inode)
+ return EXT2_ET_INVALID_ARGUMENT;
+ if (ma->entries[(unsigned) old].new == 0)
+ return ENOENT;
+ *ent = ma->entries[(unsigned) old];
+ return 0;
+}
+
+static errcode_t ima_get_by_orig(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old,
+ struct ext2_inode_relocate_entry *ent)
+{
+ struct irel_ma *ma;
+ ext2_ino_t ino;
+
+ ma = irel->priv_data;
+ if (orig > ma->max_inode)
+ return EXT2_ET_INVALID_ARGUMENT;
+ ino = ma->orig_map[(unsigned) orig];
+ if (ino == 0)
+ return ENOENT;
+ *old = ino;
+ *ent = ma->entries[(unsigned) ino];
+ return 0;
+}
+
+static errcode_t ima_start_iter(ext2_irel irel)
+{
+ irel->current = 0;
+ return 0;
+}
+
+static errcode_t ima_next(ext2_irel irel, ext2_ino_t *old,
+ struct ext2_inode_relocate_entry *ent)
+{
+ struct irel_ma *ma;
+
+ ma = irel->priv_data;
+ while (++irel->current < ma->max_inode) {
+ if (ma->entries[(unsigned) irel->current].new == 0)
+ continue;
+ *old = irel->current;
+ *ent = ma->entries[(unsigned) irel->current];
+ return 0;
+ }
+ *old = 0;
+ return 0;
+}
+
+static errcode_t ima_add_ref(ext2_irel irel, ext2_ino_t ino,
+ struct ext2_inode_reference *ref)
+{
+ struct irel_ma *ma;
+ size_t size;
+ struct inode_reference_entry *ref_ent;
+ struct ext2_inode_relocate_entry *ent;
+ errcode_t retval;
+
+ ma = irel->priv_data;
+ if (ino > ma->max_inode)
+ return EXT2_ET_INVALID_ARGUMENT;
+
+ ref_ent = ma->ref_entries + (unsigned) ino;
+ ent = ma->entries + (unsigned) ino;
+
+ /*
+ * If the inode reference array doesn't exist, create it.
+ */
+ if (ref_ent->refs == 0) {
+ size = (size_t) ((sizeof(struct ext2_inode_reference) *
+ ent->max_refs));
+ retval = ext2fs_get_mem(size, &ref_ent->refs);
+ if (retval)
+ return retval;
+ memset(ref_ent->refs, 0, size);
+ ref_ent->num = 0;
+ }
+
+ if (ref_ent->num >= ent->max_refs)
+ return EXT2_ET_TOO_MANY_REFS;
+
+ ref_ent->refs[(unsigned) ref_ent->num++] = *ref;
+ return 0;
+}
+
+static errcode_t ima_start_iter_ref(ext2_irel irel, ext2_ino_t ino)
+{
+ struct irel_ma *ma;
+
+ ma = irel->priv_data;
+ if (ino > ma->max_inode)
+ return EXT2_ET_INVALID_ARGUMENT;
+ if (ma->entries[(unsigned) ino].new == 0)
+ return ENOENT;
+ ma->ref_current = ino;
+ ma->ref_iter = 0;
+ return 0;
+}
+
+static errcode_t ima_next_ref(ext2_irel irel,
+ struct ext2_inode_reference *ref)
+{
+ struct irel_ma *ma;
+ struct inode_reference_entry *ref_ent;
+
+ ma = irel->priv_data;
+
+ ref_ent = ma->ref_entries + ma->ref_current;
+
+ if ((ref_ent->refs == NULL) ||
+ (ma->ref_iter >= ref_ent->num)) {
+ ref->block = 0;
+ ref->offset = 0;
+ return 0;
+ }
+ *ref = ref_ent->refs[ma->ref_iter++];
+ return 0;
+}
+
+
+static errcode_t ima_move(ext2_irel irel, ext2_ino_t old, ext2_ino_t new)
+{
+ struct irel_ma *ma;
+
+ ma = irel->priv_data;
+ if ((old > ma->max_inode) || (new > ma->max_inode))
+ return EXT2_ET_INVALID_ARGUMENT;
+ if (ma->entries[(unsigned) old].new == 0)
+ return ENOENT;
+
+ ma->entries[(unsigned) new] = ma->entries[(unsigned) old];
+ ext2fs_free_mem(&ma->ref_entries[(unsigned) new].refs);
+ ma->ref_entries[(unsigned) new] = ma->ref_entries[(unsigned) old];
+
+ ma->entries[(unsigned) old].new = 0;
+ ma->ref_entries[(unsigned) old].num = 0;
+ ma->ref_entries[(unsigned) old].refs = 0;
+
+ ma->orig_map[ma->entries[new].orig] = new;
+ return 0;
+}
+
+static errcode_t ima_delete(ext2_irel irel, ext2_ino_t old)
+{
+ struct irel_ma *ma;
+
+ ma = irel->priv_data;
+ if (old > ma->max_inode)
+ return EXT2_ET_INVALID_ARGUMENT;
+ if (ma->entries[(unsigned) old].new == 0)
+ return ENOENT;
+
+ ma->entries[old].new = 0;
+ ext2fs_free_mem(&ma->ref_entries[(unsigned) old].refs);
+ ma->orig_map[ma->entries[(unsigned) old].orig] = 0;
+
+ ma->ref_entries[(unsigned) old].num = 0;
+ ma->ref_entries[(unsigned) old].refs = 0;
+ return 0;
+}
+
+static errcode_t ima_free(ext2_irel irel)
+{
+ struct irel_ma *ma;
+ ext2_ino_t ino;
+
+ if (!irel)
+ return 0;
+
+ ma = irel->priv_data;
+
+ if (ma) {
+ ext2fs_free_mem(&ma->orig_map);
+ ext2fs_free_mem(&ma->entries);
+ if (ma->ref_entries) {
+ for (ino = 0; ino <= ma->max_inode; ino++) {
+ ext2fs_free_mem(&ma->ref_entries[(unsigned) ino].refs);
+ }
+ ext2fs_free_mem(&ma->ref_entries);
+ }
+ ext2fs_free_mem(&ma);
+ }
+ ext2fs_free_mem(&irel->name);
+ ext2fs_free_mem(&irel);
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ismounted.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ismounted.c
new file mode 100644
index 0000000000..d943f1185b
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/ismounted.c
@@ -0,0 +1,357 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * ismounted.c --- Check to see if the filesystem was mounted
+ *
+ * Copyright (C) 1995,1996,1997,1998,1999,2000 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <fcntl.h>
+#ifdef HAVE_LINUX_FD_H
+#include <linux/fd.h>
+#endif
+#ifdef HAVE_MNTENT_H
+#include <mntent.h>
+#endif
+#ifdef HAVE_GETMNTINFO
+#include <paths.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#endif /* HAVE_GETMNTINFO */
+#include <string.h>
+#include <sys/stat.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+#ifdef HAVE_MNTENT_H
+/*
+ * Helper function which checks a file in /etc/mtab format to see if a
+ * filesystem is mounted. Returns an error if the file doesn't exist
+ * or can't be opened.
+ */
+static errcode_t check_mntent_file(const char *mtab_file, const char *file,
+ int *mount_flags, char *mtpt, int mtlen)
+{
+ struct mntent *mnt;
+ struct stat st_buf;
+ errcode_t retval = 0;
+ dev_t file_dev=0, file_rdev=0;
+ ino_t file_ino=0;
+ FILE *f;
+ int fd;
+
+ *mount_flags = 0;
+ if ((f = setmntent (mtab_file, "r")) == NULL)
+ return errno;
+ if (stat(file, &st_buf) == 0) {
+ if (S_ISBLK(st_buf.st_mode)) {
+#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
+ file_rdev = st_buf.st_rdev;
+#endif /* __GNU__ */
+ } else {
+ file_dev = st_buf.st_dev;
+ file_ino = st_buf.st_ino;
+ }
+ }
+ while ((mnt = getmntent (f)) != NULL) {
+ if (strcmp(file, mnt->mnt_fsname) == 0)
+ break;
+ if (stat(mnt->mnt_fsname, &st_buf) == 0) {
+ if (S_ISBLK(st_buf.st_mode)) {
+#ifndef __GNU__
+ if (file_rdev && (file_rdev == st_buf.st_rdev))
+ break;
+#endif /* __GNU__ */
+ } else {
+ if (file_dev && ((file_dev == st_buf.st_dev) &&
+ (file_ino == st_buf.st_ino)))
+ break;
+ }
+ }
+ }
+
+ if (mnt == 0) {
+#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
+ /*
+ * Do an extra check to see if this is the root device. We
+ * can't trust /etc/mtab, and /proc/mounts will only list
+ * /dev/root for the root filesystem. Argh. Instead we
+ * check if the given device has the same major/minor number
+ * as the device that the root directory is on.
+ */
+ if (file_rdev && stat("/", &st_buf) == 0) {
+ if (st_buf.st_dev == file_rdev) {
+ *mount_flags = EXT2_MF_MOUNTED;
+ if (mtpt)
+ strncpy(mtpt, "/", mtlen);
+ goto is_root;
+ }
+ }
+#endif /* __GNU__ */
+ goto errout;
+ }
+#ifndef __GNU__ /* The GNU hurd is deficient; what else is new? */
+ /* Validate the entry in case /etc/mtab is out of date */
+ /*
+ * We need to be paranoid, because some broken distributions
+ * (read: Slackware) don't initialize /etc/mtab before checking
+ * all of the non-root filesystems on the disk.
+ */
+ if (stat(mnt->mnt_dir, &st_buf) < 0) {
+ retval = errno;
+ if (retval == ENOENT) {
+#ifdef DEBUG
+ printf("Bogus entry in %s! (%s does not exist)\n",
+ mtab_file, mnt->mnt_dir);
+#endif /* DEBUG */
+ retval = 0;
+ }
+ goto errout;
+ }
+ if (file_rdev && (st_buf.st_dev != file_rdev)) {
+#ifdef DEBUG
+ printf("Bogus entry in %s! (%s not mounted on %s)\n",
+ mtab_file, file, mnt->mnt_dir);
+#endif /* DEBUG */
+ goto errout;
+ }
+#endif /* __GNU__ */
+ *mount_flags = EXT2_MF_MOUNTED;
+
+#ifdef MNTOPT_RO
+ /* Check to see if the ro option is set */
+ if (hasmntopt(mnt, MNTOPT_RO))
+ *mount_flags |= EXT2_MF_READONLY;
+#endif
+
+ if (mtpt)
+ strncpy(mtpt, mnt->mnt_dir, mtlen);
+ /*
+ * Check to see if we're referring to the root filesystem.
+ * If so, do a manual check to see if we can open /etc/mtab
+ * read/write, since if the root is mounted read/only, the
+ * contents of /etc/mtab may not be accurate.
+ */
+ if (LONE_CHAR(mnt->mnt_dir, '/')) {
+is_root:
+#define TEST_FILE "/.ismount-test-file"
+ *mount_flags |= EXT2_MF_ISROOT;
+ fd = open(TEST_FILE, O_RDWR|O_CREAT);
+ if (fd < 0) {
+ if (errno == EROFS)
+ *mount_flags |= EXT2_MF_READONLY;
+ } else
+ close(fd);
+ (void) unlink(TEST_FILE);
+ }
+ retval = 0;
+errout:
+ endmntent (f);
+ return retval;
+}
+
+static errcode_t check_mntent(const char *file, int *mount_flags,
+ char *mtpt, int mtlen)
+{
+ errcode_t retval;
+
+#ifdef DEBUG
+ retval = check_mntent_file("/tmp/mtab", file, mount_flags,
+ mtpt, mtlen);
+ if (retval == 0)
+ return 0;
+#endif /* DEBUG */
+#ifdef __linux__
+ retval = check_mntent_file("/proc/mounts", file, mount_flags,
+ mtpt, mtlen);
+ if (retval == 0 && (*mount_flags != 0))
+ return 0;
+#endif /* __linux__ */
+#if defined(MOUNTED) || defined(_PATH_MOUNTED)
+#ifndef MOUNTED
+#define MOUNTED _PATH_MOUNTED
+#endif /* MOUNTED */
+ retval = check_mntent_file(MOUNTED, file, mount_flags, mtpt, mtlen);
+ return retval;
+#else
+ *mount_flags = 0;
+ return 0;
+#endif /* defined(MOUNTED) || defined(_PATH_MOUNTED) */
+}
+
+#else
+#if defined(HAVE_GETMNTINFO)
+
+static errcode_t check_getmntinfo(const char *file, int *mount_flags,
+ char *mtpt, int mtlen)
+{
+ struct statfs *mp;
+ int len, n;
+ const char *s1;
+ char *s2;
+
+ n = getmntinfo(&mp, MNT_NOWAIT);
+ if (n == 0)
+ return errno;
+
+ len = sizeof(_PATH_DEV) - 1;
+ s1 = file;
+ if (strncmp(_PATH_DEV, s1, len) == 0)
+ s1 += len;
+
+ *mount_flags = 0;
+ while (--n >= 0) {
+ s2 = mp->f_mntfromname;
+ if (strncmp(_PATH_DEV, s2, len) == 0) {
+ s2 += len - 1;
+ *s2 = 'r';
+ }
+ if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) {
+ *mount_flags = EXT2_MF_MOUNTED;
+ break;
+ }
+ ++mp;
+ }
+ if (mtpt)
+ strncpy(mtpt, mp->f_mntonname, mtlen);
+ return 0;
+}
+#endif /* HAVE_GETMNTINFO */
+#endif /* HAVE_MNTENT_H */
+
+/*
+ * Check to see if we're dealing with the swap device.
+ */
+static int is_swap_device(const char *file)
+{
+ FILE *f;
+ char buf[1024], *cp;
+ dev_t file_dev;
+ struct stat st_buf;
+ int ret = 0;
+
+ file_dev = 0;
+#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
+ if ((stat(file, &st_buf) == 0) &&
+ S_ISBLK(st_buf.st_mode))
+ file_dev = st_buf.st_rdev;
+#endif /* __GNU__ */
+
+ if (!(f = fopen("/proc/swaps", "r")))
+ return 0;
+ /* Skip the first line */
+ fgets(buf, sizeof(buf), f);
+ while (!feof(f)) {
+ if (!fgets(buf, sizeof(buf), f))
+ break;
+ if ((cp = strchr(buf, ' ')) != NULL)
+ *cp = 0;
+ if ((cp = strchr(buf, '\t')) != NULL)
+ *cp = 0;
+ if (strcmp(buf, file) == 0) {
+ ret++;
+ break;
+ }
+#ifndef __GNU__
+ if (file_dev && (stat(buf, &st_buf) == 0) &&
+ S_ISBLK(st_buf.st_mode) &&
+ file_dev == st_buf.st_rdev) {
+ ret++;
+ break;
+ }
+#endif /* __GNU__ */
+ }
+ fclose(f);
+ return ret;
+}
+
+
+/*
+ * ext2fs_check_mount_point() returns 1 if the device is mounted, 0
+ * otherwise. If mtpt is non-NULL, the directory where the device is
+ * mounted is copied to where mtpt is pointing, up to mtlen
+ * characters.
+ */
+#ifdef __TURBOC__
+# pragma argsused
+#endif
+errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags,
+ char *mtpt, int mtlen)
+{
+ if (is_swap_device(device)) {
+ *mount_flags = EXT2_MF_MOUNTED | EXT2_MF_SWAP;
+ strncpy(mtpt, "<swap>", mtlen);
+ return 0;
+ }
+#ifdef HAVE_MNTENT_H
+ return check_mntent(device, mount_flags, mtpt, mtlen);
+#else
+#ifdef HAVE_GETMNTINFO
+ return check_getmntinfo(device, mount_flags, mtpt, mtlen);
+#else
+#ifdef __GNUC__
+ #warning "Can't use getmntent or getmntinfo to check for mounted filesystems!"
+#endif
+ *mount_flags = 0;
+ return 0;
+#endif /* HAVE_GETMNTINFO */
+#endif /* HAVE_MNTENT_H */
+}
+
+/*
+ * ext2fs_check_if_mounted() sets the mount_flags EXT2_MF_MOUNTED,
+ * EXT2_MF_READONLY, and EXT2_MF_ROOT
+ *
+ */
+errcode_t ext2fs_check_if_mounted(const char *file, int *mount_flags)
+{
+ return ext2fs_check_mount_point(file, mount_flags, NULL, 0);
+}
+
+#ifdef DEBUG
+int main(int argc, char **argv)
+{
+ int retval, mount_flags;
+ char mntpt[80];
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s device\n", argv[0]);
+ exit(1);
+ }
+
+ mntpt[0] = 0;
+ retval = ext2fs_check_mount_point(argv[1], &mount_flags,
+ mntpt, sizeof(mntpt));
+ if (retval) {
+ com_err(argv[0], retval,
+ "while calling ext2fs_check_if_mounted");
+ exit(1);
+ }
+ printf("Device %s reports flags %02x\n", argv[1], mount_flags);
+ if (mount_flags & EXT2_MF_BUSY)
+ printf("\t%s is apparently in use.\n", argv[1]);
+ if (mount_flags & EXT2_MF_MOUNTED)
+ printf("\t%s is mounted.\n", argv[1]);
+ if (mount_flags & EXT2_MF_SWAP)
+ printf("\t%s is a swap device.\n", argv[1]);
+ if (mount_flags & EXT2_MF_READONLY)
+ printf("\t%s is read-only.\n", argv[1]);
+ if (mount_flags & EXT2_MF_ISROOT)
+ printf("\t%s is the root filesystem.\n", argv[1]);
+ if (mntpt[0])
+ printf("\t%s is mounted on %s.\n", argv[1], mntpt);
+ exit(0);
+}
+#endif /* DEBUG */
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/jfs_dat.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/jfs_dat.h
new file mode 100644
index 0000000000..136635de08
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/jfs_dat.h
@@ -0,0 +1,65 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * jfs_dat.h --- stripped down header file which only contains the JFS
+ * on-disk data structures
+ */
+
+#define JFS_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */
+
+/*
+ * On-disk structures
+ */
+
+/*
+ * Descriptor block types:
+ */
+
+#define JFS_DESCRIPTOR_BLOCK 1
+#define JFS_COMMIT_BLOCK 2
+#define JFS_SUPERBLOCK 3
+
+/*
+ * Standard header for all descriptor blocks:
+ */
+typedef struct journal_header_s
+{
+ __u32 h_magic;
+ __u32 h_blocktype;
+ __u32 h_sequence;
+} journal_header_t;
+
+
+/*
+ * The block tag: used to describe a single buffer in the journal
+ */
+typedef struct journal_block_tag_s
+{
+ __u32 t_blocknr; /* The on-disk block number */
+ __u32 t_flags; /* See below */
+} journal_block_tag_t;
+
+/* Definitions for the journal tag flags word: */
+#define JFS_FLAG_ESCAPE 1 /* on-disk block is escaped */
+#define JFS_FLAG_SAME_UUID 2 /* block has same uuid as previous */
+#define JFS_FLAG_DELETED 4 /* block deleted by this transaction */
+#define JFS_FLAG_LAST_TAG 8 /* last tag in this descriptor block */
+
+
+/*
+ * The journal superblock
+ */
+typedef struct journal_superblock_s
+{
+ journal_header_t s_header;
+
+ /* Static information describing the journal */
+ __u32 s_blocksize; /* journal device blocksize */
+ __u32 s_maxlen; /* total blocks in journal file */
+ __u32 s_first; /* first block of log information */
+
+ /* Dynamic information describing the current state of the log */
+ __u32 s_sequence; /* first commit ID expected in log */
+ __u32 s_start; /* blocknr of start of log */
+
+} journal_superblock_t;
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/kernel-jbd.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/kernel-jbd.h
new file mode 100644
index 0000000000..4c6c7dedd3
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/kernel-jbd.h
@@ -0,0 +1,236 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * linux/include/linux/jbd.h
+ *
+ * Written by Stephen C. Tweedie <sct@redhat.com>
+ *
+ * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * Definitions for transaction data structures for the buffer cache
+ * filesystem journaling support.
+ */
+
+#ifndef _LINUX_JBD_H
+#define _LINUX_JBD_H
+
+#include <sys/types.h>
+#include <linux/types.h>
+#include "ext2fs.h"
+
+/*
+ * Standard header for all descriptor blocks:
+ */
+
+typedef struct journal_header_s
+{
+ __u32 h_magic;
+ __u32 h_blocktype;
+ __u32 h_sequence;
+} journal_header_t;
+
+/*
+ * This is the global e2fsck structure.
+ */
+typedef struct e2fsck_struct *e2fsck_t;
+
+
+struct inode {
+ e2fsck_t i_ctx;
+ ext2_ino_t i_ino;
+ struct ext2_inode i_ext2;
+};
+
+
+/*
+ * The journal superblock. All fields are in big-endian byte order.
+ */
+typedef struct journal_superblock_s
+{
+/* 0x0000 */
+ journal_header_t s_header;
+
+/* 0x000C */
+ /* Static information describing the journal */
+ __u32 s_blocksize; /* journal device blocksize */
+ __u32 s_maxlen; /* total blocks in journal file */
+ __u32 s_first; /* first block of log information */
+
+/* 0x0018 */
+ /* Dynamic information describing the current state of the log */
+ __u32 s_sequence; /* first commit ID expected in log */
+ __u32 s_start; /* blocknr of start of log */
+
+/* 0x0020 */
+ /* Error value, as set by journal_abort(). */
+ __s32 s_errno;
+
+/* 0x0024 */
+ /* Remaining fields are only valid in a version-2 superblock */
+ __u32 s_feature_compat; /* compatible feature set */
+ __u32 s_feature_incompat; /* incompatible feature set */
+ __u32 s_feature_ro_compat; /* readonly-compatible feature set */
+/* 0x0030 */
+ __u8 s_uuid[16]; /* 128-bit uuid for journal */
+
+/* 0x0040 */
+ __u32 s_nr_users; /* Nr of filesystems sharing log */
+
+ __u32 s_dynsuper; /* Blocknr of dynamic superblock copy*/
+
+/* 0x0048 */
+ __u32 s_max_transaction; /* Limit of journal blocks per trans.*/
+ __u32 s_max_trans_data; /* Limit of data blocks per trans. */
+
+/* 0x0050 */
+ __u32 s_padding[44];
+
+/* 0x0100 */
+ __u8 s_users[16*48]; /* ids of all fs'es sharing the log */
+/* 0x0400 */
+} journal_superblock_t;
+
+
+extern int journal_blocks_per_page(struct inode *inode);
+extern int jbd_blocks_per_page(struct inode *inode);
+
+#define JFS_MIN_JOURNAL_BLOCKS 1024
+
+
+/*
+ * Internal structures used by the logging mechanism:
+ */
+
+#define JFS_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */
+
+/*
+ * Descriptor block types:
+ */
+
+#define JFS_DESCRIPTOR_BLOCK 1
+#define JFS_COMMIT_BLOCK 2
+#define JFS_SUPERBLOCK_V1 3
+#define JFS_SUPERBLOCK_V2 4
+#define JFS_REVOKE_BLOCK 5
+
+/*
+ * The block tag: used to describe a single buffer in the journal
+ */
+typedef struct journal_block_tag_s
+{
+ __u32 t_blocknr; /* The on-disk block number */
+ __u32 t_flags; /* See below */
+} journal_block_tag_t;
+
+/*
+ * The revoke descriptor: used on disk to describe a series of blocks to
+ * be revoked from the log
+ */
+typedef struct journal_revoke_header_s
+{
+ journal_header_t r_header;
+ int r_count; /* Count of bytes used in the block */
+} journal_revoke_header_t;
+
+
+/* Definitions for the journal tag flags word: */
+#define JFS_FLAG_ESCAPE 1 /* on-disk block is escaped */
+#define JFS_FLAG_SAME_UUID 2 /* block has same uuid as previous */
+#define JFS_FLAG_DELETED 4 /* block deleted by this transaction */
+#define JFS_FLAG_LAST_TAG 8 /* last tag in this descriptor block */
+
+
+
+
+#define JFS_HAS_COMPAT_FEATURE(j,mask) \
+ ((j)->j_format_version >= 2 && \
+ ((j)->j_superblock->s_feature_compat & cpu_to_be32((mask))))
+#define JFS_HAS_RO_COMPAT_FEATURE(j,mask) \
+ ((j)->j_format_version >= 2 && \
+ ((j)->j_superblock->s_feature_ro_compat & cpu_to_be32((mask))))
+#define JFS_HAS_INCOMPAT_FEATURE(j,mask) \
+ ((j)->j_format_version >= 2 && \
+ ((j)->j_superblock->s_feature_incompat & cpu_to_be32((mask))))
+
+#define JFS_FEATURE_INCOMPAT_REVOKE 0x00000001
+
+/* Features known to this kernel version: */
+#define JFS_KNOWN_COMPAT_FEATURES 0
+#define JFS_KNOWN_ROCOMPAT_FEATURES 0
+#define JFS_KNOWN_INCOMPAT_FEATURES JFS_FEATURE_INCOMPAT_REVOKE
+
+/* Comparison functions for transaction IDs: perform comparisons using
+ * modulo arithmetic so that they work over sequence number wraps. */
+
+
+/*
+ * Definitions which augment the buffer_head layer
+ */
+
+/* journaling buffer types */
+#define BJ_None 0 /* Not journaled */
+#define BJ_SyncData 1 /* Normal data: flush before commit */
+#define BJ_AsyncData 2 /* writepage data: wait on it before commit */
+#define BJ_Metadata 3 /* Normal journaled metadata */
+#define BJ_Forget 4 /* Buffer superceded by this transaction */
+#define BJ_IO 5 /* Buffer is for temporary IO use */
+#define BJ_Shadow 6 /* Buffer contents being shadowed to the log */
+#define BJ_LogCtl 7 /* Buffer contains log descriptors */
+#define BJ_Reserved 8 /* Buffer is reserved for access by journal */
+#define BJ_Types 9
+
+
+struct kdev_s {
+ e2fsck_t k_ctx;
+ int k_dev;
+};
+
+typedef struct kdev_s *kdev_t;
+typedef unsigned int tid_t;
+
+struct journal_s
+{
+ unsigned long j_flags;
+ int j_errno;
+ struct buffer_head * j_sb_buffer;
+ struct journal_superblock_s *j_superblock;
+ int j_format_version;
+ unsigned long j_head;
+ unsigned long j_tail;
+ unsigned long j_free;
+ unsigned long j_first, j_last;
+ kdev_t j_dev;
+ kdev_t j_fs_dev;
+ int j_blocksize;
+ unsigned int j_blk_offset;
+ unsigned int j_maxlen;
+ struct inode * j_inode;
+ tid_t j_tail_sequence;
+ tid_t j_transaction_sequence;
+ __u8 j_uuid[16];
+ struct jbd_revoke_table_s *j_revoke;
+};
+
+typedef struct journal_s journal_t;
+
+extern int journal_recover (journal_t *journal);
+extern int journal_skip_recovery (journal_t *);
+
+/* Primary revoke support */
+extern int journal_init_revoke(journal_t *, int);
+extern void journal_destroy_revoke_caches(void);
+extern int journal_init_revoke_caches(void);
+
+/* Recovery revoke support */
+extern int journal_set_revoke(journal_t *, unsigned long, tid_t);
+extern int journal_test_revoke(journal_t *, unsigned long, tid_t);
+extern void journal_clear_revoke(journal_t *);
+extern void journal_brelse_array(struct buffer_head *b[], int n);
+
+extern void journal_destroy_revoke(journal_t *);
+
+
+#endif /* _LINUX_JBD_H */
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/kernel-list.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/kernel-list.h
new file mode 100644
index 0000000000..3392596ca8
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/kernel-list.h
@@ -0,0 +1,113 @@
+/* vi: set sw=4 ts=4: */
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = { &name, &name }
+
+#define INIT_LIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+#if (!defined(__GNUC__) && !defined(__WATCOMC__))
+#define __inline__
+#endif
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static __inline__ void __list_add(struct list_head * new,
+ struct list_head * prev,
+ struct list_head * next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/*
+ * Insert a new entry after the specified head..
+ */
+static __inline__ void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+/*
+ * Insert a new entry at the tail
+ */
+static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static __inline__ void __list_del(struct list_head * prev,
+ struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+static __inline__ void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+}
+
+static __inline__ int list_empty(struct list_head *head)
+{
+ return head->next == head;
+}
+
+/*
+ * Splice in "list" into "head"
+ */
+static __inline__ void list_splice(struct list_head *list, struct list_head *head)
+{
+ struct list_head *first = list->next;
+
+ if (first != list) {
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+ }
+}
+
+#define list_entry(ptr, type, member) \
+ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/link.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/link.c
new file mode 100644
index 0000000000..08b2e96738
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/link.c
@@ -0,0 +1,135 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * link.c --- create links in a ext2fs directory
+ *
+ * Copyright (C) 1993, 1994 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+struct link_struct {
+ const char *name;
+ int namelen;
+ ext2_ino_t inode;
+ int flags;
+ int done;
+ struct ext2_super_block *sb;
+};
+
+static int link_proc(struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data)
+{
+ struct link_struct *ls = (struct link_struct *) priv_data;
+ struct ext2_dir_entry *next;
+ int rec_len, min_rec_len;
+ int ret = 0;
+
+ rec_len = EXT2_DIR_REC_LEN(ls->namelen);
+
+ /*
+ * See if the following directory entry (if any) is unused;
+ * if so, absorb it into this one.
+ */
+ next = (struct ext2_dir_entry *) (buf + offset + dirent->rec_len);
+ if ((offset + dirent->rec_len < blocksize - 8) &&
+ (next->inode == 0) &&
+ (offset + dirent->rec_len + next->rec_len <= blocksize)) {
+ dirent->rec_len += next->rec_len;
+ ret = DIRENT_CHANGED;
+ }
+
+ /*
+ * If the directory entry is used, see if we can split the
+ * directory entry to make room for the new name. If so,
+ * truncate it and return.
+ */
+ if (dirent->inode) {
+ min_rec_len = EXT2_DIR_REC_LEN(dirent->name_len & 0xFF);
+ if (dirent->rec_len < (min_rec_len + rec_len))
+ return ret;
+ rec_len = dirent->rec_len - min_rec_len;
+ dirent->rec_len = min_rec_len;
+ next = (struct ext2_dir_entry *) (buf + offset +
+ dirent->rec_len);
+ next->inode = 0;
+ next->name_len = 0;
+ next->rec_len = rec_len;
+ return DIRENT_CHANGED;
+ }
+
+ /*
+ * If we get this far, then the directory entry is not used.
+ * See if we can fit the request entry in. If so, do it.
+ */
+ if (dirent->rec_len < rec_len)
+ return ret;
+ dirent->inode = ls->inode;
+ dirent->name_len = ls->namelen;
+ strncpy(dirent->name, ls->name, ls->namelen);
+ if (ls->sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
+ dirent->name_len |= (ls->flags & 0x7) << 8;
+
+ ls->done++;
+ return DIRENT_ABORT|DIRENT_CHANGED;
+}
+
+/*
+ * Note: the low 3 bits of the flags field are used as the directory
+ * entry filetype.
+ */
+#ifdef __TURBOC__
+# pragma argsused
+#endif
+errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name,
+ ext2_ino_t ino, int flags)
+{
+ errcode_t retval;
+ struct link_struct ls;
+ struct ext2_inode inode;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ if (!(fs->flags & EXT2_FLAG_RW))
+ return EXT2_ET_RO_FILSYS;
+
+ ls.name = name;
+ ls.namelen = name ? strlen(name) : 0;
+ ls.inode = ino;
+ ls.flags = flags;
+ ls.done = 0;
+ ls.sb = fs->super;
+
+ retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY,
+ 0, link_proc, &ls);
+ if (retval)
+ return retval;
+
+ if (!ls.done)
+ return EXT2_ET_DIR_NO_SPACE;
+
+ if ((retval = ext2fs_read_inode(fs, dir, &inode)) != 0)
+ return retval;
+
+ if (inode.i_flags & EXT2_INDEX_FL) {
+ inode.i_flags &= ~EXT2_INDEX_FL;
+ if ((retval = ext2fs_write_inode(fs, dir, &inode)) != 0)
+ return retval;
+ }
+
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/lookup.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/lookup.c
new file mode 100644
index 0000000000..31b30a1828
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/lookup.c
@@ -0,0 +1,70 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * lookup.c --- ext2fs directory lookup operations
+ *
+ * Copyright (C) 1993, 1994, 1994, 1995 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+struct lookup_struct {
+ const char *name;
+ int len;
+ ext2_ino_t *inode;
+ int found;
+};
+
+#ifdef __TURBOC__
+# pragma argsused
+#endif
+static int lookup_proc(struct ext2_dir_entry *dirent,
+ int offset EXT2FS_ATTR((unused)),
+ int blocksize EXT2FS_ATTR((unused)),
+ char *buf EXT2FS_ATTR((unused)),
+ void *priv_data)
+{
+ struct lookup_struct *ls = (struct lookup_struct *) priv_data;
+
+ if (ls->len != (dirent->name_len & 0xFF))
+ return 0;
+ if (strncmp(ls->name, dirent->name, (dirent->name_len & 0xFF)))
+ return 0;
+ *ls->inode = dirent->inode;
+ ls->found++;
+ return DIRENT_ABORT;
+}
+
+
+errcode_t ext2fs_lookup(ext2_filsys fs, ext2_ino_t dir, const char *name,
+ int namelen, char *buf, ext2_ino_t *inode)
+{
+ errcode_t retval;
+ struct lookup_struct ls;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ ls.name = name;
+ ls.len = namelen;
+ ls.inode = inode;
+ ls.found = 0;
+
+ retval = ext2fs_dir_iterate(fs, dir, 0, buf, lookup_proc, &ls);
+ if (retval)
+ return retval;
+
+ return (ls.found) ? 0 : EXT2_ET_FILE_NOT_FOUND;
+}
+
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/mkdir.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/mkdir.c
new file mode 100644
index 0000000000..b63c5d7a68
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/mkdir.c
@@ -0,0 +1,142 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * mkdir.c --- make a directory in the filesystem
+ *
+ * Copyright (C) 1994, 1995 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+#ifndef EXT2_FT_DIR
+#define EXT2_FT_DIR 2
+#endif
+
+errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
+ const char *name)
+{
+ errcode_t retval;
+ struct ext2_inode parent_inode, inode;
+ ext2_ino_t ino = inum;
+ ext2_ino_t scratch_ino;
+ blk_t blk;
+ char *block = 0;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ /*
+ * Allocate an inode, if necessary
+ */
+ if (!ino) {
+ retval = ext2fs_new_inode(fs, parent, LINUX_S_IFDIR | 0755,
+ 0, &ino);
+ if (retval)
+ goto cleanup;
+ }
+
+ /*
+ * Allocate a data block for the directory
+ */
+ retval = ext2fs_new_block(fs, 0, 0, &blk);
+ if (retval)
+ goto cleanup;
+
+ /*
+ * Create a scratch template for the directory
+ */
+ retval = ext2fs_new_dir_block(fs, ino, parent, &block);
+ if (retval)
+ goto cleanup;
+
+ /*
+ * Get the parent's inode, if necessary
+ */
+ if (parent != ino) {
+ retval = ext2fs_read_inode(fs, parent, &parent_inode);
+ if (retval)
+ goto cleanup;
+ } else
+ memset(&parent_inode, 0, sizeof(parent_inode));
+
+ /*
+ * Create the inode structure....
+ */
+ memset(&inode, 0, sizeof(struct ext2_inode));
+ inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask);
+ inode.i_uid = inode.i_gid = 0;
+ inode.i_blocks = fs->blocksize / 512;
+ inode.i_block[0] = blk;
+ inode.i_links_count = 2;
+ inode.i_ctime = inode.i_atime = inode.i_mtime = time(NULL);
+ inode.i_size = fs->blocksize;
+
+ /*
+ * Write out the inode and inode data block
+ */
+ retval = ext2fs_write_dir_block(fs, blk, block);
+ if (retval)
+ goto cleanup;
+ retval = ext2fs_write_new_inode(fs, ino, &inode);
+ if (retval)
+ goto cleanup;
+
+ /*
+ * Link the directory into the filesystem hierarchy
+ */
+ if (name) {
+ retval = ext2fs_lookup(fs, parent, name, strlen(name), 0,
+ &scratch_ino);
+ if (!retval) {
+ retval = EXT2_ET_DIR_EXISTS;
+ name = 0;
+ goto cleanup;
+ }
+ if (retval != EXT2_ET_FILE_NOT_FOUND)
+ goto cleanup;
+ retval = ext2fs_link(fs, parent, name, ino, EXT2_FT_DIR);
+ if (retval)
+ goto cleanup;
+ }
+
+ /*
+ * Update parent inode's counts
+ */
+ if (parent != ino) {
+ parent_inode.i_links_count++;
+ retval = ext2fs_write_inode(fs, parent, &parent_inode);
+ if (retval)
+ goto cleanup;
+ }
+
+ /*
+ * Update accounting....
+ */
+ ext2fs_block_alloc_stats(fs, blk, +1);
+ ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
+
+cleanup:
+ ext2fs_free_mem(&block);
+ return retval;
+
+}
+
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/mkjournal.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/mkjournal.c
new file mode 100644
index 0000000000..5bdd346820
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/mkjournal.c
@@ -0,0 +1,428 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * mkjournal.c --- make a journal for a filesystem
+ *
+ * Copyright (C) 2000 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#include "ext2_fs.h"
+#include "../e2p/e2p.h"
+#include "../e2fsck.h"
+#include "ext2fs.h"
+#include "kernel-jbd.h"
+
+/*
+ * This function automatically sets up the journal superblock and
+ * returns it as an allocated block.
+ */
+errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
+ __u32 size, int flags,
+ char **ret_jsb)
+{
+ errcode_t retval;
+ journal_superblock_t *jsb;
+
+ if (size < 1024)
+ return EXT2_ET_JOURNAL_TOO_SMALL;
+
+ if ((retval = ext2fs_get_mem(fs->blocksize, &jsb)))
+ return retval;
+
+ memset (jsb, 0, fs->blocksize);
+
+ jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
+ if (flags & EXT2_MKJOURNAL_V1_SUPER)
+ jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V1);
+ else
+ jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
+ jsb->s_blocksize = htonl(fs->blocksize);
+ jsb->s_maxlen = htonl(size);
+ jsb->s_nr_users = htonl(1);
+ jsb->s_first = htonl(1);
+ jsb->s_sequence = htonl(1);
+ memcpy(jsb->s_uuid, fs->super->s_uuid, sizeof(fs->super->s_uuid));
+ /*
+ * If we're creating an external journal device, we need to
+ * adjust these fields.
+ */
+ if (fs->super->s_feature_incompat &
+ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
+ jsb->s_nr_users = 0;
+ if (fs->blocksize == 1024)
+ jsb->s_first = htonl(3);
+ else
+ jsb->s_first = htonl(2);
+ }
+
+ *ret_jsb = (char *) jsb;
+ return 0;
+}
+
+/*
+ * This function writes a journal using POSIX routines. It is used
+ * for creating external journals and creating journals on live
+ * filesystems.
+ */
+static errcode_t write_journal_file(ext2_filsys fs, char *filename,
+ blk_t size, int flags)
+{
+ errcode_t retval;
+ char *buf = 0;
+ int fd, ret_size;
+ blk_t i;
+
+ if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf)))
+ return retval;
+
+ /* Open the device or journal file */
+ if ((fd = open(filename, O_WRONLY)) < 0) {
+ retval = errno;
+ goto errout;
+ }
+
+ /* Write the superblock out */
+ retval = EXT2_ET_SHORT_WRITE;
+ ret_size = write(fd, buf, fs->blocksize);
+ if (ret_size < 0) {
+ retval = errno;
+ goto errout;
+ }
+ if (ret_size != (int) fs->blocksize)
+ goto errout;
+ memset(buf, 0, fs->blocksize);
+
+ for (i = 1; i < size; i++) {
+ ret_size = write(fd, buf, fs->blocksize);
+ if (ret_size < 0) {
+ retval = errno;
+ goto errout;
+ }
+ if (ret_size != (int) fs->blocksize)
+ goto errout;
+ }
+ close(fd);
+
+ retval = 0;
+errout:
+ ext2fs_free_mem(&buf);
+ return retval;
+}
+
+/*
+ * Helper function for creating the journal using direct I/O routines
+ */
+struct mkjournal_struct {
+ int num_blocks;
+ int newblocks;
+ char *buf;
+ errcode_t err;
+};
+
+static int mkjournal_proc(ext2_filsys fs,
+ blk_t *blocknr,
+ e2_blkcnt_t blockcnt,
+ blk_t ref_block EXT2FS_ATTR((unused)),
+ int ref_offset EXT2FS_ATTR((unused)),
+ void *priv_data)
+{
+ struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data;
+ blk_t new_blk;
+ static blk_t last_blk = 0;
+ errcode_t retval;
+
+ if (*blocknr) {
+ last_blk = *blocknr;
+ return 0;
+ }
+ retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
+ if (retval) {
+ es->err = retval;
+ return BLOCK_ABORT;
+ }
+ if (blockcnt > 0)
+ es->num_blocks--;
+
+ es->newblocks++;
+ retval = io_channel_write_blk(fs->io, new_blk, 1, es->buf);
+
+ if (blockcnt == 0)
+ memset(es->buf, 0, fs->blocksize);
+
+ if (retval) {
+ es->err = retval;
+ return BLOCK_ABORT;
+ }
+ *blocknr = new_blk;
+ last_blk = new_blk;
+ ext2fs_block_alloc_stats(fs, new_blk, +1);
+
+ if (es->num_blocks == 0)
+ return (BLOCK_CHANGED | BLOCK_ABORT);
+ else
+ return BLOCK_CHANGED;
+
+}
+
+/*
+ * This function creates a journal using direct I/O routines.
+ */
+static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
+ blk_t size, int flags)
+{
+ char *buf;
+ errcode_t retval;
+ struct ext2_inode inode;
+ struct mkjournal_struct es;
+
+ if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf)))
+ return retval;
+
+ if ((retval = ext2fs_read_bitmaps(fs)))
+ return retval;
+
+ if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
+ return retval;
+
+ if (inode.i_blocks > 0)
+ return EEXIST;
+
+ es.num_blocks = size;
+ es.newblocks = 0;
+ es.buf = buf;
+ es.err = 0;
+
+ retval = ext2fs_block_iterate2(fs, journal_ino, BLOCK_FLAG_APPEND,
+ 0, mkjournal_proc, &es);
+ if (es.err) {
+ retval = es.err;
+ goto errout;
+ }
+
+ if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
+ goto errout;
+
+ inode.i_size += fs->blocksize * size;
+ inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
+ inode.i_mtime = inode.i_ctime = time(0);
+ inode.i_links_count = 1;
+ inode.i_mode = LINUX_S_IFREG | 0600;
+
+ if ((retval = ext2fs_write_inode(fs, journal_ino, &inode)))
+ goto errout;
+ retval = 0;
+
+ memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4);
+ fs->super->s_jnl_blocks[16] = inode.i_size;
+ fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
+ ext2fs_mark_super_dirty(fs);
+
+errout:
+ ext2fs_free_mem(&buf);
+ return retval;
+}
+
+/*
+ * This function adds a journal device to a filesystem
+ */
+errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev)
+{
+ struct stat st;
+ errcode_t retval;
+ char buf[1024];
+ journal_superblock_t *jsb;
+ int start;
+ __u32 i, nr_users;
+
+ /* Make sure the device exists and is a block device */
+ if (stat(journal_dev->device_name, &st) < 0)
+ return errno;
+
+ if (!S_ISBLK(st.st_mode))
+ return EXT2_ET_JOURNAL_NOT_BLOCK; /* Must be a block device */
+
+ /* Get the journal superblock */
+ start = 1;
+ if (journal_dev->blocksize == 1024)
+ start++;
+ if ((retval = io_channel_read_blk(journal_dev->io, start, -1024, buf)))
+ return retval;
+
+ jsb = (journal_superblock_t *) buf;
+ if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
+ (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2)))
+ return EXT2_ET_NO_JOURNAL_SB;
+
+ if (ntohl(jsb->s_blocksize) != (unsigned long) fs->blocksize)
+ return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
+
+ /* Check and see if this filesystem has already been added */
+ nr_users = ntohl(jsb->s_nr_users);
+ for (i=0; i < nr_users; i++) {
+ if (memcmp(fs->super->s_uuid,
+ &jsb->s_users[i*16], 16) == 0)
+ break;
+ }
+ if (i >= nr_users) {
+ memcpy(&jsb->s_users[nr_users*16],
+ fs->super->s_uuid, 16);
+ jsb->s_nr_users = htonl(nr_users+1);
+ }
+
+ /* Writeback the journal superblock */
+ if ((retval = io_channel_write_blk(journal_dev->io, start, -1024, buf)))
+ return retval;
+
+ fs->super->s_journal_inum = 0;
+ fs->super->s_journal_dev = st.st_rdev;
+ memcpy(fs->super->s_journal_uuid, jsb->s_uuid,
+ sizeof(fs->super->s_journal_uuid));
+ fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
+ ext2fs_mark_super_dirty(fs);
+ return 0;
+}
+
+/*
+ * This function adds a journal inode to a filesystem, using either
+ * POSIX routines if the filesystem is mounted, or using direct I/O
+ * functions if it is not.
+ */
+errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size, int flags)
+{
+ errcode_t retval;
+ ext2_ino_t journal_ino;
+ struct stat st;
+ char jfile[1024];
+ int fd, mount_flags, f;
+
+ retval = ext2fs_check_mount_point(fs->device_name, &mount_flags,
+ jfile, sizeof(jfile)-10);
+ if (retval)
+ return retval;
+
+ if (mount_flags & EXT2_MF_MOUNTED) {
+ strcat(jfile, "/.journal");
+
+ /*
+ * If .../.journal already exists, make sure any
+ * immutable or append-only flags are cleared.
+ */
+#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
+ (void) chflags (jfile, 0);
+#else
+#if HAVE_EXT2_IOCTLS
+ fd = open(jfile, O_RDONLY);
+ if (fd >= 0) {
+ f = 0;
+ ioctl(fd, EXT2_IOC_SETFLAGS, &f);
+ close(fd);
+ }
+#endif
+#endif
+
+ /* Create the journal file */
+ if ((fd = open(jfile, O_CREAT|O_WRONLY, 0600)) < 0)
+ return errno;
+
+ if ((retval = write_journal_file(fs, jfile, size, flags)))
+ goto errout;
+
+ /* Get inode number of the journal file */
+ if (fstat(fd, &st) < 0)
+ goto errout;
+
+#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
+ retval = fchflags (fd, UF_NODUMP|UF_IMMUTABLE);
+#else
+#if HAVE_EXT2_IOCTLS
+ f = EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL;
+ retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f);
+#endif
+#endif
+ if (retval)
+ goto errout;
+
+ close(fd);
+ journal_ino = st.st_ino;
+ } else {
+ journal_ino = EXT2_JOURNAL_INO;
+ if ((retval = write_journal_inode(fs, journal_ino,
+ size, flags)))
+ return retval;
+ }
+
+ fs->super->s_journal_inum = journal_ino;
+ fs->super->s_journal_dev = 0;
+ memset(fs->super->s_journal_uuid, 0,
+ sizeof(fs->super->s_journal_uuid));
+ fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
+
+ ext2fs_mark_super_dirty(fs);
+ return 0;
+errout:
+ close(fd);
+ return retval;
+}
+
+#ifdef DEBUG
+main(int argc, char **argv)
+{
+ errcode_t retval;
+ char *device_name;
+ ext2_filsys fs;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s filesystem\n", argv[0]);
+ exit(1);
+ }
+ device_name = argv[1];
+
+ retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0,
+ unix_io_manager, &fs);
+ if (retval) {
+ com_err(argv[0], retval, "while opening %s", device_name);
+ exit(1);
+ }
+
+ retval = ext2fs_add_journal_inode(fs, 1024);
+ if (retval) {
+ com_err(argv[0], retval, "while adding journal to %s",
+ device_name);
+ exit(1);
+ }
+ retval = ext2fs_flush(fs);
+ if (retval) {
+ printf("Warning, had trouble writing out superblocks.\n");
+ }
+ ext2fs_close(fs);
+ exit(0);
+
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/namei.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/namei.c
new file mode 100644
index 0000000000..988967009b
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/namei.c
@@ -0,0 +1,205 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * namei.c --- ext2fs directory lookup operations
+ *
+ * Copyright (C) 1993, 1994, 1994, 1995 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* #define NAMEI_DEBUG */
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base,
+ const char *pathname, size_t pathlen, int follow,
+ int link_count, char *buf, ext2_ino_t *res_inode);
+
+static errcode_t follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
+ ext2_ino_t inode, int link_count,
+ char *buf, ext2_ino_t *res_inode)
+{
+ char *pathname;
+ char *buffer = 0;
+ errcode_t retval;
+ struct ext2_inode ei;
+
+#ifdef NAMEI_DEBUG
+ printf("follow_link: root=%lu, dir=%lu, inode=%lu, lc=%d\n",
+ root, dir, inode, link_count);
+
+#endif
+ retval = ext2fs_read_inode (fs, inode, &ei);
+ if (retval) return retval;
+ if (!LINUX_S_ISLNK (ei.i_mode)) {
+ *res_inode = inode;
+ return 0;
+ }
+ if (link_count++ > 5) {
+ return EXT2_ET_SYMLINK_LOOP;
+ }
+ if (ext2fs_inode_data_blocks(fs,&ei)) {
+ retval = ext2fs_get_mem(fs->blocksize, &buffer);
+ if (retval)
+ return retval;
+ retval = io_channel_read_blk(fs->io, ei.i_block[0], 1, buffer);
+ if (retval) {
+ ext2fs_free_mem(&buffer);
+ return retval;
+ }
+ pathname = buffer;
+ } else
+ pathname = (char *)&(ei.i_block[0]);
+ retval = open_namei(fs, root, dir, pathname, ei.i_size, 1,
+ link_count, buf, res_inode);
+ ext2fs_free_mem(&buffer);
+ return retval;
+}
+
+/*
+ * This routine interprets a pathname in the context of the current
+ * directory and the root directory, and returns the inode of the
+ * containing directory, and a pointer to the filename of the file
+ * (pointing into the pathname) and the length of the filename.
+ */
+static errcode_t dir_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
+ const char *pathname, int pathlen,
+ int link_count, char *buf,
+ const char **name, int *namelen,
+ ext2_ino_t *res_inode)
+{
+ char c;
+ const char *thisname;
+ int len;
+ ext2_ino_t inode;
+ errcode_t retval;
+
+ if ((c = *pathname) == '/') {
+ dir = root;
+ pathname++;
+ pathlen--;
+ }
+ while (1) {
+ thisname = pathname;
+ for (len=0; --pathlen >= 0;len++) {
+ c = *(pathname++);
+ if (c == '/')
+ break;
+ }
+ if (pathlen < 0)
+ break;
+ retval = ext2fs_lookup (fs, dir, thisname, len, buf, &inode);
+ if (retval) return retval;
+ retval = follow_link (fs, root, dir, inode,
+ link_count, buf, &dir);
+ if (retval) return retval;
+ }
+ *name = thisname;
+ *namelen = len;
+ *res_inode = dir;
+ return 0;
+}
+
+static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base,
+ const char *pathname, size_t pathlen, int follow,
+ int link_count, char *buf, ext2_ino_t *res_inode)
+{
+ const char *basename;
+ int namelen;
+ ext2_ino_t dir, inode;
+ errcode_t retval;
+
+#ifdef NAMEI_DEBUG
+ printf("open_namei: root=%lu, dir=%lu, path=%*s, lc=%d\n",
+ root, base, pathlen, pathname, link_count);
+#endif
+ retval = dir_namei(fs, root, base, pathname, pathlen,
+ link_count, buf, &basename, &namelen, &dir);
+ if (retval) return retval;
+ if (!namelen) { /* special case: '/usr/' etc */
+ *res_inode=dir;
+ return 0;
+ }
+ retval = ext2fs_lookup (fs, dir, basename, namelen, buf, &inode);
+ if (retval)
+ return retval;
+ if (follow) {
+ retval = follow_link(fs, root, dir, inode, link_count,
+ buf, &inode);
+ if (retval)
+ return retval;
+ }
+#ifdef NAMEI_DEBUG
+ printf("open_namei: (link_count=%d) returns %lu\n",
+ link_count, inode);
+#endif
+ *res_inode = inode;
+ return 0;
+}
+
+errcode_t ext2fs_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
+ const char *name, ext2_ino_t *inode)
+{
+ char *buf;
+ errcode_t retval;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ retval = ext2fs_get_mem(fs->blocksize, &buf);
+ if (retval)
+ return retval;
+
+ retval = open_namei(fs, root, cwd, name, strlen(name), 0, 0,
+ buf, inode);
+
+ ext2fs_free_mem(&buf);
+ return retval;
+}
+
+errcode_t ext2fs_namei_follow(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
+ const char *name, ext2_ino_t *inode)
+{
+ char *buf;
+ errcode_t retval;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ retval = ext2fs_get_mem(fs->blocksize, &buf);
+ if (retval)
+ return retval;
+
+ retval = open_namei(fs, root, cwd, name, strlen(name), 1, 0,
+ buf, inode);
+
+ ext2fs_free_mem(&buf);
+ return retval;
+}
+
+errcode_t ext2fs_follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
+ ext2_ino_t inode, ext2_ino_t *res_inode)
+{
+ char *buf;
+ errcode_t retval;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ retval = ext2fs_get_mem(fs->blocksize, &buf);
+ if (retval)
+ return retval;
+
+ retval = follow_link(fs, root, cwd, inode, 0, buf, res_inode);
+
+ ext2fs_free_mem(&buf);
+ return retval;
+}
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/newdir.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/newdir.c
new file mode 100644
index 0000000000..9470e7f567
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/newdir.c
@@ -0,0 +1,73 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * newdir.c --- create a new directory block
+ *
+ * Copyright (C) 1994, 1995 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+#ifndef EXT2_FT_DIR
+#define EXT2_FT_DIR 2
+#endif
+
+/*
+ * Create new directory block
+ */
+errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
+ ext2_ino_t parent_ino, char **block)
+{
+ struct ext2_dir_entry *dir = NULL;
+ errcode_t retval;
+ char *buf;
+ int rec_len;
+ int filetype = 0;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ retval = ext2fs_get_mem(fs->blocksize, &buf);
+ if (retval)
+ return retval;
+ memset(buf, 0, fs->blocksize);
+ dir = (struct ext2_dir_entry *) buf;
+ dir->rec_len = fs->blocksize;
+
+ if (dir_ino) {
+ if (fs->super->s_feature_incompat &
+ EXT2_FEATURE_INCOMPAT_FILETYPE)
+ filetype = EXT2_FT_DIR << 8;
+ /*
+ * Set up entry for '.'
+ */
+ dir->inode = dir_ino;
+ dir->name_len = 1 | filetype;
+ dir->name[0] = '.';
+ rec_len = dir->rec_len - EXT2_DIR_REC_LEN(1);
+ dir->rec_len = EXT2_DIR_REC_LEN(1);
+
+ /*
+ * Set up entry for '..'
+ */
+ dir = (struct ext2_dir_entry *) (buf + dir->rec_len);
+ dir->rec_len = rec_len;
+ dir->inode = parent_ino;
+ dir->name_len = 2 | filetype;
+ dir->name[0] = '.';
+ dir->name[1] = '.';
+
+ }
+ *block = buf;
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/openfs.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/openfs.c
new file mode 100644
index 0000000000..1b271196b1
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/openfs.c
@@ -0,0 +1,330 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * openfs.c --- open an ext2 filesystem
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+
+
+#include "ext2fs.h"
+#include "e2image.h"
+
+blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block, dgrp_t i)
+{
+ int bg;
+ int has_super = 0;
+ int ret_blk;
+
+ if (!(fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) ||
+ (i < fs->super->s_first_meta_bg))
+ return (group_block + i + 1);
+
+ bg = (fs->blocksize / sizeof (struct ext2_group_desc)) * i;
+ if (ext2fs_bg_has_super(fs, bg))
+ has_super = 1;
+ ret_blk = (fs->super->s_first_data_block + has_super +
+ (bg * fs->super->s_blocks_per_group));
+ /*
+ * If group_block is not the normal value, we're trying to use
+ * the backup group descriptors and superblock --- so use the
+ * alternate location of the second block group in the
+ * metablock group. Ideally we should be testing each bg
+ * descriptor block individually for correctness, but we don't
+ * have the infrastructure in place to do that.
+ */
+ if (group_block != fs->super->s_first_data_block &&
+ ((ret_blk + fs->super->s_blocks_per_group) <
+ fs->super->s_blocks_count))
+ ret_blk += fs->super->s_blocks_per_group;
+ return ret_blk;
+}
+
+errcode_t ext2fs_open(const char *name, int flags, int superblock,
+ unsigned int block_size, io_manager manager,
+ ext2_filsys *ret_fs)
+{
+ return ext2fs_open2(name, 0, flags, superblock, block_size,
+ manager, ret_fs);
+}
+
+/*
+ * Note: if superblock is non-zero, block-size must also be non-zero.
+ * Superblock and block_size can be zero to use the default size.
+ *
+ * Valid flags for ext2fs_open()
+ *
+ * EXT2_FLAG_RW - Open the filesystem for read/write.
+ * EXT2_FLAG_FORCE - Open the filesystem even if some of the
+ * features aren't supported.
+ * EXT2_FLAG_JOURNAL_DEV_OK - Open an ext3 journal device
+ */
+errcode_t ext2fs_open2(const char *name, const char *io_options,
+ int flags, int superblock,
+ unsigned int block_size, io_manager manager,
+ ext2_filsys *ret_fs)
+{
+ ext2_filsys fs;
+ errcode_t retval;
+ unsigned long i;
+ int groups_per_block, blocks_per_group;
+ blk_t group_block, blk;
+ char *dest, *cp;
+#if BB_BIG_ENDIAN
+ int j;
+ struct ext2_group_desc *gdp;
+#endif
+
+ EXT2_CHECK_MAGIC(manager, EXT2_ET_MAGIC_IO_MANAGER);
+
+ retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
+ if (retval)
+ return retval;
+
+ memset(fs, 0, sizeof(struct struct_ext2_filsys));
+ fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
+ fs->flags = flags;
+ fs->umask = 022;
+ retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name);
+ if (retval)
+ goto cleanup;
+ strcpy(fs->device_name, name);
+ cp = strchr(fs->device_name, '?');
+ if (!io_options && cp) {
+ *cp++ = 0;
+ io_options = cp;
+ }
+
+ retval = manager->open(fs->device_name,
+ (flags & EXT2_FLAG_RW) ? IO_FLAG_RW : 0,
+ &fs->io);
+ if (retval)
+ goto cleanup;
+ if (io_options &&
+ (retval = io_channel_set_options(fs->io, io_options)))
+ goto cleanup;
+ fs->image_io = fs->io;
+ fs->io->app_data = fs;
+ retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->super);
+ if (retval)
+ goto cleanup;
+ if (flags & EXT2_FLAG_IMAGE_FILE) {
+ retval = ext2fs_get_mem(sizeof(struct ext2_image_hdr),
+ &fs->image_header);
+ if (retval)
+ goto cleanup;
+ retval = io_channel_read_blk(fs->io, 0,
+ -(int)sizeof(struct ext2_image_hdr),
+ fs->image_header);
+ if (retval)
+ goto cleanup;
+ if (fs->image_header->magic_number != EXT2_ET_MAGIC_E2IMAGE)
+ return EXT2_ET_MAGIC_E2IMAGE;
+ superblock = 1;
+ block_size = fs->image_header->fs_blocksize;
+ }
+
+ /*
+ * If the user specifies a specific block # for the
+ * superblock, then he/she must also specify the block size!
+ * Otherwise, read the master superblock located at offset
+ * SUPERBLOCK_OFFSET from the start of the partition.
+ *
+ * Note: we only save a backup copy of the superblock if we
+ * are reading the superblock from the primary superblock location.
+ */
+ if (superblock) {
+ if (!block_size) {
+ retval = EXT2_ET_INVALID_ARGUMENT;
+ goto cleanup;
+ }
+ io_channel_set_blksize(fs->io, block_size);
+ group_block = superblock;
+ fs->orig_super = 0;
+ } else {
+ io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
+ superblock = 1;
+ group_block = 0;
+ retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super);
+ if (retval)
+ goto cleanup;
+ }
+ retval = io_channel_read_blk(fs->io, superblock, -SUPERBLOCK_SIZE,
+ fs->super);
+ if (retval)
+ goto cleanup;
+ if (fs->orig_super)
+ memcpy(fs->orig_super, fs->super, SUPERBLOCK_SIZE);
+
+#if BB_BIG_ENDIAN
+ if ((fs->super->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) ||
+ (fs->flags & EXT2_FLAG_SWAP_BYTES)) {
+ fs->flags |= EXT2_FLAG_SWAP_BYTES;
+
+ ext2fs_swap_super(fs->super);
+ }
+#endif
+
+ if (fs->super->s_magic != EXT2_SUPER_MAGIC) {
+ retval = EXT2_ET_BAD_MAGIC;
+ goto cleanup;
+ }
+ if (fs->super->s_rev_level > EXT2_LIB_CURRENT_REV) {
+ retval = EXT2_ET_REV_TOO_HIGH;
+ goto cleanup;
+ }
+
+ /*
+ * Check for feature set incompatibility
+ */
+ if (!(flags & EXT2_FLAG_FORCE)) {
+ if (fs->super->s_feature_incompat &
+ ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
+ retval = EXT2_ET_UNSUPP_FEATURE;
+ goto cleanup;
+ }
+ if ((flags & EXT2_FLAG_RW) &&
+ (fs->super->s_feature_ro_compat &
+ ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP)) {
+ retval = EXT2_ET_RO_UNSUPP_FEATURE;
+ goto cleanup;
+ }
+ if (!(flags & EXT2_FLAG_JOURNAL_DEV_OK) &&
+ (fs->super->s_feature_incompat &
+ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
+ retval = EXT2_ET_UNSUPP_FEATURE;
+ goto cleanup;
+ }
+ }
+
+ fs->blocksize = EXT2_BLOCK_SIZE(fs->super);
+ if (fs->blocksize == 0) {
+ retval = EXT2_ET_CORRUPT_SUPERBLOCK;
+ goto cleanup;
+ }
+ fs->fragsize = EXT2_FRAG_SIZE(fs->super);
+ fs->inode_blocks_per_group = ((fs->super->s_inodes_per_group *
+ EXT2_INODE_SIZE(fs->super) +
+ EXT2_BLOCK_SIZE(fs->super) - 1) /
+ EXT2_BLOCK_SIZE(fs->super));
+ if (block_size) {
+ if (block_size != fs->blocksize) {
+ retval = EXT2_ET_UNEXPECTED_BLOCK_SIZE;
+ goto cleanup;
+ }
+ }
+ /*
+ * Set the blocksize to the filesystem's blocksize.
+ */
+ io_channel_set_blksize(fs->io, fs->blocksize);
+
+ /*
+ * If this is an external journal device, don't try to read
+ * the group descriptors, because they're not there.
+ */
+ if (fs->super->s_feature_incompat &
+ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
+ fs->group_desc_count = 0;
+ *ret_fs = fs;
+ return 0;
+ }
+
+ /*
+ * Read group descriptors
+ */
+ blocks_per_group = EXT2_BLOCKS_PER_GROUP(fs->super);
+ if (blocks_per_group == 0 ||
+ blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(fs->super) ||
+ fs->inode_blocks_per_group > EXT2_MAX_INODES_PER_GROUP(fs->super)) {
+ retval = EXT2_ET_CORRUPT_SUPERBLOCK;
+ goto cleanup;
+ }
+ fs->group_desc_count = (fs->super->s_blocks_count -
+ fs->super->s_first_data_block +
+ blocks_per_group - 1) / blocks_per_group;
+ fs->desc_blocks = (fs->group_desc_count +
+ EXT2_DESC_PER_BLOCK(fs->super) - 1)
+ / EXT2_DESC_PER_BLOCK(fs->super);
+ retval = ext2fs_get_mem(fs->desc_blocks * fs->blocksize,
+ &fs->group_desc);
+ if (retval)
+ goto cleanup;
+ if (!group_block)
+ group_block = fs->super->s_first_data_block;
+ dest = (char *) fs->group_desc;
+ groups_per_block = fs->blocksize / sizeof(struct ext2_group_desc);
+ for (i = 0; i < fs->desc_blocks; i++) {
+ blk = ext2fs_descriptor_block_loc(fs, group_block, i);
+ retval = io_channel_read_blk(fs->io, blk, 1, dest);
+ if (retval)
+ goto cleanup;
+#if BB_BIG_ENDIAN
+ if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
+ gdp = (struct ext2_group_desc *) dest;
+ for (j=0; j < groups_per_block; j++)
+ ext2fs_swap_group_desc(gdp++);
+ }
+#endif
+ dest += fs->blocksize;
+ }
+
+ *ret_fs = fs;
+ return 0;
+cleanup:
+ ext2fs_free(fs);
+ return retval;
+}
+
+/*
+ * Set/get the filesystem data I/O channel.
+ *
+ * These functions are only valid if EXT2_FLAG_IMAGE_FILE is true.
+ */
+errcode_t ext2fs_get_data_io(ext2_filsys fs, io_channel *old_io)
+{
+ if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
+ return EXT2_ET_NOT_IMAGE_FILE;
+ if (old_io) {
+ *old_io = (fs->image_io == fs->io) ? 0 : fs->io;
+ }
+ return 0;
+}
+
+errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io)
+{
+ if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
+ return EXT2_ET_NOT_IMAGE_FILE;
+ fs->io = new_io ? new_io : fs->image_io;
+ return 0;
+}
+
+errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io)
+{
+ if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
+ return EXT2_ET_NOT_IMAGE_FILE;
+ fs->io = fs->image_io = new_io;
+ fs->flags |= EXT2_FLAG_DIRTY | EXT2_FLAG_RW |
+ EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
+ fs->flags &= ~EXT2_FLAG_IMAGE_FILE;
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/read_bb.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/read_bb.c
new file mode 100644
index 0000000000..4766157c23
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/read_bb.c
@@ -0,0 +1,98 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * read_bb --- read the bad blocks inode
+ *
+ * Copyright (C) 1994 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+struct read_bb_record {
+ ext2_badblocks_list bb_list;
+ errcode_t err;
+};
+
+/*
+ * Helper function for ext2fs_read_bb_inode()
+ */
+#ifdef __TURBOC__
+# pragma argsused
+#endif
+static int mark_bad_block(ext2_filsys fs, blk_t *block_nr,
+ e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
+ blk_t ref_block EXT2FS_ATTR((unused)),
+ int ref_offset EXT2FS_ATTR((unused)),
+ void *priv_data)
+{
+ struct read_bb_record *rb = (struct read_bb_record *) priv_data;
+
+ if (blockcnt < 0)
+ return 0;
+
+ if ((*block_nr < fs->super->s_first_data_block) ||
+ (*block_nr >= fs->super->s_blocks_count))
+ return 0; /* Ignore illegal blocks */
+
+ rb->err = ext2fs_badblocks_list_add(rb->bb_list, *block_nr);
+ if (rb->err)
+ return BLOCK_ABORT;
+ return 0;
+}
+
+/*
+ * Reads the current bad blocks from the bad blocks inode.
+ */
+errcode_t ext2fs_read_bb_inode(ext2_filsys fs, ext2_badblocks_list *bb_list)
+{
+ errcode_t retval;
+ struct read_bb_record rb;
+ struct ext2_inode inode;
+ blk_t numblocks;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ if (!*bb_list) {
+ retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode);
+ if (retval)
+ return retval;
+ if (inode.i_blocks < 500)
+ numblocks = (inode.i_blocks /
+ (fs->blocksize / 512)) + 20;
+ else
+ numblocks = 500;
+ retval = ext2fs_badblocks_list_create(bb_list, numblocks);
+ if (retval)
+ return retval;
+ }
+
+ rb.bb_list = *bb_list;
+ rb.err = 0;
+ retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO, 0, 0,
+ mark_bad_block, &rb);
+ if (retval)
+ return retval;
+
+ return rb.err;
+}
+
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/read_bb_file.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/read_bb_file.c
new file mode 100644
index 0000000000..831adcc3a2
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/read_bb_file.c
@@ -0,0 +1,98 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * read_bb_file.c --- read a list of bad blocks from a FILE *
+ *
+ * Copyright (C) 1994, 1995, 2000 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * Reads a list of bad blocks from a FILE *
+ */
+errcode_t ext2fs_read_bb_FILE2(ext2_filsys fs, FILE *f,
+ ext2_badblocks_list *bb_list,
+ void *priv_data,
+ void (*invalid)(ext2_filsys fs,
+ blk_t blk,
+ char *badstr,
+ void *priv_data))
+{
+ errcode_t retval;
+ blk_t blockno;
+ int count;
+ char buf[128];
+
+ if (fs)
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ if (!*bb_list) {
+ retval = ext2fs_badblocks_list_create(bb_list, 10);
+ if (retval)
+ return retval;
+ }
+
+ while (!feof (f)) {
+ if (fgets(buf, sizeof(buf), f) == NULL)
+ break;
+ count = sscanf(buf, "%u", &blockno);
+ if (count <= 0)
+ continue;
+ if (fs &&
+ ((blockno < fs->super->s_first_data_block) ||
+ (blockno >= fs->super->s_blocks_count))) {
+ if (invalid)
+ (invalid)(fs, blockno, buf, priv_data);
+ continue;
+ }
+ retval = ext2fs_badblocks_list_add(*bb_list, blockno);
+ if (retval)
+ return retval;
+ }
+ return 0;
+}
+
+static void call_compat_invalid(ext2_filsys fs, blk_t blk,
+ char *badstr EXT2FS_ATTR((unused)),
+ void *priv_data)
+{
+ void (*invalid)(ext2_filsys, blk_t);
+
+ invalid = (void (*)(ext2_filsys, blk_t)) priv_data;
+ if (invalid)
+ invalid(fs, blk);
+}
+
+
+/*
+ * Reads a list of bad blocks from a FILE *
+ */
+errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f,
+ ext2_badblocks_list *bb_list,
+ void (*invalid)(ext2_filsys fs, blk_t blk))
+{
+ return ext2fs_read_bb_FILE2(fs, f, bb_list, (void *) invalid,
+ call_compat_invalid);
+}
+
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/res_gdt.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/res_gdt.c
new file mode 100644
index 0000000000..f7ee8b1fb3
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/res_gdt.c
@@ -0,0 +1,221 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * res_gdt.c --- reserve blocks for growing the group descriptor table
+ * during online resizing.
+ *
+ * Copyright (C) 2002 Andreas Dilger
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * Iterate through the groups which hold BACKUP superblock/GDT copies in an
+ * ext3 filesystem. The counters should be initialized to 1, 5, and 7 before
+ * calling this for the first time. In a sparse filesystem it will be the
+ * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ...
+ * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ...
+ */
+static unsigned int list_backups(ext2_filsys fs, unsigned int *three,
+ unsigned int *five, unsigned int *seven)
+{
+ unsigned int *min = three;
+ int mult = 3;
+ unsigned int ret;
+
+ if (!(fs->super->s_feature_ro_compat &
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
+ ret = *min;
+ *min += 1;
+ return ret;
+ }
+
+ if (*five < *min) {
+ min = five;
+ mult = 5;
+ }
+ if (*seven < *min) {
+ min = seven;
+ mult = 7;
+ }
+
+ ret = *min;
+ *min *= mult;
+
+ return ret;
+}
+
+/*
+ * This code assumes that the reserved blocks have already been marked in-use
+ * during ext2fs_initialize(), so that they are not allocated for other
+ * uses before we can add them to the resize inode (which has to come
+ * after the creation of the inode table).
+ */
+errcode_t ext2fs_create_resize_inode(ext2_filsys fs)
+{
+ errcode_t retval, retval2;
+ struct ext2_super_block *sb;
+ struct ext2_inode inode;
+ __u32 *dindir_buf, *gdt_buf;
+ int rsv_add;
+ unsigned long long apb, inode_size;
+ blk_t dindir_blk, rsv_off, gdt_off, gdt_blk;
+ int dindir_dirty = 0, inode_dirty = 0;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ sb = fs->super;
+
+ retval = ext2fs_get_mem(2 * fs->blocksize, (void *)&dindir_buf);
+ if (retval)
+ goto out_free;
+ gdt_buf = (__u32 *)((char *)dindir_buf + fs->blocksize);
+
+ retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
+ if (retval)
+ goto out_free;
+
+ /* Maximum possible file size (we donly use the dindirect blocks) */
+ apb = EXT2_ADDR_PER_BLOCK(sb);
+ rsv_add = fs->blocksize / 512;
+ if ((dindir_blk = inode.i_block[EXT2_DIND_BLOCK])) {
+#ifdef RES_GDT_DEBUG
+ printf("reading GDT dindir %u\n", dindir_blk);
+#endif
+ retval = ext2fs_read_ind_block(fs, dindir_blk, dindir_buf);
+ if (retval)
+ goto out_inode;
+ } else {
+ blk_t goal = 3 + sb->s_reserved_gdt_blocks +
+ fs->desc_blocks + fs->inode_blocks_per_group;
+
+ retval = ext2fs_alloc_block(fs, goal, 0, &dindir_blk);
+ if (retval)
+ goto out_free;
+ inode.i_mode = LINUX_S_IFREG | 0600;
+ inode.i_links_count = 1;
+ inode.i_block[EXT2_DIND_BLOCK] = dindir_blk;
+ inode.i_blocks = rsv_add;
+ memset(dindir_buf, 0, fs->blocksize);
+#ifdef RES_GDT_DEBUG
+ printf("allocated GDT dindir %u\n", dindir_blk);
+#endif
+ dindir_dirty = inode_dirty = 1;
+ inode_size = apb*apb + apb + EXT2_NDIR_BLOCKS;
+ inode_size *= fs->blocksize;
+ inode.i_size = inode_size & 0xFFFFFFFF;
+ inode.i_size_high = (inode_size >> 32) & 0xFFFFFFFF;
+ if(inode.i_size_high) {
+ sb->s_feature_ro_compat |=
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
+ }
+ inode.i_ctime = time(0);
+ }
+
+ for (rsv_off = 0, gdt_off = fs->desc_blocks,
+ gdt_blk = sb->s_first_data_block + 1 + fs->desc_blocks;
+ rsv_off < sb->s_reserved_gdt_blocks;
+ rsv_off++, gdt_off++, gdt_blk++) {
+ unsigned int three = 1, five = 5, seven = 7;
+ unsigned int grp, last = 0;
+ int gdt_dirty = 0;
+
+ gdt_off %= apb;
+ if (!dindir_buf[gdt_off]) {
+ /* FIXME XXX XXX
+ blk_t new_blk;
+
+ retval = ext2fs_new_block(fs, gdt_blk, 0, &new_blk);
+ if (retval)
+ goto out_free;
+ if (new_blk != gdt_blk) {
+ // XXX free block
+ retval = -1; // XXX
+ }
+ */
+ gdt_dirty = dindir_dirty = inode_dirty = 1;
+ memset(gdt_buf, 0, fs->blocksize);
+ dindir_buf[gdt_off] = gdt_blk;
+ inode.i_blocks += rsv_add;
+#ifdef RES_GDT_DEBUG
+ printf("added primary GDT block %u at %u[%u]\n",
+ gdt_blk, dindir_blk, gdt_off);
+#endif
+ } else if (dindir_buf[gdt_off] == gdt_blk) {
+#ifdef RES_GDT_DEBUG
+ printf("reading primary GDT block %u\n", gdt_blk);
+#endif
+ retval = ext2fs_read_ind_block(fs, gdt_blk, gdt_buf);
+ if (retval)
+ goto out_dindir;
+ } else {
+#ifdef RES_GDT_DEBUG
+ printf("bad primary GDT %u != %u at %u[%u]\n",
+ dindir_buf[gdt_off], gdt_blk,dindir_blk,gdt_off);
+#endif
+ retval = EXT2_ET_RESIZE_INODE_CORRUPT;
+ goto out_dindir;
+ }
+
+ while ((grp = list_backups(fs, &three, &five, &seven)) <
+ fs->group_desc_count) {
+ blk_t expect = gdt_blk + grp * sb->s_blocks_per_group;
+
+ if (!gdt_buf[last]) {
+#ifdef RES_GDT_DEBUG
+ printf("added backup GDT %u grp %u@%u[%u]\n",
+ expect, grp, gdt_blk, last);
+#endif
+ gdt_buf[last] = expect;
+ inode.i_blocks += rsv_add;
+ gdt_dirty = inode_dirty = 1;
+ } else if (gdt_buf[last] != expect) {
+#ifdef RES_GDT_DEBUG
+ printf("bad backup GDT %u != %u at %u[%u]\n",
+ gdt_buf[last], expect, gdt_blk, last);
+#endif
+ retval = EXT2_ET_RESIZE_INODE_CORRUPT;
+ goto out_dindir;
+ }
+ last++;
+ }
+ if (gdt_dirty) {
+#ifdef RES_GDT_DEBUG
+ printf("writing primary GDT block %u\n", gdt_blk);
+#endif
+ retval = ext2fs_write_ind_block(fs, gdt_blk, gdt_buf);
+ if (retval)
+ goto out_dindir;
+ }
+ }
+
+out_dindir:
+ if (dindir_dirty) {
+ retval2 = ext2fs_write_ind_block(fs, dindir_blk, dindir_buf);
+ if (!retval)
+ retval = retval2;
+ }
+out_inode:
+#ifdef RES_GDT_DEBUG
+ printf("inode.i_blocks = %u, i_size = %u\n", inode.i_blocks,
+ inode.i_size);
+#endif
+ if (inode_dirty) {
+ inode.i_atime = inode.i_mtime = time(0);
+ retval2 = ext2fs_write_inode(fs, EXT2_RESIZE_INO, &inode);
+ if (!retval)
+ retval = retval2;
+ }
+out_free:
+ ext2fs_free_mem((void *)&dindir_buf);
+ return retval;
+}
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/rs_bitmap.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/rs_bitmap.c
new file mode 100644
index 0000000000..e932b3c9d9
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/rs_bitmap.c
@@ -0,0 +1,107 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * rs_bitmap.c --- routine for changing the size of a bitmap
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+errcode_t ext2fs_resize_generic_bitmap(__u32 new_end, __u32 new_real_end,
+ ext2fs_generic_bitmap bmap)
+{
+ errcode_t retval;
+ size_t size, new_size;
+ __u32 bitno;
+
+ if (!bmap)
+ return EXT2_ET_INVALID_ARGUMENT;
+
+ EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_GENERIC_BITMAP);
+
+ /*
+ * If we're expanding the bitmap, make sure all of the new
+ * parts of the bitmap are zero.
+ */
+ if (new_end > bmap->end) {
+ bitno = bmap->real_end;
+ if (bitno > new_end)
+ bitno = new_end;
+ for (; bitno > bmap->end; bitno--)
+ ext2fs_clear_bit(bitno - bmap->start, bmap->bitmap);
+ }
+ if (new_real_end == bmap->real_end) {
+ bmap->end = new_end;
+ return 0;
+ }
+
+ size = ((bmap->real_end - bmap->start) / 8) + 1;
+ new_size = ((new_real_end - bmap->start) / 8) + 1;
+
+ if (size != new_size) {
+ retval = ext2fs_resize_mem(size, new_size, &bmap->bitmap);
+ if (retval)
+ return retval;
+ }
+ if (new_size > size)
+ memset(bmap->bitmap + size, 0, new_size - size);
+
+ bmap->end = new_end;
+ bmap->real_end = new_real_end;
+ return 0;
+}
+
+errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end,
+ ext2fs_inode_bitmap bmap)
+{
+ errcode_t retval;
+
+ if (!bmap)
+ return EXT2_ET_INVALID_ARGUMENT;
+
+ EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_INODE_BITMAP);
+
+ bmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
+ retval = ext2fs_resize_generic_bitmap(new_end, new_real_end,
+ bmap);
+ bmap->magic = EXT2_ET_MAGIC_INODE_BITMAP;
+ return retval;
+}
+
+errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end,
+ ext2fs_block_bitmap bmap)
+{
+ errcode_t retval;
+
+ if (!bmap)
+ return EXT2_ET_INVALID_ARGUMENT;
+
+ EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_BLOCK_BITMAP);
+
+ bmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
+ retval = ext2fs_resize_generic_bitmap(new_end, new_real_end,
+ bmap);
+ bmap->magic = EXT2_ET_MAGIC_BLOCK_BITMAP;
+ return retval;
+}
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/rw_bitmaps.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/rw_bitmaps.c
new file mode 100644
index 0000000000..a5782db95a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/rw_bitmaps.c
@@ -0,0 +1,296 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * rw_bitmaps.c --- routines to read and write the inode and block bitmaps.
+ *
+ * Copyright (C) 1993, 1994, 1994, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+#include "e2image.h"
+
+#if defined(__powerpc__) && BB_BIG_ENDIAN
+/*
+ * On the PowerPC, the big-endian variant of the ext2 filesystem
+ * has its bitmaps stored as 32-bit words with bit 0 as the LSB
+ * of each word. Thus a bitmap with only bit 0 set would be, as
+ * a string of bytes, 00 00 00 01 00 ...
+ * To cope with this, we byte-reverse each word of a bitmap if
+ * we have a big-endian filesystem, that is, if we are *not*
+ * byte-swapping other word-sized numbers.
+ */
+#define EXT2_BIG_ENDIAN_BITMAPS
+#endif
+
+#ifdef EXT2_BIG_ENDIAN_BITMAPS
+static void ext2fs_swap_bitmap(ext2_filsys fs, char *bitmap, int nbytes)
+{
+ __u32 *p = (__u32 *) bitmap;
+ int n;
+
+ for (n = nbytes / sizeof(__u32); n > 0; --n, ++p)
+ *p = ext2fs_swab32(*p);
+}
+#endif
+
+errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs)
+{
+ dgrp_t i;
+ size_t nbytes;
+ errcode_t retval;
+ char * inode_bitmap = fs->inode_map->bitmap;
+ char * bitmap_block = NULL;
+ blk_t blk;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ if (!(fs->flags & EXT2_FLAG_RW))
+ return EXT2_ET_RO_FILSYS;
+ if (!inode_bitmap)
+ return 0;
+ nbytes = (size_t) ((EXT2_INODES_PER_GROUP(fs->super)+7) / 8);
+
+ retval = ext2fs_get_mem(fs->blocksize, &bitmap_block);
+ if (retval)
+ return retval;
+ memset(bitmap_block, 0xff, fs->blocksize);
+ for (i = 0; i < fs->group_desc_count; i++) {
+ memcpy(bitmap_block, inode_bitmap, nbytes);
+ blk = fs->group_desc[i].bg_inode_bitmap;
+ if (blk) {
+#ifdef EXT2_BIG_ENDIAN_BITMAPS
+ if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+ (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)))
+ ext2fs_swap_bitmap(fs, bitmap_block, nbytes);
+#endif
+ retval = io_channel_write_blk(fs->io, blk, 1,
+ bitmap_block);
+ if (retval)
+ return EXT2_ET_INODE_BITMAP_WRITE;
+ }
+ inode_bitmap += nbytes;
+ }
+ fs->flags &= ~EXT2_FLAG_IB_DIRTY;
+ ext2fs_free_mem(&bitmap_block);
+ return 0;
+}
+
+errcode_t ext2fs_write_block_bitmap (ext2_filsys fs)
+{
+ dgrp_t i;
+ unsigned int j;
+ int nbytes;
+ unsigned int nbits;
+ errcode_t retval;
+ char * block_bitmap = fs->block_map->bitmap;
+ char * bitmap_block = NULL;
+ blk_t blk;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ if (!(fs->flags & EXT2_FLAG_RW))
+ return EXT2_ET_RO_FILSYS;
+ if (!block_bitmap)
+ return 0;
+ nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
+ retval = ext2fs_get_mem(fs->blocksize, &bitmap_block);
+ if (retval)
+ return retval;
+ memset(bitmap_block, 0xff, fs->blocksize);
+ for (i = 0; i < fs->group_desc_count; i++) {
+ memcpy(bitmap_block, block_bitmap, nbytes);
+ if (i == fs->group_desc_count - 1) {
+ /* Force bitmap padding for the last group */
+ nbits = ((fs->super->s_blocks_count
+ - fs->super->s_first_data_block)
+ % EXT2_BLOCKS_PER_GROUP(fs->super));
+ if (nbits)
+ for (j = nbits; j < fs->blocksize * 8; j++)
+ ext2fs_set_bit(j, bitmap_block);
+ }
+ blk = fs->group_desc[i].bg_block_bitmap;
+ if (blk) {
+#ifdef EXT2_BIG_ENDIAN_BITMAPS
+ if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+ (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)))
+ ext2fs_swap_bitmap(fs, bitmap_block, nbytes);
+#endif
+ retval = io_channel_write_blk(fs->io, blk, 1,
+ bitmap_block);
+ if (retval)
+ return EXT2_ET_BLOCK_BITMAP_WRITE;
+ }
+ block_bitmap += nbytes;
+ }
+ fs->flags &= ~EXT2_FLAG_BB_DIRTY;
+ ext2fs_free_mem(&bitmap_block);
+ return 0;
+}
+
+static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
+{
+ dgrp_t i;
+ char *block_bitmap = 0, *inode_bitmap = 0;
+ char *buf;
+ errcode_t retval;
+ int block_nbytes = (int) EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
+ int inode_nbytes = (int) EXT2_INODES_PER_GROUP(fs->super) / 8;
+ blk_t blk;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ fs->write_bitmaps = ext2fs_write_bitmaps;
+
+ retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
+ if (retval)
+ return retval;
+ if (do_block) {
+ ext2fs_free_block_bitmap(fs->block_map);
+ sprintf(buf, "block bitmap for %s", fs->device_name);
+ retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
+ if (retval)
+ goto cleanup;
+ block_bitmap = fs->block_map->bitmap;
+ }
+ if (do_inode) {
+ ext2fs_free_inode_bitmap(fs->inode_map);
+ sprintf(buf, "inode bitmap for %s", fs->device_name);
+ retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
+ if (retval)
+ goto cleanup;
+ inode_bitmap = fs->inode_map->bitmap;
+ }
+ ext2fs_free_mem(&buf);
+
+ if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
+ if (inode_bitmap) {
+ blk = (fs->image_header->offset_inodemap /
+ fs->blocksize);
+ retval = io_channel_read_blk(fs->image_io, blk,
+ -(inode_nbytes * fs->group_desc_count),
+ inode_bitmap);
+ if (retval)
+ goto cleanup;
+ }
+ if (block_bitmap) {
+ blk = (fs->image_header->offset_blockmap /
+ fs->blocksize);
+ retval = io_channel_read_blk(fs->image_io, blk,
+ -(block_nbytes * fs->group_desc_count),
+ block_bitmap);
+ if (retval)
+ goto cleanup;
+ }
+ return 0;
+ }
+
+ for (i = 0; i < fs->group_desc_count; i++) {
+ if (block_bitmap) {
+ blk = fs->group_desc[i].bg_block_bitmap;
+ if (blk) {
+ retval = io_channel_read_blk(fs->io, blk,
+ -block_nbytes, block_bitmap);
+ if (retval) {
+ retval = EXT2_ET_BLOCK_BITMAP_READ;
+ goto cleanup;
+ }
+#ifdef EXT2_BIG_ENDIAN_BITMAPS
+ if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+ (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)))
+ ext2fs_swap_bitmap(fs, block_bitmap, block_nbytes);
+#endif
+ } else
+ memset(block_bitmap, 0, block_nbytes);
+ block_bitmap += block_nbytes;
+ }
+ if (inode_bitmap) {
+ blk = fs->group_desc[i].bg_inode_bitmap;
+ if (blk) {
+ retval = io_channel_read_blk(fs->io, blk,
+ -inode_nbytes, inode_bitmap);
+ if (retval) {
+ retval = EXT2_ET_INODE_BITMAP_READ;
+ goto cleanup;
+ }
+#ifdef EXT2_BIG_ENDIAN_BITMAPS
+ if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+ (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)))
+ ext2fs_swap_bitmap(fs, inode_bitmap, inode_nbytes);
+#endif
+ } else
+ memset(inode_bitmap, 0, inode_nbytes);
+ inode_bitmap += inode_nbytes;
+ }
+ }
+ return 0;
+
+cleanup:
+ if (do_block) {
+ ext2fs_free_mem(&fs->block_map);
+ }
+ if (do_inode) {
+ ext2fs_free_mem(&fs->inode_map);
+ }
+ ext2fs_free_mem(&buf);
+ return retval;
+}
+
+errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs)
+{
+ return read_bitmaps(fs, 1, 0);
+}
+
+errcode_t ext2fs_read_block_bitmap(ext2_filsys fs)
+{
+ return read_bitmaps(fs, 0, 1);
+}
+
+errcode_t ext2fs_read_bitmaps(ext2_filsys fs)
+{
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ if (fs->inode_map && fs->block_map)
+ return 0;
+
+ return read_bitmaps(fs, !fs->inode_map, !fs->block_map);
+}
+
+errcode_t ext2fs_write_bitmaps(ext2_filsys fs)
+{
+ errcode_t retval;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ if (fs->block_map && ext2fs_test_bb_dirty(fs)) {
+ retval = ext2fs_write_block_bitmap(fs);
+ if (retval)
+ return retval;
+ }
+ if (fs->inode_map && ext2fs_test_ib_dirty(fs)) {
+ retval = ext2fs_write_inode_bitmap(fs);
+ if (retval)
+ return retval;
+ }
+ return 0;
+}
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/sparse.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/sparse.c
new file mode 100644
index 0000000000..b3d3071e98
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/sparse.c
@@ -0,0 +1,79 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * sparse.c --- find the groups in an ext2 filesystem with metadata backups
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ * Copyright (C) 2002 Andreas Dilger.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+
+static int test_root(int a, int b)
+{
+ if (a == 0)
+ return 1;
+ while (1) {
+ if (a == 1)
+ return 1;
+ if (a % b)
+ return 0;
+ a = a / b;
+ }
+}
+
+int ext2fs_bg_has_super(ext2_filsys fs, int group_block)
+{
+ if (!(fs->super->s_feature_ro_compat &
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
+ return 1;
+
+ if (test_root(group_block, 3) || (test_root(group_block, 5)) ||
+ test_root(group_block, 7))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Iterate through the groups which hold BACKUP superblock/GDT copies in an
+ * ext3 filesystem. The counters should be initialized to 1, 5, and 7 before
+ * calling this for the first time. In a sparse filesystem it will be the
+ * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ...
+ * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ...
+ */
+unsigned int ext2fs_list_backups(ext2_filsys fs, unsigned int *three,
+ unsigned int *five, unsigned int *seven)
+{
+ unsigned int *min = three;
+ int mult = 3;
+ unsigned int ret;
+
+ if (!(fs->super->s_feature_ro_compat &
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
+ ret = *min;
+ *min += 1;
+ return ret;
+ }
+
+ if (*five < *min) {
+ min = five;
+ mult = 5;
+ }
+ if (*seven < *min) {
+ min = seven;
+ mult = 7;
+ }
+
+ ret = *min;
+ *min *= mult;
+
+ return ret;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/swapfs.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/swapfs.c
new file mode 100644
index 0000000000..2fca3cfbb3
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/swapfs.c
@@ -0,0 +1,236 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * swapfs.c --- swap ext2 filesystem data structures
+ *
+ * Copyright (C) 1995, 1996, 2002 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+#include "ext2_ext_attr.h"
+
+#if BB_BIG_ENDIAN
+void ext2fs_swap_super(struct ext2_super_block * sb)
+{
+ int i;
+ sb->s_inodes_count = ext2fs_swab32(sb->s_inodes_count);
+ sb->s_blocks_count = ext2fs_swab32(sb->s_blocks_count);
+ sb->s_r_blocks_count = ext2fs_swab32(sb->s_r_blocks_count);
+ sb->s_free_blocks_count = ext2fs_swab32(sb->s_free_blocks_count);
+ sb->s_free_inodes_count = ext2fs_swab32(sb->s_free_inodes_count);
+ sb->s_first_data_block = ext2fs_swab32(sb->s_first_data_block);
+ sb->s_log_block_size = ext2fs_swab32(sb->s_log_block_size);
+ sb->s_log_frag_size = ext2fs_swab32(sb->s_log_frag_size);
+ sb->s_blocks_per_group = ext2fs_swab32(sb->s_blocks_per_group);
+ sb->s_frags_per_group = ext2fs_swab32(sb->s_frags_per_group);
+ sb->s_inodes_per_group = ext2fs_swab32(sb->s_inodes_per_group);
+ sb->s_mtime = ext2fs_swab32(sb->s_mtime);
+ sb->s_wtime = ext2fs_swab32(sb->s_wtime);
+ sb->s_mnt_count = ext2fs_swab16(sb->s_mnt_count);
+ sb->s_max_mnt_count = ext2fs_swab16(sb->s_max_mnt_count);
+ sb->s_magic = ext2fs_swab16(sb->s_magic);
+ sb->s_state = ext2fs_swab16(sb->s_state);
+ sb->s_errors = ext2fs_swab16(sb->s_errors);
+ sb->s_minor_rev_level = ext2fs_swab16(sb->s_minor_rev_level);
+ sb->s_lastcheck = ext2fs_swab32(sb->s_lastcheck);
+ sb->s_checkinterval = ext2fs_swab32(sb->s_checkinterval);
+ sb->s_creator_os = ext2fs_swab32(sb->s_creator_os);
+ sb->s_rev_level = ext2fs_swab32(sb->s_rev_level);
+ sb->s_def_resuid = ext2fs_swab16(sb->s_def_resuid);
+ sb->s_def_resgid = ext2fs_swab16(sb->s_def_resgid);
+ sb->s_first_ino = ext2fs_swab32(sb->s_first_ino);
+ sb->s_inode_size = ext2fs_swab16(sb->s_inode_size);
+ sb->s_block_group_nr = ext2fs_swab16(sb->s_block_group_nr);
+ sb->s_feature_compat = ext2fs_swab32(sb->s_feature_compat);
+ sb->s_feature_incompat = ext2fs_swab32(sb->s_feature_incompat);
+ sb->s_feature_ro_compat = ext2fs_swab32(sb->s_feature_ro_compat);
+ sb->s_algorithm_usage_bitmap = ext2fs_swab32(sb->s_algorithm_usage_bitmap);
+ sb->s_reserved_gdt_blocks = ext2fs_swab16(sb->s_reserved_gdt_blocks);
+ sb->s_journal_inum = ext2fs_swab32(sb->s_journal_inum);
+ sb->s_journal_dev = ext2fs_swab32(sb->s_journal_dev);
+ sb->s_last_orphan = ext2fs_swab32(sb->s_last_orphan);
+ sb->s_default_mount_opts = ext2fs_swab32(sb->s_default_mount_opts);
+ sb->s_first_meta_bg = ext2fs_swab32(sb->s_first_meta_bg);
+ sb->s_mkfs_time = ext2fs_swab32(sb->s_mkfs_time);
+ for (i=0; i < 4; i++)
+ sb->s_hash_seed[i] = ext2fs_swab32(sb->s_hash_seed[i]);
+ for (i=0; i < 17; i++)
+ sb->s_jnl_blocks[i] = ext2fs_swab32(sb->s_jnl_blocks[i]);
+
+}
+
+void ext2fs_swap_group_desc(struct ext2_group_desc *gdp)
+{
+ gdp->bg_block_bitmap = ext2fs_swab32(gdp->bg_block_bitmap);
+ gdp->bg_inode_bitmap = ext2fs_swab32(gdp->bg_inode_bitmap);
+ gdp->bg_inode_table = ext2fs_swab32(gdp->bg_inode_table);
+ gdp->bg_free_blocks_count = ext2fs_swab16(gdp->bg_free_blocks_count);
+ gdp->bg_free_inodes_count = ext2fs_swab16(gdp->bg_free_inodes_count);
+ gdp->bg_used_dirs_count = ext2fs_swab16(gdp->bg_used_dirs_count);
+}
+
+void ext2fs_swap_ext_attr(char *to, char *from, int bufsize, int has_header)
+{
+ struct ext2_ext_attr_header *from_header =
+ (struct ext2_ext_attr_header *)from;
+ struct ext2_ext_attr_header *to_header =
+ (struct ext2_ext_attr_header *)to;
+ struct ext2_ext_attr_entry *from_entry, *to_entry;
+ char *from_end = (char *)from_header + bufsize;
+ int n;
+
+ if (to_header != from_header)
+ memcpy(to_header, from_header, bufsize);
+
+ from_entry = (struct ext2_ext_attr_entry *)from_header;
+ to_entry = (struct ext2_ext_attr_entry *)to_header;
+
+ if (has_header) {
+ to_header->h_magic = ext2fs_swab32(from_header->h_magic);
+ to_header->h_blocks = ext2fs_swab32(from_header->h_blocks);
+ to_header->h_refcount = ext2fs_swab32(from_header->h_refcount);
+ for (n=0; n<4; n++)
+ to_header->h_reserved[n] =
+ ext2fs_swab32(from_header->h_reserved[n]);
+ from_entry = (struct ext2_ext_attr_entry *)(from_header+1);
+ to_entry = (struct ext2_ext_attr_entry *)(to_header+1);
+ }
+
+ while ((char *)from_entry < from_end && *(__u32 *)from_entry) {
+ to_entry->e_value_offs =
+ ext2fs_swab16(from_entry->e_value_offs);
+ to_entry->e_value_block =
+ ext2fs_swab32(from_entry->e_value_block);
+ to_entry->e_value_size =
+ ext2fs_swab32(from_entry->e_value_size);
+ from_entry = EXT2_EXT_ATTR_NEXT(from_entry);
+ to_entry = EXT2_EXT_ATTR_NEXT(to_entry);
+ }
+}
+
+void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
+ struct ext2_inode_large *f, int hostorder,
+ int bufsize)
+{
+ unsigned i;
+ int islnk = 0;
+ __u32 *eaf, *eat;
+
+ if (hostorder && LINUX_S_ISLNK(f->i_mode))
+ islnk = 1;
+ t->i_mode = ext2fs_swab16(f->i_mode);
+ if (!hostorder && LINUX_S_ISLNK(t->i_mode))
+ islnk = 1;
+ t->i_uid = ext2fs_swab16(f->i_uid);
+ t->i_size = ext2fs_swab32(f->i_size);
+ t->i_atime = ext2fs_swab32(f->i_atime);
+ t->i_ctime = ext2fs_swab32(f->i_ctime);
+ t->i_mtime = ext2fs_swab32(f->i_mtime);
+ t->i_dtime = ext2fs_swab32(f->i_dtime);
+ t->i_gid = ext2fs_swab16(f->i_gid);
+ t->i_links_count = ext2fs_swab16(f->i_links_count);
+ t->i_blocks = ext2fs_swab32(f->i_blocks);
+ t->i_flags = ext2fs_swab32(f->i_flags);
+ t->i_file_acl = ext2fs_swab32(f->i_file_acl);
+ t->i_dir_acl = ext2fs_swab32(f->i_dir_acl);
+ if (!islnk || ext2fs_inode_data_blocks(fs, (struct ext2_inode *)t)) {
+ for (i = 0; i < EXT2_N_BLOCKS; i++)
+ t->i_block[i] = ext2fs_swab32(f->i_block[i]);
+ } else if (t != f) {
+ for (i = 0; i < EXT2_N_BLOCKS; i++)
+ t->i_block[i] = f->i_block[i];
+ }
+ t->i_generation = ext2fs_swab32(f->i_generation);
+ t->i_faddr = ext2fs_swab32(f->i_faddr);
+
+ switch (fs->super->s_creator_os) {
+ case EXT2_OS_LINUX:
+ t->osd1.linux1.l_i_reserved1 =
+ ext2fs_swab32(f->osd1.linux1.l_i_reserved1);
+ t->osd2.linux2.l_i_frag = f->osd2.linux2.l_i_frag;
+ t->osd2.linux2.l_i_fsize = f->osd2.linux2.l_i_fsize;
+ t->osd2.linux2.i_pad1 = ext2fs_swab16(f->osd2.linux2.i_pad1);
+ t->osd2.linux2.l_i_uid_high =
+ ext2fs_swab16 (f->osd2.linux2.l_i_uid_high);
+ t->osd2.linux2.l_i_gid_high =
+ ext2fs_swab16 (f->osd2.linux2.l_i_gid_high);
+ t->osd2.linux2.l_i_reserved2 =
+ ext2fs_swab32(f->osd2.linux2.l_i_reserved2);
+ break;
+ case EXT2_OS_HURD:
+ t->osd1.hurd1.h_i_translator =
+ ext2fs_swab32 (f->osd1.hurd1.h_i_translator);
+ t->osd2.hurd2.h_i_frag = f->osd2.hurd2.h_i_frag;
+ t->osd2.hurd2.h_i_fsize = f->osd2.hurd2.h_i_fsize;
+ t->osd2.hurd2.h_i_mode_high =
+ ext2fs_swab16 (f->osd2.hurd2.h_i_mode_high);
+ t->osd2.hurd2.h_i_uid_high =
+ ext2fs_swab16 (f->osd2.hurd2.h_i_uid_high);
+ t->osd2.hurd2.h_i_gid_high =
+ ext2fs_swab16 (f->osd2.hurd2.h_i_gid_high);
+ t->osd2.hurd2.h_i_author =
+ ext2fs_swab32 (f->osd2.hurd2.h_i_author);
+ break;
+ case EXT2_OS_MASIX:
+ t->osd1.masix1.m_i_reserved1 =
+ ext2fs_swab32(f->osd1.masix1.m_i_reserved1);
+ t->osd2.masix2.m_i_frag = f->osd2.masix2.m_i_frag;
+ t->osd2.masix2.m_i_fsize = f->osd2.masix2.m_i_fsize;
+ t->osd2.masix2.m_pad1 = ext2fs_swab16(f->osd2.masix2.m_pad1);
+ t->osd2.masix2.m_i_reserved2[0] =
+ ext2fs_swab32(f->osd2.masix2.m_i_reserved2[0]);
+ t->osd2.masix2.m_i_reserved2[1] =
+ ext2fs_swab32(f->osd2.masix2.m_i_reserved2[1]);
+ break;
+ }
+
+ if (bufsize < (int) (sizeof(struct ext2_inode) + sizeof(__u16)))
+ return; /* no i_extra_isize field */
+
+ t->i_extra_isize = ext2fs_swab16(f->i_extra_isize);
+ if (t->i_extra_isize > EXT2_INODE_SIZE(fs->super) -
+ sizeof(struct ext2_inode)) {
+ /* this is error case: i_extra_size is too large */
+ return;
+ }
+
+ i = sizeof(struct ext2_inode) + t->i_extra_isize + sizeof(__u32);
+ if (bufsize < (int) i)
+ return; /* no space for EA magic */
+
+ eaf = (__u32 *) (((char *) f) + sizeof(struct ext2_inode) +
+ f->i_extra_isize);
+
+ if (ext2fs_swab32(*eaf) != EXT2_EXT_ATTR_MAGIC)
+ return; /* it seems no magic here */
+
+ eat = (__u32 *) (((char *) t) + sizeof(struct ext2_inode) +
+ f->i_extra_isize);
+ *eat = ext2fs_swab32(*eaf);
+
+ /* convert EA(s) */
+ ext2fs_swap_ext_attr((char *) (eat + 1), (char *) (eaf + 1),
+ bufsize - sizeof(struct ext2_inode) -
+ t->i_extra_isize - sizeof(__u32), 0);
+
+}
+
+void ext2fs_swap_inode(ext2_filsys fs, struct ext2_inode *t,
+ struct ext2_inode *f, int hostorder)
+{
+ ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) t,
+ (struct ext2_inode_large *) f, hostorder,
+ sizeof(struct ext2_inode));
+}
+
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/test_io.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/test_io.c
new file mode 100644
index 0000000000..bd74225c00
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/test_io.c
@@ -0,0 +1,380 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * test_io.c --- This is the Test I/O interface.
+ *
+ * Copyright (C) 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * For checking structure magic numbers...
+ */
+
+#define EXT2_CHECK_MAGIC(struct, code) \
+ if ((struct)->magic != (code)) return (code)
+
+struct test_private_data {
+ int magic;
+ io_channel real;
+ int flags;
+ FILE *outfile;
+ unsigned long block;
+ int read_abort_count, write_abort_count;
+ void (*read_blk)(unsigned long block, int count, errcode_t err);
+ void (*write_blk)(unsigned long block, int count, errcode_t err);
+ void (*set_blksize)(int blksize, errcode_t err);
+ void (*write_byte)(unsigned long block, int count, errcode_t err);
+};
+
+static errcode_t test_open(const char *name, int flags, io_channel *channel);
+static errcode_t test_close(io_channel channel);
+static errcode_t test_set_blksize(io_channel channel, int blksize);
+static errcode_t test_read_blk(io_channel channel, unsigned long block,
+ int count, void *data);
+static errcode_t test_write_blk(io_channel channel, unsigned long block,
+ int count, const void *data);
+static errcode_t test_flush(io_channel channel);
+static errcode_t test_write_byte(io_channel channel, unsigned long offset,
+ int count, const void *buf);
+static errcode_t test_set_option(io_channel channel, const char *option,
+ const char *arg);
+
+static struct struct_io_manager struct_test_manager = {
+ EXT2_ET_MAGIC_IO_MANAGER,
+ "Test I/O Manager",
+ test_open,
+ test_close,
+ test_set_blksize,
+ test_read_blk,
+ test_write_blk,
+ test_flush,
+ test_write_byte,
+ test_set_option
+};
+
+io_manager test_io_manager = &struct_test_manager;
+
+/*
+ * These global variable can be set by the test program as
+ * necessary *before* calling test_open
+ */
+io_manager test_io_backing_manager = 0;
+void (*test_io_cb_read_blk)
+ (unsigned long block, int count, errcode_t err) = 0;
+void (*test_io_cb_write_blk)
+ (unsigned long block, int count, errcode_t err) = 0;
+void (*test_io_cb_set_blksize)
+ (int blksize, errcode_t err) = 0;
+void (*test_io_cb_write_byte)
+ (unsigned long block, int count, errcode_t err) = 0;
+
+/*
+ * Test flags
+ */
+#define TEST_FLAG_READ 0x01
+#define TEST_FLAG_WRITE 0x02
+#define TEST_FLAG_SET_BLKSIZE 0x04
+#define TEST_FLAG_FLUSH 0x08
+#define TEST_FLAG_DUMP 0x10
+#define TEST_FLAG_SET_OPTION 0x20
+
+static void test_dump_block(io_channel channel,
+ struct test_private_data *data,
+ unsigned long block, const void *buf)
+{
+ const unsigned char *cp;
+ FILE *f = data->outfile;
+ int i;
+ unsigned long cksum = 0;
+
+ for (i=0, cp = buf; i < channel->block_size; i++, cp++) {
+ cksum += *cp;
+ }
+ fprintf(f, "Contents of block %lu, checksum %08lu:\n", block, cksum);
+ for (i=0, cp = buf; i < channel->block_size; i++, cp++) {
+ if ((i % 16) == 0)
+ fprintf(f, "%04x: ", i);
+ fprintf(f, "%02x%c", *cp, ((i % 16) == 15) ? '\n' : ' ');
+ }
+}
+
+static void test_abort(io_channel channel, unsigned long block)
+{
+ struct test_private_data *data;
+ FILE *f;
+
+ data = (struct test_private_data *) channel->private_data;
+ f = data->outfile;
+ test_flush(channel);
+
+ fprintf(f, "Aborting due to I/O to block %lu\n", block);
+ fflush(f);
+ abort();
+}
+
+static errcode_t test_open(const char *name, int flags, io_channel *channel)
+{
+ io_channel io = NULL;
+ struct test_private_data *data = NULL;
+ errcode_t retval;
+ char *value;
+
+ if (name == 0)
+ return EXT2_ET_BAD_DEVICE_NAME;
+ retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
+ if (retval)
+ return retval;
+ memset(io, 0, sizeof(struct struct_io_channel));
+ io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
+ retval = ext2fs_get_mem(sizeof(struct test_private_data), &data);
+ if (retval) {
+ retval = EXT2_ET_NO_MEMORY;
+ goto cleanup;
+ }
+ io->manager = test_io_manager;
+ retval = ext2fs_get_mem(strlen(name)+1, &io->name);
+ if (retval)
+ goto cleanup;
+
+ strcpy(io->name, name);
+ io->private_data = data;
+ io->block_size = 1024;
+ io->read_error = 0;
+ io->write_error = 0;
+ io->refcount = 1;
+
+ memset(data, 0, sizeof(struct test_private_data));
+ data->magic = EXT2_ET_MAGIC_TEST_IO_CHANNEL;
+ if (test_io_backing_manager) {
+ retval = test_io_backing_manager->open(name, flags,
+ &data->real);
+ if (retval)
+ goto cleanup;
+ } else
+ data->real = 0;
+ data->read_blk = test_io_cb_read_blk;
+ data->write_blk = test_io_cb_write_blk;
+ data->set_blksize = test_io_cb_set_blksize;
+ data->write_byte = test_io_cb_write_byte;
+
+ data->outfile = NULL;
+ if ((value = getenv("TEST_IO_LOGFILE")) != NULL)
+ data->outfile = fopen(value, "w");
+ if (!data->outfile)
+ data->outfile = stderr;
+
+ data->flags = 0;
+ if ((value = getenv("TEST_IO_FLAGS")) != NULL)
+ data->flags = strtoul(value, NULL, 0);
+
+ data->block = 0;
+ if ((value = getenv("TEST_IO_BLOCK")) != NULL)
+ data->block = strtoul(value, NULL, 0);
+
+ data->read_abort_count = 0;
+ if ((value = getenv("TEST_IO_READ_ABORT")) != NULL)
+ data->read_abort_count = strtoul(value, NULL, 0);
+
+ data->write_abort_count = 0;
+ if ((value = getenv("TEST_IO_WRITE_ABORT")) != NULL)
+ data->write_abort_count = strtoul(value, NULL, 0);
+
+ *channel = io;
+ return 0;
+
+cleanup:
+ ext2fs_free_mem(&io);
+ ext2fs_free_mem(&data);
+ return retval;
+}
+
+static errcode_t test_close(io_channel channel)
+{
+ struct test_private_data *data;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct test_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
+
+ if (--channel->refcount > 0)
+ return 0;
+
+ if (data->real)
+ retval = io_channel_close(data->real);
+
+ if (data->outfile && data->outfile != stderr)
+ fclose(data->outfile);
+
+ ext2fs_free_mem(&channel->private_data);
+ ext2fs_free_mem(&channel->name);
+ ext2fs_free_mem(&channel);
+ return retval;
+}
+
+static errcode_t test_set_blksize(io_channel channel, int blksize)
+{
+ struct test_private_data *data;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct test_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
+
+ if (data->real)
+ retval = io_channel_set_blksize(data->real, blksize);
+ if (data->set_blksize)
+ data->set_blksize(blksize, retval);
+ if (data->flags & TEST_FLAG_SET_BLKSIZE)
+ fprintf(data->outfile,
+ "Test_io: set_blksize(%d) returned %s\n",
+ blksize, retval ? error_message(retval) : "OK");
+ channel->block_size = blksize;
+ return retval;
+}
+
+
+static errcode_t test_read_blk(io_channel channel, unsigned long block,
+ int count, void *buf)
+{
+ struct test_private_data *data;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct test_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
+
+ if (data->real)
+ retval = io_channel_read_blk(data->real, block, count, buf);
+ if (data->read_blk)
+ data->read_blk(block, count, retval);
+ if (data->flags & TEST_FLAG_READ)
+ fprintf(data->outfile,
+ "Test_io: read_blk(%lu, %d) returned %s\n",
+ block, count, retval ? error_message(retval) : "OK");
+ if (data->block && data->block == block) {
+ if (data->flags & TEST_FLAG_DUMP)
+ test_dump_block(channel, data, block, buf);
+ if (--data->read_abort_count == 0)
+ test_abort(channel, block);
+ }
+ return retval;
+}
+
+static errcode_t test_write_blk(io_channel channel, unsigned long block,
+ int count, const void *buf)
+{
+ struct test_private_data *data;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct test_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
+
+ if (data->real)
+ retval = io_channel_write_blk(data->real, block, count, buf);
+ if (data->write_blk)
+ data->write_blk(block, count, retval);
+ if (data->flags & TEST_FLAG_WRITE)
+ fprintf(data->outfile,
+ "Test_io: write_blk(%lu, %d) returned %s\n",
+ block, count, retval ? error_message(retval) : "OK");
+ if (data->block && data->block == block) {
+ if (data->flags & TEST_FLAG_DUMP)
+ test_dump_block(channel, data, block, buf);
+ if (--data->write_abort_count == 0)
+ test_abort(channel, block);
+ }
+ return retval;
+}
+
+static errcode_t test_write_byte(io_channel channel, unsigned long offset,
+ int count, const void *buf)
+{
+ struct test_private_data *data;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct test_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
+
+ if (data->real && data->real->manager->write_byte)
+ retval = io_channel_write_byte(data->real, offset, count, buf);
+ if (data->write_byte)
+ data->write_byte(offset, count, retval);
+ if (data->flags & TEST_FLAG_WRITE)
+ fprintf(data->outfile,
+ "Test_io: write_byte(%lu, %d) returned %s\n",
+ offset, count, retval ? error_message(retval) : "OK");
+ return retval;
+}
+
+/*
+ * Flush data buffers to disk.
+ */
+static errcode_t test_flush(io_channel channel)
+{
+ struct test_private_data *data;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct test_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
+
+ if (data->real)
+ retval = io_channel_flush(data->real);
+
+ if (data->flags & TEST_FLAG_FLUSH)
+ fprintf(data->outfile, "Test_io: flush() returned %s\n",
+ retval ? error_message(retval) : "OK");
+
+ return retval;
+}
+
+static errcode_t test_set_option(io_channel channel, const char *option,
+ const char *arg)
+{
+ struct test_private_data *data;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct test_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
+
+
+ if (data->flags & TEST_FLAG_SET_OPTION)
+ fprintf(data->outfile, "Test_io: set_option(%s, %s) ",
+ option, arg);
+ if (data->real && data->real->manager->set_option) {
+ retval = (data->real->manager->set_option)(data->real,
+ option, arg);
+ if (data->flags & TEST_FLAG_SET_OPTION)
+ fprintf(data->outfile, "returned %s\n",
+ retval ? error_message(retval) : "OK");
+ } else {
+ if (data->flags & TEST_FLAG_SET_OPTION)
+ fprintf(data->outfile, "not implemented\n");
+ }
+ return retval;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/unix_io.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/unix_io.c
new file mode 100644
index 0000000000..474f073402
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/unix_io.c
@@ -0,0 +1,703 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * unix_io.c --- This is the Unix (well, really POSIX) implementation
+ * of the I/O manager.
+ *
+ * Implements a one-block write-through cache.
+ *
+ * Includes support for Windows NT support under Cygwin.
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+ * 2002 by Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#ifdef __linux__
+#include <sys/utsname.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <sys/resource.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * For checking structure magic numbers...
+ */
+
+#define EXT2_CHECK_MAGIC(struct, code) \
+ if ((struct)->magic != (code)) return (code)
+
+struct unix_cache {
+ char *buf;
+ unsigned long block;
+ int access_time;
+ unsigned dirty:1;
+ unsigned in_use:1;
+};
+
+#define CACHE_SIZE 8
+#define WRITE_DIRECT_SIZE 4 /* Must be smaller than CACHE_SIZE */
+#define READ_DIRECT_SIZE 4 /* Should be smaller than CACHE_SIZE */
+
+struct unix_private_data {
+ int magic;
+ int dev;
+ int flags;
+ int access_time;
+ ext2_loff_t offset;
+ struct unix_cache cache[CACHE_SIZE];
+};
+
+static errcode_t unix_open(const char *name, int flags, io_channel *channel);
+static errcode_t unix_close(io_channel channel);
+static errcode_t unix_set_blksize(io_channel channel, int blksize);
+static errcode_t unix_read_blk(io_channel channel, unsigned long block,
+ int count, void *data);
+static errcode_t unix_write_blk(io_channel channel, unsigned long block,
+ int count, const void *data);
+static errcode_t unix_flush(io_channel channel);
+static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
+ int size, const void *data);
+static errcode_t unix_set_option(io_channel channel, const char *option,
+ const char *arg);
+
+static void reuse_cache(io_channel channel, struct unix_private_data *data,
+ struct unix_cache *cache, unsigned long block);
+
+/* __FreeBSD_kernel__ is defined by GNU/kFreeBSD - the FreeBSD kernel
+ * does not know buffered block devices - everything is raw. */
+#if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#define NEED_BOUNCE_BUFFER
+#else
+#undef NEED_BOUNCE_BUFFER
+#endif
+
+static struct struct_io_manager struct_unix_manager = {
+ EXT2_ET_MAGIC_IO_MANAGER,
+ "Unix I/O Manager",
+ unix_open,
+ unix_close,
+ unix_set_blksize,
+ unix_read_blk,
+ unix_write_blk,
+ unix_flush,
+#ifdef NEED_BOUNCE_BUFFER
+ 0,
+#else
+ unix_write_byte,
+#endif
+ unix_set_option
+};
+
+io_manager unix_io_manager = &struct_unix_manager;
+
+/*
+ * Here are the raw I/O functions
+ */
+#ifndef NEED_BOUNCE_BUFFER
+static errcode_t raw_read_blk(io_channel channel,
+ struct unix_private_data *data,
+ unsigned long block,
+ int count, void *buf)
+{
+ errcode_t retval;
+ ssize_t size;
+ ext2_loff_t location;
+ int actual = 0;
+
+ size = (count < 0) ? -count : count * channel->block_size;
+ location = ((ext2_loff_t) block * channel->block_size) + data->offset;
+ if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
+ retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
+ goto error_out;
+ }
+ actual = read(data->dev, buf, size);
+ if (actual != size) {
+ if (actual < 0)
+ actual = 0;
+ retval = EXT2_ET_SHORT_READ;
+ goto error_out;
+ }
+ return 0;
+
+error_out:
+ memset((char *) buf+actual, 0, size-actual);
+ if (channel->read_error)
+ retval = (channel->read_error)(channel, block, count, buf,
+ size, actual, retval);
+ return retval;
+}
+#else /* NEED_BOUNCE_BUFFER */
+/*
+ * Windows and FreeBSD block devices only allow sector alignment IO in offset and size
+ */
+static errcode_t raw_read_blk(io_channel channel,
+ struct unix_private_data *data,
+ unsigned long block,
+ int count, void *buf)
+{
+ errcode_t retval;
+ size_t size, alignsize, fragment;
+ ext2_loff_t location;
+ int total = 0, actual;
+#define BLOCKALIGN 512
+ char sector[BLOCKALIGN];
+
+ size = (count < 0) ? -count : count * channel->block_size;
+ location = ((ext2_loff_t) block * channel->block_size) + data->offset;
+#ifdef DEBUG
+ printf("count=%d, size=%d, block=%d, blk_size=%d, location=%lx\n",
+ count, size, block, channel->block_size, location);
+#endif
+ if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
+ retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
+ goto error_out;
+ }
+ fragment = size % BLOCKALIGN;
+ alignsize = size - fragment;
+ if (alignsize) {
+ actual = read(data->dev, buf, alignsize);
+ if (actual != alignsize)
+ goto short_read;
+ }
+ if (fragment) {
+ actual = read(data->dev, sector, BLOCKALIGN);
+ if (actual != BLOCKALIGN)
+ goto short_read;
+ memcpy(buf+alignsize, sector, fragment);
+ }
+ return 0;
+
+short_read:
+ if (actual>0)
+ total += actual;
+ retval = EXT2_ET_SHORT_READ;
+
+error_out:
+ memset((char *) buf+total, 0, size-actual);
+ if (channel->read_error)
+ retval = (channel->read_error)(channel, block, count, buf,
+ size, actual, retval);
+ return retval;
+}
+#endif
+
+static errcode_t raw_write_blk(io_channel channel,
+ struct unix_private_data *data,
+ unsigned long block,
+ int count, const void *buf)
+{
+ ssize_t size;
+ ext2_loff_t location;
+ int actual = 0;
+ errcode_t retval;
+
+ if (count == 1)
+ size = channel->block_size;
+ else {
+ if (count < 0)
+ size = -count;
+ else
+ size = count * channel->block_size;
+ }
+
+ location = ((ext2_loff_t) block * channel->block_size) + data->offset;
+ if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
+ retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
+ goto error_out;
+ }
+
+ actual = write(data->dev, buf, size);
+ if (actual != size) {
+ retval = EXT2_ET_SHORT_WRITE;
+ goto error_out;
+ }
+ return 0;
+
+error_out:
+ if (channel->write_error)
+ retval = (channel->write_error)(channel, block, count, buf,
+ size, actual, retval);
+ return retval;
+}
+
+
+/*
+ * Here we implement the cache functions
+ */
+
+/* Allocate the cache buffers */
+static errcode_t alloc_cache(io_channel channel,
+ struct unix_private_data *data)
+{
+ errcode_t retval;
+ struct unix_cache *cache;
+ int i;
+
+ data->access_time = 0;
+ for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
+ cache->block = 0;
+ cache->access_time = 0;
+ cache->dirty = 0;
+ cache->in_use = 0;
+ if ((retval = ext2fs_get_mem(channel->block_size,
+ &cache->buf)))
+ return retval;
+ }
+ return 0;
+}
+
+/* Free the cache buffers */
+static void free_cache(struct unix_private_data *data)
+{
+ struct unix_cache *cache;
+ int i;
+
+ data->access_time = 0;
+ for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
+ cache->block = 0;
+ cache->access_time = 0;
+ cache->dirty = 0;
+ cache->in_use = 0;
+ ext2fs_free_mem(&cache->buf);
+ cache->buf = 0;
+ }
+}
+
+#ifndef NO_IO_CACHE
+/*
+ * Try to find a block in the cache. If the block is not found, and
+ * eldest is a non-zero pointer, then fill in eldest with the cache
+ * entry to that should be reused.
+ */
+static struct unix_cache *find_cached_block(struct unix_private_data *data,
+ unsigned long block,
+ struct unix_cache **eldest)
+{
+ struct unix_cache *cache, *unused_cache, *oldest_cache;
+ int i;
+
+ unused_cache = oldest_cache = 0;
+ for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
+ if (!cache->in_use) {
+ if (!unused_cache)
+ unused_cache = cache;
+ continue;
+ }
+ if (cache->block == block) {
+ cache->access_time = ++data->access_time;
+ return cache;
+ }
+ if (!oldest_cache ||
+ (cache->access_time < oldest_cache->access_time))
+ oldest_cache = cache;
+ }
+ if (eldest)
+ *eldest = (unused_cache) ? unused_cache : oldest_cache;
+ return 0;
+}
+
+/*
+ * Reuse a particular cache entry for another block.
+ */
+static void reuse_cache(io_channel channel, struct unix_private_data *data,
+ struct unix_cache *cache, unsigned long block)
+{
+ if (cache->dirty && cache->in_use)
+ raw_write_blk(channel, data, cache->block, 1, cache->buf);
+
+ cache->in_use = 1;
+ cache->dirty = 0;
+ cache->block = block;
+ cache->access_time = ++data->access_time;
+}
+
+/*
+ * Flush all of the blocks in the cache
+ */
+static errcode_t flush_cached_blocks(io_channel channel,
+ struct unix_private_data *data,
+ int invalidate)
+
+{
+ struct unix_cache *cache;
+ errcode_t retval, retval2;
+ int i;
+
+ retval2 = 0;
+ for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
+ if (!cache->in_use)
+ continue;
+
+ if (invalidate)
+ cache->in_use = 0;
+
+ if (!cache->dirty)
+ continue;
+
+ retval = raw_write_blk(channel, data,
+ cache->block, 1, cache->buf);
+ if (retval)
+ retval2 = retval;
+ else
+ cache->dirty = 0;
+ }
+ return retval2;
+}
+#endif /* NO_IO_CACHE */
+
+static errcode_t unix_open(const char *name, int flags, io_channel *channel)
+{
+ io_channel io = NULL;
+ struct unix_private_data *data = NULL;
+ errcode_t retval;
+ int open_flags;
+ struct stat st;
+#ifdef __linux__
+ struct utsname ut;
+#endif
+
+ if (name == 0)
+ return EXT2_ET_BAD_DEVICE_NAME;
+ retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
+ if (retval)
+ return retval;
+ memset(io, 0, sizeof(struct struct_io_channel));
+ io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
+ retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data);
+ if (retval)
+ goto cleanup;
+
+ io->manager = unix_io_manager;
+ retval = ext2fs_get_mem(strlen(name)+1, &io->name);
+ if (retval)
+ goto cleanup;
+
+ strcpy(io->name, name);
+ io->private_data = data;
+ io->block_size = 1024;
+ io->read_error = 0;
+ io->write_error = 0;
+ io->refcount = 1;
+
+ memset(data, 0, sizeof(struct unix_private_data));
+ data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
+
+ if ((retval = alloc_cache(io, data)))
+ goto cleanup;
+
+ open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
+#ifdef CONFIG_LFS
+ data->dev = open64(io->name, open_flags);
+#else
+ data->dev = open(io->name, open_flags);
+#endif
+ if (data->dev < 0) {
+ retval = errno;
+ goto cleanup;
+ }
+
+#ifdef __linux__
+#undef RLIM_INFINITY
+#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4)))
+#define RLIM_INFINITY ((unsigned long)(~0UL>>1))
+#else
+#define RLIM_INFINITY (~0UL)
+#endif
+ /*
+ * Work around a bug in 2.4.10-2.4.18 kernels where writes to
+ * block devices are wrongly getting hit by the filesize
+ * limit. This workaround isn't perfect, since it won't work
+ * if glibc wasn't built against 2.2 header files. (Sigh.)
+ *
+ */
+ if ((flags & IO_FLAG_RW) &&
+ (uname(&ut) == 0) &&
+ ((ut.release[0] == '2') && (ut.release[1] == '.') &&
+ (ut.release[2] == '4') && (ut.release[3] == '.') &&
+ (ut.release[4] == '1') && (ut.release[5] >= '0') &&
+ (ut.release[5] < '8')) &&
+ (fstat(data->dev, &st) == 0) &&
+ (S_ISBLK(st.st_mode))) {
+ struct rlimit rlim;
+
+ rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ getrlimit(RLIMIT_FSIZE, &rlim);
+ if (((unsigned long) rlim.rlim_cur) <
+ ((unsigned long) rlim.rlim_max)) {
+ rlim.rlim_cur = rlim.rlim_max;
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ }
+ }
+#endif
+ *channel = io;
+ return 0;
+
+cleanup:
+ if (data) {
+ free_cache(data);
+ ext2fs_free_mem(&data);
+ }
+ ext2fs_free_mem(&io);
+ return retval;
+}
+
+static errcode_t unix_close(io_channel channel)
+{
+ struct unix_private_data *data;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct unix_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+ if (--channel->refcount > 0)
+ return 0;
+
+#ifndef NO_IO_CACHE
+ retval = flush_cached_blocks(channel, data, 0);
+#endif
+
+ if (close(data->dev) < 0)
+ retval = errno;
+ free_cache(data);
+
+ ext2fs_free_mem(&channel->private_data);
+ ext2fs_free_mem(&channel->name);
+ ext2fs_free_mem(&channel);
+ return retval;
+}
+
+static errcode_t unix_set_blksize(io_channel channel, int blksize)
+{
+ struct unix_private_data *data;
+ errcode_t retval;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct unix_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+ if (channel->block_size != blksize) {
+#ifndef NO_IO_CACHE
+ if ((retval = flush_cached_blocks(channel, data, 0)))
+ return retval;
+#endif
+
+ channel->block_size = blksize;
+ free_cache(data);
+ if ((retval = alloc_cache(channel, data)))
+ return retval;
+ }
+ return 0;
+}
+
+
+static errcode_t unix_read_blk(io_channel channel, unsigned long block,
+ int count, void *buf)
+{
+ struct unix_private_data *data;
+ struct unix_cache *cache, *reuse[READ_DIRECT_SIZE];
+ errcode_t retval;
+ char *cp;
+ int i, j;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct unix_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+#ifdef NO_IO_CACHE
+ return raw_read_blk(channel, data, block, count, buf);
+#else
+ /*
+ * If we're doing an odd-sized read or a very large read,
+ * flush out the cache and then do a direct read.
+ */
+ if (count < 0 || count > WRITE_DIRECT_SIZE) {
+ if ((retval = flush_cached_blocks(channel, data, 0)))
+ return retval;
+ return raw_read_blk(channel, data, block, count, buf);
+ }
+
+ cp = buf;
+ while (count > 0) {
+ /* If it's in the cache, use it! */
+ if ((cache = find_cached_block(data, block, &reuse[0]))) {
+#ifdef DEBUG
+ printf("Using cached block %d\n", block);
+#endif
+ memcpy(cp, cache->buf, channel->block_size);
+ count--;
+ block++;
+ cp += channel->block_size;
+ continue;
+ }
+ /*
+ * Find the number of uncached blocks so we can do a
+ * single read request
+ */
+ for (i=1; i < count; i++)
+ if (find_cached_block(data, block+i, &reuse[i]))
+ break;
+#ifdef DEBUG
+ printf("Reading %d blocks starting at %d\n", i, block);
+#endif
+ if ((retval = raw_read_blk(channel, data, block, i, cp)))
+ return retval;
+
+ /* Save the results in the cache */
+ for (j=0; j < i; j++) {
+ count--;
+ cache = reuse[j];
+ reuse_cache(channel, data, cache, block++);
+ memcpy(cache->buf, cp, channel->block_size);
+ cp += channel->block_size;
+ }
+ }
+ return 0;
+#endif /* NO_IO_CACHE */
+}
+
+static errcode_t unix_write_blk(io_channel channel, unsigned long block,
+ int count, const void *buf)
+{
+ struct unix_private_data *data;
+ struct unix_cache *cache, *reuse;
+ errcode_t retval = 0;
+ const char *cp;
+ int writethrough;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct unix_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+#ifdef NO_IO_CACHE
+ return raw_write_blk(channel, data, block, count, buf);
+#else
+ /*
+ * If we're doing an odd-sized write or a very large write,
+ * flush out the cache completely and then do a direct write.
+ */
+ if (count < 0 || count > WRITE_DIRECT_SIZE) {
+ if ((retval = flush_cached_blocks(channel, data, 1)))
+ return retval;
+ return raw_write_blk(channel, data, block, count, buf);
+ }
+
+ /*
+ * For a moderate-sized multi-block write, first force a write
+ * if we're in write-through cache mode, and then fill the
+ * cache with the blocks.
+ */
+ writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH;
+ if (writethrough)
+ retval = raw_write_blk(channel, data, block, count, buf);
+
+ cp = buf;
+ while (count > 0) {
+ cache = find_cached_block(data, block, &reuse);
+ if (!cache) {
+ cache = reuse;
+ reuse_cache(channel, data, cache, block);
+ }
+ memcpy(cache->buf, cp, channel->block_size);
+ cache->dirty = !writethrough;
+ count--;
+ block++;
+ cp += channel->block_size;
+ }
+ return retval;
+#endif /* NO_IO_CACHE */
+}
+
+static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
+ int size, const void *buf)
+{
+ struct unix_private_data *data;
+ errcode_t retval = 0;
+ ssize_t actual;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct unix_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+#ifndef NO_IO_CACHE
+ /*
+ * Flush out the cache completely
+ */
+ if ((retval = flush_cached_blocks(channel, data, 1)))
+ return retval;
+#endif
+
+ if (lseek(data->dev, offset + data->offset, SEEK_SET) < 0)
+ return errno;
+
+ actual = write(data->dev, buf, size);
+ if (actual != size)
+ return EXT2_ET_SHORT_WRITE;
+
+ return 0;
+}
+
+/*
+ * Flush data buffers to disk.
+ */
+static errcode_t unix_flush(io_channel channel)
+{
+ struct unix_private_data *data;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct unix_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+#ifndef NO_IO_CACHE
+ retval = flush_cached_blocks(channel, data, 0);
+#endif
+ fsync(data->dev);
+ return retval;
+}
+
+static errcode_t unix_set_option(io_channel channel, const char *option,
+ const char *arg)
+{
+ struct unix_private_data *data;
+ unsigned long tmp;
+ char *end;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct unix_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+ if (!strcmp(option, "offset")) {
+ if (!arg)
+ return EXT2_ET_INVALID_ARGUMENT;
+
+ tmp = strtoul(arg, &end, 0);
+ if (*end)
+ return EXT2_ET_INVALID_ARGUMENT;
+ data->offset = tmp;
+ return 0;
+ }
+ return EXT2_ET_INVALID_ARGUMENT;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/unlink.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/unlink.c
new file mode 100644
index 0000000000..83ac2713e0
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/unlink.c
@@ -0,0 +1,100 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * unlink.c --- delete links in a ext2fs directory
+ *
+ * Copyright (C) 1993, 1994, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+struct link_struct {
+ const char *name;
+ int namelen;
+ ext2_ino_t inode;
+ int flags;
+ struct ext2_dir_entry *prev;
+ int done;
+};
+
+#ifdef __TURBOC__
+# pragma argsused
+#endif
+static int unlink_proc(struct ext2_dir_entry *dirent,
+ int offset EXT2FS_ATTR((unused)),
+ int blocksize EXT2FS_ATTR((unused)),
+ char *buf EXT2FS_ATTR((unused)),
+ void *priv_data)
+{
+ struct link_struct *ls = (struct link_struct *) priv_data;
+ struct ext2_dir_entry *prev;
+
+ prev = ls->prev;
+ ls->prev = dirent;
+
+ if (ls->name) {
+ if ((dirent->name_len & 0xFF) != ls->namelen)
+ return 0;
+ if (strncmp(ls->name, dirent->name, dirent->name_len & 0xFF))
+ return 0;
+ }
+ if (ls->inode) {
+ if (dirent->inode != ls->inode)
+ return 0;
+ } else {
+ if (!dirent->inode)
+ return 0;
+ }
+
+ if (prev)
+ prev->rec_len += dirent->rec_len;
+ else
+ dirent->inode = 0;
+ ls->done++;
+ return DIRENT_ABORT|DIRENT_CHANGED;
+}
+
+#ifdef __TURBOC__
+ #pragma argsused
+#endif
+errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir,
+ const char *name, ext2_ino_t ino,
+ int flags EXT2FS_ATTR((unused)))
+{
+ errcode_t retval;
+ struct link_struct ls;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ if (!name && !ino)
+ return EXT2_ET_INVALID_ARGUMENT;
+
+ if (!(fs->flags & EXT2_FLAG_RW))
+ return EXT2_ET_RO_FILSYS;
+
+ ls.name = name;
+ ls.namelen = name ? strlen(name) : 0;
+ ls.inode = ino;
+ ls.flags = 0;
+ ls.done = 0;
+ ls.prev = 0;
+
+ retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY,
+ 0, unlink_proc, &ls);
+ if (retval)
+ return retval;
+
+ return (ls.done) ? 0 : EXT2_ET_DIR_NO_SPACE;
+}
+
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/valid_blk.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/valid_blk.c
new file mode 100644
index 0000000000..8ed77ae2ac
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/valid_blk.c
@@ -0,0 +1,57 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * valid_blk.c --- does the inode have valid blocks?
+ *
+ * Copyright 1997 by Theodore Ts'o
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ *
+ */
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <time.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * This function returns 1 if the inode's block entries actually
+ * contain block entries.
+ */
+int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode)
+{
+ /*
+ * Only directories, regular files, and some symbolic links
+ * have valid block entries.
+ */
+ if (!LINUX_S_ISDIR(inode->i_mode) && !LINUX_S_ISREG(inode->i_mode) &&
+ !LINUX_S_ISLNK(inode->i_mode))
+ return 0;
+
+ /*
+ * If the symbolic link is a "fast symlink", then the symlink
+ * target is stored in the block entries.
+ */
+ if (LINUX_S_ISLNK (inode->i_mode)) {
+ if (inode->i_file_acl == 0) {
+ /* With no EA block, we can rely on i_blocks */
+ if (inode->i_blocks == 0)
+ return 0;
+ } else {
+ /* With an EA block, life gets more tricky */
+ if (inode->i_size >= EXT2_N_BLOCKS*4)
+ return 1; /* definitely using i_block[] */
+ if (inode->i_size > 4 && inode->i_block[1] == 0)
+ return 1; /* definitely using i_block[] */
+ return 0; /* Probably a fast symlink */
+ }
+ }
+ return 1;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/version.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/version.c
new file mode 100644
index 0000000000..d2981e867e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/version.c
@@ -0,0 +1,51 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * version.c --- Return the version of the ext2 library
+ *
+ * Copyright (C) 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+static const char *lib_version = E2FSPROGS_VERSION;
+static const char *lib_date = E2FSPROGS_DATE;
+
+int ext2fs_parse_version_string(const char *ver_string)
+{
+ const char *cp;
+ int version = 0;
+
+ for (cp = ver_string; *cp; cp++) {
+ if (*cp == '.')
+ continue;
+ if (!isdigit(*cp))
+ break;
+ version = (version * 10) + (*cp - '0');
+ }
+ return version;
+}
+
+
+int ext2fs_get_library_version(const char **ver_string,
+ const char **date_string)
+{
+ if (ver_string)
+ *ver_string = lib_version;
+ if (date_string)
+ *date_string = lib_date;
+
+ return ext2fs_parse_version_string(lib_version);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/write_bb_file.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/write_bb_file.c
new file mode 100644
index 0000000000..5b19eefa09
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/ext2fs/write_bb_file.c
@@ -0,0 +1,35 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * write_bb_file.c --- write a list of bad blocks to a FILE *
+ *
+ * Copyright (C) 1994, 1995 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+errcode_t ext2fs_write_bb_FILE(ext2_badblocks_list bb_list,
+ unsigned int flags EXT2FS_ATTR((unused)),
+ FILE *f)
+{
+ badblocks_iterate bb_iter;
+ blk_t blk;
+ errcode_t retval;
+
+ retval = ext2fs_badblocks_list_iterate_begin(bb_list, &bb_iter);
+ if (retval)
+ return retval;
+
+ while (ext2fs_badblocks_list_iterate(bb_iter, &blk)) {
+ fprintf(f, "%d\n", blk);
+ }
+ ext2fs_badblocks_list_iterate_end(bb_iter);
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/fsck.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/fsck.c
new file mode 100644
index 0000000000..9cb9f754db
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/fsck.c
@@ -0,0 +1,1391 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * pfsck --- A generic, parallelizing front-end for the fsck program.
+ * It will automatically try to run fsck programs in parallel if the
+ * devices are on separate spindles. It is based on the same ideas as
+ * the generic front end for fsck by David Engel and Fred van Kempen,
+ * but it has been completely rewritten from scratch to support
+ * parallel execution.
+ *
+ * Written by Theodore Ts'o, <tytso@mit.edu>
+ *
+ * Miquel van Smoorenburg (miquels@drinkel.ow.org) 20-Oct-1994:
+ * o Changed -t fstype to behave like with mount when -A (all file
+ * systems) or -M (like mount) is specified.
+ * o fsck looks if it can find the fsck.type program to decide
+ * if it should ignore the fs type. This way more fsck programs
+ * can be added without changing this front-end.
+ * o -R flag skip root file system.
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+ * 2001, 2002, 2003, 2004, 2005 by Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <paths.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+
+#include "fsck.h"
+#include "blkid/blkid.h"
+
+#include "e2fsbb.h"
+
+#include "libbb.h"
+
+#ifndef _PATH_MNTTAB
+#define _PATH_MNTTAB "/etc/fstab"
+#endif
+
+/*
+ * fsck.h
+ */
+
+#ifndef DEFAULT_FSTYPE
+#define DEFAULT_FSTYPE "ext2"
+#endif
+
+#define MAX_DEVICES 32
+#define MAX_ARGS 32
+
+/*
+ * Internal structure for mount tabel entries.
+ */
+
+struct fs_info {
+ char *device;
+ char *mountpt;
+ char *type;
+ char *opts;
+ int freq;
+ int passno;
+ int flags;
+ struct fs_info *next;
+};
+
+#define FLAG_DONE 1
+#define FLAG_PROGRESS 2
+
+/*
+ * Structure to allow exit codes to be stored
+ */
+struct fsck_instance {
+ int pid;
+ int flags;
+ int exit_status;
+ time_t start_time;
+ char * prog;
+ char * type;
+ char * device;
+ char * base_device;
+ struct fsck_instance *next;
+};
+
+/*
+ * base_device.c
+ *
+ * Return the "base device" given a particular device; this is used to
+ * assure that we only fsck one partition on a particular drive at any
+ * one time. Otherwise, the disk heads will be seeking all over the
+ * place. If the base device cannot be determined, return NULL.
+ *
+ * The base_device() function returns an allocated string which must
+ * be freed.
+ *
+ */
+
+
+#ifdef CONFIG_FEATURE_DEVFS
+/*
+ * Required for the uber-silly devfs /dev/ide/host1/bus2/target3/lun3
+ * pathames.
+ */
+static const char *const devfs_hier[] = {
+ "host", "bus", "target", "lun", 0
+};
+#endif
+
+static char *base_device(const char *device)
+{
+ char *str, *cp;
+#ifdef CONFIG_FEATURE_DEVFS
+ const char *const *hier;
+ const char *disk;
+ int len;
+#endif
+
+ cp = str = xstrdup(device);
+
+ /* Skip over /dev/; if it's not present, give up. */
+ if (strncmp(cp, "/dev/", 5) != 0)
+ goto errout;
+ cp += 5;
+
+ /*
+ * For md devices, we treat them all as if they were all
+ * on one disk, since we don't know how to parallelize them.
+ */
+ if (cp[0] == 'm' && cp[1] == 'd') {
+ *(cp+2) = 0;
+ return str;
+ }
+
+ /* Handle DAC 960 devices */
+ if (strncmp(cp, "rd/", 3) == 0) {
+ cp += 3;
+ if (cp[0] != 'c' || cp[2] != 'd' ||
+ !isdigit(cp[1]) || !isdigit(cp[3]))
+ goto errout;
+ *(cp+4) = 0;
+ return str;
+ }
+
+ /* Now let's handle /dev/hd* and /dev/sd* devices.... */
+ if ((cp[0] == 'h' || cp[0] == 's') && (cp[1] == 'd')) {
+ cp += 2;
+ /* If there's a single number after /dev/hd, skip it */
+ if (isdigit(*cp))
+ cp++;
+ /* What follows must be an alpha char, or give up */
+ if (!isalpha(*cp))
+ goto errout;
+ *(cp + 1) = 0;
+ return str;
+ }
+
+#ifdef CONFIG_FEATURE_DEVFS
+ /* Now let's handle devfs (ugh) names */
+ len = 0;
+ if (strncmp(cp, "ide/", 4) == 0)
+ len = 4;
+ if (strncmp(cp, "scsi/", 5) == 0)
+ len = 5;
+ if (len) {
+ cp += len;
+ /*
+ * Now we proceed down the expected devfs hierarchy.
+ * i.e., .../host1/bus2/target3/lun4/...
+ * If we don't find the expected token, followed by
+ * some number of digits at each level, abort.
+ */
+ for (hier = devfs_hier; *hier; hier++) {
+ len = strlen(*hier);
+ if (strncmp(cp, *hier, len) != 0)
+ goto errout;
+ cp += len;
+ while (*cp != '/' && *cp != 0) {
+ if (!isdigit(*cp))
+ goto errout;
+ cp++;
+ }
+ cp++;
+ }
+ *(cp - 1) = 0;
+ return str;
+ }
+
+ /* Now handle devfs /dev/disc or /dev/disk names */
+ disk = 0;
+ if (strncmp(cp, "discs/", 6) == 0)
+ disk = "disc";
+ else if (strncmp(cp, "disks/", 6) == 0)
+ disk = "disk";
+ if (disk) {
+ cp += 6;
+ if (strncmp(cp, disk, 4) != 0)
+ goto errout;
+ cp += 4;
+ while (*cp != '/' && *cp != 0) {
+ if (!isdigit(*cp))
+ goto errout;
+ cp++;
+ }
+ *cp = 0;
+ return str;
+ }
+#endif
+
+errout:
+ free(str);
+ return NULL;
+}
+
+
+static const char *const ignored_types[] = {
+ "ignore",
+ "iso9660",
+ "nfs",
+ "proc",
+ "sw",
+ "swap",
+ "tmpfs",
+ "devpts",
+ NULL
+};
+
+static const char *const really_wanted[] = {
+ "minix",
+ "ext2",
+ "ext3",
+ "jfs",
+ "reiserfs",
+ "xiafs",
+ "xfs",
+ NULL
+};
+
+#define BASE_MD "/dev/md"
+
+/*
+ * Global variables for options
+ */
+static char *devices[MAX_DEVICES];
+static char *args[MAX_ARGS];
+static int num_devices, num_args;
+
+static int verbose;
+static int doall;
+static int noexecute;
+static int serialize;
+static int skip_root;
+static int like_mount;
+static int notitle;
+static int parallel_root;
+static int progress;
+static int progress_fd;
+static int force_all_parallel;
+static int num_running;
+static int max_running;
+static volatile int cancel_requested;
+static int kill_sent;
+static char *fstype;
+static struct fs_info *filesys_info, *filesys_last;
+static struct fsck_instance *instance_list;
+static char *fsck_path;
+static blkid_cache cache;
+
+static char *string_copy(const char *s)
+{
+ char *ret;
+
+ if (!s)
+ return 0;
+ ret = xstrdup(s);
+ return ret;
+}
+
+static int string_to_int(const char *s)
+{
+ long l;
+ char *p;
+
+ l = strtol(s, &p, 0);
+ if (*p || l == LONG_MIN || l == LONG_MAX || l < 0 || l > INT_MAX)
+ return -1;
+ else
+ return (int) l;
+}
+
+static char *skip_over_blank(char *cp)
+{
+ while (*cp && isspace(*cp))
+ cp++;
+ return cp;
+}
+
+static char *skip_over_word(char *cp)
+{
+ while (*cp && !isspace(*cp))
+ cp++;
+ return cp;
+}
+
+static void strip_line(char *line)
+{
+ char *p;
+
+ while (*line) {
+ p = line + strlen(line) - 1;
+ if ((*p == '\n') || (*p == '\r'))
+ *p = 0;
+ else
+ break;
+ }
+}
+
+static char *parse_word(char **buf)
+{
+ char *word, *next;
+
+ word = *buf;
+ if (*word == 0)
+ return 0;
+
+ word = skip_over_blank(word);
+ next = skip_over_word(word);
+ if (*next)
+ *next++ = 0;
+ *buf = next;
+ return word;
+}
+
+static void parse_escape(char *word)
+{
+ char *q, c;
+ const char *p;
+
+ if (!word)
+ return;
+
+ for (p = q = word; *p; q++) {
+ c = *p++;
+ if (c != '\\') {
+ *q = c;
+ } else {
+ *q = bb_process_escape_sequence(&p);
+ }
+ }
+ *q = 0;
+}
+
+static void free_instance(struct fsck_instance *i)
+{
+ if (i->prog)
+ free(i->prog);
+ if (i->device)
+ free(i->device);
+ if (i->base_device)
+ free(i->base_device);
+ free(i);
+}
+
+static struct fs_info *create_fs_device(const char *device, const char *mntpnt,
+ const char *type, const char *opts,
+ int freq, int passno)
+{
+ struct fs_info *fs;
+
+ if (!(fs = malloc(sizeof(struct fs_info))))
+ return NULL;
+
+ fs->device = string_copy(device);
+ fs->mountpt = string_copy(mntpnt);
+ fs->type = string_copy(type);
+ fs->opts = string_copy(opts ? opts : "");
+ fs->freq = freq;
+ fs->passno = passno;
+ fs->flags = 0;
+ fs->next = NULL;
+
+ if (!filesys_info)
+ filesys_info = fs;
+ else
+ filesys_last->next = fs;
+ filesys_last = fs;
+
+ return fs;
+}
+
+
+
+static int parse_fstab_line(char *line, struct fs_info **ret_fs)
+{
+ char *dev, *device, *mntpnt, *type, *opts, *freq, *passno, *cp;
+ struct fs_info *fs;
+
+ *ret_fs = 0;
+ strip_line(line);
+ if ((cp = strchr(line, '#')))
+ *cp = 0; /* Ignore everything after the comment char */
+ cp = line;
+
+ device = parse_word(&cp);
+ mntpnt = parse_word(&cp);
+ type = parse_word(&cp);
+ opts = parse_word(&cp);
+ freq = parse_word(&cp);
+ passno = parse_word(&cp);
+
+ if (!device)
+ return 0; /* Allow blank lines */
+
+ if (!mntpnt || !type)
+ return -1;
+
+ parse_escape(device);
+ parse_escape(mntpnt);
+ parse_escape(type);
+ parse_escape(opts);
+ parse_escape(freq);
+ parse_escape(passno);
+
+ dev = blkid_get_devname(cache, device, NULL);
+ if (dev)
+ device = dev;
+
+ if (strchr(type, ','))
+ type = 0;
+
+ fs = create_fs_device(device, mntpnt, type ? type : "auto", opts,
+ freq ? atoi(freq) : -1,
+ passno ? atoi(passno) : -1);
+ if (dev)
+ free(dev);
+
+ if (!fs)
+ return -1;
+ *ret_fs = fs;
+ return 0;
+}
+
+static void interpret_type(struct fs_info *fs)
+{
+ char *t;
+
+ if (strcmp(fs->type, "auto") != 0)
+ return;
+ t = blkid_get_tag_value(cache, "TYPE", fs->device);
+ if (t) {
+ free(fs->type);
+ fs->type = t;
+ }
+}
+
+/*
+ * Load the filesystem database from /etc/fstab
+ */
+static void load_fs_info(const char *filename)
+{
+ FILE *f;
+ char buf[1024];
+ int lineno = 0;
+ int old_fstab = 1;
+ struct fs_info *fs;
+
+ if ((f = fopen_or_warn(filename, "r")) == NULL) {
+ return;
+ }
+ while (!feof(f)) {
+ lineno++;
+ if (!fgets(buf, sizeof(buf), f))
+ break;
+ buf[sizeof(buf)-1] = 0;
+ if (parse_fstab_line(buf, &fs) < 0) {
+ bb_error_msg("WARNING: bad format "
+ "on line %d of %s\n", lineno, filename);
+ continue;
+ }
+ if (!fs)
+ continue;
+ if (fs->passno < 0)
+ fs->passno = 0;
+ else
+ old_fstab = 0;
+ }
+
+ fclose(f);
+
+ if (old_fstab) {
+ fputs("\007\007\007"
+ "WARNING: Your /etc/fstab does not contain the fsck passno\n"
+ " field. I will kludge around things for you, but you\n"
+ " should fix your /etc/fstab file as soon as you can.\n\n", stderr);
+
+ for (fs = filesys_info; fs; fs = fs->next) {
+ fs->passno = 1;
+ }
+ }
+}
+
+/* Lookup filesys in /etc/fstab and return the corresponding entry. */
+static struct fs_info *lookup(char *filesys)
+{
+ struct fs_info *fs;
+
+ /* No filesys name given. */
+ if (filesys == NULL)
+ return NULL;
+
+ for (fs = filesys_info; fs; fs = fs->next) {
+ if (!strcmp(filesys, fs->device) ||
+ (fs->mountpt && !strcmp(filesys, fs->mountpt)))
+ break;
+ }
+
+ return fs;
+}
+
+/* Find fsck program for a given fs type. */
+static char *find_fsck(char *type)
+{
+ char *s;
+ const char *tpl;
+ char *p = string_copy(fsck_path);
+ struct stat st;
+
+ /* Are we looking for a program or just a type? */
+ tpl = (strncmp(type, "fsck.", 5) ? "%s/fsck.%s" : "%s/%s");
+
+ for(s = strtok(p, ":"); s; s = strtok(NULL, ":")) {
+ s = xasprintf(tpl, s, type);
+ if (stat(s, &st) == 0) break;
+ free(s);
+ }
+ free(p);
+ return s;
+}
+
+static int progress_active(void)
+{
+ struct fsck_instance *inst;
+
+ for (inst = instance_list; inst; inst = inst->next) {
+ if (inst->flags & FLAG_DONE)
+ continue;
+ if (inst->flags & FLAG_PROGRESS)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Execute a particular fsck program, and link it into the list of
+ * child processes we are waiting for.
+ */
+static int execute(const char *type, const char *device, const char *mntpt,
+ int interactive)
+{
+ char *s, *argv[80];
+ char *prog;
+ int argc, i;
+ struct fsck_instance *inst, *p;
+ pid_t pid;
+
+ inst = malloc(sizeof(struct fsck_instance));
+ if (!inst)
+ return ENOMEM;
+ memset(inst, 0, sizeof(struct fsck_instance));
+
+ prog = xasprintf("fsck.%s", type);
+ argv[0] = prog;
+ argc = 1;
+
+ for (i=0; i <num_args; i++)
+ argv[argc++] = string_copy(args[i]);
+
+ if (progress && !progress_active()) {
+ if ((strcmp(type, "ext2") == 0) ||
+ (strcmp(type, "ext3") == 0)) {
+ char tmp[80];
+ snprintf(tmp, 80, "-C%d", progress_fd);
+ argv[argc++] = string_copy(tmp);
+ inst->flags |= FLAG_PROGRESS;
+ }
+ }
+
+ argv[argc++] = string_copy(device);
+ argv[argc] = 0;
+
+ s = find_fsck(prog);
+ if (s == NULL) {
+ bb_error_msg("%s: not found", prog);
+ return ENOENT;
+ }
+
+ if (verbose || noexecute) {
+ printf("[%s (%d) -- %s] ", s, num_running,
+ mntpt ? mntpt : device);
+ for (i=0; i < argc; i++)
+ printf("%s ", argv[i]);
+ bb_putchar('\n');
+ }
+
+ /* Fork and execute the correct program. */
+ if (noexecute)
+ pid = -1;
+ else if ((pid = fork()) < 0) {
+ perror("fork");
+ return errno;
+ } else if (pid == 0) {
+ if (!interactive)
+ close(0);
+ (void) execv(s, argv);
+ bb_simple_perror_msg_and_die(argv[0]);
+ }
+
+ for (i = 1; i < argc; i++)
+ free(argv[i]);
+
+ free(s);
+ inst->pid = pid;
+ inst->prog = prog;
+ inst->type = string_copy(type);
+ inst->device = string_copy(device);
+ inst->base_device = base_device(device);
+ inst->start_time = time(0);
+ inst->next = NULL;
+
+ /*
+ * Find the end of the list, so we add the instance on at the end.
+ */
+ for (p = instance_list; p && p->next; p = p->next);
+
+ if (p)
+ p->next = inst;
+ else
+ instance_list = inst;
+
+ return 0;
+}
+
+/*
+ * Send a signal to all outstanding fsck child processes
+ */
+static int kill_all(int signum)
+{
+ struct fsck_instance *inst;
+ int n = 0;
+
+ for (inst = instance_list; inst; inst = inst->next) {
+ if (inst->flags & FLAG_DONE)
+ continue;
+ kill(inst->pid, signum);
+ n++;
+ }
+ return n;
+}
+
+/*
+ * Wait for one child process to exit; when it does, unlink it from
+ * the list of executing child processes, and return it.
+ */
+static struct fsck_instance *wait_one(int flags)
+{
+ int status;
+ int sig;
+ struct fsck_instance *inst, *inst2, *prev;
+ pid_t pid;
+
+ if (!instance_list)
+ return NULL;
+
+ if (noexecute) {
+ inst = instance_list;
+ prev = 0;
+#ifdef RANDOM_DEBUG
+ while (inst->next && (random() & 1)) {
+ prev = inst;
+ inst = inst->next;
+ }
+#endif
+ inst->exit_status = 0;
+ goto ret_inst;
+ }
+
+ /*
+ * gcc -Wall fails saving throw against stupidity
+ * (inst and prev are thought to be uninitialized variables)
+ */
+ inst = prev = NULL;
+
+ do {
+ pid = waitpid(-1, &status, flags);
+ if (cancel_requested && !kill_sent) {
+ kill_all(SIGTERM);
+ kill_sent++;
+ }
+ if ((pid == 0) && (flags & WNOHANG))
+ return NULL;
+ if (pid < 0) {
+ if ((errno == EINTR) || (errno == EAGAIN))
+ continue;
+ if (errno == ECHILD) {
+ bb_error_msg("wait: no more child process?!?");
+ return NULL;
+ }
+ perror("wait");
+ continue;
+ }
+ for (prev = 0, inst = instance_list;
+ inst;
+ prev = inst, inst = inst->next) {
+ if (inst->pid == pid)
+ break;
+ }
+ } while (!inst);
+
+ if (WIFEXITED(status))
+ status = WEXITSTATUS(status);
+ else if (WIFSIGNALED(status)) {
+ sig = WTERMSIG(status);
+ if (sig == SIGINT) {
+ status = EXIT_UNCORRECTED;
+ } else {
+ printf("Warning... %s for device %s exited "
+ "with signal %d.\n",
+ inst->prog, inst->device, sig);
+ status = EXIT_ERROR;
+ }
+ } else {
+ printf("%s %s: status is %x, should never happen.\n",
+ inst->prog, inst->device, status);
+ status = EXIT_ERROR;
+ }
+ inst->exit_status = status;
+ if (progress && (inst->flags & FLAG_PROGRESS) &&
+ !progress_active()) {
+ for (inst2 = instance_list; inst2; inst2 = inst2->next) {
+ if (inst2->flags & FLAG_DONE)
+ continue;
+ if (strcmp(inst2->type, "ext2") &&
+ strcmp(inst2->type, "ext3"))
+ continue;
+ /*
+ * If we've just started the fsck, wait a tiny
+ * bit before sending the kill, to give it
+ * time to set up the signal handler
+ */
+ if (inst2->start_time < time(0)+2) {
+ if (fork() == 0) {
+ sleep(1);
+ kill(inst2->pid, SIGUSR1);
+ exit(0);
+ }
+ } else
+ kill(inst2->pid, SIGUSR1);
+ inst2->flags |= FLAG_PROGRESS;
+ break;
+ }
+ }
+ret_inst:
+ if (prev)
+ prev->next = inst->next;
+ else
+ instance_list = inst->next;
+ if (verbose > 1)
+ printf("Finished with %s (exit status %d)\n",
+ inst->device, inst->exit_status);
+ num_running--;
+ return inst;
+}
+
+#define FLAG_WAIT_ALL 0
+#define FLAG_WAIT_ATLEAST_ONE 1
+/*
+ * Wait until all executing child processes have exited; return the
+ * logical OR of all of their exit code values.
+ */
+static int wait_many(int flags)
+{
+ struct fsck_instance *inst;
+ int global_status = 0;
+ int wait_flags = 0;
+
+ while ((inst = wait_one(wait_flags))) {
+ global_status |= inst->exit_status;
+ free_instance(inst);
+#ifdef RANDOM_DEBUG
+ if (noexecute && (flags & WNOHANG) && !(random() % 3))
+ break;
+#endif
+ if (flags & FLAG_WAIT_ATLEAST_ONE)
+ wait_flags = WNOHANG;
+ }
+ return global_status;
+}
+
+/*
+ * Run the fsck program on a particular device
+ *
+ * If the type is specified using -t, and it isn't prefixed with "no"
+ * (as in "noext2") and only one filesystem type is specified, then
+ * use that type regardless of what is specified in /etc/fstab.
+ *
+ * If the type isn't specified by the user, then use either the type
+ * specified in /etc/fstab, or DEFAULT_FSTYPE.
+ */
+static void fsck_device(struct fs_info *fs, int interactive)
+{
+ const char *type;
+ int retval;
+
+ interpret_type(fs);
+
+ if (strcmp(fs->type, "auto") != 0)
+ type = fs->type;
+ else if (fstype && strncmp(fstype, "no", 2) &&
+ strncmp(fstype, "opts=", 5) && strncmp(fstype, "loop", 4) &&
+ !strchr(fstype, ','))
+ type = fstype;
+ else
+ type = DEFAULT_FSTYPE;
+
+ num_running++;
+ retval = execute(type, fs->device, fs->mountpt, interactive);
+ if (retval) {
+ bb_error_msg("error %d while executing fsck.%s for %s",
+ retval, type, fs->device);
+ num_running--;
+ }
+}
+
+
+/*
+ * Deal with the fsck -t argument.
+ */
+struct fs_type_compile {
+ char **list;
+ int *type;
+ int negate;
+} fs_type_compiled;
+
+#define FS_TYPE_NORMAL 0
+#define FS_TYPE_OPT 1
+#define FS_TYPE_NEGOPT 2
+
+static const char fs_type_syntax_error[] =
+"Either all or none of the filesystem types passed to -t must be prefixed\n"
+ "with 'no' or '!'.";
+
+static void compile_fs_type(char *fs_type, struct fs_type_compile *cmp)
+{
+ char *cp, *list, *s;
+ int num = 2;
+ int negate, first_negate = 1;
+
+ if (fs_type) {
+ for (cp=fs_type; *cp; cp++) {
+ if (*cp == ',')
+ num++;
+ }
+ }
+
+ cmp->list = xzalloc(num * sizeof(char *));
+ cmp->type = xzalloc(num * sizeof(int));
+ cmp->negate = 0;
+
+ if (!fs_type)
+ return;
+
+ list = string_copy(fs_type);
+ num = 0;
+ s = strtok(list, ",");
+ while(s) {
+ negate = 0;
+ if (strncmp(s, "no", 2) == 0) {
+ s += 2;
+ negate = 1;
+ } else if (*s == '!') {
+ s++;
+ negate = 1;
+ }
+ if (strcmp(s, "loop") == 0)
+ /* loop is really short-hand for opts=loop */
+ goto loop_special_case;
+ else if (strncmp(s, "opts=", 5) == 0) {
+ s += 5;
+ loop_special_case:
+ cmp->type[num] = negate ? FS_TYPE_NEGOPT : FS_TYPE_OPT;
+ } else {
+ if (first_negate) {
+ cmp->negate = negate;
+ first_negate = 0;
+ }
+ if ((negate && !cmp->negate) ||
+ (!negate && cmp->negate)) {
+ bb_error_msg_and_die("%s", fs_type_syntax_error);
+ }
+ }
+ cmp->list[num++] = string_copy(s);
+ s = strtok(NULL, ",");
+ }
+ free(list);
+}
+
+/*
+ * This function returns true if a particular option appears in a
+ * comma-delimited options list
+ */
+static int opt_in_list(char *opt, char *optlist)
+{
+ char *list, *s;
+
+ if (!optlist)
+ return 0;
+ list = string_copy(optlist);
+
+ s = strtok(list, ",");
+ while(s) {
+ if (strcmp(s, opt) == 0) {
+ free(list);
+ return 1;
+ }
+ s = strtok(NULL, ",");
+ }
+ free(list);
+ return 0;
+}
+
+/* See if the filesystem matches the criteria given by the -t option */
+static int fs_match(struct fs_info *fs, struct fs_type_compile *cmp)
+{
+ int n, ret = 0, checked_type = 0;
+ char *cp;
+
+ if (cmp->list == 0 || cmp->list[0] == 0)
+ return 1;
+
+ for (n=0; (cp = cmp->list[n]); n++) {
+ switch (cmp->type[n]) {
+ case FS_TYPE_NORMAL:
+ checked_type++;
+ if (strcmp(cp, fs->type) == 0) {
+ ret = 1;
+ }
+ break;
+ case FS_TYPE_NEGOPT:
+ if (opt_in_list(cp, fs->opts))
+ return 0;
+ break;
+ case FS_TYPE_OPT:
+ if (!opt_in_list(cp, fs->opts))
+ return 0;
+ break;
+ }
+ }
+ if (checked_type == 0)
+ return 1;
+ return (cmp->negate ? !ret : ret);
+}
+
+/* Check if we should ignore this filesystem. */
+static int ignore(struct fs_info *fs)
+{
+ int wanted;
+ char *s;
+
+ /*
+ * If the pass number is 0, ignore it.
+ */
+ if (fs->passno == 0)
+ return 1;
+
+ interpret_type(fs);
+
+ /*
+ * If a specific fstype is specified, and it doesn't match,
+ * ignore it.
+ */
+ if (!fs_match(fs, &fs_type_compiled)) return 1;
+
+ /* Are we ignoring this type? */
+ if (index_in_str_array(ignored_types, fs->type) >= 0)
+ return 1;
+
+ /* Do we really really want to check this fs? */
+ wanted = index_in_str_array(really_wanted, fs->type) >= 0;
+
+ /* See if the <fsck.fs> program is available. */
+ s = find_fsck(fs->type);
+ if (s == NULL) {
+ if (wanted)
+ bb_error_msg("cannot check %s: fsck.%s not found",
+ fs->device, fs->type);
+ return 1;
+ }
+ free(s);
+
+ /* We can and want to check this file system type. */
+ return 0;
+}
+
+/*
+ * Returns TRUE if a partition on the same disk is already being
+ * checked.
+ */
+static int device_already_active(char *device)
+{
+ struct fsck_instance *inst;
+ char *base;
+
+ if (force_all_parallel)
+ return 0;
+
+#ifdef BASE_MD
+ /* Don't check a soft raid disk with any other disk */
+ if (instance_list &&
+ (!strncmp(instance_list->device, BASE_MD, sizeof(BASE_MD)-1) ||
+ !strncmp(device, BASE_MD, sizeof(BASE_MD)-1)))
+ return 1;
+#endif
+
+ base = base_device(device);
+ /*
+ * If we don't know the base device, assume that the device is
+ * already active if there are any fsck instances running.
+ */
+ if (!base)
+ return (instance_list != 0);
+ for (inst = instance_list; inst; inst = inst->next) {
+ if (!inst->base_device || !strcmp(base, inst->base_device)) {
+ free(base);
+ return 1;
+ }
+ }
+ free(base);
+ return 0;
+}
+
+/* Check all file systems, using the /etc/fstab table. */
+static int check_all(void)
+{
+ struct fs_info *fs = NULL;
+ int status = EXIT_OK;
+ int not_done_yet = 1;
+ int passno = 1;
+ int pass_done;
+
+ if (verbose)
+ fputs("Checking all file systems.\n", stdout);
+
+ /*
+ * Do an initial scan over the filesystem; mark filesystems
+ * which should be ignored as done, and resolve any "auto"
+ * filesystem types (done as a side-effect of calling ignore()).
+ */
+ for (fs = filesys_info; fs; fs = fs->next) {
+ if (ignore(fs))
+ fs->flags |= FLAG_DONE;
+ }
+
+ /*
+ * Find and check the root filesystem.
+ */
+ if (!parallel_root) {
+ for (fs = filesys_info; fs; fs = fs->next) {
+ if (LONE_CHAR(fs->mountpt, '/'))
+ break;
+ }
+ if (fs) {
+ if (!skip_root && !ignore(fs)) {
+ fsck_device(fs, 1);
+ status |= wait_many(FLAG_WAIT_ALL);
+ if (status > EXIT_NONDESTRUCT)
+ return status;
+ }
+ fs->flags |= FLAG_DONE;
+ }
+ }
+ /*
+ * This is for the bone-headed user who enters the root
+ * filesystem twice. Skip root will skep all root entries.
+ */
+ if (skip_root)
+ for (fs = filesys_info; fs; fs = fs->next)
+ if (LONE_CHAR(fs->mountpt, '/'))
+ fs->flags |= FLAG_DONE;
+
+ while (not_done_yet) {
+ not_done_yet = 0;
+ pass_done = 1;
+
+ for (fs = filesys_info; fs; fs = fs->next) {
+ if (cancel_requested)
+ break;
+ if (fs->flags & FLAG_DONE)
+ continue;
+ /*
+ * If the filesystem's pass number is higher
+ * than the current pass number, then we don't
+ * do it yet.
+ */
+ if (fs->passno > passno) {
+ not_done_yet++;
+ continue;
+ }
+ /*
+ * If a filesystem on a particular device has
+ * already been spawned, then we need to defer
+ * this to another pass.
+ */
+ if (device_already_active(fs->device)) {
+ pass_done = 0;
+ continue;
+ }
+ /*
+ * Spawn off the fsck process
+ */
+ fsck_device(fs, serialize);
+ fs->flags |= FLAG_DONE;
+
+ /*
+ * Only do one filesystem at a time, or if we
+ * have a limit on the number of fsck's extant
+ * at one time, apply that limit.
+ */
+ if (serialize ||
+ (max_running && (num_running >= max_running))) {
+ pass_done = 0;
+ break;
+ }
+ }
+ if (cancel_requested)
+ break;
+ if (verbose > 1)
+ printf("--waiting-- (pass %d)\n", passno);
+ status |= wait_many(pass_done ? FLAG_WAIT_ALL :
+ FLAG_WAIT_ATLEAST_ONE);
+ if (pass_done) {
+ if (verbose > 1)
+ printf("----------------------------------\n");
+ passno++;
+ } else
+ not_done_yet++;
+ }
+ if (cancel_requested && !kill_sent) {
+ kill_all(SIGTERM);
+ kill_sent++;
+ }
+ status |= wait_many(FLAG_WAIT_ATLEAST_ONE);
+ return status;
+}
+
+static void signal_cancel(int sig FSCK_ATTR((unused)))
+{
+ cancel_requested++;
+}
+
+static void PRS(int argc, char **argv)
+{
+ int i, j;
+ char *arg, *dev, *tmp = 0;
+ char options[128];
+ int opt = 0;
+ int opts_for_fsck = 0;
+ struct sigaction sa;
+
+ /*
+ * Set up signal action
+ */
+ memset(&sa, 0, sizeof(struct sigaction));
+ sa.sa_handler = signal_cancel;
+ sigaction(SIGINT, &sa, 0);
+ sigaction(SIGTERM, &sa, 0);
+
+ num_devices = 0;
+ num_args = 0;
+ instance_list = 0;
+
+ for (i=1; i < argc; i++) {
+ arg = argv[i];
+ if (!arg)
+ continue;
+ if ((arg[0] == '/' && !opts_for_fsck) || strchr(arg, '=')) {
+ if (num_devices >= MAX_DEVICES) {
+ bb_error_msg_and_die("too many devices");
+ }
+ dev = blkid_get_devname(cache, arg, NULL);
+ if (!dev && strchr(arg, '=')) {
+ /*
+ * Check to see if we failed because
+ * /proc/partitions isn't found.
+ */
+ if (access("/proc/partitions", R_OK) < 0) {
+ bb_perror_msg_and_die("cannot open /proc/partitions "
+ "(is /proc mounted?)");
+ }
+ /*
+ * Check to see if this is because
+ * we're not running as root
+ */
+ if (geteuid())
+ bb_error_msg_and_die(
+ "must be root to scan for matching filesystems: %s\n", arg);
+ else
+ bb_error_msg_and_die(
+ "cannot find matching filesystem: %s", arg);
+ }
+ devices[num_devices++] = dev ? dev : string_copy(arg);
+ continue;
+ }
+ if (arg[0] != '-' || opts_for_fsck) {
+ if (num_args >= MAX_ARGS) {
+ bb_error_msg_and_die("too many arguments");
+ }
+ args[num_args++] = string_copy(arg);
+ continue;
+ }
+ for (j=1; arg[j]; j++) {
+ if (opts_for_fsck) {
+ options[++opt] = arg[j];
+ continue;
+ }
+ switch (arg[j]) {
+ case 'A':
+ doall++;
+ break;
+ case 'C':
+ progress++;
+ if (arg[j+1]) {
+ progress_fd = string_to_int(arg+j+1);
+ if (progress_fd < 0)
+ progress_fd = 0;
+ else
+ goto next_arg;
+ } else if ((i+1) < argc
+ && argv[i+1][0] != '-') {
+ progress_fd = string_to_int(argv[i]);
+ if (progress_fd < 0)
+ progress_fd = 0;
+ else {
+ goto next_arg;
+ i++;
+ }
+ }
+ break;
+ case 'V':
+ verbose++;
+ break;
+ case 'N':
+ noexecute++;
+ break;
+ case 'R':
+ skip_root++;
+ break;
+ case 'T':
+ notitle++;
+ break;
+ case 'M':
+ like_mount++;
+ break;
+ case 'P':
+ parallel_root++;
+ break;
+ case 's':
+ serialize++;
+ break;
+ case 't':
+ tmp = 0;
+ if (fstype)
+ bb_show_usage();
+ if (arg[j+1])
+ tmp = arg+j+1;
+ else if ((i+1) < argc)
+ tmp = argv[++i];
+ else
+ bb_show_usage();
+ fstype = string_copy(tmp);
+ compile_fs_type(fstype, &fs_type_compiled);
+ goto next_arg;
+ case '-':
+ opts_for_fsck++;
+ break;
+ case '?':
+ bb_show_usage();
+ break;
+ default:
+ options[++opt] = arg[j];
+ break;
+ }
+ }
+ next_arg:
+ if (opt) {
+ options[0] = '-';
+ options[++opt] = '\0';
+ if (num_args >= MAX_ARGS) {
+ bb_error_msg("too many arguments");
+ }
+ args[num_args++] = string_copy(options);
+ opt = 0;
+ }
+ }
+ if (getenv("FSCK_FORCE_ALL_PARALLEL"))
+ force_all_parallel++;
+ if ((tmp = getenv("FSCK_MAX_INST")))
+ max_running = atoi(tmp);
+}
+
+int fsck_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int fsck_main(int argc, char **argv)
+{
+ int i, status = 0;
+ int interactive = 0;
+ const char *fstab;
+ struct fs_info *fs;
+
+ setvbuf(stdout, NULL, _IONBF, BUFSIZ);
+ setvbuf(stderr, NULL, _IONBF, BUFSIZ);
+
+ blkid_get_cache(&cache, NULL);
+ PRS(argc, argv);
+
+ if (!notitle)
+ printf("fsck %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE);
+
+ fstab = getenv("FSTAB_FILE");
+ if (!fstab)
+ fstab = _PATH_MNTTAB;
+ load_fs_info(fstab);
+
+ fsck_path = e2fs_set_sbin_path();
+
+ if ((num_devices == 1) || (serialize))
+ interactive = 1;
+
+ /* If -A was specified ("check all"), do that! */
+ if (doall)
+ return check_all();
+
+ if (num_devices == 0) {
+ serialize++;
+ interactive++;
+ return check_all();
+ }
+ for (i = 0; i < num_devices; i++) {
+ if (cancel_requested) {
+ if (!kill_sent) {
+ kill_all(SIGTERM);
+ kill_sent++;
+ }
+ break;
+ }
+ fs = lookup(devices[i]);
+ if (!fs) {
+ fs = create_fs_device(devices[i], 0, "auto",
+ 0, -1, -1);
+ if (!fs)
+ continue;
+ }
+ fsck_device(fs, interactive);
+ if (serialize ||
+ (max_running && (num_running >= max_running))) {
+ struct fsck_instance *inst;
+
+ inst = wait_one(0);
+ if (inst) {
+ status |= inst->exit_status;
+ free_instance(inst);
+ }
+ if (verbose > 1)
+ printf("----------------------------------\n");
+ }
+ }
+ status |= wait_many(FLAG_WAIT_ALL);
+ blkid_put_cache(cache);
+ return status;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/fsck.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/fsck.h
new file mode 100644
index 0000000000..2ca2af7da8
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/fsck.h
@@ -0,0 +1,16 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * fsck.h
+ */
+
+#define FSCK_ATTR(x) __attribute__(x)
+
+#define EXIT_OK 0
+#define EXIT_NONDESTRUCT 1
+#define EXIT_DESTRUCT 2
+#define EXIT_UNCORRECTED 4
+#define EXIT_ERROR 8
+#define EXIT_USAGE 16
+#define FSCK_CANCELED 32 /* Aborted with a signal or ^C */
+
+extern char *e2fs_set_sbin_path(void);
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/lsattr.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/lsattr.c
new file mode 100644
index 0000000000..294bf2f2e8
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/lsattr.c
@@ -0,0 +1,129 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * lsattr.c - List file attributes on an ext2 file system
+ *
+ * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
+ * Laboratoire MASI, Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * This file can be redistributed under the terms of the GNU General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/10/30 - Creation
+ * 93/11/13 - Replace stat() calls by lstat() to avoid loops
+ * 94/02/27 - Integrated in Ted's distribution
+ * 98/12/29 - Display version info only when -V specified (G M Sipe)
+ */
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include "ext2fs/ext2_fs.h"
+#include "e2fsbb.h"
+#include "e2p/e2p.h"
+
+#define OPT_RECUR 1
+#define OPT_ALL 2
+#define OPT_DIRS_OPT 4
+#define OPT_PF_LONG 8
+#define OPT_GENERATION 16
+static int flags;
+
+static void list_attributes(const char *name)
+{
+ unsigned long fsflags;
+ unsigned long generation;
+
+ if (fgetflags(name, &fsflags) == -1)
+ goto read_err;
+ if (flags & OPT_GENERATION) {
+ if (fgetversion(name, &generation) == -1)
+ goto read_err;
+ printf("%5lu ", generation);
+ }
+
+ if (flags & OPT_PF_LONG) {
+ printf("%-28s ", name);
+ print_e2flags(stdout, fsflags, PFOPT_LONG);
+ bb_putchar('\n');
+ } else {
+ print_e2flags(stdout, fsflags, 0);
+ printf(" %s\n", name);
+ }
+
+ return;
+read_err:
+ bb_perror_msg("reading %s", name);
+}
+
+static int lsattr_dir_proc(const char *, struct dirent *, void *);
+
+static void lsattr_args(const char *name)
+{
+ struct stat st;
+
+ if (lstat(name, &st) == -1) {
+ bb_perror_msg("stating %s", name);
+ } else {
+ if (S_ISDIR(st.st_mode) && !(flags & OPT_DIRS_OPT))
+ iterate_on_dir(name, lsattr_dir_proc, NULL);
+ else
+ list_attributes(name);
+ }
+}
+
+static int lsattr_dir_proc(const char *dir_name, struct dirent *de,
+ void *private)
+{
+ struct stat st;
+ char *path;
+
+ path = concat_path_file(dir_name, de->d_name);
+
+ if (lstat(path, &st) == -1)
+ bb_perror_msg(path);
+ else {
+ if (de->d_name[0] != '.' || (flags & OPT_ALL)) {
+ list_attributes(path);
+ if (S_ISDIR(st.st_mode) && (flags & OPT_RECUR) &&
+ (de->d_name[0] != '.' && (de->d_name[1] != '\0' ||
+ (de->d_name[1] != '.' && de->d_name[2] != '\0')))) {
+ printf("\n%s:\n", path);
+ iterate_on_dir(path, lsattr_dir_proc, NULL);
+ bb_putchar('\n');
+ }
+ }
+ }
+
+ free(path);
+
+ return 0;
+}
+
+int lsattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int lsattr_main(int argc, char **argv)
+{
+ int i;
+
+ flags = getopt32(argv, "Radlv");
+
+ if (optind > argc - 1)
+ lsattr_args(".");
+ else
+ for (i = optind; i < argc; i++)
+ lsattr_args(argv[i]);
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/mke2fs.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/mke2fs.c
new file mode 100644
index 0000000000..89b5223b79
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/mke2fs.c
@@ -0,0 +1,1336 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * mke2fs.c - Make a ext2fs filesystem.
+ *
+ * Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+ * 2003, 2004, 2005 by Theodore Ts'o.
+ *
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ */
+
+/* Usage: mke2fs [options] device
+ *
+ * The device may be a block device or a image of one, but this isn't
+ * enforced (but it's not much fun on a character device :-).
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <time.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <mntent.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+
+#include "e2fsbb.h"
+#include "ext2fs/ext2_fs.h"
+#include "uuid/uuid.h"
+#include "e2p/e2p.h"
+#include "ext2fs/ext2fs.h"
+#include "util.h"
+
+#define STRIDE_LENGTH 8
+
+#ifndef __sparc__
+#define ZAP_BOOTBLOCK
+#endif
+
+static const char * device_name;
+
+/* Command line options */
+static int cflag;
+static int quiet;
+static int super_only;
+static int force;
+static int noaction;
+static int journal_size;
+static int journal_flags;
+static const char *bad_blocks_filename;
+static __u32 fs_stride;
+
+static struct ext2_super_block param;
+static char *creator_os;
+static char *volume_label;
+static char *mount_dir;
+static char *journal_device = NULL;
+static int sync_kludge; /* Set using the MKE2FS_SYNC env. option */
+
+static int sys_page_size = 4096;
+static int linux_version_code = 0;
+
+static int int_log2(int arg)
+{
+ int l = 0;
+
+ arg >>= 1;
+ while (arg) {
+ l++;
+ arg >>= 1;
+ }
+ return l;
+}
+
+static int int_log10(unsigned int arg)
+{
+ int l;
+
+ for (l = 0; arg; l++)
+ arg = arg / 10;
+ return l;
+}
+
+/*
+ * This function sets the default parameters for a filesystem
+ *
+ * The type is specified by the user. The size is the maximum size
+ * (in megabytes) for which a set of parameters applies, with a size
+ * of zero meaning that it is the default parameter for the type.
+ * Note that order is important in the table below.
+ */
+#define DEF_MAX_BLOCKSIZE -1
+static const char default_str[] = "default";
+struct mke2fs_defaults {
+ const char *type;
+ int size;
+ int blocksize;
+ int inode_ratio;
+};
+
+static const struct mke2fs_defaults settings[] = {
+ { default_str, 0, 4096, 8192 },
+ { default_str, 512, 1024, 4096 },
+ { default_str, 3, 1024, 8192 },
+ { "journal", 0, 4096, 8192 },
+ { "news", 0, 4096, 4096 },
+ { "largefile", 0, 4096, 1024 * 1024 },
+ { "largefile4", 0, 4096, 4096 * 1024 },
+ { 0, 0, 0, 0},
+};
+
+static void set_fs_defaults(const char *fs_type,
+ struct ext2_super_block *super,
+ int blocksize, int sector_size,
+ int *inode_ratio)
+{
+ int megs;
+ int ratio = 0;
+ const struct mke2fs_defaults *p;
+ int use_bsize = 1024;
+
+ megs = super->s_blocks_count * (EXT2_BLOCK_SIZE(super) / 1024) / 1024;
+ if (inode_ratio)
+ ratio = *inode_ratio;
+ if (!fs_type)
+ fs_type = default_str;
+ for (p = settings; p->type; p++) {
+ if ((strcmp(p->type, fs_type) != 0) &&
+ (strcmp(p->type, default_str) != 0))
+ continue;
+ if ((p->size != 0) && (megs > p->size))
+ continue;
+ if (ratio == 0)
+ *inode_ratio = p->inode_ratio < blocksize ?
+ blocksize : p->inode_ratio;
+ use_bsize = p->blocksize;
+ }
+ if (blocksize <= 0) {
+ if (use_bsize == DEF_MAX_BLOCKSIZE) {
+ use_bsize = sys_page_size;
+ if ((linux_version_code < (2*65536 + 6*256)) &&
+ (use_bsize > 4096))
+ use_bsize = 4096;
+ }
+ if (sector_size && use_bsize < sector_size)
+ use_bsize = sector_size;
+ if ((blocksize < 0) && (use_bsize < (-blocksize)))
+ use_bsize = -blocksize;
+ blocksize = use_bsize;
+ super->s_blocks_count /= blocksize / 1024;
+ }
+ super->s_log_frag_size = super->s_log_block_size =
+ int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE);
+}
+
+
+/*
+ * Helper function for read_bb_file and test_disk
+ */
+static void invalid_block(ext2_filsys fs EXT2FS_ATTR((unused)), blk_t blk)
+{
+ bb_error_msg("Bad block %u out of range; ignored", blk);
+}
+
+/*
+ * Busybox stuff
+ */
+static void mke2fs_error_msg_and_die(int retval, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+static void mke2fs_error_msg_and_die(int retval, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (retval) {
+ va_start(ap, fmt);
+ fprintf(stderr,"\nCould not ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void mke2fs_verbose(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+static void mke2fs_verbose(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (!quiet) {
+ va_start(ap, fmt);
+ vfprintf(stdout, fmt, ap);
+ fflush(stdout);
+ va_end(ap);
+ }
+}
+
+static void mke2fs_verbose_done(void)
+{
+ mke2fs_verbose("done\n");
+}
+
+static void mke2fs_warning_msg(int retval, char *fmt, ... ) __attribute__ ((format (printf, 2, 3)));
+static void mke2fs_warning_msg(int retval, char *fmt, ... )
+{
+ va_list ap;
+
+ if (retval) {
+ va_start(ap, fmt);
+ fprintf(stderr,"\nWarning: ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ }
+}
+
+/*
+ * Reads the bad blocks list from a file
+ */
+static void read_bb_file(ext2_filsys fs, badblocks_list *bb_list,
+ const char *bad_blocks_file)
+{
+ FILE *f;
+ errcode_t retval;
+
+ f = xfopen(bad_blocks_file, "r");
+ retval = ext2fs_read_bb_FILE(fs, f, bb_list, invalid_block);
+ fclose (f);
+ mke2fs_error_msg_and_die(retval, "read bad blocks from list");
+}
+
+/*
+ * Runs the badblocks program to test the disk
+ */
+static void test_disk(ext2_filsys fs, badblocks_list *bb_list)
+{
+ FILE *f;
+ errcode_t retval;
+ char buf[1024];
+
+ sprintf(buf, "badblocks -b %d %s%s%s %d", fs->blocksize,
+ quiet ? "" : "-s ", (cflag > 1) ? "-w " : "",
+ fs->device_name, fs->super->s_blocks_count);
+ mke2fs_verbose("Running command: %s\n", buf);
+ f = popen(buf, "r");
+ if (!f) {
+ bb_perror_msg_and_die("cannot run '%s'", buf);
+ }
+ retval = ext2fs_read_bb_FILE(fs, f, bb_list, invalid_block);
+ pclose(f);
+ mke2fs_error_msg_and_die(retval, "read bad blocks from program");
+}
+
+static void handle_bad_blocks(ext2_filsys fs, badblocks_list bb_list)
+{
+ dgrp_t i;
+ blk_t j;
+ unsigned must_be_good;
+ blk_t blk;
+ badblocks_iterate bb_iter;
+ errcode_t retval;
+ blk_t group_block;
+ int group;
+ int group_bad;
+
+ if (!bb_list)
+ return;
+
+ /*
+ * The primary superblock and group descriptors *must* be
+ * good; if not, abort.
+ */
+ must_be_good = fs->super->s_first_data_block + 1 + fs->desc_blocks;
+ for (i = fs->super->s_first_data_block; i <= must_be_good; i++) {
+ if (ext2fs_badblocks_list_test(bb_list, i)) {
+ bb_error_msg_and_die(
+ "Block %d in primary superblock/group descriptor area bad\n"
+ "Blocks %d through %d must be good in order to build a filesystem\n"
+ "Aborting ...", i, fs->super->s_first_data_block, must_be_good);
+ }
+ }
+
+ /*
+ * See if any of the bad blocks are showing up in the backup
+ * superblocks and/or group descriptors. If so, issue a
+ * warning and adjust the block counts appropriately.
+ */
+ group_block = fs->super->s_first_data_block +
+ fs->super->s_blocks_per_group;
+
+ for (i = 1; i < fs->group_desc_count; i++) {
+ group_bad = 0;
+ for (j=0; j < fs->desc_blocks+1; j++) {
+ if (ext2fs_badblocks_list_test(bb_list,
+ group_block + j)) {
+ mke2fs_warning_msg(!group_bad,
+ "the backup superblock/group descriptors at block %d contain\n"
+ "bad blocks\n", group_block);
+ group_bad++;
+ group = ext2fs_group_of_blk(fs, group_block+j);
+ fs->group_desc[group].bg_free_blocks_count++;
+ fs->super->s_free_blocks_count++;
+ }
+ }
+ group_block += fs->super->s_blocks_per_group;
+ }
+
+ /*
+ * Mark all the bad blocks as used...
+ */
+ retval = ext2fs_badblocks_list_iterate_begin(bb_list, &bb_iter);
+ mke2fs_error_msg_and_die(retval, "mark bad blocks as used");
+
+ while (ext2fs_badblocks_list_iterate(bb_iter, &blk))
+ ext2fs_mark_block_bitmap(fs->block_map, blk);
+ ext2fs_badblocks_list_iterate_end(bb_iter);
+}
+
+/*
+ * These functions implement a generalized progress meter.
+ */
+struct progress_struct {
+ char format[20];
+ char backup[80];
+ __u32 max;
+ int skip_progress;
+};
+
+static void progress_init(struct progress_struct *progress,
+ const char *label,__u32 max)
+{
+ int i;
+
+ memset(progress, 0, sizeof(struct progress_struct));
+ if (quiet)
+ return;
+
+ /*
+ * Figure out how many digits we need
+ */
+ i = int_log10(max);
+ sprintf(progress->format, "%%%dd/%%%dld", i, i);
+ memset(progress->backup, '\b', sizeof(progress->backup)-1);
+ progress->backup[sizeof(progress->backup)-1] = 0;
+ if ((2*i)+1 < (int) sizeof(progress->backup))
+ progress->backup[(2*i)+1] = 0;
+ progress->max = max;
+
+ progress->skip_progress = 0;
+ if (getenv("MKE2FS_SKIP_PROGRESS"))
+ progress->skip_progress++;
+
+ fputs(label, stdout);
+ fflush(stdout);
+}
+
+static void progress_update(struct progress_struct *progress, __u32 val)
+{
+ if ((progress->format[0] == 0) || progress->skip_progress)
+ return;
+ printf(progress->format, val, progress->max);
+ fputs(progress->backup, stdout);
+}
+
+static void progress_close(struct progress_struct *progress)
+{
+ if (progress->format[0] == 0)
+ return;
+ printf("%-28s\n", "done");
+}
+
+
+/*
+ * Helper function which zeros out _num_ blocks starting at _blk_. In
+ * case of an error, the details of the error is returned via _ret_blk_
+ * and _ret_count_ if they are non-NULL pointers. Returns 0 on
+ * success, and an error code on an error.
+ *
+ * As a special case, if the first argument is NULL, then it will
+ * attempt to free the static zeroizing buffer. (This is to keep
+ * programs that check for memory leaks happy.)
+ */
+static errcode_t zero_blocks(ext2_filsys fs, blk_t blk, int num,
+ struct progress_struct *progress,
+ blk_t *ret_blk, int *ret_count)
+{
+ int j, count, next_update, next_update_incr;
+ static char *buf;
+ errcode_t retval;
+
+ /* If fs is null, clean up the static buffer and return */
+ if (!fs) {
+ if (buf) {
+ free(buf);
+ buf = 0;
+ }
+ return 0;
+ }
+ /* Allocate the zeroizing buffer if necessary */
+ if (!buf) {
+ buf = xzalloc(fs->blocksize * STRIDE_LENGTH);
+ }
+ /* OK, do the write loop */
+ next_update = 0;
+ next_update_incr = num / 100;
+ if (next_update_incr < 1)
+ next_update_incr = 1;
+ for (j=0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH) {
+ count = num - j;
+ if (count > STRIDE_LENGTH)
+ count = STRIDE_LENGTH;
+ retval = io_channel_write_blk(fs->io, blk, count, buf);
+ if (retval) {
+ if (ret_count)
+ *ret_count = count;
+ if (ret_blk)
+ *ret_blk = blk;
+ return retval;
+ }
+ if (progress && j > next_update) {
+ next_update += num / 100;
+ progress_update(progress, blk);
+ }
+ }
+ return 0;
+}
+
+static void write_inode_tables(ext2_filsys fs)
+{
+ errcode_t retval;
+ blk_t blk;
+ dgrp_t i;
+ int num;
+ struct progress_struct progress;
+
+ if (quiet)
+ memset(&progress, 0, sizeof(progress));
+ else
+ progress_init(&progress, "Writing inode tables: ",
+ fs->group_desc_count);
+
+ for (i = 0; i < fs->group_desc_count; i++) {
+ progress_update(&progress, i);
+
+ blk = fs->group_desc[i].bg_inode_table;
+ num = fs->inode_blocks_per_group;
+
+ retval = zero_blocks(fs, blk, num, 0, &blk, &num);
+ mke2fs_error_msg_and_die(retval,
+ "write %d blocks in inode table starting at %d.",
+ num, blk);
+ if (sync_kludge) {
+ if (sync_kludge == 1)
+ sync();
+ else if ((i % sync_kludge) == 0)
+ sync();
+ }
+ }
+ zero_blocks(0, 0, 0, 0, 0, 0);
+ progress_close(&progress);
+}
+
+static void create_root_dir(ext2_filsys fs)
+{
+ errcode_t retval;
+ struct ext2_inode inode;
+
+ retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0);
+ mke2fs_error_msg_and_die(retval, "create root dir");
+ if (geteuid()) {
+ retval = ext2fs_read_inode(fs, EXT2_ROOT_INO, &inode);
+ mke2fs_error_msg_and_die(retval, "read root inode");
+ inode.i_uid = getuid();
+ if (inode.i_uid)
+ inode.i_gid = getgid();
+ retval = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode);
+ mke2fs_error_msg_and_die(retval, "set root inode ownership");
+ }
+}
+
+static void create_lost_and_found(ext2_filsys fs)
+{
+ errcode_t retval;
+ ext2_ino_t ino;
+ const char *name = "lost+found";
+ int i = 1;
+ char *msg = "create";
+ int lpf_size = 0;
+
+ fs->umask = 077;
+ retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, 0, name);
+ if (retval) {
+ goto CREATE_LOST_AND_FOUND_ERROR;
+ }
+
+ retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, strlen(name), 0, &ino);
+ if (retval) {
+ msg = "lookup";
+ goto CREATE_LOST_AND_FOUND_ERROR;
+ }
+
+ for (; i < EXT2_NDIR_BLOCKS; i++) {
+ if ((lpf_size += fs->blocksize) >= 16*1024)
+ break;
+ retval = ext2fs_expand_dir(fs, ino);
+ msg = "expand";
+CREATE_LOST_AND_FOUND_ERROR:
+ mke2fs_error_msg_and_die(retval, "%s %s", msg, name);
+ }
+}
+
+static void create_bad_block_inode(ext2_filsys fs, badblocks_list bb_list)
+{
+ errcode_t retval;
+
+ ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_BAD_INO);
+ fs->group_desc[0].bg_free_inodes_count--;
+ fs->super->s_free_inodes_count--;
+ retval = ext2fs_update_bb_inode(fs, bb_list);
+ mke2fs_error_msg_and_die(retval, "set bad block inode");
+}
+
+static void reserve_inodes(ext2_filsys fs)
+{
+ ext2_ino_t i;
+ int group;
+
+ for (i = EXT2_ROOT_INO + 1; i < EXT2_FIRST_INODE(fs->super); i++) {
+ ext2fs_mark_inode_bitmap(fs->inode_map, i);
+ group = ext2fs_group_of_ino(fs, i);
+ fs->group_desc[group].bg_free_inodes_count--;
+ fs->super->s_free_inodes_count--;
+ }
+ ext2fs_mark_ib_dirty(fs);
+}
+
+#define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */
+#define BSD_MAGICDISK (0x57455682UL) /* The disk magic number reversed */
+#define BSD_LABEL_OFFSET 64
+
+static void zap_sector(ext2_filsys fs, int sect, int nsect)
+{
+ char *buf;
+ char *fmt = "could not %s %d";
+ int retval;
+ unsigned int *magic;
+
+ buf = xmalloc(512*nsect);
+
+ if (sect == 0) {
+ /* Check for a BSD disklabel, and don't erase it if so */
+ retval = io_channel_read_blk(fs->io, 0, -512, buf);
+ if (retval)
+ mke2fs_warning_msg(retval, fmt, "read block", 0);
+ else {
+ magic = (unsigned int *) (buf + BSD_LABEL_OFFSET);
+ if ((*magic == BSD_DISKMAGIC) ||
+ (*magic == BSD_MAGICDISK))
+ return;
+ }
+ }
+
+ memset(buf, 0, 512*nsect);
+ io_channel_set_blksize(fs->io, 512);
+ retval = io_channel_write_blk(fs->io, sect, -512*nsect, buf);
+ io_channel_set_blksize(fs->io, fs->blocksize);
+ free(buf);
+ mke2fs_warning_msg(retval, fmt, "erase sector", sect);
+}
+
+static void create_journal_dev(ext2_filsys fs)
+{
+ struct progress_struct progress;
+ errcode_t retval;
+ char *buf;
+ char *fmt = "%s journal superblock";
+ blk_t blk;
+ int count;
+
+ retval = ext2fs_create_journal_superblock(fs,
+ fs->super->s_blocks_count, 0, &buf);
+ mke2fs_error_msg_and_die(retval, fmt, "init");
+ if (quiet)
+ memset(&progress, 0, sizeof(progress));
+ else
+ progress_init(&progress, "Zeroing journal device: ",
+ fs->super->s_blocks_count);
+
+ retval = zero_blocks(fs, 0, fs->super->s_blocks_count,
+ &progress, &blk, &count);
+ mke2fs_error_msg_and_die(retval, "zero journal device (block %u, count %d)",
+ blk, count);
+ zero_blocks(0, 0, 0, 0, 0, 0);
+
+ retval = io_channel_write_blk(fs->io,
+ fs->super->s_first_data_block+1,
+ 1, buf);
+ mke2fs_error_msg_and_die(retval, fmt, "write");
+ progress_close(&progress);
+}
+
+static void show_stats(ext2_filsys fs)
+{
+ struct ext2_super_block *s = fs->super;
+ char *os;
+ blk_t group_block;
+ dgrp_t i;
+ int need, col_left;
+
+ mke2fs_warning_msg((param.s_blocks_count != s->s_blocks_count),
+ "%d blocks unused\n", param.s_blocks_count - s->s_blocks_count);
+ os = e2p_os2string(fs->super->s_creator_os);
+ printf( "Filesystem label=%.*s\n"
+ "OS type: %s\n"
+ "Block size=%u (log=%u)\n"
+ "Fragment size=%u (log=%u)\n"
+ "%u inodes, %u blocks\n"
+ "%u blocks (%2.2f%%) reserved for the super user\n"
+ "First data block=%u\n",
+ (int) sizeof(s->s_volume_name),
+ s->s_volume_name,
+ os,
+ fs->blocksize, s->s_log_block_size,
+ fs->fragsize, s->s_log_frag_size,
+ s->s_inodes_count, s->s_blocks_count,
+ s->s_r_blocks_count, 100.0 * s->s_r_blocks_count / s->s_blocks_count,
+ s->s_first_data_block);
+ free(os);
+ if (s->s_reserved_gdt_blocks) {
+ printf("Maximum filesystem blocks=%lu\n",
+ (s->s_reserved_gdt_blocks + fs->desc_blocks) *
+ (fs->blocksize / sizeof(struct ext2_group_desc)) *
+ s->s_blocks_per_group);
+ }
+ printf( "%u block group%s\n"
+ "%u blocks per group, %u fragments per group\n"
+ "%u inodes per group\n",
+ fs->group_desc_count, (fs->group_desc_count > 1) ? "s" : "",
+ s->s_blocks_per_group, s->s_frags_per_group,
+ s->s_inodes_per_group);
+ if (fs->group_desc_count == 1) {
+ bb_putchar('\n');
+ return;
+ }
+
+ printf("Superblock backups stored on blocks: ");
+ group_block = s->s_first_data_block;
+ col_left = 0;
+ for (i = 1; i < fs->group_desc_count; i++) {
+ group_block += s->s_blocks_per_group;
+ if (!ext2fs_bg_has_super(fs, i))
+ continue;
+ if (i != 1)
+ printf(", ");
+ need = int_log10(group_block) + 2;
+ if (need > col_left) {
+ printf("\n\t");
+ col_left = 72;
+ }
+ col_left -= need;
+ printf("%u", group_block);
+ }
+ puts("\n");
+}
+
+/*
+ * Set the S_CREATOR_OS field. Return true if OS is known,
+ * otherwise, 0.
+ */
+static int set_os(struct ext2_super_block *sb, char *os)
+{
+ if (isdigit (*os)) {
+ sb->s_creator_os = atoi(os);
+ return 1;
+ }
+
+ if((sb->s_creator_os = e2p_string2os(os)) >= 0) {
+ return 1;
+ } else if (!strcasecmp("GNU", os)) {
+ sb->s_creator_os = EXT2_OS_HURD;
+ return 1;
+ }
+ return 0;
+}
+
+static void parse_extended_opts(struct ext2_super_block *sb_param,
+ const char *opts)
+{
+ char *buf, *token, *next, *p, *arg;
+ int r_usage = 0;
+
+ buf = xstrdup(opts);
+ for (token = buf; token && *token; token = next) {
+ p = strchr(token, ',');
+ next = 0;
+ if (p) {
+ *p = 0;
+ next = p+1;
+ }
+ arg = strchr(token, '=');
+ if (arg) {
+ *arg = 0;
+ arg++;
+ }
+ if (strcmp(token, "stride") == 0) {
+ if (!arg) {
+ r_usage++;
+ continue;
+ }
+ fs_stride = strtoul(arg, &p, 0);
+ if (*p || (fs_stride == 0)) {
+ bb_error_msg("Invalid stride parameter: %s", arg);
+ r_usage++;
+ continue;
+ }
+ } else if (!strcmp(token, "resize")) {
+ unsigned long resize, bpg, rsv_groups;
+ unsigned long group_desc_count, desc_blocks;
+ unsigned int gdpb, blocksize;
+ int rsv_gdb;
+
+ if (!arg) {
+ r_usage++;
+ continue;
+ }
+
+ resize = parse_num_blocks(arg,
+ sb_param->s_log_block_size);
+
+ if (resize == 0) {
+ bb_error_msg("Invalid resize parameter: %s", arg);
+ r_usage++;
+ continue;
+ }
+ if (resize <= sb_param->s_blocks_count) {
+ bb_error_msg("The resize maximum must be greater "
+ "than the filesystem size");
+ r_usage++;
+ continue;
+ }
+
+ blocksize = EXT2_BLOCK_SIZE(sb_param);
+ bpg = sb_param->s_blocks_per_group;
+ if (!bpg)
+ bpg = blocksize * 8;
+ gdpb = blocksize / sizeof(struct ext2_group_desc);
+ group_desc_count = (sb_param->s_blocks_count +
+ bpg - 1) / bpg;
+ desc_blocks = (group_desc_count +
+ gdpb - 1) / gdpb;
+ rsv_groups = (resize + bpg - 1) / bpg;
+ rsv_gdb = (rsv_groups + gdpb - 1) / gdpb -
+ desc_blocks;
+ if (rsv_gdb > EXT2_ADDR_PER_BLOCK(sb_param))
+ rsv_gdb = EXT2_ADDR_PER_BLOCK(sb_param);
+
+ if (rsv_gdb > 0) {
+ sb_param->s_feature_compat |=
+ EXT2_FEATURE_COMPAT_RESIZE_INODE;
+
+ sb_param->s_reserved_gdt_blocks = rsv_gdb;
+ }
+ } else
+ r_usage++;
+ }
+ if (r_usage) {
+ bb_error_msg_and_die(
+ "\nBad options specified.\n\n"
+ "Extended options are separated by commas, "
+ "and may take an argument which\n"
+ "\tis set off by an equals ('=') sign.\n\n"
+ "Valid extended options are:\n"
+ "\tstride=<stride length in blocks>\n"
+ "\tresize=<resize maximum size in blocks>\n");
+ }
+}
+
+static __u32 ok_features[3] = {
+ EXT3_FEATURE_COMPAT_HAS_JOURNAL |
+ EXT2_FEATURE_COMPAT_RESIZE_INODE |
+ EXT2_FEATURE_COMPAT_DIR_INDEX, /* Compat */
+ EXT2_FEATURE_INCOMPAT_FILETYPE| /* Incompat */
+ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|
+ EXT2_FEATURE_INCOMPAT_META_BG,
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER /* R/O compat */
+};
+
+static int PRS(int argc, char **argv)
+{
+ int c;
+ int size;
+ char * tmp;
+ int blocksize = 0;
+ int inode_ratio = 0;
+ int inode_size = 0;
+ int reserved_ratio = 5;
+ int sector_size = 0;
+ int show_version_only = 0;
+ ext2_ino_t num_inodes = 0;
+ errcode_t retval;
+ char * extended_opts = 0;
+ const char * fs_type = 0;
+ blk_t dev_size;
+ long sysval;
+
+ /* Update our PATH to include /sbin */
+ e2fs_set_sbin_path();
+
+ tmp = getenv("MKE2FS_SYNC");
+ if (tmp)
+ sync_kludge = atoi(tmp);
+
+ /* Determine the system page size if possible */
+#if (!defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE))
+#define _SC_PAGESIZE _SC_PAGE_SIZE
+#endif
+#ifdef _SC_PAGESIZE
+ sysval = sysconf(_SC_PAGESIZE);
+ if (sysval > 0)
+ sys_page_size = sysval;
+#endif /* _SC_PAGESIZE */
+
+ setbuf(stdout, NULL);
+ setbuf(stderr, NULL);
+ memset(&param, 0, sizeof(struct ext2_super_block));
+ param.s_rev_level = 1; /* Create revision 1 filesystems now */
+ param.s_feature_incompat |= EXT2_FEATURE_INCOMPAT_FILETYPE;
+ param.s_feature_ro_compat |= EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
+
+#ifdef __linux__
+ linux_version_code = get_linux_version_code();
+ if (linux_version_code && linux_version_code < KERNEL_VERSION(2,2,0)) {
+ param.s_rev_level = 0;
+ param.s_feature_incompat = 0;
+ param.s_feature_compat = 0;
+ param.s_feature_ro_compat = 0;
+ }
+#endif
+
+ /* If called as mkfs.ext3, create a journal inode */
+ if (last_char_is(applet_name, '3'))
+ journal_size = -1;
+
+ while ((c = getopt (argc, argv,
+ "b:cE:f:g:i:jl:m:no:qr:R:s:tvI:J:ST:FL:M:N:O:V")) != EOF) {
+ switch (c) {
+ case 'b':
+ blocksize = xatou_range(optarg, EXT2_MIN_BLOCK_SIZE, EXT2_MAX_BLOCK_SIZE);
+ mke2fs_warning_msg((blocksize > 4096),
+ "blocksize %d not usable on most systems",
+ blocksize);
+ param.s_log_block_size =
+ int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE);
+ break;
+ case 'c': /* Check for bad blocks */
+ case 't': /* deprecated */
+ cflag++;
+ break;
+ case 'f':
+ size = xatou_range(optarg, EXT2_MIN_BLOCK_SIZE, EXT2_MAX_BLOCK_SIZE);
+ param.s_log_frag_size =
+ int_log2(size >> EXT2_MIN_BLOCK_LOG_SIZE);
+ mke2fs_warning_msg(1, "fragments not supported. Ignoring -f option");
+ break;
+ case 'g':
+ param.s_blocks_per_group = xatou32(optarg);
+ if ((param.s_blocks_per_group % 8) != 0) {
+ bb_error_msg_and_die("blocks per group must be multiple of 8");
+ }
+ break;
+ case 'i':
+ /* Huh? is "* 1024" correct? */
+ inode_ratio = xatou_range(optarg, EXT2_MIN_BLOCK_SIZE, EXT2_MAX_BLOCK_SIZE * 1024);
+ break;
+ case 'J':
+ parse_journal_opts(&journal_device, &journal_flags, &journal_size, optarg);
+ break;
+ case 'j':
+ param.s_feature_compat |=
+ EXT3_FEATURE_COMPAT_HAS_JOURNAL;
+ if (!journal_size)
+ journal_size = -1;
+ break;
+ case 'l':
+ bad_blocks_filename = optarg;
+ break;
+ case 'm':
+ reserved_ratio = xatou_range(optarg, 0, 50);
+ break;
+ case 'n':
+ noaction++;
+ break;
+ case 'o':
+ creator_os = optarg;
+ break;
+ case 'r':
+ param.s_rev_level = xatoi_u(optarg);
+ if (param.s_rev_level == EXT2_GOOD_OLD_REV) {
+ param.s_feature_incompat = 0;
+ param.s_feature_compat = 0;
+ param.s_feature_ro_compat = 0;
+ }
+ break;
+ case 's': /* deprecated */
+ if (xatou(optarg))
+ param.s_feature_ro_compat |=
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
+ else
+ param.s_feature_ro_compat &=
+ ~EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
+ break;
+#ifdef EXT2_DYNAMIC_REV
+ case 'I':
+ inode_size = xatoi_u(optarg);
+ break;
+#endif
+ case 'N':
+ num_inodes = xatoi_u(optarg);
+ break;
+ case 'v':
+ quiet = 0;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'F':
+ force = 1;
+ break;
+ case 'L':
+ volume_label = optarg;
+ break;
+ case 'M':
+ mount_dir = optarg;
+ break;
+ case 'O':
+ if (!strcmp(optarg, "none")) {
+ param.s_feature_compat = 0;
+ param.s_feature_incompat = 0;
+ param.s_feature_ro_compat = 0;
+ break;
+ }
+ if (e2p_edit_feature(optarg,
+ &param.s_feature_compat,
+ ok_features)) {
+ bb_error_msg_and_die("Invalid filesystem option set: %s", optarg);
+ }
+ break;
+ case 'E':
+ case 'R':
+ extended_opts = optarg;
+ break;
+ case 'S':
+ super_only = 1;
+ break;
+ case 'T':
+ fs_type = optarg;
+ break;
+ case 'V':
+ /* Print version number and exit */
+ show_version_only = 1;
+ quiet = 0;
+ break;
+ default:
+ bb_show_usage();
+ }
+ }
+ if ((optind == argc) /*&& !show_version_only*/)
+ bb_show_usage();
+ device_name = argv[optind++];
+
+ mke2fs_verbose("mke2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE);
+
+ if (show_version_only) {
+ return 0;
+ }
+
+ /*
+ * If there's no blocksize specified and there is a journal
+ * device, use it to figure out the blocksize
+ */
+ if (blocksize <= 0 && journal_device) {
+ ext2_filsys jfs;
+ io_manager io_ptr;
+
+#ifdef CONFIG_TESTIO_DEBUG
+ io_ptr = test_io_manager;
+ test_io_backing_manager = unix_io_manager;
+#else
+ io_ptr = unix_io_manager;
+#endif
+ retval = ext2fs_open(journal_device,
+ EXT2_FLAG_JOURNAL_DEV_OK, 0,
+ 0, io_ptr, &jfs);
+ mke2fs_error_msg_and_die(retval, "open journal device %s", journal_device);
+ if ((blocksize < 0) && (jfs->blocksize < (unsigned) (-blocksize))) {
+ bb_error_msg_and_die(
+ "Journal dev blocksize (%d) smaller than "
+ "minimum blocksize %d\n", jfs->blocksize,
+ -blocksize);
+ }
+ blocksize = jfs->blocksize;
+ param.s_log_block_size =
+ int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE);
+ ext2fs_close(jfs);
+ }
+
+ if (blocksize > sys_page_size) {
+ mke2fs_warning_msg(1, "%d-byte blocks too big for system (max %d)",
+ blocksize, sys_page_size);
+ if (!force) {
+ proceed_question();
+ }
+ bb_error_msg("Forced to continue");
+ }
+ mke2fs_warning_msg(((blocksize > 4096) &&
+ (param.s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)),
+ "some 2.4 kernels do not support "
+ "blocksizes greater than 4096 using ext3.\n"
+ "Use -b 4096 if this is an issue for you\n");
+
+ if (optind < argc) {
+ param.s_blocks_count = parse_num_blocks(argv[optind++],
+ param.s_log_block_size);
+ mke2fs_error_msg_and_die(!param.s_blocks_count, "invalid blocks count - %s", argv[optind - 1]);
+ }
+ if (optind < argc)
+ bb_show_usage();
+
+ if (param.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
+ if (!fs_type)
+ fs_type = "journal";
+ reserved_ratio = 0;
+ param.s_feature_incompat = EXT3_FEATURE_INCOMPAT_JOURNAL_DEV;
+ param.s_feature_compat = 0;
+ param.s_feature_ro_compat = 0;
+ }
+ if (param.s_rev_level == EXT2_GOOD_OLD_REV &&
+ (param.s_feature_compat || param.s_feature_ro_compat ||
+ param.s_feature_incompat))
+ param.s_rev_level = 1; /* Create a revision 1 filesystem */
+
+ check_plausibility(device_name , force);
+ check_mount(device_name, force, "filesystem");
+
+ param.s_log_frag_size = param.s_log_block_size;
+
+ if (noaction && param.s_blocks_count) {
+ dev_size = param.s_blocks_count;
+ retval = 0;
+ } else {
+ retry:
+ retval = ext2fs_get_device_size(device_name,
+ EXT2_BLOCK_SIZE(&param),
+ &dev_size);
+ if ((retval == EFBIG) &&
+ (blocksize == 0) &&
+ (param.s_log_block_size == 0)) {
+ param.s_log_block_size = 2;
+ blocksize = 4096;
+ goto retry;
+ }
+ }
+
+ mke2fs_error_msg_and_die((retval && (retval != EXT2_ET_UNIMPLEMENTED)),"determine filesystem size");
+
+ if (!param.s_blocks_count) {
+ if (retval == EXT2_ET_UNIMPLEMENTED) {
+ mke2fs_error_msg_and_die(1,
+ "determine device size; you "
+ "must specify\nthe size of the "
+ "filesystem");
+ } else {
+ if (dev_size == 0) {
+ bb_error_msg_and_die(
+ "Device size reported to be zero. "
+ "Invalid partition specified, or\n\t"
+ "partition table wasn't reread "
+ "after running fdisk, due to\n\t"
+ "a modified partition being busy "
+ "and in use. You may need to reboot\n\t"
+ "to re-read your partition table.\n"
+ );
+ }
+ param.s_blocks_count = dev_size;
+ if (sys_page_size > EXT2_BLOCK_SIZE(&param))
+ param.s_blocks_count &= ~((sys_page_size /
+ EXT2_BLOCK_SIZE(&param))-1);
+ }
+
+ } else if (!force && (param.s_blocks_count > dev_size)) {
+ bb_error_msg("Filesystem larger than apparent device size");
+ proceed_question();
+ }
+
+ /*
+ * If the user asked for HAS_JOURNAL, then make sure a journal
+ * gets created.
+ */
+ if ((param.s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
+ !journal_size)
+ journal_size = -1;
+
+ /* Set first meta blockgroup via an environment variable */
+ /* (this is mostly for debugging purposes) */
+ if ((param.s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) &&
+ ((tmp = getenv("MKE2FS_FIRST_META_BG"))))
+ param.s_first_meta_bg = atoi(tmp);
+
+ /* Get the hardware sector size, if available */
+ retval = ext2fs_get_device_sectsize(device_name, &sector_size);
+ mke2fs_error_msg_and_die(retval, "determine hardware sector size");
+
+ if ((tmp = getenv("MKE2FS_DEVICE_SECTSIZE")) != NULL)
+ sector_size = atoi(tmp);
+
+ set_fs_defaults(fs_type, &param, blocksize, sector_size, &inode_ratio);
+ blocksize = EXT2_BLOCK_SIZE(&param);
+
+ if (extended_opts)
+ parse_extended_opts(&param, extended_opts);
+
+ /* Since sparse_super is the default, we would only have a problem
+ * here if it was explicitly disabled.
+ */
+ if ((param.s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INODE) &&
+ !(param.s_feature_ro_compat&EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
+ bb_error_msg_and_die("reserved online resize blocks not supported "
+ "on non-sparse filesystem");
+ }
+
+ if (param.s_blocks_per_group) {
+ if (param.s_blocks_per_group < 256 ||
+ param.s_blocks_per_group > 8 * (unsigned) blocksize) {
+ bb_error_msg_and_die("blocks per group count out of range");
+ }
+ }
+
+ if (!force && param.s_blocks_count >= (1 << 31)) {
+ bb_error_msg_and_die("Filesystem too large. No more than 2**31-1 blocks\n"
+ "\t (8TB using a blocksize of 4k) are currently supported.");
+ }
+
+ if (inode_size) {
+ if (inode_size < EXT2_GOOD_OLD_INODE_SIZE ||
+ inode_size > EXT2_BLOCK_SIZE(&param) ||
+ inode_size & (inode_size - 1)) {
+ bb_error_msg_and_die("invalid inode size %d (min %d/max %d)",
+ inode_size, EXT2_GOOD_OLD_INODE_SIZE,
+ blocksize);
+ }
+ mke2fs_warning_msg((inode_size != EXT2_GOOD_OLD_INODE_SIZE),
+ "%d-byte inodes not usable on most systems",
+ inode_size);
+ param.s_inode_size = inode_size;
+ }
+
+ /*
+ * Calculate number of inodes based on the inode ratio
+ */
+ param.s_inodes_count = num_inodes ? num_inodes :
+ ((__u64) param.s_blocks_count * blocksize)
+ / inode_ratio;
+
+ /*
+ * Calculate number of blocks to reserve
+ */
+ param.s_r_blocks_count = (param.s_blocks_count * reserved_ratio) / 100;
+ return 1;
+}
+
+static void mke2fs_clean_up(void)
+{
+ if (ENABLE_FEATURE_CLEAN_UP && journal_device) free(journal_device);
+}
+
+int mke2fs_main (int argc, char **argv);
+int mke2fs_main (int argc, char **argv)
+{
+ errcode_t retval;
+ ext2_filsys fs;
+ badblocks_list bb_list = 0;
+ unsigned int i;
+ int val;
+ io_manager io_ptr;
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ atexit(mke2fs_clean_up);
+ if(!PRS(argc, argv))
+ return 0;
+
+#ifdef CONFIG_TESTIO_DEBUG
+ io_ptr = test_io_manager;
+ test_io_backing_manager = unix_io_manager;
+#else
+ io_ptr = unix_io_manager;
+#endif
+
+ /*
+ * Initialize the superblock....
+ */
+ retval = ext2fs_initialize(device_name, 0, &param,
+ io_ptr, &fs);
+ mke2fs_error_msg_and_die(retval, "set up superblock");
+
+ /*
+ * Wipe out the old on-disk superblock
+ */
+ if (!noaction)
+ zap_sector(fs, 2, 6);
+
+ /*
+ * Generate a UUID for it...
+ */
+ uuid_generate(fs->super->s_uuid);
+
+ /*
+ * Initialize the directory index variables
+ */
+ fs->super->s_def_hash_version = EXT2_HASH_TEA;
+ uuid_generate((unsigned char *) fs->super->s_hash_seed);
+
+ /*
+ * Add "jitter" to the superblock's check interval so that we
+ * don't check all the filesystems at the same time. We use a
+ * kludgy hack of using the UUID to derive a random jitter value.
+ */
+ for (i = 0, val = 0; i < sizeof(fs->super->s_uuid); i++)
+ val += fs->super->s_uuid[i];
+ fs->super->s_max_mnt_count += val % EXT2_DFL_MAX_MNT_COUNT;
+
+ /*
+ * Override the creator OS, if applicable
+ */
+ if (creator_os && !set_os(fs->super, creator_os)) {
+ bb_error_msg_and_die("unknown os - %s", creator_os);
+ }
+
+ /*
+ * For the Hurd, we will turn off filetype since it doesn't
+ * support it.
+ */
+ if (fs->super->s_creator_os == EXT2_OS_HURD)
+ fs->super->s_feature_incompat &=
+ ~EXT2_FEATURE_INCOMPAT_FILETYPE;
+
+ /*
+ * Set the volume label...
+ */
+ if (volume_label) {
+ snprintf(fs->super->s_volume_name, sizeof(fs->super->s_volume_name), "%s", volume_label);
+ }
+
+ /*
+ * Set the last mount directory
+ */
+ if (mount_dir) {
+ snprintf(fs->super->s_last_mounted, sizeof(fs->super->s_last_mounted), "%s", mount_dir);
+ }
+
+ if (!quiet || noaction)
+ show_stats(fs);
+
+ if (noaction)
+ return 0;
+
+ if (fs->super->s_feature_incompat &
+ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
+ create_journal_dev(fs);
+ return (ext2fs_close(fs) ? 1 : 0);
+ }
+
+ if (bad_blocks_filename)
+ read_bb_file(fs, &bb_list, bad_blocks_filename);
+ if (cflag)
+ test_disk(fs, &bb_list);
+
+ handle_bad_blocks(fs, bb_list);
+ fs->stride = fs_stride;
+ retval = ext2fs_allocate_tables(fs);
+ mke2fs_error_msg_and_die(retval, "allocate filesystem tables");
+ if (super_only) {
+ fs->super->s_state |= EXT2_ERROR_FS;
+ fs->flags &= ~(EXT2_FLAG_IB_DIRTY|EXT2_FLAG_BB_DIRTY);
+ } else {
+ /* rsv must be a power of two (64kB is MD RAID sb alignment) */
+ unsigned int rsv = 65536 / fs->blocksize;
+ unsigned long blocks = fs->super->s_blocks_count;
+ unsigned long start;
+ blk_t ret_blk;
+
+#ifdef ZAP_BOOTBLOCK
+ zap_sector(fs, 0, 2);
+#endif
+
+ /*
+ * Wipe out any old MD RAID (or other) metadata at the end
+ * of the device. This will also verify that the device is
+ * as large as we think. Be careful with very small devices.
+ */
+ start = (blocks & ~(rsv - 1));
+ if (start > rsv)
+ start -= rsv;
+ if (start > 0)
+ retval = zero_blocks(fs, start, blocks - start,
+ NULL, &ret_blk, NULL);
+
+ mke2fs_warning_msg(retval, "cannot zero block %u at end of filesystem", ret_blk);
+ write_inode_tables(fs);
+ create_root_dir(fs);
+ create_lost_and_found(fs);
+ reserve_inodes(fs);
+ create_bad_block_inode(fs, bb_list);
+ if (fs->super->s_feature_compat &
+ EXT2_FEATURE_COMPAT_RESIZE_INODE) {
+ retval = ext2fs_create_resize_inode(fs);
+ mke2fs_error_msg_and_die(retval, "reserve blocks for online resize");
+ }
+ }
+
+ if (journal_device) {
+ make_journal_device(journal_device, fs, quiet, force);
+ } else if (journal_size) {
+ make_journal_blocks(fs, journal_size, journal_flags, quiet);
+ }
+
+ mke2fs_verbose("Writing superblocks and filesystem accounting information: ");
+ retval = ext2fs_flush(fs);
+ mke2fs_warning_msg(retval, "had trouble writing out superblocks");
+ mke2fs_verbose_done();
+ if (!quiet && !getenv("MKE2FS_SKIP_CHECK_MSG"))
+ print_check_message(fs);
+ val = ext2fs_close(fs);
+ return (retval || val) ? 1 : 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/tune2fs.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/tune2fs.c
new file mode 100644
index 0000000000..b7a1b21eb0
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/tune2fs.c
@@ -0,0 +1,713 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * tune2fs.c - Change the file system parameters on an ext2 file system
+ *
+ * Copyright (C) 1992, 1993, 1994 Remy Card <card@masi.ibp.fr>
+ * Laboratoire MASI, Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+/*
+ * History:
+ * 93/06/01 - Creation
+ * 93/10/31 - Added the -c option to change the maximal mount counts
+ * 93/12/14 - Added -l flag to list contents of superblock
+ * M.J.E. Mol (marcel@duteca.et.tudelft.nl)
+ * F.W. ten Wolde (franky@duteca.et.tudelft.nl)
+ * 93/12/29 - Added the -e option to change errors behavior
+ * 94/02/27 - Ported to use the ext2fs library
+ * 94/03/06 - Added the checks interval from Uwe Ohse (uwe@tirka.gun.de)
+ */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include "e2fsbb.h"
+#include "ext2fs/ext2_fs.h"
+#include "ext2fs/ext2fs.h"
+#include "uuid/uuid.h"
+#include "e2p/e2p.h"
+#include "ext2fs/kernel-jbd.h"
+#include "util.h"
+#include "blkid/blkid.h"
+
+#include "libbb.h"
+
+static char * device_name = NULL;
+static char * new_label, *new_last_mounted, *new_UUID;
+static char * io_options;
+static int c_flag, C_flag, e_flag, f_flag, g_flag, i_flag, l_flag, L_flag;
+static int m_flag, M_flag, r_flag, s_flag = -1, u_flag, U_flag, T_flag;
+static time_t last_check_time;
+static int print_label;
+static int max_mount_count, mount_count, mount_flags;
+static unsigned long interval, reserved_blocks;
+static unsigned reserved_ratio;
+static unsigned long resgid, resuid;
+static unsigned short errors;
+static int open_flag;
+static char *features_cmd;
+static char *mntopts_cmd;
+
+static int journal_size, journal_flags;
+static char *journal_device = NULL;
+
+static const char *please_fsck = "Please run e2fsck on the filesystem\n";
+
+static __u32 ok_features[3] = {
+ EXT3_FEATURE_COMPAT_HAS_JOURNAL | EXT2_FEATURE_COMPAT_DIR_INDEX,
+ EXT2_FEATURE_INCOMPAT_FILETYPE,
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
+};
+
+/*
+ * Remove an external journal from the filesystem
+ */
+static void remove_journal_device(ext2_filsys fs)
+{
+ char *journal_path;
+ ext2_filsys jfs;
+ char buf[1024];
+ journal_superblock_t *jsb;
+ int i, nr_users;
+ errcode_t retval;
+ int commit_remove_journal = 0;
+ io_manager io_ptr;
+
+ if (f_flag)
+ commit_remove_journal = 1; /* force removal even if error */
+
+ uuid_unparse(fs->super->s_journal_uuid, buf);
+ journal_path = blkid_get_devname(NULL, "UUID", buf);
+
+ if (!journal_path) {
+ journal_path =
+ ext2fs_find_block_device(fs->super->s_journal_dev);
+ if (!journal_path)
+ return;
+ }
+
+ io_ptr = unix_io_manager;
+ retval = ext2fs_open(journal_path, EXT2_FLAG_RW|
+ EXT2_FLAG_JOURNAL_DEV_OK, 0,
+ fs->blocksize, io_ptr, &jfs);
+ if (retval) {
+ bb_error_msg("Failed to open external journal");
+ goto no_valid_journal;
+ }
+ if (!(jfs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
+ bb_error_msg("%s is not a journal device", journal_path);
+ goto no_valid_journal;
+ }
+
+ /* Get the journal superblock */
+ if ((retval = io_channel_read_blk(jfs->io, 1, -1024, buf))) {
+ bb_error_msg("Failed to read journal superblock");
+ goto no_valid_journal;
+ }
+
+ jsb = (journal_superblock_t *) buf;
+ if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
+ (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2))) {
+ bb_error_msg("Journal superblock not found!");
+ goto no_valid_journal;
+ }
+
+ /* Find the filesystem UUID */
+ nr_users = ntohl(jsb->s_nr_users);
+ for (i=0; i < nr_users; i++) {
+ if (memcmp(fs->super->s_uuid,
+ &jsb->s_users[i*16], 16) == 0)
+ break;
+ }
+ if (i >= nr_users) {
+ bb_error_msg("Filesystem's UUID not found on journal device");
+ commit_remove_journal = 1;
+ goto no_valid_journal;
+ }
+ nr_users--;
+ for (i=0; i < nr_users; i++)
+ memcpy(&jsb->s_users[i*16], &jsb->s_users[(i+1)*16], 16);
+ jsb->s_nr_users = htonl(nr_users);
+
+ /* Write back the journal superblock */
+ if ((retval = io_channel_write_blk(jfs->io, 1, -1024, buf))) {
+ bb_error_msg("Failed to write journal superblock");
+ goto no_valid_journal;
+ }
+
+ commit_remove_journal = 1;
+
+no_valid_journal:
+ if (commit_remove_journal == 0)
+ bb_error_msg_and_die("Journal NOT removed");
+ fs->super->s_journal_dev = 0;
+ uuid_clear(fs->super->s_journal_uuid);
+ ext2fs_mark_super_dirty(fs);
+ puts("Journal removed");
+ free(journal_path);
+}
+
+/* Helper function for remove_journal_inode */
+static int release_blocks_proc(ext2_filsys fs, blk_t *blocknr,
+ int blockcnt EXT2FS_ATTR((unused)),
+ void *private EXT2FS_ATTR((unused)))
+{
+ blk_t block;
+ int group;
+
+ block = *blocknr;
+ ext2fs_unmark_block_bitmap(fs->block_map,block);
+ group = ext2fs_group_of_blk(fs, block);
+ fs->group_desc[group].bg_free_blocks_count++;
+ fs->super->s_free_blocks_count++;
+ return 0;
+}
+
+/*
+ * Remove the journal inode from the filesystem
+ */
+static void remove_journal_inode(ext2_filsys fs)
+{
+ struct ext2_inode inode;
+ errcode_t retval;
+ ino_t ino = fs->super->s_journal_inum;
+ char *msg = "to read";
+ char *s = "journal inode";
+
+ retval = ext2fs_read_inode(fs, ino, &inode);
+ if (retval)
+ goto REMOVE_JOURNAL_INODE_ERROR;
+ if (ino == EXT2_JOURNAL_INO) {
+ retval = ext2fs_read_bitmaps(fs);
+ if (retval) {
+ msg = "to read bitmaps";
+ s = "";
+ goto REMOVE_JOURNAL_INODE_ERROR;
+ }
+ retval = ext2fs_block_iterate(fs, ino, 0, NULL,
+ release_blocks_proc, NULL);
+ if (retval) {
+ msg = "clearing";
+ goto REMOVE_JOURNAL_INODE_ERROR;
+ }
+ memset(&inode, 0, sizeof(inode));
+ ext2fs_mark_bb_dirty(fs);
+ fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
+ } else
+ inode.i_flags &= ~EXT2_IMMUTABLE_FL;
+ retval = ext2fs_write_inode(fs, ino, &inode);
+ if (retval) {
+ msg = "writing";
+REMOVE_JOURNAL_INODE_ERROR:
+ bb_error_msg_and_die("Failed %s %s", msg, s);
+ }
+ fs->super->s_journal_inum = 0;
+ ext2fs_mark_super_dirty(fs);
+}
+
+/*
+ * Update the default mount options
+ */
+static void update_mntopts(ext2_filsys fs, char *mntopts)
+{
+ struct ext2_super_block *sb= fs->super;
+
+ if (e2p_edit_mntopts(mntopts, &sb->s_default_mount_opts, ~0))
+ bb_error_msg_and_die("Invalid mount option set: %s", mntopts);
+ ext2fs_mark_super_dirty(fs);
+}
+
+/*
+ * Update the feature set as provided by the user.
+ */
+static void update_feature_set(ext2_filsys fs, char *features)
+{
+ int sparse, old_sparse, filetype, old_filetype;
+ int journal, old_journal, dxdir, old_dxdir;
+ struct ext2_super_block *sb= fs->super;
+ __u32 old_compat, old_incompat, old_ro_compat;
+
+ old_compat = sb->s_feature_compat;
+ old_ro_compat = sb->s_feature_ro_compat;
+ old_incompat = sb->s_feature_incompat;
+
+ old_sparse = sb->s_feature_ro_compat &
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
+ old_filetype = sb->s_feature_incompat &
+ EXT2_FEATURE_INCOMPAT_FILETYPE;
+ old_journal = sb->s_feature_compat &
+ EXT3_FEATURE_COMPAT_HAS_JOURNAL;
+ old_dxdir = sb->s_feature_compat &
+ EXT2_FEATURE_COMPAT_DIR_INDEX;
+ if (e2p_edit_feature(features, &sb->s_feature_compat, ok_features))
+ bb_error_msg_and_die("Invalid filesystem option set: %s", features);
+ sparse = sb->s_feature_ro_compat &
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
+ filetype = sb->s_feature_incompat &
+ EXT2_FEATURE_INCOMPAT_FILETYPE;
+ journal = sb->s_feature_compat &
+ EXT3_FEATURE_COMPAT_HAS_JOURNAL;
+ dxdir = sb->s_feature_compat &
+ EXT2_FEATURE_COMPAT_DIR_INDEX;
+ if (old_journal && !journal) {
+ if ((mount_flags & EXT2_MF_MOUNTED) &&
+ !(mount_flags & EXT2_MF_READONLY)) {
+ bb_error_msg_and_die(
+ "The has_journal flag may only be "
+ "cleared when the filesystem is\n"
+ "unmounted or mounted "
+ "read-only");
+ }
+ if (sb->s_feature_incompat &
+ EXT3_FEATURE_INCOMPAT_RECOVER) {
+ bb_error_msg_and_die(
+ "The needs_recovery flag is set. "
+ "%s before clearing the has_journal flag.",
+ please_fsck);
+ }
+ if (sb->s_journal_inum) {
+ remove_journal_inode(fs);
+ }
+ if (sb->s_journal_dev) {
+ remove_journal_device(fs);
+ }
+ }
+ if (journal && !old_journal) {
+ /*
+ * If adding a journal flag, let the create journal
+ * code below handle creating setting the flag and
+ * creating the journal. We supply a default size if
+ * necessary.
+ */
+ if (!journal_size)
+ journal_size = -1;
+ sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
+ }
+ if (dxdir && !old_dxdir) {
+ if (!sb->s_def_hash_version)
+ sb->s_def_hash_version = EXT2_HASH_TEA;
+ if (uuid_is_null((unsigned char *) sb->s_hash_seed))
+ uuid_generate((unsigned char *) sb->s_hash_seed);
+ }
+
+ if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
+ (sb->s_feature_compat || sb->s_feature_ro_compat ||
+ sb->s_feature_incompat))
+ ext2fs_update_dynamic_rev(fs);
+ if ((sparse != old_sparse) ||
+ (filetype != old_filetype)) {
+ sb->s_state &= ~EXT2_VALID_FS;
+ printf("\n%s\n", please_fsck);
+ }
+ if ((old_compat != sb->s_feature_compat) ||
+ (old_ro_compat != sb->s_feature_ro_compat) ||
+ (old_incompat != sb->s_feature_incompat))
+ ext2fs_mark_super_dirty(fs);
+}
+
+/*
+ * Add a journal to the filesystem.
+ */
+static void add_journal(ext2_filsys fs)
+{
+ if (fs->super->s_feature_compat &
+ EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
+ bb_error_msg_and_die("The filesystem already has a journal");
+ }
+ if (journal_device) {
+ make_journal_device(journal_device, fs, 0, 0);
+ } else if (journal_size) {
+ make_journal_blocks(fs, journal_size, journal_flags, 0);
+ /*
+ * If the filesystem wasn't mounted, we need to force
+ * the block group descriptors out.
+ */
+ if ((mount_flags & EXT2_MF_MOUNTED) == 0)
+ fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
+ }
+ print_check_message(fs);
+}
+
+/*
+ * Busybox stuff
+ */
+static char * x_blkid_get_devname(const char *token)
+{
+ char * dev_name;
+
+ if (!(dev_name = blkid_get_devname(NULL, token, NULL)))
+ bb_error_msg_and_die("Unable to resolve '%s'", token);
+ return dev_name;
+}
+
+#ifdef CONFIG_E2LABEL
+static void parse_e2label_options(int argc, char ** argv)
+{
+ if ((argc < 2) || (argc > 3))
+ bb_show_usage();
+ io_options = strchr(argv[1], '?');
+ if (io_options)
+ *io_options++ = 0;
+ device_name = x_blkid_get_devname(argv[1]);
+ if (argc == 3) {
+ open_flag = EXT2_FLAG_RW | EXT2_FLAG_JOURNAL_DEV_OK;
+ L_flag = 1;
+ new_label = argv[2];
+ } else
+ print_label++;
+}
+#else
+#define parse_e2label_options(x,y)
+#endif
+
+static time_t parse_time(char *str)
+{
+ struct tm ts;
+
+ if (strcmp(str, "now") == 0) {
+ return time(0);
+ }
+ memset(&ts, 0, sizeof(ts));
+#ifdef HAVE_STRPTIME
+ strptime(str, "%Y%m%d%H%M%S", &ts);
+#else
+ sscanf(str, "%4d%2d%2d%2d%2d%2d", &ts.tm_year, &ts.tm_mon,
+ &ts.tm_mday, &ts.tm_hour, &ts.tm_min, &ts.tm_sec);
+ ts.tm_year -= 1900;
+ ts.tm_mon -= 1;
+ if (ts.tm_year < 0 || ts.tm_mon < 0 || ts.tm_mon > 11 ||
+ ts.tm_mday < 0 || ts.tm_mday > 31 || ts.tm_hour > 23 ||
+ ts.tm_min > 59 || ts.tm_sec > 61)
+ ts.tm_mday = 0;
+#endif
+ if (ts.tm_mday == 0) {
+ bb_error_msg_and_die("Cannot parse date/time specifier: %s", str);
+ }
+ return mktime(&ts);
+}
+
+static void parse_tune2fs_options(int argc, char **argv)
+{
+ int c;
+ char * tmp;
+
+ printf("tune2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE);
+ while ((c = getopt(argc, argv, "c:e:fg:i:jlm:o:r:s:u:C:J:L:M:O:T:U:")) != EOF)
+ switch (c)
+ {
+ case 'c':
+ max_mount_count = xatou_range(optarg, 0, 16000);
+ if (max_mount_count == 0)
+ max_mount_count = -1;
+ c_flag = 1;
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'C':
+ mount_count = xatou_range(optarg, 0, 16000);
+ C_flag = 1;
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'e':
+ if (strcmp (optarg, "continue") == 0)
+ errors = EXT2_ERRORS_CONTINUE;
+ else if (strcmp (optarg, "remount-ro") == 0)
+ errors = EXT2_ERRORS_RO;
+ else if (strcmp (optarg, "panic") == 0)
+ errors = EXT2_ERRORS_PANIC;
+ else {
+ bb_error_msg_and_die("bad error behavior - %s", optarg);
+ }
+ e_flag = 1;
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'f': /* Force */
+ f_flag = 1;
+ break;
+ case 'g':
+ resgid = bb_strtoul(optarg, NULL, 10);
+ if (errno)
+ resgid = xgroup2gid(optarg);
+ g_flag = 1;
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'i':
+ interval = strtoul(optarg, &tmp, 0);
+ switch (*tmp) {
+ case 's':
+ tmp++;
+ break;
+ case '\0':
+ case 'd':
+ case 'D': /* days */
+ interval *= 86400;
+ if (*tmp != '\0')
+ tmp++;
+ break;
+ case 'm':
+ case 'M': /* months! */
+ interval *= 86400 * 30;
+ tmp++;
+ break;
+ case 'w':
+ case 'W': /* weeks */
+ interval *= 86400 * 7;
+ tmp++;
+ break;
+ }
+ if (*tmp || interval > (365 * 86400)) {
+ bb_error_msg_and_die("bad interval - %s", optarg);
+ }
+ i_flag = 1;
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'j':
+ if (!journal_size)
+ journal_size = -1;
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'J':
+ parse_journal_opts(&journal_device, &journal_flags, &journal_size, optarg);
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'l':
+ l_flag = 1;
+ break;
+ case 'L':
+ new_label = optarg;
+ L_flag = 1;
+ open_flag = EXT2_FLAG_RW |
+ EXT2_FLAG_JOURNAL_DEV_OK;
+ break;
+ case 'm':
+ reserved_ratio = xatou_range(optarg, 0, 50);
+ m_flag = 1;
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'M':
+ new_last_mounted = optarg;
+ M_flag = 1;
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'o':
+ if (mntopts_cmd) {
+ bb_error_msg_and_die("-o may only be specified once");
+ }
+ mntopts_cmd = optarg;
+ open_flag = EXT2_FLAG_RW;
+ break;
+
+ case 'O':
+ if (features_cmd) {
+ bb_error_msg_and_die("-O may only be specified once");
+ }
+ features_cmd = optarg;
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'r':
+ reserved_blocks = xatoul(optarg);
+ r_flag = 1;
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 's':
+ s_flag = atoi(optarg);
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'T':
+ T_flag = 1;
+ last_check_time = parse_time(optarg);
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'u':
+ resuid = bb_strtoul(optarg, NULL, 10);
+ if (errno)
+ resuid = xuname2uid(optarg);
+ u_flag = 1;
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'U':
+ new_UUID = optarg;
+ U_flag = 1;
+ open_flag = EXT2_FLAG_RW |
+ EXT2_FLAG_JOURNAL_DEV_OK;
+ break;
+ default:
+ bb_show_usage();
+ }
+ if (optind < argc - 1 || optind == argc)
+ bb_show_usage();
+ if (!open_flag && !l_flag)
+ bb_show_usage();
+ io_options = strchr(argv[optind], '?');
+ if (io_options)
+ *io_options++ = 0;
+ device_name = x_blkid_get_devname(argv[optind]);
+}
+
+static void tune2fs_clean_up(void)
+{
+ if (ENABLE_FEATURE_CLEAN_UP && device_name) free(device_name);
+ if (ENABLE_FEATURE_CLEAN_UP && journal_device) free(journal_device);
+}
+
+int tune2fs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int tune2fs_main(int argc, char **argv)
+{
+ errcode_t retval;
+ ext2_filsys fs;
+ struct ext2_super_block *sb;
+ io_manager io_ptr;
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ atexit(tune2fs_clean_up);
+
+ if (ENABLE_E2LABEL && (applet_name[0] == 'e')) /* e2label */
+ parse_e2label_options(argc, argv);
+ else
+ parse_tune2fs_options(argc, argv); /* tune2fs */
+
+ io_ptr = unix_io_manager;
+ retval = ext2fs_open2(device_name, io_options, open_flag,
+ 0, 0, io_ptr, &fs);
+ if (retval)
+ bb_error_msg_and_die("No valid superblock on %s", device_name);
+ sb = fs->super;
+ if (print_label) {
+ /* For e2label emulation */
+ printf("%.*s\n", (int) sizeof(sb->s_volume_name),
+ sb->s_volume_name);
+ return 0;
+ }
+ retval = ext2fs_check_if_mounted(device_name, &mount_flags);
+ if (retval)
+ bb_error_msg_and_die("cannot determine if %s is mounted", device_name);
+ /* Normally we only need to write out the superblock */
+ fs->flags |= EXT2_FLAG_SUPER_ONLY;
+
+ if (c_flag) {
+ sb->s_max_mnt_count = max_mount_count;
+ ext2fs_mark_super_dirty(fs);
+ printf("Setting maximal mount count to %d\n", max_mount_count);
+ }
+ if (C_flag) {
+ sb->s_mnt_count = mount_count;
+ ext2fs_mark_super_dirty(fs);
+ printf("Setting current mount count to %d\n", mount_count);
+ }
+ if (e_flag) {
+ sb->s_errors = errors;
+ ext2fs_mark_super_dirty(fs);
+ printf("Setting error behavior to %d\n", errors);
+ }
+ if (g_flag) {
+ sb->s_def_resgid = resgid;
+ ext2fs_mark_super_dirty(fs);
+ printf("Setting reserved blocks gid to %lu\n", resgid);
+ }
+ if (i_flag) {
+ sb->s_checkinterval = interval;
+ ext2fs_mark_super_dirty(fs);
+ printf("Setting interval between check %lu seconds\n", interval);
+ }
+ if (m_flag) {
+ sb->s_r_blocks_count = (sb->s_blocks_count / 100)
+ * reserved_ratio;
+ ext2fs_mark_super_dirty(fs);
+ printf("Setting reserved blocks percentage to %u (%u blocks)\n",
+ reserved_ratio, sb->s_r_blocks_count);
+ }
+ if (r_flag) {
+ if (reserved_blocks >= sb->s_blocks_count/2)
+ bb_error_msg_and_die("reserved blocks count is too big (%lu)", reserved_blocks);
+ sb->s_r_blocks_count = reserved_blocks;
+ ext2fs_mark_super_dirty(fs);
+ printf("Setting reserved blocks count to %lu\n", reserved_blocks);
+ }
+ if (s_flag == 1) {
+ if (sb->s_feature_ro_compat &
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)
+ bb_error_msg("\nThe filesystem already has sparse superblocks");
+ else {
+ sb->s_feature_ro_compat |=
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
+ sb->s_state &= ~EXT2_VALID_FS;
+ ext2fs_mark_super_dirty(fs);
+ printf("\nSparse superblock flag set. %s", please_fsck);
+ }
+ }
+ if (s_flag == 0) {
+ if (!(sb->s_feature_ro_compat &
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
+ bb_error_msg("\nThe filesystem already has sparse superblocks disabled");
+ else {
+ sb->s_feature_ro_compat &=
+ ~EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
+ sb->s_state &= ~EXT2_VALID_FS;
+ fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
+ ext2fs_mark_super_dirty(fs);
+ printf("\nSparse superblock flag cleared. %s", please_fsck);
+ }
+ }
+ if (T_flag) {
+ sb->s_lastcheck = last_check_time;
+ ext2fs_mark_super_dirty(fs);
+ printf("Setting time filesystem last checked to %s\n",
+ ctime(&last_check_time));
+ }
+ if (u_flag) {
+ sb->s_def_resuid = resuid;
+ ext2fs_mark_super_dirty(fs);
+ printf("Setting reserved blocks uid to %lu\n", resuid);
+ }
+ if (L_flag) {
+ if (strlen(new_label) > sizeof(sb->s_volume_name))
+ bb_error_msg("Warning: label too long, truncating");
+ memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name));
+ safe_strncpy(sb->s_volume_name, new_label,
+ sizeof(sb->s_volume_name));
+ ext2fs_mark_super_dirty(fs);
+ }
+ if (M_flag) {
+ memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted));
+ safe_strncpy(sb->s_last_mounted, new_last_mounted,
+ sizeof(sb->s_last_mounted));
+ ext2fs_mark_super_dirty(fs);
+ }
+ if (mntopts_cmd)
+ update_mntopts(fs, mntopts_cmd);
+ if (features_cmd)
+ update_feature_set(fs, features_cmd);
+ if (journal_size || journal_device)
+ add_journal(fs);
+
+ if (U_flag) {
+ if ((strcasecmp(new_UUID, "null") == 0) ||
+ (strcasecmp(new_UUID, "clear") == 0)) {
+ uuid_clear(sb->s_uuid);
+ } else if (strcasecmp(new_UUID, "time") == 0) {
+ uuid_generate_time(sb->s_uuid);
+ } else if (strcasecmp(new_UUID, "random") == 0) {
+ uuid_generate(sb->s_uuid);
+ } else if (uuid_parse(new_UUID, sb->s_uuid)) {
+ bb_error_msg_and_die("Invalid UUID format");
+ }
+ ext2fs_mark_super_dirty(fs);
+ }
+
+ if (l_flag)
+ list_super (sb);
+ return (ext2fs_close (fs) ? 1 : 0);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/util.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/util.c
new file mode 100644
index 0000000000..b30c294b8b
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/util.c
@@ -0,0 +1,267 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * util.c --- helper functions used by tune2fs and mke2fs
+ *
+ * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <linux/major.h>
+#include <sys/stat.h>
+
+#include "e2fsbb.h"
+#include "e2p/e2p.h"
+#include "ext2fs/ext2_fs.h"
+#include "ext2fs/ext2fs.h"
+#include "blkid/blkid.h"
+#include "util.h"
+
+void proceed_question(void)
+{
+ fputs("Proceed anyway? (y,n) ", stdout);
+ if (bb_ask_confirmation() == 0)
+ exit(1);
+}
+
+void check_plausibility(const char *device, int force)
+{
+ int val;
+ struct stat s;
+ val = stat(device, &s);
+ if (force)
+ return;
+ if(val == -1)
+ bb_perror_msg_and_die("cannot stat %s", device);
+ if (!S_ISBLK(s.st_mode)) {
+ printf("%s is not a block special device.\n", device);
+ proceed_question();
+ return;
+ }
+
+#ifdef HAVE_LINUX_MAJOR_H
+#ifndef MAJOR
+#define MAJOR(dev) ((dev)>>8)
+#define MINOR(dev) ((dev) & 0xff)
+#endif
+#ifndef SCSI_BLK_MAJOR
+#ifdef SCSI_DISK0_MAJOR
+#ifdef SCSI_DISK8_MAJOR
+#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \
+ ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR) || \
+ ((M) >= SCSI_DISK8_MAJOR && (M) <= SCSI_DISK15_MAJOR))
+#else
+#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \
+ ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR))
+#endif /* defined(SCSI_DISK8_MAJOR) */
+#define SCSI_BLK_MAJOR(M) (SCSI_DISK_MAJOR((M)) || (M) == SCSI_CDROM_MAJOR)
+#else
+#define SCSI_BLK_MAJOR(M) ((M) == SCSI_DISK_MAJOR || (M) == SCSI_CDROM_MAJOR)
+#endif /* defined(SCSI_DISK0_MAJOR) */
+#endif /* defined(SCSI_BLK_MAJOR) */
+ if (((MAJOR(s.st_rdev) == HD_MAJOR &&
+ MINOR(s.st_rdev)%64 == 0) ||
+ (SCSI_BLK_MAJOR(MAJOR(s.st_rdev)) &&
+ MINOR(s.st_rdev)%16 == 0))) {
+ printf("%s is entire device, not just one partition!\n", device);
+ proceed_question();
+ }
+#endif
+}
+
+void check_mount(const char *device, int force, const char *type)
+{
+ errcode_t retval;
+ int mount_flags;
+
+ retval = ext2fs_check_if_mounted(device, &mount_flags);
+ if (retval) {
+ bb_error_msg("cannot determine if %s is mounted", device);
+ return;
+ }
+ if (mount_flags & EXT2_MF_MOUNTED) {
+ bb_error_msg("%s is mounted !", device);
+force_check:
+ if (force)
+ bb_error_msg("badblocks forced anyways");
+ else
+ bb_error_msg_and_die("it's not safe to run badblocks!");
+ }
+
+ if (mount_flags & EXT2_MF_BUSY) {
+ bb_error_msg("%s is apparently in use by the system", device);
+ goto force_check;
+ }
+
+}
+
+void parse_journal_opts(char **journal_device, int *journal_flags,
+ int *journal_size, const char *opts)
+{
+ char *buf, *token, *next, *p, *arg;
+ int journal_usage = 0;
+ buf = xstrdup(opts);
+ for (token = buf; token && *token; token = next) {
+ p = strchr(token, ',');
+ next = 0;
+ if (p) {
+ *p = 0;
+ next = p+1;
+ }
+ arg = strchr(token, '=');
+ if (arg) {
+ *arg = 0;
+ arg++;
+ }
+ if (strcmp(token, "device") == 0) {
+ *journal_device = blkid_get_devname(NULL, arg, NULL);
+ if (!journal_device) {
+ journal_usage++;
+ continue;
+ }
+ } else if (strcmp(token, "size") == 0) {
+ if (!arg) {
+ journal_usage++;
+ continue;
+ }
+ (*journal_size) = strtoul(arg, &p, 0);
+ if (*p)
+ journal_usage++;
+ } else if (strcmp(token, "v1_superblock") == 0) {
+ (*journal_flags) |= EXT2_MKJOURNAL_V1_SUPER;
+ continue;
+ } else
+ journal_usage++;
+ }
+ if (journal_usage)
+ bb_error_msg_and_die(
+ "\nBad journal options specified.\n\n"
+ "Journal options are separated by commas, "
+ "and may take an argument which\n"
+ "\tis set off by an equals ('=') sign.\n\n"
+ "Valid journal options are:\n"
+ "\tsize=<journal size in megabytes>\n"
+ "\tdevice=<journal device>\n\n"
+ "The journal size must be between "
+ "1024 and 102400 filesystem blocks.\n\n");
+}
+
+/*
+ * Determine the number of journal blocks to use, either via
+ * user-specified # of megabytes, or via some intelligently selected
+ * defaults.
+ *
+ * Find a reasonable journal file size (in blocks) given the number of blocks
+ * in the filesystem. For very small filesystems, it is not reasonable to
+ * have a journal that fills more than half of the filesystem.
+ */
+int figure_journal_size(int size, ext2_filsys fs)
+{
+ blk_t j_blocks;
+
+ if (fs->super->s_blocks_count < 2048) {
+ bb_error_msg("Filesystem too small for a journal");
+ return 0;
+ }
+
+ if (size >= 0) {
+ j_blocks = size * 1024 / (fs->blocksize / 1024);
+ if (j_blocks < 1024 || j_blocks > 102400)
+ bb_error_msg_and_die("\nThe requested journal "
+ "size is %d blocks;\n it must be "
+ "between 1024 and 102400 blocks; Aborting",
+ j_blocks);
+ if (j_blocks > fs->super->s_free_blocks_count)
+ bb_error_msg_and_die("Journal size too big for filesystem");
+ return j_blocks;
+ }
+
+ if (fs->super->s_blocks_count < 32768)
+ j_blocks = 1024;
+ else if (fs->super->s_blocks_count < 256*1024)
+ j_blocks = 4096;
+ else if (fs->super->s_blocks_count < 512*1024)
+ j_blocks = 8192;
+ else if (fs->super->s_blocks_count < 1024*1024)
+ j_blocks = 16384;
+ else
+ j_blocks = 32768;
+
+ return j_blocks;
+}
+
+void print_check_message(ext2_filsys fs)
+{
+ printf("This filesystem will be automatically "
+ "checked every %d mounts or\n"
+ "%g days, whichever comes first. "
+ "Use tune2fs -c or -i to override.\n",
+ fs->super->s_max_mnt_count,
+ (double)fs->super->s_checkinterval / (3600 * 24));
+}
+
+void make_journal_device(char *journal_device, ext2_filsys fs, int quiet, int force)
+{
+ errcode_t retval;
+ ext2_filsys jfs;
+ io_manager io_ptr;
+
+ check_plausibility(journal_device, force);
+ check_mount(journal_device, force, "journal");
+ io_ptr = unix_io_manager;
+ retval = ext2fs_open(journal_device, EXT2_FLAG_RW|
+ EXT2_FLAG_JOURNAL_DEV_OK, 0,
+ fs->blocksize, io_ptr, &jfs);
+ if (retval)
+ bb_error_msg_and_die("cannot journal device %s", journal_device);
+ if(!quiet)
+ printf("Adding journal to device %s: ", journal_device);
+ fflush(stdout);
+ retval = ext2fs_add_journal_device(fs, jfs);
+ if(retval)
+ bb_error_msg_and_die("\nFailed to add journal to device %s", journal_device);
+ if(!quiet)
+ puts("done");
+ ext2fs_close(jfs);
+}
+
+void make_journal_blocks(ext2_filsys fs, int journal_size, int journal_flags, int quiet)
+{
+ unsigned long journal_blocks;
+ errcode_t retval;
+
+ journal_blocks = figure_journal_size(journal_size, fs);
+ if (!journal_blocks) {
+ fs->super->s_feature_compat &=
+ ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
+ return;
+ }
+ if(!quiet)
+ printf("Creating journal (%ld blocks): ", journal_blocks);
+ fflush(stdout);
+ retval = ext2fs_add_journal_inode(fs, journal_blocks,
+ journal_flags);
+ if(retval)
+ bb_error_msg_and_die("cannot create journal");
+ if(!quiet)
+ puts("done");
+}
+
+char *e2fs_set_sbin_path(void)
+{
+ char *oldpath = getenv("PATH");
+ /* Update our PATH to include /sbin */
+#define PATH_SET "/sbin"
+ if (oldpath)
+ oldpath = xasprintf("%s:%s", PATH_SET, oldpath);
+ else
+ oldpath = PATH_SET;
+ putenv (oldpath);
+ return oldpath;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/util.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/util.h
new file mode 100644
index 0000000000..80d2417185
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/util.h
@@ -0,0 +1,22 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * util.h --- header file defining prototypes for helper functions
+ * used by tune2fs and mke2fs
+ *
+ * Copyright 2000 by Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+extern void proceed_question(void);
+extern void check_plausibility(const char *device, int force);
+extern void parse_journal_opts(char **, int *, int *, const char *opts);
+extern void check_mount(const char *device, int force, const char *type);
+extern int figure_journal_size(int size, ext2_filsys fs);
+extern void print_check_message(ext2_filsys fs);
+extern void make_journal_device(char *journal_device, ext2_filsys fs, int quiet, int force);
+extern void make_journal_blocks(ext2_filsys fs, int journal_size, int journal_flags, int quiet);
+extern char *e2fs_set_sbin_path(void);
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/Kbuild b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/Kbuild
new file mode 100644
index 0000000000..dde9818409
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/Kbuild
@@ -0,0 +1,14 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+NEEDED-$(CONFIG_E2FSCK) = y
+NEEDED-$(CONFIG_FSCK) = y
+NEEDED-$(CONFIG_MKE2FS) = y
+NEEDED-$(CONFIG_TUNE2FS) = y
+
+lib-y:=
+lib-$(NEEDED-y) += compare.o gen_uuid.o pack.o parse.o unpack.o unparse.o \
+ uuid_time.o
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/compare.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/compare.c
new file mode 100644
index 0000000000..348ea7c1f9
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/compare.c
@@ -0,0 +1,55 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * compare.c --- compare whether or not two UUID's are the same
+ *
+ * Returns 0 if the two UUID's are different, and 1 if they are the same.
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include "uuidP.h"
+#include <string.h>
+
+#define UUCMP(u1,u2) if (u1 != u2) return (u1 < u2) ? -1 : 1;
+
+int uuid_compare(const uuid_t uu1, const uuid_t uu2)
+{
+ struct uuid uuid1, uuid2;
+
+ uuid_unpack(uu1, &uuid1);
+ uuid_unpack(uu2, &uuid2);
+
+ UUCMP(uuid1.time_low, uuid2.time_low);
+ UUCMP(uuid1.time_mid, uuid2.time_mid);
+ UUCMP(uuid1.time_hi_and_version, uuid2.time_hi_and_version);
+ UUCMP(uuid1.clock_seq, uuid2.clock_seq);
+ return memcmp(uuid1.node, uuid2.node, 6);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/gen_uuid.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/gen_uuid.c
new file mode 100644
index 0000000000..03a9f376a5
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/gen_uuid.c
@@ -0,0 +1,304 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * gen_uuid.c --- generate a DCE-compatible uuid
+ *
+ * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#include <sys/socket.h>
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NET_IF_DL_H
+#include <net/if_dl.h>
+#endif
+
+#include "uuidP.h"
+
+#ifdef HAVE_SRANDOM
+#define srand(x) srandom(x)
+#define rand() random()
+#endif
+
+static int get_random_fd(void)
+{
+ struct timeval tv;
+ static int fd = -2;
+ int i;
+
+ if (fd == -2) {
+ gettimeofday(&tv, 0);
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd == -1)
+ fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+ srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec);
+ }
+ /* Crank the random number generator a few times */
+ gettimeofday(&tv, 0);
+ for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--)
+ rand();
+ return fd;
+}
+
+
+/*
+ * Generate a series of random bytes. Use /dev/urandom if possible,
+ * and if not, use srandom/random.
+ */
+static void get_random_bytes(void *buf, int nbytes)
+{
+ int i, n = nbytes, fd = get_random_fd();
+ int lose_counter = 0;
+ unsigned char *cp = (unsigned char *) buf;
+
+ if (fd >= 0) {
+ while (n > 0) {
+ i = read(fd, cp, n);
+ if (i <= 0) {
+ if (lose_counter++ > 16)
+ break;
+ continue;
+ }
+ n -= i;
+ cp += i;
+ lose_counter = 0;
+ }
+ }
+
+ /*
+ * We do this all the time, but this is the only source of
+ * randomness if /dev/random/urandom is out to lunch.
+ */
+ for (cp = buf, i = 0; i < nbytes; i++)
+ *cp++ ^= (rand() >> 7) & 0xFF;
+}
+
+/*
+ * Get the ethernet hardware address, if we can find it...
+ */
+static int get_node_id(unsigned char *node_id)
+{
+#ifdef HAVE_NET_IF_H
+ int sd;
+ struct ifreq ifr, *ifrp;
+ struct ifconf ifc;
+ char buf[1024];
+ int n, i;
+ unsigned char *a;
+#ifdef HAVE_NET_IF_DL_H
+ struct sockaddr_dl *sdlp;
+#endif
+
+/*
+ * BSD 4.4 defines the size of an ifreq to be
+ * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
+ * However, under earlier systems, sa_len isn't present, so the size is
+ * just sizeof(struct ifreq)
+ */
+#ifdef HAVE_SA_LEN
+#ifndef max
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+#define ifreq_size(i) max(sizeof(struct ifreq),\
+ sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
+#else
+#define ifreq_size(i) sizeof(struct ifreq)
+#endif /* HAVE_SA_LEN*/
+
+ sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+ if (sd < 0) {
+ return -1;
+ }
+ memset(buf, 0, sizeof(buf));
+ ifc.ifc_len = sizeof(buf);
+ ifc.ifc_buf = buf;
+ if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) {
+ close(sd);
+ return -1;
+ }
+ n = ifc.ifc_len;
+ for (i = 0; i < n; i+= ifreq_size(*ifrp) ) {
+ ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
+ strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
+#ifdef SIOCGIFHWADDR
+ if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
+ continue;
+ a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
+#else
+#ifdef SIOCGENADDR
+ if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
+ continue;
+ a = (unsigned char *) ifr.ifr_enaddr;
+#else
+#ifdef HAVE_NET_IF_DL_H
+ sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr;
+ if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6))
+ continue;
+ a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen];
+#else
+ /*
+ * XXX we don't have a way of getting the hardware
+ * address
+ */
+ close(sd);
+ return 0;
+#endif /* HAVE_NET_IF_DL_H */
+#endif /* SIOCGENADDR */
+#endif /* SIOCGIFHWADDR */
+ if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
+ continue;
+ if (node_id) {
+ memcpy(node_id, a, 6);
+ close(sd);
+ return 1;
+ }
+ }
+ close(sd);
+#endif
+ return 0;
+}
+
+/* Assume that the gettimeofday() has microsecond granularity */
+#define MAX_ADJUSTMENT 10
+
+static int get_clock(uint32_t *clock_high, uint32_t *clock_low, uint16_t *ret_clock_seq)
+{
+ static int adjustment = 0;
+ static struct timeval last = {0, 0};
+ static uint16_t clock_seq;
+ struct timeval tv;
+ unsigned long long clock_reg;
+
+try_again:
+ gettimeofday(&tv, 0);
+ if ((last.tv_sec == 0) && (last.tv_usec == 0)) {
+ get_random_bytes(&clock_seq, sizeof(clock_seq));
+ clock_seq &= 0x3FFF;
+ last = tv;
+ last.tv_sec--;
+ }
+ if ((tv.tv_sec < last.tv_sec) ||
+ ((tv.tv_sec == last.tv_sec) &&
+ (tv.tv_usec < last.tv_usec))) {
+ clock_seq = (clock_seq+1) & 0x3FFF;
+ adjustment = 0;
+ last = tv;
+ } else if ((tv.tv_sec == last.tv_sec) &&
+ (tv.tv_usec == last.tv_usec)) {
+ if (adjustment >= MAX_ADJUSTMENT)
+ goto try_again;
+ adjustment++;
+ } else {
+ adjustment = 0;
+ last = tv;
+ }
+
+ clock_reg = tv.tv_usec*10 + adjustment;
+ clock_reg += ((unsigned long long) tv.tv_sec)*10000000;
+ clock_reg += (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000;
+
+ *clock_high = clock_reg >> 32;
+ *clock_low = clock_reg;
+ *ret_clock_seq = clock_seq;
+ return 0;
+}
+
+void uuid_generate_time(uuid_t out)
+{
+ static unsigned char node_id[6];
+ static int has_init = 0;
+ struct uuid uu;
+ uint32_t clock_mid;
+
+ if (!has_init) {
+ if (get_node_id(node_id) <= 0) {
+ get_random_bytes(node_id, 6);
+ /*
+ * Set multicast bit, to prevent conflicts
+ * with IEEE 802 addresses obtained from
+ * network cards
+ */
+ node_id[0] |= 0x01;
+ }
+ has_init = 1;
+ }
+ get_clock(&clock_mid, &uu.time_low, &uu.clock_seq);
+ uu.clock_seq |= 0x8000;
+ uu.time_mid = (uint16_t) clock_mid;
+ uu.time_hi_and_version = ((clock_mid >> 16) & 0x0FFF) | 0x1000;
+ memcpy(uu.node, node_id, 6);
+ uuid_pack(&uu, out);
+}
+
+void uuid_generate_random(uuid_t out)
+{
+ uuid_t buf;
+ struct uuid uu;
+
+ get_random_bytes(buf, sizeof(buf));
+ uuid_unpack(buf, &uu);
+
+ uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
+ uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x4000;
+ uuid_pack(&uu, out);
+}
+
+/*
+ * This is the generic front-end to uuid_generate_random and
+ * uuid_generate_time. It uses uuid_generate_random only if
+ * /dev/urandom is available, since otherwise we won't have
+ * high-quality randomness.
+ */
+void uuid_generate(uuid_t out)
+{
+ if (get_random_fd() >= 0)
+ uuid_generate_random(out);
+ else
+ uuid_generate_time(out);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/pack.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/pack.c
new file mode 100644
index 0000000000..217cfce5d7
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/pack.c
@@ -0,0 +1,69 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Internal routine for packing UUID's
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include <string.h>
+#include "uuidP.h"
+
+void uuid_pack(const struct uuid *uu, uuid_t ptr)
+{
+ uint32_t tmp;
+ unsigned char *out = ptr;
+
+ tmp = uu->time_low;
+ out[3] = (unsigned char) tmp;
+ tmp >>= 8;
+ out[2] = (unsigned char) tmp;
+ tmp >>= 8;
+ out[1] = (unsigned char) tmp;
+ tmp >>= 8;
+ out[0] = (unsigned char) tmp;
+
+ tmp = uu->time_mid;
+ out[5] = (unsigned char) tmp;
+ tmp >>= 8;
+ out[4] = (unsigned char) tmp;
+
+ tmp = uu->time_hi_and_version;
+ out[7] = (unsigned char) tmp;
+ tmp >>= 8;
+ out[6] = (unsigned char) tmp;
+
+ tmp = uu->clock_seq;
+ out[9] = (unsigned char) tmp;
+ tmp >>= 8;
+ out[8] = (unsigned char) tmp;
+
+ memcpy(out+10, uu->node, 6);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/parse.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/parse.c
new file mode 100644
index 0000000000..9a3f9cb921
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/parse.c
@@ -0,0 +1,80 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * parse.c --- UUID parsing
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "uuidP.h"
+
+int uuid_parse(const char *in, uuid_t uu)
+{
+ struct uuid uuid;
+ int i;
+ const char *cp;
+ char buf[3];
+
+ if (strlen(in) != 36)
+ return -1;
+ for (i=0, cp = in; i <= 36; i++,cp++) {
+ if ((i == 8) || (i == 13) || (i == 18) ||
+ (i == 23)) {
+ if (*cp == '-')
+ continue;
+ else
+ return -1;
+ }
+ if (i== 36)
+ if (*cp == 0)
+ continue;
+ if (!isxdigit(*cp))
+ return -1;
+ }
+ uuid.time_low = strtoul(in, NULL, 16);
+ uuid.time_mid = strtoul(in+9, NULL, 16);
+ uuid.time_hi_and_version = strtoul(in+14, NULL, 16);
+ uuid.clock_seq = strtoul(in+19, NULL, 16);
+ cp = in+24;
+ buf[2] = 0;
+ for (i=0; i < 6; i++) {
+ buf[0] = *cp++;
+ buf[1] = *cp++;
+ uuid.node[i] = strtoul(buf, NULL, 16);
+ }
+
+ uuid_pack(&uuid, uu);
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/unpack.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/unpack.c
new file mode 100644
index 0000000000..95d3aab4a2
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/unpack.c
@@ -0,0 +1,63 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Internal routine for unpacking UUID
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include <string.h>
+#include "uuidP.h"
+
+void uuid_unpack(const uuid_t in, struct uuid *uu)
+{
+ const uint8_t *ptr = in;
+ uint32_t tmp;
+
+ tmp = *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ uu->time_low = tmp;
+
+ tmp = *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ uu->time_mid = tmp;
+
+ tmp = *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ uu->time_hi_and_version = tmp;
+
+ tmp = *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ uu->clock_seq = tmp;
+
+ memcpy(uu->node, ptr, 6);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/unparse.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/unparse.c
new file mode 100644
index 0000000000..d2948fe6dc
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/unparse.c
@@ -0,0 +1,77 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * unparse.c -- convert a UUID to string
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+
+#include "uuidP.h"
+
+static const char *fmt_lower =
+ "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
+
+static const char *fmt_upper =
+ "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X";
+
+#ifdef UUID_UNPARSE_DEFAULT_UPPER
+#define FMT_DEFAULT fmt_upper
+#else
+#define FMT_DEFAULT fmt_lower
+#endif
+
+static void uuid_unparse_x(const uuid_t uu, char *out, const char *fmt)
+{
+ struct uuid uuid;
+
+ uuid_unpack(uu, &uuid);
+ sprintf(out, fmt,
+ uuid.time_low, uuid.time_mid, uuid.time_hi_and_version,
+ uuid.clock_seq >> 8, uuid.clock_seq & 0xFF,
+ uuid.node[0], uuid.node[1], uuid.node[2],
+ uuid.node[3], uuid.node[4], uuid.node[5]);
+}
+
+void uuid_unparse_lower(const uuid_t uu, char *out)
+{
+ uuid_unparse_x(uu, out, fmt_lower);
+}
+
+void uuid_unparse_upper(const uuid_t uu, char *out)
+{
+ uuid_unparse_x(uu, out, fmt_upper);
+}
+
+void uuid_unparse(const uuid_t uu, char *out)
+{
+ uuid_unparse_x(uu, out, FMT_DEFAULT);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/uuid.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/uuid.h
new file mode 100644
index 0000000000..bd53b15d0a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/uuid.h
@@ -0,0 +1,104 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Public include file for the UUID library
+ *
+ * Copyright (C) 1996, 1997, 1998 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#ifndef _UUID_UUID_H
+#define _UUID_UUID_H
+
+#include <sys/types.h>
+#include <time.h>
+
+typedef unsigned char uuid_t[16];
+
+/* UUID Variant definitions */
+#define UUID_VARIANT_NCS 0
+#define UUID_VARIANT_DCE 1
+#define UUID_VARIANT_MICROSOFT 2
+#define UUID_VARIANT_OTHER 3
+
+/* UUID Type definitions */
+#define UUID_TYPE_DCE_TIME 1
+#define UUID_TYPE_DCE_RANDOM 4
+
+/* Allow UUID constants to be defined */
+#ifdef __GNUC__
+#define UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \
+ static const uuid_t name ATTRIBUTE_UNUSED = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15}
+#else
+#define UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \
+ static const uuid_t name = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15}
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* clear.c */
+/*void uuid_clear(uuid_t uu);*/
+#define uuid_clear(uu) memset(uu, 0, sizeof(uu))
+
+/* compare.c */
+int uuid_compare(const uuid_t uu1, const uuid_t uu2);
+
+/* copy.c */
+/*void uuid_copy(uuid_t dst, const uuid_t src);*/
+#define uuid_copy(dst,src) memcpy(dst, src, sizeof(dst))
+
+/* gen_uuid.c */
+void uuid_generate(uuid_t out);
+void uuid_generate_random(uuid_t out);
+void uuid_generate_time(uuid_t out);
+
+/* isnull.c */
+/*int uuid_is_null(const uuid_t uu);*/
+#define uuid_is_null(uu) (!memcmp(uu, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", sizeof(uu)))
+
+/* parse.c */
+int uuid_parse(const char *in, uuid_t uu);
+
+/* unparse.c */
+void uuid_unparse(const uuid_t uu, char *out);
+void uuid_unparse_lower(const uuid_t uu, char *out);
+void uuid_unparse_upper(const uuid_t uu, char *out);
+
+/* uuid_time.c */
+time_t uuid_time(const uuid_t uu, struct timeval *ret_tv);
+int uuid_type(const uuid_t uu);
+int uuid_variant(const uuid_t uu);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UUID_UUID_H */
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/uuidP.h b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/uuidP.h
new file mode 100644
index 0000000000..87041ef0a2
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/uuidP.h
@@ -0,0 +1,60 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * uuid.h -- private header file for uuids
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include <inttypes.h>
+#include <sys/types.h>
+
+#include "uuid.h"
+
+/*
+ * Offset between 15-Oct-1582 and 1-Jan-70
+ */
+#define TIME_OFFSET_HIGH 0x01B21DD2
+#define TIME_OFFSET_LOW 0x13814000
+
+struct uuid {
+ uint32_t time_low;
+ uint16_t time_mid;
+ uint16_t time_hi_and_version;
+ uint16_t clock_seq;
+ uint8_t node[6];
+};
+
+
+/*
+ * prototypes
+ */
+void uuid_pack(const struct uuid *uu, uuid_t ptr);
+void uuid_unpack(const uuid_t in, struct uuid *uu);
diff --git a/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/uuid_time.c b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/uuid_time.c
new file mode 100644
index 0000000000..b6f73e6dc9
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/e2fsprogs/old_e2fsprogs/uuid/uuid_time.c
@@ -0,0 +1,161 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * uuid_time.c --- Interpret the time field from a uuid. This program
+ * violates the UUID abstraction barrier by reaching into the guts
+ * of a UUID and interpreting it.
+ *
+ * Copyright (C) 1998, 1999 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include "uuidP.h"
+
+time_t uuid_time(const uuid_t uu, struct timeval *ret_tv)
+{
+ struct uuid uuid;
+ uint32_t high;
+ struct timeval tv;
+ unsigned long long clock_reg;
+
+ uuid_unpack(uu, &uuid);
+
+ high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16);
+ clock_reg = uuid.time_low | ((unsigned long long) high << 32);
+
+ clock_reg -= (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000;
+ tv.tv_sec = clock_reg / 10000000;
+ tv.tv_usec = (clock_reg % 10000000) / 10;
+
+ if (ret_tv)
+ *ret_tv = tv;
+
+ return tv.tv_sec;
+}
+
+int uuid_type(const uuid_t uu)
+{
+ struct uuid uuid;
+
+ uuid_unpack(uu, &uuid);
+ return ((uuid.time_hi_and_version >> 12) & 0xF);
+}
+
+int uuid_variant(const uuid_t uu)
+{
+ struct uuid uuid;
+ int var;
+
+ uuid_unpack(uu, &uuid);
+ var = uuid.clock_seq;
+
+ if ((var & 0x8000) == 0)
+ return UUID_VARIANT_NCS;
+ if ((var & 0x4000) == 0)
+ return UUID_VARIANT_DCE;
+ if ((var & 0x2000) == 0)
+ return UUID_VARIANT_MICROSOFT;
+ return UUID_VARIANT_OTHER;
+}
+
+#ifdef DEBUG
+static const char *variant_string(int variant)
+{
+ switch (variant) {
+ case UUID_VARIANT_NCS:
+ return "NCS";
+ case UUID_VARIANT_DCE:
+ return "DCE";
+ case UUID_VARIANT_MICROSOFT:
+ return "Microsoft";
+ default:
+ return "Other";
+ }
+}
+
+
+int
+main(int argc, char **argv)
+{
+ uuid_t buf;
+ time_t time_reg;
+ struct timeval tv;
+ int type, variant;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s uuid\n", argv[0]);
+ exit(1);
+ }
+ if (uuid_parse(argv[1], buf)) {
+ fprintf(stderr, "Invalid UUID: %s\n", argv[1]);
+ exit(1);
+ }
+ variant = uuid_variant(buf);
+ type = uuid_type(buf);
+ time_reg = uuid_time(buf, &tv);
+
+ printf("UUID variant is %d (%s)\n", variant, variant_string(variant));
+ if (variant != UUID_VARIANT_DCE) {
+ printf("Warning: This program only knows how to interpret "
+ "DCE UUIDs.\n\tThe rest of the output is likely "
+ "to be incorrect!!\n");
+ }
+ printf("UUID type is %d", type);
+ switch (type) {
+ case 1:
+ printf(" (time based)\n");
+ break;
+ case 2:
+ printf(" (DCE)\n");
+ break;
+ case 3:
+ printf(" (name-based)\n");
+ break;
+ case 4:
+ printf(" (random)\n");
+ break;
+ default:
+ bb_putchar('\n');
+ }
+ if (type != 1) {
+ printf("Warning: not a time-based UUID, so UUID time "
+ "decoding will likely not work!\n");
+ }
+ printf("UUID time is: (%ld, %ld): %s\n", tv.tv_sec, tv.tv_usec,
+ ctime(&time_reg));
+
+ return 0;
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/editors/Config.in b/cleopatre/busybox-1.11.1-spc300/editors/Config.in
new file mode 100644
index 0000000000..58959aa97d
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/editors/Config.in
@@ -0,0 +1,196 @@
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Editors"
+
+config AWK
+ bool "awk"
+ default n
+ help
+ Awk is used as a pattern scanning and processing language. This is
+ the BusyBox implementation of that programming language.
+
+config FEATURE_AWK_MATH
+ bool "Enable math functions (requires libm)"
+ default y
+ depends on AWK
+ help
+ Enable math functions of the Awk programming language.
+ NOTE: This will require libm to be present for linking.
+
+config CMP
+ bool "cmp"
+ default n
+ help
+ cmp is used to compare two files and returns the result
+ to standard output.
+
+config DIFF
+ bool "diff"
+ default n
+ help
+ diff compares two files or directories and outputs the
+ differences between them in a form that can be given to
+ the patch command.
+
+config FEATURE_DIFF_BINARY
+ bool "Enable checks for binary files"
+ default y
+ depends on DIFF
+ help
+ This option enables support for checking for binary files
+ before a comparison is carried out.
+
+config FEATURE_DIFF_DIR
+ bool "Enable directory support"
+ default y
+ depends on DIFF
+ help
+ This option enables support for directory and subdirectory
+ comparison.
+
+config FEATURE_DIFF_MINIMAL
+ bool "Enable -d option to find smaller sets of changes"
+ default n
+ depends on DIFF
+ help
+ Enabling this option allows the use of -d to make diff
+ try hard to find the smallest possible set of changes.
+
+config ED
+ bool "ed"
+ default n
+ help
+ The original 1970's Unix text editor, from the days of teletypes.
+ Small, simple, evil. Part of SUSv3. If you're not already using
+ this, you don't need it.
+
+config PATCH
+ bool "patch"
+ default n
+ help
+ Apply a unified diff formatted patch.
+
+config SED
+ bool "sed"
+ default n
+ help
+ sed is used to perform text transformations on a file
+ or input from a pipeline.
+
+config VI
+ bool "vi"
+ default n
+ help
+ 'vi' is a text editor. More specifically, it is the One True
+ text editor <grin>. It does, however, have a rather steep
+ learning curve. If you are not already comfortable with 'vi'
+ you may wish to use something else.
+
+config FEATURE_VI_MAX_LEN
+ int "Maximum screen width in vi"
+ range 256 16384
+ default 4096
+ depends on VI
+ help
+ Contrary to what you may think, this is not eating much.
+ Make it smaller than 4k only if you are very limited on memory.
+
+config FEATURE_VI_8BIT
+ bool "Allow vi to display 8-bit chars (otherwise shows dots)"
+ default y
+ depends on VI
+ help
+ If your terminal can display characters with high bit set,
+ you may want to enable this. Note: vi is not Unicode-capable.
+ If your terminal combines several 8-bit bytes into one character
+ (as in Unicode mode), this will not work properly.
+
+config FEATURE_VI_COLON
+ bool "Enable \":\" colon commands (no \"ex\" mode)"
+ default y
+ depends on VI
+ help
+ Enable a limited set of colon commands for vi. This does not
+ provide an "ex" mode.
+
+config FEATURE_VI_YANKMARK
+ bool "Enable yank/put commands and mark cmds"
+ default y
+ depends on VI
+ help
+ This will enable you to use yank and put, as well as mark in
+ busybox vi.
+
+config FEATURE_VI_SEARCH
+ bool "Enable search and replace cmds"
+ default y
+ depends on VI
+ help
+ Select this if you wish to be able to do search and replace in
+ busybox vi.
+
+config FEATURE_VI_USE_SIGNALS
+ bool "Catch signals"
+ default y
+ depends on VI
+ help
+ Selecting this option will make busybox vi signal aware. This will
+ make busybox vi support SIGWINCH to deal with Window Changes, catch
+ Ctrl-Z and Ctrl-C and alarms.
+
+config FEATURE_VI_DOT_CMD
+ bool "Remember previous cmd and \".\" cmd"
+ default y
+ depends on VI
+ help
+ Make busybox vi remember the last command and be able to repeat it.
+
+config FEATURE_VI_READONLY
+ bool "Enable -R option and \"view\" mode"
+ default y
+ depends on VI
+ help
+ Enable the read-only command line option, which allows the user to
+ open a file in read-only mode.
+
+config FEATURE_VI_SETOPTS
+ bool "Enable set-able options, ai ic showmatch"
+ default y
+ depends on VI
+ help
+ Enable the editor to set some (ai, ic, showmatch) options.
+
+config FEATURE_VI_SET
+ bool "Support for :set"
+ default y
+ depends on VI
+ help
+ Support for ":set".
+
+config FEATURE_VI_WIN_RESIZE
+ bool "Handle window resize"
+ default y
+ depends on VI
+ help
+ Make busybox vi behave nicely with terminals that get resized.
+
+config FEATURE_VI_OPTIMIZE_CURSOR
+ bool "Optimize cursor movement"
+ default y
+ depends on VI
+ help
+ This will make the cursor movement faster, but requires more memory
+ and it makes the applet a tiny bit larger.
+
+config FEATURE_ALLOW_EXEC
+ bool "Allow vi and awk to execute shell commands"
+ default y
+ depends on VI || AWK
+ help
+ Enables vi and awk features which allows user to execute
+ shell commands (using system() C call).
+
+endmenu
diff --git a/cleopatre/busybox-1.11.1-spc300/editors/Kbuild b/cleopatre/busybox-1.11.1-spc300/editors/Kbuild
new file mode 100644
index 0000000000..76302aa76d
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/editors/Kbuild
@@ -0,0 +1,14 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+lib-y:=
+lib-$(CONFIG_AWK) += awk.o
+lib-$(CONFIG_CMP) += cmp.o
+lib-$(CONFIG_DIFF) += diff.o
+lib-$(CONFIG_ED) += ed.o
+lib-$(CONFIG_PATCH) += patch.o
+lib-$(CONFIG_SED) += sed.o
+lib-$(CONFIG_VI) += vi.o
diff --git a/cleopatre/busybox-1.11.1-spc300/editors/awk.c b/cleopatre/busybox-1.11.1-spc300/editors/awk.c
new file mode 100644
index 0000000000..cc5dc84b53
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/editors/awk.c
@@ -0,0 +1,2889 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * awk implementation for busybox
+ *
+ * Copyright (C) 2002 by Dmitry Zakharov <dmit@crp.bank.gov.ua>
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+#include "xregex.h"
+#include <math.h>
+
+/* This is a NOEXEC applet. Be very careful! */
+
+
+#define MAXVARFMT 240
+#define MINNVBLOCK 64
+
+/* variable flags */
+#define VF_NUMBER 0x0001 /* 1 = primary type is number */
+#define VF_ARRAY 0x0002 /* 1 = it's an array */
+
+#define VF_CACHED 0x0100 /* 1 = num/str value has cached str/num eq */
+#define VF_USER 0x0200 /* 1 = user input (may be numeric string) */
+#define VF_SPECIAL 0x0400 /* 1 = requires extra handling when changed */
+#define VF_WALK 0x0800 /* 1 = variable has alloc'd x.walker list */
+#define VF_FSTR 0x1000 /* 1 = var::string points to fstring buffer */
+#define VF_CHILD 0x2000 /* 1 = function arg; x.parent points to source */
+#define VF_DIRTY 0x4000 /* 1 = variable was set explicitly */
+
+/* these flags are static, don't change them when value is changed */
+#define VF_DONTTOUCH (VF_ARRAY | VF_SPECIAL | VF_WALK | VF_CHILD | VF_DIRTY)
+
+/* Variable */
+typedef struct var_s {
+ unsigned type; /* flags */
+ double number;
+ char *string;
+ union {
+ int aidx; /* func arg idx (for compilation stage) */
+ struct xhash_s *array; /* array ptr */
+ struct var_s *parent; /* for func args, ptr to actual parameter */
+ char **walker; /* list of array elements (for..in) */
+ } x;
+} var;
+
+/* Node chain (pattern-action chain, BEGIN, END, function bodies) */
+typedef struct chain_s {
+ struct node_s *first;
+ struct node_s *last;
+ const char *programname;
+} chain;
+
+/* Function */
+typedef struct func_s {
+ unsigned nargs;
+ struct chain_s body;
+} func;
+
+/* I/O stream */
+typedef struct rstream_s {
+ FILE *F;
+ char *buffer;
+ int adv;
+ int size;
+ int pos;
+ smallint is_pipe;
+} rstream;
+
+typedef struct hash_item_s {
+ union {
+ struct var_s v; /* variable/array hash */
+ struct rstream_s rs; /* redirect streams hash */
+ struct func_s f; /* functions hash */
+ } data;
+ struct hash_item_s *next; /* next in chain */
+ char name[1]; /* really it's longer */
+} hash_item;
+
+typedef struct xhash_s {
+ unsigned nel; /* num of elements */
+ unsigned csize; /* current hash size */
+ unsigned nprime; /* next hash size in PRIMES[] */
+ unsigned glen; /* summary length of item names */
+ struct hash_item_s **items;
+} xhash;
+
+/* Tree node */
+typedef struct node_s {
+ uint32_t info;
+ unsigned lineno;
+ union {
+ struct node_s *n;
+ var *v;
+ int i;
+ char *s;
+ regex_t *re;
+ } l;
+ union {
+ struct node_s *n;
+ regex_t *ire;
+ func *f;
+ int argno;
+ } r;
+ union {
+ struct node_s *n;
+ } a;
+} node;
+
+/* Block of temporary variables */
+typedef struct nvblock_s {
+ int size;
+ var *pos;
+ struct nvblock_s *prev;
+ struct nvblock_s *next;
+ var nv[0];
+} nvblock;
+
+typedef struct tsplitter_s {
+ node n;
+ regex_t re[2];
+} tsplitter;
+
+/* simple token classes */
+/* Order and hex values are very important!!! See next_token() */
+#define TC_SEQSTART 1 /* ( */
+#define TC_SEQTERM (1 << 1) /* ) */
+#define TC_REGEXP (1 << 2) /* /.../ */
+#define TC_OUTRDR (1 << 3) /* | > >> */
+#define TC_UOPPOST (1 << 4) /* unary postfix operator */
+#define TC_UOPPRE1 (1 << 5) /* unary prefix operator */
+#define TC_BINOPX (1 << 6) /* two-opnd operator */
+#define TC_IN (1 << 7)
+#define TC_COMMA (1 << 8)
+#define TC_PIPE (1 << 9) /* input redirection pipe */
+#define TC_UOPPRE2 (1 << 10) /* unary prefix operator */
+#define TC_ARRTERM (1 << 11) /* ] */
+#define TC_GRPSTART (1 << 12) /* { */
+#define TC_GRPTERM (1 << 13) /* } */
+#define TC_SEMICOL (1 << 14)
+#define TC_NEWLINE (1 << 15)
+#define TC_STATX (1 << 16) /* ctl statement (for, next...) */
+#define TC_WHILE (1 << 17)
+#define TC_ELSE (1 << 18)
+#define TC_BUILTIN (1 << 19)
+#define TC_GETLINE (1 << 20)
+#define TC_FUNCDECL (1 << 21) /* `function' `func' */
+#define TC_BEGIN (1 << 22)
+#define TC_END (1 << 23)
+#define TC_EOF (1 << 24)
+#define TC_VARIABLE (1 << 25)
+#define TC_ARRAY (1 << 26)
+#define TC_FUNCTION (1 << 27)
+#define TC_STRING (1 << 28)
+#define TC_NUMBER (1 << 29)
+
+#define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2)
+
+/* combined token classes */
+#define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN)
+#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST)
+#define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \
+ | TC_BUILTIN | TC_GETLINE | TC_SEQSTART | TC_STRING | TC_NUMBER)
+
+#define TC_STATEMNT (TC_STATX | TC_WHILE)
+#define TC_OPTERM (TC_SEMICOL | TC_NEWLINE)
+
+/* word tokens, cannot mean something else if not expected */
+#define TC_WORD (TC_IN | TC_STATEMNT | TC_ELSE | TC_BUILTIN \
+ | TC_GETLINE | TC_FUNCDECL | TC_BEGIN | TC_END)
+
+/* discard newlines after these */
+#define TC_NOTERM (TC_COMMA | TC_GRPSTART | TC_GRPTERM \
+ | TC_BINOP | TC_OPTERM)
+
+/* what can expression begin with */
+#define TC_OPSEQ (TC_OPERAND | TC_UOPPRE | TC_REGEXP)
+/* what can group begin with */
+#define TC_GRPSEQ (TC_OPSEQ | TC_OPTERM | TC_STATEMNT | TC_GRPSTART)
+
+/* if previous token class is CONCAT1 and next is CONCAT2, concatenation */
+/* operator is inserted between them */
+#define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM \
+ | TC_STRING | TC_NUMBER | TC_UOPPOST)
+#define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE)
+
+#define OF_RES1 0x010000
+#define OF_RES2 0x020000
+#define OF_STR1 0x040000
+#define OF_STR2 0x080000
+#define OF_NUM1 0x100000
+#define OF_CHECKED 0x200000
+
+/* combined operator flags */
+#define xx 0
+#define xV OF_RES2
+#define xS (OF_RES2 | OF_STR2)
+#define Vx OF_RES1
+#define VV (OF_RES1 | OF_RES2)
+#define Nx (OF_RES1 | OF_NUM1)
+#define NV (OF_RES1 | OF_NUM1 | OF_RES2)
+#define Sx (OF_RES1 | OF_STR1)
+#define SV (OF_RES1 | OF_STR1 | OF_RES2)
+#define SS (OF_RES1 | OF_STR1 | OF_RES2 | OF_STR2)
+
+#define OPCLSMASK 0xFF00
+#define OPNMASK 0x007F
+
+/* operator priority is a highest byte (even: r->l, odd: l->r grouping)
+ * For builtins it has different meaning: n n s3 s2 s1 v3 v2 v1,
+ * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string
+ */
+#define P(x) (x << 24)
+#define PRIMASK 0x7F000000
+#define PRIMASK2 0x7E000000
+
+/* Operation classes */
+
+#define SHIFT_TIL_THIS 0x0600
+#define RECUR_FROM_THIS 0x1000
+
+enum {
+ OC_DELETE = 0x0100, OC_EXEC = 0x0200, OC_NEWSOURCE = 0x0300,
+ OC_PRINT = 0x0400, OC_PRINTF = 0x0500, OC_WALKINIT = 0x0600,
+
+ OC_BR = 0x0700, OC_BREAK = 0x0800, OC_CONTINUE = 0x0900,
+ OC_EXIT = 0x0a00, OC_NEXT = 0x0b00, OC_NEXTFILE = 0x0c00,
+ OC_TEST = 0x0d00, OC_WALKNEXT = 0x0e00,
+
+ OC_BINARY = 0x1000, OC_BUILTIN = 0x1100, OC_COLON = 0x1200,
+ OC_COMMA = 0x1300, OC_COMPARE = 0x1400, OC_CONCAT = 0x1500,
+ OC_FBLTIN = 0x1600, OC_FIELD = 0x1700, OC_FNARG = 0x1800,
+ OC_FUNC = 0x1900, OC_GETLINE = 0x1a00, OC_IN = 0x1b00,
+ OC_LAND = 0x1c00, OC_LOR = 0x1d00, OC_MATCH = 0x1e00,
+ OC_MOVE = 0x1f00, OC_PGETLINE = 0x2000, OC_REGEXP = 0x2100,
+ OC_REPLACE = 0x2200, OC_RETURN = 0x2300, OC_SPRINTF = 0x2400,
+ OC_TERNARY = 0x2500, OC_UNARY = 0x2600, OC_VAR = 0x2700,
+ OC_DONE = 0x2800,
+
+ ST_IF = 0x3000, ST_DO = 0x3100, ST_FOR = 0x3200,
+ ST_WHILE = 0x3300
+};
+
+/* simple builtins */
+enum {
+ F_in, F_rn, F_co, F_ex, F_lg, F_si, F_sq, F_sr,
+ F_ti, F_le, F_sy, F_ff, F_cl
+};
+
+/* builtins */
+enum {
+ B_a2, B_ix, B_ma, B_sp, B_ss, B_ti, B_lo, B_up,
+ B_ge, B_gs, B_su,
+ B_an, B_co, B_ls, B_or, B_rs, B_xo,
+};
+
+/* tokens and their corresponding info values */
+
+#define NTC "\377" /* switch to next token class (tc<<1) */
+#define NTCC '\377'
+
+#define OC_B OC_BUILTIN
+
+static const char tokenlist[] ALIGN1 =
+ "\1(" NTC
+ "\1)" NTC
+ "\1/" NTC /* REGEXP */
+ "\2>>" "\1>" "\1|" NTC /* OUTRDR */
+ "\2++" "\2--" NTC /* UOPPOST */
+ "\2++" "\2--" "\1$" NTC /* UOPPRE1 */
+ "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */
+ "\2*=" "\2/=" "\2%=" "\2^="
+ "\1+" "\1-" "\3**=" "\2**"
+ "\1/" "\1%" "\1^" "\1*"
+ "\2!=" "\2>=" "\2<=" "\1>"
+ "\1<" "\2!~" "\1~" "\2&&"
+ "\2||" "\1?" "\1:" NTC
+ "\2in" NTC
+ "\1," NTC
+ "\1|" NTC
+ "\1+" "\1-" "\1!" NTC /* UOPPRE2 */
+ "\1]" NTC
+ "\1{" NTC
+ "\1}" NTC
+ "\1;" NTC
+ "\1\n" NTC
+ "\2if" "\2do" "\3for" "\5break" /* STATX */
+ "\10continue" "\6delete" "\5print"
+ "\6printf" "\4next" "\10nextfile"
+ "\6return" "\4exit" NTC
+ "\5while" NTC
+ "\4else" NTC
+
+ "\3and" "\5compl" "\6lshift" "\2or"
+ "\6rshift" "\3xor"
+ "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */
+ "\3cos" "\3exp" "\3int" "\3log"
+ "\4rand" "\3sin" "\4sqrt" "\5srand"
+ "\6gensub" "\4gsub" "\5index" "\6length"
+ "\5match" "\5split" "\7sprintf" "\3sub"
+ "\6substr" "\7systime" "\10strftime"
+ "\7tolower" "\7toupper" NTC
+ "\7getline" NTC
+ "\4func" "\10function" NTC
+ "\5BEGIN" NTC
+ "\3END" "\0"
+ ;
+
+static const uint32_t tokeninfo[] = {
+ 0,
+ 0,
+ OC_REGEXP,
+ xS|'a', xS|'w', xS|'|',
+ OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m',
+ OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M',
+ OC_FIELD|xV|P(5),
+ OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74),
+ OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-',
+ OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/',
+ OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&',
+ OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-',
+ OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&',
+ OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%',
+ OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*',
+ OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3,
+ OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1,
+ OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!',
+ OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55),
+ OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?',
+ OC_COLON|xx|P(67)|':',
+ OC_IN|SV|P(49),
+ OC_COMMA|SS|P(80),
+ OC_PGETLINE|SV|P(37),
+ OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-',
+ OC_UNARY|xV|P(19)|'!',
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ ST_IF, ST_DO, ST_FOR, OC_BREAK,
+ OC_CONTINUE, OC_DELETE|Vx, OC_PRINT,
+ OC_PRINTF, OC_NEXT, OC_NEXTFILE,
+ OC_RETURN|Vx, OC_EXIT|Nx,
+ ST_WHILE,
+ 0,
+
+ OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83),
+ OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83),
+ OC_FBLTIN|Sx|F_cl, OC_FBLTIN|Sx|F_sy, OC_FBLTIN|Sx|F_ff, OC_B|B_a2|P(0x83),
+ OC_FBLTIN|Nx|F_co, OC_FBLTIN|Nx|F_ex, OC_FBLTIN|Nx|F_in, OC_FBLTIN|Nx|F_lg,
+ OC_FBLTIN|F_rn, OC_FBLTIN|Nx|F_si, OC_FBLTIN|Nx|F_sq, OC_FBLTIN|Nx|F_sr,
+ OC_B|B_ge|P(0xd6), OC_B|B_gs|P(0xb6), OC_B|B_ix|P(0x9b), OC_FBLTIN|Sx|F_le,
+ OC_B|B_ma|P(0x89), OC_B|B_sp|P(0x8b), OC_SPRINTF, OC_B|B_su|P(0xb6),
+ OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b),
+ OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49),
+ OC_GETLINE|SV|P(0),
+ 0, 0,
+ 0,
+ 0
+};
+
+/* internal variable names and their initial values */
+/* asterisk marks SPECIAL vars; $ is just no-named Field0 */
+enum {
+ CONVFMT, OFMT, FS, OFS,
+ ORS, RS, RT, FILENAME,
+ SUBSEP, ARGIND, ARGC, ARGV,
+ ERRNO, FNR,
+ NR, NF, IGNORECASE,
+ ENVIRON, F0, NUM_INTERNAL_VARS
+};
+
+static const char vNames[] ALIGN1 =
+ "CONVFMT\0" "OFMT\0" "FS\0*" "OFS\0"
+ "ORS\0" "RS\0*" "RT\0" "FILENAME\0"
+ "SUBSEP\0" "ARGIND\0" "ARGC\0" "ARGV\0"
+ "ERRNO\0" "FNR\0"
+ "NR\0" "NF\0*" "IGNORECASE\0*"
+ "ENVIRON\0" "$\0*" "\0";
+
+static const char vValues[] ALIGN1 =
+ "%.6g\0" "%.6g\0" " \0" " \0"
+ "\n\0" "\n\0" "\0" "\0"
+ "\034\0"
+ "\377";
+
+/* hash size may grow to these values */
+#define FIRST_PRIME 61
+static const uint16_t PRIMES[] ALIGN2 = { 251, 1021, 4093, 16381, 65521 };
+
+
+/* Globals. Split in two parts so that first one is addressed
+ * with (mostly short) negative offsets */
+struct globals {
+ chain beginseq, mainseq, endseq;
+ chain *seq;
+ node *break_ptr, *continue_ptr;
+ rstream *iF;
+ xhash *vhash, *ahash, *fdhash, *fnhash;
+ const char *g_progname;
+ int g_lineno;
+ int nfields;
+ int maxfields; /* used in fsrealloc() only */
+ var *Fields;
+ nvblock *g_cb;
+ char *g_pos;
+ char *g_buf;
+ smallint icase;
+ smallint exiting;
+ smallint nextrec;
+ smallint nextfile;
+ smallint is_f0_split;
+};
+struct globals2 {
+ uint32_t t_info; /* often used */
+ uint32_t t_tclass;
+ char *t_string;
+ int t_lineno;
+ int t_rollback;
+
+ var *intvar[NUM_INTERNAL_VARS]; /* often used */
+
+ /* former statics from various functions */
+ char *split_f0__fstrings;
+
+ uint32_t next_token__save_tclass;
+ uint32_t next_token__save_info;
+ uint32_t next_token__ltclass;
+ smallint next_token__concat_inserted;
+
+ smallint next_input_file__files_happen;
+ rstream next_input_file__rsm;
+
+ var *evaluate__fnargs;
+ unsigned evaluate__seed;
+ regex_t evaluate__sreg;
+
+ var ptest__v;
+
+ tsplitter exec_builtin__tspl;
+
+ /* biggest and least used members go last */
+ double t_double;
+ tsplitter fsplitter, rsplitter;
+};
+#define G1 (ptr_to_globals[-1])
+#define G (*(struct globals2 *)ptr_to_globals)
+/* For debug. nm --size-sort awk.o | grep -vi ' [tr] ' */
+/* char G1size[sizeof(G1)]; - 0x6c */
+/* char Gsize[sizeof(G)]; - 0x1cc */
+/* Trying to keep most of members accessible with short offsets: */
+/* char Gofs_seed[offsetof(struct globals2, evaluate__seed)]; - 0x90 */
+#define beginseq (G1.beginseq )
+#define mainseq (G1.mainseq )
+#define endseq (G1.endseq )
+#define seq (G1.seq )
+#define break_ptr (G1.break_ptr )
+#define continue_ptr (G1.continue_ptr)
+#define iF (G1.iF )
+#define vhash (G1.vhash )
+#define ahash (G1.ahash )
+#define fdhash (G1.fdhash )
+#define fnhash (G1.fnhash )
+#define g_progname (G1.g_progname )
+#define g_lineno (G1.g_lineno )
+#define nfields (G1.nfields )
+#define maxfields (G1.maxfields )
+#define Fields (G1.Fields )
+#define g_cb (G1.g_cb )
+#define g_pos (G1.g_pos )
+#define g_buf (G1.g_buf )
+#define icase (G1.icase )
+#define exiting (G1.exiting )
+#define nextrec (G1.nextrec )
+#define nextfile (G1.nextfile )
+#define is_f0_split (G1.is_f0_split )
+#define t_info (G.t_info )
+#define t_tclass (G.t_tclass )
+#define t_string (G.t_string )
+#define t_double (G.t_double )
+#define t_lineno (G.t_lineno )
+#define t_rollback (G.t_rollback )
+#define intvar (G.intvar )
+#define fsplitter (G.fsplitter )
+#define rsplitter (G.rsplitter )
+#define INIT_G() do { \
+ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G1) + sizeof(G)) + sizeof(G1)); \
+ G.next_token__ltclass = TC_OPTERM; \
+ G.evaluate__seed = 1; \
+} while (0)
+
+
+/* function prototypes */
+static void handle_special(var *);
+static node *parse_expr(uint32_t);
+static void chain_group(void);
+static var *evaluate(node *, var *);
+static rstream *next_input_file(void);
+static int fmt_num(char *, int, const char *, double, int);
+static int awk_exit(int) ATTRIBUTE_NORETURN;
+
+/* ---- error handling ---- */
+
+static const char EMSG_INTERNAL_ERROR[] ALIGN1 = "Internal error";
+static const char EMSG_UNEXP_EOS[] ALIGN1 = "Unexpected end of string";
+static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token";
+static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero";
+static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier";
+static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin";
+static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array";
+static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error";
+static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function";
+#if !ENABLE_FEATURE_AWK_MATH
+static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in";
+#endif
+
+static void zero_out_var(var * vp)
+{
+ memset(vp, 0, sizeof(*vp));
+}
+
+static void syntax_error(const char *const message) ATTRIBUTE_NORETURN;
+static void syntax_error(const char *const message)
+{
+ bb_error_msg_and_die("%s:%i: %s", g_progname, g_lineno, message);
+}
+
+/* ---- hash stuff ---- */
+
+static unsigned hashidx(const char *name)
+{
+ unsigned idx = 0;
+
+ while (*name) idx = *name++ + (idx << 6) - idx;
+ return idx;
+}
+
+/* create new hash */
+static xhash *hash_init(void)
+{
+ xhash *newhash;
+
+ newhash = xzalloc(sizeof(xhash));
+ newhash->csize = FIRST_PRIME;
+ newhash->items = xzalloc(newhash->csize * sizeof(hash_item *));
+
+ return newhash;
+}
+
+/* find item in hash, return ptr to data, NULL if not found */
+static void *hash_search(xhash *hash, const char *name)
+{
+ hash_item *hi;
+
+ hi = hash->items [ hashidx(name) % hash->csize ];
+ while (hi) {
+ if (strcmp(hi->name, name) == 0)
+ return &(hi->data);
+ hi = hi->next;
+ }
+ return NULL;
+}
+
+/* grow hash if it becomes too big */
+static void hash_rebuild(xhash *hash)
+{
+ unsigned newsize, i, idx;
+ hash_item **newitems, *hi, *thi;
+
+ if (hash->nprime == ARRAY_SIZE(PRIMES))
+ return;
+
+ newsize = PRIMES[hash->nprime++];
+ newitems = xzalloc(newsize * sizeof(hash_item *));
+
+ for (i = 0; i < hash->csize; i++) {
+ hi = hash->items[i];
+ while (hi) {
+ thi = hi;
+ hi = thi->next;
+ idx = hashidx(thi->name) % newsize;
+ thi->next = newitems[idx];
+ newitems[idx] = thi;
+ }
+ }
+
+ free(hash->items);
+ hash->csize = newsize;
+ hash->items = newitems;
+}
+
+/* find item in hash, add it if necessary. Return ptr to data */
+static void *hash_find(xhash *hash, const char *name)
+{
+ hash_item *hi;
+ unsigned idx;
+ int l;
+
+ hi = hash_search(hash, name);
+ if (!hi) {
+ if (++hash->nel / hash->csize > 10)
+ hash_rebuild(hash);
+
+ l = strlen(name) + 1;
+ hi = xzalloc(sizeof(hash_item) + l);
+ memcpy(hi->name, name, l);
+
+ idx = hashidx(name) % hash->csize;
+ hi->next = hash->items[idx];
+ hash->items[idx] = hi;
+ hash->glen += l;
+ }
+ return &(hi->data);
+}
+
+#define findvar(hash, name) ((var*) hash_find((hash), (name)))
+#define newvar(name) ((var*) hash_find(vhash, (name)))
+#define newfile(name) ((rstream*)hash_find(fdhash, (name)))
+#define newfunc(name) ((func*) hash_find(fnhash, (name)))
+
+static void hash_remove(xhash *hash, const char *name)
+{
+ hash_item *hi, **phi;
+
+ phi = &(hash->items[hashidx(name) % hash->csize]);
+ while (*phi) {
+ hi = *phi;
+ if (strcmp(hi->name, name) == 0) {
+ hash->glen -= (strlen(name) + 1);
+ hash->nel--;
+ *phi = hi->next;
+ free(hi);
+ break;
+ }
+ phi = &(hi->next);
+ }
+}
+
+/* ------ some useful functions ------ */
+
+static void skip_spaces(char **s)
+{
+ char *p = *s;
+
+ while (1) {
+ if (*p == '\\' && p[1] == '\n') {
+ p++;
+ t_lineno++;
+ } else if (*p != ' ' && *p != '\t') {
+ break;
+ }
+ p++;
+ }
+ *s = p;
+}
+
+static char *nextword(char **s)
+{
+ char *p = *s;
+
+ while (*(*s)++) /* */;
+
+ return p;
+}
+
+static char nextchar(char **s)
+{
+ char c, *pps;
+
+ c = *((*s)++);
+ pps = *s;
+ if (c == '\\') c = bb_process_escape_sequence((const char**)s);
+ if (c == '\\' && *s == pps) c = *((*s)++);
+ return c;
+}
+
+static ALWAYS_INLINE int isalnum_(int c)
+{
+ return (isalnum(c) || c == '_');
+}
+
+/* -------- working with variables (set/get/copy/etc) -------- */
+
+static xhash *iamarray(var *v)
+{
+ var *a = v;
+
+ while (a->type & VF_CHILD)
+ a = a->x.parent;
+
+ if (!(a->type & VF_ARRAY)) {
+ a->type |= VF_ARRAY;
+ a->x.array = hash_init();
+ }
+ return a->x.array;
+}
+
+static void clear_array(xhash *array)
+{
+ unsigned i;
+ hash_item *hi, *thi;
+
+ for (i = 0; i < array->csize; i++) {
+ hi = array->items[i];
+ while (hi) {
+ thi = hi;
+ hi = hi->next;
+ free(thi->data.v.string);
+ free(thi);
+ }
+ array->items[i] = NULL;
+ }
+ array->glen = array->nel = 0;
+}
+
+/* clear a variable */
+static var *clrvar(var *v)
+{
+ if (!(v->type & VF_FSTR))
+ free(v->string);
+
+ v->type &= VF_DONTTOUCH;
+ v->type |= VF_DIRTY;
+ v->string = NULL;
+ return v;
+}
+
+/* assign string value to variable */
+static var *setvar_p(var *v, char *value)
+{
+ clrvar(v);
+ v->string = value;
+ handle_special(v);
+ return v;
+}
+
+/* same as setvar_p but make a copy of string */
+static var *setvar_s(var *v, const char *value)
+{
+ return setvar_p(v, (value && *value) ? xstrdup(value) : NULL);
+}
+
+/* same as setvar_s but set USER flag */
+static var *setvar_u(var *v, const char *value)
+{
+ setvar_s(v, value);
+ v->type |= VF_USER;
+ return v;
+}
+
+/* set array element to user string */
+static void setari_u(var *a, int idx, const char *s)
+{
+ char sidx[sizeof(int)*3 + 1];
+ var *v;
+
+ sprintf(sidx, "%d", idx);
+ v = findvar(iamarray(a), sidx);
+ setvar_u(v, s);
+}
+
+/* assign numeric value to variable */
+static var *setvar_i(var *v, double value)
+{
+ clrvar(v);
+ v->type |= VF_NUMBER;
+ v->number = value;
+ handle_special(v);
+ return v;
+}
+
+static const char *getvar_s(var *v)
+{
+ /* if v is numeric and has no cached string, convert it to string */
+ if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) {
+ fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[CONVFMT]), v->number, TRUE);
+ v->string = xstrdup(g_buf);
+ v->type |= VF_CACHED;
+ }
+ return (v->string == NULL) ? "" : v->string;
+}
+
+static double getvar_i(var *v)
+{
+ char *s;
+
+ if ((v->type & (VF_NUMBER | VF_CACHED)) == 0) {
+ v->number = 0;
+ s = v->string;
+ if (s && *s) {
+ v->number = strtod(s, &s);
+ if (v->type & VF_USER) {
+ skip_spaces(&s);
+ if (*s != '\0')
+ v->type &= ~VF_USER;
+ }
+ } else {
+ v->type &= ~VF_USER;
+ }
+ v->type |= VF_CACHED;
+ }
+ return v->number;
+}
+
+static var *copyvar(var *dest, const var *src)
+{
+ if (dest != src) {
+ clrvar(dest);
+ dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR));
+ dest->number = src->number;
+ if (src->string)
+ dest->string = xstrdup(src->string);
+ }
+ handle_special(dest);
+ return dest;
+}
+
+static var *incvar(var *v)
+{
+ return setvar_i(v, getvar_i(v) + 1.);
+}
+
+/* return true if v is number or numeric string */
+static int is_numeric(var *v)
+{
+ getvar_i(v);
+ return ((v->type ^ VF_DIRTY) & (VF_NUMBER | VF_USER | VF_DIRTY));
+}
+
+/* return 1 when value of v corresponds to true, 0 otherwise */
+static int istrue(var *v)
+{
+ if (is_numeric(v))
+ return (v->number == 0) ? 0 : 1;
+ return (v->string && *(v->string)) ? 1 : 0;
+}
+
+/* temporary variables allocator. Last allocated should be first freed */
+static var *nvalloc(int n)
+{
+ nvblock *pb = NULL;
+ var *v, *r;
+ int size;
+
+ while (g_cb) {
+ pb = g_cb;
+ if ((g_cb->pos - g_cb->nv) + n <= g_cb->size) break;
+ g_cb = g_cb->next;
+ }
+
+ if (!g_cb) {
+ size = (n <= MINNVBLOCK) ? MINNVBLOCK : n;
+ g_cb = xmalloc(sizeof(nvblock) + size * sizeof(var));
+ g_cb->size = size;
+ g_cb->pos = g_cb->nv;
+ g_cb->prev = pb;
+ g_cb->next = NULL;
+ if (pb) pb->next = g_cb;
+ }
+
+ v = r = g_cb->pos;
+ g_cb->pos += n;
+
+ while (v < g_cb->pos) {
+ v->type = 0;
+ v->string = NULL;
+ v++;
+ }
+
+ return r;
+}
+
+static void nvfree(var *v)
+{
+ var *p;
+
+ if (v < g_cb->nv || v >= g_cb->pos)
+ syntax_error(EMSG_INTERNAL_ERROR);
+
+ for (p = v; p < g_cb->pos; p++) {
+ if ((p->type & (VF_ARRAY | VF_CHILD)) == VF_ARRAY) {
+ clear_array(iamarray(p));
+ free(p->x.array->items);
+ free(p->x.array);
+ }
+ if (p->type & VF_WALK)
+ free(p->x.walker);
+
+ clrvar(p);
+ }
+
+ g_cb->pos = v;
+ while (g_cb->prev && g_cb->pos == g_cb->nv) {
+ g_cb = g_cb->prev;
+ }
+}
+
+/* ------- awk program text parsing ------- */
+
+/* Parse next token pointed by global pos, place results into global ttt.
+ * If token isn't expected, give away. Return token class
+ */
+static uint32_t next_token(uint32_t expected)
+{
+#define concat_inserted (G.next_token__concat_inserted)
+#define save_tclass (G.next_token__save_tclass)
+#define save_info (G.next_token__save_info)
+/* Initialized to TC_OPTERM: */
+#define ltclass (G.next_token__ltclass)
+
+ char *p, *pp, *s;
+ const char *tl;
+ uint32_t tc;
+ const uint32_t *ti;
+ int l;
+
+ if (t_rollback) {
+ t_rollback = FALSE;
+
+ } else if (concat_inserted) {
+ concat_inserted = FALSE;
+ t_tclass = save_tclass;
+ t_info = save_info;
+
+ } else {
+ p = g_pos;
+ readnext:
+ skip_spaces(&p);
+ g_lineno = t_lineno;
+ if (*p == '#')
+ while (*p != '\n' && *p != '\0')
+ p++;
+
+ if (*p == '\n')
+ t_lineno++;
+
+ if (*p == '\0') {
+ tc = TC_EOF;
+
+ } else if (*p == '\"') {
+ /* it's a string */
+ t_string = s = ++p;
+ while (*p != '\"') {
+ if (*p == '\0' || *p == '\n')
+ syntax_error(EMSG_UNEXP_EOS);
+ *(s++) = nextchar(&p);
+ }
+ p++;
+ *s = '\0';
+ tc = TC_STRING;
+
+ } else if ((expected & TC_REGEXP) && *p == '/') {
+ /* it's regexp */
+ t_string = s = ++p;
+ while (*p != '/') {
+ if (*p == '\0' || *p == '\n')
+ syntax_error(EMSG_UNEXP_EOS);
+ *s = *p++;
+ if (*s++ == '\\') {
+ pp = p;
+ *(s-1) = bb_process_escape_sequence((const char **)&p);
+ if (*pp == '\\')
+ *s++ = '\\';
+ if (p == pp)
+ *s++ = *p++;
+ }
+ }
+ p++;
+ *s = '\0';
+ tc = TC_REGEXP;
+
+ } else if (*p == '.' || isdigit(*p)) {
+ /* it's a number */
+ t_double = strtod(p, &p);
+ if (*p == '.')
+ syntax_error(EMSG_UNEXP_TOKEN);
+ tc = TC_NUMBER;
+
+ } else {
+ /* search for something known */
+ tl = tokenlist;
+ tc = 0x00000001;
+ ti = tokeninfo;
+ while (*tl) {
+ l = *(tl++);
+ if (l == NTCC) {
+ tc <<= 1;
+ continue;
+ }
+ /* if token class is expected, token
+ * matches and it's not a longer word,
+ * then this is what we are looking for
+ */
+ if ((tc & (expected | TC_WORD | TC_NEWLINE))
+ && *tl == *p && strncmp(p, tl, l) == 0
+ && !((tc & TC_WORD) && isalnum_(p[l]))
+ ) {
+ t_info = *ti;
+ p += l;
+ break;
+ }
+ ti++;
+ tl += l;
+ }
+
+ if (!*tl) {
+ /* it's a name (var/array/function),
+ * otherwise it's something wrong
+ */
+ if (!isalnum_(*p))
+ syntax_error(EMSG_UNEXP_TOKEN);
+
+ t_string = --p;
+ while (isalnum_(*(++p))) {
+ *(p-1) = *p;
+ }
+ *(p-1) = '\0';
+ tc = TC_VARIABLE;
+ /* also consume whitespace between functionname and bracket */
+ if (!(expected & TC_VARIABLE))
+ skip_spaces(&p);
+ if (*p == '(') {
+ tc = TC_FUNCTION;
+ } else {
+ if (*p == '[') {
+ p++;
+ tc = TC_ARRAY;
+ }
+ }
+ }
+ }
+ g_pos = p;
+
+ /* skipping newlines in some cases */
+ if ((ltclass & TC_NOTERM) && (tc & TC_NEWLINE))
+ goto readnext;
+
+ /* insert concatenation operator when needed */
+ if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)) {
+ concat_inserted = TRUE;
+ save_tclass = tc;
+ save_info = t_info;
+ tc = TC_BINOP;
+ t_info = OC_CONCAT | SS | P(35);
+ }
+
+ t_tclass = tc;
+ }
+ ltclass = t_tclass;
+
+ /* Are we ready for this? */
+ if (!(ltclass & expected))
+ syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ?
+ EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN);
+
+ return ltclass;
+#undef concat_inserted
+#undef save_tclass
+#undef save_info
+#undef ltclass
+}
+
+static void rollback_token(void)
+{
+ t_rollback = TRUE;
+}
+
+static node *new_node(uint32_t info)
+{
+ node *n;
+
+ n = xzalloc(sizeof(node));
+ n->info = info;
+ n->lineno = g_lineno;
+ return n;
+}
+
+static node *mk_re_node(const char *s, node *n, regex_t *re)
+{
+ n->info = OC_REGEXP;
+ n->l.re = re;
+ n->r.ire = re + 1;
+ xregcomp(re, s, REG_EXTENDED);
+ xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE);
+
+ return n;
+}
+
+static node *condition(void)
+{
+ next_token(TC_SEQSTART);
+ return parse_expr(TC_SEQTERM);
+}
+
+/* parse expression terminated by given argument, return ptr
+ * to built subtree. Terminator is eaten by parse_expr */
+static node *parse_expr(uint32_t iexp)
+{
+ node sn;
+ node *cn = &sn;
+ node *vn, *glptr;
+ uint32_t tc, xtc;
+ var *v;
+
+ sn.info = PRIMASK;
+ sn.r.n = glptr = NULL;
+ xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
+
+ while (!((tc = next_token(xtc)) & iexp)) {
+ if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) {
+ /* input redirection (<) attached to glptr node */
+ cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37));
+ cn->a.n = glptr;
+ xtc = TC_OPERAND | TC_UOPPRE;
+ glptr = NULL;
+
+ } else if (tc & (TC_BINOP | TC_UOPPOST)) {
+ /* for binary and postfix-unary operators, jump back over
+ * previous operators with higher priority */
+ vn = cn;
+ while ( ((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2))
+ || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON)) )
+ vn = vn->a.n;
+ if ((t_info & OPCLSMASK) == OC_TERNARY)
+ t_info += P(6);
+ cn = vn->a.n->r.n = new_node(t_info);
+ cn->a.n = vn->a.n;
+ if (tc & TC_BINOP) {
+ cn->l.n = vn;
+ xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
+ if ((t_info & OPCLSMASK) == OC_PGETLINE) {
+ /* it's a pipe */
+ next_token(TC_GETLINE);
+ /* give maximum priority to this pipe */
+ cn->info &= ~PRIMASK;
+ xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
+ }
+ } else {
+ cn->r.n = vn;
+ xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
+ }
+ vn->a.n = cn;
+
+ } else {
+ /* for operands and prefix-unary operators, attach them
+ * to last node */
+ vn = cn;
+ cn = vn->r.n = new_node(t_info);
+ cn->a.n = vn;
+ xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
+ if (tc & (TC_OPERAND | TC_REGEXP)) {
+ xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp;
+ /* one should be very careful with switch on tclass -
+ * only simple tclasses should be used! */
+ switch (tc) {
+ case TC_VARIABLE:
+ case TC_ARRAY:
+ cn->info = OC_VAR;
+ v = hash_search(ahash, t_string);
+ if (v != NULL) {
+ cn->info = OC_FNARG;
+ cn->l.i = v->x.aidx;
+ } else {
+ cn->l.v = newvar(t_string);
+ }
+ if (tc & TC_ARRAY) {
+ cn->info |= xS;
+ cn->r.n = parse_expr(TC_ARRTERM);
+ }
+ break;
+
+ case TC_NUMBER:
+ case TC_STRING:
+ cn->info = OC_VAR;
+ v = cn->l.v = xzalloc(sizeof(var));
+ if (tc & TC_NUMBER)
+ setvar_i(v, t_double);
+ else
+ setvar_s(v, t_string);
+ break;
+
+ case TC_REGEXP:
+ mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2));
+ break;
+
+ case TC_FUNCTION:
+ cn->info = OC_FUNC;
+ cn->r.f = newfunc(t_string);
+ cn->l.n = condition();
+ break;
+
+ case TC_SEQSTART:
+ cn = vn->r.n = parse_expr(TC_SEQTERM);
+ cn->a.n = vn;
+ break;
+
+ case TC_GETLINE:
+ glptr = cn;
+ xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
+ break;
+
+ case TC_BUILTIN:
+ cn->l.n = condition();
+ break;
+ }
+ }
+ }
+ }
+ return sn.r.n;
+}
+
+/* add node to chain. Return ptr to alloc'd node */
+static node *chain_node(uint32_t info)
+{
+ node *n;
+
+ if (!seq->first)
+ seq->first = seq->last = new_node(0);
+
+ if (seq->programname != g_progname) {
+ seq->programname = g_progname;
+ n = chain_node(OC_NEWSOURCE);
+ n->l.s = xstrdup(g_progname);
+ }
+
+ n = seq->last;
+ n->info = info;
+ seq->last = n->a.n = new_node(OC_DONE);
+
+ return n;
+}
+
+static void chain_expr(uint32_t info)
+{
+ node *n;
+
+ n = chain_node(info);
+ n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM);
+ if (t_tclass & TC_GRPTERM)
+ rollback_token();
+}
+
+static node *chain_loop(node *nn)
+{
+ node *n, *n2, *save_brk, *save_cont;
+
+ save_brk = break_ptr;
+ save_cont = continue_ptr;
+
+ n = chain_node(OC_BR | Vx);
+ continue_ptr = new_node(OC_EXEC);
+ break_ptr = new_node(OC_EXEC);
+ chain_group();
+ n2 = chain_node(OC_EXEC | Vx);
+ n2->l.n = nn;
+ n2->a.n = n;
+ continue_ptr->a.n = n2;
+ break_ptr->a.n = n->r.n = seq->last;
+
+ continue_ptr = save_cont;
+ break_ptr = save_brk;
+
+ return n;
+}
+
+/* parse group and attach it to chain */
+static void chain_group(void)
+{
+ uint32_t c;
+ node *n, *n2, *n3;
+
+ do {
+ c = next_token(TC_GRPSEQ);
+ } while (c & TC_NEWLINE);
+
+ if (c & TC_GRPSTART) {
+ while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
+ if (t_tclass & TC_NEWLINE) continue;
+ rollback_token();
+ chain_group();
+ }
+ } else if (c & (TC_OPSEQ | TC_OPTERM)) {
+ rollback_token();
+ chain_expr(OC_EXEC | Vx);
+ } else { /* TC_STATEMNT */
+ switch (t_info & OPCLSMASK) {
+ case ST_IF:
+ n = chain_node(OC_BR | Vx);
+ n->l.n = condition();
+ chain_group();
+ n2 = chain_node(OC_EXEC);
+ n->r.n = seq->last;
+ if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE) == TC_ELSE) {
+ chain_group();
+ n2->a.n = seq->last;
+ } else {
+ rollback_token();
+ }
+ break;
+
+ case ST_WHILE:
+ n2 = condition();
+ n = chain_loop(NULL);
+ n->l.n = n2;
+ break;
+
+ case ST_DO:
+ n2 = chain_node(OC_EXEC);
+ n = chain_loop(NULL);
+ n2->a.n = n->a.n;
+ next_token(TC_WHILE);
+ n->l.n = condition();
+ break;
+
+ case ST_FOR:
+ next_token(TC_SEQSTART);
+ n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
+ if (t_tclass & TC_SEQTERM) { /* for-in */
+ if ((n2->info & OPCLSMASK) != OC_IN)
+ syntax_error(EMSG_UNEXP_TOKEN);
+ n = chain_node(OC_WALKINIT | VV);
+ n->l.n = n2->l.n;
+ n->r.n = n2->r.n;
+ n = chain_loop(NULL);
+ n->info = OC_WALKNEXT | Vx;
+ n->l.n = n2->l.n;
+ } else { /* for (;;) */
+ n = chain_node(OC_EXEC | Vx);
+ n->l.n = n2;
+ n2 = parse_expr(TC_SEMICOL);
+ n3 = parse_expr(TC_SEQTERM);
+ n = chain_loop(n3);
+ n->l.n = n2;
+ if (!n2)
+ n->info = OC_EXEC;
+ }
+ break;
+
+ case OC_PRINT:
+ case OC_PRINTF:
+ n = chain_node(t_info);
+ n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
+ if (t_tclass & TC_OUTRDR) {
+ n->info |= t_info;
+ n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM);
+ }
+ if (t_tclass & TC_GRPTERM)
+ rollback_token();
+ break;
+
+ case OC_BREAK:
+ n = chain_node(OC_EXEC);
+ n->a.n = break_ptr;
+ break;
+
+ case OC_CONTINUE:
+ n = chain_node(OC_EXEC);
+ n->a.n = continue_ptr;
+ break;
+
+ /* delete, next, nextfile, return, exit */
+ default:
+ chain_expr(t_info);
+ }
+ }
+}
+
+static void parse_program(char *p)
+{
+ uint32_t tclass;
+ node *cn;
+ func *f;
+ var *v;
+
+ g_pos = p;
+ t_lineno = 1;
+ while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
+ TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
+
+ if (tclass & TC_OPTERM)
+ continue;
+
+ seq = &mainseq;
+ if (tclass & TC_BEGIN) {
+ seq = &beginseq;
+ chain_group();
+
+ } else if (tclass & TC_END) {
+ seq = &endseq;
+ chain_group();
+
+ } else if (tclass & TC_FUNCDECL) {
+ next_token(TC_FUNCTION);
+ g_pos++;
+ f = newfunc(t_string);
+ f->body.first = NULL;
+ f->nargs = 0;
+ while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
+ v = findvar(ahash, t_string);
+ v->x.aidx = (f->nargs)++;
+
+ if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
+ break;
+ }
+ seq = &(f->body);
+ chain_group();
+ clear_array(ahash);
+
+ } else if (tclass & TC_OPSEQ) {
+ rollback_token();
+ cn = chain_node(OC_TEST);
+ cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
+ if (t_tclass & TC_GRPSTART) {
+ rollback_token();
+ chain_group();
+ } else {
+ chain_node(OC_PRINT);
+ }
+ cn->r.n = mainseq.last;
+
+ } else /* if (tclass & TC_GRPSTART) */ {
+ rollback_token();
+ chain_group();
+ }
+ }
+}
+
+
+/* -------- program execution part -------- */
+
+static node *mk_splitter(const char *s, tsplitter *spl)
+{
+ regex_t *re, *ire;
+ node *n;
+
+ re = &spl->re[0];
+ ire = &spl->re[1];
+ n = &spl->n;
+ if ((n->info & OPCLSMASK) == OC_REGEXP) {
+ regfree(re);
+ regfree(ire); // TODO: nuke ire, use re+1?
+ }
+ if (strlen(s) > 1) {
+ mk_re_node(s, n, re);
+ } else {
+ n->info = (uint32_t) *s;
+ }
+
+ return n;
+}
+
+/* use node as a regular expression. Supplied with node ptr and regex_t
+ * storage space. Return ptr to regex (if result points to preg, it should
+ * be later regfree'd manually
+ */
+static regex_t *as_regex(node *op, regex_t *preg)
+{
+ var *v;
+ const char *s;
+
+ if ((op->info & OPCLSMASK) == OC_REGEXP) {
+ return icase ? op->r.ire : op->l.re;
+ }
+ v = nvalloc(1);
+ s = getvar_s(evaluate(op, v));
+ xregcomp(preg, s, icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED);
+ nvfree(v);
+ return preg;
+}
+
+/* gradually increasing buffer */
+static void qrealloc(char **b, int n, int *size)
+{
+ if (!*b || n >= *size)
+ *b = xrealloc(*b, *size = n + (n>>1) + 80);
+}
+
+/* resize field storage space */
+static void fsrealloc(int size)
+{
+ int i;
+
+ if (size >= maxfields) {
+ i = maxfields;
+ maxfields = size + 16;
+ Fields = xrealloc(Fields, maxfields * sizeof(var));
+ for (; i < maxfields; i++) {
+ Fields[i].type = VF_SPECIAL;
+ Fields[i].string = NULL;
+ }
+ }
+
+ if (size < nfields) {
+ for (i = size; i < nfields; i++) {
+ clrvar(Fields + i);
+ }
+ }
+ nfields = size;
+}
+
+static int awk_split(const char *s, node *spl, char **slist)
+{
+ int l, n = 0;
+ char c[4];
+ char *s1;
+ regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough...
+
+ /* in worst case, each char would be a separate field */
+ *slist = s1 = xzalloc(strlen(s) * 2 + 3);
+ strcpy(s1, s);
+
+ c[0] = c[1] = (char)spl->info;
+ c[2] = c[3] = '\0';
+ if (*getvar_s(intvar[RS]) == '\0')
+ c[2] = '\n';
+
+ if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */
+ if (!*s)
+ return n; /* "": zero fields */
+ n++; /* at least one field will be there */
+ do {
+ l = strcspn(s, c+2); /* len till next NUL or \n */
+ if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0
+ && pmatch[0].rm_so <= l
+ ) {
+ l = pmatch[0].rm_so;
+ if (pmatch[0].rm_eo == 0) {
+ l++;
+ pmatch[0].rm_eo++;
+ }
+ n++; /* we saw yet another delimiter */
+ } else {
+ pmatch[0].rm_eo = l;
+ if (s[l]) pmatch[0].rm_eo++;
+ }
+ memcpy(s1, s, l);
+ s1[l] = '\0';
+ nextword(&s1);
+ s += pmatch[0].rm_eo;
+ } while (*s);
+ return n;
+ }
+ if (c[0] == '\0') { /* null split */
+ while (*s) {
+ *s1++ = *s++;
+ *s1++ = '\0';
+ n++;
+ }
+ return n;
+ }
+ if (c[0] != ' ') { /* single-character split */
+ if (icase) {
+ c[0] = toupper(c[0]);
+ c[1] = tolower(c[1]);
+ }
+ if (*s1) n++;
+ while ((s1 = strpbrk(s1, c))) {
+ *s1++ = '\0';
+ n++;
+ }
+ return n;
+ }
+ /* space split */
+ while (*s) {
+ s = skip_whitespace(s);
+ if (!*s) break;
+ n++;
+ while (*s && !isspace(*s))
+ *s1++ = *s++;
+ *s1++ = '\0';
+ }
+ return n;
+}
+
+static void split_f0(void)
+{
+/* static char *fstrings; */
+#define fstrings (G.split_f0__fstrings)
+
+ int i, n;
+ char *s;
+
+ if (is_f0_split)
+ return;
+
+ is_f0_split = TRUE;
+ free(fstrings);
+ fsrealloc(0);
+ n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings);
+ fsrealloc(n);
+ s = fstrings;
+ for (i = 0; i < n; i++) {
+ Fields[i].string = nextword(&s);
+ Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY);
+ }
+
+ /* set NF manually to avoid side effects */
+ clrvar(intvar[NF]);
+ intvar[NF]->type = VF_NUMBER | VF_SPECIAL;
+ intvar[NF]->number = nfields;
+#undef fstrings
+}
+
+/* perform additional actions when some internal variables changed */
+static void handle_special(var *v)
+{
+ int n;
+ char *b;
+ const char *sep, *s;
+ int sl, l, len, i, bsize;
+
+ if (!(v->type & VF_SPECIAL))
+ return;
+
+ if (v == intvar[NF]) {
+ n = (int)getvar_i(v);
+ fsrealloc(n);
+
+ /* recalculate $0 */
+ sep = getvar_s(intvar[OFS]);
+ sl = strlen(sep);
+ b = NULL;
+ len = 0;
+ for (i = 0; i < n; i++) {
+ s = getvar_s(&Fields[i]);
+ l = strlen(s);
+ if (b) {
+ memcpy(b+len, sep, sl);
+ len += sl;
+ }
+ qrealloc(&b, len+l+sl, &bsize);
+ memcpy(b+len, s, l);
+ len += l;
+ }
+ if (b)
+ b[len] = '\0';
+ setvar_p(intvar[F0], b);
+ is_f0_split = TRUE;
+
+ } else if (v == intvar[F0]) {
+ is_f0_split = FALSE;
+
+ } else if (v == intvar[FS]) {
+ mk_splitter(getvar_s(v), &fsplitter);
+
+ } else if (v == intvar[RS]) {
+ mk_splitter(getvar_s(v), &rsplitter);
+
+ } else if (v == intvar[IGNORECASE]) {
+ icase = istrue(v);
+
+ } else { /* $n */
+ n = getvar_i(intvar[NF]);
+ setvar_i(intvar[NF], n > v-Fields ? n : v-Fields+1);
+ /* right here v is invalid. Just to note... */
+ }
+}
+
+/* step through func/builtin/etc arguments */
+static node *nextarg(node **pn)
+{
+ node *n;
+
+ n = *pn;
+ if (n && (n->info & OPCLSMASK) == OC_COMMA) {
+ *pn = n->r.n;
+ n = n->l.n;
+ } else {
+ *pn = NULL;
+ }
+ return n;
+}
+
+static void hashwalk_init(var *v, xhash *array)
+{
+ char **w;
+ hash_item *hi;
+ unsigned i;
+
+ if (v->type & VF_WALK)
+ free(v->x.walker);
+
+ v->type |= VF_WALK;
+ w = v->x.walker = xzalloc(2 + 2*sizeof(char *) + array->glen);
+ w[0] = w[1] = (char *)(w + 2);
+ for (i = 0; i < array->csize; i++) {
+ hi = array->items[i];
+ while (hi) {
+ strcpy(*w, hi->name);
+ nextword(w);
+ hi = hi->next;
+ }
+ }
+}
+
+static int hashwalk_next(var *v)
+{
+ char **w;
+
+ w = v->x.walker;
+ if (w[1] == w[0])
+ return FALSE;
+
+ setvar_s(v, nextword(w+1));
+ return TRUE;
+}
+
+/* evaluate node, return 1 when result is true, 0 otherwise */
+static int ptest(node *pattern)
+{
+ /* ptest__v is "static": to save stack space? */
+ return istrue(evaluate(pattern, &G.ptest__v));
+}
+
+/* read next record from stream rsm into a variable v */
+static int awk_getline(rstream *rsm, var *v)
+{
+ char *b;
+ regmatch_t pmatch[2];
+ int a, p, pp=0, size;
+ int fd, so, eo, r, rp;
+ char c, *m, *s;
+
+ /* we're using our own buffer since we need access to accumulating
+ * characters
+ */
+ fd = fileno(rsm->F);
+ m = rsm->buffer;
+ a = rsm->adv;
+ p = rsm->pos;
+ size = rsm->size;
+ c = (char) rsplitter.n.info;
+ rp = 0;
+
+ if (!m) qrealloc(&m, 256, &size);
+ do {
+ b = m + a;
+ so = eo = p;
+ r = 1;
+ if (p > 0) {
+ if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) {
+ if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re,
+ b, 1, pmatch, 0) == 0) {
+ so = pmatch[0].rm_so;
+ eo = pmatch[0].rm_eo;
+ if (b[eo] != '\0')
+ break;
+ }
+ } else if (c != '\0') {
+ s = strchr(b+pp, c);
+ if (!s) s = memchr(b+pp, '\0', p - pp);
+ if (s) {
+ so = eo = s-b;
+ eo++;
+ break;
+ }
+ } else {
+ while (b[rp] == '\n')
+ rp++;
+ s = strstr(b+rp, "\n\n");
+ if (s) {
+ so = eo = s-b;
+ while (b[eo] == '\n') eo++;
+ if (b[eo] != '\0')
+ break;
+ }
+ }
+ }
+
+ if (a > 0) {
+ memmove(m, (const void *)(m+a), p+1);
+ b = m;
+ a = 0;
+ }
+
+ qrealloc(&m, a+p+128, &size);
+ b = m + a;
+ pp = p;
+ p += safe_read(fd, b+p, size-p-1);
+ if (p < pp) {
+ p = 0;
+ r = 0;
+ setvar_i(intvar[ERRNO], errno);
+ }
+ b[p] = '\0';
+
+ } while (p > pp);
+
+ if (p == 0) {
+ r--;
+ } else {
+ c = b[so]; b[so] = '\0';
+ setvar_s(v, b+rp);
+ v->type |= VF_USER;
+ b[so] = c;
+ c = b[eo]; b[eo] = '\0';
+ setvar_s(intvar[RT], b+so);
+ b[eo] = c;
+ }
+
+ rsm->buffer = m;
+ rsm->adv = a + eo;
+ rsm->pos = p - eo;
+ rsm->size = size;
+
+ return r;
+}
+
+static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
+{
+ int r = 0;
+ char c;
+ const char *s = format;
+
+ if (int_as_int && n == (int)n) {
+ r = snprintf(b, size, "%d", (int)n);
+ } else {
+ do { c = *s; } while (c && *++s);
+ if (strchr("diouxX", c)) {
+ r = snprintf(b, size, format, (int)n);
+ } else if (strchr("eEfgG", c)) {
+ r = snprintf(b, size, format, n);
+ } else {
+ syntax_error(EMSG_INV_FMT);
+ }
+ }
+ return r;
+}
+
+
+/* formatted output into an allocated buffer, return ptr to buffer */
+static char *awk_printf(node *n)
+{
+ char *b = NULL;
+ char *fmt, *s, *f;
+ const char *s1;
+ int i, j, incr, bsize;
+ char c, c1;
+ var *v, *arg;
+
+ v = nvalloc(1);
+ fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v)));
+
+ i = 0;
+ while (*f) {
+ s = f;
+ while (*f && (*f != '%' || *(++f) == '%'))
+ f++;
+ while (*f && !isalpha(*f)) {
+ if (*f == '*')
+ syntax_error("%*x formats are not supported");
+ f++;
+ }
+
+ incr = (f - s) + MAXVARFMT;
+ qrealloc(&b, incr + i, &bsize);
+ c = *f;
+ if (c != '\0') f++;
+ c1 = *f;
+ *f = '\0';
+ arg = evaluate(nextarg(&n), v);
+
+ j = i;
+ if (c == 'c' || !c) {
+ i += sprintf(b+i, s, is_numeric(arg) ?
+ (char)getvar_i(arg) : *getvar_s(arg));
+ } else if (c == 's') {
+ s1 = getvar_s(arg);
+ qrealloc(&b, incr+i+strlen(s1), &bsize);
+ i += sprintf(b+i, s, s1);
+ } else {
+ i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
+ }
+ *f = c1;
+
+ /* if there was an error while sprintf, return value is negative */
+ if (i < j) i = j;
+ }
+
+ b = xrealloc(b, i + 1);
+ free(fmt);
+ nvfree(v);
+ b[i] = '\0';
+ return b;
+}
+
+/* common substitution routine
+ * replace (nm) substring of (src) that match (n) with (repl), store
+ * result into (dest), return number of substitutions. If nm=0, replace
+ * all matches. If src or dst is NULL, use $0. If ex=TRUE, enable
+ * subexpression matching (\1-\9)
+ */
+static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int ex)
+{
+ char *ds = NULL;
+ const char *s;
+ const char *sp;
+ int c, i, j, di, rl, so, eo, nbs, n, dssize;
+ regmatch_t pmatch[10];
+ regex_t sreg, *re;
+
+ re = as_regex(rn, &sreg);
+ if (!src) src = intvar[F0];
+ if (!dest) dest = intvar[F0];
+
+ i = di = 0;
+ sp = getvar_s(src);
+ rl = strlen(repl);
+ while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0 : REG_NOTBOL) == 0) {
+ so = pmatch[0].rm_so;
+ eo = pmatch[0].rm_eo;
+
+ qrealloc(&ds, di + eo + rl, &dssize);
+ memcpy(ds + di, sp, eo);
+ di += eo;
+ if (++i >= nm) {
+ /* replace */
+ di -= (eo - so);
+ nbs = 0;
+ for (s = repl; *s; s++) {
+ ds[di++] = c = *s;
+ if (c == '\\') {
+ nbs++;
+ continue;
+ }
+ if (c == '&' || (ex && c >= '0' && c <= '9')) {
+ di -= ((nbs + 3) >> 1);
+ j = 0;
+ if (c != '&') {
+ j = c - '0';
+ nbs++;
+ }
+ if (nbs % 2) {
+ ds[di++] = c;
+ } else {
+ n = pmatch[j].rm_eo - pmatch[j].rm_so;
+ qrealloc(&ds, di + rl + n, &dssize);
+ memcpy(ds + di, sp + pmatch[j].rm_so, n);
+ di += n;
+ }
+ }
+ nbs = 0;
+ }
+ }
+
+ sp += eo;
+ if (i == nm) break;
+ if (eo == so) {
+ ds[di] = *sp++;
+ if (!ds[di++]) break;
+ }
+ }
+
+ qrealloc(&ds, di + strlen(sp), &dssize);
+ strcpy(ds + di, sp);
+ setvar_p(dest, ds);
+ if (re == &sreg) regfree(re);
+ return i;
+}
+
+static var *exec_builtin(node *op, var *res)
+{
+#define tspl (G.exec_builtin__tspl)
+
+ int (*to_xxx)(int);
+ var *tv;
+ node *an[4];
+ var *av[4];
+ const char *as[4];
+ regmatch_t pmatch[2];
+ regex_t sreg, *re;
+ node *spl;
+ uint32_t isr, info;
+ int nargs;
+ time_t tt;
+ char *s, *s1;
+ int i, l, ll, n;
+
+ tv = nvalloc(4);
+ isr = info = op->info;
+ op = op->l.n;
+
+ av[2] = av[3] = NULL;
+ for (i = 0; i < 4 && op; i++) {
+ an[i] = nextarg(&op);
+ if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]);
+ if (isr & 0x08000000) as[i] = getvar_s(av[i]);
+ isr >>= 1;
+ }
+
+ nargs = i;
+ if ((uint32_t)nargs < (info >> 30))
+ syntax_error(EMSG_TOO_FEW_ARGS);
+
+ switch (info & OPNMASK) {
+
+ case B_a2:
+#if ENABLE_FEATURE_AWK_MATH
+ setvar_i(res, atan2(getvar_i(av[i]), getvar_i(av[1])));
+#else
+ syntax_error(EMSG_NO_MATH);
+#endif
+ break;
+
+ case B_sp:
+ if (nargs > 2) {
+ spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
+ an[2] : mk_splitter(getvar_s(evaluate(an[2], &tv[2])), &tspl);
+ } else {
+ spl = &fsplitter.n;
+ }
+
+ n = awk_split(as[0], spl, &s);
+ s1 = s;
+ clear_array(iamarray(av[1]));
+ for (i=1; i<=n; i++)
+ setari_u(av[1], i, nextword(&s1));
+ free(s);
+ setvar_i(res, n);
+ break;
+
+ case B_ss:
+ l = strlen(as[0]);
+ i = getvar_i(av[1]) - 1;
+ if (i > l) i = l;
+ if (i < 0) i = 0;
+ n = (nargs > 2) ? getvar_i(av[2]) : l-i;
+ if (n < 0) n = 0;
+ s = xmalloc(n+1);
+ strncpy(s, as[0]+i, n);
+ s[n] = '\0';
+ setvar_p(res, s);
+ break;
+
+ case B_an:
+ setvar_i(res, (long)getvar_i(av[0]) & (long)getvar_i(av[1]));
+ break;
+
+ case B_co:
+ setvar_i(res, ~(long)getvar_i(av[0]));
+ break;
+
+ case B_ls:
+ setvar_i(res, (long)getvar_i(av[0]) << (long)getvar_i(av[1]));
+ break;
+
+ case B_or:
+ setvar_i(res, (long)getvar_i(av[0]) | (long)getvar_i(av[1]));
+ break;
+
+ case B_rs:
+ setvar_i(res, (long)((unsigned long)getvar_i(av[0]) >> (unsigned long)getvar_i(av[1])));
+ break;
+
+ case B_xo:
+ setvar_i(res, (long)getvar_i(av[0]) ^ (long)getvar_i(av[1]));
+ break;
+
+ case B_lo:
+ to_xxx = tolower;
+ goto lo_cont;
+
+ case B_up:
+ to_xxx = toupper;
+ lo_cont:
+ s1 = s = xstrdup(as[0]);
+ while (*s1) {
+ *s1 = (*to_xxx)(*s1);
+ s1++;
+ }
+ setvar_p(res, s);
+ break;
+
+ case B_ix:
+ n = 0;
+ ll = strlen(as[1]);
+ l = strlen(as[0]) - ll;
+ if (ll > 0 && l >= 0) {
+ if (!icase) {
+ s = strstr(as[0], as[1]);
+ if (s) n = (s - as[0]) + 1;
+ } else {
+ /* this piece of code is terribly slow and
+ * really should be rewritten
+ */
+ for (i=0; i<=l; i++) {
+ if (strncasecmp(as[0]+i, as[1], ll) == 0) {
+ n = i+1;
+ break;
+ }
+ }
+ }
+ }
+ setvar_i(res, n);
+ break;
+
+ case B_ti:
+ if (nargs > 1)
+ tt = getvar_i(av[1]);
+ else
+ time(&tt);
+ //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
+ i = strftime(g_buf, MAXVARFMT,
+ ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
+ localtime(&tt));
+ g_buf[i] = '\0';
+ setvar_s(res, g_buf);
+ break;
+
+ case B_ma:
+ re = as_regex(an[1], &sreg);
+ n = regexec(re, as[0], 1, pmatch, 0);
+ if (n == 0) {
+ pmatch[0].rm_so++;
+ pmatch[0].rm_eo++;
+ } else {
+ pmatch[0].rm_so = 0;
+ pmatch[0].rm_eo = -1;
+ }
+ setvar_i(newvar("RSTART"), pmatch[0].rm_so);
+ setvar_i(newvar("RLENGTH"), pmatch[0].rm_eo - pmatch[0].rm_so);
+ setvar_i(res, pmatch[0].rm_so);
+ if (re == &sreg) regfree(re);
+ break;
+
+ case B_ge:
+ awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
+ break;
+
+ case B_gs:
+ setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
+ break;
+
+ case B_su:
+ setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
+ break;
+ }
+
+ nvfree(tv);
+ return res;
+#undef tspl
+}
+
+/*
+ * Evaluate node - the heart of the program. Supplied with subtree
+ * and place where to store result. returns ptr to result.
+ */
+#define XC(n) ((n) >> 8)
+
+static var *evaluate(node *op, var *res)
+{
+/* This procedure is recursive so we should count every byte */
+#define fnargs (G.evaluate__fnargs)
+/* seed is initialized to 1 */
+#define seed (G.evaluate__seed)
+#define sreg (G.evaluate__sreg)
+
+ node *op1;
+ var *v1;
+ union {
+ var *v;
+ const char *s;
+ double d;
+ int i;
+ } L, R;
+ uint32_t opinfo;
+ int opn;
+ union {
+ char *s;
+ rstream *rsm;
+ FILE *F;
+ var *v;
+ regex_t *re;
+ uint32_t info;
+ } X;
+
+ if (!op)
+ return setvar_s(res, NULL);
+
+ v1 = nvalloc(2);
+
+ while (op) {
+ opinfo = op->info;
+ opn = (opinfo & OPNMASK);
+ g_lineno = op->lineno;
+
+ /* execute inevitable things */
+ op1 = op->l.n;
+ if (opinfo & OF_RES1) X.v = L.v = evaluate(op1, v1);
+ if (opinfo & OF_RES2) R.v = evaluate(op->r.n, v1+1);
+ if (opinfo & OF_STR1) L.s = getvar_s(L.v);
+ if (opinfo & OF_STR2) R.s = getvar_s(R.v);
+ if (opinfo & OF_NUM1) L.d = getvar_i(L.v);
+
+ switch (XC(opinfo & OPCLSMASK)) {
+
+ /* -- iterative node type -- */
+
+ /* test pattern */
+ case XC( OC_TEST ):
+ if ((op1->info & OPCLSMASK) == OC_COMMA) {
+ /* it's range pattern */
+ if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
+ op->info |= OF_CHECKED;
+ if (ptest(op1->r.n))
+ op->info &= ~OF_CHECKED;
+
+ op = op->a.n;
+ } else {
+ op = op->r.n;
+ }
+ } else {
+ op = (ptest(op1)) ? op->a.n : op->r.n;
+ }
+ break;
+
+ /* just evaluate an expression, also used as unconditional jump */
+ case XC( OC_EXEC ):
+ break;
+
+ /* branch, used in if-else and various loops */
+ case XC( OC_BR ):
+ op = istrue(L.v) ? op->a.n : op->r.n;
+ break;
+
+ /* initialize for-in loop */
+ case XC( OC_WALKINIT ):
+ hashwalk_init(L.v, iamarray(R.v));
+ break;
+
+ /* get next array item */
+ case XC( OC_WALKNEXT ):
+ op = hashwalk_next(L.v) ? op->a.n : op->r.n;
+ break;
+
+ case XC( OC_PRINT ):
+ case XC( OC_PRINTF ):
+ X.F = stdout;
+ if (op->r.n) {
+ X.rsm = newfile(R.s);
+ if (!X.rsm->F) {
+ if (opn == '|') {
+ X.rsm->F = popen(R.s, "w");
+ if (X.rsm->F == NULL)
+ bb_perror_msg_and_die("popen");
+ X.rsm->is_pipe = 1;
+ } else {
+ X.rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
+ }
+ }
+ X.F = X.rsm->F;
+ }
+
+ if ((opinfo & OPCLSMASK) == OC_PRINT) {
+ if (!op1) {
+ fputs(getvar_s(intvar[F0]), X.F);
+ } else {
+ while (op1) {
+ L.v = evaluate(nextarg(&op1), v1);
+ if (L.v->type & VF_NUMBER) {
+ fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]),
+ getvar_i(L.v), TRUE);
+ fputs(g_buf, X.F);
+ } else {
+ fputs(getvar_s(L.v), X.F);
+ }
+
+ if (op1) fputs(getvar_s(intvar[OFS]), X.F);
+ }
+ }
+ fputs(getvar_s(intvar[ORS]), X.F);
+
+ } else { /* OC_PRINTF */
+ L.s = awk_printf(op1);
+ fputs(L.s, X.F);
+ free((char*)L.s);
+ }
+ fflush(X.F);
+ break;
+
+ case XC( OC_DELETE ):
+ X.info = op1->info & OPCLSMASK;
+ if (X.info == OC_VAR) {
+ R.v = op1->l.v;
+ } else if (X.info == OC_FNARG) {
+ R.v = &fnargs[op1->l.i];
+ } else {
+ syntax_error(EMSG_NOT_ARRAY);
+ }
+
+ if (op1->r.n) {
+ clrvar(L.v);
+ L.s = getvar_s(evaluate(op1->r.n, v1));
+ hash_remove(iamarray(R.v), L.s);
+ } else {
+ clear_array(iamarray(R.v));
+ }
+ break;
+
+ case XC( OC_NEWSOURCE ):
+ g_progname = op->l.s;
+ break;
+
+ case XC( OC_RETURN ):
+ copyvar(res, L.v);
+ break;
+
+ case XC( OC_NEXTFILE ):
+ nextfile = TRUE;
+ case XC( OC_NEXT ):
+ nextrec = TRUE;
+ case XC( OC_DONE ):
+ clrvar(res);
+ break;
+
+ case XC( OC_EXIT ):
+ awk_exit(L.d);
+
+ /* -- recursive node type -- */
+
+ case XC( OC_VAR ):
+ L.v = op->l.v;
+ if (L.v == intvar[NF])
+ split_f0();
+ goto v_cont;
+
+ case XC( OC_FNARG ):
+ L.v = &fnargs[op->l.i];
+ v_cont:
+ res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
+ break;
+
+ case XC( OC_IN ):
+ setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
+ break;
+
+ case XC( OC_REGEXP ):
+ op1 = op;
+ L.s = getvar_s(intvar[F0]);
+ goto re_cont;
+
+ case XC( OC_MATCH ):
+ op1 = op->r.n;
+ re_cont:
+ X.re = as_regex(op1, &sreg);
+ R.i = regexec(X.re, L.s, 0, NULL, 0);
+ if (X.re == &sreg) regfree(X.re);
+ setvar_i(res, (R.i == 0 ? 1 : 0) ^ (opn == '!' ? 1 : 0));
+ break;
+
+ case XC( OC_MOVE ):
+ /* if source is a temporary string, jusk relink it to dest */
+ if (R.v == v1+1 && R.v->string) {
+ res = setvar_p(L.v, R.v->string);
+ R.v->string = NULL;
+ } else {
+ res = copyvar(L.v, R.v);
+ }
+ break;
+
+ case XC( OC_TERNARY ):
+ if ((op->r.n->info & OPCLSMASK) != OC_COLON)
+ syntax_error(EMSG_POSSIBLE_ERROR);
+ res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
+ break;
+
+ case XC( OC_FUNC ):
+ if (!op->r.f->body.first)
+ syntax_error(EMSG_UNDEF_FUNC);
+
+ X.v = R.v = nvalloc(op->r.f->nargs+1);
+ while (op1) {
+ L.v = evaluate(nextarg(&op1), v1);
+ copyvar(R.v, L.v);
+ R.v->type |= VF_CHILD;
+ R.v->x.parent = L.v;
+ if (++R.v - X.v >= op->r.f->nargs)
+ break;
+ }
+
+ R.v = fnargs;
+ fnargs = X.v;
+
+ L.s = g_progname;
+ res = evaluate(op->r.f->body.first, res);
+ g_progname = L.s;
+
+ nvfree(fnargs);
+ fnargs = R.v;
+ break;
+
+ case XC( OC_GETLINE ):
+ case XC( OC_PGETLINE ):
+ if (op1) {
+ X.rsm = newfile(L.s);
+ if (!X.rsm->F) {
+ if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
+ X.rsm->F = popen(L.s, "r");
+ X.rsm->is_pipe = TRUE;
+ } else {
+ X.rsm->F = fopen(L.s, "r"); /* not xfopen! */
+ }
+ }
+ } else {
+ if (!iF) iF = next_input_file();
+ X.rsm = iF;
+ }
+
+ if (!X.rsm->F) {
+ setvar_i(intvar[ERRNO], errno);
+ setvar_i(res, -1);
+ break;
+ }
+
+ if (!op->r.n)
+ R.v = intvar[F0];
+
+ L.i = awk_getline(X.rsm, R.v);
+ if (L.i > 0) {
+ if (!op1) {
+ incvar(intvar[FNR]);
+ incvar(intvar[NR]);
+ }
+ }
+ setvar_i(res, L.i);
+ break;
+
+ /* simple builtins */
+ case XC( OC_FBLTIN ):
+ switch (opn) {
+
+ case F_in:
+ R.d = (int)L.d;
+ break;
+
+ case F_rn:
+ R.d = (double)rand() / (double)RAND_MAX;
+ break;
+#if ENABLE_FEATURE_AWK_MATH
+ case F_co:
+ R.d = cos(L.d);
+ break;
+
+ case F_ex:
+ R.d = exp(L.d);
+ break;
+
+ case F_lg:
+ R.d = log(L.d);
+ break;
+
+ case F_si:
+ R.d = sin(L.d);
+ break;
+
+ case F_sq:
+ R.d = sqrt(L.d);
+ break;
+#else
+ case F_co:
+ case F_ex:
+ case F_lg:
+ case F_si:
+ case F_sq:
+ syntax_error(EMSG_NO_MATH);
+ break;
+#endif
+ case F_sr:
+ R.d = (double)seed;
+ seed = op1 ? (unsigned)L.d : (unsigned)time(NULL);
+ srand(seed);
+ break;
+
+ case F_ti:
+ R.d = time(NULL);
+ break;
+
+ case F_le:
+ if (!op1)
+ L.s = getvar_s(intvar[F0]);
+ R.d = strlen(L.s);
+ break;
+
+ case F_sy:
+ fflush(NULL);
+ R.d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
+ ? (system(L.s) >> 8) : 0;
+ break;
+
+ case F_ff:
+ if (!op1)
+ fflush(stdout);
+ else {
+ if (L.s && *L.s) {
+ X.rsm = newfile(L.s);
+ fflush(X.rsm->F);
+ } else {
+ fflush(NULL);
+ }
+ }
+ break;
+
+ case F_cl:
+ X.rsm = (rstream *)hash_search(fdhash, L.s);
+ if (X.rsm) {
+ R.i = X.rsm->is_pipe ? pclose(X.rsm->F) : fclose(X.rsm->F);
+ free(X.rsm->buffer);
+ hash_remove(fdhash, L.s);
+ }
+ if (R.i != 0)
+ setvar_i(intvar[ERRNO], errno);
+ R.d = (double)R.i;
+ break;
+ }
+ setvar_i(res, R.d);
+ break;
+
+ case XC( OC_BUILTIN ):
+ res = exec_builtin(op, res);
+ break;
+
+ case XC( OC_SPRINTF ):
+ setvar_p(res, awk_printf(op1));
+ break;
+
+ case XC( OC_UNARY ):
+ X.v = R.v;
+ L.d = R.d = getvar_i(R.v);
+ switch (opn) {
+ case 'P':
+ L.d = ++R.d;
+ goto r_op_change;
+ case 'p':
+ R.d++;
+ goto r_op_change;
+ case 'M':
+ L.d = --R.d;
+ goto r_op_change;
+ case 'm':
+ R.d--;
+ goto r_op_change;
+ case '!':
+ L.d = istrue(X.v) ? 0 : 1;
+ break;
+ case '-':
+ L.d = -R.d;
+ break;
+ r_op_change:
+ setvar_i(X.v, R.d);
+ }
+ setvar_i(res, L.d);
+ break;
+
+ case XC( OC_FIELD ):
+ R.i = (int)getvar_i(R.v);
+ if (R.i == 0) {
+ res = intvar[F0];
+ } else {
+ split_f0();
+ if (R.i > nfields)
+ fsrealloc(R.i);
+ res = &Fields[R.i - 1];
+ }
+ break;
+
+ /* concatenation (" ") and index joining (",") */
+ case XC( OC_CONCAT ):
+ case XC( OC_COMMA ):
+ opn = strlen(L.s) + strlen(R.s) + 2;
+ X.s = xmalloc(opn);
+ strcpy(X.s, L.s);
+ if ((opinfo & OPCLSMASK) == OC_COMMA) {
+ L.s = getvar_s(intvar[SUBSEP]);
+ X.s = xrealloc(X.s, opn + strlen(L.s));
+ strcat(X.s, L.s);
+ }
+ strcat(X.s, R.s);
+ setvar_p(res, X.s);
+ break;
+
+ case XC( OC_LAND ):
+ setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
+ break;
+
+ case XC( OC_LOR ):
+ setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
+ break;
+
+ case XC( OC_BINARY ):
+ case XC( OC_REPLACE ):
+ R.d = getvar_i(R.v);
+ switch (opn) {
+ case '+':
+ L.d += R.d;
+ break;
+ case '-':
+ L.d -= R.d;
+ break;
+ case '*':
+ L.d *= R.d;
+ break;
+ case '/':
+ if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
+ L.d /= R.d;
+ break;
+ case '&':
+#if ENABLE_FEATURE_AWK_MATH
+ L.d = pow(L.d, R.d);
+#else
+ syntax_error(EMSG_NO_MATH);
+#endif
+ break;
+ case '%':
+ if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
+ L.d -= (int)(L.d / R.d) * R.d;
+ break;
+ }
+ res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : X.v, L.d);
+ break;
+
+ case XC( OC_COMPARE ):
+ if (is_numeric(L.v) && is_numeric(R.v)) {
+ L.d = getvar_i(L.v) - getvar_i(R.v);
+ } else {
+ L.s = getvar_s(L.v);
+ R.s = getvar_s(R.v);
+ L.d = icase ? strcasecmp(L.s, R.s) : strcmp(L.s, R.s);
+ }
+ switch (opn & 0xfe) {
+ case 0:
+ R.i = (L.d > 0);
+ break;
+ case 2:
+ R.i = (L.d >= 0);
+ break;
+ case 4:
+ R.i = (L.d == 0);
+ break;
+ }
+ setvar_i(res, (opn & 0x1 ? R.i : !R.i) ? 1 : 0);
+ break;
+
+ default:
+ syntax_error(EMSG_POSSIBLE_ERROR);
+ }
+ if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
+ op = op->a.n;
+ if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)
+ break;
+ if (nextrec)
+ break;
+ }
+ nvfree(v1);
+ return res;
+#undef fnargs
+#undef seed
+#undef sreg
+}
+
+
+/* -------- main & co. -------- */
+
+static int awk_exit(int r)
+{
+ var tv;
+ unsigned i;
+ hash_item *hi;
+
+ zero_out_var(&tv);
+
+ if (!exiting) {
+ exiting = TRUE;
+ nextrec = FALSE;
+ evaluate(endseq.first, &tv);
+ }
+
+ /* waiting for children */
+ for (i = 0; i < fdhash->csize; i++) {
+ hi = fdhash->items[i];
+ while (hi) {
+ if (hi->data.rs.F && hi->data.rs.is_pipe)
+ pclose(hi->data.rs.F);
+ hi = hi->next;
+ }
+ }
+
+ exit(r);
+}
+
+/* if expr looks like "var=value", perform assignment and return 1,
+ * otherwise return 0 */
+static int is_assignment(const char *expr)
+{
+ char *exprc, *s, *s0, *s1;
+
+ exprc = xstrdup(expr);
+ if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) {
+ free(exprc);
+ return FALSE;
+ }
+
+ *(s++) = '\0';
+ s0 = s1 = s;
+ while (*s)
+ *(s1++) = nextchar(&s);
+
+ *s1 = '\0';
+ setvar_u(newvar(exprc), s0);
+ free(exprc);
+ return TRUE;
+}
+
+/* switch to next input file */
+static rstream *next_input_file(void)
+{
+#define rsm (G.next_input_file__rsm)
+#define files_happen (G.next_input_file__files_happen)
+
+ FILE *F = NULL;
+ const char *fname, *ind;
+
+ if (rsm.F) fclose(rsm.F);
+ rsm.F = NULL;
+ rsm.pos = rsm.adv = 0;
+
+ do {
+ if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) {
+ if (files_happen)
+ return NULL;
+ fname = "-";
+ F = stdin;
+ } else {
+ ind = getvar_s(incvar(intvar[ARGIND]));
+ fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
+ if (fname && *fname && !is_assignment(fname))
+ F = xfopen_stdin(fname);
+ }
+ } while (!F);
+
+ files_happen = TRUE;
+ setvar_s(intvar[FILENAME], fname);
+ rsm.F = F;
+ return &rsm;
+#undef rsm
+#undef files_happen
+}
+
+int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int awk_main(int argc, char **argv)
+{
+ unsigned opt;
+ char *opt_F, *opt_W;
+ llist_t *list_v = NULL;
+ llist_t *list_f = NULL;
+ int i, j;
+ var *v;
+ var tv;
+ char **envp;
+ char *vnames = (char *)vNames; /* cheat */
+ char *vvalues = (char *)vValues;
+
+ INIT_G();
+
+ /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
+ * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
+ if (ENABLE_LOCALE_SUPPORT)
+ setlocale(LC_NUMERIC, "C");
+
+ zero_out_var(&tv);
+
+ /* allocate global buffer */
+ g_buf = xmalloc(MAXVARFMT + 1);
+
+ vhash = hash_init();
+ ahash = hash_init();
+ fdhash = hash_init();
+ fnhash = hash_init();
+
+ /* initialize variables */
+ for (i = 0; *vnames; i++) {
+ intvar[i] = v = newvar(nextword(&vnames));
+ if (*vvalues != '\377')
+ setvar_s(v, nextword(&vvalues));
+ else
+ setvar_i(v, 0);
+
+ if (*vnames == '*') {
+ v->type |= VF_SPECIAL;
+ vnames++;
+ }
+ }
+
+ handle_special(intvar[FS]);
+ handle_special(intvar[RS]);
+
+ newfile("/dev/stdin")->F = stdin;
+ newfile("/dev/stdout")->F = stdout;
+ newfile("/dev/stderr")->F = stderr;
+
+ /* Huh, people report that sometimes environ is NULL. Oh well. */
+ if (environ) for (envp = environ; *envp; envp++) {
+ /* environ is writable, thus we don't strdup it needlessly */
+ char *s = *envp;
+ char *s1 = strchr(s, '=');
+ if (s1) {
+ *s1 = '\0';
+ /* Both findvar and setvar_u take const char*
+ * as 2nd arg -> environment is not trashed */
+ setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1);
+ *s1 = '=';
+ }
+ }
+ opt_complementary = "v::f::"; /* -v and -f can occur multiple times */
+ opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, &opt_W);
+ argv += optind;
+ argc -= optind;
+ if (opt & 0x1)
+ setvar_s(intvar[FS], opt_F); // -F
+ while (list_v) { /* -v */
+ if (!is_assignment(llist_pop(&list_v)))
+ bb_show_usage();
+ }
+ if (list_f) { /* -f */
+ do {
+ char *s = NULL;
+ FILE *from_file;
+
+ g_progname = llist_pop(&list_f);
+ from_file = xfopen_stdin(g_progname);
+ /* one byte is reserved for some trick in next_token */
+ for (i = j = 1; j > 0; i += j) {
+ s = xrealloc(s, i + 4096);
+ j = fread(s + i, 1, 4094, from_file);
+ }
+ s[i] = '\0';
+ fclose(from_file);
+ parse_program(s + 1);
+ free(s);
+ } while (list_f);
+ } else { // no -f: take program from 1st parameter
+ if (!argc)
+ bb_show_usage();
+ g_progname = "cmd. line";
+ parse_program(*argv++);
+ argc--;
+ }
+ if (opt & 0x8) // -W
+ bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
+
+ /* fill in ARGV array */
+ setvar_i(intvar[ARGC], argc + 1);
+ setari_u(intvar[ARGV], 0, "awk");
+ i = 0;
+ while (*argv)
+ setari_u(intvar[ARGV], ++i, *argv++);
+
+ evaluate(beginseq.first, &tv);
+ if (!mainseq.first && !endseq.first)
+ awk_exit(EXIT_SUCCESS);
+
+ /* input file could already be opened in BEGIN block */
+ if (!iF) iF = next_input_file();
+
+ /* passing through input files */
+ while (iF) {
+ nextfile = FALSE;
+ setvar_i(intvar[FNR], 0);
+
+ while ((i = awk_getline(iF, intvar[F0])) > 0) {
+ nextrec = FALSE;
+ incvar(intvar[NR]);
+ incvar(intvar[FNR]);
+ evaluate(mainseq.first, &tv);
+
+ if (nextfile)
+ break;
+ }
+
+ if (i < 0)
+ syntax_error(strerror(errno));
+
+ iF = next_input_file();
+ }
+
+ awk_exit(EXIT_SUCCESS);
+ /*return 0;*/
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/editors/cmp.c b/cleopatre/busybox-1.11.1-spc300/editors/cmp.c
new file mode 100644
index 0000000000..b211adf9fe
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/editors/cmp.c
@@ -0,0 +1,135 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini cmp implementation for busybox
+ *
+ * Copyright (C) 2000,2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* BB_AUDIT SUSv3 (virtually) compliant -- uses nicer GNU format for -l. */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/cmp.html */
+
+/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
+ *
+ * Original version majorly reworked for SUSv3 compliance, bug fixes, and
+ * size optimizations. Changes include:
+ * 1) Now correctly distinguishes between errors and actual file differences.
+ * 2) Proper handling of '-' args.
+ * 3) Actual error checking of i/o.
+ * 4) Accept SUSv3 -l option. Note that we use the slightly nicer gnu format
+ * in the '-l' case.
+ */
+
+#include "libbb.h"
+
+static const char fmt_eof[] ALIGN1 = "cmp: EOF on %s\n";
+static const char fmt_differ[] ALIGN1 = "%s %s differ: char %"OFF_FMT"d, line %d\n";
+// This fmt_l_opt uses gnu-isms. SUSv3 would be "%.0s%.0s%"OFF_FMT"d %o %o\n"
+static const char fmt_l_opt[] ALIGN1 = "%.0s%.0s%"OFF_FMT"d %3o %3o\n";
+
+static const char opt_chars[] ALIGN1 = "sl";
+#define CMP_OPT_s (1<<0)
+#define CMP_OPT_l (1<<1)
+
+int cmp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int cmp_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ FILE *fp1, *fp2, *outfile = stdout;
+ const char *filename1, *filename2 = "-";
+ USE_DESKTOP(off_t skip1 = 0, skip2 = 0;)
+ off_t char_pos = 0;
+ int line_pos = 1; /* Hopefully won't overflow... */
+ const char *fmt;
+ int c1, c2;
+ unsigned opt;
+ int retval = 0;
+
+ xfunc_error_retval = 2; /* 1 is returned if files are different. */
+
+ opt_complementary = "-1"
+ USE_DESKTOP(":?4")
+ SKIP_DESKTOP(":?2")
+ ":l--s:s--l";
+ opt = getopt32(argv, opt_chars);
+ argv += optind;
+
+ filename1 = *argv;
+ fp1 = xfopen_stdin(filename1);
+
+ if (*++argv) {
+ filename2 = *argv;
+#if ENABLE_DESKTOP
+ if (*++argv) {
+ skip1 = XATOOFF(*argv);
+ if (*++argv) {
+ skip2 = XATOOFF(*argv);
+ }
+ }
+#endif
+ }
+
+ fp2 = xfopen_stdin(filename2);
+ if (fp1 == fp2) { /* Paranoia check... stdin == stdin? */
+ /* Note that we don't bother reading stdin. Neither does gnu wc.
+ * But perhaps we should, so that other apps down the chain don't
+ * get the input. Consider 'echo hello | (cmp - - && cat -)'.
+ */
+ return 0;
+ }
+
+ if (opt & CMP_OPT_l)
+ fmt = fmt_l_opt;
+ else
+ fmt = fmt_differ;
+
+#if ENABLE_DESKTOP
+ while (skip1) { getc(fp1); skip1--; }
+ while (skip2) { getc(fp2); skip2--; }
+#endif
+ do {
+ c1 = getc(fp1);
+ c2 = getc(fp2);
+ ++char_pos;
+ if (c1 != c2) { /* Remember: a read error may have occurred. */
+ retval = 1; /* But assume the files are different for now. */
+ if (c2 == EOF) {
+ /* We know that fp1 isn't at EOF or in an error state. But to
+ * save space below, things are setup to expect an EOF in fp1
+ * if an EOF occurred. So, swap things around.
+ */
+ fp1 = fp2;
+ filename1 = filename2;
+ c1 = c2;
+ }
+ if (c1 == EOF) {
+ die_if_ferror(fp1, filename1);
+ fmt = fmt_eof; /* Well, no error, so it must really be EOF. */
+ outfile = stderr;
+ /* There may have been output to stdout (option -l), so
+ * make sure we fflush before writing to stderr. */
+ xfflush_stdout();
+ }
+ if (!(opt & CMP_OPT_s)) {
+ if (opt & CMP_OPT_l) {
+ line_pos = c1; /* line_pos is unused in the -l case. */
+ }
+ fprintf(outfile, fmt, filename1, filename2, char_pos, line_pos, c2);
+ if (opt) { /* This must be -l since not -s. */
+ /* If we encountered an EOF,
+ * the while check will catch it. */
+ continue;
+ }
+ }
+ break;
+ }
+ if (c1 == '\n') {
+ ++line_pos;
+ }
+ } while (c1 != EOF);
+
+ die_if_ferror(fp1, filename1);
+ die_if_ferror(fp2, filename2);
+
+ fflush_stdout_and_exit(retval);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/editors/diff.c b/cleopatre/busybox-1.11.1-spc300/editors/diff.c
new file mode 100644
index 0000000000..ad089e2a6e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/editors/diff.c
@@ -0,0 +1,1344 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini diff implementation for busybox, adapted from OpenBSD diff.
+ *
+ * Copyright (C) 2006 by Robert Sullivan <cogito.ergo.cogito@hotmail.com>
+ * Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+// #define FSIZE_MAX 32768
+
+/* NOINLINEs added to prevent gcc from merging too much into diffreg()
+ * (it bites more than it can (efficiently) chew). */
+
+/*
+ * Output flags
+ */
+enum {
+ /* Print a header/footer between files */
+ /* D_HEADER = 1, - unused */
+ /* Treat file as empty (/dev/null) */
+ D_EMPTY1 = 2 * ENABLE_FEATURE_DIFF_DIR,
+ D_EMPTY2 = 4 * ENABLE_FEATURE_DIFF_DIR,
+};
+
+/*
+ * Status values for print_status() and diffreg() return values
+ * Guide:
+ * D_SAME - files are the same
+ * D_DIFFER - files differ
+ * D_BINARY - binary files differ
+ * D_COMMON - subdirectory common to both dirs
+ * D_ONLY - file only exists in one dir
+ * D_ISDIR1 - path1 a dir, path2 a file
+ * D_ISDIR2 - path1 a file, path2 a dir
+ * D_ERROR - error occurred
+ * D_SKIPPED1 - skipped path1 as it is a special file
+ * D_SKIPPED2 - skipped path2 as it is a special file
+ */
+#define D_SAME 0
+#define D_DIFFER (1 << 0)
+#define D_BINARY (1 << 1)
+#define D_COMMON (1 << 2)
+/*#define D_ONLY (1 << 3) - unused */
+#define D_ISDIR1 (1 << 4)
+#define D_ISDIR2 (1 << 5)
+#define D_ERROR (1 << 6)
+#define D_SKIPPED1 (1 << 7)
+#define D_SKIPPED2 (1 << 8)
+
+/* Command line options */
+#define FLAG_a (1 << 0)
+#define FLAG_b (1 << 1)
+#define FLAG_d (1 << 2)
+#define FLAG_i (1 << 3)
+#define FLAG_L (1 << 4)
+#define FLAG_N (1 << 5)
+#define FLAG_q (1 << 6)
+#define FLAG_r (1 << 7)
+#define FLAG_s (1 << 8)
+#define FLAG_S (1 << 9)
+#define FLAG_t (1 << 10)
+#define FLAG_T (1 << 11)
+#define FLAG_U (1 << 12)
+#define FLAG_w (1 << 13)
+
+
+struct cand {
+ int x;
+ int y;
+ int pred;
+};
+
+struct line {
+ int serial;
+ int value;
+};
+
+/*
+ * The following struct is used to record change information
+ * doing a "context" or "unified" diff. (see routine "change" to
+ * understand the highly mnemonic field names)
+ */
+struct context_vec {
+ int a; /* start line in old file */
+ int b; /* end line in old file */
+ int c; /* start line in new file */
+ int d; /* end line in new file */
+};
+
+
+#define g_read_buf bb_common_bufsiz1
+
+struct globals {
+ bool anychange;
+ smallint exit_status;
+ int opt_U_context;
+ size_t max_context; /* size of context_vec_start */
+ USE_FEATURE_DIFF_DIR(int dl_count;)
+ USE_FEATURE_DIFF_DIR(char **dl;)
+ char *opt_S_start;
+ const char *label1;
+ const char *label2;
+ int *J; /* will be overlaid on class */
+ int clen;
+ int pref, suff; /* length of prefix and suffix */
+ int nlen[2];
+ int slen[2];
+ int clistlen; /* the length of clist */
+ struct cand *clist; /* merely a free storage pot for candidates */
+ long *ixnew; /* will be overlaid on nfile[1] */
+ long *ixold; /* will be overlaid on klist */
+ struct line *nfile[2];
+ struct line *sfile[2]; /* shortened by pruning common prefix/suffix */
+ struct context_vec *context_vec_start;
+ struct context_vec *context_vec_end;
+ struct context_vec *context_vec_ptr;
+ char *tempname1, *tempname2;
+ struct stat stb1, stb2;
+};
+#define G (*ptr_to_globals)
+#define anychange (G.anychange )
+#define exit_status (G.exit_status )
+#define opt_U_context (G.opt_U_context )
+#define max_context (G.max_context )
+#define dl_count (G.dl_count )
+#define dl (G.dl )
+#define opt_S_start (G.opt_S_start )
+#define label1 (G.label1 )
+#define label2 (G.label2 )
+#define J (G.J )
+#define clen (G.clen )
+#define pref (G.pref )
+#define suff (G.suff )
+#define nlen (G.nlen )
+#define slen (G.slen )
+#define clistlen (G.clistlen )
+#define clist (G.clist )
+#define ixnew (G.ixnew )
+#define ixold (G.ixold )
+#define nfile (G.nfile )
+#define sfile (G.sfile )
+#define context_vec_start (G.context_vec_start )
+#define context_vec_end (G.context_vec_end )
+#define context_vec_ptr (G.context_vec_ptr )
+#define stb1 (G.stb1 )
+#define stb2 (G.stb2 )
+#define tempname1 (G.tempname1 )
+#define tempname2 (G.tempname2 )
+#define INIT_G() do { \
+ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
+ opt_U_context = 3; \
+ max_context = 64; \
+} while (0)
+
+
+#if ENABLE_FEATURE_DIFF_DIR
+static void print_only(const char *path, const char *entry)
+{
+ printf("Only in %s: %s\n", path, entry);
+}
+#endif
+
+
+static void print_status(int val, char *_path1, char *_path2)
+{
+ /*const char *const _entry = entry ? entry : "";*/
+ /*char *const _path1 = entry ? concat_path_file(path1, _entry) : path1;*/
+ /*char *const _path2 = entry ? concat_path_file(path2, _entry) : path2;*/
+
+ switch (val) {
+/* case D_ONLY:
+ print_only(path1, entry);
+ break;
+*/
+ case D_COMMON:
+ printf("Common subdirectories: %s and %s\n", _path1, _path2);
+ break;
+ case D_BINARY:
+ printf("Binary files %s and %s differ\n", _path1, _path2);
+ break;
+ case D_DIFFER:
+ if (option_mask32 & FLAG_q)
+ printf("Files %s and %s differ\n", _path1, _path2);
+ break;
+ case D_SAME:
+ if (option_mask32 & FLAG_s)
+ printf("Files %s and %s are identical\n", _path1, _path2);
+ break;
+ case D_ISDIR1:
+ printf("File %s is a %s while file %s is a %s\n",
+ _path1, "directory", _path2, "regular file");
+ break;
+ case D_ISDIR2:
+ printf("File %s is a %s while file %s is a %s\n",
+ _path1, "regular file", _path2, "directory");
+ break;
+ case D_SKIPPED1:
+ printf("File %s is not a regular file or directory and was skipped\n",
+ _path1);
+ break;
+ case D_SKIPPED2:
+ printf("File %s is not a regular file or directory and was skipped\n",
+ _path2);
+ break;
+ }
+/*
+ if (entry) {
+ free(_path1);
+ free(_path2);
+ }
+*/
+}
+
+
+/* Read line, return its nonzero hash. Return 0 if EOF.
+ *
+ * Hash function taken from Robert Sedgewick, Algorithms in C, 3d ed., p 578.
+ */
+static ALWAYS_INLINE int fiddle_sum(int sum, int t)
+{
+ return sum * 127 + t;
+}
+static int readhash(FILE *fp)
+{
+ int i, t, space;
+ int sum;
+
+ sum = 1;
+ space = 0;
+ i = 0;
+ if (!(option_mask32 & (FLAG_b | FLAG_w))) {
+ while ((t = getc(fp)) != '\n') {
+ if (t == EOF) {
+ if (i == 0)
+ return 0;
+ break;
+ }
+ sum = fiddle_sum(sum, t);
+ i = 1;
+ }
+ } else {
+ while (1) {
+ switch (t = getc(fp)) {
+ case '\t':
+ case '\r':
+ case '\v':
+ case '\f':
+ case ' ':
+ space = 1;
+ continue;
+ default:
+ if (space && !(option_mask32 & FLAG_w)) {
+ i = 1;
+ space = 0;
+ }
+ sum = fiddle_sum(sum, t);
+ i = 1;
+ continue;
+ case EOF:
+ if (i == 0)
+ return 0;
+ /* FALLTHROUGH */
+ case '\n':
+ break;
+ }
+ break;
+ }
+ }
+ /*
+ * There is a remote possibility that we end up with a zero sum.
+ * Zero is used as an EOF marker, so return 1 instead.
+ */
+ return (sum == 0 ? 1 : sum);
+}
+
+
+/* Our diff implementation is using seek.
+ * When we meet non-seekable file, we must make a temp copy.
+ */
+static char *make_temp(FILE *f, struct stat *sb)
+{
+ char *name;
+ int fd;
+
+ if (S_ISREG(sb->st_mode) || S_ISBLK(sb->st_mode))
+ return NULL;
+ name = xstrdup("/tmp/difXXXXXX");
+ fd = mkstemp(name);
+ if (fd < 0)
+ bb_perror_msg_and_die("mkstemp");
+ if (bb_copyfd_eof(fileno(f), fd) < 0) {
+ clean_up:
+ unlink(name);
+ xfunc_die(); /* error message is printed by bb_copyfd_eof */
+ }
+ fstat(fd, sb);
+ close(fd);
+ if (freopen(name, "r+", f) == NULL) {
+ bb_perror_msg("freopen");
+ goto clean_up;
+ }
+ return name;
+}
+
+
+/*
+ * Check to see if the given files differ.
+ * Returns 0 if they are the same, 1 if different, and -1 on error.
+ */
+static NOINLINE int files_differ(FILE *f1, FILE *f2)
+{
+ size_t i, j;
+
+ /* Prevent making copies for "/dev/null" (too common) */
+ /* Deal with input from pipes etc */
+ tempname1 = make_temp(f1, &stb1);
+ tempname2 = make_temp(f2, &stb2);
+ if (stb1.st_size != stb2.st_size) {
+ return 1;
+ }
+ while (1) {
+ i = fread(g_read_buf, 1, COMMON_BUFSIZE/2, f1);
+ j = fread(g_read_buf + COMMON_BUFSIZE/2, 1, COMMON_BUFSIZE/2, f2);
+ if (i != j)
+ return 1;
+ if (i == 0)
+ return (ferror(f1) || ferror(f2)) ? -1 : 0;
+ if (memcmp(g_read_buf,
+ g_read_buf + COMMON_BUFSIZE/2, i) != 0)
+ return 1;
+ }
+}
+
+
+static void prepare(int i, FILE *fp /*, off_t filesize*/)
+{
+ struct line *p;
+ int h;
+ size_t j, sz;
+
+ rewind(fp);
+
+ /*sz = (filesize <= FSIZE_MAX ? filesize : FSIZE_MAX) / 25;*/
+ /*if (sz < 100)*/
+ sz = 100;
+
+ p = xmalloc((sz + 3) * sizeof(p[0]));
+ j = 0;
+ while ((h = readhash(fp)) != 0) { /* while not EOF */
+ if (j == sz) {
+ sz = sz * 3 / 2;
+ p = xrealloc(p, (sz + 3) * sizeof(p[0]));
+ }
+ p[++j].value = h;
+ }
+ nlen[i] = j;
+ nfile[i] = p;
+}
+
+
+static void prune(void)
+{
+ int i, j;
+
+ for (pref = 0; pref < nlen[0] && pref < nlen[1] &&
+ nfile[0][pref + 1].value == nfile[1][pref + 1].value; pref++)
+ continue;
+ for (suff = 0; suff < nlen[0] - pref && suff < nlen[1] - pref &&
+ nfile[0][nlen[0] - suff].value == nfile[1][nlen[1] - suff].value;
+ suff++)
+ continue;
+ for (j = 0; j < 2; j++) {
+ sfile[j] = nfile[j] + pref;
+ slen[j] = nlen[j] - pref - suff;
+ for (i = 0; i <= slen[j]; i++)
+ sfile[j][i].serial = i;
+ }
+}
+
+
+static void equiv(struct line *a, int n, struct line *b, int m, int *c)
+{
+ int i, j;
+
+ i = j = 1;
+ while (i <= n && j <= m) {
+ if (a[i].value < b[j].value)
+ a[i++].value = 0;
+ else if (a[i].value == b[j].value)
+ a[i++].value = j;
+ else
+ j++;
+ }
+ while (i <= n)
+ a[i++].value = 0;
+ b[m + 1].value = 0;
+ j = 0;
+ while (++j <= m) {
+ c[j] = -b[j].serial;
+ while (b[j + 1].value == b[j].value) {
+ j++;
+ c[j] = b[j].serial;
+ }
+ }
+ c[j] = -1;
+}
+
+
+static int isqrt(int n)
+{
+ int y, x;
+
+ if (n == 0)
+ return 0;
+ x = 1;
+ do {
+ y = x;
+ x = n / x;
+ x += y;
+ x /= 2;
+ } while ((x - y) > 1 || (x - y) < -1);
+
+ return x;
+}
+
+
+static int newcand(int x, int y, int pred)
+{
+ struct cand *q;
+
+ if (clen == clistlen) {
+ clistlen = clistlen * 11 / 10;
+ clist = xrealloc(clist, clistlen * sizeof(struct cand));
+ }
+ q = clist + clen;
+ q->x = x;
+ q->y = y;
+ q->pred = pred;
+ return clen++;
+}
+
+
+static int search(int *c, int k, int y)
+{
+ int i, j, l, t;
+
+ if (clist[c[k]].y < y) /* quick look for typical case */
+ return k + 1;
+ i = 0;
+ j = k + 1;
+ while (1) {
+ l = i + j;
+ if ((l >>= 1) <= i)
+ break;
+ t = clist[c[l]].y;
+ if (t > y)
+ j = l;
+ else if (t < y)
+ i = l;
+ else
+ return l;
+ }
+ return l + 1;
+}
+
+
+static int stone(int *a, int n, int *b, int *c)
+{
+ int i, k, y, j, l;
+ int oldc, tc, oldl;
+ unsigned int numtries;
+#if ENABLE_FEATURE_DIFF_MINIMAL
+ const unsigned int bound =
+ (option_mask32 & FLAG_d) ? UINT_MAX : MAX(256, isqrt(n));
+#else
+ const unsigned int bound = MAX(256, isqrt(n));
+#endif
+
+ k = 0;
+ c[0] = newcand(0, 0, 0);
+ for (i = 1; i <= n; i++) {
+ j = a[i];
+ if (j == 0)
+ continue;
+ y = -b[j];
+ oldl = 0;
+ oldc = c[0];
+ numtries = 0;
+ do {
+ if (y <= clist[oldc].y)
+ continue;
+ l = search(c, k, y);
+ if (l != oldl + 1)
+ oldc = c[l - 1];
+ if (l <= k) {
+ if (clist[c[l]].y <= y)
+ continue;
+ tc = c[l];
+ c[l] = newcand(i, y, oldc);
+ oldc = tc;
+ oldl = l;
+ numtries++;
+ } else {
+ c[l] = newcand(i, y, oldc);
+ k++;
+ break;
+ }
+ } while ((y = b[++j]) > 0 && numtries < bound);
+ }
+ return k;
+}
+
+
+static void unravel(int p)
+{
+ struct cand *q;
+ int i;
+
+ for (i = 0; i <= nlen[0]; i++)
+ J[i] = i <= pref ? i : i > nlen[0] - suff ? i + nlen[1] - nlen[0] : 0;
+ for (q = clist + p; q->y != 0; q = clist + q->pred)
+ J[q->x + pref] = q->y + pref;
+}
+
+
+static void unsort(struct line *f, int l, int *b)
+{
+ int *a, i;
+
+ a = xmalloc((l + 1) * sizeof(int));
+ for (i = 1; i <= l; i++)
+ a[f[i].serial] = f[i].value;
+ for (i = 1; i <= l; i++)
+ b[i] = a[i];
+ free(a);
+}
+
+
+static int skipline(FILE *f)
+{
+ int i, c;
+
+ for (i = 1; (c = getc(f)) != '\n' && c != EOF; i++)
+ continue;
+ return i;
+}
+
+
+/*
+ * Check does double duty:
+ * 1. ferret out any fortuitous correspondences due
+ * to confounding by hashing (which result in "jackpot")
+ * 2. collect random access indexes to the two files
+ */
+static NOINLINE void check(FILE *f1, FILE *f2)
+{
+ int i, j, jackpot, c, d;
+ long ctold, ctnew;
+
+ rewind(f1);
+ rewind(f2);
+ j = 1;
+ ixold[0] = ixnew[0] = 0;
+ jackpot = 0;
+ ctold = ctnew = 0;
+ for (i = 1; i <= nlen[0]; i++) {
+ if (J[i] == 0) {
+ ixold[i] = ctold += skipline(f1);
+ continue;
+ }
+ while (j < J[i]) {
+ ixnew[j] = ctnew += skipline(f2);
+ j++;
+ }
+ if (option_mask32 & (FLAG_b | FLAG_w | FLAG_i)) {
+ while (1) {
+ c = getc(f1);
+ d = getc(f2);
+ /*
+ * GNU diff ignores a missing newline
+ * in one file if bflag || wflag.
+ */
+ if ((option_mask32 & (FLAG_b | FLAG_w))
+ && ((c == EOF && d == '\n') || (c == '\n' && d == EOF))
+ ) {
+ break;
+ }
+ ctold++;
+ ctnew++;
+ if ((option_mask32 & FLAG_b) && isspace(c) && isspace(d)) {
+ do {
+ if (c == '\n')
+ break;
+ ctold++;
+ c = getc(f1);
+ } while (isspace(c));
+ do {
+ if (d == '\n')
+ break;
+ ctnew++;
+ d = getc(f2);
+ } while (isspace(d));
+ } else if (option_mask32 & FLAG_w) {
+ while (isspace(c) && c != '\n') {
+ c = getc(f1);
+ ctold++;
+ }
+ while (isspace(d) && d != '\n') {
+ d = getc(f2);
+ ctnew++;
+ }
+ }
+ if (c != d) {
+ jackpot++;
+ J[i] = 0;
+ if (c != '\n' && c != EOF)
+ ctold += skipline(f1);
+ if (d != '\n' && c != EOF)
+ ctnew += skipline(f2);
+ break;
+ }
+ if (c == '\n' || c == EOF)
+ break;
+ }
+ } else {
+ while (1) {
+ ctold++;
+ ctnew++;
+ c = getc(f1);
+ d = getc(f2);
+ if (c != d) {
+ J[i] = 0;
+ if (c != '\n' && c != EOF)
+ ctold += skipline(f1);
+/* was buggy? "if (d != '\n' && c != EOF)" */
+ if (d != '\n' && d != EOF)
+ ctnew += skipline(f2);
+ break;
+ }
+ if (c == '\n' || c == EOF)
+ break;
+ }
+ }
+ ixold[i] = ctold;
+ ixnew[j] = ctnew;
+ j++;
+ }
+ for (; j <= nlen[1]; j++)
+ ixnew[j] = ctnew += skipline(f2);
+}
+
+
+/* shellsort CACM #201 */
+static void sort(struct line *a, int n)
+{
+ struct line *ai, *aim, w;
+ int j, m = 0, k;
+
+ if (n == 0)
+ return;
+ for (j = 1; j <= n; j *= 2)
+ m = 2 * j - 1;
+ for (m /= 2; m != 0; m /= 2) {
+ k = n - m;
+ for (j = 1; j <= k; j++) {
+ for (ai = &a[j]; ai > a; ai -= m) {
+ aim = &ai[m];
+ if (aim < ai)
+ break; /* wraparound */
+ if (aim->value > ai[0].value
+ || (aim->value == ai[0].value && aim->serial > ai[0].serial)
+ ) {
+ break;
+ }
+ w.value = ai[0].value;
+ ai[0].value = aim->value;
+ aim->value = w.value;
+ w.serial = ai[0].serial;
+ ai[0].serial = aim->serial;
+ aim->serial = w.serial;
+ }
+ }
+ }
+}
+
+
+static void uni_range(int a, int b)
+{
+ if (a < b)
+ printf("%d,%d", a, b - a + 1);
+ else if (a == b)
+ printf("%d", b);
+ else
+ printf("%d,0", b);
+}
+
+
+static void fetch(long *f, int a, int b, FILE *lb, int ch)
+{
+ int i, j, c, lastc, col, nc;
+
+ if (a > b)
+ return;
+ for (i = a; i <= b; i++) {
+ fseek(lb, f[i - 1], SEEK_SET);
+ nc = f[i] - f[i - 1];
+ if (ch != '\0') {
+ putchar(ch);
+ if (option_mask32 & FLAG_T)
+ putchar('\t');
+ }
+ col = 0;
+ for (j = 0, lastc = '\0'; j < nc; j++, lastc = c) {
+ c = getc(lb);
+ if (c == EOF) {
+ printf("\n\\ No newline at end of file\n");
+ return;
+ }
+ if (c == '\t' && (option_mask32 & FLAG_t)) {
+ do {
+ putchar(' ');
+ } while (++col & 7);
+ } else {
+ putchar(c);
+ col++;
+ }
+ }
+ }
+}
+
+
+#if ENABLE_FEATURE_DIFF_BINARY
+static int asciifile(FILE *f)
+{
+ int i, cnt;
+
+ if (option_mask32 & FLAG_a)
+ return 1;
+ rewind(f);
+ cnt = fread(g_read_buf, 1, COMMON_BUFSIZE, f);
+ for (i = 0; i < cnt; i++) {
+ if (!isprint(g_read_buf[i])
+ && !isspace(g_read_buf[i])
+ ) {
+ return 0;
+ }
+ }
+ return 1;
+}
+#else
+#define asciifile(f) 1
+#endif
+
+
+/* dump accumulated "unified" diff changes */
+static void dump_unified_vec(FILE *f1, FILE *f2)
+{
+ struct context_vec *cvp = context_vec_start;
+ int lowa, upb, lowc, upd;
+ int a, b, c, d;
+ char ch;
+
+ if (context_vec_start > context_vec_ptr)
+ return;
+
+ b = d = 0; /* gcc */
+ lowa = MAX(1, cvp->a - opt_U_context);
+ upb = MIN(nlen[0], context_vec_ptr->b + opt_U_context);
+ lowc = MAX(1, cvp->c - opt_U_context);
+ upd = MIN(nlen[1], context_vec_ptr->d + opt_U_context);
+
+ printf("@@ -");
+ uni_range(lowa, upb);
+ printf(" +");
+ uni_range(lowc, upd);
+ printf(" @@\n");
+
+ /*
+ * Output changes in "unified" diff format--the old and new lines
+ * are printed together.
+ */
+ for (; cvp <= context_vec_ptr; cvp++) {
+ a = cvp->a;
+ b = cvp->b;
+ c = cvp->c;
+ d = cvp->d;
+
+ /*
+ * c: both new and old changes
+ * d: only changes in the old file
+ * a: only changes in the new file
+ */
+ if (a <= b && c <= d)
+ ch = 'c';
+ else
+ ch = (a <= b) ? 'd' : 'a';
+#if 0
+ switch (ch) {
+ case 'c':
+// fetch() seeks!
+ fetch(ixold, lowa, a - 1, f1, ' ');
+ fetch(ixold, a, b, f1, '-');
+ fetch(ixnew, c, d, f2, '+');
+ break;
+ case 'd':
+ fetch(ixold, lowa, a - 1, f1, ' ');
+ fetch(ixold, a, b, f1, '-');
+ break;
+ case 'a':
+ fetch(ixnew, lowc, c - 1, f2, ' ');
+ fetch(ixnew, c, d, f2, '+');
+ break;
+ }
+#else
+ if (ch == 'c' || ch == 'd') {
+ fetch(ixold, lowa, a - 1, f1, ' ');
+ fetch(ixold, a, b, f1, '-');
+ }
+ if (ch == 'a')
+ fetch(ixnew, lowc, c - 1, f2, ' ');
+ if (ch == 'c' || ch == 'a')
+ fetch(ixnew, c, d, f2, '+');
+#endif
+ lowa = b + 1;
+ lowc = d + 1;
+ }
+ fetch(ixnew, d + 1, upd, f2, ' ');
+
+ context_vec_ptr = context_vec_start - 1;
+}
+
+
+static void print_header(const char *file1, const char *file2)
+{
+ if (label1)
+ printf("--- %s\n", label1);
+ else
+ printf("--- %s\t%s", file1, ctime(&stb1.st_mtime));
+ if (label2)
+ printf("+++ %s\n", label2);
+ else
+ printf("+++ %s\t%s", file2, ctime(&stb2.st_mtime));
+}
+
+
+/*
+ * Indicate that there is a difference between lines a and b of the from file
+ * to get to lines c to d of the to file. If a is greater than b then there
+ * are no lines in the from file involved and this means that there were
+ * lines appended (beginning at b). If c is greater than d then there are
+ * lines missing from the to file.
+ */
+static void change(char *file1, FILE *f1, char *file2, FILE *f2,
+ int a, int b, int c, int d)
+{
+ if ((a > b && c > d) || (option_mask32 & FLAG_q)) {
+ anychange = 1;
+ return;
+ }
+
+ /*
+ * Allocate change records as needed.
+ */
+ if (context_vec_ptr == context_vec_end - 1) {
+ ptrdiff_t offset = context_vec_ptr - context_vec_start;
+
+ max_context <<= 1;
+ context_vec_start = xrealloc(context_vec_start,
+ max_context * sizeof(struct context_vec));
+ context_vec_end = context_vec_start + max_context;
+ context_vec_ptr = context_vec_start + offset;
+ }
+ if (anychange == 0) {
+ /*
+ * Print the context/unidiff header first time through.
+ */
+ print_header(file1, file2);
+ } else if (a > context_vec_ptr->b + (2 * opt_U_context) + 1
+ && c > context_vec_ptr->d + (2 * opt_U_context) + 1
+ ) {
+ /*
+ * If this change is more than 'context' lines from the
+ * previous change, dump the record and reset it.
+ */
+// dump_unified_vec() seeks!
+ dump_unified_vec(f1, f2);
+ }
+ context_vec_ptr++;
+ context_vec_ptr->a = a;
+ context_vec_ptr->b = b;
+ context_vec_ptr->c = c;
+ context_vec_ptr->d = d;
+ anychange = 1;
+}
+
+
+static void output(char *file1, FILE *f1, char *file2, FILE *f2)
+{
+ /* Note that j0 and j1 can't be used as they are defined in math.h.
+ * This also allows the rather amusing variable 'j00'... */
+ int m, i0, i1, j00, j01;
+
+ rewind(f1);
+ rewind(f2);
+ m = nlen[0];
+ J[0] = 0;
+ J[m + 1] = nlen[1] + 1;
+ for (i0 = 1; i0 <= m; i0 = i1 + 1) {
+ while (i0 <= m && J[i0] == J[i0 - 1] + 1)
+ i0++;
+ j00 = J[i0 - 1] + 1;
+ i1 = i0 - 1;
+ while (i1 < m && J[i1 + 1] == 0)
+ i1++;
+ j01 = J[i1 + 1] - 1;
+ J[i1] = j01;
+// change() seeks!
+ change(file1, f1, file2, f2, i0, i1, j00, j01);
+ }
+ if (m == 0) {
+// change() seeks!
+ change(file1, f1, file2, f2, 1, 0, 1, nlen[1]);
+ }
+ if (anychange != 0 && !(option_mask32 & FLAG_q)) {
+// dump_unified_vec() seeks!
+ dump_unified_vec(f1, f2);
+ }
+}
+
+/*
+ * The following code uses an algorithm due to Harold Stone,
+ * which finds a pair of longest identical subsequences in
+ * the two files.
+ *
+ * The major goal is to generate the match vector J.
+ * J[i] is the index of the line in file1 corresponding
+ * to line i in file0. J[i] = 0 if there is no
+ * such line in file1.
+ *
+ * Lines are hashed so as to work in core. All potential
+ * matches are located by sorting the lines of each file
+ * on the hash (called "value"). In particular, this
+ * collects the equivalence classes in file1 together.
+ * Subroutine equiv replaces the value of each line in
+ * file0 by the index of the first element of its
+ * matching equivalence in (the reordered) file1.
+ * To save space equiv squeezes file1 into a single
+ * array member in which the equivalence classes
+ * are simply concatenated, except that their first
+ * members are flagged by changing sign.
+ *
+ * Next the indices that point into member are unsorted into
+ * array class according to the original order of file0.
+ *
+ * The cleverness lies in routine stone. This marches
+ * through the lines of file0, developing a vector klist
+ * of "k-candidates". At step i a k-candidate is a matched
+ * pair of lines x,y (x in file0, y in file1) such that
+ * there is a common subsequence of length k
+ * between the first i lines of file0 and the first y
+ * lines of file1, but there is no such subsequence for
+ * any smaller y. x is the earliest possible mate to y
+ * that occurs in such a subsequence.
+ *
+ * Whenever any of the members of the equivalence class of
+ * lines in file1 matable to a line in file0 has serial number
+ * less than the y of some k-candidate, that k-candidate
+ * with the smallest such y is replaced. The new
+ * k-candidate is chained (via pred) to the current
+ * k-1 candidate so that the actual subsequence can
+ * be recovered. When a member has serial number greater
+ * that the y of all k-candidates, the klist is extended.
+ * At the end, the longest subsequence is pulled out
+ * and placed in the array J by unravel
+ *
+ * With J in hand, the matches there recorded are
+ * checked against reality to assure that no spurious
+ * matches have crept in due to hashing. If they have,
+ * they are broken, and "jackpot" is recorded--a harmless
+ * matter except that a true match for a spuriously
+ * mated line may now be unnecessarily reported as a change.
+ *
+ * Much of the complexity of the program comes simply
+ * from trying to minimize core utilization and
+ * maximize the range of doable problems by dynamically
+ * allocating what is needed and reusing what is not.
+ * The core requirements for problems larger than somewhat
+ * are (in words) 2*length(file0) + length(file1) +
+ * 3*(number of k-candidates installed), typically about
+ * 6n words for files of length n.
+ */
+/* NB: files can be not REGular. The only sure thing that they
+ * are not both DIRectories. */
+static unsigned diffreg(char *file1, char *file2, int flags)
+{
+ int *member; /* will be overlaid on nfile[1] */
+ int *class; /* will be overlaid on nfile[0] */
+ int *klist; /* will be overlaid on nfile[0] after class */
+ FILE *f1;
+ FILE *f2;
+ unsigned rval;
+ int i;
+
+ anychange = 0;
+ context_vec_ptr = context_vec_start - 1;
+ tempname1 = tempname2 = NULL;
+
+ /* Is any of them a directory? Then it's simple */
+ if (S_ISDIR(stb1.st_mode) != S_ISDIR(stb2.st_mode))
+ return (S_ISDIR(stb1.st_mode) ? D_ISDIR1 : D_ISDIR2);
+
+ /* None of them are directories */
+ rval = D_SAME;
+
+ if (flags & D_EMPTY1)
+ /* can't be stdin, but xfopen_stdin() is smaller code */
+ f1 = xfopen_stdin(bb_dev_null);
+ else
+ f1 = xfopen_stdin(file1);
+ if (flags & D_EMPTY2)
+ f2 = xfopen_stdin(bb_dev_null);
+ else
+ f2 = xfopen_stdin(file2);
+
+ /* NB: if D_EMPTY1/2 is set, other file is always a regular file,
+ * not pipe/fifo/chardev/etc - D_EMPTY is used by "diff -r" only,
+ * and it never diffs non-ordinary files in subdirs. */
+ if (!(flags & (D_EMPTY1 | D_EMPTY2))) {
+ /* Quick check whether they are different */
+ /* NB: copies non-REG files to tempfiles and fills tempname1/2 */
+ i = files_differ(f1, f2);
+ if (i != 1) { /* not different? */
+ if (i != 0) /* error? */
+ exit_status |= 2;
+ goto closem;
+ }
+ }
+
+ if (!asciifile(f1) || !asciifile(f2)) {
+ rval = D_BINARY;
+ exit_status |= 1;
+ goto closem;
+ }
+
+// Rewind inside!
+ prepare(0, f1 /*, stb1.st_size*/);
+ prepare(1, f2 /*, stb2.st_size*/);
+ prune();
+ sort(sfile[0], slen[0]);
+ sort(sfile[1], slen[1]);
+
+ member = (int *) nfile[1];
+ equiv(sfile[0], slen[0], sfile[1], slen[1], member);
+ member = xrealloc(member, (slen[1] + 2) * sizeof(int));
+
+ class = (int *) nfile[0];
+ unsort(sfile[0], slen[0], class);
+ class = xrealloc(class, (slen[0] + 2) * sizeof(int));
+
+ klist = xmalloc((slen[0] + 2) * sizeof(int));
+ clen = 0;
+ clistlen = 100;
+ clist = xmalloc(clistlen * sizeof(struct cand));
+ i = stone(class, slen[0], member, klist);
+ free(member);
+ free(class);
+
+ J = xrealloc(J, (nlen[0] + 2) * sizeof(int));
+ unravel(klist[i]);
+ free(clist);
+ free(klist);
+
+ ixold = xrealloc(ixold, (nlen[0] + 2) * sizeof(long));
+ ixnew = xrealloc(ixnew, (nlen[1] + 2) * sizeof(long));
+// Rewind inside!
+ check(f1, f2);
+// Rewind inside!
+ output(file1, f1, file2, f2);
+
+ closem:
+ if (anychange) {
+ exit_status |= 1;
+ if (rval == D_SAME)
+ rval = D_DIFFER;
+ }
+ fclose_if_not_stdin(f1);
+ fclose_if_not_stdin(f2);
+ if (tempname1) {
+ unlink(tempname1);
+ free(tempname1);
+ }
+ if (tempname2) {
+ unlink(tempname2);
+ free(tempname2);
+ }
+ return rval;
+}
+
+
+#if ENABLE_FEATURE_DIFF_DIR
+static void do_diff(char *dir1, char *path1, char *dir2, char *path2)
+{
+ int flags = 0; /*D_HEADER;*/
+ int val;
+ char *fullpath1 = NULL; /* if -N */
+ char *fullpath2 = NULL;
+
+ if (path1)
+ fullpath1 = concat_path_file(dir1, path1);
+ if (path2)
+ fullpath2 = concat_path_file(dir2, path2);
+
+ if (!fullpath1 || stat(fullpath1, &stb1) != 0) {
+ flags |= D_EMPTY1;
+ memset(&stb1, 0, sizeof(stb1));
+ if (path2) {
+ free(fullpath1);
+ fullpath1 = concat_path_file(dir1, path2);
+ }
+ }
+ if (!fullpath2 || stat(fullpath2, &stb2) != 0) {
+ flags |= D_EMPTY2;
+ memset(&stb2, 0, sizeof(stb2));
+ stb2.st_mode = stb1.st_mode;
+ if (path1) {
+ free(fullpath2);
+ fullpath2 = concat_path_file(dir2, path1);
+ }
+ }
+
+ if (stb1.st_mode == 0)
+ stb1.st_mode = stb2.st_mode;
+
+ if (S_ISDIR(stb1.st_mode) && S_ISDIR(stb2.st_mode)) {
+ printf("Common subdirectories: %s and %s\n", fullpath1, fullpath2);
+ goto ret;
+ }
+
+ if (!S_ISREG(stb1.st_mode) && !S_ISDIR(stb1.st_mode))
+ val = D_SKIPPED1;
+ else if (!S_ISREG(stb2.st_mode) && !S_ISDIR(stb2.st_mode))
+ val = D_SKIPPED2;
+ else {
+ /* Both files are either REGular or DIRectories */
+ val = diffreg(fullpath1, fullpath2, flags);
+ }
+
+ print_status(val, fullpath1, fullpath2 /*, NULL*/);
+ ret:
+ free(fullpath1);
+ free(fullpath2);
+}
+#endif
+
+
+#if ENABLE_FEATURE_DIFF_DIR
+/* This function adds a filename to dl, the directory listing. */
+static int add_to_dirlist(const char *filename,
+ struct stat *sb ATTRIBUTE_UNUSED,
+ void *userdata,
+ int depth ATTRIBUTE_UNUSED)
+{
+ /* +2: with space for eventual trailing NULL */
+ dl = xrealloc(dl, (dl_count+2) * sizeof(dl[0]));
+ dl[dl_count] = xstrdup(filename + (int)(ptrdiff_t)userdata);
+ dl_count++;
+ return TRUE;
+}
+
+
+/* This returns a sorted directory listing. */
+static char **get_recursive_dirlist(char *path)
+{
+ dl_count = 0;
+ dl = xzalloc(sizeof(dl[0]));
+
+ /* We need to trim root directory prefix.
+ * Using void *userdata to specify its length,
+ * add_to_dirlist will remove it. */
+ if (option_mask32 & FLAG_r) {
+ recursive_action(path, ACTION_RECURSE|ACTION_FOLLOWLINKS,
+ add_to_dirlist, /* file_action */
+ NULL, /* dir_action */
+ (void*)(strlen(path) + 1),
+ 0);
+ } else {
+ DIR *dp;
+ struct dirent *ep;
+
+ dp = warn_opendir(path);
+ while ((ep = readdir(dp))) {
+ if (!strcmp(ep->d_name, "..") || LONE_CHAR(ep->d_name, '.'))
+ continue;
+ add_to_dirlist(ep->d_name, NULL, (void*)(int)0, 0);
+ }
+ closedir(dp);
+ }
+
+ /* Sort dl alphabetically. */
+ qsort_string_vector(dl, dl_count);
+
+ dl[dl_count] = NULL;
+ return dl;
+}
+
+
+static void diffdir(char *p1, char *p2)
+{
+ char **dirlist1, **dirlist2;
+ char *dp1, *dp2;
+ int pos;
+
+ /* Check for trailing slashes. */
+ dp1 = last_char_is(p1, '/');
+ if (dp1 != NULL)
+ *dp1 = '\0';
+ dp2 = last_char_is(p2, '/');
+ if (dp2 != NULL)
+ *dp2 = '\0';
+
+ /* Get directory listings for p1 and p2. */
+ dirlist1 = get_recursive_dirlist(p1);
+ dirlist2 = get_recursive_dirlist(p2);
+
+ /* If -S was set, find the starting point. */
+ if (opt_S_start) {
+ while (*dirlist1 != NULL && strcmp(*dirlist1, opt_S_start) < 0)
+ dirlist1++;
+ while (*dirlist2 != NULL && strcmp(*dirlist2, opt_S_start) < 0)
+ dirlist2++;
+ if ((*dirlist1 == NULL) || (*dirlist2 == NULL))
+ bb_error_msg(bb_msg_invalid_arg, "NULL", "-S");
+ }
+
+ /* Now that both dirlist1 and dirlist2 contain sorted directory
+ * listings, we can start to go through dirlist1. If both listings
+ * contain the same file, then do a normal diff. Otherwise, behaviour
+ * is determined by whether the -N flag is set. */
+ while (*dirlist1 != NULL || *dirlist2 != NULL) {
+ dp1 = *dirlist1;
+ dp2 = *dirlist2;
+ pos = dp1 == NULL ? 1 : (dp2 == NULL ? -1 : strcmp(dp1, dp2));
+ if (pos == 0) {
+ do_diff(p1, dp1, p2, dp2);
+ dirlist1++;
+ dirlist2++;
+ } else if (pos < 0) {
+ if (option_mask32 & FLAG_N)
+ do_diff(p1, dp1, p2, NULL);
+ else
+ print_only(p1, dp1);
+ dirlist1++;
+ } else {
+ if (option_mask32 & FLAG_N)
+ do_diff(p1, NULL, p2, dp2);
+ else
+ print_only(p2, dp2);
+ dirlist2++;
+ }
+ }
+}
+#endif
+
+
+int diff_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int diff_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ int gotstdin = 0;
+ char *f1, *f2;
+ llist_t *L_arg = NULL;
+
+ INIT_G();
+
+ /* exactly 2 params; collect multiple -L <label>; -U N */
+ opt_complementary = "=2:L::U+";
+ getopt32(argv, "abdiL:NqrsS:tTU:wu"
+ "p" /* ignored (for compatibility) */,
+ &L_arg, &opt_S_start, &opt_U_context);
+ /*argc -= optind;*/
+ argv += optind;
+ while (L_arg) {
+ if (label1 && label2)
+ bb_show_usage();
+ if (label1) /* then label2 is NULL */
+ label2 = label1;
+ label1 = llist_pop(&L_arg);
+ }
+
+ /*
+ * Do sanity checks, fill in stb1 and stb2 and call the appropriate
+ * driver routine. Both drivers use the contents of stb1 and stb2.
+ */
+ f1 = argv[0];
+ f2 = argv[1];
+ if (LONE_DASH(f1)) {
+ fstat(STDIN_FILENO, &stb1);
+ gotstdin++;
+ } else
+ xstat(f1, &stb1);
+ if (LONE_DASH(f2)) {
+ fstat(STDIN_FILENO, &stb2);
+ gotstdin++;
+ } else
+ xstat(f2, &stb2);
+
+ if (gotstdin && (S_ISDIR(stb1.st_mode) || S_ISDIR(stb2.st_mode)))
+ bb_error_msg_and_die("can't compare stdin to a directory");
+
+ if (S_ISDIR(stb1.st_mode) && S_ISDIR(stb2.st_mode)) {
+#if ENABLE_FEATURE_DIFF_DIR
+ diffdir(f1, f2);
+ return exit_status;
+#else
+ bb_error_msg_and_die("no support for directory comparison");
+#endif
+ }
+
+ if (S_ISDIR(stb1.st_mode)) { /* "diff dir file" */
+ /* NB: "diff dir dir2/dir3/file" must become
+ * "diff dir/file dir2/dir3/file" */
+ char *slash = strrchr(f2, '/');
+ f1 = concat_path_file(f1, slash ? slash + 1 : f2);
+ xstat(f1, &stb1);
+ }
+ if (S_ISDIR(stb2.st_mode)) {
+ char *slash = strrchr(f1, '/');
+ f2 = concat_path_file(f2, slash ? slash + 1 : f1);
+ xstat(f2, &stb2);
+ }
+
+ /* diffreg can get non-regular files here,
+ * they are not both DIRestories */
+ print_status((gotstdin > 1 ? D_SAME : diffreg(f1, f2, 0)),
+ f1, f2 /*, NULL*/);
+ return exit_status;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/editors/ed.c b/cleopatre/busybox-1.11.1-spc300/editors/ed.c
new file mode 100644
index 0000000000..0961cc38ea
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/editors/ed.c
@@ -0,0 +1,1049 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (c) 2002 by David I. Bell
+ * Permission is granted to use, distribute, or modify this source,
+ * provided that this copyright notice remains intact.
+ *
+ * The "ed" built-in command (much simplified)
+ */
+
+#include "libbb.h"
+
+typedef struct LINE {
+ struct LINE *next;
+ struct LINE *prev;
+ int len;
+ char data[1];
+} LINE;
+
+
+#define searchString bb_common_bufsiz1
+
+enum {
+ USERSIZE = sizeof(searchString) > 1024 ? 1024
+ : sizeof(searchString) - 1, /* max line length typed in by user */
+ INITBUF_SIZE = 1024, /* initial buffer size */
+};
+
+struct globals {
+ int curNum;
+ int lastNum;
+ int bufUsed;
+ int bufSize;
+ LINE *curLine;
+ char *bufBase;
+ char *bufPtr;
+ char *fileName;
+ LINE lines;
+ smallint dirty;
+ int marks[26];
+};
+#define G (*ptr_to_globals)
+#define curLine (G.curLine )
+#define bufBase (G.bufBase )
+#define bufPtr (G.bufPtr )
+#define fileName (G.fileName )
+#define curNum (G.curNum )
+#define lastNum (G.lastNum )
+#define bufUsed (G.bufUsed )
+#define bufSize (G.bufSize )
+#define dirty (G.dirty )
+#define lines (G.lines )
+#define marks (G.marks )
+#define INIT_G() do { \
+ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
+} while (0)
+
+
+static void doCommands(void);
+static void subCommand(const char *cmd, int num1, int num2);
+static int getNum(const char **retcp, smallint *retHaveNum, int *retNum);
+static int setCurNum(int num);
+static void addLines(int num);
+static int insertLine(int num, const char *data, int len);
+static void deleteLines(int num1, int num2);
+static int printLines(int num1, int num2, int expandFlag);
+static int writeLines(const char *file, int num1, int num2);
+static int readLines(const char *file, int num);
+static int searchLines(const char *str, int num1, int num2);
+static LINE *findLine(int num);
+static int findString(const LINE *lp, const char * str, int len, int offset);
+
+
+static int bad_nums(int num1, int num2, const char *for_what)
+{
+ if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) {
+ bb_error_msg("bad line range for %s", for_what);
+ return 1;
+ }
+ return 0;
+}
+
+
+static char *skip_blank(const char *cp)
+{
+ while (isblank(*cp))
+ cp++;
+ return (char *)cp;
+}
+
+
+int ed_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int ed_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ INIT_G();
+
+ bufSize = INITBUF_SIZE;
+ bufBase = xmalloc(bufSize);
+ bufPtr = bufBase;
+ lines.next = &lines;
+ lines.prev = &lines;
+
+ if (argv[1]) {
+ fileName = xstrdup(argv[1]);
+ if (!readLines(fileName, 1)) {
+ return EXIT_SUCCESS;
+ }
+ if (lastNum)
+ setCurNum(1);
+ dirty = FALSE;
+ }
+
+ doCommands();
+ return EXIT_SUCCESS;
+}
+
+/*
+ * Read commands until we are told to stop.
+ */
+static void doCommands(void)
+{
+ const char *cp;
+ char *endbuf, buf[USERSIZE];
+ int len, num1, num2;
+ smallint have1, have2;
+
+ while (TRUE) {
+ /* Returns:
+ * -1 on read errors or EOF, or on bare Ctrl-D.
+ * 0 on ctrl-C,
+ * >0 length of input string, including terminating '\n'
+ */
+ len = read_line_input(": ", buf, sizeof(buf), NULL);
+ if (len <= 0)
+ return;
+ endbuf = &buf[len - 1];
+ while ((endbuf > buf) && isblank(endbuf[-1]))
+ endbuf--;
+ *endbuf = '\0';
+
+ cp = skip_blank(buf);
+ have1 = FALSE;
+ have2 = FALSE;
+
+ if ((curNum == 0) && (lastNum > 0)) {
+ curNum = 1;
+ curLine = lines.next;
+ }
+
+ if (!getNum(&cp, &have1, &num1))
+ continue;
+
+ cp = skip_blank(cp);
+
+ if (*cp == ',') {
+ cp++;
+ if (!getNum(&cp, &have2, &num2))
+ continue;
+ if (!have1)
+ num1 = 1;
+ if (!have2)
+ num2 = lastNum;
+ have1 = TRUE;
+ have2 = TRUE;
+ }
+ if (!have1)
+ num1 = curNum;
+ if (!have2)
+ num2 = num1;
+
+ switch (*cp++) {
+ case 'a':
+ addLines(num1 + 1);
+ break;
+
+ case 'c':
+ deleteLines(num1, num2);
+ addLines(num1);
+ break;
+
+ case 'd':
+ deleteLines(num1, num2);
+ break;
+
+ case 'f':
+ if (*cp && !isblank(*cp)) {
+ bb_error_msg("bad file command");
+ break;
+ }
+ cp = skip_blank(cp);
+ if (*cp == '\0') {
+ if (fileName)
+ printf("\"%s\"\n", fileName);
+ else
+ printf("No file name\n");
+ break;
+ }
+ free(fileName);
+ fileName = xstrdup(cp);
+ break;
+
+ case 'i':
+ addLines(num1);
+ break;
+
+ case 'k':
+ cp = skip_blank(cp);
+ if ((*cp < 'a') || (*cp > 'z') || cp[1]) {
+ bb_error_msg("bad mark name");
+ break;
+ }
+ marks[*cp - 'a'] = num2;
+ break;
+
+ case 'l':
+ printLines(num1, num2, TRUE);
+ break;
+
+ case 'p':
+ printLines(num1, num2, FALSE);
+ break;
+
+ case 'q':
+ cp = skip_blank(cp);
+ if (have1 || *cp) {
+ bb_error_msg("bad quit command");
+ break;
+ }
+ if (!dirty)
+ return;
+ len = read_line_input("Really quit? ", buf, 16, NULL);
+ /* read error/EOF - no way to continue */
+ if (len < 0)
+ return;
+ cp = skip_blank(buf);
+ if ((*cp | 0x20) == 'y') /* Y or y */
+ return;
+ break;
+
+ case 'r':
+ if (*cp && !isblank(*cp)) {
+ bb_error_msg("bad read command");
+ break;
+ }
+ cp = skip_blank(cp);
+ if (*cp == '\0') {
+ bb_error_msg("no file name");
+ break;
+ }
+ if (!have1)
+ num1 = lastNum;
+ if (readLines(cp, num1 + 1))
+ break;
+ if (fileName == NULL)
+ fileName = xstrdup(cp);
+ break;
+
+ case 's':
+ subCommand(cp, num1, num2);
+ break;
+
+ case 'w':
+ if (*cp && !isblank(*cp)) {
+ bb_error_msg("bad write command");
+ break;
+ }
+ cp = skip_blank(cp);
+ if (!have1) {
+ num1 = 1;
+ num2 = lastNum;
+ }
+ if (*cp == '\0')
+ cp = fileName;
+ if (cp == NULL) {
+ bb_error_msg("no file name specified");
+ break;
+ }
+ writeLines(cp, num1, num2);
+ break;
+
+ case 'z':
+ switch (*cp) {
+ case '-':
+ printLines(curNum - 21, curNum, FALSE);
+ break;
+ case '.':
+ printLines(curNum - 11, curNum + 10, FALSE);
+ break;
+ default:
+ printLines(curNum, curNum + 21, FALSE);
+ break;
+ }
+ break;
+
+ case '.':
+ if (have1) {
+ bb_error_msg("no arguments allowed");
+ break;
+ }
+ printLines(curNum, curNum, FALSE);
+ break;
+
+ case '-':
+ if (setCurNum(curNum - 1))
+ printLines(curNum, curNum, FALSE);
+ break;
+
+ case '=':
+ printf("%d\n", num1);
+ break;
+ case '\0':
+ if (have1) {
+ printLines(num2, num2, FALSE);
+ break;
+ }
+ if (setCurNum(curNum + 1))
+ printLines(curNum, curNum, FALSE);
+ break;
+
+ default:
+ bb_error_msg("unimplemented command");
+ break;
+ }
+ }
+}
+
+
+/*
+ * Do the substitute command.
+ * The current line is set to the last substitution done.
+ */
+static void subCommand(const char *cmd, int num1, int num2)
+{
+ char *cp, *oldStr, *newStr, buf[USERSIZE];
+ int delim, oldLen, newLen, deltaLen, offset;
+ LINE *lp, *nlp;
+ int globalFlag, printFlag, didSub, needPrint;
+
+ if (bad_nums(num1, num2, "substitute"))
+ return;
+
+ globalFlag = FALSE;
+ printFlag = FALSE;
+ didSub = FALSE;
+ needPrint = FALSE;
+
+ /*
+ * Copy the command so we can modify it.
+ */
+ strcpy(buf, cmd);
+ cp = buf;
+
+ if (isblank(*cp) || (*cp == '\0')) {
+ bb_error_msg("bad delimiter for substitute");
+ return;
+ }
+
+ delim = *cp++;
+ oldStr = cp;
+
+ cp = strchr(cp, delim);
+ if (cp == NULL) {
+ bb_error_msg("missing 2nd delimiter for substitute");
+ return;
+ }
+
+ *cp++ = '\0';
+
+ newStr = cp;
+ cp = strchr(cp, delim);
+
+ if (cp)
+ *cp++ = '\0';
+ else
+ cp = (char*)"";
+
+ while (*cp) switch (*cp++) {
+ case 'g':
+ globalFlag = TRUE;
+ break;
+ case 'p':
+ printFlag = TRUE;
+ break;
+ default:
+ bb_error_msg("unknown option for substitute");
+ return;
+ }
+
+ if (*oldStr == '\0') {
+ if (searchString[0] == '\0') {
+ bb_error_msg("no previous search string");
+ return;
+ }
+ oldStr = searchString;
+ }
+
+ if (oldStr != searchString)
+ strcpy(searchString, oldStr);
+
+ lp = findLine(num1);
+ if (lp == NULL)
+ return;
+
+ oldLen = strlen(oldStr);
+ newLen = strlen(newStr);
+ deltaLen = newLen - oldLen;
+ offset = 0;
+ nlp = NULL;
+
+ while (num1 <= num2) {
+ offset = findString(lp, oldStr, oldLen, offset);
+
+ if (offset < 0) {
+ if (needPrint) {
+ printLines(num1, num1, FALSE);
+ needPrint = FALSE;
+ }
+ offset = 0;
+ lp = lp->next;
+ num1++;
+ continue;
+ }
+
+ needPrint = printFlag;
+ didSub = TRUE;
+ dirty = TRUE;
+
+ /*
+ * If the replacement string is the same size or shorter
+ * than the old string, then the substitution is easy.
+ */
+ if (deltaLen <= 0) {
+ memcpy(&lp->data[offset], newStr, newLen);
+ if (deltaLen) {
+ memcpy(&lp->data[offset + newLen],
+ &lp->data[offset + oldLen],
+ lp->len - offset - oldLen);
+
+ lp->len += deltaLen;
+ }
+ offset += newLen;
+ if (globalFlag)
+ continue;
+ if (needPrint) {
+ printLines(num1, num1, FALSE);
+ needPrint = FALSE;
+ }
+ lp = lp->next;
+ num1++;
+ continue;
+ }
+
+ /*
+ * The new string is larger, so allocate a new line
+ * structure and use that. Link it in in place of
+ * the old line structure.
+ */
+ nlp = malloc(sizeof(LINE) + lp->len + deltaLen);
+ if (nlp == NULL) {
+ bb_error_msg("cannot get memory for line");
+ return;
+ }
+
+ nlp->len = lp->len + deltaLen;
+
+ memcpy(nlp->data, lp->data, offset);
+ memcpy(&nlp->data[offset], newStr, newLen);
+ memcpy(&nlp->data[offset + newLen],
+ &lp->data[offset + oldLen],
+ lp->len - offset - oldLen);
+
+ nlp->next = lp->next;
+ nlp->prev = lp->prev;
+ nlp->prev->next = nlp;
+ nlp->next->prev = nlp;
+
+ if (curLine == lp)
+ curLine = nlp;
+
+ free(lp);
+ lp = nlp;
+
+ offset += newLen;
+
+ if (globalFlag)
+ continue;
+
+ if (needPrint) {
+ printLines(num1, num1, FALSE);
+ needPrint = FALSE;
+ }
+
+ lp = lp->next;
+ num1++;
+ }
+
+ if (!didSub)
+ bb_error_msg("no substitutions found for \"%s\"", oldStr);
+}
+
+
+/*
+ * Search a line for the specified string starting at the specified
+ * offset in the line. Returns the offset of the found string, or -1.
+ */
+static int findString(const LINE *lp, const char *str, int len, int offset)
+{
+ int left;
+ const char *cp, *ncp;
+
+ cp = &lp->data[offset];
+ left = lp->len - offset;
+
+ while (left >= len) {
+ ncp = memchr(cp, *str, left);
+ if (ncp == NULL)
+ return -1;
+ left -= (ncp - cp);
+ if (left < len)
+ return -1;
+ cp = ncp;
+ if (memcmp(cp, str, len) == 0)
+ return (cp - lp->data);
+ cp++;
+ left--;
+ }
+
+ return -1;
+}
+
+
+/*
+ * Add lines which are typed in by the user.
+ * The lines are inserted just before the specified line number.
+ * The lines are terminated by a line containing a single dot (ugly!),
+ * or by an end of file.
+ */
+static void addLines(int num)
+{
+ int len;
+ char buf[USERSIZE + 1];
+
+ while (1) {
+ /* Returns:
+ * -1 on read errors or EOF, or on bare Ctrl-D.
+ * 0 on ctrl-C,
+ * >0 length of input string, including terminating '\n'
+ */
+ len = read_line_input("", buf, sizeof(buf), NULL);
+ if (len <= 0) {
+ /* Previously, ctrl-C was exiting to shell.
+ * Now we exit to ed prompt. Is in important? */
+ return;
+ }
+ if ((buf[0] == '.') && (buf[1] == '\n') && (buf[2] == '\0'))
+ return;
+ if (!insertLine(num++, buf, len))
+ return;
+ }
+}
+
+
+/*
+ * Parse a line number argument if it is present. This is a sum
+ * or difference of numbers, '.', '$', 'x, or a search string.
+ * Returns TRUE if successful (whether or not there was a number).
+ * Returns FALSE if there was a parsing error, with a message output.
+ * Whether there was a number is returned indirectly, as is the number.
+ * The character pointer which stopped the scan is also returned.
+ */
+static int getNum(const char **retcp, smallint *retHaveNum, int *retNum)
+{
+ const char *cp;
+ char *endStr, str[USERSIZE];
+ int value, num;
+ smallint haveNum, minus;
+
+ cp = *retcp;
+ value = 0;
+ haveNum = FALSE;
+ minus = 0;
+
+ while (TRUE) {
+ cp = skip_blank(cp);
+
+ switch (*cp) {
+ case '.':
+ haveNum = TRUE;
+ num = curNum;
+ cp++;
+ break;
+
+ case '$':
+ haveNum = TRUE;
+ num = lastNum;
+ cp++;
+ break;
+
+ case '\'':
+ cp++;
+ if ((*cp < 'a') || (*cp > 'z')) {
+ bb_error_msg("bad mark name");
+ return FALSE;
+ }
+ haveNum = TRUE;
+ num = marks[*cp++ - 'a'];
+ break;
+
+ case '/':
+ strcpy(str, ++cp);
+ endStr = strchr(str, '/');
+ if (endStr) {
+ *endStr++ = '\0';
+ cp += (endStr - str);
+ } else
+ cp = "";
+ num = searchLines(str, curNum, lastNum);
+ if (num == 0)
+ return FALSE;
+ haveNum = TRUE;
+ break;
+
+ default:
+ if (!isdigit(*cp)) {
+ *retcp = cp;
+ *retHaveNum = haveNum;
+ *retNum = value;
+ return TRUE;
+ }
+ num = 0;
+ while (isdigit(*cp))
+ num = num * 10 + *cp++ - '0';
+ haveNum = TRUE;
+ break;
+ }
+
+ value += (minus ? -num : num);
+
+ cp = skip_blank(cp);
+
+ switch (*cp) {
+ case '-':
+ minus = 1;
+ cp++;
+ break;
+
+ case '+':
+ minus = 0;
+ cp++;
+ break;
+
+ default:
+ *retcp = cp;
+ *retHaveNum = haveNum;
+ *retNum = value;
+ return TRUE;
+ }
+ }
+}
+
+
+/*
+ * Read lines from a file at the specified line number.
+ * Returns TRUE if the file was successfully read.
+ */
+static int readLines(const char *file, int num)
+{
+ int fd, cc;
+ int len, lineCount, charCount;
+ char *cp;
+
+ if ((num < 1) || (num > lastNum + 1)) {
+ bb_error_msg("bad line for read");
+ return FALSE;
+ }
+
+ fd = open(file, 0);
+ if (fd < 0) {
+ perror(file);
+ return FALSE;
+ }
+
+ bufPtr = bufBase;
+ bufUsed = 0;
+ lineCount = 0;
+ charCount = 0;
+ cc = 0;
+
+ printf("\"%s\", ", file);
+ fflush(stdout);
+
+ do {
+ cp = memchr(bufPtr, '\n', bufUsed);
+
+ if (cp) {
+ len = (cp - bufPtr) + 1;
+ if (!insertLine(num, bufPtr, len)) {
+ close(fd);
+ return FALSE;
+ }
+ bufPtr += len;
+ bufUsed -= len;
+ charCount += len;
+ lineCount++;
+ num++;
+ continue;
+ }
+
+ if (bufPtr != bufBase) {
+ memcpy(bufBase, bufPtr, bufUsed);
+ bufPtr = bufBase + bufUsed;
+ }
+
+ if (bufUsed >= bufSize) {
+ len = (bufSize * 3) / 2;
+ cp = realloc(bufBase, len);
+ if (cp == NULL) {
+ bb_error_msg("no memory for buffer");
+ close(fd);
+ return FALSE;
+ }
+ bufBase = cp;
+ bufPtr = bufBase + bufUsed;
+ bufSize = len;
+ }
+
+ cc = safe_read(fd, bufPtr, bufSize - bufUsed);
+ bufUsed += cc;
+ bufPtr = bufBase;
+
+ } while (cc > 0);
+
+ if (cc < 0) {
+ perror(file);
+ close(fd);
+ return FALSE;
+ }
+
+ if (bufUsed) {
+ if (!insertLine(num, bufPtr, bufUsed)) {
+ close(fd);
+ return -1;
+ }
+ lineCount++;
+ charCount += bufUsed;
+ }
+
+ close(fd);
+
+ printf("%d lines%s, %d chars\n", lineCount,
+ (bufUsed ? " (incomplete)" : ""), charCount);
+
+ return TRUE;
+}
+
+
+/*
+ * Write the specified lines out to the specified file.
+ * Returns TRUE if successful, or FALSE on an error with a message output.
+ */
+static int writeLines(const char *file, int num1, int num2)
+{
+ LINE *lp;
+ int fd, lineCount, charCount;
+
+ if (bad_nums(num1, num2, "write"))
+ return FALSE;
+
+ lineCount = 0;
+ charCount = 0;
+
+ fd = creat(file, 0666);
+ if (fd < 0) {
+ perror(file);
+ return FALSE;
+ }
+
+ printf("\"%s\", ", file);
+ fflush(stdout);
+
+ lp = findLine(num1);
+ if (lp == NULL) {
+ close(fd);
+ return FALSE;
+ }
+
+ while (num1++ <= num2) {
+ if (full_write(fd, lp->data, lp->len) != lp->len) {
+ perror(file);
+ close(fd);
+ return FALSE;
+ }
+ charCount += lp->len;
+ lineCount++;
+ lp = lp->next;
+ }
+
+ if (close(fd) < 0) {
+ perror(file);
+ return FALSE;
+ }
+
+ printf("%d lines, %d chars\n", lineCount, charCount);
+ return TRUE;
+}
+
+
+/*
+ * Print lines in a specified range.
+ * The last line printed becomes the current line.
+ * If expandFlag is TRUE, then the line is printed specially to
+ * show magic characters.
+ */
+static int printLines(int num1, int num2, int expandFlag)
+{
+ const LINE *lp;
+ const char *cp;
+ int ch, count;
+
+ if (bad_nums(num1, num2, "print"))
+ return FALSE;
+
+ lp = findLine(num1);
+ if (lp == NULL)
+ return FALSE;
+
+ while (num1 <= num2) {
+ if (!expandFlag) {
+ write(STDOUT_FILENO, lp->data, lp->len);
+ setCurNum(num1++);
+ lp = lp->next;
+ continue;
+ }
+
+ /*
+ * Show control characters and characters with the
+ * high bit set specially.
+ */
+ cp = lp->data;
+ count = lp->len;
+
+ if ((count > 0) && (cp[count - 1] == '\n'))
+ count--;
+
+ while (count-- > 0) {
+ ch = (unsigned char) *cp++;
+ fputc_printable(ch | PRINTABLE_META, stdout);
+ }
+
+ fputs("$\n", stdout);
+
+ setCurNum(num1++);
+ lp = lp->next;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * Insert a new line with the specified text.
+ * The line is inserted so as to become the specified line,
+ * thus pushing any existing and further lines down one.
+ * The inserted line is also set to become the current line.
+ * Returns TRUE if successful.
+ */
+static int insertLine(int num, const char *data, int len)
+{
+ LINE *newLp, *lp;
+
+ if ((num < 1) || (num > lastNum + 1)) {
+ bb_error_msg("inserting at bad line number");
+ return FALSE;
+ }
+
+ newLp = malloc(sizeof(LINE) + len - 1);
+ if (newLp == NULL) {
+ bb_error_msg("failed to allocate memory for line");
+ return FALSE;
+ }
+
+ memcpy(newLp->data, data, len);
+ newLp->len = len;
+
+ if (num > lastNum)
+ lp = &lines;
+ else {
+ lp = findLine(num);
+ if (lp == NULL) {
+ free((char *) newLp);
+ return FALSE;
+ }
+ }
+
+ newLp->next = lp;
+ newLp->prev = lp->prev;
+ lp->prev->next = newLp;
+ lp->prev = newLp;
+
+ lastNum++;
+ dirty = TRUE;
+ return setCurNum(num);
+}
+
+
+/*
+ * Delete lines from the given range.
+ */
+static void deleteLines(int num1, int num2)
+{
+ LINE *lp, *nlp, *plp;
+ int count;
+
+ if (bad_nums(num1, num2, "delete"))
+ return;
+
+ lp = findLine(num1);
+ if (lp == NULL)
+ return;
+
+ if ((curNum >= num1) && (curNum <= num2)) {
+ if (num2 < lastNum)
+ setCurNum(num2 + 1);
+ else if (num1 > 1)
+ setCurNum(num1 - 1);
+ else
+ curNum = 0;
+ }
+
+ count = num2 - num1 + 1;
+ if (curNum > num2)
+ curNum -= count;
+ lastNum -= count;
+
+ while (count-- > 0) {
+ nlp = lp->next;
+ plp = lp->prev;
+ plp->next = nlp;
+ nlp->prev = plp;
+ free(lp);
+ lp = nlp;
+ }
+
+ dirty = TRUE;
+}
+
+
+/*
+ * Search for a line which contains the specified string.
+ * If the string is "", then the previously searched for string
+ * is used. The currently searched for string is saved for future use.
+ * Returns the line number which matches, or 0 if there was no match
+ * with an error printed.
+ */
+static int searchLines(const char *str, int num1, int num2)
+{
+ const LINE *lp;
+ int len;
+
+ if (bad_nums(num1, num2, "search"))
+ return 0;
+
+ if (*str == '\0') {
+ if (searchString[0] == '\0') {
+ bb_error_msg("no previous search string");
+ return 0;
+ }
+ str = searchString;
+ }
+
+ if (str != searchString)
+ strcpy(searchString, str);
+
+ len = strlen(str);
+
+ lp = findLine(num1);
+ if (lp == NULL)
+ return 0;
+
+ while (num1 <= num2) {
+ if (findString(lp, str, len, 0) >= 0)
+ return num1;
+ num1++;
+ lp = lp->next;
+ }
+
+ bb_error_msg("cannot find string \"%s\"", str);
+ return 0;
+}
+
+
+/*
+ * Return a pointer to the specified line number.
+ */
+static LINE *findLine(int num)
+{
+ LINE *lp;
+ int lnum;
+
+ if ((num < 1) || (num > lastNum)) {
+ bb_error_msg("line number %d does not exist", num);
+ return NULL;
+ }
+
+ if (curNum <= 0) {
+ curNum = 1;
+ curLine = lines.next;
+ }
+
+ if (num == curNum)
+ return curLine;
+
+ lp = curLine;
+ lnum = curNum;
+ if (num < (curNum / 2)) {
+ lp = lines.next;
+ lnum = 1;
+ } else if (num > ((curNum + lastNum) / 2)) {
+ lp = lines.prev;
+ lnum = lastNum;
+ }
+
+ while (lnum < num) {
+ lp = lp->next;
+ lnum++;
+ }
+
+ while (lnum > num) {
+ lp = lp->prev;
+ lnum--;
+ }
+ return lp;
+}
+
+
+/*
+ * Set the current line number.
+ * Returns TRUE if successful.
+ */
+static int setCurNum(int num)
+{
+ LINE *lp;
+
+ lp = findLine(num);
+ if (lp == NULL)
+ return FALSE;
+ curNum = num;
+ curLine = lp;
+ return TRUE;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/editors/patch.c b/cleopatre/busybox-1.11.1-spc300/editors/patch.c
new file mode 100644
index 0000000000..1c9e97005b
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/editors/patch.c
@@ -0,0 +1,254 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * busybox patch applet to handle the unified diff format.
+ * Copyright (C) 2003 Glenn McGrath
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ *
+ * This applet is written to work with patches generated by GNU diff,
+ * where there is equivalent functionality busybox patch shall behave
+ * as per GNU patch.
+ *
+ * There is a SUSv3 specification for patch, however it looks to be
+ * incomplete, it doesnt even mention unified diff format.
+ * http://www.opengroup.org/onlinepubs/007904975/utilities/patch.html
+ *
+ * Issues
+ * - Non-interactive
+ * - Patches must apply cleanly or patch (not just one hunk) will fail.
+ * - Reject file isnt saved
+ */
+
+#include "libbb.h"
+
+static unsigned copy_lines(FILE *src_stream, FILE *dst_stream, unsigned lines_count)
+{
+ while (src_stream && lines_count) {
+ char *line;
+ line = xmalloc_fgets(src_stream);
+ if (line == NULL) {
+ break;
+ }
+ if (fputs(line, dst_stream) == EOF) {
+ bb_perror_msg_and_die("error writing to new file");
+ }
+ free(line);
+ lines_count--;
+ }
+ return lines_count;
+}
+
+/* If patch_level is -1 it will remove all directory names
+ * char *line must be greater than 4 chars
+ * returns NULL if the file doesnt exist or error
+ * returns malloc'ed filename
+ * NB: frees 1st argument!
+ */
+static char *extract_filename(char *line, int patch_level, const char *pat)
+{
+ char *temp = NULL, *filename_start_ptr = line + 4;
+
+ if (strncmp(line, pat, 4) == 0) {
+ /* Terminate string at end of source filename */
+ line[strcspn(line,"\t\n\r")] = '\0';
+
+ /* Skip over (patch_level) number of leading directories */
+ while (patch_level--) {
+ temp = strchr(filename_start_ptr, '/');
+ if (!temp)
+ break;
+ filename_start_ptr = temp + 1;
+ }
+ temp = xstrdup(filename_start_ptr);
+ }
+ free(line);
+ return temp;
+}
+
+int patch_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int patch_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ struct stat saved_stat;
+ char *patch_line;
+ FILE *patch_file;
+ int patch_level;
+ int ret = 0;
+ char plus = '+';
+
+ xfunc_error_retval = 2;
+ {
+ const char *p = "-1";
+ const char *i = "-"; /* compat */
+ if (getopt32(argv, "p:i:R", &p, &i) & 4)
+ plus = '-';
+ patch_level = xatoi(p); /* can be negative! */
+ patch_file = xfopen_stdin(i);
+ }
+
+ patch_line = xmalloc_fgetline(patch_file);
+ while (patch_line) {
+ FILE *src_stream;
+ FILE *dst_stream;
+ //char *old_filename;
+ char *new_filename;
+ char *backup_filename;
+ unsigned src_cur_line = 1;
+ unsigned dst_cur_line = 0;
+ unsigned dst_beg_line;
+ unsigned bad_hunk_count = 0;
+ unsigned hunk_count = 0;
+ smallint copy_trailing_lines_flag = 0;
+
+ /* Skip everything upto the "---" marker
+ * No need to parse the lines "Only in <dir>", and "diff <args>"
+ */
+ do {
+ /* Extract the filename used before the patch was generated */
+ new_filename = extract_filename(patch_line, patch_level, "--- ");
+ // was old_filename above
+ patch_line = xmalloc_fgetline(patch_file);
+ if (!patch_line) goto quit;
+ } while (!new_filename);
+ free(new_filename); // "source" filename is irrelevant
+
+ new_filename = extract_filename(patch_line, patch_level, "+++ ");
+ if (!new_filename) {
+ bb_error_msg_and_die("invalid patch");
+ }
+
+ /* Get access rights from the file to be patched */
+ if (stat(new_filename, &saved_stat) != 0) {
+ char *slash = strrchr(new_filename, '/');
+ if (slash) {
+ /* Create leading directories */
+ *slash = '\0';
+ bb_make_directory(new_filename, -1, FILEUTILS_RECUR);
+ *slash = '/';
+ }
+ backup_filename = NULL;
+ src_stream = NULL;
+ saved_stat.st_mode = 0644;
+ } else {
+ backup_filename = xasprintf("%s.orig", new_filename);
+ xrename(new_filename, backup_filename);
+ src_stream = xfopen(backup_filename, "r");
+ }
+ dst_stream = xfopen(new_filename, "w");
+ fchmod(fileno(dst_stream), saved_stat.st_mode);
+
+ printf("patching file %s\n", new_filename);
+
+ /* Handle all hunks for this file */
+ patch_line = xmalloc_fgets(patch_file);
+ while (patch_line) {
+ unsigned count;
+ unsigned src_beg_line;
+ unsigned hunk_offset_start;
+ unsigned src_last_line = 1;
+ unsigned dst_last_line = 1;
+
+ if ((sscanf(patch_line, "@@ -%d,%d +%d,%d", &src_beg_line, &src_last_line, &dst_beg_line, &dst_last_line) < 3)
+ && (sscanf(patch_line, "@@ -%d +%d,%d", &src_beg_line, &dst_beg_line, &dst_last_line) < 2)
+ ) {
+ /* No more hunks for this file */
+ break;
+ }
+ if (plus != '+') {
+ /* reverse patch */
+ unsigned tmp = src_last_line;
+ src_last_line = dst_last_line;
+ dst_last_line = tmp;
+ tmp = src_beg_line;
+ src_beg_line = dst_beg_line;
+ dst_beg_line = tmp;
+ }
+ hunk_count++;
+
+ if (src_beg_line && dst_beg_line) {
+ /* Copy unmodified lines upto start of hunk */
+ /* src_beg_line will be 0 if it's a new file */
+ count = src_beg_line - src_cur_line;
+ if (copy_lines(src_stream, dst_stream, count)) {
+ bb_error_msg_and_die("bad src file");
+ }
+ src_cur_line += count;
+ dst_cur_line += count;
+ copy_trailing_lines_flag = 1;
+ }
+ src_last_line += hunk_offset_start = src_cur_line;
+ dst_last_line += dst_cur_line;
+
+ while (1) {
+ free(patch_line);
+ patch_line = xmalloc_fgets(patch_file);
+ if (patch_line == NULL)
+ break; /* EOF */
+ if ((*patch_line != '-') && (*patch_line != '+')
+ && (*patch_line != ' ')
+ ) {
+ break; /* End of hunk */
+ }
+ if (*patch_line != plus) { /* '-' or ' ' */
+ char *src_line = NULL;
+ if (src_cur_line == src_last_line)
+ break;
+ if (src_stream) {
+ src_line = xmalloc_fgets(src_stream);
+ if (src_line) {
+ int diff = strcmp(src_line, patch_line + 1);
+ src_cur_line++;
+ free(src_line);
+ if (diff)
+ src_line = NULL;
+ }
+ }
+ if (!src_line) {
+ bb_error_msg("hunk #%u FAILED at %u", hunk_count, hunk_offset_start);
+ bad_hunk_count++;
+ break;
+ }
+ if (*patch_line != ' ') { /* '-' */
+ continue;
+ }
+ }
+ if (dst_cur_line == dst_last_line)
+ break;
+ fputs(patch_line + 1, dst_stream);
+ dst_cur_line++;
+ } /* end of while loop handling one hunk */
+ } /* end of while loop handling one file */
+
+ /* Cleanup last patched file */
+ if (copy_trailing_lines_flag) {
+ copy_lines(src_stream, dst_stream, (unsigned)(-1));
+ }
+ if (src_stream) {
+ fclose(src_stream);
+ }
+ fclose(dst_stream);
+ if (bad_hunk_count) {
+ ret = 1;
+ bb_error_msg("%u out of %u hunk FAILED", bad_hunk_count, hunk_count);
+ } else {
+ /* It worked, we can remove the backup */
+ if (backup_filename) {
+ unlink(backup_filename);
+ }
+ if ((dst_cur_line == 0) || (dst_beg_line == 0)) {
+ /* The new patched file is empty, remove it */
+ xunlink(new_filename);
+ // /* old_filename and new_filename may be the same file */
+ // unlink(old_filename);
+ }
+ }
+ free(backup_filename);
+ //free(old_filename);
+ free(new_filename);
+ } /* end of "while there are patch lines" */
+ quit:
+ /* 0 = SUCCESS
+ * 1 = Some hunks failed
+ * 2 = More serious problems (exited earlier)
+ */
+ return ret;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/editors/sed.c b/cleopatre/busybox-1.11.1-spc300/editors/sed.c
new file mode 100644
index 0000000000..bf01fc6308
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/editors/sed.c
@@ -0,0 +1,1350 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * sed.c - very minimalist version of sed
+ *
+ * Copyright (C) 1999,2000,2001 by Lineo, inc. and Mark Whitley
+ * Copyright (C) 1999,2000,2001 by Mark Whitley <markw@codepoet.org>
+ * Copyright (C) 2002 Matt Kraai
+ * Copyright (C) 2003 by Glenn McGrath
+ * Copyright (C) 2003,2004 by Rob Landley <rob@landley.net>
+ *
+ * MAINTAINER: Rob Landley <rob@landley.net>
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+
+/* Code overview.
+
+ Files are laid out to avoid unnecessary function declarations. So for
+ example, every function add_cmd calls occurs before add_cmd in this file.
+
+ add_cmd() is called on each line of sed command text (from a file or from
+ the command line). It calls get_address() and parse_cmd_args(). The
+ resulting sed_cmd_t structures are appended to a linked list
+ (G.sed_cmd_head/G.sed_cmd_tail).
+
+ add_input_file() adds a FILE * to the list of input files. We need to
+ know all input sources ahead of time to find the last line for the $ match.
+
+ process_files() does actual sedding, reading data lines from each input FILE *
+ (which could be stdin) and applying the sed command list (sed_cmd_head) to
+ each of the resulting lines.
+
+ sed_main() is where external code calls into this, with a command line.
+*/
+
+
+/*
+ Supported features and commands in this version of sed:
+
+ - comments ('#')
+ - address matching: num|/matchstr/[,num|/matchstr/|$]command
+ - commands: (p)rint, (d)elete, (s)ubstitue (with g & I flags)
+ - edit commands: (a)ppend, (i)nsert, (c)hange
+ - file commands: (r)ead
+ - backreferences in substitution expressions (\0, \1, \2...\9)
+ - grouped commands: {cmd1;cmd2}
+ - transliteration (y/source-chars/dest-chars/)
+ - pattern space hold space storing / swapping (g, h, x)
+ - labels / branching (: label, b, t, T)
+
+ (Note: Specifying an address (range) to match is *optional*; commands
+ default to the whole pattern space if no specific address match was
+ requested.)
+
+ Todo:
+ - Create a wrapper around regex to make libc's regex conform with sed
+
+ Reference http://www.opengroup.org/onlinepubs/007904975/utilities/sed.html
+*/
+
+#include "libbb.h"
+#include "xregex.h"
+
+/* Each sed command turns into one of these structures. */
+typedef struct sed_cmd_s {
+ /* Ordered by alignment requirements: currently 36 bytes on x86 */
+ struct sed_cmd_s *next; /* Next command (linked list, NULL terminated) */
+
+ /* address storage */
+ regex_t *beg_match; /* sed -e '/match/cmd' */
+ regex_t *end_match; /* sed -e '/match/,/end_match/cmd' */
+ regex_t *sub_match; /* For 's/sub_match/string/' */
+ int beg_line; /* 'sed 1p' 0 == apply commands to all lines */
+ int end_line; /* 'sed 1,3p' 0 == one line only. -1 = last line ($) */
+
+ FILE *sw_file; /* File (sw) command writes to, -1 for none. */
+ char *string; /* Data string for (saicytb) commands. */
+
+ unsigned which_match; /* (s) Which match to replace (0 for all) */
+
+ /* Bitfields (gcc won't group them if we don't) */
+ unsigned invert:1; /* the '!' after the address */
+ unsigned in_match:1; /* Next line also included in match? */
+ unsigned sub_p:1; /* (s) print option */
+
+ char sw_last_char; /* Last line written by (sw) had no '\n' */
+
+ /* GENERAL FIELDS */
+ char cmd; /* The command char: abcdDgGhHilnNpPqrstwxy:={} */
+} sed_cmd_t;
+
+static const char semicolon_whitespace[] ALIGN1 = "; \n\r\t\v";
+
+struct globals {
+ /* options */
+ int be_quiet, regex_type;
+ FILE *nonstdout;
+ char *outname, *hold_space;
+
+ /* List of input files */
+ int input_file_count, current_input_file;
+ FILE **input_file_list;
+
+ regmatch_t regmatch[10];
+ regex_t *previous_regex_ptr;
+
+ /* linked list of sed commands */
+ sed_cmd_t sed_cmd_head, *sed_cmd_tail;
+
+ /* Linked list of append lines */
+ llist_t *append_head;
+
+ char *add_cmd_line;
+
+ struct pipeline {
+ char *buf; /* Space to hold string */
+ int idx; /* Space used */
+ int len; /* Space allocated */
+ } pipeline;
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+void BUG_sed_globals_too_big(void);
+#define INIT_G() do { \
+ if (sizeof(struct globals) > COMMON_BUFSIZE) \
+ BUG_sed_globals_too_big(); \
+ G.sed_cmd_tail = &G.sed_cmd_head; \
+} while (0)
+
+
+#if ENABLE_FEATURE_CLEAN_UP
+static void sed_free_and_close_stuff(void)
+{
+ sed_cmd_t *sed_cmd = G.sed_cmd_head.next;
+
+ llist_free(G.append_head, free);
+
+ while (sed_cmd) {
+ sed_cmd_t *sed_cmd_next = sed_cmd->next;
+
+ if (sed_cmd->sw_file)
+ xprint_and_close_file(sed_cmd->sw_file);
+
+ if (sed_cmd->beg_match) {
+ regfree(sed_cmd->beg_match);
+ free(sed_cmd->beg_match);
+ }
+ if (sed_cmd->end_match) {
+ regfree(sed_cmd->end_match);
+ free(sed_cmd->end_match);
+ }
+ if (sed_cmd->sub_match) {
+ regfree(sed_cmd->sub_match);
+ free(sed_cmd->sub_match);
+ }
+ free(sed_cmd->string);
+ free(sed_cmd);
+ sed_cmd = sed_cmd_next;
+ }
+
+ free(G.hold_space);
+
+ while (G.current_input_file < G.input_file_count)
+ fclose(G.input_file_list[G.current_input_file++]);
+}
+#else
+void sed_free_and_close_stuff(void);
+#endif
+
+/* If something bad happens during -i operation, delete temp file */
+
+static void cleanup_outname(void)
+{
+ if (G.outname) unlink(G.outname);
+}
+
+/* strcpy, replacing "\from" with 'to'. If to is NUL, replacing "\any" with 'any' */
+
+static void parse_escapes(char *dest, const char *string, int len, char from, char to)
+{
+ int i = 0;
+
+ while (i < len) {
+ if (string[i] == '\\') {
+ if (!to || string[i+1] == from) {
+ *dest++ = to ? to : string[i+1];
+ i += 2;
+ continue;
+ }
+ *dest++ = string[i++];
+ }
+ /* TODO: is it safe wrt a string with trailing '\\' ? */
+ *dest++ = string[i++];
+ }
+ *dest = '\0';
+}
+
+static char *copy_parsing_escapes(const char *string, int len)
+{
+ char *dest = xmalloc(len + 1);
+
+ parse_escapes(dest, string, len, 'n', '\n');
+ /* GNU sed also recognizes \t */
+ parse_escapes(dest, dest, strlen(dest), 't', '\t');
+ return dest;
+}
+
+
+/*
+ * index_of_next_unescaped_regexp_delim - walks left to right through a string
+ * beginning at a specified index and returns the index of the next regular
+ * expression delimiter (typically a forward slash ('/')) not preceded by
+ * a backslash ('\'). A negative delimiter disables square bracket checking.
+ */
+static int index_of_next_unescaped_regexp_delim(int delimiter, const char *str)
+{
+ int bracket = -1;
+ int escaped = 0;
+ int idx = 0;
+ char ch;
+
+ if (delimiter < 0) {
+ bracket--;
+ delimiter = -delimiter;
+ }
+
+ for (; (ch = str[idx]); idx++) {
+ if (bracket >= 0) {
+ if (ch == ']' && !(bracket == idx - 1 || (bracket == idx - 2
+ && str[idx - 1] == '^')))
+ bracket = -1;
+ } else if (escaped)
+ escaped = 0;
+ else if (ch == '\\')
+ escaped = 1;
+ else if (bracket == -1 && ch == '[')
+ bracket = idx;
+ else if (ch == delimiter)
+ return idx;
+ }
+
+ /* if we make it to here, we've hit the end of the string */
+ bb_error_msg_and_die("unmatched '%c'", delimiter);
+}
+
+/*
+ * Returns the index of the third delimiter
+ */
+static int parse_regex_delim(const char *cmdstr, char **match, char **replace)
+{
+ const char *cmdstr_ptr = cmdstr;
+ char delimiter;
+ int idx = 0;
+
+ /* verify that the 's' or 'y' is followed by something. That something
+ * (typically a 'slash') is now our regexp delimiter... */
+ if (*cmdstr == '\0')
+ bb_error_msg_and_die("bad format in substitution expression");
+ delimiter = *cmdstr_ptr++;
+
+ /* save the match string */
+ idx = index_of_next_unescaped_regexp_delim(delimiter, cmdstr_ptr);
+ *match = copy_parsing_escapes(cmdstr_ptr, idx);
+
+ /* save the replacement string */
+ cmdstr_ptr += idx + 1;
+ idx = index_of_next_unescaped_regexp_delim(-delimiter, cmdstr_ptr);
+ *replace = copy_parsing_escapes(cmdstr_ptr, idx);
+
+ return ((cmdstr_ptr - cmdstr) + idx);
+}
+
+/*
+ * returns the index in the string just past where the address ends.
+ */
+static int get_address(const char *my_str, int *linenum, regex_t ** regex)
+{
+ const char *pos = my_str;
+
+ if (isdigit(*my_str)) {
+ *linenum = strtol(my_str, (char**)&pos, 10);
+ /* endstr shouldnt ever equal NULL */
+ } else if (*my_str == '$') {
+ *linenum = -1;
+ pos++;
+ } else if (*my_str == '/' || *my_str == '\\') {
+ int next;
+ char delimiter;
+ char *temp;
+
+ delimiter = '/';
+ if (*my_str == '\\') delimiter = *++pos;
+ next = index_of_next_unescaped_regexp_delim(delimiter, ++pos);
+ temp = copy_parsing_escapes(pos, next);
+ *regex = xmalloc(sizeof(regex_t));
+ xregcomp(*regex, temp, G.regex_type|REG_NEWLINE);
+ free(temp);
+ /* Move position to next character after last delimiter */
+ pos += (next+1);
+ }
+ return pos - my_str;
+}
+
+/* Grab a filename. Whitespace at start is skipped, then goes to EOL. */
+static int parse_file_cmd(/*sed_cmd_t *sed_cmd,*/ const char *filecmdstr, char **retval)
+{
+ int start = 0, idx, hack = 0;
+
+ /* Skip whitespace, then grab filename to end of line */
+ while (isspace(filecmdstr[start]))
+ start++;
+ idx = start;
+ while (filecmdstr[idx] && filecmdstr[idx] != '\n')
+ idx++;
+
+ /* If lines glued together, put backslash back. */
+ if (filecmdstr[idx] == '\n')
+ hack = 1;
+ if (idx == start)
+ bb_error_msg_and_die("empty filename");
+ *retval = xstrndup(filecmdstr+start, idx-start+hack+1);
+ if (hack)
+ (*retval)[idx] = '\\';
+
+ return idx;
+}
+
+static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr)
+{
+ int cflags = G.regex_type;
+ char *match;
+ int idx;
+
+ /*
+ * A substitution command should look something like this:
+ * s/match/replace/ #gIpw
+ * || | |||
+ * mandatory optional
+ */
+ idx = parse_regex_delim(substr, &match, &sed_cmd->string);
+
+ /* determine the number of back references in the match string */
+ /* Note: we compute this here rather than in the do_subst_command()
+ * function to save processor time, at the expense of a little more memory
+ * (4 bits) per sed_cmd */
+
+ /* process the flags */
+
+ sed_cmd->which_match = 1;
+ while (substr[++idx]) {
+ /* Parse match number */
+ if (isdigit(substr[idx])) {
+ if (match[0] != '^') {
+ /* Match 0 treated as all, multiple matches we take the last one. */
+ const char *pos = substr + idx;
+/* FIXME: error check? */
+ sed_cmd->which_match = (unsigned)strtol(substr+idx, (char**) &pos, 10);
+ idx = pos - substr;
+ }
+ continue;
+ }
+ /* Skip spaces */
+ if (isspace(substr[idx])) continue;
+
+ switch (substr[idx]) {
+ /* Replace all occurrences */
+ case 'g':
+ if (match[0] != '^')
+ sed_cmd->which_match = 0;
+ break;
+ /* Print pattern space */
+ case 'p':
+ sed_cmd->sub_p = 1;
+ break;
+ /* Write to file */
+ case 'w':
+ {
+ char *temp;
+ idx += parse_file_cmd(/*sed_cmd,*/ substr+idx, &temp);
+ break;
+ }
+ /* Ignore case (gnu exension) */
+ case 'I':
+ cflags |= REG_ICASE;
+ break;
+ /* Comment */
+ case '#':
+ while (substr[++idx]) /*skip all*/;
+ /* Fall through */
+ /* End of command */
+ case ';':
+ case '}':
+ goto out;
+ default:
+ bb_error_msg_and_die("bad option in substitution expression");
+ }
+ }
+out:
+ /* compile the match string into a regex */
+ if (*match != '\0') {
+ /* If match is empty, we use last regex used at runtime */
+ sed_cmd->sub_match = xmalloc(sizeof(regex_t));
+ xregcomp(sed_cmd->sub_match, match, cflags);
+ }
+ free(match);
+
+ return idx;
+}
+
+/*
+ * Process the commands arguments
+ */
+static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr)
+{
+ /* handle (s)ubstitution command */
+ if (sed_cmd->cmd == 's')
+ cmdstr += parse_subst_cmd(sed_cmd, cmdstr);
+ /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */
+ else if (strchr("aic", sed_cmd->cmd)) {
+ if ((sed_cmd->end_line || sed_cmd->end_match) && sed_cmd->cmd != 'c')
+ bb_error_msg_and_die
+ ("only a beginning address can be specified for edit commands");
+ for (;;) {
+ if (*cmdstr == '\n' || *cmdstr == '\\') {
+ cmdstr++;
+ break;
+ } else if (isspace(*cmdstr))
+ cmdstr++;
+ else
+ break;
+ }
+ sed_cmd->string = xstrdup(cmdstr);
+ /* "\anychar" -> "anychar" */
+ parse_escapes(sed_cmd->string, sed_cmd->string, strlen(cmdstr), '\0', '\0');
+ cmdstr += strlen(cmdstr);
+ /* handle file cmds: (r)ead */
+ } else if (strchr("rw", sed_cmd->cmd)) {
+ if (sed_cmd->end_line || sed_cmd->end_match)
+ bb_error_msg_and_die("command only uses one address");
+ cmdstr += parse_file_cmd(/*sed_cmd,*/ cmdstr, &sed_cmd->string);
+ if (sed_cmd->cmd == 'w') {
+ sed_cmd->sw_file = xfopen(sed_cmd->string, "w");
+ sed_cmd->sw_last_char = '\n';
+ }
+ /* handle branch commands */
+ } else if (strchr(":btT", sed_cmd->cmd)) {
+ int length;
+
+ cmdstr = skip_whitespace(cmdstr);
+ length = strcspn(cmdstr, semicolon_whitespace);
+ if (length) {
+ sed_cmd->string = xstrndup(cmdstr, length);
+ cmdstr += length;
+ }
+ }
+ /* translation command */
+ else if (sed_cmd->cmd == 'y') {
+ char *match, *replace;
+ int i = cmdstr[0];
+
+ cmdstr += parse_regex_delim(cmdstr, &match, &replace)+1;
+ /* \n already parsed, but \delimiter needs unescaping. */
+ parse_escapes(match, match, strlen(match), i, i);
+ parse_escapes(replace, replace, strlen(replace), i, i);
+
+ sed_cmd->string = xzalloc((strlen(match) + 1) * 2);
+ for (i = 0; match[i] && replace[i]; i++) {
+ sed_cmd->string[i*2] = match[i];
+ sed_cmd->string[i*2+1] = replace[i];
+ }
+ free(match);
+ free(replace);
+ }
+ /* if it wasnt a single-letter command that takes no arguments
+ * then it must be an invalid command.
+ */
+ else if (strchr("dDgGhHlnNpPqx={}", sed_cmd->cmd) == 0) {
+ bb_error_msg_and_die("unsupported command %c", sed_cmd->cmd);
+ }
+
+ /* give back whatever's left over */
+ return cmdstr;
+}
+
+
+/* Parse address+command sets, skipping comment lines. */
+
+static void add_cmd(const char *cmdstr)
+{
+ sed_cmd_t *sed_cmd;
+ int temp;
+
+ /* Append this line to any unfinished line from last time. */
+ if (G.add_cmd_line) {
+ char *tp = xasprintf("%s\n%s", G.add_cmd_line, cmdstr);
+ free(G.add_cmd_line);
+ cmdstr = G.add_cmd_line = tp;
+ }
+
+ /* If this line ends with backslash, request next line. */
+ temp = strlen(cmdstr);
+ if (temp && cmdstr[--temp] == '\\') {
+ if (!G.add_cmd_line)
+ G.add_cmd_line = xstrdup(cmdstr);
+ G.add_cmd_line[temp] = '\0';
+ return;
+ }
+
+ /* Loop parsing all commands in this line. */
+ while (*cmdstr) {
+ /* Skip leading whitespace and semicolons */
+ cmdstr += strspn(cmdstr, semicolon_whitespace);
+
+ /* If no more commands, exit. */
+ if (!*cmdstr) break;
+
+ /* if this is a comment, jump past it and keep going */
+ if (*cmdstr == '#') {
+ /* "#n" is the same as using -n on the command line */
+ if (cmdstr[1] == 'n')
+ G.be_quiet++;
+ cmdstr = strpbrk(cmdstr, "\n\r");
+ if (!cmdstr) break;
+ continue;
+ }
+
+ /* parse the command
+ * format is: [addr][,addr][!]cmd
+ * |----||-----||-|
+ * part1 part2 part3
+ */
+
+ sed_cmd = xzalloc(sizeof(sed_cmd_t));
+
+ /* first part (if present) is an address: either a '$', a number or a /regex/ */
+ cmdstr += get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match);
+
+ /* second part (if present) will begin with a comma */
+ if (*cmdstr == ',') {
+ int idx;
+
+ cmdstr++;
+ idx = get_address(cmdstr, &sed_cmd->end_line, &sed_cmd->end_match);
+ if (!idx)
+ bb_error_msg_and_die("no address after comma");
+ cmdstr += idx;
+ }
+
+ /* skip whitespace before the command */
+ cmdstr = skip_whitespace(cmdstr);
+
+ /* Check for inversion flag */
+ if (*cmdstr == '!') {
+ sed_cmd->invert = 1;
+ cmdstr++;
+
+ /* skip whitespace before the command */
+ cmdstr = skip_whitespace(cmdstr);
+ }
+
+ /* last part (mandatory) will be a command */
+ if (!*cmdstr)
+ bb_error_msg_and_die("missing command");
+ sed_cmd->cmd = *(cmdstr++);
+ cmdstr = parse_cmd_args(sed_cmd, cmdstr);
+
+ /* Add the command to the command array */
+ G.sed_cmd_tail->next = sed_cmd;
+ G.sed_cmd_tail = G.sed_cmd_tail->next;
+ }
+
+ /* If we glued multiple lines together, free the memory. */
+ free(G.add_cmd_line);
+ G.add_cmd_line = NULL;
+}
+
+/* Append to a string, reallocating memory as necessary. */
+
+#define PIPE_GROW 64
+
+static void pipe_putc(char c)
+{
+ if (G.pipeline.idx == G.pipeline.len) {
+ G.pipeline.buf = xrealloc(G.pipeline.buf,
+ G.pipeline.len + PIPE_GROW);
+ G.pipeline.len += PIPE_GROW;
+ }
+ G.pipeline.buf[G.pipeline.idx++] = c;
+}
+
+static void do_subst_w_backrefs(char *line, char *replace)
+{
+ int i,j;
+
+ /* go through the replacement string */
+ for (i = 0; replace[i]; i++) {
+ /* if we find a backreference (\1, \2, etc.) print the backref'ed * text */
+ if (replace[i] == '\\') {
+ unsigned backref = replace[++i] - '0';
+ if (backref <= 9) {
+ /* print out the text held in G.regmatch[backref] */
+ if (G.regmatch[backref].rm_so != -1) {
+ j = G.regmatch[backref].rm_so;
+ while (j < G.regmatch[backref].rm_eo)
+ pipe_putc(line[j++]);
+ }
+ continue;
+ }
+ /* I _think_ it is impossible to get '\' to be
+ * the last char in replace string. Thus we dont check
+ * for replace[i] == NUL. (counterexample anyone?) */
+ /* if we find a backslash escaped character, print the character */
+ pipe_putc(replace[i]);
+ continue;
+ }
+ /* if we find an unescaped '&' print out the whole matched text. */
+ if (replace[i] == '&') {
+ j = G.regmatch[0].rm_so;
+ while (j < G.regmatch[0].rm_eo)
+ pipe_putc(line[j++]);
+ continue;
+ }
+ /* Otherwise just output the character. */
+ pipe_putc(replace[i]);
+ }
+}
+
+static int do_subst_command(sed_cmd_t *sed_cmd, char **line)
+{
+ char *oldline = *line;
+ int altered = 0;
+ unsigned match_count = 0;
+ regex_t *current_regex;
+
+ /* Handle empty regex. */
+ if (sed_cmd->sub_match == NULL) {
+ current_regex = G.previous_regex_ptr;
+ if (!current_regex)
+ bb_error_msg_and_die("no previous regexp");
+ } else
+ G.previous_regex_ptr = current_regex = sed_cmd->sub_match;
+
+ /* Find the first match */
+ if (REG_NOMATCH == regexec(current_regex, oldline, 10, G.regmatch, 0))
+ return 0;
+
+ /* Initialize temporary output buffer. */
+ G.pipeline.buf = xmalloc(PIPE_GROW);
+ G.pipeline.len = PIPE_GROW;
+ G.pipeline.idx = 0;
+
+ /* Now loop through, substituting for matches */
+ do {
+ int i;
+
+ /* Work around bug in glibc regexec, demonstrated by:
+ echo " a.b" | busybox sed 's [^ .]* x g'
+ The match_count check is so not to break
+ echo "hi" | busybox sed 's/^/!/g' */
+ if (!G.regmatch[0].rm_so && !G.regmatch[0].rm_eo && match_count) {
+ pipe_putc(*oldline++);
+ continue;
+ }
+
+ match_count++;
+
+ /* If we aren't interested in this match, output old line to
+ end of match and continue */
+ if (sed_cmd->which_match
+ && (sed_cmd->which_match != match_count)
+ ) {
+ for (i = 0; i < G.regmatch[0].rm_eo; i++)
+ pipe_putc(*oldline++);
+ continue;
+ }
+
+ /* print everything before the match */
+ for (i = 0; i < G.regmatch[0].rm_so; i++)
+ pipe_putc(oldline[i]);
+
+ /* then print the substitution string */
+ do_subst_w_backrefs(oldline, sed_cmd->string);
+
+ /* advance past the match */
+ oldline += G.regmatch[0].rm_eo;
+ /* flag that something has changed */
+ altered++;
+
+ /* if we're not doing this globally, get out now */
+ if (sed_cmd->which_match)
+ break;
+ } while (*oldline && (regexec(current_regex, oldline, 10, G.regmatch, 0) != REG_NOMATCH));
+
+ /* Copy rest of string into output pipeline */
+
+ while (*oldline)
+ pipe_putc(*oldline++);
+ pipe_putc(0);
+
+ free(*line);
+ *line = G.pipeline.buf;
+ return altered;
+}
+
+/* Set command pointer to point to this label. (Does not handle null label.) */
+static sed_cmd_t *branch_to(char *label)
+{
+ sed_cmd_t *sed_cmd;
+
+ for (sed_cmd = G.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) {
+ if (sed_cmd->cmd == ':' && sed_cmd->string && !strcmp(sed_cmd->string, label)) {
+ return sed_cmd;
+ }
+ }
+ bb_error_msg_and_die("can't find label for jump to '%s'", label);
+}
+
+static void append(char *s)
+{
+ llist_add_to_end(&G.append_head, xstrdup(s));
+}
+
+static void flush_append(void)
+{
+ char *data;
+
+ /* Output appended lines. */
+ while ((data = (char *)llist_pop(&G.append_head))) {
+ fprintf(G.nonstdout, "%s\n", data);
+ free(data);
+ }
+}
+
+static void add_input_file(FILE *file)
+{
+ G.input_file_list = xrealloc(G.input_file_list,
+ (G.input_file_count + 1) * sizeof(FILE *));
+ G.input_file_list[G.input_file_count++] = file;
+}
+
+/* Get next line of input from G.input_file_list, flushing append buffer and
+ * noting if we ran out of files without a newline on the last line we read.
+ */
+enum {
+ NO_EOL_CHAR = 1,
+ LAST_IS_NUL = 2,
+};
+static char *get_next_line(char *gets_char)
+{
+ char *temp = NULL;
+ int len;
+ char gc;
+
+ flush_append();
+
+ /* will be returned if last line in the file
+ * doesn't end with either '\n' or '\0' */
+ gc = NO_EOL_CHAR;
+ while (G.current_input_file < G.input_file_count) {
+ FILE *fp = G.input_file_list[G.current_input_file];
+ /* Read line up to a newline or NUL byte, inclusive,
+ * return malloc'ed char[]. length of the chunk read
+ * is stored in len. NULL if EOF/error */
+ temp = bb_get_chunk_from_file(fp, &len);
+ if (temp) {
+ /* len > 0 here, it's ok to do temp[len-1] */
+ char c = temp[len-1];
+ if (c == '\n' || c == '\0') {
+ temp[len-1] = '\0';
+ gc = c;
+ if (c == '\0') {
+ int ch = fgetc(fp);
+ if (ch != EOF)
+ ungetc(ch, fp);
+ else
+ gc = LAST_IS_NUL;
+ }
+ }
+ /* else we put NO_EOL_CHAR into *gets_char */
+ break;
+
+ /* NB: I had the idea of peeking next file(s) and returning
+ * NO_EOL_CHAR only if it is the *last* non-empty
+ * input file. But there is a case where this won't work:
+ * file1: "a woo\nb woo"
+ * file2: "c no\nd no"
+ * sed -ne 's/woo/bang/p' input1 input2 => "a bang\nb bang"
+ * (note: *no* newline after "b bang"!) */
+ }
+ /* Close this file and advance to next one */
+ fclose(fp);
+ G.current_input_file++;
+ }
+ *gets_char = gc;
+ return temp;
+}
+
+/* Output line of text. */
+/* Note:
+ * The tricks with NO_EOL_CHAR and last_puts_char are there to emulate gnu sed.
+ * Without them, we had this:
+ * echo -n thingy >z1
+ * echo -n again >z2
+ * >znull
+ * sed "s/i/z/" z1 z2 znull | hexdump -vC
+ * output:
+ * gnu sed 4.1.5:
+ * 00000000 74 68 7a 6e 67 79 0a 61 67 61 7a 6e |thzngy.agazn|
+ * bbox:
+ * 00000000 74 68 7a 6e 67 79 61 67 61 7a 6e |thzngyagazn|
+ */
+static void puts_maybe_newline(char *s, FILE *file, char *last_puts_char, char last_gets_char)
+{
+ char lpc = *last_puts_char;
+
+ /* Need to insert a '\n' between two files because first file's
+ * last line wasn't terminated? */
+ if (lpc != '\n' && lpc != '\0') {
+ fputc('\n', file);
+ lpc = '\n';
+ }
+ fputs(s, file);
+
+ /* 'x' - just something which is not '\n', '\0' or NO_EOL_CHAR */
+ if (s[0])
+ lpc = 'x';
+
+ /* had trailing '\0' and it was last char of file? */
+ if (last_gets_char == LAST_IS_NUL) {
+ fputc('\0', file);
+ lpc = 'x'; /* */
+ } else
+ /* had trailing '\n' or '\0'? */
+ if (last_gets_char != NO_EOL_CHAR) {
+ fputc(last_gets_char, file);
+ lpc = last_gets_char;
+ }
+
+ if (ferror(file)) {
+ xfunc_error_retval = 4; /* It's what gnu sed exits with... */
+ bb_error_msg_and_die(bb_msg_write_error);
+ }
+ *last_puts_char = lpc;
+}
+
+#define sed_puts(s, n) (puts_maybe_newline(s, G.nonstdout, &last_puts_char, n))
+
+static int beg_match(sed_cmd_t *sed_cmd, const char *pattern_space)
+{
+ int retval = sed_cmd->beg_match && !regexec(sed_cmd->beg_match, pattern_space, 0, NULL, 0);
+ if (retval)
+ G.previous_regex_ptr = sed_cmd->beg_match;
+ return retval;
+}
+
+/* Process all the lines in all the files */
+
+static void process_files(void)
+{
+ char *pattern_space, *next_line;
+ int linenum = 0;
+ char last_puts_char = '\n';
+ char last_gets_char, next_gets_char;
+ sed_cmd_t *sed_cmd;
+ int substituted;
+
+ /* Prime the pump */
+ next_line = get_next_line(&next_gets_char);
+
+ /* go through every line in each file */
+ again:
+ substituted = 0;
+
+ /* Advance to next line. Stop if out of lines. */
+ pattern_space = next_line;
+ if (!pattern_space) return;
+ last_gets_char = next_gets_char;
+
+ /* Read one line in advance so we can act on the last line,
+ * the '$' address */
+ next_line = get_next_line(&next_gets_char);
+ linenum++;
+ restart:
+ /* for every line, go through all the commands */
+ for (sed_cmd = G.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) {
+ int old_matched, matched;
+
+ old_matched = sed_cmd->in_match;
+
+ /* Determine if this command matches this line: */
+
+ /* Are we continuing a previous multi-line match? */
+ sed_cmd->in_match = sed_cmd->in_match
+ /* Or is no range necessary? */
+ || (!sed_cmd->beg_line && !sed_cmd->end_line
+ && !sed_cmd->beg_match && !sed_cmd->end_match)
+ /* Or did we match the start of a numerical range? */
+ || (sed_cmd->beg_line > 0 && (sed_cmd->beg_line == linenum))
+ /* Or does this line match our begin address regex? */
+ || (beg_match(sed_cmd, pattern_space))
+ /* Or did we match last line of input? */
+ || (sed_cmd->beg_line == -1 && next_line == NULL);
+
+ /* Snapshot the value */
+
+ matched = sed_cmd->in_match;
+
+ /* Is this line the end of the current match? */
+
+ if (matched) {
+ sed_cmd->in_match = !(
+ /* has the ending line come, or is this a single address command? */
+ (sed_cmd->end_line ?
+ sed_cmd->end_line == -1 ?
+ !next_line
+ : (sed_cmd->end_line <= linenum)
+ : !sed_cmd->end_match
+ )
+ /* or does this line matches our last address regex */
+ || (sed_cmd->end_match && old_matched
+ && (regexec(sed_cmd->end_match,
+ pattern_space, 0, NULL, 0) == 0))
+ );
+ }
+
+ /* Skip blocks of commands we didn't match. */
+ if (sed_cmd->cmd == '{') {
+ if (sed_cmd->invert ? matched : !matched) {
+ while (sed_cmd->cmd != '}') {
+ sed_cmd = sed_cmd->next;
+ if (!sed_cmd)
+ bb_error_msg_and_die("unterminated {");
+ }
+ }
+ continue;
+ }
+
+ /* Okay, so did this line match? */
+ if (sed_cmd->invert ? !matched : matched) {
+ /* Update last used regex in case a blank substitute BRE is found */
+ if (sed_cmd->beg_match) {
+ G.previous_regex_ptr = sed_cmd->beg_match;
+ }
+
+ /* actual sedding */
+ switch (sed_cmd->cmd) {
+
+ /* Print line number */
+ case '=':
+ fprintf(G.nonstdout, "%d\n", linenum);
+ break;
+
+ /* Write the current pattern space up to the first newline */
+ case 'P':
+ {
+ char *tmp = strchr(pattern_space, '\n');
+
+ if (tmp) {
+ *tmp = '\0';
+ /* TODO: explain why '\n' below */
+ sed_puts(pattern_space, '\n');
+ *tmp = '\n';
+ break;
+ }
+ /* Fall Through */
+ }
+
+ /* Write the current pattern space to output */
+ case 'p':
+ /* NB: we print this _before_ the last line
+ * (of current file) is printed. Even if
+ * that line is nonterminated, we print
+ * '\n' here (gnu sed does the same) */
+ sed_puts(pattern_space, '\n');
+ break;
+ /* Delete up through first newline */
+ case 'D':
+ {
+ char *tmp = strchr(pattern_space, '\n');
+
+ if (tmp) {
+ tmp = xstrdup(tmp+1);
+ free(pattern_space);
+ pattern_space = tmp;
+ goto restart;
+ }
+ }
+ /* discard this line. */
+ case 'd':
+ goto discard_line;
+
+ /* Substitute with regex */
+ case 's':
+ if (!do_subst_command(sed_cmd, &pattern_space))
+ break;
+ substituted |= 1;
+
+ /* handle p option */
+ if (sed_cmd->sub_p)
+ sed_puts(pattern_space, last_gets_char);
+ /* handle w option */
+ if (sed_cmd->sw_file)
+ puts_maybe_newline(
+ pattern_space, sed_cmd->sw_file,
+ &sed_cmd->sw_last_char, last_gets_char);
+ break;
+
+ /* Append line to linked list to be printed later */
+ case 'a':
+ append(sed_cmd->string);
+ break;
+
+ /* Insert text before this line */
+ case 'i':
+ sed_puts(sed_cmd->string, '\n');
+ break;
+
+ /* Cut and paste text (replace) */
+ case 'c':
+ /* Only triggers on last line of a matching range. */
+ if (!sed_cmd->in_match)
+ sed_puts(sed_cmd->string, NO_EOL_CHAR);
+ goto discard_line;
+
+ /* Read file, append contents to output */
+ case 'r':
+ {
+ FILE *rfile;
+
+ rfile = fopen(sed_cmd->string, "r");
+ if (rfile) {
+ char *line;
+
+ while ((line = xmalloc_fgetline(rfile))
+ != NULL)
+ append(line);
+ xprint_and_close_file(rfile);
+ }
+
+ break;
+ }
+
+ /* Write pattern space to file. */
+ case 'w':
+ puts_maybe_newline(
+ pattern_space, sed_cmd->sw_file,
+ &sed_cmd->sw_last_char, last_gets_char);
+ break;
+
+ /* Read next line from input */
+ case 'n':
+ if (!G.be_quiet)
+ sed_puts(pattern_space, last_gets_char);
+ if (next_line) {
+ free(pattern_space);
+ pattern_space = next_line;
+ last_gets_char = next_gets_char;
+ next_line = get_next_line(&next_gets_char);
+ substituted = 0;
+ linenum++;
+ break;
+ }
+ /* fall through */
+
+ /* Quit. End of script, end of input. */
+ case 'q':
+ /* Exit the outer while loop */
+ free(next_line);
+ next_line = NULL;
+ goto discard_commands;
+
+ /* Append the next line to the current line */
+ case 'N':
+ {
+ int len;
+ /* If no next line, jump to end of script and exit. */
+ if (next_line == NULL) {
+ /* Jump to end of script and exit */
+ free(next_line);
+ next_line = NULL;
+ goto discard_line;
+ /* append next_line, read new next_line. */
+ }
+ len = strlen(pattern_space);
+ pattern_space = realloc(pattern_space, len + strlen(next_line) + 2);
+ pattern_space[len] = '\n';
+ strcpy(pattern_space + len+1, next_line);
+ last_gets_char = next_gets_char;
+ next_line = get_next_line(&next_gets_char);
+ linenum++;
+ break;
+ }
+
+ /* Test/branch if substitution occurred */
+ case 't':
+ if (!substituted) break;
+ substituted = 0;
+ /* Fall through */
+ /* Test/branch if substitution didn't occur */
+ case 'T':
+ if (substituted) break;
+ /* Fall through */
+ /* Branch to label */
+ case 'b':
+ if (!sed_cmd->string) goto discard_commands;
+ else sed_cmd = branch_to(sed_cmd->string);
+ break;
+ /* Transliterate characters */
+ case 'y':
+ {
+ int i, j;
+
+ for (i = 0; pattern_space[i]; i++) {
+ for (j = 0; sed_cmd->string[j]; j += 2) {
+ if (pattern_space[i] == sed_cmd->string[j]) {
+ pattern_space[i] = sed_cmd->string[j + 1];
+ break;
+ }
+ }
+ }
+
+ break;
+ }
+ case 'g': /* Replace pattern space with hold space */
+ free(pattern_space);
+ pattern_space = xstrdup(G.hold_space ? G.hold_space : "");
+ break;
+ case 'G': /* Append newline and hold space to pattern space */
+ {
+ int pattern_space_size = 2;
+ int hold_space_size = 0;
+
+ if (pattern_space)
+ pattern_space_size += strlen(pattern_space);
+ if (G.hold_space)
+ hold_space_size = strlen(G.hold_space);
+ pattern_space = xrealloc(pattern_space,
+ pattern_space_size + hold_space_size);
+ if (pattern_space_size == 2)
+ pattern_space[0] = 0;
+ strcat(pattern_space, "\n");
+ if (G.hold_space)
+ strcat(pattern_space, G.hold_space);
+ last_gets_char = '\n';
+
+ break;
+ }
+ case 'h': /* Replace hold space with pattern space */
+ free(G.hold_space);
+ G.hold_space = xstrdup(pattern_space);
+ break;
+ case 'H': /* Append newline and pattern space to hold space */
+ {
+ int hold_space_size = 2;
+ int pattern_space_size = 0;
+
+ if (G.hold_space)
+ hold_space_size += strlen(G.hold_space);
+ if (pattern_space)
+ pattern_space_size = strlen(pattern_space);
+ G.hold_space = xrealloc(G.hold_space,
+ hold_space_size + pattern_space_size);
+
+ if (hold_space_size == 2)
+ *G.hold_space = 0;
+ strcat(G.hold_space, "\n");
+ if (pattern_space)
+ strcat(G.hold_space, pattern_space);
+
+ break;
+ }
+ case 'x': /* Exchange hold and pattern space */
+ {
+ char *tmp = pattern_space;
+ pattern_space = G.hold_space ? : xzalloc(1);
+ last_gets_char = '\n';
+ G.hold_space = tmp;
+ break;
+ }
+ }
+ }
+ }
+
+ /*
+ * exit point from sedding...
+ */
+ discard_commands:
+ /* we will print the line unless we were told to be quiet ('-n')
+ or if the line was suppressed (ala 'd'elete) */
+ if (!G.be_quiet)
+ sed_puts(pattern_space, last_gets_char);
+
+ /* Delete and such jump here. */
+ discard_line:
+ flush_append();
+ free(pattern_space);
+
+ goto again;
+}
+
+/* It is possible to have a command line argument with embedded
+ * newlines. This counts as multiple command lines.
+ * However, newline can be escaped: 's/e/z\<newline>z/'
+ * We check for this.
+ */
+
+static void add_cmd_block(char *cmdstr)
+{
+ char *sv, *eol;
+
+ cmdstr = sv = xstrdup(cmdstr);
+ do {
+ eol = strchr(cmdstr, '\n');
+ next:
+ if (eol) {
+ /* Count preceding slashes */
+ int slashes = 0;
+ char *sl = eol;
+
+ while (sl != cmdstr && *--sl == '\\')
+ slashes++;
+ /* Odd number of preceding slashes - newline is escaped */
+ if (slashes & 1) {
+ strcpy(eol-1, eol);
+ eol = strchr(eol, '\n');
+ goto next;
+ }
+ *eol = '\0';
+ }
+ add_cmd(cmdstr);
+ cmdstr = eol + 1;
+ } while (eol);
+ free(sv);
+}
+
+int sed_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int sed_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ enum {
+ OPT_in_place = 1 << 0,
+ };
+ unsigned opt;
+ llist_t *opt_e, *opt_f;
+ int status = EXIT_SUCCESS;
+
+ INIT_G();
+
+ /* destroy command strings on exit */
+ if (ENABLE_FEATURE_CLEAN_UP) atexit(sed_free_and_close_stuff);
+
+ /* Lie to autoconf when it starts asking stupid questions. */
+ if (argv[1] && !strcmp(argv[1], "--version")) {
+ puts("This is not GNU sed version 4.0");
+ return 0;
+ }
+
+ /* do normal option parsing */
+ opt_e = opt_f = NULL;
+ opt_complementary = "e::f::" /* can occur multiple times */
+ "nn"; /* count -n */
+ opt = getopt32(argv, "irne:f:", &opt_e, &opt_f,
+ &G.be_quiet); /* counter for -n */
+ //argc -= optind;
+ argv += optind;
+ if (opt & OPT_in_place) { // -i
+ atexit(cleanup_outname);
+ }
+ if (opt & 0x2) G.regex_type |= REG_EXTENDED; // -r
+ //if (opt & 0x4) G.be_quiet++; // -n
+ while (opt_e) { // -e
+ add_cmd_block(llist_pop(&opt_e));
+ }
+ while (opt_f) { // -f
+ char *line;
+ FILE *cmdfile;
+ cmdfile = xfopen(llist_pop(&opt_f), "r");
+ while ((line = xmalloc_fgetline(cmdfile)) != NULL) {
+ add_cmd(line);
+ free(line);
+ }
+ fclose(cmdfile);
+ }
+ /* if we didn't get a pattern from -e or -f, use argv[0] */
+ if (!(opt & 0x18)) {
+ if (!*argv)
+ bb_show_usage();
+ add_cmd_block(*argv++);
+ }
+ /* Flush any unfinished commands. */
+ add_cmd("");
+
+ /* By default, we write to stdout */
+ G.nonstdout = stdout;
+
+ /* argv[0..(argc-1)] should be names of file to process. If no
+ * files were specified or '-' was specified, take input from stdin.
+ * Otherwise, we process all the files specified. */
+ if (argv[0] == NULL) {
+ if (opt & OPT_in_place)
+ bb_error_msg_and_die(bb_msg_requires_arg, "-i");
+ add_input_file(stdin);
+ process_files();
+ } else {
+ int i;
+ FILE *file;
+
+ for (i = 0; argv[i]; i++) {
+ struct stat statbuf;
+ int nonstdoutfd;
+
+ if (LONE_DASH(argv[i]) && !(opt & OPT_in_place)) {
+ add_input_file(stdin);
+ process_files();
+ continue;
+ }
+ file = fopen_or_warn(argv[i], "r");
+ if (!file) {
+ status = EXIT_FAILURE;
+ continue;
+ }
+ if (!(opt & OPT_in_place)) {
+ add_input_file(file);
+ continue;
+ }
+
+ G.outname = xasprintf("%sXXXXXX", argv[i]);
+ nonstdoutfd = mkstemp(G.outname);
+ if (-1 == nonstdoutfd)
+ bb_perror_msg_and_die("cannot create temp file %s", G.outname);
+ G.nonstdout = fdopen(nonstdoutfd, "w");
+
+ /* Set permissions of output file */
+
+ fstat(fileno(file), &statbuf);
+ fchmod(nonstdoutfd, statbuf.st_mode);
+ add_input_file(file);
+ process_files();
+ fclose(G.nonstdout);
+
+ G.nonstdout = stdout;
+ /* unlink(argv[i]); */
+ xrename(G.outname, argv[i]);
+ free(G.outname);
+ G.outname = NULL;
+ }
+ if (G.input_file_count > G.current_input_file)
+ process_files();
+ }
+
+ return status;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/editors/sed1line.txt b/cleopatre/busybox-1.11.1-spc300/editors/sed1line.txt
new file mode 100644
index 0000000000..11a2e36be8
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/editors/sed1line.txt
@@ -0,0 +1,425 @@
+http://www.student.northpark.edu/pemente/sed/sed1line.txt
+-------------------------------------------------------------------------
+HANDY ONE-LINERS FOR SED (Unix stream editor) Apr. 26, 2004
+compiled by Eric Pement - pemente[at]northpark[dot]edu version 5.4
+Latest version of this file is usually at:
+ http://sed.sourceforge.net/sed1line.txt
+ http://www.student.northpark.edu/pemente/sed/sed1line.txt
+This file is also available in Portuguese at:
+ http://www.lrv.ufsc.br/wmaker/sed_ptBR.html
+
+FILE SPACING:
+
+ # double space a file
+ sed G
+
+ # double space a file which already has blank lines in it. Output file
+ # should contain no more than one blank line between lines of text.
+ sed '/^$/d;G'
+
+ # triple space a file
+ sed 'G;G'
+
+ # undo double-spacing (assumes even-numbered lines are always blank)
+ sed 'n;d'
+
+ # insert a blank line above every line which matches "regex"
+ sed '/regex/{x;p;x;}'
+
+ # insert a blank line below every line which matches "regex"
+ sed '/regex/G'
+
+ # insert a blank line above and below every line which matches "regex"
+ sed '/regex/{x;p;x;G;}'
+
+NUMBERING:
+
+ # number each line of a file (simple left alignment). Using a tab (see
+ # note on '\t' at end of file) instead of space will preserve margins.
+ sed = filename | sed 'N;s/\n/\t/'
+
+ # number each line of a file (number on left, right-aligned)
+ sed = filename | sed 'N; s/^/ /; s/ *\(.\{6,\}\)\n/\1 /'
+
+ # number each line of file, but only print numbers if line is not blank
+ sed '/./=' filename | sed '/./N; s/\n/ /'
+
+ # count lines (emulates "wc -l")
+ sed -n '$='
+
+TEXT CONVERSION AND SUBSTITUTION:
+
+ # IN UNIX ENVIRONMENT: convert DOS newlines (CR/LF) to Unix format
+ sed 's/.$//' # assumes that all lines end with CR/LF
+ sed 's/^M$//' # in bash/tcsh, press Ctrl-V then Ctrl-M
+ sed 's/\x0D$//' # gsed 3.02.80, but top script is easier
+
+ # IN UNIX ENVIRONMENT: convert Unix newlines (LF) to DOS format
+ sed "s/$/`echo -e \\\r`/" # command line under ksh
+ sed 's/$'"/`echo \\\r`/" # command line under bash
+ sed "s/$/`echo \\\r`/" # command line under zsh
+ sed 's/$/\r/' # gsed 3.02.80
+
+ # IN DOS ENVIRONMENT: convert Unix newlines (LF) to DOS format
+ sed "s/$//" # method 1
+ sed -n p # method 2
+
+ # IN DOS ENVIRONMENT: convert DOS newlines (CR/LF) to Unix format
+ # Can only be done with UnxUtils sed, version 4.0.7 or higher.
+ # Cannot be done with other DOS versions of sed. Use "tr" instead.
+ sed "s/\r//" infile >outfile # UnxUtils sed v4.0.7 or higher
+ tr -d \r <infile >outfile # GNU tr version 1.22 or higher
+
+ # delete leading whitespace (spaces, tabs) from front of each line
+ # aligns all text flush left
+ sed 's/^[ \t]*//' # see note on '\t' at end of file
+
+ # delete trailing whitespace (spaces, tabs) from end of each line
+ sed 's/[ \t]*$//' # see note on '\t' at end of file
+
+ # delete BOTH leading and trailing whitespace from each line
+ sed 's/^[ \t]*//;s/[ \t]*$//'
+
+ # insert 5 blank spaces at beginning of each line (make page offset)
+ sed 's/^/ /'
+
+ # align all text flush right on a 79-column width
+ sed -e :a -e 's/^.\{1,78\}$/ &/;ta' # set at 78 plus 1 space
+
+ # center all text in the middle of 79-column width. In method 1,
+ # spaces at the beginning of the line are significant, and trailing
+ # spaces are appended at the end of the line. In method 2, spaces at
+ # the beginning of the line are discarded in centering the line, and
+ # no trailing spaces appear at the end of lines.
+ sed -e :a -e 's/^.\{1,77\}$/ & /;ta' # method 1
+ sed -e :a -e 's/^.\{1,77\}$/ &/;ta' -e 's/\( *\)\1/\1/' # method 2
+
+ # substitute (find and replace) "foo" with "bar" on each line
+ sed 's/foo/bar/' # replaces only 1st instance in a line
+ sed 's/foo/bar/4' # replaces only 4th instance in a line
+ sed 's/foo/bar/g' # replaces ALL instances in a line
+ sed 's/\(.*\)foo\(.*foo\)/\1bar\2/' # replace the next-to-last case
+ sed 's/\(.*\)foo/\1bar/' # replace only the last case
+
+ # substitute "foo" with "bar" ONLY for lines which contain "baz"
+ sed '/baz/s/foo/bar/g'
+
+ # substitute "foo" with "bar" EXCEPT for lines which contain "baz"
+ sed '/baz/!s/foo/bar/g'
+
+ # change "scarlet" or "ruby" or "puce" to "red"
+ sed 's/scarlet/red/g;s/ruby/red/g;s/puce/red/g' # most seds
+ gsed 's/scarlet\|ruby\|puce/red/g' # GNU sed only
+
+ # reverse order of lines (emulates "tac")
+ # bug/feature in HHsed v1.5 causes blank lines to be deleted
+ sed '1!G;h;$!d' # method 1
+ sed -n '1!G;h;$p' # method 2
+
+ # reverse each character on the line (emulates "rev")
+ sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//'
+
+ # join pairs of lines side-by-side (like "paste")
+ sed '$!N;s/\n/ /'
+
+ # if a line ends with a backslash, append the next line to it
+ sed -e :a -e '/\\$/N; s/\\\n//; ta'
+
+ # if a line begins with an equal sign, append it to the previous line
+ # and replace the "=" with a single space
+ sed -e :a -e '$!N;s/\n=/ /;ta' -e 'P;D'
+
+ # add commas to numeric strings, changing "1234567" to "1,234,567"
+ gsed ':a;s/\B[0-9]\{3\}\>/,&/;ta' # GNU sed
+ sed -e :a -e 's/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/;ta' # other seds
+
+ # add commas to numbers with decimal points and minus signs (GNU sed)
+ gsed ':a;s/\(^\|[^0-9.]\)\([0-9]\+\)\([0-9]\{3\}\)/\1\2,\3/g;ta'
+
+ # add a blank line every 5 lines (after lines 5, 10, 15, 20, etc.)
+ gsed '0~5G' # GNU sed only
+ sed 'n;n;n;n;G;' # other seds
+
+SELECTIVE PRINTING OF CERTAIN LINES:
+
+ # print first 10 lines of file (emulates behavior of "head")
+ sed 10q
+
+ # print first line of file (emulates "head -1")
+ sed q
+
+ # print the last 10 lines of a file (emulates "tail")
+ sed -e :a -e '$q;N;11,$D;ba'
+
+ # print the last 2 lines of a file (emulates "tail -2")
+ sed '$!N;$!D'
+
+ # print the last line of a file (emulates "tail -1")
+ sed '$!d' # method 1
+ sed -n '$p' # method 2
+
+ # print only lines which match regular expression (emulates "grep")
+ sed -n '/regexp/p' # method 1
+ sed '/regexp/!d' # method 2
+
+ # print only lines which do NOT match regexp (emulates "grep -v")
+ sed -n '/regexp/!p' # method 1, corresponds to above
+ sed '/regexp/d' # method 2, simpler syntax
+
+ # print the line immediately before a regexp, but not the line
+ # containing the regexp
+ sed -n '/regexp/{g;1!p;};h'
+
+ # print the line immediately after a regexp, but not the line
+ # containing the regexp
+ sed -n '/regexp/{n;p;}'
+
+ # print 1 line of context before and after regexp, with line number
+ # indicating where the regexp occurred (similar to "grep -A1 -B1")
+ sed -n -e '/regexp/{=;x;1!p;g;$!N;p;D;}' -e h
+
+ # grep for AAA and BBB and CCC (in any order)
+ sed '/AAA/!d; /BBB/!d; /CCC/!d'
+
+ # grep for AAA and BBB and CCC (in that order)
+ sed '/AAA.*BBB.*CCC/!d'
+
+ # grep for AAA or BBB or CCC (emulates "egrep")
+ sed -e '/AAA/b' -e '/BBB/b' -e '/CCC/b' -e d # most seds
+ gsed '/AAA\|BBB\|CCC/!d' # GNU sed only
+
+ # print paragraph if it contains AAA (blank lines separate paragraphs)
+ # HHsed v1.5 must insert a 'G;' after 'x;' in the next 3 scripts below
+ sed -e '/./{H;$!d;}' -e 'x;/AAA/!d;'
+
+ # print paragraph if it contains AAA and BBB and CCC (in any order)
+ sed -e '/./{H;$!d;}' -e 'x;/AAA/!d;/BBB/!d;/CCC/!d'
+
+ # print paragraph if it contains AAA or BBB or CCC
+ sed -e '/./{H;$!d;}' -e 'x;/AAA/b' -e '/BBB/b' -e '/CCC/b' -e d
+ gsed '/./{H;$!d;};x;/AAA\|BBB\|CCC/b;d' # GNU sed only
+
+ # print only lines of 65 characters or longer
+ sed -n '/^.\{65\}/p'
+
+ # print only lines of less than 65 characters
+ sed -n '/^.\{65\}/!p' # method 1, corresponds to above
+ sed '/^.\{65\}/d' # method 2, simpler syntax
+
+ # print section of file from regular expression to end of file
+ sed -n '/regexp/,$p'
+
+ # print section of file based on line numbers (lines 8-12, inclusive)
+ sed -n '8,12p' # method 1
+ sed '8,12!d' # method 2
+
+ # print line number 52
+ sed -n '52p' # method 1
+ sed '52!d' # method 2
+ sed '52q;d' # method 3, efficient on large files
+
+ # beginning at line 3, print every 7th line
+ gsed -n '3~7p' # GNU sed only
+ sed -n '3,${p;n;n;n;n;n;n;}' # other seds
+
+ # print section of file between two regular expressions (inclusive)
+ sed -n '/Iowa/,/Montana/p' # case sensitive
+
+SELECTIVE DELETION OF CERTAIN LINES:
+
+ # print all of file EXCEPT section between 2 regular expressions
+ sed '/Iowa/,/Montana/d'
+
+ # delete duplicate, consecutive lines from a file (emulates "uniq").
+ # First line in a set of duplicate lines is kept, rest are deleted.
+ sed '$!N; /^\(.*\)\n\1$/!P; D'
+
+ # delete duplicate, nonconsecutive lines from a file. Beware not to
+ # overflow the buffer size of the hold space, or else use GNU sed.
+ sed -n 'G; s/\n/&&/; /^\([ -~]*\n\).*\n\1/d; s/\n//; h; P'
+
+ # delete all lines except duplicate lines (emulates "uniq -d").
+ sed '$!N; s/^\(.*\)\n\1$/\1/; t; D'
+
+ # delete the first 10 lines of a file
+ sed '1,10d'
+
+ # delete the last line of a file
+ sed '$d'
+
+ # delete the last 2 lines of a file
+ sed 'N;$!P;$!D;$d'
+
+ # delete the last 10 lines of a file
+ sed -e :a -e '$d;N;2,10ba' -e 'P;D' # method 1
+ sed -n -e :a -e '1,10!{P;N;D;};N;ba' # method 2
+
+ # delete every 8th line
+ gsed '0~8d' # GNU sed only
+ sed 'n;n;n;n;n;n;n;d;' # other seds
+
+ # delete ALL blank lines from a file (same as "grep '.' ")
+ sed '/^$/d' # method 1
+ sed '/./!d' # method 2
+
+ # delete all CONSECUTIVE blank lines from file except the first; also
+ # deletes all blank lines from top and end of file (emulates "cat -s")
+ sed '/./,/^$/!d' # method 1, allows 0 blanks at top, 1 at EOF
+ sed '/^$/N;/\n$/D' # method 2, allows 1 blank at top, 0 at EOF
+
+ # delete all CONSECUTIVE blank lines from file except the first 2:
+ sed '/^$/N;/\n$/N;//D'
+
+ # delete all leading blank lines at top of file
+ sed '/./,$!d'
+
+ # delete all trailing blank lines at end of file
+ sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' # works on all seds
+ sed -e :a -e '/^\n*$/N;/\n$/ba' # ditto, except for gsed 3.02*
+
+ # delete the last line of each paragraph
+ sed -n '/^$/{p;h;};/./{x;/./p;}'
+
+SPECIAL APPLICATIONS:
+
+ # remove nroff overstrikes (char, backspace) from man pages. The 'echo'
+ # command may need an -e switch if you use Unix System V or bash shell.
+ sed "s/.`echo \\\b`//g" # double quotes required for Unix environment
+ sed 's/.^H//g' # in bash/tcsh, press Ctrl-V and then Ctrl-H
+ sed 's/.\x08//g' # hex expression for sed v1.5
+
+ # get Usenet/e-mail message header
+ sed '/^$/q' # deletes everything after first blank line
+
+ # get Usenet/e-mail message body
+ sed '1,/^$/d' # deletes everything up to first blank line
+
+ # get Subject header, but remove initial "Subject: " portion
+ sed '/^Subject: */!d; s///;q'
+
+ # get return address header
+ sed '/^Reply-To:/q; /^From:/h; /./d;g;q'
+
+ # parse out the address proper. Pulls out the e-mail address by itself
+ # from the 1-line return address header (see preceding script)
+ sed 's/ *(.*)//; s/>.*//; s/.*[:<] *//'
+
+ # add a leading angle bracket and space to each line (quote a message)
+ sed 's/^/> /'
+
+ # delete leading angle bracket & space from each line (unquote a message)
+ sed 's/^> //'
+
+ # remove most HTML tags (accommodates multiple-line tags)
+ sed -e :a -e 's/<[^>]*>//g;/</N;//ba'
+
+ # extract multi-part uuencoded binaries, removing extraneous header
+ # info, so that only the uuencoded portion remains. Files passed to
+ # sed must be passed in the proper order. Version 1 can be entered
+ # from the command line; version 2 can be made into an executable
+ # Unix shell script. (Modified from a script by Rahul Dhesi.)
+ sed '/^end/,/^begin/d' file1 file2 ... fileX | uudecode # vers. 1
+ sed '/^end/,/^begin/d' "$@" | uudecode # vers. 2
+
+ # zip up each .TXT file individually, deleting the source file and
+ # setting the name of each .ZIP file to the basename of the .TXT file
+ # (under DOS: the "dir /b" switch returns bare filenames in all caps).
+ echo @echo off >zipup.bat
+ dir /b *.txt | sed "s/^\(.*\)\.TXT/pkzip -mo \1 \1.TXT/" >>zipup.bat
+
+TYPICAL USE: Sed takes one or more editing commands and applies all of
+them, in sequence, to each line of input. After all the commands have
+been applied to the first input line, that line is output and a second
+input line is taken for processing, and the cycle repeats. The
+preceding examples assume that input comes from the standard input
+device (i.e, the console, normally this will be piped input). One or
+more filenames can be appended to the command line if the input does
+not come from stdin. Output is sent to stdout (the screen). Thus:
+
+ cat filename | sed '10q' # uses piped input
+ sed '10q' filename # same effect, avoids a useless "cat"
+ sed '10q' filename > newfile # redirects output to disk
+
+For additional syntax instructions, including the way to apply editing
+commands from a disk file instead of the command line, consult "sed &
+awk, 2nd Edition," by Dale Dougherty and Arnold Robbins (O'Reilly,
+1997; http://www.ora.com), "UNIX Text Processing," by Dale Dougherty
+and Tim O'Reilly (Hayden Books, 1987) or the tutorials by Mike Arst
+distributed in U-SEDIT2.ZIP (many sites). To fully exploit the power
+of sed, one must understand "regular expressions." For this, see
+"Mastering Regular Expressions" by Jeffrey Friedl (O'Reilly, 1997).
+The manual ("man") pages on Unix systems may be helpful (try "man
+sed", "man regexp", or the subsection on regular expressions in "man
+ed"), but man pages are notoriously difficult. They are not written to
+teach sed use or regexps to first-time users, but as a reference text
+for those already acquainted with these tools.
+
+QUOTING SYNTAX: The preceding examples use single quotes ('...')
+instead of double quotes ("...") to enclose editing commands, since
+sed is typically used on a Unix platform. Single quotes prevent the
+Unix shell from intrepreting the dollar sign ($) and backquotes
+(`...`), which are expanded by the shell if they are enclosed in
+double quotes. Users of the "csh" shell and derivatives will also need
+to quote the exclamation mark (!) with the backslash (i.e., \!) to
+properly run the examples listed above, even within single quotes.
+Versions of sed written for DOS invariably require double quotes
+("...") instead of single quotes to enclose editing commands.
+
+USE OF '\t' IN SED SCRIPTS: For clarity in documentation, we have used
+the expression '\t' to indicate a tab character (0x09) in the scripts.
+However, most versions of sed do not recognize the '\t' abbreviation,
+so when typing these scripts from the command line, you should press
+the TAB key instead. '\t' is supported as a regular expression
+metacharacter in awk, perl, and HHsed, sedmod, and GNU sed v3.02.80.
+
+VERSIONS OF SED: Versions of sed do differ, and some slight syntax
+variation is to be expected. In particular, most do not support the
+use of labels (:name) or branch instructions (b,t) within editing
+commands, except at the end of those commands. We have used the syntax
+which will be portable to most users of sed, even though the popular
+GNU versions of sed allow a more succinct syntax. When the reader sees
+a fairly long command such as this:
+
+ sed -e '/AAA/b' -e '/BBB/b' -e '/CCC/b' -e d
+
+it is heartening to know that GNU sed will let you reduce it to:
+
+ sed '/AAA/b;/BBB/b;/CCC/b;d' # or even
+ sed '/AAA\|BBB\|CCC/b;d'
+
+In addition, remember that while many versions of sed accept a command
+like "/one/ s/RE1/RE2/", some do NOT allow "/one/! s/RE1/RE2/", which
+contains space before the 's'. Omit the space when typing the command.
+
+OPTIMIZING FOR SPEED: If execution speed needs to be increased (due to
+large input files or slow processors or hard disks), substitution will
+be executed more quickly if the "find" expression is specified before
+giving the "s/.../.../" instruction. Thus:
+
+ sed 's/foo/bar/g' filename # standard replace command
+ sed '/foo/ s/foo/bar/g' filename # executes more quickly
+ sed '/foo/ s//bar/g' filename # shorthand sed syntax
+
+On line selection or deletion in which you only need to output lines
+from the first part of the file, a "quit" command (q) in the script
+will drastically reduce processing time for large files. Thus:
+
+ sed -n '45,50p' filename # print line nos. 45-50 of a file
+ sed -n '51q;45,50p' filename # same, but executes much faster
+
+If you have any additional scripts to contribute or if you find errors
+in this document, please send e-mail to the compiler. Indicate the
+version of sed you used, the operating system it was compiled for, and
+the nature of the problem. Various scripts in this file were written
+or contributed by:
+
+ Al Aab <af137@freenet.toronto.on.ca> # "seders" list moderator
+ Edgar Allen <era@sky.net> # various
+ Yiorgos Adamopoulos <adamo@softlab.ece.ntua.gr>
+ Dale Dougherty <dale@songline.com> # author of "sed & awk"
+ Carlos Duarte <cdua@algos.inesc.pt> # author of "do it with sed"
+ Eric Pement <pemente@northpark.edu> # author of this document
+ Ken Pizzini <ken@halcyon.com> # author of GNU sed v3.02
+ S.G. Ravenhall <stew.ravenhall@totalise.co.uk> # great de-html script
+ Greg Ubben <gsu@romulus.ncsc.mil> # many contributions & much help
+-------------------------------------------------------------------------
diff --git a/cleopatre/busybox-1.11.1-spc300/editors/sed_summary.htm b/cleopatre/busybox-1.11.1-spc300/editors/sed_summary.htm
new file mode 100644
index 0000000000..34e72b0f86
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/editors/sed_summary.htm
@@ -0,0 +1,223 @@
+<html>
+
+<head><title>Command Summary for sed (sed & awk, Second Edition)</title>
+</head>
+
+<body>
+
+<h2>Command Summary for sed</h2>
+
+<dl>
+
+<dt><b>: </b> <b> :</b><em>label</em></dt>
+<dd>Label a line in the script for the transfer of control by
+<b>b</b> or <b>t</b>.
+<em>label</em> may contain up to seven characters.
+(The POSIX standard says that an implementation can allow longer
+labels if it wishes to. GNU sed allows labels to be of any length.)
+</p></dd>
+
+
+<dt><b>=</b> [<em>address</em>]<b>=</b></dt>
+<dd>Write to standard output the line number of addressed line.</p></dd>
+
+
+<dt><b>a</b> [<em>address</em>]<b>a\</b></dt>
+<dd><em>text</em></p>
+
+<p>Append <em>text</em>
+following each line matched by <em>address</em>. If
+<em>text</em> goes over more than one line, newlines
+must be "hidden" by preceding them with a backslash. The
+<em>text</em> will be terminated by the first
+newline that is not hidden in this way. The
+<em>text</em> is not available in the pattern space
+and subsequent commands cannot be applied to it. The results of this
+command are sent to standard output when the list of editing commands
+is finished, regardless of what happens to the current line in the
+pattern space.</p></dd>
+
+
+<dt><b>b</b> [<em>address1</em>[,<em>address2</em>]]<b>b</b>[<em>label</em>]</dt>
+<dd>Transfer control unconditionally (branch) to
+<b>:</b><em>label</em> elsewhere in
+script. That is, the command following the
+<em>label</em> is the next command applied to the
+current line. If no <em>label</em> is specified,
+control falls through to the end of the script, so no more commands
+are applied to the current line.</p></dd>
+
+
+<dt><b>c</b> [<em>address1</em>[,<em>address2</em>]]<b>c\</b></dt>
+<dd><em>text</em></p>
+
+<p>Replace (change) the lines selected by the address with
+<em>text</em>. When a range of lines is specified,
+all lines as a group are replaced by a single copy of
+<em>text</em>. The newline following each line of
+<em>text</em> must be escaped by a backslash, except
+the last line. The contents of the pattern space are, in effect,
+deleted and no subsequent editing commands can be applied to it (or to
+<em>text</em>).</p></dd>
+
+
+<dt><b>d</b> [<em>address1</em>[,<em>address2</em>]]<b>d</b></dt>
+<dd>Delete line(s) from pattern space. Thus, the line is not passed to standard
+output. A new line of input is read and editing resumes with first
+command in script.</p></dd>
+
+
+<dt><b>D</b> [<em>address1</em>[,<em>address2</em>]]<b>D</b></dt>
+<dd>Delete first part (up to embedded newline) of multiline pattern space created
+by <b>N</b> command and resume editing with first command in
+script. If this command empties the pattern space, then a new line
+of input is read, as if the <b>d</b> command had been executed.</p></dd>
+
+
+<dt><b>g</b> [<em>address1</em>[,<em>address2</em>]]<b>g</b></dt>
+<dd>Copy (get) contents of hold space (see <b>h</b> or
+<b>H</b> command) into the pattern space, wiping out
+previous contents.</p></dd>
+
+
+<dt><b>G</b> [<em>address1</em>[,<em>address2</em>]]<b>G</b></dt>
+<dd>Append newline followed by contents of hold space (see
+<b>h</b> or <b>H</b> command) to contents of
+the pattern space. If hold space is empty, a newline is still
+appended to the pattern space.</p></dd>
+
+
+<dt><b>h</b> [<em>address1</em>[,<em>address2</em>]]<b>h</b></dt>
+<dd>Copy pattern space into hold space, a special temporary buffer.
+Previous contents of hold space are wiped out.</p></dd>
+
+
+<dt><b>H</b> [<em>address1</em>[,<em>address2</em>]]<b>H</b></dt>
+<dd>Append newline and contents of pattern space to contents of the hold
+space. Even if hold space is empty, this command still appends the
+newline first.</p></dd>
+
+
+<dt><b>i</b> [<em>address1</em>]<b>i\</b></dt>
+<dd><em>text</em></p>
+
+<p>Insert <em>text</em> before each line matched by
+<em>address</em>. (See <b>a</b> for
+details on <em>text</em>.)</p></dd>
+
+
+<dt><b>l</b> [<em>address1</em>[,<em>address2</em>]]<b>l</b></dt>
+<dd>List the contents of the pattern space, showing nonprinting characters
+as ASCII codes. Long lines are wrapped.</p></dd>
+
+
+<dt><b>n</b> [<em>address1</em>[,<em>address2</em>]]<b>n</b></dt>
+<dd>Read next line of input into pattern space. Current line is sent to
+standard output. New line becomes current line and increments line
+counter. Control passes to command following <b>n</b>
+instead of resuming at the top of the script.</p></dd>
+
+
+<dt><b>N</b> [<em>address1</em>[,<em>address2</em>]]<b>N</b></dt>
+<dd>Append next input line to contents of pattern space; the new line is
+separated from the previous contents of the pattern space by a newline.
+(This command is designed to allow pattern matches across two
+lines. Using \n to match the embedded newline, you can match
+patterns across multiple lines.)</p></dd>
+
+
+<dt><b>p</b> [<em>address1</em>[,<em>address2</em>]]<b>p</b></dt>
+<dd>Print the addressed line(s). Note that this can result in duplicate
+output unless default output is suppressed by using "#n" or
+the <span class="option">-n</span>
+
+command-line option. Typically used before commands that change flow
+control (<b>d</b>, <b>n</b>,
+<b>b</b>) and might prevent the current line from being
+output.</p></dd>
+
+
+<dt><b>P</b> [<em>address1</em>[,<em>address2</em>]]<b>P</b></dt>
+<dd>Print first part (up to embedded newline) of multiline pattern space
+created by <b>N</b> command. Same as <b>p</b>
+if <b>N</b> has not been applied to a line.</p></dd>
+
+
+<dt><b>q</b> [<em>address</em>]<b>q</b></dt>
+<dd>Quit when <em>address</em> is encountered. The
+addressed line is first written to output (if default output is not
+suppressed), along with any text appended to it by previous
+<b>a</b> or <b>r</b> commands.</p></dd>
+
+
+<dt><b>r</b> [<em>address</em>]<b>r</b> <em>file</em></dt>
+<dd>Read contents of <em>file</em> and append after the
+contents of the pattern space. Exactly one space must be put between
+<b>r</b> and the filename.</p></dd>
+
+
+<dt><b>s</b> [<em>address1</em>[,<em>address2</em>]]<b>s</b>/<em>pattern</em>/<em>replacement</em>/[<em>flags</em>]</dt>
+<dd>Substitute <em>replacement</em> for
+<em>pattern</em> on each addressed line. If pattern
+addresses are used, the pattern <b>//</b> represents the
+last pattern address specified. The following flags can be specified:</p>
+
+ <dl>
+
+ <dt><b>n</b></dt>
+ <dd>Replace <em>n</em>th instance of
+ /<em>pattern</em>/ on each addressed line.
+ <em>n</em> is any number in the range 1 to 512, and
+ the default is 1.</p></dd>
+
+ <dt><b>g</b></dt>
+ <dd>Replace all instances of /<em>pattern</em>/ on each
+ addressed line, not just the first instance.</p></dd>
+
+ <dt><b>I</b></dt>
+ <dd>Matching is case-insensitive.<p></p></dd>
+
+ <dt><b>p</b></dt>
+ <dd>Print the line if a successful substitution is done. If several
+ successful substitutions are done, multiple copies of the line will be
+ printed.</p></dd>
+
+ <dt><b>w</b> <em>file</em></dt>
+ <dd>Write the line to <em>file</em> if a replacement
+ was done. A maximum of 10 different <em>files</em> can be opened.</p></dd>
+
+ </dl>
+
+</dd>
+
+
+<dt><b>t</b> [<em>address1</em>[,<em>address2</em>]]<b>t </b>[<em>label</em>]</dt>
+<dd>Test if successful substitutions have been made on addressed lines,
+and if so, branch to line marked by :<em>label</em>.
+(See <b>b</b> and <b>:</b>.) If label is not
+specified, control falls through to bottom of script.</p></dd>
+
+
+<dt><b>w</b> [<em>address1</em>[,<em>address2</em>]]<b>w</b> <em>file</em></dt>
+<dd>Append contents of pattern space to <em>file</em>.
+This action occurs when the command is encountered rather than when
+the pattern space is output. Exactly one space must separate the
+<b>w</b> and the filename. A maximum of 10 different
+files can be opened in a script. This command will create the file if
+it does not exist; if the file exists, its contents will be
+overwritten each time the script is executed. Multiple write commands
+that direct output to the same file append to the end of the file.</p></dd>
+
+
+<dt><b>x</b> [<em>address1</em>[,<em>address2</em>]]<b>x</b></dt>
+<dd>Exchange contents of the pattern space with the contents of the hold
+space.</p></dd>
+
+
+<dt><b>y</b> [<em>address1</em>[,<em>address2</em>]]<b>y</b>/<em>abc</em>/<em>xyz</em>/</dt>
+<dd>Transform each character by position in string
+<em>abc</em> to its equivalent in string
+<em>xyz</em>.</p></dd>
+
+
+</dl>
diff --git a/cleopatre/busybox-1.11.1-spc300/editors/vi.c b/cleopatre/busybox-1.11.1-spc300/editors/vi.c
new file mode 100644
index 0000000000..81baa890f7
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/editors/vi.c
@@ -0,0 +1,4073 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * tiny vi.c: A small 'vi' clone
+ * Copyright (C) 2000, 2001 Sterling Huxley <sterling@europa.com>
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+/*
+ * Things To Do:
+ * EXINIT
+ * $HOME/.exrc and ./.exrc
+ * add magic to search /foo.*bar
+ * add :help command
+ * :map macros
+ * if mark[] values were line numbers rather than pointers
+ * it would be easier to change the mark when add/delete lines
+ * More intelligence in refresh()
+ * ":r !cmd" and "!cmd" to filter text through an external command
+ * A true "undo" facility
+ * An "ex" line oriented mode- maybe using "cmdedit"
+ */
+
+#include "libbb.h"
+
+/* the CRASHME code is unmaintained, and doesn't currently build */
+#define ENABLE_FEATURE_VI_CRASHME 0
+
+
+#if ENABLE_LOCALE_SUPPORT
+
+#if ENABLE_FEATURE_VI_8BIT
+#define Isprint(c) isprint(c)
+#else
+#define Isprint(c) (isprint(c) && (unsigned char)(c) < 0x7f)
+#endif
+
+#else
+
+/* 0x9b is Meta-ESC */
+#if ENABLE_FEATURE_VI_8BIT
+#define Isprint(c) ((unsigned char)(c) >= ' ' && (c) != 0x7f && (unsigned char)(c) != 0x9b)
+#else
+#define Isprint(c) ((unsigned char)(c) >= ' ' && (unsigned char)(c) < 0x7f)
+#endif
+
+#endif
+
+
+enum {
+ MAX_TABSTOP = 32, // sanity limit
+ // User input len. Need not be extra big.
+ // Lines in file being edited *can* be bigger than this.
+ MAX_INPUT_LEN = 128,
+ // Sanity limits. We have only one buffer of this size.
+ MAX_SCR_COLS = CONFIG_FEATURE_VI_MAX_LEN,
+ MAX_SCR_ROWS = CONFIG_FEATURE_VI_MAX_LEN,
+};
+
+// Misc. non-Ascii keys that report an escape sequence
+#define VI_K_UP (char)128 // cursor key Up
+#define VI_K_DOWN (char)129 // cursor key Down
+#define VI_K_RIGHT (char)130 // Cursor Key Right
+#define VI_K_LEFT (char)131 // cursor key Left
+#define VI_K_HOME (char)132 // Cursor Key Home
+#define VI_K_END (char)133 // Cursor Key End
+#define VI_K_INSERT (char)134 // Cursor Key Insert
+#define VI_K_DELETE (char)135 // Cursor Key Insert
+#define VI_K_PAGEUP (char)136 // Cursor Key Page Up
+#define VI_K_PAGEDOWN (char)137 // Cursor Key Page Down
+#define VI_K_FUN1 (char)138 // Function Key F1
+#define VI_K_FUN2 (char)139 // Function Key F2
+#define VI_K_FUN3 (char)140 // Function Key F3
+#define VI_K_FUN4 (char)141 // Function Key F4
+#define VI_K_FUN5 (char)142 // Function Key F5
+#define VI_K_FUN6 (char)143 // Function Key F6
+#define VI_K_FUN7 (char)144 // Function Key F7
+#define VI_K_FUN8 (char)145 // Function Key F8
+#define VI_K_FUN9 (char)146 // Function Key F9
+#define VI_K_FUN10 (char)147 // Function Key F10
+#define VI_K_FUN11 (char)148 // Function Key F11
+#define VI_K_FUN12 (char)149 // Function Key F12
+
+/* vt102 typical ESC sequence */
+/* terminal standout start/normal ESC sequence */
+static const char SOs[] ALIGN1 = "\033[7m";
+static const char SOn[] ALIGN1 = "\033[0m";
+/* terminal bell sequence */
+static const char bell[] ALIGN1 = "\007";
+/* Clear-end-of-line and Clear-end-of-screen ESC sequence */
+static const char Ceol[] ALIGN1 = "\033[0K";
+static const char Ceos[] ALIGN1 = "\033[0J";
+/* Cursor motion arbitrary destination ESC sequence */
+static const char CMrc[] ALIGN1 = "\033[%d;%dH";
+/* Cursor motion up and down ESC sequence */
+static const char CMup[] ALIGN1 = "\033[A";
+static const char CMdown[] ALIGN1 = "\n";
+
+
+enum {
+ YANKONLY = FALSE,
+ YANKDEL = TRUE,
+ FORWARD = 1, // code depends on "1" for array index
+ BACK = -1, // code depends on "-1" for array index
+ LIMITED = 0, // how much of text[] in char_search
+ FULL = 1, // how much of text[] in char_search
+
+ S_BEFORE_WS = 1, // used in skip_thing() for moving "dot"
+ S_TO_WS = 2, // used in skip_thing() for moving "dot"
+ S_OVER_WS = 3, // used in skip_thing() for moving "dot"
+ S_END_PUNCT = 4, // used in skip_thing() for moving "dot"
+ S_END_ALNUM = 5, // used in skip_thing() for moving "dot"
+};
+
+
+/* vi.c expects chars to be unsigned. */
+/* busybox build system provides that, but it's better */
+/* to audit and fix the source */
+
+struct globals {
+ /* many references - keep near the top of globals */
+ char *text, *end; // pointers to the user data in memory
+ char *dot; // where all the action takes place
+ int text_size; // size of the allocated buffer
+
+ /* the rest */
+ smallint vi_setops;
+#define VI_AUTOINDENT 1
+#define VI_SHOWMATCH 2
+#define VI_IGNORECASE 4
+#define VI_ERR_METHOD 8
+#define autoindent (vi_setops & VI_AUTOINDENT)
+#define showmatch (vi_setops & VI_SHOWMATCH )
+#define ignorecase (vi_setops & VI_IGNORECASE)
+/* indicate error with beep or flash */
+#define err_method (vi_setops & VI_ERR_METHOD)
+
+#if ENABLE_FEATURE_VI_READONLY
+ smallint readonly_mode;
+#define SET_READONLY_FILE(flags) ((flags) |= 0x01)
+#define SET_READONLY_MODE(flags) ((flags) |= 0x02)
+#define UNSET_READONLY_FILE(flags) ((flags) &= 0xfe)
+#else
+#define SET_READONLY_FILE(flags) ((void)0)
+#define SET_READONLY_MODE(flags) ((void)0)
+#define UNSET_READONLY_FILE(flags) ((void)0)
+#endif
+
+ smallint editing; // >0 while we are editing a file
+ // [code audit says "can be 0 or 1 only"]
+ smallint cmd_mode; // 0=command 1=insert 2=replace
+ int file_modified; // buffer contents changed (counter, not flag!)
+ int last_file_modified; // = -1;
+ int fn_start; // index of first cmd line file name
+ int save_argc; // how many file names on cmd line
+ int cmdcnt; // repetition count
+ unsigned rows, columns; // the terminal screen is this size
+ int crow, ccol; // cursor is on Crow x Ccol
+ int offset; // chars scrolled off the screen to the left
+ int have_status_msg; // is default edit status needed?
+ // [don't make smallint!]
+ int last_status_cksum; // hash of current status line
+ char *current_filename;
+ char *screenbegin; // index into text[], of top line on the screen
+ char *screen; // pointer to the virtual screen buffer
+ int screensize; // and its size
+ int tabstop;
+ char erase_char; // the users erase character
+ char last_input_char; // last char read from user
+ char last_forward_char; // last char searched for with 'f'
+
+#if ENABLE_FEATURE_VI_DOT_CMD
+ smallint adding2q; // are we currently adding user input to q
+ int lmc_len; // length of last_modifying_cmd
+ char *ioq, *ioq_start; // pointer to string for get_one_char to "read"
+#endif
+#if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
+ int last_row; // where the cursor was last moved to
+#endif
+#if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME
+ int my_pid;
+#endif
+#if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK
+ char *modifying_cmds; // cmds that modify text[]
+#endif
+#if ENABLE_FEATURE_VI_SEARCH
+ char *last_search_pattern; // last pattern from a '/' or '?' search
+#endif
+ int chars_to_parse;
+ /* former statics */
+#if ENABLE_FEATURE_VI_YANKMARK
+ char *edit_file__cur_line;
+#endif
+ int refresh__old_offset;
+ int format_edit_status__tot;
+
+ /* a few references only */
+#if ENABLE_FEATURE_VI_YANKMARK
+ int YDreg, Ureg; // default delete register and orig line for "U"
+ char *reg[28]; // named register a-z, "D", and "U" 0-25,26,27
+ char *mark[28]; // user marks points somewhere in text[]- a-z and previous context ''
+ char *context_start, *context_end;
+#endif
+#if ENABLE_FEATURE_VI_USE_SIGNALS
+ sigjmp_buf restart; // catch_sig()
+#endif
+ struct termios term_orig, term_vi; // remember what the cooked mode was
+#if ENABLE_FEATURE_VI_COLON
+ char *initial_cmds[3]; // currently 2 entries, NULL terminated
+#endif
+ // Should be just enough to hold a key sequence,
+ // but CRASME mode uses it as generated command buffer too
+#if ENABLE_FEATURE_VI_CRASHME
+ char readbuffer[128];
+#else
+ char readbuffer[32];
+#endif
+#define STATUS_BUFFER_LEN 200
+ char status_buffer[STATUS_BUFFER_LEN]; // messages to the user
+#if ENABLE_FEATURE_VI_DOT_CMD
+ char last_modifying_cmd[MAX_INPUT_LEN]; // last modifying cmd for "."
+#endif
+ char get_input_line__buf[MAX_INPUT_LEN]; /* former static */
+
+ char scr_out_buf[MAX_SCR_COLS + MAX_TABSTOP * 2];
+};
+#define G (*ptr_to_globals)
+#define text (G.text )
+#define text_size (G.text_size )
+#define end (G.end )
+#define dot (G.dot )
+#define reg (G.reg )
+
+#define vi_setops (G.vi_setops )
+#define editing (G.editing )
+#define cmd_mode (G.cmd_mode )
+#define file_modified (G.file_modified )
+#define last_file_modified (G.last_file_modified )
+#define fn_start (G.fn_start )
+#define save_argc (G.save_argc )
+#define cmdcnt (G.cmdcnt )
+#define rows (G.rows )
+#define columns (G.columns )
+#define crow (G.crow )
+#define ccol (G.ccol )
+#define offset (G.offset )
+#define status_buffer (G.status_buffer )
+#define have_status_msg (G.have_status_msg )
+#define last_status_cksum (G.last_status_cksum )
+#define current_filename (G.current_filename )
+#define screen (G.screen )
+#define screensize (G.screensize )
+#define screenbegin (G.screenbegin )
+#define tabstop (G.tabstop )
+#define erase_char (G.erase_char )
+#define last_input_char (G.last_input_char )
+#define last_forward_char (G.last_forward_char )
+#if ENABLE_FEATURE_VI_READONLY
+#define readonly_mode (G.readonly_mode )
+#else
+#define readonly_mode 0
+#endif
+#define adding2q (G.adding2q )
+#define lmc_len (G.lmc_len )
+#define ioq (G.ioq )
+#define ioq_start (G.ioq_start )
+#define last_row (G.last_row )
+#define my_pid (G.my_pid )
+#define modifying_cmds (G.modifying_cmds )
+#define last_search_pattern (G.last_search_pattern)
+#define chars_to_parse (G.chars_to_parse )
+
+#define edit_file__cur_line (G.edit_file__cur_line)
+#define refresh__old_offset (G.refresh__old_offset)
+#define format_edit_status__tot (G.format_edit_status__tot)
+
+#define YDreg (G.YDreg )
+#define Ureg (G.Ureg )
+#define mark (G.mark )
+#define context_start (G.context_start )
+#define context_end (G.context_end )
+#define restart (G.restart )
+#define term_orig (G.term_orig )
+#define term_vi (G.term_vi )
+#define initial_cmds (G.initial_cmds )
+#define readbuffer (G.readbuffer )
+#define scr_out_buf (G.scr_out_buf )
+#define last_modifying_cmd (G.last_modifying_cmd )
+#define get_input_line__buf (G.get_input_line__buf)
+
+#define INIT_G() do { \
+ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
+ last_file_modified = -1; \
+} while (0)
+
+
+static int init_text_buffer(char *); // init from file or create new
+static void edit_file(char *); // edit one file
+static void do_cmd(char); // execute a command
+static int next_tabstop(int);
+static void sync_cursor(char *, int *, int *); // synchronize the screen cursor to dot
+static char *begin_line(char *); // return pointer to cur line B-o-l
+static char *end_line(char *); // return pointer to cur line E-o-l
+static char *prev_line(char *); // return pointer to prev line B-o-l
+static char *next_line(char *); // return pointer to next line B-o-l
+static char *end_screen(void); // get pointer to last char on screen
+static int count_lines(char *, char *); // count line from start to stop
+static char *find_line(int); // find begining of line #li
+static char *move_to_col(char *, int); // move "p" to column l
+static void dot_left(void); // move dot left- dont leave line
+static void dot_right(void); // move dot right- dont leave line
+static void dot_begin(void); // move dot to B-o-l
+static void dot_end(void); // move dot to E-o-l
+static void dot_next(void); // move dot to next line B-o-l
+static void dot_prev(void); // move dot to prev line B-o-l
+static void dot_scroll(int, int); // move the screen up or down
+static void dot_skip_over_ws(void); // move dot pat WS
+static void dot_delete(void); // delete the char at 'dot'
+static char *bound_dot(char *); // make sure text[0] <= P < "end"
+static char *new_screen(int, int); // malloc virtual screen memory
+static char *char_insert(char *, char); // insert the char c at 'p'
+static char *stupid_insert(char *, char); // stupidly insert the char c at 'p'
+static int find_range(char **, char **, char); // return pointers for an object
+static int st_test(char *, int, int, char *); // helper for skip_thing()
+static char *skip_thing(char *, int, int, int); // skip some object
+static char *find_pair(char *, char); // find matching pair () [] {}
+static char *text_hole_delete(char *, char *); // at "p", delete a 'size' byte hole
+static char *text_hole_make(char *, int); // at "p", make a 'size' byte hole
+static char *yank_delete(char *, char *, int, int); // yank text[] into register then delete
+static void show_help(void); // display some help info
+static void rawmode(void); // set "raw" mode on tty
+static void cookmode(void); // return to "cooked" mode on tty
+// sleep for 'h' 1/100 seconds, return 1/0 if stdin is (ready for read)/(not ready)
+static int mysleep(int);
+static char readit(void); // read (maybe cursor) key from stdin
+static char get_one_char(void); // read 1 char from stdin
+static int file_size(const char *); // what is the byte size of "fn"
+#if ENABLE_FEATURE_VI_READONLY
+static int file_insert(const char *, char *, int);
+#else
+static int file_insert(const char *, char *);
+#endif
+static int file_write(char *, char *, char *);
+#if !ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
+#define place_cursor(a, b, optimize) place_cursor(a, b)
+#endif
+static void place_cursor(int, int, int);
+static void screen_erase(void);
+static void clear_to_eol(void);
+static void clear_to_eos(void);
+static void standout_start(void); // send "start reverse video" sequence
+static void standout_end(void); // send "end reverse video" sequence
+static void flash(int); // flash the terminal screen
+static void show_status_line(void); // put a message on the bottom line
+static void status_line(const char *, ...); // print to status buf
+static void status_line_bold(const char *, ...);
+static void not_implemented(const char *); // display "Not implemented" message
+static int format_edit_status(void); // format file status on status line
+static void redraw(int); // force a full screen refresh
+static char* format_line(char* /*, int*/);
+static void refresh(int); // update the terminal from screen[]
+
+static void Indicate_Error(void); // use flash or beep to indicate error
+#define indicate_error(c) Indicate_Error()
+static void Hit_Return(void);
+
+#if ENABLE_FEATURE_VI_SEARCH
+static char *char_search(char *, const char *, int, int); // search for pattern starting at p
+static int mycmp(const char *, const char *, int); // string cmp based in "ignorecase"
+#endif
+#if ENABLE_FEATURE_VI_COLON
+static char *get_one_address(char *, int *); // get colon addr, if present
+static char *get_address(char *, int *, int *); // get two colon addrs, if present
+static void colon(char *); // execute the "colon" mode cmds
+#endif
+#if ENABLE_FEATURE_VI_USE_SIGNALS
+static void winch_sig(int); // catch window size changes
+static void suspend_sig(int); // catch ctrl-Z
+static void catch_sig(int); // catch ctrl-C and alarm time-outs
+#endif
+#if ENABLE_FEATURE_VI_DOT_CMD
+static void start_new_cmd_q(char); // new queue for command
+static void end_cmd_q(void); // stop saving input chars
+#else
+#define end_cmd_q() ((void)0)
+#endif
+#if ENABLE_FEATURE_VI_SETOPTS
+static void showmatching(char *); // show the matching pair () [] {}
+#endif
+#if ENABLE_FEATURE_VI_YANKMARK || (ENABLE_FEATURE_VI_COLON && ENABLE_FEATURE_VI_SEARCH) || ENABLE_FEATURE_VI_CRASHME
+static char *string_insert(char *, char *); // insert the string at 'p'
+#endif
+#if ENABLE_FEATURE_VI_YANKMARK
+static char *text_yank(char *, char *, int); // save copy of "p" into a register
+static char what_reg(void); // what is letter of current YDreg
+static void check_context(char); // remember context for '' command
+#endif
+#if ENABLE_FEATURE_VI_CRASHME
+static void crash_dummy();
+static void crash_test();
+static int crashme = 0;
+#endif
+
+
+static void write1(const char *out)
+{
+ fputs(out, stdout);
+}
+
+int vi_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int vi_main(int argc, char **argv)
+{
+ int c;
+
+ INIT_G();
+
+#if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME
+ my_pid = getpid();
+#endif
+#if ENABLE_FEATURE_VI_CRASHME
+ srand((long) my_pid);
+#endif
+#ifdef NO_SUCH_APPLET_YET
+ /* If we aren't "vi", we are "view" */
+ if (ENABLE_FEATURE_VI_READONLY && applet_name[2]) {
+ SET_READONLY_MODE(readonly_mode);
+ }
+#endif
+
+ vi_setops = VI_AUTOINDENT | VI_SHOWMATCH | VI_IGNORECASE;
+#if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK
+ modifying_cmds = (char *) "aAcCdDiIJoOpPrRsxX<>~"; // cmds modifying text[]
+#endif
+
+ // 1- process $HOME/.exrc file (not inplemented yet)
+ // 2- process EXINIT variable from environment
+ // 3- process command line args
+#if ENABLE_FEATURE_VI_COLON
+ {
+ char *p = getenv("EXINIT");
+ if (p && *p)
+ initial_cmds[0] = xstrndup(p, MAX_INPUT_LEN);
+ }
+#endif
+ while ((c = getopt(argc, argv, "hCRH" USE_FEATURE_VI_COLON("c:"))) != -1) {
+ switch (c) {
+#if ENABLE_FEATURE_VI_CRASHME
+ case 'C':
+ crashme = 1;
+ break;
+#endif
+#if ENABLE_FEATURE_VI_READONLY
+ case 'R': // Read-only flag
+ SET_READONLY_MODE(readonly_mode);
+ break;
+#endif
+#if ENABLE_FEATURE_VI_COLON
+ case 'c': // cmd line vi command
+ if (*optarg)
+ initial_cmds[initial_cmds[0] != 0] = xstrndup(optarg, MAX_INPUT_LEN);
+ break;
+#endif
+ case 'H':
+ show_help();
+ /* fall through */
+ default:
+ bb_show_usage();
+ return 1;
+ }
+ }
+
+ // The argv array can be used by the ":next" and ":rewind" commands
+ // save optind.
+ fn_start = optind; // remember first file name for :next and :rew
+ save_argc = argc;
+
+ //----- This is the main file handling loop --------------
+ if (optind >= argc) {
+ edit_file(0);
+ } else {
+ for (; optind < argc; optind++) {
+ edit_file(argv[optind]);
+ }
+ }
+ //-----------------------------------------------------------
+
+ return 0;
+}
+
+/* read text from file or create an empty buf */
+/* will also update current_filename */
+static int init_text_buffer(char *fn)
+{
+ int rc;
+ int size = file_size(fn); // file size. -1 means does not exist.
+
+ /* allocate/reallocate text buffer */
+ free(text);
+ text_size = size + 10240;
+ screenbegin = dot = end = text = xzalloc(text_size);
+
+ if (fn != current_filename) {
+ free(current_filename);
+ current_filename = xstrdup(fn);
+ }
+ if (size < 0) {
+ // file dont exist. Start empty buf with dummy line
+ char_insert(text, '\n');
+ rc = 0;
+ } else {
+ rc = file_insert(fn, text
+ USE_FEATURE_VI_READONLY(, 1));
+ }
+ file_modified = 0;
+ last_file_modified = -1;
+#if ENABLE_FEATURE_VI_YANKMARK
+ /* init the marks. */
+ memset(mark, 0, sizeof(mark));
+#endif
+ return rc;
+}
+
+static void edit_file(char *fn)
+{
+#if ENABLE_FEATURE_VI_YANKMARK
+#define cur_line edit_file__cur_line
+#endif
+ char c;
+ int size;
+#if ENABLE_FEATURE_VI_USE_SIGNALS
+ int sig;
+#endif
+
+ editing = 1; // 0 = exit, 1 = one file, 2 = multiple files
+ rawmode();
+ rows = 24;
+ columns = 80;
+ size = 0;
+ if (ENABLE_FEATURE_VI_WIN_RESIZE) {
+ get_terminal_width_height(0, &columns, &rows);
+ if (rows > MAX_SCR_ROWS) rows = MAX_SCR_ROWS;
+ if (columns > MAX_SCR_COLS) columns = MAX_SCR_COLS;
+ }
+ new_screen(rows, columns); // get memory for virtual screen
+ init_text_buffer(fn);
+
+#if ENABLE_FEATURE_VI_YANKMARK
+ YDreg = 26; // default Yank/Delete reg
+ Ureg = 27; // hold orig line for "U" cmd
+ mark[26] = mark[27] = text; // init "previous context"
+#endif
+
+ last_forward_char = last_input_char = '\0';
+ crow = 0;
+ ccol = 0;
+
+#if ENABLE_FEATURE_VI_USE_SIGNALS
+ catch_sig(0);
+ signal(SIGWINCH, winch_sig);
+ signal(SIGTSTP, suspend_sig);
+ sig = sigsetjmp(restart, 1);
+ if (sig != 0) {
+ screenbegin = dot = text;
+ }
+#endif
+
+ cmd_mode = 0; // 0=command 1=insert 2='R'eplace
+ cmdcnt = 0;
+ tabstop = 8;
+ offset = 0; // no horizontal offset
+ c = '\0';
+#if ENABLE_FEATURE_VI_DOT_CMD
+ free(ioq_start);
+ ioq = ioq_start = NULL;
+ lmc_len = 0;
+ adding2q = 0;
+#endif
+
+#if ENABLE_FEATURE_VI_COLON
+ {
+ char *p, *q;
+ int n = 0;
+
+ while ((p = initial_cmds[n])) {
+ do {
+ q = p;
+ p = strchr(q, '\n');
+ if (p)
+ while (*p == '\n')
+ *p++ = '\0';
+ if (*q)
+ colon(q);
+ } while (p);
+ free(initial_cmds[n]);
+ initial_cmds[n] = NULL;
+ n++;
+ }
+ }
+#endif
+ redraw(FALSE); // dont force every col re-draw
+ //------This is the main Vi cmd handling loop -----------------------
+ while (editing > 0) {
+#if ENABLE_FEATURE_VI_CRASHME
+ if (crashme > 0) {
+ if ((end - text) > 1) {
+ crash_dummy(); // generate a random command
+ } else {
+ crashme = 0;
+ dot = string_insert(text, "\n\n##### Ran out of text to work on. #####\n\n"); // insert the string
+ refresh(FALSE);
+ }
+ }
+#endif
+ last_input_char = c = get_one_char(); // get a cmd from user
+#if ENABLE_FEATURE_VI_YANKMARK
+ // save a copy of the current line- for the 'U" command
+ if (begin_line(dot) != cur_line) {
+ cur_line = begin_line(dot);
+ text_yank(begin_line(dot), end_line(dot), Ureg);
+ }
+#endif
+#if ENABLE_FEATURE_VI_DOT_CMD
+ // These are commands that change text[].
+ // Remember the input for the "." command
+ if (!adding2q && ioq_start == NULL
+ && strchr(modifying_cmds, c)
+ ) {
+ start_new_cmd_q(c);
+ }
+#endif
+ do_cmd(c); // execute the user command
+ //
+ // poll to see if there is input already waiting. if we are
+ // not able to display output fast enough to keep up, skip
+ // the display update until we catch up with input.
+ if (mysleep(0) == 0) {
+ // no input pending- so update output
+ refresh(FALSE);
+ show_status_line();
+ }
+#if ENABLE_FEATURE_VI_CRASHME
+ if (crashme > 0)
+ crash_test(); // test editor variables
+#endif
+ }
+ //-------------------------------------------------------------------
+
+ place_cursor(rows, 0, FALSE); // go to bottom of screen
+ clear_to_eol(); // Erase to end of line
+ cookmode();
+#undef cur_line
+}
+
+//----- The Colon commands -------------------------------------
+#if ENABLE_FEATURE_VI_COLON
+static char *get_one_address(char *p, int *addr) // get colon addr, if present
+{
+ int st;
+ char *q;
+ USE_FEATURE_VI_YANKMARK(char c;)
+ USE_FEATURE_VI_SEARCH(char *pat;)
+
+ *addr = -1; // assume no addr
+ if (*p == '.') { // the current line
+ p++;
+ q = begin_line(dot);
+ *addr = count_lines(text, q);
+ }
+#if ENABLE_FEATURE_VI_YANKMARK
+ else if (*p == '\'') { // is this a mark addr
+ p++;
+ c = tolower(*p);
+ p++;
+ if (c >= 'a' && c <= 'z') {
+ // we have a mark
+ c = c - 'a';
+ q = mark[(unsigned char) c];
+ if (q != NULL) { // is mark valid
+ *addr = count_lines(text, q); // count lines
+ }
+ }
+ }
+#endif
+#if ENABLE_FEATURE_VI_SEARCH
+ else if (*p == '/') { // a search pattern
+ q = strchrnul(++p, '/');
+ pat = xstrndup(p, q - p); // save copy of pattern
+ p = q;
+ if (*p == '/')
+ p++;
+ q = char_search(dot, pat, FORWARD, FULL);
+ if (q != NULL) {
+ *addr = count_lines(text, q);
+ }
+ free(pat);
+ }
+#endif
+ else if (*p == '$') { // the last line in file
+ p++;
+ q = begin_line(end - 1);
+ *addr = count_lines(text, q);
+ } else if (isdigit(*p)) { // specific line number
+ sscanf(p, "%d%n", addr, &st);
+ p += st;
+ } else {
+ // unrecognised address - assume -1
+ *addr = -1;
+ }
+ return p;
+}
+
+static char *get_address(char *p, int *b, int *e) // get two colon addrs, if present
+{
+ //----- get the address' i.e., 1,3 'a,'b -----
+ // get FIRST addr, if present
+ while (isblank(*p))
+ p++; // skip over leading spaces
+ if (*p == '%') { // alias for 1,$
+ p++;
+ *b = 1;
+ *e = count_lines(text, end-1);
+ goto ga0;
+ }
+ p = get_one_address(p, b);
+ while (isblank(*p))
+ p++;
+ if (*p == ',') { // is there a address separator
+ p++;
+ while (isblank(*p))
+ p++;
+ // get SECOND addr, if present
+ p = get_one_address(p, e);
+ }
+ ga0:
+ while (isblank(*p))
+ p++; // skip over trailing spaces
+ return p;
+}
+
+#if ENABLE_FEATURE_VI_SET && ENABLE_FEATURE_VI_SETOPTS
+static void setops(const char *args, const char *opname, int flg_no,
+ const char *short_opname, int opt)
+{
+ const char *a = args + flg_no;
+ int l = strlen(opname) - 1; /* opname have + ' ' */
+
+ if (strncasecmp(a, opname, l) == 0
+ || strncasecmp(a, short_opname, 2) == 0
+ ) {
+ if (flg_no)
+ vi_setops &= ~opt;
+ else
+ vi_setops |= opt;
+ }
+}
+#endif
+
+// buf must be no longer than MAX_INPUT_LEN!
+static void colon(char *buf)
+{
+ char c, *orig_buf, *buf1, *q, *r;
+ char *fn, cmd[MAX_INPUT_LEN], args[MAX_INPUT_LEN];
+ int i, l, li, ch, b, e;
+ int useforce, forced = FALSE;
+
+ // :3154 // if (-e line 3154) goto it else stay put
+ // :4,33w! foo // write a portion of buffer to file "foo"
+ // :w // write all of buffer to current file
+ // :q // quit
+ // :q! // quit- dont care about modified file
+ // :'a,'z!sort -u // filter block through sort
+ // :'f // goto mark "f"
+ // :'fl // list literal the mark "f" line
+ // :.r bar // read file "bar" into buffer before dot
+ // :/123/,/abc/d // delete lines from "123" line to "abc" line
+ // :/xyz/ // goto the "xyz" line
+ // :s/find/replace/ // substitute pattern "find" with "replace"
+ // :!<cmd> // run <cmd> then return
+ //
+
+ if (!buf[0])
+ goto vc1;
+ if (*buf == ':')
+ buf++; // move past the ':'
+
+ li = ch = i = 0;
+ b = e = -1;
+ q = text; // assume 1,$ for the range
+ r = end - 1;
+ li = count_lines(text, end - 1);
+ fn = current_filename;
+
+ // look for optional address(es) :. :1 :1,9 :'q,'a :%
+ buf = get_address(buf, &b, &e);
+
+ // remember orig command line
+ orig_buf = buf;
+
+ // get the COMMAND into cmd[]
+ buf1 = cmd;
+ while (*buf != '\0') {
+ if (isspace(*buf))
+ break;
+ *buf1++ = *buf++;
+ }
+ *buf1 = '\0';
+ // get any ARGuments
+ while (isblank(*buf))
+ buf++;
+ strcpy(args, buf);
+ useforce = FALSE;
+ buf1 = last_char_is(cmd, '!');
+ if (buf1) {
+ useforce = TRUE;
+ *buf1 = '\0'; // get rid of !
+ }
+ if (b >= 0) {
+ // if there is only one addr, then the addr
+ // is the line number of the single line the
+ // user wants. So, reset the end
+ // pointer to point at end of the "b" line
+ q = find_line(b); // what line is #b
+ r = end_line(q);
+ li = 1;
+ }
+ if (e >= 0) {
+ // we were given two addrs. change the
+ // end pointer to the addr given by user.
+ r = find_line(e); // what line is #e
+ r = end_line(r);
+ li = e - b + 1;
+ }
+ // ------------ now look for the command ------------
+ i = strlen(cmd);
+ if (i == 0) { // :123CR goto line #123
+ if (b >= 0) {
+ dot = find_line(b); // what line is #b
+ dot_skip_over_ws();
+ }
+ }
+#if ENABLE_FEATURE_ALLOW_EXEC
+ else if (strncmp(cmd, "!", 1) == 0) { // run a cmd
+ int retcode;
+ // :!ls run the <cmd>
+ place_cursor(rows - 1, 0, FALSE); // go to Status line
+ clear_to_eol(); // clear the line
+ cookmode();
+ retcode = system(orig_buf + 1); // run the cmd
+ if (retcode)
+ printf("\nshell returned %i\n\n", retcode);
+ rawmode();
+ Hit_Return(); // let user see results
+ }
+#endif
+ else if (strncmp(cmd, "=", i) == 0) { // where is the address
+ if (b < 0) { // no addr given- use defaults
+ b = e = count_lines(text, dot);
+ }
+ status_line("%d", b);
+ } else if (strncasecmp(cmd, "delete", i) == 0) { // delete lines
+ if (b < 0) { // no addr given- use defaults
+ q = begin_line(dot); // assume .,. for the range
+ r = end_line(dot);
+ }
+ dot = yank_delete(q, r, 1, YANKDEL); // save, then delete lines
+ dot_skip_over_ws();
+ } else if (strncasecmp(cmd, "edit", i) == 0) { // Edit a file
+ // don't edit, if the current file has been modified
+ if (file_modified && !useforce) {
+ status_line_bold("No write since last change (:edit! overrides)");
+ goto vc1;
+ }
+ if (args[0]) {
+ // the user supplied a file name
+ fn = args;
+ } else if (current_filename && current_filename[0]) {
+ // no user supplied name- use the current filename
+ // fn = current_filename; was set by default
+ } else {
+ // no user file name, no current name- punt
+ status_line_bold("No current filename");
+ goto vc1;
+ }
+
+ if (init_text_buffer(fn) < 0)
+ goto vc1;
+
+#if ENABLE_FEATURE_VI_YANKMARK
+ if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) {
+ free(reg[Ureg]); // free orig line reg- for 'U'
+ reg[Ureg]= 0;
+ }
+ if (YDreg >= 0 && YDreg < 28 && reg[YDreg] != 0) {
+ free(reg[YDreg]); // free default yank/delete register
+ reg[YDreg]= 0;
+ }
+#endif
+ // how many lines in text[]?
+ li = count_lines(text, end - 1);
+ status_line("\"%s\"%s"
+ USE_FEATURE_VI_READONLY("%s")
+ " %dL, %dC", current_filename,
+ (file_size(fn) < 0 ? " [New file]" : ""),
+ USE_FEATURE_VI_READONLY(
+ ((readonly_mode) ? " [Readonly]" : ""),
+ )
+ li, ch);
+ } else if (strncasecmp(cmd, "file", i) == 0) { // what File is this
+ if (b != -1 || e != -1) {
+ not_implemented("No address allowed on this command");
+ goto vc1;
+ }
+ if (args[0]) {
+ // user wants a new filename
+ free(current_filename);
+ current_filename = xstrdup(args);
+ } else {
+ // user wants file status info
+ last_status_cksum = 0; // force status update
+ }
+ } else if (strncasecmp(cmd, "features", i) == 0) { // what features are available
+ // print out values of all features
+ place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen
+ clear_to_eol(); // clear the line
+ cookmode();
+ show_help();
+ rawmode();
+ Hit_Return();
+ } else if (strncasecmp(cmd, "list", i) == 0) { // literal print line
+ if (b < 0) { // no addr given- use defaults
+ q = begin_line(dot); // assume .,. for the range
+ r = end_line(dot);
+ }
+ place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen
+ clear_to_eol(); // clear the line
+ puts("\r");
+ for (; q <= r; q++) {
+ int c_is_no_print;
+
+ c = *q;
+ c_is_no_print = (c & 0x80) && !Isprint(c);
+ if (c_is_no_print) {
+ c = '.';
+ standout_start();
+ }
+ if (c == '\n') {
+ write1("$\r");
+ } else if (c < ' ' || c == 127) {
+ bb_putchar('^');
+ if (c == 127)
+ c = '?';
+ else
+ c += '@';
+ }
+ bb_putchar(c);
+ if (c_is_no_print)
+ standout_end();
+ }
+#if ENABLE_FEATURE_VI_SET
+ vc2:
+#endif
+ Hit_Return();
+ } else if (strncasecmp(cmd, "quit", i) == 0 // Quit
+ || strncasecmp(cmd, "next", i) == 0 // edit next file
+ ) {
+ if (useforce) {
+ // force end of argv list
+ if (*cmd == 'q') {
+ optind = save_argc;
+ }
+ editing = 0;
+ goto vc1;
+ }
+ // don't exit if the file been modified
+ if (file_modified) {
+ status_line_bold("No write since last change (:%s! overrides)",
+ (*cmd == 'q' ? "quit" : "next"));
+ goto vc1;
+ }
+ // are there other file to edit
+ if (*cmd == 'q' && optind < save_argc - 1) {
+ status_line_bold("%d more file to edit", (save_argc - optind - 1));
+ goto vc1;
+ }
+ if (*cmd == 'n' && optind >= save_argc - 1) {
+ status_line_bold("No more files to edit");
+ goto vc1;
+ }
+ editing = 0;
+ } else if (strncasecmp(cmd, "read", i) == 0) { // read file into text[]
+ fn = args;
+ if (!fn[0]) {
+ status_line_bold("No filename given");
+ goto vc1;
+ }
+ if (b < 0) { // no addr given- use defaults
+ q = begin_line(dot); // assume "dot"
+ }
+ // read after current line- unless user said ":0r foo"
+ if (b != 0)
+ q = next_line(q);
+ ch = file_insert(fn, q USE_FEATURE_VI_READONLY(, 0));
+ if (ch < 0)
+ goto vc1; // nothing was inserted
+ // how many lines in text[]?
+ li = count_lines(q, q + ch - 1);
+ status_line("\"%s\""
+ USE_FEATURE_VI_READONLY("%s")
+ " %dL, %dC", fn,
+ USE_FEATURE_VI_READONLY((readonly_mode ? " [Readonly]" : ""),)
+ li, ch);
+ if (ch > 0) {
+ // if the insert is before "dot" then we need to update
+ if (q <= dot)
+ dot += ch;
+ file_modified++;
+ }
+ } else if (strncasecmp(cmd, "rewind", i) == 0) { // rewind cmd line args
+ if (file_modified && !useforce) {
+ status_line_bold("No write since last change (:rewind! overrides)");
+ } else {
+ // reset the filenames to edit
+ optind = fn_start - 1;
+ editing = 0;
+ }
+#if ENABLE_FEATURE_VI_SET
+ } else if (strncasecmp(cmd, "set", i) == 0) { // set or clear features
+#if ENABLE_FEATURE_VI_SETOPTS
+ char *argp;
+#endif
+ i = 0; // offset into args
+ // only blank is regarded as args delmiter. What about tab '\t' ?
+ if (!args[0] || strcasecmp(args, "all") == 0) {
+ // print out values of all options
+ place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen
+ clear_to_eol(); // clear the line
+ printf("----------------------------------------\r\n");
+#if ENABLE_FEATURE_VI_SETOPTS
+ if (!autoindent)
+ printf("no");
+ printf("autoindent ");
+ if (!err_method)
+ printf("no");
+ printf("flash ");
+ if (!ignorecase)
+ printf("no");
+ printf("ignorecase ");
+ if (!showmatch)
+ printf("no");
+ printf("showmatch ");
+ printf("tabstop=%d ", tabstop);
+#endif
+ printf("\r\n");
+ goto vc2;
+ }
+#if ENABLE_FEATURE_VI_SETOPTS
+ argp = args;
+ while (*argp) {
+ if (strncasecmp(argp, "no", 2) == 0)
+ i = 2; // ":set noautoindent"
+ setops(argp, "autoindent ", i, "ai", VI_AUTOINDENT);
+ setops(argp, "flash ", i, "fl", VI_ERR_METHOD);
+ setops(argp, "ignorecase ", i, "ic", VI_IGNORECASE);
+ setops(argp, "showmatch ", i, "ic", VI_SHOWMATCH);
+ /* tabstopXXXX */
+ if (strncasecmp(argp + i, "tabstop=%d ", 7) == 0) {
+ sscanf(strchr(argp + i, '='), "tabstop=%d" + 7, &ch);
+ if (ch > 0 && ch <= MAX_TABSTOP)
+ tabstop = ch;
+ }
+ while (*argp && *argp != ' ')
+ argp++; // skip to arg delimiter (i.e. blank)
+ while (*argp && *argp == ' ')
+ argp++; // skip all delimiting blanks
+ }
+#endif /* FEATURE_VI_SETOPTS */
+#endif /* FEATURE_VI_SET */
+#if ENABLE_FEATURE_VI_SEARCH
+ } else if (strncasecmp(cmd, "s", 1) == 0) { // substitute a pattern with a replacement pattern
+ char *ls, *F, *R;
+ int gflag;
+
+ // F points to the "find" pattern
+ // R points to the "replace" pattern
+ // replace the cmd line delimiters "/" with NULLs
+ gflag = 0; // global replace flag
+ c = orig_buf[1]; // what is the delimiter
+ F = orig_buf + 2; // start of "find"
+ R = strchr(F, c); // middle delimiter
+ if (!R) goto colon_s_fail;
+ *R++ = '\0'; // terminate "find"
+ buf1 = strchr(R, c);
+ if (!buf1) goto colon_s_fail;
+ *buf1++ = '\0'; // terminate "replace"
+ if (*buf1 == 'g') { // :s/foo/bar/g
+ buf1++;
+ gflag++; // turn on gflag
+ }
+ q = begin_line(q);
+ if (b < 0) { // maybe :s/foo/bar/
+ q = begin_line(dot); // start with cur line
+ b = count_lines(text, q); // cur line number
+ }
+ if (e < 0)
+ e = b; // maybe :.s/foo/bar/
+ for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0
+ ls = q; // orig line start
+ vc4:
+ buf1 = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find"
+ if (buf1) {
+ // we found the "find" pattern - delete it
+ text_hole_delete(buf1, buf1 + strlen(F) - 1);
+ // inset the "replace" patern
+ string_insert(buf1, R); // insert the string
+ // check for "global" :s/foo/bar/g
+ if (gflag == 1) {
+ if ((buf1 + strlen(R)) < end_line(ls)) {
+ q = buf1 + strlen(R);
+ goto vc4; // don't let q move past cur line
+ }
+ }
+ }
+ q = next_line(ls);
+ }
+#endif /* FEATURE_VI_SEARCH */
+ } else if (strncasecmp(cmd, "version", i) == 0) { // show software version
+ status_line(BB_VER " " BB_BT);
+ } else if (strncasecmp(cmd, "write", i) == 0 // write text to file
+ || strncasecmp(cmd, "wq", i) == 0
+ || strncasecmp(cmd, "wn", i) == 0
+ || strncasecmp(cmd, "x", i) == 0
+ ) {
+ // is there a file name to write to?
+ if (args[0]) {
+ fn = args;
+ }
+#if ENABLE_FEATURE_VI_READONLY
+ if (readonly_mode && !useforce) {
+ status_line_bold("\"%s\" File is read only", fn);
+ goto vc3;
+ }
+#endif
+ // how many lines in text[]?
+ li = count_lines(q, r);
+ ch = r - q + 1;
+ // see if file exists- if not, its just a new file request
+ if (useforce) {
+ // if "fn" is not write-able, chmod u+w
+ // sprintf(syscmd, "chmod u+w %s", fn);
+ // system(syscmd);
+ forced = TRUE;
+ }
+ l = file_write(fn, q, r);
+ if (useforce && forced) {
+ // chmod u-w
+ // sprintf(syscmd, "chmod u-w %s", fn);
+ // system(syscmd);
+ forced = FALSE;
+ }
+ if (l < 0) {
+ if (l == -1)
+ status_line_bold("\"%s\" %s", fn, strerror(errno));
+ } else {
+ status_line("\"%s\" %dL, %dC", fn, li, l);
+ if (q == text && r == end - 1 && l == ch) {
+ file_modified = 0;
+ last_file_modified = -1;
+ }
+ if ((cmd[0] == 'x' || cmd[1] == 'q' || cmd[1] == 'n' ||
+ cmd[0] == 'X' || cmd[1] == 'Q' || cmd[1] == 'N')
+ && l == ch) {
+ editing = 0;
+ }
+ }
+#if ENABLE_FEATURE_VI_READONLY
+ vc3:;
+#endif
+#if ENABLE_FEATURE_VI_YANKMARK
+ } else if (strncasecmp(cmd, "yank", i) == 0) { // yank lines
+ if (b < 0) { // no addr given- use defaults
+ q = begin_line(dot); // assume .,. for the range
+ r = end_line(dot);
+ }
+ text_yank(q, r, YDreg);
+ li = count_lines(q, r);
+ status_line("Yank %d lines (%d chars) into [%c]",
+ li, strlen(reg[YDreg]), what_reg());
+#endif
+ } else {
+ // cmd unknown
+ not_implemented(cmd);
+ }
+ vc1:
+ dot = bound_dot(dot); // make sure "dot" is valid
+ return;
+#if ENABLE_FEATURE_VI_SEARCH
+ colon_s_fail:
+ status_line(":s expression missing delimiters");
+#endif
+}
+
+#endif /* FEATURE_VI_COLON */
+
+static void Hit_Return(void)
+{
+ char c;
+
+ standout_start();
+ write1("[Hit return to continue]");
+ standout_end();
+ while ((c = get_one_char()) != '\n' && c != '\r')
+ continue;
+ redraw(TRUE); // force redraw all
+}
+
+static int next_tabstop(int col)
+{
+ return col + ((tabstop - 1) - (col % tabstop));
+}
+
+//----- Synchronize the cursor to Dot --------------------------
+static void sync_cursor(char *d, int *row, int *col)
+{
+ char *beg_cur; // begin and end of "d" line
+ char *tp;
+ int cnt, ro, co;
+
+ beg_cur = begin_line(d); // first char of cur line
+
+ if (beg_cur < screenbegin) {
+ // "d" is before top line on screen
+ // how many lines do we have to move
+ cnt = count_lines(beg_cur, screenbegin);
+ sc1:
+ screenbegin = beg_cur;
+ if (cnt > (rows - 1) / 2) {
+ // we moved too many lines. put "dot" in middle of screen
+ for (cnt = 0; cnt < (rows - 1) / 2; cnt++) {
+ screenbegin = prev_line(screenbegin);
+ }
+ }
+ } else {
+ char *end_scr; // begin and end of screen
+ end_scr = end_screen(); // last char of screen
+ if (beg_cur > end_scr) {
+ // "d" is after bottom line on screen
+ // how many lines do we have to move
+ cnt = count_lines(end_scr, beg_cur);
+ if (cnt > (rows - 1) / 2)
+ goto sc1; // too many lines
+ for (ro = 0; ro < cnt - 1; ro++) {
+ // move screen begin the same amount
+ screenbegin = next_line(screenbegin);
+ // now, move the end of screen
+ end_scr = next_line(end_scr);
+ end_scr = end_line(end_scr);
+ }
+ }
+ }
+ // "d" is on screen- find out which row
+ tp = screenbegin;
+ for (ro = 0; ro < rows - 1; ro++) { // drive "ro" to correct row
+ if (tp == beg_cur)
+ break;
+ tp = next_line(tp);
+ }
+
+ // find out what col "d" is on
+ co = 0;
+ while (tp < d) { // drive "co" to correct column
+ if (*tp == '\n') //vda || *tp == '\0')
+ break;
+ if (*tp == '\t') {
+ // handle tabs like real vi
+ if (d == tp && cmd_mode) {
+ break;
+ }
+ co = next_tabstop(co);
+ } else if ((unsigned char)*tp < ' ' || *tp == 0x7f) {
+ co++; // display as ^X, use 2 columns
+ }
+ co++;
+ tp++;
+ }
+
+ // "co" is the column where "dot" is.
+ // The screen has "columns" columns.
+ // The currently displayed columns are 0+offset -- columns+ofset
+ // |-------------------------------------------------------------|
+ // ^ ^ ^
+ // offset | |------- columns ----------------|
+ //
+ // If "co" is already in this range then we do not have to adjust offset
+ // but, we do have to subtract the "offset" bias from "co".
+ // If "co" is outside this range then we have to change "offset".
+ // If the first char of a line is a tab the cursor will try to stay
+ // in column 7, but we have to set offset to 0.
+
+ if (co < 0 + offset) {
+ offset = co;
+ }
+ if (co >= columns + offset) {
+ offset = co - columns + 1;
+ }
+ // if the first char of the line is a tab, and "dot" is sitting on it
+ // force offset to 0.
+ if (d == beg_cur && *d == '\t') {
+ offset = 0;
+ }
+ co -= offset;
+
+ *row = ro;
+ *col = co;
+}
+
+//----- Text Movement Routines ---------------------------------
+static char *begin_line(char *p) // return pointer to first char cur line
+{
+ if (p > text) {
+ p = memrchr(text, '\n', p - text);
+ if (!p)
+ return text;
+ return p + 1;
+ }
+ return p;
+}
+
+static char *end_line(char *p) // return pointer to NL of cur line
+{
+ if (p < end - 1) {
+ p = memchr(p, '\n', end - p - 1);
+ if (!p)
+ return end - 1;
+ }
+ return p;
+}
+
+static char *dollar_line(char *p) // return pointer to just before NL line
+{
+ p = end_line(p);
+ // Try to stay off of the Newline
+ if (*p == '\n' && (p - begin_line(p)) > 0)
+ p--;
+ return p;
+}
+
+static char *prev_line(char *p) // return pointer first char prev line
+{
+ p = begin_line(p); // goto begining of cur line
+ if (p > text && p[-1] == '\n')
+ p--; // step to prev line
+ p = begin_line(p); // goto begining of prev line
+ return p;
+}
+
+static char *next_line(char *p) // return pointer first char next line
+{
+ p = end_line(p);
+ if (p < end - 1 && *p == '\n')
+ p++; // step to next line
+ return p;
+}
+
+//----- Text Information Routines ------------------------------
+static char *end_screen(void)
+{
+ char *q;
+ int cnt;
+
+ // find new bottom line
+ q = screenbegin;
+ for (cnt = 0; cnt < rows - 2; cnt++)
+ q = next_line(q);
+ q = end_line(q);
+ return q;
+}
+
+// count line from start to stop
+static int count_lines(char *start, char *stop)
+{
+ char *q;
+ int cnt;
+
+ if (stop < start) { // start and stop are backwards- reverse them
+ q = start;
+ start = stop;
+ stop = q;
+ }
+ cnt = 0;
+ stop = end_line(stop);
+ while (start <= stop && start <= end - 1) {
+ start = end_line(start);
+ if (*start == '\n')
+ cnt++;
+ start++;
+ }
+ return cnt;
+}
+
+static char *find_line(int li) // find begining of line #li
+{
+ char *q;
+
+ for (q = text; li > 1; li--) {
+ q = next_line(q);
+ }
+ return q;
+}
+
+//----- Dot Movement Routines ----------------------------------
+static void dot_left(void)
+{
+ if (dot > text && dot[-1] != '\n')
+ dot--;
+}
+
+static void dot_right(void)
+{
+ if (dot < end - 1 && *dot != '\n')
+ dot++;
+}
+
+static void dot_begin(void)
+{
+ dot = begin_line(dot); // return pointer to first char cur line
+}
+
+static void dot_end(void)
+{
+ dot = end_line(dot); // return pointer to last char cur line
+}
+
+static char *move_to_col(char *p, int l)
+{
+ int co;
+
+ p = begin_line(p);
+ co = 0;
+ while (co < l && p < end) {
+ if (*p == '\n') //vda || *p == '\0')
+ break;
+ if (*p == '\t') {
+ co = next_tabstop(co);
+ } else if (*p < ' ' || *p == 127) {
+ co++; // display as ^X, use 2 columns
+ }
+ co++;
+ p++;
+ }
+ return p;
+}
+
+static void dot_next(void)
+{
+ dot = next_line(dot);
+}
+
+static void dot_prev(void)
+{
+ dot = prev_line(dot);
+}
+
+static void dot_scroll(int cnt, int dir)
+{
+ char *q;
+
+ for (; cnt > 0; cnt--) {
+ if (dir < 0) {
+ // scroll Backwards
+ // ctrl-Y scroll up one line
+ screenbegin = prev_line(screenbegin);
+ } else {
+ // scroll Forwards
+ // ctrl-E scroll down one line
+ screenbegin = next_line(screenbegin);
+ }
+ }
+ // make sure "dot" stays on the screen so we dont scroll off
+ if (dot < screenbegin)
+ dot = screenbegin;
+ q = end_screen(); // find new bottom line
+ if (dot > q)
+ dot = begin_line(q); // is dot is below bottom line?
+ dot_skip_over_ws();
+}
+
+static void dot_skip_over_ws(void)
+{
+ // skip WS
+ while (isspace(*dot) && *dot != '\n' && dot < end - 1)
+ dot++;
+}
+
+static void dot_delete(void) // delete the char at 'dot'
+{
+ text_hole_delete(dot, dot);
+}
+
+static char *bound_dot(char *p) // make sure text[0] <= P < "end"
+{
+ if (p >= end && end > text) {
+ p = end - 1;
+ indicate_error('1');
+ }
+ if (p < text) {
+ p = text;
+ indicate_error('2');
+ }
+ return p;
+}
+
+//----- Helper Utility Routines --------------------------------
+
+//----------------------------------------------------------------
+//----- Char Routines --------------------------------------------
+/* Chars that are part of a word-
+ * 0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+ * Chars that are Not part of a word (stoppers)
+ * !"#$%&'()*+,-./:;<=>?@[\]^`{|}~
+ * Chars that are WhiteSpace
+ * TAB NEWLINE VT FF RETURN SPACE
+ * DO NOT COUNT NEWLINE AS WHITESPACE
+ */
+
+static char *new_screen(int ro, int co)
+{
+ int li;
+
+ free(screen);
+ screensize = ro * co + 8;
+ screen = xmalloc(screensize);
+ // initialize the new screen. assume this will be a empty file.
+ screen_erase();
+ // non-existent text[] lines start with a tilde (~).
+ for (li = 1; li < ro - 1; li++) {
+ screen[(li * co) + 0] = '~';
+ }
+ return screen;
+}
+
+#if ENABLE_FEATURE_VI_SEARCH
+static int mycmp(const char *s1, const char *s2, int len)
+{
+ int i;
+
+ i = strncmp(s1, s2, len);
+ if (ENABLE_FEATURE_VI_SETOPTS && ignorecase) {
+ i = strncasecmp(s1, s2, len);
+ }
+ return i;
+}
+
+// search for pattern starting at p
+static char *char_search(char *p, const char *pat, int dir, int range)
+{
+#ifndef REGEX_SEARCH
+ char *start, *stop;
+ int len;
+
+ len = strlen(pat);
+ if (dir == FORWARD) {
+ stop = end - 1; // assume range is p - end-1
+ if (range == LIMITED)
+ stop = next_line(p); // range is to next line
+ for (start = p; start < stop; start++) {
+ if (mycmp(start, pat, len) == 0) {
+ return start;
+ }
+ }
+ } else if (dir == BACK) {
+ stop = text; // assume range is text - p
+ if (range == LIMITED)
+ stop = prev_line(p); // range is to prev line
+ for (start = p - len; start >= stop; start--) {
+ if (mycmp(start, pat, len) == 0) {
+ return start;
+ }
+ }
+ }
+ // pattern not found
+ return NULL;
+#else /* REGEX_SEARCH */
+ char *q;
+ struct re_pattern_buffer preg;
+ int i;
+ int size, range;
+
+ re_syntax_options = RE_SYNTAX_POSIX_EXTENDED;
+ preg.translate = 0;
+ preg.fastmap = 0;
+ preg.buffer = 0;
+ preg.allocated = 0;
+
+ // assume a LIMITED forward search
+ q = next_line(p);
+ q = end_line(q);
+ q = end - 1;
+ if (dir == BACK) {
+ q = prev_line(p);
+ q = text;
+ }
+ // count the number of chars to search over, forward or backward
+ size = q - p;
+ if (size < 0)
+ size = p - q;
+ // RANGE could be negative if we are searching backwards
+ range = q - p;
+
+ q = re_compile_pattern(pat, strlen(pat), &preg);
+ if (q != 0) {
+ // The pattern was not compiled
+ status_line_bold("bad search pattern: \"%s\": %s", pat, q);
+ i = 0; // return p if pattern not compiled
+ goto cs1;
+ }
+
+ q = p;
+ if (range < 0) {
+ q = p - size;
+ if (q < text)
+ q = text;
+ }
+ // search for the compiled pattern, preg, in p[]
+ // range < 0- search backward
+ // range > 0- search forward
+ // 0 < start < size
+ // re_search() < 0 not found or error
+ // re_search() > 0 index of found pattern
+ // struct pattern char int int int struct reg
+ // re_search (*pattern_buffer, *string, size, start, range, *regs)
+ i = re_search(&preg, q, size, 0, range, 0);
+ if (i == -1) {
+ p = 0;
+ i = 0; // return NULL if pattern not found
+ }
+ cs1:
+ if (dir == FORWARD) {
+ p = p + i;
+ } else {
+ p = p - i;
+ }
+ return p;
+#endif /* REGEX_SEARCH */
+}
+#endif /* FEATURE_VI_SEARCH */
+
+static char *char_insert(char *p, char c) // insert the char c at 'p'
+{
+ if (c == 22) { // Is this an ctrl-V?
+ p = stupid_insert(p, '^'); // use ^ to indicate literal next
+ p--; // backup onto ^
+ refresh(FALSE); // show the ^
+ c = get_one_char();
+ *p = c;
+ p++;
+ file_modified++;
+ } else if (c == 27) { // Is this an ESC?
+ cmd_mode = 0;
+ cmdcnt = 0;
+ end_cmd_q(); // stop adding to q
+ last_status_cksum = 0; // force status update
+ if ((p[-1] != '\n') && (dot > text)) {
+ p--;
+ }
+ } else if (c == erase_char || c == 8 || c == 127) { // Is this a BS
+ // 123456789
+ if ((p[-1] != '\n') && (dot>text)) {
+ p--;
+ p = text_hole_delete(p, p); // shrink buffer 1 char
+ }
+ } else {
+ // insert a char into text[]
+ char *sp; // "save p"
+
+ if (c == 13)
+ c = '\n'; // translate \r to \n
+ sp = p; // remember addr of insert
+ p = stupid_insert(p, c); // insert the char
+#if ENABLE_FEATURE_VI_SETOPTS
+ if (showmatch && strchr(")]}", *sp) != NULL) {
+ showmatching(sp);
+ }
+ if (autoindent && c == '\n') { // auto indent the new line
+ char *q;
+
+ q = prev_line(p); // use prev line as templet
+ for (; isblank(*q); q++) {
+ p = stupid_insert(p, *q); // insert the char
+ }
+ }
+#endif
+ }
+ return p;
+}
+
+static char *stupid_insert(char *p, char c) // stupidly insert the char c at 'p'
+{
+ p = text_hole_make(p, 1);
+ *p = c;
+ //file_modified++; - done by text_hole_make()
+ return p + 1;
+}
+
+static int find_range(char **start, char **stop, char c)
+{
+ char *save_dot, *p, *q, *t;
+ int cnt, multiline = 0;
+
+ save_dot = dot;
+ p = q = dot;
+
+ if (strchr("cdy><", c)) {
+ // these cmds operate on whole lines
+ p = q = begin_line(p);
+ for (cnt = 1; cnt < cmdcnt; cnt++) {
+ q = next_line(q);
+ }
+ q = end_line(q);
+ } else if (strchr("^%$0bBeEfth\b\177", c)) {
+ // These cmds operate on char positions
+ do_cmd(c); // execute movement cmd
+ q = dot;
+ } else if (strchr("wW", c)) {
+ do_cmd(c); // execute movement cmd
+ // if we are at the next word's first char
+ // step back one char
+ // but check the possibilities when it is true
+ if (dot > text && ((isspace(dot[-1]) && !isspace(dot[0]))
+ || (ispunct(dot[-1]) && !ispunct(dot[0]))
+ || (isalnum(dot[-1]) && !isalnum(dot[0]))))
+ dot--; // move back off of next word
+ if (dot > text && *dot == '\n')
+ dot--; // stay off NL
+ q = dot;
+ } else if (strchr("H-k{", c)) {
+ // these operate on multi-lines backwards
+ q = end_line(dot); // find NL
+ do_cmd(c); // execute movement cmd
+ dot_begin();
+ p = dot;
+ } else if (strchr("L+j}\r\n", c)) {
+ // these operate on multi-lines forwards
+ p = begin_line(dot);
+ do_cmd(c); // execute movement cmd
+ dot_end(); // find NL
+ q = dot;
+ } else {
+ // nothing -- this causes any other values of c to
+ // represent the one-character range under the
+ // cursor. this is correct for ' ' and 'l', but
+ // perhaps no others.
+ //
+ }
+ if (q < p) {
+ t = q;
+ q = p;
+ p = t;
+ }
+
+ // backward char movements don't include start position
+ if (q > p && strchr("^0bBh\b\177", c)) q--;
+
+ multiline = 0;
+ for (t = p; t <= q; t++) {
+ if (*t == '\n') {
+ multiline = 1;
+ break;
+ }
+ }
+
+ *start = p;
+ *stop = q;
+ dot = save_dot;
+ return multiline;
+}
+
+static int st_test(char *p, int type, int dir, char *tested)
+{
+ char c, c0, ci;
+ int test, inc;
+
+ inc = dir;
+ c = c0 = p[0];
+ ci = p[inc];
+ test = 0;
+
+ if (type == S_BEFORE_WS) {
+ c = ci;
+ test = ((!isspace(c)) || c == '\n');
+ }
+ if (type == S_TO_WS) {
+ c = c0;
+ test = ((!isspace(c)) || c == '\n');
+ }
+ if (type == S_OVER_WS) {
+ c = c0;
+ test = ((isspace(c)));
+ }
+ if (type == S_END_PUNCT) {
+ c = ci;
+ test = ((ispunct(c)));
+ }
+ if (type == S_END_ALNUM) {
+ c = ci;
+ test = ((isalnum(c)) || c == '_');
+ }
+ *tested = c;
+ return test;
+}
+
+static char *skip_thing(char *p, int linecnt, int dir, int type)
+{
+ char c;
+
+ while (st_test(p, type, dir, &c)) {
+ // make sure we limit search to correct number of lines
+ if (c == '\n' && --linecnt < 1)
+ break;
+ if (dir >= 0 && p >= end - 1)
+ break;
+ if (dir < 0 && p <= text)
+ break;
+ p += dir; // move to next char
+ }
+ return p;
+}
+
+// find matching char of pair () [] {}
+static char *find_pair(char *p, const char c)
+{
+ char match, *q;
+ int dir, level;
+
+ match = ')';
+ level = 1;
+ dir = 1; // assume forward
+ switch (c) {
+ case '(': match = ')'; break;
+ case '[': match = ']'; break;
+ case '{': match = '}'; break;
+ case ')': match = '('; dir = -1; break;
+ case ']': match = '['; dir = -1; break;
+ case '}': match = '{'; dir = -1; break;
+ }
+ for (q = p + dir; text <= q && q < end; q += dir) {
+ // look for match, count levels of pairs (( ))
+ if (*q == c)
+ level++; // increase pair levels
+ if (*q == match)
+ level--; // reduce pair level
+ if (level == 0)
+ break; // found matching pair
+ }
+ if (level != 0)
+ q = NULL; // indicate no match
+ return q;
+}
+
+#if ENABLE_FEATURE_VI_SETOPTS
+// show the matching char of a pair, () [] {}
+static void showmatching(char *p)
+{
+ char *q, *save_dot;
+
+ // we found half of a pair
+ q = find_pair(p, *p); // get loc of matching char
+ if (q == NULL) {
+ indicate_error('3'); // no matching char
+ } else {
+ // "q" now points to matching pair
+ save_dot = dot; // remember where we are
+ dot = q; // go to new loc
+ refresh(FALSE); // let the user see it
+ mysleep(40); // give user some time
+ dot = save_dot; // go back to old loc
+ refresh(FALSE);
+ }
+}
+#endif /* FEATURE_VI_SETOPTS */
+
+// open a hole in text[]
+static char *text_hole_make(char *p, int size) // at "p", make a 'size' byte hole
+{
+ if (size <= 0)
+ return p;
+ end += size; // adjust the new END
+ if (end >= (text + text_size)) {
+ char *new_text;
+ text_size += end - (text + text_size) + 10240;
+ new_text = xrealloc(text, text_size);
+ screenbegin = new_text + (screenbegin - text);
+ dot = new_text + (dot - text);
+ end = new_text + (end - text);
+ p = new_text + (p - text);
+ text = new_text;
+ }
+ memmove(p + size, p, end - size - p);
+ memset(p, ' ', size); // clear new hole
+ file_modified++;
+ return p;
+}
+
+// close a hole in text[]
+static char *text_hole_delete(char *p, char *q) // delete "p" through "q", inclusive
+{
+ char *src, *dest;
+ int cnt, hole_size;
+
+ // move forwards, from beginning
+ // assume p <= q
+ src = q + 1;
+ dest = p;
+ if (q < p) { // they are backward- swap them
+ src = p + 1;
+ dest = q;
+ }
+ hole_size = q - p + 1;
+ cnt = end - src;
+ if (src < text || src > end)
+ goto thd0;
+ if (dest < text || dest >= end)
+ goto thd0;
+ if (src >= end)
+ goto thd_atend; // just delete the end of the buffer
+ memmove(dest, src, cnt);
+ thd_atend:
+ end = end - hole_size; // adjust the new END
+ if (dest >= end)
+ dest = end - 1; // make sure dest in below end-1
+ if (end <= text)
+ dest = end = text; // keep pointers valid
+ file_modified++;
+ thd0:
+ return dest;
+}
+
+// copy text into register, then delete text.
+// if dist <= 0, do not include, or go past, a NewLine
+//
+static char *yank_delete(char *start, char *stop, int dist, int yf)
+{
+ char *p;
+
+ // make sure start <= stop
+ if (start > stop) {
+ // they are backwards, reverse them
+ p = start;
+ start = stop;
+ stop = p;
+ }
+ if (dist <= 0) {
+ // we cannot cross NL boundaries
+ p = start;
+ if (*p == '\n')
+ return p;
+ // dont go past a NewLine
+ for (; p + 1 <= stop; p++) {
+ if (p[1] == '\n') {
+ stop = p; // "stop" just before NewLine
+ break;
+ }
+ }
+ }
+ p = start;
+#if ENABLE_FEATURE_VI_YANKMARK
+ text_yank(start, stop, YDreg);
+#endif
+ if (yf == YANKDEL) {
+ p = text_hole_delete(start, stop);
+ } // delete lines
+ return p;
+}
+
+static void show_help(void)
+{
+ puts("These features are available:"
+#if ENABLE_FEATURE_VI_SEARCH
+ "\n\tPattern searches with / and ?"
+#endif
+#if ENABLE_FEATURE_VI_DOT_CMD
+ "\n\tLast command repeat with \'.\'"
+#endif
+#if ENABLE_FEATURE_VI_YANKMARK
+ "\n\tLine marking with 'x"
+ "\n\tNamed buffers with \"x"
+#endif
+#if ENABLE_FEATURE_VI_READONLY
+ "\n\tReadonly if vi is called as \"view\""
+ "\n\tReadonly with -R command line arg"
+#endif
+#if ENABLE_FEATURE_VI_SET
+ "\n\tSome colon mode commands with \':\'"
+#endif
+#if ENABLE_FEATURE_VI_SETOPTS
+ "\n\tSettable options with \":set\""
+#endif
+#if ENABLE_FEATURE_VI_USE_SIGNALS
+ "\n\tSignal catching- ^C"
+ "\n\tJob suspend and resume with ^Z"
+#endif
+#if ENABLE_FEATURE_VI_WIN_RESIZE
+ "\n\tAdapt to window re-sizes"
+#endif
+ );
+}
+
+#if ENABLE_FEATURE_VI_DOT_CMD
+static void start_new_cmd_q(char c)
+{
+ // get buffer for new cmd
+ // if there is a current cmd count put it in the buffer first
+ if (cmdcnt > 0)
+ lmc_len = sprintf(last_modifying_cmd, "%d%c", cmdcnt, c);
+ else { // just save char c onto queue
+ last_modifying_cmd[0] = c;
+ lmc_len = 1;
+ }
+ adding2q = 1;
+}
+
+static void end_cmd_q(void)
+{
+#if ENABLE_FEATURE_VI_YANKMARK
+ YDreg = 26; // go back to default Yank/Delete reg
+#endif
+ adding2q = 0;
+}
+#endif /* FEATURE_VI_DOT_CMD */
+
+#if ENABLE_FEATURE_VI_YANKMARK \
+ || (ENABLE_FEATURE_VI_COLON && ENABLE_FEATURE_VI_SEARCH) \
+ || ENABLE_FEATURE_VI_CRASHME
+static char *string_insert(char *p, char *s) // insert the string at 'p'
+{
+ int cnt, i;
+
+ i = strlen(s);
+ text_hole_make(p, i);
+ strncpy(p, s, i);
+ for (cnt = 0; *s != '\0'; s++) {
+ if (*s == '\n')
+ cnt++;
+ }
+#if ENABLE_FEATURE_VI_YANKMARK
+ status_line("Put %d lines (%d chars) from [%c]", cnt, i, what_reg());
+#endif
+ return p;
+}
+#endif
+
+#if ENABLE_FEATURE_VI_YANKMARK
+static char *text_yank(char *p, char *q, int dest) // copy text into a register
+{
+ char *t;
+ int cnt;
+
+ if (q < p) { // they are backwards- reverse them
+ t = q;
+ q = p;
+ p = t;
+ }
+ cnt = q - p + 1;
+ t = reg[dest];
+ free(t); // if already a yank register, free it
+ t = xmalloc(cnt + 1); // get a new register
+ memset(t, '\0', cnt + 1); // clear new text[]
+ strncpy(t, p, cnt); // copy text[] into bufer
+ reg[dest] = t;
+ return p;
+}
+
+static char what_reg(void)
+{
+ char c;
+
+ c = 'D'; // default to D-reg
+ if (0 <= YDreg && YDreg <= 25)
+ c = 'a' + (char) YDreg;
+ if (YDreg == 26)
+ c = 'D';
+ if (YDreg == 27)
+ c = 'U';
+ return c;
+}
+
+static void check_context(char cmd)
+{
+ // A context is defined to be "modifying text"
+ // Any modifying command establishes a new context.
+
+ if (dot < context_start || dot > context_end) {
+ if (strchr(modifying_cmds, cmd) != NULL) {
+ // we are trying to modify text[]- make this the current context
+ mark[27] = mark[26]; // move cur to prev
+ mark[26] = dot; // move local to cur
+ context_start = prev_line(prev_line(dot));
+ context_end = next_line(next_line(dot));
+ //loiter= start_loiter= now;
+ }
+ }
+}
+
+static char *swap_context(char *p) // goto new context for '' command make this the current context
+{
+ char *tmp;
+
+ // the current context is in mark[26]
+ // the previous context is in mark[27]
+ // only swap context if other context is valid
+ if (text <= mark[27] && mark[27] <= end - 1) {
+ tmp = mark[27];
+ mark[27] = mark[26];
+ mark[26] = tmp;
+ p = mark[26]; // where we are going- previous context
+ context_start = prev_line(prev_line(prev_line(p)));
+ context_end = next_line(next_line(next_line(p)));
+ }
+ return p;
+}
+#endif /* FEATURE_VI_YANKMARK */
+
+//----- Set terminal attributes --------------------------------
+static void rawmode(void)
+{
+ tcgetattr(0, &term_orig);
+ term_vi = term_orig;
+ term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG ON- allow intr's
+ term_vi.c_iflag &= (~IXON & ~ICRNL);
+ term_vi.c_oflag &= (~ONLCR);
+ term_vi.c_cc[VMIN] = 1;
+ term_vi.c_cc[VTIME] = 0;
+ erase_char = term_vi.c_cc[VERASE];
+ tcsetattr(0, TCSANOW, &term_vi);
+}
+
+static void cookmode(void)
+{
+ fflush(stdout);
+ tcsetattr(0, TCSANOW, &term_orig);
+}
+
+//----- Come here when we get a window resize signal ---------
+#if ENABLE_FEATURE_VI_USE_SIGNALS
+static void winch_sig(int sig ATTRIBUTE_UNUSED)
+{
+ // FIXME: do it in main loop!!!
+ signal(SIGWINCH, winch_sig);
+ if (ENABLE_FEATURE_VI_WIN_RESIZE) {
+ get_terminal_width_height(0, &columns, &rows);
+ if (rows > MAX_SCR_ROWS) rows = MAX_SCR_ROWS;
+ if (columns > MAX_SCR_COLS) columns = MAX_SCR_COLS;
+ }
+ new_screen(rows, columns); // get memory for virtual screen
+ redraw(TRUE); // re-draw the screen
+}
+
+//----- Come here when we get a continue signal -------------------
+static void cont_sig(int sig ATTRIBUTE_UNUSED)
+{
+ rawmode(); // terminal to "raw"
+ last_status_cksum = 0; // force status update
+ redraw(TRUE); // re-draw the screen
+
+ signal(SIGTSTP, suspend_sig);
+ signal(SIGCONT, SIG_DFL);
+ kill(my_pid, SIGCONT);
+}
+
+//----- Come here when we get a Suspend signal -------------------
+static void suspend_sig(int sig ATTRIBUTE_UNUSED)
+{
+ place_cursor(rows - 1, 0, FALSE); // go to bottom of screen
+ clear_to_eol(); // Erase to end of line
+ cookmode(); // terminal to "cooked"
+
+ signal(SIGCONT, cont_sig);
+ signal(SIGTSTP, SIG_DFL);
+ kill(my_pid, SIGTSTP);
+}
+
+//----- Come here when we get a signal ---------------------------
+static void catch_sig(int sig)
+{
+ signal(SIGINT, catch_sig);
+ if (sig)
+ siglongjmp(restart, sig);
+}
+#endif /* FEATURE_VI_USE_SIGNALS */
+
+static int mysleep(int hund) // sleep for 'h' 1/100 seconds
+{
+ struct pollfd pfd[1];
+
+ pfd[0].fd = 0;
+ pfd[0].events = POLLIN;
+ return safe_poll(pfd, 1, hund*10) > 0;
+}
+
+//----- IO Routines --------------------------------------------
+static char readit(void) // read (maybe cursor) key from stdin
+{
+ char c;
+ int n;
+ struct esc_cmds {
+ const char seq[4];
+ char val;
+ };
+
+ static const struct esc_cmds esccmds[] = {
+ {"OA" , VI_K_UP }, // cursor key Up
+ {"OB" , VI_K_DOWN }, // cursor key Down
+ {"OC" , VI_K_RIGHT }, // Cursor Key Right
+ {"OD" , VI_K_LEFT }, // cursor key Left
+ {"OH" , VI_K_HOME }, // Cursor Key Home
+ {"OF" , VI_K_END }, // Cursor Key End
+ {"[A" , VI_K_UP }, // cursor key Up
+ {"[B" , VI_K_DOWN }, // cursor key Down
+ {"[C" , VI_K_RIGHT }, // Cursor Key Right
+ {"[D" , VI_K_LEFT }, // cursor key Left
+ {"[H" , VI_K_HOME }, // Cursor Key Home
+ {"[F" , VI_K_END }, // Cursor Key End
+ {"[1~" , VI_K_HOME }, // Cursor Key Home
+ {"[2~" , VI_K_INSERT }, // Cursor Key Insert
+ {"[3~" , VI_K_DELETE }, // Cursor Key Delete
+ {"[4~" , VI_K_END }, // Cursor Key End
+ {"[5~" , VI_K_PAGEUP }, // Cursor Key Page Up
+ {"[6~" , VI_K_PAGEDOWN}, // Cursor Key Page Down
+ {"OP" , VI_K_FUN1 }, // Function Key F1
+ {"OQ" , VI_K_FUN2 }, // Function Key F2
+ {"OR" , VI_K_FUN3 }, // Function Key F3
+ {"OS" , VI_K_FUN4 }, // Function Key F4
+ // careful: these have no terminating NUL!
+ {"[11~", VI_K_FUN1 }, // Function Key F1
+ {"[12~", VI_K_FUN2 }, // Function Key F2
+ {"[13~", VI_K_FUN3 }, // Function Key F3
+ {"[14~", VI_K_FUN4 }, // Function Key F4
+ {"[15~", VI_K_FUN5 }, // Function Key F5
+ {"[17~", VI_K_FUN6 }, // Function Key F6
+ {"[18~", VI_K_FUN7 }, // Function Key F7
+ {"[19~", VI_K_FUN8 }, // Function Key F8
+ {"[20~", VI_K_FUN9 }, // Function Key F9
+ {"[21~", VI_K_FUN10 }, // Function Key F10
+ {"[23~", VI_K_FUN11 }, // Function Key F11
+ {"[24~", VI_K_FUN12 }, // Function Key F12
+ };
+ enum { ESCCMDS_COUNT = ARRAY_SIZE(esccmds) };
+
+ fflush(stdout);
+ n = chars_to_parse;
+ // get input from User- are there already input chars in Q?
+ if (n <= 0) {
+ // the Q is empty, wait for a typed char
+ n = safe_read(STDIN_FILENO, readbuffer, sizeof(readbuffer));
+ if (n < 0) {
+ if (errno == EBADF || errno == EFAULT || errno == EINVAL
+ || errno == EIO)
+ editing = 0; // want to exit
+ errno = 0;
+ }
+ if (n <= 0)
+ return 0; // error
+ if (readbuffer[0] == 27) {
+ // This is an ESC char. Is this Esc sequence?
+ // Could be bare Esc key. See if there are any
+ // more chars to read after the ESC. This would
+ // be a Function or Cursor Key sequence.
+ struct pollfd pfd[1];
+ pfd[0].fd = 0;
+ pfd[0].events = POLLIN;
+ // keep reading while there are input chars, and room in buffer
+ // for a complete ESC sequence (assuming 8 chars is enough)
+ while ((safe_poll(pfd, 1, 0) > 0)
+ && ((size_t)n <= (sizeof(readbuffer) - 8))
+ ) {
+ // read the rest of the ESC string
+ int r = safe_read(STDIN_FILENO, readbuffer + n, sizeof(readbuffer) - n);
+ if (r > 0)
+ n += r;
+ }
+ }
+ chars_to_parse = n;
+ }
+ c = readbuffer[0];
+ if (c == 27 && n > 1) {
+ // Maybe cursor or function key?
+ const struct esc_cmds *eindex;
+
+ for (eindex = esccmds; eindex < &esccmds[ESCCMDS_COUNT]; eindex++) {
+ int cnt = strnlen(eindex->seq, 4);
+ if (n <= cnt)
+ continue;
+ if (strncmp(eindex->seq, readbuffer + 1, cnt) != 0)
+ continue;
+ c = eindex->val; // magic char value
+ n = cnt + 1; // squeeze out the ESC sequence
+ goto found;
+ }
+ // defined ESC sequence not found
+ }
+ n = 1;
+ found:
+ // remove key sequence from Q
+ chars_to_parse -= n;
+ memmove(readbuffer, readbuffer + n, sizeof(readbuffer) - n);
+ return c;
+}
+
+//----- IO Routines --------------------------------------------
+static char get_one_char(void)
+{
+ char c;
+
+#if ENABLE_FEATURE_VI_DOT_CMD
+ if (!adding2q) {
+ // we are not adding to the q.
+ // but, we may be reading from a q
+ if (ioq == 0) {
+ // there is no current q, read from STDIN
+ c = readit(); // get the users input
+ } else {
+ // there is a queue to get chars from first
+ c = *ioq++;
+ if (c == '\0') {
+ // the end of the q, read from STDIN
+ free(ioq_start);
+ ioq_start = ioq = 0;
+ c = readit(); // get the users input
+ }
+ }
+ } else {
+ // adding STDIN chars to q
+ c = readit(); // get the users input
+ if (lmc_len >= MAX_INPUT_LEN - 1) {
+ status_line_bold("last_modifying_cmd overrun");
+ } else {
+ // add new char to q
+ last_modifying_cmd[lmc_len++] = c;
+ }
+ }
+#else
+ c = readit(); // get the users input
+#endif /* FEATURE_VI_DOT_CMD */
+ return c;
+}
+
+// Get input line (uses "status line" area)
+static char *get_input_line(const char *prompt)
+{
+ // char [MAX_INPUT_LEN]
+#define buf get_input_line__buf
+
+ char c;
+ int i;
+
+ strcpy(buf, prompt);
+ last_status_cksum = 0; // force status update
+ place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen
+ clear_to_eol(); // clear the line
+ write1(prompt); // write out the :, /, or ? prompt
+
+ i = strlen(buf);
+ while (i < MAX_INPUT_LEN) {
+ c = get_one_char();
+ if (c == '\n' || c == '\r' || c == 27)
+ break; // this is end of input
+ if (c == erase_char || c == 8 || c == 127) {
+ // user wants to erase prev char
+ buf[--i] = '\0';
+ write1("\b \b"); // erase char on screen
+ if (i <= 0) // user backs up before b-o-l, exit
+ break;
+ } else {
+ buf[i] = c;
+ buf[++i] = '\0';
+ bb_putchar(c);
+ }
+ }
+ refresh(FALSE);
+ return buf;
+#undef buf
+}
+
+static int file_size(const char *fn) // what is the byte size of "fn"
+{
+ struct stat st_buf;
+ int cnt;
+
+ cnt = -1;
+ if (fn && fn[0] && stat(fn, &st_buf) == 0) // see if file exists
+ cnt = (int) st_buf.st_size;
+ return cnt;
+}
+
+static int file_insert(const char *fn, char *p
+ USE_FEATURE_VI_READONLY(, int update_ro_status))
+{
+ int cnt = -1;
+ int fd, size;
+ struct stat statbuf;
+
+ /* Validate file */
+ if (stat(fn, &statbuf) < 0) {
+ status_line_bold("\"%s\" %s", fn, strerror(errno));
+ goto fi0;
+ }
+ if (!S_ISREG(statbuf.st_mode)) {
+ // This is not a regular file
+ status_line_bold("\"%s\" Not a regular file", fn);
+ goto fi0;
+ }
+ if (p < text || p > end) {
+ status_line_bold("Trying to insert file outside of memory");
+ goto fi0;
+ }
+
+ // read file to buffer
+ fd = open(fn, O_RDONLY);
+ if (fd < 0) {
+ status_line_bold("\"%s\" %s", fn, strerror(errno));
+ goto fi0;
+ }
+ size = statbuf.st_size;
+ p = text_hole_make(p, size);
+ cnt = safe_read(fd, p, size);
+ if (cnt < 0) {
+ status_line_bold("\"%s\" %s", fn, strerror(errno));
+ p = text_hole_delete(p, p + size - 1); // un-do buffer insert
+ } else if (cnt < size) {
+ // There was a partial read, shrink unused space text[]
+ p = text_hole_delete(p + cnt, p + (size - cnt) - 1); // un-do buffer insert
+ status_line_bold("cannot read all of file \"%s\"", fn);
+ }
+ if (cnt >= size)
+ file_modified++;
+ close(fd);
+ fi0:
+#if ENABLE_FEATURE_VI_READONLY
+ if (update_ro_status
+ && ((access(fn, W_OK) < 0) ||
+ /* root will always have access()
+ * so we check fileperms too */
+ !(statbuf.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))
+ )
+ ) {
+ SET_READONLY_FILE(readonly_mode);
+ }
+#endif
+ return cnt;
+}
+
+static int file_write(char *fn, char *first, char *last)
+{
+ int fd, cnt, charcnt;
+
+ if (fn == 0) {
+ status_line_bold("No current filename");
+ return -2;
+ }
+ charcnt = 0;
+ /* By popular request we do not open file with O_TRUNC,
+ * but instead ftruncate() it _after_ successful write.
+ * Might reduce amount of data lost on power fail etc.
+ */
+ fd = open(fn, (O_WRONLY | O_CREAT), 0666);
+ if (fd < 0)
+ return -1;
+ cnt = last - first + 1;
+ charcnt = full_write(fd, first, cnt);
+ ftruncate(fd, charcnt);
+ if (charcnt == cnt) {
+ // good write
+ //file_modified = FALSE;
+ } else {
+ charcnt = 0;
+ }
+ close(fd);
+ return charcnt;
+}
+
+//----- Terminal Drawing ---------------------------------------
+// The terminal is made up of 'rows' line of 'columns' columns.
+// classically this would be 24 x 80.
+// screen coordinates
+// 0,0 ... 0,79
+// 1,0 ... 1,79
+// . ... .
+// . ... .
+// 22,0 ... 22,79
+// 23,0 ... 23,79 <- status line
+
+//----- Move the cursor to row x col (count from 0, not 1) -------
+static void place_cursor(int row, int col, int optimize)
+{
+ char cm1[sizeof(CMrc) + sizeof(int)*3 * 2];
+ char *cm;
+
+ if (row < 0) row = 0;
+ if (row >= rows) row = rows - 1;
+ if (col < 0) col = 0;
+ if (col >= columns) col = columns - 1;
+
+ //----- 1. Try the standard terminal ESC sequence
+ sprintf(cm1, CMrc, row + 1, col + 1);
+ cm = cm1;
+
+#if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
+ if (optimize && col < 16) {
+ enum {
+ SZ_UP = sizeof(CMup),
+ SZ_DN = sizeof(CMdown),
+ SEQ_SIZE = SZ_UP > SZ_DN ? SZ_UP : SZ_DN,
+ };
+ char cm2[SEQ_SIZE * 5 + 32]; // bigger than worst case size
+ char *screenp;
+ int Rrow = last_row;
+ int diff = Rrow - row;
+
+ if (diff < -5 || diff > 5)
+ goto skip;
+
+ //----- find the minimum # of chars to move cursor -------------
+ //----- 2. Try moving with discreet chars (Newline, [back]space, ...)
+ cm2[0] = '\0';
+
+ // move to the correct row
+ while (row < Rrow) {
+ // the cursor has to move up
+ strcat(cm2, CMup);
+ Rrow--;
+ }
+ while (row > Rrow) {
+ // the cursor has to move down
+ strcat(cm2, CMdown);
+ Rrow++;
+ }
+
+ // now move to the correct column
+ strcat(cm2, "\r"); // start at col 0
+ // just send out orignal source char to get to correct place
+ screenp = &screen[row * columns]; // start of screen line
+ strncat(cm2, screenp, col);
+
+ // pick the shortest cursor motion to send out
+ if (strlen(cm2) < strlen(cm)) {
+ cm = cm2;
+ }
+ skip: ;
+ }
+ last_row = row;
+#endif /* FEATURE_VI_OPTIMIZE_CURSOR */
+ write1(cm);
+}
+
+//----- Erase from cursor to end of line -----------------------
+static void clear_to_eol(void)
+{
+ write1(Ceol); // Erase from cursor to end of line
+}
+
+//----- Erase from cursor to end of screen -----------------------
+static void clear_to_eos(void)
+{
+ write1(Ceos); // Erase from cursor to end of screen
+}
+
+//----- Start standout mode ------------------------------------
+static void standout_start(void) // send "start reverse video" sequence
+{
+ write1(SOs); // Start reverse video mode
+}
+
+//----- End standout mode --------------------------------------
+static void standout_end(void) // send "end reverse video" sequence
+{
+ write1(SOn); // End reverse video mode
+}
+
+//----- Flash the screen --------------------------------------
+static void flash(int h)
+{
+ standout_start(); // send "start reverse video" sequence
+ redraw(TRUE);
+ mysleep(h);
+ standout_end(); // send "end reverse video" sequence
+ redraw(TRUE);
+}
+
+static void Indicate_Error(void)
+{
+#if ENABLE_FEATURE_VI_CRASHME
+ if (crashme > 0)
+ return; // generate a random command
+#endif
+ if (!err_method) {
+ write1(bell); // send out a bell character
+ } else {
+ flash(10);
+ }
+}
+
+//----- Screen[] Routines --------------------------------------
+//----- Erase the Screen[] memory ------------------------------
+static void screen_erase(void)
+{
+ memset(screen, ' ', screensize); // clear new screen
+}
+
+static int bufsum(char *buf, int count)
+{
+ int sum = 0;
+ char *e = buf + count;
+
+ while (buf < e)
+ sum += (unsigned char) *buf++;
+ return sum;
+}
+
+//----- Draw the status line at bottom of the screen -------------
+static void show_status_line(void)
+{
+ int cnt = 0, cksum = 0;
+
+ // either we already have an error or status message, or we
+ // create one.
+ if (!have_status_msg) {
+ cnt = format_edit_status();
+ cksum = bufsum(status_buffer, cnt);
+ }
+ if (have_status_msg || ((cnt > 0 && last_status_cksum != cksum))) {
+ last_status_cksum = cksum; // remember if we have seen this line
+ place_cursor(rows - 1, 0, FALSE); // put cursor on status line
+ write1(status_buffer);
+ clear_to_eol();
+ if (have_status_msg) {
+ if (((int)strlen(status_buffer) - (have_status_msg - 1)) >
+ (columns - 1) ) {
+ have_status_msg = 0;
+ Hit_Return();
+ }
+ have_status_msg = 0;
+ }
+ place_cursor(crow, ccol, FALSE); // put cursor back in correct place
+ }
+ fflush(stdout);
+}
+
+//----- format the status buffer, the bottom line of screen ------
+// format status buffer, with STANDOUT mode
+static void status_line_bold(const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ strcpy(status_buffer, SOs); // Terminal standout mode on
+ vsprintf(status_buffer + sizeof(SOs)-1, format, args);
+ strcat(status_buffer, SOn); // Terminal standout mode off
+ va_end(args);
+
+ have_status_msg = 1 + sizeof(SOs) + sizeof(SOn) - 2;
+}
+
+// format status buffer
+static void status_line(const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ vsprintf(status_buffer, format, args);
+ va_end(args);
+
+ have_status_msg = 1;
+}
+
+// copy s to buf, convert unprintable
+static void print_literal(char *buf, const char *s)
+{
+ unsigned char c;
+ char b[2];
+
+ b[1] = '\0';
+ buf[0] = '\0';
+ if (!s[0])
+ s = "(NULL)";
+ for (; *s; s++) {
+ int c_is_no_print;
+
+ c = *s;
+ c_is_no_print = (c & 0x80) && !Isprint(c);
+ if (c_is_no_print) {
+ strcat(buf, SOn);
+ c = '.';
+ }
+ if (c < ' ' || c == 127) {
+ strcat(buf, "^");
+ if (c == 127)
+ c = '?';
+ else
+ c += '@';
+ }
+ b[0] = c;
+ strcat(buf, b);
+ if (c_is_no_print)
+ strcat(buf, SOs);
+ if (*s == '\n')
+ strcat(buf, "$");
+ if (strlen(buf) > MAX_INPUT_LEN - 10) // paranoia
+ break;
+ }
+}
+
+static void not_implemented(const char *s)
+{
+ char buf[MAX_INPUT_LEN];
+
+ print_literal(buf, s);
+ status_line_bold("\'%s\' is not implemented", buf);
+}
+
+// show file status on status line
+static int format_edit_status(void)
+{
+ static const char cmd_mode_indicator[] ALIGN1 = "-IR-";
+
+#define tot format_edit_status__tot
+
+ int cur, percent, ret, trunc_at;
+
+ // file_modified is now a counter rather than a flag. this
+ // helps reduce the amount of line counting we need to do.
+ // (this will cause a mis-reporting of modified status
+ // once every MAXINT editing operations.)
+
+ // it would be nice to do a similar optimization here -- if
+ // we haven't done a motion that could have changed which line
+ // we're on, then we shouldn't have to do this count_lines()
+ cur = count_lines(text, dot);
+
+ // reduce counting -- the total lines can't have
+ // changed if we haven't done any edits.
+ if (file_modified != last_file_modified) {
+ tot = cur + count_lines(dot, end - 1) - 1;
+ last_file_modified = file_modified;
+ }
+
+ // current line percent
+ // ------------- ~~ ----------
+ // total lines 100
+ if (tot > 0) {
+ percent = (100 * cur) / tot;
+ } else {
+ cur = tot = 0;
+ percent = 100;
+ }
+
+ trunc_at = columns < STATUS_BUFFER_LEN-1 ?
+ columns : STATUS_BUFFER_LEN-1;
+
+ ret = snprintf(status_buffer, trunc_at+1,
+#if ENABLE_FEATURE_VI_READONLY
+ "%c %s%s%s %d/%d %d%%",
+#else
+ "%c %s%s %d/%d %d%%",
+#endif
+ cmd_mode_indicator[cmd_mode & 3],
+ (current_filename != NULL ? current_filename : "No file"),
+#if ENABLE_FEATURE_VI_READONLY
+ (readonly_mode ? " [Readonly]" : ""),
+#endif
+ (file_modified ? " [Modified]" : ""),
+ cur, tot, percent);
+
+ if (ret >= 0 && ret < trunc_at)
+ return ret; /* it all fit */
+
+ return trunc_at; /* had to truncate */
+#undef tot
+}
+
+//----- Force refresh of all Lines -----------------------------
+static void redraw(int full_screen)
+{
+ place_cursor(0, 0, FALSE); // put cursor in correct place
+ clear_to_eos(); // tell terminal to erase display
+ screen_erase(); // erase the internal screen buffer
+ last_status_cksum = 0; // force status update
+ refresh(full_screen); // this will redraw the entire display
+ show_status_line();
+}
+
+//----- Format a text[] line into a buffer ---------------------
+static char* format_line(char *src /*, int li*/)
+{
+ unsigned char c;
+ int co;
+ int ofs = offset;
+ char *dest = scr_out_buf; // [MAX_SCR_COLS + MAX_TABSTOP * 2]
+
+ c = '~'; // char in col 0 in non-existent lines is '~'
+ co = 0;
+ while (co < columns + tabstop) {
+ // have we gone past the end?
+ if (src < end) {
+ c = *src++;
+ if (c == '\n')
+ break;
+ if ((c & 0x80) && !Isprint(c)) {
+ c = '.';
+ }
+ if (c < ' ' || c == 0x7f) {
+ if (c == '\t') {
+ c = ' ';
+ // co % 8 != 7
+ while ((co % tabstop) != (tabstop - 1)) {
+ dest[co++] = c;
+ }
+ } else {
+ dest[co++] = '^';
+ if (c == 0x7f)
+ c = '?';
+ else
+ c += '@'; // Ctrl-X -> 'X'
+ }
+ }
+ }
+ dest[co++] = c;
+ // discard scrolled-off-to-the-left portion,
+ // in tabstop-sized pieces
+ if (ofs >= tabstop && co >= tabstop) {
+ memmove(dest, dest + tabstop, co);
+ co -= tabstop;
+ ofs -= tabstop;
+ }
+ if (src >= end)
+ break;
+ }
+ // check "short line, gigantic offset" case
+ if (co < ofs)
+ ofs = co;
+ // discard last scrolled off part
+ co -= ofs;
+ dest += ofs;
+ // fill the rest with spaces
+ if (co < columns)
+ memset(&dest[co], ' ', columns - co);
+ return dest;
+}
+
+//----- Refresh the changed screen lines -----------------------
+// Copy the source line from text[] into the buffer and note
+// if the current screenline is different from the new buffer.
+// If they differ then that line needs redrawing on the terminal.
+//
+static void refresh(int full_screen)
+{
+#define old_offset refresh__old_offset
+
+ int li, changed;
+ char *tp, *sp; // pointer into text[] and screen[]
+
+ if (ENABLE_FEATURE_VI_WIN_RESIZE) {
+ unsigned c = columns, r = rows;
+ get_terminal_width_height(0, &columns, &rows);
+ if (rows > MAX_SCR_ROWS) rows = MAX_SCR_ROWS;
+ if (columns > MAX_SCR_COLS) columns = MAX_SCR_COLS;
+ full_screen |= (c - columns) | (r - rows);
+ }
+ sync_cursor(dot, &crow, &ccol); // where cursor will be (on "dot")
+ tp = screenbegin; // index into text[] of top line
+
+ // compare text[] to screen[] and mark screen[] lines that need updating
+ for (li = 0; li < rows - 1; li++) {
+ int cs, ce; // column start & end
+ char *out_buf;
+ // format current text line
+ out_buf = format_line(tp /*, li*/);
+
+ // skip to the end of the current text[] line
+ if (tp < end) {
+ char *t = memchr(tp, '\n', end - tp);
+ if (!t) t = end - 1;
+ tp = t + 1;
+ }
+
+ // see if there are any changes between vitual screen and out_buf
+ changed = FALSE; // assume no change
+ cs = 0;
+ ce = columns - 1;
+ sp = &screen[li * columns]; // start of screen line
+ if (full_screen) {
+ // force re-draw of every single column from 0 - columns-1
+ goto re0;
+ }
+ // compare newly formatted buffer with virtual screen
+ // look forward for first difference between buf and screen
+ for (; cs <= ce; cs++) {
+ if (out_buf[cs] != sp[cs]) {
+ changed = TRUE; // mark for redraw
+ break;
+ }
+ }
+
+ // look backward for last difference between out_buf and screen
+ for (; ce >= cs; ce--) {
+ if (out_buf[ce] != sp[ce]) {
+ changed = TRUE; // mark for redraw
+ break;
+ }
+ }
+ // now, cs is index of first diff, and ce is index of last diff
+
+ // if horz offset has changed, force a redraw
+ if (offset != old_offset) {
+ re0:
+ changed = TRUE;
+ }
+
+ // make a sanity check of columns indexes
+ if (cs < 0) cs = 0;
+ if (ce > columns - 1) ce = columns - 1;
+ if (cs > ce) { cs = 0; ce = columns - 1; }
+ // is there a change between vitual screen and out_buf
+ if (changed) {
+ // copy changed part of buffer to virtual screen
+ memcpy(sp+cs, out_buf+cs, ce-cs+1);
+
+ // move cursor to column of first change
+ //if (offset != old_offset) {
+ // // place_cursor is still too stupid
+ // // to handle offsets correctly
+ // place_cursor(li, cs, FALSE);
+ //} else {
+ place_cursor(li, cs, TRUE);
+ //}
+
+ // write line out to terminal
+ fwrite(&sp[cs], ce - cs + 1, 1, stdout);
+ }
+ }
+
+ place_cursor(crow, ccol, TRUE);
+
+ old_offset = offset;
+#undef old_offset
+}
+
+//---------------------------------------------------------------------
+//----- the Ascii Chart -----------------------------------------------
+//
+// 00 nul 01 soh 02 stx 03 etx 04 eot 05 enq 06 ack 07 bel
+// 08 bs 09 ht 0a nl 0b vt 0c np 0d cr 0e so 0f si
+// 10 dle 11 dc1 12 dc2 13 dc3 14 dc4 15 nak 16 syn 17 etb
+// 18 can 19 em 1a sub 1b esc 1c fs 1d gs 1e rs 1f us
+// 20 sp 21 ! 22 " 23 # 24 $ 25 % 26 & 27 '
+// 28 ( 29 ) 2a * 2b + 2c , 2d - 2e . 2f /
+// 30 0 31 1 32 2 33 3 34 4 35 5 36 6 37 7
+// 38 8 39 9 3a : 3b ; 3c < 3d = 3e > 3f ?
+// 40 @ 41 A 42 B 43 C 44 D 45 E 46 F 47 G
+// 48 H 49 I 4a J 4b K 4c L 4d M 4e N 4f O
+// 50 P 51 Q 52 R 53 S 54 T 55 U 56 V 57 W
+// 58 X 59 Y 5a Z 5b [ 5c \ 5d ] 5e ^ 5f _
+// 60 ` 61 a 62 b 63 c 64 d 65 e 66 f 67 g
+// 68 h 69 i 6a j 6b k 6c l 6d m 6e n 6f o
+// 70 p 71 q 72 r 73 s 74 t 75 u 76 v 77 w
+// 78 x 79 y 7a z 7b { 7c | 7d } 7e ~ 7f del
+//---------------------------------------------------------------------
+
+//----- Execute a Vi Command -----------------------------------
+static void do_cmd(char c)
+{
+ const char *msg = msg; // for compiler
+ char c1, *p, *q, *save_dot;
+ char buf[12];
+ int dir = dir; // for compiler
+ int cnt, i, j;
+
+// c1 = c; // quiet the compiler
+// cnt = yf = 0; // quiet the compiler
+// msg = p = q = save_dot = buf; // quiet the compiler
+ memset(buf, '\0', 12);
+
+ show_status_line();
+
+ /* if this is a cursor key, skip these checks */
+ switch (c) {
+ case VI_K_UP:
+ case VI_K_DOWN:
+ case VI_K_LEFT:
+ case VI_K_RIGHT:
+ case VI_K_HOME:
+ case VI_K_END:
+ case VI_K_PAGEUP:
+ case VI_K_PAGEDOWN:
+ goto key_cmd_mode;
+ }
+
+ if (cmd_mode == 2) {
+ // flip-flop Insert/Replace mode
+ if (c == VI_K_INSERT)
+ goto dc_i;
+ // we are 'R'eplacing the current *dot with new char
+ if (*dot == '\n') {
+ // don't Replace past E-o-l
+ cmd_mode = 1; // convert to insert
+ } else {
+ if (1 <= c || Isprint(c)) {
+ if (c != 27)
+ dot = yank_delete(dot, dot, 0, YANKDEL); // delete char
+ dot = char_insert(dot, c); // insert new char
+ }
+ goto dc1;
+ }
+ }
+ if (cmd_mode == 1) {
+ // hitting "Insert" twice means "R" replace mode
+ if (c == VI_K_INSERT) goto dc5;
+ // insert the char c at "dot"
+ if (1 <= c || Isprint(c)) {
+ dot = char_insert(dot, c);
+ }
+ goto dc1;
+ }
+
+ key_cmd_mode:
+ switch (c) {
+ //case 0x01: // soh
+ //case 0x09: // ht
+ //case 0x0b: // vt
+ //case 0x0e: // so
+ //case 0x0f: // si
+ //case 0x10: // dle
+ //case 0x11: // dc1
+ //case 0x13: // dc3
+#if ENABLE_FEATURE_VI_CRASHME
+ case 0x14: // dc4 ctrl-T
+ crashme = (crashme == 0) ? 1 : 0;
+ break;
+#endif
+ //case 0x16: // syn
+ //case 0x17: // etb
+ //case 0x18: // can
+ //case 0x1c: // fs
+ //case 0x1d: // gs
+ //case 0x1e: // rs
+ //case 0x1f: // us
+ //case '!': // !-
+ //case '#': // #-
+ //case '&': // &-
+ //case '(': // (-
+ //case ')': // )-
+ //case '*': // *-
+ //case '=': // =-
+ //case '@': // @-
+ //case 'F': // F-
+ //case 'K': // K-
+ //case 'Q': // Q-
+ //case 'S': // S-
+ //case 'T': // T-
+ //case 'V': // V-
+ //case '[': // [-
+ //case '\\': // \-
+ //case ']': // ]-
+ //case '_': // _-
+ //case '`': // `-
+ //case 'u': // u- FIXME- there is no undo
+ //case 'v': // v-
+ default: // unrecognised command
+ buf[0] = c;
+ buf[1] = '\0';
+ if (c < ' ') {
+ buf[0] = '^';
+ buf[1] = c + '@';
+ buf[2] = '\0';
+ }
+ not_implemented(buf);
+ end_cmd_q(); // stop adding to q
+ case 0x00: // nul- ignore
+ break;
+ case 2: // ctrl-B scroll up full screen
+ case VI_K_PAGEUP: // Cursor Key Page Up
+ dot_scroll(rows - 2, -1);
+ break;
+ case 4: // ctrl-D scroll down half screen
+ dot_scroll((rows - 2) / 2, 1);
+ break;
+ case 5: // ctrl-E scroll down one line
+ dot_scroll(1, 1);
+ break;
+ case 6: // ctrl-F scroll down full screen
+ case VI_K_PAGEDOWN: // Cursor Key Page Down
+ dot_scroll(rows - 2, 1);
+ break;
+ case 7: // ctrl-G show current status
+ last_status_cksum = 0; // force status update
+ break;
+ case 'h': // h- move left
+ case VI_K_LEFT: // cursor key Left
+ case 8: // ctrl-H- move left (This may be ERASE char)
+ case 0x7f: // DEL- move left (This may be ERASE char)
+ if (cmdcnt-- > 1) {
+ do_cmd(c);
+ } // repeat cnt
+ dot_left();
+ break;
+ case 10: // Newline ^J
+ case 'j': // j- goto next line, same col
+ case VI_K_DOWN: // cursor key Down
+ if (cmdcnt-- > 1) {
+ do_cmd(c);
+ } // repeat cnt
+ dot_next(); // go to next B-o-l
+ dot = move_to_col(dot, ccol + offset); // try stay in same col
+ break;
+ case 12: // ctrl-L force redraw whole screen
+ case 18: // ctrl-R force redraw
+ place_cursor(0, 0, FALSE); // put cursor in correct place
+ clear_to_eos(); // tel terminal to erase display
+ mysleep(10);
+ screen_erase(); // erase the internal screen buffer
+ last_status_cksum = 0; // force status update
+ refresh(TRUE); // this will redraw the entire display
+ break;
+ case 13: // Carriage Return ^M
+ case '+': // +- goto next line
+ if (cmdcnt-- > 1) {
+ do_cmd(c);
+ } // repeat cnt
+ dot_next();
+ dot_skip_over_ws();
+ break;
+ case 21: // ctrl-U scroll up half screen
+ dot_scroll((rows - 2) / 2, -1);
+ break;
+ case 25: // ctrl-Y scroll up one line
+ dot_scroll(1, -1);
+ break;
+ case 27: // esc
+ if (cmd_mode == 0)
+ indicate_error(c);
+ cmd_mode = 0; // stop insrting
+ end_cmd_q();
+ last_status_cksum = 0; // force status update
+ break;
+ case ' ': // move right
+ case 'l': // move right
+ case VI_K_RIGHT: // Cursor Key Right
+ if (cmdcnt-- > 1) {
+ do_cmd(c);
+ } // repeat cnt
+ dot_right();
+ break;
+#if ENABLE_FEATURE_VI_YANKMARK
+ case '"': // "- name a register to use for Delete/Yank
+ c1 = get_one_char();
+ c1 = tolower(c1);
+ if (islower(c1)) {
+ YDreg = c1 - 'a';
+ } else {
+ indicate_error(c);
+ }
+ break;
+ case '\'': // '- goto a specific mark
+ c1 = get_one_char();
+ c1 = tolower(c1);
+ if (islower(c1)) {
+ c1 = c1 - 'a';
+ // get the b-o-l
+ q = mark[(unsigned char) c1];
+ if (text <= q && q < end) {
+ dot = q;
+ dot_begin(); // go to B-o-l
+ dot_skip_over_ws();
+ }
+ } else if (c1 == '\'') { // goto previous context
+ dot = swap_context(dot); // swap current and previous context
+ dot_begin(); // go to B-o-l
+ dot_skip_over_ws();
+ } else {
+ indicate_error(c);
+ }
+ break;
+ case 'm': // m- Mark a line
+ // this is really stupid. If there are any inserts or deletes
+ // between text[0] and dot then this mark will not point to the
+ // correct location! It could be off by many lines!
+ // Well..., at least its quick and dirty.
+ c1 = get_one_char();
+ c1 = tolower(c1);
+ if (islower(c1)) {
+ c1 = c1 - 'a';
+ // remember the line
+ mark[(int) c1] = dot;
+ } else {
+ indicate_error(c);
+ }
+ break;
+ case 'P': // P- Put register before
+ case 'p': // p- put register after
+ p = reg[YDreg];
+ if (p == 0) {
+ status_line_bold("Nothing in register %c", what_reg());
+ break;
+ }
+ // are we putting whole lines or strings
+ if (strchr(p, '\n') != NULL) {
+ if (c == 'P') {
+ dot_begin(); // putting lines- Put above
+ }
+ if (c == 'p') {
+ // are we putting after very last line?
+ if (end_line(dot) == (end - 1)) {
+ dot = end; // force dot to end of text[]
+ } else {
+ dot_next(); // next line, then put before
+ }
+ }
+ } else {
+ if (c == 'p')
+ dot_right(); // move to right, can move to NL
+ }
+ dot = string_insert(dot, p); // insert the string
+ end_cmd_q(); // stop adding to q
+ break;
+ case 'U': // U- Undo; replace current line with original version
+ if (reg[Ureg] != 0) {
+ p = begin_line(dot);
+ q = end_line(dot);
+ p = text_hole_delete(p, q); // delete cur line
+ p = string_insert(p, reg[Ureg]); // insert orig line
+ dot = p;
+ dot_skip_over_ws();
+ }
+ break;
+#endif /* FEATURE_VI_YANKMARK */
+ case '$': // $- goto end of line
+ case VI_K_END: // Cursor Key End
+ if (cmdcnt-- > 1) {
+ do_cmd(c);
+ } // repeat cnt
+ dot = end_line(dot);
+ break;
+ case '%': // %- find matching char of pair () [] {}
+ for (q = dot; q < end && *q != '\n'; q++) {
+ if (strchr("()[]{}", *q) != NULL) {
+ // we found half of a pair
+ p = find_pair(q, *q);
+ if (p == NULL) {
+ indicate_error(c);
+ } else {
+ dot = p;
+ }
+ break;
+ }
+ }
+ if (*q == '\n')
+ indicate_error(c);
+ break;
+ case 'f': // f- forward to a user specified char
+ last_forward_char = get_one_char(); // get the search char
+ //
+ // dont separate these two commands. 'f' depends on ';'
+ //
+ //**** fall through to ... ';'
+ case ';': // ;- look at rest of line for last forward char
+ if (cmdcnt-- > 1) {
+ do_cmd(';');
+ } // repeat cnt
+ if (last_forward_char == 0)
+ break;
+ q = dot + 1;
+ while (q < end - 1 && *q != '\n' && *q != last_forward_char) {
+ q++;
+ }
+ if (*q == last_forward_char)
+ dot = q;
+ break;
+ case ',': // repeat latest 'f' in opposite direction
+ if (cmdcnt-- > 1) {
+ do_cmd(',');
+ } // repeat cnt
+ if (last_forward_char == 0)
+ break;
+ q = dot - 1;
+ while (q >= text && *q != '\n' && *q != last_forward_char) {
+ q--;
+ }
+ if (q >= text && *q == last_forward_char)
+ dot = q;
+ break;
+
+ case '-': // -- goto prev line
+ if (cmdcnt-- > 1) {
+ do_cmd(c);
+ } // repeat cnt
+ dot_prev();
+ dot_skip_over_ws();
+ break;
+#if ENABLE_FEATURE_VI_DOT_CMD
+ case '.': // .- repeat the last modifying command
+ // Stuff the last_modifying_cmd back into stdin
+ // and let it be re-executed.
+ if (lmc_len > 0) {
+ last_modifying_cmd[lmc_len] = 0;
+ ioq = ioq_start = xstrdup(last_modifying_cmd);
+ }
+ break;
+#endif
+#if ENABLE_FEATURE_VI_SEARCH
+ case '?': // /- search for a pattern
+ case '/': // /- search for a pattern
+ buf[0] = c;
+ buf[1] = '\0';
+ q = get_input_line(buf); // get input line- use "status line"
+ if (q[0] && !q[1]) {
+ if (last_search_pattern[0])
+ last_search_pattern[0] = c;
+ goto dc3; // if no pat re-use old pat
+ }
+ if (q[0]) { // strlen(q) > 1: new pat- save it and find
+ // there is a new pat
+ free(last_search_pattern);
+ last_search_pattern = xstrdup(q);
+ goto dc3; // now find the pattern
+ }
+ // user changed mind and erased the "/"- do nothing
+ break;
+ case 'N': // N- backward search for last pattern
+ if (cmdcnt-- > 1) {
+ do_cmd(c);
+ } // repeat cnt
+ dir = BACK; // assume BACKWARD search
+ p = dot - 1;
+ if (last_search_pattern[0] == '?') {
+ dir = FORWARD;
+ p = dot + 1;
+ }
+ goto dc4; // now search for pattern
+ break;
+ case 'n': // n- repeat search for last pattern
+ // search rest of text[] starting at next char
+ // if search fails return orignal "p" not the "p+1" address
+ if (cmdcnt-- > 1) {
+ do_cmd(c);
+ } // repeat cnt
+ dc3:
+ if (last_search_pattern == 0) {
+ msg = "No previous regular expression";
+ goto dc2;
+ }
+ if (last_search_pattern[0] == '/') {
+ dir = FORWARD; // assume FORWARD search
+ p = dot + 1;
+ }
+ if (last_search_pattern[0] == '?') {
+ dir = BACK;
+ p = dot - 1;
+ }
+ dc4:
+ q = char_search(p, last_search_pattern + 1, dir, FULL);
+ if (q != NULL) {
+ dot = q; // good search, update "dot"
+ msg = "";
+ goto dc2;
+ }
+ // no pattern found between "dot" and "end"- continue at top
+ p = text;
+ if (dir == BACK) {
+ p = end - 1;
+ }
+ q = char_search(p, last_search_pattern + 1, dir, FULL);
+ if (q != NULL) { // found something
+ dot = q; // found new pattern- goto it
+ msg = "search hit BOTTOM, continuing at TOP";
+ if (dir == BACK) {
+ msg = "search hit TOP, continuing at BOTTOM";
+ }
+ } else {
+ msg = "Pattern not found";
+ }
+ dc2:
+ if (*msg)
+ status_line_bold("%s", msg);
+ break;
+ case '{': // {- move backward paragraph
+ q = char_search(dot, "\n\n", BACK, FULL);
+ if (q != NULL) { // found blank line
+ dot = next_line(q); // move to next blank line
+ }
+ break;
+ case '}': // }- move forward paragraph
+ q = char_search(dot, "\n\n", FORWARD, FULL);
+ if (q != NULL) { // found blank line
+ dot = next_line(q); // move to next blank line
+ }
+ break;
+#endif /* FEATURE_VI_SEARCH */
+ case '0': // 0- goto begining of line
+ case '1': // 1-
+ case '2': // 2-
+ case '3': // 3-
+ case '4': // 4-
+ case '5': // 5-
+ case '6': // 6-
+ case '7': // 7-
+ case '8': // 8-
+ case '9': // 9-
+ if (c == '0' && cmdcnt < 1) {
+ dot_begin(); // this was a standalone zero
+ } else {
+ cmdcnt = cmdcnt * 10 + (c - '0'); // this 0 is part of a number
+ }
+ break;
+ case ':': // :- the colon mode commands
+ p = get_input_line(":"); // get input line- use "status line"
+#if ENABLE_FEATURE_VI_COLON
+ colon(p); // execute the command
+#else
+ if (*p == ':')
+ p++; // move past the ':'
+ cnt = strlen(p);
+ if (cnt <= 0)
+ break;
+ if (strncasecmp(p, "quit", cnt) == 0
+ || strncasecmp(p, "q!", cnt) == 0 // delete lines
+ ) {
+ if (file_modified && p[1] != '!') {
+ status_line_bold("No write since last change (:quit! overrides)");
+ } else {
+ editing = 0;
+ }
+ } else if (strncasecmp(p, "write", cnt) == 0
+ || strncasecmp(p, "wq", cnt) == 0
+ || strncasecmp(p, "wn", cnt) == 0
+ || strncasecmp(p, "x", cnt) == 0
+ ) {
+ cnt = file_write(current_filename, text, end - 1);
+ if (cnt < 0) {
+ if (cnt == -1)
+ status_line_bold("Write error: %s", strerror(errno));
+ } else {
+ file_modified = 0;
+ last_file_modified = -1;
+ status_line("\"%s\" %dL, %dC", current_filename, count_lines(text, end - 1), cnt);
+ if (p[0] == 'x' || p[1] == 'q' || p[1] == 'n'
+ || p[0] == 'X' || p[1] == 'Q' || p[1] == 'N'
+ ) {
+ editing = 0;
+ }
+ }
+ } else if (strncasecmp(p, "file", cnt) == 0) {
+ last_status_cksum = 0; // force status update
+ } else if (sscanf(p, "%d", &j) > 0) {
+ dot = find_line(j); // go to line # j
+ dot_skip_over_ws();
+ } else { // unrecognised cmd
+ not_implemented(p);
+ }
+#endif /* !FEATURE_VI_COLON */
+ break;
+ case '<': // <- Left shift something
+ case '>': // >- Right shift something
+ cnt = count_lines(text, dot); // remember what line we are on
+ c1 = get_one_char(); // get the type of thing to delete
+ find_range(&p, &q, c1);
+ yank_delete(p, q, 1, YANKONLY); // save copy before change
+ p = begin_line(p);
+ q = end_line(q);
+ i = count_lines(p, q); // # of lines we are shifting
+ for ( ; i > 0; i--, p = next_line(p)) {
+ if (c == '<') {
+ // shift left- remove tab or 8 spaces
+ if (*p == '\t') {
+ // shrink buffer 1 char
+ text_hole_delete(p, p);
+ } else if (*p == ' ') {
+ // we should be calculating columns, not just SPACE
+ for (j = 0; *p == ' ' && j < tabstop; j++) {
+ text_hole_delete(p, p);
+ }
+ }
+ } else if (c == '>') {
+ // shift right -- add tab or 8 spaces
+ char_insert(p, '\t');
+ }
+ }
+ dot = find_line(cnt); // what line were we on
+ dot_skip_over_ws();
+ end_cmd_q(); // stop adding to q
+ break;
+ case 'A': // A- append at e-o-l
+ dot_end(); // go to e-o-l
+ //**** fall through to ... 'a'
+ case 'a': // a- append after current char
+ if (*dot != '\n')
+ dot++;
+ goto dc_i;
+ break;
+ case 'B': // B- back a blank-delimited Word
+ case 'E': // E- end of a blank-delimited word
+ case 'W': // W- forward a blank-delimited word
+ if (cmdcnt-- > 1) {
+ do_cmd(c);
+ } // repeat cnt
+ dir = FORWARD;
+ if (c == 'B')
+ dir = BACK;
+ if (c == 'W' || isspace(dot[dir])) {
+ dot = skip_thing(dot, 1, dir, S_TO_WS);
+ dot = skip_thing(dot, 2, dir, S_OVER_WS);
+ }
+ if (c != 'W')
+ dot = skip_thing(dot, 1, dir, S_BEFORE_WS);
+ break;
+ case 'C': // C- Change to e-o-l
+ case 'D': // D- delete to e-o-l
+ save_dot = dot;
+ dot = dollar_line(dot); // move to before NL
+ // copy text into a register and delete
+ dot = yank_delete(save_dot, dot, 0, YANKDEL); // delete to e-o-l
+ if (c == 'C')
+ goto dc_i; // start inserting
+#if ENABLE_FEATURE_VI_DOT_CMD
+ if (c == 'D')
+ end_cmd_q(); // stop adding to q
+#endif
+ break;
+ case 'g': // 'gg' goto a line number (from vim)
+ // (default to first line in file)
+ c1 = get_one_char();
+ if (c1 != 'g') {
+ buf[0] = 'g';
+ buf[1] = c1;
+ buf[2] = '\0';
+ not_implemented(buf);
+ break;
+ }
+ if (cmdcnt == 0)
+ cmdcnt = 1;
+ /* fall through */
+ case 'G': // G- goto to a line number (default= E-O-F)
+ dot = end - 1; // assume E-O-F
+ if (cmdcnt > 0) {
+ dot = find_line(cmdcnt); // what line is #cmdcnt
+ }
+ dot_skip_over_ws();
+ break;
+ case 'H': // H- goto top line on screen
+ dot = screenbegin;
+ if (cmdcnt > (rows - 1)) {
+ cmdcnt = (rows - 1);
+ }
+ if (cmdcnt-- > 1) {
+ do_cmd('+');
+ } // repeat cnt
+ dot_skip_over_ws();
+ break;
+ case 'I': // I- insert before first non-blank
+ dot_begin(); // 0
+ dot_skip_over_ws();
+ //**** fall through to ... 'i'
+ case 'i': // i- insert before current char
+ case VI_K_INSERT: // Cursor Key Insert
+ dc_i:
+ cmd_mode = 1; // start insrting
+ break;
+ case 'J': // J- join current and next lines together
+ if (cmdcnt-- > 2) {
+ do_cmd(c);
+ } // repeat cnt
+ dot_end(); // move to NL
+ if (dot < end - 1) { // make sure not last char in text[]
+ *dot++ = ' '; // replace NL with space
+ file_modified++;
+ while (isblank(*dot)) { // delete leading WS
+ dot_delete();
+ }
+ }
+ end_cmd_q(); // stop adding to q
+ break;
+ case 'L': // L- goto bottom line on screen
+ dot = end_screen();
+ if (cmdcnt > (rows - 1)) {
+ cmdcnt = (rows - 1);
+ }
+ if (cmdcnt-- > 1) {
+ do_cmd('-');
+ } // repeat cnt
+ dot_begin();
+ dot_skip_over_ws();
+ break;
+ case 'M': // M- goto middle line on screen
+ dot = screenbegin;
+ for (cnt = 0; cnt < (rows-1) / 2; cnt++)
+ dot = next_line(dot);
+ break;
+ case 'O': // O- open a empty line above
+ // 0i\n ESC -i
+ p = begin_line(dot);
+ if (p[-1] == '\n') {
+ dot_prev();
+ case 'o': // o- open a empty line below; Yes, I know it is in the middle of the "if (..."
+ dot_end();
+ dot = char_insert(dot, '\n');
+ } else {
+ dot_begin(); // 0
+ dot = char_insert(dot, '\n'); // i\n ESC
+ dot_prev(); // -
+ }
+ goto dc_i;
+ break;
+ case 'R': // R- continuous Replace char
+ dc5:
+ cmd_mode = 2;
+ break;
+ case VI_K_DELETE:
+ c = 'x';
+ // fall through
+ case 'X': // X- delete char before dot
+ case 'x': // x- delete the current char
+ case 's': // s- substitute the current char
+ if (cmdcnt-- > 1) {
+ do_cmd(c);
+ } // repeat cnt
+ dir = 0;
+ if (c == 'X')
+ dir = -1;
+ if (dot[dir] != '\n') {
+ if (c == 'X')
+ dot--; // delete prev char
+ dot = yank_delete(dot, dot, 0, YANKDEL); // delete char
+ }
+ if (c == 's')
+ goto dc_i; // start insrting
+ end_cmd_q(); // stop adding to q
+ break;
+ case 'Z': // Z- if modified, {write}; exit
+ // ZZ means to save file (if necessary), then exit
+ c1 = get_one_char();
+ if (c1 != 'Z') {
+ indicate_error(c);
+ break;
+ }
+ if (file_modified) {
+ if (ENABLE_FEATURE_VI_READONLY && readonly_mode) {
+ status_line_bold("\"%s\" File is read only", current_filename);
+ break;
+ }
+ cnt = file_write(current_filename, text, end - 1);
+ if (cnt < 0) {
+ if (cnt == -1)
+ status_line_bold("Write error: %s", strerror(errno));
+ } else if (cnt == (end - 1 - text + 1)) {
+ editing = 0;
+ }
+ } else {
+ editing = 0;
+ }
+ break;
+ case '^': // ^- move to first non-blank on line
+ dot_begin();
+ dot_skip_over_ws();
+ break;
+ case 'b': // b- back a word
+ case 'e': // e- end of word
+ if (cmdcnt-- > 1) {
+ do_cmd(c);
+ } // repeat cnt
+ dir = FORWARD;
+ if (c == 'b')
+ dir = BACK;
+ if ((dot + dir) < text || (dot + dir) > end - 1)
+ break;
+ dot += dir;
+ if (isspace(*dot)) {
+ dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS);
+ }
+ if (isalnum(*dot) || *dot == '_') {
+ dot = skip_thing(dot, 1, dir, S_END_ALNUM);
+ } else if (ispunct(*dot)) {
+ dot = skip_thing(dot, 1, dir, S_END_PUNCT);
+ }
+ break;
+ case 'c': // c- change something
+ case 'd': // d- delete something
+#if ENABLE_FEATURE_VI_YANKMARK
+ case 'y': // y- yank something
+ case 'Y': // Y- Yank a line
+#endif
+ {
+ int yf, ml, whole = 0;
+ yf = YANKDEL; // assume either "c" or "d"
+#if ENABLE_FEATURE_VI_YANKMARK
+ if (c == 'y' || c == 'Y')
+ yf = YANKONLY;
+#endif
+ c1 = 'y';
+ if (c != 'Y')
+ c1 = get_one_char(); // get the type of thing to delete
+ // determine range, and whether it spans lines
+ ml = find_range(&p, &q, c1);
+ if (c1 == 27) { // ESC- user changed mind and wants out
+ c = c1 = 27; // Escape- do nothing
+ } else if (strchr("wW", c1)) {
+ if (c == 'c') {
+ // don't include trailing WS as part of word
+ while (isblank(*q)) {
+ if (q <= text || q[-1] == '\n')
+ break;
+ q--;
+ }
+ }
+ dot = yank_delete(p, q, ml, yf); // delete word
+ } else if (strchr("^0bBeEft%$ lh\b\177", c1)) {
+ // partial line copy text into a register and delete
+ dot = yank_delete(p, q, ml, yf); // delete word
+ } else if (strchr("cdykjHL+-{}\r\n", c1)) {
+ // whole line copy text into a register and delete
+ dot = yank_delete(p, q, ml, yf); // delete lines
+ whole = 1;
+ } else {
+ // could not recognize object
+ c = c1 = 27; // error-
+ ml = 0;
+ indicate_error(c);
+ }
+ if (ml && whole) {
+ if (c == 'c') {
+ dot = char_insert(dot, '\n');
+ // on the last line of file don't move to prev line
+ if (whole && dot != (end-1)) {
+ dot_prev();
+ }
+ } else if (c == 'd') {
+ dot_begin();
+ dot_skip_over_ws();
+ }
+ }
+ if (c1 != 27) {
+ // if CHANGING, not deleting, start inserting after the delete
+ if (c == 'c') {
+ strcpy(buf, "Change");
+ goto dc_i; // start inserting
+ }
+ if (c == 'd') {
+ strcpy(buf, "Delete");
+ }
+#if ENABLE_FEATURE_VI_YANKMARK
+ if (c == 'y' || c == 'Y') {
+ strcpy(buf, "Yank");
+ }
+ p = reg[YDreg];
+ q = p + strlen(p);
+ for (cnt = 0; p <= q; p++) {
+ if (*p == '\n')
+ cnt++;
+ }
+ status_line("%s %d lines (%d chars) using [%c]",
+ buf, cnt, strlen(reg[YDreg]), what_reg());
+#endif
+ end_cmd_q(); // stop adding to q
+ }
+ }
+ break;
+ case 'k': // k- goto prev line, same col
+ case VI_K_UP: // cursor key Up
+ if (cmdcnt-- > 1) {
+ do_cmd(c);
+ } // repeat cnt
+ dot_prev();
+ dot = move_to_col(dot, ccol + offset); // try stay in same col
+ break;
+ case 'r': // r- replace the current char with user input
+ c1 = get_one_char(); // get the replacement char
+ if (*dot != '\n') {
+ *dot = c1;
+ file_modified++;
+ }
+ end_cmd_q(); // stop adding to q
+ break;
+ case 't': // t- move to char prior to next x
+ last_forward_char = get_one_char();
+ do_cmd(';');
+ if (*dot == last_forward_char)
+ dot_left();
+ last_forward_char= 0;
+ break;
+ case 'w': // w- forward a word
+ if (cmdcnt-- > 1) {
+ do_cmd(c);
+ } // repeat cnt
+ if (isalnum(*dot) || *dot == '_') { // we are on ALNUM
+ dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM);
+ } else if (ispunct(*dot)) { // we are on PUNCT
+ dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT);
+ }
+ if (dot < end - 1)
+ dot++; // move over word
+ if (isspace(*dot)) {
+ dot = skip_thing(dot, 2, FORWARD, S_OVER_WS);
+ }
+ break;
+ case 'z': // z-
+ c1 = get_one_char(); // get the replacement char
+ cnt = 0;
+ if (c1 == '.')
+ cnt = (rows - 2) / 2; // put dot at center
+ if (c1 == '-')
+ cnt = rows - 2; // put dot at bottom
+ screenbegin = begin_line(dot); // start dot at top
+ dot_scroll(cnt, -1);
+ break;
+ case '|': // |- move to column "cmdcnt"
+ dot = move_to_col(dot, cmdcnt - 1); // try to move to column
+ break;
+ case '~': // ~- flip the case of letters a-z -> A-Z
+ if (cmdcnt-- > 1) {
+ do_cmd(c);
+ } // repeat cnt
+ if (islower(*dot)) {
+ *dot = toupper(*dot);
+ file_modified++;
+ } else if (isupper(*dot)) {
+ *dot = tolower(*dot);
+ file_modified++;
+ }
+ dot_right();
+ end_cmd_q(); // stop adding to q
+ break;
+ //----- The Cursor and Function Keys -----------------------------
+ case VI_K_HOME: // Cursor Key Home
+ dot_begin();
+ break;
+ // The Fn keys could point to do_macro which could translate them
+ case VI_K_FUN1: // Function Key F1
+ case VI_K_FUN2: // Function Key F2
+ case VI_K_FUN3: // Function Key F3
+ case VI_K_FUN4: // Function Key F4
+ case VI_K_FUN5: // Function Key F5
+ case VI_K_FUN6: // Function Key F6
+ case VI_K_FUN7: // Function Key F7
+ case VI_K_FUN8: // Function Key F8
+ case VI_K_FUN9: // Function Key F9
+ case VI_K_FUN10: // Function Key F10
+ case VI_K_FUN11: // Function Key F11
+ case VI_K_FUN12: // Function Key F12
+ break;
+ }
+
+ dc1:
+ // if text[] just became empty, add back an empty line
+ if (end == text) {
+ char_insert(text, '\n'); // start empty buf with dummy line
+ dot = text;
+ }
+ // it is OK for dot to exactly equal to end, otherwise check dot validity
+ if (dot != end) {
+ dot = bound_dot(dot); // make sure "dot" is valid
+ }
+#if ENABLE_FEATURE_VI_YANKMARK
+ check_context(c); // update the current context
+#endif
+
+ if (!isdigit(c))
+ cmdcnt = 0; // cmd was not a number, reset cmdcnt
+ cnt = dot - begin_line(dot);
+ // Try to stay off of the Newline
+ if (*dot == '\n' && cnt > 0 && cmd_mode == 0)
+ dot--;
+}
+
+/* NB! the CRASHME code is unmaintained, and doesn't currently build */
+#if ENABLE_FEATURE_VI_CRASHME
+static int totalcmds = 0;
+static int Mp = 85; // Movement command Probability
+static int Np = 90; // Non-movement command Probability
+static int Dp = 96; // Delete command Probability
+static int Ip = 97; // Insert command Probability
+static int Yp = 98; // Yank command Probability
+static int Pp = 99; // Put command Probability
+static int M = 0, N = 0, I = 0, D = 0, Y = 0, P = 0, U = 0;
+static const char chars[20] = "\t012345 abcdABCD-=.$";
+static const char *const words[20] = {
+ "this", "is", "a", "test",
+ "broadcast", "the", "emergency", "of",
+ "system", "quick", "brown", "fox",
+ "jumped", "over", "lazy", "dogs",
+ "back", "January", "Febuary", "March"
+};
+static const char *const lines[20] = {
+ "You should have received a copy of the GNU General Public License\n",
+ "char c, cm, *cmd, *cmd1;\n",
+ "generate a command by percentages\n",
+ "Numbers may be typed as a prefix to some commands.\n",
+ "Quit, discarding changes!\n",
+ "Forced write, if permission originally not valid.\n",
+ "In general, any ex or ed command (such as substitute or delete).\n",
+ "I have tickets available for the Blazers vs LA Clippers for Monday, Janurary 1 at 1:00pm.\n",
+ "Please get w/ me and I will go over it with you.\n",
+ "The following is a list of scheduled, committed changes.\n",
+ "1. Launch Norton Antivirus (Start, Programs, Norton Antivirus)\n",
+ "Reminder....Town Meeting in Central Perk cafe today at 3:00pm.\n",
+ "Any question about transactions please contact Sterling Huxley.\n",
+ "I will try to get back to you by Friday, December 31.\n",
+ "This Change will be implemented on Friday.\n",
+ "Let me know if you have problems accessing this;\n",
+ "Sterling Huxley recently added you to the access list.\n",
+ "Would you like to go to lunch?\n",
+ "The last command will be automatically run.\n",
+ "This is too much english for a computer geek.\n",
+};
+static char *multilines[20] = {
+ "You should have received a copy of the GNU General Public License\n",
+ "char c, cm, *cmd, *cmd1;\n",
+ "generate a command by percentages\n",
+ "Numbers may be typed as a prefix to some commands.\n",
+ "Quit, discarding changes!\n",
+ "Forced write, if permission originally not valid.\n",
+ "In general, any ex or ed command (such as substitute or delete).\n",
+ "I have tickets available for the Blazers vs LA Clippers for Monday, Janurary 1 at 1:00pm.\n",
+ "Please get w/ me and I will go over it with you.\n",
+ "The following is a list of scheduled, committed changes.\n",
+ "1. Launch Norton Antivirus (Start, Programs, Norton Antivirus)\n",
+ "Reminder....Town Meeting in Central Perk cafe today at 3:00pm.\n",
+ "Any question about transactions please contact Sterling Huxley.\n",
+ "I will try to get back to you by Friday, December 31.\n",
+ "This Change will be implemented on Friday.\n",
+ "Let me know if you have problems accessing this;\n",
+ "Sterling Huxley recently added you to the access list.\n",
+ "Would you like to go to lunch?\n",
+ "The last command will be automatically run.\n",
+ "This is too much english for a computer geek.\n",
+};
+
+// create a random command to execute
+static void crash_dummy()
+{
+ static int sleeptime; // how long to pause between commands
+ char c, cm, *cmd, *cmd1;
+ int i, cnt, thing, rbi, startrbi, percent;
+
+ // "dot" movement commands
+ cmd1 = " \n\r\002\004\005\006\025\0310^$-+wWeEbBhjklHL";
+
+ // is there already a command running?
+ if (chars_to_parse > 0)
+ goto cd1;
+ cd0:
+ startrbi = rbi = 0;
+ sleeptime = 0; // how long to pause between commands
+ memset(readbuffer, '\0', sizeof(readbuffer));
+ // generate a command by percentages
+ percent = (int) lrand48() % 100; // get a number from 0-99
+ if (percent < Mp) { // Movement commands
+ // available commands
+ cmd = cmd1;
+ M++;
+ } else if (percent < Np) { // non-movement commands
+ cmd = "mz<>\'\""; // available commands
+ N++;
+ } else if (percent < Dp) { // Delete commands
+ cmd = "dx"; // available commands
+ D++;
+ } else if (percent < Ip) { // Inset commands
+ cmd = "iIaAsrJ"; // available commands
+ I++;
+ } else if (percent < Yp) { // Yank commands
+ cmd = "yY"; // available commands
+ Y++;
+ } else if (percent < Pp) { // Put commands
+ cmd = "pP"; // available commands
+ P++;
+ } else {
+ // We do not know how to handle this command, try again
+ U++;
+ goto cd0;
+ }
+ // randomly pick one of the available cmds from "cmd[]"
+ i = (int) lrand48() % strlen(cmd);
+ cm = cmd[i];
+ if (strchr(":\024", cm))
+ goto cd0; // dont allow colon or ctrl-T commands
+ readbuffer[rbi++] = cm; // put cmd into input buffer
+
+ // now we have the command-
+ // there are 1, 2, and multi char commands
+ // find out which and generate the rest of command as necessary
+ if (strchr("dmryz<>\'\"", cm)) { // 2-char commands
+ cmd1 = " \n\r0$^-+wWeEbBhjklHL";
+ if (cm == 'm' || cm == '\'' || cm == '\"') { // pick a reg[]
+ cmd1 = "abcdefghijklmnopqrstuvwxyz";
+ }
+ thing = (int) lrand48() % strlen(cmd1); // pick a movement command
+ c = cmd1[thing];
+ readbuffer[rbi++] = c; // add movement to input buffer
+ }
+ if (strchr("iIaAsc", cm)) { // multi-char commands
+ if (cm == 'c') {
+ // change some thing
+ thing = (int) lrand48() % strlen(cmd1); // pick a movement command
+ c = cmd1[thing];
+ readbuffer[rbi++] = c; // add movement to input buffer
+ }
+ thing = (int) lrand48() % 4; // what thing to insert
+ cnt = (int) lrand48() % 10; // how many to insert
+ for (i = 0; i < cnt; i++) {
+ if (thing == 0) { // insert chars
+ readbuffer[rbi++] = chars[((int) lrand48() % strlen(chars))];
+ } else if (thing == 1) { // insert words
+ strcat(readbuffer, words[(int) lrand48() % 20]);
+ strcat(readbuffer, " ");
+ sleeptime = 0; // how fast to type
+ } else if (thing == 2) { // insert lines
+ strcat(readbuffer, lines[(int) lrand48() % 20]);
+ sleeptime = 0; // how fast to type
+ } else { // insert multi-lines
+ strcat(readbuffer, multilines[(int) lrand48() % 20]);
+ sleeptime = 0; // how fast to type
+ }
+ }
+ strcat(readbuffer, "\033");
+ }
+ chars_to_parse = strlen(readbuffer);
+ cd1:
+ totalcmds++;
+ if (sleeptime > 0)
+ mysleep(sleeptime); // sleep 1/100 sec
+}
+
+// test to see if there are any errors
+static void crash_test()
+{
+ static time_t oldtim;
+
+ time_t tim;
+ char d[2], msg[80];
+
+ msg[0] = '\0';
+ if (end < text) {
+ strcat(msg, "end<text ");
+ }
+ if (end > textend) {
+ strcat(msg, "end>textend ");
+ }
+ if (dot < text) {
+ strcat(msg, "dot<text ");
+ }
+ if (dot > end) {
+ strcat(msg, "dot>end ");
+ }
+ if (screenbegin < text) {
+ strcat(msg, "screenbegin<text ");
+ }
+ if (screenbegin > end - 1) {
+ strcat(msg, "screenbegin>end-1 ");
+ }
+
+ if (msg[0]) {
+ printf("\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s",
+ totalcmds, last_input_char, msg, SOs, SOn);
+ fflush(stdout);
+ while (safe_read(STDIN_FILENO, d, 1) > 0) {
+ if (d[0] == '\n' || d[0] == '\r')
+ break;
+ }
+ }
+ tim = time(NULL);
+ if (tim >= (oldtim + 3)) {
+ sprintf(status_buffer,
+ "Tot=%d: M=%d N=%d I=%d D=%d Y=%d P=%d U=%d size=%d",
+ totalcmds, M, N, I, D, Y, P, U, end - text + 1);
+ oldtim = tim;
+ }
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/bootfloppy.txt b/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/bootfloppy.txt
new file mode 100644
index 0000000000..9e2cbe2bc3
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/bootfloppy.txt
@@ -0,0 +1,180 @@
+Building a Busybox Boot Floppy
+==============================
+
+This document describes how to buid a boot floppy using the following
+components:
+
+ - Linux Kernel (http://www.kernel.org)
+ - uClibc: C library (http://www.uclibc.org/)
+ - Busybox: Unix utilities (http://busybox.net/)
+ - Syslinux: bootloader (http://syslinux.zytor.com)
+
+It is based heavily on a paper presented by Erik Andersen at the 2001 Embedded
+Systems Conference.
+
+
+
+Building The Software Components
+--------------------------------
+
+Detailed instructions on how to build Busybox, uClibc, or a working Linux
+kernel are beyond the scope of this document. The following guidelines will
+help though:
+
+ - Stock Busybox from CVS or a tarball will work with no modifications to
+ any files. Just extract and go.
+ - Ditto uClibc.
+ - Your Linux kernel must include support for initrd or else the floppy
+ won't be able to mount it's root file system.
+
+If you require further information on building Busybox uClibc or Linux, please
+refer to the web pages and documentation for those individual programs.
+
+
+
+Making a Root File System
+-------------------------
+
+The following steps will create a root file system.
+
+ - Create an empty file that you can format as a filesystem:
+
+ dd if=/dev/zero of=rootfs bs=1k count=4000
+
+ - Set up the rootfs file we just created to be used as a loop device (may not
+ be necessary)
+
+ losetup /dev/loop0 rootfs
+
+ - Format the rootfs file with a filesystem:
+
+ mkfs.ext2 -F -i 2000 rootfs
+
+ - Mount the file on a mountpoint so we can place files in it:
+
+ mkdir loop
+ mount -o loop rootfs loop/
+
+ (you will probably need to be root to do this)
+
+ - Copy on the C library, the dynamic linking library, and other necessary
+ libraries. For this example, we copy the following files from the uClibc
+ tree:
+
+ mkdir loop/lib
+ (chdir to uClibc directory)
+ cp -a libc.so* uClibc*.so \
+ ld.so-1/d-link/ld-linux-uclibc.so* \
+ ld.so-1/libdl/libdl.so* \
+ crypt/libcrypt.so* \
+ (path to)loop/lib
+
+ - Install the Busybox binary and accompanying symlinks:
+
+ (chdir to busybox directory)
+ make CONFIG_PREFIX=(path to)loop/ install
+
+ - Make device files in /dev:
+
+ This can be done by running the 'mkdevs.sh' script. If you want the gory
+ details, you can read the script.
+
+ - Make necessary files in /etc:
+
+ For this, just cp -a the etc/ directory onto rootfs. Again, if you want
+ all the details, you can just look at the files in the dir.
+
+ - Unmount the rootfs from the mountpoint:
+
+ umount loop
+
+ - Compress it:
+
+ gzip -9 rootfs
+
+
+Making a SYSLINUX boot floppy
+-----------------------------
+
+The following steps will create the boot floppy.
+
+Note: You will need to have the mtools package installed beforehand.
+
+ - Insert a floppy in the drive and format it with an MSDOS filesystem:
+
+ mformat a:
+
+ (if the system doesn't know what device 'a:' is, look at /etc/mtools.conf)
+
+ - Run syslinux on the floppy:
+
+ syslinux -s /dev/fd0
+
+ (the -s stands for "safe, slow, and stupid" and should work better with
+ buggy BIOSes; it can be omitted)
+
+ - Put on a syslinux.cfg file:
+
+ mcopy syslinux.cfg a:
+
+ (more on syslinux.cfg below)
+
+ - Copy the root file system you made onto the MSDOS formatted floppy
+
+ mcopy rootfs.gz a:
+
+ - Build a linux kernel and copy it onto the disk with the filename 'linux'
+
+ mcopy bzImage a:linux
+
+
+Sample syslinux.cfg
+~~~~~~~~~~~~~~~~~~~
+
+The following simple syslinux.cfg file should work. You can tweak it if you
+like.
+
+----begin-syslinux.cfg---------------
+DEFAULT linux
+APPEND initrd=rootfs.gz root=/dev/ram0
+TIMEOUT 10
+PROMPT 1
+----end-syslinux.cfg---------------
+
+Some changes you could make to syslinux.cfg:
+
+ - This value is the number seconds it will wait before booting. You can set
+ the timeout to 0 (or omit) to boot instantly, or you can set it as high as
+ 10 to wait awhile.
+
+ - PROMPT can be set to 0 to disable the 'boot:' prompt.
+
+ - you can add this line to display the contents of a file as a welcome
+ message:
+
+ DISPLAY display.txt
+
+
+
+Additional Resources
+--------------------
+
+Other useful information on making a Linux bootfloppy is available at the
+following URLs:
+
+http://www.linuxdoc.org/HOWTO/Bootdisk-HOWTO/index.html
+http://www.linux-embedded.com/howto/Embedded-Linux-Howto.html
+http://linux-embedded.org/howto/LFS-HOWTO.html
+http://linux-embedded.org/pmhowto.html
+http://recycle.lbl.gov/~ldoolitt/embedded/ (Larry Doolittle's stuff)
+
+
+
+Possible TODOs
+--------------
+
+The following features that we might want to add later:
+
+ - support for additional filesystems besides ext2, i.e. minix
+ - different libc, static vs dynamic loading
+ - maybe using an alternate bootloader
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/display.txt b/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/display.txt
new file mode 100644
index 0000000000..399d326d94
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/display.txt
@@ -0,0 +1,4 @@
+
+This boot floppy is made with Busybox, uClibc, and the Linux kernel.
+Hit RETURN to boot or enter boot parameters at the prompt below.
+
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/etc/fstab b/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/etc/fstab
new file mode 100644
index 0000000000..ef14ca2cc0
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/etc/fstab
@@ -0,0 +1,2 @@
+proc /proc proc defaults 0 0
+
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/etc/init.d/rcS b/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/etc/init.d/rcS
new file mode 100755
index 0000000000..4f29b923f1
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/etc/init.d/rcS
@@ -0,0 +1,3 @@
+#! /bin/sh
+
+/bin/mount -a
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/etc/inittab b/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/etc/inittab
new file mode 100644
index 0000000000..eb3e979cee
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/etc/inittab
@@ -0,0 +1,5 @@
+::sysinit:/etc/init.d/rcS
+::respawn:-/bin/sh
+tty2::askfirst:-/bin/sh
+::ctrlaltdel:/bin/umount -a -r
+
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/etc/profile b/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/etc/profile
new file mode 100644
index 0000000000..8a7c77d784
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/etc/profile
@@ -0,0 +1,8 @@
+# /etc/profile: system-wide .profile file for the Bourne shells
+
+echo
+echo -n "Processing /etc/profile... "
+# no-op
+echo "Done"
+echo
+
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/mkdevs.sh b/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/mkdevs.sh
new file mode 100755
index 0000000000..03a1a8550e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/mkdevs.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+#
+# makedev.sh - creates device files for a busybox boot floppy image
+
+
+# we do our work in the dev/ directory
+if [ -z "$1" ]; then
+ echo "usage: `basename $0` path/to/dev/dir"
+ exit 1
+fi
+
+cd $1
+
+
+# miscellaneous one-of-a-kind stuff
+mknod console c 5 1
+mknod full c 1 7
+mknod kmem c 1 2
+mknod mem c 1 1
+mknod null c 1 3
+mknod port c 1 4
+mknod random c 1 8
+mknod urandom c 1 9
+mknod zero c 1 5
+ln -s /proc/kcore core
+
+# IDE HD devs
+# note: not going to bother creating all concievable partitions; you can do
+# that yourself as you need 'em.
+mknod hda b 3 0
+mknod hdb b 3 64
+mknod hdc b 22 0
+mknod hdd b 22 64
+
+# loop devs
+for i in `seq 0 7`; do
+ mknod loop$i b 7 $i
+done
+
+# ram devs
+for i in `seq 0 9`; do
+ mknod ram$i b 1 $i
+done
+ln -s ram1 ram
+
+# ttys
+mknod tty c 5 0
+for i in `seq 0 9`; do
+ mknod tty$i c 4 $i
+done
+
+# virtual console screen devs
+for i in `seq 0 9`; do
+ mknod vcs$i b 7 $i
+done
+ln -s vcs0 vcs
+
+# virtual console screen w/ attributes devs
+for i in `seq 0 9`; do
+ mknod vcsa$i b 7 $i
+done
+ln -s vcsa0 vcsa
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/mkrootfs.sh b/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/mkrootfs.sh
new file mode 100755
index 0000000000..5cdff21a0f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/mkrootfs.sh
@@ -0,0 +1,105 @@
+#!/bin/bash
+#
+# mkrootfs.sh - creates a root file system
+#
+
+# TODO: need to add checks here to verify that busybox, uClibc and bzImage
+# exist
+
+
+# command-line settable variables
+BUSYBOX_DIR=..
+UCLIBC_DIR=../../uClibc
+TARGET_DIR=./loop
+FSSIZE=4000
+CLEANUP=1
+MKFS='mkfs.ext2 -F'
+
+# don't-touch variables
+BASE_DIR=`pwd`
+
+
+while getopts 'b:u:s:t:Cm' opt
+do
+ case $opt in
+ b) BUSYBOX_DIR=$OPTARG ;;
+ u) UCLIBC_DIR=$OPTARG ;;
+ t) TARGET_DIR=$OPTARG ;;
+ s) FSSIZE=$OPTARG ;;
+ C) CLEANUP=0 ;;
+ m) MKFS='mkfs.minix' ;;
+ *)
+ echo "usage: `basename $0` [-bu]"
+ echo " -b DIR path to busybox direcory (default ..)"
+ echo " -u DIR path to uClibc direcory (default ../../uClibc)"
+ echo " -t DIR path to target direcory (default ./loop)"
+ echo " -s SIZE size of root filesystem in Kbytes (default 4000)"
+ echo " -C don't perform cleanup (umount target dir, gzip rootfs, etc.)"
+ echo " (this allows you to 'chroot loop/ /bin/sh' to test it)"
+ echo " -m use minix filesystem (default is ext2)"
+ exit 1
+ ;;
+ esac
+done
+
+
+
+
+# clean up from any previous work
+mount | grep -q loop
+[ $? -eq 0 ] && umount $TARGET_DIR
+[ -d $TARGET_DIR ] && rm -rf $TARGET_DIR/
+[ -f rootfs ] && rm -f rootfs
+[ -f rootfs.gz ] && rm -f rootfs.gz
+
+
+# prepare root file system and mount as loopback
+dd if=/dev/zero of=rootfs bs=1k count=$FSSIZE
+$MKFS -i 2000 rootfs
+mkdir $TARGET_DIR
+mount -o loop,exec rootfs $TARGET_DIR # must be root
+
+
+# install uClibc
+mkdir -p $TARGET_DIR/lib
+cd $UCLIBC_DIR
+make INSTALL_DIR=
+cp -a libc.so* $BASE_DIR/$TARGET_DIR/lib
+cp -a uClibc*.so $BASE_DIR/$TARGET_DIR/lib
+cp -a ld.so-1/d-link/ld-linux-uclibc.so* $BASE_DIR/$TARGET_DIR/lib
+cp -a ld.so-1/libdl/libdl.so* $BASE_DIR/$TARGET_DIR/lib
+cp -a crypt/libcrypt.so* $BASE_DIR/$TARGET_DIR/lib
+cd $BASE_DIR
+
+
+# install busybox and components
+cd $BUSYBOX_DIR
+make distclean
+make CC=$BASE_DIR/$UCLIBC_DIR/extra/gcc-uClibc/i386-uclibc-gcc
+make CONFIG_PREFIX=$BASE_DIR/$TARGET_DIR install
+cd $BASE_DIR
+
+
+# make files in /dev
+mkdir $TARGET_DIR/dev
+./mkdevs.sh $TARGET_DIR/dev
+
+
+# make files in /etc
+cp -a etc $TARGET_DIR
+ln -s /proc/mounts $TARGET_DIR/etc/mtab
+
+
+# other miscellaneous setup
+mkdir $TARGET_DIR/initrd
+mkdir $TARGET_DIR/proc
+
+
+# Done. Maybe do cleanup.
+if [ $CLEANUP -eq 1 ]
+then
+ umount $TARGET_DIR
+ rmdir $TARGET_DIR
+ gzip -9 rootfs
+fi
+
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/mksyslinux.sh b/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/mksyslinux.sh
new file mode 100755
index 0000000000..e254173535
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/mksyslinux.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+#
+# Formats a floppy to use Syslinux
+
+dummy=""
+
+
+# need to have mtools installed
+if [ -z `which mformat` -o -z `which mcopy` ]; then
+ echo "You must have the mtools package installed to run this script"
+ exit 1
+fi
+
+
+# need an arg for the location of the kernel
+if [ -z "$1" ]; then
+ echo "usage: `basename $0` path/to/linux/kernel"
+ exit 1
+fi
+
+
+# need to have a root file system built
+if [ ! -f rootfs.gz ]; then
+ echo "You need to have a rootfs built first."
+ echo "Hit RETURN to make one now or Control-C to quit."
+ read dummy
+ ./mkrootfs.sh
+fi
+
+
+# prepare the floppy
+echo "Please insert a blank floppy in the drive and press RETURN to format"
+echo "(WARNING: All data will be erased! Hit Control-C to abort)"
+read dummy
+
+echo "Formatting the floppy..."
+mformat a:
+echo "Making it bootable with Syslinux..."
+syslinux -s /dev/fd0
+echo "Copying Syslinux configuration files..."
+mcopy syslinux.cfg display.txt a:
+echo "Copying root filesystem file..."
+mcopy rootfs.gz a:
+# XXX: maybe check for "no space on device" errors here
+echo "Copying linux kernel..."
+mcopy $1 a:linux
+# XXX: maybe check for "no space on device" errors here too
+echo "Finished: boot floppy created"
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/quickstart.txt b/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/quickstart.txt
new file mode 100644
index 0000000000..0d80908247
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/quickstart.txt
@@ -0,0 +1,15 @@
+Quickstart on making the Busybox boot-floppy:
+
+ 1) Download Busybox and uClibc from CVS or tarballs. Make sure they share a
+ common parent directory. (i.e. busybox/ and uclibc/ are both right off of
+ /tmp, or wherever.)
+
+ 2) Build a Linux kernel. Make sure you include support for initrd.
+
+ 3) Put a floppy in the drive. Make sure it is a floppy you don't care about
+ because the contents will be overwritten.
+
+ 4) As root, type ./mksyslinux.sh path/to/linux/kernel from this directory.
+ Wait patiently while the magic happens.
+
+ 5) Boot up on the floppy.
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/syslinux.cfg b/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/syslinux.cfg
new file mode 100644
index 0000000000..fa2677ca8d
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/bootfloppy/syslinux.cfg
@@ -0,0 +1,7 @@
+display display.txt
+default linux
+timeout 10
+prompt 1
+label linux
+ kernel linux
+ append initrd=rootfs.gz root=/dev/ram0
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/busybox.spec b/cleopatre/busybox-1.11.1-spc300/examples/busybox.spec
new file mode 100644
index 0000000000..494eed9413
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/busybox.spec
@@ -0,0 +1,44 @@
+%define name busybox
+%define epoch 0
+%define version 0.61.pre
+%define release %(date -I | sed -e 's/-/_/g')
+%define serial 1
+
+Name: %{name}
+#Epoch: %{epoch}
+Version: %{version}
+Release: %{release}
+Serial: %{serial}
+Copyright: GPL
+Group: System/Utilities
+Summary: BusyBox is a tiny suite of Unix utilities in a multi-call binary.
+URL: http://busybox.net/
+Source: ftp://busybox.net/busybox/%{name}-%{version}.tar.gz
+Buildroot: /var/tmp/%{name}-%{version}
+Packager : Erik Andersen <andersen@codepoet.org>
+
+%Description
+BusyBox combines tiny versions of many common UNIX utilities into a single
+small executable. It provides minimalist replacements for most of the utilities
+you usually find in fileutils, shellutils, findutils, textutils, grep, gzip,
+tar, etc. BusyBox provides a fairly complete POSIX environment for any small
+or emdedded system. The utilities in BusyBox generally have fewer options then
+their full featured GNU cousins; however, the options that are provided behave
+very much like their GNU counterparts.
+
+%Prep
+%setup -q -n %{name}-%{version}
+
+%Build
+make
+
+%Install
+rm -rf $RPM_BUILD_ROOT
+make CONFIG_PREFIX=$RPM_BUILD_ROOT install
+
+%Clean
+rm -rf $RPM_BUILD_ROOT
+
+%Files
+%defattr(-,root,root)
+/
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/depmod b/cleopatre/busybox-1.11.1-spc300/examples/depmod
new file mode 100644
index 0000000000..d8c4cc5aa9
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/depmod
@@ -0,0 +1,57 @@
+#!/bin/sh
+#
+# Simple depmod, use to generate modprobe.conf
+#
+# Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
+#
+# Licensed under GPLv2
+#
+
+local BASE="${1:-/usr/lib/modules}"
+
+find "$BASE" -name '*.ko.gz' | while read I ; do
+ N=`basename "$I" '.ko.gz'`
+ echo -n "@$N"
+ zcat "$I" | strings | grep '^depends=' | sed -e 's/^depends=$//' -e 's/^depends=/,/' -e 's/,/ @/g'
+done | awk '
+{
+ # modules which has no dependencies are resolved
+ if ( NF == 1 ) { res[$1] = ""; next }
+ # others have to be resolved based on those which already resolved
+ i = $1; $1 = ""; deps[i] = $0; ++ndeps
+}
+END {
+ # resolve implicit dependencies
+ while ( ndeps ) for (mod in deps) {
+ if ( index(deps[mod], "@") > 0 ) {
+ $0 = deps[mod]
+ for ( i=1; i<=NF; ++i ) {
+ if ( substr($i,1,1) == "@" ) {
+ if ( $i in res ) {
+ $i = res[$i] " " substr($i,2)
+ }
+ }
+ }
+ deps[mod] = $0
+ } else {
+ res[mod] = deps[mod]
+ delete deps[mod]
+ --ndeps
+ }
+ }
+
+ # output dependencies in modules.dep format
+ for ( mod in res ) {
+ $0 = res[mod]
+ s = ""
+ delete a
+ for ( i=1; i<=NF; ++i ) {
+ if ( ! ($i in a) ) {
+ a[$i] = $i
+ s = " ," $i s
+ }
+ }
+ print "," substr(mod,2) ":" s
+ }
+}
+' | sort | sed -r -e "s!,([^,: ]*)!/usr/lib/modules/\\1.ko.gz!g"
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/depmod.pl b/cleopatre/busybox-1.11.1-spc300/examples/depmod.pl
new file mode 100755
index 0000000000..c356d27151
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/depmod.pl
@@ -0,0 +1,292 @@
+#!/usr/bin/perl -w
+# vi: set sw=4 ts=4:
+# Copyright (c) 2001 David Schleef <ds@schleef.org>
+# Copyright (c) 2001 Erik Andersen <andersen@codepoet.org>
+# Copyright (c) 2001 Stuart Hughes <seh@zee2.com>
+# Copyright (c) 2002 Steven J. Hill <shill@broadcom.com>
+# Copyright (c) 2006 Freescale Semiconductor, Inc <stuarth@freescale.com>
+#
+# History:
+# March 2006: Stuart Hughes <stuarth@freescale.com>.
+# Significant updates, including implementing the '-F' option
+# and adding support for 2.6 kernels.
+
+# This program is free software; you can redistribute it and/or modify it
+# under the same terms as Perl itself.
+use Getopt::Long;
+use File::Find;
+use strict;
+
+# Set up some default values
+my $kdir="";
+my $basedir="";
+my $kernel="";
+my $kernelsyms="";
+my $symprefix="";
+my $stdout=0;
+my $verbose=0;
+my $help=0;
+my $nm = $ENV{'NM'} || "nm";
+
+# more globals
+my (@liblist) = ();
+my $exp = {};
+my $dep = {};
+my $mod = {};
+
+my $usage = <<TXT;
+$0 -b basedir { -k <vmlinux> | -F <System.map> } [options]...
+ Where:
+ -h --help : Show this help screen
+ -b --basedir : Modules base directory (e.g /lib/modules/<2.x.y>)
+ -k --kernel : Kernel binary for the target (e.g. vmlinux)
+ -F --kernelsyms : Kernel symbol file (e.g. System.map)
+ -n --stdout : Write to stdout instead of <basedir>/modules.dep
+ -v --verbose : Print out lots of debugging stuff
+ -P --symbol-prefix : Symbol prefix
+TXT
+
+# get command-line options
+GetOptions(
+ "help|h" => \$help,
+ "basedir|b=s" => \$basedir,
+ "kernel|k=s" => \$kernel,
+ "kernelsyms|F=s" => \$kernelsyms,
+ "stdout|n" => \$stdout,
+ "verbose|v" => \$verbose,
+ "symbol-prefix|P=s" => \$symprefix,
+);
+
+die $usage if $help;
+die $usage unless $basedir && ( $kernel || $kernelsyms );
+die "can't use both -k and -F\n\n$usage" if $kernel && $kernelsyms;
+
+# Strip any trailing or multiple slashes from basedir
+$basedir =~ s-(/)\1+-/-g;
+
+# The base directory should contain /lib/modules somewhere
+if($basedir !~ m-/lib/modules-) {
+ warn "WARNING: base directory does not match ..../lib/modules\n";
+}
+
+# if no kernel version is contained in the basedir, try to find one
+if($basedir !~ m-/lib/modules/\d\.\d-) {
+ opendir(BD, $basedir) or die "can't open basedir $basedir : $!\n";
+ foreach ( readdir(BD) ) {
+ next if /^\.\.?$/;
+ next unless -d "$basedir/$_";
+ warn "dir = $_\n" if $verbose;
+ if( /^\d\.\d/ ) {
+ $kdir = $_;
+ warn("Guessed module directory as $basedir/$kdir\n");
+ last;
+ }
+ }
+ closedir(BD);
+ die "Cannot find a kernel version under $basedir\n" unless $kdir;
+ $basedir = "$basedir/$kdir";
+}
+
+# Find the list of .o or .ko files living under $basedir
+warn "**** Locating all modules\n" if $verbose;
+find sub {
+ my $file;
+ if ( -f $_ && ! -d $_ ) {
+ $file = $File::Find::name;
+ if ( $file =~ /\.k?o$/ ) {
+ push(@liblist, $file);
+ warn "$file\n" if $verbose;
+ }
+ }
+}, $basedir;
+warn "**** Finished locating modules\n" if $verbose;
+
+foreach my $obj ( @liblist ){
+ # turn the input file name into a target tag name
+ my ($tgtname) = $obj =~ m-(/lib/modules/.*)$-;
+
+ warn "\nMODULE = $tgtname\n" if $verbose;
+
+ # get a list of symbols
+ my @output=`$nm $obj`;
+
+ build_ref_tables($tgtname, \@output, $exp, $dep);
+}
+
+
+# vmlinux is a special name that is only used to resolve symbols
+my $tgtname = 'vmlinux';
+my @output = $kernelsyms ? `cat $kernelsyms` : `$nm $kernel`;
+warn "\nMODULE = $tgtname\n" if $verbose;
+build_ref_tables($tgtname, \@output, $exp, $dep);
+
+# resolve the dependencies for each module
+# reduce dependencies: remove unresolvable and resolved from vmlinux/System.map
+# remove duplicates
+foreach my $module (keys %$dep) {
+ warn "reducing module: $module\n" if $verbose;
+ $mod->{$module} = {};
+ foreach (@{$dep->{$module}}) {
+ if( $exp->{$_} ) {
+ warn "resolved symbol $_ in file $exp->{$_}\n" if $verbose;
+ next if $exp->{$_} =~ /vmlinux/;
+ $mod->{$module}{$exp->{$_}} = 1;
+ } else {
+ warn "unresolved symbol $_ in file $module\n";
+ }
+ }
+}
+
+# figure out where the output should go
+if ($stdout == 0) {
+ open(STDOUT, ">$basedir/modules.dep")
+ or die "cannot open $basedir/modules.dep: $!";
+}
+my $kseries = $basedir =~ m,/2\.6\.[^/]*, ? '2.6' : '2.4';
+
+foreach my $module ( keys %$mod ) {
+ if($kseries eq '2.4') {
+ print "$module:\t";
+ my @sorted = sort bydep keys %{$mod->{$module}};
+ print join(" \\\n\t",@sorted);
+ print "\n\n";
+ } else {
+ print "$module: ";
+ my @sorted = sort bydep keys %{$mod->{$module}};
+ print join(" ",@sorted);
+ print "\n";
+ }
+}
+
+
+sub build_ref_tables
+{
+ my ($name, $sym_ar, $exp, $dep) = @_;
+
+ my $ksymtab = grep m/ __ksymtab/, @$sym_ar;
+
+ # gather the exported symbols
+ if($ksymtab){
+ # explicitly exported
+ foreach ( @$sym_ar ) {
+ / __ksymtab_(.*)$/ and do {
+ warn "sym = $1\n" if $verbose;
+ $exp->{$1} = $name;
+ };
+ }
+ } else {
+ # exporting all symbols
+ foreach ( @$sym_ar ) {
+ / [ABCDGRSTW] (.*)$/ and do {
+ warn "syma = $1\n" if $verbose;
+ $exp->{$1} = $name;
+ };
+ }
+ }
+
+ # this takes makes sure modules with no dependencies get listed
+ push @{$dep->{$name}}, $symprefix . 'printk' unless $name eq 'vmlinux';
+
+ # gather the unresolved symbols
+ foreach ( @$sym_ar ) {
+ !/ __this_module/ && / U (.*)$/ and do {
+ warn "und = $1\n" if $verbose;
+ push @{$dep->{$name}}, $1;
+ };
+ }
+}
+
+sub bydep
+{
+ foreach my $f ( keys %{$mod->{$b}} ) {
+ if($f eq $a) {
+ return 1;
+ }
+ }
+ return -1;
+}
+
+
+
+__END__
+
+=head1 NAME
+
+depmod.pl - a cross platform script to generate kernel module
+dependency lists (modules.conf) which can then be used by modprobe
+on the target platform.
+
+It supports Linux 2.4 and 2.6 styles of modules.conf (auto-detected)
+
+=head1 SYNOPSIS
+
+depmod.pl [OPTION]... [basedir]...
+
+Example:
+
+ depmod.pl -F linux/System.map -b target/lib/modules/2.6.11
+
+=head1 DESCRIPTION
+
+The purpose of this script is to automagically generate a list of of kernel
+module dependencies. This script produces dependency lists that should be
+identical to the depmod program from the modutils package. Unlike the depmod
+binary, however, depmod.pl is designed to be run on your host system, not
+on your target system.
+
+This script was written by David Schleef <ds@schleef.org> to be used in
+conjunction with the BusyBox modprobe applet.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-h --help>
+
+This displays the help message.
+
+=item B<-b --basedir>
+
+The base directory uner which the target's modules will be found. This
+defaults to the /lib/modules directory.
+
+If you don't specify the kernel version, this script will search for
+one under the specified based directory and use the first thing that
+looks like a kernel version.
+
+=item B<-k --kernel>
+
+Kernel binary for the target (vmlinux). You must either supply a kernel binary
+or a kernel symbol file (using the -F option).
+
+=item B<-F --kernelsyms>
+
+Kernel symbol file for the target (System.map).
+
+=item B<-n --stdout>
+
+Write to stdout instead of modules.dep
+kernel binary for the target (using the -k option).
+
+=item B<--verbose>
+
+Verbose (debug) output
+
+=back
+
+=head1 COPYRIGHT AND LICENSE
+
+ Copyright (c) 2001 David Schleef <ds@schleef.org>
+ Copyright (c) 2001 Erik Andersen <andersen@codepoet.org>
+ Copyright (c) 2001 Stuart Hughes <seh@zee2.com>
+ Copyright (c) 2002 Steven J. Hill <shill@broadcom.com>
+ Copyright (c) 2006 Freescale Semiconductor, Inc <stuarth@freescale.com>
+
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl itself.
+
+=head1 AUTHOR
+
+David Schleef <ds@schleef.org>
+
+=cut
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/devfsd.conf b/cleopatre/busybox-1.11.1-spc300/examples/devfsd.conf
new file mode 100644
index 0000000000..10f1c87889
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/devfsd.conf
@@ -0,0 +1,133 @@
+# Sample /etc/devfsd.conf configuration file.
+# Richard Gooch <rgooch@atnf.csiro.au> 17-FEB-2002
+#
+# adapted for busybox devfsd implementation by Tito <farmatito@tiscali.it>
+#
+# Enable full compatibility mode for old device names. You may comment these
+# out if you don't use the old device names. Make sure you know what you're
+# doing!
+REGISTER .* MKOLDCOMPAT
+UNREGISTER .* RMOLDCOMPAT
+
+# You may comment out the above and uncomment the following if you've
+# configured your system to use the original "new" devfs names or the really
+# new names
+#REGISTER ^vc/ MKOLDCOMPAT
+#UNREGISTER ^vc/ RMOLDCOMPAT
+#REGISTER ^pty/ MKOLDCOMPAT
+#UNREGISTER ^pty/ RMOLDCOMPAT
+#REGISTER ^misc/ MKOLDCOMPAT
+#UNREGISTER ^misc/ RMOLDCOMPAT
+
+# You may comment these out if you don't use the original "new" names
+REGISTER .* MKNEWCOMPAT
+UNREGISTER .* RMNEWCOMPAT
+
+# Enable module autoloading. You may comment this out if you don't use
+# autoloading
+# Supported by busybox when CONFIG_DEVFSD_MODLOAD is set.
+# This actually doesn't work with busybox modutils but needs
+# the real modutils' modprobe
+LOOKUP .* MODLOAD
+
+# Uncomment the following if you want to set the group to "tty" for the
+# pseudo-tty devices. This is necessary so that mesg(1) can later be used to
+# enable/disable talk requests and wall(1) messages.
+REGISTER ^pty/s.* PERMISSIONS -1.tty 0600
+#REGISTER ^pts/.* PERMISSIONS -1.tty 0600
+
+# Restoring /dev/log on startup would trigger the minilogd/initlog deadlock
+# (minilogd falsely assuming syslogd has been started).
+REGISTER ^log$ IGNORE
+CREATE ^log$ IGNORE
+CHANGE ^log$ IGNORE
+DELETE ^log$ IGNORE
+
+#
+# Uncomment this if you want permissions to be saved and restored
+# Do not do this for pseudo-terminal devices
+REGISTER ^pt[sy] IGNORE
+CREATE ^pt[sy] IGNORE
+CHANGE ^pt[sy] IGNORE
+DELETE ^pt[sy] IGNORE
+REGISTER .* COPY /lib/dev-state/$devname $devpath
+CREATE .* COPY $devpath /lib/dev-state/$devname
+CHANGE .* COPY $devpath /lib/dev-state/$devname
+#DELETE .* CFUNCTION GLOBAL unlink /lib/dev-state/$devname
+# Busybox
+DELETE .* EXECUTE /bin/rm -f /lib/dev-state/$devname
+
+RESTORE /lib/dev-state
+
+#
+# Uncomment this if you want the old /dev/cdrom symlink
+#REGISTER ^cdroms/cdrom0$ CFUNCTION GLOBAL mksymlink $devname cdrom
+#UNREGISTER ^cdroms/cdrom0$ CFUNCTION GLOBAL unlink cdrom
+# busybox
+REGISTER ^cdroms/cdrom0$ EXECUTE /bin/ln -sf $devname cdrom
+UNREGISTER ^cdroms/cdrom0$ EXECUTE /bin/rm -f cdrom
+
+#REGISTER ^v4l/video0$ CFUNCTION GLOBAL mksymlink v4l/video0 video
+#UNREGISTER ^v4l/video0$ CFUNCTION GLOBAL unlink video
+#REGISTER ^radio0$ CFUNCTION GLOBAL mksymlink radio0 radio
+#UNREGISTER ^radio0$ CFUNCTION GLOBAL unlink radio
+# Busybox
+REGISTER ^v4l/video0$ EXECUTE /bin/ln -sf v4l/video0 video
+UNREGISTER ^v4l/video0$ EXECUTE /bin/rm -f video
+REGISTER ^radio0$ EXECUTE /bin/ln -sf radio0 radio
+UNREGISTER ^radio0$ EXECUTE /bin/rm -f radio
+
+# ALSA stuff
+#LOOKUP snd MODLOAD ACTION snd
+
+# Uncomment this to let PAM manage devfs
+# Not supported by busybox
+#REGISTER .* CFUNCTION /lib/security/pam_console_apply_devfsd.so pam_console_apply_single $devpath
+
+# Uncomment this to manage USB mouse
+# Not supported by busybox
+#REGISTER ^input/mouse0$ CFUNCTION GLOBAL mksymlink $devname usbmouse
+#UNREGISTER ^input/mouse0$ CFUNCTION GLOBAL unlink usbmouse
+# Busybox
+#REGISTER ^input/mouse0$ EXECUTE /bin/ln -sf $devname usbmouse
+#UNREGISTER ^input/mouse0$ EXECUTE /bin/rm -f usbmouse
+# Not supported by busybox
+#REGISTER ^input/mice$ CFUNCTION GLOBAL mksymlink $devname usbmouse
+#UNREGISTER ^input/mice$ CFUNCTION GLOBAL unlink usbmouse
+# Busybox
+REGISTER ^input/mice$ EXECUTE /bin/ln -sf $devname usbmouse
+UNREGISTER ^input/mice$ EXECUTE /bin/rm -f usbmouse
+
+# If you have removable media and want to force media revalidation when looking
+# up new or old compatibility names, uncomment the following lines
+# SCSI NEWCOMPAT /dev/sd/* names
+LOOKUP ^(sd/c[0-9]+b[0-9]+t[0-9]+u[0-9]+)p[0-9]+$ EXECUTE /bin/dd if=$mntpnt/\1 of=/dev/null count=1
+# SCSI OLDCOMPAT /dev/sd?? names
+LOOKUP ^(sd[a-z]+)[0-9]+$ EXECUTE /bin/dd if=$mntpnt/\1 of=/dev/null count=1
+# IDE NEWCOMPAT /dev/ide/hd/* names
+LOOKUP ^(ide/hd/c[0-9]+b[0-9]+t[0-9]+u[0-9]+)p[0-9]+$ EXECUTE /bin/dd if=$mntpnt/\1 of=/dev/null count=1
+# IDE OLDCOMPAT /dev/hd?? names
+LOOKUP ^(hd[a-z])[0-9]+$ EXECUTE /bin/dd if=$mntpnt/\1 of=/dev/null count=1
+# IDE-SCSI NEWCOMPAT /dev/sd/* names
+#LOOKUP ^(sd/c[0-9]+b[0-9]+t[0-9]+u[0-9]+)p[0-9]+$ EXECUTE /bin/dd if=$mntpnt/\1 of=/dev/null count=1
+#SCSI OLDCOMPAT /dev/scd? names
+LOOKUP ^(scd+)[0-9]+$ EXECUTE /bin/dd if=$mntpnt/\1 of=/dev/null count=1
+
+
+REGISTER ^dvb/card[0-9]+/[^/]+$ PERMISSIONS root.video 0660
+# Not supported by busybox
+#REGISTER ^dvb/card([0-9]+)/([^/0-9]*)[0-9]+$ CFUNCTION GLOBAL mksymlink /dev/$devname ost/\2\1
+#UNREGISTER ^dvb/card([0-9]+)/([^/0-9]*)[0-9]+$ CFUNCTION GLOBAL unlink ost/\2\1
+# Busybox
+REGISTER ^dvb/card([0-9]+)/([^/0-9]*)[0-9]+$ EXECUTE /bin/ln -sf /dev/$devname ost/\2\1
+UNREGISTER ^dvb/card([0-9]+)/([^/0-9]*)[0-9]+$ EXECUTE /bin/rm -f ost/\2\1
+
+# Include package-generated files from /etc/devfs/conf.d
+# Supported by busybox
+# INCLUDE /etc/devfs/conf.d/
+INCLUDE /etc/devfs/busybox/
+# Busybox: just for testing
+#INCLUDE /etc/devfs/nothing/
+#INCLUDE /etc/devfs/nothing/nothing
+#OPTIONAL_INCLUDE /etc/devfs/nothing/
+#OPTIONAL_INCLUDE /etc/devfs/nothing/nothing
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/dnsd.conf b/cleopatre/busybox-1.11.1-spc300/examples/dnsd.conf
new file mode 100644
index 0000000000..8af622b027
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/dnsd.conf
@@ -0,0 +1 @@
+thebox 192.168.1.5
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/inetd.conf b/cleopatre/busybox-1.11.1-spc300/examples/inetd.conf
new file mode 100644
index 0000000000..ca7e3d8e12
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/inetd.conf
@@ -0,0 +1,73 @@
+# /etc/inetd.conf: see inetd(8) for further informations.
+#
+# Internet server configuration database
+#
+#
+# If you want to disable an entry so it isn't touched during
+# package updates just comment it out with a single '#' character.
+#
+# If you make changes to this file, either reboot your machine or
+# send the inetd process a HUP signal:
+# Do a "ps x" as root and look up the pid of inetd. Then do a
+# kill -HUP <pid of inetd>
+# inetd will re-read this file whenever it gets that signal.
+# <service_name> <sock_type> <proto> <flags> <user> <server_path> <args>
+#
+#:INTERNAL: Internal services
+# It is generally considered safer to keep these off.
+echo stream tcp nowait root internal
+echo dgram udp wait root internal
+#discard stream tcp nowait root internal
+#discard dgram udp wait root internal
+daytime stream tcp nowait root internal
+daytime dgram udp wait root internal
+#chargen stream tcp nowait root internal
+#chargen dgram udp wait root internal
+time stream tcp nowait root internal
+time dgram udp wait root internal
+
+# These are standard services.
+#
+#ftp stream tcp nowait root /usr/sbin/tcpd in.ftpd
+#telnet stream tcp nowait root /sbin/telnetd /sbin/telnetd
+#nntp stream tcp nowait root tcpd in.nntpd
+#smtp stream tcp nowait root tcpd sendmail -v
+#
+# Shell, login, exec and talk are BSD protocols.
+#
+# If you run an ntalk daemon (such as netkit-ntalk) on the old talk
+# port, that is, "talk" as opposed to "ntalk", it won't work and may
+# cause certain broken talk clients to malfunction.
+#
+# The talkd from netkit-ntalk 0.12 and higher, however, can speak the
+# old talk protocol and can be used safely.
+#
+#shell stream tcp nowait root /usr/sbin/tcpd in.rshd -L
+#login stream tcp nowait root /usr/sbin/tcpd in.rlogind -L
+#exec stream tcp nowait root /usr/sbin/tcpd in.rexecd
+#talk dgram udp wait root /usr/sbin/tcpd in.talkd
+#ntalk dgram udp wait root /usr/sbin/tcpd in.talkd
+#
+# Pop et al
+# Leave these off unless you're using them.
+#pop2 stream tcp nowait root /usr/sbin/tcpd in.pop2d
+#pop3 stream tcp nowait root /usr/sbin/tcpd in.pop3d
+#
+# The Internet UUCP service.
+# uucp stream tcp nowait uucp /usr/sbin/tcpd /usr/lib/uucp/uucico -l
+#
+# Tftp service is provided primarily for booting. Most sites
+# run this only on machines acting as "boot servers." If you don't
+# need it, don't use it.
+#
+#tftp dgram udp wait nobody /usr/sbin/tcpd in.tftpd
+#bootps dgram udp wait root /usr/sbin/in.bootpd in.bootpd
+#
+# Finger, systat and netstat give out user information which may be
+# valuable to potential "system crackers." Many sites choose to disable
+# some or all of these services to improve security.
+#
+#finger stream tcp nowait nobody /usr/sbin/tcpd in.fingerd -w
+#systat stream tcp nowait nobody /usr/sbin/tcpd /bin/ps -auwwx
+#netstat stream tcp nowait root /bin/netstat /bin/netstat -a
+#ident stream tcp nowait root /usr/sbin/in.identd in.identd
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/inittab b/cleopatre/busybox-1.11.1-spc300/examples/inittab
new file mode 100644
index 0000000000..5f2af8724b
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/inittab
@@ -0,0 +1,90 @@
+# /etc/inittab init(8) configuration for BusyBox
+#
+# Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+#
+#
+# Note, BusyBox init doesn't support runlevels. The runlevels field is
+# completely ignored by BusyBox init. If you want runlevels, use sysvinit.
+#
+#
+# Format for each entry: <id>:<runlevels>:<action>:<process>
+#
+# <id>: WARNING: This field has a non-traditional meaning for BusyBox init!
+#
+# The id field is used by BusyBox init to specify the controlling tty for
+# the specified process to run on. The contents of this field are
+# appended to "/dev/" and used as-is. There is no need for this field to
+# be unique, although if it isn't you may have strange results. If this
+# field is left blank, it is completely ignored. Also note that if
+# BusyBox detects that a serial console is in use, then all entries
+# containing non-empty id fields will be ignored. BusyBox init does
+# nothing with utmp. We don't need no stinkin' utmp.
+#
+# <runlevels>: The runlevels field is completely ignored.
+#
+# <action>: Valid actions include: sysinit, respawn, askfirst, wait, once,
+# restart, ctrlaltdel, and shutdown.
+#
+# Note: askfirst acts just like respawn, but before running the specified
+# process it displays the line "Please press Enter to activate this
+# console." and then waits for the user to press enter before starting
+# the specified process.
+#
+# Note: unrecognised actions (like initdefault) will cause init to emit
+# an error message, and then go along with its business.
+#
+# <process>: Specifies the process to be executed and it's command line.
+#
+# Note: BusyBox init works just fine without an inittab. If no inittab is
+# found, it has the following default behavior:
+# ::sysinit:/etc/init.d/rcS
+# ::askfirst:/bin/sh
+# ::ctrlaltdel:/sbin/reboot
+# ::shutdown:/sbin/swapoff -a
+# ::shutdown:/bin/umount -a -r
+# ::restart:/sbin/init
+#
+# if it detects that /dev/console is _not_ a serial console, it will
+# also run:
+# tty2::askfirst:/bin/sh
+# tty3::askfirst:/bin/sh
+# tty4::askfirst:/bin/sh
+#
+# Boot-time system configuration/initialization script.
+# This is run first except when booting in single-user mode.
+#
+::sysinit:/etc/init.d/rcS
+
+# /bin/sh invocations on selected ttys
+#
+# Note below that we prefix the shell commands with a "-" to indicate to the
+# shell that it is supposed to be a login shell. Normally this is handled by
+# login, but since we are bypassing login in this case, BusyBox lets you do
+# this yourself...
+#
+# Start an "askfirst" shell on the console (whatever that may be)
+::askfirst:-/bin/sh
+# Start an "askfirst" shell on /dev/tty2-4
+tty2::askfirst:-/bin/sh
+tty3::askfirst:-/bin/sh
+tty4::askfirst:-/bin/sh
+
+# /sbin/getty invocations for selected ttys
+tty4::respawn:/sbin/getty 38400 tty5
+tty5::respawn:/sbin/getty 38400 tty6
+
+# Example of how to put a getty on a serial line (for a terminal)
+#::respawn:/sbin/getty -L ttyS0 9600 vt100
+#::respawn:/sbin/getty -L ttyS1 9600 vt100
+#
+# Example how to put a getty on a modem line.
+#::respawn:/sbin/getty 57600 ttyS2
+
+# Stuff to do when restarting the init process
+::restart:/sbin/init
+
+# Stuff to do before rebooting
+::ctrlaltdel:/sbin/reboot
+::shutdown:/bin/umount -a -r
+::shutdown:/sbin/swapoff -a
+
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/mk2knr.pl b/cleopatre/busybox-1.11.1-spc300/examples/mk2knr.pl
new file mode 100755
index 0000000000..1259b8436c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/mk2knr.pl
@@ -0,0 +1,84 @@
+#!/usr/bin/perl -w
+#
+# @(#) mk2knr.pl - generates a perl script that converts lexemes to K&R-style
+#
+# How to use this script:
+# - In the busybox directory type 'examples/mk2knr.pl files-to-convert'
+# - Review the 'convertme.pl' script generated and remove / edit any of the
+# substitutions in there (please especially check for false positives)
+# - Type './convertme.pl same-files-as-before'
+# - Compile and see if it works
+#
+# BUGS: This script does not ignore strings inside comments or strings inside
+# quotes (it probably should).
+
+# set this to something else if you want
+$convertme = 'convertme.pl';
+
+# internal-use variables (don't touch)
+$convert = 0;
+%converted = ();
+
+# if no files were specified, print usage
+die "usage: $0 file.c | file.h\n" if scalar(@ARGV) == 0;
+
+# prepare the "convert me" file
+open(CM, ">$convertme") or die "convertme.pl $!";
+print CM "#!/usr/bin/perl -p -i\n\n";
+
+# process each file passed on the cmd line
+while (<>) {
+
+ # if the line says "getopt" in it anywhere, we don't want to muck with it
+ # because option lists tend to include strings like "cxtzvOf:" which get
+ # matched by the "check for mixed case" regexps below
+ next if /getopt/;
+
+ # tokenize the string into just the variables
+ while (/([a-zA-Z_][a-zA-Z0-9_]*)/g) {
+ $var = $1;
+
+ # ignore the word "BusyBox"
+ next if ($var =~ /BusyBox/);
+
+ # this checks for javaStyle or szHungarianNotation
+ $convert++ if ($var =~ /^[a-z]+[A-Z][a-z]+/);
+
+ # this checks for PascalStyle
+ $convert++ if ($var =~ /^[A-Z][a-z]+[A-Z][a-z]+/);
+
+ # if we want to add more checks, we can add 'em here, but the above
+ # checks catch "just enough" and not too much, so prolly not.
+
+ if ($convert) {
+ $convert = 0;
+
+ # skip ahead if we've already dealt with this one
+ next if ($converted{$var});
+
+ # record that we've dealt with this var
+ $converted{$var} = 1;
+
+ print CM "s/\\b$var\\b/"; # more to come in just a minute
+
+ # change the first letter to lower-case
+ $var = lcfirst($var);
+
+ # put underscores before all remaining upper-case letters
+ $var =~ s/([A-Z])/_$1/g;
+
+ # now change the remaining characters to lower-case
+ $var = lc($var);
+
+ print CM "$var/g;\n";
+ }
+ }
+}
+
+# tidy up and make the $convertme script executable
+close(CM);
+chmod 0755, $convertme;
+
+# print a helpful help message
+print "Done. Scheduled name changes are in $convertme.\n";
+print "Please review/modify it and then type ./$convertme to do the search & replace.\n";
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/udhcp/sample.bound b/cleopatre/busybox-1.11.1-spc300/examples/udhcp/sample.bound
new file mode 100755
index 0000000000..2a95d8b7d5
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/udhcp/sample.bound
@@ -0,0 +1,31 @@
+#!/bin/sh
+# Sample udhcpc renew script
+
+RESOLV_CONF="/etc/udhcpc/resolv.conf"
+
+[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
+[ -n "$subnet" ] && NETMASK="netmask $subnet"
+
+/sbin/ifconfig $interface $ip $BROADCAST $NETMASK
+
+if [ -n "$router" ]
+then
+ echo "deleting routers"
+ while /sbin/route del default gw 0.0.0.0 dev $interface
+ do :
+ done
+
+ metric=0
+ for i in $router
+ do
+ /sbin/route add default gw $i dev $interface metric $((metric++))
+ done
+fi
+
+echo -n > $RESOLV_CONF
+[ -n "$domain" ] && echo domain $domain >> $RESOLV_CONF
+for i in $dns
+do
+ echo adding dns $i
+ echo nameserver $i >> $RESOLV_CONF
+done \ No newline at end of file
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/udhcp/sample.deconfig b/cleopatre/busybox-1.11.1-spc300/examples/udhcp/sample.deconfig
new file mode 100755
index 0000000000..b221bcf12b
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/udhcp/sample.deconfig
@@ -0,0 +1,4 @@
+#!/bin/sh
+# Sample udhcpc deconfig script
+
+/sbin/ifconfig $interface 0.0.0.0
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/udhcp/sample.nak b/cleopatre/busybox-1.11.1-spc300/examples/udhcp/sample.nak
new file mode 100755
index 0000000000..f4d08e6691
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/udhcp/sample.nak
@@ -0,0 +1,4 @@
+#!/bin/sh
+# Sample udhcpc nak script
+
+echo Received a NAK: $message
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/udhcp/sample.renew b/cleopatre/busybox-1.11.1-spc300/examples/udhcp/sample.renew
new file mode 100755
index 0000000000..842bafe916
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/udhcp/sample.renew
@@ -0,0 +1,31 @@
+#!/bin/sh
+# Sample udhcpc bound script
+
+RESOLV_CONF="/etc/udhcpc/resolv.conf"
+
+[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
+[ -n "$subnet" ] && NETMASK="netmask $subnet"
+
+/sbin/ifconfig $interface $ip $BROADCAST $NETMASK
+
+if [ -n "$router" ]
+then
+ echo "deleting routers"
+ while /sbin/route del default gw 0.0.0.0 dev $interface
+ do :
+ done
+
+ metric=0
+ for i in $router
+ do
+ /sbin/route add default gw $i dev $interface metric $((metric++))
+ done
+fi
+
+echo -n > $RESOLV_CONF
+[ -n "$domain" ] && echo domain $domain >> $RESOLV_CONF
+for i in $dns
+do
+ echo adding dns $i
+ echo nameserver $i >> $RESOLV_CONF
+done \ No newline at end of file
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/udhcp/sample.script b/cleopatre/busybox-1.11.1-spc300/examples/udhcp/sample.script
new file mode 100644
index 0000000000..9b717ac3c5
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/udhcp/sample.script
@@ -0,0 +1,7 @@
+#!/bin/sh
+# Currently, we only dispatch according to command. However, a more
+# elaborate system might dispatch by command and interface or do some
+# common initialization first, especially if more dhcp event notifications
+# are added.
+
+exec /usr/share/udhcpc/sample.$1
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/udhcp/simple.script b/cleopatre/busybox-1.11.1-spc300/examples/udhcp/simple.script
new file mode 100644
index 0000000000..98ebc159f0
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/udhcp/simple.script
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+# udhcpc script edited by Tim Riker <Tim@Rikers.org>
+
+[ -z "$1" ] && echo "Error: should be called from udhcpc" && exit 1
+
+RESOLV_CONF="/etc/resolv.conf"
+[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
+[ -n "$subnet" ] && NETMASK="netmask $subnet"
+
+case "$1" in
+ deconfig)
+ /sbin/ifconfig $interface 0.0.0.0
+ ;;
+
+ renew|bound)
+ /sbin/ifconfig $interface $ip $BROADCAST $NETMASK
+
+ if [ -n "$router" ] ; then
+ echo "deleting routers"
+ while route del default gw 0.0.0.0 dev $interface ; do
+ :
+ done
+
+ metric=0
+ for i in $router ; do
+ route add default gw $i dev $interface metric $((metric++))
+ done
+ fi
+
+ echo -n > $RESOLV_CONF
+ [ -n "$domain" ] && echo search $domain >> $RESOLV_CONF
+ for i in $dns ; do
+ echo adding dns $i
+ echo nameserver $i >> $RESOLV_CONF
+ done
+ ;;
+esac
+
+exit 0
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/udhcp/udhcpd.conf b/cleopatre/busybox-1.11.1-spc300/examples/udhcp/udhcpd.conf
new file mode 100644
index 0000000000..8c9a968400
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/udhcp/udhcpd.conf
@@ -0,0 +1,123 @@
+# Sample udhcpd configuration file (/etc/udhcpd.conf)
+
+# The start and end of the IP lease block
+
+start 192.168.0.20 #default: 192.168.0.20
+end 192.168.0.254 #default: 192.168.0.254
+
+
+# The interface that udhcpd will use
+
+interface eth0 #default: eth0
+
+
+# The maximim number of leases (includes addressesd reserved
+# by OFFER's, DECLINE's, and ARP conficts
+
+#max_leases 254 #default: 254
+
+
+# If remaining is true (default), udhcpd will store the time
+# remaining for each lease in the udhcpd leases file. This is
+# for embedded systems that cannot keep time between reboots.
+# If you set remaining to no, the absolute time that the lease
+# expires at will be stored in the dhcpd.leases file.
+
+#remaining yes #default: yes
+
+
+# The time period at which udhcpd will write out a dhcpd.leases
+# file. If this is 0, udhcpd will never automatically write a
+# lease file. (specified in seconds)
+
+#auto_time 7200 #default: 7200 (2 hours)
+
+
+# The amount of time that an IP will be reserved (leased) for if a
+# DHCP decline message is received (seconds).
+
+#decline_time 3600 #default: 3600 (1 hour)
+
+
+# The amount of time that an IP will be reserved (leased) for if an
+# ARP conflct occurs. (seconds
+
+#conflict_time 3600 #default: 3600 (1 hour)
+
+
+# How long an offered address is reserved (leased) in seconds
+
+#offer_time 60 #default: 60 (1 minute)
+
+# If a lease to be given is below this value, the full lease time is
+# instead used (seconds).
+
+#min_lease 60 #defult: 60
+
+
+# The location of the leases file
+
+#lease_file /var/lib/misc/udhcpd.leases #defualt: /var/lib/misc/udhcpd.leases
+
+# The location of the pid file
+#pidfile /var/run/udhcpd.pid #default: /var/run/udhcpd.pid
+
+# Everytime udhcpd writes a leases file, the below script will be called.
+# Useful for writing the lease file to flash every few hours.
+
+#notify_file #default: (no script)
+
+#notify_file dumpleases # <--- useful for debugging
+
+# The following are bootp specific options, setable by udhcpd.
+
+#siaddr 192.168.0.22 #default: 0.0.0.0
+
+#sname zorak #default: (none)
+
+#boot_file /var/nfs_root #default: (none)
+
+# The remainer of options are DHCP options and can be specifed with the
+# keyword 'opt' or 'option'. If an option can take multiple items, such
+# as the dns option, they can be listed on the same line, or multiple
+# lines. The only option with a default is 'lease'.
+
+#Examles
+opt dns 192.168.10.2 192.168.10.10
+option subnet 255.255.255.0
+opt router 192.168.10.2
+opt wins 192.168.10.10
+option dns 129.219.13.81 # appened to above DNS servers for a total of 3
+option domain local
+option lease 864000 # 10 days of seconds
+
+
+# Currently supported options, for more info, see options.c
+#opt subnet
+#opt timezone
+#opt router
+#opt timesrv
+#opt namesrv
+#opt dns
+#opt logsrv
+#opt cookiesrv
+#opt lprsrv
+#opt bootsize
+#opt domain
+#opt swapsrv
+#opt rootpath
+#opt ipttl
+#opt mtu
+#opt broadcast
+#opt wins
+#opt lease
+#opt ntpsrv
+#opt tftp
+#opt bootfile
+
+
+# Static leases map
+#static_lease 00:60:08:11:CE:4E 192.168.0.54
+#static_lease 00:60:08:11:CE:3E 192.168.0.44
+
+
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/undeb b/cleopatre/busybox-1.11.1-spc300/examples/undeb
new file mode 100644
index 0000000000..37104e9d81
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/undeb
@@ -0,0 +1,53 @@
+#!/bin/sh
+#
+# This should work with the GNU version of tar and gzip!
+# This should work with the bash or ash shell!
+# Requires the programs (ar, tar, gzip, and the pager more or less).
+#
+usage() {
+echo "Usage: undeb -c package.deb <Print control file info>"
+echo " undeb -l package.deb <List contents of deb package>"
+echo " undeb -x package.deb /foo/boo <Extract deb package to this directory,"
+echo " put . for current directory>"
+exit
+}
+
+deb=$2
+
+exist() {
+if [ "$deb" = "" ]; then
+usage
+elif [ ! -s "$deb" ]; then
+echo "Can't find $deb!"
+exit
+fi
+}
+
+if [ "$1" = "" ]; then
+usage
+elif [ "$1" = "-l" ]; then
+exist
+type more >/dev/null 2>&1 && pager=more
+type less >/dev/null 2>&1 && pager=less
+[ "$pager" = "" ] && echo "No pager found!" && exit
+(ar -p $deb control.tar.gz | tar -xzO *control ; echo -e "\nPress enter to scroll, q to Quit!\n" ; ar -p $deb data.tar.gz | tar -tzv) | $pager
+exit
+elif [ "$1" = "-c" ]; then
+exist
+ar -p $deb control.tar.gz | tar -xzO *control
+exit
+elif [ "$1" = "-x" ]; then
+exist
+if [ "$3" = "" ]; then
+usage
+elif [ ! -d "$3" ]; then
+echo "No such directory $3!"
+exit
+fi
+ar -p $deb data.tar.gz | tar -xzvpf - -C $3 || exit
+echo
+echo "Extracted $deb to $3!"
+exit
+else
+usage
+fi
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/unrpm b/cleopatre/busybox-1.11.1-spc300/examples/unrpm
new file mode 100644
index 0000000000..7fd3676f64
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/unrpm
@@ -0,0 +1,48 @@
+#!/bin/sh
+#
+# This should work with the GNU version of cpio and gzip!
+# This should work with the bash or ash shell!
+# Requires the programs (cpio, gzip, and the pager more or less).
+#
+usage() {
+echo "Usage: unrpm -l package.rpm <List contents of rpm package>"
+echo " unrpm -x package.rpm /foo/boo <Extract rpm package to this directory,"
+echo " put . for current directory>"
+exit
+}
+
+rpm=$2
+
+exist() {
+if [ "$rpm" = "" ]; then
+usage
+elif [ ! -s "$rpm" ]; then
+echo "Can't find $rpm!"
+exit
+fi
+}
+
+if [ "$1" = "" ]; then
+usage
+elif [ "$1" = "-l" ]; then
+exist
+type more >/dev/null 2>&1 && pager=more
+type less >/dev/null 2>&1 && pager=less
+[ "$pager" = "" ] && echo "No pager found!" && exit
+(echo -e "\nPress enter to scroll, q to Quit!\n" ; rpm2cpio $rpm | cpio -tv --quiet) | $pager
+exit
+elif [ "$1" = "-x" ]; then
+exist
+if [ "$3" = "" ]; then
+usage
+elif [ ! -d "$3" ]; then
+echo "No such directory $3!"
+exit
+fi
+rpm2cpio $rpm | (umask 0 ; cd $3 ; cpio -idmuv) || exit
+echo
+echo "Extracted $rpm to $3!"
+exit
+else
+usage
+fi
diff --git a/cleopatre/busybox-1.11.1-spc300/examples/zcip.script b/cleopatre/busybox-1.11.1-spc300/examples/zcip.script
new file mode 100644
index 0000000000..988e542a4c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/examples/zcip.script
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+# only for use as a "zcip" callback script
+if [ "x$interface" = x ]
+then
+ exit 1
+fi
+
+# zcip should start on boot/resume and various media changes
+case "$1" in
+init)
+ # for now, zcip requires the link to be already up,
+ # and it drops links when they go down. that isn't
+ # the most robust model...
+ exit 0
+ ;;
+config)
+ if [ "x$ip" = x ]
+ then
+ exit 1
+ fi
+ # remember $ip for $interface, to use on restart
+ if [ "x$IP" != x -a -w "$IP.$interface" ]
+ then
+ echo $ip > "$IP.$interface"
+ fi
+ exec ip address add dev $interface \
+ scope link local "$ip/16" broadcast +
+ ;;
+deconfig)
+ if [ x$ip = x ]
+ then
+ exit 1
+ fi
+ exec ip address del dev $interface local $ip
+ ;;
+esac
+exit 1
diff --git a/cleopatre/busybox-1.11.1-spc300/findutils/Config.in b/cleopatre/busybox-1.11.1-spc300/findutils/Config.in
new file mode 100644
index 0000000000..a830394a01
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/findutils/Config.in
@@ -0,0 +1,247 @@
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Finding Utilities"
+
+config FIND
+ bool "find"
+ default n
+ help
+ find is used to search your system to find specified files.
+
+config FEATURE_FIND_PRINT0
+ bool "Enable -print0 option"
+ default y
+ depends on FIND
+ help
+ Causes output names to be separated by a null character
+ rather than a newline. This allows names that contain
+ newlines and other whitespace to be more easily
+ interpreted by other programs.
+
+config FEATURE_FIND_MTIME
+ bool "Enable modified time matching (-mtime option)"
+ default y
+ depends on FIND
+ help
+ Allow searching based on the modification time of
+ files, in days.
+
+config FEATURE_FIND_MMIN
+ bool "Enable modified time matching (-mmin option)"
+ default y
+ depends on FIND
+ help
+ Allow searching based on the modification time of
+ files, in minutes.
+
+config FEATURE_FIND_PERM
+ bool "Enable permissions matching (-perm option)"
+ default y
+ depends on FIND
+ help
+ Enable searching based on file permissions.
+
+config FEATURE_FIND_TYPE
+ bool "Enable filetype matching (-type option)"
+ default y
+ depends on FIND
+ help
+ Enable searching based on file type (file,
+ directory, socket, device, etc.).
+
+config FEATURE_FIND_XDEV
+ bool "Enable 'stay in filesystem' option (-xdev)"
+ default y
+ depends on FIND
+ help
+ This option allows find to restrict searches to a single filesystem.
+
+config FEATURE_FIND_MAXDEPTH
+ bool "Enable -maxdepth N option"
+ default y
+ depends on FIND
+ help
+ This option enables -maxdepth N option.
+
+config FEATURE_FIND_NEWER
+ bool "Enable -newer option for comparing file mtimes"
+ default y
+ depends on FIND
+ help
+ Support the 'find -newer' option for finding any files which have
+ a modified time that is more recent than the specified FILE.
+
+config FEATURE_FIND_INUM
+ bool "Enable inode number matching (-inum option)"
+ default y
+ depends on FIND
+ help
+ Support the 'find -inum' option for searching by inode number.
+
+config FEATURE_FIND_EXEC
+ bool "Enable -exec option allowing execution of commands"
+ default y
+ depends on FIND
+ help
+ Support the 'find -exec' option for executing commands based upon
+ the files matched.
+
+config FEATURE_FIND_USER
+ bool "Enable username/uid matching (-user option)"
+ default y
+ depends on FIND
+ help
+ Support the 'find -user' option for searching by username or uid.
+
+config FEATURE_FIND_GROUP
+ bool "Enable group/gid matching (-group option)"
+ default y
+ depends on FIND
+ help
+ Support the 'find -group' option for searching by group name or gid.
+
+config FEATURE_FIND_NOT
+ bool "Enable the 'not' (!) operator"
+ default y
+ depends on FIND
+ help
+ Support the '!' operator to invert the test results.
+ If 'Enable full-blown desktop' is enabled, then will also support
+ the non-POSIX notation '-not'.
+
+config FEATURE_FIND_DEPTH
+ bool "Enable the -depth option"
+ default y
+ depends on FIND
+ help
+ Process each directory's contents before the directory itself.
+
+config FEATURE_FIND_PAREN
+ bool "Enable parens in options"
+ default y
+ depends on FIND
+ help
+ Enable usage of parens '(' to specify logical order of arguments.
+
+config FEATURE_FIND_SIZE
+ bool "Enable -size option allowing matching for file size"
+ default y
+ depends on FIND
+ help
+ Support the 'find -size' option for searching by file size.
+
+config FEATURE_FIND_PRUNE
+ bool "Enable -prune option allowing to exclude subdirectories"
+ default y
+ depends on FIND
+ help
+ If the file is a directory, dont descend into it. Useful for
+ exclusion .svn and CVS directories.
+
+config FEATURE_FIND_DELETE
+ bool "Enable -delete option allowing to delete files"
+ default n
+ depends on FIND && FEATURE_FIND_DEPTH
+ help
+ Support the 'find -delete' option for deleting files and direcotries.
+ WARNING: This option can do much harm if used wrong. Busybox will not
+ try to protect the user from doing stupid things. Use with care.
+
+config FEATURE_FIND_PATH
+ bool "Enable -path option allowing to match pathname patterns"
+ default y
+ depends on FIND
+ help
+ The -path option matches whole pathname instead of just filename.
+
+config FEATURE_FIND_REGEX
+ bool "Enable -regex: match pathname to regex"
+ default y
+ depends on FIND
+ help
+ The -regex option matches whole pathname against regular expression.
+
+config FEATURE_FIND_CONTEXT
+ bool "Enable -context option for matching security context"
+ default n
+ depends on FIND && SELINUX
+ help
+ Support the 'find -context' option for matching security context.
+
+config GREP
+ bool "grep"
+ default n
+ help
+ grep is used to search files for a specified pattern.
+
+config FEATURE_GREP_EGREP_ALIAS
+ bool "Support extended regular expressions (egrep & grep -E)"
+ default y
+ depends on GREP
+ help
+ Enabled support for extended regular expressions. Extended
+ regular expressions allow for alternation (foo|bar), grouping,
+ and various repetition operators.
+
+config FEATURE_GREP_FGREP_ALIAS
+ bool "Alias fgrep to grep -F"
+ default y
+ depends on GREP
+ help
+ fgrep sees the search pattern as a normal string rather than
+ regular expressions.
+ grep -F is always builtin, this just creates the fgrep alias.
+
+config FEATURE_GREP_CONTEXT
+ bool "Enable before and after context flags (-A, -B and -C)"
+ default y
+ depends on GREP
+ help
+ Print the specified number of leading (-B) and/or trailing (-A)
+ context surrounding our matching lines.
+ Print the specified number of context lines (-C).
+
+config XARGS
+ bool "xargs"
+ default n
+ help
+ xargs is used to execute a specified command on
+ every item from standard input.
+
+config FEATURE_XARGS_SUPPORT_CONFIRMATION
+ bool "Enable prompt and confirmation option -p"
+ default n
+ depends on XARGS
+ help
+ Support prompt the user about whether to run each command
+ line and read a line from the terminal.
+
+config FEATURE_XARGS_SUPPORT_QUOTES
+ bool "Enable support single and double quotes and backslash"
+ default n
+ depends on XARGS
+ help
+ Default xargs unsupport single and double quotes
+ and backslash for can use aruments with spaces.
+
+config FEATURE_XARGS_SUPPORT_TERMOPT
+ bool "Enable support options -x"
+ default n
+ depends on XARGS
+ help
+ Enable support exit if the size (see the -s or -n option)
+ is exceeded.
+
+config FEATURE_XARGS_SUPPORT_ZERO_TERM
+ bool "Enable null terminated option -0"
+ default n
+ depends on XARGS
+ help
+ Enable input filenames are terminated by a null character
+ instead of by whitespace, and the quotes and backslash
+ are not special.
+
+endmenu
diff --git a/cleopatre/busybox-1.11.1-spc300/findutils/Kbuild b/cleopatre/busybox-1.11.1-spc300/findutils/Kbuild
new file mode 100644
index 0000000000..7b504bacf0
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/findutils/Kbuild
@@ -0,0 +1,10 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+lib-y:=
+lib-$(CONFIG_FIND) += find.o
+lib-$(CONFIG_GREP) += grep.o
+lib-$(CONFIG_XARGS) += xargs.o
diff --git a/cleopatre/busybox-1.11.1-spc300/findutils/find.c b/cleopatre/busybox-1.11.1-spc300/findutils/find.c
new file mode 100644
index 0000000000..f75bc9ef90
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/findutils/find.c
@@ -0,0 +1,908 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini find implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Reworked by David Douthitt <n9ubh@callsign.net> and
+ * Matt Kraai <kraai@alumni.carnegiemellon.edu>.
+ *
+ * Licensed under the GPL version 2, see the file LICENSE in this tarball.
+ */
+
+/* findutils-4.1.20:
+ *
+ * # find file.txt -exec 'echo {}' '{} {}' ';'
+ * find: echo file.txt: No such file or directory
+ * # find file.txt -exec 'echo' '{} {}' '; '
+ * find: missing argument to `-exec'
+ * # find file.txt -exec 'echo {}' '{} {}' ';' junk
+ * find: paths must precede expression
+ * # find file.txt -exec 'echo {}' '{} {}' ';' junk ';'
+ * find: paths must precede expression
+ * # find file.txt -exec 'echo' '{} {}' ';'
+ * file.txt file.txt
+ * (strace: execve("/bin/echo", ["echo", "file.txt file.txt"], [ 30 vars ]))
+ * # find file.txt -exec 'echo' '{} {}' ';' -print -exec pwd ';'
+ * file.txt file.txt
+ * file.txt
+ * /tmp
+ * # find -name '*.c' -o -name '*.h'
+ * [shows files, *.c and *.h intermixed]
+ * # find file.txt -name '*f*' -o -name '*t*'
+ * file.txt
+ * # find file.txt -name '*z*' -o -name '*t*'
+ * file.txt
+ * # find file.txt -name '*f*' -o -name '*z*'
+ * file.txt
+ *
+ * # find t z -name '*t*' -print -o -name '*z*'
+ * t
+ * # find t z t z -name '*t*' -o -name '*z*' -print
+ * z
+ * z
+ * # find t z t z '(' -name '*t*' -o -name '*z*' ')' -o -print
+ * (no output)
+ */
+
+/* Testing script
+ * ./busybox find "$@" | tee /tmp/bb_find
+ * echo ==================
+ * /path/to/gnu/find "$@" | tee /tmp/std_find
+ * echo ==================
+ * diff -u /tmp/std_find /tmp/bb_find && echo Identical
+ */
+
+#include <fnmatch.h>
+#include "libbb.h"
+#if ENABLE_FEATURE_FIND_REGEX
+#include "xregex.h"
+#endif
+
+/* This is a NOEXEC applet. Be very careful! */
+
+
+USE_FEATURE_FIND_XDEV(static dev_t *xdev_dev;)
+USE_FEATURE_FIND_XDEV(static int xdev_count;)
+
+typedef int (*action_fp)(const char *fileName, struct stat *statbuf, void *);
+
+typedef struct {
+ action_fp f;
+#if ENABLE_FEATURE_FIND_NOT
+ bool invert;
+#endif
+} action;
+#define ACTS(name, arg...) typedef struct { action a; arg; } action_##name;
+#define ACTF(name) static int func_##name(const char *fileName ATTRIBUTE_UNUSED, \
+ struct stat *statbuf ATTRIBUTE_UNUSED, \
+ action_##name* ap ATTRIBUTE_UNUSED)
+ ACTS(print)
+ ACTS(name, const char *pattern; bool iname;)
+USE_FEATURE_FIND_PATH( ACTS(path, const char *pattern;))
+USE_FEATURE_FIND_REGEX( ACTS(regex, regex_t compiled_pattern;))
+USE_FEATURE_FIND_PRINT0( ACTS(print0))
+USE_FEATURE_FIND_TYPE( ACTS(type, int type_mask;))
+USE_FEATURE_FIND_PERM( ACTS(perm, char perm_char; mode_t perm_mask;))
+USE_FEATURE_FIND_MTIME( ACTS(mtime, char mtime_char; unsigned mtime_days;))
+USE_FEATURE_FIND_MMIN( ACTS(mmin, char mmin_char; unsigned mmin_mins;))
+USE_FEATURE_FIND_NEWER( ACTS(newer, time_t newer_mtime;))
+USE_FEATURE_FIND_INUM( ACTS(inum, ino_t inode_num;))
+USE_FEATURE_FIND_USER( ACTS(user, uid_t uid;))
+USE_FEATURE_FIND_SIZE( ACTS(size, char size_char; off_t size;))
+USE_FEATURE_FIND_CONTEXT(ACTS(context, security_context_t context;))
+USE_FEATURE_FIND_PAREN( ACTS(paren, action ***subexpr;))
+USE_FEATURE_FIND_PRUNE( ACTS(prune))
+USE_FEATURE_FIND_DELETE( ACTS(delete))
+USE_FEATURE_FIND_EXEC( ACTS(exec, char **exec_argv; unsigned *subst_count; int exec_argc;))
+USE_FEATURE_FIND_GROUP( ACTS(group, gid_t gid;))
+
+static action ***actions;
+static bool need_print = 1;
+static int recurse_flags = ACTION_RECURSE;
+
+#if ENABLE_FEATURE_FIND_EXEC
+static unsigned count_subst(const char *str)
+{
+ unsigned count = 0;
+ while ((str = strstr(str, "{}")) != NULL) {
+ count++;
+ str++;
+ }
+ return count;
+}
+
+
+static char* subst(const char *src, unsigned count, const char* filename)
+{
+ char *buf, *dst, *end;
+ size_t flen = strlen(filename);
+ /* we replace each '{}' with filename: growth by strlen-2 */
+ buf = dst = xmalloc(strlen(src) + count*(flen-2) + 1);
+ while ((end = strstr(src, "{}"))) {
+ memcpy(dst, src, end - src);
+ dst += end - src;
+ src = end + 2;
+ memcpy(dst, filename, flen);
+ dst += flen;
+ }
+ strcpy(dst, src);
+ return buf;
+}
+#endif
+
+/* Return values of ACTFs ('action functions') are a bit mask:
+ * bit 1=1: prune (use SKIP constant for setting it)
+ * bit 0=1: matched successfully (TRUE)
+ */
+
+static int exec_actions(action ***appp, const char *fileName, struct stat *statbuf)
+{
+ int cur_group;
+ int cur_action;
+ int rc = 0;
+ action **app, *ap;
+
+ /* "action group" is a set of actions ANDed together.
+ * groups are ORed together.
+ * We simply evaluate each group until we find one in which all actions
+ * succeed. */
+
+ /* -prune is special: if it is encountered, then we won't
+ * descend into current directory. It doesn't matter whether
+ * action group (in which -prune sits) will succeed or not:
+ * find * -prune -name 'f*' -o -name 'm*' -- prunes every dir
+ * find * -name 'f*' -o -prune -name 'm*' -- prunes all dirs
+ * not starting with 'f' */
+
+ /* We invert TRUE bit (bit 0). Now 1 there means 'failure'.
+ * and bitwise OR in "rc |= TRUE ^ ap->f()" will:
+ * (1) make SKIP (-prune) bit stick; and (2) detect 'failure'.
+ * On return, bit is restored. */
+
+ cur_group = -1;
+ while ((app = appp[++cur_group])) {
+ rc &= ~TRUE; /* 'success' so far, clear TRUE bit */
+ cur_action = -1;
+ while (1) {
+ ap = app[++cur_action];
+ if (!ap) /* all actions in group were successful */
+ return rc ^ TRUE; /* restore TRUE bit */
+ rc |= TRUE ^ ap->f(fileName, statbuf, ap);
+#if ENABLE_FEATURE_FIND_NOT
+ if (ap->invert) rc ^= TRUE;
+#endif
+ if (rc & TRUE) /* current group failed, try next */
+ break;
+ }
+ }
+ return rc ^ TRUE; /* restore TRUE bit */
+}
+
+
+ACTF(name)
+{
+ const char *tmp = bb_basename(fileName);
+ if (tmp != fileName && !*tmp) { /* "foo/bar/". Oh no... go back to 'b' */
+ tmp--;
+ while (tmp != fileName && *--tmp != '/')
+ continue;
+ if (*tmp == '/')
+ tmp++;
+ }
+ return fnmatch(ap->pattern, tmp, FNM_PERIOD | (ap->iname ? FNM_CASEFOLD : 0)) == 0;
+}
+
+#if ENABLE_FEATURE_FIND_PATH
+ACTF(path)
+{
+ return fnmatch(ap->pattern, fileName, 0) == 0;
+}
+#endif
+#if ENABLE_FEATURE_FIND_REGEX
+ACTF(regex)
+{
+ regmatch_t match;
+ if (regexec(&ap->compiled_pattern, fileName, 1, &match, 0 /*eflags*/))
+ return 0; /* no match */
+ if (match.rm_so)
+ return 0; /* match doesn't start at pos 0 */
+ if (fileName[match.rm_eo])
+ return 0; /* match doesn't end exactly at end of pathname */
+ return 1;
+}
+#endif
+#if ENABLE_FEATURE_FIND_TYPE
+ACTF(type)
+{
+ return ((statbuf->st_mode & S_IFMT) == ap->type_mask);
+}
+#endif
+#if ENABLE_FEATURE_FIND_PERM
+ACTF(perm)
+{
+ /* -perm +mode: at least one of perm_mask bits are set */
+ if (ap->perm_char == '+')
+ return (statbuf->st_mode & ap->perm_mask) != 0;
+ /* -perm -mode: all of perm_mask are set */
+ if (ap->perm_char == '-')
+ return (statbuf->st_mode & ap->perm_mask) == ap->perm_mask;
+ /* -perm mode: file mode must match perm_mask */
+ return (statbuf->st_mode & 07777) == ap->perm_mask;
+}
+#endif
+#if ENABLE_FEATURE_FIND_MTIME
+ACTF(mtime)
+{
+ time_t file_age = time(NULL) - statbuf->st_mtime;
+ time_t mtime_secs = ap->mtime_days * 24*60*60;
+ if (ap->mtime_char == '+')
+ return file_age >= mtime_secs + 24*60*60;
+ if (ap->mtime_char == '-')
+ return file_age < mtime_secs;
+ /* just numeric mtime */
+ return file_age >= mtime_secs && file_age < (mtime_secs + 24*60*60);
+}
+#endif
+#if ENABLE_FEATURE_FIND_MMIN
+ACTF(mmin)
+{
+ time_t file_age = time(NULL) - statbuf->st_mtime;
+ time_t mmin_secs = ap->mmin_mins * 60;
+ if (ap->mmin_char == '+')
+ return file_age >= mmin_secs + 60;
+ if (ap->mmin_char == '-')
+ return file_age < mmin_secs;
+ /* just numeric mmin */
+ return file_age >= mmin_secs && file_age < (mmin_secs + 60);
+}
+#endif
+#if ENABLE_FEATURE_FIND_NEWER
+ACTF(newer)
+{
+ return (ap->newer_mtime < statbuf->st_mtime);
+}
+#endif
+#if ENABLE_FEATURE_FIND_INUM
+ACTF(inum)
+{
+ return (statbuf->st_ino == ap->inode_num);
+}
+#endif
+#if ENABLE_FEATURE_FIND_EXEC
+ACTF(exec)
+{
+ int i, rc;
+ char *argv[ap->exec_argc + 1];
+ for (i = 0; i < ap->exec_argc; i++)
+ argv[i] = subst(ap->exec_argv[i], ap->subst_count[i], fileName);
+ argv[i] = NULL; /* terminate the list */
+
+ rc = spawn_and_wait(argv);
+ if (rc < 0)
+ bb_simple_perror_msg(argv[0]);
+
+ i = 0;
+ while (argv[i])
+ free(argv[i++]);
+ return rc == 0; /* return 1 if exitcode 0 */
+}
+#endif
+#if ENABLE_FEATURE_FIND_USER
+ACTF(user)
+{
+ return (statbuf->st_uid == ap->uid);
+}
+#endif
+#if ENABLE_FEATURE_FIND_GROUP
+ACTF(group)
+{
+ return (statbuf->st_gid == ap->gid);
+}
+#endif
+#if ENABLE_FEATURE_FIND_PRINT0
+ACTF(print0)
+{
+ printf("%s%c", fileName, '\0');
+ return TRUE;
+}
+#endif
+ACTF(print)
+{
+ puts(fileName);
+ return TRUE;
+}
+#if ENABLE_FEATURE_FIND_PAREN
+ACTF(paren)
+{
+ return exec_actions(ap->subexpr, fileName, statbuf);
+}
+#endif
+#if ENABLE_FEATURE_FIND_SIZE
+ACTF(size)
+{
+ if (ap->size_char == '+')
+ return statbuf->st_size > ap->size;
+ if (ap->size_char == '-')
+ return statbuf->st_size < ap->size;
+ return statbuf->st_size == ap->size;
+}
+#endif
+#if ENABLE_FEATURE_FIND_PRUNE
+/*
+ * -prune: if -depth is not given, return true and do not descend
+ * current dir; if -depth is given, return false with no effect.
+ * Example:
+ * find dir -name 'asm-*' -prune -o -name '*.[chS]' -print
+ */
+ACTF(prune)
+{
+ return SKIP + TRUE;
+}
+#endif
+#if ENABLE_FEATURE_FIND_DELETE
+ACTF(delete)
+{
+ int rc;
+ if (S_ISDIR(statbuf->st_mode)) {
+ rc = rmdir(fileName);
+ } else {
+ rc = unlink(fileName);
+ }
+ if (rc < 0)
+ bb_simple_perror_msg(fileName);
+ return TRUE;
+}
+#endif
+#if ENABLE_FEATURE_FIND_CONTEXT
+ACTF(context)
+{
+ security_context_t con;
+ int rc;
+
+ if (recurse_flags & ACTION_FOLLOWLINKS) {
+ rc = getfilecon(fileName, &con);
+ } else {
+ rc = lgetfilecon(fileName, &con);
+ }
+ if (rc < 0)
+ return FALSE;
+ rc = strcmp(ap->context, con);
+ freecon(con);
+ return rc == 0;
+}
+#endif
+
+
+static int fileAction(const char *fileName,
+ struct stat *statbuf,
+ void *userData SKIP_FEATURE_FIND_MAXDEPTH(ATTRIBUTE_UNUSED),
+ int depth SKIP_FEATURE_FIND_MAXDEPTH(ATTRIBUTE_UNUSED))
+{
+ int i;
+#if ENABLE_FEATURE_FIND_MAXDEPTH
+ int maxdepth = (int)(ptrdiff_t)userData;
+
+ if (depth > maxdepth) return SKIP;
+#endif
+
+#if ENABLE_FEATURE_FIND_XDEV
+ if (S_ISDIR(statbuf->st_mode) && xdev_count) {
+ for (i = 0; i < xdev_count; i++) {
+ if (xdev_dev[i] == statbuf->st_dev)
+ break;
+ }
+ if (i == xdev_count)
+ return SKIP;
+ }
+#endif
+ i = exec_actions(actions, fileName, statbuf);
+ /* Had no explicit -print[0] or -exec? then print */
+ if ((i & TRUE) && need_print)
+ puts(fileName);
+ /* Cannot return 0: our caller, recursive_action(),
+ * will perror() and skip dirs (if called on dir) */
+ return (i & SKIP) ? SKIP : TRUE;
+}
+
+
+#if ENABLE_FEATURE_FIND_TYPE
+static int find_type(const char *type)
+{
+ int mask = 0;
+
+ if (*type == 'b')
+ mask = S_IFBLK;
+ else if (*type == 'c')
+ mask = S_IFCHR;
+ else if (*type == 'd')
+ mask = S_IFDIR;
+ else if (*type == 'p')
+ mask = S_IFIFO;
+ else if (*type == 'f')
+ mask = S_IFREG;
+ else if (*type == 'l')
+ mask = S_IFLNK;
+ else if (*type == 's')
+ mask = S_IFSOCK;
+
+ if (mask == 0 || *(type + 1) != '\0')
+ bb_error_msg_and_die(bb_msg_invalid_arg, type, "-type");
+
+ return mask;
+}
+#endif
+
+#if ENABLE_FEATURE_FIND_PERM \
+ || ENABLE_FEATURE_FIND_MTIME || ENABLE_FEATURE_FIND_MMIN \
+ || ENABLE_FEATURE_FIND_SIZE
+static const char* plus_minus_num(const char* str)
+{
+ if (*str == '-' || *str == '+')
+ str++;
+ return str;
+}
+#endif
+
+static action*** parse_params(char **argv)
+{
+ enum {
+ PARM_a ,
+ PARM_o ,
+ USE_FEATURE_FIND_NOT( PARM_char_not ,)
+#if ENABLE_DESKTOP
+ PARM_and ,
+ PARM_or ,
+ USE_FEATURE_FIND_NOT( PARM_not ,)
+#endif
+ PARM_print ,
+ USE_FEATURE_FIND_PRINT0( PARM_print0 ,)
+ USE_FEATURE_FIND_DEPTH( PARM_depth ,)
+ USE_FEATURE_FIND_PRUNE( PARM_prune ,)
+ USE_FEATURE_FIND_DELETE( PARM_delete ,)
+ USE_FEATURE_FIND_EXEC( PARM_exec ,)
+ USE_FEATURE_FIND_PAREN( PARM_char_brace,)
+ /* All options starting from here require argument */
+ PARM_name ,
+ PARM_iname ,
+ USE_FEATURE_FIND_PATH( PARM_path ,)
+ USE_FEATURE_FIND_REGEX( PARM_regex ,)
+ USE_FEATURE_FIND_TYPE( PARM_type ,)
+ USE_FEATURE_FIND_PERM( PARM_perm ,)
+ USE_FEATURE_FIND_MTIME( PARM_mtime ,)
+ USE_FEATURE_FIND_MMIN( PARM_mmin ,)
+ USE_FEATURE_FIND_NEWER( PARM_newer ,)
+ USE_FEATURE_FIND_INUM( PARM_inum ,)
+ USE_FEATURE_FIND_USER( PARM_user ,)
+ USE_FEATURE_FIND_GROUP( PARM_group ,)
+ USE_FEATURE_FIND_SIZE( PARM_size ,)
+ USE_FEATURE_FIND_CONTEXT(PARM_context ,)
+ };
+
+ static const char params[] ALIGN1 =
+ "-a\0"
+ "-o\0"
+ USE_FEATURE_FIND_NOT( "!\0" )
+#if ENABLE_DESKTOP
+ "-and\0"
+ "-or\0"
+ USE_FEATURE_FIND_NOT( "-not\0" )
+#endif
+ "-print\0"
+ USE_FEATURE_FIND_PRINT0( "-print0\0" )
+ USE_FEATURE_FIND_DEPTH( "-depth\0" )
+ USE_FEATURE_FIND_PRUNE( "-prune\0" )
+ USE_FEATURE_FIND_DELETE( "-delete\0" )
+ USE_FEATURE_FIND_EXEC( "-exec\0" )
+ USE_FEATURE_FIND_PAREN( "(\0" )
+ /* All options starting from here require argument */
+ "-name\0"
+ "-iname\0"
+ USE_FEATURE_FIND_PATH( "-path\0" )
+ USE_FEATURE_FIND_REGEX( "-regex\0" )
+ USE_FEATURE_FIND_TYPE( "-type\0" )
+ USE_FEATURE_FIND_PERM( "-perm\0" )
+ USE_FEATURE_FIND_MTIME( "-mtime\0" )
+ USE_FEATURE_FIND_MMIN( "-mmin\0" )
+ USE_FEATURE_FIND_NEWER( "-newer\0" )
+ USE_FEATURE_FIND_INUM( "-inum\0" )
+ USE_FEATURE_FIND_USER( "-user\0" )
+ USE_FEATURE_FIND_GROUP( "-group\0" )
+ USE_FEATURE_FIND_SIZE( "-size\0" )
+ USE_FEATURE_FIND_CONTEXT("-context\0")
+ ;
+
+ action*** appp;
+ unsigned cur_group = 0;
+ unsigned cur_action = 0;
+ USE_FEATURE_FIND_NOT( bool invert_flag = 0; )
+
+ /* This is the only place in busybox where we use nested function.
+ * So far more standard alternatives were bigger. */
+ /* Suppress a warning "func without a prototype" */
+ auto action* alloc_action(int sizeof_struct, action_fp f);
+ action* alloc_action(int sizeof_struct, action_fp f)
+ {
+ action *ap;
+ appp[cur_group] = xrealloc(appp[cur_group], (cur_action+2) * sizeof(*appp));
+ appp[cur_group][cur_action++] = ap = xmalloc(sizeof_struct);
+ appp[cur_group][cur_action] = NULL;
+ ap->f = f;
+ USE_FEATURE_FIND_NOT( ap->invert = invert_flag; )
+ USE_FEATURE_FIND_NOT( invert_flag = 0; )
+ return ap;
+ }
+
+#define ALLOC_ACTION(name) (action_##name*)alloc_action(sizeof(action_##name), (action_fp) func_##name)
+
+ appp = xzalloc(2 * sizeof(appp[0])); /* appp[0],[1] == NULL */
+
+/* Actions have side effects and return a true or false value
+ * We implement: -print, -print0, -exec
+ *
+ * The rest are tests.
+ *
+ * Tests and actions are grouped by operators
+ * ( expr ) Force precedence
+ * ! expr True if expr is false
+ * -not expr Same as ! expr
+ * expr1 [-a[nd]] expr2 And; expr2 is not evaluated if expr1 is false
+ * expr1 -o[r] expr2 Or; expr2 is not evaluated if expr1 is true
+ * expr1 , expr2 List; both expr1 and expr2 are always evaluated
+ * We implement: (), -a, -o
+ */
+ while (*argv) {
+ const char *arg = argv[0];
+ int parm = index_in_strings(params, arg);
+ const char *arg1 = argv[1];
+
+ if (parm >= PARM_name) {
+ /* All options starting from -name require argument */
+ if (!arg1)
+ bb_error_msg_and_die(bb_msg_requires_arg, arg);
+ argv++;
+ }
+
+ /* We can use big switch() here, but on i386
+ * it doesn't give smaller code. Other arches? */
+
+ /* --- Operators --- */
+ if (parm == PARM_a USE_DESKTOP(|| parm == PARM_and)) {
+ /* no further special handling required */
+ }
+ else if (parm == PARM_o USE_DESKTOP(|| parm == PARM_or)) {
+ /* start new OR group */
+ cur_group++;
+ appp = xrealloc(appp, (cur_group+2) * sizeof(*appp));
+ /*appp[cur_group] = NULL; - already NULL */
+ appp[cur_group+1] = NULL;
+ cur_action = 0;
+ }
+#if ENABLE_FEATURE_FIND_NOT
+ else if (parm == PARM_char_not USE_DESKTOP(|| parm == PARM_not)) {
+ /* also handles "find ! ! -name 'foo*'" */
+ invert_flag ^= 1;
+ }
+#endif
+
+ /* --- Tests and actions --- */
+ else if (parm == PARM_print) {
+ need_print = 0;
+ /* GNU find ignores '!' here: "find ! -print" */
+ USE_FEATURE_FIND_NOT( invert_flag = 0; )
+ (void) ALLOC_ACTION(print);
+ }
+#if ENABLE_FEATURE_FIND_PRINT0
+ else if (parm == PARM_print0) {
+ need_print = 0;
+ USE_FEATURE_FIND_NOT( invert_flag = 0; )
+ (void) ALLOC_ACTION(print0);
+ }
+#endif
+#if ENABLE_FEATURE_FIND_DEPTH
+ else if (parm == PARM_depth) {
+ recurse_flags |= ACTION_DEPTHFIRST;
+ }
+#endif
+#if ENABLE_FEATURE_FIND_PRUNE
+ else if (parm == PARM_prune) {
+ USE_FEATURE_FIND_NOT( invert_flag = 0; )
+ (void) ALLOC_ACTION(prune);
+ }
+#endif
+#if ENABLE_FEATURE_FIND_DELETE
+ else if (parm == PARM_delete) {
+ need_print = 0;
+ recurse_flags |= ACTION_DEPTHFIRST;
+ (void) ALLOC_ACTION(delete);
+ }
+#endif
+#if ENABLE_FEATURE_FIND_EXEC
+ else if (parm == PARM_exec) {
+ int i;
+ action_exec *ap;
+ need_print = 0;
+ USE_FEATURE_FIND_NOT( invert_flag = 0; )
+ ap = ALLOC_ACTION(exec);
+ ap->exec_argv = ++argv; /* first arg after -exec */
+ ap->exec_argc = 0;
+ while (1) {
+ if (!*argv) /* did not see ';' until end */
+ bb_error_msg_and_die("-exec CMD must end by ';'");
+ if (LONE_CHAR(argv[0], ';'))
+ break;
+ argv++;
+ ap->exec_argc++;
+ }
+ if (ap->exec_argc == 0)
+ bb_error_msg_and_die(bb_msg_requires_arg, arg);
+ ap->subst_count = xmalloc(ap->exec_argc * sizeof(int));
+ i = ap->exec_argc;
+ while (i--)
+ ap->subst_count[i] = count_subst(ap->exec_argv[i]);
+ }
+#endif
+#if ENABLE_FEATURE_FIND_PAREN
+ else if (parm == PARM_char_brace) {
+ action_paren *ap;
+ char **endarg;
+ unsigned nested = 1;
+
+ endarg = argv;
+ while (1) {
+ if (!*++endarg)
+ bb_error_msg_and_die("unpaired '('");
+ if (LONE_CHAR(*endarg, '('))
+ nested++;
+ else if (LONE_CHAR(*endarg, ')') && !--nested) {
+ *endarg = NULL;
+ break;
+ }
+ }
+ ap = ALLOC_ACTION(paren);
+ ap->subexpr = parse_params(argv + 1);
+ *endarg = (char*) ")"; /* restore NULLed parameter */
+ argv = endarg;
+ }
+#endif
+ else if (parm == PARM_name || parm == PARM_iname) {
+ action_name *ap;
+ ap = ALLOC_ACTION(name);
+ ap->pattern = arg1;
+ ap->iname = (parm == PARM_iname);
+ }
+#if ENABLE_FEATURE_FIND_PATH
+ else if (parm == PARM_path) {
+ action_path *ap;
+ ap = ALLOC_ACTION(path);
+ ap->pattern = arg1;
+ }
+#endif
+#if ENABLE_FEATURE_FIND_REGEX
+ else if (parm == PARM_regex) {
+ action_regex *ap;
+ ap = ALLOC_ACTION(regex);
+ xregcomp(&ap->compiled_pattern, arg1, 0 /*cflags*/);
+ }
+#endif
+#if ENABLE_FEATURE_FIND_TYPE
+ else if (parm == PARM_type) {
+ action_type *ap;
+ ap = ALLOC_ACTION(type);
+ ap->type_mask = find_type(arg1);
+ }
+#endif
+#if ENABLE_FEATURE_FIND_PERM
+/* -perm mode File's permission bits are exactly mode (octal or symbolic).
+ * Symbolic modes use mode 0 as a point of departure.
+ * -perm -mode All of the permission bits mode are set for the file.
+ * -perm +mode Any of the permission bits mode are set for the file.
+ */
+ else if (parm == PARM_perm) {
+ action_perm *ap;
+ ap = ALLOC_ACTION(perm);
+ ap->perm_char = arg1[0];
+ arg1 = plus_minus_num(arg1);
+ ap->perm_mask = 0;
+ if (!bb_parse_mode(arg1, &ap->perm_mask))
+ bb_error_msg_and_die("invalid mode: %s", arg1);
+ }
+#endif
+#if ENABLE_FEATURE_FIND_MTIME
+ else if (parm == PARM_mtime) {
+ action_mtime *ap;
+ ap = ALLOC_ACTION(mtime);
+ ap->mtime_char = arg1[0];
+ ap->mtime_days = xatoul(plus_minus_num(arg1));
+ }
+#endif
+#if ENABLE_FEATURE_FIND_MMIN
+ else if (parm == PARM_mmin) {
+ action_mmin *ap;
+ ap = ALLOC_ACTION(mmin);
+ ap->mmin_char = arg1[0];
+ ap->mmin_mins = xatoul(plus_minus_num(arg1));
+ }
+#endif
+#if ENABLE_FEATURE_FIND_NEWER
+ else if (parm == PARM_newer) {
+ struct stat stat_newer;
+ action_newer *ap;
+ ap = ALLOC_ACTION(newer);
+ xstat(arg1, &stat_newer);
+ ap->newer_mtime = stat_newer.st_mtime;
+ }
+#endif
+#if ENABLE_FEATURE_FIND_INUM
+ else if (parm == PARM_inum) {
+ action_inum *ap;
+ ap = ALLOC_ACTION(inum);
+ ap->inode_num = xatoul(arg1);
+ }
+#endif
+#if ENABLE_FEATURE_FIND_USER
+ else if (parm == PARM_user) {
+ action_user *ap;
+ ap = ALLOC_ACTION(user);
+ ap->uid = bb_strtou(arg1, NULL, 10);
+ if (errno)
+ ap->uid = xuname2uid(arg1);
+ }
+#endif
+#if ENABLE_FEATURE_FIND_GROUP
+ else if (parm == PARM_group) {
+ action_group *ap;
+ ap = ALLOC_ACTION(group);
+ ap->gid = bb_strtou(arg1, NULL, 10);
+ if (errno)
+ ap->gid = xgroup2gid(arg1);
+ }
+#endif
+#if ENABLE_FEATURE_FIND_SIZE
+ else if (parm == PARM_size) {
+/* -size n[bckw]: file uses n units of space
+ * b (default): units are 512-byte blocks
+ * c: 1 byte
+ * k: kilobytes
+ * w: 2-byte words
+ */
+#if ENABLE_LFS
+#define XATOU_SFX xatoull_sfx
+#else
+#define XATOU_SFX xatoul_sfx
+#endif
+ static const struct suffix_mult find_suffixes[] = {
+ { "c", 1 },
+ { "w", 2 },
+ { "", 512 },
+ { "b", 512 },
+ { "k", 1024 },
+ { }
+ };
+ action_size *ap;
+ ap = ALLOC_ACTION(size);
+ ap->size_char = arg1[0];
+ ap->size = XATOU_SFX(plus_minus_num(arg1), find_suffixes);
+ }
+#endif
+#if ENABLE_FEATURE_FIND_CONTEXT
+ else if (parm == PARM_context) {
+ action_context *ap;
+ ap = ALLOC_ACTION(context);
+ ap->context = NULL;
+ /* SELinux headers erroneously declare non-const parameter */
+ if (selinux_raw_to_trans_context((char*)arg1, &ap->context))
+ bb_simple_perror_msg(arg1);
+ }
+#endif
+ else {
+ bb_error_msg("unrecognized: %s", arg);
+ bb_show_usage();
+ }
+ argv++;
+ }
+ return appp;
+#undef ALLOC_ACTION
+}
+
+
+int find_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int find_main(int argc, char **argv)
+{
+ static const char options[] ALIGN1 =
+ "-follow\0"
+USE_FEATURE_FIND_XDEV( "-xdev\0" )
+USE_FEATURE_FIND_MAXDEPTH("-maxdepth\0")
+ ;
+ enum {
+ OPT_FOLLOW,
+USE_FEATURE_FIND_XDEV( OPT_XDEV ,)
+USE_FEATURE_FIND_MAXDEPTH(OPT_MAXDEPTH,)
+ };
+
+ char *arg;
+ char **argp;
+ int i, firstopt, status = EXIT_SUCCESS;
+#if ENABLE_FEATURE_FIND_MAXDEPTH
+ int maxdepth = INT_MAX;
+#endif
+
+ for (firstopt = 1; firstopt < argc; firstopt++) {
+ if (argv[firstopt][0] == '-')
+ break;
+ if (ENABLE_FEATURE_FIND_NOT && LONE_CHAR(argv[firstopt], '!'))
+ break;
+#if ENABLE_FEATURE_FIND_PAREN
+ if (LONE_CHAR(argv[firstopt], '('))
+ break;
+#endif
+ }
+ if (firstopt == 1) {
+ argv[0] = (char*)".";
+ argv--;
+ firstopt++;
+ }
+
+/* All options always return true. They always take effect
+ * rather than being processed only when their place in the
+ * expression is reached.
+ * We implement: -follow, -xdev, -maxdepth
+ */
+ /* Process options, and replace then with -a */
+ /* (-a will be ignored by recursive parser later) */
+ argp = &argv[firstopt];
+ while ((arg = argp[0])) {
+ int opt = index_in_strings(options, arg);
+ if (opt == OPT_FOLLOW) {
+ recurse_flags |= ACTION_FOLLOWLINKS;
+ argp[0] = (char*)"-a";
+ }
+#if ENABLE_FEATURE_FIND_XDEV
+ if (opt == OPT_XDEV) {
+ struct stat stbuf;
+ if (!xdev_count) {
+ xdev_count = firstopt - 1;
+ xdev_dev = xmalloc(xdev_count * sizeof(dev_t));
+ for (i = 1; i < firstopt; i++) {
+ /* not xstat(): shouldn't bomb out on
+ * "find not_exist exist -xdev" */
+ if (stat(argv[i], &stbuf))
+ stbuf.st_dev = -1L;
+ xdev_dev[i-1] = stbuf.st_dev;
+ }
+ }
+ argp[0] = (char*)"-a";
+ }
+#endif
+#if ENABLE_FEATURE_FIND_MAXDEPTH
+ if (opt == OPT_MAXDEPTH) {
+ if (!argp[1])
+ bb_show_usage();
+ maxdepth = xatoi_u(argp[1]);
+ argp[0] = (char*)"-a";
+ argp[1] = (char*)"-a";
+ argp++;
+ }
+#endif
+ argp++;
+ }
+
+ actions = parse_params(&argv[firstopt]);
+
+ for (i = 1; i < firstopt; i++) {
+ if (!recursive_action(argv[i],
+ recurse_flags, /* flags */
+ fileAction, /* file action */
+ fileAction, /* dir action */
+#if ENABLE_FEATURE_FIND_MAXDEPTH
+ /* double cast suppresses
+ * "cast to ptr from int of different size" */
+ (void*)(ptrdiff_t)maxdepth,/* user data */
+#else
+ NULL, /* user data */
+#endif
+ 0)) /* depth */
+ status = EXIT_FAILURE;
+ }
+ return status;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/findutils/grep.c b/cleopatre/busybox-1.11.1-spc300/findutils/grep.c
new file mode 100644
index 0000000000..9792ce4798
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/findutils/grep.c
@@ -0,0 +1,549 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini grep implementation for busybox using libc regex.
+ *
+ * Copyright (C) 1999,2000,2001 by Lineo, inc. and Mark Whitley
+ * Copyright (C) 1999,2000,2001 by Mark Whitley <markw@codepoet.org>
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+/* BB_AUDIT SUSv3 defects - unsupported option -x "match whole line only". */
+/* BB_AUDIT GNU defects - always acts as -a. */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/grep.html */
+/*
+ * 2004,2006 (C) Vladimir Oleynik <dzo@simtreas.ru> -
+ * correction "-e pattern1 -e pattern2" logic and more optimizations.
+ * precompiled regex
+ */
+/*
+ * (C) 2006 Jac Goudsmit added -o option
+ */
+
+#include "libbb.h"
+#include "xregex.h"
+
+/* options */
+#define OPTSTR_GREP \
+ "lnqvscFiHhe:f:Lorm:" \
+ USE_FEATURE_GREP_CONTEXT("A:B:C:") \
+ USE_FEATURE_GREP_EGREP_ALIAS("E") \
+ USE_DESKTOP("w") \
+ "aI"
+/* ignored: -a "assume all files to be text" */
+/* ignored: -I "assume binary files have no matches" */
+
+enum {
+ OPTBIT_l, /* list matched file names only */
+ OPTBIT_n, /* print line# */
+ OPTBIT_q, /* quiet - exit(EXIT_SUCCESS) of first match */
+ OPTBIT_v, /* invert the match, to select non-matching lines */
+ OPTBIT_s, /* suppress errors about file open errors */
+ OPTBIT_c, /* count matches per file (suppresses normal output) */
+ OPTBIT_F, /* literal match */
+ OPTBIT_i, /* case-insensitive */
+ OPTBIT_H, /* force filename display */
+ OPTBIT_h, /* inhibit filename display */
+ OPTBIT_e, /* -e PATTERN */
+ OPTBIT_f, /* -f FILE_WITH_PATTERNS */
+ OPTBIT_L, /* list unmatched file names only */
+ OPTBIT_o, /* show only matching parts of lines */
+ OPTBIT_r, /* recurse dirs */
+ OPTBIT_m, /* -m MAX_MATCHES */
+ USE_FEATURE_GREP_CONTEXT( OPTBIT_A ,) /* -A NUM: after-match context */
+ USE_FEATURE_GREP_CONTEXT( OPTBIT_B ,) /* -B NUM: before-match context */
+ USE_FEATURE_GREP_CONTEXT( OPTBIT_C ,) /* -C NUM: -A and -B combined */
+ USE_FEATURE_GREP_EGREP_ALIAS(OPTBIT_E ,) /* extended regexp */
+ USE_DESKTOP( OPTBIT_w ,) /* whole word match */
+ OPT_l = 1 << OPTBIT_l,
+ OPT_n = 1 << OPTBIT_n,
+ OPT_q = 1 << OPTBIT_q,
+ OPT_v = 1 << OPTBIT_v,
+ OPT_s = 1 << OPTBIT_s,
+ OPT_c = 1 << OPTBIT_c,
+ OPT_F = 1 << OPTBIT_F,
+ OPT_i = 1 << OPTBIT_i,
+ OPT_H = 1 << OPTBIT_H,
+ OPT_h = 1 << OPTBIT_h,
+ OPT_e = 1 << OPTBIT_e,
+ OPT_f = 1 << OPTBIT_f,
+ OPT_L = 1 << OPTBIT_L,
+ OPT_o = 1 << OPTBIT_o,
+ OPT_r = 1 << OPTBIT_r,
+ OPT_m = 1 << OPTBIT_m,
+ OPT_A = USE_FEATURE_GREP_CONTEXT( (1 << OPTBIT_A)) + 0,
+ OPT_B = USE_FEATURE_GREP_CONTEXT( (1 << OPTBIT_B)) + 0,
+ OPT_C = USE_FEATURE_GREP_CONTEXT( (1 << OPTBIT_C)) + 0,
+ OPT_E = USE_FEATURE_GREP_EGREP_ALIAS((1 << OPTBIT_E)) + 0,
+ OPT_w = USE_DESKTOP( (1 << OPTBIT_w)) + 0,
+};
+
+#define PRINT_FILES_WITH_MATCHES (option_mask32 & OPT_l)
+#define PRINT_LINE_NUM (option_mask32 & OPT_n)
+#define BE_QUIET (option_mask32 & OPT_q)
+#define SUPPRESS_ERR_MSGS (option_mask32 & OPT_s)
+#define PRINT_MATCH_COUNTS (option_mask32 & OPT_c)
+#define FGREP_FLAG (option_mask32 & OPT_F)
+#define PRINT_FILES_WITHOUT_MATCHES (option_mask32 & OPT_L)
+
+struct globals {
+ int max_matches;
+ int reflags;
+ smalluint invert_search;
+ smalluint print_filename;
+ smalluint open_errors;
+#if ENABLE_FEATURE_GREP_CONTEXT
+ smalluint did_print_line;
+ int lines_before;
+ int lines_after;
+ char **before_buf;
+ int last_line_printed;
+#endif
+ /* globals used internally */
+ llist_t *pattern_head; /* growable list of patterns to match */
+ const char *cur_file; /* the current file we are reading */
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+#define INIT_G() do { \
+ struct G_sizecheck { \
+ char G_sizecheck[sizeof(G) > COMMON_BUFSIZE ? -1 : 1]; \
+ }; \
+} while (0)
+#define max_matches (G.max_matches )
+#define reflags (G.reflags )
+#define invert_search (G.invert_search )
+#define print_filename (G.print_filename )
+#define open_errors (G.open_errors )
+#define did_print_line (G.did_print_line )
+#define lines_before (G.lines_before )
+#define lines_after (G.lines_after )
+#define before_buf (G.before_buf )
+#define last_line_printed (G.last_line_printed )
+#define pattern_head (G.pattern_head )
+#define cur_file (G.cur_file )
+
+
+typedef struct grep_list_data_t {
+ char *pattern;
+ regex_t preg;
+#define ALLOCATED 1
+#define COMPILED 2
+ int flg_mem_alocated_compiled;
+} grep_list_data_t;
+
+
+static void print_line(const char *line, int linenum, char decoration)
+{
+#if ENABLE_FEATURE_GREP_CONTEXT
+ /* Happens when we go to next file, immediately hit match
+ * and try to print prev context... from prev file! Don't do it */
+ if (linenum < 1)
+ return;
+ /* possibly print the little '--' separator */
+ if ((lines_before || lines_after) && did_print_line &&
+ last_line_printed != linenum - 1) {
+ puts("--");
+ }
+ /* guard against printing "--" before first line of first file */
+ did_print_line = 1;
+ last_line_printed = linenum;
+#endif
+ if (print_filename)
+ printf("%s%c", cur_file, decoration);
+ if (PRINT_LINE_NUM)
+ printf("%i%c", linenum, decoration);
+ /* Emulate weird GNU grep behavior with -ov */
+ if ((option_mask32 & (OPT_v|OPT_o)) != (OPT_v|OPT_o))
+ puts(line);
+}
+
+static int grep_file(FILE *file)
+{
+ char *line;
+ smalluint found;
+ int linenum = 0;
+ int nmatches = 0;
+ regmatch_t regmatch;
+#if ENABLE_FEATURE_GREP_CONTEXT
+ int print_n_lines_after = 0;
+ int curpos = 0; /* track where we are in the circular 'before' buffer */
+ int idx = 0; /* used for iteration through the circular buffer */
+#else
+ enum { print_n_lines_after = 0 };
+#endif /* ENABLE_FEATURE_GREP_CONTEXT */
+
+ while ((line = xmalloc_fgetline(file)) != NULL) {
+ llist_t *pattern_ptr = pattern_head;
+ grep_list_data_t *gl = gl; /* for gcc */
+
+ linenum++;
+ found = 0;
+ while (pattern_ptr) {
+ gl = (grep_list_data_t *)pattern_ptr->data;
+ if (FGREP_FLAG) {
+ found |= (strstr(line, gl->pattern) != NULL);
+ } else {
+ if (!(gl->flg_mem_alocated_compiled & COMPILED)) {
+ gl->flg_mem_alocated_compiled |= COMPILED;
+ xregcomp(&(gl->preg), gl->pattern, reflags);
+ }
+ regmatch.rm_so = 0;
+ regmatch.rm_eo = 0;
+ if (regexec(&(gl->preg), line, 1, &regmatch, 0) == 0) {
+ if (!(option_mask32 & OPT_w))
+ found = 1;
+ else {
+ char c = ' ';
+ if (regmatch.rm_so)
+ c = line[regmatch.rm_so - 1];
+ if (!isalnum(c) && c != '_') {
+ c = line[regmatch.rm_eo];
+ if (!c || (!isalnum(c) && c != '_'))
+ found = 1;
+ }
+ }
+ }
+ }
+ /* If it's non-inverted search, we can stop
+ * at first match */
+ if (found && !invert_search)
+ goto do_found;
+ pattern_ptr = pattern_ptr->link;
+ } /* while (pattern_ptr) */
+
+ if (found ^ invert_search) {
+ do_found:
+ /* keep track of matches */
+ nmatches++;
+
+ /* quiet/print (non)matching file names only? */
+ if (option_mask32 & (OPT_q|OPT_l|OPT_L)) {
+ free(line); /* we don't need line anymore */
+ if (BE_QUIET) {
+ /* manpage says about -q:
+ * "exit immediately with zero status
+ * if any match is found,
+ * even if errors were detected" */
+ exit(EXIT_SUCCESS);
+ }
+ /* if we're just printing filenames, we stop after the first match */
+ if (PRINT_FILES_WITH_MATCHES) {
+ puts(cur_file);
+ /* fall through to "return 1" */
+ }
+ /* OPT_L aka PRINT_FILES_WITHOUT_MATCHES: return early */
+ return 1; /* one match */
+ }
+
+#if ENABLE_FEATURE_GREP_CONTEXT
+ /* Were we printing context and saw next (unwanted) match? */
+ if ((option_mask32 & OPT_m) && nmatches > max_matches)
+ break;
+#endif
+
+ /* print the matched line */
+ if (PRINT_MATCH_COUNTS == 0) {
+#if ENABLE_FEATURE_GREP_CONTEXT
+ int prevpos = (curpos == 0) ? lines_before - 1 : curpos - 1;
+
+ /* if we were told to print 'before' lines and there is at least
+ * one line in the circular buffer, print them */
+ if (lines_before && before_buf[prevpos] != NULL) {
+ int first_buf_entry_line_num = linenum - lines_before;
+
+ /* advance to the first entry in the circular buffer, and
+ * figure out the line number is of the first line in the
+ * buffer */
+ idx = curpos;
+ while (before_buf[idx] == NULL) {
+ idx = (idx + 1) % lines_before;
+ first_buf_entry_line_num++;
+ }
+
+ /* now print each line in the buffer, clearing them as we go */
+ while (before_buf[idx] != NULL) {
+ print_line(before_buf[idx], first_buf_entry_line_num, '-');
+ free(before_buf[idx]);
+ before_buf[idx] = NULL;
+ idx = (idx + 1) % lines_before;
+ first_buf_entry_line_num++;
+ }
+ }
+
+ /* make a note that we need to print 'after' lines */
+ print_n_lines_after = lines_after;
+#endif
+ if (option_mask32 & OPT_o) {
+ if (FGREP_FLAG) {
+ /* -Fo just prints the pattern
+ * (unless -v: -Fov doesnt print anything at all) */
+ if (found)
+ print_line(gl->pattern, linenum, ':');
+ } else {
+ line[regmatch.rm_eo] = '\0';
+ print_line(line + regmatch.rm_so, linenum, ':');
+ }
+ } else {
+ print_line(line, linenum, ':');
+ }
+ }
+ }
+#if ENABLE_FEATURE_GREP_CONTEXT
+ else { /* no match */
+ /* if we need to print some context lines after the last match, do so */
+ if (print_n_lines_after) {
+ print_line(line, linenum, '-');
+ print_n_lines_after--;
+ } else if (lines_before) {
+ /* Add the line to the circular 'before' buffer */
+ free(before_buf[curpos]);
+ before_buf[curpos] = line;
+ curpos = (curpos + 1) % lines_before;
+ /* avoid free(line) - we took the line */
+ line = NULL;
+ }
+ }
+
+#endif /* ENABLE_FEATURE_GREP_CONTEXT */
+ free(line);
+
+ /* Did we print all context after last requested match? */
+ if ((option_mask32 & OPT_m)
+ && !print_n_lines_after && nmatches == max_matches)
+ break;
+ }
+
+ /* special-case file post-processing for options where we don't print line
+ * matches, just filenames and possibly match counts */
+
+ /* grep -c: print [filename:]count, even if count is zero */
+ if (PRINT_MATCH_COUNTS) {
+ if (print_filename)
+ printf("%s:", cur_file);
+ printf("%d\n", nmatches);
+ }
+
+ /* grep -L: print just the filename */
+ if (PRINT_FILES_WITHOUT_MATCHES) {
+ /* nmatches is zero, no need to check it:
+ * we return 1 early if we detected a match
+ * and PRINT_FILES_WITHOUT_MATCHES is set */
+ puts(cur_file);
+ }
+
+ return nmatches;
+}
+
+#if ENABLE_FEATURE_CLEAN_UP
+#define new_grep_list_data(p, m) add_grep_list_data(p, m)
+static char *add_grep_list_data(char *pattern, int flg_used_mem)
+#else
+#define new_grep_list_data(p, m) add_grep_list_data(p)
+static char *add_grep_list_data(char *pattern)
+#endif
+{
+ grep_list_data_t *gl = xzalloc(sizeof(*gl));
+ gl->pattern = pattern;
+#if ENABLE_FEATURE_CLEAN_UP
+ gl->flg_mem_alocated_compiled = flg_used_mem;
+#else
+ /*gl->flg_mem_alocated_compiled = 0;*/
+#endif
+ return (char *)gl;
+}
+
+static void load_regexes_from_file(llist_t *fopt)
+{
+ char *line;
+ FILE *f;
+
+ while (fopt) {
+ llist_t *cur = fopt;
+ char *ffile = cur->data;
+
+ fopt = cur->link;
+ free(cur);
+ f = xfopen_stdin(ffile);
+ while ((line = xmalloc_fgetline(f)) != NULL) {
+ llist_add_to(&pattern_head,
+ new_grep_list_data(line, ALLOCATED));
+ }
+ }
+}
+
+static int file_action_grep(const char *filename,
+ struct stat *statbuf ATTRIBUTE_UNUSED,
+ void* matched,
+ int depth ATTRIBUTE_UNUSED)
+{
+ FILE *file = fopen(filename, "r");
+ if (file == NULL) {
+ if (!SUPPRESS_ERR_MSGS)
+ bb_simple_perror_msg(filename);
+ open_errors = 1;
+ return 0;
+ }
+ cur_file = filename;
+ *(int*)matched += grep_file(file);
+ fclose(file);
+ return 1;
+}
+
+static int grep_dir(const char *dir)
+{
+ int matched = 0;
+ recursive_action(dir,
+ /* recurse=yes */ ACTION_RECURSE |
+ /* followLinks=no */
+ /* depthFirst=yes */ ACTION_DEPTHFIRST,
+ /* fileAction= */ file_action_grep,
+ /* dirAction= */ NULL,
+ /* userData= */ &matched,
+ /* depth= */ 0);
+ return matched;
+}
+
+int grep_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int grep_main(int argc, char **argv)
+{
+ FILE *file;
+ int matched;
+ llist_t *fopt = NULL;
+
+ /* do normal option parsing */
+#if ENABLE_FEATURE_GREP_CONTEXT
+ int Copt;
+
+ /* -H unsets -h; -C unsets -A,-B; -e,-f are lists;
+ * -m,-A,-B,-C have numeric param */
+ opt_complementary = "H-h:C-AB:e::f::m+:A+:B+:C+";
+ getopt32(argv,
+ OPTSTR_GREP,
+ &pattern_head, &fopt, &max_matches,
+ &lines_after, &lines_before, &Copt);
+
+ if (option_mask32 & OPT_C) {
+ /* -C unsets prev -A and -B, but following -A or -B
+ may override it */
+ if (!(option_mask32 & OPT_A)) /* not overridden */
+ lines_after = Copt;
+ if (!(option_mask32 & OPT_B)) /* not overridden */
+ lines_before = Copt;
+ //option_mask32 |= OPT_A|OPT_B; /* for parser */
+ }
+ /* sanity checks */
+ if (option_mask32 & (OPT_c|OPT_q|OPT_l|OPT_L)) {
+ option_mask32 &= ~OPT_n;
+ lines_before = 0;
+ lines_after = 0;
+ } else if (lines_before > 0)
+ before_buf = xzalloc(lines_before * sizeof(char *));
+#else
+ /* with auto sanity checks */
+ /* -H unsets -h; -c,-q or -l unset -n; -e,-f are lists; -m N */
+ opt_complementary = "H-h:c-n:q-n:l-n:e::f::m+";
+ getopt32(argv, OPTSTR_GREP,
+ &pattern_head, &fopt, &max_matches);
+#endif
+ invert_search = ((option_mask32 & OPT_v) != 0); /* 0 | 1 */
+
+ if (pattern_head != NULL) {
+ /* convert char **argv to grep_list_data_t */
+ llist_t *cur;
+
+ for (cur = pattern_head; cur; cur = cur->link)
+ cur->data = new_grep_list_data(cur->data, 0);
+ }
+ if (option_mask32 & OPT_f)
+ load_regexes_from_file(fopt);
+
+ if (ENABLE_FEATURE_GREP_FGREP_ALIAS && applet_name[0] == 'f')
+ option_mask32 |= OPT_F;
+
+ if (!(option_mask32 & (OPT_o | OPT_w)))
+ reflags = REG_NOSUB;
+
+ if (ENABLE_FEATURE_GREP_EGREP_ALIAS
+ && (applet_name[0] == 'e' || (option_mask32 & OPT_E))
+ ) {
+ reflags |= REG_EXTENDED;
+ }
+
+ if (option_mask32 & OPT_i)
+ reflags |= REG_ICASE;
+
+ argv += optind;
+ argc -= optind;
+
+ /* if we didn't get a pattern from -e and no command file was specified,
+ * first parameter should be the pattern. no pattern, no worky */
+ if (pattern_head == NULL) {
+ char *pattern;
+ if (*argv == NULL)
+ bb_show_usage();
+ pattern = new_grep_list_data(*argv++, 0);
+ llist_add_to(&pattern_head, pattern);
+ argc--;
+ }
+
+ /* argv[0..(argc-1)] should be names of file to grep through. If
+ * there is more than one file to grep, we will print the filenames. */
+ if (argc > 1)
+ print_filename = 1;
+ /* -H / -h of course override */
+ if (option_mask32 & OPT_H)
+ print_filename = 1;
+ if (option_mask32 & OPT_h)
+ print_filename = 0;
+
+ /* If no files were specified, or '-' was specified, take input from
+ * stdin. Otherwise, we grep through all the files specified. */
+ matched = 0;
+ do {
+ cur_file = *argv++;
+ file = stdin;
+ if (!cur_file || LONE_DASH(cur_file)) {
+ cur_file = "(standard input)";
+ } else {
+ if (option_mask32 & OPT_r) {
+ struct stat st;
+ if (stat(cur_file, &st) == 0 && S_ISDIR(st.st_mode)) {
+ if (!(option_mask32 & OPT_h))
+ print_filename = 1;
+ matched += grep_dir(cur_file);
+ goto grep_done;
+ }
+ }
+ /* else: fopen(dir) will succeed, but reading won't */
+ file = fopen(cur_file, "r");
+ if (file == NULL) {
+ if (!SUPPRESS_ERR_MSGS)
+ bb_simple_perror_msg(cur_file);
+ open_errors = 1;
+ continue;
+ }
+ }
+ matched += grep_file(file);
+ fclose_if_not_stdin(file);
+ grep_done: ;
+ } while (--argc > 0);
+
+ /* destroy all the elments in the pattern list */
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ while (pattern_head) {
+ llist_t *pattern_head_ptr = pattern_head;
+ grep_list_data_t *gl = (grep_list_data_t *)pattern_head_ptr->data;
+
+ pattern_head = pattern_head->link;
+ if (gl->flg_mem_alocated_compiled & ALLOCATED)
+ free(gl->pattern);
+ if (gl->flg_mem_alocated_compiled & COMPILED)
+ regfree(&(gl->preg));
+ free(gl);
+ free(pattern_head_ptr);
+ }
+ }
+ /* 0 = success, 1 = failed, 2 = error */
+ if (open_errors)
+ return 2;
+ return !matched; /* invert return value: 0 = success, 1 = failed */
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/findutils/xargs.c b/cleopatre/busybox-1.11.1-spc300/findutils/xargs.c
new file mode 100644
index 0000000000..3322e9ebdf
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/findutils/xargs.c
@@ -0,0 +1,527 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini xargs implementation for busybox
+ * Options are supported: "-prtx -n max_arg -s max_chars -e[ouf_str]"
+ *
+ * (C) 2002,2003 by Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * Special thanks
+ * - Mark Whitley and Glenn McGrath for stimulus to rewrite :)
+ * - Mike Rendell <michael@cs.mun.ca>
+ * and David MacKenzie <djm@gnu.ai.mit.edu>.
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ *
+ * xargs is described in the Single Unix Specification v3 at
+ * http://www.opengroup.org/onlinepubs/007904975/utilities/xargs.html
+ *
+ */
+
+#include "libbb.h"
+
+/* This is a NOEXEC applet. Be very careful! */
+
+
+/* COMPAT: SYSV version defaults size (and has a max value of) to 470.
+ We try to make it as large as possible. */
+#if !defined(ARG_MAX) && defined(_SC_ARG_MAX)
+#define ARG_MAX sysconf (_SC_ARG_MAX)
+#endif
+#ifndef ARG_MAX
+#define ARG_MAX 470
+#endif
+
+
+#ifdef TEST
+# ifndef ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION
+# define ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION 1
+# endif
+# ifndef ENABLE_FEATURE_XARGS_SUPPORT_QUOTES
+# define ENABLE_FEATURE_XARGS_SUPPORT_QUOTES 1
+# endif
+# ifndef ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT
+# define ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT 1
+# endif
+# ifndef ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
+# define ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM 1
+# endif
+#endif
+
+/*
+ This function has special algorithm.
+ Don't use fork and include to main!
+*/
+static int xargs_exec(char **args)
+{
+ int status;
+
+ status = spawn_and_wait(args);
+ if (status < 0) {
+ bb_simple_perror_msg(args[0]);
+ return errno == ENOENT ? 127 : 126;
+ }
+ if (status == 255) {
+ bb_error_msg("%s: exited with status 255; aborting", args[0]);
+ return 124;
+ }
+/* Huh? I think we won't see this, ever. We don't wait with WUNTRACED!
+ if (WIFSTOPPED(status)) {
+ bb_error_msg("%s: stopped by signal %d",
+ args[0], WSTOPSIG(status));
+ return 125;
+ }
+*/
+ if (status >= 1000) {
+ bb_error_msg("%s: terminated by signal %d",
+ args[0], status - 1000);
+ return 125;
+ }
+ if (status)
+ return 123;
+ return 0;
+}
+
+
+typedef struct xlist_t {
+ struct xlist_t *link;
+ size_t length;
+ char xstr[1];
+} xlist_t;
+
+static smallint eof_stdin_detected;
+
+#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
+#define ISSPACE(c) (ISBLANK(c) || (c) == '\n' || (c) == '\r' \
+ || (c) == '\f' || (c) == '\v')
+
+#if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES
+static xlist_t *process_stdin(xlist_t *list_arg,
+ const char *eof_str, size_t mc, char *buf)
+{
+#define NORM 0
+#define QUOTE 1
+#define BACKSLASH 2
+#define SPACE 4
+
+ char *s = NULL; /* start word */
+ char *p = NULL; /* pointer to end word */
+ char q = '\0'; /* quote char */
+ char state = NORM;
+ char eof_str_detected = 0;
+ size_t line_l = 0; /* size loaded args line */
+ int c; /* current char */
+ xlist_t *cur;
+ xlist_t *prev;
+
+ prev = cur = list_arg;
+ while (1) {
+ if (!cur) break;
+ prev = cur;
+ line_l += cur->length;
+ cur = cur->link;
+ }
+
+ while (!eof_stdin_detected) {
+ c = getchar();
+ if (c == EOF) {
+ eof_stdin_detected = 1;
+ if (s)
+ goto unexpected_eof;
+ break;
+ }
+ if (eof_str_detected)
+ continue;
+ if (state == BACKSLASH) {
+ state = NORM;
+ goto set;
+ } else if (state == QUOTE) {
+ if (c != q)
+ goto set;
+ q = '\0';
+ state = NORM;
+ } else { /* if (state == NORM) */
+ if (ISSPACE(c)) {
+ if (s) {
+ unexpected_eof:
+ state = SPACE;
+ c = '\0';
+ goto set;
+ }
+ } else {
+ if (s == NULL)
+ s = p = buf;
+ if (c == '\\') {
+ state = BACKSLASH;
+ } else if (c == '\'' || c == '"') {
+ q = c;
+ state = QUOTE;
+ } else {
+ set:
+ if ((size_t)(p - buf) >= mc)
+ bb_error_msg_and_die("argument line too long");
+ *p++ = c;
+ }
+ }
+ }
+ if (state == SPACE) { /* word's delimiter or EOF detected */
+ if (q) {
+ bb_error_msg_and_die("unmatched %s quote",
+ q == '\'' ? "single" : "double");
+ }
+ /* word loaded */
+ if (eof_str) {
+ eof_str_detected = (strcmp(s, eof_str) == 0);
+ }
+ if (!eof_str_detected) {
+ size_t length = (p - buf);
+ /* Dont xzalloc - it can be quite big */
+ cur = xmalloc(offsetof(xlist_t, xstr) + length);
+ cur->link = NULL;
+ cur->length = length;
+ memcpy(cur->xstr, s, length);
+ if (prev == NULL) {
+ list_arg = cur;
+ } else {
+ prev->link = cur;
+ }
+ prev = cur;
+ line_l += length;
+ if (line_l > mc) {
+ /* stop memory usage :-) */
+ break;
+ }
+ }
+ s = NULL;
+ state = NORM;
+ }
+ }
+ return list_arg;
+}
+#else
+/* The variant does not support single quotes, double quotes or backslash */
+static xlist_t *process_stdin(xlist_t *list_arg,
+ const char *eof_str, size_t mc, char *buf)
+{
+
+ int c; /* current char */
+ char eof_str_detected = 0;
+ char *s = NULL; /* start word */
+ char *p = NULL; /* pointer to end word */
+ size_t line_l = 0; /* size loaded args line */
+ xlist_t *cur;
+ xlist_t *prev;
+
+ prev = cur = list_arg;
+ while (1) {
+ if (!cur) break;
+ prev = cur;
+ line_l += cur->length;
+ cur = cur->link;
+ }
+
+ while (!eof_stdin_detected) {
+ c = getchar();
+ if (c == EOF) {
+ eof_stdin_detected = 1;
+ }
+ if (eof_str_detected)
+ continue;
+ if (c == EOF || ISSPACE(c)) {
+ if (s == NULL)
+ continue;
+ c = EOF;
+ }
+ if (s == NULL)
+ s = p = buf;
+ if ((size_t)(p - buf) >= mc)
+ bb_error_msg_and_die("argument line too long");
+ *p++ = (c == EOF ? '\0' : c);
+ if (c == EOF) { /* word's delimiter or EOF detected */
+ /* word loaded */
+ if (eof_str) {
+ eof_str_detected = (strcmp(s, eof_str) == 0);
+ }
+ if (!eof_str_detected) {
+ size_t length = (p - buf);
+ /* Dont xzalloc - it can be quite big */
+ cur = xmalloc(offsetof(xlist_t, xstr) + length);
+ cur->link = NULL;
+ cur->length = length;
+ memcpy(cur->xstr, s, length);
+ if (prev == NULL) {
+ list_arg = cur;
+ } else {
+ prev->link = cur;
+ }
+ prev = cur;
+ line_l += length;
+ if (line_l > mc) {
+ /* stop memory usage :-) */
+ break;
+ }
+ s = NULL;
+ }
+ }
+ }
+ return list_arg;
+}
+#endif /* FEATURE_XARGS_SUPPORT_QUOTES */
+
+
+#if ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION
+/* Prompt the user for a response, and
+ if the user responds affirmatively, return true;
+ otherwise, return false. Uses "/dev/tty", not stdin. */
+static int xargs_ask_confirmation(void)
+{
+ FILE *tty_stream;
+ int c, savec;
+
+ tty_stream = xfopen(CURRENT_TTY, "r");
+ fputs(" ?...", stderr);
+ fflush(stderr);
+ c = savec = getc(tty_stream);
+ while (c != EOF && c != '\n')
+ c = getc(tty_stream);
+ fclose(tty_stream);
+ return (savec == 'y' || savec == 'Y');
+}
+#else
+# define xargs_ask_confirmation() 1
+#endif /* FEATURE_XARGS_SUPPORT_CONFIRMATION */
+
+#if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
+static xlist_t *process0_stdin(xlist_t *list_arg,
+ const char *eof_str ATTRIBUTE_UNUSED, size_t mc, char *buf)
+{
+ int c; /* current char */
+ char *s = NULL; /* start word */
+ char *p = NULL; /* pointer to end word */
+ size_t line_l = 0; /* size loaded args line */
+ xlist_t *cur;
+ xlist_t *prev;
+
+ prev = cur = list_arg;
+ while (1) {
+ if (!cur) break;
+ prev = cur;
+ line_l += cur->length;
+ cur = cur->link;
+ }
+
+ while (!eof_stdin_detected) {
+ c = getchar();
+ if (c == EOF) {
+ eof_stdin_detected = 1;
+ if (s == NULL)
+ break;
+ c = '\0';
+ }
+ if (s == NULL)
+ s = p = buf;
+ if ((size_t)(p - buf) >= mc)
+ bb_error_msg_and_die("argument line too long");
+ *p++ = c;
+ if (c == '\0') { /* word's delimiter or EOF detected */
+ /* word loaded */
+ size_t length = (p - buf);
+ /* Dont xzalloc - it can be quite big */
+ cur = xmalloc(offsetof(xlist_t, xstr) + length);
+ cur->link = NULL;
+ cur->length = length;
+ memcpy(cur->xstr, s, length);
+ if (prev == NULL) {
+ list_arg = cur;
+ } else {
+ prev->link = cur;
+ }
+ prev = cur;
+ line_l += length;
+ if (line_l > mc) {
+ /* stop memory usage :-) */
+ break;
+ }
+ s = NULL;
+ }
+ }
+ return list_arg;
+}
+#endif /* FEATURE_XARGS_SUPPORT_ZERO_TERM */
+
+/* Correct regardless of combination of CONFIG_xxx */
+enum {
+ OPTBIT_VERBOSE = 0,
+ OPTBIT_NO_EMPTY,
+ OPTBIT_UPTO_NUMBER,
+ OPTBIT_UPTO_SIZE,
+ OPTBIT_EOF_STRING,
+ USE_FEATURE_XARGS_SUPPORT_CONFIRMATION(OPTBIT_INTERACTIVE,)
+ USE_FEATURE_XARGS_SUPPORT_TERMOPT( OPTBIT_TERMINATE ,)
+ USE_FEATURE_XARGS_SUPPORT_ZERO_TERM( OPTBIT_ZEROTERM ,)
+
+ OPT_VERBOSE = 1<<OPTBIT_VERBOSE ,
+ OPT_NO_EMPTY = 1<<OPTBIT_NO_EMPTY ,
+ OPT_UPTO_NUMBER = 1<<OPTBIT_UPTO_NUMBER,
+ OPT_UPTO_SIZE = 1<<OPTBIT_UPTO_SIZE ,
+ OPT_EOF_STRING = 1<<OPTBIT_EOF_STRING ,
+ OPT_INTERACTIVE = USE_FEATURE_XARGS_SUPPORT_CONFIRMATION((1<<OPTBIT_INTERACTIVE)) + 0,
+ OPT_TERMINATE = USE_FEATURE_XARGS_SUPPORT_TERMOPT( (1<<OPTBIT_TERMINATE )) + 0,
+ OPT_ZEROTERM = USE_FEATURE_XARGS_SUPPORT_ZERO_TERM( (1<<OPTBIT_ZEROTERM )) + 0,
+};
+#define OPTION_STR "+trn:s:e::" \
+ USE_FEATURE_XARGS_SUPPORT_CONFIRMATION("p") \
+ USE_FEATURE_XARGS_SUPPORT_TERMOPT( "x") \
+ USE_FEATURE_XARGS_SUPPORT_ZERO_TERM( "0")
+
+int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int xargs_main(int argc, char **argv)
+{
+ char **args;
+ int i, n;
+ xlist_t *list = NULL;
+ xlist_t *cur;
+ int child_error = 0;
+ char *max_args, *max_chars;
+ int n_max_arg;
+ size_t n_chars = 0;
+ long orig_arg_max;
+ const char *eof_str = "_";
+ unsigned opt;
+ size_t n_max_chars;
+#if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
+ xlist_t* (*read_args)(xlist_t*, const char*, size_t, char*) = process_stdin;
+#else
+#define read_args process_stdin
+#endif
+
+ opt = getopt32(argv, OPTION_STR, &max_args, &max_chars, &eof_str);
+
+ if (opt & OPT_ZEROTERM)
+ USE_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin);
+
+ argv += optind;
+ argc -= optind;
+ if (!argc) {
+ /* default behavior is to echo all the filenames */
+ *argv = (char*)"echo";
+ argc++;
+ }
+
+ orig_arg_max = ARG_MAX;
+ if (orig_arg_max == -1)
+ orig_arg_max = LONG_MAX;
+ orig_arg_max -= 2048; /* POSIX.2 requires subtracting 2048 */
+
+ if (opt & OPT_UPTO_SIZE) {
+ n_max_chars = xatoul_range(max_chars, 1, orig_arg_max);
+ for (i = 0; i < argc; i++) {
+ n_chars += strlen(*argv) + 1;
+ }
+ if (n_max_chars < n_chars) {
+ bb_error_msg_and_die("cannot fit single argument within argument list size limit");
+ }
+ n_max_chars -= n_chars;
+ } else {
+ /* Sanity check for systems with huge ARG_MAX defines (e.g., Suns which
+ have it at 1 meg). Things will work fine with a large ARG_MAX but it
+ will probably hurt the system more than it needs to; an array of this
+ size is allocated. */
+ if (orig_arg_max > 20 * 1024)
+ orig_arg_max = 20 * 1024;
+ n_max_chars = orig_arg_max;
+ }
+ max_chars = xmalloc(n_max_chars);
+
+ if (opt & OPT_UPTO_NUMBER) {
+ n_max_arg = xatoul_range(max_args, 1, INT_MAX);
+ } else {
+ n_max_arg = n_max_chars;
+ }
+
+ while ((list = read_args(list, eof_str, n_max_chars, max_chars)) != NULL ||
+ !(opt & OPT_NO_EMPTY))
+ {
+ opt |= OPT_NO_EMPTY;
+ n = 0;
+ n_chars = 0;
+#if ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT
+ for (cur = list; cur;) {
+ n_chars += cur->length;
+ n++;
+ cur = cur->link;
+ if (n_chars > n_max_chars || (n == n_max_arg && cur)) {
+ if (opt & OPT_TERMINATE)
+ bb_error_msg_and_die("argument list too long");
+ break;
+ }
+ }
+#else
+ for (cur = list; cur; cur = cur->link) {
+ n_chars += cur->length;
+ n++;
+ if (n_chars > n_max_chars || n == n_max_arg) {
+ break;
+ }
+ }
+#endif /* FEATURE_XARGS_SUPPORT_TERMOPT */
+
+ /* allocate pointers for execvp:
+ argc*arg, n*arg from stdin, NULL */
+ args = xzalloc((n + argc + 1) * sizeof(char *));
+
+ /* store the command to be executed
+ (taken from the command line) */
+ for (i = 0; i < argc; i++)
+ args[i] = argv[i];
+ /* (taken from stdin) */
+ for (cur = list; n; cur = cur->link) {
+ args[i++] = cur->xstr;
+ n--;
+ }
+
+ if (opt & (OPT_INTERACTIVE | OPT_VERBOSE)) {
+ for (i = 0; args[i]; i++) {
+ if (i)
+ fputc(' ', stderr);
+ fputs(args[i], stderr);
+ }
+ if (!(opt & OPT_INTERACTIVE))
+ fputc('\n', stderr);
+ }
+ if (!(opt & OPT_INTERACTIVE) || xargs_ask_confirmation()) {
+ child_error = xargs_exec(args);
+ }
+
+ /* clean up */
+ for (i = argc; args[i]; i++) {
+ cur = list;
+ list = list->link;
+ free(cur);
+ }
+ free(args);
+ if (child_error > 0 && child_error != 123) {
+ break;
+ }
+ } /* while */
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(max_chars);
+ return child_error;
+}
+
+
+#ifdef TEST
+
+const char *applet_name = "debug stuff usage";
+
+void bb_show_usage(void)
+{
+ fprintf(stderr, "Usage: %s [-p] [-r] [-t] -[x] [-n max_arg] [-s max_chars]\n",
+ applet_name);
+ exit(EXIT_FAILURE);
+}
+
+int main(int argc, char **argv)
+{
+ return xargs_main(argc, argv);
+}
+#endif /* TEST */
diff --git a/cleopatre/busybox-1.11.1-spc300/include/applets.h b/cleopatre/busybox-1.11.1-spc300/include/applets.h
new file mode 100644
index 0000000000..e7fc3c03c1
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/include/applets.h
@@ -0,0 +1,404 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * applets.h - a listing of all busybox applets.
+ *
+ * If you write a new applet, you need to add an entry to this list to make
+ * busybox aware of it.
+ *
+ * It is CRUCIAL that this listing be kept in ascii order, otherwise the binary
+ * search lookup contributed by Gaute B Strokkenes stops working. If you value
+ * your kneecaps, you'll be sure to *make sure* that any changes made to this
+ * file result in the listing remaining in ascii order. You have been warned.
+ */
+
+/*
+name - applet name as it is typed on command line
+name2 - applet name, converted to C (ether-wake: name2 = ether_wake)
+main - corresponding <applet>_main to call (bzcat: main = bunzip2)
+l - location to install link to: [/usr]/[s]bin
+s - suid type:
+ _BB_SUID_ALWAYS: will complain if busybox isn't suid
+ and is run by non-root (applet_main() will not be called at all)
+ _BB_SUID_NEVER: will drop suid prior to applet_main()
+ _BB_SUID_MAYBE: neither of the above
+*/
+
+#if defined(PROTOTYPES)
+# define APPLET(name,l,s) int name##_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+# define APPLET_ODDNAME(name,main,l,s,name2) int main##_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+# define APPLET_NOEXEC(name,main,l,s,name2) int main##_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+# define APPLET_NOFORK(name,main,l,s,name2) int main##_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+
+#elif defined(NAME_MAIN_CNAME)
+# define APPLET(name,l,s) name name##_main name
+# define APPLET_ODDNAME(name,main,l,s,name2) name main##_main name2
+# define APPLET_NOEXEC(name,main,l,s,name2) name main##_main name2
+# define APPLET_NOFORK(name,main,l,s,name2) name main##_main name2
+
+#elif defined(MAKE_USAGE) && ENABLE_FEATURE_VERBOSE_USAGE
+# define APPLET(name,l,s) name##_trivial_usage name##_full_usage "\0"
+# define APPLET_ODDNAME(name,main,l,s,name2) name2##_trivial_usage name2##_full_usage "\0"
+# define APPLET_NOEXEC(name,main,l,s,name2) name2##_trivial_usage name2##_full_usage "\0"
+# define APPLET_NOFORK(name,main,l,s,name2) name2##_trivial_usage name2##_full_usage "\0"
+
+#elif defined(MAKE_USAGE) && !ENABLE_FEATURE_VERBOSE_USAGE
+# define APPLET(name,l,s) name##_trivial_usage "\0"
+# define APPLET_ODDNAME(name,main,l,s,name2) name2##_trivial_usage "\0"
+# define APPLET_NOEXEC(name,main,l,s,name2) name2##_trivial_usage "\0"
+# define APPLET_NOFORK(name,main,l,s,name2) name2##_trivial_usage "\0"
+
+#elif defined(MAKE_LINKS)
+# define APPLET(name,l,c) LINK l name
+# define APPLET_ODDNAME(name,main,l,s,name2) LINK l name
+# define APPLET_NOEXEC(name,main,l,s,name2) LINK l name
+# define APPLET_NOFORK(name,main,l,s,name2) LINK l name
+
+#else
+ static struct bb_applet applets[] = { /* name, main, location, need_suid */
+# define APPLET(name,l,s) { #name, #name, l, s },
+# define APPLET_ODDNAME(name,main,l,s,name2) { #name, #main, l, s },
+# define APPLET_NOEXEC(name,main,l,s,name2) { #name, #main, l, s, 1 },
+# define APPLET_NOFORK(name,main,l,s,name2) { #name, #main, l, s, 1, 1 },
+#endif
+
+#if ENABLE_INSTALL_NO_USR
+# define _BB_DIR_USR_BIN _BB_DIR_BIN
+# define _BB_DIR_USR_SBIN _BB_DIR_SBIN
+#endif
+
+
+USE_TEST(APPLET_NOFORK([, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test))
+USE_TEST(APPLET_NOFORK([[, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test))
+USE_ADDGROUP(APPLET(addgroup, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_ADDUSER(APPLET(adduser, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_ADJTIMEX(APPLET(adjtimex, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_AR(APPLET(ar, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_ARP(APPLET(arp, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_ARPING(APPLET(arping, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_ASH(APPLET(ash, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_AWK(APPLET_NOEXEC(awk, awk, _BB_DIR_USR_BIN, _BB_SUID_NEVER, awk))
+USE_BASENAME(APPLET_NOFORK(basename, basename, _BB_DIR_USR_BIN, _BB_SUID_NEVER, basename))
+USE_BBCONFIG(APPLET(bbconfig, _BB_DIR_BIN, _BB_SUID_NEVER))
+//USE_BBSH(APPLET(bbsh, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_BRCTL(APPLET(brctl, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+USE_BUNZIP2(APPLET(bunzip2, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_BUNZIP2(APPLET_ODDNAME(bzcat, bunzip2, _BB_DIR_USR_BIN, _BB_SUID_NEVER, bzcat))
+USE_BZIP2(APPLET(bzip2, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_CAL(APPLET(cal, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_CAT(APPLET_NOFORK(cat, cat, _BB_DIR_BIN, _BB_SUID_NEVER, cat))
+USE_CATV(APPLET(catv, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_CHAT(APPLET(chat, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_CHATTR(APPLET(chattr, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_CHCON(APPLET(chcon, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_CHGRP(APPLET_NOEXEC(chgrp, chgrp, _BB_DIR_BIN, _BB_SUID_NEVER, chgrp))
+USE_CHMOD(APPLET_NOEXEC(chmod, chmod, _BB_DIR_BIN, _BB_SUID_NEVER, chmod))
+USE_CHOWN(APPLET_NOEXEC(chown, chown, _BB_DIR_BIN, _BB_SUID_NEVER, chown))
+USE_CHPASSWD(APPLET(chpasswd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+USE_CHPST(APPLET(chpst, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_CHROOT(APPLET(chroot, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+USE_CHRT(APPLET(chrt, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_CHVT(APPLET(chvt, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_CKSUM(APPLET(cksum, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_CLEAR(APPLET(clear, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_CMP(APPLET(cmp, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_COMM(APPLET(comm, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_CP(APPLET_NOEXEC(cp, cp, _BB_DIR_BIN, _BB_SUID_NEVER, cp))
+USE_CPIO(APPLET(cpio, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_CROND(APPLET(crond, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+USE_CRONTAB(APPLET(crontab, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS))
+USE_CRYPTPW(APPLET(cryptpw, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_CTTYHACK(APPLET(cttyhack, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_CUT(APPLET_NOEXEC(cut, cut, _BB_DIR_USR_BIN, _BB_SUID_NEVER, cut))
+USE_DATE(APPLET(date, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_DC(APPLET(dc, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_DD(APPLET_NOEXEC(dd, dd, _BB_DIR_BIN, _BB_SUID_NEVER, dd))
+USE_DEALLOCVT(APPLET(deallocvt, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_DELGROUP(APPLET_ODDNAME(delgroup, deluser, _BB_DIR_BIN, _BB_SUID_NEVER, delgroup))
+USE_DELUSER(APPLET(deluser, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_DEPMOD(APPLET(depmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_DEVFSD(APPLET(devfsd, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_DF(APPLET(df, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_APP_DHCPRELAY(APPLET(dhcprelay, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+USE_DIFF(APPLET(diff, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_DIRNAME(APPLET_NOFORK(dirname, dirname, _BB_DIR_USR_BIN, _BB_SUID_NEVER, dirname))
+USE_DMESG(APPLET(dmesg, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_DNSD(APPLET(dnsd, _BB_DIR_USR_SBIN, _BB_SUID_ALWAYS))
+USE_DOS2UNIX(APPLET(dos2unix, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_DPKG(APPLET(dpkg, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_DPKG_DEB(APPLET_ODDNAME(dpkg-deb, dpkg_deb, _BB_DIR_USR_BIN, _BB_SUID_NEVER, dpkg_deb))
+USE_DU(APPLET(du, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_DUMPKMAP(APPLET(dumpkmap, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_APP_DUMPLEASES(APPLET(dumpleases, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+//USE_E2FSCK(APPLET(e2fsck, _BB_DIR_SBIN, _BB_SUID_NEVER))
+//USE_E2LABEL(APPLET_ODDNAME(e2label, tune2fs, _BB_DIR_SBIN, _BB_SUID_NEVER, e2label))
+USE_ECHO(APPLET_NOFORK(echo, echo, _BB_DIR_BIN, _BB_SUID_NEVER, echo))
+USE_ED(APPLET(ed, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_FEATURE_GREP_EGREP_ALIAS(APPLET_ODDNAME(egrep, grep, _BB_DIR_BIN, _BB_SUID_NEVER, egrep))
+USE_EJECT(APPLET(eject, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_ENV(APPLET(env, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_ENVDIR(APPLET_ODDNAME(envdir, chpst, _BB_DIR_USR_BIN, _BB_SUID_NEVER, envdir))
+USE_ENVUIDGID(APPLET_ODDNAME(envuidgid, chpst, _BB_DIR_USR_BIN, _BB_SUID_NEVER, envuidgid))
+USE_ETHER_WAKE(APPLET_ODDNAME(ether-wake, ether_wake, _BB_DIR_USR_BIN, _BB_SUID_NEVER, ether_wake))
+USE_EXPAND(APPLET(expand, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_EXPR(APPLET(expr, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_FAKEIDENTD(APPLET(fakeidentd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+USE_FALSE(APPLET_NOFORK(false, false, _BB_DIR_BIN, _BB_SUID_NEVER, false))
+USE_FBSET(APPLET(fbset, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+USE_FBSPLASH(APPLET(fbsplash, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_FDFLUSH(APPLET_ODDNAME(fdflush, freeramdisk, _BB_DIR_BIN, _BB_SUID_NEVER, fdflush))
+USE_FDFORMAT(APPLET(fdformat, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_FDISK(APPLET(fdisk, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_FETCHMAIL(APPLET_ODDNAME(fetchmail, sendgetmail, _BB_DIR_USR_BIN, _BB_SUID_NEVER, fetchmail))
+USE_FEATURE_GREP_FGREP_ALIAS(APPLET_ODDNAME(fgrep, grep, _BB_DIR_BIN, _BB_SUID_NEVER, fgrep))
+USE_FIND(APPLET_NOEXEC(find, find, _BB_DIR_USR_BIN, _BB_SUID_NEVER, find))
+USE_FINDFS(APPLET(findfs, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_FOLD(APPLET(fold, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_FREE(APPLET(free, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_FREERAMDISK(APPLET(freeramdisk, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_FSCK(APPLET(fsck, _BB_DIR_SBIN, _BB_SUID_NEVER))
+//USE_E2FSCK(APPLET_ODDNAME(fsck.ext2, e2fsck, _BB_DIR_SBIN, _BB_SUID_NEVER, fsck_ext2))
+//USE_E2FSCK(APPLET_ODDNAME(fsck.ext3, e2fsck, _BB_DIR_SBIN, _BB_SUID_NEVER, fsck_ext3))
+USE_FSCK_MINIX(APPLET_ODDNAME(fsck.minix, fsck_minix, _BB_DIR_SBIN, _BB_SUID_NEVER, fsck_minix))
+USE_FTPGET(APPLET_ODDNAME(ftpget, ftpgetput, _BB_DIR_USR_BIN, _BB_SUID_NEVER, ftpget))
+USE_FTPPUT(APPLET_ODDNAME(ftpput, ftpgetput, _BB_DIR_USR_BIN, _BB_SUID_NEVER, ftpput))
+USE_FUSER(APPLET(fuser, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_GETENFORCE(APPLET(getenforce, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+USE_GETOPT(APPLET(getopt, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_GETSEBOOL(APPLET(getsebool, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+USE_GETTY(APPLET(getty, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_GREP(APPLET(grep, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_GUNZIP(APPLET(gunzip, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_GZIP(APPLET(gzip, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_HALT(APPLET(halt, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_HD(APPLET_ODDNAME(hd, hexdump, _BB_DIR_USR_BIN, _BB_SUID_NEVER, hd))
+USE_HDPARM(APPLET(hdparm, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_HEAD(APPLET(head, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_HEXDUMP(APPLET_NOEXEC(hexdump, hexdump, _BB_DIR_USR_BIN, _BB_SUID_NEVER, hexdump))
+USE_HOSTID(APPLET_NOFORK(hostid, hostid, _BB_DIR_USR_BIN, _BB_SUID_NEVER, hostid))
+USE_HOSTNAME(APPLET(hostname, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_HTTPD(APPLET(httpd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+USE_HUSH(APPLET(hush, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_HWCLOCK(APPLET(hwclock, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_ID(APPLET(id, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_IFCONFIG(APPLET(ifconfig, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_IFUPDOWN(APPLET_ODDNAME(ifdown, ifupdown, _BB_DIR_SBIN, _BB_SUID_NEVER, ifdown))
+USE_IFENSLAVE(APPLET(ifenslave, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_IFUPDOWN(APPLET_ODDNAME(ifup, ifupdown, _BB_DIR_SBIN, _BB_SUID_NEVER, ifup))
+USE_INETD(APPLET(inetd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+USE_INIT(APPLET(init, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_INOTIFYD(APPLET(inotifyd, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_INSMOD(APPLET(insmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_INSTALL(APPLET(install, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+#if ENABLE_FEATURE_IP_ADDRESS \
+ || ENABLE_FEATURE_IP_ROUTE \
+ || ENABLE_FEATURE_IP_LINK \
+ || ENABLE_FEATURE_IP_TUNNEL \
+ || ENABLE_FEATURE_IP_RULE
+USE_IP(APPLET(ip, _BB_DIR_BIN, _BB_SUID_NEVER))
+#endif
+USE_IPADDR(APPLET(ipaddr, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_IPCALC(APPLET(ipcalc, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_IPCRM(APPLET(ipcrm, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS))
+USE_IPCS(APPLET(ipcs, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS))
+USE_IPLINK(APPLET(iplink, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_IPROUTE(APPLET(iproute, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_IPRULE(APPLET(iprule, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_IPTUNNEL(APPLET(iptunnel, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_KBD_MODE(APPLET(kbd_mode, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_KILL(APPLET(kill, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_KILLALL(APPLET_ODDNAME(killall, kill, _BB_DIR_USR_BIN, _BB_SUID_NEVER, killall))
+USE_KILLALL5(APPLET_ODDNAME(killall5, kill, _BB_DIR_USR_BIN, _BB_SUID_NEVER, killall5))
+USE_KLOGD(APPLET(klogd, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_LASH(APPLET(lash, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_LAST(APPLET(last, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_LENGTH(APPLET_NOFORK(length, length, _BB_DIR_USR_BIN, _BB_SUID_NEVER, length))
+USE_LESS(APPLET(less, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_SETARCH(APPLET_ODDNAME(linux32, setarch, _BB_DIR_BIN, _BB_SUID_NEVER, linux32))
+USE_SETARCH(APPLET_ODDNAME(linux64, setarch, _BB_DIR_BIN, _BB_SUID_NEVER, linux64))
+USE_FEATURE_INITRD(APPLET_ODDNAME(linuxrc, init, _BB_DIR_ROOT, _BB_SUID_NEVER, linuxrc))
+USE_LN(APPLET_NOEXEC(ln, ln, _BB_DIR_BIN, _BB_SUID_NEVER, ln))
+USE_LOAD_POLICY(APPLET(load_policy, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+USE_LOADFONT(APPLET(loadfont, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_LOADKMAP(APPLET(loadkmap, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_LOGGER(APPLET(logger, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_LOGIN(APPLET(login, _BB_DIR_BIN, _BB_SUID_ALWAYS))
+USE_LOGNAME(APPLET_NOFORK(logname, logname, _BB_DIR_USR_BIN, _BB_SUID_NEVER, logname))
+USE_LOGREAD(APPLET(logread, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_LOSETUP(APPLET(losetup, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_LPD(APPLET(lpd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+USE_LPQ(APPLET_ODDNAME(lpq, lpqr, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lpq))
+USE_LPR(APPLET_ODDNAME(lpr, lpqr, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lpr))
+USE_LS(APPLET_NOEXEC(ls, ls, _BB_DIR_BIN, _BB_SUID_NEVER, ls))
+USE_LSATTR(APPLET(lsattr, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_LSMOD(APPLET(lsmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_UNLZMA(APPLET_ODDNAME(lzmacat, unlzma, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lzmacat))
+USE_MAKEDEVS(APPLET(makedevs, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_MAN(APPLET(man, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_MATCHPATHCON(APPLET(matchpathcon, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+USE_MD5SUM(APPLET_ODDNAME(md5sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER, md5sum))
+USE_MDEV(APPLET(mdev, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_MESG(APPLET(mesg, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_MICROCOM(APPLET(microcom, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_MKDIR(APPLET_NOFORK(mkdir, mkdir, _BB_DIR_BIN, _BB_SUID_NEVER, mkdir))
+//USE_MKE2FS(APPLET(mke2fs, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_MKFIFO(APPLET(mkfifo, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+//USE_MKE2FS(APPLET_ODDNAME(mkfs.ext2, mke2fs, _BB_DIR_SBIN, _BB_SUID_NEVER, mkfs_ext2))
+//USE_MKE2FS(APPLET_ODDNAME(mkfs.ext3, mke2fs, _BB_DIR_SBIN, _BB_SUID_NEVER, mkfs_ext3))
+USE_MKFS_MINIX(APPLET_ODDNAME(mkfs.minix, mkfs_minix, _BB_DIR_SBIN, _BB_SUID_NEVER, mkfs_minix))
+USE_MKNOD(APPLET(mknod, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_MKSWAP(APPLET(mkswap, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_MKTEMP(APPLET(mktemp, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_MODPROBE(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_MORE(APPLET(more, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_MOUNT(APPLET(mount, _BB_DIR_BIN, USE_DESKTOP(_BB_SUID_MAYBE) SKIP_DESKTOP(_BB_SUID_NEVER)))
+USE_MOUNTPOINT(APPLET(mountpoint, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_MSH(APPLET(msh, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_MT(APPLET(mt, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_MV(APPLET(mv, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_NAMEIF(APPLET(nameif, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_NC(APPLET(nc, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_NETSTAT(APPLET(netstat, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_NICE(APPLET(nice, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_NMETER(APPLET(nmeter, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_NOHUP(APPLET(nohup, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_NSLOOKUP(APPLET(nslookup, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_OD(APPLET(od, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_OPENVT(APPLET(openvt, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_PASSWD(APPLET(passwd, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS))
+USE_PATCH(APPLET(patch, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_PGREP(APPLET(pgrep, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_PIDOF(APPLET(pidof, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_PING(APPLET(ping, _BB_DIR_BIN, _BB_SUID_MAYBE))
+USE_PING6(APPLET(ping6, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_PIPE_PROGRESS(APPLET(pipe_progress, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_PIVOT_ROOT(APPLET(pivot_root, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_PKILL(APPLET_ODDNAME(pkill, pgrep, _BB_DIR_USR_BIN, _BB_SUID_NEVER, pkill))
+USE_HALT(APPLET_ODDNAME(poweroff, halt, _BB_DIR_SBIN, _BB_SUID_NEVER, poweroff))
+USE_PRINTENV(APPLET(printenv, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_PRINTF(APPLET_NOFORK(printf, printf, _BB_DIR_USR_BIN, _BB_SUID_NEVER, printf))
+USE_PS(APPLET(ps, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_PSCAN(APPLET(pscan, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_PWD(APPLET_NOFORK(pwd, pwd, _BB_DIR_BIN, _BB_SUID_NEVER, pwd))
+USE_RAIDAUTORUN(APPLET(raidautorun, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_RDATE(APPLET(rdate, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+USE_READAHEAD(APPLET(readahead, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_READLINK(APPLET(readlink, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_READPROFILE(APPLET(readprofile, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+USE_REALPATH(APPLET(realpath, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_HALT(APPLET_ODDNAME(reboot, halt, _BB_DIR_SBIN, _BB_SUID_NEVER, reboot))
+USE_RENICE(APPLET(renice, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_RESET(APPLET(reset, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_RESIZE(APPLET(resize, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_RESTORECON(APPLET_ODDNAME(restorecon, setfiles, _BB_DIR_SBIN, _BB_SUID_NEVER, restorecon))
+USE_RM(APPLET_NOFORK(rm, rm, _BB_DIR_BIN, _BB_SUID_NEVER, rm))
+USE_RMDIR(APPLET_NOFORK(rmdir, rmdir, _BB_DIR_BIN, _BB_SUID_NEVER, rmdir))
+USE_RMMOD(APPLET(rmmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_ROUTE(APPLET(route, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_RPM(APPLET(rpm, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_RPM2CPIO(APPLET(rpm2cpio, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_RTCWAKE(APPLET(rtcwake, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_RUN_PARTS(APPLET_ODDNAME(run-parts, run_parts, _BB_DIR_BIN, _BB_SUID_NEVER, run_parts))
+USE_RUNCON(APPLET(runcon, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_RUNLEVEL(APPLET(runlevel, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_RUNSV(APPLET(runsv, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_RUNSVDIR(APPLET(runsvdir, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_RX(APPLET(rx, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_SCRIPT(APPLET(script, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_SED(APPLET(sed, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_SELINUXENABLED(APPLET(selinuxenabled, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+USE_SENDMAIL(APPLET_ODDNAME(sendmail, sendgetmail, _BB_DIR_USR_BIN, _BB_SUID_NEVER, sendmail))
+USE_SEQ(APPLET_NOFORK(seq, seq, _BB_DIR_USR_BIN, _BB_SUID_NEVER, seq))
+USE_SESTATUS(APPLET(sestatus, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+USE_SETARCH(APPLET(setarch, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_SETCONSOLE(APPLET(setconsole, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_SETENFORCE(APPLET(setenforce, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+USE_SETFILES(APPLET(setfiles, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_SETKEYCODES(APPLET(setkeycodes, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_SETLOGCONS(APPLET(setlogcons, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+USE_SETSEBOOL(APPLET(setsebool, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+USE_SETSID(APPLET(setsid, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_SETUIDGID(APPLET_ODDNAME(setuidgid, chpst, _BB_DIR_USR_BIN, _BB_SUID_NEVER, setuidgid))
+USE_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, _BB_DIR_BIN, _BB_SUID_NEVER, sh))
+USE_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, _BB_DIR_BIN, _BB_SUID_NEVER, sh))
+USE_FEATURE_SH_IS_MSH(APPLET_ODDNAME(sh, msh, _BB_DIR_BIN, _BB_SUID_NEVER, sh))
+USE_SHA1SUM(APPLET_ODDNAME(sha1sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER, sha1sum))
+USE_SLATTACH(APPLET(slattach, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_SLEEP(APPLET_NOFORK(sleep, sleep, _BB_DIR_BIN, _BB_SUID_NEVER, sleep))
+USE_SOFTLIMIT(APPLET_ODDNAME(softlimit, chpst, _BB_DIR_USR_BIN, _BB_SUID_NEVER, softlimit))
+USE_SORT(APPLET_NOEXEC(sort, sort, _BB_DIR_USR_BIN, _BB_SUID_NEVER, sort))
+USE_SPLIT(APPLET(split, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_START_STOP_DAEMON(APPLET_ODDNAME(start-stop-daemon, start_stop_daemon, _BB_DIR_SBIN, _BB_SUID_NEVER, start_stop_daemon))
+USE_STAT(APPLET(stat, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_STRINGS(APPLET(strings, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_STTY(APPLET(stty, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_SU(APPLET(su, _BB_DIR_BIN, _BB_SUID_ALWAYS))
+USE_SULOGIN(APPLET(sulogin, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_SUM(APPLET(sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_SV(APPLET(sv, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_SVLOGD(APPLET(svlogd, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_SWAPONOFF(APPLET_ODDNAME(swapoff, swap_on_off, _BB_DIR_SBIN, _BB_SUID_NEVER,swapoff))
+USE_SWAPONOFF(APPLET_ODDNAME(swapon, swap_on_off, _BB_DIR_SBIN, _BB_SUID_NEVER, swapon))
+USE_SWITCH_ROOT(APPLET(switch_root, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_SYNC(APPLET_NOFORK(sync, sync, _BB_DIR_BIN, _BB_SUID_NEVER, sync))
+USE_BB_SYSCTL(APPLET(sysctl, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_SYSLOGD(APPLET(syslogd, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_TAC(APPLET_NOEXEC(tac, tac, _BB_DIR_USR_BIN, _BB_SUID_NEVER, tac))
+USE_TAIL(APPLET(tail, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_TAR(APPLET(tar, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_TASKSET(APPLET(taskset, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_TCPSVD(APPLET_ODDNAME(tcpsvd, tcpudpsvd, _BB_DIR_USR_BIN, _BB_SUID_NEVER, tcpsvd))
+USE_TEE(APPLET(tee, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_TELNET(APPLET(telnet, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_TELNETD(APPLET(telnetd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+USE_TEST(APPLET_NOFORK(test, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test))
+#if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT
+USE_TFTP(APPLET(tftp, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_TFTPD(APPLET(tftpd, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+#endif
+USE_TIME(APPLET(time, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_TOP(APPLET(top, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_TOUCH(APPLET_NOFORK(touch, touch, _BB_DIR_BIN, _BB_SUID_NEVER, touch))
+USE_TR(APPLET(tr, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_TRACEROUTE(APPLET(traceroute, _BB_DIR_USR_BIN, _BB_SUID_MAYBE))
+USE_TRUE(APPLET_NOFORK(true, true, _BB_DIR_BIN, _BB_SUID_NEVER, true))
+USE_TTY(APPLET(tty, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_TTYSIZE(APPLET(ttysize, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+//USE_TUNE2FS(APPLET(tune2fs, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_APP_UDHCPC(APPLET(udhcpc, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_APP_UDHCPD(APPLET(udhcpd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+USE_UDPSVD(APPLET_ODDNAME(udpsvd, tcpudpsvd, _BB_DIR_USR_BIN, _BB_SUID_NEVER, udpsvd))
+USE_UMOUNT(APPLET(umount, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_UNAME(APPLET(uname, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_UNCOMPRESS(APPLET(uncompress, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_UNEXPAND(APPLET_ODDNAME(unexpand, expand, _BB_DIR_USR_BIN, _BB_SUID_NEVER, unexpand))
+USE_UNIQ(APPLET(uniq, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_UNIX2DOS(APPLET_ODDNAME(unix2dos, dos2unix, _BB_DIR_USR_BIN, _BB_SUID_NEVER, unix2dos))
+USE_UNLZMA(APPLET(unlzma, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_UNZIP(APPLET(unzip, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_UPTIME(APPLET(uptime, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_USLEEP(APPLET_NOFORK(usleep, usleep, _BB_DIR_BIN, _BB_SUID_NEVER, usleep))
+USE_UUDECODE(APPLET(uudecode, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_UUENCODE(APPLET(uuencode, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_VCONFIG(APPLET(vconfig, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_VI(APPLET(vi, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_VLOCK(APPLET(vlock, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS))
+USE_WATCH(APPLET(watch, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_WATCHDOG(APPLET(watchdog, _BB_DIR_SBIN, _BB_SUID_NEVER))
+USE_WC(APPLET(wc, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_WGET(APPLET(wget, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_WHICH(APPLET(which, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_WHO(APPLET(who, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_WHOAMI(APPLET_NOFORK(whoami, whoami, _BB_DIR_USR_BIN, _BB_SUID_NEVER, whoami))
+USE_XARGS(APPLET_NOEXEC(xargs, xargs, _BB_DIR_USR_BIN, _BB_SUID_NEVER, xargs))
+USE_YES(APPLET_NOFORK(yes, yes, _BB_DIR_USR_BIN, _BB_SUID_NEVER, yes))
+USE_GUNZIP(APPLET_ODDNAME(zcat, gunzip, _BB_DIR_BIN, _BB_SUID_NEVER, zcat))
+USE_ZCIP(APPLET(zcip, _BB_DIR_SBIN, _BB_SUID_NEVER))
+
+#if !defined(PROTOTYPES) && !defined(NAME_MAIN_CNAME) && !defined(MAKE_USAGE)
+};
+#endif
+
+#undef APPLET
+#undef APPLET_ODDNAME
+#undef APPLET_NOEXEC
+#undef APPLET_NOFORK
diff --git a/cleopatre/busybox-1.11.1-spc300/include/busybox.h b/cleopatre/busybox-1.11.1-spc300/include/busybox.h
new file mode 100644
index 0000000000..314b95126f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/include/busybox.h
@@ -0,0 +1,78 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Busybox main internal header file
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+#ifndef _BB_INTERNAL_H_
+#define _BB_INTERNAL_H_ 1
+
+#include "libbb.h"
+
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility push(hidden)
+#endif
+
+/* order matters: used as index into "install_dir[]" in appletlib.c */
+typedef enum bb_install_loc_t {
+ _BB_DIR_ROOT = 0,
+ _BB_DIR_BIN,
+ _BB_DIR_SBIN,
+ _BB_DIR_USR_BIN,
+ _BB_DIR_USR_SBIN
+} bb_install_loc_t;
+
+typedef enum bb_suid_t {
+ _BB_SUID_NEVER = 0,
+ _BB_SUID_MAYBE,
+ _BB_SUID_ALWAYS
+} bb_suid_t;
+
+
+/* Defined in appletlib.c (by including generated applet_tables.h) */
+/* Keep in sync with applets/applet_tables.c! */
+extern const char applet_names[];
+extern int (*const applet_main[])(int argc, char **argv);
+extern const uint16_t applet_nameofs[];
+extern const uint8_t applet_install_loc[];
+
+#if ENABLE_FEATURE_SUID || ENABLE_FEATURE_PREFER_APPLETS
+#define APPLET_NAME(i) (applet_names + (applet_nameofs[i] & 0x0fff))
+#else
+#define APPLET_NAME(i) (applet_names + applet_nameofs[i])
+#endif
+
+#if ENABLE_FEATURE_PREFER_APPLETS
+#define APPLET_IS_NOFORK(i) (applet_nameofs[i] & (1 << 12))
+#define APPLET_IS_NOEXEC(i) (applet_nameofs[i] & (1 << 13))
+#endif
+
+#if ENABLE_FEATURE_SUID
+#define APPLET_SUID(i) ((applet_nameofs[i] >> 14) & 0x3)
+#endif
+
+#if ENABLE_FEATURE_INSTALLER
+#define APPLET_INSTALL_LOC(i) ({ \
+ unsigned v = (i); \
+ if (v & 1) v = applet_install_loc[v/2] >> 4; \
+ else v = applet_install_loc[v/2] & 0xf; \
+ v; })
+#endif
+
+
+/* Length of these names has effect on size of libbusybox
+ * and "individual" binaries. Keep them short.
+ */
+#if ENABLE_BUILD_LIBBUSYBOX
+#if ENABLE_FEATURE_SHARED_BUSYBOX
+int lbb_main(char **argv) EXTERNALLY_VISIBLE;
+#else
+int lbb_main(char **argv);
+#endif
+#endif
+
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility pop
+#endif
+
+#endif /* _BB_INTERNAL_H_ */
diff --git a/cleopatre/busybox-1.11.1-spc300/include/dump.h b/cleopatre/busybox-1.11.1-spc300/include/dump.h
new file mode 100644
index 0000000000..20c39c41ee
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/include/dump.h
@@ -0,0 +1,59 @@
+/* vi: set sw=4 ts=4: */
+
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility push(hidden)
+#endif
+
+#define F_IGNORE 0x01 /* %_A */
+#define F_SETREP 0x02 /* rep count set, not default */
+#define F_ADDRESS 0x001 /* print offset */
+#define F_BPAD 0x002 /* blank pad */
+#define F_C 0x004 /* %_c */
+#define F_CHAR 0x008 /* %c */
+#define F_DBL 0x010 /* %[EefGf] */
+#define F_INT 0x020 /* %[di] */
+#define F_P 0x040 /* %_p */
+#define F_STR 0x080 /* %s */
+#define F_U 0x100 /* %_u */
+#define F_UINT 0x200 /* %[ouXx] */
+#define F_TEXT 0x400 /* no conversions */
+
+enum _vflag { ALL, DUP, FIRST, WAIT }; /* -v values */
+
+typedef struct _pr {
+ struct _pr *nextpr; /* next print unit */
+ unsigned int flags; /* flag values */
+ int bcnt; /* byte count */
+ char *cchar; /* conversion character */
+ char *fmt; /* printf format */
+ char *nospace; /* no whitespace version */
+} PR;
+
+typedef struct _fu {
+ struct _fu *nextfu; /* next format unit */
+ struct _pr *nextpr; /* next print unit */
+ unsigned int flags; /* flag values */
+ int reps; /* repetition count */
+ int bcnt; /* byte count */
+ char *fmt; /* format string */
+} FU;
+
+typedef struct _fs { /* format strings */
+ struct _fs *nextfs; /* linked list of format strings */
+ struct _fu *nextfu; /* linked list of format units */
+ int bcnt;
+} FS;
+
+extern void bb_dump_add(const char *fmt);
+extern int bb_dump_dump(char **argv);
+extern int bb_dump_size(FS * fs);
+
+extern FS *bb_dump_fshead; /* head of format strings */
+extern int bb_dump_blocksize; /* data block size */
+extern int bb_dump_length; /* max bytes to read */
+extern enum _vflag bb_dump_vflag;
+extern off_t bb_dump_skip; /* bytes to skip */
+
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility pop
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/include/grp_.h b/cleopatre/busybox-1.11.1-spc300/include/grp_.h
new file mode 100644
index 0000000000..23c4dcc035
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/include/grp_.h
@@ -0,0 +1,128 @@
+/* vi: set sw=4 ts=4: */
+/* Copyright (C) 1991,92,95,96,97,98,99,2000,01 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/*
+ * POSIX Standard: 9.2.1 Group Database Access <grp.h>
+ */
+
+#ifndef _GRP_H
+#define _GRP_H 1
+
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility push(hidden)
+#endif
+
+/* The group structure. */
+struct group {
+ char *gr_name; /* Group name. */
+ char *gr_passwd; /* Password. */
+ gid_t gr_gid; /* Group ID. */
+ char **gr_mem; /* Member list. */
+};
+
+
+#define setgrent bb_internal_setgrent
+#define endgrent bb_internal_endgrent
+#define getgrent bb_internal_getgrent
+#define fgetgrent bb_internal_fgetgrent
+#define putgrent bb_internal_putgrent
+#define getgrgid bb_internal_getgrgid
+#define getgrnam bb_internal_getgrnam
+#define getgrent_r bb_internal_getgrent_r
+#define getgrgid_r bb_internal_getgrgid_r
+#define getgrnam_r bb_internal_getgrnam_r
+#define fgetgrent_r bb_internal_fgetgrent_r
+#define getgrouplist bb_internal_getgrouplist
+#define initgroups bb_internal_initgroups
+
+
+/* All function names below should be remapped by #defines above
+ * in order to not collide with libc names.
+ * In theory it isn't necessary, but I saw weird interactions at link time.
+ * Let's play safe */
+
+
+/* Rewind the group-file stream. */
+extern void setgrent(void);
+
+/* Close the group-file stream. */
+extern void endgrent(void);
+
+/* Read an entry from the group-file stream, opening it if necessary. */
+extern struct group *getgrent(void);
+
+/* Read a group entry from STREAM. */
+extern struct group *fgetgrent(FILE *__stream);
+
+/* Write the given entry onto the given stream. */
+extern int putgrent(__const struct group *__restrict __p,
+ FILE *__restrict __f);
+
+/* Search for an entry with a matching group ID. */
+extern struct group *getgrgid(gid_t __gid);
+
+/* Search for an entry with a matching group name. */
+extern struct group *getgrnam(__const char *__name);
+
+/* Reentrant versions of some of the functions above.
+
+ PLEASE NOTE: the `getgrent_r' function is not (yet) standardized.
+ The interface may change in later versions of this library. But
+ the interface is designed following the principals used for the
+ other reentrant functions so the chances are good this is what the
+ POSIX people would choose. */
+
+extern int getgrent_r(struct group *__restrict __resultbuf,
+ char *__restrict __buffer, size_t __buflen,
+ struct group **__restrict __result);
+
+/* Search for an entry with a matching group ID. */
+extern int getgrgid_r(gid_t __gid, struct group *__restrict __resultbuf,
+ char *__restrict __buffer, size_t __buflen,
+ struct group **__restrict __result);
+
+/* Search for an entry with a matching group name. */
+extern int getgrnam_r(__const char *__restrict __name,
+ struct group *__restrict __resultbuf,
+ char *__restrict __buffer, size_t __buflen,
+ struct group **__restrict __result);
+
+/* Read a group entry from STREAM. This function is not standardized
+ an probably never will. */
+extern int fgetgrent_r(FILE *__restrict __stream,
+ struct group *__restrict __resultbuf,
+ char *__restrict __buffer, size_t __buflen,
+ struct group **__restrict __result);
+
+/* Store at most *NGROUPS members of the group set for USER into
+ *GROUPS. Also include GROUP. The actual number of groups found is
+ returned in *NGROUPS. Return -1 if the if *NGROUPS is too small. */
+extern int getgrouplist(__const char *__user, gid_t __group,
+ gid_t *__groups, int *__ngroups);
+
+/* Initialize the group set for the current user
+ by reading the group database and using all groups
+ of which USER is a member. Also include GROUP. */
+extern int initgroups(__const char *__user, gid_t __group);
+
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility pop
+#endif
+
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/include/inet_common.h b/cleopatre/busybox-1.11.1-spc300/include/inet_common.h
new file mode 100644
index 0000000000..eb4cb73255
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/include/inet_common.h
@@ -0,0 +1,26 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * stolen from net-tools-1.59 and stripped down for busybox by
+ * Erik Andersen <andersen@codepoet.org>
+ *
+ * Heavily modified by Manuel Novoa III Mar 12, 2001
+ *
+ */
+
+#include "platform.h"
+
+/* hostfirst!=0 If we expect this to be a hostname,
+ try hostname database first
+ */
+int INET_resolve(const char *name, struct sockaddr_in *s_in, int hostfirst);
+
+/* numeric: & 0x8000: "default" instead of "*",
+ * & 0x4000: host instead of net,
+ * & 0x0fff: don't resolve
+ */
+
+int INET6_resolve(const char *name, struct sockaddr_in6 *sin6);
+
+/* These return malloced string */
+char *INET_rresolve(struct sockaddr_in *s_in, int numeric, uint32_t netmask);
+char *INET6_rresolve(struct sockaddr_in6 *sin6, int numeric);
diff --git a/cleopatre/busybox-1.11.1-spc300/include/libbb.h b/cleopatre/busybox-1.11.1-spc300/include/libbb.h
new file mode 100644
index 0000000000..e92dbc4c09
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/include/libbb.h
@@ -0,0 +1,1400 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Busybox main internal header file
+ *
+ * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
+ * Permission has been granted to redistribute this code under the GPL.
+ *
+ * Licensed under the GPL version 2, see the file LICENSE in this tarball.
+ */
+#ifndef __LIBBUSYBOX_H__
+#define __LIBBUSYBOX_H__ 1
+
+#include "platform.h"
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <netdb.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <time.h>
+#include <unistd.h>
+#include <utime.h>
+/* Try to pull in PATH_MAX */
+#include <limits.h>
+#include <sys/param.h>
+#ifndef PATH_MAX
+#define PATH_MAX 256
+#endif
+
+#ifdef HAVE_MNTENT_H
+#include <mntent.h>
+#endif
+
+#ifdef HAVE_SYS_STATFS_H
+#include <sys/statfs.h>
+#endif
+
+#if ENABLE_SELINUX
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+#include <selinux/flask.h>
+#include <selinux/av_permissions.h>
+#endif
+
+#if ENABLE_LOCALE_SUPPORT
+#include <locale.h>
+#else
+#define setlocale(x,y) ((void)0)
+#endif
+
+#ifdef DMALLOC
+#include <dmalloc.h>
+#endif
+
+#if !ENABLE_USE_BB_PWD_GRP
+# include <pwd.h>
+# include <grp.h>
+#endif
+#if ENABLE_FEATURE_SHADOWPASSWDS
+# if !ENABLE_USE_BB_SHADOW
+# include <shadow.h>
+# endif
+#endif
+
+/* Some libc's forget to declare these, do it ourself */
+extern char **environ;
+
+/* Set the group set for the current user to GROUPS (N of them). */
+int setgroups(size_t n, const gid_t *groups);
+#if defined(__GLIBC__) && __GLIBC__ < 2
+int vdprintf(int d, const char *format, va_list ap);
+#endif
+/* klogctl is in libc's klog.h, but we cheat and not #include that */
+int klogctl(int type, char *b, int len);
+/* This is declared here rather than #including <libgen.h> in order to avoid
+ * confusing the two versions of basename. See the dirname/basename man page
+ * for details. */
+char *dirname(char *path);
+/* Include our own copy of struct sysinfo to avoid binary compatibility
+ * problems with Linux 2.4, which changed things. Grumble, grumble. */
+struct sysinfo {
+ long uptime; /* Seconds since boot */
+ unsigned long loads[3]; /* 1, 5, and 15 minute load averages */
+ unsigned long totalram; /* Total usable main memory size */
+ unsigned long freeram; /* Available memory size */
+ unsigned long sharedram; /* Amount of shared memory */
+ unsigned long bufferram; /* Memory used by buffers */
+ unsigned long totalswap; /* Total swap space size */
+ unsigned long freeswap; /* swap space still available */
+ unsigned short procs; /* Number of current processes */
+ unsigned short pad; /* Padding needed for m68k */
+ unsigned long totalhigh; /* Total high memory size */
+ unsigned long freehigh; /* Available high memory size */
+ unsigned int mem_unit; /* Memory unit size in bytes */
+ char _f[20 - 2*sizeof(long) - sizeof(int)]; /* Padding: libc5 uses this.. */
+};
+int sysinfo(struct sysinfo* info);
+
+
+/* Make all declarations hidden (-fvisibility flag only affects definitions) */
+/* (don't include system headers after this until corresponding pop!) */
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility push(hidden)
+#endif
+
+
+#if ENABLE_USE_BB_PWD_GRP
+# include "pwd_.h"
+# include "grp_.h"
+#endif
+#if ENABLE_FEATURE_SHADOWPASSWDS
+# if ENABLE_USE_BB_SHADOW
+# include "shadow_.h"
+# endif
+#endif
+
+/* Tested to work correctly with all int types (IIRC :]) */
+#define MAXINT(T) (T)( \
+ ((T)-1) > 0 \
+ ? (T)-1 \
+ : (T)~((T)1 << (sizeof(T)*8-1)) \
+ )
+
+#define MININT(T) (T)( \
+ ((T)-1) > 0 \
+ ? (T)0 \
+ : ((T)1 << (sizeof(T)*8-1)) \
+ )
+
+/* Large file support */
+/* Note that CONFIG_LFS=y forces bbox to be built with all common ops
+ * (stat, lseek etc) mapped to "largefile" variants by libc.
+ * Practically it means that open() automatically has O_LARGEFILE added
+ * and all filesize/file_offset parameters and struct members are "large"
+ * (in today's world - signed 64bit). For full support of large files,
+ * we need a few helper #defines (below) and careful use of off_t
+ * instead of int/ssize_t. No lseek64(), O_LARGEFILE etc necessary */
+#if ENABLE_LFS
+/* CONFIG_LFS is on */
+# if ULONG_MAX > 0xffffffff
+/* "long" is long enough on this system */
+# define XATOOFF(a) xatoul_range(a, 0, LONG_MAX)
+/* usage: sz = BB_STRTOOFF(s, NULL, 10); if (errno || sz < 0) die(); */
+# define BB_STRTOOFF bb_strtoul
+# define STRTOOFF strtoul
+/* usage: printf("size: %"OFF_FMT"d (%"OFF_FMT"x)\n", sz, sz); */
+# define OFF_FMT "l"
+# else
+/* "long" is too short, need "long long" */
+# define XATOOFF(a) xatoull_range(a, 0, LLONG_MAX)
+# define BB_STRTOOFF bb_strtoull
+# define STRTOOFF strtoull
+# define OFF_FMT "ll"
+# endif
+#else
+/* CONFIG_LFS is off */
+# if UINT_MAX == 0xffffffff
+/* While sizeof(off_t) == sizeof(int), off_t is typedef'ed to long anyway.
+ * gcc will throw warnings on printf("%d", off_t). Crap... */
+# define XATOOFF(a) xatoi_u(a)
+# define BB_STRTOOFF bb_strtou
+# define STRTOOFF strtol
+# define OFF_FMT "l"
+# else
+# define XATOOFF(a) xatoul_range(a, 0, LONG_MAX)
+# define BB_STRTOOFF bb_strtoul
+# define STRTOOFF strtol
+# define OFF_FMT "l"
+# endif
+#endif
+/* scary. better ideas? (but do *test* them first!) */
+#define OFF_T_MAX ((off_t)~((off_t)1 << (sizeof(off_t)*8-1)))
+
+/* Some useful definitions */
+#undef FALSE
+#define FALSE ((int) 0)
+#undef TRUE
+#define TRUE ((int) 1)
+#undef SKIP
+#define SKIP ((int) 2)
+
+/* for mtab.c */
+#define MTAB_GETMOUNTPT '1'
+#define MTAB_GETDEVICE '2'
+
+#define BUF_SIZE 8192
+#define EXPAND_ALLOC 1024
+
+/* Macros for min/max. */
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+#ifndef MAX
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+
+/* buffer allocation schemes */
+#if ENABLE_FEATURE_BUFFERS_GO_ON_STACK
+#define RESERVE_CONFIG_BUFFER(buffer,len) char buffer[len]
+#define RESERVE_CONFIG_UBUFFER(buffer,len) unsigned char buffer[len]
+#define RELEASE_CONFIG_BUFFER(buffer) ((void)0)
+#else
+#if ENABLE_FEATURE_BUFFERS_GO_IN_BSS
+#define RESERVE_CONFIG_BUFFER(buffer,len) static char buffer[len]
+#define RESERVE_CONFIG_UBUFFER(buffer,len) static unsigned char buffer[len]
+#define RELEASE_CONFIG_BUFFER(buffer) ((void)0)
+#else
+#define RESERVE_CONFIG_BUFFER(buffer,len) char *buffer = xmalloc(len)
+#define RESERVE_CONFIG_UBUFFER(buffer,len) unsigned char *buffer = xmalloc(len)
+#define RELEASE_CONFIG_BUFFER(buffer) free(buffer)
+#endif
+#endif
+
+#if defined(__GLIBC__)
+/* glibc uses __errno_location() to get a ptr to errno */
+/* We can just memorize it once - no multithreading in busybox :) */
+extern int *const bb_errno;
+#undef errno
+#define errno (*bb_errno)
+#endif
+
+unsigned long long monotonic_us(void);
+unsigned monotonic_sec(void);
+
+extern void chomp(char *s);
+extern void trim(char *s);
+extern char *skip_whitespace(const char *);
+extern char *skip_non_whitespace(const char *);
+extern char *strrstr(const char *haystack, const char *needle);
+
+//TODO: supply a pointer to char[11] buffer (avoid statics)?
+extern const char *bb_mode_string(mode_t mode);
+extern int is_directory(const char *name, int followLinks, struct stat *statBuf);
+enum { /* DO NOT CHANGE THESE VALUES! cp.c, mv.c, install.c depend on them. */
+ FILEUTILS_PRESERVE_STATUS = 1,
+ FILEUTILS_DEREFERENCE = 2,
+ FILEUTILS_RECUR = 4,
+ FILEUTILS_FORCE = 8,
+ FILEUTILS_INTERACTIVE = 0x10,
+ FILEUTILS_MAKE_HARDLINK = 0x20,
+ FILEUTILS_MAKE_SOFTLINK = 0x40,
+ FILEUTILS_DEREF_SOFTLINK = 0x80,
+#if ENABLE_SELINUX
+ FILEUTILS_PRESERVE_SECURITY_CONTEXT = 0x100,
+ FILEUTILS_SET_SECURITY_CONTEXT = 0x200
+#endif
+};
+#define FILEUTILS_CP_OPTSTR "pdRfilsL" USE_SELINUX("c")
+extern int remove_file(const char *path, int flags);
+/* NB: without FILEUTILS_RECUR in flags, it will basically "cat"
+ * the source, not copy (unless "source" is a directory).
+ * This makes "cp /dev/null file" and "install /dev/null file" (!!!)
+ * work coreutils-compatibly. */
+extern int copy_file(const char *source, const char *dest, int flags);
+
+enum {
+ ACTION_RECURSE = (1 << 0),
+ ACTION_FOLLOWLINKS = (1 << 1),
+ ACTION_FOLLOWLINKS_L0 = (1 << 2),
+ ACTION_DEPTHFIRST = (1 << 3),
+ /*ACTION_REVERSE = (1 << 4), - unused */
+};
+extern int recursive_action(const char *fileName, unsigned flags,
+ int (*fileAction) (const char *fileName, struct stat* statbuf, void* userData, int depth),
+ int (*dirAction) (const char *fileName, struct stat* statbuf, void* userData, int depth),
+ void* userData, unsigned depth);
+extern int device_open(const char *device, int mode);
+enum { GETPTY_BUFSIZE = 16 }; /* more than enough for "/dev/ttyXXX" */
+extern int xgetpty(char *line);
+extern int get_console_fd(void);
+extern void console_make_active(int fd, const int vt_num);
+extern char *find_block_device(const char *path);
+/* bb_copyfd_XX print read/write errors and return -1 if they occur */
+extern off_t bb_copyfd_eof(int fd1, int fd2);
+extern off_t bb_copyfd_size(int fd1, int fd2, off_t size);
+extern void bb_copyfd_exact_size(int fd1, int fd2, off_t size);
+/* "short" copy can be detected by return value < size */
+/* this helper yells "short read!" if param is not -1 */
+extern void complain_copyfd_and_die(off_t sz) ATTRIBUTE_NORETURN;
+extern char bb_process_escape_sequence(const char **ptr);
+/* xxxx_strip version can modify its parameter:
+ * "/" -> "/"
+ * "abc" -> "abc"
+ * "abc/def" -> "def"
+ * "abc/def/" -> "def" !!
+ */
+extern char *bb_get_last_path_component_strip(char *path);
+/* "abc/def/" -> "" and it never modifies 'path' */
+extern char *bb_get_last_path_component_nostrip(const char *path);
+
+int ndelay_on(int fd);
+int ndelay_off(int fd);
+int close_on_exec_on(int fd);
+void xdup2(int, int);
+void xmove_fd(int, int);
+
+
+DIR *xopendir(const char *path);
+DIR *warn_opendir(const char *path);
+
+/* UNUSED: char *xmalloc_realpath(const char *path); */
+char *xmalloc_readlink(const char *path);
+char *xmalloc_readlink_or_warn(const char *path);
+char *xrealloc_getcwd_or_warn(char *cwd);
+
+char *xmalloc_follow_symlinks(const char *path);
+
+
+enum {
+ /* bb_signals(BB_FATAL_SIGS, handler) catches all signals which
+ * otherwise would kill us, except for those resulting from bugs:
+ * SIGSEGV, SIGILL, SIGFPE.
+ * Other fatal signals not included (TODO?):
+ * SIGBUS Bus error (bad memory access)
+ * SIGPOLL Pollable event. Synonym of SIGIO
+ * SIGPROF Profiling timer expired
+ * SIGSYS Bad argument to routine
+ * SIGTRAP Trace/breakpoint trap
+ *
+ * The only known arch with some of these sigs not fitting
+ * into 32 bits is parisc (SIGXCPU=33, SIGXFSZ=34, SIGSTKFLT=36).
+ * Dance around with long long to guard against that...
+ */
+ BB_FATAL_SIGS = (int)(0
+ + (1LL << SIGHUP)
+ + (1LL << SIGINT)
+ + (1LL << SIGTERM)
+ + (1LL << SIGPIPE) // Write to pipe with no readers
+ + (1LL << SIGQUIT) // Quit from keyboard
+ + (1LL << SIGABRT) // Abort signal from abort(3)
+ + (1LL << SIGALRM) // Timer signal from alarm(2)
+ + (1LL << SIGVTALRM) // Virtual alarm clock
+ + (1LL << SIGXCPU) // CPU time limit exceeded
+ + (1LL << SIGXFSZ) // File size limit exceeded
+ + (1LL << SIGUSR1) // Yes kids, these are also fatal!
+ + (1LL << SIGUSR2)
+ + 0),
+};
+void bb_signals(int sigs, void (*f)(int));
+/* Unlike signal() and bb_signals, sets handler with sigaction()
+ * and in a way that while signal handler is run, no other signals
+ * will be blocked: */
+void bb_signals_recursive(int sigs, void (*f)(int));
+/* syscalls like read() will be interrupted with EINTR: */
+void signal_no_SA_RESTART_empty_mask(int sig, void (*handler)(int));
+/* syscalls like read() won't be interrupted (though select/poll will be): */
+void signal_SA_RESTART_empty_mask(int sig, void (*handler)(int));
+void wait_for_any_sig(void);
+void kill_myself_with_sig(int sig) ATTRIBUTE_NORETURN;
+void sig_block(int sig);
+void sig_unblock(int sig);
+/* Will do sigaction(signum, act, NULL): */
+int sigaction_set(int sig, const struct sigaction *act);
+/* SIG_BLOCK/SIG_UNBLOCK all signals: */
+int sigprocmask_allsigs(int how);
+
+
+void xsetgid(gid_t gid);
+void xsetuid(uid_t uid);
+void xchdir(const char *path);
+void xchroot(const char *path);
+void xsetenv(const char *key, const char *value);
+void xunlink(const char *pathname);
+void xstat(const char *pathname, struct stat *buf);
+int xopen(const char *pathname, int flags);
+int xopen3(const char *pathname, int flags, int mode);
+int open_or_warn(const char *pathname, int flags);
+int open3_or_warn(const char *pathname, int flags, int mode);
+int open_or_warn_stdin(const char *pathname);
+void xrename(const char *oldpath, const char *newpath);
+int rename_or_warn(const char *oldpath, const char *newpath);
+off_t xlseek(int fd, off_t offset, int whence);
+off_t fdlength(int fd);
+
+void xpipe(int filedes[2]);
+/* In this form code with pipes is much more readable */
+struct fd_pair { int rd; int wr; };
+#define piped_pair(pair) pipe(&((pair).rd))
+#define xpiped_pair(pair) xpipe(&((pair).rd))
+
+/* Useful for having small structure members/global variables */
+typedef int8_t socktype_t;
+typedef int8_t family_t;
+struct BUG_too_small {
+ char BUG_socktype_t_too_small[(0
+ | SOCK_STREAM
+ | SOCK_DGRAM
+ | SOCK_RDM
+ | SOCK_SEQPACKET
+ | SOCK_RAW
+ ) <= 127 ? 1 : -1];
+ char BUG_family_t_too_small[(0
+ | AF_UNSPEC
+ | AF_INET
+ | AF_INET6
+ | AF_UNIX
+#ifdef AF_PACKET
+ | AF_PACKET
+#endif
+#ifdef AF_NETLINK
+ | AF_NETLINK
+#endif
+ /* | AF_DECnet */
+ /* | AF_IPX */
+ ) <= 127 ? 1 : -1];
+};
+
+
+int xsocket(int domain, int type, int protocol);
+void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
+void xlisten(int s, int backlog);
+void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen);
+ssize_t xsendto(int s, const void *buf, size_t len, const struct sockaddr *to,
+ socklen_t tolen);
+/* SO_REUSEADDR allows a server to rebind to an address that is already
+ * "in use" by old connections to e.g. previous server instance which is
+ * killed or crashed. Without it bind will fail until all such connections
+ * time out. Linux does not allow multiple live binds on same ip:port
+ * regardless of SO_REUSEADDR (unlike some other flavors of Unix).
+ * Turn it on before you call bind(). */
+void setsockopt_reuseaddr(int fd); /* On Linux this never fails. */
+int setsockopt_broadcast(int fd);
+/* NB: returns port in host byte order */
+unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default_port);
+typedef struct len_and_sockaddr {
+ socklen_t len;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+#if ENABLE_FEATURE_IPV6
+ struct sockaddr_in6 sin6;
+#endif
+ } u;
+} len_and_sockaddr;
+enum {
+ LSA_LEN_SIZE = offsetof(len_and_sockaddr, u),
+ LSA_SIZEOF_SA = sizeof(
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+#if ENABLE_FEATURE_IPV6
+ struct sockaddr_in6 sin6;
+#endif
+ }
+ )
+};
+/* Create stream socket, and allocate suitable lsa.
+ * (lsa of correct size and lsa->sa.sa_family (AF_INET/AF_INET6))
+ * af == AF_UNSPEC will result in trying to create IPv6 socket,
+ * and if kernel doesn't support it, IPv4.
+ */
+#if ENABLE_FEATURE_IPV6
+int xsocket_type(len_and_sockaddr **lsap, int af, int sock_type);
+#else
+int xsocket_type(len_and_sockaddr **lsap, int sock_type);
+#define xsocket_type(lsap, af, sock_type) xsocket_type((lsap), (sock_type))
+#endif
+int xsocket_stream(len_and_sockaddr **lsap);
+/* Create server socket bound to bindaddr:port. bindaddr can be NULL,
+ * numeric IP ("N.N.N.N") or numeric IPv6 address,
+ * and can have ":PORT" suffix (for IPv6 use "[X:X:...:X]:PORT").
+ * Only if there is no suffix, port argument is used */
+/* NB: these set SO_REUSEADDR before bind */
+int create_and_bind_stream_or_die(const char *bindaddr, int port);
+int create_and_bind_dgram_or_die(const char *bindaddr, int port);
+/* Create client TCP socket connected to peer:port. Peer cannot be NULL.
+ * Peer can be numeric IP ("N.N.N.N"), numeric IPv6 address or hostname,
+ * and can have ":PORT" suffix (for IPv6 use "[X:X:...:X]:PORT").
+ * If there is no suffix, port argument is used */
+int create_and_connect_stream_or_die(const char *peer, int port);
+/* Connect to peer identified by lsa */
+int xconnect_stream(const len_and_sockaddr *lsa);
+/* Return malloc'ed len_and_sockaddr with socket address of host:port
+ * Currently will return IPv4 or IPv6 sockaddrs only
+ * (depending on host), but in theory nothing prevents e.g.
+ * UNIX socket address being returned, IPX sockaddr etc...
+ * On error does bb_error_msg and returns NULL */
+len_and_sockaddr* host2sockaddr(const char *host, int port);
+/* Version which dies on error */
+len_and_sockaddr* xhost2sockaddr(const char *host, int port);
+len_and_sockaddr* xdotted2sockaddr(const char *host, int port);
+/* Same, useful if you want to force family (e.g. IPv6) */
+#if !ENABLE_FEATURE_IPV6
+#define host_and_af2sockaddr(host, port, af) host2sockaddr((host), (port))
+#define xhost_and_af2sockaddr(host, port, af) xhost2sockaddr((host), (port))
+#else
+len_and_sockaddr* host_and_af2sockaddr(const char *host, int port, sa_family_t af);
+len_and_sockaddr* xhost_and_af2sockaddr(const char *host, int port, sa_family_t af);
+#endif
+/* Assign sin[6]_port member if the socket is an AF_INET[6] one,
+ * otherwise no-op. Useful for ftp.
+ * NB: does NOT do htons() internally, just direct assignment. */
+void set_nport(len_and_sockaddr *lsa, unsigned port);
+/* Retrieve sin[6]_port or return -1 for non-INET[6] lsa's */
+int get_nport(const struct sockaddr *sa);
+/* Reverse DNS. Returns NULL on failure. */
+char* xmalloc_sockaddr2host(const struct sockaddr *sa);
+/* This one doesn't append :PORTNUM */
+char* xmalloc_sockaddr2host_noport(const struct sockaddr *sa);
+/* This one also doesn't fall back to dotted IP (returns NULL) */
+char* xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa);
+/* inet_[ap]ton on steroids */
+char* xmalloc_sockaddr2dotted(const struct sockaddr *sa);
+char* xmalloc_sockaddr2dotted_noport(const struct sockaddr *sa);
+// "old" (ipv4 only) API
+// users: traceroute.c hostname.c - use _list_ of all IPs
+struct hostent *xgethostbyname(const char *name);
+// Also mount.c and inetd.c are using gethostbyname(),
+// + inet_common.c has additional IPv4-only stuff
+
+
+void socket_want_pktinfo(int fd);
+ssize_t send_to_from(int fd, void *buf, size_t len, int flags,
+ const struct sockaddr *to,
+ const struct sockaddr *from,
+ socklen_t tolen);
+ssize_t recv_from_to(int fd, void *buf, size_t len, int flags,
+ struct sockaddr *from,
+ struct sockaddr *to,
+ socklen_t sa_size);
+
+char *xstrdup(const char *s);
+char *xstrndup(const char *s, int n);
+char *safe_strncpy(char *dst, const char *src, size_t size);
+/* Guaranteed to NOT be a macro (smallest code). Saves nearly 2k on uclibc.
+ * But potentially slow, don't use in one-billion-times loops */
+int bb_putchar(int ch);
+char *xasprintf(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
+/* Prints unprintable chars ch as ^C or M-c to file
+ * (M-c is used only if ch is ORed with PRINTABLE_META),
+ * else it is printed as-is (except for ch = 0x9b) */
+enum { PRINTABLE_META = 0x100 };
+void fputc_printable(int ch, FILE *file);
+// gcc-4.1.1 still isn't good enough at optimizing it
+// (+200 bytes compared to macro)
+//static ALWAYS_INLINE
+//int LONE_DASH(const char *s) { return s[0] == '-' && !s[1]; }
+//static ALWAYS_INLINE
+//int NOT_LONE_DASH(const char *s) { return s[0] != '-' || s[1]; }
+#define LONE_DASH(s) ((s)[0] == '-' && !(s)[1])
+#define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1])
+#define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1])
+#define NOT_LONE_CHAR(s,c) ((s)[0] != (c) || (s)[1])
+#define DOT_OR_DOTDOT(s) ((s)[0] == '.' && (!(s)[1] || ((s)[1] == '.' && !(s)[2])))
+
+/* dmalloc will redefine these to it's own implementation. It is safe
+ * to have the prototypes here unconditionally. */
+extern void *malloc_or_warn(size_t size);
+extern void *xmalloc(size_t size);
+extern void *xzalloc(size_t size);
+extern void *xrealloc(void *old, size_t size);
+
+extern ssize_t safe_read(int fd, void *buf, size_t count);
+extern ssize_t nonblock_safe_read(int fd, void *buf, size_t count);
+// NB: will return short read on error, not -1,
+// if some data was read before error occurred
+extern ssize_t full_read(int fd, void *buf, size_t count);
+extern void xread(int fd, void *buf, size_t count);
+extern unsigned char xread_char(int fd);
+// Reads one line a-la fgets (but doesn't save terminating '\n').
+// Uses single full_read() call, works only on seekable streams.
+extern char *reads(int fd, char *buf, size_t count);
+// Reads one line a-la fgets (but doesn't save terminating '\n').
+// Reads byte-by-byte. Useful when it is important to not read ahead.
+// Bytes are appended to pfx (which must be malloced, or NULL).
+extern char *xmalloc_reads(int fd, char *pfx, size_t *maxsz_p);
+extern ssize_t read_close(int fd, void *buf, size_t maxsz);
+extern ssize_t open_read_close(const char *filename, void *buf, size_t maxsz);
+/* Returns NULL if file can't be opened */
+extern void *xmalloc_open_read_close(const char *filename, size_t *maxsz_p);
+/* Never returns NULL */
+extern void *xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p);
+
+extern ssize_t safe_write(int fd, const void *buf, size_t count);
+// NB: will return short write on error, not -1,
+// if some data was written before error occurred
+extern ssize_t full_write(int fd, const void *buf, size_t count);
+extern void xwrite(int fd, const void *buf, size_t count);
+extern void xopen_xwrite_close(const char* file, const char *str);
+
+/* Reads and prints to stdout till eof, then closes FILE. Exits on error: */
+extern void xprint_and_close_file(FILE *file);
+/* Reads up to (and including) TERMINATING_STRING: */
+extern char *xmalloc_fgets_str(FILE *file, const char *terminating_string);
+/* Chops off TERMINATING_STRING from the end: */
+extern char *xmalloc_fgetline_str(FILE *file, const char *terminating_string);
+/* Reads up to (and including) "\n" or NUL byte: */
+extern char *xmalloc_fgets(FILE *file);
+/* Chops off '\n' from the end, unlike fgets: */
+extern char *xmalloc_fgetline(FILE *file);
+extern char *bb_get_chunk_from_file(FILE *file, int *end);
+extern void die_if_ferror(FILE *file, const char *msg);
+extern void die_if_ferror_stdout(void);
+extern void xfflush_stdout(void);
+extern void fflush_stdout_and_exit(int retval) ATTRIBUTE_NORETURN;
+extern int fclose_if_not_stdin(FILE *file);
+extern FILE *xfopen(const char *filename, const char *mode);
+/* Prints warning to stderr and returns NULL on failure: */
+extern FILE *fopen_or_warn(const char *filename, const char *mode);
+/* "Opens" stdin if filename is special, else just opens file: */
+extern FILE *xfopen_stdin(const char *filename);
+extern FILE *fopen_or_warn_stdin(const char *filename);
+
+int bb_pstrcmp(const void *a, const void *b);
+void qsort_string_vector(char **sv, unsigned count);
+
+/* Wrapper which restarts poll on EINTR or ENOMEM.
+ * On other errors complains [perror("poll")] and returns.
+ * Warning! May take (much) longer than timeout_ms to return!
+ * If this is a problem, use bare poll and open-code EINTR/ENOMEM handling */
+int safe_poll(struct pollfd *ufds, nfds_t nfds, int timeout_ms);
+
+char *safe_gethostname(void);
+
+/* Convert each alpha char in str to lower-case */
+char* str_tolower(char *str);
+
+char *utoa(unsigned n);
+char *itoa(int n);
+/* Returns a pointer past the formatted number, does NOT null-terminate */
+char *utoa_to_buf(unsigned n, char *buf, unsigned buflen);
+char *itoa_to_buf(int n, char *buf, unsigned buflen);
+/* Intelligent formatters of bignums */
+void smart_ulltoa4(unsigned long long ul, char buf[5], const char *scale);
+void smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale);
+//TODO: provide pointer to buf (avoid statics)?
+const char *make_human_readable_str(unsigned long long size,
+ unsigned long block_size, unsigned long display_unit);
+/* Put a string of hex bytes ("1b2e66fe"...), return advanced pointer */
+char *bin2hex(char *buf, const char *cp, int count);
+
+/* Last element is marked by mult == 0 */
+struct suffix_mult {
+ char suffix[4];
+ unsigned mult;
+};
+#include "xatonum.h"
+/* Specialized: */
+/* Using xatoi() instead of naive atoi() is not always convenient -
+ * in many places people want *non-negative* values, but store them
+ * in signed int. Therefore we need this one:
+ * dies if input is not in [0, INT_MAX] range. Also will reject '-0' etc */
+int xatoi_u(const char *numstr);
+/* Useful for reading port numbers */
+uint16_t xatou16(const char *numstr);
+
+
+/* These parse entries in /etc/passwd and /etc/group. This is desirable
+ * for BusyBox since we want to avoid using the glibc NSS stuff, which
+ * increases target size and is often not needed on embedded systems. */
+long xuname2uid(const char *name);
+long xgroup2gid(const char *name);
+/* wrapper: allows string to contain numeric uid or gid */
+unsigned long get_ug_id(const char *s, long (*xname2id)(const char *));
+/* from chpst. Does not die, returns 0 on failure */
+struct bb_uidgid_t {
+ uid_t uid;
+ gid_t gid;
+};
+/* always sets uid and gid */
+int get_uidgid(struct bb_uidgid_t*, const char*, int numeric_ok);
+/* chown-like handling of "user[:[group]" */
+void parse_chown_usergroup_or_die(struct bb_uidgid_t *u, char *user_group);
+/* bb_getpwuid, bb_getgrgid:
+ * bb_getXXXid(buf, bufsz, id) - copy user/group name or id
+ * as a string to buf, return user/group name or NULL
+ * bb_getXXXid(NULL, 0, id) - return user/group name or NULL
+ * bb_getXXXid(NULL, -1, id) - return user/group name or exit
+*/
+char *bb_getpwuid(char *name, int bufsize, long uid);
+char *bb_getgrgid(char *group, int bufsize, long gid);
+/* versions which cache results (useful for ps, ls etc) */
+const char* get_cached_username(uid_t uid);
+const char* get_cached_groupname(gid_t gid);
+void clear_username_cache(void);
+/* internally usernames are saved in fixed-sized char[] buffers */
+enum { USERNAME_MAX_SIZE = 16 - sizeof(int) };
+#if ENABLE_FEATURE_CHECK_NAMES
+void die_if_bad_username(const char* name);
+#else
+#define die_if_bad_username(name) ((void)(name))
+#endif
+
+int execable_file(const char *name);
+char *find_execable(const char *filename, char **PATHp);
+int exists_execable(const char *filename);
+
+/* BB_EXECxx always execs (it's not doing NOFORK/NOEXEC stuff),
+ * but it may exec busybox and call applet instead of searching PATH.
+ */
+#if ENABLE_FEATURE_PREFER_APPLETS
+int bb_execvp(const char *file, char *const argv[]);
+#define BB_EXECVP(prog,cmd) bb_execvp(prog,cmd)
+#define BB_EXECLP(prog,cmd,...) \
+ execlp((find_applet_by_name(prog) >= 0) ? CONFIG_BUSYBOX_EXEC_PATH : prog, \
+ cmd, __VA_ARGS__)
+#else
+#define BB_EXECVP(prog,cmd) execvp(prog,cmd)
+#define BB_EXECLP(prog,cmd,...) execlp(prog,cmd, __VA_ARGS__)
+#endif
+
+/* NOMMU friendy fork+exec */
+pid_t spawn(char **argv);
+pid_t xspawn(char **argv);
+
+int safe_waitpid(int pid, int *wstat, int options);
+/* Unlike waitpid, waits ONLY for one process.
+ * It's safe to pass negative 'pids' from failed [v]fork -
+ * wait4pid will return -1 (and will not clobber [v]fork's errno).
+ * IOW: rc = wait4pid(spawn(argv));
+ * if (rc < 0) bb_perror_msg("%s", argv[0]);
+ * if (rc > 0) bb_error_msg("exit code: %d", rc);
+ */
+int wait4pid(int pid);
+int wait_any_nohang(int *wstat);
+#define wait_crashed(w) ((w) & 127)
+#define wait_exitcode(w) ((w) >> 8)
+#define wait_stopsig(w) ((w) >> 8)
+#define wait_stopped(w) (((w) & 127) == 127)
+/* wait4pid(spawn(argv)) + NOFORK/NOEXEC (if configured) */
+int spawn_and_wait(char **argv);
+struct nofork_save_area {
+ jmp_buf die_jmp;
+ const char *applet_name;
+ int xfunc_error_retval;
+ uint32_t option_mask32;
+ int die_sleep;
+ smallint saved;
+};
+void save_nofork_data(struct nofork_save_area *save);
+void restore_nofork_data(struct nofork_save_area *save);
+/* Does NOT check that applet is NOFORK, just blindly runs it */
+int run_nofork_applet(int applet_no, char **argv);
+int run_nofork_applet_prime(struct nofork_save_area *old, int applet_no, char **argv);
+
+/* Helpers for daemonization.
+ *
+ * bb_daemonize(flags) = daemonize, does not compile on NOMMU
+ *
+ * bb_daemonize_or_rexec(flags, argv) = daemonizes on MMU (and ignores argv),
+ * rexec's itself on NOMMU with argv passed as command line.
+ * Thus bb_daemonize_or_rexec may cause your <applet>_main() to be re-executed
+ * from the start. (It will detect it and not reexec again second time).
+ * You have to audit carefully that you don't do something twice as a result
+ * (opening files/sockets, parsing config files etc...)!
+ *
+ * Both of the above will redirect fd 0,1,2 to /dev/null and drop ctty
+ * (will do setsid()).
+ *
+ * forkexit_or_rexec(argv) = bare-bones "fork + parent exits" on MMU,
+ * "vfork + re-exec ourself" on NOMMU. No fd redirection, no setsid().
+ * Currently used for openvt and setsid. On MMU ignores argv.
+ *
+ * Helper for network daemons in foreground mode:
+ *
+ * bb_sanitize_stdio() = make sure that fd 0,1,2 are opened by opening them
+ * to /dev/null if they are not.
+ */
+enum {
+ DAEMON_CHDIR_ROOT = 1,
+ DAEMON_DEVNULL_STDIO = 2,
+ DAEMON_CLOSE_EXTRA_FDS = 4,
+ DAEMON_ONLY_SANITIZE = 8, /* internal use */
+};
+#if BB_MMU
+ void forkexit_or_rexec(void);
+ enum { re_execed = 0 };
+# define forkexit_or_rexec(argv) forkexit_or_rexec()
+# define bb_daemonize_or_rexec(flags, argv) bb_daemonize_or_rexec(flags)
+# define bb_daemonize(flags) bb_daemonize_or_rexec(flags, bogus)
+#else
+ void re_exec(char **argv) ATTRIBUTE_NORETURN;
+ void forkexit_or_rexec(char **argv);
+ extern bool re_execed;
+ int BUG_fork_is_unavailable_on_nommu(void);
+ int BUG_daemon_is_unavailable_on_nommu(void);
+ void BUG_bb_daemonize_is_unavailable_on_nommu(void);
+# define fork() BUG_fork_is_unavailable_on_nommu()
+# define daemon(a,b) BUG_daemon_is_unavailable_on_nommu()
+# define bb_daemonize(a) BUG_bb_daemonize_is_unavailable_on_nommu()
+#endif
+void bb_daemonize_or_rexec(int flags, char **argv);
+void bb_sanitize_stdio(void);
+/* Clear dangerous stuff, set PATH. Return 1 if was run by different user. */
+int sanitize_env_if_suid(void);
+
+
+extern const char *const bb_argv_dash[]; /* "-", NULL */
+extern const char *opt_complementary;
+#if ENABLE_GETOPT_LONG
+#define No_argument "\0"
+#define Required_argument "\001"
+#define Optional_argument "\002"
+extern const char *applet_long_options;
+#endif
+extern uint32_t option_mask32;
+extern uint32_t getopt32(char **argv, const char *applet_opts, ...);
+
+
+typedef struct llist_t {
+ char *data;
+ struct llist_t *link;
+} llist_t;
+void llist_add_to(llist_t **old_head, void *data);
+void llist_add_to_end(llist_t **list_head, void *data);
+void *llist_pop(llist_t **elm);
+void llist_unlink(llist_t **head, llist_t *elm);
+void llist_free(llist_t *elm, void (*freeit)(void *data));
+llist_t *llist_rev(llist_t *list);
+/* BTW, surprisingly, changing API to
+ * llist_t *llist_add_to(llist_t *old_head, void *data)
+ * etc does not result in smaller code... */
+
+/* start_stop_daemon and udhcpc are special - they want
+ * to create pidfiles regardless of FEATURE_PIDFILE */
+#if ENABLE_FEATURE_PIDFILE || defined(WANT_PIDFILE)
+/* True only if we created pidfile which is *file*, not /dev/null etc */
+extern smallint wrote_pidfile;
+void write_pidfile(const char *path);
+#define remove_pidfile(path) do { if (wrote_pidfile) unlink(path); } while (0)
+#else
+enum { wrote_pidfile = 0 };
+#define write_pidfile(path) ((void)0)
+#define remove_pidfile(path) ((void)0)
+#endif
+
+enum {
+ LOGMODE_NONE = 0,
+ LOGMODE_STDIO = (1 << 0),
+ LOGMODE_SYSLOG = (1 << 1) * ENABLE_FEATURE_SYSLOG,
+ LOGMODE_BOTH = LOGMODE_SYSLOG + LOGMODE_STDIO,
+};
+extern const char *msg_eol;
+extern smallint logmode;
+extern int die_sleep;
+extern int xfunc_error_retval;
+extern jmp_buf die_jmp;
+extern void xfunc_die(void) ATTRIBUTE_NORETURN;
+extern void bb_show_usage(void) ATTRIBUTE_NORETURN;
+extern void bb_error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2)));
+extern void bb_error_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2)));
+extern void bb_perror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2)));
+extern void bb_simple_perror_msg(const char *s);
+extern void bb_perror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2)));
+extern void bb_simple_perror_msg_and_die(const char *s) __attribute__ ((noreturn));
+extern void bb_herror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2)));
+extern void bb_herror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2)));
+extern void bb_perror_nomsg_and_die(void) ATTRIBUTE_NORETURN;
+extern void bb_perror_nomsg(void);
+extern void bb_info_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2)));
+extern void bb_verror_msg(const char *s, va_list p, const char *strerr);
+
+/* We need to export XXX_main from libbusybox
+ * only if we build "individual" binaries
+ */
+#if ENABLE_FEATURE_INDIVIDUAL
+#define MAIN_EXTERNALLY_VISIBLE EXTERNALLY_VISIBLE
+#else
+#define MAIN_EXTERNALLY_VISIBLE
+#endif
+
+
+/* Applets which are useful from another applets */
+int bb_cat(char** argv);
+/* If shell needs them, they exist even if not enabled as applets */
+int echo_main(int argc, char** argv) USE_ECHO(MAIN_EXTERNALLY_VISIBLE);
+int printf_main(int argc, char **argv) USE_PRINTF(MAIN_EXTERNALLY_VISIBLE);
+int test_main(int argc, char **argv) USE_TEST(MAIN_EXTERNALLY_VISIBLE);
+int kill_main(int argc, char **argv) USE_KILL(MAIN_EXTERNALLY_VISIBLE);
+/* Similar, but used by chgrp, not shell */
+int chown_main(int argc, char **argv) USE_CHOWN(MAIN_EXTERNALLY_VISIBLE);
+/* Don't need USE_xxx() guard for these */
+int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int bbunpack(char **argv,
+ char* (*make_new_name)(char *filename),
+ USE_DESKTOP(long long) int (*unpacker)(void)
+);
+#if ENABLE_ROUTE
+void bb_displayroutes(int noresolve, int netstatfmt);
+#endif
+
+
+/* Networking */
+int create_icmp_socket(void);
+int create_icmp6_socket(void);
+/* interface.c */
+/* This structure defines protocol families and their handlers. */
+struct aftype {
+ const char *name;
+ const char *title;
+ int af;
+ int alen;
+ char *(*print) (unsigned char *);
+ const char *(*sprint) (struct sockaddr *, int numeric);
+ int (*input) (/*int type,*/ const char *bufp, struct sockaddr *);
+ void (*herror) (char *text);
+ int (*rprint) (int options);
+ int (*rinput) (int typ, int ext, char **argv);
+
+ /* may modify src */
+ int (*getmask) (char *src, struct sockaddr * mask, char *name);
+};
+/* This structure defines hardware protocols and their handlers. */
+struct hwtype {
+ const char *name;
+ const char *title;
+ int type;
+ int alen;
+ char *(*print) (unsigned char *);
+ int (*input) (const char *, struct sockaddr *);
+ int (*activate) (int fd);
+ int suppress_null_addr;
+};
+extern smallint interface_opt_a;
+int display_interfaces(char *ifname);
+#if ENABLE_FEATURE_HWIB
+int in_ib(const char *bufp, struct sockaddr *sap);
+#else
+#define in_ib(a, b) 1 /* fail */
+#endif
+const struct aftype *get_aftype(const char *name);
+const struct hwtype *get_hwtype(const char *name);
+const struct hwtype *get_hwntype(int type);
+
+
+#ifndef BUILD_INDIVIDUAL
+extern int find_applet_by_name(const char *name);
+/* Returns only if applet is not found. */
+extern void run_applet_and_exit(const char *name, char **argv);
+extern void run_applet_no_and_exit(int a, char **argv) ATTRIBUTE_NORETURN;
+#endif
+
+#ifdef HAVE_MNTENT_H
+extern int match_fstype(const struct mntent *mt, const char *fstypes);
+extern struct mntent *find_mount_point(const char *name, const char *table);
+#endif
+extern void erase_mtab(const char * name);
+extern unsigned int tty_baud_to_value(speed_t speed);
+extern speed_t tty_value_to_baud(unsigned int value);
+extern void bb_warn_ignoring_args(int n);
+
+extern int get_linux_version_code(void);
+
+extern char *query_loop(const char *device);
+extern int del_loop(const char *device);
+/* If *devname is not NULL, use that name, otherwise try to find free one,
+ * malloc and return it in *devname.
+ * return value: 1: read-only loopdev was setup, 0: rw, < 0: error */
+extern int set_loop(char **devname, const char *file, unsigned long long offset);
+
+
+//TODO: pass buf pointer or return allocated buf (avoid statics)?
+char *bb_askpass(int timeout, const char * prompt);
+int bb_ask_confirmation(void);
+
+extern int bb_parse_mode(const char* s, mode_t* theMode);
+
+/* Concatenate path and filename to new allocated buffer.
+ * Add "/" only as needed (no duplicate "//" are produced).
+ * If path is NULL, it is assumed to be "/".
+ * filename should not be NULL. */
+char *concat_path_file(const char *path, const char *filename);
+char *concat_subpath_file(const char *path, const char *filename);
+const char *bb_basename(const char *name);
+/* NB: can violate const-ness (similarly to strchr) */
+char *last_char_is(const char *s, int c);
+
+
+USE_DESKTOP(long long) int uncompress(int fd_in, int fd_out);
+int inflate(int in, int out);
+
+
+int bb_make_directory(char *path, long mode, int flags);
+
+int get_signum(const char *name);
+const char *get_signame(int number);
+void print_signames(void);
+
+char *bb_simplify_path(const char *path);
+
+#define FAIL_DELAY 3
+extern void bb_do_delay(int seconds);
+extern void change_identity(const struct passwd *pw);
+extern void run_shell(const char *shell, int loginshell, const char *command, const char **additional_args) ATTRIBUTE_NORETURN;
+extern void run_shell(const char *shell, int loginshell, const char *command, const char **additional_args);
+#if ENABLE_SELINUX
+extern void renew_current_security_context(void);
+extern void set_current_security_context(security_context_t sid);
+extern context_t set_security_context_component(security_context_t cur_context,
+ char *user, char *role, char *type, char *range);
+extern void setfscreatecon_or_die(security_context_t scontext);
+extern void selinux_preserve_fcontext(int fdesc);
+#else
+#define selinux_preserve_fcontext(fdesc) ((void)0)
+#endif
+extern void selinux_or_die(void);
+extern int restricted_shell(const char *shell);
+
+/* setup_environment:
+ * if clear_env = 1: cd(pw->pw_dir), clear environment, then set
+ * TERM=(old value)
+ * USER=pw->pw_name, LOGNAME=pw->pw_name
+ * PATH=bb_default_[root_]path
+ * HOME=pw->pw_dir
+ * SHELL=shell
+ * else if change_env = 1:
+ * if not root (if pw->pw_uid != 0):
+ * USER=pw->pw_name, LOGNAME=pw->pw_name
+ * HOME=pw->pw_dir
+ * SHELL=shell
+ * else does nothing
+ */
+extern void setup_environment(const char *shell, int clear_env, int change_env, const struct passwd *pw);
+extern int correct_password(const struct passwd *pw);
+/* Returns a malloced string */
+#if !ENABLE_USE_BB_CRYPT
+#define pw_encrypt(clear, salt, cleanup) pw_encrypt(clear, salt)
+#endif
+extern char *pw_encrypt(const char *clear, const char *salt, int cleanup);
+extern int obscure(const char *old, const char *newval, const struct passwd *pwdp);
+/* rnd is additional random input. New one is returned.
+ * Useful if you call crypt_make_salt many times in a row:
+ * rnd = crypt_make_salt(buf1, 4, 0);
+ * rnd = crypt_make_salt(buf2, 4, rnd);
+ * rnd = crypt_make_salt(buf3, 4, rnd);
+ * (otherwise we risk having same salt generated)
+ */
+extern int crypt_make_salt(char *p, int cnt, int rnd);
+/* Returns number of lines changed, or -1 on error */
+extern int update_passwd(const char *filename, const char *username,
+ const char *new_pw);
+
+int index_in_str_array(const char *const string_array[], const char *key);
+int index_in_strings(const char *strings, const char *key);
+int index_in_substr_array(const char *const string_array[], const char *key);
+int index_in_substrings(const char *strings, const char *key);
+const char *nth_string(const char *strings, int n);
+
+extern void print_login_issue(const char *issue_file, const char *tty);
+extern void print_login_prompt(void);
+
+/* NB: typically you want to pass fd 0, not 1. Think 'applet | grep something' */
+int get_terminal_width_height(int fd, unsigned *width, unsigned *height);
+
+/* NB: "unsigned request" is crucial! "int request" will break some arches! */
+int ioctl_or_perror(int fd, unsigned request, void *argp, const char *fmt,...) __attribute__ ((format (printf, 4, 5)));
+int ioctl_or_perror_and_die(int fd, unsigned request, void *argp, const char *fmt,...) __attribute__ ((format (printf, 4, 5)));
+#if ENABLE_IOCTL_HEX2STR_ERROR
+int bb_ioctl_or_warn(int fd, unsigned request, void *argp, const char *ioctl_name);
+int bb_xioctl(int fd, unsigned request, void *argp, const char *ioctl_name);
+#define ioctl_or_warn(fd,request,argp) bb_ioctl_or_warn(fd,request,argp,#request)
+#define xioctl(fd,request,argp) bb_xioctl(fd,request,argp,#request)
+#else
+int bb_ioctl_or_warn(int fd, unsigned request, void *argp);
+int bb_xioctl(int fd, unsigned request, void *argp);
+#define ioctl_or_warn(fd,request,argp) bb_ioctl_or_warn(fd,request,argp)
+#define xioctl(fd,request,argp) bb_xioctl(fd,request,argp)
+#endif
+
+char *is_in_ino_dev_hashtable(const struct stat *statbuf);
+void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name);
+void reset_ino_dev_hashtable(void);
+#ifdef __GLIBC__
+/* At least glibc has horrendously large inline for this, so wrap it */
+unsigned long long bb_makedev(unsigned int major, unsigned int minor);
+#undef makedev
+#define makedev(a,b) bb_makedev(a,b)
+#endif
+
+
+#if ENABLE_FEATURE_EDITING
+/* It's NOT just ENABLEd or disabled. It's a number: */
+#ifdef CONFIG_FEATURE_EDITING_HISTORY
+#define MAX_HISTORY (CONFIG_FEATURE_EDITING_HISTORY + 0)
+#else
+#define MAX_HISTORY 0
+#endif
+typedef struct line_input_t {
+ int flags;
+ const char *path_lookup;
+#if MAX_HISTORY
+ int cnt_history;
+ int cur_history;
+ USE_FEATURE_EDITING_SAVEHISTORY(const char *hist_file;)
+ char *history[MAX_HISTORY + 1];
+#endif
+} line_input_t;
+enum {
+ DO_HISTORY = 1 * (MAX_HISTORY > 0),
+ SAVE_HISTORY = 2 * (MAX_HISTORY > 0) * ENABLE_FEATURE_EDITING_SAVEHISTORY,
+ TAB_COMPLETION = 4 * ENABLE_FEATURE_TAB_COMPLETION,
+ USERNAME_COMPLETION = 8 * ENABLE_FEATURE_USERNAME_COMPLETION,
+ VI_MODE = 0x10 * ENABLE_FEATURE_EDITING_VI,
+ WITH_PATH_LOOKUP = 0x20,
+ FOR_SHELL = DO_HISTORY | SAVE_HISTORY | TAB_COMPLETION | USERNAME_COMPLETION,
+};
+line_input_t *new_line_input_t(int flags);
+/* Returns:
+ * -1 on read errors or EOF, or on bare Ctrl-D,
+ * 0 on ctrl-C (the line entered is still returned in 'command'),
+ * >0 length of input string, including terminating '\n'
+ */
+int read_line_input(const char* prompt, char* command, int maxsize, line_input_t *state);
+#else
+int read_line_input(const char* prompt, char* command, int maxsize);
+#define read_line_input(prompt, command, maxsize, state) \
+ read_line_input(prompt, command, maxsize)
+#endif
+
+
+#ifndef COMM_LEN
+#ifdef TASK_COMM_LEN
+enum { COMM_LEN = TASK_COMM_LEN };
+#else
+/* synchronize with sizeof(task_struct.comm) in /usr/include/linux/sched.h */
+enum { COMM_LEN = 16 };
+#endif
+#endif
+typedef struct procps_status_t {
+ DIR *dir;
+ uint8_t shift_pages_to_bytes;
+ uint8_t shift_pages_to_kb;
+/* Fields are set to 0/NULL if failed to determine (or not requested) */
+ char *argv0;
+ USE_SELINUX(char *context;)
+ /* Everything below must contain no ptrs to malloc'ed data:
+ * it is memset(0) for each process in procps_scan() */
+ unsigned long vsz, rss; /* we round it to kbytes */
+ unsigned long stime, utime;
+ unsigned long start_time;
+ unsigned pid;
+ unsigned ppid;
+ unsigned pgid;
+ unsigned sid;
+ unsigned uid;
+ unsigned gid;
+ unsigned tty_major,tty_minor;
+#if ENABLE_FEATURE_TOPMEM
+ unsigned long mapped_rw;
+ unsigned long mapped_ro;
+ unsigned long shared_clean;
+ unsigned long shared_dirty;
+ unsigned long private_clean;
+ unsigned long private_dirty;
+ unsigned long stack;
+#endif
+ char state[4];
+ /* basename of executable in exec(2), read from /proc/N/stat
+ * (if executable is symlink or script, it is NOT replaced
+ * by link target or interpreter name) */
+ char comm[COMM_LEN];
+ /* user/group? - use passwd/group parsing functions */
+} procps_status_t;
+enum {
+ PSSCAN_PID = 1 << 0,
+ PSSCAN_PPID = 1 << 1,
+ PSSCAN_PGID = 1 << 2,
+ PSSCAN_SID = 1 << 3,
+ PSSCAN_UIDGID = 1 << 4,
+ PSSCAN_COMM = 1 << 5,
+ /* PSSCAN_CMD = 1 << 6, - use read_cmdline instead */
+ PSSCAN_ARGV0 = 1 << 7,
+ /* PSSCAN_EXE = 1 << 8, - not implemented */
+ PSSCAN_STATE = 1 << 9,
+ PSSCAN_VSZ = 1 << 10,
+ PSSCAN_RSS = 1 << 11,
+ PSSCAN_STIME = 1 << 12,
+ PSSCAN_UTIME = 1 << 13,
+ PSSCAN_TTY = 1 << 14,
+ PSSCAN_SMAPS = (1 << 15) * ENABLE_FEATURE_TOPMEM,
+ PSSCAN_ARGVN = (1 << 16) * (ENABLE_PGREP | ENABLE_PKILL),
+ USE_SELINUX(PSSCAN_CONTEXT = 1 << 17,)
+ PSSCAN_START_TIME = 1 << 18,
+ /* These are all retrieved from proc/NN/stat in one go: */
+ PSSCAN_STAT = PSSCAN_PPID | PSSCAN_PGID | PSSCAN_SID
+ | PSSCAN_COMM | PSSCAN_STATE
+ | PSSCAN_VSZ | PSSCAN_RSS
+ | PSSCAN_STIME | PSSCAN_UTIME | PSSCAN_START_TIME
+ | PSSCAN_TTY,
+};
+//procps_status_t* alloc_procps_scan(void);
+void free_procps_scan(procps_status_t* sp);
+procps_status_t* procps_scan(procps_status_t* sp, int flags);
+/* Format cmdline (up to col chars) into char buf[col+1] */
+/* Puts [comm] if cmdline is empty (-> process is a kernel thread) */
+void read_cmdline(char *buf, int col, unsigned pid, const char *comm);
+pid_t *find_pid_by_name(const char* procName);
+pid_t *pidlist_reverse(pid_t *pidList);
+
+
+extern const char bb_uuenc_tbl_base64[];
+extern const char bb_uuenc_tbl_std[];
+void bb_uuencode(char *store, const void *s, int length, const char *tbl);
+
+typedef struct sha1_ctx_t {
+ uint32_t count[2];
+ uint32_t hash[5];
+ uint32_t wbuf[16];
+} sha1_ctx_t;
+void sha1_begin(sha1_ctx_t *ctx);
+void sha1_hash(const void *data, size_t length, sha1_ctx_t *ctx);
+void *sha1_end(void *resbuf, sha1_ctx_t *ctx);
+
+typedef struct md5_ctx_t {
+ uint32_t A;
+ uint32_t B;
+ uint32_t C;
+ uint32_t D;
+ uint64_t total;
+ uint32_t buflen;
+ char buffer[128];
+} md5_ctx_t;
+void md5_begin(md5_ctx_t *ctx);
+void md5_hash(const void *data, size_t length, md5_ctx_t *ctx);
+void *md5_end(void *resbuf, md5_ctx_t *ctx);
+
+uint32_t *crc32_filltable(uint32_t *tbl256, int endian);
+
+
+extern const char *applet_name;
+/* "BusyBox vN.N.N (timestamp or extra_version)" */
+extern const char bb_banner[];
+extern const char bb_msg_memory_exhausted[];
+extern const char bb_msg_invalid_date[];
+extern const char bb_msg_read_error[];
+extern const char bb_msg_write_error[];
+extern const char bb_msg_unknown[];
+extern const char bb_msg_can_not_create_raw_socket[];
+extern const char bb_msg_perm_denied_are_you_root[];
+extern const char bb_msg_requires_arg[];
+extern const char bb_msg_invalid_arg[];
+extern const char bb_msg_standard_input[];
+extern const char bb_msg_standard_output[];
+
+extern const char bb_str_default[];
+/* NB: (bb_hexdigits_upcase[i] | 0x20) -> lowercase hex digit */
+extern const char bb_hexdigits_upcase[];
+
+extern const char bb_path_mtab_file[];
+extern const char bb_path_passwd_file[];
+extern const char bb_path_shadow_file[];
+extern const char bb_path_gshadow_file[];
+extern const char bb_path_group_file[];
+extern const char bb_path_motd_file[];
+extern const char bb_path_wtmp_file[];
+extern const char bb_dev_null[];
+extern const char bb_busybox_exec_path[];
+/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin,
+ * but I want to save a few bytes here */
+extern const char bb_PATH_root_path[]; /* "PATH=/sbin:/usr/sbin:/bin:/usr/bin" */
+#define bb_default_root_path (bb_PATH_root_path + sizeof("PATH"))
+#define bb_default_path (bb_PATH_root_path + sizeof("PATH=/sbin:/usr/sbin"))
+
+extern const int const_int_0;
+extern const int const_int_1;
+
+
+#ifndef BUFSIZ
+#define BUFSIZ 4096
+#endif
+/* Providing hard guarantee on minimum size (think of BUFSIZ == 128) */
+enum { COMMON_BUFSIZE = (BUFSIZ >= 256*sizeof(void*) ? BUFSIZ+1 : 256*sizeof(void*)) };
+extern char bb_common_bufsiz1[COMMON_BUFSIZE];
+/* This struct is deliberately not defined. */
+/* See docs/keep_data_small.txt */
+struct globals;
+/* '*const' ptr makes gcc optimize code much better.
+ * Magic prevents ptr_to_globals from going into rodata.
+ * If you want to assign a value, use SET_PTR_TO_GLOBALS(x) */
+extern struct globals *const ptr_to_globals;
+/* At least gcc 3.4.6 on mipsel system needs optimization barrier */
+#define barrier() __asm__ __volatile__("":::"memory")
+#define SET_PTR_TO_GLOBALS(x) do { \
+ (*(struct globals**)&ptr_to_globals) = (x); \
+ barrier(); \
+} while (0)
+
+/* You can change LIBBB_DEFAULT_LOGIN_SHELL, but don't use it,
+ * use bb_default_login_shell and following defines.
+ * If you change LIBBB_DEFAULT_LOGIN_SHELL,
+ * don't forget to change increment constant. */
+#define LIBBB_DEFAULT_LOGIN_SHELL "-/bin/sh"
+extern const char bb_default_login_shell[];
+/* "/bin/sh" */
+#define DEFAULT_SHELL (bb_default_login_shell+1)
+/* "sh" */
+#define DEFAULT_SHELL_SHORT_NAME (bb_default_login_shell+6)
+
+typedef struct masks_labels_t {
+ const char *labels;
+ const int masks[];
+} masks_labels_t;
+
+int print_flags_separated(const int *masks, const char *labels,
+ int flags, const char *separator);
+extern int print_flags(const masks_labels_t *ml, int flags);
+
+#if ENABLE_FEATURE_DEVFS
+# define CURRENT_VC "/dev/vc/0"
+# define VC_1 "/dev/vc/1"
+# define VC_2 "/dev/vc/2"
+# define VC_3 "/dev/vc/3"
+# define VC_4 "/dev/vc/4"
+# define VC_5 "/dev/vc/5"
+#if defined(__sh__) || defined(__H8300H__) || defined(__H8300S__)
+/* Yes, this sucks, but both SH (including sh64) and H8 have a SCI(F) for their
+ respective serial ports .. as such, we can't use the common device paths for
+ these. -- PFM */
+# define SC_0 "/dev/ttsc/0"
+# define SC_1 "/dev/ttsc/1"
+# define SC_FORMAT "/dev/ttsc/%d"
+#else
+# define SC_0 "/dev/tts/0"
+# define SC_1 "/dev/tts/1"
+# define SC_FORMAT "/dev/tts/%d"
+#endif
+# define VC_FORMAT "/dev/vc/%d"
+# define LOOP_FORMAT "/dev/loop/%d"
+# define LOOP_NAMESIZE (sizeof("/dev/loop/") + sizeof(int)*3 + 1)
+# define LOOP_NAME "/dev/loop/"
+# define FB_0 "/dev/fb/0"
+#else
+# define CURRENT_VC "/dev/tty0"
+# define VC_1 "/dev/tty1"
+# define VC_2 "/dev/tty2"
+# define VC_3 "/dev/tty3"
+# define VC_4 "/dev/tty4"
+# define VC_5 "/dev/tty5"
+#if defined(__sh__) || defined(__H8300H__) || defined(__H8300S__)
+# define SC_0 "/dev/ttySC0"
+# define SC_1 "/dev/ttySC1"
+# define SC_FORMAT "/dev/ttySC%d"
+#else
+# define SC_0 "/dev/ttyS0"
+# define SC_1 "/dev/ttyS1"
+# define SC_FORMAT "/dev/ttyS%d"
+#endif
+# define VC_FORMAT "/dev/tty%d"
+# define LOOP_FORMAT "/dev/loop%d"
+# define LOOP_NAMESIZE (sizeof("/dev/loop") + sizeof(int)*3 + 1)
+# define LOOP_NAME "/dev/loop"
+# define FB_0 "/dev/fb0"
+#endif
+
+/* The following devices are the same on devfs and non-devfs systems. */
+#define CURRENT_TTY "/dev/tty"
+#define DEV_CONSOLE "/dev/console"
+
+
+#ifndef RB_POWER_OFF
+/* Stop system and switch power off if possible. */
+#define RB_POWER_OFF 0x4321fedc
+#endif
+
+/* Make sure we call functions instead of macros. */
+#undef isalnum
+#undef isalpha
+#undef isascii
+#undef isblank
+#undef iscntrl
+#undef isgraph
+#undef islower
+#undef isprint
+#undef ispunct
+#undef isspace
+#undef isupper
+#undef isxdigit
+
+/* This one is more efficient - we save ~400 bytes */
+#undef isdigit
+#define isdigit(a) ((unsigned)((a) - '0') <= 9)
+
+#define ARRAY_SIZE(x) ((unsigned)(sizeof(x) / sizeof((x)[0])))
+
+
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility pop
+#endif
+
+
+#endif /* __LIBBUSYBOX_H__ */
diff --git a/cleopatre/busybox-1.11.1-spc300/include/platform.h b/cleopatre/busybox-1.11.1-spc300/include/platform.h
new file mode 100644
index 0000000000..cdc1151ad3
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/include/platform.h
@@ -0,0 +1,349 @@
+/* vi: set sw=4 ts=4: */
+/*
+ Copyright 2006, Bernhard Fischer
+
+ Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+*/
+#ifndef __PLATFORM_H
+#define __PLATFORM_H 1
+
+/* Convenience macros to test the version of gcc. */
+#undef __GNUC_PREREQ
+#if defined __GNUC__ && defined __GNUC_MINOR__
+# define __GNUC_PREREQ(maj, min) \
+ ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+#else
+# define __GNUC_PREREQ(maj, min) 0
+#endif
+
+/* __restrict is known in EGCS 1.2 and above. */
+#if !__GNUC_PREREQ(2,92)
+# ifndef __restrict
+# define __restrict /* Ignore */
+# endif
+#endif
+
+/* Define macros for some gcc attributes. This permits us to use the
+ macros freely, and know that they will come into play for the
+ version of gcc in which they are supported. */
+
+#if !__GNUC_PREREQ(2,7)
+# ifndef __attribute__
+# define __attribute__(x)
+# endif
+#endif
+
+#undef inline
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ > 199901L
+/* it's a keyword */
+#else
+# if __GNUC_PREREQ(2,7)
+# define inline __inline__
+# else
+# define inline
+# endif
+#endif
+
+#ifndef __const
+# define __const const
+#endif
+
+#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
+#define ATTRIBUTE_PACKED __attribute__ ((__packed__))
+#define ATTRIBUTE_ALIGNED(m) __attribute__ ((__aligned__(m)))
+/* __NO_INLINE__: some gcc's do not honor inlining! :( */
+#if __GNUC_PREREQ(3,0) && !defined(__NO_INLINE__)
+# define ALWAYS_INLINE __attribute__ ((always_inline)) inline
+/* I've seen a toolchain where I needed __noinline__ instead of noinline */
+# define NOINLINE __attribute__((__noinline__))
+# if !ENABLE_WERROR
+# define ATTRIBUTE_DEPRECATED __attribute__ ((__deprecated__))
+# define ATTRIBUTE_UNUSED_RESULT __attribute__ ((warn_unused_result))
+# else
+# define ATTRIBUTE_DEPRECATED /* n/a */
+# define ATTRIBUTE_UNUSED_RESULT /* n/a */
+# endif
+#else
+# define ALWAYS_INLINE inline /* n/a */
+# define NOINLINE /* n/a */
+# define ATTRIBUTE_DEPRECATED /* n/a */
+# define ATTRIBUTE_UNUSED_RESULT /* n/a */
+#endif
+
+/* -fwhole-program makes all symbols local. The attribute externally_visible
+ forces a symbol global. */
+#if __GNUC_PREREQ(4,1)
+# define EXTERNALLY_VISIBLE __attribute__(( visibility("default") ))
+//__attribute__ ((__externally_visible__))
+#else
+# define EXTERNALLY_VISIBLE
+#endif /* GNUC >= 4.1 */
+
+/* We use __extension__ in some places to suppress -pedantic warnings
+ about GCC extensions. This feature didn't work properly before
+ gcc 2.8. */
+#if !__GNUC_PREREQ(2,8)
+# ifndef __extension__
+# define __extension__
+# endif
+#endif
+
+/* gcc-2.95 had no va_copy but only __va_copy. */
+#if !__GNUC_PREREQ(3,0)
+# include <stdarg.h>
+# if !defined va_copy && defined __va_copy
+# define va_copy(d,s) __va_copy((d),(s))
+# endif
+#endif
+
+/* ---- Endian Detection ------------------------------------ */
+
+#if (defined __digital__ && defined __unix__)
+# include <sex.h>
+# define __BIG_ENDIAN__ (BYTE_ORDER == BIG_ENDIAN)
+# define __BYTE_ORDER BYTE_ORDER
+#elif !defined __APPLE__
+# include <byteswap.h>
+# include <endian.h>
+#endif
+
+#ifdef __BIG_ENDIAN__
+# define BB_BIG_ENDIAN 1
+# define BB_LITTLE_ENDIAN 0
+#elif __BYTE_ORDER == __BIG_ENDIAN
+# define BB_BIG_ENDIAN 1
+# define BB_LITTLE_ENDIAN 0
+#else
+# define BB_BIG_ENDIAN 0
+# define BB_LITTLE_ENDIAN 1
+#endif
+
+#if BB_BIG_ENDIAN
+#define SWAP_BE16(x) (x)
+#define SWAP_BE32(x) (x)
+#define SWAP_BE64(x) (x)
+#define SWAP_LE16(x) bswap_16(x)
+#define SWAP_LE32(x) bswap_32(x)
+#define SWAP_LE64(x) bswap_64(x)
+#else
+#define SWAP_BE16(x) bswap_16(x)
+#define SWAP_BE32(x) bswap_32(x)
+#define SWAP_BE64(x) bswap_64(x)
+#define SWAP_LE16(x) (x)
+#define SWAP_LE32(x) (x)
+#define SWAP_LE64(x) (x)
+#endif
+
+/* ---- Unaligned access ------------------------------------ */
+
+/* parameter is supposed to be an uint32_t* ptr */
+#if defined(i386) || defined(__x86_64__) /* + other arches? */
+#define get_unaligned_u32p(u32p) (*(u32p))
+#else
+/* performs reasonably well (gcc usually inlines memcpy here) */
+#define get_unaligned_u32p(u32p) ({ uint32_t __t; memcpy(&__t, (u32p), 4); __t; })
+#endif
+
+/* ---- Networking ------------------------------------------ */
+
+#ifndef __APPLE__
+# include <arpa/inet.h>
+# ifndef __socklen_t_defined
+typedef int socklen_t;
+# endif
+#else
+# include <netinet/in.h>
+#endif
+
+/* ---- Compiler dependent settings ------------------------- */
+
+#if (defined __digital__ && defined __unix__) || defined __APPLE__
+# undef HAVE_MNTENT_H
+# undef HAVE_SYS_STATFS_H
+#else
+# define HAVE_MNTENT_H 1
+# define HAVE_SYS_STATFS_H 1
+#endif /* ___digital__ && __unix__ */
+
+/* linux/loop.h relies on __u64. Make sure we have that as a proper type
+ * until userspace is widely fixed. */
+#if (defined __INTEL_COMPILER && !defined __GNUC__) || \
+ (defined __GNUC__ && defined __STRICT_ANSI__)
+__extension__ typedef __signed__ long long __s64;
+__extension__ typedef unsigned long long __u64;
+#endif
+
+/*----- Kernel versioning ------------------------------------*/
+
+#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+
+/* ---- Miscellaneous --------------------------------------- */
+
+#if defined(__GNU_LIBRARY__) && __GNU_LIBRARY__ < 5 && \
+ !defined(__dietlibc__) && \
+ !defined(_NEWLIB_VERSION) && \
+ !(defined __digital__ && defined __unix__)
+# error "Sorry, this libc version is not supported :("
+#endif
+
+/* Don't perpetuate e2fsck crap into the headers. Clean up e2fsck instead. */
+
+#if defined __GLIBC__ || defined __UCLIBC__ \
+ || defined __dietlibc__ || defined _NEWLIB_VERSION
+#include <features.h>
+#define HAVE_FEATURES_H
+#include <stdint.h>
+#define HAVE_STDINT_H
+#elif !defined __APPLE__
+/* Largest integral types. */
+#if __BIG_ENDIAN__
+typedef long intmax_t;
+typedef unsigned long uintmax_t;
+#else
+__extension__
+typedef long long intmax_t;
+__extension__
+typedef unsigned long long uintmax_t;
+#endif
+#endif
+
+/* Size-saving "small" ints (arch-dependent) */
+#if defined(i386) || defined(__x86_64__) || defined(__mips__) || defined(__cris__)
+/* add other arches which benefit from this... */
+typedef signed char smallint;
+typedef unsigned char smalluint;
+#else
+/* for arches where byte accesses generate larger code: */
+typedef int smallint;
+typedef unsigned smalluint;
+#endif
+
+/* ISO C Standard: 7.16 Boolean type and values <stdbool.h> */
+#if (defined __digital__ && defined __unix__)
+/* old system without (proper) C99 support */
+#define bool smalluint
+#else
+/* modern system, so use it */
+#include <stdbool.h>
+#endif
+
+/* Try to defeat gcc's alignment of "char message[]"-like data */
+#if 1 /* if needed: !defined(arch1) && !defined(arch2) */
+#define ALIGN1 __attribute__((aligned(1)))
+#define ALIGN2 __attribute__((aligned(2)))
+#else
+/* Arches which MUST have 2 or 4 byte alignment for everything are here */
+#define ALIGN1
+#define ALIGN2
+#endif
+
+
+/* uclibc does not implement daemon() for no-mmu systems.
+ * For 0.9.29 and svn, __ARCH_USE_MMU__ indicates no-mmu reliably.
+ * For earlier versions there is no reliable way to check if we are building
+ * for a mmu-less system.
+ */
+#if ENABLE_NOMMU || \
+ (defined __UCLIBC__ && __UCLIBC_MAJOR__ >= 0 && __UCLIBC_MINOR__ >= 9 && \
+ __UCLIBC_SUBLEVEL__ > 28 && !defined __ARCH_USE_MMU__)
+#define BB_MMU 0
+#define USE_FOR_NOMMU(...) __VA_ARGS__
+#define USE_FOR_MMU(...)
+#else
+#define BB_MMU 1
+#define USE_FOR_NOMMU(...)
+#define USE_FOR_MMU(...) __VA_ARGS__
+#endif
+
+/* Platforms that haven't got dprintf need to implement fdprintf() in
+ * libbb. This would require a platform.c. It's not going to be cleaned
+ * out of the tree, so stop saying it should be. */
+#if !defined(__dietlibc__)
+/* Needed for: glibc */
+/* Not needed for: dietlibc */
+/* Others: ?? (add as needed) */
+#define fdprintf dprintf
+#endif
+
+#if defined(__dietlibc__)
+static ALWAYS_INLINE char* strchrnul(const char *s, char c)
+{
+ while (*s && *s != c) ++s;
+ return (char*)s;
+}
+#endif
+
+/* Don't use lchown with glibc older than 2.1.x ... uClibc lacks it */
+#if (defined __GLIBC__ && __GLIBC__ <= 2 && __GLIBC_MINOR__ < 1) || \
+ defined __UC_LIBC__
+# define lchown chown
+#endif
+
+#if (defined __digital__ && defined __unix__)
+#include <standards.h>
+#define HAVE_STANDARDS_H
+#include <inttypes.h>
+#define HAVE_INTTYPES_H
+#define PRIu32 "u"
+
+/* use legacy setpgrp(pid_t,pid_t) for now. move to platform.c */
+#define bb_setpgrp() do { pid_t __me = getpid(); setpgrp(__me,__me); } while (0)
+
+#if !defined ADJ_OFFSET_SINGLESHOT && defined MOD_CLKA && defined MOD_OFFSET
+#define ADJ_OFFSET_SINGLESHOT (MOD_CLKA | MOD_OFFSET)
+#endif
+#if !defined ADJ_FREQUENCY && defined MOD_FREQUENCY
+#define ADJ_FREQUENCY MOD_FREQUENCY
+#endif
+#if !defined ADJ_TIMECONST && defined MOD_TIMECONST
+#define ADJ_TIMECONST MOD_TIMECONST
+#endif
+#if !defined ADJ_TICK && defined MOD_CLKB
+#define ADJ_TICK MOD_CLKB
+#endif
+
+#else
+#define bb_setpgrp() setpgrp()
+#endif
+
+#if defined(__linux__)
+#include <sys/mount.h>
+/* Make sure we have all the new mount flags we actually try to use. */
+#ifndef MS_BIND
+#define MS_BIND (1<<12)
+#endif
+#ifndef MS_MOVE
+#define MS_MOVE (1<<13)
+#endif
+#ifndef MS_RECURSIVE
+#define MS_RECURSIVE (1<<14)
+#endif
+#ifndef MS_SILENT
+#define MS_SILENT (1<<15)
+#endif
+
+/* The shared subtree stuff, which went in around 2.6.15. */
+#ifndef MS_UNBINDABLE
+#define MS_UNBINDABLE (1<<17)
+#endif
+#ifndef MS_PRIVATE
+#define MS_PRIVATE (1<<18)
+#endif
+#ifndef MS_SLAVE
+#define MS_SLAVE (1<<19)
+#endif
+#ifndef MS_SHARED
+#define MS_SHARED (1<<20)
+#endif
+
+
+#if !defined(BLKSSZGET)
+#define BLKSSZGET _IO(0x12, 104)
+#endif
+#if !defined(BLKGETSIZE64)
+#define BLKGETSIZE64 _IOR(0x12,114,size_t)
+#endif
+#endif
+
+#endif /* platform.h */
diff --git a/cleopatre/busybox-1.11.1-spc300/include/pwd_.h b/cleopatre/busybox-1.11.1-spc300/include/pwd_.h
new file mode 100644
index 0000000000..6199034d2b
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/include/pwd_.h
@@ -0,0 +1,123 @@
+/* vi: set sw=4 ts=4: */
+/* Copyright (C) 1991,92,95,96,97,98,99,2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/*
+ * POSIX Standard: 9.2.2 User Database Access <pwd.h>
+ */
+
+#ifndef _PWD_H
+#define _PWD_H 1
+
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility push(hidden)
+#endif
+
+/* The passwd structure. */
+struct passwd {
+ char *pw_name; /* Username. */
+ char *pw_passwd; /* Password. */
+ uid_t pw_uid; /* User ID. */
+ gid_t pw_gid; /* Group ID. */
+ char *pw_gecos; /* Real name. */
+ char *pw_dir; /* Home directory. */
+ char *pw_shell; /* Shell program. */
+};
+
+
+#define setpwent bb_internal_setpwent
+#define endpwent bb_internal_endpwent
+#define getpwent bb_internal_getpwent
+#define fgetpwent bb_internal_fgetpwent
+#define putpwent bb_internal_putpwent
+#define getpwuid bb_internal_getpwuid
+#define getpwnam bb_internal_getpwnam
+#define getpwent_r bb_internal_getpwent_r
+#define getpwuid_r bb_internal_getpwuid_r
+#define getpwnam_r bb_internal_getpwnam_r
+#define fgetpwent_r bb_internal_fgetpwent_r
+#define getpw bb_internal_getpw
+
+
+/* All function names below should be remapped by #defines above
+ * in order to not collide with libc names.
+ * In theory it isn't necessary, but I saw weird interactions at link time.
+ * Let's play safe */
+
+
+/* Rewind the password-file stream. */
+extern void setpwent(void);
+
+/* Close the password-file stream. */
+extern void endpwent(void);
+
+/* Read an entry from the password-file stream, opening it if necessary. */
+extern struct passwd *getpwent(void);
+
+/* Read an entry from STREAM. */
+extern struct passwd *fgetpwent(FILE *__stream);
+
+/* Write the given entry onto the given stream. */
+extern int putpwent(__const struct passwd *__restrict __p,
+ FILE *__restrict __f);
+
+/* Search for an entry with a matching user ID. */
+extern struct passwd *getpwuid(uid_t __uid);
+
+/* Search for an entry with a matching username. */
+extern struct passwd *getpwnam(__const char *__name);
+
+/* Reentrant versions of some of the functions above.
+
+ PLEASE NOTE: the `getpwent_r' function is not (yet) standardized.
+ The interface may change in later versions of this library. But
+ the interface is designed following the principals used for the
+ other reentrant functions so the chances are good this is what the
+ POSIX people would choose. */
+
+extern int getpwent_r(struct passwd *__restrict __resultbuf,
+ char *__restrict __buffer, size_t __buflen,
+ struct passwd **__restrict __result);
+
+extern int getpwuid_r(uid_t __uid,
+ struct passwd *__restrict __resultbuf,
+ char *__restrict __buffer, size_t __buflen,
+ struct passwd **__restrict __result);
+
+extern int getpwnam_r(__const char *__restrict __name,
+ struct passwd *__restrict __resultbuf,
+ char *__restrict __buffer, size_t __buflen,
+ struct passwd **__restrict __result);
+
+/* Read an entry from STREAM. This function is not standardized and
+ probably never will. */
+extern int fgetpwent_r(FILE *__restrict __stream,
+ struct passwd *__restrict __resultbuf,
+ char *__restrict __buffer, size_t __buflen,
+ struct passwd **__restrict __result);
+
+/* Re-construct the password-file line for the given uid
+ in the given buffer. This knows the format that the caller
+ will expect, but this need not be the format of the password file. */
+extern int getpw(uid_t __uid, char *__buffer);
+
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility pop
+#endif
+
+#endif /* pwd.h */
diff --git a/cleopatre/busybox-1.11.1-spc300/include/rtc_.h b/cleopatre/busybox-1.11.1-spc300/include/rtc_.h
new file mode 100644
index 0000000000..b8e4de8957
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/include/rtc_.h
@@ -0,0 +1,79 @@
+/*
+ * Common defines/structures/etc... for applets that need to work with the RTC.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _BB_RTC_H_
+#define _BB_RTC_H_
+
+#include "libbb.h"
+
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility push(hidden)
+#endif
+
+extern int rtc_adjtime_is_utc(void);
+extern int rtc_xopen(const char **default_rtc, int flags);
+extern time_t rtc_read_time(int fd, int utc);
+
+/*
+ * Everything below this point has been copied from linux/rtc.h
+ * to eliminate the kernel header dependency
+ */
+
+struct linux_rtc_time {
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+ int tm_wday;
+ int tm_yday;
+ int tm_isdst;
+};
+
+struct linux_rtc_wkalrm {
+ unsigned char enabled; /* 0 = alarm disabled, 1 = alarm enabled */
+ unsigned char pending; /* 0 = alarm not pending, 1 = alarm pending */
+ struct linux_rtc_time time; /* time the alarm is set to */
+};
+
+/*
+ * ioctl calls that are permitted to the /dev/rtc interface, if
+ * any of the RTC drivers are enabled.
+ */
+
+#define RTC_AIE_ON _IO('p', 0x01) /* Alarm int. enable on */
+#define RTC_AIE_OFF _IO('p', 0x02) /* ... off */
+#define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on */
+#define RTC_UIE_OFF _IO('p', 0x04) /* ... off */
+#define RTC_PIE_ON _IO('p', 0x05) /* Periodic int. enable on */
+#define RTC_PIE_OFF _IO('p', 0x06) /* ... off */
+#define RTC_WIE_ON _IO('p', 0x0f) /* Watchdog int. enable on */
+#define RTC_WIE_OFF _IO('p', 0x10) /* ... off */
+
+#define RTC_ALM_SET _IOW('p', 0x07, struct linux_rtc_time) /* Set alarm time */
+#define RTC_ALM_READ _IOR('p', 0x08, struct linux_rtc_time) /* Read alarm time */
+#define RTC_RD_TIME _IOR('p', 0x09, struct linux_rtc_time) /* Read RTC time */
+#define RTC_SET_TIME _IOW('p', 0x0a, struct linux_rtc_time) /* Set RTC time */
+#define RTC_IRQP_READ _IOR('p', 0x0b, unsigned long) /* Read IRQ rate */
+#define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate */
+#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */
+#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */
+
+#define RTC_WKALM_SET _IOW('p', 0x0f, struct linux_rtc_wkalrm)/* Set wakeup alarm*/
+#define RTC_WKALM_RD _IOR('p', 0x10, struct linux_rtc_wkalrm)/* Get wakeup alarm*/
+
+/* interrupt flags */
+#define RTC_IRQF 0x80 /* any of the following is active */
+#define RTC_PF 0x40
+#define RTC_AF 0x20
+#define RTC_UF 0x10
+
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility pop
+#endif
+
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/include/shadow_.h b/cleopatre/busybox-1.11.1-spc300/include/shadow_.h
new file mode 100644
index 0000000000..5a8b71a471
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/include/shadow_.h
@@ -0,0 +1,115 @@
+/* vi: set sw=4 ts=4: */
+/* Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* Declaration of types and functions for shadow password suite */
+
+#ifndef _SHADOW_H
+#define _SHADOW_H 1
+
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility push(hidden)
+#endif
+
+/* Paths to the user database files */
+#ifndef _PATH_SHADOW
+#define _PATH_SHADOW "/etc/shadow"
+#endif
+
+/* Structure of the password file */
+struct spwd {
+ char *sp_namp; /* Login name */
+ char *sp_pwdp; /* Encrypted password */
+ long sp_lstchg; /* Date of last change */
+ long sp_min; /* Minimum number of days between changes */
+ long sp_max; /* Maximum number of days between changes */
+ long sp_warn; /* Number of days to warn user to change the password */
+ long sp_inact; /* Number of days the account may be inactive */
+ long sp_expire; /* Number of days since 1970-01-01 until account expires */
+ unsigned long sp_flag; /* Reserved */
+};
+
+
+#define setspent bb_internal_setspent
+#define endspent bb_internal_endspent
+#define getspent bb_internal_getspent
+#define getspnam bb_internal_getspnam
+#define sgetspent bb_internal_sgetspent
+#define fgetspent bb_internal_fgetspent
+#define putspent bb_internal_putspent
+#define getspent_r bb_internal_getspent_r
+#define getspnam_r bb_internal_getspnam_r
+#define sgetspent_r bb_internal_sgetspent_r
+#define fgetspent_r bb_internal_fgetspent_r
+#define lckpwdf bb_internal_lckpwdf
+#define ulckpwdf bb_internal_ulckpwdf
+
+
+/* All function names below should be remapped by #defines above
+ * in order to not collide with libc names.
+ * In theory it isn't necessary, but I saw weird interactions at link time.
+ * Let's play safe */
+
+
+/* Open database for reading */
+extern void setspent(void);
+
+/* Close database */
+extern void endspent(void);
+
+/* Get next entry from database, perhaps after opening the file */
+extern struct spwd *getspent(void);
+
+/* Get shadow entry matching NAME */
+extern struct spwd *getspnam(__const char *__name);
+
+/* Read shadow entry from STRING */
+extern struct spwd *sgetspent(__const char *__string);
+
+/* Read next shadow entry from STREAM */
+extern struct spwd *fgetspent(FILE *__stream);
+
+/* Write line containing shadow password entry to stream */
+extern int putspent(__const struct spwd *__p, FILE *__stream);
+
+/* Reentrant versions of some of the functions above */
+extern int getspent_r(struct spwd *__result_buf, char *__buffer,
+ size_t __buflen, struct spwd **__result);
+
+extern int getspnam_r(__const char *__name, struct spwd *__result_buf,
+ char *__buffer, size_t __buflen,
+ struct spwd **__result);
+
+extern int sgetspent_r(__const char *__string, struct spwd *__result_buf,
+ char *__buffer, size_t __buflen,
+ struct spwd **__result);
+
+extern int fgetspent_r(FILE *__stream, struct spwd *__result_buf,
+ char *__buffer, size_t __buflen,
+ struct spwd **__result);
+/* Protect password file against multi writers */
+extern int lckpwdf(void);
+
+/* Unlock password file */
+extern int ulckpwdf(void);
+
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility pop
+#endif
+
+#endif /* shadow.h */
diff --git a/cleopatre/busybox-1.11.1-spc300/include/unarchive.h b/cleopatre/busybox-1.11.1-spc300/include/unarchive.h
new file mode 100644
index 0000000000..a6b0477940
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/include/unarchive.h
@@ -0,0 +1,137 @@
+/* vi: set sw=4 ts=4: */
+#ifndef __UNARCHIVE_H__
+#define __UNARCHIVE_H__
+
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility push(hidden)
+#endif
+
+#define ARCHIVE_PRESERVE_DATE 1
+#define ARCHIVE_CREATE_LEADING_DIRS 2
+#define ARCHIVE_EXTRACT_UNCONDITIONAL 4
+#define ARCHIVE_EXTRACT_QUIET 8
+#define ARCHIVE_EXTRACT_NEWER 16
+#define ARCHIVE_NOPRESERVE_OWN 32
+#define ARCHIVE_NOPRESERVE_PERM 64
+
+typedef struct file_header_t {
+ char *name;
+ char *link_target;
+#if ENABLE_FEATURE_TAR_UNAME_GNAME
+ char *uname;
+ char *gname;
+#endif
+ off_t size;
+ uid_t uid;
+ gid_t gid;
+ mode_t mode;
+ time_t mtime;
+ dev_t device;
+} file_header_t;
+
+typedef struct archive_handle_t {
+ /* define if the header and data component should be processed */
+ char (*filter)(struct archive_handle_t *);
+ llist_t *accept;
+ /* List of files that have been rejected */
+ llist_t *reject;
+ /* List of files that have successfully been worked on */
+ llist_t *passed;
+
+ /* Contains the processed header entry */
+ file_header_t *file_header;
+
+ /* process the header component, e.g. tar -t */
+ void (*action_header)(const file_header_t *);
+
+ /* process the data component, e.g. extract to filesystem */
+ void (*action_data)(struct archive_handle_t *);
+
+ /* How to process any sub archive, e.g. get_header_tar_gz */
+ char (*action_data_subarchive)(struct archive_handle_t *);
+
+ /* Contains the handle to a sub archive */
+ struct archive_handle_t *sub_archive;
+
+ /* The raw stream as read from disk or stdin */
+ int src_fd;
+
+ /* Count the number of bytes processed */
+ off_t offset;
+
+ /* Function that skips data: read_by_char or read_by_skip */
+ void (*seek)(const struct archive_handle_t *archive_handle, const unsigned amount);
+
+ /* Temporary storage */
+ char *buffer;
+
+ /* Flags and misc. stuff */
+ unsigned char flags;
+
+} archive_handle_t;
+
+
+extern archive_handle_t *init_handle(void);
+
+extern char filter_accept_all(archive_handle_t *archive_handle);
+extern char filter_accept_list(archive_handle_t *archive_handle);
+extern char filter_accept_list_reassign(archive_handle_t *archive_handle);
+extern char filter_accept_reject_list(archive_handle_t *archive_handle);
+
+extern void unpack_ar_archive(archive_handle_t *ar_archive);
+
+extern void data_skip(archive_handle_t *archive_handle);
+extern void data_extract_all(archive_handle_t *archive_handle);
+extern void data_extract_to_stdout(archive_handle_t *archive_handle);
+extern void data_extract_to_buffer(archive_handle_t *archive_handle);
+
+extern void header_skip(const file_header_t *file_header);
+extern void header_list(const file_header_t *file_header);
+extern void header_verbose_list(const file_header_t *file_header);
+
+extern char get_header_ar(archive_handle_t *archive_handle);
+extern char get_header_cpio(archive_handle_t *archive_handle);
+extern char get_header_tar(archive_handle_t *archive_handle);
+extern char get_header_tar_bz2(archive_handle_t *archive_handle);
+extern char get_header_tar_lzma(archive_handle_t *archive_handle);
+extern char get_header_tar_gz(archive_handle_t *archive_handle);
+
+extern void seek_by_jump(const archive_handle_t *archive_handle, unsigned amount);
+extern void seek_by_read(const archive_handle_t *archive_handle, unsigned amount);
+
+extern ssize_t archive_xread_all_eof(archive_handle_t *archive_handle, unsigned char *buf, size_t count);
+
+extern void data_align(archive_handle_t *archive_handle, unsigned boundary);
+extern const llist_t *find_list_entry(const llist_t *list, const char *filename);
+extern const llist_t *find_list_entry2(const llist_t *list, const char *filename);
+
+/* A bit of bunzip2 internals are exposed for compressed help support: */
+typedef struct bunzip_data bunzip_data;
+int start_bunzip(bunzip_data **bdp, int in_fd, const unsigned char *inbuf, int len);
+int read_bunzip(bunzip_data *bd, char *outbuf, int len);
+void dealloc_bunzip(bunzip_data *bd);
+
+typedef struct inflate_unzip_result {
+ off_t bytes_out;
+ uint32_t crc;
+} inflate_unzip_result;
+
+extern USE_DESKTOP(long long) int unpack_bz2_stream(int src_fd, int dst_fd);
+extern USE_DESKTOP(long long) int inflate_unzip(inflate_unzip_result *res, off_t compr_size, int src_fd, int dst_fd);
+extern USE_DESKTOP(long long) int unpack_gz_stream(int src_fd, int dst_fd);
+extern USE_DESKTOP(long long) int unpack_lzma_stream(int src_fd, int dst_fd);
+
+#if BB_MMU
+extern int open_transformer(int src_fd,
+ USE_DESKTOP(long long) int (*transformer)(int src_fd, int dst_fd));
+#define open_transformer(src_fd, transformer, transform_prog) open_transformer(src_fd, transformer)
+#else
+extern int open_transformer(int src_fd, const char *transform_prog);
+#define open_transformer(src_fd, transformer, transform_prog) open_transformer(src_fd, transform_prog)
+#endif
+
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility pop
+#endif
+
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/include/usage.h b/cleopatre/busybox-1.11.1-spc300/include/usage.h
new file mode 100644
index 0000000000..ceac6d0afb
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/include/usage.h
@@ -0,0 +1,4591 @@
+/* vi: set sw=8 ts=8: */
+/*
+ * This file suffers from chronically incorrect tabification
+ * of messages. Before editing this file:
+ * 1. Switch you editor to 8-space tab mode.
+ * 2. Do not use \t in messages, use real tab character.
+ * 3. Start each source line with message as follows:
+ * |<7 spaces>"text with tabs"....
+ * or
+ * |<5 spaces>"\ntext with tabs"....
+ */
+
+#ifndef __BB_USAGE_H__
+#define __BB_USAGE_H__
+
+
+#define NOUSAGE_STR "\b"
+
+
+#define addgroup_trivial_usage \
+ "[-g GID] " USE_FEATURE_ADDUSER_TO_GROUP("[user_name] ") "group_name"
+#define addgroup_full_usage "\n\n" \
+ "Add a group " USE_FEATURE_ADDUSER_TO_GROUP("or add an user to a group") "\n" \
+ "\nOptions:" \
+ "\n -g GID Group id" \
+
+#define adduser_trivial_usage \
+ "[OPTIONS] user_name"
+#define adduser_full_usage "\n\n" \
+ "Add an user\n" \
+ "\nOptions:" \
+ "\n -h DIR Home directory" \
+ "\n -g GECOS GECOS field" \
+ "\n -s SHELL Login shell" \
+ "\n -G GROUP Add user to existing group" \
+ "\n -S Create a system user" \
+ "\n -D Do not assign a password" \
+ "\n -H Do not create home directory" \
+
+#define adjtimex_trivial_usage \
+ "[-q] [-o offset] [-f frequency] [-p timeconstant] [-t tick]"
+#define adjtimex_full_usage "\n\n" \
+ "Read and optionally set system timebase parameters. See adjtimex(2).\n" \
+ "\nOptions:" \
+ "\n -q Quiet" \
+ "\n -o offset Time offset, microseconds" \
+ "\n -f frequency Frequency adjust, integer kernel units (65536 is 1ppm)" \
+ "\n (positive values make clock run faster)" \
+ "\n -t tick Microseconds per tick, usually 10000" \
+ "\n -p timeconstant" \
+
+#define ar_trivial_usage \
+ "[-o] [-v] [-p] [-t] [-x] ARCHIVE FILES"
+#define ar_full_usage "\n\n" \
+ "Extract or list FILES from an ar archive\n" \
+ "\nOptions:" \
+ "\n -o Preserve original dates" \
+ "\n -p Extract to stdout" \
+ "\n -t List" \
+ "\n -x Extract" \
+ "\n -v Verbose" \
+
+#define arp_trivial_usage \
+ "\n" \
+ "[-vn] [-H type] [-i if] -a [hostname]\n" \
+ "[-v] [-i if] -d hostname [pub]\n" \
+ "[-v] [-H type] [-i if] -s hostname hw_addr [temp]\n" \
+ "[-v] [-H type] [-i if] -s hostname hw_addr [netmask nm] pub\n" \
+ "[-v] [-H type] [-i if] -Ds hostname ifa [netmask nm] pub\n"
+#define arp_full_usage "\n\n" \
+ "Manipulate ARP cache\n" \
+ "\nOptions:" \
+ "\n -a Display (all) hosts" \
+ "\n -s Set new ARP entry" \
+ "\n -d Delete a specified entry" \
+ "\n -v Verbose" \
+ "\n -n Don't resolve names" \
+ "\n -i IF Network interface" \
+ "\n -D Read <hwaddr> from given device" \
+ "\n -A, -p AF Protocol family" \
+ "\n -H HWTYPE Hardware address type" \
+
+#define arping_trivial_usage \
+ "[-fqbDUA] [-c count] [-w timeout] [-I dev] [-s sender] target"
+#define arping_full_usage "\n\n" \
+ "Send ARP requests/replies\n" \
+ "\nOptions:" \
+ "\n -f Quit on first ARP reply" \
+ "\n -q Quiet" \
+ "\n -b Keep broadcasting, don't go unicast" \
+ "\n -D Duplicated address detection mode" \
+ "\n -U Unsolicited ARP mode, update your neighbors" \
+ "\n -A ARP answer mode, update your neighbors" \
+ "\n -c N Stop after sending N ARP requests" \
+ "\n -w timeout Time to wait for ARP reply, in seconds" \
+ "\n -I dev Interface to use (default eth0)" \
+ "\n -s sender Sender IP address" \
+ "\n target Target IP address" \
+
+#define sh_trivial_usage NOUSAGE_STR
+#define sh_full_usage ""
+#define ash_trivial_usage NOUSAGE_STR
+#define ash_full_usage ""
+#define hush_trivial_usage NOUSAGE_STR
+#define hush_full_usage ""
+#define msh_trivial_usage NOUSAGE_STR
+#define msh_full_usage ""
+
+#define awk_trivial_usage \
+ "[OPTION]... [program-text] [FILE...]"
+#define awk_full_usage "\n\n" \
+ "Options:" \
+ "\n -v var=val Set variable" \
+ "\n -F sep Use sep as field separator" \
+ "\n -f file Read program from file" \
+
+#define basename_trivial_usage \
+ "FILE [SUFFIX]"
+#define basename_full_usage "\n\n" \
+ "Strip directory path and suffixes from FILE.\n" \
+ "If specified, also remove any trailing SUFFIX."
+#define basename_example_usage \
+ "$ basename /usr/local/bin/foo\n" \
+ "foo\n" \
+ "$ basename /usr/local/bin/\n" \
+ "bin\n" \
+ "$ basename /foo/bar.txt .txt\n" \
+ "bar"
+
+#define fbsplash_trivial_usage \
+ "-s IMGFILE [-c] [-d DEV] [-i INIFILE] [-f CMD]"
+#define fbsplash_full_usage "\n\n" \
+ "Options:\n" \
+ "\n -s Image" \
+ "\n -c Hide cursor" \
+ "\n -d Framebuffer device (default /dev/fb0)" \
+ "\n -i Config file (var=value):" \
+ "\n BAR_LEFT,BAR_TOP,BAR_WIDTH,BAR_HEIGHT" \
+ "\n BAR_R,BAR_G,BAR_B" \
+ "\n -f Control pipe (else exit after drawing image)" \
+ "\n commands: 'NN' (% for progress bar) or 'exit'" \
+
+#define brctl_trivial_usage \
+ "COMMAND [BRIDGE [INTERFACE]]"
+#define brctl_full_usage "\n\n" \
+ "Manage ethernet bridges.\n" \
+ "\nCommands:" \
+ USE_FEATURE_BRCTL_SHOW( \
+ "\n show Show a list of bridges" \
+ ) \
+ "\n addbr BRIDGE Create BRIDGE" \
+ "\n delbr BRIDGE Delete BRIDGE" \
+ "\n addif BRIDGE IFACE Add IFACE to BRIDGE" \
+ "\n delif BRIDGE IFACE Delete IFACE from BRIDGE" \
+ USE_FEATURE_BRCTL_FANCY( \
+ "\n setageing BRIDGE TIME Set ageing time" \
+ "\n setfd BRIDGE TIME Set bridge forward delay" \
+ "\n sethello BRIDGE TIME Set hello time" \
+ "\n setmaxage BRIDGE TIME Set max message age" \
+ "\n setpathcost BRIDGE COST Set path cost" \
+ "\n setportprio BRIDGE PRIO Set port priority" \
+ "\n setbridgeprio BRIDGE PRIO Set bridge priority" \
+ "\n stp BRIDGE [1|0] STP on/off" \
+ ) \
+
+#define bunzip2_trivial_usage \
+ "[OPTION]... [FILE]"
+#define bunzip2_full_usage "\n\n" \
+ "Uncompress FILE (or standard input if FILE is '-' or omitted)\n" \
+ "\nOptions:" \
+ "\n -c Write to standard output" \
+ "\n -f Force" \
+
+#define bzip2_trivial_usage \
+ "[OPTION]... [FILE]..."
+#define bzip2_full_usage "\n\n" \
+ "Compress FILE(s) with bzip2 algorithm.\n" \
+ "When FILE is '-' or unspecified, reads standard input. Implies -c.\n" \
+ "\nOptions:" \
+ "\n -c Write to standard output" \
+ "\n -d Decompress" \
+ "\n -f Force" \
+ "\n -1..-9 Compression level" \
+
+#define busybox_notes_usage \
+ "Hello world!\n"
+
+#define bzcat_trivial_usage \
+ "FILE"
+#define bzcat_full_usage "\n\n" \
+ "Uncompress to stdout"
+
+#define unlzma_trivial_usage \
+ "[OPTION]... [FILE]"
+#define unlzma_full_usage "\n\n" \
+ "Uncompress FILE (or standard input if FILE is '-' or omitted)\n" \
+ "\nOptions:" \
+ "\n -c Write to standard output" \
+ "\n -f Force" \
+
+#define lzmacat_trivial_usage \
+ "FILE"
+#define lzmacat_full_usage "\n\n" \
+ "Uncompress to stdout"
+
+#define cal_trivial_usage \
+ "[-jy] [[month] year]"
+#define cal_full_usage "\n\n" \
+ "Display a calendar\n" \
+ "\nOptions:" \
+ "\n -j Use julian dates" \
+ "\n -y Display the entire year" \
+
+#define cat_trivial_usage \
+ "[-u] [FILE]..."
+#define cat_full_usage "\n\n" \
+ "Concatenate FILE(s) and print them to stdout\n" \
+ "\nOptions:" \
+ "\n -u Use unbuffered i/o (ignored)" \
+
+#define cat_example_usage \
+ "$ cat /proc/uptime\n" \
+ "110716.72 17.67"
+
+#define catv_trivial_usage \
+ "[-etv] [FILE]..."
+#define catv_full_usage "\n\n" \
+ "Display nonprinting characters as ^x or M-x\n" \
+ "\nOptions:" \
+ "\n -e End each line with $" \
+ "\n -t Show tabs as ^I" \
+ "\n -v Don't use ^x or M-x escapes" \
+
+#define chat_trivial_usage \
+ "EXPECT [SEND [EXPECT [SEND...]]]"
+#define chat_full_usage "\n\n" \
+ "Useful for interacting with a modem connected to stdin/stdout.\n" \
+ "A script consists of one or more \"expect-send\" pairs of strings,\n" \
+ "each pair is a pair of arguments. Example:\n" \
+ "chat '' ATZ OK ATD123456 CONNECT '' ogin: pppuser word: ppppass '~'" \
+
+#define chattr_trivial_usage \
+ "[-R] [-+=AacDdijsStTu] [-v version] files..."
+#define chattr_full_usage "\n\n" \
+ "Change file attributes on an ext2 fs\n" \
+ "\nModifiers:" \
+ "\n - Remove attributes" \
+ "\n + Add attributes" \
+ "\n = Set attributes" \
+ "\nAttributes:" \
+ "\n A Don't track atime" \
+ "\n a Append mode only" \
+ "\n c Enable compress" \
+ "\n D Write dir contents synchronously" \
+ "\n d Do not backup with dump" \
+ "\n i Cannot be modified (immutable)" \
+ "\n j Write all data to journal first" \
+ "\n s Zero disk storage when deleted" \
+ "\n S Write file contents synchronously" \
+ "\n t Disable tail-merging of partial blocks with other files" \
+ "\n u Allow file to be undeleted" \
+ "\nOptions:" \
+ "\n -R Recursively list subdirectories" \
+ "\n -v Set the file's version/generation number" \
+
+#define chcon_trivial_usage \
+ "[OPTIONS] CONTEXT FILE..." \
+ "\n chcon [OPTIONS] [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE..." \
+ USE_FEATURE_CHCON_LONG_OPTIONS( \
+ "\n chcon [OPTIONS] --reference=RFILE FILE..." \
+ )
+#define chcon_full_usage "\n\n" \
+ "Change the security context of each FILE to CONTEXT\n" \
+ USE_FEATURE_CHCON_LONG_OPTIONS( \
+ "\n -v,--verbose Verbose" \
+ "\n -c,--changes Report changes made" \
+ "\n -h,--no-dereference Affect symlinks instead of their targets" \
+ "\n -f,--silent,--quiet Suppress most error messages" \
+ "\n --reference=RFILE Use RFILE's group instead of using a CONTEXT value" \
+ "\n -u,--user=USER Set user/role/type/range in the target" \
+ "\n -r,--role=ROLE security context" \
+ "\n -t,--type=TYPE" \
+ "\n -l,--range=RANGE" \
+ "\n -R,--recursive Recurse subdirectories" \
+ ) \
+ SKIP_FEATURE_CHCON_LONG_OPTIONS( \
+ "\n -v Verbose" \
+ "\n -c Report changes made" \
+ "\n -h Affect symlinks instead of their targets" \
+ "\n -f Suppress most error messages" \
+ "\n -u USER Set user/role/type/range in the target security context" \
+ "\n -r ROLE" \
+ "\n -t TYPE" \
+ "\n -l RNG" \
+ "\n -R Recurse subdirectories" \
+ )
+
+#define chmod_trivial_usage \
+ "[-R"USE_DESKTOP("cvf")"] MODE[,MODE]... FILE..."
+#define chmod_full_usage "\n\n" \
+ "Each MODE is one or more of the letters ugoa, one of the\n" \
+ "symbols +-= and one or more of the letters rwxst\n" \
+ "\nOptions:" \
+ "\n -R Recurse directories" \
+ USE_DESKTOP( \
+ "\n -c List changed files" \
+ "\n -v List all files" \
+ "\n -f Hide errors" \
+ )
+#define chmod_example_usage \
+ "$ ls -l /tmp/foo\n" \
+ "-rw-rw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n" \
+ "$ chmod u+x /tmp/foo\n" \
+ "$ ls -l /tmp/foo\n" \
+ "-rwxrw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo*\n" \
+ "$ chmod 444 /tmp/foo\n" \
+ "$ ls -l /tmp/foo\n" \
+ "-r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n"
+
+#define chgrp_trivial_usage \
+ "[-RhLHP"USE_DESKTOP("cvf")"]... GROUP FILE..."
+#define chgrp_full_usage "\n\n" \
+ "Change the group membership of each FILE to GROUP\n" \
+ "\nOptions:" \
+ "\n -R Recurse directories" \
+ "\n -h Affect symlinks instead of symlink targets" \
+ "\n -L Traverse all symlinks to directories" \
+ "\n -H Traverse symlinks on command line only" \
+ "\n -P Do not traverse symlinks (default)" \
+ USE_DESKTOP( \
+ "\n -c List changed files" \
+ "\n -v Verbose" \
+ "\n -f Hide errors" \
+ )
+#define chgrp_example_usage \
+ "$ ls -l /tmp/foo\n" \
+ "-r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo\n" \
+ "$ chgrp root /tmp/foo\n" \
+ "$ ls -l /tmp/foo\n" \
+ "-r--r--r-- 1 andersen root 0 Apr 12 18:25 /tmp/foo\n"
+
+#define chown_trivial_usage \
+ "[-RhLHP"USE_DESKTOP("cvf")"]... OWNER[<.|:>[GROUP]] FILE..."
+#define chown_full_usage "\n\n" \
+ "Change the owner and/or group of each FILE to OWNER and/or GROUP\n" \
+ "\nOptions:" \
+ "\n -R Recurse directories" \
+ "\n -h Affect symlinks instead of symlink targets" \
+ "\n -L Traverse all symlinks to directories" \
+ "\n -H Traverse symlinks on command line only" \
+ "\n -P Do not traverse symlinks (default)" \
+ USE_DESKTOP( \
+ "\n -c List changed files" \
+ "\n -v List all files" \
+ "\n -f Hide errors" \
+ )
+#define chown_example_usage \
+ "$ ls -l /tmp/foo\n" \
+ "-r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo\n" \
+ "$ chown root /tmp/foo\n" \
+ "$ ls -l /tmp/foo\n" \
+ "-r--r--r-- 1 root andersen 0 Apr 12 18:25 /tmp/foo\n" \
+ "$ chown root.root /tmp/foo\n" \
+ "ls -l /tmp/foo\n" \
+ "-r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n"
+
+#define chpst_trivial_usage \
+ "[-vP012] [-u user[:group]] [-U user[:group]] [-e dir] " \
+ "[-/ dir] [-n nice] [-m bytes] [-d bytes] [-o files] " \
+ "[-p processes] [-f bytes] [-c bytes] prog args"
+#define chpst_full_usage "\n\n" \
+ "Change the process state and run specified program\n" \
+ "\nOptions:" \
+ "\n -u USER[:GRP] Set uid and gid" \
+ "\n -U USER[:GRP] Set $UID and $GID in environment" \
+ "\n -e DIR Set environment variables as specified by files" \
+ "\n in DIR: file=1st_line_of_file" \
+ "\n -/ DIR Chroot to DIR" \
+ "\n -n INC Add INC to nice value" \
+ "\n -m BYTES Limit data segment, stack segment, locked physical pages," \
+ "\n and total of all segment per process to BYTES each" \
+ "\n -d BYTES Limit data segment" \
+ "\n -o N Limit the number of open file descriptors per process to N" \
+ "\n -p N Limit number of processes per uid to N" \
+ "\n -f BYTES Limit output file size to BYTES" \
+ "\n -c BYTES Limit core file size to BYTES" \
+ "\n -v Verbose" \
+ "\n -P Run prog in a new process group" \
+ "\n -0 Close standard input" \
+ "\n -1 Close standard output" \
+ "\n -2 Close standard error" \
+
+#define setuidgid_trivial_usage \
+ "account prog args"
+#define setuidgid_full_usage "\n\n" \
+ "Set uid and gid to account's uid and gid, removing all supplementary\n" \
+ "groups, then run prog"
+#define envuidgid_trivial_usage \
+ "account prog args"
+#define envuidgid_full_usage "\n\n" \
+ "Set $UID to account's uid and $GID to account's gid, then run prog"
+#define envdir_trivial_usage \
+ "dir prog args"
+#define envdir_full_usage "\n\n" \
+ "Set various environment variables as specified by files\n" \
+ "in the directory dir, then run prog"
+#define softlimit_trivial_usage \
+ "[-a allbytes] [-c corebytes] [-d databytes] [-f filebytes] " \
+ "[-l lockbytes] [-m membytes] [-o openfiles] [-p processes] " \
+ "[-r residentbytes] [-s stackbytes] [-t cpusecs] prog args"
+#define softlimit_full_usage "\n\n" \
+ "Set soft resource limits, then run prog\n" \
+ "\nOptions:" \
+ "\n -m n Same as -d n -s n -l n -a n" \
+ "\n -d n Limit the data segment per process to n bytes" \
+ "\n -s n Limit the stack segment per process to n bytes" \
+ "\n -l n Limit the locked physical pages per process to n bytes" \
+ "\n -a n Limit the total of all segments per process to n bytes" \
+ "\n -o n Limit the number of open file descriptors per process to n" \
+ "\n -p n Limit the number of processes per uid to n" \
+ "\nOptions controlling file sizes:" \
+ "\n -f n Limit output file sizes to n bytes" \
+ "\n -c n Limit core file sizes to n bytes" \
+ "\nEfficiency opts:" \
+ "\n -r n Limit the resident set size to n bytes. This limit is not" \
+ "\n enforced unless physical memory is full" \
+ "\n -t n Limit the CPU time to n seconds. This limit is not enforced" \
+ "\n except that the process receives a SIGXCPU signal after n seconds" \
+ "\n" \
+ "\nSome options may have no effect on some operating systems" \
+ "\nn may be =, indicating that soft limit should be set equal to hard limit" \
+
+#define chroot_trivial_usage \
+ "NEWROOT [COMMAND...]"
+#define chroot_full_usage "\n\n" \
+ "Run COMMAND with root directory set to NEWROOT"
+#define chroot_example_usage \
+ "$ ls -l /bin/ls\n" \
+ "lrwxrwxrwx 1 root root 12 Apr 13 00:46 /bin/ls -> /BusyBox\n" \
+ "# mount /dev/hdc1 /mnt -t minix\n" \
+ "# chroot /mnt\n" \
+ "# ls -l /bin/ls\n" \
+ "-rwxr-xr-x 1 root root 40816 Feb 5 07:45 /bin/ls*\n"
+
+#define chvt_trivial_usage \
+ "N"
+#define chvt_full_usage "\n\n" \
+ "Change the foreground virtual terminal to /dev/ttyN"
+
+#define cksum_trivial_usage \
+ "FILES..."
+#define cksum_full_usage "\n\n" \
+ "Calculate the CRC32 checksums of FILES"
+
+#define clear_trivial_usage \
+ ""
+#define clear_full_usage "\n\n" \
+ "Clear screen"
+
+#define cmp_trivial_usage \
+ "[-l] [-s] FILE1 [FILE2" USE_DESKTOP(" [SKIP1 [SKIP2]") "]]"
+#define cmp_full_usage "\n\n" \
+ "Compares FILE1 vs stdin if FILE2 is not specified\n" \
+ "\nOptions:" \
+ "\n -l Write the byte numbers (decimal) and values (octal)" \
+ "\n for all differing bytes" \
+ "\n -s Quiet" \
+
+#define comm_trivial_usage \
+ "[-123] FILE1 FILE2"
+#define comm_full_usage "\n\n" \
+ "Compare FILE1 to FILE2, or to stdin if - is specified\n" \
+ "\nOptions:" \
+ "\n -1 Suppress lines unique to FILE1" \
+ "\n -2 Suppress lines unique to FILE2" \
+ "\n -3 Suppress lines common to both files" \
+
+#define bbconfig_trivial_usage \
+ ""
+#define bbconfig_full_usage "\n\n" \
+ "Print the config file which built busybox"
+
+#define bbsh_trivial_usage \
+ "[FILE]...\n" \
+ "or: bbsh -c command [args]..."
+#define bbsh_full_usage "\n\n" \
+ "The bbsh shell (command interpreter)"
+
+#define chrt_trivial_usage \
+ "[OPTION]... [prio] [pid | command [arg]...]"
+#define chrt_full_usage "\n\n" \
+ "Manipulate real-time attributes of a process\n" \
+ "\nOptions:" \
+ "\n -p Operate on pid" \
+ "\n -r Set scheduling policy to SCHED_RR" \
+ "\n -f Set scheduling policy to SCHED_FIFO" \
+ "\n -o Set scheduling policy to SCHED_OTHER" \
+ "\n -m Show min and max priorities" \
+
+#define chrt_example_usage \
+ "$ chrt -r 4 sleep 900; x=$!\n" \
+ "$ chrt -f -p 3 $x\n" \
+ "You need CAP_SYS_NICE privileges to set scheduling attributes of a process"
+
+#define cp_trivial_usage \
+ "[OPTION]... SOURCE DEST"
+#define cp_full_usage "\n\n" \
+ "Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY\n" \
+ "\nOptions:" \
+ "\n -a Same as -dpR" \
+ USE_SELINUX( \
+ "\n -c Preserve security context" \
+ ) \
+ "\n -d,-P Preserve links" \
+ "\n -H,-L Dereference all symlinks (default)" \
+ "\n -p Preserve file attributes if possible" \
+ "\n -f Force overwrite" \
+ "\n -i Prompt before overwrite" \
+ "\n -R,-r Recurse directories" \
+ "\n -l,-s Create (sym)links" \
+
+#define cpio_trivial_usage \
+ "-[dim" USE_FEATURE_CPIO_O("o") "tuv][F cpiofile]" \
+ USE_FEATURE_CPIO_O( "[H newc]" )
+#define cpio_full_usage "\n\n" \
+ "Extract or list files from a cpio archive" \
+ USE_FEATURE_CPIO_O( ", or create a cpio archive" ) \
+ "\n" \
+ "Main operation mode:" \
+ "\n d Make leading directories" \
+ "\n i Extract" \
+ "\n m Preserve mtime" \
+ USE_FEATURE_CPIO_O( \
+ "\n o Create" \
+ "\n H newc Define format" \
+ ) \
+ "\n t List" \
+ "\n v Verbose" \
+ "\n u Unconditional overwrite" \
+ "\n F Input from file" \
+
+#define crond_trivial_usage \
+ "-fbS -l N " USE_DEBUG_CROND_OPTION("-d N ") "-L LOGFILE -c DIR"
+#define crond_full_usage "\n\n" \
+ " -f Foreground" \
+ "\n -b Background (default)" \
+ "\n -S Log to syslog (default)" \
+ "\n -l Set log level. 0 is the most verbose, default 8" \
+ USE_DEBUG_CROND_OPTION( \
+ "\n -d Set log level, log to stderr" \
+ ) \
+ "\n -L Log to file" \
+ "\n -c Working dir" \
+
+#define crontab_trivial_usage \
+ "[-c DIR] [-u USER] [-ler]|[FILE]"
+#define crontab_full_usage "\n\n" \
+ " -c Crontab directory" \
+ "\n -u User" \
+ "\n -l List crontab" \
+ "\n -e Edit crontab" \
+ "\n -r Delete crontab" \
+ "\n FILE Replace crontab by FILE ('-': stdin)" \
+
+#define cryptpw_trivial_usage \
+ "[-a des|md5] [string]"
+#define cryptpw_full_usage "\n\n" \
+ "Output crypted string.\n" \
+ "If string isn't supplied on cmdline, read it from stdin.\n" \
+ "\nOptions:" \
+ "\n -a Algorithm to use (default: md5)" \
+
+#define cttyhack_trivial_usage NOUSAGE_STR
+#define cttyhack_full_usage ""
+
+#define cut_trivial_usage \
+ "[OPTION]... [FILE]..."
+#define cut_full_usage "\n\n" \
+ "Print selected fields from each input FILE to standard output\n" \
+ "\nOptions:" \
+ "\n -b LIST Output only bytes from LIST" \
+ "\n -c LIST Output only characters from LIST" \
+ "\n -d CHAR Use CHAR instead of tab as the field delimiter" \
+ "\n -s Output only the lines containing delimiter" \
+ "\n -f N Print only these fields" \
+ "\n -n Ignored" \
+
+#define cut_example_usage \
+ "$ echo \"Hello world\" | cut -f 1 -d ' '\n" \
+ "Hello\n" \
+ "$ echo \"Hello world\" | cut -f 2 -d ' '\n" \
+ "world\n"
+
+#define date_trivial_usage \
+ "[OPTION]... [+FMT] [TIME]"
+#define date_full_usage "\n\n" \
+ "Display time (using +FMT), or set time\n" \
+ "\nOptions:" \
+ "\n -u Work in UTC (don't convert to local time)" \
+ "\n -R Output RFC-822 compliant date string" \
+ USE_FEATURE_DATE_ISOFMT( \
+ "\n -I[SPEC] Output ISO-8601 compliant date string" \
+ "\n SPEC='date' (default) for date only," \
+ "\n 'hours', 'minutes', or 'seconds' for date and" \
+ "\n time to the indicated precision" \
+ ) \
+ "\n -d TIME Display TIME, not 'now'" \
+ "\n -r FILE Display last modification time of FILE" \
+ "\n [-s] TIME Set time to TIME" \
+ USE_FEATURE_DATE_ISOFMT( \
+ "\n -D FMT Use FMT for str->date conversion" \
+ ) \
+ "\n" \
+ "\nRecognized formats for TIME:" \
+ "\n hh:mm[:ss]" \
+ "\n [YYYY.]MM.DD-hh:mm[:ss]" \
+ "\n YYYY-MM-DD hh:mm[:ss]" \
+ "\n MMDDhhmm[[YY]YY][.ss]" \
+
+#define date_example_usage \
+ "$ date\n" \
+ "Wed Apr 12 18:52:41 MDT 2000\n"
+
+#define dc_trivial_usage \
+ "expression..."
+#define dc_full_usage "\n\n" \
+ "Tiny RPN calculator. Operations:\n" \
+ "+, add, -, sub, *, mul, /, div, %, mod, **, exp, and, or, not, eor,\n" \
+ "p - print top of the stack (without altering the stack),\n" \
+ "f - print entire stack, o - pop the value and set output radix\n" \
+ "(value must be 10 or 16).\n" \
+ "Examples: 'dc 2 2 add' -> 4, 'dc 8 8 * 2 2 + /' -> 16.\n" \
+
+#define dc_example_usage \
+ "$ dc 2 2 + p\n" \
+ "4\n" \
+ "$ dc 8 8 \\* 2 2 + / p\n" \
+ "16\n" \
+ "$ dc 0 1 and p\n" \
+ "0\n" \
+ "$ dc 0 1 or p\n" \
+ "1\n" \
+ "$ echo 72 9 div 8 mul p | dc\n" \
+ "64\n"
+
+#define dd_trivial_usage \
+ "[if=FILE] [of=FILE] " USE_FEATURE_DD_IBS_OBS("[ibs=N] [obs=N] ") "[bs=N] [count=N] [skip=N]\n" \
+ " [seek=N]" USE_FEATURE_DD_IBS_OBS(" [conv=notrunc|noerror|sync|fsync]")
+#define dd_full_usage "\n\n" \
+ "Copy a file with converting and formatting\n" \
+ "\nOptions:" \
+ "\n if=FILE Read from FILE instead of stdin" \
+ "\n of=FILE Write to FILE instead of stdout" \
+ "\n bs=N Read and write N bytes at a time" \
+ USE_FEATURE_DD_IBS_OBS( \
+ "\n ibs=N Read N bytes at a time" \
+ ) \
+ USE_FEATURE_DD_IBS_OBS( \
+ "\n obs=N Write N bytes at a time" \
+ ) \
+ "\n count=N Copy only N input blocks" \
+ "\n skip=N Skip N input blocks" \
+ "\n seek=N Skip N output blocks" \
+ USE_FEATURE_DD_IBS_OBS( \
+ "\n conv=notrunc Don't truncate output file" \
+ "\n conv=noerror Continue after read errors" \
+ "\n conv=sync Pad blocks with zeros" \
+ "\n conv=fsync Physically write data out before finishing" \
+ ) \
+ "\n" \
+ "\nNumbers may be suffixed by c (x1), w (x2), b (x512), kD (x1000), k (x1024)," \
+ "\nMD (x1000000), M (x1048576), GD (x1000000000) or G (x1073741824)" \
+
+#define dd_example_usage \
+ "$ dd if=/dev/zero of=/dev/ram1 bs=1M count=4\n" \
+ "4+0 records in\n" \
+ "4+0 records out\n"
+
+#define deallocvt_trivial_usage \
+ "[N]"
+#define deallocvt_full_usage "\n\n" \
+ "Deallocate unused virtual terminal /dev/ttyN"
+
+#define delgroup_trivial_usage \
+ USE_FEATURE_DEL_USER_FROM_GROUP("[USER] ")"GROUP"
+#define delgroup_full_usage "\n\n" \
+ "Delete group GROUP from the system" \
+ USE_FEATURE_DEL_USER_FROM_GROUP(" or user USER from group GROUP")
+
+#define deluser_trivial_usage \
+ "USER"
+#define deluser_full_usage "\n\n" \
+ "Delete USER from the system"
+
+#define depmod_trivial_usage NOUSAGE_STR
+#define depmod_full_usage ""
+
+#define devfsd_trivial_usage \
+ "mntpnt [-v]" USE_DEVFSD_FG_NP("[-fg][-np]")
+#define devfsd_full_usage "\n\n" \
+ "Manage devfs permissions and old device name symlinks\n" \
+ "\nOptions:" \
+ "\n mntpnt The mount point where devfs is mounted" \
+ "\n -v Print the protocol version numbers for devfsd" \
+ "\n and the kernel-side protocol version and exit" \
+ USE_DEVFSD_FG_NP( \
+ "\n -fg Run in foreground" \
+ "\n -np Exit after parsing the configuration file" \
+ "\n and processing synthetic REGISTER events," \
+ "\n do not poll for events" \
+ )
+
+/* -k is accepted but ignored for !HUMAN_READABLE,
+ * but we won't mention this (unimportant) */
+#if ENABLE_FEATURE_HUMAN_READABLE || ENABLE_FEATURE_DF_INODE
+#define DF_HAS_OPTIONS(x) x
+#else
+#define DF_HAS_OPTIONS(x)
+#endif
+#define df_trivial_usage \
+ DF_HAS_OPTIONS("[-") \
+ USE_FEATURE_HUMAN_READABLE("hmk") USE_FEATURE_DF_INODE("i") \
+ DF_HAS_OPTIONS("] ") "[FILESYSTEM...]"
+#define df_full_usage "\n\n" \
+ "Print filesystem usage statistics\n" \
+ DF_HAS_OPTIONS("\nOptions:") \
+ USE_FEATURE_HUMAN_READABLE( \
+ "\n -h Human readable (e.g. 1K 243M 2G)" \
+ "\n -m 1024*1024 blocks" \
+ "\n -k 1024 blocks" \
+ ) \
+ USE_FEATURE_DF_INODE( \
+ "\n -i Inodes" \
+ )
+#define df_example_usage \
+ "$ df\n" \
+ "Filesystem 1k-blocks Used Available Use% Mounted on\n" \
+ "/dev/sda3 8690864 8553540 137324 98% /\n" \
+ "/dev/sda1 64216 36364 27852 57% /boot\n" \
+ "$ df /dev/sda3\n" \
+ "Filesystem 1k-blocks Used Available Use% Mounted on\n" \
+ "/dev/sda3 8690864 8553540 137324 98% /\n"
+
+#define dhcprelay_trivial_usage \
+ "[client1,client2,...] [server_device]"
+#define dhcprelay_full_usage "\n\n" \
+ "Relay dhcp requests from client devices to server device.\n" \
+ "Pass clients as CSV"
+
+#define diff_trivial_usage \
+ "[-abdiNqrTstw] [-L LABEL] [-S FILE] [-U LINES] FILE1 FILE2"
+#define diff_full_usage "\n\n" \
+ "Compare files line by line and output the differences between them.\n" \
+ "This implementation supports unified diffs only.\n" \
+ "\nOptions:" \
+ "\n -a Treat all files as text" \
+ "\n -b Ignore changes in the amount of whitespace" \
+ "\n -d Try hard to find a smaller set of changes" \
+ "\n -i Ignore case differences" \
+ "\n -L Use LABEL instead of the filename in the unified header" \
+ "\n -N Treat absent files as empty" \
+ "\n -q Output only whether files differ" \
+ "\n -r Recursively compare subdirectories" \
+ "\n -S Start with FILE when comparing directories" \
+ "\n -T Make tabs line up by prefixing a tab when necessary" \
+ "\n -s Report when two files are the same" \
+ "\n -t Expand tabs to spaces in output" \
+ "\n -U Output LINES lines of context" \
+ "\n -w Ignore all whitespace" \
+
+#define dirname_trivial_usage \
+ "FILENAME"
+#define dirname_full_usage "\n\n" \
+ "Strip non-directory suffix from FILENAME"
+#define dirname_example_usage \
+ "$ dirname /tmp/foo\n" \
+ "/tmp\n" \
+ "$ dirname /tmp/foo/\n" \
+ "/tmp\n"
+
+#define dmesg_trivial_usage \
+ "[-c] [-n LEVEL] [-s SIZE]"
+#define dmesg_full_usage "\n\n" \
+ "Print or control the kernel ring buffer\n" \
+ "\nOptions:" \
+ "\n -c Clear ring buffer after printing" \
+ "\n -n LEVEL Set console logging level" \
+ "\n -s SIZE Buffer size" \
+
+#define dnsd_trivial_usage \
+ "[-c config] [-t seconds] [-p port] [-i iface-ip] [-d]"
+#define dnsd_full_usage "\n\n" \
+ "Small static DNS server daemon\n" \
+ "\nOptions:" \
+ "\n -c Config filename" \
+ "\n -t TTL in seconds" \
+ "\n -p Listening port" \
+ "\n -i Listening ip (default all)" \
+ "\n -d Daemonize" \
+
+#define dos2unix_trivial_usage \
+ "[option] [FILE]"
+#define dos2unix_full_usage "\n\n" \
+ "Convert FILE from dos to unix format.\n" \
+ "When no file is given, use stdin/stdout.\n" \
+ "\nOptions:" \
+ "\n -u dos2unix" \
+ "\n -d unix2dos" \
+
+#define dpkg_trivial_usage \
+ "[-ilCPru] [-F option] package_name"
+#define dpkg_full_usage "\n\n" \
+ "Install, remove and manage Debian packages\n" \
+ "\nOptions:" \
+ "\n -i Install the package" \
+ "\n -l List of installed packages" \
+ "\n -C Configure an unpackaged package" \
+ "\n -F depends Ignore dependency problems" \
+ "\n -P Purge all files of a package" \
+ "\n -r Remove all but the configuration files for a package" \
+ "\n -u Unpack a package, but don't configure it" \
+
+#define dpkg_deb_trivial_usage \
+ "[-cefxX] FILE [argument]"
+#define dpkg_deb_full_usage "\n\n" \
+ "Perform actions on Debian packages (.debs)\n" \
+ "\nOptions:" \
+ "\n -c List contents of filesystem tree" \
+ "\n -e Extract control files to [argument] directory" \
+ "\n -f Display control field name starting with [argument]" \
+ "\n -x Extract packages filesystem tree to directory" \
+ "\n -X Verbose extract" \
+
+#define dpkg_deb_example_usage \
+ "$ dpkg-deb -X ./busybox_0.48-1_i386.deb /tmp\n"
+
+#define du_trivial_usage \
+ "[-aHLdclsx" USE_FEATURE_HUMAN_READABLE("hm") "k] [FILE]..."
+#define du_full_usage "\n\n" \
+ "Summarize disk space used for each FILE and/or directory.\n" \
+ "Disk space is printed in units of " \
+ USE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K("1024") \
+ SKIP_FEATURE_DU_DEFAULT_BLOCKSIZE_1K("512") \
+ " bytes.\n" \
+ "\nOptions:" \
+ "\n -a Show file sizes too" \
+ "\n -H Follow symlinks on command line" \
+ "\n -L Follow all symlinks" \
+ "\n -d N Limit output to directories (and files with -a) of depth < N" \
+ "\n -c Show grand total" \
+ "\n -l Count sizes many times if hard linked" \
+ "\n -s Display only a total for each argument" \
+ "\n -x Skip directories on different filesystems" \
+ USE_FEATURE_HUMAN_READABLE( \
+ "\n -h Sizes in human readable format (e.g., 1K 243M 2G )" \
+ "\n -m Sizes in megabytes" \
+ ) \
+ "\n -k Sizes in kilobytes" \
+ USE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(" (default)") \
+
+#define du_example_usage \
+ "$ du\n" \
+ "16 ./CVS\n" \
+ "12 ./kernel-patches/CVS\n" \
+ "80 ./kernel-patches\n" \
+ "12 ./tests/CVS\n" \
+ "36 ./tests\n" \
+ "12 ./scripts/CVS\n" \
+ "16 ./scripts\n" \
+ "12 ./docs/CVS\n" \
+ "104 ./docs\n" \
+ "2417 .\n"
+
+#define dumpkmap_trivial_usage \
+ "> keymap"
+#define dumpkmap_full_usage "\n\n" \
+ "Print a binary keyboard translation table to standard output"
+#define dumpkmap_example_usage \
+ "$ dumpkmap > keymap\n"
+
+#define dumpleases_trivial_usage \
+ "[-r|-a] [-f LEASEFILE]"
+#define dumpleases_full_usage "\n\n" \
+ "Display DHCP leases granted by udhcpd\n" \
+ "\nOptions:" \
+ USE_GETOPT_LONG( \
+ "\n -f,--file=FILE Leases file to load" \
+ "\n -r,--remaining Interpret lease times as time remaining" \
+ "\n -a,--absolute Interpret lease times as expire time" \
+ ) \
+ SKIP_GETOPT_LONG( \
+ "\n -f FILE Leases file to load" \
+ "\n -r Interpret lease times as time remaining" \
+ "\n -a Interpret lease times as expire time" \
+ )
+
+#define e2fsck_trivial_usage \
+ "[-panyrcdfvstDFSV] [-b superblock] [-B blocksize] " \
+ "[-I inode_buffer_blocks] [-P process_inode_size] " \
+ "[-l|-L bad_blocks_file] [-C fd] [-j external_journal] " \
+ "[-E extended-options] device"
+#define e2fsck_full_usage "\n\n" \
+ "Check ext2/ext3 file system\n" \
+ "\nOptions:" \
+ "\n -p Automatic repair (no questions)" \
+ "\n -n Make no changes to the filesystem" \
+ "\n -y Assume 'yes' to all questions" \
+ "\n -c Check for bad blocks and add them to the badblock list" \
+ "\n -f Force checking even if filesystem is marked clean" \
+ "\n -v Verbose" \
+ "\n -b superblock Use alternative superblock" \
+ "\n -B blocksize Force blocksize when looking for superblock" \
+ "\n -j journal Set location of the external journal" \
+ "\n -l file Add to badblocks list" \
+ "\n -L file Set badblocks list" \
+
+#define echo_trivial_usage \
+ USE_FEATURE_FANCY_ECHO("[-neE] ") "[ARG...]"
+#define echo_full_usage "\n\n" \
+ "Print the specified ARGs to stdout" \
+ USE_FEATURE_FANCY_ECHO( "\n" \
+ "\nOptions:" \
+ "\n -n Suppress trailing newline" \
+ "\n -e Interpret backslash-escaped characters (i.e., \\t=tab)" \
+ "\n -E Disable interpretation of backslash-escaped characters" \
+ )
+#define echo_example_usage \
+ "$ echo \"Erik is cool\"\n" \
+ "Erik is cool\n" \
+ USE_FEATURE_FANCY_ECHO("$ echo -e \"Erik\\nis\\ncool\"\n" \
+ "Erik\n" \
+ "is\n" \
+ "cool\n" \
+ "$ echo \"Erik\\nis\\ncool\"\n" \
+ "Erik\\nis\\ncool\n")
+
+#define eject_trivial_usage \
+ "[-t] [-T] [DEVICE]"
+#define eject_full_usage "\n\n" \
+ "Eject specified DEVICE (or default /dev/cdrom)\n" \
+ "\nOptions:" \
+ USE_FEATURE_EJECT_SCSI( \
+ "\n -s SCSI device" \
+ ) \
+ "\n -t Close tray" \
+ "\n -T Open/close tray (toggle)" \
+
+#define ed_trivial_usage ""
+#define ed_full_usage ""
+
+#define env_trivial_usage \
+ "[-iu] [-] [name=value]... [command]"
+#define env_full_usage "\n\n" \
+ "Print the current environment or run a program after setting\n" \
+ "up the specified environment\n" \
+ "\nOptions:" \
+ "\n -, -i Start with an empty environment" \
+ "\n -u Remove variable from the environment" \
+
+#define ether_wake_trivial_usage \
+ "[-b] [-i iface] [-p aa:bb:cc:dd[:ee:ff]] MAC"
+#define ether_wake_full_usage "\n\n" \
+ "Send a magic packet to wake up sleeping machines.\n" \
+ "MAC must be a station address (00:11:22:33:44:55) or\n" \
+ "a hostname with a known 'ethers' entry.\n" \
+ "\nOptions:" \
+ "\n -b Send wake-up packet to the broadcast address" \
+ "\n -i iface Interface to use (default eth0)" \
+ "\n -p pass Append four or six byte password PW to the packet" \
+
+#define expand_trivial_usage \
+ "[-i] [-t NUM] [FILE|-]"
+#define expand_full_usage "\n\n" \
+ "Convert tabs to spaces, writing to standard output.\n" \
+ "\nOptions:" \
+ USE_FEATURE_EXPAND_LONG_OPTIONS( \
+ "\n -i,--initial Do not convert tabs after non blanks" \
+ "\n -t,--tabs=N Tabstops every N chars" \
+ ) \
+ SKIP_FEATURE_EXPAND_LONG_OPTIONS( \
+ "\n -i Do not convert tabs after non blanks" \
+ "\n -t Tabstops every N chars" \
+ )
+
+#define expr_trivial_usage \
+ "EXPRESSION"
+#define expr_full_usage "\n\n" \
+ "Print the value of EXPRESSION to standard output.\n" \
+ "\n" \
+ "EXPRESSION may be:\n" \
+ " ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n" \
+ " ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n" \
+ " ARG1 < ARG2 1 if ARG1 is less than ARG2, else 0. Similarly:\n" \
+ " ARG1 <= ARG2\n" \
+ " ARG1 = ARG2\n" \
+ " ARG1 != ARG2\n" \
+ " ARG1 >= ARG2\n" \
+ " ARG1 > ARG2\n" \
+ " ARG1 + ARG2 Sum of ARG1 and ARG2. Similarly:\n" \
+ " ARG1 - ARG2\n" \
+ " ARG1 * ARG2\n" \
+ " ARG1 / ARG2\n" \
+ " ARG1 % ARG2\n" \
+ " STRING : REGEXP Anchored pattern match of REGEXP in STRING\n" \
+ " match STRING REGEXP Same as STRING : REGEXP\n" \
+ " substr STRING POS LENGTH Substring of STRING, POS counted from 1\n" \
+ " index STRING CHARS Index in STRING where any CHARS is found, or 0\n" \
+ " length STRING Length of STRING\n" \
+ " quote TOKEN Interpret TOKEN as a string, even if\n" \
+ " it is a keyword like 'match' or an\n" \
+ " operator like '/'\n" \
+ " (EXPRESSION) Value of EXPRESSION\n" \
+ "\n" \
+ "Beware that many operators need to be escaped or quoted for shells.\n" \
+ "Comparisons are arithmetic if both ARGs are numbers, else\n" \
+ "lexicographical. Pattern matches return the string matched between\n" \
+ "\\( and \\) or null; if \\( and \\) are not used, they return the number\n" \
+ "of characters matched or 0."
+
+#define fakeidentd_trivial_usage \
+ "[-fiw] [-b ADDR] [STRING]"
+#define fakeidentd_full_usage "\n\n" \
+ "Provide fake ident (auth) service\n" \
+ "\nOptions:" \
+ "\n -f Run in foreground" \
+ "\n -i Inetd mode" \
+ "\n -w Inetd 'wait' mode" \
+ "\n -b ADDR Bind to specified address" \
+ "\n STRING Ident answer string (default is 'nobody')" \
+
+#define false_trivial_usage \
+ ""
+#define false_full_usage "\n\n" \
+ "Return an exit code of FALSE (1)"
+
+#define false_example_usage \
+ "$ false\n" \
+ "$ echo $?\n" \
+ "1\n"
+
+#define fbset_trivial_usage \
+ "[options] [mode]"
+#define fbset_full_usage "\n\n" \
+ "Show and modify frame buffer settings"
+
+#define fbset_example_usage \
+ "$ fbset\n" \
+ "mode \"1024x768-76\"\n" \
+ " # D: 78.653 MHz, H: 59.949 kHz, V: 75.694 Hz\n" \
+ " geometry 1024 768 1024 768 16\n" \
+ " timings 12714 128 32 16 4 128 4\n" \
+ " accel false\n" \
+ " rgba 5/11,6/5,5/0,0/0\n" \
+ "endmode\n"
+
+#define fdflush_trivial_usage \
+ "DEVICE"
+#define fdflush_full_usage "\n\n" \
+ "Force floppy disk drive to detect disk change"
+
+#define fdformat_trivial_usage \
+ "[-n] DEVICE"
+#define fdformat_full_usage "\n\n" \
+ "Format floppy disk\n" \
+ "\nOptions:" \
+ "\n -n Don't verify after format" \
+
+/* Looks like someone forgot to add this to config system */
+#ifndef ENABLE_FEATURE_FDISK_BLKSIZE
+# define ENABLE_FEATURE_FDISK_BLKSIZE 0
+# define USE_FEATURE_FDISK_BLKSIZE(a)
+#endif
+
+#define fdisk_trivial_usage \
+ "[-ul" USE_FEATURE_FDISK_BLKSIZE("s") "] " \
+ "[-C CYLINDERS] [-H HEADS] [-S SECTORS] [-b SSZ] DISK"
+#define fdisk_full_usage "\n\n" \
+ "Change partition table\n" \
+ "\nOptions:" \
+ "\n -u Start and End are in sectors (instead of cylinders)" \
+ "\n -l Show partition table for each DISK, then exit" \
+ USE_FEATURE_FDISK_BLKSIZE( \
+ "\n -s Show partition sizes in kb for each DISK, then exit" \
+ ) \
+ "\n -b 2048 (for certain MO disks) use 2048-byte sectors" \
+ "\n -C CYLINDERS Set number of cylinders/heads/sectors" \
+ "\n -H HEADS\n" \
+ "\n -S SECTORS" \
+
+#define fetchmail_trivial_usage \
+ "[-w timeout] [-U user] -P password [-X] [-t] [-z] server[:port] maildir [prog]"
+#define fetchmail_full_usage "\n\n" \
+ "Fetch content of remote mailbox to local Maildir.\n" \
+ "\nOptions:" \
+ "\n -w timeout Set timeout on network operations" \
+ "\n -U username Authenticate with specified username/password" \
+ "\n -P password" \
+ "\n -X Use openssl connection helper for secured servers" \
+ "\n -t Get only headers" \
+ "\n -z Delete messages on server" \
+ "\n prog Run prog <message_file> on message delivery" \
+
+#define findfs_trivial_usage \
+ "LABEL=label or UUID=uuid"
+#define findfs_full_usage "\n\n" \
+ "Find a filesystem device based on a label or UUID."
+#define findfs_example_usage \
+ "$ findfs LABEL=MyDevice"
+
+#define find_trivial_usage \
+ "[PATH...] [EXPRESSION]"
+#define find_full_usage "\n\n" \
+ "Search for files. The default PATH is the current directory,\n" \
+ "default EXPRESSION is '-print'\n" \
+ "\nEXPRESSION may consist of:" \
+ "\n -follow Dereference symlinks" \
+ USE_FEATURE_FIND_XDEV( \
+ "\n -xdev Don't descend directories on other filesystems") \
+ USE_FEATURE_FIND_MAXDEPTH( \
+ "\n -maxdepth N Descend at most N levels. -maxdepth 0 applies" \
+ "\n tests/actions to command line arguments only") \
+ "\n -name PATTERN File name (w/o directory name) matches PATTERN" \
+ "\n -iname PATTERN Case insensitive -name" \
+ USE_FEATURE_FIND_PATH( \
+ "\n -path PATTERN Path matches PATTERN") \
+ USE_FEATURE_FIND_REGEX( \
+ "\n -regex PATTERN Path matches regex PATTERN") \
+ USE_FEATURE_FIND_TYPE( \
+ "\n -type X File type is X (X is one of: f,d,l,b,c,...)") \
+ USE_FEATURE_FIND_PERM( \
+ "\n -perm NNN Permissions match any of (+NNN), all of (-NNN)," \
+ "\n or exactly (NNN)") \
+ USE_FEATURE_FIND_MTIME( \
+ "\n -mtime DAYS Modified time is greater than (+N), less than (-N)," \
+ "\n or exactly (N) days") \
+ USE_FEATURE_FIND_MMIN( \
+ "\n -mmin MINS Modified time is greater than (+N), less than (-N)," \
+ "\n or exactly (N) minutes") \
+ USE_FEATURE_FIND_NEWER( \
+ "\n -newer FILE Modified time is more recent than FILE's") \
+ USE_FEATURE_FIND_INUM( \
+ "\n -inum N File has inode number N") \
+ USE_FEATURE_FIND_USER( \
+ "\n -user NAME File is owned by user NAME (numeric user ID allowed)") \
+ USE_FEATURE_FIND_GROUP( \
+ "\n -group NAME File belongs to group NAME (numeric group ID allowed)") \
+ USE_FEATURE_FIND_DEPTH( \
+ "\n -depth Process directory name after traversing it") \
+ USE_FEATURE_FIND_SIZE( \
+ "\n -size N[bck] File size is N (c:bytes,k:kbytes,b:512 bytes(def.))." \
+ "\n +/-N: file size is bigger/smaller than N") \
+ "\n -print Print (default and assumed)" \
+ USE_FEATURE_FIND_PRINT0( \
+ "\n -print0 Delimit output with null characters rather than" \
+ "\n newlines") \
+ USE_FEATURE_FIND_CONTEXT ( \
+ "\n -context File has specified security context") \
+ USE_FEATURE_FIND_EXEC( \
+ "\n -exec CMD ARG ; Execute CMD with all instances of {} replaced by the" \
+ "\n matching files") \
+ USE_FEATURE_FIND_PRUNE( \
+ "\n -prune Stop traversing current subtree") \
+ USE_FEATURE_FIND_DELETE( \
+ "\n -delete Delete files, turns on -depth option") \
+ USE_FEATURE_FIND_PAREN( \
+ "\n (EXPR) Group an expression") \
+
+#define find_example_usage \
+ "$ find / -name passwd\n" \
+ "/etc/passwd\n"
+
+#define fold_trivial_usage \
+ "[-bs] [-w WIDTH] [FILE]"
+#define fold_full_usage "\n\n" \
+ "Wrap input lines in each FILE (standard input by default), writing to\n" \
+ "standard output\n" \
+ "\nOptions:" \
+ "\n -b Count bytes rather than columns" \
+ "\n -s Break at spaces" \
+ "\n -w Use WIDTH columns instead of 80" \
+
+#define free_trivial_usage \
+ ""
+#define free_full_usage "\n\n" \
+ "Display the amount of free and used system memory"
+#define free_example_usage \
+ "$ free\n" \
+ " total used free shared buffers\n" \
+ " Mem: 257628 248724 8904 59644 93124\n" \
+ " Swap: 128516 8404 120112\n" \
+ "Total: 386144 257128 129016\n" \
+
+#define freeramdisk_trivial_usage \
+ "DEVICE"
+#define freeramdisk_full_usage "\n\n" \
+ "Free all memory used by the specified ramdisk"
+#define freeramdisk_example_usage \
+ "$ freeramdisk /dev/ram2\n"
+
+#define fsck_trivial_usage \
+ "[-ANPRTV] [-C fd] [-t fstype] [fs-options] [filesys...]"
+#define fsck_full_usage "\n\n" \
+ "Check and repair filesystems\n" \
+ "\nOptions:" \
+ "\n -A Walk /etc/fstab and check all filesystems" \
+ "\n -N Don't execute, just show what would be done" \
+ "\n -P With -A, check filesystems in parallel" \
+ "\n -R With -A, skip the root filesystem" \
+ "\n -T Don't show title on startup" \
+ "\n -V Verbose" \
+ "\n -C n Write status information to specified filedescriptor" \
+ "\n -t type List of filesystem types to check" \
+
+#define fsck_minix_trivial_usage \
+ "[-larvsmf] /dev/name"
+#define fsck_minix_full_usage "\n\n" \
+ "Check MINIX filesystem\n" \
+ "\nOptions:" \
+ "\n -l List all filenames" \
+ "\n -r Perform interactive repairs" \
+ "\n -a Perform automatic repairs" \
+ "\n -v Verbose" \
+ "\n -s Output super-block information" \
+ "\n -m Show \"mode not cleared\" warnings" \
+ "\n -f Force file system check" \
+
+#define ftpget_trivial_usage \
+ "[options] remote-host local-file remote-file"
+#define ftpget_full_usage "\n\n" \
+ "Retrieve a remote file via FTP\n" \
+ "\nOptions:" \
+ USE_GETOPT_LONG( \
+ "\n -c,--continue Continue previous transfer" \
+ "\n -v,--verbose Verbose" \
+ "\n -u,--username Username" \
+ "\n -p,--password Password" \
+ "\n -P,--port Port number" \
+ ) \
+ SKIP_GETOPT_LONG( \
+ "\n -c Continue previous transfer" \
+ "\n -v Verbose" \
+ "\n -u Username" \
+ "\n -p Password" \
+ "\n -P Port number" \
+ )
+
+#define ftpput_trivial_usage \
+ "[options] remote-host remote-file local-file"
+#define ftpput_full_usage "\n\n" \
+ "Store a local file on a remote machine via FTP\n" \
+ "\nOptions:" \
+ USE_GETOPT_LONG( \
+ "\n -v,--verbose Verbose" \
+ "\n -u,--username Username" \
+ "\n -p,--password Password" \
+ "\n -P,--port Port number" \
+ ) \
+ SKIP_GETOPT_LONG( \
+ "\n -v Verbose" \
+ "\n -u Username" \
+ "\n -p Password" \
+ "\n -P Port number" \
+ )
+
+#define fuser_trivial_usage \
+ "[options] FILE or PORT/PROTO"
+#define fuser_full_usage "\n\n" \
+ "Find processes which use FILEs or PORTs\n" \
+ "\nOptions:" \
+ "\n -m Find processes which use same fs as FILEs" \
+ "\n -4 Search only IPv4 space" \
+ "\n -6 Search only IPv6 space" \
+ "\n -s Silent: just exit with 0 if any processes are found" \
+ "\n -k Kill found processes (otherwise display PIDs)" \
+ "\n -SIGNAL Signal to send (default: TERM)" \
+
+#define getenforce_trivial_usage NOUSAGE_STR
+#define getenforce_full_usage ""
+
+#define getopt_trivial_usage \
+ "[OPTIONS]..."
+#define getopt_full_usage "\n\n" \
+ "Parse command options\n" \
+ USE_GETOPT_LONG( \
+ "\n -a,--alternative Allow long options starting with single -" \
+ "\n -l,--longoptions=longopts Long options to be recognized" \
+ "\n -n,--name=progname The name under which errors are reported" \
+ "\n -o,--options=optstring Short options to be recognized" \
+ "\n -q,--quiet Disable error reporting by getopt(3)" \
+ "\n -Q,--quiet-output No normal output" \
+ "\n -s,--shell=shell Set shell quoting conventions" \
+ "\n -T,--test Test for getopt(1) version" \
+ "\n -u,--unquoted Don't quote the output" \
+ ) \
+ SKIP_GETOPT_LONG( \
+ "\n -a Allow long options starting with single -" \
+ "\n -l longopts Long options to be recognized" \
+ "\n -n progname The name under which errors are reported" \
+ "\n -o optstring Short options to be recognized" \
+ "\n -q Disable error reporting by getopt(3)" \
+ "\n -Q No normal output" \
+ "\n -s shell Set shell quoting conventions" \
+ "\n -T Test for getopt(1) version" \
+ "\n -u Don't quote the output" \
+ )
+#define getopt_example_usage \
+ "$ cat getopt.test\n" \
+ "#!/bin/sh\n" \
+ "GETOPT=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \\\n" \
+ " -n 'example.busybox' -- \"$@\"`\n" \
+ "if [ $? != 0 ]; then exit 1; fi\n" \
+ "eval set -- \"$GETOPT\"\n" \
+ "while true; do\n" \
+ " case $1 in\n" \
+ " -a|--a-long) echo \"Option a\"; shift;;\n" \
+ " -b|--b-long) echo \"Option b, argument '$2'\"; shift 2;;\n" \
+ " -c|--c-long)\n" \
+ " case \"$2\" in\n" \
+ " \"\") echo \"Option c, no argument\"; shift 2;;\n" \
+ " *) echo \"Option c, argument '$2'\"; shift 2;;\n" \
+ " esac;;\n" \
+ " --) shift; break;;\n" \
+ " *) echo \"Internal error!\"; exit 1;;\n" \
+ " esac\n" \
+ "done\n"
+
+#define getsebool_trivial_usage \
+ "-a or getsebool boolean..."
+#define getsebool_full_usage "\n\n" \
+ " -a Show all SELinux booleans"
+
+#define getty_trivial_usage \
+ "[OPTIONS] BAUD_RATE TTY [TERMTYPE]"
+#define getty_full_usage "\n\n" \
+ "Open a tty, prompt for a login name, then invoke /bin/login\n" \
+ "\nOptions:" \
+ "\n -h Enable hardware (RTS/CTS) flow control" \
+ "\n -i Do not display /etc/issue before running login" \
+ "\n -L Local line, do not do carrier detect" \
+ "\n -m Get baud rate from modem's CONNECT status message" \
+ "\n -w Wait for a CR or LF before sending /etc/issue" \
+ "\n -n Do not prompt the user for a login name" \
+ "\n -f issue_file Display issue_file instead of /etc/issue" \
+ "\n -l login_app Invoke login_app instead of /bin/login" \
+ "\n -t timeout Terminate after timeout if no username is read" \
+ "\n -I initstring Init string to send before anything else" \
+ "\n -H login_host Log login_host into the utmp file as the hostname" \
+
+#define grep_trivial_usage \
+ "[-HhrilLnqvso" \
+ USE_DESKTOP("w") \
+ "eF" \
+ USE_FEATURE_GREP_EGREP_ALIAS("E") \
+ USE_FEATURE_GREP_CONTEXT("ABC") \
+ "] PATTERN [FILEs...]"
+#define grep_full_usage "\n\n" \
+ "Search for PATTERN in each FILE or standard input\n" \
+ "\nOptions:" \
+ "\n -H Prefix output lines with filename where match was found" \
+ "\n -h Suppress the prefixing filename on output" \
+ "\n -r Recurse subdirectories" \
+ "\n -i Ignore case distinctions" \
+ "\n -l List names of files that match" \
+ "\n -L List names of files that do not match" \
+ "\n -n Print line number with output lines" \
+ "\n -q Quiet. Return 0 if PATTERN is found, 1 otherwise" \
+ "\n -v Select non-matching lines" \
+ "\n -s Suppress file open/read error messages" \
+ "\n -c Only print count of matching lines" \
+ "\n -o Show only the part of a line that matches PATTERN" \
+ "\n -m MAX Match up to MAX times per file" \
+ USE_DESKTOP( \
+ "\n -w Match whole words only") \
+ "\n -F PATTERN is a set of newline-separated strings" \
+ USE_FEATURE_GREP_EGREP_ALIAS( \
+ "\n -E PATTERN is an extended regular expression") \
+ "\n -e PTRN Pattern to match" \
+ "\n -f FILE Read pattern from file" \
+ USE_FEATURE_GREP_CONTEXT( \
+ "\n -A Print NUM lines of trailing context" \
+ "\n -B Print NUM lines of leading context" \
+ "\n -C Print NUM lines of output context") \
+
+#define grep_example_usage \
+ "$ grep root /etc/passwd\n" \
+ "root:x:0:0:root:/root:/bin/bash\n" \
+ "$ grep ^[rR]oo. /etc/passwd\n" \
+ "root:x:0:0:root:/root:/bin/bash\n"
+
+#define egrep_trivial_usage NOUSAGE_STR
+#define egrep_full_usage ""
+
+#define fgrep_trivial_usage NOUSAGE_STR
+#define fgrep_full_usage ""
+
+#define gunzip_trivial_usage \
+ "[OPTION]... [FILE]..."
+#define gunzip_full_usage "\n\n" \
+ "Uncompress FILEs (or standard input)\n" \
+ "\nOptions:" \
+ "\n -c Write to standard output" \
+ "\n -f Force" \
+ "\n -t Test file integrity" \
+
+#define gunzip_example_usage \
+ "$ ls -la /tmp/BusyBox*\n" \
+ "-rw-rw-r-- 1 andersen andersen 557009 Apr 11 10:55 /tmp/BusyBox-0.43.tar.gz\n" \
+ "$ gunzip /tmp/BusyBox-0.43.tar.gz\n" \
+ "$ ls -la /tmp/BusyBox*\n" \
+ "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar\n"
+
+#define gzip_trivial_usage \
+ "[OPTION]... [FILE]..."
+#define gzip_full_usage "\n\n" \
+ "Compress FILEs (or standard input)\n" \
+ "\nOptions:" \
+ "\n -c Write to standard output" \
+ "\n -d Decompress" \
+ "\n -f Force" \
+
+#define gzip_example_usage \
+ "$ ls -la /tmp/busybox*\n" \
+ "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/busybox.tar\n" \
+ "$ gzip /tmp/busybox.tar\n" \
+ "$ ls -la /tmp/busybox*\n" \
+ "-rw-rw-r-- 1 andersen andersen 554058 Apr 14 17:49 /tmp/busybox.tar.gz\n"
+
+#define halt_trivial_usage \
+ "[-d delay] [-n] [-f]"
+#define halt_full_usage "\n\n" \
+ "Halt the system\n" \
+ "\nOptions:" \
+ "\n -d Delay interval for halting" \
+ "\n -n No call to sync()" \
+ "\n -f Force halt (don't go through init)" \
+ USE_FEATURE_WTMP( \
+ "\n -w Only write a wtmp record" \
+ )
+
+#define hdparm_trivial_usage \
+ "[options] [device] .."
+#define hdparm_full_usage "\n\n" \
+ "Options:" \
+ "\n -a Get/set fs readahead" \
+ "\n -A Set drive read-lookahead flag (0/1)" \
+ "\n -b Get/set bus state (0 == off, 1 == on, 2 == tristate)" \
+ "\n -B Set Advanced Power Management setting (1-255)" \
+ "\n -c Get/set IDE 32-bit IO setting" \
+ "\n -C Check IDE power mode status" \
+ USE_FEATURE_HDPARM_HDIO_GETSET_DMA( \
+ "\n -d Get/set using_dma flag") \
+ "\n -D Enable/disable drive defect-mgmt" \
+ "\n -f Flush buffer cache for device on exit" \
+ "\n -g Display drive geometry" \
+ "\n -h Display terse usage information" \
+ USE_FEATURE_HDPARM_GET_IDENTITY( \
+ "\n -i Display drive identification") \
+ USE_FEATURE_HDPARM_GET_IDENTITY( \
+ "\n -I Detailed/current information directly from drive") \
+ "\n -k Get/set keep_settings_over_reset flag (0/1)" \
+ "\n -K Set drive keep_features_over_reset flag (0/1)" \
+ "\n -L Set drive doorlock (0/1) (removable harddisks only)" \
+ "\n -m Get/set multiple sector count" \
+ "\n -n Get/set ignore-write-errors flag (0/1)" \
+ "\n -p Set PIO mode on IDE interface chipset (0,1,2,3,4,...)" \
+ "\n -P Set drive prefetch count" \
+/* "\n -q Change next setting quietly" - not supported ib bbox */ \
+ "\n -Q Get/set DMA tagged-queuing depth (if supported)" \
+ "\n -r Get/set readonly flag (DANGEROUS to set)" \
+ USE_FEATURE_HDPARM_HDIO_SCAN_HWIF( \
+ "\n -R Register an IDE interface (DANGEROUS)") \
+ "\n -S Set standby (spindown) timeout" \
+ "\n -t Perform device read timings" \
+ "\n -T Perform cache read timings" \
+ "\n -u Get/set unmaskirq flag (0/1)" \
+ USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF( \
+ "\n -U Un-register an IDE interface (DANGEROUS)") \
+ "\n -v Defaults; same as -mcudkrag for IDE drives" \
+ "\n -V Display program version and exit immediately" \
+ USE_FEATURE_HDPARM_HDIO_DRIVE_RESET( \
+ "\n -w Perform device reset (DANGEROUS)") \
+ "\n -W Set drive write-caching flag (0/1) (DANGEROUS)" \
+ USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( \
+ "\n -x Tristate device for hotswap (0/1) (DANGEROUS)") \
+ "\n -X Set IDE xfer mode (DANGEROUS)" \
+ "\n -y Put IDE drive in standby mode" \
+ "\n -Y Put IDE drive to sleep" \
+ "\n -Z Disable Seagate auto-powersaving mode" \
+ "\n -z Re-read partition table" \
+
+#define head_trivial_usage \
+ "[OPTION]... [FILE]..."
+#define head_full_usage "\n\n" \
+ "Print first 10 lines of each FILE to standard output.\n" \
+ "With more than one FILE, precede each with a header giving the\n" \
+ "file name. With no FILE, or when FILE is -, read standard input.\n" \
+ "\nOptions:" \
+ "\n -n NUM Print first NUM lines instead of first 10" \
+ USE_FEATURE_FANCY_HEAD( \
+ "\n -c NUM Output the first NUM bytes" \
+ "\n -q Never output headers giving file names" \
+ "\n -v Always output headers giving file names") \
+
+#define head_example_usage \
+ "$ head -n 2 /etc/passwd\n" \
+ "root:x:0:0:root:/root:/bin/bash\n" \
+ "daemon:x:1:1:daemon:/usr/sbin:/bin/sh\n"
+
+#define hexdump_trivial_usage \
+ "[-bcCdefnosvx" USE_FEATURE_HEXDUMP_REVERSE("R") "] FILE..."
+#define hexdump_full_usage "\n\n" \
+ "Display file(s) or standard input in a user specified format\n" \
+ "\nOptions:" \
+ "\n -b One-byte octal display" \
+ "\n -c One-byte character display" \
+ "\n -C Canonical hex+ASCII, 16 bytes per line" \
+ "\n -d Two-byte decimal display" \
+ "\n -e FORMAT STRING" \
+ "\n -f FORMAT FILE" \
+ "\n -n LENGTH Interpret only LENGTH bytes of input" \
+ "\n -o Two-byte octal display" \
+ "\n -s OFFSET Skip OFFSET bytes" \
+ "\n -v Display all input data" \
+ "\n -x Two-byte hexadecimal display" \
+ USE_FEATURE_HEXDUMP_REVERSE( \
+ "\n -R Reverse of 'hexdump -Cv'") \
+
+#define hd_trivial_usage \
+ "FILE..."
+#define hd_full_usage "\n\n" \
+ "hd is an alias for hexdump -C"
+
+#define hostid_trivial_usage \
+ ""
+#define hostid_full_usage "\n\n" \
+ "Print out a unique 32-bit identifier for the machine"
+
+#define hostname_trivial_usage \
+ "[OPTION] [hostname | -F FILE]"
+#define hostname_full_usage "\n\n" \
+ "Get or set hostname or DNS domain name\n" \
+ "\nOptions:" \
+ "\n -s Short" \
+ "\n -i Addresses for the hostname" \
+ "\n -d DNS domain name" \
+ "\n -f Fully qualified domain name" \
+ "\n -F FILE Use the contents of FILE to specify the hostname" \
+
+#define hostname_example_usage \
+ "$ hostname\n" \
+ "sage\n"
+
+#define httpd_trivial_usage \
+ "[-c conffile]" \
+ " [-p [ip:]port]" \
+ " [-i] [-f] [-v[v]]" \
+ USE_FEATURE_HTTPD_SETUID(" [-u user[:grp]]") \
+ USE_FEATURE_HTTPD_BASIC_AUTH(" [-r realm]") \
+ USE_FEATURE_HTTPD_AUTH_MD5(" [-m pass]") \
+ " [-h home]" \
+ " [-d/-e string]"
+#define httpd_full_usage "\n\n" \
+ "Listen for incoming HTTP requests\n" \
+ "\nOptions:" \
+ "\n -c FILE Configuration file (default httpd.conf)" \
+ "\n -p [IP:]PORT Bind to ip:port (default *:80)" \
+ "\n -i Inetd mode" \
+ "\n -f Do not daemonize" \
+ "\n -v[v] Verbose" \
+ USE_FEATURE_HTTPD_SETUID( \
+ "\n -u USER[:GRP] Set uid/gid after binding to port") \
+ USE_FEATURE_HTTPD_BASIC_AUTH( \
+ "\n -r REALM Authentication Realm for Basic Authentication") \
+ USE_FEATURE_HTTPD_AUTH_MD5( \
+ "\n -m PASS Crypt PASS with md5 algorithm") \
+ "\n -h HOME Home directory (default .)" \
+ "\n -e STRING HTML encode STRING" \
+ "\n -d STRING URL decode STRING" \
+
+#define hwclock_trivial_usage \
+ USE_GETOPT_LONG( \
+ "[-r|--show] [-s|--hctosys] [-w|--systohc]" \
+ " [-l|--localtime] [-u|--utc]" \
+ " [-f FILE]" \
+ ) \
+ SKIP_GETOPT_LONG( \
+ "[-r] [-s] [-w] [-l] [-u] [-f FILE]" \
+ )
+#define hwclock_full_usage "\n\n" \
+ "Query and set hardware clock (RTC)\n" \
+ "\nOptions:" \
+ "\n -r Show hardware clock time" \
+ "\n -s Set system time from hardware clock" \
+ "\n -w Set hardware clock to system time" \
+ "\n -u Hardware clock is in UTC" \
+ "\n -l Hardware clock is in local time" \
+ "\n -f FILE Use specified device (e.g. /dev/rtc2)" \
+
+#define id_trivial_usage \
+ "[OPTIONS]... [USER]"
+#define id_full_usage "\n\n" \
+ "Print information about USER or the current user\n" \
+ "\nOptions:" \
+ USE_SELINUX( \
+ "\n -Z Print the security context" \
+ ) \
+ "\n -g Print group ID" \
+ "\n -u Print user ID" \
+ "\n -n Print name instead of a number" \
+ "\n -r Print real user ID instead of effective ID" \
+
+#define id_example_usage \
+ "$ id\n" \
+ "uid=1000(andersen) gid=1000(andersen)\n"
+
+#define ifconfig_trivial_usage \
+ USE_FEATURE_IFCONFIG_STATUS("[-a]") " interface [address]"
+#define ifconfig_full_usage "\n\n" \
+ "Configure a network interface\n" \
+ "\nOptions:" \
+ "\n" \
+ USE_FEATURE_IPV6( \
+ " [add ADDRESS[/PREFIXLEN]]\n") \
+ USE_FEATURE_IPV6( \
+ " [del ADDRESS[/PREFIXLEN]]\n") \
+ " [[-]broadcast [ADDRESS]] [[-]pointopoint [ADDRESS]]\n" \
+ " [netmask ADDRESS] [dstaddr ADDRESS]\n" \
+ USE_FEATURE_IFCONFIG_SLIP( \
+ " [outfill NN] [keepalive NN]\n") \
+ " " USE_FEATURE_IFCONFIG_HW("[hw ether" USE_FEATURE_HWIB("|infiniband")" ADDRESS] ") "[metric NN] [mtu NN]\n" \
+ " [[-]trailers] [[-]arp] [[-]allmulti]\n" \
+ " [multicast] [[-]promisc] [txqueuelen NN] [[-]dynamic]\n" \
+ USE_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ( \
+ " [mem_start NN] [io_addr NN] [irq NN]\n") \
+ " [up|down] ..."
+
+#define ifenslave_trivial_usage \
+ "[-cdf] master-iface <slave-iface...>"
+#define ifenslave_full_usage "\n\n" \
+ "Configure network interfaces for parallel routing\n" \
+ "\nOptions:" \
+ "\n -c, --change-active Change active slave" \
+ "\n -d, --detach Remove slave interface from bonding device" \
+ "\n -f, --force Force, even if interface is not Ethernet" \
+/* "\n -r, --receive-slave Create a receive-only slave" */
+
+#define ifenslave_example_usage \
+ "To create a bond device, simply follow these three steps :\n" \
+ "- ensure that the required drivers are properly loaded :\n" \
+ " # modprobe bonding ; modprobe <3c59x|eepro100|pcnet32|tulip|...>\n" \
+ "- assign an IP address to the bond device :\n" \
+ " # ifconfig bond0 <addr> netmask <mask> broadcast <bcast>\n" \
+ "- attach all the interfaces you need to the bond device :\n" \
+ " # ifenslave bond0 eth0 eth1 eth2\n" \
+ " If bond0 didn't have a MAC address, it will take eth0's. Then, all\n" \
+ " interfaces attached AFTER this assignment will get the same MAC addr.\n\n" \
+ " To detach a dead interface without setting the bond device down :\n" \
+ " # ifenslave -d bond0 eth1\n\n" \
+ " To set the bond device down and automatically release all the slaves :\n" \
+ " # ifconfig bond0 down\n\n" \
+ " To change active slave :\n" \
+ " # ifenslave -c bond0 eth0\n" \
+
+#define ifup_trivial_usage \
+ "[-ain"USE_FEATURE_IFUPDOWN_MAPPING("m")"vf] ifaces..."
+#define ifup_full_usage "\n\n" \
+ "Options:" \
+ "\n -a De/configure all interfaces automatically" \
+ "\n -i FILE Use FILE for interface definitions" \
+ "\n -n Print out what would happen, but don't do it" \
+ USE_FEATURE_IFUPDOWN_MAPPING( \
+ "\n (note: doesn't disable mappings)" \
+ "\n -m Don't run any mappings" \
+ ) \
+ "\n -v Print out what would happen before doing it" \
+ "\n -f Force de/configuration" \
+
+#define ifdown_trivial_usage \
+ "[-ain"USE_FEATURE_IFUPDOWN_MAPPING("m")"vf] ifaces..."
+#define ifdown_full_usage "\n\n" \
+ "Options:" \
+ "\n -a De/configure all interfaces automatically" \
+ "\n -i FILE Use FILE for interface definitions" \
+ "\n -n Print out what would happen, but don't do it" \
+ USE_FEATURE_IFUPDOWN_MAPPING( \
+ "\n (note: doesn't disable mappings)" \
+ "\n -m Don't run any mappings" \
+ ) \
+ "\n -v Print out what would happen before doing it" \
+ "\n -f Force de/configuration" \
+
+#define inetd_trivial_usage \
+ "[-fe] [-q N] [-R N] [CONFFILE]"
+#define inetd_full_usage "\n\n" \
+ "Listen for network connections and launch programs\n" \
+ "\nOptions:" \
+ "\n -f Run in foreground" \
+ "\n -e Log to stderr" \
+ "\n -q N Socket listen queue (default: 128)" \
+ "\n -R N Pause services after N connects/min" \
+ "\n (default: 0 - disabled)" \
+
+#define init_trivial_usage \
+ ""
+#define init_full_usage "\n\n" \
+ "Init is the parent of all processes"
+
+#define init_notes_usage \
+"This version of init is designed to be run only by the kernel.\n" \
+"\n" \
+"BusyBox init doesn't support multiple runlevels. The runlevels field of\n" \
+"the /etc/inittab file is completely ignored by BusyBox init. If you want\n" \
+"runlevels, use sysvinit.\n" \
+"\n" \
+"BusyBox init works just fine without an inittab. If no inittab is found,\n" \
+"it has the following default behavior:\n" \
+"\n" \
+" ::sysinit:/etc/init.d/rcS\n" \
+" ::askfirst:/bin/sh\n" \
+" ::ctrlaltdel:/sbin/reboot\n" \
+" ::shutdown:/sbin/swapoff -a\n" \
+" ::shutdown:/bin/umount -a -r\n" \
+" ::restart:/sbin/init\n" \
+"\n" \
+"if it detects that /dev/console is _not_ a serial console, it will also run:\n" \
+"\n" \
+" tty2::askfirst:/bin/sh\n" \
+" tty3::askfirst:/bin/sh\n" \
+" tty4::askfirst:/bin/sh\n" \
+"\n" \
+"If you choose to use an /etc/inittab file, the inittab entry format is as follows:\n" \
+"\n" \
+" <id>:<runlevels>:<action>:<process>\n" \
+"\n" \
+" <id>:\n" \
+"\n" \
+" WARNING: This field has a non-traditional meaning for BusyBox init!\n" \
+" The id field is used by BusyBox init to specify the controlling tty for\n" \
+" the specified process to run on. The contents of this field are\n" \
+" appended to \"/dev/\" and used as-is. There is no need for this field to\n" \
+" be unique, although if it isn't you may have strange results. If this\n" \
+" field is left blank, the controlling tty is set to the console. Also\n" \
+" note that if BusyBox detects that a serial console is in use, then only\n" \
+" entries whose controlling tty is either the serial console or /dev/null\n" \
+" will be run. BusyBox init does nothing with utmp. We don't need no\n" \
+" stinkin' utmp.\n" \
+"\n" \
+" <runlevels>:\n" \
+"\n" \
+" The runlevels field is completely ignored.\n" \
+"\n" \
+" <action>:\n" \
+"\n" \
+" Valid actions include: sysinit, respawn, askfirst, wait,\n" \
+" once, restart, ctrlaltdel, and shutdown.\n" \
+"\n" \
+" The available actions can be classified into two groups: actions\n" \
+" that are run only once, and actions that are re-run when the specified\n" \
+" process exits.\n" \
+"\n" \
+" Run only-once actions:\n" \
+"\n" \
+" 'sysinit' is the first item run on boot. init waits until all\n" \
+" sysinit actions are completed before continuing. Following the\n" \
+" completion of all sysinit actions, all 'wait' actions are run.\n" \
+" 'wait' actions, like 'sysinit' actions, cause init to wait until\n" \
+" the specified task completes. 'once' actions are asynchronous,\n" \
+" therefore, init does not wait for them to complete. 'restart' is\n" \
+" the action taken to restart the init process. By default this should\n" \
+" simply run /sbin/init, but can be a script which runs pivot_root or it\n" \
+" can do all sorts of other interesting things. The 'ctrlaltdel' init\n" \
+" actions are run when the system detects that someone on the system\n" \
+" console has pressed the CTRL-ALT-DEL key combination. Typically one\n" \
+" wants to run 'reboot' at this point to cause the system to reboot.\n" \
+" Finally the 'shutdown' action specifies the actions to taken when\n" \
+" init is told to reboot. Unmounting filesystems and disabling swap\n" \
+" is a very good here.\n" \
+"\n" \
+" Run repeatedly actions:\n" \
+"\n" \
+" 'respawn' actions are run after the 'once' actions. When a process\n" \
+" started with a 'respawn' action exits, init automatically restarts\n" \
+" it. Unlike sysvinit, BusyBox init does not stop processes from\n" \
+" respawning out of control. The 'askfirst' actions acts just like\n" \
+" respawn, except that before running the specified process it\n" \
+" displays the line \"Please press Enter to activate this console.\"\n" \
+" and then waits for the user to press enter before starting the\n" \
+" specified process.\n" \
+"\n" \
+" Unrecognized actions (like initdefault) will cause init to emit an\n" \
+" error message, and then go along with its business. All actions are\n" \
+" run in the order they appear in /etc/inittab.\n" \
+"\n" \
+" <process>:\n" \
+"\n" \
+" Specifies the process to be executed and its command line.\n" \
+"\n" \
+"Example /etc/inittab file:\n" \
+"\n" \
+" # This is run first except when booting in single-user mode\n" \
+" #\n" \
+" ::sysinit:/etc/init.d/rcS\n" \
+" \n" \
+" # /bin/sh invocations on selected ttys\n" \
+" #\n" \
+" # Start an \"askfirst\" shell on the console (whatever that may be)\n" \
+" ::askfirst:-/bin/sh\n" \
+" # Start an \"askfirst\" shell on /dev/tty2-4\n" \
+" tty2::askfirst:-/bin/sh\n" \
+" tty3::askfirst:-/bin/sh\n" \
+" tty4::askfirst:-/bin/sh\n" \
+" \n" \
+" # /sbin/getty invocations for selected ttys\n" \
+" #\n" \
+" tty4::respawn:/sbin/getty 38400 tty4\n" \
+" tty5::respawn:/sbin/getty 38400 tty5\n" \
+" \n" \
+" \n" \
+" # Example of how to put a getty on a serial line (for a terminal)\n" \
+" #\n" \
+" #::respawn:/sbin/getty -L ttyS0 9600 vt100\n" \
+" #::respawn:/sbin/getty -L ttyS1 9600 vt100\n" \
+" #\n" \
+" # Example how to put a getty on a modem line\n" \
+" #::respawn:/sbin/getty 57600 ttyS2\n" \
+" \n" \
+" # Stuff to do when restarting the init process\n" \
+" ::restart:/sbin/init\n" \
+" \n" \
+" # Stuff to do before rebooting\n" \
+" ::ctrlaltdel:/sbin/reboot\n" \
+" ::shutdown:/bin/umount -a -r\n" \
+" ::shutdown:/sbin/swapoff -a\n"
+
+#define inotifyd_trivial_usage \
+ "/user/space/agent dir/or/file/being/watched[:mask] ..."
+#define inotifyd_full_usage "\n\n" \
+ "Spawn userspace agent on filesystem changes." \
+ "\nWhen a filesystem event matching the mask occurs" \
+ "\non specified file/directory an userspace agent is spawned" \
+ "\nwith the parameters:" \
+ "\n1. actual event(s)" \
+ "\n2. file/directory name" \
+ "\n3. name of subfile (if any), in case of watching a directory" \
+ "\n" \
+ "\n a File is accessed" \
+ "\n c File is modified" \
+ "\n e Metadata changed" \
+ "\n w Writtable file is closed" \
+ "\n 0 Unwrittable file is closed" \
+ "\n r File is opened" \
+ "\n m File is moved from X" \
+ "\n y File is moved to Y" \
+ "\n n Subfile is created" \
+ "\n d Subfile is deleted" \
+ "\n D Self is deleted" \
+ "\n M Self is moved" \
+
+#define insmod_trivial_usage \
+ USE_FEATURE_2_4_MODULES("[OPTION]... ") "MODULE [symbol=value]..."
+#define insmod_full_usage "\n\n" \
+ "Load the specified kernel modules into the kernel" \
+ USE_FEATURE_2_4_MODULES( "\n" \
+ "\nOptions:" \
+ "\n -f Force module to load into the wrong kernel version" \
+ "\n -k Make module autoclean-able" \
+ "\n -v Verbose" \
+ "\n -q Quiet" \
+ "\n -L Lock to prevent simultaneous loads of a module" \
+ USE_FEATURE_INSMOD_LOAD_MAP( \
+ "\n -m Output load map to stdout" \
+ ) \
+ "\n -o NAME Set internal module name to NAME" \
+ "\n -x Do not export externs" \
+ )
+
+#define install_trivial_usage \
+ "[-cgmops] [sources] dest|directory"
+#define install_full_usage "\n\n" \
+ "Copy files and set attributes\n" \
+ "\nOptions:" \
+ "\n -c Copy the file, default" \
+ "\n -d Create directories" \
+ "\n -g Set group ownership" \
+ "\n -m Set permissions" \
+ "\n -o Set ownership" \
+ "\n -p Preserve date" \
+ "\n -s Strip symbol tables" \
+ USE_SELINUX( \
+ "\n -Z Set security context of copy" \
+ )
+
+/* would need to make the " | " optional depending on more than one selected: */
+#define ip_trivial_usage \
+ "[OPTIONS] {" \
+ USE_FEATURE_IP_ADDRESS("address | ") \
+ USE_FEATURE_IP_ROUTE("route | ") \
+ USE_FEATURE_IP_LINK("link | ") \
+ USE_FEATURE_IP_TUNNEL("tunnel | ") \
+ USE_FEATURE_IP_RULE("rule") \
+ "} {COMMAND}"
+#define ip_full_usage "\n\n" \
+ "ip [OPTIONS] OBJECT {COMMAND}\n" \
+ "where OBJECT := {" \
+ USE_FEATURE_IP_ADDRESS("address | ") \
+ USE_FEATURE_IP_ROUTE("route | ") \
+ USE_FEATURE_IP_LINK("link | ") \
+ USE_FEATURE_IP_TUNNEL("tunnel | ") \
+ USE_FEATURE_IP_RULE("rule") \
+ "}\n" \
+ "OPTIONS := { -f[amily] { inet | inet6 | link } | -o[neline] }" \
+
+#define ipaddr_trivial_usage \
+ "{ {add|del} IFADDR dev STRING | {show|flush}\n" \
+ " [dev STRING] [to PREFIX] }"
+#define ipaddr_full_usage "\n\n" \
+ "ipaddr {add|delete} IFADDR dev STRING\n" \
+ "ipaddr {show|flush} [dev STRING] [scope SCOPE-ID]\n" \
+ " [to PREFIX] [label PATTERN]\n" \
+ " IFADDR := PREFIX | ADDR peer PREFIX\n" \
+ " [broadcast ADDR] [anycast ADDR]\n" \
+ " [label STRING] [scope SCOPE-ID]\n" \
+ " SCOPE-ID := [host | link | global | NUMBER]" \
+
+#define ipcalc_trivial_usage \
+ "[OPTION]... ADDRESS[[/]NETMASK] [NETMASK]"
+#define ipcalc_full_usage "\n\n" \
+ "Calculate IP network settings from a IP address\n" \
+ "\nOptions:" \
+ USE_FEATURE_IPCALC_LONG_OPTIONS( \
+ "\n -b,--broadcast Display calculated broadcast address" \
+ "\n -n,--network Display calculated network address" \
+ "\n -m,--netmask Display default netmask for IP" \
+ USE_FEATURE_IPCALC_FANCY( \
+ "\n -p,--prefix Display the prefix for IP/NETMASK" \
+ "\n -h,--hostname Display first resolved host name" \
+ "\n -s,--silent Don't ever display error messages" \
+ ) \
+ ) \
+ SKIP_FEATURE_IPCALC_LONG_OPTIONS( \
+ "\n -b Display calculated broadcast address" \
+ "\n -n Display calculated network address" \
+ "\n -m Display default netmask for IP" \
+ USE_FEATURE_IPCALC_FANCY( \
+ "\n -p Display the prefix for IP/NETMASK" \
+ "\n -h Display first resolved host name" \
+ "\n -s Don't ever display error messages" \
+ ) \
+ )
+
+#define ipcrm_trivial_usage \
+ "[-MQS key] [-mqs id]"
+#define ipcrm_full_usage "\n\n" \
+ "Upper-case options MQS remove an object by shmkey value.\n" \
+ "Lower-case options remove an object by shmid value.\n" \
+ "\nOptions:" \
+ "\n -mM Remove memory segment after last detach" \
+ "\n -qQ Remove message queue" \
+ "\n -sS Remove semaphore" \
+
+#define ipcs_trivial_usage \
+ "[[-smq] -i shmid] | [[-asmq] [-tcplu]]"
+#define ipcs_full_usage "\n\n" \
+ " -i Show specific resource" \
+ "\nResource specification:" \
+ "\n -m Shared memory segments" \
+ "\n -q Message queues" \
+ "\n -s Semaphore arrays" \
+ "\n -a All (default)" \
+ "\nOutput format:" \
+ "\n -t Time" \
+ "\n -c Creator" \
+ "\n -p Pid" \
+ "\n -l Limits" \
+ "\n -u Summary" \
+
+#define iplink_trivial_usage \
+ "{ set DEVICE { up | down | arp { on | off } | show [DEVICE] }"
+#define iplink_full_usage "\n\n" \
+ "iplink set DEVICE { up | down | arp | multicast { on | off } |\n" \
+ " dynamic { on | off } |\n" \
+ " mtu MTU }\n" \
+ "iplink show [DEVICE]" \
+
+#define iproute_trivial_usage \
+ "{ list | flush | { add | del | change | append |\n" \
+ " replace | monitor } ROUTE }"
+#define iproute_full_usage "\n\n" \
+ "iproute { list | flush } SELECTOR\n" \
+ "iproute get ADDRESS [from ADDRESS iif STRING]\n" \
+ " [oif STRING] [tos TOS]\n" \
+ "iproute { add | del | change | append | replace | monitor } ROUTE\n" \
+ " SELECTOR := [root PREFIX] [match PREFIX] [proto RTPROTO]\n" \
+ " ROUTE := [TYPE] PREFIX [tos TOS] [proto RTPROTO]" \
+
+#define iprule_trivial_usage \
+ "{[list | add | del] RULE}"
+#define iprule_full_usage "\n\n" \
+ "iprule [list | add | del] SELECTOR ACTION\n" \
+ " SELECTOR := [from PREFIX] [to PREFIX] [tos TOS] [fwmark FWMARK]\n" \
+ " [dev STRING] [pref NUMBER]\n" \
+ " ACTION := [table TABLE_ID] [nat ADDRESS]\n" \
+ " [prohibit | reject | unreachable]\n" \
+ " [realms [SRCREALM/]DSTREALM]\n" \
+ " TABLE_ID := [local | main | default | NUMBER]" \
+
+#define iptunnel_trivial_usage \
+ "{ add | change | del | show } [NAME]\n" \
+ " [mode { ipip | gre | sit }]\n" \
+ " [remote ADDR] [local ADDR] [ttl TTL]"
+#define iptunnel_full_usage "\n\n" \
+ "iptunnel { add | change | del | show } [NAME]\n" \
+ " [mode { ipip | gre | sit }] [remote ADDR] [local ADDR]\n" \
+ " [[i|o]seq] [[i|o]key KEY] [[i|o]csum]\n" \
+ " [ttl TTL] [tos TOS] [[no]pmtudisc] [dev PHYS_DEV]" \
+
+#define kbd_mode_trivial_usage \
+ "[-a|k|s|u]"
+#define kbd_mode_full_usage "\n\n" \
+ "Report or set the keyboard mode\n" \
+ "\nOptions set mode:" \
+ "\n -a Default (ASCII)" \
+ "\n -k Medium-raw (keyboard)" \
+ "\n -s Raw (scancode)" \
+ "\n -u Unicode (utf-8)" \
+
+#define kill_trivial_usage \
+ "[-l] [-signal] process-id..."
+#define kill_full_usage "\n\n" \
+ "Send a signal (default is TERM) to the specified process(es)\n" \
+ "\nOptions:" \
+ "\n -l List all signal names and numbers" \
+
+#define kill_example_usage \
+ "$ ps | grep apache\n" \
+ "252 root root S [apache]\n" \
+ "263 www-data www-data S [apache]\n" \
+ "264 www-data www-data S [apache]\n" \
+ "265 www-data www-data S [apache]\n" \
+ "266 www-data www-data S [apache]\n" \
+ "267 www-data www-data S [apache]\n" \
+ "$ kill 252\n"
+
+#define killall_trivial_usage \
+ "[-l] [-q] [-signal] process-name..."
+#define killall_full_usage "\n\n" \
+ "Send a signal (default is TERM) to the specified process(es)\n" \
+ "\nOptions:" \
+ "\n -l List all signal names and numbers" \
+ "\n -q Do not complain if no processes were killed" \
+
+#define killall_example_usage \
+ "$ killall apache\n"
+
+#define killall5_trivial_usage \
+ "[-l] [-signal]"
+#define killall5_full_usage "\n\n" \
+ "Send a signal (default is TERM) to all processes outside current session\n" \
+ "\nOptions:" \
+ "\n -l List all signal names and numbers" \
+
+#define klogd_trivial_usage \
+ "[-c N] [-n]"
+#define klogd_full_usage "\n\n" \
+ "Kernel logger\n" \
+ "\nOptions:" \
+ "\n -c N Only messages with level < N are printed to console" \
+ "\n -n Run in foreground" \
+
+#define length_trivial_usage \
+ "STRING"
+#define length_full_usage "\n\n" \
+ "Print STRING's length"
+
+#define length_example_usage \
+ "$ length Hello\n" \
+ "5\n"
+
+#define less_trivial_usage \
+ "[-EMNmh~?] [FILE...]"
+#define less_full_usage "\n\n" \
+ "View a file or list of files. The position within files can be\n" \
+ "changed, and files can be manipulated in various ways.\n" \
+ "\nOptions:" \
+ "\n -E Quit once the end of a file is reached" \
+ "\n -M,-m Display a status line containing the line numbers" \
+ "\n and percentage through the file" \
+ "\n -N Prefix line numbers to each line" \
+ "\n -~ Suppress ~s displayed past the end of the file" \
+
+#define linux32_trivial_usage NOUSAGE_STR
+#define linux32_full_usage ""
+#define linux64_trivial_usage NOUSAGE_STR
+#define linux64_full_usage ""
+
+#define linuxrc_trivial_usage NOUSAGE_STR
+#define linuxrc_full_usage ""
+
+#define setarch_trivial_usage \
+ "personality program [args...]"
+#define setarch_full_usage "\n\n" \
+ "Personality may be:\n" \
+ " linux32 Set 32bit uname emulation\n" \
+ " linux64 Set 64bit uname emulation" \
+
+#define ln_trivial_usage \
+ "[OPTION] TARGET... LINK_NAME|DIRECTORY"
+#define ln_full_usage "\n\n" \
+ "Create a link named LINK_NAME or DIRECTORY to the specified TARGET.\n" \
+ "Use '--' to indicate that all following arguments are non-options.\n" \
+ "\nOptions:" \
+ "\n -s Make symlinks instead of hardlinks" \
+ "\n -f Remove existing destination files" \
+ "\n -n Don't dereference symlinks - treat like normal file" \
+ "\n -b Make a backup of the target (if exists) before link operation" \
+ "\n -S suf Use suffix instead of ~ when making backup files" \
+
+#define ln_example_usage \
+ "$ ln -s BusyBox /tmp/ls\n" \
+ "$ ls -l /tmp/ls\n" \
+ "lrwxrwxrwx 1 root root 7 Apr 12 18:39 ls -> BusyBox*\n"
+
+#define load_policy_trivial_usage NOUSAGE_STR
+
+#define load_policy_full_usage ""
+
+#define loadfont_trivial_usage \
+ "< font"
+#define loadfont_full_usage "\n\n" \
+ "Load a console font from standard input"
+#define loadfont_example_usage \
+ "$ loadfont < /etc/i18n/fontname\n"
+
+#define loadkmap_trivial_usage \
+ "< keymap"
+#define loadkmap_full_usage "\n\n" \
+ "Load a binary keyboard translation table from standard input"
+#define loadkmap_example_usage \
+ "$ loadkmap < /etc/i18n/lang-keymap\n"
+
+#define logger_trivial_usage \
+ "[OPTION]... [MESSAGE]"
+#define logger_full_usage "\n\n" \
+ "Write MESSAGE to the system log. If MESSAGE is omitted, log stdin.\n" \
+ "\nOptions:" \
+ "\n -s Log to stderr as well as the system log" \
+ "\n -t TAG Log using the specified tag (defaults to user name)" \
+ "\n -p PRIO Priority (numeric or facility.level pair)" \
+
+#define logger_example_usage \
+ "$ logger \"hello\"\n"
+
+#define login_trivial_usage \
+ "[-p] [-h HOST] [[-f] USER]"
+#define login_full_usage "\n\n" \
+ "Begin a new session on the system\n" \
+ "\nOptions:" \
+ "\n -f Do not authenticate (user already authenticated)" \
+ "\n -h Name of the remote host" \
+ "\n -p Preserve environment" \
+
+#define logname_trivial_usage \
+ ""
+#define logname_full_usage "\n\n" \
+ "Print the name of the current user"
+#define logname_example_usage \
+ "$ logname\n" \
+ "root\n"
+
+#define logread_trivial_usage \
+ "[OPTION]..."
+#define logread_full_usage "\n\n" \
+ "Show messages in syslogd's circular buffer\n" \
+ "\nOptions:" \
+ "\n -f Output data as log grows" \
+
+#define losetup_trivial_usage \
+ "[-o OFS] LOOPDEV FILE - associate loop devices\n" \
+ " losetup -d LOOPDEV - disassociate\n" \
+ " losetup [-f] - show"
+#define losetup_full_usage "\n\n" \
+ "Options:" \
+ "\n -o OFS Start OFS bytes into FILE" \
+ "\n -f Show first free loop device" \
+
+#define losetup_notes_usage \
+ "No arguments will display all current associations.\n" \
+ "One argument (losetup /dev/loop1) will display the current association\n" \
+ "(if any), or disassociate it (with -d). The display shows the offset\n" \
+ "and filename of the file the loop device is currently bound to.\n\n" \
+ "Two arguments (losetup /dev/loop1 file.img) create a new association,\n" \
+ "with an optional offset (-o 12345). Encryption is not yet supported.\n" \
+ "losetup -f will show the first loop free loop device\n\n"
+
+#define lpd_trivial_usage \
+ "SPOOLDIR [HELPER [ARGS...]]"
+#define lpd_full_usage "\n\n" \
+ "Example:" \
+ "\n tcpsvd -E 0 515 softlimit -m 999999 lpd /var/spool ./print"
+
+#define lpq_trivial_usage \
+ "[-P queue[@host[:port]]] [-U USERNAME] [-d JOBID...] [-fs]"
+#define lpq_full_usage "\n\n" \
+ "Options:" \
+ "\n -P lp service to connect to (else uses $PRINTER)" \
+ "\n -d Delete jobs" \
+ "\n -f Force any waiting job to be printed" \
+ "\n -s Short display" \
+
+#define lpr_trivial_usage \
+ "-P queue[@host[:port]] -U USERNAME -J TITLE -Vmh [FILE...]"
+/* -C CLASS exists too, not shown.
+ * CLASS is supposed to be printed on banner page, if one is requested */
+#define lpr_full_usage "\n\n" \
+ "Options:" \
+ "\n -P lp service to connect to (else uses $PRINTER)"\
+ "\n -m Send mail on completion" \
+ "\n -h Print banner page too" \
+ "\n -V Verbose" \
+
+#define ls_trivial_usage \
+ "[-1Aa" USE_FEATURE_LS_TIMESTAMPS("c") "Cd" \
+ USE_FEATURE_LS_TIMESTAMPS("e") USE_FEATURE_LS_FILETYPES("F") "iln" \
+ USE_FEATURE_LS_FILETYPES("p") USE_FEATURE_LS_FOLLOWLINKS("L") \
+ USE_FEATURE_LS_RECURSIVE("R") USE_FEATURE_LS_SORTFILES("rS") "s" \
+ USE_FEATURE_AUTOWIDTH("T") USE_FEATURE_LS_TIMESTAMPS("tu") \
+ USE_FEATURE_LS_SORTFILES("v") USE_FEATURE_AUTOWIDTH("w") "x" \
+ USE_FEATURE_LS_SORTFILES("X") USE_FEATURE_HUMAN_READABLE("h") "k" \
+ USE_SELINUX("K") "] [filenames...]"
+#define ls_full_usage "\n\n" \
+ "List directory contents\n" \
+ "\nOptions:" \
+ "\n -1 List files in a single column" \
+ "\n -A Do not list implied . and .." \
+ "\n -a Do not hide entries starting with ." \
+ "\n -C List entries by columns" \
+ USE_FEATURE_LS_TIMESTAMPS( \
+ "\n -c With -l: show ctime") \
+ USE_FEATURE_LS_COLOR( \
+ "\n --color[={always,never,auto}] Control coloring") \
+ "\n -d List directory entries instead of contents" \
+ USE_FEATURE_LS_TIMESTAMPS( \
+ "\n -e List both full date and full time") \
+ USE_FEATURE_LS_FILETYPES( \
+ "\n -F Append indicator (one of */=@|) to entries") \
+ "\n -i List the i-node for each file" \
+ "\n -l Use a long listing format" \
+ "\n -n List numeric UIDs and GIDs instead of names" \
+ USE_FEATURE_LS_FILETYPES( \
+ "\n -p Append indicator (one of /=@|) to entries") \
+ USE_FEATURE_LS_FOLLOWLINKS( \
+ "\n -L List entries pointed to by symlinks") \
+ USE_FEATURE_LS_RECURSIVE( \
+ "\n -R List subdirectories recursively") \
+ USE_FEATURE_LS_SORTFILES( \
+ "\n -r Sort the listing in reverse order") \
+ USE_FEATURE_LS_SORTFILES( \
+ "\n -S Sort the listing by file size") \
+ "\n -s List the size of each file, in blocks" \
+ USE_FEATURE_AUTOWIDTH( \
+ "\n -T NUM Assume Tabstop every NUM columns") \
+ USE_FEATURE_LS_TIMESTAMPS( \
+ "\n -t With -l: show modification time") \
+ USE_FEATURE_LS_TIMESTAMPS( \
+ "\n -u With -l: show access time") \
+ USE_FEATURE_LS_SORTFILES( \
+ "\n -v Sort the listing by version") \
+ USE_FEATURE_AUTOWIDTH( \
+ "\n -w NUM Assume the terminal is NUM columns wide") \
+ "\n -x List entries by lines instead of by columns" \
+ USE_FEATURE_LS_SORTFILES( \
+ "\n -X Sort the listing by extension") \
+ USE_FEATURE_HUMAN_READABLE( \
+ "\n -h Print sizes in human readable format (e.g., 1K 243M 2G)") \
+ USE_SELINUX( \
+ "\n -k Print security context") \
+ USE_SELINUX( \
+ "\n -K Print security context in long format") \
+ USE_SELINUX( \
+ "\n -Z Print security context and permission") \
+
+#define lsattr_trivial_usage \
+ "[-Radlv] [files...]"
+#define lsattr_full_usage "\n\n" \
+ "List file attributes on an ext2 fs\n" \
+ "\nOptions:" \
+ "\n -R Recursively list subdirectories" \
+ "\n -a Do not hide entries starting with ." \
+ "\n -d List directory entries instead of contents" \
+ "\n -l Print long flag names" \
+ "\n -v List the file's version/generation number" \
+
+#define lsmod_trivial_usage \
+ ""
+#define lsmod_full_usage "\n\n" \
+ "List the currently loaded kernel modules"
+
+#if ENABLE_FEATURE_MAKEDEVS_LEAF
+#define makedevs_trivial_usage \
+ "NAME TYPE MAJOR MINOR FIRST LAST [s]"
+#define makedevs_full_usage "\n\n" \
+ "Create a range of block or character special files\n\n" \
+ "TYPEs include:\n" \
+ " b Make a block device\n" \
+ " c or u Make a character device\n" \
+ " p Make a named pipe. MAJOR and MINOR are ignored\n" \
+ "\n" \
+ "FIRST specifies the number appended to NAME to create the first device.\n" \
+ "LAST specifies the number of the last item that should be created\n" \
+ "If 's' is the last argument, the base device is created as well.\n\n" \
+ "For example:\n" \
+ " makedevs /dev/ttyS c 4 66 2 63 -> ttyS2-ttyS63\n" \
+ " makedevs /dev/hda b 3 0 0 8 s -> hda,hda1-hda8"
+#define makedevs_example_usage \
+ "# makedevs /dev/ttyS c 4 66 2 63\n" \
+ "[creates ttyS2-ttyS63]\n" \
+ "# makedevs /dev/hda b 3 0 0 8 s\n" \
+ "[creates hda,hda1-hda8]\n"
+#endif
+
+#if ENABLE_FEATURE_MAKEDEVS_TABLE
+#define makedevs_trivial_usage \
+ "[-d device_table] rootdir"
+#define makedevs_full_usage "\n\n" \
+ "Create a range of special files as specified in a device table.\n" \
+ "Device table entries take the form of:\n" \
+ "<type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>\n" \
+ "Where name is the file name, type can be one of:\n" \
+ " f A regular file\n" \
+ " d Directory\n" \
+ " c Character special device file\n" \
+ " b Block special device file\n" \
+ " p Fifo (named pipe)\n" \
+ "uid is the user id for the target file, gid is the group id for the\n" \
+ "target file. The rest of the entries (major, minor, etc) apply to\n" \
+ "to device special files. A '-' may be used for blank entries."
+#define makedevs_example_usage \
+ "For example:\n" \
+ "<name> <type> <mode><uid><gid><major><minor><start><inc><count>\n" \
+ "/dev d 755 0 0 - - - - -\n" \
+ "/dev/console c 666 0 0 5 1 - - -\n" \
+ "/dev/null c 666 0 0 1 3 0 0 -\n" \
+ "/dev/zero c 666 0 0 1 5 0 0 -\n" \
+ "/dev/hda b 640 0 0 3 0 0 0 -\n" \
+ "/dev/hda b 640 0 0 3 1 1 1 15\n\n" \
+ "Will Produce:\n" \
+ "/dev\n" \
+ "/dev/console\n" \
+ "/dev/null\n" \
+ "/dev/zero\n" \
+ "/dev/hda\n" \
+ "/dev/hda[0-15]\n"
+#endif
+
+#define man_trivial_usage \
+ "[OPTION]... [MANPAGE]..."
+#define man_full_usage "\n\n" \
+ "Format and display manual page\n" \
+ "\nOptions:" \
+ "\n -a Display all pages" \
+ "\n -w Show page locations" \
+
+#define matchpathcon_trivial_usage \
+ "[-n] [-N] [-f file_contexts_file] [-p prefix] [-V]"
+#define matchpathcon_full_usage "\n\n" \
+ " -n Do not display path" \
+ "\n -N Do not use translations" \
+ "\n -f Use alternate file_context file" \
+ "\n -p Use prefix to speed translations" \
+ "\n -V Verify file context on disk matches defaults" \
+
+#define md5sum_trivial_usage \
+ "[OPTION] [FILEs...]" \
+ USE_FEATURE_MD5_SHA1_SUM_CHECK("\n or: md5sum [OPTION] -c [FILE]")
+#define md5sum_full_usage "\n\n" \
+ "Print" USE_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " MD5 checksums" \
+ USE_FEATURE_MD5_SHA1_SUM_CHECK( "\n" \
+ "\nOptions:" \
+ "\n -c Check MD5 sums against given list" \
+ "\n -s Don't output anything, status code shows success" \
+ "\n -w Warn about improperly formatted MD5 checksum lines") \
+
+#define md5sum_example_usage \
+ "$ md5sum < busybox\n" \
+ "6fd11e98b98a58f64ff3398d7b324003\n" \
+ "$ md5sum busybox\n" \
+ "6fd11e98b98a58f64ff3398d7b324003 busybox\n" \
+ "$ md5sum -c -\n" \
+ "6fd11e98b98a58f64ff3398d7b324003 busybox\n" \
+ "busybox: OK\n" \
+ "^D\n"
+
+#define mdev_trivial_usage \
+ "[-s]"
+#define mdev_full_usage "\n\n" \
+ " -s Scan /sys and populate /dev during system boot\n" \
+ "\n" \
+ "Called with no options (via hotplug) it uses environment variables\n" \
+ "to determine which device to add/remove."
+
+#define mdev_notes_usage "" \
+ USE_FEATURE_MDEV_CONFIG( \
+ "The mdev config file contains lines that look like:\n" \
+ " hd[a-z][0-9]* 0:3 660\n\n" \
+ "That's device name (with regex match), uid:gid, and permissions.\n\n" \
+ USE_FEATURE_MDEV_EXEC( \
+ "Optionally, that can be followed (on the same line) by a special character\n" \
+ "and a command line to run after creating/before deleting the corresponding\n" \
+ "device(s). The environment variable $MDEV indicates the active device node\n" \
+ "(which is useful if it's a regex match). For example:\n\n" \
+ " hdc root:cdrom 660 *ln -s $MDEV cdrom\n\n" \
+ "The special characters are @ (run after creating), $ (run before deleting),\n" \
+ "and * (run both after creating and before deleting). The commands run in\n" \
+ "the /dev directory, and use system() which calls /bin/sh.\n\n" \
+ ) \
+ "Config file parsing stops on the first matching line. If no config\n" \
+ "entry is matched, devices are created with default 0:0 660. (Make\n" \
+ "the last line match .* to override this.)\n\n" \
+ )
+
+#define mesg_trivial_usage \
+ "[y|n]"
+#define mesg_full_usage "\n\n" \
+ "Control write access to your terminal\n" \
+ " y Allow write access to your terminal\n" \
+ " n Disallow write access to your terminal"
+
+#define microcom_trivial_usage \
+ "[-d DELAY] [-t TIMEOUT] [-s SPEED] [-X] TTY"
+#define microcom_full_usage "\n\n" \
+ "Copy bytes for stdin to TTY and from TTY to stdout\n" \
+ "\nOptions:" \
+ "\n -d Wait up to DELAY ms for TTY output before sending every" \
+ "\n next byte to it" \
+ "\n -t Exit if both stdin and TTY are silent for TIMEOUT ms" \
+ "\n -s Set serial line to SPEED" \
+ "\n -X Disable special meaning of NUL and Ctrl-X from stdin" \
+
+#define mkdir_trivial_usage \
+ "[OPTION] DIRECTORY..."
+#define mkdir_full_usage "\n\n" \
+ "Create DIRECTORY\n" \
+ "\nOptions:" \
+ "\n -m Set permission mode (as in chmod), not rwxrwxrwx - umask" \
+ "\n -p No error if existing, make parent directories as needed" \
+ USE_SELINUX( \
+ "\n -Z Set security context" \
+ )
+
+#define mkdir_example_usage \
+ "$ mkdir /tmp/foo\n" \
+ "$ mkdir /tmp/foo\n" \
+ "/tmp/foo: File exists\n" \
+ "$ mkdir /tmp/foo/bar/baz\n" \
+ "/tmp/foo/bar/baz: No such file or directory\n" \
+ "$ mkdir -p /tmp/foo/bar/baz\n"
+
+#define mke2fs_trivial_usage \
+ "[-c|-l filename] [-b block-size] [-f fragment-size] [-g blocks-per-group] " \
+ "[-i bytes-per-inode] [-j] [-J journal-options] [-N number-of-inodes] [-n] " \
+ "[-m reserved-blocks-percentage] [-o creator-os] [-O feature[,...]] [-q] " \
+ "[r fs-revision-level] [-E extended-options] [-v] [-F] [-L volume-label] " \
+ "[-M last-mounted-directory] [-S] [-T filesystem-type] " \
+ "device [blocks-count]"
+#define mke2fs_full_usage "\n\n" \
+ " -b size Block size in bytes" \
+ "\n -c Check for bad blocks before creating" \
+ "\n -E opts Set extended options" \
+ "\n -f size Fragment size in bytes" \
+ "\n -F Force (ignore sanity checks)" \
+ "\n -g num Number of blocks in a block group" \
+ "\n -i ratio The bytes/inode ratio" \
+ "\n -j Create a journal (ext3)" \
+ "\n -J opts Set journal options (size/device)" \
+ "\n -l file Read bad blocks list from file" \
+ "\n -L lbl Set the volume label" \
+ "\n -m percent Percent of fs blocks to reserve for admin" \
+ "\n -M dir Set last mounted directory" \
+ "\n -n Do not actually create anything" \
+ "\n -N num Number of inodes to create" \
+ "\n -o os Set the 'creator os' field" \
+ "\n -O features Dir_index/filetype/has_journal/journal_dev/sparse_super" \
+ "\n -q Quiet" \
+ "\n -r rev Set filesystem revision" \
+ "\n -S Write superblock and group descriptors only" \
+ "\n -T fs-type Set usage type (news/largefile/largefile4)" \
+ "\n -v Verbose" \
+
+#define mkfifo_trivial_usage \
+ "[OPTIONS] name"
+#define mkfifo_full_usage "\n\n" \
+ "Create named pipe (identical to 'mknod name p')\n" \
+ "\nOptions:" \
+ "\n -m MODE Mode (default a=rw)" \
+ USE_SELINUX( \
+ "\n -Z Set security context" \
+ )
+
+#define mkfs_minix_trivial_usage \
+ "[-c | -l filename] [-nXX] [-iXX] /dev/name [blocks]"
+#define mkfs_minix_full_usage "\n\n" \
+ "Make a MINIX filesystem\n" \
+ "\nOptions:" \
+ "\n -c Check device for bad blocks" \
+ "\n -n [14|30] Maximum length of filenames" \
+ "\n -i INODES Number of inodes for the filesystem" \
+ "\n -l FILENAME Read bad blocks list from FILENAME" \
+ "\n -v Make version 2 filesystem" \
+
+#define mknod_trivial_usage \
+ "[OPTIONS] NAME TYPE MAJOR MINOR"
+#define mknod_full_usage "\n\n" \
+ "Create a special file (block, character, or pipe)\n" \
+ "\nOptions:" \
+ "\n -m Create the special file using the specified mode (default a=rw)" \
+ "\nTYPEs include:" \
+ "\n b: Make a block device" \
+ "\n c or u: Make a character device" \
+ "\n p: Make a named pipe (MAJOR and MINOR are ignored)" \
+ USE_SELINUX( \
+ "\n -Z Set security context" \
+ )
+
+#define mknod_example_usage \
+ "$ mknod /dev/fd0 b 2 0\n" \
+ "$ mknod -m 644 /tmp/pipe p\n"
+
+#define mkswap_trivial_usage \
+ "DEVICE"
+#define mkswap_full_usage "\n\n" \
+ "Prepare block device to be used as swap partition"
+#if 0
+ "[-c] [-v0|-v1] DEVICE [BLOCKS]"
+ "\nOptions:"
+ "\n -c Check for readability"
+ "\n -v0 Make swap version 0 (max 128M)"
+ "\n -v1 Make swap version 1 (default for kernels > 2.1.117)"
+ "\n BLOCKS Number of blocks to use (default is entire partition)"
+#endif
+
+#define mktemp_trivial_usage \
+ "[-dt] [-p DIR] [TEMPLATE]"
+#define mktemp_full_usage "\n\n" \
+ "Create a temporary file with name based on TEMPLATE and print its name.\n" \
+ "TEMPLATE must end with XXXXXX (e.g. [/dir/]nameXXXXXX).\n" \
+ "\nOptions:" \
+ "\n -d Make a directory instead of a file" \
+/* "\n -q Fail silently if an error occurs" - we ignore it */ \
+ "\n -t Generate a path rooted in temporary directory" \
+ "\n -p DIR Use DIR as a temporary directory (implies -t)" \
+ "\n" \
+ "\nFor -t or -p, directory is chosen as follows:" \
+ "\n$TMPDIR if set, else -p DIR, else /tmp" \
+
+#define mktemp_example_usage \
+ "$ mktemp /tmp/temp.XXXXXX\n" \
+ "/tmp/temp.mWiLjM\n" \
+ "$ ls -la /tmp/temp.mWiLjM\n" \
+ "-rw------- 1 andersen andersen 0 Apr 25 17:10 /tmp/temp.mWiLjM\n"
+
+#define modprobe_trivial_usage \
+ "[-knqrsv] MODULE [symbol=value...]"
+#define modprobe_full_usage "\n\n" \
+ "Options:" \
+ "\n -k Make module autoclean-able" \
+ "\n -n Dry run" \
+ "\n -q Quiet" \
+ "\n -r Remove module (stacks) or do autoclean" \
+ "\n -s Report via syslog instead of stderr" \
+ "\n -v Verbose" \
+
+#define modprobe_notes_usage \
+"modprobe can (un)load a stack of modules, passing each module options (when\n" \
+"loading). modprobe uses a configuration file to determine what option(s) to\n" \
+"pass each module it loads.\n" \
+"\n" \
+"The configuration file is searched (in order) amongst:\n" \
+"\n" \
+" /etc/modprobe.conf (2.6 only)\n" \
+" /etc/modules.conf\n" \
+" /etc/conf.modules (deprecated)\n" \
+"\n" \
+"They all have the same syntax (see below). If none is present, it is\n" \
+"_not_ an error; each loaded module is then expected to load without\n" \
+"options. Once a file is found, the others are tested for.\n" \
+"\n" \
+"/etc/modules.conf entry format:\n" \
+"\n" \
+" alias <alias_name> <mod_name>\n" \
+" Makes it possible to modprobe alias_name, when there is no such module.\n" \
+" It makes sense if your mod_name is long, or you want a more representative\n" \
+" name for that module (eg. 'scsi' in place of 'aha7xxx').\n" \
+" This makes it also possible to use a different set of options (below) for\n" \
+" the module and the alias.\n" \
+" A module can be aliased more than once.\n" \
+"\n" \
+" options <mod_name|alias_name> <symbol=value...>\n" \
+" When loading module mod_name (or the module aliased by alias_name), pass\n" \
+" the \"symbol=value\" pairs as option to that module.\n" \
+"\n" \
+"Sample /etc/modules.conf file:\n" \
+"\n" \
+" options tulip irq=3\n" \
+" alias tulip tulip2\n" \
+" options tulip2 irq=4 io=0x308\n" \
+"\n" \
+"Other functionality offered by 'classic' modprobe is not available in\n" \
+"this implementation.\n" \
+"\n" \
+"If module options are present both in the config file, and on the command line,\n" \
+"then the options from the command line will be passed to the module _after_\n" \
+"the options from the config file. That way, you can have defaults in the config\n" \
+"file, and override them for a specific usage from the command line.\n"
+#define modprobe_example_usage \
+ "(with the above /etc/modules.conf):\n\n" \
+ "$ modprobe tulip\n" \
+ " will load the module 'tulip' with default option 'irq=3'\n\n" \
+ "$ modprobe tulip irq=5\n" \
+ " will load the module 'tulip' with option 'irq=5', thus overriding the default\n\n" \
+ "$ modprobe tulip2\n" \
+ " will load the module 'tulip' with default options 'irq=4 io=0x308',\n" \
+ " which are the default for alias 'tulip2'\n\n" \
+ "$ modprobe tulip2 irq=8\n" \
+ " will load the module 'tulip' with default options 'irq=4 io=0x308 irq=8',\n" \
+ " which are the default for alias 'tulip2' overridden by the option 'irq=8'\n\n" \
+ " from the command line\n\n" \
+ "$ modprobe tulip2 irq=2 io=0x210\n" \
+ " will load the module 'tulip' with default options 'irq=4 io=0x308 irq=4 io=0x210',\n" \
+ " which are the default for alias 'tulip2' overridden by the options 'irq=2 io=0x210'\n\n" \
+ " from the command line\n"
+
+#define more_trivial_usage \
+ "[FILE...]"
+#define more_full_usage "\n\n" \
+ "View FILE or standard input one screenful at a time"
+
+#define more_example_usage \
+ "$ dmesg | more\n"
+
+#define mount_trivial_usage \
+ "[flags] DEVICE NODE [-o options,more-options]"
+#define mount_full_usage "\n\n" \
+ "Mount a filesystem. Filesystem autodetection requires /proc be mounted.\n" \
+ "\nOptions:" \
+ "\n -a Mount all filesystems in fstab" \
+ USE_FEATURE_MOUNT_FAKE( \
+ "\n -f "USE_FEATURE_MTAB_SUPPORT("Update /etc/mtab, but ")"don't mount" \
+ ) \
+ USE_FEATURE_MTAB_SUPPORT( \
+ "\n -n Don't update /etc/mtab" \
+ ) \
+ "\n -r Read-only mount" \
+ "\n -t fs-type Filesystem type" \
+ "\n -w Read-write mount (default)" \
+ "\n" \
+ "-o option:\n" \
+ USE_FEATURE_MOUNT_LOOP( \
+ " loop Ignored (loop devices are autodetected)\n" \
+ ) \
+ USE_FEATURE_MOUNT_FLAGS( \
+ " [a]sync Writes are asynchronous / synchronous\n" \
+ " [no]atime Disable / enable updates to inode access times\n" \
+ " [no]diratime Disable / enable atime updates to directories\n" \
+ " [no]dev Allow use of special device files / disallow them\n" \
+ " [no]exec Allow use of executable files / disallow them\n" \
+ " [no]suid Allow set-user-id-root programs / disallow them\n" \
+ " [r]shared Convert [recursively] to a shared subtree\n" \
+ " [r]slave Convert [recursively] to a slave subtree\n" \
+ " [r]private Convert [recursively] to a private subtree\n" \
+ " [un]bindable Make mount point [un]able to be bind mounted\n" \
+ " bind Bind a directory to an additional location\n" \
+ " move Relocate an existing mount point\n" \
+ ) \
+ " remount Remount a mounted filesystem, changing its flags\n" \
+ " ro/rw Mount for read-only / read-write\n" \
+ "\n" \
+ "There are EVEN MORE flags that are specific to each filesystem\n" \
+ "You'll have to see the written documentation for those filesystems" \
+
+#define mount_example_usage \
+ "$ mount\n" \
+ "/dev/hda3 on / type minix (rw)\n" \
+ "proc on /proc type proc (rw)\n" \
+ "devpts on /dev/pts type devpts (rw)\n" \
+ "$ mount /dev/fd0 /mnt -t msdos -o ro\n" \
+ "$ mount /tmp/diskimage /opt -t ext2 -o loop\n" \
+ "$ mount cd_image.iso mydir\n"
+#define mount_notes_usage \
+ "Returns 0 for success, number of failed mounts for -a, or errno for one mount."
+
+#define mountpoint_trivial_usage \
+ "[-q] <[-d] DIR | -x DEVICE>"
+#define mountpoint_full_usage "\n\n" \
+ "mountpoint checks if the directory is a mountpoint\n" \
+ "\nOptions:" \
+ "\n -q Quiet" \
+ "\n -d Print major/minor device number of the filesystem" \
+ "\n -x Print major/minor device number of the blockdevice" \
+
+#define mountpoint_example_usage \
+ "$ mountpoint /proc\n" \
+ "/proc is not a mountpoint\n" \
+ "$ mountpoint /sys\n" \
+ "/sys is a mountpoint\n"
+
+#define mt_trivial_usage \
+ "[-f device] opcode value"
+#define mt_full_usage "\n\n" \
+ "Control magnetic tape drive operation\n" \
+ "\n" \
+ "Available Opcodes:\n" \
+ "\n" \
+ "bsf bsfm bsr bss datacompression drvbuffer eof eom erase\n" \
+ "fsf fsfm fsr fss load lock mkpart nop offline ras1 ras2\n" \
+ "ras3 reset retension rewind rewoffline seek setblk setdensity\n" \
+ "setpart tell unload unlock weof wset" \
+
+#define mv_trivial_usage \
+ "[OPTION]... SOURCE DEST\n" \
+ "or: mv [OPTION]... SOURCE... DIRECTORY"
+#define mv_full_usage "\n\n" \
+ "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY\n" \
+ "\nOptions:" \
+ "\n -f Don't prompt before overwriting" \
+ "\n -i Interactive, prompt before overwrite" \
+
+#define mv_example_usage \
+ "$ mv /tmp/foo /bin/bar\n"
+
+#define nameif_trivial_usage \
+ "[-s] [-c FILE] [{IFNAME MACADDR}]"
+#define nameif_full_usage "\n\n" \
+ "Rename network interface while it in the down state\n" \
+ "\nOptions:" \
+ "\n -c FILE Use configuration file (default is /etc/mactab)" \
+ "\n -s Use syslog (LOCAL0 facility)" \
+ "\n IFNAME MACADDR new_interface_name interface_mac_address" \
+
+#define nameif_example_usage \
+ "$ nameif -s dmz0 00:A0:C9:8C:F6:3F\n" \
+ " or\n" \
+ "$ nameif -c /etc/my_mactab_file\n" \
+
+#if !ENABLE_DESKTOP
+
+#if ENABLE_NC_SERVER || ENABLE_NC_EXTRA
+#define NC_OPTIONS_STR "\n\nOptions:"
+#else
+#define NC_OPTIONS_STR
+#endif
+
+#define nc_trivial_usage \
+ USE_NC_EXTRA("[-iN] [-wN] ")USE_NC_SERVER("[-l] [-p PORT] ") \
+ "["USE_NC_EXTRA("-f FILENAME|")"IPADDR PORTNUM]"USE_NC_EXTRA(" [-e COMMAND]")
+#define nc_full_usage "\n\n" \
+ "Open a pipe to IP:port" USE_NC_EXTRA(" or file") \
+ NC_OPTIONS_STR \
+ USE_NC_EXTRA( \
+ "\n -e Exec rest of command line after connect" \
+ "\n -i SECS Delay interval for lines sent" \
+ "\n -w SECS Timeout for connect" \
+ "\n -f FILE Use file (ala /dev/ttyS0) instead of network" \
+ ) \
+ USE_NC_SERVER( \
+ "\n -l Listen mode, for inbound connects" \
+ USE_NC_EXTRA( \
+ "\n (use -l twice with -e for persistent server)") \
+ "\n -p PORT Local port number" \
+ )
+
+#define nc_notes_usage "" \
+ USE_NC_EXTRA( \
+ "To use netcat as a terminal emulator on a serial port:\n\n" \
+ "$ stty 115200 -F /dev/ttyS0\n" \
+ "$ stty raw -echo -ctlecho && nc -f /dev/ttyS0\n" \
+ )
+
+#define nc_example_usage \
+ "$ nc foobar.somedomain.com 25\n" \
+ "220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600\n" \
+ "help\n" \
+ "214-Commands supported:\n" \
+ "214- HELO EHLO MAIL RCPT DATA AUTH\n" \
+ "214 NOOP QUIT RSET HELP\n" \
+ "quit\n" \
+ "221 foobar closing connection\n"
+
+#else /* DESKTOP nc - much more compatible with nc 1.10 */
+
+#define nc_trivial_usage \
+ "[-options] hostname port - connect" \
+ USE_NC_SERVER("\n" \
+ "nc [-options] -l -p port [hostname] [port] - listen")
+#define nc_full_usage "\n\n" \
+ "Options:" \
+ "\n -e prog [args] Program to exec after connect (must be last)" \
+ USE_NC_SERVER( \
+ "\n -l Listen mode, for inbound connects" \
+ ) \
+ "\n -n Don't do DNS resolution" \
+ "\n -s addr Local address" \
+ "\n -p port Local port" \
+ "\n -u UDP mode" \
+ "\n -v Verbose (cumulative: -vv)" \
+ "\n -w secs Timeout for connects and final net reads" \
+ USE_NC_EXTRA( \
+ "\n -i sec Delay interval for lines sent" /* ", ports scanned" */ \
+ "\n -o file Hex dump of traffic" \
+ "\n -z Zero-I/O mode (scanning)" \
+ ) \
+/* "\n -r Randomize local and remote ports" */
+/* "\n -g gateway Source-routing hop point[s], up to 8" */
+/* "\n -G num Source-routing pointer: 4, 8, 12, ..." */
+/* "\nport numbers can be individual or ranges: lo-hi [inclusive]" */
+
+#endif
+
+#define netstat_trivial_usage \
+ "[-laentuwxr"USE_FEATURE_NETSTAT_WIDE("W")"]"
+#define netstat_full_usage "\n\n" \
+ "Display networking information\n" \
+ "\nOptions:" \
+ "\n -l Display listening server sockets" \
+ "\n -a Display all sockets (default: connected)" \
+ "\n -e Display other/more information" \
+ "\n -n Don't resolve names" \
+ "\n -t Tcp sockets" \
+ "\n -u Udp sockets" \
+ "\n -w Raw sockets" \
+ "\n -x Unix sockets" \
+ "\n -r Display routing table" \
+ USE_FEATURE_NETSTAT_WIDE( \
+ "\n -W Display with no column truncation" \
+ )
+
+#define nice_trivial_usage \
+ "[-n ADJUST] [COMMAND [ARG]...]"
+#define nice_full_usage "\n\n" \
+ "Run a program with modified scheduling priority\n" \
+ "\nOptions:" \
+ "\n -n ADJUST Adjust the scheduling priority by ADJUST" \
+
+#define nmeter_trivial_usage \
+ "format_string"
+#define nmeter_full_usage "\n\n" \
+ "Monitor system in real time\n\n" \
+ "Format specifiers:\n" \
+ "%Nc or %[cN] Monitor CPU. N - bar size, default 10\n" \
+ " (displays: S:system U:user N:niced D:iowait I:irq i:softirq)\n" \
+ "%[niface] Monitor network interface 'iface'\n" \
+ "%m Monitor allocated memory\n" \
+ "%[mf] Monitor free memory\n" \
+ "%[mt] Monitor total memory\n" \
+ "%s Monitor allocated swap\n" \
+ "%f Monitor number of used file descriptors\n" \
+ "%Ni Monitor total/specific IRQ rate\n" \
+ "%x Monitor context switch rate\n" \
+ "%p Monitor forks\n" \
+ "%[pn] Monitor # of processes\n" \
+ "%b Monitor block io\n" \
+ "%Nt Show time (with N decimal points)\n" \
+ "%Nd Milliseconds between updates (default=1000)\n" \
+ "%r Print <cr> instead of <lf> at EOL" \
+
+#define nmeter_example_usage \
+ "nmeter '%250d%t %20c int %i bio %b mem %m forks%p'"
+
+#define nohup_trivial_usage \
+ "COMMAND [ARGS]"
+#define nohup_full_usage "\n\n" \
+ "Run a command immune to hangups, with output to a non-tty"
+#define nohup_example_usage \
+ "$ nohup make &"
+
+#define nslookup_trivial_usage \
+ "[HOST] [SERVER]"
+#define nslookup_full_usage "\n\n" \
+ "Query the nameserver for the IP address of the given HOST\n" \
+ "optionally using a specified DNS server"
+#define nslookup_example_usage \
+ "$ nslookup localhost\n" \
+ "Server: default\n" \
+ "Address: default\n" \
+ "\n" \
+ "Name: debian\n" \
+ "Address: 127.0.0.1\n"
+
+#define od_trivial_usage \
+ "[-aBbcDdeFfHhIiLlOovXx] " USE_DESKTOP("[-t TYPE] ") "[FILE]"
+#define od_full_usage "\n\n" \
+ "Write an unambiguous representation, octal bytes by default, of FILE\n" \
+ "to standard output. With no FILE or when FILE is -, read standard input."
+
+#define openvt_trivial_usage \
+ "[-c NUM] [-sw] [COMMAND [ARGS]]"
+#define openvt_full_usage "\n\n" \
+ "Start COMMAND on a new virtual terminal\n" \
+ "\nOptions:" \
+ "\n -c Use specified VT" \
+ "\n -s Switch to the VT" \
+/* "\n -l Run COMMAND as login shell (by prepending '-')" */ \
+ "\n -w Wait for COMMAND to exit" \
+
+#define openvt_example_usage \
+ "openvt 2 /bin/ash\n"
+
+#define passwd_trivial_usage \
+ "[OPTION] [name]"
+#define passwd_full_usage "\n\n" \
+ "Change user's password. If no name is specified,\n" \
+ "changes the password for the current user.\n" \
+ "\nOptions:" \
+ "\n -a Algorithm to use for password (choices: des, md5)" /* ", sha1)" */ \
+ "\n -d Delete password for the account" \
+ "\n -l Lock (disable) account" \
+ "\n -u Unlock (re-enable) account" \
+
+#define chpasswd_trivial_usage \
+ USE_GETOPT_LONG("[--md5|--encrypt]") SKIP_GETOPT_LONG("[-m|-e]")
+#define chpasswd_full_usage "\n\n" \
+ "Read user:password information from stdin\n" \
+ "and update /etc/passwd accordingly.\n" \
+ "\nOptions:" \
+ USE_GETOPT_LONG( \
+ "\n -e,--encrypt Supplied passwords are in encrypted form" \
+ "\n -m,--md5 Use MD5 encryption instead of DES" \
+ ) \
+ SKIP_GETOPT_LONG( \
+ "\n -e Supplied passwords are in encrypted form" \
+ "\n -m Use MD5 encryption instead of DES" \
+ )
+
+#define patch_trivial_usage \
+ "[-p NUM] [-i DIFF] [-R]"
+#define patch_full_usage "\n\n" \
+ " -p NUM Strip NUM leading components from file names" \
+ "\n -i DIFF Read DIFF instead of stdin" \
+ "\n -R Reverse patch" \
+
+#define patch_example_usage \
+ "$ patch -p1 < example.diff\n" \
+ "$ patch -p0 -i example.diff"
+
+#define pgrep_trivial_usage \
+ "[-flnovx] pattern"
+#define pgrep_full_usage "\n\n" \
+ "Display process(es) selected by regex pattern\n" \
+ "\nOptions:" \
+ "\n -l Show command name too" \
+ "\n -f Match against entire command line" \
+ "\n -n Show the newest process only" \
+ "\n -o Show the oldest process only" \
+ "\n -v Negate the matching" \
+ "\n -x Match whole name (not substring)" \
+
+#if (ENABLE_FEATURE_PIDOF_SINGLE || ENABLE_FEATURE_PIDOF_OMIT)
+#define pidof_trivial_usage \
+ "[OPTION] [NAME...]"
+#define USAGE_PIDOF "\n\nOptions:"
+#else
+#define pidof_trivial_usage \
+ "[NAME...]"
+#define USAGE_PIDOF /* none */
+#endif
+#define pidof_full_usage "\n\n" \
+ "List PIDs of all processes with names that match NAMEs" \
+ USAGE_PIDOF \
+ USE_FEATURE_PIDOF_SINGLE( \
+ "\n -s Show only one PID") \
+ USE_FEATURE_PIDOF_OMIT( \
+ "\n -o PID Omit given pid" \
+ "\n Use %PPID to omit pid of pidof's parent") \
+
+#define pidof_example_usage \
+ "$ pidof init\n" \
+ "1\n" \
+ USE_FEATURE_PIDOF_OMIT( \
+ "$ pidof /bin/sh\n20351 5973 5950\n") \
+ USE_FEATURE_PIDOF_OMIT( \
+ "$ pidof /bin/sh -o %PPID\n20351 5950")
+
+#if !ENABLE_FEATURE_FANCY_PING
+#define ping_trivial_usage \
+ "host"
+#define ping_full_usage "\n\n" \
+ "Send ICMP ECHO_REQUEST packets to network hosts"
+#define ping6_trivial_usage \
+ "host"
+#define ping6_full_usage "\n\n" \
+ "Send ICMP ECHO_REQUEST packets to network hosts"
+#else
+#define ping_trivial_usage \
+ "[OPTION]... host"
+#define ping_full_usage "\n\n" \
+ "Send ICMP ECHO_REQUEST packets to network hosts\n" \
+ "\nOptions:" \
+ "\n -4, -6 Force IPv4 or IPv6 hostname resolution" \
+ "\n -c CNT Send only CNT pings" \
+ "\n -s SIZE Send SIZE data bytes in packets (default=56)" \
+ "\n -I iface/IP Use interface or IP address as source" \
+ "\n -W timeout Seconds to wait for the first response (default:10)" \
+ "\n (after all -c CNT packets are sent)" \
+ "\n -w deadline Seconds until ping exits (default:infinite)" \
+ "\n (can exit earlier with -c CNT)" \
+ "\n -q Quiet, only displays output at start" \
+ "\n and when finished" \
+
+#define ping6_trivial_usage \
+ "[OPTION]... host"
+#define ping6_full_usage "\n\n" \
+ "Send ICMP ECHO_REQUEST packets to network hosts\n" \
+ "\nOptions:" \
+ "\n -c CNT Send only CNT pings" \
+ "\n -s SIZE Send SIZE data bytes in packets (default=56)" \
+ "\n -I iface/IP Use interface or IP address as source" \
+ "\n -q Quiet, only displays output at start" \
+ "\n and when finished" \
+
+#endif
+#define ping_example_usage \
+ "$ ping localhost\n" \
+ "PING slag (127.0.0.1): 56 data bytes\n" \
+ "64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=20.1 ms\n" \
+ "\n" \
+ "--- debian ping statistics ---\n" \
+ "1 packets transmitted, 1 packets received, 0% packet loss\n" \
+ "round-trip min/avg/max = 20.1/20.1/20.1 ms\n"
+#define ping6_example_usage \
+ "$ ping6 ip6-localhost\n" \
+ "PING ip6-localhost (::1): 56 data bytes\n" \
+ "64 bytes from ::1: icmp6_seq=0 ttl=64 time=20.1 ms\n" \
+ "\n" \
+ "--- ip6-localhost ping statistics ---\n" \
+ "1 packets transmitted, 1 packets received, 0% packet loss\n" \
+ "round-trip min/avg/max = 20.1/20.1/20.1 ms\n"
+
+#define pipe_progress_trivial_usage NOUSAGE_STR
+#define pipe_progress_full_usage ""
+
+#define pivot_root_trivial_usage \
+ "NEW_ROOT PUT_OLD"
+#define pivot_root_full_usage "\n\n" \
+ "Move the current root file system to PUT_OLD and make NEW_ROOT\n" \
+ "the new root file system"
+
+#define pkill_trivial_usage \
+ "[-l] | [-fnovx] [-signal] pattern"
+#define pkill_full_usage "\n\n" \
+ "Send a signal to process(es) selected by regex pattern\n" \
+ "\nOptions:" \
+ "\n -l List all signals" \
+ "\n -f Match against entire command line" \
+ "\n -n Signal the newest process only" \
+ "\n -o Signal the oldest process only" \
+ "\n -v Negate the matching" \
+ "\n -x Match whole name (not substring)" \
+
+#define poweroff_trivial_usage \
+ "[-d delay] [-n] [-f]"
+#define poweroff_full_usage "\n\n" \
+ "Halt and shut off power\n" \
+ "\nOptions:" \
+ "\n -d Delay interval for halting" \
+ "\n -n No call to sync()" \
+ "\n -f Force power off (don't go through init)" \
+
+#define printenv_trivial_usage \
+ "[VARIABLES...]"
+#define printenv_full_usage "\n\n" \
+ "Print all or part of environment.\n" \
+ "If no environment VARIABLE specified, print them all."
+
+#define printf_trivial_usage \
+ "FORMAT [ARGUMENT...]"
+#define printf_full_usage "\n\n" \
+ "Format and print ARGUMENT(s) according to FORMAT,\n" \
+ "where FORMAT controls the output exactly as in C printf"
+#define printf_example_usage \
+ "$ printf \"Val=%d\\n\" 5\n" \
+ "Val=5\n"
+
+
+#if ENABLE_DESKTOP
+
+#define ps_trivial_usage \
+ ""
+#define ps_full_usage "\n\n" \
+ "Report process status\n" \
+ "\nOptions:" \
+ "\n -o col1,col2=header Select columns for display" \
+
+#else /* !ENABLE_DESKTOP */
+
+#if !ENABLE_SELINUX && !ENABLE_FEATURE_PS_WIDE
+#define USAGE_PS "\nThis version of ps accepts no options"
+#else
+#define USAGE_PS "\nOptions:"
+#endif
+
+#define ps_trivial_usage \
+ ""
+#define ps_full_usage "\n\n" \
+ "Report process status\n" \
+ USAGE_PS \
+ USE_SELINUX( \
+ "\n -Z Show SE Linux context" \
+ ) \
+ USE_FEATURE_PS_WIDE( \
+ "\n w Wide output" \
+ )
+
+#endif /* ENABLE_DESKTOP */
+
+#define ps_example_usage \
+ "$ ps\n" \
+ " PID Uid Gid State Command\n" \
+ " 1 root root S init\n" \
+ " 2 root root S [kflushd]\n" \
+ " 3 root root S [kupdate]\n" \
+ " 4 root root S [kpiod]\n" \
+ " 5 root root S [kswapd]\n" \
+ " 742 andersen andersen S [bash]\n" \
+ " 743 andersen andersen S -bash\n" \
+ " 745 root root S [getty]\n" \
+ " 2990 andersen andersen R ps\n"
+
+#define pscan_trivial_usage \
+ "[-cb] [-p MIN_PORT] [-P MAX_PORT] [-t TIMEOUT] [-T MIN_RTT] HOST"
+#define pscan_full_usage "\n\n" \
+ "Scan a host, print all open ports\n" \
+ "\nOptions:" \
+ "\n -c Show closed ports too" \
+ "\n -b Show blocked ports too" \
+ "\n -p Scan from this port (default 1)" \
+ "\n -P Scan up to this port (default 1024)" \
+ "\n -t Timeout (default 5000 ms)" \
+ "\n -T Minimum rtt (default 5 ms, increase for congested hosts)" \
+
+#define pwd_trivial_usage \
+ ""
+#define pwd_full_usage "\n\n" \
+ "Print the full filename of the current working directory"
+#define pwd_example_usage \
+ "$ pwd\n" \
+ "/root\n"
+
+#define raidautorun_trivial_usage \
+ "DEVICE"
+#define raidautorun_full_usage "\n\n" \
+ "Tell the kernel to automatically search and start RAID arrays"
+#define raidautorun_example_usage \
+ "$ raidautorun /dev/md0"
+
+#define rdate_trivial_usage \
+ "[-sp] HOST"
+#define rdate_full_usage "\n\n" \
+ "Get and possibly set the system date and time from a remote HOST\n" \
+ "\nOptions:" \
+ "\n -s Set the system date and time (default)" \
+ "\n -p Print the date and time" \
+
+#define readahead_trivial_usage \
+ "[FILE]..."
+#define readahead_full_usage "\n\n" \
+ "Preload FILE(s) in RAM cache so that subsequent reads for those" \
+ "files do not block on disk I/O"
+
+#define readlink_trivial_usage \
+ USE_FEATURE_READLINK_FOLLOW("[-f] ") "FILE"
+#define readlink_full_usage "\n\n" \
+ "Display the value of a symlink" \
+ USE_FEATURE_READLINK_FOLLOW( "\n" \
+ "\nOptions:" \
+ "\n -f Canonicalize by following all symlinks") \
+
+#define readprofile_trivial_usage \
+ "[OPTIONS]..."
+#define readprofile_full_usage "\n\n" \
+ "Options:" \
+ "\n -m mapfile (Default: /boot/System.map)" \
+ "\n -p profile (Default: /proc/profile)" \
+ "\n -M mult Set the profiling multiplier to mult" \
+ "\n -i Print only info about the sampling step" \
+ "\n -v Verbose" \
+ "\n -a Print all symbols, even if count is 0" \
+ "\n -b Print individual histogram-bin counts" \
+ "\n -s Print individual counters within functions" \
+ "\n -r Reset all the counters (root only)" \
+ "\n -n Disable byte order auto-detection" \
+
+#define realpath_trivial_usage \
+ "pathname..."
+#define realpath_full_usage "\n\n" \
+ "Return the absolute pathnames of given argument"
+
+#define reboot_trivial_usage \
+ "[-d delay] [-n] [-f]"
+#define reboot_full_usage "\n\n" \
+ "Reboot the system\n" \
+ "\nOptions:" \
+ "\n -d Delay interval for rebooting" \
+ "\n -n No call to sync()" \
+ "\n -f Force reboot (don't go through init)" \
+
+#define renice_trivial_usage \
+ "{{-n INCREMENT} | PRIORITY} [[-p | -g | -u] ID...]"
+#define renice_full_usage "\n\n" \
+ "Change priority of running processes\n" \
+ "\nOptions:" \
+ "\n -n Adjust current nice value (smaller is faster)" \
+ "\n -p Process id(s) (default)" \
+ "\n -g Process group id(s)" \
+ "\n -u Process user name(s) and/or id(s)" \
+
+#define reset_trivial_usage \
+ ""
+#define reset_full_usage "\n\n" \
+ "Reset the screen"
+
+#define resize_trivial_usage \
+ ""
+#define resize_full_usage "\n\n" \
+ "Resize the screen"
+
+#define restorecon_trivial_usage \
+ "[-iFnrRv] [-e excludedir]... [-o filename] [-f filename | pathname]"
+#define restorecon_full_usage "\n\n" \
+ "Reset security contexts of files in pathname\n" \
+ "\n -i Ignore files that do not exist" \
+ "\n -f file File with list of files to process. Use - for stdin" \
+ "\n -e directory Directory to exclude" \
+ "\n -R,-r Recurse directories" \
+ "\n -n Don't change any file labels" \
+ "\n -o file Save list of files with incorrect context" \
+ "\n -v Verbose" \
+ "\n -vv Show changed labels" \
+ "\n -F Force reset of context to match file_context" \
+ "\n for customizable files, or the user section," \
+ "\n if it has changed" \
+
+#define rm_trivial_usage \
+ "[OPTION]... FILE..."
+#define rm_full_usage "\n\n" \
+ "Remove (unlink) the FILE(s). Use '--' to\n" \
+ "indicate that all following arguments are non-options.\n" \
+ "\nOptions:" \
+ "\n -i Always prompt before removing" \
+ "\n -f Never prompt" \
+ "\n -r,-R Remove directories recursively" \
+
+#define rm_example_usage \
+ "$ rm -rf /tmp/foo\n"
+
+#define rmdir_trivial_usage \
+ "[OPTION]... DIRECTORY..."
+#define rmdir_full_usage "\n\n" \
+ "Remove the DIRECTORY, if it is empty"
+#define rmdir_example_usage \
+ "# rmdir /tmp/foo\n"
+
+#define rmmod_trivial_usage \
+ "[OPTION]... [MODULE]..."
+#define rmmod_full_usage "\n\n" \
+ "Unload the specified kernel modules from the kernel\n" \
+ "\nOptions:" \
+ "\n -a Remove all unused modules (recursively)" \
+
+#define rmmod_example_usage \
+ "$ rmmod tulip\n"
+
+#define route_trivial_usage \
+ "[{add|del|delete}]"
+#define route_full_usage "\n\n" \
+ "Edit the kernel's routing tables\n" \
+ "\nOptions:" \
+ "\n -n Don't resolve names" \
+ "\n -e Display other/more information" \
+ "\n -A inet" USE_FEATURE_IPV6("{6}") " Select address family" \
+
+#define rpm_trivial_usage \
+ "-i -q[ildc]p package.rpm"
+#define rpm_full_usage "\n\n" \
+ "Manipulate RPM packages\n" \
+ "\nOptions:" \
+ "\n -i Install package" \
+ "\n -q Query package" \
+ "\n -p Query uninstalled package" \
+ "\n -i Show information" \
+ "\n -l List contents" \
+ "\n -d List documents" \
+ "\n -c List config files" \
+
+#define rpm2cpio_trivial_usage \
+ "package.rpm"
+#define rpm2cpio_full_usage "\n\n" \
+ "Output a cpio archive of the rpm file"
+
+#define rtcwake_trivial_usage \
+ "[-a | -l | -u] [-d DEV] [-m MODE] [-s SECS | -t TIME]"
+#define rtcwake_full_usage "\n\n" \
+ "Enter a system sleep state until specified wakeup time\n" \
+ USE_GETOPT_LONG( \
+ "\n -a,--auto Read clock mode from adjtime" \
+ "\n -l,--local Clock is set to local time" \
+ "\n -u,--utc Clock is set to UTC time" \
+ "\n -d,--device=DEV Specify the RTC device" \
+ "\n -m,--mode=MODE Set the sleep state (default: standby)" \
+ "\n -s,--seconds=SEC Set the timeout in SEC seconds from now" \
+ "\n -t,--time=TIME Set the timeout to TIME seconds from epoch" \
+ ) \
+ SKIP_GETOPT_LONG( \
+ "\n -a Read clock mode from adjtime" \
+ "\n -l Clock is set to local time" \
+ "\n -u Clock is set to UTC time" \
+ "\n -d DEV Specify the RTC device" \
+ "\n -m MODE Set the sleep state (default: standby)" \
+ "\n -s SEC Set the timeout in SEC seconds from now" \
+ "\n -t TIME Set the timeout to TIME seconds from epoch" \
+ )
+
+#define runcon_trivial_usage \
+ "[-c] [-u USER] [-r ROLE] [-t TYPE] [-l RANGE] COMMAND [args]\n" \
+ " runcon CONTEXT COMMAND [args]"
+#define runcon_full_usage "\n\n" \
+ "Run a program in a different security context\n" \
+ "\n CONTEXT Complete security context\n" \
+ USE_GETOPT_LONG( \
+ "\n -c,--compute Compute process transition context before modifying" \
+ "\n -t,--type=TYPE Type (for same role as parent)" \
+ "\n -u,--user=USER User identity" \
+ "\n -r,--role=ROLE Role" \
+ "\n -l,--range=RNG Levelrange" \
+ ) \
+ SKIP_GETOPT_LONG( \
+ "\n -c Compute process transition context before modifying" \
+ "\n -t TYPE Type (for same role as parent)" \
+ "\n -u USER User identity" \
+ "\n -r ROLE Role" \
+ "\n -l RNG Levelrange" \
+ )
+
+#define run_parts_trivial_usage \
+ "[-t] "USE_FEATURE_RUN_PARTS_FANCY("[-l] ")"[-a ARG] [-u MASK] DIRECTORY"
+#define run_parts_full_usage "\n\n" \
+ "Run a bunch of scripts in a directory\n" \
+ "\nOptions:" \
+ "\n -t Print what would be run, but don't actually run anything" \
+ "\n -a ARG Pass ARG as argument for every program" \
+ "\n -u MASK Set the umask to MASK before running every program" \
+ USE_FEATURE_RUN_PARTS_FANCY( \
+ "\n -l Print names of all matching files even if they are not executable" \
+ )
+
+#define run_parts_example_usage \
+ "$ run-parts -a start /etc/init.d\n" \
+ "$ run-parts -a stop=now /etc/init.d\n\n" \
+ "Let's assume you have a script foo/dosomething:\n" \
+ "#!/bin/sh\n" \
+ "for i in $*; do eval $i; done; unset i\n" \
+ "case \"$1\" in\n" \
+ "start*) echo starting something;;\n" \
+ "stop*) set -x; shutdown -h $stop;;\n" \
+ "esac\n\n" \
+ "Running this yields:\n" \
+ "$run-parts -a stop=+4m foo/\n" \
+ "+ shutdown -h +4m"
+
+#define runlevel_trivial_usage \
+ "[utmp]"
+#define runlevel_full_usage "\n\n" \
+ "Find the current and previous system runlevel.\n\n" \
+ "If no utmp file exists or if no runlevel record can be found,\n" \
+ "print \"unknown\""
+#define runlevel_example_usage \
+ "$ runlevel /var/run/utmp\n" \
+ "N 2"
+
+#define runsv_trivial_usage \
+ "dir"
+#define runsv_full_usage "\n\n" \
+ "Start and monitor a service and optionally an appendant log service"
+
+#define runsvdir_trivial_usage \
+ "[-P] dir"
+#define runsvdir_full_usage "\n\n" \
+ "Start a runsv process for each subdirectory"
+
+#define rx_trivial_usage \
+ "FILE"
+#define rx_full_usage "\n\n" \
+ "Receive a file using the xmodem protocol"
+#define rx_example_usage \
+ "$ rx /tmp/foo\n"
+
+#define script_trivial_usage \
+ "[-afq] [-c COMMAND] [OUTFILE]"
+#define script_full_usage "\n\n" \
+ "Options:" \
+ "\n -a Append output" \
+ "\n -c Run COMMAND, not shell" \
+ "\n -f Flush output after each write" \
+ "\n -q Quiet" \
+
+#define sed_trivial_usage \
+ "[-efinr] pattern [files...]"
+#define sed_full_usage "\n\n" \
+ "Options:" \
+ "\n -e script Add the script to the commands to be executed" \
+ "\n -f scriptfile Add scriptfile contents to the" \
+ "\n commands to be executed" \
+ "\n -i Edit files in-place" \
+ "\n -n Suppress automatic printing of pattern space" \
+ "\n -r Use extended regular expression syntax" \
+ "\n" \
+ "\nIf no -e or -f is given, the first non-option argument is taken as the sed" \
+ "\nscript to interpret. All remaining arguments are names of input files; if no" \
+ "\ninput files are specified, then the standard input is read. Source files" \
+ "\nwill not be modified unless -i option is given." \
+
+#define sed_example_usage \
+ "$ echo \"foo\" | sed -e 's/f[a-zA-Z]o/bar/g'\n" \
+ "bar\n"
+
+#define selinuxenabled_trivial_usage NOUSAGE_STR
+#define selinuxenabled_full_usage ""
+
+#define sendmail_trivial_usage \
+ "[-w timeout] [-U user] [-P password] [-X]\n" \
+ "-t to [-t to]... [-n] [-s subject] [-c charset] server[:port] from [body] [attachment ...]"
+#define sendmail_full_usage "\n\n" \
+ "Send an email.\n" \
+ "\nOptions:" \
+ "\n -w timeout Set timeout on network operations" \
+ "\n -U username Authenticate with specified username/password" \
+ "\n -P password" \
+ "\n -t address Recipient(s). May be repeated" \
+ "\n -X Use openssl connection helper for secured servers" \
+ "\n -n Request delivery notification to sender" \
+ "\n -s subject Subject" \
+ "\n -c charset Assumed charset for body and subject [utf-8]" \
+
+#define seq_trivial_usage \
+ "[first [increment]] last"
+#define seq_full_usage "\n\n" \
+ "Print numbers from FIRST to LAST, in steps of INCREMENT.\n" \
+ "FIRST, INCREMENT default to 1" \
+ "\n\nArguments:\n" \
+ " LAST\n" \
+ " FIRST LAST\n" \
+ " FIRST INCREMENT LAST"
+
+#define sestatus_trivial_usage \
+ "[-vb]"
+#define sestatus_full_usage "\n\n" \
+ " -v Verbose" \
+ "\n -b Display current state of booleans" \
+
+#define setconsole_trivial_usage \
+ "[-r" USE_FEATURE_SETCONSOLE_LONG_OPTIONS("|--reset") "] [DEVICE]"
+#define setconsole_full_usage "\n\n" \
+ "Redirect system console output to DEVICE (default: /dev/tty)\n" \
+ "\nOptions:" \
+ "\n -r Reset output to /dev/console" \
+
+#define setenforce_trivial_usage \
+ "[Enforcing | Permissive | 1 | 0]"
+#define setenforce_full_usage ""
+
+#define setfiles_trivial_usage \
+ "[-dnpqsvW] [-e dir]... [-o file] [-r alt_root_path]" \
+ USE_FEATURE_SETFILES_CHECK_OPTION( \
+ " [-c policyfile] spec_file" \
+ ) \
+ " pathname"
+#define setfiles_full_usage "\n\n" \
+ "Reset file contexts under pathname according to spec_file\n" \
+ USE_FEATURE_SETFILES_CHECK_OPTION( \
+ "\n -c file Check the validity of the contexts against the specified binary policy" \
+ ) \
+ "\n -d Show which specification matched each file" \
+ "\n -l Log changes in file labels to syslog" \
+ "\n -n Don't change any file labels" \
+ "\n -q Suppress warnings" \
+ "\n -r dir Use an altenate root path" \
+ "\n -e dir Exclude directory" \
+ "\n -F Force reset of context to match file_context for customizable files" \
+ "\n -o file Save list of files with incorrect context" \
+ "\n -s Take a list of files from standard input (instead of command line)" \
+ "\n -v Show changes in file labels, if type or role are changing" \
+ "\n -vv Show changes in file labels, if type, role, or user are changing" \
+ "\n -W Display warnings about entries that had no matching files" \
+
+#define setkeycodes_trivial_usage \
+ "SCANCODE KEYCODE..."
+#define setkeycodes_full_usage "\n\n" \
+ "Set entries into the kernel's scancode-to-keycode map,\n" \
+ "allowing unusual keyboards to generate usable keycodes.\n\n" \
+ "SCANCODE may be either xx or e0xx (hexadecimal),\n" \
+ "and KEYCODE is given in decimal" \
+
+#define setkeycodes_example_usage \
+ "$ setkeycodes e030 127\n"
+
+#define setlogcons_trivial_usage \
+ "N"
+#define setlogcons_full_usage "\n\n" \
+ "Redirect the kernel output to console N (0 for current)"
+
+#define setsebool_trivial_usage \
+ "boolean value"
+
+#define setsebool_full_usage "\n\n" \
+ "Change boolean setting"
+
+#define setsid_trivial_usage \
+ "PROG [ARG...]"
+#define setsid_full_usage "\n\n" \
+ "Run PROG in a new session. PROG will have no controlling terminal\n" \
+ "and will not be affected by keyboard signals (Ctrl-C etc).\n" \
+ "See setsid(2) for details." \
+
+#define lash_trivial_usage \
+ "[FILE]...\n" \
+ "or: sh -c command [args]..."
+#define lash_full_usage "\n\n" \
+ "lash is deprecated, please use hush"
+
+#define last_trivial_usage \
+ ""USE_FEATURE_LAST_FANCY("[-HW] [-f file]")
+#define last_full_usage "\n\n" \
+ "Show listing of the last users that logged into the system" \
+ USE_FEATURE_LAST_FANCY( "\n" \
+ "\nOptions:" \
+/* "\n -H Show header line" */ \
+ "\n -W Display with no host column truncation" \
+ "\n -f file Read from file instead of /var/log/wtmp" \
+ )
+
+#define sha1sum_trivial_usage \
+ "[OPTION] [FILEs...]" \
+ USE_FEATURE_MD5_SHA1_SUM_CHECK("\n or: sha1sum [OPTION] -c [FILE]")
+#define sha1sum_full_usage "\n\n" \
+ "Print" USE_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA1 checksums." \
+ USE_FEATURE_MD5_SHA1_SUM_CHECK( "\n" \
+ "\nOptions:" \
+ "\n -c Check SHA1 sums against given list" \
+ "\n -s Don't output anything, status code shows success" \
+ "\n -w Warn about improperly formatted SHA1 checksum lines" \
+ )
+
+#define slattach_trivial_usage \
+ "[-cehmLF] [-s speed] [-p protocol] DEVICEs"
+#define slattach_full_usage "\n\n" \
+ "Attach network interface(s) to serial line(s)\n" \
+ "\nOptions:" \
+ "\n -p Set protocol (slip, cslip, slip6, clisp6 or adaptive)" \
+ "\n -s Set line speed" \
+ "\n -e Exit after initializing device" \
+ "\n -h Exit when the carrier is lost" \
+ "\n -c Execute a command when the line is hung up" \
+ "\n -m Do NOT initialize the line in raw 8 bits mode" \
+ "\n -L Enable 3-wire operation" \
+ "\n -F Disable RTS/CTS flow control" \
+
+#define sleep_trivial_usage \
+ USE_FEATURE_FANCY_SLEEP("[") "N" USE_FEATURE_FANCY_SLEEP("]...")
+#define sleep_full_usage "\n\n" \
+ SKIP_FEATURE_FANCY_SLEEP("Pause for N seconds") \
+ USE_FEATURE_FANCY_SLEEP( \
+ "Pause for a time equal to the total of the args given, where each arg can\n" \
+ "have an optional suffix of (s)econds, (m)inutes, (h)ours, or (d)ays")
+#define sleep_example_usage \
+ "$ sleep 2\n" \
+ "[2 second delay results]\n" \
+ USE_FEATURE_FANCY_SLEEP( \
+ "$ sleep 1d 3h 22m 8s\n" \
+ "[98528 second delay results]\n")
+
+#define sort_trivial_usage \
+ "[-nru" \
+ USE_FEATURE_SORT_BIG("gMcszbdfimSTokt] [-o FILE] [-k start[.offset][opts][,end[.offset][opts]] [-t CHAR") \
+ "] [FILE]..."
+#define sort_full_usage "\n\n" \
+ "Sort lines of text\n" \
+ "\nOptions:" \
+ USE_FEATURE_SORT_BIG( \
+ "\n -b Ignore leading blanks" \
+ "\n -c Check whether input is sorted" \
+ "\n -d Dictionary order (blank or alphanumeric only)" \
+ "\n -f Ignore case" \
+ "\n -g General numerical sort" \
+ "\n -i Ignore unprintable characters" \
+ "\n -k Sort key" \
+ "\n -M Sort month" \
+ ) \
+ "\n -n Sort numbers" \
+ USE_FEATURE_SORT_BIG( \
+ "\n -o Output to file" \
+ "\n -k Sort by key" \
+ "\n -t CHAR Key separator" \
+ ) \
+ "\n -r Reverse sort order" \
+ USE_FEATURE_SORT_BIG( \
+ "\n -s Stable (don't sort ties alphabetically)" \
+ ) \
+ "\n -u Suppress duplicate lines" \
+ USE_FEATURE_SORT_BIG( \
+ "\n -z Lines are terminated by NUL, not newline" \
+ "\n -mST Ignored for GNU compatibility") \
+
+#define sort_example_usage \
+ "$ echo -e \"e\\nf\\nb\\nd\\nc\\na\" | sort\n" \
+ "a\n" \
+ "b\n" \
+ "c\n" \
+ "d\n" \
+ "e\n" \
+ "f\n" \
+ USE_FEATURE_SORT_BIG( \
+ "$ echo -e \"c 3\\nb 2\\nd 2\" | $SORT -k 2,2n -k 1,1r\n" \
+ "d 2\n" \
+ "b 2\n" \
+ "c 3\n" \
+ ) \
+ ""
+
+#define split_trivial_usage \
+ "[OPTION] [INPUT [PREFIX]]"
+#define split_full_usage "\n\n" \
+ "Options:" \
+ "\n -b n[k|m] Split by bytes" \
+ "\n -l n Split by lines" \
+ "\n -a n Use n letters as suffix" \
+
+#define split_example_usage \
+ "$ split TODO foo\n" \
+ "$ cat TODO | split -a 2 -l 2 TODO_\n"
+
+#define start_stop_daemon_trivial_usage \
+ "[OPTIONS] [-S|-K] ... [-- arguments...]"
+#define start_stop_daemon_full_usage "\n\n" \
+ "Search for matching processes, and then\n" \
+ "-S: stop all matching processes.\n" \
+ "-K: start a process unless a matching process is found.\n" \
+ USE_GETOPT_LONG( \
+ "\nProcess matching:" \
+ "\n -u,--user USERNAME|UID Match only this user's processes" \
+ "\n -n,--name NAME Match processes with NAME" \
+ "\n in comm field in /proc/PID/stat" \
+ "\n -x,--exec EXECUTABLE Match processes with this command" \
+ "\n in /proc/PID/cmdline" \
+ "\n -p,--pidfile FILE Match a process with PID from the file" \
+ "\n All specified conditions must match" \
+ "\n-K only:" \
+ "\n -x,--exec EXECUTABLE Program to run" \
+ "\n -a,--startas NAME Zeroth argument" \
+ "\n -b,--background Background" \
+ USE_FEATURE_START_STOP_DAEMON_FANCY( \
+ "\n -N,--nicelevel N Change nice level" \
+ ) \
+ "\n -c,--chuid USER[:[GRP]] Change to user/group" \
+ "\n -m,--make-pidfile Write PID to the pidfile specified by -p" \
+ "\n-S only:" \
+ "\n -s,--signal SIG Signal to send" \
+ "\n -t,--test Match only, exit with 0 if a process is found" \
+ "\nOther:" \
+ USE_FEATURE_START_STOP_DAEMON_FANCY( \
+ "\n -o,--oknodo Exit with status 0 if nothing is done" \
+ "\n -q,--quiet Quiet" \
+ ) \
+ "\n -v,--verbose Verbose" \
+ ) \
+ SKIP_GETOPT_LONG( \
+ "\nProcess matching:" \
+ "\n -u USERNAME|UID Match only this user's processes" \
+ "\n -n NAME Match processes with NAME" \
+ "\n in comm field in /proc/PID/stat" \
+ "\n -x EXECUTABLE Match processes with this command" \
+ "\n command in /proc/PID/cmdline" \
+ "\n -p FILE Match a process with PID from the file" \
+ "\n All specified conditions must match" \
+ "\n-K only:" \
+ "\n -x EXECUTABLE Program to run" \
+ "\n -a NAME Zeroth argument" \
+ "\n -b Background" \
+ USE_FEATURE_START_STOP_DAEMON_FANCY( \
+ "\n -N N Change nice level" \
+ ) \
+ "\n -c USER[:[GRP]] Change to user/group" \
+ "\n -m Write PID to the pidfile specified by -p" \
+ "\n-S only:" \
+ "\n -s SIG Signal to send" \
+ "\n -t Match only, exit with 0 if a process is found" \
+ "\nOther:" \
+ USE_FEATURE_START_STOP_DAEMON_FANCY( \
+ "\n -o Exit with status 0 if nothing is done" \
+ "\n -q Quiet" \
+ ) \
+ "\n -v Verbose" \
+ ) \
+
+#define stat_trivial_usage \
+ "[OPTION] FILE..."
+#define stat_full_usage "\n\n" \
+ "Display file (default) or filesystem status\n" \
+ "\nOptions:" \
+ USE_FEATURE_STAT_FORMAT( \
+ "\n -c fmt Use the specified format" \
+ ) \
+ "\n -f Display filesystem status" \
+ "\n -L Dereference links" \
+ "\n -t Display info in terse form" \
+ USE_SELINUX( \
+ "\n -Z Print security context" \
+ ) \
+ USE_FEATURE_STAT_FORMAT( \
+ "\n\nValid format sequences for files:\n" \
+ " %a Access rights in octal\n" \
+ " %A Access rights in human readable form\n" \
+ " %b Number of blocks allocated (see %B)\n" \
+ " %B The size in bytes of each block reported by %b\n" \
+ " %d Device number in decimal\n" \
+ " %D Device number in hex\n" \
+ " %f Raw mode in hex\n" \
+ " %F File type\n" \
+ " %g Group ID of owner\n" \
+ " %G Group name of owner\n" \
+ " %h Number of hard links\n" \
+ " %i Inode number\n" \
+ " %n File name\n" \
+ " %N Quoted file name with dereference if symlink\n" \
+ " %o I/O block size\n" \
+ " %s Total size, in bytes\n" \
+ " %t Major device type in hex\n" \
+ " %T Minor device type in hex\n" \
+ " %u User ID of owner\n" \
+ " %U User name of owner\n" \
+ " %x Time of last access\n" \
+ " %X Time of last access as seconds since Epoch\n" \
+ " %y Time of last modification\n" \
+ " %Y Time of last modification as seconds since Epoch\n" \
+ " %z Time of last change\n" \
+ " %Z Time of last change as seconds since Epoch\n" \
+ "\nValid format sequences for file systems:\n" \
+ " %a Free blocks available to non-superuser\n" \
+ " %b Total data blocks in file system\n" \
+ " %c Total file nodes in file system\n" \
+ " %d Free file nodes in file system\n" \
+ " %f Free blocks in file system\n" \
+ USE_SELINUX( \
+ " %C Security context in SELinux\n" \
+ ) \
+ " %i File System ID in hex\n" \
+ " %l Maximum length of filenames\n" \
+ " %n File name\n" \
+ " %s Block size (for faster transfer)\n" \
+ " %S Fundamental block size (for block counts)\n" \
+ " %t Type in hex\n" \
+ " %T Type in human readable form" \
+ )
+
+#define strings_trivial_usage \
+ "[-afo] [-n length] [file...]"
+#define strings_full_usage "\n\n" \
+ "Display printable strings in a binary file\n" \
+ "\nOptions:" \
+ "\n -a Scan whole file (default)" \
+ "\n -f Precede strings with filenames" \
+ "\n -n N At least N characters form a string (default 4)" \
+ "\n -o Precede strings with decimal offsets" \
+
+#define stty_trivial_usage \
+ "[-a|g] [-F DEVICE] [SETTING]..."
+#define stty_full_usage "\n\n" \
+ "Without arguments, prints baud rate, line discipline,\n" \
+ "and deviations from stty sane\n" \
+ "\nOptions:" \
+ "\n -F DEVICE Open device instead of stdin" \
+ "\n -a Print all current settings in human-readable form" \
+ "\n -g Print in stty-readable form" \
+ "\n [SETTING] See manpage" \
+
+#define su_trivial_usage \
+ "[OPTION]... [-] [username]"
+#define su_full_usage "\n\n" \
+ "Change user id or become root\n" \
+ "\nOptions:" \
+ "\n -p, -m Preserve environment" \
+ "\n -c Command to pass to 'sh -c'" \
+ "\n -s Shell to use instead of default shell" \
+
+#define sulogin_trivial_usage \
+ "[OPTION]... [tty-device]"
+#define sulogin_full_usage "\n\n" \
+ "Single user login\n" \
+ "\nOptions:" \
+ "\n -t Timeout" \
+
+#define sum_trivial_usage \
+ "[rs] [files...]"
+#define sum_full_usage "\n\n" \
+ "Checksum and count the blocks in a file\n" \
+ "\nOptions:" \
+ "\n -r Use BSD sum algorithm (1K blocks)" \
+ "\n -s Use System V sum algorithm (512byte blocks)" \
+
+#define sv_trivial_usage \
+ "[-v] [-w sec] command service..."
+#define sv_full_usage "\n\n" \
+ "Control services monitored by runsv supervisor.\n" \
+ "Commands (only first character is enough):\n" \
+ "\n" \
+ "status: query service status\n" \
+ "up: if service isn't running, start it. If service stops, restart it\n" \
+ "once: like 'up', but if service stops, don't restart it\n" \
+ "down: send TERM and CONT signals. If ./run exits, start ./finish\n" \
+ " if it exists. After it stops, do not restart service\n" \
+ "exit: send TERM and CONT signals to service and log service. If they exit,\n" \
+ " runsv exits too\n" \
+ "pause, cont, hup, alarm, interrupt, quit, 1, 2, term, kill: send\n" \
+ "STOP, CONT, HUP, ALRM, INT, QUIT, USR1, USR2, TERM, KILL signal to service" \
+
+#define svlogd_trivial_usage \
+ "[-ttv] [-r c] [-R abc] [-l len] [-b buflen] dir..."
+#define svlogd_full_usage "\n\n" \
+ "Continuously read log data from standard input, optionally " \
+ "filter log messages, and write the data to one or more automatically " \
+ "rotated logs" \
+
+#define swapoff_trivial_usage \
+ "[-a] [DEVICE]"
+#define swapoff_full_usage "\n\n" \
+ "Stop swapping on DEVICE\n" \
+ "\nOptions:" \
+ "\n -a Stop swapping on all swap devices" \
+
+#define swapon_trivial_usage \
+ "[-a]" USE_FEATURE_SWAPON_PRI(" [-p pri]") " [DEVICE]"
+#define swapon_full_usage "\n\n" \
+ "Start swapping on DEVICE\n" \
+ "\nOptions:" \
+ "\n -a Start swapping on all swap devices" \
+ USE_FEATURE_SWAPON_PRI( \
+ "\n -p pri Set swap device priority" \
+ ) \
+
+#define switch_root_trivial_usage \
+ "[-c /dev/console] NEW_ROOT NEW_INIT [ARGUMENTS_TO_INIT]"
+#define switch_root_full_usage "\n\n" \
+ "Use from PID 1 under initramfs to free initramfs, chroot to NEW_ROOT,\n" \
+ "and exec NEW_INIT\n" \
+ "\nOptions:" \
+ "\n -c Redirect console to device on new root" \
+
+#define sync_trivial_usage \
+ ""
+#define sync_full_usage "\n\n" \
+ "Write all buffered filesystem blocks to disk"
+
+#define sysctl_trivial_usage \
+ "[OPTIONS]... [VALUE]..."
+#define sysctl_full_usage "\n\n" \
+ "Configure kernel parameters at runtime\n" \
+ "\nOptions:" \
+ "\n -n Disable printing of key names" \
+ "\n -e Don't warn about unknown keys" \
+ "\n -w Change sysctl setting" \
+ "\n -p FILE Load sysctl settings from FILE (default /etc/sysctl.conf)" \
+ "\n -a Display all values" \
+ "\n -A Display all values in table form" \
+
+#define sysctl_example_usage \
+ "sysctl [-n] [-e] variable...\n" \
+ "sysctl [-n] [-e] -w variable=value...\n" \
+ "sysctl [-n] [-e] -a\n" \
+ "sysctl [-n] [-e] -p file (default /etc/sysctl.conf)\n" \
+ "sysctl [-n] [-e] -A\n"
+
+#define syslogd_trivial_usage \
+ "[OPTION]..."
+#define syslogd_full_usage "\n\n" \
+ "System logging utility.\n" \
+ "Note that this version of syslogd ignores /etc/syslog.conf.\n" \
+ "\nOptions:" \
+ "\n -n Run in foreground" \
+ "\n -O FILE Log to given file (default=/var/log/messages)" \
+ "\n -l n Set local log level" \
+ "\n -S Smaller logging output" \
+ USE_FEATURE_ROTATE_LOGFILE( \
+ "\n -s SIZE Max size (KB) before rotate (default=200KB, 0=off)" \
+ "\n -b NUM Number of rotated logs to keep (default=1, max=99, 0=purge)") \
+ USE_FEATURE_REMOTE_LOG( \
+ "\n -R HOST[:PORT] Log to IP or hostname on PORT (default PORT=514/UDP)" \
+ "\n -L Log locally and via network (default is network only if -R)") \
+ USE_FEATURE_SYSLOGD_DUP( \
+ "\n -D Drop duplicates") \
+ USE_FEATURE_IPC_SYSLOG( \
+ "\n -C[size(KiB)] Log to shared mem buffer (read it using logread)") \
+ /* NB: -Csize shouldn't have space (because size is optional) */
+/* "\n -m MIN Minutes between MARK lines (default=20, 0=off)" */
+
+#define syslogd_example_usage \
+ "$ syslogd -R masterlog:514\n" \
+ "$ syslogd -R 192.168.1.1:601\n"
+
+#define tac_trivial_usage \
+ "[FILE]..."
+#define tac_full_usage "\n\n" \
+ "Concatenate FILE(s) and print them in reverse"
+
+#define tail_trivial_usage \
+ "[OPTION]... [FILE]..."
+#define tail_full_usage "\n\n" \
+ "Print last 10 lines of each FILE to standard output.\n" \
+ "With more than one FILE, precede each with a header giving the\n" \
+ "file name. With no FILE, or when FILE is -, read standard input.\n" \
+ "\nOptions:" \
+ USE_FEATURE_FANCY_TAIL( \
+ "\n -c N[kbm] Output the last N bytes") \
+ "\n -n N[kbm] Print last N lines instead of last 10" \
+ "\n -f Output data as the file grows" \
+ USE_FEATURE_FANCY_TAIL( \
+ "\n -q Never output headers giving file names" \
+ "\n -s SEC Wait SEC seconds between reads with -f" \
+ "\n -v Always output headers giving file names" \
+ "\n\n" \
+ "If the first character of N (bytes or lines) is a '+', output begins with\n" \
+ "the Nth item from the start of each file, otherwise, print the last N items\n" \
+ "in the file. N bytes may be suffixed by k (x1024), b (x512), or m (1024^2)." ) \
+
+#define tail_example_usage \
+ "$ tail -n 1 /etc/resolv.conf\n" \
+ "nameserver 10.0.0.1\n"
+
+#define tar_trivial_usage \
+ "-[" USE_FEATURE_TAR_CREATE("c") USE_FEATURE_TAR_GZIP("z") \
+ USE_FEATURE_TAR_BZIP2("j") USE_FEATURE_TAR_LZMA("a") \
+ USE_FEATURE_TAR_COMPRESS("Z") "xtvO] " \
+ USE_FEATURE_TAR_FROM("[-X FILE] ") \
+ "[-f TARFILE] [-C DIR] [FILE(s)]..."
+#define tar_full_usage "\n\n" \
+ "Create, extract, or list files from a tar file\n" \
+ "\nOptions:" \
+ USE_FEATURE_TAR_CREATE( \
+ "\n c Create") \
+ "\n x Extract" \
+ "\n t List" \
+ "\nArchive format selection:" \
+ USE_FEATURE_TAR_GZIP( \
+ "\n z Filter the archive through gzip" \
+ ) \
+ USE_FEATURE_TAR_BZIP2( \
+ "\n j Filter the archive through bzip2" \
+ ) \
+ USE_FEATURE_TAR_LZMA( \
+ "\n a Filter the archive through lzma" \
+ ) \
+ USE_FEATURE_TAR_COMPRESS( \
+ "\n Z Filter the archive through compress" \
+ ) \
+ "\nFile selection:" \
+ "\n f Name of TARFILE or \"-\" for stdin" \
+ "\n O Extract to stdout" \
+ USE_FEATURE_TAR_FROM( \
+ "\n exclude File to exclude" \
+ "\n X File with names to exclude" \
+ ) \
+ "\n C Change to directory DIR before operation" \
+ "\n v Verbose" \
+
+#define tar_example_usage \
+ "$ zcat /tmp/tarball.tar.gz | tar -xf -\n" \
+ "$ tar -cf /tmp/tarball.tar /usr/local\n"
+
+#define taskset_trivial_usage \
+ "[-p] [mask] [pid | command [arg]...]"
+#define taskset_full_usage "\n\n" \
+ "Set or get CPU affinity\n" \
+ "\nOptions:" \
+ "\n -p Operate on an existing PID" \
+
+#define taskset_example_usage \
+ "$ taskset 0x7 ./dgemm_test&\n" \
+ "$ taskset -p 0x1 $!\n" \
+ "pid 4790's current affinity mask: 7\n" \
+ "pid 4790's new affinity mask: 1\n" \
+ "$ taskset 0x7 /bin/sh -c './taskset -p 0x1 $$'\n" \
+ "pid 6671's current affinity mask: 1\n" \
+ "pid 6671's new affinity mask: 1\n" \
+ "$ taskset -p 1\n" \
+ "pid 1's current affinity mask: 3\n"
+
+#define tee_trivial_usage \
+ "[OPTION]... [FILE]..."
+#define tee_full_usage "\n\n" \
+ "Copy standard input to each FILE, and also to standard output\n" \
+ "\nOptions:" \
+ "\n -a Append to the given FILEs, do not overwrite" \
+ "\n -i Ignore interrupt signals (SIGINT)" \
+
+#define tee_example_usage \
+ "$ echo \"Hello\" | tee /tmp/foo\n" \
+ "$ cat /tmp/foo\n" \
+ "Hello\n"
+
+#if ENABLE_FEATURE_TELNET_AUTOLOGIN
+#define telnet_trivial_usage \
+ "[-a] [-l USER] HOST [PORT]"
+#define telnet_full_usage "\n\n" \
+ "Connect to telnet server\n" \
+ "\nOptions:" \
+ "\n -a Attempt an automatic login with USER variable" \
+ "\n -l USER Attempt an automatic login with USER argument" \
+
+#else
+#define telnet_trivial_usage \
+ "HOST [PORT]"
+#define telnet_full_usage "\n\n" \
+ "Connect to telnet server"
+#endif
+
+#define telnetd_trivial_usage \
+ "[OPTION]"
+#define telnetd_full_usage "\n\n" \
+ "Handle incoming telnet connections" \
+ SKIP_FEATURE_TELNETD_STANDALONE(" via inetd") "\n" \
+ "\nOptions:" \
+ "\n -l LOGIN Exec LOGIN on connect" \
+ "\n -f issue_file Display issue_file instead of /etc/issue" \
+ "\n -K Close connection as soon as login exits" \
+ "\n (normally wait until all programs close slave pty)" \
+ USE_FEATURE_TELNETD_STANDALONE( \
+ "\n -p PORT Port to listen on" \
+ "\n -b ADDR Address to bind to" \
+ "\n -F Run in foreground" \
+ "\n -i Run as inetd subservice" \
+ )
+
+#define test_trivial_usage \
+ "EXPRESSION\n" \
+ " or [ EXPRESSION ]"
+#define test_full_usage "\n\n" \
+ "Check file types and compares values returning an exit code\n" \
+ "determined by the value of EXPRESSION"
+#define test_example_usage \
+ "$ test 1 -eq 2\n" \
+ "$ echo $?\n" \
+ "1\n" \
+ "$ test 1 -eq 1\n" \
+ "$ echo $?\n" \
+ "0\n" \
+ "$ [ -d /etc ]\n" \
+ "$ echo $?\n" \
+ "0\n" \
+ "$ [ -d /junk ]\n" \
+ "$ echo $?\n" \
+ "1\n"
+
+#define tcpsvd_trivial_usage \
+ "[-hEv] [-c n] [-C n:msg] [-b n] [-u user] [-l name] ip port prog..."
+/* with not-implemented options: */
+/* "[-hpEvv] [-c n] [-C n:msg] [-b n] [-u user] [-l name] [-i dir|-x cdb] [-t sec] ip port prog..." */
+#define tcpsvd_full_usage "\n\n" \
+ "Create TCP socket, bind it to ip:port and listen\n" \
+ "for incoming connection. Run PROG for each connection.\n" \
+ "\nip IP to listen on. '0' = all" \
+ "\nport Port to listen on" \
+ "\nprog [arg] Program to run" \
+ "\n-l name Local hostname (else looks up local hostname in DNS)" \
+ "\n-u user[:group] Change to user/group after bind" \
+ "\n-c n Handle up to n connections simultaneously" \
+ "\n-b n Allow a backlog of approximately n TCP SYNs" \
+ "\n-C n[:msg] Allow only up to n connections from the same IP" \
+ "\n New connections from this IP address are closed" \
+ "\n immediately. 'msg' is written to the peer before close" \
+ "\n-h Look up peer's hostname" \
+ "\n-E Do not set up environment variables" \
+ "\n-v Verbose" \
+
+#define udpsvd_trivial_usage \
+ "[-hEv] [-c n] [-u user] [-l name] ip port prog"
+#define udpsvd_full_usage "\n\n" \
+ "Create UDP socket, bind it to ip:port and wait\n" \
+ "for incoming packets. Run PROG for each packet,\n" \
+ "redirecting all further packets with same peer ip:port to it\n" \
+ "\nip IP to listen on. '0' = all" \
+ "\nport Port to listen on" \
+ "\nprog [arg] Program to run" \
+ "\n-l name Local hostname (else looks up local hostname in DNS)" \
+ "\n-u user[:group] Change to user/group after bind" \
+ "\n-c n Handle up to n connections simultaneously" \
+ "\n-h Look up peer's hostname" \
+ "\n-E Do not set up environment variables" \
+ "\n-v Verbose" \
+
+#define tftp_trivial_usage \
+ "[OPTION]... HOST [PORT]"
+#define tftp_full_usage "\n\n" \
+ "Transfer a file from/to tftp server\n" \
+ "\nOptions:" \
+ "\n -l FILE Local FILE" \
+ "\n -r FILE Remote FILE" \
+ USE_FEATURE_TFTP_GET( \
+ "\n -g Get file" \
+ ) \
+ USE_FEATURE_TFTP_PUT( \
+ "\n -p Put file" \
+ ) \
+ USE_FEATURE_TFTP_BLOCKSIZE( \
+ "\n -b SIZE Transfer blocks of SIZE octets" \
+ )
+
+#define tftpd_trivial_usage \
+ "[-cr] [-u USER] [DIR]"
+#define tftpd_full_usage "\n\n" \
+ "Transfer a file on tftp client's request.\n" \
+ "\nOptions:" \
+ "\n -r Prohibit upload" \
+ "\n -c Allow file creation via upload" \
+ "\n -u Access files as USER" \
+
+#define time_trivial_usage \
+ "[OPTION]... COMMAND [ARGS...]"
+#define time_full_usage "\n\n" \
+ "Run the program COMMAND with arguments ARGS. When COMMAND finishes,\n" \
+ "COMMAND's resource usage information is displayed.\n" \
+ "\nOptions:" \
+ "\n -v Verbose" \
+
+#define top_trivial_usage \
+ "[-b] [-n COUNT] [-d SECONDS]"
+#define top_full_usage "\n\n" \
+ "Provide a view of process activity in real time.\n" \
+ "Read the status of all processes from /proc each SECONDS\n" \
+ "and show the status for however many processes will fit on the screen." \
+
+#define touch_trivial_usage \
+ "[-c] FILE [FILE...]"
+#define touch_full_usage "\n\n" \
+ "Update the last-modified date on the given FILE[s]\n" \
+ "\nOptions:" \
+ "\n -c Do not create any files" \
+
+#define touch_example_usage \
+ "$ ls -l /tmp/foo\n" \
+ "/bin/ls: /tmp/foo: No such file or directory\n" \
+ "$ touch /tmp/foo\n" \
+ "$ ls -l /tmp/foo\n" \
+ "-rw-rw-r-- 1 andersen andersen 0 Apr 15 01:11 /tmp/foo\n"
+
+#define tr_trivial_usage \
+ "[-cds] STRING1 [STRING2]"
+#define tr_full_usage "\n\n" \
+ "Translate, squeeze, and/or delete characters from\n" \
+ "standard input, writing to standard output\n" \
+ "\nOptions:" \
+ "\n -c Take complement of STRING1" \
+ "\n -d Delete input characters coded STRING1" \
+ "\n -s Squeeze multiple output characters of STRING2 into one character" \
+
+#define tr_example_usage \
+ "$ echo \"gdkkn vnqkc\" | tr [a-y] [b-z]\n" \
+ "hello world\n"
+
+#define traceroute_trivial_usage \
+ "[-FIldnrv] [-f 1st_ttl] [-m max_ttl] [-p port#] [-q nqueries]\n" \
+ " [-s src_addr] [-t tos] [-w wait] [-g gateway] [-i iface]\n" \
+ " [-z pausemsecs] HOST [data size]"
+#define traceroute_full_usage "\n\n" \
+ "Trace the route to HOST\n" \
+ "\nOptions:" \
+ "\n -F Set the don't fragment bit" \
+ "\n -I Use ICMP ECHO instead of UDP datagrams" \
+ "\n -l Display the ttl value of the returned packet" \
+ "\n -d Set SO_DEBUG options to socket" \
+ "\n -n Print hop addresses numerically rather than symbolically" \
+ "\n -r Bypass the normal routing tables and send directly to a host" \
+ "\n -v Verbose" \
+ "\n -m max_ttl Max time-to-live (max number of hops)" \
+ "\n -p port# Base UDP port number used in probes" \
+ "\n (default is 33434)" \
+ "\n -q nqueries Number of probes per 'ttl' (default 3)" \
+ "\n -s src_addr IP address to use as the source address" \
+ "\n -t tos Type-of-service in probe packets (default 0)" \
+ "\n -w wait Time in seconds to wait for a response" \
+ "\n (default 3 sec)" \
+ "\n -g Loose source route gateway (8 max)" \
+
+#define true_trivial_usage \
+ ""
+#define true_full_usage "\n\n" \
+ "Return an exit code of TRUE (0)"
+#define true_example_usage \
+ "$ true\n" \
+ "$ echo $?\n" \
+ "0\n"
+
+#define tty_trivial_usage \
+ ""
+#define tty_full_usage "\n\n" \
+ "Print file name of standard input's terminal" \
+ USE_INCLUDE_SUSv2( "\n" \
+ "\nOptions:" \
+ "\n -s Print nothing, only return exit status" \
+ )
+#define tty_example_usage \
+ "$ tty\n" \
+ "/dev/tty2\n"
+
+#define ttysize_trivial_usage \
+ "[w] [h]"
+#define ttysize_full_usage "\n\n" \
+ "Print dimension(s) of standard input's terminal, on error return 80x25"
+
+#define tune2fs_trivial_usage \
+ "[-c max-mounts-count] [-e errors-behavior] [-g group] " \
+ "[-i interval[d|m|w]] [-j] [-J journal-options] [-l] [-s sparse-flag] " \
+ "[-m reserved-blocks-percent] [-o [^]mount-options[,...]] " \
+ "[-r reserved-blocks-count] [-u user] [-C mount-count] " \
+ "[-L volume-label] [-M last-mounted-dir] [-O [^]feature[,...]] " \
+ "[-T last-check-time] [-U UUID] device"
+#define tune2fs_full_usage "\n\n" \
+ "Adjust filesystem options on ext[23] filesystems"
+
+#define udhcpc_trivial_usage \
+ "[-Cfbnqtvo] [-c CID] [-V VCLS] [-H HOSTNAME] [-i INTERFACE]\n" \
+ " [-p pidfile] [-r IP] [-s script] [-O dhcp-option]..." USE_FEATURE_UDHCP_PORT(" [-P N]")
+#define udhcpc_full_usage "\n\n" \
+ USE_GETOPT_LONG( \
+ " -V,--vendorclass=CLASSID Vendor class identifier" \
+ "\n -i,--interface=INTERFACE Interface to use (default eth0)" \
+ "\n -H,-h,--hostname=HOSTNAME Client hostname" \
+ "\n -c,--clientid=CLIENTID Client identifier" \
+ "\n -C,--clientid-none Suppress default client identifier" \
+ "\n -p,--pidfile=file Create pidfile" \
+ "\n -r,--request=IP IP address to request" \
+ "\n -s,--script=file Run file at DHCP events (default "CONFIG_DHCPC_DEFAULT_SCRIPT")" \
+ "\n -t,--retries=N Send up to N request packets" \
+ "\n -T,--timeout=N Try to get a lease for N seconds (default 3)" \
+ "\n -A,--tryagain=N Wait N seconds (default 20) after failure" \
+ "\n -O,--request-option=OPT Request DHCP option OPT (cumulative)" \
+ "\n -o,--no-default-options Do not request any options (unless -O is also given)" \
+ "\n -f,--foreground Run in foreground" \
+ USE_FOR_MMU( \
+ "\n -b,--background Background if lease is not immediately obtained" \
+ ) \
+ "\n -S,--syslog Log to syslog too" \
+ "\n -n,--now Exit with failure if lease is not immediately obtained" \
+ "\n -q,--quit Quit after obtaining lease" \
+ "\n -R,--release Release IP on quit" \
+ USE_FEATURE_UDHCP_PORT( \
+ "\n -P,--client-port N Use port N instead of default 68" \
+ ) \
+ USE_FEATURE_UDHCPC_ARPING( \
+ "\n -a,--arping Use arping to validate offered address" \
+ ) \
+ ) \
+ SKIP_GETOPT_LONG( \
+ " -V CLASSID Vendor class identifier" \
+ "\n -i INTERFACE Interface to use (default: eth0)" \
+ "\n -H,-h HOSTNAME Client hostname" \
+ "\n -c CLIENTID Client identifier" \
+ "\n -C Suppress default client identifier" \
+ "\n -p file Create pidfile" \
+ "\n -r IP IP address to request" \
+ "\n -s file Run file at DHCP events (default "CONFIG_DHCPC_DEFAULT_SCRIPT")" \
+ "\n -t N Send up to N request packets" \
+ "\n -T N Try to get a lease for N seconds (default 3)" \
+ "\n -A N Wait N seconds (default 20) after failure" \
+ "\n -O OPT Request DHCP option OPT (cumulative)" \
+ "\n -o Do not request any options (unless -O is also given)" \
+ "\n -f Run in foreground" \
+ USE_FOR_MMU( \
+ "\n -b Background if lease is not immediately obtained" \
+ ) \
+ "\n -S Log to syslog too" \
+ "\n -n Exit with failure if lease is not immediately obtained" \
+ "\n -q Quit after obtaining lease" \
+ "\n -R Release IP on quit" \
+ USE_FEATURE_UDHCP_PORT( \
+ "\n -P N Use port N instead of default 68" \
+ ) \
+ USE_FEATURE_UDHCPC_ARPING( \
+ "\n -a Use arping to validate offered address" \
+ ) \
+ )
+
+#define udhcpd_trivial_usage \
+ "[-fS]" USE_FEATURE_UDHCP_PORT(" [-P N]") " [configfile]" \
+
+#define udhcpd_full_usage "\n\n" \
+ "DHCP server\n" \
+ "\n -f Run in foreground" \
+ "\n -S Log to syslog too" \
+ USE_FEATURE_UDHCP_PORT( \
+ "\n -P N Use port N instead of default 67" \
+ )
+
+#define umount_trivial_usage \
+ "[flags] FILESYSTEM|DIRECTORY"
+#define umount_full_usage "\n\n" \
+ "Unmount file systems\n" \
+ "\nOptions:" \
+ USE_FEATURE_UMOUNT_ALL( \
+ "\n -a Unmount all file systems" USE_FEATURE_MTAB_SUPPORT(" in /etc/mtab") \
+ ) \
+ USE_FEATURE_MTAB_SUPPORT( \
+ "\n -n Don't erase /etc/mtab entries" \
+ ) \
+ "\n -r Try to remount devices as read-only if mount is busy" \
+ "\n -l Lazy umount (detach filesystem)" \
+ "\n -f Force umount (i.e., unreachable NFS server)" \
+ USE_FEATURE_MOUNT_LOOP( \
+ "\n -d Free loop device if it has been used" \
+ )
+
+#define umount_example_usage \
+ "$ umount /dev/hdc1\n"
+
+#define uname_trivial_usage \
+ "[-amnrspv]"
+#define uname_full_usage "\n\n" \
+ "Print system information.\n" \
+ "\nOptions:" \
+ "\n -a Print all" \
+ "\n -m The machine (hardware) type" \
+ "\n -n Hostname" \
+ "\n -r OS release" \
+ "\n -s OS name (default)" \
+ "\n -p Processor type" \
+ "\n -v OS version" \
+
+#define uname_example_usage \
+ "$ uname -a\n" \
+ "Linux debian 2.4.23 #2 Tue Dec 23 17:09:10 MST 2003 i686 GNU/Linux\n"
+
+#define uncompress_trivial_usage \
+ "[-c] [-f] [name...]"
+#define uncompress_full_usage "\n\n" \
+ "Uncompress .Z file[s]\n" \
+ "\nOptions:" \
+ "\n -c Extract to stdout" \
+ "\n -f Overwrite an existing file" \
+
+#define unexpand_trivial_usage \
+ "[-f][-a][-t NUM] [FILE|-]"
+#define unexpand_full_usage "\n\n" \
+ "Convert spaces to tabs, writing to standard output.\n" \
+ "\nOptions:" \
+ USE_FEATURE_UNEXPAND_LONG_OPTIONS( \
+ "\n -a,--all Convert all blanks" \
+ "\n -f,--first-only Convert only leading blanks" \
+ "\n -t,--tabs=N Tabstops every N chars" \
+ ) \
+ SKIP_FEATURE_UNEXPAND_LONG_OPTIONS( \
+ "\n -a Convert all blanks" \
+ "\n -f Convert only leading blanks" \
+ "\n -t N Tabstops every N chars" \
+ )
+
+#define uniq_trivial_usage \
+ "[-fscduw]... [INPUT [OUTPUT]]"
+#define uniq_full_usage "\n\n" \
+ "Discard duplicate lines\n" \
+ "\nOptions:" \
+ "\n -c Prefix lines by the number of occurrences" \
+ "\n -d Only print duplicate lines" \
+ "\n -u Only print unique lines" \
+ "\n -f N Skip first N fields" \
+ "\n -s N Skip first N chars (after any skipped fields)" \
+ "\n -w N Compare N characters in line" \
+
+#define uniq_example_usage \
+ "$ echo -e \"a\\na\\nb\\nc\\nc\\na\" | sort | uniq\n" \
+ "a\n" \
+ "b\n" \
+ "c\n"
+
+#define unix2dos_trivial_usage \
+ "[option] [FILE]"
+#define unix2dos_full_usage "\n\n" \
+ "Convert FILE from unix to dos format.\n" \
+ "When no file is given, use stdin/stdout.\n" \
+ "\nOptions:" \
+ "\n -u dos2unix" \
+ "\n -d unix2dos" \
+
+#define unzip_trivial_usage \
+ "[-opts[modifiers]] file[.zip] [list] [-x xlist] [-d exdir]"
+#define unzip_full_usage "\n\n" \
+ "Extract files from ZIP archives\n" \
+ "\nOptions:" \
+ "\n -l List archive contents (with -q for short form)" \
+ "\n -n Never overwrite existing files (default)" \
+ "\n -o Overwrite files without prompting" \
+ "\n -p Send output to stdout" \
+ "\n -q Quiet" \
+ "\n -x Exclude these files" \
+ "\n -d Extract files into this directory" \
+
+#define uptime_trivial_usage \
+ ""
+#define uptime_full_usage "\n\n" \
+ "Display the time since the last boot"
+
+#define uptime_example_usage \
+ "$ uptime\n" \
+ " 1:55pm up 2:30, load average: 0.09, 0.04, 0.00\n"
+
+#define usleep_trivial_usage \
+ "N"
+#define usleep_full_usage "\n\n" \
+ "Pause for N microseconds"
+
+#define usleep_example_usage \
+ "$ usleep 1000000\n" \
+ "[pauses for 1 second]\n"
+
+#define uudecode_trivial_usage \
+ "[-o outfile] [infile]"
+#define uudecode_full_usage "\n\n" \
+ "Uudecode a file\n" \
+ "Finds outfile name in uuencoded source unless -o is given"
+
+#define uudecode_example_usage \
+ "$ uudecode -o busybox busybox.uu\n" \
+ "$ ls -l busybox\n" \
+ "-rwxr-xr-x 1 ams ams 245264 Jun 7 21:35 busybox\n"
+
+#define uuencode_trivial_usage \
+ "[-m] [infile] stored_filename"
+#define uuencode_full_usage "\n\n" \
+ "Uuencode a file to stdout\n" \
+ "\nOptions:" \
+ "\n -m Use base64 encoding per RFC1521" \
+
+#define uuencode_example_usage \
+ "$ uuencode busybox busybox\n" \
+ "begin 755 busybox\n" \
+ "<encoded file snipped>\n" \
+ "$ uudecode busybox busybox > busybox.uu\n" \
+ "$\n"
+
+#define vconfig_trivial_usage \
+ "COMMAND [OPTIONS]..."
+#define vconfig_full_usage "\n\n" \
+ "Create and remove virtual ethernet devices\n" \
+ "\nOptions:" \
+ "\n add [interface-name] [vlan_id]" \
+ "\n rem [vlan-name]" \
+ "\n set_flag [interface-name] [flag-num] [0 | 1]" \
+ "\n set_egress_map [vlan-name] [skb_priority] [vlan_qos]" \
+ "\n set_ingress_map [vlan-name] [skb_priority] [vlan_qos]" \
+ "\n set_name_type [name-type]" \
+
+#define vi_trivial_usage \
+ "[OPTION] [FILE]..."
+#define vi_full_usage "\n\n" \
+ "Edit FILE\n" \
+ "\nOptions:" \
+ USE_FEATURE_VI_COLON( \
+ "\n -c Initial command to run ($EXINIT also available)") \
+ USE_FEATURE_VI_READONLY( \
+ "\n -R Read-only - do not write to the file") \
+ "\n -H Short help regarding available features" \
+
+#define vlock_trivial_usage \
+ "[OPTIONS]"
+#define vlock_full_usage "\n\n" \
+ "Lock a virtual terminal. A password is required to unlock.\n" \
+ "\nOptions:" \
+ "\n -a Lock all VTs" \
+
+#define watch_trivial_usage \
+ "[-n seconds] [-t] COMMAND..."
+#define watch_full_usage "\n\n" \
+ "Execute a program periodically\n" \
+ "\nOptions:" \
+ "\n -n Loop period in seconds (default 2)" \
+ "\n -t Don't print header" \
+
+#define watch_example_usage \
+ "$ watch date\n" \
+ "Mon Dec 17 10:31:40 GMT 2000\n" \
+ "Mon Dec 17 10:31:42 GMT 2000\n" \
+ "Mon Dec 17 10:31:44 GMT 2000"
+
+#define watchdog_trivial_usage \
+ "[-t N[ms]] [-F] DEV"
+#define watchdog_full_usage "\n\n" \
+ "Periodically write to watchdog device DEV\n" \
+ "\nOptions:" \
+ "\n -t N Timer period (default 30)" \
+ "\n -F Run in foreground" \
+ "\n" \
+ "\nUse -t 500ms to specify period in milliseconds" \
+
+#define wc_trivial_usage \
+ "[OPTION]... [FILE]..."
+#define wc_full_usage "\n\n" \
+ "Print line, word, and byte counts for each FILE, and a total line if\n" \
+ "more than one FILE is specified. With no FILE, read standard input.\n" \
+ "\nOptions:" \
+ "\n -c Print the byte counts" \
+ "\n -l Print the newline counts" \
+ "\n -L Print the length of the longest line" \
+ "\n -w Print the word counts" \
+
+#define wc_example_usage \
+ "$ wc /etc/passwd\n" \
+ " 31 46 1365 /etc/passwd\n"
+
+#define wget_trivial_usage \
+ USE_GETOPT_LONG( \
+ "[-c|--continue] [-s|--spider] [-q|--quiet] [-O|--output-document file]\n" \
+ " [--header 'header: value'] [-Y|--proxy on/off] [-P DIR]\n" \
+ " [-U|--user-agent agent] url" \
+ ) \
+ SKIP_GETOPT_LONG( \
+ "[-csq] [-O file] [-Y on/off] [-P DIR] [-U agent] url" \
+ )
+#define wget_full_usage "\n\n" \
+ "Retrieve files via HTTP or FTP\n" \
+ "\nOptions:" \
+ "\n -s Spider mode - only check file existence" \
+ "\n -c Continue retrieval of aborted transfer" \
+ "\n -q Quiet" \
+ "\n -P Set directory prefix to DIR" \
+ "\n -O Save to filename ('-' for stdout)" \
+ "\n -U Adjust 'User-Agent' field" \
+ "\n -Y Use proxy ('on' or 'off')" \
+
+#define which_trivial_usage \
+ "[COMMAND...]"
+#define which_full_usage "\n\n" \
+ "Locate a COMMAND"
+#define which_example_usage \
+ "$ which login\n" \
+ "/bin/login\n"
+
+#define who_trivial_usage \
+ "[-a]"
+#define who_full_usage "\n\n" \
+ "Show who is logged on\n" \
+ "\nOptions:" \
+ "\n -a show all" \
+
+#define whoami_trivial_usage \
+ ""
+#define whoami_full_usage "\n\n" \
+ "Print the user name associated with the current effective user id"
+
+#define xargs_trivial_usage \
+ "[OPTIONS] [COMMAND] [ARGS...]"
+#define xargs_full_usage "\n\n" \
+ "Execute COMMAND on every item given by standard input\n" \
+ "\nOptions:" \
+ USE_FEATURE_XARGS_SUPPORT_CONFIRMATION( \
+ "\n -p Prompt the user about whether to run each command") \
+ "\n -r Do not run command for empty read lines" \
+ USE_FEATURE_XARGS_SUPPORT_TERMOPT( \
+ "\n -x Exit if the size is exceeded") \
+ USE_FEATURE_XARGS_SUPPORT_ZERO_TERM( \
+ "\n -0 Input filenames are terminated by a null character") \
+ "\n -t Print the command line on stderr before executing it" \
+
+#define xargs_example_usage \
+ "$ ls | xargs gzip\n" \
+ "$ find . -name '*.c' -print | xargs rm\n"
+
+#define yes_trivial_usage \
+ "[OPTION]... [STRING]..."
+#define yes_full_usage "\n\n" \
+ "Repeatedly output a line with all specified STRING(s), or 'y'"
+
+#define zcat_trivial_usage \
+ "FILE"
+#define zcat_full_usage "\n\n" \
+ "Uncompress to stdout"
+
+#define zcip_trivial_usage \
+ "[OPTIONS] ifname script"
+#define zcip_full_usage "\n\n" \
+ "Manage a ZeroConf IPv4 link-local address\n" \
+ "\nOptions:" \
+ "\n -f Run in foreground" \
+ "\n -q Quit after address (no daemon)" \
+ "\n -r 169.254.x.x Request this address first" \
+ "\n -v Verbose" \
+
+#endif /* __BB_USAGE_H__ */
diff --git a/cleopatre/busybox-1.11.1-spc300/include/volume_id.h b/cleopatre/busybox-1.11.1-spc300/include/volume_id.h
new file mode 100644
index 0000000000..99cb11ff60
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/include/volume_id.h
@@ -0,0 +1,22 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+char *get_devname_from_label(const char *spec);
+char *get_devname_from_uuid(const char *spec);
diff --git a/cleopatre/busybox-1.11.1-spc300/include/xatonum.h b/cleopatre/busybox-1.11.1-spc300/include/xatonum.h
new file mode 100644
index 0000000000..6cf1299b30
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/include/xatonum.h
@@ -0,0 +1,176 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * ascii-to-numbers implementations for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility push(hidden)
+#endif
+
+/* Provides extern declarations of functions */
+#define DECLARE_STR_CONV(type, T, UT) \
+\
+unsigned type xstrto##UT##_range_sfx(const char *str, int b, unsigned type l, unsigned type u, const struct suffix_mult *sfx); \
+unsigned type xstrto##UT##_range(const char *str, int b, unsigned type l, unsigned type u); \
+unsigned type xstrto##UT##_sfx(const char *str, int b, const struct suffix_mult *sfx); \
+unsigned type xstrto##UT(const char *str, int b); \
+unsigned type xato##UT##_range_sfx(const char *str, unsigned type l, unsigned type u, const struct suffix_mult *sfx); \
+unsigned type xato##UT##_range(const char *str, unsigned type l, unsigned type u); \
+unsigned type xato##UT##_sfx(const char *str, const struct suffix_mult *sfx); \
+unsigned type xato##UT(const char *str); \
+type xstrto##T##_range_sfx(const char *str, int b, type l, type u, const struct suffix_mult *sfx); \
+type xstrto##T##_range(const char *str, int b, type l, type u); \
+type xato##T##_range_sfx(const char *str, type l, type u, const struct suffix_mult *sfx); \
+type xato##T##_range(const char *str, type l, type u); \
+type xato##T##_sfx(const char *str, const struct suffix_mult *sfx); \
+type xato##T(const char *str); \
+
+/* Unsigned long long functions always exist */
+DECLARE_STR_CONV(long long, ll, ull)
+
+
+/* Provides inline definitions of functions */
+/* (useful for mapping them to the type of the same width) */
+#define DEFINE_EQUIV_STR_CONV(narrow, N, W, UN, UW) \
+\
+static ALWAYS_INLINE \
+unsigned narrow xstrto##UN##_range_sfx(const char *str, int b, unsigned narrow l, unsigned narrow u, const struct suffix_mult *sfx) \
+{ return xstrto##UW##_range_sfx(str, b, l, u, sfx); } \
+static ALWAYS_INLINE \
+unsigned narrow xstrto##UN##_range(const char *str, int b, unsigned narrow l, unsigned narrow u) \
+{ return xstrto##UW##_range(str, b, l, u); } \
+static ALWAYS_INLINE \
+unsigned narrow xstrto##UN##_sfx(const char *str, int b, const struct suffix_mult *sfx) \
+{ return xstrto##UW##_sfx(str, b, sfx); } \
+static ALWAYS_INLINE \
+unsigned narrow xstrto##UN(const char *str, int b) \
+{ return xstrto##UW(str, b); } \
+static ALWAYS_INLINE \
+unsigned narrow xato##UN##_range_sfx(const char *str, unsigned narrow l, unsigned narrow u, const struct suffix_mult *sfx) \
+{ return xato##UW##_range_sfx(str, l, u, sfx); } \
+static ALWAYS_INLINE \
+unsigned narrow xato##UN##_range(const char *str, unsigned narrow l, unsigned narrow u) \
+{ return xato##UW##_range(str, l, u); } \
+static ALWAYS_INLINE \
+unsigned narrow xato##UN##_sfx(const char *str, const struct suffix_mult *sfx) \
+{ return xato##UW##_sfx(str, sfx); } \
+static ALWAYS_INLINE \
+unsigned narrow xato##UN(const char *str) \
+{ return xato##UW(str); } \
+static ALWAYS_INLINE \
+narrow xstrto##N##_range_sfx(const char *str, int b, narrow l, narrow u, const struct suffix_mult *sfx) \
+{ return xstrto##W##_range_sfx(str, b, l, u, sfx); } \
+static ALWAYS_INLINE \
+narrow xstrto##N##_range(const char *str, int b, narrow l, narrow u) \
+{ return xstrto##W##_range(str, b, l, u); } \
+static ALWAYS_INLINE \
+narrow xato##N##_range_sfx(const char *str, narrow l, narrow u, const struct suffix_mult *sfx) \
+{ return xato##W##_range_sfx(str, l, u, sfx); } \
+static ALWAYS_INLINE \
+narrow xato##N##_range(const char *str, narrow l, narrow u) \
+{ return xato##W##_range(str, l, u); } \
+static ALWAYS_INLINE \
+narrow xato##N##_sfx(const char *str, const struct suffix_mult *sfx) \
+{ return xato##W##_sfx(str, sfx); } \
+static ALWAYS_INLINE \
+narrow xato##N(const char *str) \
+{ return xato##W(str); } \
+
+/* If long == long long, then just map them one-to-one */
+#if ULONG_MAX == ULLONG_MAX
+DEFINE_EQUIV_STR_CONV(long, l, ll, ul, ull)
+#else
+/* Else provide extern defs */
+DECLARE_STR_CONV(long, l, ul)
+#endif
+
+/* Same for int -> [long] long */
+#if UINT_MAX == ULLONG_MAX
+DEFINE_EQUIV_STR_CONV(int, i, ll, u, ull)
+#elif UINT_MAX == ULONG_MAX
+DEFINE_EQUIV_STR_CONV(int, i, l, u, ul)
+#else
+DECLARE_STR_CONV(int, i, u)
+#endif
+
+/* Specialized */
+
+int BUG_xatou32_unimplemented(void);
+static ALWAYS_INLINE uint32_t xatou32(const char *numstr)
+{
+ if (UINT_MAX == 0xffffffff)
+ return xatou(numstr);
+ if (ULONG_MAX == 0xffffffff)
+ return xatoul(numstr);
+ return BUG_xatou32_unimplemented();
+}
+
+/* Non-aborting kind of convertors: bb_strto[u][l]l */
+
+/* On exit: errno = 0 only if there was non-empty, '\0' terminated value
+ * errno = EINVAL if value was not '\0' terminated, but othervise ok
+ * Return value is still valid, caller should just check whether end[0]
+ * is a valid terminating char for particular case. OTOH, if caller
+ * requires '\0' terminated input, [s]he can just check errno == 0.
+ * errno = ERANGE if value had alphanumeric terminating char ("1234abcg").
+ * errno = ERANGE if value is out of range, missing, etc.
+ * errno = ERANGE if value had minus sign for strtouXX (even "-0" is not ok )
+ * return value is all-ones in this case.
+ */
+
+unsigned long long bb_strtoull(const char *arg, char **endp, int base);
+long long bb_strtoll(const char *arg, char **endp, int base);
+
+#if ULONG_MAX == ULLONG_MAX
+static ALWAYS_INLINE
+unsigned long bb_strtoul(const char *arg, char **endp, int base)
+{ return bb_strtoull(arg, endp, base); }
+static ALWAYS_INLINE
+long bb_strtol(const char *arg, char **endp, int base)
+{ return bb_strtoll(arg, endp, base); }
+#else
+unsigned long bb_strtoul(const char *arg, char **endp, int base);
+long bb_strtol(const char *arg, char **endp, int base);
+#endif
+
+#if UINT_MAX == ULLONG_MAX
+static ALWAYS_INLINE
+unsigned bb_strtou(const char *arg, char **endp, int base)
+{ return bb_strtoull(arg, endp, base); }
+static ALWAYS_INLINE
+int bb_strtoi(const char *arg, char **endp, int base)
+{ return bb_strtoll(arg, endp, base); }
+#elif UINT_MAX == ULONG_MAX
+static ALWAYS_INLINE
+unsigned bb_strtou(const char *arg, char **endp, int base)
+{ return bb_strtoul(arg, endp, base); }
+static ALWAYS_INLINE
+int bb_strtoi(const char *arg, char **endp, int base)
+{ return bb_strtol(arg, endp, base); }
+#else
+unsigned bb_strtou(const char *arg, char **endp, int base);
+int bb_strtoi(const char *arg, char **endp, int base);
+#endif
+
+int BUG_bb_strtou32_unimplemented(void);
+static ALWAYS_INLINE
+uint32_t bb_strtou32(const char *arg, char **endp, int base)
+{
+ if (sizeof(uint32_t) == sizeof(unsigned))
+ return bb_strtou(arg, endp, base);
+ if (sizeof(uint32_t) == sizeof(unsigned long))
+ return bb_strtoul(arg, endp, base);
+ return BUG_bb_strtou32_unimplemented();
+}
+
+/* Floating point */
+
+/* double bb_strtod(const char *arg, char **endp); */
+
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility pop
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/include/xregex.h b/cleopatre/busybox-1.11.1-spc300/include/xregex.h
new file mode 100644
index 0000000000..d4bf732797
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/include/xregex.h
@@ -0,0 +1,27 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Busybox xregcomp utility routine. This isn't in libbb.h because the
+ * C library we're linking against may not support regex.h.
+ *
+ * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
+ * Permission has been granted to redistribute this code under the GPL.
+ *
+ * Licensed under GPLv2 or later, see file License in this tarball for details.
+ */
+#ifndef __BB_REGEX__
+#define __BB_REGEX__
+
+#include <regex.h>
+
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility push(hidden)
+#endif
+
+char* regcomp_or_errmsg(regex_t *preg, const char *regex, int cflags);
+void xregcomp(regex_t *preg, const char *regex, int cflags);
+
+#if __GNUC_PREREQ(4,1)
+# pragma GCC visibility pop
+#endif
+
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/init/Config.in b/cleopatre/busybox-1.11.1-spc300/init/Config.in
new file mode 100644
index 0000000000..a1684d45db
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/init/Config.in
@@ -0,0 +1,112 @@
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Init Utilities"
+
+config INIT
+ bool "init"
+ default n
+ select FEATURE_SYSLOG
+ help
+ init is the first program run when the system boots.
+
+config DEBUG_INIT
+ bool "Debugging aid"
+ default n
+ depends on INIT
+ help
+ Turn this on to disable all the dangerous
+ rebooting stuff when debugging.
+
+config FEATURE_USE_INITTAB
+ bool "Support reading an inittab file"
+ default y
+ depends on INIT
+ help
+ Allow init to read an inittab file when the system boot.
+
+config FEATURE_KILL_REMOVED
+ bool "Support killing processes that have been removed from inittab"
+ default y
+ depends on FEATURE_USE_INITTAB
+ help
+ When respawn entries are removed from inittab and a SIGHUP is
+ sent to init, this feature will kill the processes that have
+ been removed.
+
+config FEATURE_KILL_DELAY
+ int "How long to wait between TERM and KILL (0 - send TERM only)" if FEATURE_KILL_REMOVED
+ range 0 1024
+ default 0
+ help
+ With nonzero setting, init sends TERM, forks, child waits N
+ seconds, sends KILL and exits. Setting it too high is unwise
+ (child will hang around for too long and can actually kill
+ wrong process!)
+
+config FEATURE_INIT_SCTTY
+ bool "Run commands with leading dash with controlling tty"
+ default n
+ depends on INIT
+ help
+ If this option is enabled, init will try to give a controlling
+ tty to any command which has leading hyphen (often it's "-/bin/sh").
+ More precisely, init will do "ioctl(STDIN_FILENO, TIOCSCTTY, 0)".
+ If device attached to STDIN_FILENO can be a ctty but is not yet
+ a ctty for other session, it will become this process' ctty.
+ This is not the traditional init behavour, but is often what you want
+ in an embedded system where the console is only accessed during
+ development or for maintenance.
+ NB: using cttyhack applet may work better.
+
+config FEATURE_INIT_SYSLOG
+ bool "Enable init to write to syslog"
+ default n
+ depends on INIT
+
+config FEATURE_EXTRA_QUIET
+ bool "Be _extra_ quiet on boot"
+ default y
+ depends on INIT
+ help
+ Prevent init from logging some messages to the console during boot.
+
+config FEATURE_INIT_COREDUMPS
+ bool "Support dumping core for child processes (debugging only)"
+ default n
+ depends on INIT
+ help
+ If this option is enabled and the file /.init_enable_core
+ exists, then init will call setrlimit() to allow unlimited
+ core file sizes. If this option is disabled, processes
+ will not generate any core files.
+
+
+
+config FEATURE_INITRD
+ bool "Support running init from within an initrd (not initramfs)"
+ default y
+ depends on INIT
+ help
+ Legacy support for running init under the old-style initrd. Allows
+ the name linuxrc to act as init, and it doesn't assume init is PID 1.
+
+ This does not apply to initramfs, which runs /init as PID 1 and
+ requires no special support.
+
+config HALT
+ bool "poweroff, halt, and reboot"
+ default n
+ help
+ Stop all processes and either halt, reboot, or power off the system.
+
+config MESG
+ bool "mesg"
+ default n
+ help
+ Mesg controls access to your terminal by others. It is typically
+ used to allow or disallow other users to write to your terminal
+
+endmenu
diff --git a/cleopatre/busybox-1.11.1-spc300/init/Kbuild b/cleopatre/busybox-1.11.1-spc300/init/Kbuild
new file mode 100644
index 0000000000..c060f3af4a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/init/Kbuild
@@ -0,0 +1,10 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+lib-y:=
+lib-$(CONFIG_HALT) += halt.o
+lib-$(CONFIG_INIT) += init.o
+lib-$(CONFIG_MESG) += mesg.o
diff --git a/cleopatre/busybox-1.11.1-spc300/init/halt.c b/cleopatre/busybox-1.11.1-spc300/init/halt.c
new file mode 100644
index 0000000000..4fac3a86bc
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/init/halt.c
@@ -0,0 +1,90 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Poweroff reboot and halt, oh my.
+ *
+ * Copyright 2006 by Rob Landley <rob@landley.net>
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include <sys/reboot.h>
+
+#if ENABLE_FEATURE_WTMP
+#include <sys/utsname.h>
+#include <utmp.h>
+#endif
+
+int halt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int halt_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ static const int magic[] = {
+#ifdef RB_HALT_SYSTEM
+RB_HALT_SYSTEM,
+#elif defined RB_HALT
+RB_HALT,
+#endif
+#ifdef RB_POWER_OFF
+RB_POWER_OFF,
+#elif defined RB_POWERDOWN
+RB_POWERDOWN,
+#endif
+RB_AUTOBOOT
+ };
+ static const smallint signals[] = { SIGUSR1, SIGUSR2, SIGTERM };
+
+ int delay = 0;
+ int which, flags, rc = 1;
+#if ENABLE_FEATURE_WTMP
+ struct utmp utmp;
+ struct utsname uts;
+#endif
+
+ /* Figure out which applet we're running */
+ for (which = 0; "hpr"[which] != *applet_name; which++)
+ continue;
+
+ /* Parse and handle arguments */
+ opt_complementary = "d+"; /* -d N */
+ flags = getopt32(argv, "d:nfw", &delay);
+
+ sleep(delay);
+
+#if ENABLE_FEATURE_WTMP
+ if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) {
+ close(creat(bb_path_wtmp_file, 0664));
+ }
+ memset(&utmp, 0, sizeof(utmp));
+ utmp.ut_tv.tv_sec = time(NULL);
+ safe_strncpy(utmp.ut_user, "shutdown", UT_NAMESIZE);
+ utmp.ut_type = RUN_LVL;
+ safe_strncpy(utmp.ut_id, "~~", sizeof(utmp.ut_id));
+ safe_strncpy(utmp.ut_line, "~~", UT_LINESIZE);
+ if (uname(&uts) == 0)
+ safe_strncpy(utmp.ut_host, uts.release, sizeof(utmp.ut_host));
+ updwtmp(bb_path_wtmp_file, &utmp);
+#endif /* !ENABLE_FEATURE_WTMP */
+
+ if (flags & 8) /* -w */
+ return 0;
+ if (!(flags & 2)) /* no -n */
+ sync();
+
+ /* Perform action. */
+ if (ENABLE_INIT && !(flags & 4)) {
+ if (ENABLE_FEATURE_INITRD) {
+ pid_t *pidlist = find_pid_by_name("linuxrc");
+ if (pidlist[0] > 0)
+ rc = kill(pidlist[0], signals[which]);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(pidlist);
+ }
+ if (rc)
+ rc = kill(1, signals[which]);
+ } else
+ rc = reboot(magic[which]);
+
+ if (rc)
+ bb_error_msg("no");
+ return rc;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/init/init.c b/cleopatre/busybox-1.11.1-spc300/init/init.c
new file mode 100644
index 0000000000..e3993896dc
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/init/init.c
@@ -0,0 +1,994 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini init implementation for busybox
+ *
+ * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Adjusted by so many folks, it's impossible to keep track.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include <syslog.h>
+#include <paths.h>
+#include <sys/reboot.h>
+
+#define COMMAND_SIZE 256
+#define CONSOLE_NAME_SIZE 32
+#define MAXENV 16 /* Number of env. vars */
+
+/*
+ * When a file named CORE_ENABLE_FLAG_FILE exists, setrlimit is called
+ * before processes are spawned to set core file size as unlimited.
+ * This is for debugging only. Don't use this is production, unless
+ * you want core dumps lying about....
+ */
+#define CORE_ENABLE_FLAG_FILE "/.init_enable_core"
+#include <sys/resource.h>
+
+#define INITTAB "/etc/inittab" /* inittab file location */
+#ifndef INIT_SCRIPT
+#define INIT_SCRIPT "/etc/init.d/rcS" /* Default sysinit script. */
+#endif
+
+/* Allowed init action types */
+#define SYSINIT 0x01
+#define RESPAWN 0x02
+/* like respawn, but wait for <Enter> to be pressed on tty: */
+#define ASKFIRST 0x04
+#define WAIT 0x08
+#define ONCE 0x10
+#define CTRLALTDEL 0x20
+#define SHUTDOWN 0x40
+#define RESTART 0x80
+
+#define STR_SYSINIT "\x01"
+#define STR_RESPAWN "\x02"
+#define STR_ASKFIRST "\x04"
+#define STR_WAIT "\x08"
+#define STR_ONCE "\x10"
+#define STR_CTRLALTDEL "\x20"
+#define STR_SHUTDOWN "\x40"
+#define STR_RESTART "\x80"
+
+/* Set up a linked list of init_actions, to be read from inittab */
+struct init_action {
+ struct init_action *next;
+ pid_t pid;
+ uint8_t action_type;
+ char terminal[CONSOLE_NAME_SIZE];
+ char command[COMMAND_SIZE];
+};
+
+/* Static variables */
+static struct init_action *init_action_list = NULL;
+
+static const char *log_console = VC_5;
+static sig_atomic_t got_cont = 0;
+
+enum {
+ L_LOG = 0x1,
+ L_CONSOLE = 0x2,
+
+#if ENABLE_FEATURE_EXTRA_QUIET
+ MAYBE_CONSOLE = 0x0,
+#else
+ MAYBE_CONSOLE = L_CONSOLE,
+#endif
+
+#ifndef RB_HALT_SYSTEM
+ RB_HALT_SYSTEM = 0xcdef0123, /* FIXME: this overflows enum */
+ RB_ENABLE_CAD = 0x89abcdef,
+ RB_DISABLE_CAD = 0,
+ RB_POWER_OFF = 0x4321fedc,
+ RB_AUTOBOOT = 0x01234567,
+#endif
+};
+
+static const char *const environment[] = {
+ "HOME=/",
+ bb_PATH_root_path,
+ "SHELL=/bin/sh",
+ "USER=root",
+ NULL
+};
+
+/* Function prototypes */
+static void delete_init_action(struct init_action *a);
+static void halt_reboot_pwoff(int sig) ATTRIBUTE_NORETURN;
+
+static void waitfor(pid_t pid)
+{
+ /* waitfor(run(x)): protect against failed fork inside run() */
+ if (pid <= 0)
+ return;
+
+ /* Wait for any child (prevent zombies from exiting orphaned processes)
+ * but exit the loop only when specified one has exited. */
+ while (wait(NULL) != pid)
+ continue;
+}
+
+static void loop_forever(void) ATTRIBUTE_NORETURN;
+static void loop_forever(void)
+{
+ while (1)
+ sleep(1);
+}
+
+/* Print a message to the specified device.
+ * "where" may be bitwise-or'd from L_LOG | L_CONSOLE
+ * NB: careful, we can be called after vfork!
+ */
+#define messageD(...) do { if (ENABLE_DEBUG_INIT) message(__VA_ARGS__); } while (0)
+static void message(int where, const char *fmt, ...)
+ __attribute__ ((format(printf, 2, 3)));
+static void message(int where, const char *fmt, ...)
+{
+ static int log_fd = -1;
+ va_list arguments;
+ int l;
+ char msg[128];
+
+ msg[0] = '\r';
+ va_start(arguments, fmt);
+ vsnprintf(msg + 1, sizeof(msg) - 2, fmt, arguments);
+ va_end(arguments);
+ msg[sizeof(msg) - 2] = '\0';
+ l = strlen(msg);
+
+ if (ENABLE_FEATURE_INIT_SYSLOG) {
+ /* Log the message to syslogd */
+ if (where & L_LOG) {
+ /* don't out "\r" */
+ openlog(applet_name, 0, LOG_DAEMON);
+ syslog(LOG_INFO, "init: %s", msg + 1);
+ closelog();
+ }
+ msg[l++] = '\n';
+ msg[l] = '\0';
+ } else {
+ msg[l++] = '\n';
+ msg[l] = '\0';
+ /* Take full control of the log tty, and never close it.
+ * It's mine, all mine! Muhahahaha! */
+ if (log_fd < 0) {
+ if (!log_console) {
+ log_fd = 2;
+ } else {
+ log_fd = device_open(log_console, O_WRONLY | O_NONBLOCK | O_NOCTTY);
+ if (log_fd < 0) {
+ bb_error_msg("can't log to %s", log_console);
+ where = L_CONSOLE;
+ } else {
+ close_on_exec_on(log_fd);
+ }
+ }
+ }
+ if (where & L_LOG) {
+ full_write(log_fd, msg, l);
+ if (log_fd == 2)
+ return; /* don't print dup messages */
+ }
+ }
+
+ if (where & L_CONSOLE) {
+ /* Send console messages to console so people will see them. */
+ full_write(STDERR_FILENO, msg, l);
+ }
+}
+
+/* From <linux/serial.h> */
+struct serial_struct {
+ int type;
+ int line;
+ unsigned int port;
+ int irq;
+ int flags;
+ int xmit_fifo_size;
+ int custom_divisor;
+ int baud_base;
+ unsigned short close_delay;
+ char io_type;
+ char reserved_char[1];
+ int hub6;
+ unsigned short closing_wait; /* time to wait before closing */
+ unsigned short closing_wait2; /* no longer used... */
+ unsigned char *iomem_base;
+ unsigned short iomem_reg_shift;
+ unsigned int port_high;
+ unsigned long iomap_base; /* cookie passed into ioremap */
+ int reserved[1];
+ /* Paranoia (imagine 64bit kernel overwriting 32bit userspace stack) */
+ uint32_t bbox_reserved[16];
+};
+static void console_init(void)
+{
+ struct serial_struct sr;
+ char *s;
+
+ s = getenv("CONSOLE");
+ if (!s) s = getenv("console");
+ if (s) {
+ int fd = open(s, O_RDWR | O_NONBLOCK | O_NOCTTY);
+ if (fd >= 0) {
+ dup2(fd, 0);
+ dup2(fd, 1);
+ xmove_fd(fd, 2);
+ }
+ messageD(L_LOG, "console='%s'", s);
+ } else {
+ /* Make sure fd 0,1,2 are not closed
+ * (so that they won't be used by future opens) */
+
+ /* bb_sanitize_stdio(); - WRONG.
+ * It fails if "/dev/null" doesnt exist, and for init
+ * this is a real possibility! Open code it instead. */
+
+ int fd = open(bb_dev_null, O_RDWR);
+ if (fd < 0) {
+ /* Give me _ANY_ open descriptor! */
+ fd = xopen("/", O_RDONLY); /* we don't believe this can fail */
+ }
+ while ((unsigned)fd < 2)
+ fd = dup(fd);
+ if (fd > 2)
+ close(fd);
+ }
+
+ s = getenv("TERM");
+ if (ioctl(STDIN_FILENO, TIOCGSERIAL, &sr) == 0) {
+ /* Force the TERM setting to vt102 for serial console
+ * if TERM is set to linux (the default) */
+ if (!s || strcmp(s, "linux") == 0)
+ putenv((char*)"TERM=vt102");
+ if (!ENABLE_FEATURE_INIT_SYSLOG)
+ log_console = NULL;
+ } else if (!s)
+ putenv((char*)"TERM=linux");
+}
+
+/* Set terminal settings to reasonable defaults.
+ * NB: careful, we can be called after vfork! */
+static void set_sane_term(void)
+{
+ struct termios tty;
+
+ tcgetattr(STDIN_FILENO, &tty);
+
+ /* set control chars */
+ tty.c_cc[VINTR] = 3; /* C-c */
+ tty.c_cc[VQUIT] = 28; /* C-\ */
+ tty.c_cc[VERASE] = 127; /* C-? */
+ tty.c_cc[VKILL] = 21; /* C-u */
+ tty.c_cc[VEOF] = 4; /* C-d */
+ tty.c_cc[VSTART] = 17; /* C-q */
+ tty.c_cc[VSTOP] = 19; /* C-s */
+ tty.c_cc[VSUSP] = 26; /* C-z */
+
+ /* use line dicipline 0 */
+ tty.c_line = 0;
+
+ /* Make it be sane */
+ tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD;
+ tty.c_cflag |= CREAD | HUPCL | CLOCAL;
+
+ /* input modes */
+ tty.c_iflag = ICRNL | IXON | IXOFF;
+
+ /* output modes */
+ tty.c_oflag = OPOST | ONLCR;
+
+ /* local modes */
+ tty.c_lflag =
+ ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN;
+
+ tcsetattr(STDIN_FILENO, TCSANOW, &tty);
+}
+
+/* Open the new terminal device.
+ * NB: careful, we can be called after vfork! */
+static void open_stdio_to_tty(const char* tty_name, int exit_on_failure)
+{
+ /* empty tty_name means "use init's tty", else... */
+ if (tty_name[0]) {
+ int fd;
+ close(0);
+ /* fd can be only < 0 or 0: */
+ fd = device_open(tty_name, O_RDWR);
+ if (fd) {
+ message(L_LOG | L_CONSOLE, "Can't open %s: %s",
+ tty_name, strerror(errno));
+ if (exit_on_failure)
+ _exit(EXIT_FAILURE);
+ if (ENABLE_DEBUG_INIT)
+ _exit(2);
+ /* NB: we don't reach this if we were called after vfork.
+ * Thus halt_reboot_pwoff() itself need not be vfork-safe. */
+ halt_reboot_pwoff(SIGUSR1); /* halt the system */
+ }
+ dup2(0, 1);
+ dup2(0, 2);
+ }
+ set_sane_term();
+}
+
+/* Wrapper around exec:
+ * Takes string (max COMMAND_SIZE chars).
+ * If chars like '>' detected, execs '[-]/bin/sh -c "exec ......."'.
+ * Otherwise splits words on whitespace, deals with leading dash,
+ * and uses plain exec().
+ * NB: careful, we can be called after vfork!
+ */
+static void init_exec(const char *command)
+{
+ char *cmd[COMMAND_SIZE / 2];
+ char buf[COMMAND_SIZE + 6]; /* COMMAND_SIZE+strlen("exec ")+1 */
+ int dash = (command[0] == '-' /* maybe? && command[1] == '/' */);
+
+ /* See if any special /bin/sh requiring characters are present */
+ if (strpbrk(command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) {
+ strcpy(buf, "exec ");
+ strcpy(buf + 5, command + dash); /* excluding "-" */
+ /* NB: LIBBB_DEFAULT_LOGIN_SHELL define has leading dash */
+ cmd[0] = (char*)(LIBBB_DEFAULT_LOGIN_SHELL + !dash);
+ cmd[1] = (char*)"-c";
+ cmd[2] = buf;
+ cmd[3] = NULL;
+ } else {
+ /* Convert command (char*) into cmd (char**, one word per string) */
+ char *word, *next;
+ int i = 0;
+ next = strcpy(buf, command); /* including "-" */
+ while ((word = strsep(&next, " \t")) != NULL) {
+ if (*word != '\0') { /* not two spaces/tabs together? */
+ cmd[i] = word;
+ i++;
+ }
+ }
+ cmd[i] = NULL;
+ }
+ /* If we saw leading "-", it is interactive shell.
+ * Try harder to give it a controlling tty.
+ * And skip "-" in actual exec call. */
+ if (dash) {
+ /* _Attempt_ to make stdin a controlling tty. */
+ if (ENABLE_FEATURE_INIT_SCTTY)
+ ioctl(STDIN_FILENO, TIOCSCTTY, 0 /*only try, don't steal*/);
+ }
+ BB_EXECVP(cmd[0] + dash, cmd);
+ message(L_LOG | L_CONSOLE, "Cannot run '%s': %s",
+ cmd[0], strerror(errno));
+ /* returns if execvp fails */
+}
+
+/* Used only by run_actions */
+static pid_t run(const struct init_action *a)
+{
+ pid_t pid;
+ sigset_t nmask, omask;
+
+ /* Block sigchild while forking (why?) */
+ sigemptyset(&nmask);
+ sigaddset(&nmask, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &nmask, &omask);
+ if (BB_MMU && (a->action_type & ASKFIRST))
+ pid = fork();
+ else
+ pid = vfork();
+ sigprocmask(SIG_SETMASK, &omask, NULL);
+
+ if (pid < 0)
+ message(L_LOG | L_CONSOLE, "Can't fork");
+ if (pid)
+ return pid;
+
+ /* Child */
+
+ /* Reset signal handlers that were set by the parent process */
+ bb_signals(0
+ + (1 << SIGUSR1)
+ + (1 << SIGUSR2)
+ + (1 << SIGINT)
+ + (1 << SIGTERM)
+ + (1 << SIGHUP)
+ + (1 << SIGQUIT)
+ + (1 << SIGCONT)
+ + (1 << SIGSTOP)
+ + (1 << SIGTSTP)
+ , SIG_DFL);
+
+ /* Create a new session and make ourself the process
+ * group leader */
+ setsid();
+
+ /* Open the new terminal device */
+ open_stdio_to_tty(a->terminal, 1 /* - exit if open fails */);
+
+// NB: do not enable unless you change vfork to fork above
+#ifdef BUT_RUN_ACTIONS_ALREADY_DOES_WAITING
+ /* If the init Action requires us to wait, then force the
+ * supplied terminal to be the controlling tty. */
+ if (a->action_type & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) {
+ /* Now fork off another process to just hang around */
+ pid = fork();
+ if (pid < 0) {
+ message(L_LOG | L_CONSOLE, "Can't fork");
+ _exit(EXIT_FAILURE);
+ }
+
+ if (pid > 0) {
+ /* Parent - wait till the child is done */
+ bb_signals(0
+ + (1 << SIGINT)
+ + (1 << SIGTSTP)
+ + (1 << SIGQUIT)
+ , SIG_IGN);
+ signal(SIGCHLD, SIG_DFL);
+
+ waitfor(pid);
+ /* See if stealing the controlling tty back is necessary */
+ if (tcgetpgrp(0) != getpid())
+ _exit(EXIT_SUCCESS);
+
+ /* Use a temporary process to steal the controlling tty. */
+ pid = fork();
+ if (pid < 0) {
+ message(L_LOG | L_CONSOLE, "Can't fork");
+ _exit(EXIT_FAILURE);
+ }
+ if (pid == 0) {
+ setsid();
+ ioctl(0, TIOCSCTTY, 1);
+ _exit(EXIT_SUCCESS);
+ }
+ waitfor(pid);
+ _exit(EXIT_SUCCESS);
+ }
+
+ /* Child - fall though to actually execute things */
+ }
+#endif
+
+ /* NB: on NOMMU we can't wait for input in child, so
+ * "askfirst" will work the same as "respawn". */
+ if (BB_MMU && (a->action_type & ASKFIRST)) {
+ static const char press_enter[] ALIGN1 =
+#ifdef CUSTOMIZED_BANNER
+#include CUSTOMIZED_BANNER
+#endif
+ "\nPlease press Enter to activate this console. ";
+ char c;
+ /*
+ * Save memory by not exec-ing anything large (like a shell)
+ * before the user wants it. This is critical if swap is not
+ * enabled and the system has low memory. Generally this will
+ * be run on the second virtual console, and the first will
+ * be allowed to start a shell or whatever an init script
+ * specifies.
+ */
+ messageD(L_LOG, "waiting for enter to start '%s'"
+ "(pid %d, tty '%s')\n",
+ a->command, getpid(), a->terminal);
+ full_write(STDOUT_FILENO, press_enter, sizeof(press_enter) - 1);
+ while (safe_read(STDIN_FILENO, &c, 1) == 1 && c != '\n')
+ continue;
+ }
+
+ if (ENABLE_FEATURE_INIT_COREDUMPS) {
+ struct stat sb;
+ if (stat(CORE_ENABLE_FLAG_FILE, &sb) == 0) {
+ struct rlimit limit;
+ limit.rlim_cur = RLIM_INFINITY;
+ limit.rlim_max = RLIM_INFINITY;
+ setrlimit(RLIMIT_CORE, &limit);
+ }
+ }
+
+ /* Log the process name and args */
+ message(L_LOG, "starting pid %d, tty '%s': '%s'",
+ getpid(), a->terminal, a->command);
+
+ /* Now run it. The new program will take over this PID,
+ * so nothing further in init.c should be run. */
+ init_exec(a->command);
+ /* We're still here? Some error happened. */
+ _exit(-1);
+}
+
+/* Run all commands of a particular type */
+static void run_actions(int action_type)
+{
+ struct init_action *a, *tmp;
+
+ for (a = init_action_list; a; a = tmp) {
+ tmp = a->next;
+ if (a->action_type & action_type) {
+ // Pointless: run() will error out if open of device fails.
+ ///* a->terminal of "" means "init's console" */
+ //if (a->terminal[0] && access(a->terminal, R_OK | W_OK)) {
+ // //message(L_LOG | L_CONSOLE, "Device %s cannot be opened in RW mode", a->terminal /*, strerror(errno)*/);
+ // delete_init_action(a);
+ //} else
+ if (a->action_type & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) {
+ waitfor(run(a));
+ delete_init_action(a);
+ } else if (a->action_type & ONCE) {
+ run(a);
+ delete_init_action(a);
+ } else if (a->action_type & (RESPAWN | ASKFIRST)) {
+ /* Only run stuff with pid==0. If they have
+ * a pid, that means it is still running */
+ if (a->pid == 0) {
+ a->pid = run(a);
+ }
+ }
+ }
+ }
+}
+
+static void init_reboot(unsigned long magic)
+{
+ pid_t pid;
+ /* We have to fork here, since the kernel calls do_exit(EXIT_SUCCESS) in
+ * linux/kernel/sys.c, which can cause the machine to panic when
+ * the init process is killed.... */
+ pid = vfork();
+ if (pid == 0) { /* child */
+ reboot(magic);
+ _exit(EXIT_SUCCESS);
+ }
+ waitfor(pid);
+}
+
+static void kill_all_processes(void)
+{
+ /* run everything to be run at "shutdown". This is done _prior_
+ * to killing everything, in case people wish to use scripts to
+ * shut things down gracefully... */
+ run_actions(SHUTDOWN);
+
+ /* first disable all our signals */
+ sigprocmask_allsigs(SIG_BLOCK);
+
+ message(L_CONSOLE | L_LOG, "The system is going down NOW!");
+
+ /* Allow Ctrl-Alt-Del to reboot system. */
+ init_reboot(RB_ENABLE_CAD);
+
+ /* Send signals to every process _except_ pid 1 */
+ message(L_CONSOLE | L_LOG, "Sending SIG%s to all processes", "TERM");
+ kill(-1, SIGTERM);
+ sync();
+ sleep(1);
+
+ message(L_CONSOLE | L_LOG, "Sending SIG%s to all processes", "KILL");
+ kill(-1, SIGKILL);
+ sync();
+ sleep(1);
+}
+
+static void halt_reboot_pwoff(int sig)
+{
+ const char *m;
+ int rb;
+
+ kill_all_processes();
+
+ m = "halt";
+ rb = RB_HALT_SYSTEM;
+ if (sig == SIGTERM) {
+ m = "reboot";
+ rb = RB_AUTOBOOT;
+ } else if (sig == SIGUSR2) {
+ m = "poweroff";
+ rb = RB_POWER_OFF;
+ }
+ message(L_CONSOLE | L_LOG, "Requesting system %s", m);
+ /* allow time for last message to reach serial console */
+ sleep(2);
+ init_reboot(rb);
+ loop_forever();
+}
+
+/* Handler for QUIT - exec "restart" action,
+ * else (no such action defined) do nothing */
+static void exec_restart_action(int sig ATTRIBUTE_UNUSED)
+{
+ struct init_action *a;
+
+ for (a = init_action_list; a; a = a->next) {
+ if (a->action_type & RESTART) {
+ kill_all_processes();
+
+ /* unblock all signals (blocked in kill_all_processes()) */
+ sigprocmask_allsigs(SIG_UNBLOCK);
+
+ /* Open the new terminal device */
+ open_stdio_to_tty(a->terminal, 0 /* - halt if open fails */);
+
+ messageD(L_CONSOLE | L_LOG, "Trying to re-exec %s", a->command);
+ init_exec(a->command);
+ sleep(2);
+ init_reboot(RB_HALT_SYSTEM);
+ loop_forever();
+ }
+ }
+}
+
+static void ctrlaltdel_signal(int sig ATTRIBUTE_UNUSED)
+{
+ run_actions(CTRLALTDEL);
+}
+
+/* The SIGSTOP & SIGTSTP handler */
+static void stop_handler(int sig ATTRIBUTE_UNUSED)
+{
+ int saved_errno = errno;
+
+ got_cont = 0;
+ while (!got_cont)
+ pause();
+
+ errno = saved_errno;
+}
+
+/* The SIGCONT handler */
+static void cont_handler(int sig ATTRIBUTE_UNUSED)
+{
+ got_cont = 1;
+}
+
+static void new_init_action(uint8_t action_type, const char *command, const char *cons)
+{
+ struct init_action *a, *last;
+
+// Why?
+// if (strcmp(cons, bb_dev_null) == 0 && (action & ASKFIRST))
+// return;
+
+ /* Append to the end of the list */
+ for (a = last = init_action_list; a; a = a->next) {
+ /* don't enter action if it's already in the list,
+ * but do overwrite existing actions */
+ if ((strcmp(a->command, command) == 0)
+ && (strcmp(a->terminal, cons) == 0)
+ ) {
+ a->action_type = action_type;
+ return;
+ }
+ last = a;
+ }
+
+ a = xzalloc(sizeof(*a));
+ if (last) {
+ last->next = a;
+ } else {
+ init_action_list = a;
+ }
+ a->action_type = action_type;
+ safe_strncpy(a->command, command, sizeof(a->command));
+ safe_strncpy(a->terminal, cons, sizeof(a->terminal));
+ messageD(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n",
+ a->command, a->action_type, a->terminal);
+}
+
+static void delete_init_action(struct init_action *action)
+{
+ struct init_action *a, *b = NULL;
+
+ for (a = init_action_list; a; b = a, a = a->next) {
+ if (a == action) {
+ if (b == NULL) {
+ init_action_list = a->next;
+ } else {
+ b->next = a->next;
+ }
+ free(a);
+ break;
+ }
+ }
+}
+
+/* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined,
+ * then parse_inittab() simply adds in some default
+ * actions(i.e., runs INIT_SCRIPT and then starts a pair
+ * of "askfirst" shells). If CONFIG_FEATURE_USE_INITTAB
+ * _is_ defined, but /etc/inittab is missing, this
+ * results in the same set of default behaviors.
+ */
+static void parse_inittab(void)
+{
+ FILE *file;
+ char buf[COMMAND_SIZE];
+
+ if (ENABLE_FEATURE_USE_INITTAB)
+ file = fopen(INITTAB, "r");
+ else
+ file = NULL;
+
+ /* No inittab file -- set up some default behavior */
+ if (file == NULL) {
+ /* Reboot on Ctrl-Alt-Del */
+ new_init_action(CTRLALTDEL, "reboot", "");
+ /* Umount all filesystems on halt/reboot */
+ new_init_action(SHUTDOWN, "umount -a -r", "");
+ /* Swapoff on halt/reboot */
+ if (ENABLE_SWAPONOFF)
+ new_init_action(SHUTDOWN, "swapoff -a", "");
+ /* Prepare to restart init when a QUIT is received */
+ new_init_action(RESTART, "init", "");
+ /* Askfirst shell on tty1-4 */
+ new_init_action(ASKFIRST, bb_default_login_shell, "");
+ new_init_action(ASKFIRST, bb_default_login_shell, VC_2);
+ new_init_action(ASKFIRST, bb_default_login_shell, VC_3);
+ new_init_action(ASKFIRST, bb_default_login_shell, VC_4);
+ /* sysinit */
+ new_init_action(SYSINIT, INIT_SCRIPT, "");
+
+ return;
+ }
+
+ while (fgets(buf, COMMAND_SIZE, file) != NULL) {
+ static const char actions[] =
+ STR_SYSINIT "sysinit\0"
+ STR_RESPAWN "respawn\0"
+ STR_ASKFIRST "askfirst\0"
+ STR_WAIT "wait\0"
+ STR_ONCE "once\0"
+ STR_CTRLALTDEL "ctrlaltdel\0"
+ STR_SHUTDOWN "shutdown\0"
+ STR_RESTART "restart\0"
+ ;
+ char tmpConsole[CONSOLE_NAME_SIZE];
+ char *id, *runlev, *action, *command;
+ const char *a;
+
+ /* Skip leading spaces */
+ id = skip_whitespace(buf);
+ /* Trim the trailing '\n' */
+ *strchrnul(id, '\n') = '\0';
+ /* Skip the line if it is a comment */
+ if (*id == '#' || *id == '\0')
+ continue;
+
+ /* Line is: "id:runlevel_ignored:action:command" */
+ runlev = strchr(id, ':');
+ if (runlev == NULL /*|| runlev[1] == '\0' - not needed */)
+ goto bad_entry;
+ action = strchr(runlev + 1, ':');
+ if (action == NULL /*|| action[1] == '\0' - not needed */)
+ goto bad_entry;
+ command = strchr(action + 1, ':');
+ if (command == NULL || command[1] == '\0')
+ goto bad_entry;
+
+ *command = '\0'; /* action => ":action\0" now */
+ for (a = actions; a[0]; a += strlen(a) + 1) {
+ if (strcmp(a + 1, action + 1) == 0) {
+ *runlev = '\0';
+ if (*id != '\0') {
+ if (strncmp(id, "/dev/", 5) == 0)
+ id += 5;
+ strcpy(tmpConsole, "/dev/");
+ safe_strncpy(tmpConsole + 5, id,
+ sizeof(tmpConsole) - 5);
+ id = tmpConsole;
+ }
+ new_init_action((uint8_t)a[0], command + 1, id);
+ goto next_line;
+ }
+ }
+ *command = ':';
+ /* Choke on an unknown action */
+ bad_entry:
+ message(L_LOG | L_CONSOLE, "Bad inittab entry: %s", id);
+ next_line: ;
+ }
+ fclose(file);
+}
+
+#if ENABLE_FEATURE_USE_INITTAB
+static void reload_signal(int sig ATTRIBUTE_UNUSED)
+{
+ struct init_action *a, *tmp;
+
+ message(L_LOG, "reloading /etc/inittab");
+
+ /* disable old entrys */
+ for (a = init_action_list; a; a = a->next) {
+ a->action_type = ONCE;
+ }
+
+ parse_inittab();
+
+ if (ENABLE_FEATURE_KILL_REMOVED) {
+ /* Be nice and send SIGTERM first */
+ for (a = init_action_list; a; a = a->next) {
+ pid_t pid = a->pid;
+ if ((a->action_type & ONCE) && pid != 0) {
+ kill(pid, SIGTERM);
+ }
+ }
+#if CONFIG_FEATURE_KILL_DELAY
+ /* NB: parent will wait in NOMMU case */
+ if ((BB_MMU ? fork() : vfork()) == 0) { /* child */
+ sleep(CONFIG_FEATURE_KILL_DELAY);
+ for (a = init_action_list; a; a = a->next) {
+ pid_t pid = a->pid;
+ if ((a->action_type & ONCE) && pid != 0) {
+ kill(pid, SIGKILL);
+ }
+ }
+ _exit(EXIT_SUCCESS);
+ }
+#endif
+ }
+
+ /* remove unused entrys */
+ for (a = init_action_list; a; a = tmp) {
+ tmp = a->next;
+ if ((a->action_type & (ONCE | SYSINIT | WAIT)) && a->pid == 0) {
+ delete_init_action(a);
+ }
+ }
+ run_actions(RESPAWN | ASKFIRST);
+}
+#endif
+
+int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int init_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ struct init_action *a;
+ pid_t wpid;
+
+ die_sleep = 30 * 24*60*60; /* if xmalloc will ever die... */
+
+ if (argv[1] && !strcmp(argv[1], "-q")) {
+ return kill(1, SIGHUP);
+ }
+
+ if (!ENABLE_DEBUG_INIT) {
+ /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */
+ if (getpid() != 1
+ && (!ENABLE_FEATURE_INITRD || !strstr(applet_name, "linuxrc"))
+ ) {
+ bb_show_usage();
+ }
+ /* Set up sig handlers -- be sure to
+ * clear all of these in run() */
+ signal(SIGQUIT, exec_restart_action);
+ bb_signals(0
+ + (1 << SIGUSR1) /* halt */
+ + (1 << SIGUSR2) /* poweroff */
+ + (1 << SIGTERM) /* reboot */
+ , halt_reboot_pwoff);
+ signal(SIGINT, ctrlaltdel_signal);
+ signal(SIGCONT, cont_handler);
+ bb_signals(0
+ + (1 << SIGSTOP)
+ + (1 << SIGTSTP)
+ , stop_handler);
+
+ /* Turn off rebooting via CTL-ALT-DEL -- we get a
+ * SIGINT on CAD so we can shut things down gracefully... */
+ init_reboot(RB_DISABLE_CAD);
+ }
+
+ /* Figure out where the default console should be */
+ console_init();
+ set_sane_term();
+ chdir("/");
+ setsid();
+ {
+ const char *const *e;
+ /* Make sure environs is set to something sane */
+ for (e = environment; *e; e++)
+ putenv((char *) *e);
+ }
+
+ if (argv[1]) setenv("RUNLEVEL", argv[1], 1);
+
+ /* Hello world */
+ message(MAYBE_CONSOLE | L_LOG, "init started: %s", bb_banner);
+
+ /* Make sure there is enough memory to do something useful. */
+ if (ENABLE_SWAPONOFF) {
+ struct sysinfo info;
+
+ if (!sysinfo(&info) &&
+ (info.mem_unit ? : 1) * (long long)info.totalram < 1024*1024)
+ {
+ message(L_CONSOLE, "Low memory, forcing swapon");
+ /* swapon -a requires /proc typically */
+ new_init_action(SYSINIT, "mount -t proc proc /proc", "");
+ /* Try to turn on swap */
+ new_init_action(SYSINIT, "swapon -a", "");
+ run_actions(SYSINIT); /* wait and removing */
+ }
+ }
+
+ /* Check if we are supposed to be in single user mode */
+ if (argv[1]
+ && (!strcmp(argv[1], "single") || !strcmp(argv[1], "-s") || LONE_CHAR(argv[1], '1'))
+ ) {
+ /* Start a shell on console */
+ new_init_action(RESPAWN, bb_default_login_shell, "");
+ } else {
+ /* Not in single user mode -- see what inittab says */
+
+ /* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined,
+ * then parse_inittab() simply adds in some default
+ * actions(i.e., runs INIT_SCRIPT and then starts a pair
+ * of "askfirst" shells */
+ parse_inittab();
+ }
+
+#if ENABLE_SELINUX
+ if (getenv("SELINUX_INIT") == NULL) {
+ int enforce = 0;
+
+ putenv((char*)"SELINUX_INIT=YES");
+ if (selinux_init_load_policy(&enforce) == 0) {
+ BB_EXECVP(argv[0], argv);
+ } else if (enforce > 0) {
+ /* SELinux in enforcing mode but load_policy failed */
+ message(L_CONSOLE, "Cannot load SELinux Policy. "
+ "Machine is in enforcing mode. Halting now.");
+ exit(EXIT_FAILURE);
+ }
+ }
+#endif /* CONFIG_SELINUX */
+
+ /* Make the command line just say "init" - thats all, nothing else */
+ strncpy(argv[0], "init", strlen(argv[0]));
+ /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */
+ while (*++argv)
+ memset(*argv, 0, strlen(*argv));
+
+ /* Now run everything that needs to be run */
+
+ /* First run the sysinit command */
+ run_actions(SYSINIT);
+
+ /* Next run anything that wants to block */
+ run_actions(WAIT);
+
+ /* Next run anything to be run only once */
+ run_actions(ONCE);
+
+ /* Redefine SIGHUP to reread /etc/inittab */
+#if ENABLE_FEATURE_USE_INITTAB
+ signal(SIGHUP, reload_signal);
+#else
+ signal(SIGHUP, SIG_IGN);
+#endif
+
+ /* Now run the looping stuff for the rest of forever */
+ while (1) {
+ /* run the respawn/askfirst stuff */
+ run_actions(RESPAWN | ASKFIRST);
+
+ /* Don't consume all CPU time -- sleep a bit */
+ sleep(1);
+
+ /* Wait for any child process to exit */
+ wpid = wait(NULL);
+ while (wpid > 0) {
+ /* Find out who died and clean up their corpse */
+ for (a = init_action_list; a; a = a->next) {
+ if (a->pid == wpid) {
+ /* Set the pid to 0 so that the process gets
+ * restarted by run_actions() */
+ a->pid = 0;
+ message(L_LOG, "process '%s' (pid %d) exited. "
+ "Scheduling for restart.",
+ a->command, wpid);
+ }
+ }
+ /* see if anyone else is waiting to be reaped */
+ wpid = wait_any_nohang(NULL);
+ }
+ }
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/init/mesg.c b/cleopatre/busybox-1.11.1-spc300/init/mesg.c
new file mode 100644
index 0000000000..cfb517f60a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/init/mesg.c
@@ -0,0 +1,46 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * mesg implementation for busybox
+ *
+ * Copyright (c) 2002 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+
+#ifdef USE_TTY_GROUP
+#define S_IWGRP_OR_S_IWOTH S_IWGRP
+#else
+#define S_IWGRP_OR_S_IWOTH (S_IWGRP | S_IWOTH)
+#endif
+
+int mesg_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int mesg_main(int argc, char **argv)
+{
+ struct stat sb;
+ const char *tty;
+ char c = 0;
+
+ if (--argc == 0
+ || (argc == 1 && ((c = **++argv) == 'y' || c == 'n'))
+ ) {
+ tty = ttyname(STDERR_FILENO);
+ if (tty == NULL) {
+ tty = "ttyname";
+ } else if (stat(tty, &sb) == 0) {
+ mode_t m;
+ if (argc == 0) {
+ puts((sb.st_mode & (S_IWGRP|S_IWOTH)) ? "is y" : "is n");
+ return EXIT_SUCCESS;
+ }
+ m = (c == 'y') ? sb.st_mode | S_IWGRP_OR_S_IWOTH
+ : sb.st_mode & ~(S_IWGRP|S_IWOTH);
+ if (chmod(tty, m) == 0) {
+ return EXIT_SUCCESS;
+ }
+ }
+ bb_simple_perror_msg_and_die(tty);
+ }
+ bb_show_usage();
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/Config.in b/cleopatre/busybox-1.11.1-spc300/libbb/Config.in
new file mode 100644
index 0000000000..5bf0d2ea22
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/Config.in
@@ -0,0 +1,154 @@
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Busybox Library Tuning"
+
+config PASSWORD_MINLEN
+ int "Minimum password length"
+ default 6
+ range 5 32
+ help
+ Minimum allowable password length.
+
+config MD5_SIZE_VS_SPEED
+ int "MD5: Trade Bytes for Speed"
+ default 2
+ range 0 3
+ help
+ Trade binary size versus speed for the md5sum algorithm.
+ Approximate values running uClibc and hashing
+ linux-2.4.4.tar.bz2 were:
+ user times (sec) text size (386)
+ 0 (fastest) 1.1 6144
+ 1 1.4 5392
+ 2 3.0 5088
+ 3 (smallest) 5.1 4912
+
+config FEATURE_FAST_TOP
+ bool "Faster /proc scanning code (+100 bytes)"
+ default n
+ help
+ This option makes top (and ps) ~20% faster (or 20% less CPU hungry),
+ but code size is slightly bigger.
+
+config FEATURE_ETC_NETWORKS
+ bool "Support for /etc/networks"
+ default n
+ help
+ Enable support for network names in /etc/networks. This is
+ a rarely used feature which allows you to use names
+ instead of IP/mask pairs in route command.
+
+config FEATURE_EDITING
+ bool "Command line editing"
+ default n
+ help
+ Enable line editing (mainly for shell command line).
+
+config FEATURE_EDITING_MAX_LEN
+ int "Maximum length of input"
+ range 128 8192
+ default 1024
+ depends on FEATURE_EDITING
+ help
+ Line editing code uses on-stack buffers for storage.
+ You may want to decrease this parameter if your target machine
+ benefits from smaller stack usage.
+
+config FEATURE_EDITING_VI
+ bool "vi-style line editing commands"
+ default n
+ depends on FEATURE_EDITING
+ help
+ Enable vi-style line editing. In shells, this mode can be
+ turned on and off with "set -o vi" and "set +o vi".
+
+config FEATURE_EDITING_HISTORY
+ int "History size"
+ range 0 99999
+ default 15
+ depends on FEATURE_EDITING
+ help
+ Specify command history size.
+
+config FEATURE_EDITING_SAVEHISTORY
+ bool "History saving"
+ default n
+ depends on ASH && FEATURE_EDITING
+ help
+ Enable history saving in ash shell.
+
+config FEATURE_TAB_COMPLETION
+ bool "Tab completion"
+ default n
+ depends on FEATURE_EDITING
+ help
+ Enable tab completion.
+
+config FEATURE_USERNAME_COMPLETION
+ bool "Username completion"
+ default n
+ depends on FEATURE_TAB_COMPLETION
+ help
+ Enable username completion.
+
+config FEATURE_EDITING_FANCY_PROMPT
+ bool "Fancy shell prompts"
+ default n
+ depends on FEATURE_EDITING
+ help
+ Setting this option allows for prompts to use things like \w and
+ \$ and escape codes.
+
+config FEATURE_VERBOSE_CP_MESSAGE
+ bool "Give more precise messages when copy fails (cp, mv etc)"
+ default n
+ help
+ Error messages with this feature enabled:
+ $ cp file /does_not_exist/file
+ cp: cannot create '/does_not_exist/file': Path does not exist
+ $ cp file /vmlinuz/file
+ cp: cannot stat '/vmlinuz/file': Path has non-directory component
+ If this feature is not enabled, they will be, respectively:
+ cp: cannot remove '/does_not_exist/file': No such file or directory
+ cp: cannot stat '/vmlinuz/file': Not a directory
+ respectively.
+ This will cost you ~60 bytes.
+
+config FEATURE_COPYBUF_KB
+ int "Copy buffer size, in kilobytes"
+ range 1 1024
+ default 4
+ help
+ Size of buffer used by cp, mv, install etc.
+ Buffers which are 4 kb or less will be allocated on stack.
+ Bigger buffers will be allocated with mmap, with fallback to 4 kb
+ stack buffer if mmap fails.
+
+config MONOTONIC_SYSCALL
+ bool "Use clock_gettime(CLOCK_MONOTONIC) syscall"
+ default y
+ help
+ Use clock_gettime(CLOCK_MONOTONIC) syscall for measuring
+ time intervals (time, ping, traceroute etc need this).
+ Probably requires Linux 2.6+. If not selected, gettimeofday
+ will be used instead (which gives wrong results if date/time
+ is reset).
+
+config IOCTL_HEX2STR_ERROR
+ bool "Use ioctl names rather than hex values in error messages"
+ default y
+ help
+ Use ioctl names rather than hex values in error messages
+ (e.g. VT_DISALLOCATE rather than 0x5608). If disabled this
+ saves about 1400 bytes.
+
+config FEATURE_HWIB
+ bool "Support infiniband HW"
+ default y
+ help
+ Support for printing infiniband addresses in
+ network applets.
+endmenu
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/Kbuild b/cleopatre/busybox-1.11.1-spc300/libbb/Kbuild
new file mode 100644
index 0000000000..5cbecd537b
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/Kbuild
@@ -0,0 +1,145 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+lib-y:=
+
+lib-y += appletlib.o
+lib-y += ask_confirmation.o
+lib-y += bb_askpass.o
+lib-y += bb_basename.o
+lib-y += bb_do_delay.o
+lib-y += bb_pwd.o
+lib-y += bb_qsort.o
+lib-y += bb_strtonum.o
+lib-y += change_identity.o
+lib-y += chomp.o
+lib-y += compare_string_array.o
+lib-y += concat_path_file.o
+lib-y += concat_subpath_file.o
+lib-y += copy_file.o
+lib-y += copyfd.o
+lib-y += crc32.o
+lib-y += create_icmp6_socket.o
+lib-y += create_icmp_socket.o
+lib-y += default_error_retval.o
+lib-y += device_open.o
+lib-y += dump.o
+lib-y += error_msg.o
+lib-y += error_msg_and_die.o
+lib-y += execable.o
+lib-y += fclose_nonstdin.o
+lib-y += fflush_stdout_and_exit.o
+lib-y += fgets_str.o
+lib-y += find_pid_by_name.o
+lib-y += find_root_device.o
+lib-y += full_write.o
+lib-y += get_console.o
+lib-y += get_last_path_component.o
+lib-y += get_line_from_file.o
+lib-y += getopt32.o
+lib-y += getpty.o
+lib-y += herror_msg.o
+lib-y += herror_msg_and_die.o
+lib-y += human_readable.o
+lib-y += inet_common.o
+lib-y += info_msg.o
+lib-y += inode_hash.o
+lib-y += isdirectory.o
+lib-y += kernel_version.o
+lib-y += last_char_is.o
+lib-y += lineedit.o lineedit_ptr_hack.o
+lib-y += llist.o
+lib-y += login.o
+lib-y += make_directory.o
+lib-y += makedev.o
+lib-y += match_fstype.o
+lib-y += md5.o
+lib-y += messages.o
+lib-y += mode_string.o
+lib-y += mtab_file.o
+lib-y += obscure.o
+lib-y += parse_mode.o
+lib-y += perror_msg.o
+lib-y += perror_msg_and_die.o
+lib-y += perror_nomsg.o
+lib-y += perror_nomsg_and_die.o
+lib-y += pidfile.o
+lib-y += printable.o
+lib-y += print_flags.o
+lib-y += process_escape_sequence.o
+lib-y += procps.o
+lib-y += ptr_to_globals.o
+lib-y += read.o
+lib-y += recursive_action.o
+lib-y += remove_file.o
+lib-y += restricted_shell.o
+lib-y += run_shell.o
+lib-y += safe_gethostname.o
+lib-y += safe_poll.o
+lib-y += safe_strncpy.o
+lib-y += safe_write.o
+lib-y += setup_environment.o
+lib-y += sha1.o
+lib-y += signals.o
+lib-y += simplify_path.o
+lib-y += skip_whitespace.o
+lib-y += speed_table.o
+lib-y += str_tolower.o
+lib-y += strrstr.o
+lib-y += time.o
+lib-y += trim.o
+lib-y += u_signal_names.o
+lib-y += udp_io.o
+lib-y += uuencode.o
+lib-y += vdprintf.o
+lib-y += verror_msg.o
+lib-y += vfork_daemon_rexec.o
+lib-y += warn_ignoring_args.o
+lib-y += wfopen.o
+lib-y += wfopen_input.o
+lib-y += write.o
+lib-y += xatonum.o
+lib-y += xconnect.o
+lib-y += xfuncs.o
+lib-y += xfuncs_printf.o
+lib-y += xfunc_die.o
+lib-y += xgetcwd.o
+lib-y += xgethostbyname.o
+lib-y += xreadlink.o
+
+# conditionally compiled objects:
+lib-$(CONFIG_FEATURE_MOUNT_LOOP) += loop.o
+lib-$(CONFIG_LOSETUP) += loop.o
+lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o
+lib-$(CONFIG_PASSWD) += pw_encrypt.o crypt_make_salt.o update_passwd.o
+lib-$(CONFIG_CHPASSWD) += pw_encrypt.o crypt_make_salt.o update_passwd.o
+lib-$(CONFIG_CRYPTPW) += pw_encrypt.o crypt_make_salt.o
+lib-$(CONFIG_SULOGIN) += pw_encrypt.o
+lib-$(CONFIG_FEATURE_HTTPD_AUTH_MD5) += pw_encrypt.o
+lib-$(CONFIG_VLOCK) += pw_encrypt.o correct_password.o
+lib-$(CONFIG_SU) += pw_encrypt.o correct_password.o
+lib-$(CONFIG_LOGIN) += pw_encrypt.o correct_password.o
+lib-$(CONFIG_DF) += find_mount_point.o
+lib-$(CONFIG_MKFS_MINIX) += find_mount_point.o
+lib-$(CONFIG_SELINUX) += selinux_common.o
+lib-$(CONFIG_HWCLOCK) += rtc.o
+lib-$(CONFIG_RTCWAKE) += rtc.o
+lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o
+
+# We shouldn't build xregcomp.c if we don't need it - this ensures we don't
+# require regex.h to be in the include dir even if we don't need it thereby
+# allowing us to build busybox even if uclibc regex support is disabled.
+
+lib-$(CONFIG_AWK) += xregcomp.o
+lib-$(CONFIG_SED) += xregcomp.o
+lib-$(CONFIG_GREP) += xregcomp.o
+lib-$(CONFIG_EXPR) += xregcomp.o
+lib-$(CONFIG_MDEV) += xregcomp.o
+lib-$(CONFIG_LESS) += xregcomp.o
+lib-$(CONFIG_PGREP) += xregcomp.o
+lib-$(CONFIG_PKILL) += xregcomp.o
+lib-$(CONFIG_DEVFSD) += xregcomp.o
+lib-$(CONFIG_FEATURE_FIND_REGEX) += xregcomp.o
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/README b/cleopatre/busybox-1.11.1-spc300/libbb/README
new file mode 100644
index 0000000000..4f28f7e34f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/README
@@ -0,0 +1,11 @@
+Please see the LICENSE file for copyright information (GPLv2)
+
+libbb is BusyBox's utility library. All of this stuff used to be stuffed into
+a single file named utility.c. When I split utility.c to create libbb, some of
+the very oldest stuff ended up without their original copyright and licensing
+information (which is now lost in the mists of time). If you see something
+that you wrote that is mis-attributed, do let me know so we can fix that up.
+
+ Erik Andersen
+ <andersen@codepoet.org>
+
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/appletlib.c b/cleopatre/busybox-1.11.1-spc300/libbb/appletlib.c
new file mode 100644
index 0000000000..06a83e58dc
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/appletlib.c
@@ -0,0 +1,773 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) tons of folks. Tracking down who wrote what
+ * isn't something I'm going to worry about... If you wrote something
+ * here, please feel free to acknowledge your work.
+ *
+ * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
+ * Permission has been granted to redistribute this code under the GPL.
+ *
+ * Licensed under GPLv2 or later, see file License in this tarball for details.
+ */
+
+/* We are trying to not use printf, this benefits the case when selected
+ * applets are really simple. Example:
+ *
+ * $ ./busybox
+ * ...
+ * Currently defined functions:
+ * basename, false, true
+ *
+ * $ size busybox
+ * text data bss dec hex filename
+ * 4473 52 72 4597 11f5 busybox
+ *
+ * FEATURE_INSTALLER or FEATURE_SUID will still link printf routines in. :(
+ */
+
+#include <assert.h>
+#include "busybox.h"
+
+
+/* Declare <applet>_main() */
+#define PROTOTYPES
+#include "applets.h"
+#undef PROTOTYPES
+
+#if ENABLE_SHOW_USAGE && !ENABLE_FEATURE_COMPRESS_USAGE
+/* Define usage_messages[] */
+static const char usage_messages[] ALIGN1 = ""
+#define MAKE_USAGE
+#include "usage.h"
+#include "applets.h"
+;
+#undef MAKE_USAGE
+#else
+#define usage_messages 0
+#endif /* SHOW_USAGE */
+
+
+/* Include generated applet names, pointers to <applet>_main, etc */
+#include "applet_tables.h"
+/* ...and if applet_tables generator says we have only one applet... */
+#ifdef SINGLE_APPLET_MAIN
+#undef ENABLE_FEATURE_INDIVIDUAL
+#define ENABLE_FEATURE_INDIVIDUAL 1
+#undef USE_FEATURE_INDIVIDUAL
+#define USE_FEATURE_INDIVIDUAL(...) __VA_ARGS__
+#endif
+
+
+#if ENABLE_FEATURE_COMPRESS_USAGE
+
+#include "usage_compressed.h"
+#include "unarchive.h"
+
+static const char *unpack_usage_messages(void)
+{
+ char *outbuf = NULL;
+ bunzip_data *bd;
+ int i;
+
+ i = start_bunzip(&bd,
+ /* src_fd: */ -1,
+ /* inbuf: */ (void *)packed_usage,
+ /* len: */ sizeof(packed_usage));
+ /* read_bunzip can longjmp to start_bunzip, and ultimately
+ * end up here with i != 0 on read data errors! Not trivial */
+ if (!i) {
+ /* Cannot use xmalloc: will leak bd in NOFORK case! */
+ outbuf = malloc_or_warn(SIZEOF_usage_messages);
+ if (outbuf)
+ read_bunzip(bd, outbuf, SIZEOF_usage_messages);
+ }
+ dealloc_bunzip(bd);
+ return outbuf;
+}
+#define dealloc_usage_messages(s) free(s)
+
+#else
+
+#define unpack_usage_messages() usage_messages
+#define dealloc_usage_messages(s) ((void)(s))
+
+#endif /* FEATURE_COMPRESS_USAGE */
+
+
+static void full_write2_str(const char *str)
+{
+ full_write(STDERR_FILENO, str, strlen(str));
+}
+
+void bb_show_usage(void)
+{
+ if (ENABLE_SHOW_USAGE) {
+#ifdef SINGLE_APPLET_STR
+ /* Imagine that this applet is "true". Dont suck in printf! */
+ const char *p;
+ const char *usage_string = p = unpack_usage_messages();
+
+ if (*p == '\b') {
+ full_write2_str("\nNo help available.\n\n");
+ } else {
+ full_write2_str("\nUsage: "SINGLE_APPLET_STR" ");
+ full_write2_str(p);
+ full_write2_str("\n\n");
+ }
+ dealloc_usage_messages((char*)usage_string);
+#else
+ const char *p;
+ const char *usage_string = p = unpack_usage_messages();
+ int ap = find_applet_by_name(applet_name);
+
+ if (ap < 0) /* never happens, paranoia */
+ xfunc_die();
+ while (ap) {
+ while (*p++) continue;
+ ap--;
+ }
+ full_write2_str(bb_banner);
+ full_write2_str(" multi-call binary\n");
+ if (*p == '\b')
+ full_write2_str("\nNo help available.\n\n");
+ else {
+ full_write2_str("\nUsage: ");
+ full_write2_str(applet_name);
+ full_write2_str(" ");
+ full_write2_str(p);
+ full_write2_str("\n\n");
+ }
+ dealloc_usage_messages((char*)usage_string);
+#endif
+ }
+ xfunc_die();
+}
+
+#if NUM_APPLETS > 8
+/* NB: any char pointer will work as well, not necessarily applet_names */
+static int applet_name_compare(const void *name, const void *v)
+{
+ int i = (const char *)v - applet_names;
+ return strcmp(name, APPLET_NAME(i));
+}
+#endif
+int find_applet_by_name(const char *name)
+{
+#if NUM_APPLETS > 8
+ /* Do a binary search to find the applet entry given the name. */
+ const char *p;
+ p = bsearch(name, applet_names, ARRAY_SIZE(applet_main), 1, applet_name_compare);
+ if (!p)
+ return -1;
+ return p - applet_names;
+#else
+ /* A version which does not pull in bsearch */
+ int i = 0;
+ const char *p = applet_names;
+ while (i < NUM_APPLETS) {
+ if (strcmp(name, p) == 0)
+ return i;
+ p += strlen(p) + 1;
+ i++;
+ }
+ return -1;
+#endif
+}
+
+
+void lbb_prepare(const char *applet
+ USE_FEATURE_INDIVIDUAL(, char **argv))
+ MAIN_EXTERNALLY_VISIBLE;
+void lbb_prepare(const char *applet
+ USE_FEATURE_INDIVIDUAL(, char **argv))
+{
+#ifdef __GLIBC__
+ (*(int **)&bb_errno) = __errno_location();
+ barrier();
+#endif
+ applet_name = applet;
+
+ /* Set locale for everybody except 'init' */
+ if (ENABLE_LOCALE_SUPPORT && getpid() != 1)
+ setlocale(LC_ALL, "");
+
+#if ENABLE_FEATURE_INDIVIDUAL
+ /* Redundant for busybox (run_applet_and_exit covers that case)
+ * but needed for "individual applet" mode */
+ if (argv[1] && strcmp(argv[1], "--help") == 0)
+ bb_show_usage();
+#endif
+}
+
+/* The code below can well be in applets/applets.c, as it is used only
+ * for busybox binary, not "individual" binaries.
+ * However, keeping it here and linking it into libbusybox.so
+ * (together with remaining tiny applets/applets.o)
+ * makes it possible to avoid --whole-archive at link time.
+ * This makes (shared busybox) + libbusybox smaller.
+ * (--gc-sections would be even better....)
+ */
+
+const char *applet_name;
+#if !BB_MMU
+bool re_execed;
+#endif
+
+
+/* If not built as a single-applet executable... */
+#if !defined(SINGLE_APPLET_MAIN)
+
+USE_FEATURE_SUID(static uid_t ruid;) /* real uid */
+
+#if ENABLE_FEATURE_SUID_CONFIG
+
+/* applets[] is const, so we have to define this "override" structure */
+static struct BB_suid_config {
+ int m_applet;
+ uid_t m_uid;
+ gid_t m_gid;
+ mode_t m_mode;
+ struct BB_suid_config *m_next;
+} *suid_config;
+
+static bool suid_cfg_readable;
+
+/* check if u is member of group g */
+static int ingroup(uid_t u, gid_t g)
+{
+ struct group *grp = getgrgid(g);
+
+ if (grp) {
+ char **mem;
+
+ for (mem = grp->gr_mem; *mem; mem++) {
+ struct passwd *pwd = getpwnam(*mem);
+
+ if (pwd && (pwd->pw_uid == u))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* This should probably be a libbb routine. In that case,
+ * I'd probably rename it to something like bb_trimmed_slice.
+ */
+static char *get_trimmed_slice(char *s, char *e)
+{
+ /* First, consider the value at e to be nul and back up until we
+ * reach a non-space char. Set the char after that (possibly at
+ * the original e) to nul. */
+ while (e-- > s) {
+ if (!isspace(*e)) {
+ break;
+ }
+ }
+ e[1] = '\0';
+
+ /* Next, advance past all leading space and return a ptr to the
+ * first non-space char; possibly the terminating nul. */
+ return skip_whitespace(s);
+}
+
+/* Don't depend on the tools to combine strings. */
+static const char config_file[] ALIGN1 = "/etc/busybox.conf";
+
+/* We don't supply a value for the nul, so an index adjustment is
+ * necessary below. Also, we use unsigned short here to save some
+ * space even though these are really mode_t values. */
+static const unsigned short mode_mask[] ALIGN2 = {
+ /* SST sst xxx --- */
+ S_ISUID, S_ISUID|S_IXUSR, S_IXUSR, 0, /* user */
+ S_ISGID, S_ISGID|S_IXGRP, S_IXGRP, 0, /* group */
+ 0, S_IXOTH, S_IXOTH, 0 /* other */
+};
+
+#define parse_error(x) do { errmsg = x; goto pe_label; } while (0)
+
+static void parse_config_file(void)
+{
+ struct BB_suid_config *sct_head;
+ struct BB_suid_config *sct;
+ int applet_no;
+ FILE *f;
+ const char *errmsg;
+ char *s;
+ char *e;
+ int i;
+ unsigned lc;
+ smallint section;
+ char buffer[256];
+ struct stat st;
+
+ assert(!suid_config); /* Should be set to NULL by bss init. */
+
+ ruid = getuid();
+ if (ruid == 0) /* run by root - don't need to even read config file */
+ return;
+
+ if ((stat(config_file, &st) != 0) /* No config file? */
+ || !S_ISREG(st.st_mode) /* Not a regular file? */
+ || (st.st_uid != 0) /* Not owned by root? */
+ || (st.st_mode & (S_IWGRP | S_IWOTH)) /* Writable by non-root? */
+ || !(f = fopen(config_file, "r")) /* Cannot open? */
+ ) {
+ return;
+ }
+
+ suid_cfg_readable = 1;
+ sct_head = NULL;
+ section = lc = 0;
+
+ while (1) {
+ s = buffer;
+
+ if (!fgets(s, sizeof(buffer), f)) { /* Are we done? */
+// why?
+ if (ferror(f)) { /* Make sure it wasn't a read error. */
+ parse_error("reading");
+ }
+ fclose(f);
+ suid_config = sct_head; /* Success, so set the pointer. */
+ return;
+ }
+
+ lc++; /* Got a (partial) line. */
+
+ /* If a line is too long for our buffer, we consider it an error.
+ * The following test does mistreat one corner case though.
+ * If the final line of the file does not end with a newline and
+ * yet exactly fills the buffer, it will be treated as too long
+ * even though there isn't really a problem. But it isn't really
+ * worth adding code to deal with such an unlikely situation, and
+ * we do err on the side of caution. Besides, the line would be
+ * too long if it did end with a newline. */
+ if (!strchr(s, '\n') && !feof(f)) {
+ parse_error("line too long");
+ }
+
+ /* Trim leading and trailing whitespace, ignoring comments, and
+ * check if the resulting string is empty. */
+ s = get_trimmed_slice(s, strchrnul(s, '#'));
+ if (!*s) {
+ continue;
+ }
+
+ /* Check for a section header. */
+
+ if (*s == '[') {
+ /* Unlike the old code, we ignore leading and trailing
+ * whitespace for the section name. We also require that
+ * there are no stray characters after the closing bracket. */
+ e = strchr(s, ']');
+ if (!e /* Missing right bracket? */
+ || e[1] /* Trailing characters? */
+ || !*(s = get_trimmed_slice(s+1, e)) /* Missing name? */
+ ) {
+ parse_error("section header");
+ }
+ /* Right now we only have one section so just check it.
+ * If more sections are added in the future, please don't
+ * resort to cascading ifs with multiple strcasecmp calls.
+ * That kind of bloated code is all too common. A loop
+ * and a string table would be a better choice unless the
+ * number of sections is very small. */
+ if (strcasecmp(s, "SUID") == 0) {
+ section = 1;
+ continue;
+ }
+ section = -1; /* Unknown section so set to skip. */
+ continue;
+ }
+
+ /* Process sections. */
+
+ if (section == 1) { /* SUID */
+ /* Since we trimmed leading and trailing space above, we're
+ * now looking for strings of the form
+ * <key>[::space::]*=[::space::]*<value>
+ * where both key and value could contain inner whitespace. */
+
+ /* First get the key (an applet name in our case). */
+ e = strchr(s, '=');
+ if (e) {
+ s = get_trimmed_slice(s, e);
+ }
+ if (!e || !*s) { /* Missing '=' or empty key. */
+ parse_error("keyword");
+ }
+
+ /* Ok, we have an applet name. Process the rhs if this
+ * applet is currently built in and ignore it otherwise.
+ * Note: this can hide config file bugs which only pop
+ * up when the busybox configuration is changed. */
+ applet_no = find_applet_by_name(s);
+ if (applet_no >= 0) {
+ /* Note: We currently don't check for duplicates!
+ * The last config line for each applet will be the
+ * one used since we insert at the head of the list.
+ * I suppose this could be considered a feature. */
+ sct = xmalloc(sizeof(struct BB_suid_config));
+ sct->m_applet = applet_no;
+ sct->m_mode = 0;
+ sct->m_next = sct_head;
+ sct_head = sct;
+
+ /* Get the specified mode. */
+
+ e = skip_whitespace(e+1);
+
+ for (i = 0; i < 3; i++) {
+ /* There are 4 chars + 1 nul for each of user/group/other. */
+ static const char mode_chars[] ALIGN1 = "Ssx-\0" "Ssx-\0" "Ttx-";
+
+ const char *q;
+ q = strchrnul(mode_chars + 5*i, *e++);
+ if (!*q) {
+ parse_error("mode");
+ }
+ /* Adjust by -i to account for nul. */
+ sct->m_mode |= mode_mask[(q - mode_chars) - i];
+ }
+
+ /* Now get the the user/group info. */
+
+ s = skip_whitespace(e);
+
+ /* Note: we require whitespace between the mode and the
+ * user/group info. */
+ if ((s == e) || !(e = strchr(s, '.'))) {
+ parse_error("<uid>.<gid>");
+ }
+ *e++ = '\0';
+
+ /* We can't use get_ug_id here since it would exit()
+ * if a uid or gid was not found. Oh well... */
+ sct->m_uid = bb_strtoul(s, NULL, 10);
+ if (errno) {
+ struct passwd *pwd = getpwnam(s);
+ if (!pwd) {
+ parse_error("user");
+ }
+ sct->m_uid = pwd->pw_uid;
+ }
+
+ sct->m_gid = bb_strtoul(e, NULL, 10);
+ if (errno) {
+ struct group *grp;
+ grp = getgrnam(e);
+ if (!grp) {
+ parse_error("group");
+ }
+ sct->m_gid = grp->gr_gid;
+ }
+ }
+ continue;
+ }
+
+ /* Unknown sections are ignored. */
+
+ /* Encountering configuration lines prior to seeing a
+ * section header is treated as an error. This is how
+ * the old code worked, but it may not be desirable.
+ * We may want to simply ignore such lines in case they
+ * are used in some future version of busybox. */
+ if (!section) {
+ parse_error("keyword outside section");
+ }
+
+ } /* while (1) */
+
+ pe_label:
+ fprintf(stderr, "Parse error in %s, line %d: %s\n",
+ config_file, lc, errmsg);
+
+ fclose(f);
+ /* Release any allocated memory before returning. */
+ while (sct_head) {
+ sct = sct_head->m_next;
+ free(sct_head);
+ sct_head = sct;
+ }
+}
+#else
+static inline void parse_config_file(void)
+{
+ USE_FEATURE_SUID(ruid = getuid();)
+}
+#endif /* FEATURE_SUID_CONFIG */
+
+
+#if ENABLE_FEATURE_SUID
+static void check_suid(int applet_no)
+{
+ gid_t rgid; /* real gid */
+
+ if (ruid == 0) /* set by parse_config_file() */
+ return; /* run by root - no need to check more */
+ rgid = getgid();
+
+#if ENABLE_FEATURE_SUID_CONFIG
+ if (suid_cfg_readable) {
+ uid_t uid;
+ struct BB_suid_config *sct;
+ mode_t m;
+
+ for (sct = suid_config; sct; sct = sct->m_next) {
+ if (sct->m_applet == applet_no)
+ goto found;
+ }
+ goto check_need_suid;
+ found:
+ m = sct->m_mode;
+ if (sct->m_uid == ruid)
+ /* same uid */
+ m >>= 6;
+ else if ((sct->m_gid == rgid) || ingroup(ruid, sct->m_gid))
+ /* same group / in group */
+ m >>= 3;
+
+ if (!(m & S_IXOTH)) /* is x bit not set ? */
+ bb_error_msg_and_die("you have no permission to run this applet!");
+
+ /* _both_ sgid and group_exec have to be set for setegid */
+ if ((sct->m_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))
+ rgid = sct->m_gid;
+ /* else (no setegid) we will set egid = rgid */
+
+ /* We set effective AND saved ids. If saved-id is not set
+ * like we do below, seteiud(0) can still later succeed! */
+ if (setresgid(-1, rgid, rgid))
+ bb_perror_msg_and_die("setresgid");
+
+ /* do we have to set effective uid? */
+ uid = ruid;
+ if (sct->m_mode & S_ISUID)
+ uid = sct->m_uid;
+ /* else (no seteuid) we will set euid = ruid */
+
+ if (setresuid(-1, uid, uid))
+ bb_perror_msg_and_die("setresuid");
+ return;
+ }
+#if !ENABLE_FEATURE_SUID_CONFIG_QUIET
+ {
+ static bool onetime = 0;
+
+ if (!onetime) {
+ onetime = 1;
+ fprintf(stderr, "Using fallback suid method\n");
+ }
+ }
+#endif
+ check_need_suid:
+#endif
+ if (APPLET_SUID(applet_no) == _BB_SUID_ALWAYS) {
+ /* Real uid is not 0. If euid isn't 0 too, suid bit
+ * is most probably not set on our executable */
+ if (geteuid())
+ bb_error_msg_and_die("must be suid to work properly");
+ } else if (APPLET_SUID(applet_no) == _BB_SUID_NEVER) {
+ xsetgid(rgid); /* drop all privileges */
+ xsetuid(ruid);
+ }
+}
+#else
+#define check_suid(x) ((void)0)
+#endif /* FEATURE_SUID */
+
+
+#if ENABLE_FEATURE_INSTALLER
+/* create (sym)links for each applet */
+static void install_links(const char *busybox, int use_symbolic_links)
+{
+ /* directory table
+ * this should be consistent w/ the enum,
+ * busybox.h::bb_install_loc_t, or else... */
+ static const char usr_bin [] ALIGN1 = "/usr/bin";
+ static const char usr_sbin[] ALIGN1 = "/usr/sbin";
+ static const char *const install_dir[] = {
+ &usr_bin [8], /* "", equivalent to "/" for concat_path_file() */
+ &usr_bin [4], /* "/bin" */
+ &usr_sbin[4], /* "/sbin" */
+ usr_bin,
+ usr_sbin
+ };
+
+ int (*lf)(const char *, const char *);
+ char *fpc;
+ unsigned i;
+ int rc;
+
+ lf = link;
+ if (use_symbolic_links)
+ lf = symlink;
+
+ for (i = 0; i < ARRAY_SIZE(applet_main); i++) {
+ fpc = concat_path_file(
+ install_dir[APPLET_INSTALL_LOC(i)],
+ APPLET_NAME(i));
+ // debug: bb_error_msg("%slinking %s to busybox",
+ // use_symbolic_links ? "sym" : "", fpc);
+ rc = lf(busybox, fpc);
+ if (rc != 0 && errno != EEXIST) {
+ bb_simple_perror_msg(fpc);
+ }
+ free(fpc);
+ }
+}
+#else
+#define install_links(x,y) ((void)0)
+#endif /* FEATURE_INSTALLER */
+
+/* If we were called as "busybox..." */
+static int busybox_main(char **argv)
+{
+ if (!argv[1]) {
+ /* Called without arguments */
+ const char *a;
+ unsigned col, output_width;
+ help:
+ output_width = 80;
+ if (ENABLE_FEATURE_AUTOWIDTH) {
+ /* Obtain the terminal width */
+ get_terminal_width_height(0, &output_width, NULL);
+ }
+ /* leading tab and room to wrap */
+ output_width -= MAX_APPLET_NAME_LEN + 8;
+
+ dup2(1, 2);
+ full_write2_str(bb_banner); /* reuse const string... */
+ full_write2_str(" multi-call binary\n"
+ "Copyright (C) 1998-2008 Erik Andersen, Rob Landley, Denys Vlasenko\n"
+ "and others. Licensed under GPLv2.\n"
+ "See source distribution for full notice.\n"
+ "\n"
+ "Usage: busybox [function] [arguments]...\n"
+ " or: function [arguments]...\n"
+ "\n"
+ "\tBusyBox is a multi-call binary that combines many common Unix\n"
+ "\tutilities into a single executable. Most people will create a\n"
+ "\tlink to busybox for each function they wish to use and BusyBox\n"
+ "\twill act like whatever it was invoked as!\n"
+ "\n"
+ "Currently defined functions:\n");
+ col = 0;
+ a = applet_names;
+ while (*a) {
+ int len;
+ if (col > output_width) {
+ full_write2_str(",\n");
+ col = 0;
+ }
+ full_write2_str(col ? ", " : "\t");
+ full_write2_str(a);
+ len = strlen(a);
+ col += len + 2;
+ a += len + 1;
+ }
+ full_write2_str("\n\n");
+ return 0;
+ }
+
+ if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) {
+ const char *busybox;
+ busybox = xmalloc_readlink(bb_busybox_exec_path);
+ if (!busybox)
+ busybox = bb_busybox_exec_path;
+ /* -s makes symlinks */
+ install_links(busybox, argv[2] && strcmp(argv[2], "-s") == 0);
+ return 0;
+ }
+
+ if (strcmp(argv[1], "--help") == 0) {
+ /* "busybox --help [<applet>]" */
+ if (!argv[2])
+ goto help;
+ /* convert to "<applet> --help" */
+ argv[0] = argv[2];
+ argv[2] = NULL;
+ } else {
+ /* "busybox <applet> arg1 arg2 ..." */
+ argv++;
+ }
+ /* We support "busybox /a/path/to/applet args..." too. Allows for
+ * "#!/bin/busybox"-style wrappers */
+ applet_name = bb_get_last_path_component_nostrip(argv[0]);
+ run_applet_and_exit(applet_name, argv);
+
+ /*bb_error_msg_and_die("applet not found"); - sucks in printf */
+ full_write2_str(applet_name);
+ full_write2_str(": applet not found\n");
+ xfunc_die();
+}
+
+void run_applet_no_and_exit(int applet_no, char **argv)
+{
+ int argc = 1;
+
+ while (argv[argc])
+ argc++;
+
+ /* Reinit some shared global data */
+ xfunc_error_retval = EXIT_FAILURE;
+
+ applet_name = APPLET_NAME(applet_no);
+ if (argc == 2 && !strcmp(argv[1], "--help"))
+ bb_show_usage();
+ if (ENABLE_FEATURE_SUID)
+ check_suid(applet_no);
+ exit(applet_main[applet_no](argc, argv));
+}
+
+void run_applet_and_exit(const char *name, char **argv)
+{
+ int applet = find_applet_by_name(name);
+ if (applet >= 0)
+ run_applet_no_and_exit(applet, argv);
+ if (!strncmp(name, "busybox", 7))
+ exit(busybox_main(argv));
+}
+
+#endif /* !defined(SINGLE_APPLET_MAIN) */
+
+
+
+#if ENABLE_BUILD_LIBBUSYBOX
+int lbb_main(char **argv)
+#else
+int main(int argc ATTRIBUTE_UNUSED, char **argv)
+#endif
+{
+#if defined(SINGLE_APPLET_MAIN)
+ /* Only one applet is selected by the user! */
+ /* applet_names in this case is just "applet\0\0" */
+ lbb_prepare(applet_names USE_FEATURE_INDIVIDUAL(, argv));
+ return SINGLE_APPLET_MAIN(argc, argv);
+#else
+ lbb_prepare("busybox" USE_FEATURE_INDIVIDUAL(, argv));
+
+#if !BB_MMU
+ /* NOMMU re-exec trick sets high-order bit in first byte of name */
+ if (argv[0][0] & 0x80) {
+ re_execed = 1;
+ argv[0][0] &= 0x7f;
+ }
+#endif
+ applet_name = argv[0];
+ if (applet_name[0] == '-')
+ applet_name++;
+ applet_name = bb_basename(applet_name);
+
+ parse_config_file(); /* ...maybe, if FEATURE_SUID_CONFIG */
+
+ run_applet_and_exit(applet_name, argv);
+
+ /*bb_error_msg_and_die("applet not found"); - sucks in printf */
+ full_write2_str(applet_name);
+ full_write2_str(": applet not found\n");
+ xfunc_die();
+#endif
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/ask_confirmation.c b/cleopatre/busybox-1.11.1-spc300/libbb/ask_confirmation.c
new file mode 100644
index 0000000000..646ec4b7e1
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/ask_confirmation.c
@@ -0,0 +1,34 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bb_ask_confirmation implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* Read a line from stdin. If the first non-whitespace char is 'y' or 'Y',
+ * return 1. Otherwise return 0.
+ */
+
+#include "libbb.h"
+
+int bb_ask_confirmation(void)
+{
+ int retval = 0;
+ int first = 1;
+ int c;
+
+ while (((c = getchar()) != EOF) && (c != '\n')) {
+ /* Make sure we get the actual function call for isspace,
+ * as speed is not critical here. */
+ if (first && !(isspace)(c)) {
+ --first;
+ if ((c == 'y') || (c == 'Y')) {
+ ++retval;
+ }
+ }
+ }
+
+ return retval;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/bb_askpass.c b/cleopatre/busybox-1.11.1-spc300/libbb/bb_askpass.c
new file mode 100644
index 0000000000..3ad0e97cdd
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/bb_askpass.c
@@ -0,0 +1,77 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Ask for a password
+ * I use a static buffer in this function. Plan accordingly.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include <termios.h>
+
+#include "libbb.h"
+
+/* do nothing signal handler */
+static void askpass_timeout(int ATTRIBUTE_UNUSED ignore)
+{
+}
+
+char *bb_askpass(int timeout, const char *prompt)
+{
+ /* Was static char[BIGNUM] */
+ enum { sizeof_passwd = 128 };
+ static char *passwd;
+
+ char *ret;
+ int i;
+ struct sigaction sa, oldsa;
+ struct termios tio, oldtio;
+
+ if (!passwd)
+ passwd = xmalloc(sizeof_passwd);
+ memset(passwd, 0, sizeof_passwd);
+
+ tcgetattr(STDIN_FILENO, &oldtio);
+ tcflush(STDIN_FILENO, TCIFLUSH);
+ tio = oldtio;
+ tio.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY);
+ tio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP);
+ tcsetattr(STDIN_FILENO, TCSANOW, &tio);
+
+ memset(&sa, 0, sizeof(sa));
+ /* sa.sa_flags = 0; - no SA_RESTART! */
+ /* SIGINT and SIGALRM will interrupt read below */
+ sa.sa_handler = askpass_timeout;
+ sigaction(SIGINT, &sa, &oldsa);
+ if (timeout) {
+ sigaction_set(SIGALRM, &sa);
+ alarm(timeout);
+ }
+
+ fputs(prompt, stdout);
+ fflush(stdout);
+ ret = NULL;
+ /* On timeout or Ctrl-C, read will hopefully be interrupted,
+ * and we return NULL */
+ if (read(STDIN_FILENO, passwd, sizeof_passwd - 1) > 0) {
+ ret = passwd;
+ i = 0;
+ /* Last byte is guaranteed to be 0
+ (read did not overwrite it) */
+ do {
+ if (passwd[i] == '\r' || passwd[i] == '\n')
+ passwd[i] = '\0';
+ } while (passwd[i++]);
+ }
+
+ if (timeout) {
+ alarm(0);
+ }
+ sigaction_set(SIGINT, &oldsa);
+
+ tcsetattr(STDIN_FILENO, TCSANOW, &oldtio);
+ bb_putchar('\n');
+ fflush(stdout);
+ return ret;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/bb_basename.c b/cleopatre/busybox-1.11.1-spc300/libbb/bb_basename.c
new file mode 100644
index 0000000000..e6832f8ef5
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/bb_basename.c
@@ -0,0 +1,18 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2007 Denys Vlasenko
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+const char *bb_basename(const char *name)
+{
+ const char *cp = strrchr(name, '/');
+ if (cp)
+ return cp + 1;
+ return name;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/bb_do_delay.c b/cleopatre/busybox-1.11.1-spc300/libbb/bb_do_delay.c
new file mode 100644
index 0000000000..aa26aded17
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/bb_do_delay.c
@@ -0,0 +1,22 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Busybox utility routines.
+ *
+ * Copyright (C) 2005 by Tito Ragusa <tito-wolit@tiscali.it>
+ *
+ * Licensed under the GPL v2, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+
+void bb_do_delay(int seconds)
+{
+ time_t start, now;
+
+ time(&start);
+ now = start;
+ while (difftime(now, start) < seconds) {
+ sleep(seconds);
+ time(&now);
+ }
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/bb_pwd.c b/cleopatre/busybox-1.11.1-spc300/libbb/bb_pwd.c
new file mode 100644
index 0000000000..2bdb66230e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/bb_pwd.c
@@ -0,0 +1,99 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * password utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+
+#define assert(x) ((void)0)
+
+/* internal function for bb_getpwuid and bb_getgrgid */
+/* Hacked by Tito Ragusa (c) 2004 <farmatito@tiscali.it> to make it more
+ * flexible:
+ *
+ * bufsize > 0: If idname is not NULL it is copied to buffer,
+ * and buffer is returned. Else id as string is written
+ * to buffer, and NULL is returned.
+ *
+ * bufsize == 0: idname is returned.
+ *
+ * bufsize < 0: If idname is not NULL it is returned.
+ * Else an error message is printed and the program exits.
+ */
+static char* bb_getug(char *buffer, int bufsize, char *idname, long id, char prefix)
+{
+ if (bufsize > 0) {
+ assert(buffer != NULL);
+ if (idname) {
+ return safe_strncpy(buffer, idname, bufsize);
+ }
+ snprintf(buffer, bufsize, "%ld", id);
+ } else if (bufsize < 0 && !idname) {
+ bb_error_msg_and_die("unknown %cid %ld", prefix, id);
+ }
+ return idname;
+}
+
+/* bb_getpwuid, bb_getgrgid:
+ * bb_getXXXid(buf, bufsz, id) - copy user/group name or id
+ * as a string to buf, return user/group name or NULL
+ * bb_getXXXid(NULL, 0, id) - return user/group name or NULL
+ * bb_getXXXid(NULL, -1, id) - return user/group name or exit
+ */
+/* gets a username given a uid */
+char* bb_getpwuid(char *name, int bufsize, long uid)
+{
+ struct passwd *myuser = getpwuid(uid);
+
+ return bb_getug(name, bufsize,
+ (myuser ? myuser->pw_name : (char*)myuser),
+ uid, 'u');
+}
+/* gets a groupname given a gid */
+char* bb_getgrgid(char *group, int bufsize, long gid)
+{
+ struct group *mygroup = getgrgid(gid);
+
+ return bb_getug(group, bufsize,
+ (mygroup ? mygroup->gr_name : (char*)mygroup),
+ gid, 'g');
+}
+
+/* returns a gid given a group name */
+long xgroup2gid(const char *name)
+{
+ struct group *mygroup;
+
+ mygroup = getgrnam(name);
+ if (mygroup == NULL)
+ bb_error_msg_and_die("unknown group name: %s", name);
+
+ return mygroup->gr_gid;
+}
+
+/* returns a uid given a username */
+long xuname2uid(const char *name)
+{
+ struct passwd *myuser;
+
+ myuser = getpwnam(name);
+ if (myuser == NULL)
+ bb_error_msg_and_die("unknown user name: %s", name);
+
+ return myuser->pw_uid;
+}
+
+unsigned long get_ug_id(const char *s,
+ long (*xname2id)(const char *))
+{
+ unsigned long r;
+
+ r = bb_strtoul(s, NULL, 10);
+ if (errno)
+ return xname2id(s);
+ return r;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/bb_qsort.c b/cleopatre/busybox-1.11.1-spc300/libbb/bb_qsort.c
new file mode 100644
index 0000000000..e8673abf92
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/bb_qsort.c
@@ -0,0 +1,20 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Wrapper for common string vector sorting operation
+ *
+ * Copyright (c) 2008 Denys Vlasenko
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+int bb_pstrcmp(const void *a, const void *b)
+{
+ return strcmp(*(char**)a, *(char**)b);
+}
+
+void qsort_string_vector(char **sv, unsigned count)
+{
+ qsort(sv, count, sizeof(char*), bb_pstrcmp);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/bb_strtonum.c b/cleopatre/busybox-1.11.1-spc300/libbb/bb_strtonum.c
new file mode 100644
index 0000000000..50ef0ba267
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/bb_strtonum.c
@@ -0,0 +1,156 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* On exit: errno = 0 only if there was non-empty, '\0' terminated value
+ * errno = EINVAL if value was not '\0' terminated, but othervise ok
+ * Return value is still valid, caller should just check whether end[0]
+ * is a valid terminating char for particular case. OTOH, if caller
+ * requires '\0' terminated input, [s]he can just check errno == 0.
+ * errno = ERANGE if value had alphanumeric terminating char ("1234abcg").
+ * errno = ERANGE if value is out of range, missing, etc.
+ * errno = ERANGE if value had minus sign for strtouXX (even "-0" is not ok )
+ * return value is all-ones in this case.
+ */
+
+static unsigned long long ret_ERANGE(void)
+{
+ errno = ERANGE; /* this ain't as small as it looks (on glibc) */
+ return ULLONG_MAX;
+}
+
+static unsigned long long handle_errors(unsigned long long v, char **endp, char *endptr)
+{
+ if (endp) *endp = endptr;
+
+ /* Check for the weird "feature":
+ * a "-" string is apparently a valid "number" for strto[u]l[l]!
+ * It returns zero and errno is 0! :( */
+ if (endptr[-1] == '-')
+ return ret_ERANGE();
+
+ /* errno is already set to ERANGE by strtoXXX if value overflowed */
+ if (endptr[0]) {
+ /* "1234abcg" or out-of-range? */
+ if (isalnum(endptr[0]) || errno)
+ return ret_ERANGE();
+ /* good number, just suspicious terminator */
+ errno = EINVAL;
+ }
+ return v;
+}
+
+
+unsigned long long bb_strtoull(const char *arg, char **endp, int base)
+{
+ unsigned long long v;
+ char *endptr;
+
+ /* strtoul(" -4200000000") returns 94967296, errno 0 (!) */
+ /* I don't think that this is right. Preventing this... */
+ if (!isalnum(arg[0])) return ret_ERANGE();
+
+ /* not 100% correct for lib func, but convenient for the caller */
+ errno = 0;
+ v = strtoull(arg, &endptr, base);
+ return handle_errors(v, endp, endptr);
+}
+
+long long bb_strtoll(const char *arg, char **endp, int base)
+{
+ unsigned long long v;
+ char *endptr;
+
+ if (arg[0] != '-' && !isalnum(arg[0])) return ret_ERANGE();
+ errno = 0;
+ v = strtoll(arg, &endptr, base);
+ return handle_errors(v, endp, endptr);
+}
+
+#if ULONG_MAX != ULLONG_MAX
+unsigned long bb_strtoul(const char *arg, char **endp, int base)
+{
+ unsigned long v;
+ char *endptr;
+
+ if (!isalnum(arg[0])) return ret_ERANGE();
+ errno = 0;
+ v = strtoul(arg, &endptr, base);
+ return handle_errors(v, endp, endptr);
+}
+
+long bb_strtol(const char *arg, char **endp, int base)
+{
+ long v;
+ char *endptr;
+
+ if (arg[0] != '-' && !isalnum(arg[0])) return ret_ERANGE();
+ errno = 0;
+ v = strtol(arg, &endptr, base);
+ return handle_errors(v, endp, endptr);
+}
+#endif
+
+#if UINT_MAX != ULONG_MAX
+unsigned bb_strtou(const char *arg, char **endp, int base)
+{
+ unsigned long v;
+ char *endptr;
+
+ if (!isalnum(arg[0])) return ret_ERANGE();
+ errno = 0;
+ v = strtoul(arg, &endptr, base);
+ if (v > UINT_MAX) return ret_ERANGE();
+ return handle_errors(v, endp, endptr);
+}
+
+int bb_strtoi(const char *arg, char **endp, int base)
+{
+ long v;
+ char *endptr;
+
+ if (arg[0] != '-' && !isalnum(arg[0])) return ret_ERANGE();
+ errno = 0;
+ v = strtol(arg, &endptr, base);
+ if (v > INT_MAX) return ret_ERANGE();
+ if (v < INT_MIN) return ret_ERANGE();
+ return handle_errors(v, endp, endptr);
+}
+#endif
+
+/* Floating point */
+
+#if 0
+
+#include <math.h> /* just for HUGE_VAL */
+#define NOT_DIGIT(a) (((unsigned char)(a-'0')) > 9)
+double bb_strtod(const char *arg, char **endp)
+{
+ double v;
+ char *endptr;
+
+ if (arg[0] != '-' && NOT_DIGIT(arg[0])) goto err;
+ errno = 0;
+ v = strtod(arg, &endptr);
+ if (endp) *endp = endptr;
+ if (endptr[0]) {
+ /* "1234abcg" or out-of-range? */
+ if (isalnum(endptr[0]) || errno) {
+ err:
+ errno = ERANGE;
+ return HUGE_VAL;
+ }
+ /* good number, just suspicious terminator */
+ errno = EINVAL;
+ }
+ return v;
+}
+
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/change_identity.c b/cleopatre/busybox-1.11.1-spc300/libbb/change_identity.c
new file mode 100644
index 0000000000..da840bfb33
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/change_identity.c
@@ -0,0 +1,41 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "libbb.h"
+
+/* Become the user and group(s) specified by PW. */
+void change_identity(const struct passwd *pw)
+{
+ if (initgroups(pw->pw_name, pw->pw_gid) == -1)
+ bb_perror_msg_and_die("can't set groups");
+ endgrent(); /* helps to close a fd used internally by libc */
+ xsetgid(pw->pw_gid);
+ xsetuid(pw->pw_uid);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/chomp.c b/cleopatre/busybox-1.11.1-spc300/libbb/chomp.c
new file mode 100644
index 0000000000..8ffaff5184
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/chomp.c
@@ -0,0 +1,19 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+void chomp(char *s)
+{
+ char *lc = last_char_is(s, '\n');
+
+ if (lc)
+ *lc = '\0';
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/compare_string_array.c b/cleopatre/busybox-1.11.1-spc300/libbb/compare_string_array.c
new file mode 100644
index 0000000000..ec7f94e793
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/compare_string_array.c
@@ -0,0 +1,78 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* returns the array index of the string */
+/* (index of first match is returned, or -1) */
+int index_in_str_array(const char *const string_array[], const char *key)
+{
+ int i;
+
+ for (i = 0; string_array[i] != 0; i++) {
+ if (strcmp(string_array[i], key) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int index_in_strings(const char *strings, const char *key)
+{
+ int idx = 0;
+
+ while (*strings) {
+ if (strcmp(strings, key) == 0) {
+ return idx;
+ }
+ strings += strlen(strings) + 1; /* skip NUL */
+ idx++;
+ }
+ return -1;
+}
+
+/* returns the array index of the string, even if it matches only a beginning */
+/* (index of first match is returned, or -1) */
+#ifdef UNUSED
+int index_in_substr_array(const char *const string_array[], const char *key)
+{
+ int i;
+ int len = strlen(key);
+ if (len) {
+ for (i = 0; string_array[i] != 0; i++) {
+ if (strncmp(string_array[i], key, len) == 0) {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+#endif
+
+int index_in_substrings(const char *strings, const char *key)
+{
+ int len = strlen(key);
+
+ if (len) {
+ int idx = 0;
+ while (*strings) {
+ if (strncmp(strings, key, len) == 0) {
+ return idx;
+ }
+ strings += strlen(strings) + 1; /* skip NUL */
+ idx++;
+ }
+ }
+ return -1;
+}
+
+const char *nth_string(const char *strings, int n)
+{
+ while (n) {
+ n--;
+ strings += strlen(strings) + 1;
+ }
+ return strings;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/concat_path_file.c b/cleopatre/busybox-1.11.1-spc300/libbb/concat_path_file.c
new file mode 100644
index 0000000000..dd6909fc2a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/concat_path_file.c
@@ -0,0 +1,29 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* Concatenate path and filename to new allocated buffer.
+ * Add '/' only as needed (no duplicate // are produced).
+ * If path is NULL, it is assumed to be "/".
+ * filename should not be NULL.
+ */
+
+#include "libbb.h"
+
+char *concat_path_file(const char *path, const char *filename)
+{
+ char *lc;
+
+ if (!path)
+ path = "";
+ lc = last_char_is(path, '/');
+ while (*filename == '/')
+ filename++;
+ return xasprintf("%s%s%s", path, (lc==NULL ? "/" : ""), filename);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/concat_subpath_file.c b/cleopatre/busybox-1.11.1-spc300/libbb/concat_subpath_file.c
new file mode 100644
index 0000000000..1c00588895
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/concat_subpath_file.c
@@ -0,0 +1,23 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/*
+ This function make special for recursive actions with usage
+ concat_path_file(path, filename)
+ and skipping "." and ".." directory entries
+*/
+
+#include "libbb.h"
+
+char *concat_subpath_file(const char *path, const char *f)
+{
+ if (f && DOT_OR_DOTDOT(f))
+ return NULL;
+ return concat_path_file(path, f);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/copy_file.c b/cleopatre/busybox-1.11.1-spc300/libbb/copy_file.c
new file mode 100644
index 0000000000..3b83e1216d
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/copy_file.c
@@ -0,0 +1,399 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini copy_file implementation for busybox
+ *
+ * Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ * SELinux support by Yuichi Nakamura <ynakam@hitachisoft.jp>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ */
+
+#include "libbb.h"
+
+// POSIX: if exists and -i, ask (w/o -i assume yes).
+// Then open w/o EXCL (yes, not unlink!).
+// If open still fails and -f, try unlink, then try open again.
+// Result: a mess:
+// If dest is a softlink, we overwrite softlink's destination!
+// (or fail, if it points to dir/nonexistent location/etc).
+// This is strange, but POSIX-correct.
+// coreutils cp has --remove-destination to override this...
+//
+// NB: we have special code which still allows for "cp file /dev/node"
+// to work POSIX-ly (the only realistic case where it makes sense)
+
+#define DO_POSIX_CP 0 /* 1 - POSIX behavior, 0 - safe behavior */
+
+// errno must be set to relevant value ("why we cannot create dest?")
+// for POSIX mode to give reasonable error message
+static int ask_and_unlink(const char *dest, int flags)
+{
+ int e = errno;
+#if DO_POSIX_CP
+ if (!(flags & (FILEUTILS_FORCE|FILEUTILS_INTERACTIVE))) {
+ // Either it exists, or the *path* doesnt exist
+ bb_perror_msg("cannot create '%s'", dest);
+ return -1;
+ }
+#endif
+ // If !DO_POSIX_CP, act as if -f is always in effect - we don't want
+ // "cannot create" msg, we want unlink to be done (silently unless -i).
+
+ // TODO: maybe we should do it only if ctty is present?
+ if (flags & FILEUTILS_INTERACTIVE) {
+ // We would not do POSIX insanity. -i asks,
+ // then _unlinks_ the offender. Presto.
+ // (No "opening without O_EXCL", no "unlink only if -f")
+ // Or else we will end up having 3 open()s!
+ fprintf(stderr, "%s: overwrite '%s'? ", applet_name, dest);
+ if (!bb_ask_confirmation())
+ return 0; // not allowed to overwrite
+ }
+ if (unlink(dest) < 0) {
+#if ENABLE_FEATURE_VERBOSE_CP_MESSAGE
+ if (e == errno && e == ENOENT) {
+ /* e == ENOTDIR is similar: path has non-dir component,
+ * but in this case we don't even reach copy_file() */
+ bb_error_msg("cannot create '%s': Path does not exist", dest);
+ return -1; // error
+ }
+#endif
+ errno = e;
+ bb_perror_msg("cannot create '%s'", dest);
+ return -1; // error
+ }
+ return 1; // ok (to try again)
+}
+
+/* Return:
+ * -1 error, copy not made
+ * 0 copy is made or user answered "no" in interactive mode
+ * (failures to preserve mode/owner/times are not reported in exit code)
+ */
+int copy_file(const char *source, const char *dest, int flags)
+{
+ /* This is a recursive function, try to minimize stack usage */
+ /* NB: each struct stat is ~100 bytes */
+ struct stat source_stat;
+ struct stat dest_stat;
+ signed char retval = 0;
+ signed char dest_exists = 0;
+ signed char ovr;
+
+/* Inverse of cp -d ("cp without -d") */
+#define FLAGS_DEREF (flags & FILEUTILS_DEREFERENCE)
+
+ if ((FLAGS_DEREF ? stat : lstat)(source, &source_stat) < 0) {
+ // This may be a dangling symlink.
+ // Making [sym]links to dangling symlinks works, so...
+ if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK))
+ goto make_links;
+ bb_perror_msg("cannot stat '%s'", source);
+ return -1;
+ }
+
+ if (lstat(dest, &dest_stat) < 0) {
+ if (errno != ENOENT) {
+ bb_perror_msg("cannot stat '%s'", dest);
+ return -1;
+ }
+ } else {
+ if (source_stat.st_dev == dest_stat.st_dev
+ && source_stat.st_ino == dest_stat.st_ino
+ ) {
+ bb_error_msg("'%s' and '%s' are the same file", source, dest);
+ return -1;
+ }
+ dest_exists = 1;
+ }
+
+#if ENABLE_SELINUX
+ if ((flags & FILEUTILS_PRESERVE_SECURITY_CONTEXT) && is_selinux_enabled() > 0) {
+ security_context_t con;
+ if (lgetfilecon(source, &con) >= 0) {
+ if (setfscreatecon(con) < 0) {
+ bb_perror_msg("cannot set setfscreatecon %s", con);
+ freecon(con);
+ return -1;
+ }
+ } else if (errno == ENOTSUP || errno == ENODATA) {
+ setfscreatecon_or_die(NULL);
+ } else {
+ bb_perror_msg("cannot lgetfilecon %s", source);
+ return -1;
+ }
+ }
+#endif
+
+ if (S_ISDIR(source_stat.st_mode)) {
+ DIR *dp;
+ const char *tp;
+ struct dirent *d;
+ mode_t saved_umask = 0;
+
+ if (!(flags & FILEUTILS_RECUR)) {
+ bb_error_msg("omitting directory '%s'", source);
+ return -1;
+ }
+
+ /* Did we ever create source ourself before? */
+ tp = is_in_ino_dev_hashtable(&source_stat);
+ if (tp) {
+ /* We did! it's a recursion! man the lifeboats... */
+ bb_error_msg("recursion detected, omitting directory '%s'",
+ source);
+ return -1;
+ }
+
+ /* Create DEST */
+ if (dest_exists) {
+ if (!S_ISDIR(dest_stat.st_mode)) {
+ bb_error_msg("target '%s' is not a directory", dest);
+ return -1;
+ }
+ /* race here: user can substitute a symlink between
+ * this check and actual creation of files inside dest */
+ } else {
+ mode_t mode;
+ saved_umask = umask(0);
+
+ mode = source_stat.st_mode;
+ if (!(flags & FILEUTILS_PRESERVE_STATUS))
+ mode = source_stat.st_mode & ~saved_umask;
+ /* Allow owner to access new dir (at least for now) */
+ mode |= S_IRWXU;
+ if (mkdir(dest, mode) < 0) {
+ umask(saved_umask);
+ bb_perror_msg("cannot create directory '%s'", dest);
+ return -1;
+ }
+ umask(saved_umask);
+ /* need stat info for add_to_ino_dev_hashtable */
+ if (lstat(dest, &dest_stat) < 0) {
+ bb_perror_msg("cannot stat '%s'", dest);
+ return -1;
+ }
+ }
+ /* remember (dev,inode) of each created dir.
+ * NULL: name is not remembered */
+ add_to_ino_dev_hashtable(&dest_stat, NULL);
+
+ /* Recursively copy files in SOURCE */
+ dp = opendir(source);
+ if (dp == NULL) {
+ retval = -1;
+ goto preserve_mode_ugid_time;
+ }
+
+ while ((d = readdir(dp)) != NULL) {
+ char *new_source, *new_dest;
+
+ new_source = concat_subpath_file(source, d->d_name);
+ if (new_source == NULL)
+ continue;
+ new_dest = concat_path_file(dest, d->d_name);
+ if (copy_file(new_source, new_dest, flags) < 0)
+ retval = -1;
+ free(new_source);
+ free(new_dest);
+ }
+ closedir(dp);
+
+ if (!dest_exists
+ && chmod(dest, source_stat.st_mode & ~saved_umask) < 0
+ ) {
+ bb_perror_msg("cannot preserve %s of '%s'", "permissions", dest);
+ /* retval = -1; - WRONG! copy *WAS* made */
+ }
+ goto preserve_mode_ugid_time;
+ }
+
+ if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) {
+ int (*lf)(const char *oldpath, const char *newpath);
+ make_links:
+ // Hmm... maybe
+ // if (DEREF && MAKE_SOFTLINK) source = realpath(source) ?
+ // (but realpath returns NULL on dangling symlinks...)
+ lf = (flags & FILEUTILS_MAKE_SOFTLINK) ? symlink : link;
+ if (lf(source, dest) < 0) {
+ ovr = ask_and_unlink(dest, flags);
+ if (ovr <= 0)
+ return ovr;
+ if (lf(source, dest) < 0) {
+ bb_perror_msg("cannot create link '%s'", dest);
+ return -1;
+ }
+ }
+ /* _Not_ jumping to preserve_mode_ugid_time:
+ * hard/softlinks don't have those */
+ return 0;
+ }
+
+ if (/* "cp thing1 thing2" without -R: just open and read() from thing1 */
+ !(flags & FILEUTILS_RECUR)
+ /* "cp [-opts] regular_file thing2" */
+ || S_ISREG(source_stat.st_mode)
+ /* DEREF uses stat, which never returns S_ISLNK() == true.
+ * So the below is never true: */
+ /* || (FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) */
+ ) {
+ int src_fd;
+ int dst_fd;
+ mode_t new_mode;
+
+ if (!FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) {
+ /* "cp -d symlink dst": create a link */
+ goto dont_cat;
+ }
+
+ if (ENABLE_FEATURE_PRESERVE_HARDLINKS && !FLAGS_DEREF) {
+ const char *link_target;
+ link_target = is_in_ino_dev_hashtable(&source_stat);
+ if (link_target) {
+ if (link(link_target, dest) < 0) {
+ ovr = ask_and_unlink(dest, flags);
+ if (ovr <= 0)
+ return ovr;
+ if (link(link_target, dest) < 0) {
+ bb_perror_msg("cannot create link '%s'", dest);
+ return -1;
+ }
+ }
+ return 0;
+ }
+ add_to_ino_dev_hashtable(&source_stat, dest);
+ }
+
+ src_fd = open_or_warn(source, O_RDONLY);
+ if (src_fd < 0)
+ return -1;
+
+ /* Do not try to open with weird mode fields */
+ new_mode = source_stat.st_mode;
+ if (!S_ISREG(source_stat.st_mode))
+ new_mode = 0666;
+
+ /* POSIX way is a security problem versus symlink attacks,
+ * we do it only for non-symlinks, and only for non-recursive,
+ * non-interactive cp. NB: it is still racy
+ * for "cp file /home/bad_user/file" case
+ * (user can rm file and create a link to /etc/passwd) */
+ if (DO_POSIX_CP
+ || (dest_exists
+ && !(flags & (FILEUTILS_RECUR|FILEUTILS_INTERACTIVE))
+ && !S_ISLNK(dest_stat.st_mode))
+ ) {
+ dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, new_mode);
+ } else /* safe way: */
+ dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode);
+ if (dst_fd == -1) {
+ ovr = ask_and_unlink(dest, flags);
+ if (ovr <= 0) {
+ close(src_fd);
+ return ovr;
+ }
+ /* It shouldn't exist. If it exists, do not open (symlink attack?) */
+ dst_fd = open3_or_warn(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode);
+ if (dst_fd < 0) {
+ close(src_fd);
+ return -1;
+ }
+ }
+
+#if ENABLE_SELINUX
+ if ((flags & (FILEUTILS_PRESERVE_SECURITY_CONTEXT|FILEUTILS_SET_SECURITY_CONTEXT))
+ && is_selinux_enabled() > 0
+ ) {
+ security_context_t con;
+ if (getfscreatecon(&con) == -1) {
+ bb_perror_msg("getfscreatecon");
+ return -1;
+ }
+ if (con) {
+ if (setfilecon(dest, con) == -1) {
+ bb_perror_msg("setfilecon:%s,%s", dest, con);
+ freecon(con);
+ return -1;
+ }
+ freecon(con);
+ }
+ }
+#endif
+ if (bb_copyfd_eof(src_fd, dst_fd) == -1)
+ retval = -1;
+ /* Ok, writing side I can understand... */
+ if (close(dst_fd) < 0) {
+ bb_perror_msg("cannot close '%s'", dest);
+ retval = -1;
+ }
+ /* ...but read size is already checked by bb_copyfd_eof */
+ close(src_fd);
+ /* "cp /dev/something new_file" should not
+ * copy mode of /dev/something */
+ if (!S_ISREG(source_stat.st_mode))
+ return retval;
+ goto preserve_mode_ugid_time;
+ }
+ dont_cat:
+
+ /* Source is a symlink or a special file */
+ /* We are lazy here, a bit lax with races... */
+ if (dest_exists) {
+ errno = EEXIST;
+ ovr = ask_and_unlink(dest, flags);
+ if (ovr <= 0)
+ return ovr;
+ }
+ if (S_ISLNK(source_stat.st_mode)) {
+ char *lpath = xmalloc_readlink_or_warn(source);
+ if (lpath) {
+ int r = symlink(lpath, dest);
+ free(lpath);
+ if (r < 0) {
+ bb_perror_msg("cannot create symlink '%s'", dest);
+ return -1;
+ }
+ if (flags & FILEUTILS_PRESERVE_STATUS)
+ if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0)
+ bb_perror_msg("cannot preserve %s of '%s'", "ownership", dest);
+ }
+ /* _Not_ jumping to preserve_mode_ugid_time:
+ * symlinks don't have those */
+ return 0;
+ }
+ if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode)
+ || S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode)
+ ) {
+ if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) {
+ bb_perror_msg("cannot create '%s'", dest);
+ return -1;
+ }
+ } else {
+ bb_error_msg("unrecognized file '%s' with mode %x", source, source_stat.st_mode);
+ return -1;
+ }
+
+ preserve_mode_ugid_time:
+
+ if (flags & FILEUTILS_PRESERVE_STATUS
+ /* Cannot happen: */
+ /* && !(flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) */
+ ) {
+ struct utimbuf times;
+
+ times.actime = source_stat.st_atime;
+ times.modtime = source_stat.st_mtime;
+ /* BTW, utimes sets usec-precision time - just FYI */
+ if (utime(dest, &times) < 0)
+ bb_perror_msg("cannot preserve %s of '%s'", "times", dest);
+ if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) {
+ source_stat.st_mode &= ~(S_ISUID | S_ISGID);
+ bb_perror_msg("cannot preserve %s of '%s'", "ownership", dest);
+ }
+ if (chmod(dest, source_stat.st_mode) < 0)
+ bb_perror_msg("cannot preserve %s of '%s'", "permissions", dest);
+ }
+
+ return retval;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/copyfd.c b/cleopatre/busybox-1.11.1-spc300/libbb/copyfd.c
new file mode 100644
index 0000000000..08bc6f8dfd
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/copyfd.c
@@ -0,0 +1,119 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* Used by NOFORK applets (e.g. cat) - must not use xmalloc */
+
+static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size)
+{
+ int status = -1;
+ off_t total = 0;
+#if CONFIG_FEATURE_COPYBUF_KB <= 4
+ char buffer[CONFIG_FEATURE_COPYBUF_KB * 1024];
+ enum { buffer_size = sizeof(buffer) };
+#else
+ char *buffer;
+ int buffer_size;
+
+ /* We want page-aligned buffer, just in case kernel is clever
+ * and can do page-aligned io more efficiently */
+ buffer = mmap(NULL, CONFIG_FEATURE_COPYBUF_KB * 1024,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON,
+ /* ignored: */ -1, 0);
+ buffer_size = CONFIG_FEATURE_COPYBUF_KB * 1024;
+ if (buffer == MAP_FAILED) {
+ buffer = alloca(4 * 1024);
+ buffer_size = 4 * 1024;
+ }
+#endif
+
+ if (src_fd < 0)
+ goto out;
+
+ if (!size) {
+ size = buffer_size;
+ status = 1; /* copy until eof */
+ }
+
+ while (1) {
+ ssize_t rd;
+
+ rd = safe_read(src_fd, buffer, size > buffer_size ? buffer_size : size);
+
+ if (!rd) { /* eof - all done */
+ status = 0;
+ break;
+ }
+ if (rd < 0) {
+ bb_perror_msg(bb_msg_read_error);
+ break;
+ }
+ /* dst_fd == -1 is a fake, else... */
+ if (dst_fd >= 0) {
+ ssize_t wr = full_write(dst_fd, buffer, rd);
+ if (wr < rd) {
+ bb_perror_msg(bb_msg_write_error);
+ break;
+ }
+ }
+ total += rd;
+ if (status < 0) { /* if we aren't copying till EOF... */
+ size -= rd;
+ if (!size) {
+ /* 'size' bytes copied - all done */
+ status = 0;
+ break;
+ }
+ }
+ }
+ out:
+
+#if CONFIG_FEATURE_COPYBUF_KB > 4
+ if (buffer_size != 4 * 1024)
+ munmap(buffer, buffer_size);
+#endif
+ return status ? -1 : total;
+}
+
+
+#if 0
+void complain_copyfd_and_die(off_t sz)
+{
+ if (sz != -1)
+ bb_error_msg_and_die("short read");
+ /* if sz == -1, bb_copyfd_XX already complained */
+ xfunc_die();
+}
+#endif
+
+off_t bb_copyfd_size(int fd1, int fd2, off_t size)
+{
+ if (size) {
+ return bb_full_fd_action(fd1, fd2, size);
+ }
+ return 0;
+}
+
+void bb_copyfd_exact_size(int fd1, int fd2, off_t size)
+{
+ off_t sz = bb_copyfd_size(fd1, fd2, size);
+ if (sz == size)
+ return;
+ if (sz != -1)
+ bb_error_msg_and_die("short read");
+ /* if sz == -1, bb_copyfd_XX already complained */
+ xfunc_die();
+}
+
+off_t bb_copyfd_eof(int fd1, int fd2)
+{
+ return bb_full_fd_action(fd1, fd2, 0);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/correct_password.c b/cleopatre/busybox-1.11.1-spc300/libbb/correct_password.c
new file mode 100644
index 0000000000..f47642fd5a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/correct_password.c
@@ -0,0 +1,80 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "libbb.h"
+
+/* Ask the user for a password.
+ * Return 1 if the user gives the correct password for entry PW,
+ * 0 if not. Return 1 without asking if PW has an empty password.
+ *
+ * NULL pw means "just fake it for login with bad username" */
+
+int correct_password(const struct passwd *pw)
+{
+ char *unencrypted, *encrypted;
+ const char *correct;
+ int r;
+#if ENABLE_FEATURE_SHADOWPASSWDS
+ /* Using _r function to avoid pulling in static buffers */
+ struct spwd spw;
+ char buffer[256];
+#endif
+
+ /* fake salt. crypt() can choke otherwise. */
+ correct = "aa";
+ if (!pw) {
+ /* "aa" will never match */
+ goto fake_it;
+ }
+ correct = pw->pw_passwd;
+#if ENABLE_FEATURE_SHADOWPASSWDS
+ if ((correct[0] == 'x' || correct[0] == '*') && !correct[1]) {
+ /* getspnam_r may return 0 yet set result to NULL.
+ * At least glibc 2.4 does this. Be extra paranoid here. */
+ struct spwd *result = NULL;
+ r = getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result);
+ correct = (r || !result) ? "aa" : result->sp_pwdp;
+ }
+#endif
+
+ if (!correct[0]) /* empty password field? */
+ return 1;
+
+ fake_it:
+ unencrypted = bb_askpass(0, "Password: ");
+ if (!unencrypted) {
+ return 0;
+ }
+ encrypted = pw_encrypt(unencrypted, correct, 1);
+ r = (strcmp(encrypted, correct) == 0);
+ free(encrypted);
+ memset(unencrypted, 0, strlen(unencrypted));
+ return r;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/crc32.c b/cleopatre/busybox-1.11.1-spc300/libbb/crc32.c
new file mode 100644
index 0000000000..acbc458275
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/crc32.c
@@ -0,0 +1,40 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * CRC32 table fill function
+ * Copyright (C) 2006 by Rob Sullivan <cogito.ergo.cogito@gmail.com>
+ * (I can't really claim much credit however, as the algorithm is
+ * very well-known)
+ *
+ * The following function creates a CRC32 table depending on whether
+ * a big-endian (0x04c11db7) or little-endian (0xedb88320) CRC32 is
+ * required. Admittedly, there are other CRC32 polynomials floating
+ * around, but Busybox doesn't use them.
+ *
+ * endian = 1: big-endian
+ * endian = 0: little-endian
+ */
+
+#include "libbb.h"
+
+uint32_t *crc32_filltable(uint32_t *crc_table, int endian)
+{
+ uint32_t polynomial = endian ? 0x04c11db7 : 0xedb88320;
+ uint32_t c;
+ int i, j;
+
+ if (!crc_table)
+ crc_table = xmalloc(256 * sizeof(uint32_t));
+
+ for (i = 0; i < 256; i++) {
+ c = endian ? (i << 24) : i;
+ for (j = 8; j; j--) {
+ if (endian)
+ c = (c&0x80000000) ? ((c << 1) ^ polynomial) : (c << 1);
+ else
+ c = (c&1) ? ((c >> 1) ^ polynomial) : (c >> 1);
+ }
+ *crc_table++ = c;
+ }
+
+ return crc_table - 256;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/create_icmp6_socket.c b/cleopatre/busybox-1.11.1-spc300/libbb/create_icmp6_socket.c
new file mode 100644
index 0000000000..a22ac5d02a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/create_icmp6_socket.c
@@ -0,0 +1,36 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * create raw socket for icmp (IPv6 version) protocol
+ * and drop root privileges if running setuid
+ */
+
+#include "libbb.h"
+
+#if ENABLE_FEATURE_IPV6
+int create_icmp6_socket(void)
+{
+ int sock;
+#if 0
+ struct protoent *proto;
+ proto = getprotobyname("ipv6-icmp");
+ /* if getprotobyname failed, just silently force
+ * proto->p_proto to have the correct value for "ipv6-icmp" */
+ sock = socket(AF_INET6, SOCK_RAW,
+ (proto ? proto->p_proto : IPPROTO_ICMPV6));
+#else
+ sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+#endif
+ if (sock < 0) {
+ if (errno == EPERM)
+ bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
+ bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
+ }
+
+ /* drop root privs if running setuid */
+ xsetuid(getuid());
+
+ return sock;
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/create_icmp_socket.c b/cleopatre/busybox-1.11.1-spc300/libbb/create_icmp_socket.c
new file mode 100644
index 0000000000..64beba82ba
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/create_icmp_socket.c
@@ -0,0 +1,34 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * create raw socket for icmp protocol
+ * and drop root privileges if running setuid
+ */
+
+#include "libbb.h"
+
+int create_icmp_socket(void)
+{
+ int sock;
+#if 0
+ struct protoent *proto;
+ proto = getprotobyname("icmp");
+ /* if getprotobyname failed, just silently force
+ * proto->p_proto to have the correct value for "icmp" */
+ sock = socket(AF_INET, SOCK_RAW,
+ (proto ? proto->p_proto : 1)); /* 1 == ICMP */
+#else
+ sock = socket(AF_INET, SOCK_RAW, 1); /* 1 == ICMP */
+#endif
+ if (sock < 0) {
+ if (errno == EPERM)
+ bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
+ bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
+ }
+
+ /* drop root privs if running setuid */
+ xsetuid(getuid());
+
+ return sock;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/crypt_make_salt.c b/cleopatre/busybox-1.11.1-spc300/libbb/crypt_make_salt.c
new file mode 100644
index 0000000000..ebdf024202
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/crypt_make_salt.c
@@ -0,0 +1,45 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * crypt_make_salt
+ *
+ * i64c was also put here, this is the only function that uses it.
+ *
+ * Lifted from loginutils/passwd.c by Thomas Lundquist <thomasez@zelow.no>
+ *
+ */
+
+#include "libbb.h"
+
+static int i64c(int i)
+{
+ i &= 0x3f;
+ if (i == 0)
+ return '.';
+ if (i == 1)
+ return '/';
+ if (i < 12)
+ return ('0' - 2 + i);
+ if (i < 38)
+ return ('A' - 12 + i);
+ return ('a' - 38 + i);
+}
+
+int crypt_make_salt(char *p, int cnt, int x)
+{
+ x += getpid() + time(NULL);
+ do {
+ /* x = (x*1664525 + 1013904223) % 2^32 generator is lame
+ * (low-order bit is not "random", etc...),
+ * but for our purposes it is good enough */
+ x = x*1664525 + 1013904223;
+ /* BTW, Park and Miller's "minimal standard generator" is
+ * x = x*16807 % ((2^31)-1)
+ * It has no problem with visibly alternating lowest bit
+ * but is also weak in cryptographic sense + needs div,
+ * which needs more code (and slower) on many CPUs */
+ *p++ = i64c(x >> 16);
+ *p++ = i64c(x >> 22);
+ } while (--cnt);
+ *p = '\0';
+ return x;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/default_error_retval.c b/cleopatre/busybox-1.11.1-spc300/libbb/default_error_retval.c
new file mode 100644
index 0000000000..0b19f21635
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/default_error_retval.c
@@ -0,0 +1,18 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* Seems silly to copyright a global variable. ;-) Oh well.
+ *
+ * At least one applet (cmp) returns a value different from the typical
+ * EXIT_FAILURE values (1) when an error occurs. So, make it configurable
+ * by the applet. I suppose we could use a wrapper function to set it, but
+ * that too seems silly.
+ */
+
+#include "libbb.h"
+
+int xfunc_error_retval = EXIT_FAILURE;
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/device_open.c b/cleopatre/busybox-1.11.1-spc300/libbb/device_open.c
new file mode 100644
index 0000000000..6907e98148
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/device_open.c
@@ -0,0 +1,32 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* try to open up the specified device */
+int device_open(const char *device, int mode)
+{
+ int m, f, fd;
+
+ m = mode | O_NONBLOCK;
+
+ /* Retry up to 5 times */
+ /* TODO: explain why it can't be considered insane */
+ for (f = 0; f < 5; f++) {
+ fd = open(device, m, 0600);
+ if (fd >= 0)
+ break;
+ }
+ if (fd < 0)
+ return fd;
+ /* Reset original flags. */
+ if (m != mode)
+ fcntl(fd, F_SETFL, mode);
+ return fd;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/die_if_bad_username.c b/cleopatre/busybox-1.11.1-spc300/libbb/die_if_bad_username.c
new file mode 100644
index 0000000000..337ac6012b
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/die_if_bad_username.c
@@ -0,0 +1,36 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Ckeck user and group names for illegal characters
+ *
+ * Copyright (C) 2008 Tito Ragusa <farmatito@tiscali.it>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* To avoid problems, the username should consist only of
+ * letters, digits, underscores, periods, at signs and dashes,
+ * and not start with a dash (as defined by IEEE Std 1003.1-2001).
+ * For compatibility with Samba machine accounts $ is also supported
+ * at the end of the username.
+ */
+
+void die_if_bad_username(const char *name)
+{
+ goto skip; /* 1st char being dash isn't valid */
+ do {
+ if (*name == '-')
+ continue;
+ skip:
+ if (isalnum(*name)
+ || *name == '_'
+ || *name == '.'
+ || *name == '@'
+ || (*name == '$' && !*(name + 1))
+ ) {
+ continue;
+ }
+ bb_error_msg_and_die("illegal character '%c'", *name);
+ } while (*++name);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/dump.c b/cleopatre/busybox-1.11.1-spc300/libbb/dump.c
new file mode 100644
index 0000000000..4d6472e37a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/dump.c
@@ -0,0 +1,811 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Support code for the hexdump and od applets,
+ * based on code from util-linux v 2.11l
+ *
+ * Copyright (c) 1989
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ * Original copyright notice is retained at the end of this file.
+ */
+
+#include "libbb.h"
+#include "dump.h"
+
+enum _vflag bb_dump_vflag = FIRST;
+FS *bb_dump_fshead; /* head of format strings */
+static FU *endfu;
+static char **_argv;
+static off_t savaddress; /* saved address/offset in stream */
+static off_t eaddress; /* end address */
+static off_t address; /* address/offset in stream */
+off_t bb_dump_skip; /* bytes to skip */
+static int exitval; /* final exit value */
+int bb_dump_blocksize; /* data block size */
+int bb_dump_length = -1; /* max bytes to read */
+
+static const char index_str[] ALIGN1 = ".#-+ 0123456789";
+
+static const char size_conv_str[] ALIGN1 =
+"\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG";
+
+static const char lcc[] ALIGN1 = "diouxX";
+
+int bb_dump_size(FS * fs)
+{
+ FU *fu;
+ int bcnt, cur_size;
+ char *fmt;
+ const char *p;
+ int prec;
+
+ /* figure out the data block bb_dump_size needed for each format unit */
+ for (cur_size = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {
+ if (fu->bcnt) {
+ cur_size += fu->bcnt * fu->reps;
+ continue;
+ }
+ for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) {
+ if (*fmt != '%')
+ continue;
+ /*
+ * bb_dump_skip any special chars -- save precision in
+ * case it's a %s format.
+ */
+ while (strchr(index_str + 1, *++fmt));
+ if (*fmt == '.' && isdigit(*++fmt)) {
+ prec = atoi(fmt);
+ while (isdigit(*++fmt));
+ }
+ p = strchr(size_conv_str + 12, *fmt);
+ if (!p) {
+ if (*fmt == 's') {
+ bcnt += prec;
+ } else if (*fmt == '_') {
+ ++fmt;
+ if ((*fmt == 'c') || (*fmt == 'p') || (*fmt == 'u')) {
+ bcnt += 1;
+ }
+ }
+ } else {
+ bcnt += size_conv_str[p - (size_conv_str + 12)];
+ }
+ }
+ cur_size += bcnt * fu->reps;
+ }
+ return cur_size;
+}
+
+static void rewrite(FS * fs)
+{
+ enum { NOTOKAY, USEBCNT, USEPREC } sokay;
+ PR *pr, **nextpr = NULL;
+ FU *fu;
+ char *p1, *p2, *p3;
+ char savech, *fmtp;
+ const char *byte_count_str;
+ int nconv, prec = 0;
+
+ for (fu = fs->nextfu; fu; fu = fu->nextfu) {
+ /*
+ * break each format unit into print units; each
+ * conversion character gets its own.
+ */
+ for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) {
+ /* NOSTRICT */
+ /* DBU:[dvae@cray.com] zalloc so that forward ptrs start out NULL*/
+ pr = xzalloc(sizeof(PR));
+ if (!fu->nextpr)
+ fu->nextpr = pr;
+ /* ignore nextpr -- its unused inside the loop and is
+ * uninitialized 1st time through.
+ */
+
+ /* bb_dump_skip preceding text and up to the next % sign */
+ for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);
+
+ /* only text in the string */
+ if (!*p1) {
+ pr->fmt = fmtp;
+ pr->flags = F_TEXT;
+ break;
+ }
+
+ /*
+ * get precision for %s -- if have a byte count, don't
+ * need it.
+ */
+ if (fu->bcnt) {
+ sokay = USEBCNT;
+ /* bb_dump_skip to conversion character */
+ for (++p1; strchr(index_str, *p1); ++p1);
+ } else {
+ /* bb_dump_skip any special chars, field width */
+ while (strchr(index_str + 1, *++p1));
+ if (*p1 == '.' && isdigit(*++p1)) {
+ sokay = USEPREC;
+ prec = atoi(p1);
+ while (isdigit(*++p1));
+ } else
+ sokay = NOTOKAY;
+ }
+
+ p2 = p1 + 1; /* set end pointer */
+
+ /*
+ * figure out the byte count for each conversion;
+ * rewrite the format as necessary, set up blank-
+ * pbb_dump_adding for end of data.
+ */
+
+ if (*p1 == 'c') {
+ pr->flags = F_CHAR;
+ DO_BYTE_COUNT_1:
+ byte_count_str = "\001";
+ DO_BYTE_COUNT:
+ if (fu->bcnt) {
+ do {
+ if (fu->bcnt == *byte_count_str) {
+ break;
+ }
+ } while (*++byte_count_str);
+ }
+ /* Unlike the original, output the remainder of the format string. */
+ if (!*byte_count_str) {
+ bb_error_msg_and_die("bad byte count for conversion character %s", p1);
+ }
+ pr->bcnt = *byte_count_str;
+ } else if (*p1 == 'l') {
+ ++p2;
+ ++p1;
+ DO_INT_CONV:
+ {
+ const char *e;
+ e = strchr(lcc, *p1);
+ if (!e) {
+ goto DO_BAD_CONV_CHAR;
+ }
+ pr->flags = F_INT;
+ if (e > lcc + 1) {
+ pr->flags = F_UINT;
+ }
+ byte_count_str = "\004\002\001";
+ goto DO_BYTE_COUNT;
+ }
+ /* NOTREACHED */
+ } else if (strchr(lcc, *p1)) {
+ goto DO_INT_CONV;
+ } else if (strchr("eEfgG", *p1)) {
+ pr->flags = F_DBL;
+ byte_count_str = "\010\004";
+ goto DO_BYTE_COUNT;
+ } else if (*p1 == 's') {
+ pr->flags = F_STR;
+ if (sokay == USEBCNT) {
+ pr->bcnt = fu->bcnt;
+ } else if (sokay == USEPREC) {
+ pr->bcnt = prec;
+ } else { /* NOTOKAY */
+ bb_error_msg_and_die("%%s requires a precision or a byte count");
+ }
+ } else if (*p1 == '_') {
+ ++p2;
+ switch (p1[1]) {
+ case 'A':
+ endfu = fu;
+ fu->flags |= F_IGNORE;
+ /* FALLTHROUGH */
+ case 'a':
+ pr->flags = F_ADDRESS;
+ ++p2;
+ if ((p1[2] != 'd') && (p1[2] != 'o') && (p1[2] != 'x')) {
+ goto DO_BAD_CONV_CHAR;
+ }
+ *p1 = p1[2];
+ break;
+ case 'c':
+ pr->flags = F_C;
+ /* *p1 = 'c'; set in conv_c */
+ goto DO_BYTE_COUNT_1;
+ case 'p':
+ pr->flags = F_P;
+ *p1 = 'c';
+ goto DO_BYTE_COUNT_1;
+ case 'u':
+ pr->flags = F_U;
+ /* *p1 = 'c'; set in conv_u */
+ goto DO_BYTE_COUNT_1;
+ default:
+ goto DO_BAD_CONV_CHAR;
+ }
+ } else {
+ DO_BAD_CONV_CHAR:
+ bb_error_msg_and_die("bad conversion character %%%s", p1);
+ }
+
+ /*
+ * copy to PR format string, set conversion character
+ * pointer, update original.
+ */
+ savech = *p2;
+ p1[1] = '\0';
+ pr->fmt = xstrdup(fmtp);
+ *p2 = savech;
+ pr->cchar = pr->fmt + (p1 - fmtp);
+
+ /* DBU:[dave@cray.com] w/o this, trailing fmt text, space is lost.
+ * Skip subsequent text and up to the next % sign and tack the
+ * additional text onto fmt: eg. if fmt is "%x is a HEX number",
+ * we lose the " is a HEX number" part of fmt.
+ */
+ for (p3 = p2; *p3 && *p3 != '%'; p3++);
+ if (p3 > p2)
+ {
+ savech = *p3;
+ *p3 = '\0';
+ pr->fmt = xrealloc(pr->fmt, strlen(pr->fmt)+(p3-p2)+1);
+ strcat(pr->fmt, p2);
+ *p3 = savech;
+ p2 = p3;
+ }
+
+ fmtp = p2;
+
+ /* only one conversion character if byte count */
+ if (!(pr->flags & F_ADDRESS) && fu->bcnt && nconv++) {
+ bb_error_msg_and_die("byte count with multiple conversion characters");
+ }
+ }
+ /*
+ * if format unit byte count not specified, figure it out
+ * so can adjust rep count later.
+ */
+ if (!fu->bcnt)
+ for (pr = fu->nextpr; pr; pr = pr->nextpr)
+ fu->bcnt += pr->bcnt;
+ }
+ /*
+ * if the format string interprets any data at all, and it's
+ * not the same as the bb_dump_blocksize, and its last format unit
+ * interprets any data at all, and has no iteration count,
+ * repeat it as necessary.
+ *
+ * if, rep count is greater than 1, no trailing whitespace
+ * gets output from the last iteration of the format unit.
+ */
+ for (fu = fs->nextfu;; fu = fu->nextfu) {
+ if (!fu->nextfu && fs->bcnt < bb_dump_blocksize &&
+ !(fu->flags & F_SETREP) && fu->bcnt)
+ fu->reps += (bb_dump_blocksize - fs->bcnt) / fu->bcnt;
+ if (fu->reps > 1) {
+ for (pr = fu->nextpr;; pr = pr->nextpr)
+ if (!pr->nextpr)
+ break;
+ for (p1 = pr->fmt, p2 = NULL; *p1; ++p1)
+ p2 = isspace(*p1) ? p1 : NULL;
+ if (p2)
+ pr->nospace = p2;
+ }
+ if (!fu->nextfu)
+ break;
+ }
+}
+
+static void do_skip(const char *fname, int statok)
+{
+ struct stat sbuf;
+
+ if (statok) {
+ if (fstat(STDIN_FILENO, &sbuf)) {
+ bb_simple_perror_msg_and_die(fname);
+ }
+ if ((!(S_ISCHR(sbuf.st_mode) ||
+ S_ISBLK(sbuf.st_mode) ||
+ S_ISFIFO(sbuf.st_mode))) && bb_dump_skip >= sbuf.st_size) {
+ /* If bb_dump_size valid and bb_dump_skip >= size */
+ bb_dump_skip -= sbuf.st_size;
+ address += sbuf.st_size;
+ return;
+ }
+ }
+ if (fseek(stdin, bb_dump_skip, SEEK_SET)) {
+ bb_simple_perror_msg_and_die(fname);
+ }
+ savaddress = address += bb_dump_skip;
+ bb_dump_skip = 0;
+}
+
+static int next(char **argv)
+{
+ static smallint done;
+
+ int statok;
+
+ if (argv) {
+ _argv = argv;
+ return 1;
+ }
+ for (;;) {
+ if (*_argv) {
+ if (!(freopen(*_argv, "r", stdin))) {
+ bb_simple_perror_msg(*_argv);
+ exitval = 1;
+ ++_argv;
+ continue;
+ }
+ done = statok = 1;
+ } else {
+ if (done)
+ return 0;
+ done = 1;
+ statok = 0;
+ }
+ if (bb_dump_skip)
+ do_skip(statok ? *_argv : "stdin", statok);
+ if (*_argv)
+ ++_argv;
+ if (!bb_dump_skip)
+ return 1;
+ }
+ /* NOTREACHED */
+}
+
+static unsigned char *get(void)
+{
+ static smallint ateof = 1;
+ static unsigned char *curp = NULL, *savp; /*DBU:[dave@cray.com]initialize curp */
+
+ int n;
+ int need, nread;
+ unsigned char *tmpp;
+
+ if (!curp) {
+ address = (off_t)0; /*DBU:[dave@cray.com] initialize,initialize..*/
+ curp = xmalloc(bb_dump_blocksize);
+ savp = xmalloc(bb_dump_blocksize);
+ } else {
+ tmpp = curp;
+ curp = savp;
+ savp = tmpp;
+ address = savaddress += bb_dump_blocksize;
+ }
+ for (need = bb_dump_blocksize, nread = 0;;) {
+ /*
+ * if read the right number of bytes, or at EOF for one file,
+ * and no other files are available, zero-pad the rest of the
+ * block and set the end flag.
+ */
+ if (!bb_dump_length || (ateof && !next((char **) NULL))) {
+ if (need == bb_dump_blocksize) {
+ return NULL;
+ }
+ if (bb_dump_vflag != ALL && !memcmp(curp, savp, nread)) {
+ if (bb_dump_vflag != DUP) {
+ puts("*");
+ }
+ return NULL;
+ }
+ memset((char *) curp + nread, 0, need);
+ eaddress = address + nread;
+ return curp;
+ }
+ n = fread((char *) curp + nread, sizeof(unsigned char),
+ bb_dump_length == -1 ? need : MIN(bb_dump_length, need), stdin);
+ if (!n) {
+ if (ferror(stdin)) {
+ bb_simple_perror_msg(_argv[-1]);
+ }
+ ateof = 1;
+ continue;
+ }
+ ateof = 0;
+ if (bb_dump_length != -1) {
+ bb_dump_length -= n;
+ }
+ need -= n;
+ if (!need) {
+ if (bb_dump_vflag == ALL || bb_dump_vflag == FIRST
+ || memcmp(curp, savp, bb_dump_blocksize)) {
+ if (bb_dump_vflag == DUP || bb_dump_vflag == FIRST) {
+ bb_dump_vflag = WAIT;
+ }
+ return curp;
+ }
+ if (bb_dump_vflag == WAIT) {
+ puts("*");
+ }
+ bb_dump_vflag = DUP;
+ address = savaddress += bb_dump_blocksize;
+ need = bb_dump_blocksize;
+ nread = 0;
+ } else {
+ nread += n;
+ }
+ }
+}
+
+static void bpad(PR * pr)
+{
+ char *p1, *p2;
+
+ /*
+ * remove all conversion flags; '-' is the only one valid
+ * with %s, and it's not useful here.
+ */
+ pr->flags = F_BPAD;
+ *pr->cchar = 's';
+ for (p1 = pr->fmt; *p1 != '%'; ++p1);
+ for (p2 = ++p1; *p1 && strchr(" -0+#", *p1); ++p1)
+ if (pr->nospace) pr->nospace--;
+ while ((*p2++ = *p1++) != 0);
+}
+
+static const char conv_str[] ALIGN1 =
+ "\0\\0\0"
+ "\007\\a\0" /* \a */
+ "\b\\b\0"
+ "\f\\b\0"
+ "\n\\n\0"
+ "\r\\r\0"
+ "\t\\t\0"
+ "\v\\v\0"
+ ;
+
+
+static void conv_c(PR * pr, unsigned char * p)
+{
+ const char *str = conv_str;
+ char buf[10];
+
+ do {
+ if (*p == *str) {
+ ++str;
+ goto strpr;
+ }
+ str += 4;
+ } while (*str);
+
+ if (isprint(*p)) {
+ *pr->cchar = 'c';
+ (void) printf(pr->fmt, *p);
+ } else {
+ sprintf(buf, "%03o", (int) *p);
+ str = buf;
+ strpr:
+ *pr->cchar = 's';
+ printf(pr->fmt, str);
+ }
+}
+
+static void conv_u(PR * pr, unsigned char * p)
+{
+ static const char list[] ALIGN1 =
+ "nul\0soh\0stx\0etx\0eot\0enq\0ack\0bel\0"
+ "bs\0_ht\0_lf\0_vt\0_ff\0_cr\0_so\0_si\0_"
+ "dle\0dcl\0dc2\0dc3\0dc4\0nak\0syn\0etb\0"
+ "can\0em\0_sub\0esc\0fs\0_gs\0_rs\0_us";
+
+ /* od used nl, not lf */
+ if (*p <= 0x1f) {
+ *pr->cchar = 's';
+ printf(pr->fmt, list + (4 * (int)*p));
+ } else if (*p == 0x7f) {
+ *pr->cchar = 's';
+ printf(pr->fmt, "del");
+ } else if (isprint(*p)) {
+ *pr->cchar = 'c';
+ printf(pr->fmt, *p);
+ } else {
+ *pr->cchar = 'x';
+ printf(pr->fmt, (int) *p);
+ }
+}
+
+static void display(void)
+{
+/* extern FU *endfu; */
+ FS *fs;
+ FU *fu;
+ PR *pr;
+ int cnt;
+ unsigned char *bp;
+
+ off_t saveaddress;
+ unsigned char savech = 0, *savebp;
+
+ while ((bp = get()) != NULL) {
+ for (fs = bb_dump_fshead, savebp = bp, saveaddress = address; fs;
+ fs = fs->nextfs, bp = savebp, address = saveaddress) {
+ for (fu = fs->nextfu; fu; fu = fu->nextfu) {
+ if (fu->flags & F_IGNORE) {
+ break;
+ }
+ for (cnt = fu->reps; cnt; --cnt) {
+ for (pr = fu->nextpr; pr; address += pr->bcnt,
+ bp += pr->bcnt, pr = pr->nextpr) {
+ if (eaddress && address >= eaddress &&
+ !(pr->flags & (F_TEXT | F_BPAD))) {
+ bpad(pr);
+ }
+ if (cnt == 1 && pr->nospace) {
+ savech = *pr->nospace;
+ *pr->nospace = '\0';
+ }
+/* PRINT; */
+ switch (pr->flags) {
+ case F_ADDRESS:
+ printf(pr->fmt, (unsigned int) address);
+ break;
+ case F_BPAD:
+ printf(pr->fmt, "");
+ break;
+ case F_C:
+ conv_c(pr, bp);
+ break;
+ case F_CHAR:
+ printf(pr->fmt, *bp);
+ break;
+ case F_DBL:{
+ double dval;
+ float fval;
+
+ switch (pr->bcnt) {
+ case 4:
+ memmove((char *) &fval, (char *) bp,
+ sizeof(fval));
+ printf(pr->fmt, fval);
+ break;
+ case 8:
+ memmove((char *) &dval, (char *) bp,
+ sizeof(dval));
+ printf(pr->fmt, dval);
+ break;
+ }
+ break;
+ }
+ case F_INT:{
+ int ival;
+ short sval;
+
+ switch (pr->bcnt) {
+ case 1:
+ printf(pr->fmt, (int) *bp);
+ break;
+ case 2:
+ memmove((char *) &sval, (char *) bp,
+ sizeof(sval));
+ printf(pr->fmt, (int) sval);
+ break;
+ case 4:
+ memmove((char *) &ival, (char *) bp,
+ sizeof(ival));
+ printf(pr->fmt, ival);
+ break;
+ }
+ break;
+ }
+ case F_P:
+ printf(pr->fmt, isprint(*bp) ? *bp : '.');
+ break;
+ case F_STR:
+ printf(pr->fmt, (char *) bp);
+ break;
+ case F_TEXT:
+ printf(pr->fmt);
+ break;
+ case F_U:
+ conv_u(pr, bp);
+ break;
+ case F_UINT:{
+ unsigned int ival;
+ unsigned short sval;
+
+ switch (pr->bcnt) {
+ case 1:
+ printf(pr->fmt, (unsigned int) * bp);
+ break;
+ case 2:
+ memmove((char *) &sval, (char *) bp,
+ sizeof(sval));
+ printf(pr->fmt, (unsigned int) sval);
+ break;
+ case 4:
+ memmove((char *) &ival, (char *) bp,
+ sizeof(ival));
+ printf(pr->fmt, ival);
+ break;
+ }
+ break;
+ }
+ }
+ if (cnt == 1 && pr->nospace) {
+ *pr->nospace = savech;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (endfu) {
+ /*
+ * if eaddress not set, error or file bb_dump_size was multiple of
+ * bb_dump_blocksize, and no partial block ever found.
+ */
+ if (!eaddress) {
+ if (!address) {
+ return;
+ }
+ eaddress = address;
+ }
+ for (pr = endfu->nextpr; pr; pr = pr->nextpr) {
+ switch (pr->flags) {
+ case F_ADDRESS:
+ (void) printf(pr->fmt, (unsigned int) eaddress);
+ break;
+ case F_TEXT:
+ (void) printf(pr->fmt);
+ break;
+ }
+ }
+ }
+}
+
+int bb_dump_dump(char **argv)
+{
+ FS *tfs;
+
+ /* figure out the data block bb_dump_size */
+ for (bb_dump_blocksize = 0, tfs = bb_dump_fshead; tfs; tfs = tfs->nextfs) {
+ tfs->bcnt = bb_dump_size(tfs);
+ if (bb_dump_blocksize < tfs->bcnt) {
+ bb_dump_blocksize = tfs->bcnt;
+ }
+ }
+ /* rewrite the rules, do syntax checking */
+ for (tfs = bb_dump_fshead; tfs; tfs = tfs->nextfs) {
+ rewrite(tfs);
+ }
+
+ next(argv);
+ display();
+
+ return exitval;
+}
+
+void bb_dump_add(const char *fmt)
+{
+ const char *p;
+ char *p1;
+ char *p2;
+ static FS **nextfs;
+ FS *tfs;
+ FU *tfu, **nextfu;
+ const char *savep;
+
+ /* start new linked list of format units */
+ tfs = xzalloc(sizeof(FS)); /*DBU:[dave@cray.com] start out NULL */
+ if (!bb_dump_fshead) {
+ bb_dump_fshead = tfs;
+ } else {
+ *nextfs = tfs;
+ }
+ nextfs = &tfs->nextfs;
+ nextfu = &tfs->nextfu;
+
+ /* take the format string and break it up into format units */
+ for (p = fmt;;) {
+ /* bb_dump_skip leading white space */
+ p = skip_whitespace(p);
+ if (!*p) {
+ break;
+ }
+
+ /* allocate a new format unit and link it in */
+ /* NOSTRICT */
+ /* DBU:[dave@cray.com] zalloc so that forward pointers start out NULL */
+ tfu = xzalloc(sizeof(FU));
+ *nextfu = tfu;
+ nextfu = &tfu->nextfu;
+ tfu->reps = 1;
+
+ /* if leading digit, repetition count */
+ if (isdigit(*p)) {
+ for (savep = p; isdigit(*p); ++p);
+ if (!isspace(*p) && *p != '/') {
+ bb_error_msg_and_die("bad format {%s}", fmt);
+ }
+ /* may overwrite either white space or slash */
+ tfu->reps = atoi(savep);
+ tfu->flags = F_SETREP;
+ /* bb_dump_skip trailing white space */
+ p = skip_whitespace(++p);
+ }
+
+ /* bb_dump_skip slash and trailing white space */
+ if (*p == '/') {
+ p = skip_whitespace(++p);
+ }
+
+ /* byte count */
+ if (isdigit(*p)) {
+// TODO: use bb_strtou
+ savep = p;
+ do p++; while (isdigit(*p));
+ if (!isspace(*p)) {
+ bb_error_msg_and_die("bad format {%s}", fmt);
+ }
+ tfu->bcnt = atoi(savep);
+ /* bb_dump_skip trailing white space */
+ p = skip_whitespace(++p);
+ }
+
+ /* format */
+ if (*p != '"') {
+ bb_error_msg_and_die("bad format {%s}", fmt);
+ }
+ for (savep = ++p; *p != '"';) {
+ if (*p++ == 0) {
+ bb_error_msg_and_die("bad format {%s}", fmt);
+ }
+ }
+ tfu->fmt = xmalloc(p - savep + 1);
+ strncpy(tfu->fmt, savep, p - savep);
+ tfu->fmt[p - savep] = '\0';
+/* escape(tfu->fmt); */
+
+ p1 = tfu->fmt;
+
+ /* alphabetic escape sequences have to be done in place */
+ for (p2 = p1;; ++p1, ++p2) {
+ if (!*p1) {
+ *p2 = *p1;
+ break;
+ }
+ if (*p1 == '\\') {
+ const char *cs = conv_str + 4;
+ ++p1;
+ *p2 = *p1;
+ do {
+ if (*p1 == cs[2]) {
+ *p2 = cs[0];
+ break;
+ }
+ cs += 4;
+ } while (*cs);
+ }
+ }
+
+ p++;
+ }
+}
+
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/error_msg.c b/cleopatre/busybox-1.11.1-spc300/libbb/error_msg.c
new file mode 100644
index 0000000000..5f53f03118
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/error_msg.c
@@ -0,0 +1,19 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+void bb_error_msg(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ bb_verror_msg(s, p, NULL);
+ va_end(p);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/error_msg_and_die.c b/cleopatre/busybox-1.11.1-spc300/libbb/error_msg_and_die.c
new file mode 100644
index 0000000000..addd818b79
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/error_msg_and_die.c
@@ -0,0 +1,20 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+void bb_error_msg_and_die(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ bb_verror_msg(s, p, NULL);
+ va_end(p);
+ xfunc_die();
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/execable.c b/cleopatre/busybox-1.11.1-spc300/libbb/execable.c
new file mode 100644
index 0000000000..5c2b4505cb
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/execable.c
@@ -0,0 +1,78 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2006 Gabriel Somlo <somlo at cmu.edu>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* check if path points to an executable file;
+ * return 1 if found;
+ * return 0 otherwise;
+ */
+int execable_file(const char *name)
+{
+ struct stat s;
+ return (!access(name, X_OK) && !stat(name, &s) && S_ISREG(s.st_mode));
+}
+
+/* search (*PATHp) for an executable file;
+ * return allocated string containing full path if found;
+ * PATHp points to the component after the one where it was found
+ * (or NULL),
+ * you may call find_execable again with this PATHp to continue
+ * (if it's not NULL).
+ * return NULL otherwise; (PATHp is undefined)
+ * in all cases (*PATHp) contents will be trashed (s/:/NUL/).
+ */
+char *find_execable(const char *filename, char **PATHp)
+{
+ char *p, *n;
+
+ p = *PATHp;
+ while (p) {
+ n = strchr(p, ':');
+ if (n)
+ *n++ = '\0';
+ if (*p != '\0') { /* it's not a PATH="foo::bar" situation */
+ p = concat_path_file(p, filename);
+ if (execable_file(p)) {
+ *PATHp = n;
+ return p;
+ }
+ free(p);
+ }
+ p = n;
+ } /* on loop exit p == NULL */
+ return p;
+}
+
+/* search $PATH for an executable file;
+ * return 1 if found;
+ * return 0 otherwise;
+ */
+int exists_execable(const char *filename)
+{
+ char *path = xstrdup(getenv("PATH"));
+ char *tmp = path;
+ char *ret = find_execable(filename, &tmp);
+ free(path);
+ if (ret) {
+ free(ret);
+ return 1;
+ }
+ return 0;
+}
+
+#if ENABLE_FEATURE_PREFER_APPLETS
+/* just like the real execvp, but try to launch an applet named 'file' first
+ */
+int bb_execvp(const char *file, char *const argv[])
+{
+ return execvp(find_applet_by_name(file) >= 0 ? bb_busybox_exec_path : file,
+ argv);
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/fclose_nonstdin.c b/cleopatre/busybox-1.11.1-spc300/libbb/fclose_nonstdin.c
new file mode 100644
index 0000000000..768ee946d7
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/fclose_nonstdin.c
@@ -0,0 +1,25 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * fclose_nonstdin implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* A number of standard utilities can accept multiple command line args
+ * of '-' for stdin, according to SUSv3. So we encapsulate the check
+ * here to save a little space.
+ */
+
+#include "libbb.h"
+
+int fclose_if_not_stdin(FILE *f)
+{
+ /* Some more paranoid applets want ferror() check too */
+ int r = ferror(f); /* NB: does NOT set errno! */
+ if (r) errno = EIO; /* so we'll help it */
+ if (f != stdin)
+ return (r | fclose(f)); /* fclose does set errno on error */
+ return r;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/fflush_stdout_and_exit.c b/cleopatre/busybox-1.11.1-spc300/libbb/fflush_stdout_and_exit.c
new file mode 100644
index 0000000000..9f05500f31
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/fflush_stdout_and_exit.c
@@ -0,0 +1,29 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * fflush_stdout_and_exit implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* Attempt to fflush(stdout), and exit with an error code if stdout is
+ * in an error state.
+ */
+
+#include "libbb.h"
+
+void fflush_stdout_and_exit(int retval)
+{
+ if (fflush(stdout))
+ bb_perror_msg_and_die(bb_msg_standard_output);
+
+ if (ENABLE_FEATURE_PREFER_APPLETS && die_sleep < 0) {
+ /* We are in NOFORK applet. Do not exit() directly,
+ * but use xfunc_die() */
+ xfunc_error_retval = retval;
+ xfunc_die();
+ }
+
+ exit(retval);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/fgets_str.c b/cleopatre/busybox-1.11.1-spc300/libbb/fgets_str.c
new file mode 100644
index 0000000000..d6fada1a17
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/fgets_str.c
@@ -0,0 +1,66 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+static char *xmalloc_fgets_internal(FILE *file, const char *terminating_string, int chop_off)
+{
+ char *linebuf = NULL;
+ const int term_length = strlen(terminating_string);
+ int end_string_offset;
+ int linebufsz = 0;
+ int idx = 0;
+ int ch;
+
+ while (1) {
+ ch = fgetc(file);
+ if (ch == EOF) {
+ if (idx == 0)
+ return linebuf; /* NULL */
+ break;
+ }
+
+ if (idx >= linebufsz) {
+ linebufsz += 200;
+ linebuf = xrealloc(linebuf, linebufsz);
+ }
+
+ linebuf[idx] = ch;
+ idx++;
+
+ /* Check for terminating string */
+ end_string_offset = idx - term_length;
+ if (end_string_offset >= 0
+ && memcmp(&linebuf[end_string_offset], terminating_string, term_length) == 0
+ ) {
+ if (chop_off)
+ idx -= term_length;
+ break;
+ }
+ }
+ /* Grow/shrink *first*, then store NUL */
+ linebuf = xrealloc(linebuf, idx + 1);
+ linebuf[idx] = '\0';
+ return linebuf;
+}
+
+/* Read up to TERMINATING_STRING from FILE and return it,
+ * including terminating string.
+ * Non-terminated string can be returned if EOF is reached.
+ * Return NULL if EOF is reached immediately. */
+char *xmalloc_fgets_str(FILE *file, const char *terminating_string)
+{
+ return xmalloc_fgets_internal(file, terminating_string, 0);
+}
+
+char *xmalloc_fgetline_str(FILE *file, const char *terminating_string)
+{
+ return xmalloc_fgets_internal(file, terminating_string, 1);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/find_mount_point.c b/cleopatre/busybox-1.11.1-spc300/libbb/find_mount_point.c
new file mode 100644
index 0000000000..cb00b9806f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/find_mount_point.c
@@ -0,0 +1,53 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include <mntent.h>
+
+/*
+ * Given a block device, find the mount table entry if that block device
+ * is mounted.
+ *
+ * Given any other file (or directory), find the mount table entry for its
+ * filesystem.
+ */
+struct mntent *find_mount_point(const char *name, const char *table)
+{
+ struct stat s;
+ dev_t mountDevice;
+ FILE *mountTable;
+ struct mntent *mountEntry;
+
+ if (stat(name, &s) != 0)
+ return 0;
+
+ if ((s.st_mode & S_IFMT) == S_IFBLK)
+ mountDevice = s.st_rdev;
+ else
+ mountDevice = s.st_dev;
+
+
+ mountTable = setmntent(table ? table : bb_path_mtab_file, "r");
+ if (!mountTable)
+ return 0;
+
+ while ((mountEntry = getmntent(mountTable)) != 0) {
+ if (strcmp(name, mountEntry->mnt_dir) == 0
+ || strcmp(name, mountEntry->mnt_fsname) == 0
+ ) { /* String match. */
+ break;
+ }
+ if (stat(mountEntry->mnt_fsname, &s) == 0 && s.st_rdev == mountDevice) /* Match the device. */
+ break;
+ if (stat(mountEntry->mnt_dir, &s) == 0 && s.st_dev == mountDevice) /* Match the directory's mount point. */
+ break;
+ }
+ endmntent(mountTable);
+ return mountEntry;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/find_pid_by_name.c b/cleopatre/busybox-1.11.1-spc300/libbb/find_pid_by_name.c
new file mode 100644
index 0000000000..8dcdb13bc9
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/find_pid_by_name.c
@@ -0,0 +1,92 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+
+/*
+In Linux we have three ways to determine "process name":
+1. /proc/PID/stat has "...(name)...", among other things. It's so-called "comm" field.
+2. /proc/PID/cmdline's first NUL-terminated string. It's argv[0] from exec syscall.
+3. /proc/PID/exe symlink. Points to the running executable file.
+
+kernel threads:
+ comm: thread name
+ cmdline: empty
+ exe: <readlink fails>
+
+executable
+ comm: first 15 chars of base name
+ (if executable is a symlink, then first 15 chars of symlink name are used)
+ cmdline: argv[0] from exec syscall
+ exe: points to executable (resolves symlink, unlike comm)
+
+script (an executable with #!/path/to/interpreter):
+ comm: first 15 chars of script's base name (symlinks are not resolved)
+ cmdline: /path/to/interpreter (symlinks are not resolved)
+ (script name is in argv[1], args are pushed into argv[2] etc)
+ exe: points to interpreter's executable (symlinks are resolved)
+
+If FEATURE_PREFER_APPLETS=y (and more so if FEATURE_SH_STANDALONE=y),
+some commands started from busybox shell, xargs or find are started by
+execXXX("/proc/self/exe", applet_name, params....)
+and therefore comm field contains "exe".
+*/
+
+/* find_pid_by_name()
+ *
+ * Modified by Vladimir Oleynik for use with libbb/procps.c
+ * This finds the pid of the specified process.
+ * Currently, it's implemented by rummaging through
+ * the proc filesystem.
+ *
+ * Returns a list of all matching PIDs
+ * It is the caller's duty to free the returned pidlist.
+ */
+pid_t* find_pid_by_name(const char* procName)
+{
+ pid_t* pidList;
+ int i = 0;
+ procps_status_t* p = NULL;
+
+ pidList = xmalloc(sizeof(*pidList));
+ while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_COMM|PSSCAN_ARGV0))) {
+ if (
+ /* we require comm to match and to not be truncated */
+ /* in Linux, if comm is 15 chars, it may be a truncated
+ * name, so we don't allow that to match */
+ (!p->comm[sizeof(p->comm)-2] && strcmp(p->comm, procName) == 0)
+ /* or we require argv0 to match (essential for matching reexeced /proc/self/exe)*/
+ || (p->argv0 && strcmp(bb_basename(p->argv0), procName) == 0)
+ /* TOOD: we can also try /proc/NUM/exe link, do we want that? */
+ ) {
+ pidList = xrealloc(pidList, sizeof(*pidList) * (i+2));
+ pidList[i++] = p->pid;
+ }
+ }
+
+ pidList[i] = 0;
+ return pidList;
+}
+
+pid_t *pidlist_reverse(pid_t *pidList)
+{
+ int i = 0;
+ while (pidList[i])
+ i++;
+ if (--i >= 0) {
+ pid_t k;
+ int j;
+ for (j = 0; i > j; i--, j++) {
+ k = pidList[i];
+ pidList[i] = pidList[j];
+ pidList[j] = k;
+ }
+ }
+ return pidList;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/find_root_device.c b/cleopatre/busybox-1.11.1-spc300/libbb/find_root_device.c
new file mode 100644
index 0000000000..9779f7e82d
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/find_root_device.c
@@ -0,0 +1,74 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* Find block device /dev/XXX which contains specified file
+ * We handle /dev/dir/dir/dir too, at a cost of ~80 more bytes code */
+
+/* Do not reallocate all this stuff on each recursion */
+enum { DEVNAME_MAX = 256 };
+struct arena {
+ struct stat st;
+ dev_t dev;
+ /* Was PATH_MAX, but we recurse _/dev_. We can assume
+ * people are not crazy enough to have mega-deep tree there */
+ char devpath[DEVNAME_MAX];
+};
+
+static char *find_block_device_in_dir(struct arena *ap)
+{
+ DIR *dir;
+ struct dirent *entry;
+ char *retpath = NULL;
+ int len, rem;
+
+ dir = opendir(ap->devpath);
+ if (!dir)
+ return NULL;
+
+ len = strlen(ap->devpath);
+ rem = DEVNAME_MAX-2 - len;
+ if (rem <= 0)
+ return NULL;
+ ap->devpath[len++] = '/';
+
+ while ((entry = readdir(dir)) != NULL) {
+ safe_strncpy(ap->devpath + len, entry->d_name, rem);
+ /* lstat: do not follow links */
+ if (lstat(ap->devpath, &ap->st) != 0)
+ continue;
+ if (S_ISBLK(ap->st.st_mode) && ap->st.st_rdev == ap->dev) {
+ retpath = xstrdup(ap->devpath);
+ break;
+ }
+ if (S_ISDIR(ap->st.st_mode)) {
+ /* Do not recurse for '.' and '..' */
+ if (DOT_OR_DOTDOT(entry->d_name))
+ continue;
+ retpath = find_block_device_in_dir(ap);
+ if (retpath)
+ break;
+ }
+ }
+ closedir(dir);
+
+ return retpath;
+}
+
+char *find_block_device(const char *path)
+{
+ struct arena a;
+
+ if (stat(path, &a.st) != 0)
+ return NULL;
+ a.dev = S_ISBLK(a.st.st_mode) ? a.st.st_rdev : a.st.st_dev;
+ strcpy(a.devpath, "/dev");
+ return find_block_device_in_dir(&a);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/full_write.c b/cleopatre/busybox-1.11.1-spc300/libbb/full_write.c
new file mode 100644
index 0000000000..7503c8b42e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/full_write.c
@@ -0,0 +1,42 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/*
+ * Write all of the supplied buffer out to a file.
+ * This does multiple writes as necessary.
+ * Returns the amount written, or -1 on an error.
+ */
+ssize_t full_write(int fd, const void *buf, size_t len)
+{
+ ssize_t cc;
+ ssize_t total;
+
+ total = 0;
+
+ while (len) {
+ cc = safe_write(fd, buf, len);
+
+ if (cc < 0) {
+ if (total) {
+ /* we already wrote some! */
+ /* user can do another write to know the error code */
+ return total;
+ }
+ return cc; /* write() returns -1 on failure. */
+ }
+
+ total += cc;
+ buf = ((const char *)buf) + cc;
+ len -= cc;
+ }
+
+ return total;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/get_console.c b/cleopatre/busybox-1.11.1-spc300/libbb/get_console.c
new file mode 100644
index 0000000000..36fe204265
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/get_console.c
@@ -0,0 +1,82 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people. If you wrote this, please
+ * acknowledge your work.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* From <linux/kd.h> */
+enum { KDGKBTYPE = 0x4B33 }; /* get keyboard type */
+
+
+static int open_a_console(const char *fnam)
+{
+ int fd;
+
+ /* try read-write */
+ fd = open(fnam, O_RDWR);
+
+ /* if failed, try read-only */
+ if (fd < 0 && errno == EACCES)
+ fd = open(fnam, O_RDONLY);
+
+ /* if failed, try write-only */
+ if (fd < 0 && errno == EACCES)
+ fd = open(fnam, O_WRONLY);
+
+ return fd;
+}
+
+/*
+ * Get an fd for use with kbd/console ioctls.
+ * We try several things because opening /dev/console will fail
+ * if someone else used X (which does a chown on /dev/console).
+ */
+
+int get_console_fd(void)
+{
+ static const char *const console_names[] = {
+ DEV_CONSOLE, CURRENT_VC, CURRENT_TTY
+ };
+
+ int fd;
+
+ for (fd = 2; fd >= 0; fd--) {
+ int fd4name;
+ int choice_fd;
+ char arg;
+
+ fd4name = open_a_console(console_names[fd]);
+ chk_std:
+ choice_fd = (fd4name >= 0 ? fd4name : fd);
+
+ arg = 0;
+ if (ioctl(choice_fd, KDGKBTYPE, &arg) == 0)
+ return choice_fd;
+ if (fd4name >= 0) {
+ close(fd4name);
+ fd4name = -1;
+ goto chk_std;
+ }
+ }
+
+ bb_error_msg("can't open console");
+ return fd; /* total failure */
+}
+
+/* From <linux/vt.h> */
+enum {
+ VT_ACTIVATE = 0x5606, /* make vt active */
+ VT_WAITACTIVE = 0x5607 /* wait for vt active */
+};
+
+void console_make_active(int fd, const int vt_num)
+{
+ xioctl(fd, VT_ACTIVATE, (void *)(ptrdiff_t)vt_num);
+ xioctl(fd, VT_WAITACTIVE, (void *)(ptrdiff_t)vt_num);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/get_last_path_component.c b/cleopatre/busybox-1.11.1-spc300/libbb/get_last_path_component.c
new file mode 100644
index 0000000000..0f602157d9
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/get_last_path_component.c
@@ -0,0 +1,42 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bb_get_last_path_component implementation for busybox
+ *
+ * Copyright (C) 2001 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+/*
+ * "/" -> "/"
+ * "abc" -> "abc"
+ * "abc/def" -> "def"
+ * "abc/def/" -> ""
+ */
+char *bb_get_last_path_component_nostrip(const char *path)
+{
+ char *slash = strrchr(path, '/');
+
+ if (!slash || (slash == path && !slash[1]))
+ return (char*)path;
+
+ return slash + 1;
+}
+
+/*
+ * "/" -> "/"
+ * "abc" -> "abc"
+ * "abc/def" -> "def"
+ * "abc/def/" -> "def" !!
+ */
+char *bb_get_last_path_component_strip(char *path)
+{
+ char *slash = last_char_is(path, '/');
+
+ if (slash)
+ while (*slash == '/' && slash != path)
+ *slash-- = '\0';
+
+ return bb_get_last_path_component_nostrip(path);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/get_line_from_file.c b/cleopatre/busybox-1.11.1-spc300/libbb/get_line_from_file.c
new file mode 100644
index 0000000000..b88872d531
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/get_line_from_file.c
@@ -0,0 +1,69 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2005, 2006 Rob Landley <rob@landley.net>
+ * Copyright (C) 2004 Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2001 Matt Krai
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* This function reads an entire line from a text file, up to a newline
+ * or NUL byte, inclusive. It returns a malloc'ed char * which
+ * must be free'ed by the caller. If end is NULL '\n' isn't considered
+ * end of line. If end isn't NULL, length of the chunk read is stored in it.
+ * Return NULL if EOF/error */
+char *bb_get_chunk_from_file(FILE *file, int *end)
+{
+ int ch;
+ int idx = 0;
+ char *linebuf = NULL;
+ int linebufsz = 0;
+
+ while ((ch = getc(file)) != EOF) {
+ /* grow the line buffer as necessary */
+ if (idx >= linebufsz) {
+ linebufsz += 80;
+ linebuf = xrealloc(linebuf, linebufsz);
+ }
+ linebuf[idx++] = (char) ch;
+ if (!ch || (end && ch == '\n'))
+ break;
+ }
+ if (end)
+ *end = idx;
+ if (linebuf) {
+ // huh, does fgets discard prior data on error like this?
+ // I don't think so....
+ //if (ferror(file)) {
+ // free(linebuf);
+ // return NULL;
+ //}
+ linebuf = xrealloc(linebuf, idx+1);
+ linebuf[idx] = '\0';
+ }
+ return linebuf;
+}
+
+/* Get line, including trailing \n if any */
+char *xmalloc_fgets(FILE *file)
+{
+ int i;
+
+ return bb_get_chunk_from_file(file, &i);
+}
+
+/* Get line. Remove trailing \n */
+char *xmalloc_fgetline(FILE *file)
+{
+ int i;
+ char *c = bb_get_chunk_from_file(file, &i);
+
+ if (i && c[--i] == '\n')
+ c[i] = '\0';
+
+ return c;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/getopt32.c b/cleopatre/busybox-1.11.1-spc300/libbb/getopt32.c
new file mode 100644
index 0000000000..86c33483ba
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/getopt32.c
@@ -0,0 +1,605 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * universal getopt32 implementation for busybox
+ *
+ * Copyright (C) 2003-2005 Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include <getopt.h>
+#include "libbb.h"
+
+/* Documentation
+
+uint32_t
+getopt32(char **argv, const char *applet_opts, ...)
+
+ The command line options must be declared in const char
+ *applet_opts as a string of chars, for example:
+
+ flags = getopt32(argv, "rnug");
+
+ If one of the given options is found, a flag value is added to
+ the return value (an unsigned long).
+
+ The flag value is determined by the position of the char in
+ applet_opts string. For example, in the above case:
+
+ flags = getopt32(argv, "rnug");
+
+ "r" will add 1 (bit 0)
+ "n" will add 2 (bit 1)
+ "u" will add 4 (bit 2)
+ "g" will add 8 (bit 3)
+
+ and so on. You can also look at the return value as a bit
+ field and each option sets one bit.
+
+ On exit, global variable optind is set so that if you
+ will do argc -= optind; argv += optind; then
+ argc will be equal to number of remaining non-option
+ arguments, first one would be in argv[0], next in argv[1] and so on
+ (options and their parameters will be moved into argv[]
+ positions prior to argv[optind]).
+
+ ":" If one of the options requires an argument, then add a ":"
+ after the char in applet_opts and provide a pointer to store
+ the argument. For example:
+
+ char *pointer_to_arg_for_a;
+ char *pointer_to_arg_for_b;
+ char *pointer_to_arg_for_c;
+ char *pointer_to_arg_for_d;
+
+ flags = getopt32(argv, "a:b:c:d:",
+ &pointer_to_arg_for_a, &pointer_to_arg_for_b,
+ &pointer_to_arg_for_c, &pointer_to_arg_for_d);
+
+ The type of the pointer (char* or llist_t*) may be controlled
+ by the "::" special separator that is set in the external string
+ opt_complementary (see below for more info).
+
+ "::" If option can have an *optional* argument, then add a "::"
+ after its char in applet_opts and provide a pointer to store
+ the argument. Note that optional arguments _must_
+ immediately follow the option: -oparam, not -o param.
+
+ "+" If the first character in the applet_opts string is a plus,
+ then option processing will stop as soon as a non-option is
+ encountered in the argv array. Useful for applets like env
+ which should not process arguments to subprograms:
+ env -i ls -d /
+ Here we want env to process just the '-i', not the '-d'.
+
+const char *applet_long_options
+
+ This struct allows you to define long options:
+
+ static const char applet_longopts[] ALIGN1 =
+ //"name\0" has_arg val
+ "verbose\0" No_argument "v"
+ ;
+ applet_long_options = applet_longopts;
+
+ The last member of struct option (val) typically is set to
+ matching short option from applet_opts. If there is no matching
+ char in applet_opts, then:
+ - return bit have next position after short options
+ - if has_arg is not "No_argument", use ptr for arg also
+ - opt_complementary affects it too
+
+ Note: a good applet will make long options configurable via the
+ config process and not a required feature. The current standard
+ is to name the config option CONFIG_FEATURE_<applet>_LONG_OPTIONS.
+
+const char *opt_complementary
+
+ ":" The colon (":") is used to separate groups of two or more chars
+ and/or groups of chars and special characters (stating some
+ conditions to be checked).
+
+ "abc" If groups of two or more chars are specified, the first char
+ is the main option and the other chars are secondary options.
+ Their flags will be turned on if the main option is found even
+ if they are not specifed on the command line. For example:
+
+ opt_complementary = "abc";
+ flags = getopt32(argv, "abcd")
+
+ If getopt() finds "-a" on the command line, then
+ getopt32's return value will be as if "-a -b -c" were
+ found.
+
+ "ww" Adjacent double options have a counter associated which indicates
+ the number of occurences of the option.
+ For example the ps applet needs:
+ if w is given once, GNU ps sets the width to 132,
+ if w is given more than once, it is "unlimited"
+
+ int w_counter = 0; // must be initialized!
+ opt_complementary = "ww";
+ getopt32(argv, "w", &w_counter);
+ if (w_counter)
+ width = (w_counter == 1) ? 132 : INT_MAX;
+ else
+ get_terminal_width(...&width...);
+
+ w_counter is a pointer to an integer. It has to be passed to
+ getopt32() after all other option argument sinks.
+
+ For example: accept multiple -v to indicate the level of verbosity
+ and for each -b optarg, add optarg to my_b. Finally, if b is given,
+ turn off c and vice versa:
+
+ llist_t *my_b = NULL;
+ int verbose_level = 0;
+ opt_complementary = "vv:b::b-c:c-b";
+ f = getopt32(argv, "vb:c", &my_b, &verbose_level);
+ if (f & 2) // -c after -b unsets -b flag
+ while (my_b) dosomething_with(llist_pop(&my_b));
+ if (my_b) // but llist is stored if -b is specified
+ free_llist(my_b);
+ if (verbose_level) printf("verbose level is %d\n", verbose_level);
+
+Special characters:
+
+ "-" A dash as the first char in a opt_complementary group forces
+ all arguments to be treated as options, even if they have
+ no leading dashes. Next char in this case can't be a digit (0-9),
+ use ':' or end of line. For example:
+
+ opt_complementary = "-:w-x:x-w";
+ getopt32(argv, "wx");
+
+ Allows any arguments to be given without a dash (./program w x)
+ as well as with a dash (./program -x).
+
+ "--" A double dash at the beginning of opt_complementary means the
+ argv[1] string should always be treated as options, even if it isn't
+ prefixed with a "-". This is useful for special syntax in applets
+ such as "ar" and "tar":
+ tar xvf foo.tar
+
+ "-N" A dash as the first char in a opt_complementary group followed
+ by a single digit (0-9) means that at least N non-option
+ arguments must be present on the command line
+
+ "=N" An equal sign as the first char in a opt_complementary group followed
+ by a single digit (0-9) means that exactly N non-option
+ arguments must be present on the command line
+
+ "?N" A "?" as the first char in a opt_complementary group followed
+ by a single digit (0-9) means that at most N arguments must be present
+ on the command line.
+
+ "V-" An option with dash before colon or end-of-line results in
+ bb_show_usage being called if this option is encountered.
+ This is typically used to implement "print verbose usage message
+ and exit" option.
+
+ "a-b" A dash between two options causes the second of the two
+ to be unset (and ignored) if it is given on the command line.
+
+ [FIXME: what if they are the same? like "x-x"? Is it ever useful?]
+
+ For example:
+ The du applet has the options "-s" and "-d depth". If
+ getopt32 finds -s, then -d is unset or if it finds -d
+ then -s is unset. (Note: busybox implements the GNU
+ "--max-depth" option as "-d".) To obtain this behavior, you
+ set opt_complementary = "s-d:d-s". Only one flag value is
+ added to getopt32's return value depending on the
+ position of the options on the command line. If one of the
+ two options requires an argument pointer (":" in applet_opts
+ as in "d:") optarg is set accordingly.
+
+ char *smax_print_depth;
+
+ opt_complementary = "s-d:d-s:x-x";
+ opt = getopt32(argv, "sd:x", &smax_print_depth);
+
+ if (opt & 2)
+ max_print_depth = atoi(smax_print_depth);
+ if (opt & 4)
+ printf("Detected odd -x usage\n");
+
+ "a--b" A double dash between two options, or between an option and a group
+ of options, means that they are mutually exclusive. Unlike
+ the "-" case above, an error will be forced if the options
+ are used together.
+
+ For example:
+ The cut applet must have only one type of list specified, so
+ -b, -c and -f are mutually exclusive and should raise an error
+ if specified together. In this case you must set
+ opt_complementary = "b--cf:c--bf:f--bc". If two of the
+ mutually exclusive options are found, getopt32 will call
+ bb_show_usage() and die.
+
+ "x--x" Variation of the above, it means that -x option should occur
+ at most once.
+
+ "a+" A plus after a char in opt_complementary means that the parameter
+ for this option is a nonnegative integer. It will be processed
+ with xatoi_u() - allowed range is 0..INT_MAX.
+
+ int param; // "unsigned param;" will also work
+ opt_complementary = "p+";
+ getopt32(argv, "p:", &param);
+
+ "a::" A double colon after a char in opt_complementary means that the
+ option can occur multiple times. Each occurrence will be saved as
+ a llist_t element instead of char*.
+
+ For example:
+ The grep applet can have one or more "-e pattern" arguments.
+ In this case you should use getopt32() as follows:
+
+ llist_t *patterns = NULL;
+
+ (this pointer must be initializated to NULL if the list is empty
+ as required by llist_add_to_end(llist_t **old_head, char *new_item).)
+
+ opt_complementary = "e::";
+
+ getopt32(argv, "e:", &patterns);
+ $ grep -e user -e root /etc/passwd
+ root:x:0:0:root:/root:/bin/bash
+ user:x:500:500::/home/user:/bin/bash
+
+ "a?b" A "?" between an option and a group of options means that
+ at least one of them is required to occur if the first option
+ occurs in preceding command line arguments.
+
+ For example from "id" applet:
+
+ // Don't allow -n -r -rn -ug -rug -nug -rnug
+ opt_complementary = "r?ug:n?ug:u--g:g--u";
+ flags = getopt32(argv, "rnug");
+
+ This example allowed only:
+ $ id; id -u; id -g; id -ru; id -nu; id -rg; id -ng; id -rnu; id -rng
+
+ "X" A opt_complementary group with just a single letter means
+ that this option is required. If more than one such group exists,
+ at least one option is required to occur (not all of them).
+ For example from "start-stop-daemon" applet:
+
+ // Don't allow -KS -SK, but -S or -K is required
+ opt_complementary = "K:S:K--S:S--K";
+ flags = getopt32(argv, "KS...);
+
+
+ Don't forget to use ':'. For example, "?322-22-23X-x-a"
+ is interpreted as "?3:22:-2:2-2:2-3Xa:2--x" -
+ max 3 args; count uses of '-2'; min 2 args; if there is
+ a '-2' option then unset '-3', '-X' and '-a'; if there is
+ a '-2' and after it a '-x' then error out.
+ But it's far too obfuscated. Use ':' to separate groups.
+*/
+
+/* Code here assumes that 'unsigned' is at least 32 bits wide */
+
+const char *const bb_argv_dash[] = { "-", NULL };
+
+const char *opt_complementary;
+
+/* Many small applets don't want to suck in stdio.h only because
+ * they need to parse options by calling us */
+#define DONT_USE_PRINTF 1
+
+enum {
+ PARAM_STRING,
+ PARAM_LIST,
+ PARAM_INT,
+};
+
+typedef struct {
+ unsigned char opt_char;
+ smallint param_type;
+ unsigned switch_on;
+ unsigned switch_off;
+ unsigned incongruously;
+ unsigned requires;
+ void **optarg; /* char**, llist_t** or int *. */
+ int *counter;
+} t_complementary;
+
+/* You can set applet_long_options for parse called long options */
+#if ENABLE_GETOPT_LONG
+static const struct option bb_null_long_options[1] = {
+ { 0, 0, 0, 0 }
+};
+const char *applet_long_options;
+#endif
+
+uint32_t option_mask32;
+
+uint32_t
+getopt32(char **argv, const char *applet_opts, ...)
+{
+ int argc;
+ unsigned flags = 0;
+ unsigned requires = 0;
+ t_complementary complementary[33];
+ int c;
+ const unsigned char *s;
+ t_complementary *on_off;
+ va_list p;
+#if ENABLE_GETOPT_LONG
+ const struct option *l_o;
+ struct option *long_options = (struct option *) &bb_null_long_options;
+#endif
+ unsigned trigger;
+ char **pargv = NULL;
+ int min_arg = 0;
+ int max_arg = -1;
+
+#define SHOW_USAGE_IF_ERROR 1
+#define ALL_ARGV_IS_OPTS 2
+#define FIRST_ARGV_IS_OPT 4
+#define FREE_FIRST_ARGV_IS_OPT (8 * !DONT_USE_PRINTF)
+
+ int spec_flgs = 0;
+
+ argc = 0;
+ while (argv[argc])
+ argc++;
+
+ va_start(p, applet_opts);
+
+ c = 0;
+ on_off = complementary;
+ memset(on_off, 0, sizeof(complementary));
+
+ /* skip GNU extension */
+ s = (const unsigned char *)applet_opts;
+ if (*s == '+' || *s == '-')
+ s++;
+ while (*s) {
+ if (c >= 32)
+ break;
+ on_off->opt_char = *s;
+ on_off->switch_on = (1 << c);
+ if (*++s == ':') {
+ on_off->optarg = va_arg(p, void **);
+ while (*++s == ':')
+ continue;
+ }
+ on_off++;
+ c++;
+ }
+
+#if ENABLE_GETOPT_LONG
+ if (applet_long_options) {
+ const char *optstr;
+ unsigned i, count;
+
+ count = 1;
+ optstr = applet_long_options;
+ while (optstr[0]) {
+ optstr += strlen(optstr) + 3; /* skip NUL, has_arg, val */
+ count++;
+ }
+ /* count == no. of longopts + 1 */
+ long_options = alloca(count * sizeof(*long_options));
+ memset(long_options, 0, count * sizeof(*long_options));
+ i = 0;
+ optstr = applet_long_options;
+ while (--count) {
+ long_options[i].name = optstr;
+ optstr += strlen(optstr) + 1;
+ long_options[i].has_arg = (unsigned char)(*optstr++);
+ /* long_options[i].flag = NULL; */
+ long_options[i].val = (unsigned char)(*optstr++);
+ i++;
+ }
+ for (l_o = long_options; l_o->name; l_o++) {
+ if (l_o->flag)
+ continue;
+ for (on_off = complementary; on_off->opt_char; on_off++)
+ if (on_off->opt_char == l_o->val)
+ goto next_long;
+ if (c >= 32)
+ break;
+ on_off->opt_char = l_o->val;
+ on_off->switch_on = (1 << c);
+ if (l_o->has_arg != no_argument)
+ on_off->optarg = va_arg(p, void **);
+ c++;
+ next_long: ;
+ }
+ }
+#endif /* ENABLE_GETOPT_LONG */
+ for (s = (const unsigned char *)opt_complementary; s && *s; s++) {
+ t_complementary *pair;
+ unsigned *pair_switch;
+
+ if (*s == ':')
+ continue;
+ c = s[1];
+ if (*s == '?') {
+ if (c < '0' || c > '9') {
+ spec_flgs |= SHOW_USAGE_IF_ERROR;
+ } else {
+ max_arg = c - '0';
+ s++;
+ }
+ continue;
+ }
+ if (*s == '-') {
+ if (c < '0' || c > '9') {
+ if (c == '-') {
+ spec_flgs |= FIRST_ARGV_IS_OPT;
+ s++;
+ } else
+ spec_flgs |= ALL_ARGV_IS_OPTS;
+ } else {
+ min_arg = c - '0';
+ s++;
+ }
+ continue;
+ }
+ if (*s == '=') {
+ min_arg = max_arg = c - '0';
+ s++;
+ continue;
+ }
+ for (on_off = complementary; on_off->opt_char; on_off++)
+ if (on_off->opt_char == *s)
+ break;
+ if (c == ':' && s[2] == ':') {
+ on_off->param_type = PARAM_LIST;
+ continue;
+ }
+ if (c == '+' && (s[2] == ':' || s[2] == '\0')) {
+ on_off->param_type = PARAM_INT;
+ continue;
+ }
+ if (c == ':' || c == '\0') {
+ requires |= on_off->switch_on;
+ continue;
+ }
+ if (c == '-' && (s[2] == ':' || s[2] == '\0')) {
+ flags |= on_off->switch_on;
+ on_off->incongruously |= on_off->switch_on;
+ s++;
+ continue;
+ }
+ if (c == *s) {
+ on_off->counter = va_arg(p, int *);
+ s++;
+ }
+ pair = on_off;
+ pair_switch = &(pair->switch_on);
+ for (s++; *s && *s != ':'; s++) {
+ if (*s == '?') {
+ pair_switch = &(pair->requires);
+ } else if (*s == '-') {
+ if (pair_switch == &(pair->switch_off))
+ pair_switch = &(pair->incongruously);
+ else
+ pair_switch = &(pair->switch_off);
+ } else {
+ for (on_off = complementary; on_off->opt_char; on_off++)
+ if (on_off->opt_char == *s) {
+ *pair_switch |= on_off->switch_on;
+ break;
+ }
+ }
+ }
+ s--;
+ }
+ va_end(p);
+
+ if (spec_flgs & FIRST_ARGV_IS_OPT) {
+ if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0') {
+#if DONT_USE_PRINTF
+ char *pp = alloca(strlen(argv[1]) + 2);
+ *pp = '-';
+ strcpy(pp + 1, argv[1]);
+ argv[1] = pp;
+#else
+ argv[1] = xasprintf("-%s", argv[1]);
+ spec_flgs |= FREE_FIRST_ARGV_IS_OPT;
+#endif
+ }
+ }
+
+ /* In case getopt32 was already called:
+ * reset the libc getopt() function, which keeps internal state.
+ *
+ * BSD-derived getopt() functions require that optind be set to 1 in
+ * order to reset getopt() state. This used to be generally accepted
+ * way of resetting getopt(). However, glibc's getopt()
+ * has additional getopt() state beyond optind, and requires that
+ * optind be set to zero to reset its state. So the unfortunate state of
+ * affairs is that BSD-derived versions of getopt() misbehave if
+ * optind is set to 0 in order to reset getopt(), and glibc's getopt()
+ * will core dump if optind is set 1 in order to reset getopt().
+ *
+ * More modern versions of BSD require that optreset be set to 1 in
+ * order to reset getopt(). Sigh. Standards, anyone?
+ */
+#ifdef __GLIBC__
+ optind = 0;
+#else /* BSD style */
+ optind = 1;
+ /* optreset = 1; */
+#endif
+ /* optarg = NULL; opterr = 0; optopt = 0; - do we need this?? */
+
+ /* Note: just "getopt() <= 0" will not work well for
+ * "fake" short options, like this one:
+ * wget $'-\203' "Test: test" http://kernel.org/
+ * (supposed to act as --header, but doesn't) */
+#if ENABLE_GETOPT_LONG
+ while ((c = getopt_long(argc, argv, applet_opts,
+ long_options, NULL)) != -1) {
+#else
+ while ((c = getopt(argc, argv, applet_opts)) != -1) {
+#endif
+ c &= 0xff; /* fight libc's sign extension */
+ loop_arg_is_opt:
+ for (on_off = complementary; on_off->opt_char != c; on_off++) {
+ /* c==0 if long opt have non NULL flag */
+ if (on_off->opt_char == '\0' && c != '\0')
+ bb_show_usage();
+ }
+ if (flags & on_off->incongruously)
+ bb_show_usage();
+ trigger = on_off->switch_on & on_off->switch_off;
+ flags &= ~(on_off->switch_off ^ trigger);
+ flags |= on_off->switch_on ^ trigger;
+ flags ^= trigger;
+ if (on_off->counter)
+ (*(on_off->counter))++;
+ if (on_off->param_type == PARAM_LIST) {
+ if (optarg)
+ llist_add_to_end((llist_t **)(on_off->optarg), optarg);
+ } else if (on_off->param_type == PARAM_INT) {
+ if (optarg)
+//TODO: xatoi_u indirectly pulls in printf machinery
+ *(unsigned*)(on_off->optarg) = xatoi_u(optarg);
+ } else if (on_off->optarg) {
+ if (optarg)
+ *(char **)(on_off->optarg) = optarg;
+ }
+ if (pargv != NULL)
+ break;
+ }
+
+ if (spec_flgs & ALL_ARGV_IS_OPTS) {
+ /* process argv is option, for example "ps" applet */
+ if (pargv == NULL)
+ pargv = argv + optind;
+ while (*pargv) {
+ c = **pargv;
+ if (c == '\0') {
+ pargv++;
+ } else {
+ (*pargv)++;
+ goto loop_arg_is_opt;
+ }
+ }
+ }
+
+ if (spec_flgs & FREE_FIRST_ARGV_IS_OPT)
+ free(argv[1]);
+
+ /* check depending requires for given options */
+ for (on_off = complementary; on_off->opt_char; on_off++) {
+ if (on_off->requires && (flags & on_off->switch_on) &&
+ (flags & on_off->requires) == 0)
+ bb_show_usage();
+ }
+ if (requires && (flags & requires) == 0)
+ bb_show_usage();
+ argc -= optind;
+ if (argc < min_arg || (max_arg >= 0 && argc > max_arg))
+ bb_show_usage();
+
+ option_mask32 = flags;
+ return flags;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/getpty.c b/cleopatre/busybox-1.11.1-spc300/libbb/getpty.c
new file mode 100644
index 0000000000..d43fb825f0
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/getpty.c
@@ -0,0 +1,60 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini getpty implementation for busybox
+ * Bjorn Wesen, Axis Communications AB (bjornw@axis.com)
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+#define DEBUG 0
+
+int xgetpty(char *line)
+{
+ int p;
+#if ENABLE_FEATURE_DEVPTS
+ p = open("/dev/ptmx", O_RDWR);
+ if (p > 0) {
+ const char *name;
+ grantpt(p);
+ unlockpt(p);
+ name = ptsname(p);
+ if (!name) {
+ bb_perror_msg("ptsname error (is /dev/pts mounted?)");
+ goto fail;
+ }
+ safe_strncpy(line, name, GETPTY_BUFSIZE);
+ return p;
+ }
+#else
+ struct stat stb;
+ int i;
+ int j;
+
+ strcpy(line, "/dev/ptyXX");
+
+ for (i = 0; i < 16; i++) {
+ line[8] = "pqrstuvwxyzabcde"[i];
+ line[9] = '0';
+ if (stat(line, &stb) < 0) {
+ continue;
+ }
+ for (j = 0; j < 16; j++) {
+ line[9] = j < 10 ? j + '0' : j - 10 + 'a';
+ if (DEBUG)
+ fprintf(stderr, "Trying to open device: %s\n", line);
+ p = open(line, O_RDWR | O_NOCTTY);
+ if (p >= 0) {
+ line[5] = 't';
+ return p;
+ }
+ }
+ }
+#endif /* FEATURE_DEVPTS */
+USE_FEATURE_DEVPTS( fail:)
+ bb_error_msg_and_die("open pty");
+ return -1; /* never get here */
+}
+
+
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/herror_msg.c b/cleopatre/busybox-1.11.1-spc300/libbb/herror_msg.c
new file mode 100644
index 0000000000..264690ba0a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/herror_msg.c
@@ -0,0 +1,19 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+void bb_herror_msg(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ bb_verror_msg(s, p, hstrerror(h_errno));
+ va_end(p);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/herror_msg_and_die.c b/cleopatre/busybox-1.11.1-spc300/libbb/herror_msg_and_die.c
new file mode 100644
index 0000000000..894c80f389
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/herror_msg_and_die.c
@@ -0,0 +1,20 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+void bb_herror_msg_and_die(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ bb_verror_msg(s, p, hstrerror(h_errno));
+ va_end(p);
+ xfunc_die();
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/human_readable.c b/cleopatre/busybox-1.11.1-spc300/libbb/human_readable.c
new file mode 100644
index 0000000000..d60ef61d7f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/human_readable.c
@@ -0,0 +1,88 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * June 30, 2001 Manuel Novoa III
+ *
+ * All-integer version (hey, not everyone has floating point) of
+ * make_human_readable_str, modified from similar code I had written
+ * for busybox several months ago.
+ *
+ * Notes:
+ * 1) I'm using an unsigned long long to hold the product size * block_size,
+ * as df (which calls this routine) could request a representation of a
+ * partition size in bytes > max of unsigned long. If long longs aren't
+ * available, it would be possible to do what's needed using polynomial
+ * representations (say, powers of 1024) and manipulating coefficients.
+ * The base ten "bytes" output could be handled similarly.
+ *
+ * 2) This routine always outputs a decimal point and a tenths digit when
+ * display_unit != 0. Hence, it isn't uncommon for the returned string
+ * to have a length of 5 or 6.
+ *
+ * It might be nice to add a flag to indicate no decimal digits in
+ * that case. This could be either an additional parameter, or a
+ * special value of display_unit. Such a flag would also be nice for du.
+ *
+ * Some code to omit the decimal point and tenths digit is sketched out
+ * and "#if 0"'d below.
+ */
+
+#include "libbb.h"
+
+const char *make_human_readable_str(unsigned long long size,
+ unsigned long block_size, unsigned long display_unit)
+{
+ /* The code will adjust for additional (appended) units */
+ static const char zero_and_units[] ALIGN1 = { '0', 0, 'k', 'M', 'G', 'T' };
+ static const char fmt[] ALIGN1 = "%llu";
+ static const char fmt_tenths[] ALIGN1 = "%llu.%d%c";
+
+ static char str[21] ALIGN1; /* Sufficient for 64 bit unsigned integers */
+
+ unsigned long long val;
+ int frac;
+ const char *u;
+ const char *f;
+
+ u = zero_and_units;
+ f = fmt;
+ frac = 0;
+
+ val = size * block_size;
+ if (val == 0) {
+ return u;
+ }
+
+ if (display_unit) {
+ val += display_unit/2; /* Deal with rounding */
+ val /= display_unit; /* Don't combine with the line above!!! */
+ } else {
+ ++u;
+ while ((val >= 1024)
+ && (u < zero_and_units + sizeof(zero_and_units) - 1)
+ ) {
+ f = fmt_tenths;
+ ++u;
+ frac = (((int)(val % 1024)) * 10 + 1024/2) / 1024;
+ val /= 1024;
+ }
+ if (frac >= 10) { /* We need to round up here. */
+ ++val;
+ frac = 0;
+ }
+#if 0
+ /* Sample code to omit decimal point and tenths digit. */
+ if (/* no_tenths */ 1) {
+ if (frac >= 5) {
+ ++val;
+ }
+ f = "%llu%*c" /* fmt_no_tenths */;
+ frac = 1;
+ }
+#endif
+ }
+
+ /* If f==fmt then 'frac' and 'u' are ignored. */
+ snprintf(str, sizeof(str), f, val, frac, *u);
+
+ return str;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/inet_common.c b/cleopatre/busybox-1.11.1-spc300/libbb/inet_common.c
new file mode 100644
index 0000000000..9c4f49649d
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/inet_common.c
@@ -0,0 +1,224 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * stolen from net-tools-1.59 and stripped down for busybox by
+ * Erik Andersen <andersen@codepoet.org>
+ *
+ * Heavily modified by Manuel Novoa III Mar 12, 2001
+ *
+ *
+ */
+
+#include "libbb.h"
+#include "inet_common.h"
+
+int INET_resolve(const char *name, struct sockaddr_in *s_in, int hostfirst)
+{
+ struct hostent *hp;
+#if ENABLE_FEATURE_ETC_NETWORKS
+ struct netent *np;
+#endif
+
+ /* Grmpf. -FvK */
+ s_in->sin_family = AF_INET;
+ s_in->sin_port = 0;
+
+ /* Default is special, meaning 0.0.0.0. */
+ if (!strcmp(name, bb_str_default)) {
+ s_in->sin_addr.s_addr = INADDR_ANY;
+ return 1;
+ }
+ /* Look to see if it's a dotted quad. */
+ if (inet_aton(name, &s_in->sin_addr)) {
+ return 0;
+ }
+ /* If we expect this to be a hostname, try hostname database first */
+#ifdef DEBUG
+ if (hostfirst) {
+ bb_error_msg("gethostbyname(%s)", name);
+ }
+#endif
+ if (hostfirst) {
+ hp = gethostbyname(name);
+ if (hp != NULL) {
+ memcpy(&s_in->sin_addr, hp->h_addr_list[0],
+ sizeof(struct in_addr));
+ return 0;
+ }
+ }
+#if ENABLE_FEATURE_ETC_NETWORKS
+ /* Try the NETWORKS database to see if this is a known network. */
+#ifdef DEBUG
+ bb_error_msg("getnetbyname(%s)", name);
+#endif
+ np = getnetbyname(name);
+ if (np != NULL) {
+ s_in->sin_addr.s_addr = htonl(np->n_net);
+ return 1;
+ }
+#endif
+ if (hostfirst) {
+ /* Don't try again */
+ return -1;
+ }
+#ifdef DEBUG
+ res_init();
+ _res.options |= RES_DEBUG;
+#endif
+
+#ifdef DEBUG
+ bb_error_msg("gethostbyname(%s)", name);
+#endif
+ hp = gethostbyname(name);
+ if (hp == NULL) {
+ return -1;
+ }
+ memcpy(&s_in->sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
+ return 0;
+}
+
+
+/* numeric: & 0x8000: default instead of *,
+ * & 0x4000: host instead of net,
+ * & 0x0fff: don't resolve
+ */
+char *INET_rresolve(struct sockaddr_in *s_in, int numeric, uint32_t netmask)
+{
+ /* addr-to-name cache */
+ struct addr {
+ struct addr *next;
+ struct sockaddr_in addr;
+ int host;
+ char name[1];
+ };
+ static struct addr *cache = NULL;
+
+ struct addr *pn;
+ char *name;
+ uint32_t ad, host_ad;
+ int host = 0;
+
+ if (s_in->sin_family != AF_INET) {
+#ifdef DEBUG
+ bb_error_msg("rresolve: unsupported address family %d!",
+ s_in->sin_family);
+#endif
+ errno = EAFNOSUPPORT;
+ return NULL;
+ }
+ ad = s_in->sin_addr.s_addr;
+#ifdef DEBUG
+ bb_error_msg("rresolve: %08x, mask %08x, num %08x", (unsigned)ad, netmask, numeric);
+#endif
+ if (ad == INADDR_ANY) {
+ if ((numeric & 0x0FFF) == 0) {
+ if (numeric & 0x8000)
+ return xstrdup(bb_str_default);
+ return xstrdup("*");
+ }
+ }
+ if (numeric & 0x0FFF)
+ return xstrdup(inet_ntoa(s_in->sin_addr));
+
+ if ((ad & (~netmask)) != 0 || (numeric & 0x4000))
+ host = 1;
+ pn = cache;
+ while (pn) {
+ if (pn->addr.sin_addr.s_addr == ad && pn->host == host) {
+#ifdef DEBUG
+ bb_error_msg("rresolve: found %s %08x in cache",
+ (host ? "host" : "net"), (unsigned)ad);
+#endif
+ return xstrdup(pn->name);
+ }
+ pn = pn->next;
+ }
+
+ host_ad = ntohl(ad);
+ name = NULL;
+ if (host) {
+ struct hostent *ent;
+#ifdef DEBUG
+ bb_error_msg("gethostbyaddr (%08x)", (unsigned)ad);
+#endif
+ ent = gethostbyaddr((char *) &ad, 4, AF_INET);
+ if (ent)
+ name = xstrdup(ent->h_name);
+ } else if (ENABLE_FEATURE_ETC_NETWORKS) {
+ struct netent *np;
+#ifdef DEBUG
+ bb_error_msg("getnetbyaddr (%08x)", (unsigned)host_ad);
+#endif
+ np = getnetbyaddr(host_ad, AF_INET);
+ if (np)
+ name = xstrdup(np->n_name);
+ }
+ if (!name)
+ name = xstrdup(inet_ntoa(s_in->sin_addr));
+ pn = xmalloc(sizeof(*pn) + strlen(name)); /* no '+ 1', it's already accounted for */
+ pn->next = cache;
+ pn->addr = *s_in;
+ pn->host = host;
+ strcpy(pn->name, name);
+ cache = pn;
+ return name;
+}
+
+#if ENABLE_FEATURE_IPV6
+
+int INET6_resolve(const char *name, struct sockaddr_in6 *sin6)
+{
+ struct addrinfo req, *ai;
+ int s;
+
+ memset(&req, '\0', sizeof req);
+ req.ai_family = AF_INET6;
+ s = getaddrinfo(name, NULL, &req, &ai);
+ if (s) {
+ bb_error_msg("getaddrinfo: %s: %d", name, s);
+ return -1;
+ }
+ memcpy(sin6, ai->ai_addr, sizeof(struct sockaddr_in6));
+ freeaddrinfo(ai);
+ return 0;
+}
+
+#ifndef IN6_IS_ADDR_UNSPECIFIED
+# define IN6_IS_ADDR_UNSPECIFIED(a) \
+ (((uint32_t *) (a))[0] == 0 && ((uint32_t *) (a))[1] == 0 && \
+ ((uint32_t *) (a))[2] == 0 && ((uint32_t *) (a))[3] == 0)
+#endif
+
+
+char *INET6_rresolve(struct sockaddr_in6 *sin6, int numeric)
+{
+ char name[128];
+ int s;
+
+ if (sin6->sin6_family != AF_INET6) {
+#ifdef DEBUG
+ bb_error_msg("rresolve: unsupport address family %d!",
+ sin6->sin6_family);
+#endif
+ errno = EAFNOSUPPORT;
+ return NULL;
+ }
+ if (numeric & 0x7FFF) {
+ inet_ntop(AF_INET6, &sin6->sin6_addr, name, sizeof(name));
+ return xstrdup(name);
+ }
+ if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
+ if (numeric & 0x8000)
+ return xstrdup(bb_str_default);
+ return xstrdup("*");
+ }
+
+ s = getnameinfo((struct sockaddr *) sin6, sizeof(struct sockaddr_in6),
+ name, sizeof(name), NULL, 0, 0);
+ if (s) {
+ bb_error_msg("getnameinfo failed");
+ return NULL;
+ }
+ return xstrdup(name);
+}
+
+#endif /* CONFIG_FEATURE_IPV6 */
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/info_msg.c b/cleopatre/busybox-1.11.1-spc300/libbb/info_msg.c
new file mode 100644
index 0000000000..3231bc8cff
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/info_msg.c
@@ -0,0 +1,30 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include <syslog.h>
+
+void bb_info_msg(const char *s, ...)
+{
+ va_list p;
+ /* va_copy is used because it is not portable
+ * to use va_list p twice */
+ va_list p2;
+
+ va_start(p, s);
+ va_copy(p2, p);
+ if (logmode & LOGMODE_STDIO) {
+ vprintf(s, p);
+ fputs(msg_eol, stdout);
+ }
+ if (ENABLE_FEATURE_SYSLOG && (logmode & LOGMODE_SYSLOG))
+ vsyslog(LOG_INFO, s, p2);
+ va_end(p2);
+ va_end(p);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/inode_hash.c b/cleopatre/busybox-1.11.1-spc300/libbb/inode_hash.c
new file mode 100644
index 0000000000..9cca74bcb4
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/inode_hash.c
@@ -0,0 +1,87 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+typedef struct ino_dev_hash_bucket_struct {
+ struct ino_dev_hash_bucket_struct *next;
+ ino_t ino;
+ dev_t dev;
+ char name[1];
+} ino_dev_hashtable_bucket_t;
+
+#define HASH_SIZE 311 /* Should be prime */
+#define hash_inode(i) ((i) % HASH_SIZE)
+
+/* array of [HASH_SIZE] elements */
+static ino_dev_hashtable_bucket_t **ino_dev_hashtable;
+
+/*
+ * Return name if statbuf->st_ino && statbuf->st_dev are recorded in
+ * ino_dev_hashtable, else return NULL
+ */
+char *is_in_ino_dev_hashtable(const struct stat *statbuf)
+{
+ ino_dev_hashtable_bucket_t *bucket;
+
+ if (!ino_dev_hashtable)
+ return NULL;
+
+ bucket = ino_dev_hashtable[hash_inode(statbuf->st_ino)];
+ while (bucket != NULL) {
+ if ((bucket->ino == statbuf->st_ino)
+ && (bucket->dev == statbuf->st_dev)
+ ) {
+ return bucket->name;
+ }
+ bucket = bucket->next;
+ }
+ return NULL;
+}
+
+/* Add statbuf to statbuf hash table */
+void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name)
+{
+ int i;
+ ino_dev_hashtable_bucket_t *bucket;
+
+ i = hash_inode(statbuf->st_ino);
+ if (!name)
+ name = "";
+ bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + strlen(name));
+ bucket->ino = statbuf->st_ino;
+ bucket->dev = statbuf->st_dev;
+ strcpy(bucket->name, name);
+
+ if (!ino_dev_hashtable)
+ ino_dev_hashtable = xzalloc(HASH_SIZE * sizeof(*ino_dev_hashtable));
+
+ bucket->next = ino_dev_hashtable[i];
+ ino_dev_hashtable[i] = bucket;
+}
+
+#if ENABLE_FEATURE_CLEAN_UP
+/* Clear statbuf hash table */
+void reset_ino_dev_hashtable(void)
+{
+ int i;
+ ino_dev_hashtable_bucket_t *bucket;
+
+ for (i = 0; ino_dev_hashtable && i < HASH_SIZE; i++) {
+ while (ino_dev_hashtable[i] != NULL) {
+ bucket = ino_dev_hashtable[i]->next;
+ free(ino_dev_hashtable[i]);
+ ino_dev_hashtable[i] = bucket;
+ }
+ }
+ free(ino_dev_hashtable);
+ ino_dev_hashtable = NULL;
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/isdirectory.c b/cleopatre/busybox-1.11.1-spc300/libbb/isdirectory.c
new file mode 100644
index 0000000000..1d2477f47a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/isdirectory.c
@@ -0,0 +1,36 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
+ * Permission has been granted to redistribute this code under the GPL.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include <sys/stat.h>
+#include "libbb.h"
+
+/*
+ * Return TRUE if fileName is a directory.
+ * Nonexistent files return FALSE.
+ */
+int is_directory(const char *fileName, const int followLinks, struct stat *statBuf)
+{
+ int status;
+ struct stat astatBuf;
+
+ if (statBuf == NULL) {
+ /* use auto stack buffer */
+ statBuf = &astatBuf;
+ }
+
+ if (followLinks)
+ status = stat(fileName, statBuf);
+ else
+ status = lstat(fileName, statBuf);
+
+ status = (status == 0 && S_ISDIR(statBuf->st_mode));
+
+ return status;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/kernel_version.c b/cleopatre/busybox-1.11.1-spc300/libbb/kernel_version.c
new file mode 100644
index 0000000000..50b82ae184
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/kernel_version.c
@@ -0,0 +1,37 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include <sys/utsname.h> /* for uname(2) */
+
+#include "libbb.h"
+
+/* Returns current kernel version encoded as major*65536 + minor*256 + patch,
+ * so, for example, to check if the kernel is greater than 2.2.11:
+ *
+ * if (get_linux_version_code() > KERNEL_VERSION(2,2,11)) { <stuff> }
+ */
+int get_linux_version_code(void)
+{
+ struct utsname name;
+ char *s;
+ int i, r;
+
+ if (uname(&name) == -1) {
+ bb_perror_msg("cannot get system information");
+ return 0;
+ }
+
+ s = name.release;
+ r = 0;
+ for (i = 0; i < 3; i++) {
+ r = r * 256 + atoi(strtok(s, "."));
+ s = NULL;
+ }
+ return r;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/last_char_is.c b/cleopatre/busybox-1.11.1-spc300/libbb/last_char_is.c
new file mode 100644
index 0000000000..aaa85ddd9c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/last_char_is.c
@@ -0,0 +1,24 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * busybox library eXtended function
+ *
+ * Copyright (C) 2001 Larry Doolittle, <ldoolitt@recycle.lbl.gov>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* Find out if the last character of a string matches the one given.
+ * Don't underrun the buffer if the string length is 0.
+ */
+char* last_char_is(const char *s, int c)
+{
+ if (s && *s) {
+ size_t sz = strlen(s) - 1;
+ s += sz;
+ if ( (unsigned char)*s == c)
+ return (char*)s;
+ }
+ return NULL;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/lineedit.c b/cleopatre/busybox-1.11.1-spc300/libbb/lineedit.c
new file mode 100644
index 0000000000..fb595c0108
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/lineedit.c
@@ -0,0 +1,1906 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Termios command line History and Editing.
+ *
+ * Copyright (c) 1986-2003 may safely be consumed by a BSD or GPL license.
+ * Written by: Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * Used ideas:
+ * Adam Rogoyski <rogoyski@cs.utexas.edu>
+ * Dave Cinege <dcinege@psychosis.com>
+ * Jakub Jelinek (c) 1995
+ * Erik Andersen <andersen@codepoet.org> (Majorly adjusted for busybox)
+ *
+ * This code is 'as is' with no warranty.
+ */
+
+/*
+ Usage and known bugs:
+ Terminal key codes are not extensive, and more will probably
+ need to be added. This version was created on Debian GNU/Linux 2.x.
+ Delete, Backspace, Home, End, and the arrow keys were tested
+ to work in an Xterm and console. Ctrl-A also works as Home.
+ Ctrl-E also works as End.
+
+ Small bugs (simple effect):
+ - not true viewing if terminal size (x*y symbols) less
+ size (prompt + editor's line + 2 symbols)
+ - not true viewing if length prompt less terminal width
+ */
+
+#include "libbb.h"
+
+
+/* FIXME: obsolete CONFIG item? */
+#define ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 0
+
+
+#ifdef TEST
+
+#define ENABLE_FEATURE_EDITING 0
+#define ENABLE_FEATURE_TAB_COMPLETION 0
+#define ENABLE_FEATURE_USERNAME_COMPLETION 0
+#define ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 0
+
+#endif /* TEST */
+
+
+/* Entire file (except TESTing part) sits inside this #if */
+#if ENABLE_FEATURE_EDITING
+
+#if ENABLE_LOCALE_SUPPORT
+#define Isprint(c) isprint(c)
+#else
+#define Isprint(c) ((c) >= ' ' && (c) != ((unsigned char)'\233'))
+#endif
+
+#define ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR \
+ (ENABLE_FEATURE_USERNAME_COMPLETION || ENABLE_FEATURE_EDITING_FANCY_PROMPT)
+#define USE_FEATURE_GETUSERNAME_AND_HOMEDIR(...)
+#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
+#undef USE_FEATURE_GETUSERNAME_AND_HOMEDIR
+#define USE_FEATURE_GETUSERNAME_AND_HOMEDIR(...) __VA_ARGS__
+#endif
+
+enum {
+ /* We use int16_t for positions, need to limit line len */
+ MAX_LINELEN = CONFIG_FEATURE_EDITING_MAX_LEN < 0x7ff0
+ ? CONFIG_FEATURE_EDITING_MAX_LEN
+ : 0x7ff0
+};
+
+#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
+static const char null_str[] ALIGN1 = "";
+#endif
+
+/* We try to minimize both static and stack usage. */
+struct lineedit_statics {
+ line_input_t *state;
+
+ volatile unsigned cmdedit_termw; /* = 80; */ /* actual terminal width */
+ sighandler_t previous_SIGWINCH_handler;
+
+ unsigned cmdedit_x; /* real x terminal position */
+ unsigned cmdedit_y; /* pseudoreal y terminal position */
+ unsigned cmdedit_prmt_len; /* length of prompt (without colors etc) */
+
+ unsigned cursor;
+ unsigned command_len;
+ char *command_ps;
+
+ const char *cmdedit_prompt;
+#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
+ int num_ok_lines; /* = 1; */
+#endif
+
+#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
+ char *user_buf;
+ char *home_pwd_buf; /* = (char*)null_str; */
+#endif
+
+#if ENABLE_FEATURE_TAB_COMPLETION
+ char **matches;
+ unsigned num_matches;
+#endif
+
+#if ENABLE_FEATURE_EDITING_VI
+#define DELBUFSIZ 128
+ char *delptr;
+ smallint newdelflag; /* whether delbuf should be reused yet */
+ char delbuf[DELBUFSIZ]; /* a place to store deleted characters */
+#endif
+
+ /* Formerly these were big buffers on stack: */
+#if ENABLE_FEATURE_TAB_COMPLETION
+ char exe_n_cwd_tab_completion__dirbuf[MAX_LINELEN];
+ char input_tab__matchBuf[MAX_LINELEN];
+ int16_t find_match__int_buf[MAX_LINELEN + 1]; /* need to have 9 bits at least */
+ int16_t find_match__pos_buf[MAX_LINELEN + 1];
+#endif
+};
+
+/* See lineedit_ptr_hack.c */
+extern struct lineedit_statics *const lineedit_ptr_to_statics;
+
+#define S (*lineedit_ptr_to_statics)
+#define state (S.state )
+#define cmdedit_termw (S.cmdedit_termw )
+#define previous_SIGWINCH_handler (S.previous_SIGWINCH_handler)
+#define cmdedit_x (S.cmdedit_x )
+#define cmdedit_y (S.cmdedit_y )
+#define cmdedit_prmt_len (S.cmdedit_prmt_len)
+#define cursor (S.cursor )
+#define command_len (S.command_len )
+#define command_ps (S.command_ps )
+#define cmdedit_prompt (S.cmdedit_prompt )
+#define num_ok_lines (S.num_ok_lines )
+#define user_buf (S.user_buf )
+#define home_pwd_buf (S.home_pwd_buf )
+#define matches (S.matches )
+#define num_matches (S.num_matches )
+#define delptr (S.delptr )
+#define newdelflag (S.newdelflag )
+#define delbuf (S.delbuf )
+
+#define INIT_S() do { \
+ (*(struct lineedit_statics**)&lineedit_ptr_to_statics) = xzalloc(sizeof(S)); \
+ barrier(); \
+ cmdedit_termw = 80; \
+ USE_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines = 1;) \
+ USE_FEATURE_GETUSERNAME_AND_HOMEDIR(home_pwd_buf = (char*)null_str;) \
+} while (0)
+static void deinit_S(void)
+{
+#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
+ /* This one is allocated only if FANCY_PROMPT is on
+ * (otherwise it points to verbatim prompt (NOT malloced) */
+ free((char*)cmdedit_prompt);
+#endif
+#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
+ free(user_buf);
+ if (home_pwd_buf != null_str)
+ free(home_pwd_buf);
+#endif
+ free(lineedit_ptr_to_statics);
+}
+#define DEINIT_S() deinit_S()
+
+
+/* Put 'command_ps[cursor]', cursor++.
+ * Advance cursor on screen. If we reached right margin, scroll text up
+ * and remove terminal margin effect by printing 'next_char' */
+#define HACK_FOR_WRONG_WIDTH 1
+#if HACK_FOR_WRONG_WIDTH
+static void cmdedit_set_out_char(void)
+#define cmdedit_set_out_char(next_char) cmdedit_set_out_char()
+#else
+static void cmdedit_set_out_char(int next_char)
+#endif
+{
+ int c = (unsigned char)command_ps[cursor];
+
+ if (c == '\0') {
+ /* erase character after end of input string */
+ c = ' ';
+ }
+#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
+ /* Display non-printable characters in reverse */
+ if (!Isprint(c)) {
+ if (c >= 128)
+ c -= 128;
+ if (c < ' ')
+ c += '@';
+ if (c == 127)
+ c = '?';
+ printf("\033[7m%c\033[0m", c);
+ } else
+#endif
+ {
+ bb_putchar(c);
+ }
+ if (++cmdedit_x >= cmdedit_termw) {
+ /* terminal is scrolled down */
+ cmdedit_y++;
+ cmdedit_x = 0;
+#if HACK_FOR_WRONG_WIDTH
+ /* This works better if our idea of term width is wrong
+ * and it is actually wider (often happens on serial lines).
+ * Printing CR,LF *forces* cursor to next line.
+ * OTOH if terminal width is correct AND terminal does NOT
+ * have automargin (IOW: it is moving cursor to next line
+ * by itself (which is wrong for VT-10x terminals)),
+ * this will break things: there will be one extra empty line */
+ puts("\r"); /* + implicit '\n' */
+#else
+ /* Works ok only if cmdedit_termw is correct */
+ /* destroy "(auto)margin" */
+ bb_putchar(next_char);
+ bb_putchar('\b');
+#endif
+ }
+// Huh? What if command_ps[cursor] == '\0' (we are at the end already?)
+ cursor++;
+}
+
+/* Move to end of line (by printing all chars till the end) */
+static void input_end(void)
+{
+ while (cursor < command_len)
+ cmdedit_set_out_char(' ');
+}
+
+/* Go to the next line */
+static void goto_new_line(void)
+{
+ input_end();
+ if (cmdedit_x)
+ bb_putchar('\n');
+}
+
+
+static void out1str(const char *s)
+{
+ if (s)
+ fputs(s, stdout);
+}
+
+static void beep(void)
+{
+ bb_putchar('\007');
+}
+
+/* Move back one character */
+/* (optimized for slow terminals) */
+static void input_backward(unsigned num)
+{
+ int count_y;
+
+ if (num > cursor)
+ num = cursor;
+ if (!num)
+ return;
+ cursor -= num;
+
+ if (cmdedit_x >= num) {
+ cmdedit_x -= num;
+ if (num <= 4) {
+ /* This is longer by 5 bytes on x86.
+ * Also gets miscompiled for ARM users
+ * (busybox.net/bugs/view.php?id=2274).
+ * printf(("\b\b\b\b" + 4) - num);
+ * return;
+ */
+ do {
+ bb_putchar('\b');
+ } while (--num);
+ return;
+ }
+ printf("\033[%uD", num);
+ return;
+ }
+
+ /* Need to go one or more lines up */
+ num -= cmdedit_x;
+ {
+ unsigned w = cmdedit_termw; /* volatile var */
+ count_y = 1 + (num / w);
+ cmdedit_y -= count_y;
+ cmdedit_x = w * count_y - num;
+ }
+ /* go to 1st column; go up; go to correct column */
+ printf("\r" "\033[%dA" "\033[%dC", count_y, cmdedit_x);
+}
+
+static void put_prompt(void)
+{
+ out1str(cmdedit_prompt);
+ cursor = 0;
+ {
+ unsigned w = cmdedit_termw; /* volatile var */
+ cmdedit_y = cmdedit_prmt_len / w; /* new quasireal y */
+ cmdedit_x = cmdedit_prmt_len % w;
+ }
+}
+
+/* draw prompt, editor line, and clear tail */
+static void redraw(int y, int back_cursor)
+{
+ if (y > 0) /* up to start y */
+ printf("\033[%dA", y);
+ bb_putchar('\r');
+ put_prompt();
+ input_end(); /* rewrite */
+ printf("\033[J"); /* erase after cursor */
+ input_backward(back_cursor);
+}
+
+/* Delete the char in front of the cursor, optionally saving it
+ * for later putback */
+#if !ENABLE_FEATURE_EDITING_VI
+static void input_delete(void)
+#define input_delete(save) input_delete()
+#else
+static void input_delete(int save)
+#endif
+{
+ int j = cursor;
+
+ if (j == (int)command_len)
+ return;
+
+#if ENABLE_FEATURE_EDITING_VI
+ if (save) {
+ if (newdelflag) {
+ delptr = delbuf;
+ newdelflag = 0;
+ }
+ if ((delptr - delbuf) < DELBUFSIZ)
+ *delptr++ = command_ps[j];
+ }
+#endif
+
+ strcpy(command_ps + j, command_ps + j + 1);
+ command_len--;
+ input_end(); /* rewrite new line */
+ cmdedit_set_out_char(' '); /* erase char */
+ input_backward(cursor - j); /* back to old pos cursor */
+}
+
+#if ENABLE_FEATURE_EDITING_VI
+static void put(void)
+{
+ int ocursor;
+ int j = delptr - delbuf;
+
+ if (j == 0)
+ return;
+ ocursor = cursor;
+ /* open hole and then fill it */
+ memmove(command_ps + cursor + j, command_ps + cursor, command_len - cursor + 1);
+ strncpy(command_ps + cursor, delbuf, j);
+ command_len += j;
+ input_end(); /* rewrite new line */
+ input_backward(cursor - ocursor - j + 1); /* at end of new text */
+}
+#endif
+
+/* Delete the char in back of the cursor */
+static void input_backspace(void)
+{
+ if (cursor > 0) {
+ input_backward(1);
+ input_delete(0);
+ }
+}
+
+/* Move forward one character */
+static void input_forward(void)
+{
+ if (cursor < command_len)
+ cmdedit_set_out_char(command_ps[cursor + 1]);
+}
+
+#if ENABLE_FEATURE_TAB_COMPLETION
+
+static void free_tab_completion_data(void)
+{
+ if (matches) {
+ while (num_matches)
+ free(matches[--num_matches]);
+ free(matches);
+ matches = NULL;
+ }
+}
+
+static void add_match(char *matched)
+{
+ int nm = num_matches;
+ int nm1 = nm + 1;
+
+ matches = xrealloc(matches, nm1 * sizeof(char *));
+ matches[nm] = matched;
+ num_matches++;
+}
+
+#if ENABLE_FEATURE_USERNAME_COMPLETION
+static void username_tab_completion(char *ud, char *with_shash_flg)
+{
+ struct passwd *entry;
+ int userlen;
+
+ ud++; /* ~user/... to user/... */
+ userlen = strlen(ud);
+
+ if (with_shash_flg) { /* "~/..." or "~user/..." */
+ char *sav_ud = ud - 1;
+ char *home = NULL;
+
+ if (*ud == '/') { /* "~/..." */
+ home = home_pwd_buf;
+ } else {
+ /* "~user/..." */
+ char *temp;
+ temp = strchr(ud, '/');
+ *temp = '\0'; /* ~user\0 */
+ entry = getpwnam(ud);
+ *temp = '/'; /* restore ~user/... */
+ ud = temp;
+ if (entry)
+ home = entry->pw_dir;
+ }
+ if (home) {
+ if ((userlen + strlen(home) + 1) < MAX_LINELEN) {
+ /* /home/user/... */
+ sprintf(sav_ud, "%s%s", home, ud);
+ }
+ }
+ } else {
+ /* "~[^/]*" */
+ /* Using _r function to avoid pulling in static buffers */
+ char line_buff[256];
+ struct passwd pwd;
+ struct passwd *result;
+
+ setpwent();
+ while (!getpwent_r(&pwd, line_buff, sizeof(line_buff), &result)) {
+ /* Null usernames should result in all users as possible completions. */
+ if (/*!userlen || */ strncmp(ud, pwd.pw_name, userlen) == 0) {
+ add_match(xasprintf("~%s/", pwd.pw_name));
+ }
+ }
+ endpwent();
+ }
+}
+#endif /* FEATURE_COMMAND_USERNAME_COMPLETION */
+
+enum {
+ FIND_EXE_ONLY = 0,
+ FIND_DIR_ONLY = 1,
+ FIND_FILE_ONLY = 2,
+};
+
+static int path_parse(char ***p, int flags)
+{
+ int npth;
+ const char *pth;
+ char *tmp;
+ char **res;
+
+ /* if not setenv PATH variable, to search cur dir "." */
+ if (flags != FIND_EXE_ONLY)
+ return 1;
+
+ if (state->flags & WITH_PATH_LOOKUP)
+ pth = state->path_lookup;
+ else
+ pth = getenv("PATH");
+ /* PATH=<empty> or PATH=:<empty> */
+ if (!pth || !pth[0] || LONE_CHAR(pth, ':'))
+ return 1;
+
+ tmp = (char*)pth;
+ npth = 1; /* path component count */
+ while (1) {
+ tmp = strchr(tmp, ':');
+ if (!tmp)
+ break;
+ if (*++tmp == '\0')
+ break; /* :<empty> */
+ npth++;
+ }
+
+ res = xmalloc(npth * sizeof(char*));
+ res[0] = tmp = xstrdup(pth);
+ npth = 1;
+ while (1) {
+ tmp = strchr(tmp, ':');
+ if (!tmp)
+ break;
+ *tmp++ = '\0'; /* ':' -> '\0' */
+ if (*tmp == '\0')
+ break; /* :<empty> */
+ res[npth++] = tmp;
+ }
+ *p = res;
+ return npth;
+}
+
+static void exe_n_cwd_tab_completion(char *command, int type)
+{
+ DIR *dir;
+ struct dirent *next;
+ struct stat st;
+ char *path1[1];
+ char **paths = path1;
+ int npaths;
+ int i;
+ char *found;
+ char *pfind = strrchr(command, '/');
+/* char dirbuf[MAX_LINELEN]; */
+#define dirbuf (S.exe_n_cwd_tab_completion__dirbuf)
+
+ npaths = 1;
+ path1[0] = (char*)".";
+
+ if (pfind == NULL) {
+ /* no dir, if flags==EXE_ONLY - get paths, else "." */
+ npaths = path_parse(&paths, type);
+ pfind = command;
+ } else {
+ /* dirbuf = ".../.../.../" */
+ safe_strncpy(dirbuf, command, (pfind - command) + 2);
+#if ENABLE_FEATURE_USERNAME_COMPLETION
+ if (dirbuf[0] == '~') /* ~/... or ~user/... */
+ username_tab_completion(dirbuf, dirbuf);
+#endif
+ paths[0] = dirbuf;
+ /* point to 'l' in "..../last_component" */
+ pfind++;
+ }
+
+ for (i = 0; i < npaths; i++) {
+ dir = opendir(paths[i]);
+ if (!dir)
+ continue; /* don't print an error */
+
+ while ((next = readdir(dir)) != NULL) {
+ int len1;
+ const char *str_found = next->d_name;
+
+ /* matched? */
+ if (strncmp(str_found, pfind, strlen(pfind)))
+ continue;
+ /* not see .name without .match */
+ if (*str_found == '.' && *pfind == '\0') {
+ if (NOT_LONE_CHAR(paths[i], '/') || str_found[1])
+ continue;
+ str_found = ""; /* only "/" */
+ }
+ found = concat_path_file(paths[i], str_found);
+ /* hmm, remove in progress? */
+ /* NB: stat() first so that we see is it a directory;
+ * but if that fails, use lstat() so that
+ * we still match dangling links */
+ if (stat(found, &st) && lstat(found, &st))
+ goto cont;
+ /* find with dirs? */
+ if (paths[i] != dirbuf)
+ strcpy(found, next->d_name); /* only name */
+
+ len1 = strlen(found);
+ found = xrealloc(found, len1 + 2);
+ found[len1] = '\0';
+ found[len1+1] = '\0';
+
+ if (S_ISDIR(st.st_mode)) {
+ /* name is a directory */
+ if (found[len1-1] != '/') {
+ found[len1] = '/';
+ }
+ } else {
+ /* not put found file if search only dirs for cd */
+ if (type == FIND_DIR_ONLY)
+ goto cont;
+ }
+ /* Add it to the list */
+ add_match(found);
+ continue;
+ cont:
+ free(found);
+ }
+ closedir(dir);
+ }
+ if (paths != path1) {
+ free(paths[0]); /* allocated memory is only in first member */
+ free(paths);
+ }
+#undef dirbuf
+}
+
+#define QUOT (UCHAR_MAX+1)
+
+#define collapse_pos(is, in) do { \
+ memmove(int_buf+(is), int_buf+(in), (MAX_LINELEN+1-(is)-(in)) * sizeof(pos_buf[0])); \
+ memmove(pos_buf+(is), pos_buf+(in), (MAX_LINELEN+1-(is)-(in)) * sizeof(pos_buf[0])); \
+} while (0)
+
+static int find_match(char *matchBuf, int *len_with_quotes)
+{
+ int i, j;
+ int command_mode;
+ int c, c2;
+/* int16_t int_buf[MAX_LINELEN + 1]; */
+/* int16_t pos_buf[MAX_LINELEN + 1]; */
+#define int_buf (S.find_match__int_buf)
+#define pos_buf (S.find_match__pos_buf)
+
+ /* set to integer dimension characters and own positions */
+ for (i = 0;; i++) {
+ int_buf[i] = (unsigned char)matchBuf[i];
+ if (int_buf[i] == 0) {
+ pos_buf[i] = -1; /* indicator end line */
+ break;
+ }
+ pos_buf[i] = i;
+ }
+
+ /* mask \+symbol and convert '\t' to ' ' */
+ for (i = j = 0; matchBuf[i]; i++, j++)
+ if (matchBuf[i] == '\\') {
+ collapse_pos(j, j + 1);
+ int_buf[j] |= QUOT;
+ i++;
+#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
+ if (matchBuf[i] == '\t') /* algorithm equivalent */
+ int_buf[j] = ' ' | QUOT;
+#endif
+ }
+#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
+ else if (matchBuf[i] == '\t')
+ int_buf[j] = ' ';
+#endif
+
+ /* mask "symbols" or 'symbols' */
+ c2 = 0;
+ for (i = 0; int_buf[i]; i++) {
+ c = int_buf[i];
+ if (c == '\'' || c == '"') {
+ if (c2 == 0)
+ c2 = c;
+ else {
+ if (c == c2)
+ c2 = 0;
+ else
+ int_buf[i] |= QUOT;
+ }
+ } else if (c2 != 0 && c != '$')
+ int_buf[i] |= QUOT;
+ }
+
+ /* skip commands with arguments if line has commands delimiters */
+ /* ';' ';;' '&' '|' '&&' '||' but `>&' `<&' `>|' */
+ for (i = 0; int_buf[i]; i++) {
+ c = int_buf[i];
+ c2 = int_buf[i + 1];
+ j = i ? int_buf[i - 1] : -1;
+ command_mode = 0;
+ if (c == ';' || c == '&' || c == '|') {
+ command_mode = 1 + (c == c2);
+ if (c == '&') {
+ if (j == '>' || j == '<')
+ command_mode = 0;
+ } else if (c == '|' && j == '>')
+ command_mode = 0;
+ }
+ if (command_mode) {
+ collapse_pos(0, i + command_mode);
+ i = -1; /* hack incremet */
+ }
+ }
+ /* collapse `command...` */
+ for (i = 0; int_buf[i]; i++)
+ if (int_buf[i] == '`') {
+ for (j = i + 1; int_buf[j]; j++)
+ if (int_buf[j] == '`') {
+ collapse_pos(i, j + 1);
+ j = 0;
+ break;
+ }
+ if (j) {
+ /* not found close ` - command mode, collapse all previous */
+ collapse_pos(0, i + 1);
+ break;
+ } else
+ i--; /* hack incremet */
+ }
+
+ /* collapse (command...(command...)...) or {command...{command...}...} */
+ c = 0; /* "recursive" level */
+ c2 = 0;
+ for (i = 0; int_buf[i]; i++)
+ if (int_buf[i] == '(' || int_buf[i] == '{') {
+ if (int_buf[i] == '(')
+ c++;
+ else
+ c2++;
+ collapse_pos(0, i + 1);
+ i = -1; /* hack incremet */
+ }
+ for (i = 0; pos_buf[i] >= 0 && (c > 0 || c2 > 0); i++)
+ if ((int_buf[i] == ')' && c > 0) || (int_buf[i] == '}' && c2 > 0)) {
+ if (int_buf[i] == ')')
+ c--;
+ else
+ c2--;
+ collapse_pos(0, i + 1);
+ i = -1; /* hack incremet */
+ }
+
+ /* skip first not quote space */
+ for (i = 0; int_buf[i]; i++)
+ if (int_buf[i] != ' ')
+ break;
+ if (i)
+ collapse_pos(0, i);
+
+ /* set find mode for completion */
+ command_mode = FIND_EXE_ONLY;
+ for (i = 0; int_buf[i]; i++)
+ if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') {
+ if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY
+ && matchBuf[pos_buf[0]] == 'c'
+ && matchBuf[pos_buf[1]] == 'd'
+ ) {
+ command_mode = FIND_DIR_ONLY;
+ } else {
+ command_mode = FIND_FILE_ONLY;
+ break;
+ }
+ }
+ for (i = 0; int_buf[i]; i++)
+ /* "strlen" */;
+ /* find last word */
+ for (--i; i >= 0; i--) {
+ c = int_buf[i];
+ if (c == ' ' || c == '<' || c == '>' || c == '|' || c == '&') {
+ collapse_pos(0, i + 1);
+ break;
+ }
+ }
+ /* skip first not quoted '\'' or '"' */
+ for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++)
+ /*skip*/;
+ /* collapse quote or unquote // or /~ */
+ while ((int_buf[i] & ~QUOT) == '/'
+ && ((int_buf[i+1] & ~QUOT) == '/' || (int_buf[i+1] & ~QUOT) == '~')
+ ) {
+ i++;
+ }
+
+ /* set only match and destroy quotes */
+ j = 0;
+ for (c = 0; pos_buf[i] >= 0; i++) {
+ matchBuf[c++] = matchBuf[pos_buf[i]];
+ j = pos_buf[i] + 1;
+ }
+ matchBuf[c] = '\0';
+ /* old length matchBuf with quotes symbols */
+ *len_with_quotes = j ? j - pos_buf[0] : 0;
+
+ return command_mode;
+#undef int_buf
+#undef pos_buf
+}
+
+/*
+ * display by column (original idea from ls applet,
+ * very optimized by me :)
+ */
+static void showfiles(void)
+{
+ int ncols, row;
+ int column_width = 0;
+ int nfiles = num_matches;
+ int nrows = nfiles;
+ int l;
+
+ /* find the longest file name- use that as the column width */
+ for (row = 0; row < nrows; row++) {
+ l = strlen(matches[row]);
+ if (column_width < l)
+ column_width = l;
+ }
+ column_width += 2; /* min space for columns */
+ ncols = cmdedit_termw / column_width;
+
+ if (ncols > 1) {
+ nrows /= ncols;
+ if (nfiles % ncols)
+ nrows++; /* round up fractionals */
+ } else {
+ ncols = 1;
+ }
+ for (row = 0; row < nrows; row++) {
+ int n = row;
+ int nc;
+
+ for (nc = 1; nc < ncols && n+nrows < nfiles; n += nrows, nc++) {
+ printf("%s%-*s", matches[n],
+ (int)(column_width - strlen(matches[n])), "");
+ }
+ puts(matches[n]);
+ }
+}
+
+static char *add_quote_for_spec_chars(char *found)
+{
+ int l = 0;
+ char *s = xmalloc((strlen(found) + 1) * 2);
+
+ while (*found) {
+ if (strchr(" `\"#$%^&*()=+{}[]:;\'|\\<>", *found))
+ s[l++] = '\\';
+ s[l++] = *found++;
+ }
+ s[l] = 0;
+ return s;
+}
+
+/* Do TAB completion */
+static void input_tab(smallint *lastWasTab)
+{
+ if (!(state->flags & TAB_COMPLETION))
+ return;
+
+ if (!*lastWasTab) {
+ char *tmp, *tmp1;
+ size_t len_found;
+/* char matchBuf[MAX_LINELEN]; */
+#define matchBuf (S.input_tab__matchBuf)
+ int find_type;
+ int recalc_pos;
+
+ *lastWasTab = TRUE; /* flop trigger */
+
+ /* Make a local copy of the string -- up
+ * to the position of the cursor */
+ tmp = strncpy(matchBuf, command_ps, cursor);
+ tmp[cursor] = '\0';
+
+ find_type = find_match(matchBuf, &recalc_pos);
+
+ /* Free up any memory already allocated */
+ free_tab_completion_data();
+
+#if ENABLE_FEATURE_USERNAME_COMPLETION
+ /* If the word starts with `~' and there is no slash in the word,
+ * then try completing this word as a username. */
+ if (state->flags & USERNAME_COMPLETION)
+ if (matchBuf[0] == '~' && strchr(matchBuf, '/') == 0)
+ username_tab_completion(matchBuf, NULL);
+#endif
+ /* Try to match any executable in our path and everything
+ * in the current working directory */
+ if (!matches)
+ exe_n_cwd_tab_completion(matchBuf, find_type);
+ /* Sort, then remove any duplicates found */
+ if (matches) {
+ unsigned i;
+ int n = 0;
+ qsort_string_vector(matches, num_matches);
+ for (i = 0; i < num_matches - 1; ++i) {
+ if (matches[i] && matches[i+1]) { /* paranoia */
+ if (strcmp(matches[i], matches[i+1]) == 0) {
+ free(matches[i]);
+ matches[i] = NULL; /* paranoia */
+ } else {
+ matches[n++] = matches[i];
+ }
+ }
+ }
+ matches[n] = matches[i];
+ num_matches = n + 1;
+ }
+ /* Did we find exactly one match? */
+ if (!matches || num_matches > 1) {
+ beep();
+ if (!matches)
+ return; /* not found */
+ /* find minimal match */
+ tmp1 = xstrdup(matches[0]);
+ for (tmp = tmp1; *tmp; tmp++)
+ for (len_found = 1; len_found < num_matches; len_found++)
+ if (matches[len_found][(tmp - tmp1)] != *tmp) {
+ *tmp = '\0';
+ break;
+ }
+ if (*tmp1 == '\0') { /* have unique */
+ free(tmp1);
+ return;
+ }
+ tmp = add_quote_for_spec_chars(tmp1);
+ free(tmp1);
+ } else { /* one match */
+ tmp = add_quote_for_spec_chars(matches[0]);
+ /* for next completion current found */
+ *lastWasTab = FALSE;
+
+ len_found = strlen(tmp);
+ if (tmp[len_found-1] != '/') {
+ tmp[len_found] = ' ';
+ tmp[len_found+1] = '\0';
+ }
+ }
+ len_found = strlen(tmp);
+ /* have space to placed match? */
+ if ((len_found - strlen(matchBuf) + command_len) < MAX_LINELEN) {
+ /* before word for match */
+ command_ps[cursor - recalc_pos] = '\0';
+ /* save tail line */
+ strcpy(matchBuf, command_ps + cursor);
+ /* add match */
+ strcat(command_ps, tmp);
+ /* add tail */
+ strcat(command_ps, matchBuf);
+ /* back to begin word for match */
+ input_backward(recalc_pos);
+ /* new pos */
+ recalc_pos = cursor + len_found;
+ /* new len */
+ command_len = strlen(command_ps);
+ /* write out the matched command */
+ redraw(cmdedit_y, command_len - recalc_pos);
+ }
+ free(tmp);
+#undef matchBuf
+ } else {
+ /* Ok -- the last char was a TAB. Since they
+ * just hit TAB again, print a list of all the
+ * available choices... */
+ if (matches && num_matches > 0) {
+ int sav_cursor = cursor; /* change goto_new_line() */
+
+ /* Go to the next line */
+ goto_new_line();
+ showfiles();
+ redraw(0, command_len - sav_cursor);
+ }
+ }
+}
+
+#endif /* FEATURE_COMMAND_TAB_COMPLETION */
+
+
+#if MAX_HISTORY > 0
+
+/* state->flags is already checked to be nonzero */
+static void get_previous_history(void)
+{
+ if (command_ps[0] != '\0' || state->history[state->cur_history] == NULL) {
+ free(state->history[state->cur_history]);
+ state->history[state->cur_history] = xstrdup(command_ps);
+ }
+ state->cur_history--;
+}
+
+static int get_next_history(void)
+{
+ if (state->flags & DO_HISTORY) {
+ int ch = state->cur_history;
+ if (ch < state->cnt_history) {
+ get_previous_history(); /* save the current history line */
+ state->cur_history = ch + 1;
+ return state->cur_history;
+ }
+ }
+ beep();
+ return 0;
+}
+
+#if ENABLE_FEATURE_EDITING_SAVEHISTORY
+/* state->flags is already checked to be nonzero */
+static void load_history(const char *fromfile)
+{
+ FILE *fp;
+ int hi;
+
+ /* NB: do not trash old history if file can't be opened */
+
+ fp = fopen(fromfile, "r");
+ if (fp) {
+ /* clean up old history */
+ for (hi = state->cnt_history; hi > 0;) {
+ hi--;
+ free(state->history[hi]);
+ }
+
+ for (hi = 0; hi < MAX_HISTORY;) {
+ char *hl = xmalloc_fgetline(fp);
+ int l;
+
+ if (!hl)
+ break;
+ l = strlen(hl);
+ if (l >= MAX_LINELEN)
+ hl[MAX_LINELEN-1] = '\0';
+ if (l == 0 || hl[0] == ' ') {
+ free(hl);
+ continue;
+ }
+ state->history[hi++] = hl;
+ }
+ fclose(fp);
+ state->cur_history = state->cnt_history = hi;
+ }
+}
+
+/* state->flags is already checked to be nonzero */
+static void save_history(const char *tofile)
+{
+ FILE *fp;
+
+ fp = fopen(tofile, "w");
+ if (fp) {
+ int i;
+
+ for (i = 0; i < state->cnt_history; i++) {
+ fprintf(fp, "%s\n", state->history[i]);
+ }
+ fclose(fp);
+ }
+}
+#else
+#define load_history(a) ((void)0)
+#define save_history(a) ((void)0)
+#endif /* FEATURE_COMMAND_SAVEHISTORY */
+
+static void remember_in_history(const char *str)
+{
+ int i;
+
+ if (!(state->flags & DO_HISTORY))
+ return;
+
+ i = state->cnt_history;
+ free(state->history[MAX_HISTORY]);
+ state->history[MAX_HISTORY] = NULL;
+ /* After max history, remove the oldest command */
+ if (i >= MAX_HISTORY) {
+ free(state->history[0]);
+ for (i = 0; i < MAX_HISTORY-1; i++)
+ state->history[i] = state->history[i+1];
+ }
+// Maybe "if (!i || strcmp(history[i-1], command) != 0) ..."
+// (i.e. do not save dups?)
+ state->history[i++] = xstrdup(str);
+ state->cur_history = i;
+ state->cnt_history = i;
+#if ENABLE_FEATURE_EDITING_SAVEHISTORY
+ if ((state->flags & SAVE_HISTORY) && state->hist_file)
+ save_history(state->hist_file);
+#endif
+ USE_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;)
+}
+
+#else /* MAX_HISTORY == 0 */
+#define remember_in_history(a) ((void)0)
+#endif /* MAX_HISTORY */
+
+
+/*
+ * This function is used to grab a character buffer
+ * from the input file descriptor and allows you to
+ * a string with full command editing (sort of like
+ * a mini readline).
+ *
+ * The following standard commands are not implemented:
+ * ESC-b -- Move back one word
+ * ESC-f -- Move forward one word
+ * ESC-d -- Delete back one word
+ * ESC-h -- Delete forward one word
+ * CTL-t -- Transpose two characters
+ *
+ * Minimalist vi-style command line editing available if configured.
+ * vi mode implemented 2005 by Paul Fox <pgf@foxharp.boston.ma.us>
+ */
+
+#if ENABLE_FEATURE_EDITING_VI
+static void
+vi_Word_motion(char *command, int eat)
+{
+ while (cursor < command_len && !isspace(command[cursor]))
+ input_forward();
+ if (eat) while (cursor < command_len && isspace(command[cursor]))
+ input_forward();
+}
+
+static void
+vi_word_motion(char *command, int eat)
+{
+ if (isalnum(command[cursor]) || command[cursor] == '_') {
+ while (cursor < command_len
+ && (isalnum(command[cursor+1]) || command[cursor+1] == '_'))
+ input_forward();
+ } else if (ispunct(command[cursor])) {
+ while (cursor < command_len && ispunct(command[cursor+1]))
+ input_forward();
+ }
+
+ if (cursor < command_len)
+ input_forward();
+
+ if (eat && cursor < command_len && isspace(command[cursor]))
+ while (cursor < command_len && isspace(command[cursor]))
+ input_forward();
+}
+
+static void
+vi_End_motion(char *command)
+{
+ input_forward();
+ while (cursor < command_len && isspace(command[cursor]))
+ input_forward();
+ while (cursor < command_len-1 && !isspace(command[cursor+1]))
+ input_forward();
+}
+
+static void
+vi_end_motion(char *command)
+{
+ if (cursor >= command_len-1)
+ return;
+ input_forward();
+ while (cursor < command_len-1 && isspace(command[cursor]))
+ input_forward();
+ if (cursor >= command_len-1)
+ return;
+ if (isalnum(command[cursor]) || command[cursor] == '_') {
+ while (cursor < command_len-1
+ && (isalnum(command[cursor+1]) || command[cursor+1] == '_')
+ ) {
+ input_forward();
+ }
+ } else if (ispunct(command[cursor])) {
+ while (cursor < command_len-1 && ispunct(command[cursor+1]))
+ input_forward();
+ }
+}
+
+static void
+vi_Back_motion(char *command)
+{
+ while (cursor > 0 && isspace(command[cursor-1]))
+ input_backward(1);
+ while (cursor > 0 && !isspace(command[cursor-1]))
+ input_backward(1);
+}
+
+static void
+vi_back_motion(char *command)
+{
+ if (cursor <= 0)
+ return;
+ input_backward(1);
+ while (cursor > 0 && isspace(command[cursor]))
+ input_backward(1);
+ if (cursor <= 0)
+ return;
+ if (isalnum(command[cursor]) || command[cursor] == '_') {
+ while (cursor > 0
+ && (isalnum(command[cursor-1]) || command[cursor-1] == '_')
+ ) {
+ input_backward(1);
+ }
+ } else if (ispunct(command[cursor])) {
+ while (cursor > 0 && ispunct(command[cursor-1]))
+ input_backward(1);
+ }
+}
+#endif
+
+
+/*
+ * read_line_input and its helpers
+ */
+
+#if !ENABLE_FEATURE_EDITING_FANCY_PROMPT
+static void parse_and_put_prompt(const char *prmt_ptr)
+{
+ cmdedit_prompt = prmt_ptr;
+ cmdedit_prmt_len = strlen(prmt_ptr);
+ put_prompt();
+}
+#else
+static void parse_and_put_prompt(const char *prmt_ptr)
+{
+ int prmt_len = 0;
+ size_t cur_prmt_len = 0;
+ char flg_not_length = '[';
+ char *prmt_mem_ptr = xzalloc(1);
+ char *cwd_buf = xrealloc_getcwd_or_warn(NULL);
+ char cbuf[2];
+ char c;
+ char *pbuf;
+
+ cmdedit_prmt_len = 0;
+
+ if (!cwd_buf) {
+ cwd_buf = (char *)bb_msg_unknown;
+ }
+
+ cbuf[1] = '\0'; /* never changes */
+
+ while (*prmt_ptr) {
+ char *free_me = NULL;
+
+ pbuf = cbuf;
+ c = *prmt_ptr++;
+ if (c == '\\') {
+ const char *cp = prmt_ptr;
+ int l;
+
+ c = bb_process_escape_sequence(&prmt_ptr);
+ if (prmt_ptr == cp) {
+ if (*cp == '\0')
+ break;
+ c = *prmt_ptr++;
+
+ switch (c) {
+#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
+ case 'u':
+ pbuf = user_buf ? user_buf : (char*)"";
+ break;
+#endif
+ case 'h':
+ pbuf = free_me = safe_gethostname();
+ *strchrnul(pbuf, '.') = '\0';
+ break;
+ case '$':
+ c = (geteuid() == 0 ? '#' : '$');
+ break;
+#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
+ case 'w':
+ /* /home/user[/something] -> ~[/something] */
+ pbuf = cwd_buf;
+ l = strlen(home_pwd_buf);
+ if (l != 0
+ && strncmp(home_pwd_buf, cwd_buf, l) == 0
+ && (cwd_buf[l]=='/' || cwd_buf[l]=='\0')
+ && strlen(cwd_buf + l) < PATH_MAX
+ ) {
+ pbuf = free_me = xasprintf("~%s", cwd_buf + l);
+ }
+ break;
+#endif
+ case 'W':
+ pbuf = cwd_buf;
+ cp = strrchr(pbuf, '/');
+ if (cp != NULL && cp != pbuf)
+ pbuf += (cp-pbuf) + 1;
+ break;
+ case '!':
+ pbuf = free_me = xasprintf("%d", num_ok_lines);
+ break;
+ case 'e': case 'E': /* \e \E = \033 */
+ c = '\033';
+ break;
+ case 'x': case 'X': {
+ char buf2[4];
+ for (l = 0; l < 3;) {
+ unsigned h;
+ buf2[l++] = *prmt_ptr;
+ buf2[l] = '\0';
+ h = strtoul(buf2, &pbuf, 16);
+ if (h > UCHAR_MAX || (pbuf - buf2) < l) {
+ buf2[--l] = '\0';
+ break;
+ }
+ prmt_ptr++;
+ }
+ c = (char)strtoul(buf2, NULL, 16);
+ if (c == 0)
+ c = '?';
+ pbuf = cbuf;
+ break;
+ }
+ case '[': case ']':
+ if (c == flg_not_length) {
+ flg_not_length = (flg_not_length == '[' ? ']' : '[');
+ continue;
+ }
+ break;
+ } /* switch */
+ } /* if */
+ } /* if */
+ cbuf[0] = c;
+ cur_prmt_len = strlen(pbuf);
+ prmt_len += cur_prmt_len;
+ if (flg_not_length != ']')
+ cmdedit_prmt_len += cur_prmt_len;
+ prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf);
+ free(free_me);
+ } /* while */
+
+ if (cwd_buf != (char *)bb_msg_unknown)
+ free(cwd_buf);
+ cmdedit_prompt = prmt_mem_ptr;
+ put_prompt();
+}
+#endif
+
+static void cmdedit_setwidth(unsigned w, int redraw_flg)
+{
+ cmdedit_termw = w;
+ if (redraw_flg) {
+ /* new y for current cursor */
+ int new_y = (cursor + cmdedit_prmt_len) / w;
+ /* redraw */
+ redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), command_len - cursor);
+ fflush(stdout);
+ }
+}
+
+static void win_changed(int nsig)
+{
+ unsigned width;
+ get_terminal_width_height(0, &width, NULL);
+ cmdedit_setwidth(width, nsig /* - just a yes/no flag */);
+ if (nsig == SIGWINCH)
+ signal(SIGWINCH, win_changed); /* rearm ourself */
+}
+
+/*
+ * The emacs and vi modes share much of the code in the big
+ * command loop. Commands entered when in vi's command mode (aka
+ * "escape mode") get an extra bit added to distinguish them --
+ * this keeps them from being self-inserted. This clutters the
+ * big switch a bit, but keeps all the code in one place.
+ */
+
+#define vbit 0x100
+
+/* leave out the "vi-mode"-only case labels if vi editing isn't
+ * configured. */
+#define vi_case(caselabel) USE_FEATURE_EDITING(case caselabel)
+
+/* convert uppercase ascii to equivalent control char, for readability */
+#undef CTRL
+#define CTRL(a) ((a) & ~0x40)
+
+/* Returns:
+ * -1 on read errors or EOF, or on bare Ctrl-D,
+ * 0 on ctrl-C (the line entered is still returned in 'command'),
+ * >0 length of input string, including terminating '\n'
+ */
+int read_line_input(const char *prompt, char *command, int maxsize, line_input_t *st)
+{
+#if ENABLE_FEATURE_TAB_COMPLETION
+ smallint lastWasTab = FALSE;
+#endif
+ unsigned ic;
+ unsigned char c;
+ smallint break_out = 0;
+#if ENABLE_FEATURE_EDITING_VI
+ smallint vi_cmdmode = 0;
+ smalluint prevc;
+#endif
+ struct termios initial_settings;
+ struct termios new_settings;
+
+ INIT_S();
+
+ if (tcgetattr(STDIN_FILENO, &initial_settings) < 0
+ || !(initial_settings.c_lflag & ECHO)
+ ) {
+ /* Happens when e.g. stty -echo was run before */
+ int len;
+ parse_and_put_prompt(prompt);
+ fflush(stdout);
+ if (fgets(command, maxsize, stdin) == NULL)
+ len = -1; /* EOF or error */
+ else
+ len = strlen(command);
+ DEINIT_S();
+ return len;
+ }
+
+// FIXME: audit & improve this
+ if (maxsize > MAX_LINELEN)
+ maxsize = MAX_LINELEN;
+
+ /* With null flags, no other fields are ever used */
+ state = st ? st : (line_input_t*) &const_int_0;
+#if ENABLE_FEATURE_EDITING_SAVEHISTORY
+ if ((state->flags & SAVE_HISTORY) && state->hist_file)
+ load_history(state->hist_file);
+#endif
+
+ /* prepare before init handlers */
+ cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */
+ command_len = 0;
+ command_ps = command;
+ command[0] = '\0';
+
+ new_settings = initial_settings;
+ new_settings.c_lflag &= ~ICANON; /* unbuffered input */
+ /* Turn off echoing and CTRL-C, so we can trap it */
+ new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG);
+ /* Hmm, in linux c_cc[] is not parsed if ICANON is off */
+ new_settings.c_cc[VMIN] = 1;
+ new_settings.c_cc[VTIME] = 0;
+ /* Turn off CTRL-C, so we can trap it */
+#ifndef _POSIX_VDISABLE
+#define _POSIX_VDISABLE '\0'
+#endif
+ new_settings.c_cc[VINTR] = _POSIX_VDISABLE;
+ tcsetattr(STDIN_FILENO, TCSANOW, &new_settings);
+
+ /* Now initialize things */
+ previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
+ win_changed(0); /* do initial resizing */
+#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
+ {
+ struct passwd *entry;
+
+ entry = getpwuid(geteuid());
+ if (entry) {
+ user_buf = xstrdup(entry->pw_name);
+ home_pwd_buf = xstrdup(entry->pw_dir);
+ }
+ }
+#endif
+ /* Print out the command prompt */
+ parse_and_put_prompt(prompt);
+
+ while (1) {
+ fflush(NULL);
+
+ if (nonblock_safe_read(STDIN_FILENO, &c, 1) < 1) {
+ /* if we can't read input then exit */
+ goto prepare_to_die;
+ }
+
+ ic = c;
+
+#if ENABLE_FEATURE_EDITING_VI
+ newdelflag = 1;
+ if (vi_cmdmode)
+ ic |= vbit;
+#endif
+ switch (ic) {
+ case '\n':
+ case '\r':
+ vi_case('\n'|vbit:)
+ vi_case('\r'|vbit:)
+ /* Enter */
+ goto_new_line();
+ break_out = 1;
+ break;
+ case CTRL('A'):
+ vi_case('0'|vbit:)
+ /* Control-a -- Beginning of line */
+ input_backward(cursor);
+ break;
+ case CTRL('B'):
+ vi_case('h'|vbit:)
+ vi_case('\b'|vbit:)
+ vi_case('\x7f'|vbit:) /* DEL */
+ /* Control-b -- Move back one character */
+ input_backward(1);
+ break;
+ case CTRL('C'):
+ vi_case(CTRL('C')|vbit:)
+ /* Control-c -- stop gathering input */
+ goto_new_line();
+ command_len = 0;
+ break_out = -1; /* "do not append '\n'" */
+ break;
+ case CTRL('D'):
+ /* Control-d -- Delete one character, or exit
+ * if the len=0 and no chars to delete */
+ if (command_len == 0) {
+ errno = 0;
+ prepare_to_die:
+ /* to control stopped jobs */
+ break_out = command_len = -1;
+ break;
+ }
+ input_delete(0);
+ break;
+
+ case CTRL('E'):
+ vi_case('$'|vbit:)
+ /* Control-e -- End of line */
+ input_end();
+ break;
+ case CTRL('F'):
+ vi_case('l'|vbit:)
+ vi_case(' '|vbit:)
+ /* Control-f -- Move forward one character */
+ input_forward();
+ break;
+
+ case '\b':
+ case '\x7f': /* DEL */
+ /* Control-h and DEL */
+ input_backspace();
+ break;
+
+#if ENABLE_FEATURE_TAB_COMPLETION
+ case '\t':
+ input_tab(&lastWasTab);
+ break;
+#endif
+
+ case CTRL('K'):
+ /* Control-k -- clear to end of line */
+ command[cursor] = 0;
+ command_len = cursor;
+ printf("\033[J");
+ break;
+ case CTRL('L'):
+ vi_case(CTRL('L')|vbit:)
+ /* Control-l -- clear screen */
+ printf("\033[H");
+ redraw(0, command_len - cursor);
+ break;
+
+#if MAX_HISTORY > 0
+ case CTRL('N'):
+ vi_case(CTRL('N')|vbit:)
+ vi_case('j'|vbit:)
+ /* Control-n -- Get next command in history */
+ if (get_next_history())
+ goto rewrite_line;
+ break;
+ case CTRL('P'):
+ vi_case(CTRL('P')|vbit:)
+ vi_case('k'|vbit:)
+ /* Control-p -- Get previous command from history */
+ if ((state->flags & DO_HISTORY) && state->cur_history > 0) {
+ get_previous_history();
+ goto rewrite_line;
+ }
+ beep();
+ break;
+#endif
+
+ case CTRL('U'):
+ vi_case(CTRL('U')|vbit:)
+ /* Control-U -- Clear line before cursor */
+ if (cursor) {
+ strcpy(command, command + cursor);
+ command_len -= cursor;
+ redraw(cmdedit_y, command_len);
+ }
+ break;
+ case CTRL('W'):
+ vi_case(CTRL('W')|vbit:)
+ /* Control-W -- Remove the last word */
+ while (cursor > 0 && isspace(command[cursor-1]))
+ input_backspace();
+ while (cursor > 0 && !isspace(command[cursor-1]))
+ input_backspace();
+ break;
+
+#if ENABLE_FEATURE_EDITING_VI
+ case 'i'|vbit:
+ vi_cmdmode = 0;
+ break;
+ case 'I'|vbit:
+ input_backward(cursor);
+ vi_cmdmode = 0;
+ break;
+ case 'a'|vbit:
+ input_forward();
+ vi_cmdmode = 0;
+ break;
+ case 'A'|vbit:
+ input_end();
+ vi_cmdmode = 0;
+ break;
+ case 'x'|vbit:
+ input_delete(1);
+ break;
+ case 'X'|vbit:
+ if (cursor > 0) {
+ input_backward(1);
+ input_delete(1);
+ }
+ break;
+ case 'W'|vbit:
+ vi_Word_motion(command, 1);
+ break;
+ case 'w'|vbit:
+ vi_word_motion(command, 1);
+ break;
+ case 'E'|vbit:
+ vi_End_motion(command);
+ break;
+ case 'e'|vbit:
+ vi_end_motion(command);
+ break;
+ case 'B'|vbit:
+ vi_Back_motion(command);
+ break;
+ case 'b'|vbit:
+ vi_back_motion(command);
+ break;
+ case 'C'|vbit:
+ vi_cmdmode = 0;
+ /* fall through */
+ case 'D'|vbit:
+ goto clear_to_eol;
+
+ case 'c'|vbit:
+ vi_cmdmode = 0;
+ /* fall through */
+ case 'd'|vbit: {
+ int nc, sc;
+ sc = cursor;
+ prevc = ic;
+ if (safe_read(STDIN_FILENO, &c, 1) < 1)
+ goto prepare_to_die;
+ if (c == (prevc & 0xff)) {
+ /* "cc", "dd" */
+ input_backward(cursor);
+ goto clear_to_eol;
+ break;
+ }
+ switch (c) {
+ case 'w':
+ case 'W':
+ case 'e':
+ case 'E':
+ switch (c) {
+ case 'w': /* "dw", "cw" */
+ vi_word_motion(command, vi_cmdmode);
+ break;
+ case 'W': /* 'dW', 'cW' */
+ vi_Word_motion(command, vi_cmdmode);
+ break;
+ case 'e': /* 'de', 'ce' */
+ vi_end_motion(command);
+ input_forward();
+ break;
+ case 'E': /* 'dE', 'cE' */
+ vi_End_motion(command);
+ input_forward();
+ break;
+ }
+ nc = cursor;
+ input_backward(cursor - sc);
+ while (nc-- > cursor)
+ input_delete(1);
+ break;
+ case 'b': /* "db", "cb" */
+ case 'B': /* implemented as B */
+ if (c == 'b')
+ vi_back_motion(command);
+ else
+ vi_Back_motion(command);
+ while (sc-- > cursor)
+ input_delete(1);
+ break;
+ case ' ': /* "d ", "c " */
+ input_delete(1);
+ break;
+ case '$': /* "d$", "c$" */
+ clear_to_eol:
+ while (cursor < command_len)
+ input_delete(1);
+ break;
+ }
+ break;
+ }
+ case 'p'|vbit:
+ input_forward();
+ /* fallthrough */
+ case 'P'|vbit:
+ put();
+ break;
+ case 'r'|vbit:
+ if (safe_read(STDIN_FILENO, &c, 1) < 1)
+ goto prepare_to_die;
+ if (c == 0)
+ beep();
+ else {
+ *(command + cursor) = c;
+ bb_putchar(c);
+ bb_putchar('\b');
+ }
+ break;
+#endif /* FEATURE_COMMAND_EDITING_VI */
+
+ case '\x1b': /* ESC */
+
+#if ENABLE_FEATURE_EDITING_VI
+ if (state->flags & VI_MODE) {
+ /* ESC: insert mode --> command mode */
+ vi_cmdmode = 1;
+ input_backward(1);
+ break;
+ }
+#endif
+ /* escape sequence follows */
+ if (safe_read(STDIN_FILENO, &c, 1) < 1)
+ goto prepare_to_die;
+ /* different vt100 emulations */
+ if (c == '[' || c == 'O') {
+ vi_case('['|vbit:)
+ vi_case('O'|vbit:)
+ if (safe_read(STDIN_FILENO, &c, 1) < 1)
+ goto prepare_to_die;
+ }
+ if (c >= '1' && c <= '9') {
+ unsigned char dummy;
+
+ if (safe_read(STDIN_FILENO, &dummy, 1) < 1)
+ goto prepare_to_die;
+ if (dummy != '~')
+ c = '\0';
+ }
+
+ switch (c) {
+#if ENABLE_FEATURE_TAB_COMPLETION
+ case '\t': /* Alt-Tab */
+ input_tab(&lastWasTab);
+ break;
+#endif
+#if MAX_HISTORY > 0
+ case 'A':
+ /* Up Arrow -- Get previous command from history */
+ if ((state->flags & DO_HISTORY) && state->cur_history > 0) {
+ get_previous_history();
+ goto rewrite_line;
+ }
+ beep();
+ break;
+ case 'B':
+ /* Down Arrow -- Get next command in history */
+ if (!get_next_history())
+ break;
+ rewrite_line:
+ /* Rewrite the line with the selected history item */
+ /* change command */
+ command_len = strlen(strcpy(command, state->history[state->cur_history]));
+ /* redraw and go to eol (bol, in vi */
+ redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0);
+ break;
+#endif
+ case 'C':
+ /* Right Arrow -- Move forward one character */
+ input_forward();
+ break;
+ case 'D':
+ /* Left Arrow -- Move back one character */
+ input_backward(1);
+ break;
+ case '3':
+ /* Delete */
+ input_delete(0);
+ break;
+ case '1': // vt100? linux vt? or what?
+ case '7': // vt100? linux vt? or what?
+ case 'H': /* xterm's <Home> */
+ input_backward(cursor);
+ break;
+ case '4': // vt100? linux vt? or what?
+ case '8': // vt100? linux vt? or what?
+ case 'F': /* xterm's <End> */
+ input_end();
+ break;
+ default:
+ c = '\0';
+ beep();
+ }
+ break;
+
+ default: /* If it's regular input, do the normal thing */
+
+ /* Control-V -- force insert of next char */
+ if (c == CTRL('V')) {
+ if (safe_read(STDIN_FILENO, &c, 1) < 1)
+ goto prepare_to_die;
+ if (c == 0) {
+ beep();
+ break;
+ }
+ }
+
+#if ENABLE_FEATURE_EDITING_VI
+ if (vi_cmdmode) /* Don't self-insert */
+ break;
+#endif
+ if ((int)command_len >= (maxsize - 2)) /* Need to leave space for enter */
+ break;
+
+ command_len++;
+ if (cursor == (command_len - 1)) { /* Append if at the end of the line */
+ command[cursor] = c;
+ command[cursor+1] = '\0';
+ cmdedit_set_out_char(' ');
+ } else { /* Insert otherwise */
+ int sc = cursor;
+
+ memmove(command + sc + 1, command + sc, command_len - sc);
+ command[sc] = c;
+ sc++;
+ /* rewrite from cursor */
+ input_end();
+ /* to prev x pos + 1 */
+ input_backward(cursor - sc);
+ }
+ break;
+ }
+ if (break_out) /* Enter is the command terminator, no more input. */
+ break;
+
+#if ENABLE_FEATURE_TAB_COMPLETION
+ if (c != '\t')
+ lastWasTab = FALSE;
+#endif
+ }
+
+ if (command_len > 0)
+ remember_in_history(command);
+
+ if (break_out > 0) {
+ command[command_len++] = '\n';
+ command[command_len] = '\0';
+ }
+
+#if ENABLE_FEATURE_TAB_COMPLETION
+ free_tab_completion_data();
+#endif
+
+ /* restore initial_settings */
+ tcsetattr(STDIN_FILENO, TCSANOW, &initial_settings);
+ /* restore SIGWINCH handler */
+ signal(SIGWINCH, previous_SIGWINCH_handler);
+ fflush(stdout);
+
+ DEINIT_S();
+
+ return command_len;
+}
+
+line_input_t *new_line_input_t(int flags)
+{
+ line_input_t *n = xzalloc(sizeof(*n));
+ n->flags = flags;
+ return n;
+}
+
+#else
+
+#undef read_line_input
+int read_line_input(const char* prompt, char* command, int maxsize)
+{
+ fputs(prompt, stdout);
+ fflush(stdout);
+ fgets(command, maxsize, stdin);
+ return strlen(command);
+}
+
+#endif /* FEATURE_COMMAND_EDITING */
+
+
+/*
+ * Testing
+ */
+
+#ifdef TEST
+
+#include <locale.h>
+
+const char *applet_name = "debug stuff usage";
+
+int main(int argc, char **argv)
+{
+ char buff[MAX_LINELEN];
+ char *prompt =
+#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
+ "\\[\\033[32;1m\\]\\u@\\[\\x1b[33;1m\\]\\h:"
+ "\\[\\033[34;1m\\]\\w\\[\\033[35;1m\\] "
+ "\\!\\[\\e[36;1m\\]\\$ \\[\\E[0m\\]";
+#else
+ "% ";
+#endif
+
+#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
+ setlocale(LC_ALL, "");
+#endif
+ while (1) {
+ int l;
+ l = read_line_input(prompt, buff);
+ if (l <= 0 || buff[l-1] != '\n')
+ break;
+ buff[l-1] = 0;
+ printf("*** read_line_input() returned line =%s=\n", buff);
+ }
+ printf("*** read_line_input() detect ^D\n");
+ return 0;
+}
+
+#endif /* TEST */
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/lineedit_ptr_hack.c b/cleopatre/busybox-1.11.1-spc300/libbb/lineedit_ptr_hack.c
new file mode 100644
index 0000000000..53716a235e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/lineedit_ptr_hack.c
@@ -0,0 +1,23 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2008 by Denys Vlasenko <vda.linux@googlemail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+struct lineedit_statics;
+
+#ifndef GCC_COMBINE
+
+/* We cheat here. It is declared as const ptr in libbb.h,
+ * but here we make it live in R/W memory */
+struct lineedit_statics *lineedit_ptr_to_statics;
+
+#else
+
+/* gcc -combine will see through and complain */
+/* Using alternative method which is more likely to break
+ * on weird architectures, compilers, linkers and so on */
+struct lineedit_statics *const lineedit_ptr_to_statics __attribute__ ((section (".data")));
+
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/llist.c b/cleopatre/busybox-1.11.1-spc300/libbb/llist.c
new file mode 100644
index 0000000000..4b3971bbe5
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/llist.c
@@ -0,0 +1,108 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * linked list helper functions.
+ *
+ * Copyright (C) 2003 Glenn McGrath
+ * Copyright (C) 2005 Vladimir Oleynik
+ * Copyright (C) 2005 Bernhard Fischer
+ * Copyright (C) 2006 Rob Landley <rob@landley.net>
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+
+/* Add data to the start of the linked list. */
+void llist_add_to(llist_t **old_head, void *data)
+{
+ llist_t *new_head = xmalloc(sizeof(llist_t));
+
+ new_head->data = data;
+ new_head->link = *old_head;
+ *old_head = new_head;
+}
+
+/* Add data to the end of the linked list. */
+void llist_add_to_end(llist_t **list_head, void *data)
+{
+ llist_t *new_item = xmalloc(sizeof(llist_t));
+
+ new_item->data = data;
+ new_item->link = NULL;
+
+ if (!*list_head)
+ *list_head = new_item;
+ else {
+ llist_t *tail = *list_head;
+
+ while (tail->link)
+ tail = tail->link;
+ tail->link = new_item;
+ }
+}
+
+/* Remove first element from the list and return it */
+void *llist_pop(llist_t **head)
+{
+ void *data, *next;
+
+ if (!*head)
+ return NULL;
+
+ data = (*head)->data;
+ next = (*head)->link;
+ free(*head);
+ *head = next;
+
+ return data;
+}
+
+/* Unlink arbitrary given element from the list */
+void llist_unlink(llist_t **head, llist_t *elm)
+{
+ llist_t *crt;
+
+ if (!(elm && *head))
+ return;
+
+ if (elm == *head) {
+ *head = (*head)->link;
+ return;
+ }
+
+ for (crt = *head; crt; crt = crt->link) {
+ if (crt->link == elm) {
+ crt->link = elm->link;
+ return;
+ }
+ }
+}
+
+/* Recursively free all elements in the linked list. If freeit != NULL
+ * call it on each datum in the list */
+void llist_free(llist_t *elm, void (*freeit) (void *data))
+{
+ while (elm) {
+ void *data = llist_pop(&elm);
+
+ if (freeit)
+ freeit(data);
+ }
+}
+
+#ifdef UNUSED
+/* Reverse list order. */
+llist_t *llist_rev(llist_t *list)
+{
+ llist_t *rev = NULL;
+
+ while (list) {
+ llist_t *next = list->link;
+
+ list->link = rev;
+ rev = list;
+ list = next;
+ }
+ return rev;
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/login.c b/cleopatre/busybox-1.11.1-spc300/libbb/login.c
new file mode 100644
index 0000000000..a5be2c8c9f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/login.c
@@ -0,0 +1,130 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * issue.c: issue printing code
+ *
+ * Copyright (C) 2003 Bastian Blank <waldi@tuxbox.org>
+ *
+ * Optimize and correcting OCRNL by Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include <sys/param.h> /* MAXHOSTNAMELEN */
+#include <sys/utsname.h>
+#include "libbb.h"
+
+#define LOGIN " login: "
+
+static const char fmtstr_d[] ALIGN1 = "%A, %d %B %Y";
+static const char fmtstr_t[] ALIGN1 = "%H:%M:%S";
+
+void print_login_issue(const char *issue_file, const char *tty)
+{
+ FILE *fd;
+ int c;
+ char buf[256+1];
+ const char *outbuf;
+ time_t t;
+ struct utsname uts;
+
+ time(&t);
+ uname(&uts);
+
+ puts("\r"); /* start a new line */
+
+ fd = fopen(issue_file, "r");
+ if (!fd)
+ return;
+ while ((c = fgetc(fd)) != EOF) {
+ outbuf = buf;
+ buf[0] = c;
+ buf[1] = '\0';
+ if (c == '\n') {
+ buf[1] = '\r';
+ buf[2] = '\0';
+ }
+ if (c == '\\' || c == '%') {
+ c = fgetc(fd);
+ switch (c) {
+ case 's':
+ outbuf = uts.sysname;
+ break;
+ case 'n':
+ case 'h':
+ outbuf = uts.nodename;
+ break;
+ case 'r':
+ outbuf = uts.release;
+ break;
+ case 'v':
+ outbuf = uts.version;
+ break;
+ case 'm':
+ outbuf = uts.machine;
+ break;
+ case 'D':
+ case 'o':
+ c = getdomainname(buf, sizeof(buf) - 1);
+ buf[c >= 0 ? c : 0] = '\0';
+ break;
+ case 'd':
+ strftime(buf, sizeof(buf), fmtstr_d, localtime(&t));
+ break;
+ case 't':
+ strftime(buf, sizeof(buf), fmtstr_t, localtime(&t));
+ break;
+ case 'l':
+ outbuf = tty;
+ break;
+ default:
+ buf[0] = c;
+ }
+ }
+ fputs(outbuf, stdout);
+ }
+ fclose(fd);
+ fflush(stdout);
+}
+
+void print_login_prompt(void)
+{
+ char *hostname = safe_gethostname();
+
+ fputs(hostname, stdout);
+ fputs(LOGIN, stdout);
+ fflush(stdout);
+ free(hostname);
+}
+
+/* Clear dangerous stuff, set PATH */
+static const char forbid[] ALIGN1 =
+ "ENV" "\0"
+ "BASH_ENV" "\0"
+ "HOME" "\0"
+ "IFS" "\0"
+ "SHELL" "\0"
+ "LD_LIBRARY_PATH" "\0"
+ "LD_PRELOAD" "\0"
+ "LD_TRACE_LOADED_OBJECTS" "\0"
+ "LD_BIND_NOW" "\0"
+ "LD_AOUT_LIBRARY_PATH" "\0"
+ "LD_AOUT_PRELOAD" "\0"
+ "LD_NOWARN" "\0"
+ "LD_KEEPDIR" "\0";
+
+int sanitize_env_if_suid(void)
+{
+ const char *p;
+
+ if (getuid() == geteuid())
+ return 0;
+
+ p = forbid;
+ do {
+ unsetenv(p);
+ p += strlen(p) + 1;
+ } while (*p);
+ putenv((char*)bb_PATH_root_path);
+
+ return 1; /* we indeed were run by different user! */
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/loop.c b/cleopatre/busybox-1.11.1-spc300/libbb/loop.c
new file mode 100644
index 0000000000..6934b7a3bd
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/loop.c
@@ -0,0 +1,154 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2005 by Rob Landley <rob@landley.net>
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+
+/* For 2.6, use the cleaned up header to get the 64 bit API. */
+#include <linux/version.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#include <linux/loop.h>
+typedef struct loop_info64 bb_loop_info;
+#define BB_LOOP_SET_STATUS LOOP_SET_STATUS64
+#define BB_LOOP_GET_STATUS LOOP_GET_STATUS64
+
+/* For 2.4 and earlier, use the 32 bit API (and don't trust the headers) */
+#else
+/* Stuff stolen from linux/loop.h for 2.4 and earlier kernels*/
+#include <linux/posix_types.h>
+#define LO_NAME_SIZE 64
+#define LO_KEY_SIZE 32
+#define LOOP_SET_FD 0x4C00
+#define LOOP_CLR_FD 0x4C01
+#define BB_LOOP_SET_STATUS 0x4C02
+#define BB_LOOP_GET_STATUS 0x4C03
+typedef struct {
+ int lo_number;
+ __kernel_dev_t lo_device;
+ unsigned long lo_inode;
+ __kernel_dev_t lo_rdevice;
+ int lo_offset;
+ int lo_encrypt_type;
+ int lo_encrypt_key_size;
+ int lo_flags;
+ char lo_file_name[LO_NAME_SIZE];
+ unsigned char lo_encrypt_key[LO_KEY_SIZE];
+ unsigned long lo_init[2];
+ char reserved[4];
+} bb_loop_info;
+#endif
+
+char *query_loop(const char *device)
+{
+ int fd;
+ bb_loop_info loopinfo;
+ char *dev = 0;
+
+ fd = open(device, O_RDONLY);
+ if (fd < 0) return 0;
+ if (!ioctl(fd, BB_LOOP_GET_STATUS, &loopinfo))
+ dev = xasprintf("%ld %s", (long) loopinfo.lo_offset,
+ (char *)loopinfo.lo_file_name);
+ close(fd);
+
+ return dev;
+}
+
+
+int del_loop(const char *device)
+{
+ int fd, rc;
+
+ fd = open(device, O_RDONLY);
+ if (fd < 0) return 1;
+ rc = ioctl(fd, LOOP_CLR_FD, 0);
+ close(fd);
+
+ return rc;
+}
+
+/* Returns 0 if mounted RW, 1 if mounted read-only, <0 for error.
+ *device is loop device to use, or if *device==NULL finds a loop device to
+ mount it on and sets *device to a strdup of that loop device name. This
+ search will re-use an existing loop device already bound to that
+ file/offset if it finds one.
+ */
+int set_loop(char **device, const char *file, unsigned long long offset)
+{
+ char dev[LOOP_NAMESIZE];
+ char *try;
+ bb_loop_info loopinfo;
+ struct stat statbuf;
+ int i, dfd, ffd, mode, rc = -1;
+
+ /* Open the file. Barf if this doesn't work. */
+ mode = O_RDWR;
+ ffd = open(file, mode);
+ if (ffd < 0) {
+ mode = O_RDONLY;
+ ffd = open(file, mode);
+ if (ffd < 0)
+ return -errno;
+ }
+
+ /* Find a loop device. */
+ try = *device ? : dev;
+ for (i = 0; rc; i++) {
+ sprintf(dev, LOOP_FORMAT, i);
+
+ /* Ran out of block devices, return failure. */
+ if (stat(try, &statbuf) || !S_ISBLK(statbuf.st_mode)) {
+ rc = -ENOENT;
+ break;
+ }
+ /* Open the sucker and check its loopiness. */
+ dfd = open(try, mode);
+ if (dfd < 0 && errno == EROFS) {
+ mode = O_RDONLY;
+ dfd = open(try, mode);
+ }
+ if (dfd < 0)
+ goto try_again;
+
+ rc = ioctl(dfd, BB_LOOP_GET_STATUS, &loopinfo);
+
+ /* If device is free, claim it. */
+ if (rc && errno == ENXIO) {
+ memset(&loopinfo, 0, sizeof(loopinfo));
+ safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE);
+ loopinfo.lo_offset = offset;
+ /* Associate free loop device with file. */
+ if (!ioctl(dfd, LOOP_SET_FD, ffd)) {
+ if (!ioctl(dfd, BB_LOOP_SET_STATUS, &loopinfo))
+ rc = 0;
+ else
+ ioctl(dfd, LOOP_CLR_FD, 0);
+ }
+
+ /* If this block device already set up right, re-use it.
+ (Yes this is racy, but associating two loop devices with the same
+ file isn't pretty either. In general, mounting the same file twice
+ without using losetup manually is problematic.)
+ */
+ } else if (strcmp(file, (char *)loopinfo.lo_file_name) != 0
+ || offset != loopinfo.lo_offset) {
+ rc = -1;
+ }
+ close(dfd);
+ try_again:
+ if (*device) break;
+ }
+ close(ffd);
+ if (!rc) {
+ if (!*device)
+ *device = xstrdup(dev);
+ return (mode == O_RDONLY); /* 1:ro, 0:rw */
+ }
+ return rc;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/make_directory.c b/cleopatre/busybox-1.11.1-spc300/libbb/make_directory.c
new file mode 100644
index 0000000000..8841c95d33
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/make_directory.c
@@ -0,0 +1,103 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * parse_mode implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* Mar 5, 2003 Manuel Novoa III
+ *
+ * This is the main work function for the 'mkdir' applet. As such, it
+ * strives to be SUSv3 compliant in it's behaviour when recursively
+ * making missing parent dirs, and in it's mode setting of the final
+ * directory 'path'.
+ *
+ * To recursively build all missing intermediate directories, make
+ * sure that (flags & FILEUTILS_RECUR) is non-zero. Newly created
+ * intermediate directories will have at least u+wx perms.
+ *
+ * To set specific permissions on 'path', pass the appropriate 'mode'
+ * val. Otherwise, pass -1 to get default permissions.
+ */
+
+#include "libbb.h"
+
+/* This function is used from NOFORK applets. It must not allocate anything */
+
+int bb_make_directory (char *path, long mode, int flags)
+{
+ mode_t mask;
+ const char *fail_msg;
+ char *s = path;
+ char c;
+ struct stat st;
+
+ mask = umask(0);
+ if (mode == -1) {
+ umask(mask);
+ mode = (S_IXUSR | S_IXGRP | S_IXOTH |
+ S_IWUSR | S_IWGRP | S_IWOTH |
+ S_IRUSR | S_IRGRP | S_IROTH) & ~mask;
+ } else {
+ umask(mask & ~0300);
+ }
+
+ do {
+ c = 0;
+
+ if (flags & FILEUTILS_RECUR) { /* Get the parent. */
+ /* Bypass leading non-'/'s and then subsequent '/'s. */
+ while (*s) {
+ if (*s == '/') {
+ do {
+ ++s;
+ } while (*s == '/');
+ c = *s; /* Save the current char */
+ *s = 0; /* and replace it with nul. */
+ break;
+ }
+ ++s;
+ }
+ }
+
+ if (mkdir(path, 0777) < 0) {
+ /* If we failed for any other reason than the directory
+ * already exists, output a diagnostic and return -1.*/
+ if (errno != EEXIST
+ || !(flags & FILEUTILS_RECUR)
+ || (stat(path, &st) < 0 || !S_ISDIR(st.st_mode))) {
+ fail_msg = "create";
+ umask(mask);
+ break;
+ }
+ /* Since the directory exists, don't attempt to change
+ * permissions if it was the full target. Note that
+ * this is not an error conditon. */
+ if (!c) {
+ umask(mask);
+ return 0;
+ }
+ }
+
+ if (!c) {
+ /* Done. If necessary, updated perms on the newly
+ * created directory. Failure to update here _is_
+ * an error.*/
+ umask(mask);
+ if ((mode != -1) && (chmod(path, mode) < 0)){
+ fail_msg = "set permissions of";
+ break;
+ }
+ return 0;
+ }
+
+ /* Remove any inserted nul from the path (recursive mode). */
+ *s = c;
+
+ } while (1);
+
+ bb_perror_msg("cannot %s directory '%s'", fail_msg, path);
+ return -1;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/makedev.c b/cleopatre/busybox-1.11.1-spc300/libbb/makedev.c
new file mode 100644
index 0000000000..efd51224f6
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/makedev.c
@@ -0,0 +1,23 @@
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2006 Denys Vlasenko
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+
+/* We do not include libbb.h - #define makedev() is there! */
+#include <features.h>
+#include <sys/sysmacros.h>
+
+#ifdef __GLIBC__
+/* At least glibc has horrendously large inline for this, so wrap it */
+/* uclibc people please check - do we need "&& !__UCLIBC__" above? */
+
+/* suppress gcc "no previous prototype" warning */
+unsigned long long bb_makedev(unsigned int major, unsigned int minor);
+unsigned long long bb_makedev(unsigned int major, unsigned int minor)
+{
+ return makedev(major, minor);
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/match_fstype.c b/cleopatre/busybox-1.11.1-spc300/libbb/match_fstype.c
new file mode 100644
index 0000000000..bd4dbb0640
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/match_fstype.c
@@ -0,0 +1,44 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Match fstypes for use in mount unmount
+ * We accept notmpfs,nfs but not notmpfs,nonfs
+ * This allows us to match fstypes that start with no like so
+ * mount -at ,noddy
+ *
+ * Returns 0 for a match, otherwise -1
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+int match_fstype(const struct mntent *mt, const char *fstype)
+{
+ int no = 0;
+ int len;
+
+ if (!mt)
+ return -1;
+
+ if (!fstype)
+ return 0;
+
+ if (fstype[0] == 'n' && fstype[1] == 'o') {
+ no = -1;
+ fstype += 2;
+ }
+
+ len = strlen(mt->mnt_type);
+ while (fstype) {
+ if (!strncmp(mt->mnt_type, fstype, len)
+ && (!fstype[len] || fstype[len] == ',')
+ ) {
+ return no;
+ }
+ fstype = strchr(fstype, ',');
+ if (fstype)
+ fstype++;
+ }
+
+ return -(no + 1);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/md5.c b/cleopatre/busybox-1.11.1-spc300/libbb/md5.c
new file mode 100644
index 0000000000..8d4b9fe52c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/md5.c
@@ -0,0 +1,446 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * md5.c - Compute MD5 checksum of strings according to the
+ * definition of MD5 in RFC 1321 from April 1992.
+ *
+ * Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+ *
+ * Copyright (C) 1995-1999 Free Software Foundation, Inc.
+ * Copyright (C) 2001 Manuel Novoa III
+ * Copyright (C) 2003 Glenn L. McGrath
+ * Copyright (C) 2003 Erik Andersen
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+
+#if CONFIG_MD5_SIZE_VS_SPEED < 0 || CONFIG_MD5_SIZE_VS_SPEED > 3
+# define MD5_SIZE_VS_SPEED 2
+#else
+# define MD5_SIZE_VS_SPEED CONFIG_MD5_SIZE_VS_SPEED
+#endif
+
+/* Initialize structure containing state of computation.
+ * (RFC 1321, 3.3: Step 3)
+ */
+void md5_begin(md5_ctx_t *ctx)
+{
+ ctx->A = 0x67452301;
+ ctx->B = 0xefcdab89;
+ ctx->C = 0x98badcfe;
+ ctx->D = 0x10325476;
+
+ ctx->total = 0;
+ ctx->buflen = 0;
+}
+
+/* These are the four functions used in the four steps of the MD5 algorithm
+ * and defined in the RFC 1321. The first function is a little bit optimized
+ * (as found in Colin Plumbs public domain implementation).
+ * #define FF(b, c, d) ((b & c) | (~b & d))
+ */
+# define FF(b, c, d) (d ^ (b & (c ^ d)))
+# define FG(b, c, d) FF (d, b, c)
+# define FH(b, c, d) (b ^ c ^ d)
+# define FI(b, c, d) (c ^ (b | ~d))
+
+/* Hash a single block, 64 bytes long and 4-byte aligned. */
+static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
+{
+ uint32_t correct_words[16];
+ const uint32_t *words = buffer;
+
+# if MD5_SIZE_VS_SPEED > 0
+ static const uint32_t C_array[] = {
+ /* round 1 */
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+ 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+ /* round 2 */
+ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+ 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8,
+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+ 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+ /* round 3 */
+ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
+ 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+ /* round 4 */
+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+ };
+
+ static const char P_array[] ALIGN1 = {
+# if MD5_SIZE_VS_SPEED > 1
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */
+# endif /* MD5_SIZE_VS_SPEED > 1 */
+ 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */
+ 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */
+ 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */
+ };
+
+# if MD5_SIZE_VS_SPEED > 1
+ static const char S_array[] ALIGN1 = {
+ 7, 12, 17, 22,
+ 5, 9, 14, 20,
+ 4, 11, 16, 23,
+ 6, 10, 15, 21
+ };
+# endif /* MD5_SIZE_VS_SPEED > 1 */
+# endif
+
+ uint32_t A = ctx->A;
+ uint32_t B = ctx->B;
+ uint32_t C = ctx->C;
+ uint32_t D = ctx->D;
+
+ /* Process all bytes in the buffer with 64 bytes in each round of
+ the loop. */
+ uint32_t *cwp = correct_words;
+ uint32_t A_save = A;
+ uint32_t B_save = B;
+ uint32_t C_save = C;
+ uint32_t D_save = D;
+
+# if MD5_SIZE_VS_SPEED > 1
+# define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
+
+ const uint32_t *pc;
+ const char *pp;
+ const char *ps;
+ int i;
+ uint32_t temp;
+
+ for (i = 0; i < 16; i++) {
+ cwp[i] = SWAP_LE32(words[i]);
+ }
+ words += 16;
+
+# if MD5_SIZE_VS_SPEED > 2
+ pc = C_array;
+ pp = P_array;
+ ps = S_array - 4;
+
+ for (i = 0; i < 64; i++) {
+ if ((i & 0x0f) == 0)
+ ps += 4;
+ temp = A;
+ switch (i >> 4) {
+ case 0:
+ temp += FF(B, C, D);
+ break;
+ case 1:
+ temp += FG(B, C, D);
+ break;
+ case 2:
+ temp += FH(B, C, D);
+ break;
+ case 3:
+ temp += FI(B, C, D);
+ }
+ temp += cwp[(int) (*pp++)] + *pc++;
+ CYCLIC(temp, ps[i & 3]);
+ temp += B;
+ A = D;
+ D = C;
+ C = B;
+ B = temp;
+ }
+# else
+ pc = C_array;
+ pp = P_array;
+ ps = S_array;
+
+ for (i = 0; i < 16; i++) {
+ temp = A + FF(B, C, D) + cwp[(int) (*pp++)] + *pc++;
+ CYCLIC(temp, ps[i & 3]);
+ temp += B;
+ A = D;
+ D = C;
+ C = B;
+ B = temp;
+ }
+
+ ps += 4;
+ for (i = 0; i < 16; i++) {
+ temp = A + FG(B, C, D) + cwp[(int) (*pp++)] + *pc++;
+ CYCLIC(temp, ps[i & 3]);
+ temp += B;
+ A = D;
+ D = C;
+ C = B;
+ B = temp;
+ }
+ ps += 4;
+ for (i = 0; i < 16; i++) {
+ temp = A + FH(B, C, D) + cwp[(int) (*pp++)] + *pc++;
+ CYCLIC(temp, ps[i & 3]);
+ temp += B;
+ A = D;
+ D = C;
+ C = B;
+ B = temp;
+ }
+ ps += 4;
+ for (i = 0; i < 16; i++) {
+ temp = A + FI(B, C, D) + cwp[(int) (*pp++)] + *pc++;
+ CYCLIC(temp, ps[i & 3]);
+ temp += B;
+ A = D;
+ D = C;
+ C = B;
+ B = temp;
+ }
+
+# endif /* MD5_SIZE_VS_SPEED > 2 */
+# else
+ /* First round: using the given function, the context and a constant
+ the next context is computed. Because the algorithms processing
+ unit is a 32-bit word and it is determined to work on words in
+ little endian byte order we perhaps have to change the byte order
+ before the computation. To reduce the work for the next steps
+ we store the swapped words in the array CORRECT_WORDS. */
+
+# define OP(a, b, c, d, s, T) \
+ do { \
+ a += FF (b, c, d) + (*cwp++ = SWAP_LE32(*words)) + T; \
+ ++words; \
+ CYCLIC (a, s); \
+ a += b; \
+ } while (0)
+
+ /* It is unfortunate that C does not provide an operator for
+ cyclic rotation. Hope the C compiler is smart enough. */
+ /* gcc 2.95.4 seems to be --aaronl */
+# define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
+
+ /* Before we start, one word to the strange constants.
+ They are defined in RFC 1321 as
+
+ T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
+ */
+
+# if MD5_SIZE_VS_SPEED == 1
+ const uint32_t *pc;
+ const char *pp;
+ int i;
+# endif /* MD5_SIZE_VS_SPEED */
+
+ /* Round 1. */
+# if MD5_SIZE_VS_SPEED == 1
+ pc = C_array;
+ for (i = 0; i < 4; i++) {
+ OP(A, B, C, D, 7, *pc++);
+ OP(D, A, B, C, 12, *pc++);
+ OP(C, D, A, B, 17, *pc++);
+ OP(B, C, D, A, 22, *pc++);
+ }
+# else
+ OP(A, B, C, D, 7, 0xd76aa478);
+ OP(D, A, B, C, 12, 0xe8c7b756);
+ OP(C, D, A, B, 17, 0x242070db);
+ OP(B, C, D, A, 22, 0xc1bdceee);
+ OP(A, B, C, D, 7, 0xf57c0faf);
+ OP(D, A, B, C, 12, 0x4787c62a);
+ OP(C, D, A, B, 17, 0xa8304613);
+ OP(B, C, D, A, 22, 0xfd469501);
+ OP(A, B, C, D, 7, 0x698098d8);
+ OP(D, A, B, C, 12, 0x8b44f7af);
+ OP(C, D, A, B, 17, 0xffff5bb1);
+ OP(B, C, D, A, 22, 0x895cd7be);
+ OP(A, B, C, D, 7, 0x6b901122);
+ OP(D, A, B, C, 12, 0xfd987193);
+ OP(C, D, A, B, 17, 0xa679438e);
+ OP(B, C, D, A, 22, 0x49b40821);
+# endif /* MD5_SIZE_VS_SPEED == 1 */
+
+ /* For the second to fourth round we have the possibly swapped words
+ in CORRECT_WORDS. Redefine the macro to take an additional first
+ argument specifying the function to use. */
+# undef OP
+# define OP(f, a, b, c, d, k, s, T) \
+ do { \
+ a += f (b, c, d) + correct_words[k] + T; \
+ CYCLIC (a, s); \
+ a += b; \
+ } while (0)
+
+ /* Round 2. */
+# if MD5_SIZE_VS_SPEED == 1
+ pp = P_array;
+ for (i = 0; i < 4; i++) {
+ OP(FG, A, B, C, D, (int) (*pp++), 5, *pc++);
+ OP(FG, D, A, B, C, (int) (*pp++), 9, *pc++);
+ OP(FG, C, D, A, B, (int) (*pp++), 14, *pc++);
+ OP(FG, B, C, D, A, (int) (*pp++), 20, *pc++);
+ }
+# else
+ OP(FG, A, B, C, D, 1, 5, 0xf61e2562);
+ OP(FG, D, A, B, C, 6, 9, 0xc040b340);
+ OP(FG, C, D, A, B, 11, 14, 0x265e5a51);
+ OP(FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
+ OP(FG, A, B, C, D, 5, 5, 0xd62f105d);
+ OP(FG, D, A, B, C, 10, 9, 0x02441453);
+ OP(FG, C, D, A, B, 15, 14, 0xd8a1e681);
+ OP(FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
+ OP(FG, A, B, C, D, 9, 5, 0x21e1cde6);
+ OP(FG, D, A, B, C, 14, 9, 0xc33707d6);
+ OP(FG, C, D, A, B, 3, 14, 0xf4d50d87);
+ OP(FG, B, C, D, A, 8, 20, 0x455a14ed);
+ OP(FG, A, B, C, D, 13, 5, 0xa9e3e905);
+ OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8);
+ OP(FG, C, D, A, B, 7, 14, 0x676f02d9);
+ OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
+# endif /* MD5_SIZE_VS_SPEED == 1 */
+
+ /* Round 3. */
+# if MD5_SIZE_VS_SPEED == 1
+ for (i = 0; i < 4; i++) {
+ OP(FH, A, B, C, D, (int) (*pp++), 4, *pc++);
+ OP(FH, D, A, B, C, (int) (*pp++), 11, *pc++);
+ OP(FH, C, D, A, B, (int) (*pp++), 16, *pc++);
+ OP(FH, B, C, D, A, (int) (*pp++), 23, *pc++);
+ }
+# else
+ OP(FH, A, B, C, D, 5, 4, 0xfffa3942);
+ OP(FH, D, A, B, C, 8, 11, 0x8771f681);
+ OP(FH, C, D, A, B, 11, 16, 0x6d9d6122);
+ OP(FH, B, C, D, A, 14, 23, 0xfde5380c);
+ OP(FH, A, B, C, D, 1, 4, 0xa4beea44);
+ OP(FH, D, A, B, C, 4, 11, 0x4bdecfa9);
+ OP(FH, C, D, A, B, 7, 16, 0xf6bb4b60);
+ OP(FH, B, C, D, A, 10, 23, 0xbebfbc70);
+ OP(FH, A, B, C, D, 13, 4, 0x289b7ec6);
+ OP(FH, D, A, B, C, 0, 11, 0xeaa127fa);
+ OP(FH, C, D, A, B, 3, 16, 0xd4ef3085);
+ OP(FH, B, C, D, A, 6, 23, 0x04881d05);
+ OP(FH, A, B, C, D, 9, 4, 0xd9d4d039);
+ OP(FH, D, A, B, C, 12, 11, 0xe6db99e5);
+ OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8);
+ OP(FH, B, C, D, A, 2, 23, 0xc4ac5665);
+# endif /* MD5_SIZE_VS_SPEED == 1 */
+
+ /* Round 4. */
+# if MD5_SIZE_VS_SPEED == 1
+ for (i = 0; i < 4; i++) {
+ OP(FI, A, B, C, D, (int) (*pp++), 6, *pc++);
+ OP(FI, D, A, B, C, (int) (*pp++), 10, *pc++);
+ OP(FI, C, D, A, B, (int) (*pp++), 15, *pc++);
+ OP(FI, B, C, D, A, (int) (*pp++), 21, *pc++);
+ }
+# else
+ OP(FI, A, B, C, D, 0, 6, 0xf4292244);
+ OP(FI, D, A, B, C, 7, 10, 0x432aff97);
+ OP(FI, C, D, A, B, 14, 15, 0xab9423a7);
+ OP(FI, B, C, D, A, 5, 21, 0xfc93a039);
+ OP(FI, A, B, C, D, 12, 6, 0x655b59c3);
+ OP(FI, D, A, B, C, 3, 10, 0x8f0ccc92);
+ OP(FI, C, D, A, B, 10, 15, 0xffeff47d);
+ OP(FI, B, C, D, A, 1, 21, 0x85845dd1);
+ OP(FI, A, B, C, D, 8, 6, 0x6fa87e4f);
+ OP(FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
+ OP(FI, C, D, A, B, 6, 15, 0xa3014314);
+ OP(FI, B, C, D, A, 13, 21, 0x4e0811a1);
+ OP(FI, A, B, C, D, 4, 6, 0xf7537e82);
+ OP(FI, D, A, B, C, 11, 10, 0xbd3af235);
+ OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
+ OP(FI, B, C, D, A, 9, 21, 0xeb86d391);
+# endif /* MD5_SIZE_VS_SPEED == 1 */
+# endif /* MD5_SIZE_VS_SPEED > 1 */
+
+ /* Add the starting values of the context. */
+ A += A_save;
+ B += B_save;
+ C += C_save;
+ D += D_save;
+
+ /* Put checksum in context given as argument. */
+ ctx->A = A;
+ ctx->B = B;
+ ctx->C = C;
+ ctx->D = D;
+}
+
+/* Feed data through a temporary buffer to call md5_hash_aligned_block()
+ * with chunks of data that are 4-byte aligned and a multiple of 64 bytes.
+ * This function's internal buffer remembers previous data until it has 64
+ * bytes worth to pass on. Call md5_end() to flush this buffer. */
+
+void md5_hash(const void *buffer, size_t len, md5_ctx_t *ctx)
+{
+ char *buf=(char *)buffer;
+
+ /* RFC 1321 specifies the possible length of the file up to 2^64 bits,
+ * Here we only track the number of bytes. */
+
+ ctx->total += len;
+
+ // Process all input.
+
+ while (len) {
+ unsigned i = 64 - ctx->buflen;
+
+ // Copy data into aligned buffer.
+
+ if (i > len) i = len;
+ memcpy(ctx->buffer + ctx->buflen, buf, i);
+ len -= i;
+ ctx->buflen += i;
+ buf += i;
+
+ // When buffer fills up, process it.
+
+ if (ctx->buflen == 64) {
+ md5_hash_block(ctx->buffer, ctx);
+ ctx->buflen = 0;
+ }
+ }
+}
+
+/* Process the remaining bytes in the buffer and put result from CTX
+ * in first 16 bytes following RESBUF. The result is always in little
+ * endian byte order, so that a byte-wise output yields to the wanted
+ * ASCII representation of the message digest.
+ *
+ * IMPORTANT: On some systems it is required that RESBUF is correctly
+ * aligned for a 32 bits value.
+ */
+void *md5_end(void *resbuf, md5_ctx_t *ctx)
+{
+ char *buf = ctx->buffer;
+ int i;
+
+ /* Pad data to block size. */
+
+ buf[ctx->buflen++] = 0x80;
+ memset(buf + ctx->buflen, 0, 128 - ctx->buflen);
+
+ /* Put the 64-bit file length in *bits* at the end of the buffer. */
+ ctx->total <<= 3;
+ if (ctx->buflen > 56) buf += 64;
+ for (i = 0; i < 8; i++) buf[56 + i] = ctx->total >> (i*8);
+
+ /* Process last bytes. */
+ if (buf != ctx->buffer) md5_hash_block(ctx->buffer, ctx);
+ md5_hash_block(buf, ctx);
+
+ /* Put result from CTX in first 16 bytes following RESBUF. The result is
+ * always in little endian byte order, so that a byte-wise output yields
+ * to the wanted ASCII representation of the message digest.
+ *
+ * IMPORTANT: On some systems it is required that RESBUF is correctly
+ * aligned for a 32 bits value.
+ */
+ ((uint32_t *) resbuf)[0] = SWAP_LE32(ctx->A);
+ ((uint32_t *) resbuf)[1] = SWAP_LE32(ctx->B);
+ ((uint32_t *) resbuf)[2] = SWAP_LE32(ctx->C);
+ ((uint32_t *) resbuf)[3] = SWAP_LE32(ctx->D);
+
+ return resbuf;
+}
+
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/messages.c b/cleopatre/busybox-1.11.1-spc300/libbb/messages.c
new file mode 100644
index 0000000000..74a070c49a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/messages.c
@@ -0,0 +1,73 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* allow default system PATH to be extended via CFLAGS */
+#ifndef BB_ADDITIONAL_PATH
+#define BB_ADDITIONAL_PATH ""
+#endif
+
+/* allow version to be extended, via CFLAGS */
+#ifndef BB_EXTRA_VERSION
+#define BB_EXTRA_VERSION BB_BT
+#endif
+
+#define BANNER "BusyBox v" BB_VER " (" BB_EXTRA_VERSION ")"
+
+const char bb_banner[] ALIGN1 = BANNER;
+
+
+const char bb_msg_memory_exhausted[] ALIGN1 = "memory exhausted";
+const char bb_msg_invalid_date[] ALIGN1 = "invalid date '%s'";
+const char bb_msg_write_error[] ALIGN1 = "write error";
+const char bb_msg_read_error[] ALIGN1 = "read error";
+const char bb_msg_unknown[] ALIGN1 = "(unknown)";
+const char bb_msg_can_not_create_raw_socket[] ALIGN1 = "can't create raw socket";
+const char bb_msg_perm_denied_are_you_root[] ALIGN1 = "permission denied. (are you root?)";
+const char bb_msg_requires_arg[] ALIGN1 = "%s requires an argument";
+const char bb_msg_invalid_arg[] ALIGN1 = "invalid argument '%s' to '%s'";
+const char bb_msg_standard_input[] ALIGN1 = "standard input";
+const char bb_msg_standard_output[] ALIGN1 = "standard output";
+
+const char bb_str_default[] ALIGN1 = "default";
+const char bb_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF";
+
+const char bb_path_passwd_file[] ALIGN1 = "/etc/passwd";
+const char bb_path_shadow_file[] ALIGN1 = "/etc/shadow";
+const char bb_path_group_file[] ALIGN1 = "/etc/group";
+const char bb_path_gshadow_file[] ALIGN1 = "/etc/gshadow";
+const char bb_path_motd_file[] ALIGN1 = "/etc/motd";
+const char bb_dev_null[] ALIGN1 = "/dev/null";
+const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH;
+const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL;
+/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin,
+ * but I want to save a few bytes here. Check libbb.h before changing! */
+const char bb_PATH_root_path[] ALIGN1 =
+ "PATH=/sbin:/usr/sbin:/bin:/usr/bin" BB_ADDITIONAL_PATH;
+
+
+const int const_int_1 = 1;
+/* explicitly = 0, otherwise gcc may make it a common variable
+ * and it will end up in bss */
+const int const_int_0 = 0;
+
+#include <utmp.h>
+/* This is usually something like "/var/adm/wtmp" or "/var/log/wtmp" */
+const char bb_path_wtmp_file[] ALIGN1 =
+#if defined _PATH_WTMP
+ _PATH_WTMP;
+#elif defined WTMP_FILE
+ WTMP_FILE;
+#else
+#error unknown path to wtmp file
+#endif
+
+/* We use it for "global" data via *(struct global*)&bb_common_bufsiz1.
+ * Since gcc insists on aligning struct global's members, it would be a pity
+ * (and an alignment fault on some CPUs) to mess it up. */
+char bb_common_bufsiz1[COMMON_BUFSIZE] __attribute__(( aligned(sizeof(long long)) ));
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/mode_string.c b/cleopatre/busybox-1.11.1-spc300/libbb/mode_string.c
new file mode 100644
index 0000000000..d17cc4a43a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/mode_string.c
@@ -0,0 +1,128 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * mode_string implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* Aug 13, 2003
+ * Fix a bug reported by junkio@cox.net involving the mode_chars index.
+ */
+
+
+#include <assert.h>
+#include <sys/stat.h>
+
+#include "libbb.h"
+
+#if ( S_ISUID != 04000 ) || ( S_ISGID != 02000 ) || ( S_ISVTX != 01000 ) \
+ || ( S_IRUSR != 00400 ) || ( S_IWUSR != 00200 ) || ( S_IXUSR != 00100 ) \
+ || ( S_IRGRP != 00040 ) || ( S_IWGRP != 00020 ) || ( S_IXGRP != 00010 ) \
+ || ( S_IROTH != 00004 ) || ( S_IWOTH != 00002 ) || ( S_IXOTH != 00001 )
+#error permission bitflag value assumption(s) violated!
+#endif
+
+#if ( S_IFSOCK!= 0140000 ) || ( S_IFLNK != 0120000 ) \
+ || ( S_IFREG != 0100000 ) || ( S_IFBLK != 0060000 ) \
+ || ( S_IFDIR != 0040000 ) || ( S_IFCHR != 0020000 ) \
+ || ( S_IFIFO != 0010000 )
+#warning mode type bitflag value assumption(s) violated! falling back to larger version
+
+#if (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX) == 07777
+#undef mode_t
+#define mode_t unsigned short
+#endif
+
+static const mode_t mode_flags[] = {
+ S_IRUSR, S_IWUSR, S_IXUSR, S_ISUID,
+ S_IRGRP, S_IWGRP, S_IXGRP, S_ISGID,
+ S_IROTH, S_IWOTH, S_IXOTH, S_ISVTX
+};
+
+/* The static const char arrays below are duplicated for the two cases
+ * because moving them ahead of the mode_flags declaration cause a text
+ * size increase with the gcc version I'm using. */
+
+/* The previous version used "0pcCd?bB-?l?s???". However, the '0', 'C',
+ * and 'B' types don't appear to be available on linux. So I removed them. */
+static const char type_chars[16] ALIGN1 = "?pc?d?b?-?l?s???";
+/* 0123456789abcdef */
+static const char mode_chars[7] ALIGN1 = "rwxSTst";
+
+const char *bb_mode_string(mode_t mode)
+{
+ static char buf[12];
+ char *p = buf;
+
+ int i, j, k;
+
+ *p = type_chars[ (mode >> 12) & 0xf ];
+ i = 0;
+ do {
+ j = k = 0;
+ do {
+ *++p = '-';
+ if (mode & mode_flags[i+j]) {
+ *p = mode_chars[j];
+ k = j;
+ }
+ } while (++j < 3);
+ if (mode & mode_flags[i+j]) {
+ *p = mode_chars[3 + (k & 2) + ((i&8) >> 3)];
+ }
+ i += 4;
+ } while (i < 12);
+
+ /* Note: We don't bother with nul termination because bss initialization
+ * should have taken care of that for us. If the user scribbled in buf
+ * memory, they deserve whatever happens. But we'll at least assert. */
+ assert(buf[10] == 0);
+
+ return buf;
+}
+
+#else
+
+/* The previous version used "0pcCd?bB-?l?s???". However, the '0', 'C',
+ * and 'B' types don't appear to be available on linux. So I removed them. */
+static const char type_chars[16] = "?pc?d?b?-?l?s???";
+/* 0123456789abcdef */
+static const char mode_chars[7] = "rwxSTst";
+
+const char *bb_mode_string(mode_t mode)
+{
+ static char buf[12];
+ char *p = buf;
+
+ int i, j, k, m;
+
+ *p = type_chars[ (mode >> 12) & 0xf ];
+ i = 0;
+ m = 0400;
+ do {
+ j = k = 0;
+ do {
+ *++p = '-';
+ if (mode & m) {
+ *p = mode_chars[j];
+ k = j;
+ }
+ m >>= 1;
+ } while (++j < 3);
+ ++i;
+ if (mode & (010000 >> i)) {
+ *p = mode_chars[3 + (k & 2) + (i == 3)];
+ }
+ } while (i < 3);
+
+ /* Note: We don't bother with nul termination because bss initialization
+ * should have taken care of that for us. If the user scribbled in buf
+ * memory, they deserve whatever happens. But we'll at least assert. */
+ assert(buf[10] == 0);
+
+ return buf;
+}
+
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/mtab.c b/cleopatre/busybox-1.11.1-spc300/libbb/mtab.c
new file mode 100644
index 0000000000..18386efb5a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/mtab.c
@@ -0,0 +1,52 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include <mntent.h>
+#include "libbb.h"
+
+#if ENABLE_FEATURE_MTAB_SUPPORT
+void erase_mtab(const char *name)
+{
+ struct mntent *entries = NULL;
+ int i, count = 0;
+ FILE *mountTable;
+ struct mntent *m;
+
+ mountTable = setmntent(bb_path_mtab_file, "r");
+ /* Bummer. Fall back on trying the /proc filesystem */
+ if (!mountTable) mountTable = setmntent("/proc/mounts", "r");
+ if (!mountTable) {
+ bb_perror_msg(bb_path_mtab_file);
+ return;
+ }
+
+ while ((m = getmntent(mountTable)) != 0) {
+ i = count++;
+ entries = xrealloc(entries, count * sizeof(entries[0]));
+ entries[i].mnt_fsname = xstrdup(m->mnt_fsname);
+ entries[i].mnt_dir = xstrdup(m->mnt_dir);
+ entries[i].mnt_type = xstrdup(m->mnt_type);
+ entries[i].mnt_opts = xstrdup(m->mnt_opts);
+ entries[i].mnt_freq = m->mnt_freq;
+ entries[i].mnt_passno = m->mnt_passno;
+ }
+ endmntent(mountTable);
+
+ mountTable = setmntent(bb_path_mtab_file, "w");
+ if (mountTable) {
+ for (i = 0; i < count; i++) {
+ if (strcmp(entries[i].mnt_fsname, name) != 0
+ && strcmp(entries[i].mnt_dir, name) != 0)
+ addmntent(mountTable, &entries[i]);
+ }
+ endmntent(mountTable);
+ } else if (errno != EROFS)
+ bb_perror_msg(bb_path_mtab_file);
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/mtab_file.c b/cleopatre/busybox-1.11.1-spc300/libbb/mtab_file.c
new file mode 100644
index 0000000000..030b148d38
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/mtab_file.c
@@ -0,0 +1,15 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* Busybox mount uses either /proc/mounts or /etc/mtab to
+ * get the list of currently mounted filesystems */
+const char bb_path_mtab_file[] ALIGN1 =
+USE_FEATURE_MTAB_SUPPORT("/etc/mtab")SKIP_FEATURE_MTAB_SUPPORT("/proc/mounts");
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/obscure.c b/cleopatre/busybox-1.11.1-spc300/libbb/obscure.c
new file mode 100644
index 0000000000..1841b27d6a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/obscure.c
@@ -0,0 +1,170 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini weak password checker implementation for busybox
+ *
+ * Copyright (C) 2006 Tito Ragusa <farmatito@tiscali.it>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* A good password:
+ 1) should contain at least six characters (man passwd);
+ 2) empty passwords are not permitted;
+ 3) should contain a mix of four different types of characters
+ upper case letters,
+ lower case letters,
+ numbers,
+ special characters such as !@#$%^&*,;".
+ This password types should not be permitted:
+ a) pure numbers: birthdates, social security number, license plate, phone numbers;
+ b) words and all letters only passwords (uppercase, lowercase or mixed)
+ as palindromes, consecutive or repetitive letters
+ or adjacent letters on your keyboard;
+ c) username, real name, company name or (e-mail?) address
+ in any form (as-is, reversed, capitalized, doubled, etc.).
+ (we can check only against username, gecos and hostname)
+ d) common and obvious letter-number replacements
+ (e.g. replace the letter O with number 0)
+ such as "M1cr0$0ft" or "P@ssw0rd" (CAVEAT: we cannot check for them
+ without the use of a dictionary).
+
+ For each missing type of characters an increase of password length is
+ requested.
+
+ If user is root we warn only.
+
+ CAVEAT: some older versions of crypt() truncates passwords to 8 chars,
+ so that aaaaaaaa1Q$ is equal to aaaaaaaa making it possible to fool
+ some of our checks. We don't test for this special case as newer versions
+ of crypt do not truncate passwords.
+*/
+
+#include "libbb.h"
+
+static int string_checker_helper(const char *p1, const char *p2) __attribute__ ((__pure__));
+
+static int string_checker_helper(const char *p1, const char *p2)
+{
+ /* as-is or capitalized */
+ if (strcasecmp(p1, p2) == 0
+ /* as sub-string */
+ || strcasestr(p2, p1) != NULL
+ /* invert in case haystack is shorter than needle */
+ || strcasestr(p1, p2) != NULL)
+ return 1;
+ return 0;
+}
+
+static int string_checker(const char *p1, const char *p2)
+{
+ int size;
+ /* check string */
+ int ret = string_checker_helper(p1, p2);
+ /* Make our own copy */
+ char *p = xstrdup(p1);
+ /* reverse string */
+ size = strlen(p);
+
+ while (size--) {
+ *p = p1[size];
+ p++;
+ }
+ /* restore pointer */
+ p -= strlen(p1);
+ /* check reversed string */
+ ret |= string_checker_helper(p, p2);
+ /* clean up */
+ memset(p, 0, strlen(p1));
+ free(p);
+ return ret;
+}
+
+#define LOWERCASE 1
+#define UPPERCASE 2
+#define NUMBERS 4
+#define SPECIAL 8
+
+static const char *obscure_msg(const char *old_p, const char *new_p, const struct passwd *pw)
+{
+ int i;
+ int c;
+ int length;
+ int mixed = 0;
+ /* Add 2 for each type of characters to the minlen of password */
+ int size = CONFIG_PASSWORD_MINLEN + 8;
+ const char *p;
+ char *hostname;
+
+ /* size */
+ if (!new_p || (length = strlen(new_p)) < CONFIG_PASSWORD_MINLEN)
+ return "too short";
+
+ /* no username as-is, as sub-string, reversed, capitalized, doubled */
+ if (string_checker(new_p, pw->pw_name)) {
+ return "similar to username";
+ }
+ /* no gecos as-is, as sub-string, reversed, capitalized, doubled */
+ if (*pw->pw_gecos && string_checker(new_p, pw->pw_gecos)) {
+ return "similar to gecos";
+ }
+ /* hostname as-is, as sub-string, reversed, capitalized, doubled */
+ hostname = safe_gethostname();
+ i = string_checker(new_p, hostname);
+ free(hostname);
+ if (i)
+ return "similar to hostname";
+
+ /* Should / Must contain a mix of: */
+ for (i = 0; i < length; i++) {
+ if (islower(new_p[i])) { /* a-z */
+ mixed |= LOWERCASE;
+ } else if (isupper(new_p[i])) { /* A-Z */
+ mixed |= UPPERCASE;
+ } else if (isdigit(new_p[i])) { /* 0-9 */
+ mixed |= NUMBERS;
+ } else { /* special characters */
+ mixed |= SPECIAL;
+ }
+ /* More than 50% similar characters ? */
+ c = 0;
+ p = new_p;
+ while (1) {
+ p = strchr(p, new_p[i]);
+ if (p == NULL) {
+ break;
+ }
+ c++;
+ if (!++p) {
+ break; /* move past the matched char if possible */
+ }
+ }
+
+ if (c >= (length / 2)) {
+ return "too many similar characters";
+ }
+ }
+ for (i=0; i<4; i++)
+ if (mixed & (1<<i)) size -= 2;
+ if (length < size)
+ return "too weak";
+
+ if (old_p && old_p[0] != '\0') {
+ /* check vs. old password */
+ if (string_checker(new_p, old_p)) {
+ return "similar to old password";
+ }
+ }
+ return NULL;
+}
+
+int obscure(const char *old, const char *newval, const struct passwd *pw)
+{
+ const char *msg;
+
+ msg = obscure_msg(old, newval, pw);
+ if (msg) {
+ printf("Bad password: %s\n", msg);
+ return 1;
+ }
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/parse_mode.c b/cleopatre/busybox-1.11.1-spc300/libbb/parse_mode.c
new file mode 100644
index 0000000000..fd54900398
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/parse_mode.c
@@ -0,0 +1,150 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * parse_mode implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/chmod.html */
+
+#include "libbb.h"
+
+/* This function is used from NOFORK applets. It must not allocate anything */
+
+#define FILEMODEBITS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
+
+int bb_parse_mode(const char *s, mode_t *current_mode)
+{
+ static const mode_t who_mask[] = {
+ S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO, /* a */
+ S_ISUID | S_IRWXU, /* u */
+ S_ISGID | S_IRWXG, /* g */
+ S_IRWXO /* o */
+ };
+ static const mode_t perm_mask[] = {
+ S_IRUSR | S_IRGRP | S_IROTH, /* r */
+ S_IWUSR | S_IWGRP | S_IWOTH, /* w */
+ S_IXUSR | S_IXGRP | S_IXOTH, /* x */
+ S_IXUSR | S_IXGRP | S_IXOTH, /* X -- special -- see below */
+ S_ISUID | S_ISGID, /* s */
+ S_ISVTX /* t */
+ };
+ static const char who_chars[] ALIGN1 = "augo";
+ static const char perm_chars[] ALIGN1 = "rwxXst";
+
+ const char *p;
+ mode_t wholist;
+ mode_t permlist;
+ mode_t new_mode;
+ char op;
+
+ if (((unsigned int)(*s - '0')) < 8) {
+ unsigned long tmp;
+ char *e;
+
+ tmp = strtoul(s, &e, 8);
+ if (*e || (tmp > 07777U)) { /* Check range and trailing chars. */
+ return 0;
+ }
+ *current_mode = tmp;
+ return 1;
+ }
+
+ new_mode = *current_mode;
+
+ /* Note: we allow empty clauses, and hence empty modes.
+ * We treat an empty mode as no change to perms. */
+
+ while (*s) { /* Process clauses. */
+ if (*s == ',') { /* We allow empty clauses. */
+ ++s;
+ continue;
+ }
+
+ /* Get a wholist. */
+ wholist = 0;
+ WHO_LIST:
+ p = who_chars;
+ do {
+ if (*p == *s) {
+ wholist |= who_mask[(int)(p-who_chars)];
+ if (!*++s) {
+ return 0;
+ }
+ goto WHO_LIST;
+ }
+ } while (*++p);
+
+ do { /* Process action list. */
+ if ((*s != '+') && (*s != '-')) {
+ if (*s != '=') {
+ return 0;
+ }
+ /* Since op is '=', clear all bits corresponding to the
+ * wholist, or all file bits if wholist is empty. */
+ permlist = ~FILEMODEBITS;
+ if (wholist) {
+ permlist = ~wholist;
+ }
+ new_mode &= permlist;
+ }
+ op = *s++;
+
+ /* Check for permcopy. */
+ p = who_chars + 1; /* Skip 'a' entry. */
+ do {
+ if (*p == *s) {
+ int i = 0;
+ permlist = who_mask[(int)(p-who_chars)]
+ & (S_IRWXU | S_IRWXG | S_IRWXO)
+ & new_mode;
+ do {
+ if (permlist & perm_mask[i]) {
+ permlist |= perm_mask[i];
+ }
+ } while (++i < 3);
+ ++s;
+ goto GOT_ACTION;
+ }
+ } while (*++p);
+
+ /* It was not a permcopy, so get a permlist. */
+ permlist = 0;
+ PERM_LIST:
+ p = perm_chars;
+ do {
+ if (*p == *s) {
+ if ((*p != 'X')
+ || (new_mode & (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH))
+ ) {
+ permlist |= perm_mask[(int)(p-perm_chars)];
+ }
+ if (!*++s) {
+ break;
+ }
+ goto PERM_LIST;
+ }
+ } while (*++p);
+ GOT_ACTION:
+ if (permlist) { /* The permlist was nonempty. */
+ mode_t tmp = wholist;
+ if (!wholist) {
+ mode_t u_mask = umask(0);
+ umask(u_mask);
+ tmp = ~u_mask;
+ }
+ permlist &= tmp;
+ if (op == '-') {
+ new_mode &= ~permlist;
+ } else {
+ new_mode |= permlist;
+ }
+ }
+ } while (*s && (*s != ','));
+ }
+
+ *current_mode = new_mode;
+ return 1;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/perror_msg.c b/cleopatre/busybox-1.11.1-spc300/libbb/perror_msg.c
new file mode 100644
index 0000000000..af9ff59498
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/perror_msg.c
@@ -0,0 +1,25 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+void bb_perror_msg(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ /* Guard against "<error message>: Success" */
+ bb_verror_msg(s, p, errno ? strerror(errno) : NULL);
+ va_end(p);
+}
+
+void bb_simple_perror_msg(const char *s)
+{
+ bb_perror_msg("%s", s);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/perror_msg_and_die.c b/cleopatre/busybox-1.11.1-spc300/libbb/perror_msg_and_die.c
new file mode 100644
index 0000000000..7b500736a8
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/perror_msg_and_die.c
@@ -0,0 +1,26 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+void bb_perror_msg_and_die(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ /* Guard against "<error message>: Success" */
+ bb_verror_msg(s, p, errno ? strerror(errno) : NULL);
+ va_end(p);
+ xfunc_die();
+}
+
+void bb_simple_perror_msg_and_die(const char *s)
+{
+ bb_perror_msg_and_die("%s", s);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/perror_nomsg.c b/cleopatre/busybox-1.11.1-spc300/libbb/perror_nomsg.c
new file mode 100644
index 0000000000..62ce888ae7
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/perror_nomsg.c
@@ -0,0 +1,21 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bb_perror_nomsg implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* gcc warns about a null format string, therefore we provide
+ * modified definition without "attribute (format)"
+ * instead of including libbb.h */
+//#include "libbb.h"
+extern void bb_perror_msg(const char *s, ...);
+
+/* suppress gcc "no previous prototype" warning */
+void bb_perror_nomsg(void);
+void bb_perror_nomsg(void)
+{
+ bb_perror_msg(0);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/perror_nomsg_and_die.c b/cleopatre/busybox-1.11.1-spc300/libbb/perror_nomsg_and_die.c
new file mode 100644
index 0000000000..dab3df60ab
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/perror_nomsg_and_die.c
@@ -0,0 +1,21 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bb_perror_nomsg_and_die implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* gcc warns about a null format string, therefore we provide
+ * modified definition without "attribute (format)"
+ * instead of including libbb.h */
+//#include "libbb.h"
+extern void bb_perror_msg_and_die(const char *s, ...);
+
+/* suppress gcc "no previous prototype" warning */
+void bb_perror_nomsg_and_die(void);
+void bb_perror_nomsg_and_die(void)
+{
+ bb_perror_msg_and_die(0);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/pidfile.c b/cleopatre/busybox-1.11.1-spc300/libbb/pidfile.c
new file mode 100644
index 0000000000..cafa7891f3
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/pidfile.c
@@ -0,0 +1,40 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * pid file routines
+ *
+ * Copyright (C) 2007 by Stephane Billiart <stephane.billiart@gmail.com>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* Override ENABLE_FEATURE_PIDFILE */
+#define WANT_PIDFILE 1
+#include "libbb.h"
+
+smallint wrote_pidfile;
+
+void write_pidfile(const char *path)
+{
+ int pid_fd;
+ char *end;
+ char buf[sizeof(int)*3 + 2];
+ struct stat sb;
+
+ if (!path)
+ return;
+ /* we will overwrite stale pidfile */
+ pid_fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0666);
+ if (pid_fd < 0)
+ return;
+
+ /* path can be "/dev/null"! Test for such cases */
+ wrote_pidfile = (fstat(pid_fd, &sb) == 0) && S_ISREG(sb.st_mode);
+
+ if (wrote_pidfile) {
+ /* few bytes larger, but doesn't use stdio */
+ end = utoa_to_buf(getpid(), buf, sizeof(buf));
+ *end = '\n';
+ full_write(pid_fd, buf, end - buf + 1);
+ }
+ close(pid_fd);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/print_flags.c b/cleopatre/busybox-1.11.1-spc300/libbb/print_flags.c
new file mode 100644
index 0000000000..a1dcc01ecc
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/print_flags.c
@@ -0,0 +1,32 @@
+/* vi: set sw=4 ts=4: */
+/* Print string that matches bit masked flags
+ *
+ * Copyright (C) 2008 Natanael Copa <natanael.copa@gmail.com>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include <libbb.h>
+
+/* returns a set with the flags not printed */
+int print_flags_separated(const int *masks, const char *labels, int flags, const char *separator)
+{
+ const char *need_separator = NULL;
+ while (*labels) {
+ if (flags & *masks) {
+ printf("%s%s",
+ need_separator ? need_separator : "",
+ labels);
+ need_separator = separator;
+ flags &= ~ *masks;
+ }
+ masks++;
+ labels += strlen(labels) + 1;
+ }
+ return flags;
+}
+
+int print_flags(const masks_labels_t *ml, int flags)
+{
+ return print_flags_separated(ml->masks, ml->labels, flags, NULL);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/printable.c b/cleopatre/busybox-1.11.1-spc300/libbb/printable.c
new file mode 100644
index 0000000000..676758a2b8
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/printable.c
@@ -0,0 +1,34 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2007 Denys Vlasenko
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+void fputc_printable(int ch, FILE *file)
+{
+ if ((ch & (0x80 + PRINTABLE_META)) == (0x80 + PRINTABLE_META)) {
+ fputs("M-", file);
+ ch &= 0x7f;
+ }
+ ch = (unsigned char) ch;
+ if (ch == 0x9b) {
+ /* VT100's CSI, aka Meta-ESC, is not printable on vt-100 */
+ ch = '{';
+ goto print_caret;
+ }
+ if (ch < ' ') {
+ ch += '@';
+ goto print_caret;
+ }
+ if (ch == 0x7f) {
+ ch = '?';
+ print_caret:
+ fputc('^', file);
+ }
+ fputc(ch, file);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/process_escape_sequence.c b/cleopatre/busybox-1.11.1-spc300/libbb/process_escape_sequence.c
new file mode 100644
index 0000000000..1cadbd373e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/process_escape_sequence.c
@@ -0,0 +1,86 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) Manuel Novoa III <mjn3@codepoet.org>
+ * and Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+#define WANT_HEX_ESCAPES 1
+
+/* Usual "this only works for ascii compatible encodings" disclaimer. */
+#undef _tolower
+#define _tolower(X) ((X)|((char) 0x20))
+
+char bb_process_escape_sequence(const char **ptr)
+{
+ static const char charmap[] ALIGN1 = {
+ 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', 0,
+ '\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\', '\\' };
+
+ const char *p;
+ const char *q;
+ unsigned int num_digits;
+ unsigned int r;
+ unsigned int n;
+ unsigned int d;
+ unsigned int base;
+
+ num_digits = n = 0;
+ base = 8;
+ q = *ptr;
+
+#ifdef WANT_HEX_ESCAPES
+ if (*q == 'x') {
+ ++q;
+ base = 16;
+ ++num_digits;
+ }
+#endif
+
+ do {
+ d = (unsigned char)(*q) - '0';
+#ifdef WANT_HEX_ESCAPES
+ if (d >= 10) {
+ d = (unsigned char)(_tolower(*q)) - 'a' + 10;
+ }
+#endif
+
+ if (d >= base) {
+#ifdef WANT_HEX_ESCAPES
+ if ((base == 16) && (!--num_digits)) {
+/* return '\\'; */
+ --q;
+ }
+#endif
+ break;
+ }
+
+ r = n * base + d;
+ if (r > UCHAR_MAX) {
+ break;
+ }
+
+ n = r;
+ ++q;
+ } while (++num_digits < 3);
+
+ if (num_digits == 0) { /* mnemonic escape sequence? */
+ p = charmap;
+ do {
+ if (*p == *q) {
+ q++;
+ break;
+ }
+ } while (*++p);
+ n = *(p + (sizeof(charmap)/2));
+ }
+
+ *ptr = q;
+
+ return (char) n;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/procps.c b/cleopatre/busybox-1.11.1-spc300/libbb/procps.c
new file mode 100644
index 0000000000..8946917a21
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/procps.c
@@ -0,0 +1,458 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright 1998 by Albert Cahalan; all rights reserved.
+ * Copyright (C) 2002 by Vladimir Oleynik <dzo@simtreas.ru>
+ * SELinux support: (c) 2007 by Yuichi Nakamura <ynakam@hitachisoft.jp>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+
+typedef struct unsigned_to_name_map_t {
+ unsigned id;
+ char name[USERNAME_MAX_SIZE];
+} unsigned_to_name_map_t;
+
+typedef struct cache_t {
+ unsigned_to_name_map_t *cache;
+ int size;
+} cache_t;
+
+static cache_t username, groupname;
+
+static void clear_cache(cache_t *cp)
+{
+ free(cp->cache);
+ cp->cache = NULL;
+ cp->size = 0;
+}
+void clear_username_cache(void)
+{
+ clear_cache(&username);
+ clear_cache(&groupname);
+}
+
+#if 0 /* more generic, but we don't need that yet */
+/* Returns -N-1 if not found. */
+/* cp->cache[N] is allocated and must be filled in this case */
+static int get_cached(cache_t *cp, unsigned id)
+{
+ int i;
+ for (i = 0; i < cp->size; i++)
+ if (cp->cache[i].id == id)
+ return i;
+ i = cp->size++;
+ cp->cache = xrealloc(cp->cache, cp->size * sizeof(*cp->cache));
+ cp->cache[i++].id = id;
+ return -i;
+}
+#endif
+
+typedef char* ug_func(char *name, int bufsize, long uid);
+static char* get_cached(cache_t *cp, unsigned id, ug_func* fp)
+{
+ int i;
+ for (i = 0; i < cp->size; i++)
+ if (cp->cache[i].id == id)
+ return cp->cache[i].name;
+ i = cp->size++;
+ cp->cache = xrealloc(cp->cache, cp->size * sizeof(*cp->cache));
+ cp->cache[i].id = id;
+ /* Never fails. Generates numeric string if name isn't found */
+ fp(cp->cache[i].name, sizeof(cp->cache[i].name), id);
+ return cp->cache[i].name;
+}
+const char* get_cached_username(uid_t uid)
+{
+ return get_cached(&username, uid, bb_getpwuid);
+}
+const char* get_cached_groupname(gid_t gid)
+{
+ return get_cached(&groupname, gid, bb_getgrgid);
+}
+
+
+#define PROCPS_BUFSIZE 1024
+
+static int read_to_buf(const char *filename, void *buf)
+{
+ int fd;
+ /* open_read_close() would do two reads, checking for EOF.
+ * When you have 10000 /proc/$NUM/stat to read, it isn't desirable */
+ ssize_t ret = -1;
+ fd = open(filename, O_RDONLY);
+ if (fd >= 0) {
+ ret = read(fd, buf, PROCPS_BUFSIZE-1);
+ close(fd);
+ }
+ ((char *)buf)[ret > 0 ? ret : 0] = '\0';
+ return ret;
+}
+
+static procps_status_t *alloc_procps_scan(void)
+{
+ unsigned n = getpagesize();
+ procps_status_t* sp = xzalloc(sizeof(procps_status_t));
+ sp->dir = xopendir("/proc");
+ while (1) {
+ n >>= 1;
+ if (!n) break;
+ sp->shift_pages_to_bytes++;
+ }
+ sp->shift_pages_to_kb = sp->shift_pages_to_bytes - 10;
+ return sp;
+}
+
+void free_procps_scan(procps_status_t* sp)
+{
+ closedir(sp->dir);
+ free(sp->argv0);
+ USE_SELINUX(free(sp->context);)
+ free(sp);
+}
+
+#if ENABLE_FEATURE_TOPMEM
+static unsigned long fast_strtoul_16(char **endptr)
+{
+ unsigned char c;
+ char *str = *endptr;
+ unsigned long n = 0;
+
+ while ((c = *str++) != ' ') {
+ c = ((c|0x20) - '0');
+ if (c > 9)
+ // c = c + '0' - 'a' + 10:
+ c = c - ('a' - '0' - 10);
+ n = n*16 + c;
+ }
+ *endptr = str; /* We skip trailing space! */
+ return n;
+}
+/* TOPMEM uses fast_strtoul_10, so... */
+#undef ENABLE_FEATURE_FAST_TOP
+#define ENABLE_FEATURE_FAST_TOP 1
+#endif
+
+#if ENABLE_FEATURE_FAST_TOP
+/* We cut a lot of corners here for speed */
+static unsigned long fast_strtoul_10(char **endptr)
+{
+ char c;
+ char *str = *endptr;
+ unsigned long n = *str - '0';
+
+ while ((c = *++str) != ' ')
+ n = n*10 + (c - '0');
+
+ *endptr = str + 1; /* We skip trailing space! */
+ return n;
+}
+static char *skip_fields(char *str, int count)
+{
+ do {
+ while (*str++ != ' ')
+ continue;
+ /* we found a space char, str points after it */
+ } while (--count);
+ return str;
+}
+#endif
+
+void BUG_comm_size(void);
+procps_status_t *procps_scan(procps_status_t* sp, int flags)
+{
+ struct dirent *entry;
+ char buf[PROCPS_BUFSIZE];
+ char filename[sizeof("/proc//cmdline") + sizeof(int)*3];
+ char *filename_tail;
+ long tasknice;
+ unsigned pid;
+ int n;
+ struct stat sb;
+
+ if (!sp)
+ sp = alloc_procps_scan();
+
+ for (;;) {
+ entry = readdir(sp->dir);
+ if (entry == NULL) {
+ free_procps_scan(sp);
+ return NULL;
+ }
+ pid = bb_strtou(entry->d_name, NULL, 10);
+ if (errno)
+ continue;
+
+ /* After this point we have to break, not continue
+ * ("continue" would mean that current /proc/NNN
+ * is not a valid process info) */
+
+ memset(&sp->vsz, 0, sizeof(*sp) - offsetof(procps_status_t, vsz));
+
+ sp->pid = pid;
+ if (!(flags & ~PSSCAN_PID)) break;
+
+#if ENABLE_SELINUX
+ if (flags & PSSCAN_CONTEXT) {
+ if (getpidcon(sp->pid, &sp->context) < 0)
+ sp->context = NULL;
+ }
+#endif
+
+ filename_tail = filename + sprintf(filename, "/proc/%d", pid);
+
+ if (flags & PSSCAN_UIDGID) {
+ if (stat(filename, &sb))
+ break;
+ /* Need comment - is this effective or real UID/GID? */
+ sp->uid = sb.st_uid;
+ sp->gid = sb.st_gid;
+ }
+
+ if (flags & PSSCAN_STAT) {
+ char *cp, *comm1;
+ int tty;
+#if !ENABLE_FEATURE_FAST_TOP
+ unsigned long vsz, rss;
+#endif
+
+ /* see proc(5) for some details on this */
+ strcpy(filename_tail, "/stat");
+ n = read_to_buf(filename, buf);
+ if (n < 0)
+ break;
+ cp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */
+ /*if (!cp || cp[1] != ' ')
+ break;*/
+ cp[0] = '\0';
+ if (sizeof(sp->comm) < 16)
+ BUG_comm_size();
+ comm1 = strchr(buf, '(');
+ /*if (comm1)*/
+ safe_strncpy(sp->comm, comm1 + 1, sizeof(sp->comm));
+
+#if !ENABLE_FEATURE_FAST_TOP
+ n = sscanf(cp+2,
+ "%c %u " /* state, ppid */
+ "%u %u %d %*s " /* pgid, sid, tty, tpgid */
+ "%*s %*s %*s %*s %*s " /* flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
+ "%lu %lu " /* utime, stime */
+ "%*s %*s %*s " /* cutime, cstime, priority */
+ "%ld " /* nice */
+ "%*s %*s " /* timeout, it_real_value */
+ "%lu " /* start_time */
+ "%lu " /* vsize */
+ "%lu " /* rss */
+ /* "%lu %lu %lu %lu %lu %lu " rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */
+ /* "%u %u %u %u " signal, blocked, sigignore, sigcatch */
+ /* "%lu %lu %lu" wchan, nswap, cnswap */
+ ,
+ sp->state, &sp->ppid,
+ &sp->pgid, &sp->sid, &tty,
+ &sp->utime, &sp->stime,
+ &tasknice,
+ &sp->start_time,
+ &vsz,
+ &rss);
+ if (n != 11)
+ break;
+ /* vsz is in bytes and we want kb */
+ sp->vsz = vsz >> 10;
+ /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */
+ sp->rss = rss << sp->shift_pages_to_kb;
+ sp->tty_major = (tty >> 8) & 0xfff;
+ sp->tty_minor = (tty & 0xff) | ((tty >> 12) & 0xfff00);
+#else
+/* This costs ~100 bytes more but makes top faster by 20%
+ * If you run 10000 processes, this may be important for you */
+ sp->state[0] = cp[2];
+ cp += 4;
+ sp->ppid = fast_strtoul_10(&cp);
+ sp->pgid = fast_strtoul_10(&cp);
+ sp->sid = fast_strtoul_10(&cp);
+ tty = fast_strtoul_10(&cp);
+ sp->tty_major = (tty >> 8) & 0xfff;
+ sp->tty_minor = (tty & 0xff) | ((tty >> 12) & 0xfff00);
+ cp = skip_fields(cp, 6); /* tpgid, flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
+ sp->utime = fast_strtoul_10(&cp);
+ sp->stime = fast_strtoul_10(&cp);
+ cp = skip_fields(cp, 3); /* cutime, cstime, priority */
+ tasknice = fast_strtoul_10(&cp);
+ cp = skip_fields(cp, 2); /* timeout, it_real_value */
+ sp->start_time = fast_strtoul_10(&cp);
+ /* vsz is in bytes and we want kb */
+ sp->vsz = fast_strtoul_10(&cp) >> 10;
+ /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */
+ sp->rss = fast_strtoul_10(&cp) << sp->shift_pages_to_kb;
+#endif
+
+ if (sp->vsz == 0 && sp->state[0] != 'Z')
+ sp->state[1] = 'W';
+ else
+ sp->state[1] = ' ';
+ if (tasknice < 0)
+ sp->state[2] = '<';
+ else if (tasknice) /* > 0 */
+ sp->state[2] = 'N';
+ else
+ sp->state[2] = ' ';
+
+ }
+
+#if ENABLE_FEATURE_TOPMEM
+ if (flags & (PSSCAN_SMAPS)) {
+ FILE *file;
+
+ strcpy(filename_tail, "/smaps");
+ file = fopen(filename, "r");
+ if (!file)
+ break;
+ while (fgets(buf, sizeof(buf), file)) {
+ unsigned long sz;
+ char *tp;
+ char w;
+#define SCAN(str, name) \
+ if (strncmp(buf, str, sizeof(str)-1) == 0) { \
+ tp = skip_whitespace(buf + sizeof(str)-1); \
+ sp->name += fast_strtoul_10(&tp); \
+ continue; \
+ }
+ SCAN("Shared_Clean:" , shared_clean );
+ SCAN("Shared_Dirty:" , shared_dirty );
+ SCAN("Private_Clean:", private_clean);
+ SCAN("Private_Dirty:", private_dirty);
+#undef SCAN
+ // f7d29000-f7d39000 rw-s ADR M:m OFS FILE
+ tp = strchr(buf, '-');
+ if (tp) {
+ *tp = ' ';
+ tp = buf;
+ sz = fast_strtoul_16(&tp); /* start */
+ sz = (fast_strtoul_16(&tp) - sz) >> 10; /* end - start */
+ // tp -> "rw-s" string
+ w = tp[1];
+ // skipping "rw-s ADR M:m OFS "
+ tp = skip_whitespace(skip_fields(tp, 4));
+ // filter out /dev/something (something != zero)
+ if (strncmp(tp, "/dev/", 5) != 0 || strcmp(tp, "/dev/zero\n") == 0) {
+ if (w == 'w') {
+ sp->mapped_rw += sz;
+ } else if (w == '-') {
+ sp->mapped_ro += sz;
+ }
+ }
+//else printf("DROPPING %s (%s)\n", buf, tp);
+ if (strcmp(tp, "[stack]\n") == 0)
+ sp->stack += sz;
+ }
+ }
+ fclose(file);
+ }
+#endif /* TOPMEM */
+
+#if 0 /* PSSCAN_CMD is not used */
+ if (flags & (PSSCAN_CMD|PSSCAN_ARGV0)) {
+ free(sp->argv0);
+ sp->argv0 = NULL;
+ free(sp->cmd);
+ sp->cmd = NULL;
+ strcpy(filename_tail, "/cmdline");
+ /* TODO: to get rid of size limits, read into malloc buf,
+ * then realloc it down to real size. */
+ n = read_to_buf(filename, buf);
+ if (n <= 0)
+ break;
+ if (flags & PSSCAN_ARGV0)
+ sp->argv0 = xstrdup(buf);
+ if (flags & PSSCAN_CMD) {
+ do {
+ n--;
+ if ((unsigned char)(buf[n]) < ' ')
+ buf[n] = ' ';
+ } while (n);
+ sp->cmd = xstrdup(buf);
+ }
+ }
+#else
+ if (flags & (PSSCAN_ARGV0|PSSCAN_ARGVN)) {
+ free(sp->argv0);
+ sp->argv0 = NULL;
+ strcpy(filename_tail, "/cmdline");
+ n = read_to_buf(filename, buf);
+ if (n <= 0)
+ break;
+#if ENABLE_PGREP || ENABLE_PKILL
+ if (flags & PSSCAN_ARGVN) {
+ do {
+ n--;
+ if (buf[n] == '\0')
+ buf[n] = ' ';
+ } while (n);
+ }
+#endif
+ sp->argv0 = xstrdup(buf);
+ }
+#endif
+ break;
+ }
+ return sp;
+}
+
+void read_cmdline(char *buf, int col, unsigned pid, const char *comm)
+{
+ ssize_t sz;
+ char filename[sizeof("/proc//cmdline") + sizeof(int)*3];
+
+ sprintf(filename, "/proc/%u/cmdline", pid);
+ sz = open_read_close(filename, buf, col);
+ if (sz > 0) {
+ buf[sz] = '\0';
+ while (--sz >= 0)
+ if ((unsigned char)(buf[sz]) < ' ')
+ buf[sz] = ' ';
+ } else {
+ snprintf(buf, col, "[%s]", comm);
+ }
+}
+
+/* from kernel:
+ // pid comm S ppid pgid sid tty_nr tty_pgrp flg
+ sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
+%lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \
+%lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %llu\n",
+ task->pid,
+ tcomm,
+ state,
+ ppid,
+ pgid,
+ sid,
+ tty_nr,
+ tty_pgrp,
+ task->flags,
+ min_flt,
+ cmin_flt,
+ maj_flt,
+ cmaj_flt,
+ cputime_to_clock_t(utime),
+ cputime_to_clock_t(stime),
+ cputime_to_clock_t(cutime),
+ cputime_to_clock_t(cstime),
+ priority,
+ nice,
+ num_threads,
+ // 0,
+ start_time,
+ vsize,
+ mm ? get_mm_rss(mm) : 0,
+ rsslim,
+ mm ? mm->start_code : 0,
+ mm ? mm->end_code : 0,
+ mm ? mm->start_stack : 0,
+ esp,
+ eip,
+the rest is some obsolete cruft
+*/
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/ptr_to_globals.c b/cleopatre/busybox-1.11.1-spc300/libbb/ptr_to_globals.c
new file mode 100644
index 0000000000..5f30e2a64c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/ptr_to_globals.c
@@ -0,0 +1,35 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2008 by Denys Vlasenko <vda.linux@googlemail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+#include <errno.h>
+
+struct globals;
+
+#ifndef GCC_COMBINE
+
+/* We cheat here. It is declared as const ptr in libbb.h,
+ * but here we make it live in R/W memory */
+struct globals *ptr_to_globals;
+
+#ifdef __GLIBC__
+int *bb_errno;
+#endif
+
+
+#else
+
+
+/* gcc -combine will see through and complain */
+/* Using alternative method which is more likely to break
+ * on weird architectures, compilers, linkers and so on */
+struct globals *const ptr_to_globals __attribute__ ((section (".data")));
+
+#ifdef __GLIBC__
+int *const bb_errno __attribute__ ((section (".data")));
+#endif
+
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/pw_encrypt.c b/cleopatre/busybox-1.11.1-spc300/libbb/pw_encrypt.c
new file mode 100644
index 0000000000..73631865c6
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/pw_encrypt.c
@@ -0,0 +1,84 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routine.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+#if ENABLE_USE_BB_CRYPT
+
+/*
+ * DES and MD5 crypt implementations are taken from uclibc.
+ * They were modified to not use static buffers.
+ */
+/* Common for them */
+static const uint8_t ascii64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+#include "pw_encrypt_des.c"
+#include "pw_encrypt_md5.c"
+
+
+static struct const_des_ctx *des_cctx;
+static struct des_ctx *des_ctx;
+
+/* my_crypt returns malloc'ed data */
+static char *my_crypt(const char *key, const char *salt)
+{
+ /* First, check if we are supposed to be using the MD5 replacement
+ * instead of DES... */
+ if (salt[0] == '$' && salt[1] == '1' && salt[2] == '$') {
+ return md5_crypt(xzalloc(MD5_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt);
+ }
+
+ {
+ if (!des_cctx)
+ des_cctx = const_des_init();
+ des_ctx = des_init(des_ctx, des_cctx);
+ return des_crypt(des_ctx, xzalloc(DES_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt);
+ }
+}
+
+/* So far nobody wants to have it public */
+static void my_crypt_cleanup(void)
+{
+ free(des_cctx);
+ free(des_ctx);
+ des_cctx = NULL;
+ des_ctx = NULL;
+}
+
+char *pw_encrypt(const char *clear, const char *salt, int cleanup)
+{
+ char *encrypted;
+
+#if 0 /* was CONFIG_FEATURE_SHA1_PASSWORDS, but there is no such thing??? */
+ if (strncmp(salt, "$2$", 3) == 0) {
+ return sha1_crypt(clear);
+ }
+#endif
+
+ encrypted = my_crypt(clear, salt);
+
+ if (cleanup)
+ my_crypt_cleanup();
+
+ return encrypted;
+}
+
+#else /* if !ENABLE_USE_BB_CRYPT */
+
+char *pw_encrypt(const char *clear, const char *salt, int cleanup)
+{
+#if 0 /* was CONFIG_FEATURE_SHA1_PASSWORDS, but there is no such thing??? */
+ if (strncmp(salt, "$2$", 3) == 0) {
+ return xstrdup(sha1_crypt(clear));
+ }
+#endif
+
+ return xstrdup(crypt(clear, salt));
+}
+
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/pw_encrypt_des.c b/cleopatre/busybox-1.11.1-spc300/libbb/pw_encrypt_des.c
new file mode 100644
index 0000000000..cd19a63f78
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/pw_encrypt_des.c
@@ -0,0 +1,798 @@
+/*
+ * FreeSec: libcrypt for NetBSD
+ *
+ * Copyright (c) 1994 David Burren
+ * All rights reserved.
+ *
+ * Adapted for FreeBSD-2.0 by Geoffrey M. Rehmet
+ * this file should now *only* export crypt(), in order to make
+ * binaries of libcrypt exportable from the USA
+ *
+ * Adapted for FreeBSD-4.0 by Mark R V Murray
+ * this file should now *only* export crypt_des(), in order to make
+ * a module that can be optionally included in libcrypt.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of other contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This is an original implementation of the DES and the crypt(3) interfaces
+ * by David Burren <davidb@werj.com.au>.
+ *
+ * An excellent reference on the underlying algorithm (and related
+ * algorithms) is:
+ *
+ * B. Schneier, Applied Cryptography: protocols, algorithms,
+ * and source code in C, John Wiley & Sons, 1994.
+ *
+ * Note that in that book's description of DES the lookups for the initial,
+ * pbox, and final permutations are inverted (this has been brought to the
+ * attention of the author). A list of errata for this book has been
+ * posted to the sci.crypt newsgroup by the author and is available for FTP.
+ *
+ * ARCHITECTURE ASSUMPTIONS:
+ * It is assumed that the 8-byte arrays passed by reference can be
+ * addressed as arrays of uint32_t's (ie. the CPU is not picky about
+ * alignment).
+ */
+
+
+/* Parts busybox doesn't need or had optimized */
+#define USE_PRECOMPUTED_u_sbox 1
+#define USE_REPETITIVE_SPEEDUP 0
+#define USE_ip_mask 0
+#define USE_de_keys 0
+
+
+/* A pile of data */
+static const uint8_t IP[64] = {
+ 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,
+ 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
+ 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
+ 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7
+};
+
+static const uint8_t key_perm[56] = {
+ 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
+ 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
+ 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22,
+ 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4
+};
+
+static const uint8_t key_shifts[16] = {
+ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
+};
+
+static const uint8_t comp_perm[48] = {
+ 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
+ 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
+ 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
+ 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
+};
+
+/*
+ * No E box is used, as it's replaced by some ANDs, shifts, and ORs.
+ */
+#if !USE_PRECOMPUTED_u_sbox
+static const uint8_t sbox[8][64] = {
+ { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
+ 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
+ 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
+ 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13
+ },
+ { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
+ 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
+ 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
+ 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9
+ },
+ { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
+ 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
+ 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
+ 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12
+ },
+ { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
+ 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
+ 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
+ 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14
+ },
+ { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
+ 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
+ 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
+ 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3
+ },
+ { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
+ 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
+ 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
+ 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13
+ },
+ { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
+ 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
+ 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
+ 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12
+ },
+ { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
+ 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
+ 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
+ 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11
+ }
+};
+#else /* precomputed, with half-bytes packed into one byte */
+static const uint8_t u_sbox[8][32] = {
+ { 0x0e, 0xf4, 0x7d, 0x41, 0xe2, 0x2f, 0xdb, 0x18,
+ 0xa3, 0x6a, 0xc6, 0xbc, 0x95, 0x59, 0x30, 0x87,
+ 0xf4, 0xc1, 0x8e, 0x28, 0x4d, 0x96, 0x12, 0x7b,
+ 0x5f, 0xbc, 0x39, 0xe7, 0xa3, 0x0a, 0x65, 0xd0,
+ },
+ { 0x3f, 0xd1, 0x48, 0x7e, 0xf6, 0x2b, 0x83, 0xe4,
+ 0xc9, 0x07, 0x12, 0xad, 0x6c, 0x90, 0xb5, 0x5a,
+ 0xd0, 0x8e, 0xa7, 0x1b, 0x3a, 0xf4, 0x4d, 0x21,
+ 0xb5, 0x68, 0x7c, 0xc6, 0x09, 0x53, 0xe2, 0x9f,
+ },
+ { 0xda, 0x70, 0x09, 0x9e, 0x36, 0x43, 0x6f, 0xa5,
+ 0x21, 0x8d, 0x5c, 0xe7, 0xcb, 0xb4, 0xf2, 0x18,
+ 0x1d, 0xa6, 0xd4, 0x09, 0x68, 0x9f, 0x83, 0x70,
+ 0x4b, 0xf1, 0xe2, 0x3c, 0xb5, 0x5a, 0x2e, 0xc7,
+ },
+ { 0xd7, 0x8d, 0xbe, 0x53, 0x60, 0xf6, 0x09, 0x3a,
+ 0x41, 0x72, 0x28, 0xc5, 0x1b, 0xac, 0xe4, 0x9f,
+ 0x3a, 0xf6, 0x09, 0x60, 0xac, 0x1b, 0xd7, 0x8d,
+ 0x9f, 0x41, 0x53, 0xbe, 0xc5, 0x72, 0x28, 0xe4,
+ },
+ { 0xe2, 0xbc, 0x24, 0xc1, 0x47, 0x7a, 0xdb, 0x16,
+ 0x58, 0x05, 0xf3, 0xaf, 0x3d, 0x90, 0x8e, 0x69,
+ 0xb4, 0x82, 0xc1, 0x7b, 0x1a, 0xed, 0x27, 0xd8,
+ 0x6f, 0xf9, 0x0c, 0x95, 0xa6, 0x43, 0x50, 0x3e,
+ },
+ { 0xac, 0xf1, 0x4a, 0x2f, 0x79, 0xc2, 0x96, 0x58,
+ 0x60, 0x1d, 0xd3, 0xe4, 0x0e, 0xb7, 0x35, 0x8b,
+ 0x49, 0x3e, 0x2f, 0xc5, 0x92, 0x58, 0xfc, 0xa3,
+ 0xb7, 0xe0, 0x14, 0x7a, 0x61, 0x0d, 0x8b, 0xd6,
+ },
+ { 0xd4, 0x0b, 0xb2, 0x7e, 0x4f, 0x90, 0x18, 0xad,
+ 0xe3, 0x3c, 0x59, 0xc7, 0x25, 0xfa, 0x86, 0x61,
+ 0x61, 0xb4, 0xdb, 0x8d, 0x1c, 0x43, 0xa7, 0x7e,
+ 0x9a, 0x5f, 0x06, 0xf8, 0xe0, 0x25, 0x39, 0xc2,
+ },
+ { 0x1d, 0xf2, 0xd8, 0x84, 0xa6, 0x3f, 0x7b, 0x41,
+ 0xca, 0x59, 0x63, 0xbe, 0x05, 0xe0, 0x9c, 0x27,
+ 0x27, 0x1b, 0xe4, 0x71, 0x49, 0xac, 0x8e, 0xd2,
+ 0xf0, 0xc6, 0x9a, 0x0d, 0x3f, 0x53, 0x65, 0xb8,
+ },
+};
+#endif
+
+static const uint8_t pbox[32] = {
+ 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
+ 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
+};
+
+static const uint32_t bits32[32] =
+{
+ 0x80000000, 0x40000000, 0x20000000, 0x10000000,
+ 0x08000000, 0x04000000, 0x02000000, 0x01000000,
+ 0x00800000, 0x00400000, 0x00200000, 0x00100000,
+ 0x00080000, 0x00040000, 0x00020000, 0x00010000,
+ 0x00008000, 0x00004000, 0x00002000, 0x00001000,
+ 0x00000800, 0x00000400, 0x00000200, 0x00000100,
+ 0x00000080, 0x00000040, 0x00000020, 0x00000010,
+ 0x00000008, 0x00000004, 0x00000002, 0x00000001
+};
+
+static const uint8_t bits8[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
+
+
+static int
+ascii_to_bin(char ch)
+{
+ if (ch > 'z')
+ return 0;
+ if (ch >= 'a')
+ return (ch - 'a' + 38);
+ if (ch > 'Z')
+ return 0;
+ if (ch >= 'A')
+ return (ch - 'A' + 12);
+ if (ch > '9')
+ return 0;
+ if (ch >= '.')
+ return (ch - '.');
+ return 0;
+}
+
+
+/* Static stuff that stays resident and doesn't change after
+ * being initialized, and therefore doesn't need to be made
+ * reentrant. */
+struct const_des_ctx {
+#if USE_ip_mask
+ uint8_t init_perm[64]; /* referenced 2 times */
+#endif
+ uint8_t final_perm[64]; /* 2 times */
+ uint8_t m_sbox[4][4096]; /* 5 times */
+};
+#define C (*cctx)
+#define init_perm (C.init_perm )
+#define final_perm (C.final_perm)
+#define m_sbox (C.m_sbox )
+
+static struct const_des_ctx*
+const_des_init(void)
+{
+ unsigned i, j, b;
+ struct const_des_ctx *cctx;
+
+#if !USE_PRECOMPUTED_u_sbox
+ uint8_t u_sbox[8][64];
+
+ cctx = xmalloc(sizeof(*cctx));
+
+ /* Invert the S-boxes, reordering the input bits. */
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 64; j++) {
+ b = (j & 0x20) | ((j & 1) << 4) | ((j >> 1) & 0xf);
+ u_sbox[i][j] = sbox[i][b];
+ }
+ }
+ for (i = 0; i < 8; i++) {
+ fprintf(stderr, "\t{\t");
+ for (j = 0; j < 64; j+=2)
+ fprintf(stderr, " 0x%02x,", u_sbox[i][j] + u_sbox[i][j+1]*16);
+ fprintf(stderr, "\n\t},\n");
+ }
+ /*
+ * Convert the inverted S-boxes into 4 arrays of 8 bits.
+ * Each will handle 12 bits of the S-box input.
+ */
+ for (b = 0; b < 4; b++)
+ for (i = 0; i < 64; i++)
+ for (j = 0; j < 64; j++)
+ m_sbox[b][(i << 6) | j] =
+ (uint8_t)((u_sbox[(b << 1)][i] << 4) |
+ u_sbox[(b << 1) + 1][j]);
+#else
+ cctx = xmalloc(sizeof(*cctx));
+
+ /*
+ * Convert the inverted S-boxes into 4 arrays of 8 bits.
+ * Each will handle 12 bits of the S-box input.
+ */
+ for (b = 0; b < 4; b++)
+ for (i = 0; i < 64; i++)
+ for (j = 0; j < 64; j++) {
+ uint8_t lo, hi;
+ hi = u_sbox[(b << 1)][i / 2];
+ if (!(i & 1))
+ hi <<= 4;
+ lo = u_sbox[(b << 1) + 1][j / 2];
+ if (j & 1)
+ lo >>= 4;
+ m_sbox[b][(i << 6) | j] = (hi & 0xf0) | (lo & 0x0f);
+ }
+#endif
+
+ /*
+ * Set up the initial & final permutations into a useful form.
+ */
+ for (i = 0; i < 64; i++) {
+ final_perm[i] = IP[i] - 1;
+#if USE_ip_mask
+ init_perm[final_perm[i]] = (uint8_t)i;
+#endif
+ }
+
+ return cctx;
+}
+
+
+struct des_ctx {
+ const struct const_des_ctx *const_ctx;
+ uint32_t saltbits; /* referenced 5 times */
+#if USE_REPETITIVE_SPEEDUP
+ uint32_t old_salt; /* 3 times */
+ uint32_t old_rawkey0, old_rawkey1; /* 3 times each */
+#endif
+ uint8_t un_pbox[32]; /* 2 times */
+ uint8_t inv_comp_perm[56]; /* 3 times */
+ uint8_t inv_key_perm[64]; /* 3 times */
+ uint32_t en_keysl[16], en_keysr[16]; /* 2 times each */
+#if USE_de_keys
+ uint32_t de_keysl[16], de_keysr[16]; /* 2 times each */
+#endif
+#if USE_ip_mask
+ uint32_t ip_maskl[8][256], ip_maskr[8][256]; /* 9 times each */
+#endif
+ uint32_t fp_maskl[8][256], fp_maskr[8][256]; /* 9 times each */
+ uint32_t key_perm_maskl[8][128], key_perm_maskr[8][128]; /* 9 times */
+ uint32_t comp_maskl[8][128], comp_maskr[8][128]; /* 9 times each */
+ uint32_t psbox[4][256]; /* 5 times */
+};
+#define D (*ctx)
+#define const_ctx (D.const_ctx )
+#define saltbits (D.saltbits )
+#define old_salt (D.old_salt )
+#define old_rawkey0 (D.old_rawkey0 )
+#define old_rawkey1 (D.old_rawkey1 )
+#define un_pbox (D.un_pbox )
+#define inv_comp_perm (D.inv_comp_perm )
+#define inv_key_perm (D.inv_key_perm )
+#define en_keysl (D.en_keysl )
+#define en_keysr (D.en_keysr )
+#define de_keysl (D.de_keysl )
+#define de_keysr (D.de_keysr )
+#define ip_maskl (D.ip_maskl )
+#define ip_maskr (D.ip_maskr )
+#define fp_maskl (D.fp_maskl )
+#define fp_maskr (D.fp_maskr )
+#define key_perm_maskl (D.key_perm_maskl )
+#define key_perm_maskr (D.key_perm_maskr )
+#define comp_maskl (D.comp_maskl )
+#define comp_maskr (D.comp_maskr )
+#define psbox (D.psbox )
+
+static struct des_ctx*
+des_init(struct des_ctx *ctx, const struct const_des_ctx *cctx)
+{
+ int i, j, b, k, inbit, obit;
+ uint32_t p;
+ const uint32_t *bits28, *bits24;
+
+ if (!ctx)
+ ctx = xmalloc(sizeof(*ctx));
+ const_ctx = cctx;
+
+#if USE_REPETITIVE_SPEEDUP
+ old_rawkey0 = old_rawkey1 = 0;
+ old_salt = 0;
+#endif
+ saltbits = 0;
+ bits28 = bits32 + 4;
+ bits24 = bits28 + 4;
+
+ /* Initialise the inverted key permutation. */
+ for (i = 0; i < 64; i++) {
+ inv_key_perm[i] = 255;
+ }
+
+ /*
+ * Invert the key permutation and initialise the inverted key
+ * compression permutation.
+ */
+ for (i = 0; i < 56; i++) {
+ inv_key_perm[key_perm[i] - 1] = (uint8_t)i;
+ inv_comp_perm[i] = 255;
+ }
+
+ /* Invert the key compression permutation. */
+ for (i = 0; i < 48; i++) {
+ inv_comp_perm[comp_perm[i] - 1] = (uint8_t)i;
+ }
+
+ /*
+ * Set up the OR-mask arrays for the initial and final permutations,
+ * and for the key initial and compression permutations.
+ */
+ for (k = 0; k < 8; k++) {
+ uint32_t il, ir;
+ uint32_t fl, fr;
+ for (i = 0; i < 256; i++) {
+#if USE_ip_mask
+ il = 0;
+ ir = 0;
+#endif
+ fl = 0;
+ fr = 0;
+ for (j = 0; j < 8; j++) {
+ inbit = 8 * k + j;
+ if (i & bits8[j]) {
+#if USE_ip_mask
+ obit = init_perm[inbit];
+ if (obit < 32)
+ il |= bits32[obit];
+ else
+ ir |= bits32[obit - 32];
+#endif
+ obit = final_perm[inbit];
+ if (obit < 32)
+ fl |= bits32[obit];
+ else
+ fr |= bits32[obit - 32];
+ }
+ }
+#if USE_ip_mask
+ ip_maskl[k][i] = il;
+ ip_maskr[k][i] = ir;
+#endif
+ fp_maskl[k][i] = fl;
+ fp_maskr[k][i] = fr;
+ }
+ for (i = 0; i < 128; i++) {
+ il = 0;
+ ir = 0;
+ for (j = 0; j < 7; j++) {
+ inbit = 8 * k + j;
+ if (i & bits8[j + 1]) {
+ obit = inv_key_perm[inbit];
+ if (obit == 255)
+ continue;
+ if (obit < 28)
+ il |= bits28[obit];
+ else
+ ir |= bits28[obit - 28];
+ }
+ }
+ key_perm_maskl[k][i] = il;
+ key_perm_maskr[k][i] = ir;
+ il = 0;
+ ir = 0;
+ for (j = 0; j < 7; j++) {
+ inbit = 7 * k + j;
+ if (i & bits8[j + 1]) {
+ obit = inv_comp_perm[inbit];
+ if (obit == 255)
+ continue;
+ if (obit < 24)
+ il |= bits24[obit];
+ else
+ ir |= bits24[obit - 24];
+ }
+ }
+ comp_maskl[k][i] = il;
+ comp_maskr[k][i] = ir;
+ }
+ }
+
+ /*
+ * Invert the P-box permutation, and convert into OR-masks for
+ * handling the output of the S-box arrays setup above.
+ */
+ for (i = 0; i < 32; i++)
+ un_pbox[pbox[i] - 1] = (uint8_t)i;
+
+ for (b = 0; b < 4; b++) {
+ for (i = 0; i < 256; i++) {
+ p = 0;
+ for (j = 0; j < 8; j++) {
+ if (i & bits8[j])
+ p |= bits32[un_pbox[8 * b + j]];
+ }
+ psbox[b][i] = p;
+ }
+ }
+
+ return ctx;
+}
+
+
+static void
+setup_salt(struct des_ctx *ctx, uint32_t salt)
+{
+ uint32_t obit, saltbit;
+ int i;
+
+#if USE_REPETITIVE_SPEEDUP
+ if (salt == old_salt)
+ return;
+ old_salt = salt;
+#endif
+
+ saltbits = 0;
+ saltbit = 1;
+ obit = 0x800000;
+ for (i = 0; i < 24; i++) {
+ if (salt & saltbit)
+ saltbits |= obit;
+ saltbit <<= 1;
+ obit >>= 1;
+ }
+}
+
+static void
+des_setkey(struct des_ctx *ctx, const char *key)
+{
+ uint32_t k0, k1, rawkey0, rawkey1;
+ int shifts, round;
+
+ rawkey0 = ntohl(*(const uint32_t *) key);
+ rawkey1 = ntohl(*(const uint32_t *) (key + 4));
+
+#if USE_REPETITIVE_SPEEDUP
+ if ((rawkey0 | rawkey1)
+ && rawkey0 == old_rawkey0
+ && rawkey1 == old_rawkey1
+ ) {
+ /*
+ * Already setup for this key.
+ * This optimisation fails on a zero key (which is weak and
+ * has bad parity anyway) in order to simplify the starting
+ * conditions.
+ */
+ return;
+ }
+ old_rawkey0 = rawkey0;
+ old_rawkey1 = rawkey1;
+#endif
+
+ /*
+ * Do key permutation and split into two 28-bit subkeys.
+ */
+ k0 = key_perm_maskl[0][rawkey0 >> 25]
+ | key_perm_maskl[1][(rawkey0 >> 17) & 0x7f]
+ | key_perm_maskl[2][(rawkey0 >> 9) & 0x7f]
+ | key_perm_maskl[3][(rawkey0 >> 1) & 0x7f]
+ | key_perm_maskl[4][rawkey1 >> 25]
+ | key_perm_maskl[5][(rawkey1 >> 17) & 0x7f]
+ | key_perm_maskl[6][(rawkey1 >> 9) & 0x7f]
+ | key_perm_maskl[7][(rawkey1 >> 1) & 0x7f];
+ k1 = key_perm_maskr[0][rawkey0 >> 25]
+ | key_perm_maskr[1][(rawkey0 >> 17) & 0x7f]
+ | key_perm_maskr[2][(rawkey0 >> 9) & 0x7f]
+ | key_perm_maskr[3][(rawkey0 >> 1) & 0x7f]
+ | key_perm_maskr[4][rawkey1 >> 25]
+ | key_perm_maskr[5][(rawkey1 >> 17) & 0x7f]
+ | key_perm_maskr[6][(rawkey1 >> 9) & 0x7f]
+ | key_perm_maskr[7][(rawkey1 >> 1) & 0x7f];
+ /*
+ * Rotate subkeys and do compression permutation.
+ */
+ shifts = 0;
+ for (round = 0; round < 16; round++) {
+ uint32_t t0, t1;
+
+ shifts += key_shifts[round];
+
+ t0 = (k0 << shifts) | (k0 >> (28 - shifts));
+ t1 = (k1 << shifts) | (k1 >> (28 - shifts));
+
+#if USE_de_keys
+ de_keysl[15 - round] =
+#endif
+ en_keysl[round] = comp_maskl[0][(t0 >> 21) & 0x7f]
+ | comp_maskl[1][(t0 >> 14) & 0x7f]
+ | comp_maskl[2][(t0 >> 7) & 0x7f]
+ | comp_maskl[3][t0 & 0x7f]
+ | comp_maskl[4][(t1 >> 21) & 0x7f]
+ | comp_maskl[5][(t1 >> 14) & 0x7f]
+ | comp_maskl[6][(t1 >> 7) & 0x7f]
+ | comp_maskl[7][t1 & 0x7f];
+
+#if USE_de_keys
+ de_keysr[15 - round] =
+#endif
+ en_keysr[round] = comp_maskr[0][(t0 >> 21) & 0x7f]
+ | comp_maskr[1][(t0 >> 14) & 0x7f]
+ | comp_maskr[2][(t0 >> 7) & 0x7f]
+ | comp_maskr[3][t0 & 0x7f]
+ | comp_maskr[4][(t1 >> 21) & 0x7f]
+ | comp_maskr[5][(t1 >> 14) & 0x7f]
+ | comp_maskr[6][(t1 >> 7) & 0x7f]
+ | comp_maskr[7][t1 & 0x7f];
+ }
+}
+
+
+static void
+do_des(struct des_ctx *ctx, /*uint32_t l_in, uint32_t r_in,*/ uint32_t *l_out, uint32_t *r_out, int count)
+{
+ const struct const_des_ctx *cctx = const_ctx;
+ /*
+ * l_in, r_in, l_out, and r_out are in pseudo-"big-endian" format.
+ */
+ uint32_t l, r, *kl, *kr;
+ uint32_t f = f; /* silence gcc */
+ uint32_t r48l, r48r;
+ int round;
+
+ /* Do initial permutation (IP). */
+#if USE_ip_mask
+ uint32_t l_in = 0;
+ uint32_t r_in = 0;
+ l = ip_maskl[0][l_in >> 24]
+ | ip_maskl[1][(l_in >> 16) & 0xff]
+ | ip_maskl[2][(l_in >> 8) & 0xff]
+ | ip_maskl[3][l_in & 0xff]
+ | ip_maskl[4][r_in >> 24]
+ | ip_maskl[5][(r_in >> 16) & 0xff]
+ | ip_maskl[6][(r_in >> 8) & 0xff]
+ | ip_maskl[7][r_in & 0xff];
+ r = ip_maskr[0][l_in >> 24]
+ | ip_maskr[1][(l_in >> 16) & 0xff]
+ | ip_maskr[2][(l_in >> 8) & 0xff]
+ | ip_maskr[3][l_in & 0xff]
+ | ip_maskr[4][r_in >> 24]
+ | ip_maskr[5][(r_in >> 16) & 0xff]
+ | ip_maskr[6][(r_in >> 8) & 0xff]
+ | ip_maskr[7][r_in & 0xff];
+#elif 0 /* -65 bytes (using the fact that l_in == r_in == 0) */
+ l = r = 0;
+ for (round = 0; round < 8; round++) {
+ l |= ip_maskl[round][0];
+ r |= ip_maskr[round][0];
+ }
+ bb_error_msg("l:%x r:%x", l, r); /* reports 0, 0 always! */
+#else /* using the fact that ip_maskX[] is constant (written to by des_init) */
+ l = r = 0;
+#endif
+
+ do {
+ /* Do each round. */
+ kl = en_keysl;
+ kr = en_keysr;
+ round = 16;
+ do {
+ /* Expand R to 48 bits (simulate the E-box). */
+ r48l = ((r & 0x00000001) << 23)
+ | ((r & 0xf8000000) >> 9)
+ | ((r & 0x1f800000) >> 11)
+ | ((r & 0x01f80000) >> 13)
+ | ((r & 0x001f8000) >> 15);
+
+ r48r = ((r & 0x0001f800) << 7)
+ | ((r & 0x00001f80) << 5)
+ | ((r & 0x000001f8) << 3)
+ | ((r & 0x0000001f) << 1)
+ | ((r & 0x80000000) >> 31);
+ /*
+ * Do salting for crypt() and friends, and
+ * XOR with the permuted key.
+ */
+ f = (r48l ^ r48r) & saltbits;
+ r48l ^= f ^ *kl++;
+ r48r ^= f ^ *kr++;
+ /*
+ * Do sbox lookups (which shrink it back to 32 bits)
+ * and do the pbox permutation at the same time.
+ */
+ f = psbox[0][m_sbox[0][r48l >> 12]]
+ | psbox[1][m_sbox[1][r48l & 0xfff]]
+ | psbox[2][m_sbox[2][r48r >> 12]]
+ | psbox[3][m_sbox[3][r48r & 0xfff]];
+ /* Now that we've permuted things, complete f(). */
+ f ^= l;
+ l = r;
+ r = f;
+ } while (--round);
+ r = l;
+ l = f;
+ } while (--count);
+
+ /* Do final permutation (inverse of IP). */
+ *l_out = fp_maskl[0][l >> 24]
+ | fp_maskl[1][(l >> 16) & 0xff]
+ | fp_maskl[2][(l >> 8) & 0xff]
+ | fp_maskl[3][l & 0xff]
+ | fp_maskl[4][r >> 24]
+ | fp_maskl[5][(r >> 16) & 0xff]
+ | fp_maskl[6][(r >> 8) & 0xff]
+ | fp_maskl[7][r & 0xff];
+ *r_out = fp_maskr[0][l >> 24]
+ | fp_maskr[1][(l >> 16) & 0xff]
+ | fp_maskr[2][(l >> 8) & 0xff]
+ | fp_maskr[3][l & 0xff]
+ | fp_maskr[4][r >> 24]
+ | fp_maskr[5][(r >> 16) & 0xff]
+ | fp_maskr[6][(r >> 8) & 0xff]
+ | fp_maskr[7][r & 0xff];
+}
+
+#define DES_OUT_BUFSIZE 21
+
+static char *
+NOINLINE
+des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE],
+ const unsigned char *key, const unsigned char *setting)
+{
+ uint32_t salt, l, r0, r1, keybuf[2];
+ uint8_t *p, *q;
+
+ /*
+ * Copy the key, shifting each character up by one bit
+ * and padding with zeros.
+ */
+ q = (uint8_t *)keybuf;
+ while (q - (uint8_t *)keybuf != 8) {
+ *q = *key << 1;
+ if (*q)
+ key++;
+ q++;
+ }
+ des_setkey(ctx, (char *)keybuf);
+
+ /*
+ * setting - 2 bytes of salt
+ * key - up to 8 characters
+ */
+ salt = (ascii_to_bin(setting[1]) << 6)
+ | ascii_to_bin(setting[0]);
+
+ output[0] = setting[0];
+ /*
+ * If the encrypted password that the salt was extracted from
+ * is only 1 character long, the salt will be corrupted. We
+ * need to ensure that the output string doesn't have an extra
+ * NUL in it!
+ */
+ output[1] = setting[1] ? setting[1] : output[0];
+
+ p = (uint8_t *)output + 2;
+
+ setup_salt(ctx, salt);
+ /*
+ * Do it.
+ */
+ do_des(ctx, /*0, 0,*/ &r0, &r1, 25 /* count */);
+
+ /*
+ * Now encode the result...
+ */
+ l = (r0 >> 8);
+ *p++ = ascii64[(l >> 18) & 0x3f];
+ *p++ = ascii64[(l >> 12) & 0x3f];
+ *p++ = ascii64[(l >> 6) & 0x3f];
+ *p++ = ascii64[l & 0x3f];
+
+ l = ((r0 << 16) | (r1 >> 16));
+ *p++ = ascii64[(l >> 18) & 0x3f];
+ *p++ = ascii64[(l >> 12) & 0x3f];
+ *p++ = ascii64[(l >> 6) & 0x3f];
+ *p++ = ascii64[l & 0x3f];
+
+ l = r1 << 2;
+ *p++ = ascii64[(l >> 12) & 0x3f];
+ *p++ = ascii64[(l >> 6) & 0x3f];
+ *p++ = ascii64[l & 0x3f];
+ *p = 0;
+
+ return output;
+}
+
+#undef USE_PRECOMPUTED_u_sbox
+#undef USE_REPETITIVE_SPEEDUP
+#undef USE_ip_mask
+#undef USE_de_keys
+
+#undef C
+#undef init_perm
+#undef final_perm
+#undef m_sbox
+#undef D
+#undef const_ctx
+#undef saltbits
+#undef old_salt
+#undef old_rawkey0
+#undef old_rawkey1
+#undef un_pbox
+#undef inv_comp_perm
+#undef inv_key_perm
+#undef en_keysl
+#undef en_keysr
+#undef de_keysl
+#undef de_keysr
+#undef ip_maskl
+#undef ip_maskr
+#undef fp_maskl
+#undef fp_maskr
+#undef key_perm_maskl
+#undef key_perm_maskr
+#undef comp_maskl
+#undef comp_maskr
+#undef psbox
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/pw_encrypt_md5.c b/cleopatre/busybox-1.11.1-spc300/libbb/pw_encrypt_md5.c
new file mode 100644
index 0000000000..8d0a516cf9
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/pw_encrypt_md5.c
@@ -0,0 +1,648 @@
+/*
+ * MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ *
+ * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ *
+ * $FreeBSD: src/lib/libmd/md5c.c,v 1.9.2.1 1999/08/29 14:57:12 peter Exp $
+ *
+ * This code is the same as the code published by RSA Inc. It has been
+ * edited for clarity and style only.
+ *
+ * ----------------------------------------------------------------------------
+ * The md5_crypt() function was taken from freeBSD's libcrypt and contains
+ * this license:
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ *
+ * $FreeBSD: src/lib/libcrypt/crypt.c,v 1.7.2.1 1999/08/29 14:56:33 peter Exp $
+ *
+ * ----------------------------------------------------------------------------
+ * On April 19th, 2001 md5_crypt() was modified to make it reentrant
+ * by Erik Andersen <andersen@uclibc.org>
+ *
+ *
+ * June 28, 2001 Manuel Novoa III
+ *
+ * "Un-inlined" code using loops and static const tables in order to
+ * reduce generated code size (on i386 from approx 4k to approx 2.5k).
+ *
+ * June 29, 2001 Manuel Novoa III
+ *
+ * Completely removed static PADDING array.
+ *
+ * Reintroduced the loop unrolling in MD5_Transform and added the
+ * MD5_SIZE_OVER_SPEED option for configurability. Define below as:
+ * 0 fully unrolled loops
+ * 1 partially unrolled (4 ops per loop)
+ * 2 no unrolling -- introduces the need to swap 4 variables (slow)
+ * 3 no unrolling and all 4 loops merged into one with switch
+ * in each loop (glacial)
+ * On i386, sizes are roughly (-Os -fno-builtin):
+ * 0: 3k 1: 2.5k 2: 2.2k 3: 2k
+ *
+ *
+ * Since SuSv3 does not require crypt_r, modified again August 7, 2002
+ * by Erik Andersen to remove reentrance stuff...
+ */
+
+/*
+ * Valid values are 1 (fastest/largest) to 3 (smallest/slowest).
+ */
+#define MD5_SIZE_OVER_SPEED 3
+
+/**********************************************************************/
+
+/* MD5 context. */
+struct MD5Context {
+ uint32_t state[4]; /* state (ABCD) */
+ uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+};
+
+static void __md5_Init(struct MD5Context *);
+static void __md5_Update(struct MD5Context *, const unsigned char *, unsigned int);
+static void __md5_Pad(struct MD5Context *);
+static void __md5_Final(unsigned char [16], struct MD5Context *);
+static void __md5_Transform(uint32_t [4], const unsigned char [64]);
+
+
+#define MD5_MAGIC_STR "$1$"
+#define MD5_MAGIC_LEN (sizeof(MD5_MAGIC_STR) - 1)
+static const unsigned char __md5__magic[] = MD5_MAGIC_STR;
+
+
+#ifdef i386
+#define __md5_Encode memcpy
+#define __md5_Decode memcpy
+#else /* i386 */
+
+/*
+ * __md5_Encodes input (uint32_t) into output (unsigned char). Assumes len is
+ * a multiple of 4.
+ */
+static void
+__md5_Encode(unsigned char *output, uint32_t *input, unsigned int len)
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = input[i];
+ output[j+1] = (input[i] >> 8);
+ output[j+2] = (input[i] >> 16);
+ output[j+3] = (input[i] >> 24);
+ }
+}
+
+/*
+ * __md5_Decodes input (unsigned char) into output (uint32_t). Assumes len is
+ * a multiple of 4.
+ */
+static void
+__md5_Decode(uint32_t *output, const unsigned char *input, unsigned int len)
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) |
+ (((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24);
+}
+#endif /* i386 */
+
+/* F, G, H and I are basic MD5 functions. */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+
+/* ROTATE_LEFT rotates x left n bits. */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/*
+ * FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+ * Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = ROTATE_LEFT((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = ROTATE_LEFT((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = ROTATE_LEFT((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = ROTATE_LEFT((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context. */
+static void __md5_Init(struct MD5Context *context)
+{
+ context->count[0] = context->count[1] = 0;
+
+ /* Load magic initialization constants. */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/*
+ * MD5 block update operation. Continues an MD5 message-digest
+ * operation, processing another message block, and updating the
+ * context.
+ */
+static void __md5_Update(struct MD5Context *context, const unsigned char *input, unsigned int inputLen)
+{
+ unsigned int i, idx, partLen;
+
+ /* Compute number of bytes mod 64 */
+ idx = (context->count[0] >> 3) & 0x3F;
+
+ /* Update number of bits */
+ context->count[0] += (inputLen << 3);
+ if (context->count[0] < (inputLen << 3))
+ context->count[1]++;
+ context->count[1] += (inputLen >> 29);
+
+ partLen = 64 - idx;
+
+ /* Transform as many times as possible. */
+ if (inputLen >= partLen) {
+ memcpy(&context->buffer[idx], input, partLen);
+ __md5_Transform(context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ __md5_Transform(context->state, &input[i]);
+
+ idx = 0;
+ } else
+ i = 0;
+
+ /* Buffer remaining input */
+ memcpy(&context->buffer[idx], &input[i], inputLen - i);
+}
+
+/*
+ * MD5 padding. Adds padding followed by original length.
+ */
+static void __md5_Pad(struct MD5Context *context)
+{
+ unsigned char bits[8];
+ unsigned int idx, padLen;
+ unsigned char PADDING[64];
+
+ memset(PADDING, 0, sizeof(PADDING));
+ PADDING[0] = 0x80;
+
+ /* Save number of bits */
+ __md5_Encode(bits, context->count, 8);
+
+ /* Pad out to 56 mod 64. */
+ idx = (context->count[0] >> 3) & 0x3f;
+ padLen = (idx < 56) ? (56 - idx) : (120 - idx);
+ __md5_Update(context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ __md5_Update(context, bits, 8);
+}
+
+/*
+ * MD5 finalization. Ends an MD5 message-digest operation, writing the
+ * the message digest and zeroizing the context.
+ */
+static void __md5_Final(unsigned char digest[16], struct MD5Context *context)
+{
+ /* Do padding. */
+ __md5_Pad(context);
+
+ /* Store state in digest */
+ __md5_Encode(digest, context->state, 16);
+
+ /* Zeroize sensitive information. */
+ memset(context, 0, sizeof(*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block. */
+static void __md5_Transform(uint32_t state[4], const unsigned char block[64])
+{
+ uint32_t a, b, c, d, x[16];
+#if MD5_SIZE_OVER_SPEED > 1
+ uint32_t temp;
+ const unsigned char *ps;
+
+ static const unsigned char S[] = {
+ 7, 12, 17, 22,
+ 5, 9, 14, 20,
+ 4, 11, 16, 23,
+ 6, 10, 15, 21
+ };
+#endif /* MD5_SIZE_OVER_SPEED > 1 */
+
+#if MD5_SIZE_OVER_SPEED > 0
+ const uint32_t *pc;
+ const unsigned char *pp;
+ int i;
+
+ static const uint32_t C[] = {
+ /* round 1 */
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+ 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+ /* round 2 */
+ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+ 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8,
+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+ 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+ /* round 3 */
+ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
+ 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+ /* round 4 */
+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+ };
+
+ static const unsigned char P[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */
+ 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */
+ 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */
+ 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */
+ };
+
+#endif /* MD5_SIZE_OVER_SPEED > 0 */
+
+ __md5_Decode(x, block, 64);
+
+ a = state[0]; b = state[1]; c = state[2]; d = state[3];
+
+#if MD5_SIZE_OVER_SPEED > 2
+ pc = C; pp = P; ps = S - 4;
+
+ for (i = 0; i < 64; i++) {
+ if ((i & 0x0f) == 0) ps += 4;
+ temp = a;
+ switch (i>>4) {
+ case 0:
+ temp += F(b, c, d);
+ break;
+ case 1:
+ temp += G(b, c, d);
+ break;
+ case 2:
+ temp += H(b, c, d);
+ break;
+ case 3:
+ temp += I(b, c, d);
+ break;
+ }
+ temp += x[*pp++] + *pc++;
+ temp = ROTATE_LEFT(temp, ps[i & 3]);
+ temp += b;
+ a = d; d = c; c = b; b = temp;
+ }
+#elif MD5_SIZE_OVER_SPEED > 1
+ pc = C; pp = P; ps = S;
+
+ /* Round 1 */
+ for (i = 0; i < 16; i++) {
+ FF(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++;
+ temp = d; d = c; c = b; b = a; a = temp;
+ }
+
+ /* Round 2 */
+ ps += 4;
+ for (; i < 32; i++) {
+ GG(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++;
+ temp = d; d = c; c = b; b = a; a = temp;
+ }
+ /* Round 3 */
+ ps += 4;
+ for (; i < 48; i++) {
+ HH(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++;
+ temp = d; d = c; c = b; b = a; a = temp;
+ }
+
+ /* Round 4 */
+ ps += 4;
+ for (; i < 64; i++) {
+ II(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++;
+ temp = d; d = c; c = b; b = a; a = temp;
+ }
+#elif MD5_SIZE_OVER_SPEED > 0
+ pc = C; pp = P;
+
+ /* Round 1 */
+ for (i = 0; i < 4; i++) {
+ FF(a, b, c, d, x[*pp], 7, *pc); pp++; pc++;
+ FF(d, a, b, c, x[*pp], 12, *pc); pp++; pc++;
+ FF(c, d, a, b, x[*pp], 17, *pc); pp++; pc++;
+ FF(b, c, d, a, x[*pp], 22, *pc); pp++; pc++;
+ }
+
+ /* Round 2 */
+ for (i = 0; i < 4; i++) {
+ GG(a, b, c, d, x[*pp], 5, *pc); pp++; pc++;
+ GG(d, a, b, c, x[*pp], 9, *pc); pp++; pc++;
+ GG(c, d, a, b, x[*pp], 14, *pc); pp++; pc++;
+ GG(b, c, d, a, x[*pp], 20, *pc); pp++; pc++;
+ }
+ /* Round 3 */
+ for (i = 0; i < 4; i++) {
+ HH(a, b, c, d, x[*pp], 4, *pc); pp++; pc++;
+ HH(d, a, b, c, x[*pp], 11, *pc); pp++; pc++;
+ HH(c, d, a, b, x[*pp], 16, *pc); pp++; pc++;
+ HH(b, c, d, a, x[*pp], 23, *pc); pp++; pc++;
+ }
+
+ /* Round 4 */
+ for (i = 0; i < 4; i++) {
+ II(a, b, c, d, x[*pp], 6, *pc); pp++; pc++;
+ II(d, a, b, c, x[*pp], 10, *pc); pp++; pc++;
+ II(c, d, a, b, x[*pp], 15, *pc); pp++; pc++;
+ II(b, c, d, a, x[*pp], 21, *pc); pp++; pc++;
+ }
+#else
+ /* Round 1 */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+ FF(a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF(d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF(c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF(b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF(a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF(d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF(c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF(b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF(a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF(d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+ GG(a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG(d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG(a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG(a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG(c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG(b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG(d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG(c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+ HH(a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH(d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH(a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH(d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH(c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH(d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH(c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH(b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH(a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH(b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+ II(a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II(d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II(b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II(d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II(b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II(a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II(c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II(a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II(b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+#endif
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information. */
+ memset(x, 0, sizeof(x));
+}
+
+
+static char*
+__md5_to64(char *s, unsigned v, int n)
+{
+ while (--n >= 0) {
+ *s++ = ascii64[v & 0x3f];
+ v >>= 6;
+ }
+ return s;
+}
+
+/*
+ * UNIX password
+ *
+ * Use MD5 for what it is best at...
+ */
+#define MD5_OUT_BUFSIZE 36
+static char *
+NOINLINE
+md5_crypt(char passwd[MD5_OUT_BUFSIZE], const unsigned char *pw, const unsigned char *salt)
+{
+ const unsigned char *sp, *ep;
+ char *p;
+ unsigned char final[17]; /* final[16] exists only to aid in looping */
+ int sl, pl, i, pw_len;
+ struct MD5Context ctx, ctx1;
+
+ /* Refine the Salt first */
+ sp = salt;
+
+// always true for bbox
+// /* If it starts with the magic string, then skip that */
+// if (!strncmp(sp, __md5__magic, MD5_MAGIC_LEN))
+ sp += MD5_MAGIC_LEN;
+
+ /* It stops at the first '$', max 8 chars */
+ for (ep = sp; *ep && *ep != '$' && ep < (sp+8); ep++)
+ continue;
+
+ /* get the length of the true salt */
+ sl = ep - sp;
+
+ __md5_Init(&ctx);
+
+ /* The password first, since that is what is most unknown */
+ pw_len = strlen((char*)pw);
+ __md5_Update(&ctx, pw, pw_len);
+
+ /* Then our magic string */
+ __md5_Update(&ctx, __md5__magic, MD5_MAGIC_LEN);
+
+ /* Then the raw salt */
+ __md5_Update(&ctx, sp, sl);
+
+ /* Then just as many characters of the MD5(pw, salt, pw) */
+ __md5_Init(&ctx1);
+ __md5_Update(&ctx1, pw, pw_len);
+ __md5_Update(&ctx1, sp, sl);
+ __md5_Update(&ctx1, pw, pw_len);
+ __md5_Final(final, &ctx1);
+ for (pl = pw_len; pl > 0; pl -= 16)
+ __md5_Update(&ctx, final, pl > 16 ? 16 : pl);
+
+ /* Don't leave anything around in vm they could use. */
+//TODO: the above comment seems to be wrong. final is used later.
+ memset(final, 0, sizeof(final));
+
+ /* Then something really weird... */
+ for (i = pw_len; i; i >>= 1) {
+ __md5_Update(&ctx, ((i & 1) ? final : (const unsigned char *) pw), 1);
+ }
+
+ /* Now make the output string */
+ passwd[0] = '$';
+ passwd[1] = '1';
+ passwd[2] = '$';
+ strncpy(passwd + 3, (char*)sp, sl);
+ passwd[sl + 3] = '$';
+
+ __md5_Final(final, &ctx);
+
+ /*
+ * and now, just to make sure things don't run too fast
+ * On a 60 Mhz Pentium this takes 34 msec, so you would
+ * need 30 seconds to build a 1000 entry dictionary...
+ */
+ for (i = 0; i < 1000; i++) {
+ __md5_Init(&ctx1);
+ if (i & 1)
+ __md5_Update(&ctx1, pw, pw_len);
+ else
+ __md5_Update(&ctx1, final, 16);
+
+ if (i % 3)
+ __md5_Update(&ctx1, sp, sl);
+
+ if (i % 7)
+ __md5_Update(&ctx1, pw, pw_len);
+
+ if (i & 1)
+ __md5_Update(&ctx1, final, 16);
+ else
+ __md5_Update(&ctx1, pw, pw_len);
+ __md5_Final(final, &ctx1);
+ }
+
+ p = passwd + sl + 4; /* 12 bytes max (sl is up to 8 bytes) */
+
+ /* Add 5*4+2 = 22 bytes of hash, + NUL byte. */
+ final[16] = final[5];
+ for (i = 0; i < 5; i++) {
+ unsigned l = (final[i] << 16) | (final[i+6] << 8) | final[i+12];
+ p = __md5_to64(p, l, 4);
+ }
+ p = __md5_to64(p, final[11], 2);
+ *p = '\0';
+
+ /* Don't leave anything around in vm they could use. */
+ memset(final, 0, sizeof(final));
+
+ return passwd;
+}
+
+#undef MD5_SIZE_OVER_SPEED
+#undef MD5_MAGIC_STR
+#undef MD5_MAGIC_LEN
+#undef __md5_Encode
+#undef __md5_Decode
+#undef F
+#undef G
+#undef H
+#undef I
+#undef ROTATE_LEFT
+#undef FF
+#undef GG
+#undef HH
+#undef II
+#undef S11
+#undef S12
+#undef S13
+#undef S14
+#undef S21
+#undef S22
+#undef S23
+#undef S24
+#undef S31
+#undef S32
+#undef S33
+#undef S34
+#undef S41
+#undef S42
+#undef S43
+#undef S44
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/read.c b/cleopatre/busybox-1.11.1-spc300/libbb/read.c
new file mode 100644
index 0000000000..fa9874d311
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/read.c
@@ -0,0 +1,293 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+ssize_t safe_read(int fd, void *buf, size_t count)
+{
+ ssize_t n;
+
+ do {
+ n = read(fd, buf, count);
+ } while (n < 0 && errno == EINTR);
+
+ return n;
+}
+
+/* Suppose that you are a shell. You start child processes.
+ * They work and eventually exit. You want to get user input.
+ * You read stdin. But what happens if last child switched
+ * its stdin into O_NONBLOCK mode?
+ *
+ * *** SURPRISE! It will affect the parent too! ***
+ * *** BIG SURPRISE! It stays even after child exits! ***
+ *
+ * This is a design bug in UNIX API.
+ * fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) | O_NONBLOCK);
+ * will set nonblocking mode not only on _your_ stdin, but
+ * also on stdin of your parent, etc.
+ *
+ * In general,
+ * fd2 = dup(fd1);
+ * fcntl(fd2, F_SETFL, fcntl(fd2, F_GETFL, 0) | O_NONBLOCK);
+ * sets both fd1 and fd2 to O_NONBLOCK. This includes cases
+ * where duping is done implicitly by fork() etc.
+ *
+ * We need
+ * fcntl(fd2, F_SETFD, fcntl(fd2, F_GETFD, 0) | O_NONBLOCK);
+ * (note SETFD, not SETFL!) but such thing doesn't exist.
+ *
+ * Alternatively, we need nonblocking_read(fd, ...) which doesn't
+ * require O_NONBLOCK dance at all. Actually, it exists:
+ * n = recv(fd, buf, len, MSG_DONTWAIT);
+ * "MSG_DONTWAIT:
+ * Enables non-blocking operation; if the operation
+ * would block, EAGAIN is returned."
+ * but recv() works only for sockets!
+ *
+ * So far I don't see any good solution, I can only propose
+ * that affected readers should be careful and use this routine,
+ * which detects EAGAIN and uses poll() to wait on the fd.
+ * Thankfully, poll() doesn't care about O_NONBLOCK flag.
+ */
+ssize_t nonblock_safe_read(int fd, void *buf, size_t count)
+{
+ struct pollfd pfd[1];
+ ssize_t n;
+
+ while (1) {
+ n = safe_read(fd, buf, count);
+ if (n >= 0 || errno != EAGAIN)
+ return n;
+ /* fd is in O_NONBLOCK mode. Wait using poll and repeat */
+ pfd[0].fd = fd;
+ pfd[0].events = POLLIN;
+ safe_poll(pfd, 1, -1);
+ }
+}
+
+/*
+ * Read all of the supplied buffer from a file.
+ * This does multiple reads as necessary.
+ * Returns the amount read, or -1 on an error.
+ * A short read is returned on an end of file.
+ */
+ssize_t full_read(int fd, void *buf, size_t len)
+{
+ ssize_t cc;
+ ssize_t total;
+
+ total = 0;
+
+ while (len) {
+ cc = safe_read(fd, buf, len);
+
+ if (cc < 0) {
+ if (total) {
+ /* we already have some! */
+ /* user can do another read to know the error code */
+ return total;
+ }
+ return cc; /* read() returns -1 on failure. */
+ }
+ if (cc == 0)
+ break;
+ buf = ((char *)buf) + cc;
+ total += cc;
+ len -= cc;
+ }
+
+ return total;
+}
+
+// Die with an error message if we can't read the entire buffer.
+void xread(int fd, void *buf, size_t count)
+{
+ if (count) {
+ ssize_t size = full_read(fd, buf, count);
+ if ((size_t)size != count)
+ bb_error_msg_and_die("short read");
+ }
+}
+
+// Die with an error message if we can't read one character.
+unsigned char xread_char(int fd)
+{
+ char tmp;
+ xread(fd, &tmp, 1);
+ return tmp;
+}
+
+// Read one line a-la fgets. Works only on seekable streams
+char *reads(int fd, char *buffer, size_t size)
+{
+ char *p;
+
+ if (size < 2)
+ return NULL;
+ size = full_read(fd, buffer, size-1);
+ if ((ssize_t)size <= 0)
+ return NULL;
+
+ buffer[size] = '\0';
+ p = strchr(buffer, '\n');
+ if (p) {
+ off_t offset;
+ *p++ = '\0';
+ // avoid incorrect (unsigned) widening
+ offset = (off_t)(p - buffer) - (off_t)size;
+ // set fd position right after '\n'
+ if (offset && lseek(fd, offset, SEEK_CUR) == (off_t)-1)
+ return NULL;
+ }
+ return buffer;
+}
+
+// Reads one line a-la fgets (but doesn't save terminating '\n').
+// Reads byte-by-byte. Useful when it is important to not read ahead.
+// Bytes are appended to pfx (which must be malloced, or NULL).
+char *xmalloc_reads(int fd, char *buf, size_t *maxsz_p)
+{
+ char *p;
+ size_t sz = buf ? strlen(buf) : 0;
+ size_t maxsz = maxsz_p ? *maxsz_p : MAXINT(size_t);
+
+ goto jump_in;
+ while (sz < maxsz) {
+ if ((size_t)(p - buf) == sz) {
+ jump_in:
+ buf = xrealloc(buf, sz + 128);
+ p = buf + sz;
+ sz += 128;
+ }
+ /* nonblock_safe_read() because we are used by e.g. shells */
+ if (nonblock_safe_read(fd, p, 1) != 1) { /* EOF/error */
+ if (p == buf) { /* we read nothing */
+ free(buf);
+ return NULL;
+ }
+ break;
+ }
+ if (*p == '\n')
+ break;
+ p++;
+ }
+ *p = '\0';
+ if (maxsz_p)
+ *maxsz_p = p - buf;
+ p++;
+ return xrealloc(buf, p - buf);
+}
+
+ssize_t read_close(int fd, void *buf, size_t size)
+{
+ /*int e;*/
+ size = full_read(fd, buf, size);
+ /*e = errno;*/
+ close(fd);
+ /*errno = e;*/
+ return size;
+}
+
+ssize_t open_read_close(const char *filename, void *buf, size_t size)
+{
+ int fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return fd;
+ return read_close(fd, buf, size);
+}
+
+// Read (potentially big) files in one go. File size is estimated
+// by stat.
+void *xmalloc_open_read_close(const char *filename, size_t *sizep)
+{
+ char *buf;
+ size_t size;
+ int fd;
+ off_t len;
+ struct stat st;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+
+ st.st_size = 0; /* in case fstat fail, define to 0 */
+ fstat(fd, &st);
+ /* /proc/N/stat files report len 0 here */
+ /* In order to make such files readable, we add small const */
+ len = st.st_size | 0x3ff; /* read only 1k on unseekable files */
+ size = sizep ? *sizep : INT_MAX;
+ if (len < size)
+ size = len;
+ buf = xmalloc(size + 1);
+ size = read_close(fd, buf, size);
+ if ((ssize_t)size < 0) {
+ free(buf);
+ return NULL;
+ }
+ xrealloc(buf, size + 1);
+ buf[size] = '\0';
+
+ if (sizep)
+ *sizep = size;
+ return buf;
+}
+
+#ifdef USING_LSEEK_TO_GET_SIZE
+/* Alternatively, file size can be obtained by lseek to the end.
+ * The code is slightly bigger. Retained in case fstat approach
+ * will not work for some weird cases (/proc, block devices, etc).
+ * (NB: lseek also can fail to work for some weird files) */
+
+// Read (potentially big) files in one go. File size is estimated by
+// lseek to end.
+void *xmalloc_open_read_close(const char *filename, size_t *sizep)
+{
+ char *buf;
+ size_t size;
+ int fd;
+ off_t len;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+
+ /* /proc/N/stat files report len 0 here */
+ /* In order to make such files readable, we add small const */
+ size = 0x3ff; /* read only 1k on unseekable files */
+ len = lseek(fd, 0, SEEK_END) | 0x3ff; /* + up to 1k */
+ if (len != (off_t)-1) {
+ xlseek(fd, 0, SEEK_SET);
+ size = sizep ? *sizep : INT_MAX;
+ if (len < size)
+ size = len;
+ }
+
+ buf = xmalloc(size + 1);
+ size = read_close(fd, buf, size);
+ if ((ssize_t)size < 0) {
+ free(buf);
+ return NULL;
+ }
+ xrealloc(buf, size + 1);
+ buf[size] = '\0';
+
+ if (sizep)
+ *sizep = size;
+ return buf;
+}
+#endif
+
+void *xmalloc_xopen_read_close(const char *filename, size_t *sizep)
+{
+ void *buf = xmalloc_open_read_close(filename, sizep);
+ if (!buf)
+ bb_perror_msg_and_die("can't read '%s'", filename);
+ return buf;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/recursive_action.c b/cleopatre/busybox-1.11.1-spc300/libbb/recursive_action.c
new file mode 100644
index 0000000000..513aff3157
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/recursive_action.c
@@ -0,0 +1,127 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+#undef DEBUG_RECURS_ACTION
+
+/*
+ * Walk down all the directories under the specified
+ * location, and do something (something specified
+ * by the fileAction and dirAction function pointers).
+ *
+ * Unfortunately, while nftw(3) could replace this and reduce
+ * code size a bit, nftw() wasn't supported before GNU libc 2.1,
+ * and so isn't sufficiently portable to take over since glibc2.1
+ * is so stinking huge.
+ */
+
+static int true_action(const char *fileName ATTRIBUTE_UNUSED,
+ struct stat *statbuf ATTRIBUTE_UNUSED,
+ void* userData ATTRIBUTE_UNUSED,
+ int depth ATTRIBUTE_UNUSED)
+{
+ return TRUE;
+}
+
+/* fileAction return value of 0 on any file in directory will make
+ * recursive_action() return 0, but it doesn't stop directory traversal
+ * (fileAction/dirAction will be called on each file).
+ *
+ * if !depthFirst, dirAction return value of 0 (FALSE) or 2 (SKIP)
+ * prevents recursion into that directory, instead
+ * recursive_action() returns 0 (if FALSE) or 1 (if SKIP).
+ *
+ * followLinks=0/1 differs mainly in handling of links to dirs.
+ * 0: lstat(statbuf). Calls fileAction on link name even if points to dir.
+ * 1: stat(statbuf). Calls dirAction and optionally recurse on link to dir.
+ */
+
+int recursive_action(const char *fileName,
+ unsigned flags,
+ int (*fileAction)(const char *fileName, struct stat *statbuf, void* userData, int depth),
+ int (*dirAction)(const char *fileName, struct stat *statbuf, void* userData, int depth),
+ void* userData,
+ unsigned depth)
+{
+ struct stat statbuf;
+ int status;
+ DIR *dir;
+ struct dirent *next;
+
+ if (!fileAction) fileAction = true_action;
+ if (!dirAction) dirAction = true_action;
+
+ status = ACTION_FOLLOWLINKS; /* hijack a variable for bitmask... */
+ if (!depth) status = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0;
+ status = ((flags & status) ? stat : lstat)(fileName, &statbuf);
+ if (status < 0) {
+#ifdef DEBUG_RECURS_ACTION
+ bb_error_msg("status=%d flags=%x", status, flags);
+#endif
+ goto done_nak_warn;
+ }
+
+ /* If S_ISLNK(m), then we know that !S_ISDIR(m).
+ * Then we can skip checking first part: if it is true, then
+ * (!dir) is also true! */
+ if ( /* (!(flags & ACTION_FOLLOWLINKS) && S_ISLNK(statbuf.st_mode)) || */
+ !S_ISDIR(statbuf.st_mode)
+ ) {
+ return fileAction(fileName, &statbuf, userData, depth);
+ }
+
+ /* It's a directory (or a link to one, and followLinks is set) */
+
+ if (!(flags & ACTION_RECURSE)) {
+ return dirAction(fileName, &statbuf, userData, depth);
+ }
+
+ if (!(flags & ACTION_DEPTHFIRST)) {
+ status = dirAction(fileName, &statbuf, userData, depth);
+ if (!status)
+ goto done_nak_warn;
+ if (status == SKIP)
+ return TRUE;
+ }
+
+ dir = opendir(fileName);
+ if (!dir) {
+ /* findutils-4.1.20 reports this */
+ /* (i.e. it doesn't silently return with exit code 1) */
+ /* To trigger: "find -exec rm -rf {} \;" */
+ goto done_nak_warn;
+ }
+ status = TRUE;
+ while ((next = readdir(dir)) != NULL) {
+ char *nextFile;
+
+ nextFile = concat_subpath_file(fileName, next->d_name);
+ if (nextFile == NULL)
+ continue;
+ /* now descend into it (NB: ACTION_RECURSE is set in flags) */
+ if (!recursive_action(nextFile, flags, fileAction, dirAction, userData, depth+1))
+ status = FALSE;
+ free(nextFile);
+ }
+ closedir(dir);
+
+ if (flags & ACTION_DEPTHFIRST) {
+ if (!dirAction(fileName, &statbuf, userData, depth))
+ goto done_nak_warn;
+ }
+
+ if (!status)
+ return FALSE;
+ return TRUE;
+
+ done_nak_warn:
+ bb_simple_perror_msg(fileName);
+ return FALSE;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/remove_file.c b/cleopatre/busybox-1.11.1-spc300/libbb/remove_file.c
new file mode 100644
index 0000000000..21878dc3b3
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/remove_file.c
@@ -0,0 +1,102 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini remove_file implementation for busybox
+ *
+ * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* Used from NOFORK applets. Must not allocate anything */
+
+int remove_file(const char *path, int flags)
+{
+ struct stat path_stat;
+
+ if (lstat(path, &path_stat) < 0) {
+ if (errno != ENOENT) {
+ bb_perror_msg("cannot stat '%s'", path);
+ return -1;
+ }
+ if (!(flags & FILEUTILS_FORCE)) {
+ bb_perror_msg("cannot remove '%s'", path);
+ return -1;
+ }
+ return 0;
+ }
+
+ if (S_ISDIR(path_stat.st_mode)) {
+ DIR *dp;
+ struct dirent *d;
+ int status = 0;
+
+ if (!(flags & FILEUTILS_RECUR)) {
+ bb_error_msg("%s: is a directory", path);
+ return -1;
+ }
+
+ if ((!(flags & FILEUTILS_FORCE) && access(path, W_OK) < 0 && isatty(0))
+ || (flags & FILEUTILS_INTERACTIVE)
+ ) {
+ fprintf(stderr, "%s: descend into directory '%s'? ", applet_name,
+ path);
+ if (!bb_ask_confirmation())
+ return 0;
+ }
+
+ dp = opendir(path);
+ if (dp == NULL) {
+ return -1;
+ }
+
+ while ((d = readdir(dp)) != NULL) {
+ char *new_path;
+
+ new_path = concat_subpath_file(path, d->d_name);
+ if (new_path == NULL)
+ continue;
+ if (remove_file(new_path, flags) < 0)
+ status = -1;
+ free(new_path);
+ }
+
+ if (closedir(dp) < 0) {
+ bb_perror_msg("cannot close '%s'", path);
+ return -1;
+ }
+
+ if (flags & FILEUTILS_INTERACTIVE) {
+ fprintf(stderr, "%s: remove directory '%s'? ", applet_name, path);
+ if (!bb_ask_confirmation())
+ return status;
+ }
+
+ if (rmdir(path) < 0) {
+ bb_perror_msg("cannot remove '%s'", path);
+ return -1;
+ }
+
+ return status;
+ }
+
+ /* !ISDIR */
+ if ((!(flags & FILEUTILS_FORCE)
+ && access(path, W_OK) < 0
+ && !S_ISLNK(path_stat.st_mode)
+ && isatty(0))
+ || (flags & FILEUTILS_INTERACTIVE)
+ ) {
+ fprintf(stderr, "%s: remove '%s'? ", applet_name, path);
+ if (!bb_ask_confirmation())
+ return 0;
+ }
+
+ if (unlink(path) < 0) {
+ bb_perror_msg("cannot remove '%s'", path);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/restricted_shell.c b/cleopatre/busybox-1.11.1-spc300/libbb/restricted_shell.c
new file mode 100644
index 0000000000..dc4cfb4584
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/restricted_shell.c
@@ -0,0 +1,46 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "libbb.h"
+
+/* Return 1 if SHELL is a restricted shell (one not returned by
+ getusershell), else 0, meaning it is a standard shell. */
+int restricted_shell(const char *shell)
+{
+ char *line;
+
+ setusershell();
+ while ((line = getusershell())) {
+ if (*line != '#' && strcmp(line, shell) == 0)
+ return 0;
+ }
+ endusershell();
+ return 1;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/rtc.c b/cleopatre/busybox-1.11.1-spc300/libbb/rtc.c
new file mode 100644
index 0000000000..78f10c65d1
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/rtc.c
@@ -0,0 +1,88 @@
+/*
+ * Common RTC functions
+ */
+
+#include "libbb.h"
+#include "rtc_.h"
+
+#if ENABLE_FEATURE_HWCLOCK_ADJTIME_FHS
+# define ADJTIME_PATH "/var/lib/hwclock/adjtime"
+#else
+# define ADJTIME_PATH "/etc/adjtime"
+#endif
+
+int rtc_adjtime_is_utc(void)
+{
+ int utc = 0;
+ FILE *f = fopen(ADJTIME_PATH, "r");
+
+ if (f) {
+ RESERVE_CONFIG_BUFFER(buffer, 128);
+
+ while (fgets(buffer, sizeof(buffer), f)) {
+ int len = strlen(buffer);
+
+ while (len && isspace(buffer[len - 1]))
+ len--;
+
+ buffer[len] = 0;
+
+ if (strncmp(buffer, "UTC", 3) == 0) {
+ utc = 1;
+ break;
+ }
+ }
+ fclose(f);
+
+ RELEASE_CONFIG_BUFFER(buffer);
+ }
+
+ return utc;
+}
+
+int rtc_xopen(const char **default_rtc, int flags)
+{
+ int rtc;
+
+ if (!*default_rtc) {
+ *default_rtc = "/dev/rtc";
+ rtc = open(*default_rtc, flags);
+ if (rtc >= 0)
+ return rtc;
+ *default_rtc = "/dev/rtc0";
+ rtc = open(*default_rtc, flags);
+ if (rtc >= 0)
+ return rtc;
+ *default_rtc = "/dev/misc/rtc";
+ }
+
+ return xopen(*default_rtc, flags);
+}
+
+time_t rtc_read_time(int fd, int utc)
+{
+ struct tm tm;
+ char *oldtz = 0;
+ time_t t = 0;
+
+ memset(&tm, 0, sizeof(struct tm));
+ xioctl(fd, RTC_RD_TIME, &tm);
+ tm.tm_isdst = -1; /* not known */
+
+ if (utc) {
+ oldtz = getenv("TZ");
+ putenv((char*)"TZ=UTC0");
+ tzset();
+ }
+
+ t = mktime(&tm);
+
+ if (utc) {
+ unsetenv("TZ");
+ if (oldtz)
+ putenv(oldtz - 3);
+ tzset();
+ }
+
+ return t;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/run_shell.c b/cleopatre/busybox-1.11.1-spc300/libbb/run_shell.c
new file mode 100644
index 0000000000..239887d85c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/run_shell.c
@@ -0,0 +1,92 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "libbb.h"
+#if ENABLE_SELINUX
+#include <selinux/selinux.h> /* for setexeccon */
+#endif
+
+#if ENABLE_SELINUX
+static security_context_t current_sid;
+
+void
+renew_current_security_context(void)
+{
+ freecon(current_sid); /* Release old context */
+ getcon(&current_sid); /* update */
+}
+void
+set_current_security_context(security_context_t sid)
+{
+ freecon(current_sid); /* Release old context */
+ current_sid = sid;
+}
+
+#endif
+
+/* Run SHELL, or DEFAULT_SHELL if SHELL is empty.
+ If COMMAND is nonzero, pass it to the shell with the -c option.
+ If ADDITIONAL_ARGS is nonzero, pass it to the shell as more
+ arguments. */
+
+void run_shell(const char *shell, int loginshell, const char *command, const char **additional_args)
+{
+ const char **args;
+ int argno = 1;
+ int additional_args_cnt = 0;
+
+ for (args = additional_args; args && *args; args++)
+ additional_args_cnt++;
+
+ args = xmalloc(sizeof(char*) * (4 + additional_args_cnt));
+
+ args[0] = bb_get_last_path_component_nostrip(xstrdup(shell));
+
+ if (loginshell)
+ args[0] = xasprintf("-%s", args[0]);
+
+ if (command) {
+ args[argno++] = "-c";
+ args[argno++] = command;
+ }
+ if (additional_args) {
+ for (; *additional_args; ++additional_args)
+ args[argno++] = *additional_args;
+ }
+ args[argno] = NULL;
+#if ENABLE_SELINUX
+ if (current_sid)
+ setexeccon(current_sid);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ freecon(current_sid);
+#endif
+ execv(shell, (char **) args);
+ bb_perror_msg_and_die("cannot run %s", shell);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/safe_gethostname.c b/cleopatre/busybox-1.11.1-spc300/libbb/safe_gethostname.c
new file mode 100644
index 0000000000..3b24edba57
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/safe_gethostname.c
@@ -0,0 +1,53 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Safe gethostname implementation for busybox
+ *
+ * Copyright (C) 2008 Tito Ragusa <farmatito@tiscali.it>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/*
+ * SUSv2 guarantees that "Host names are limited to 255 bytes"
+ * POSIX.1-2001 guarantees that "Host names (not including the terminating
+ * null byte) are limited to HOST_NAME_MAX bytes" (64 bytes on my box).
+ *
+ * RFC1123 says:
+ *
+ * The syntax of a legal Internet host name was specified in RFC-952
+ * [DNS:4]. One aspect of host name syntax is hereby changed: the
+ * restriction on the first character is relaxed to allow either a
+ * letter or a digit. Host software MUST support this more liberal
+ * syntax.
+ *
+ * Host software MUST handle host names of up to 63 characters and
+ * SHOULD handle host names of up to 255 characters.
+ */
+
+#include "libbb.h"
+#include <sys/utsname.h>
+
+/*
+ * On success return the current malloced and NUL terminated hostname.
+ * On error return malloced and NUL terminated string "?".
+ * This is an illegal first character for a hostname.
+ * The returned malloced string must be freed by the caller.
+ */
+char *safe_gethostname(void)
+{
+ struct utsname uts;
+
+ /* The length of the arrays in a struct utsname is unspecified;
+ * the fields are terminated by a null byte.
+ * Note that there is no standard that says that the hostname
+ * set by sethostname(2) is the same string as the nodename field of the
+ * struct returned by uname (indeed, some systems allow a 256-byte host-
+ * name and an 8-byte nodename), but this is true on Linux. The same holds
+ * for setdomainname(2) and the domainname field.
+ */
+
+ /* Uname can fail only if you pass a bad pointer to it. */
+ uname(&uts);
+
+ return xstrndup(!*(uts.nodename) ? "?" : uts.nodename, sizeof(uts.nodename));
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/safe_poll.c b/cleopatre/busybox-1.11.1-spc300/libbb/safe_poll.c
new file mode 100644
index 0000000000..d2b773c36b
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/safe_poll.c
@@ -0,0 +1,34 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2007 by Denys Vlasenko <vda.linux@googlemail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* Wrapper which restarts poll on EINTR or ENOMEM.
+ * On other errors does perror("poll") and returns.
+ * Warning! May take longer than timeout_ms to return! */
+int safe_poll(struct pollfd *ufds, nfds_t nfds, int timeout)
+{
+ while (1) {
+ int n = poll(ufds, nfds, timeout);
+ if (n >= 0)
+ return n;
+ /* Make sure we inch towards completion */
+ if (timeout > 0)
+ timeout--;
+ /* E.g. strace causes poll to return this */
+ if (errno == EINTR)
+ continue;
+ /* Kernel is very low on memory. Retry. */
+ /* I doubt many callers would handle this correctly! */
+ if (errno == ENOMEM)
+ continue;
+ bb_perror_msg("poll");
+ return n;
+ }
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/safe_strncpy.c b/cleopatre/busybox-1.11.1-spc300/libbb/safe_strncpy.c
new file mode 100644
index 0000000000..cc425839fb
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/safe_strncpy.c
@@ -0,0 +1,18 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* Like strncpy but make sure the resulting string is always 0 terminated. */
+char *safe_strncpy(char *dst, const char *src, size_t size)
+{
+ if (!size) return dst;
+ dst[--size] = '\0';
+ return strncpy(dst, src, size);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/safe_write.c b/cleopatre/busybox-1.11.1-spc300/libbb/safe_write.c
new file mode 100644
index 0000000000..5bbb82e84f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/safe_write.c
@@ -0,0 +1,21 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+ssize_t safe_write(int fd, const void *buf, size_t count)
+{
+ ssize_t n;
+
+ do {
+ n = write(fd, buf, count);
+ } while (n < 0 && errno == EINTR);
+
+ return n;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/selinux_common.c b/cleopatre/busybox-1.11.1-spc300/libbb/selinux_common.c
new file mode 100644
index 0000000000..7478cc7b59
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/selinux_common.c
@@ -0,0 +1,54 @@
+/*
+ * libbb/selinux_common.c
+ * -- common SELinux utility functions
+ *
+ * Copyright 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
+ */
+#include "libbb.h"
+#include <selinux/context.h>
+
+context_t set_security_context_component(security_context_t cur_context,
+ char *user, char *role, char *type, char *range)
+{
+ context_t con = context_new(cur_context);
+ if (!con)
+ return NULL;
+
+ if (user && context_user_set(con, user))
+ goto error;
+ if (type && context_type_set(con, type))
+ goto error;
+ if (range && context_range_set(con, range))
+ goto error;
+ if (role && context_role_set(con, role))
+ goto error;
+ return con;
+
+error:
+ context_free(con);
+ return NULL;
+}
+
+void setfscreatecon_or_die(security_context_t scontext)
+{
+ if (setfscreatecon(scontext) < 0) {
+ /* Can be NULL. All known printf implementations
+ * display "(null)", "<null>" etc */
+ bb_perror_msg_and_die("cannot set default "
+ "file creation context to %s", scontext);
+ }
+}
+
+void selinux_preserve_fcontext(int fdesc)
+{
+ security_context_t context;
+
+ if (fgetfilecon(fdesc, &context) < 0) {
+ if (errno == ENODATA || errno == ENOTSUP)
+ return;
+ bb_perror_msg_and_die("fgetfilecon failed");
+ }
+ setfscreatecon_or_die(context);
+ freecon(context);
+}
+
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/setup_environment.c b/cleopatre/busybox-1.11.1-spc300/libbb/setup_environment.c
new file mode 100644
index 0000000000..6e3575cf9c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/setup_environment.c
@@ -0,0 +1,70 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "libbb.h"
+
+void setup_environment(const char *shell, int clear_env, int change_env, const struct passwd *pw)
+{
+ if (clear_env) {
+ const char *term;
+
+ /* Change the current working directory to be the home directory
+ * of the user */
+ if (chdir(pw->pw_dir)) {
+ xchdir("/");
+ bb_error_msg("can't chdir to home directory '%s'", pw->pw_dir);
+ }
+
+ /* Leave TERM unchanged. Set HOME, SHELL, USER, LOGNAME, PATH.
+ Unset all other environment variables. */
+ term = getenv("TERM");
+ clearenv();
+ if (term)
+ xsetenv("TERM", term);
+ xsetenv("PATH", (pw->pw_uid ? bb_default_path : bb_default_root_path));
+ goto shortcut;
+ // No, gcc (4.2.1) is not clever enougn to do it itself.
+ //xsetenv("USER", pw->pw_name);
+ //xsetenv("LOGNAME", pw->pw_name);
+ //xsetenv("HOME", pw->pw_dir);
+ //xsetenv("SHELL", shell);
+ }
+ else if (change_env) {
+ /* Set HOME, SHELL, and if not becoming a super-user,
+ USER and LOGNAME. */
+ if (pw->pw_uid) {
+ shortcut:
+ xsetenv("USER", pw->pw_name);
+ xsetenv("LOGNAME", pw->pw_name);
+ }
+ xsetenv("HOME", pw->pw_dir);
+ xsetenv("SHELL", shell);
+ }
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/sha1.c b/cleopatre/busybox-1.11.1-spc300/libbb/sha1.c
new file mode 100644
index 0000000000..552dcad807
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/sha1.c
@@ -0,0 +1,170 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Based on shasum from http://www.netsw.org/crypto/hash/
+ * Majorly hacked up to use Dr Brian Gladman's sha1 code
+ *
+ * Copyright (C) 2002 Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK.
+ * Copyright (C) 2003 Glenn L. McGrath
+ * Copyright (C) 2003 Erik Andersen
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ * ---------------------------------------------------------------------------
+ * Issue Date: 10/11/2002
+ *
+ * This is a byte oriented version of SHA1 that operates on arrays of bytes
+ * stored in memory. It runs at 22 cycles per byte on a Pentium P4 processor
+ */
+
+#include "libbb.h"
+
+#define SHA1_BLOCK_SIZE 64
+#define SHA1_DIGEST_SIZE 20
+#define SHA1_HASH_SIZE SHA1_DIGEST_SIZE
+#define SHA2_GOOD 0
+#define SHA2_BAD 1
+
+#define rotl32(x,n) (((x) << n) | ((x) >> (32 - n)))
+
+#define SHA1_MASK (SHA1_BLOCK_SIZE - 1)
+
+/* reverse byte order in 32-bit words */
+#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
+#define parity(x,y,z) ((x) ^ (y) ^ (z))
+#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y))))
+
+/* A normal version as set out in the FIPS. This version uses */
+/* partial loop unrolling and is optimised for the Pentium 4 */
+#define rnd(f,k) \
+ do { \
+ t = a; a = rotl32(a,5) + f(b,c,d) + e + k + w[i]; \
+ e = d; d = c; c = rotl32(b, 30); b = t; \
+ } while (0)
+
+static void sha1_compile(sha1_ctx_t *ctx)
+{
+ uint32_t w[80], i, a, b, c, d, e, t;
+
+ /* note that words are compiled from the buffer into 32-bit */
+ /* words in big-endian order so an order reversal is needed */
+ /* here on little endian machines */
+ for (i = 0; i < SHA1_BLOCK_SIZE / 4; ++i)
+ w[i] = htonl(ctx->wbuf[i]);
+
+ for (i = SHA1_BLOCK_SIZE / 4; i < 80; ++i)
+ w[i] = rotl32(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
+
+ a = ctx->hash[0];
+ b = ctx->hash[1];
+ c = ctx->hash[2];
+ d = ctx->hash[3];
+ e = ctx->hash[4];
+
+ for (i = 0; i < 20; ++i) {
+ rnd(ch, 0x5a827999);
+ }
+
+ for (i = 20; i < 40; ++i) {
+ rnd(parity, 0x6ed9eba1);
+ }
+
+ for (i = 40; i < 60; ++i) {
+ rnd(maj, 0x8f1bbcdc);
+ }
+
+ for (i = 60; i < 80; ++i) {
+ rnd(parity, 0xca62c1d6);
+ }
+
+ ctx->hash[0] += a;
+ ctx->hash[1] += b;
+ ctx->hash[2] += c;
+ ctx->hash[3] += d;
+ ctx->hash[4] += e;
+}
+
+void sha1_begin(sha1_ctx_t *ctx)
+{
+ ctx->count[0] = ctx->count[1] = 0;
+ ctx->hash[0] = 0x67452301;
+ ctx->hash[1] = 0xefcdab89;
+ ctx->hash[2] = 0x98badcfe;
+ ctx->hash[3] = 0x10325476;
+ ctx->hash[4] = 0xc3d2e1f0;
+}
+
+/* SHA1 hash data in an array of bytes into hash buffer and call the */
+/* hash_compile function as required. */
+void sha1_hash(const void *data, size_t length, sha1_ctx_t *ctx)
+{
+ uint32_t pos = (uint32_t) (ctx->count[0] & SHA1_MASK);
+ uint32_t freeb = SHA1_BLOCK_SIZE - pos;
+ const unsigned char *sp = data;
+
+ if ((ctx->count[0] += length) < length)
+ ++(ctx->count[1]);
+
+ while (length >= freeb) { /* tranfer whole blocks while possible */
+ memcpy(((unsigned char *) ctx->wbuf) + pos, sp, freeb);
+ sp += freeb;
+ length -= freeb;
+ freeb = SHA1_BLOCK_SIZE;
+ pos = 0;
+ sha1_compile(ctx);
+ }
+
+ memcpy(((unsigned char *) ctx->wbuf) + pos, sp, length);
+}
+
+void *sha1_end(void *resbuf, sha1_ctx_t *ctx)
+{
+ /* SHA1 Final padding and digest calculation */
+#if BB_BIG_ENDIAN
+ static uint32_t mask[4] = { 0x00000000, 0xff000000, 0xffff0000, 0xffffff00 };
+ static uint32_t bits[4] = { 0x80000000, 0x00800000, 0x00008000, 0x00000080 };
+#else
+ static uint32_t mask[4] = { 0x00000000, 0x000000ff, 0x0000ffff, 0x00ffffff };
+ static uint32_t bits[4] = { 0x00000080, 0x00008000, 0x00800000, 0x80000000 };
+#endif
+
+ uint8_t *hval = resbuf;
+ uint32_t i, cnt = (uint32_t) (ctx->count[0] & SHA1_MASK);
+
+ /* mask out the rest of any partial 32-bit word and then set */
+ /* the next byte to 0x80. On big-endian machines any bytes in */
+ /* the buffer will be at the top end of 32 bit words, on little */
+ /* endian machines they will be at the bottom. Hence the AND */
+ /* and OR masks above are reversed for little endian systems */
+ ctx->wbuf[cnt >> 2] =
+ (ctx->wbuf[cnt >> 2] & mask[cnt & 3]) | bits[cnt & 3];
+
+ /* we need 9 or more empty positions, one for the padding byte */
+ /* (above) and eight for the length count. If there is not */
+ /* enough space pad and empty the buffer */
+ if (cnt > SHA1_BLOCK_SIZE - 9) {
+ if (cnt < 60)
+ ctx->wbuf[15] = 0;
+ sha1_compile(ctx);
+ cnt = 0;
+ } else /* compute a word index for the empty buffer positions */
+ cnt = (cnt >> 2) + 1;
+
+ while (cnt < 14) /* and zero pad all but last two positions */
+ ctx->wbuf[cnt++] = 0;
+
+ /* assemble the eight byte counter in the buffer in big-endian */
+ /* format */
+
+ ctx->wbuf[14] = htonl((ctx->count[1] << 3) | (ctx->count[0] >> 29));
+ ctx->wbuf[15] = htonl(ctx->count[0] << 3);
+
+ sha1_compile(ctx);
+
+ /* extract the hash value as bytes in case the hash buffer is */
+ /* misaligned for 32-bit words */
+
+ for (i = 0; i < SHA1_DIGEST_SIZE; ++i)
+ hval[i] = (unsigned char) (ctx->hash[i >> 2] >> 8 * (~i & 3));
+
+ return resbuf;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/signals.c b/cleopatre/busybox-1.11.1-spc300/libbb/signals.c
new file mode 100644
index 0000000000..1342c89a8e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/signals.c
@@ -0,0 +1,113 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2006 Rob Landley
+ * Copyright (C) 2006 Denys Vlasenko
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* Saves 2 bytes on x86! Oh my... */
+int sigaction_set(int signum, const struct sigaction *act)
+{
+ return sigaction(signum, act, NULL);
+}
+
+int sigprocmask_allsigs(int how)
+{
+ sigset_t set;
+ sigfillset(&set);
+ return sigprocmask(how, &set, NULL);
+}
+
+void bb_signals(int sigs, void (*f)(int))
+{
+ int sig_no = 0;
+ int bit = 1;
+
+ while (sigs) {
+ if (sigs & bit) {
+ sigs &= ~bit;
+ signal(sig_no, f);
+ }
+ sig_no++;
+ bit <<= 1;
+ }
+}
+
+void bb_signals_recursive(int sigs, void (*f)(int))
+{
+ int sig_no = 0;
+ int bit = 1;
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = f;
+ /*sa.sa_flags = 0;*/
+ /*sigemptyset(&sa.sa_mask); - hope memset did it*/
+
+ while (sigs) {
+ if (sigs & bit) {
+ sigs &= ~bit;
+ sigaction_set(sig_no, &sa);
+ }
+ sig_no++;
+ bit <<= 1;
+ }
+}
+
+void sig_block(int sig)
+{
+ sigset_t ss;
+ sigemptyset(&ss);
+ sigaddset(&ss, sig);
+ sigprocmask(SIG_BLOCK, &ss, NULL);
+}
+
+void sig_unblock(int sig)
+{
+ sigset_t ss;
+ sigemptyset(&ss);
+ sigaddset(&ss, sig);
+ sigprocmask(SIG_UNBLOCK, &ss, NULL);
+}
+
+void wait_for_any_sig(void)
+{
+ sigset_t ss;
+ sigemptyset(&ss);
+ sigsuspend(&ss);
+}
+
+/* Assuming the sig is fatal */
+void kill_myself_with_sig(int sig)
+{
+ signal(sig, SIG_DFL);
+ sig_unblock(sig);
+ raise(sig);
+ _exit(EXIT_FAILURE); /* Should not reach it */
+}
+
+void signal_SA_RESTART_empty_mask(int sig, void (*handler)(int))
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ /*sigemptyset(&sa.sa_mask);*/
+ sa.sa_flags = SA_RESTART;
+ sa.sa_handler = handler;
+ sigaction_set(sig, &sa);
+}
+
+void signal_no_SA_RESTART_empty_mask(int sig, void (*handler)(int))
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ /*sigemptyset(&sa.sa_mask);*/
+ /*sa.sa_flags = 0;*/
+ sa.sa_handler = handler;
+ sigaction_set(sig, &sa);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/simplify_path.c b/cleopatre/busybox-1.11.1-spc300/libbb/simplify_path.c
new file mode 100644
index 0000000000..29e371df60
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/simplify_path.c
@@ -0,0 +1,53 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bb_simplify_path implementation for busybox
+ *
+ * Copyright (C) 2001 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+char *bb_simplify_path(const char *path)
+{
+ char *s, *start, *p;
+
+ if (path[0] == '/')
+ start = xstrdup(path);
+ else {
+ s = xrealloc_getcwd_or_warn(NULL);
+ start = concat_path_file(s, path);
+ free(s);
+ }
+ p = s = start;
+
+ do {
+ if (*p == '/') {
+ if (*s == '/') { /* skip duplicate (or initial) slash */
+ continue;
+ }
+ if (*s == '.') {
+ if (s[1] == '/' || !s[1]) { /* remove extra '.' */
+ continue;
+ }
+ if ((s[1] == '.') && (s[2] == '/' || !s[2])) {
+ ++s;
+ if (p > start) {
+ while (*--p != '/') /* omit previous dir */
+ continue;
+ }
+ continue;
+ }
+ }
+ }
+ *++p = *s;
+ } while (*++s);
+
+ if ((p == start) || (*p != '/')) { /* not a trailing slash */
+ ++p; /* so keep last character */
+ }
+ *p = 0;
+
+ return start;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/skip_whitespace.c b/cleopatre/busybox-1.11.1-spc300/libbb/skip_whitespace.c
new file mode 100644
index 0000000000..87b5f23ba1
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/skip_whitespace.c
@@ -0,0 +1,25 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * skip_whitespace implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+char *skip_whitespace(const char *s)
+{
+ /* NB: isspace('\0') returns 0 */
+ while (isspace(*s)) ++s;
+
+ return (char *) s;
+}
+
+char *skip_non_whitespace(const char *s)
+{
+ while (*s && !isspace(*s)) ++s;
+
+ return (char *) s;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/speed_table.c b/cleopatre/busybox-1.11.1-spc300/libbb/speed_table.c
new file mode 100644
index 0000000000..94a296238e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/speed_table.c
@@ -0,0 +1,117 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * compact speed_t <-> speed functions for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include <termios.h>
+#include "libbb.h"
+
+struct speed_map {
+ unsigned short speed;
+ unsigned short value;
+};
+
+static const struct speed_map speeds[] = {
+ {B0, 0},
+ {B50, 50},
+ {B75, 75},
+ {B110, 110},
+ {B134, 134},
+ {B150, 150},
+ {B200, 200},
+ {B300, 300},
+ {B600, 600},
+ {B1200, 1200},
+ {B1800, 1800},
+ {B2400, 2400},
+ {B4800, 4800},
+ {B9600, 9600},
+#ifdef B19200
+ {B19200, 19200},
+#elif defined(EXTA)
+ {EXTA, 19200},
+#endif
+#ifdef B38400
+ {B38400, 38400/256 + 0x8000U},
+#elif defined(EXTB)
+ {EXTB, 38400/256 + 0x8000U},
+#endif
+#ifdef B57600
+ {B57600, 57600/256 + 0x8000U},
+#endif
+#ifdef B115200
+ {B115200, 115200/256 + 0x8000U},
+#endif
+#ifdef B230400
+ {B230400, 230400/256 + 0x8000U},
+#endif
+#ifdef B460800
+ {B460800, 460800/256 + 0x8000U},
+#endif
+};
+
+enum { NUM_SPEEDS = ARRAY_SIZE(speeds) };
+
+unsigned int tty_baud_to_value(speed_t speed)
+{
+ int i = 0;
+
+ do {
+ if (speed == speeds[i].speed) {
+ if (speeds[i].value & 0x8000U) {
+ return ((unsigned long) (speeds[i].value) & 0x7fffU) * 256;
+ }
+ return speeds[i].value;
+ }
+ } while (++i < NUM_SPEEDS);
+
+ return 0;
+}
+
+speed_t tty_value_to_baud(unsigned int value)
+{
+ int i = 0;
+
+ do {
+ if (value == tty_baud_to_value(speeds[i].speed)) {
+ return speeds[i].speed;
+ }
+ } while (++i < NUM_SPEEDS);
+
+ return (speed_t) - 1;
+}
+
+#if 0
+/* testing code */
+#include <stdio.h>
+
+int main(void)
+{
+ unsigned long v;
+ speed_t s;
+
+ for (v = 0 ; v < 500000; v++) {
+ s = tty_value_to_baud(v);
+ if (s == (speed_t) -1) {
+ continue;
+ }
+ printf("v = %lu -- s = %0lo\n", v, (unsigned long) s);
+ }
+
+ printf("-------------------------------\n");
+
+ for (s = 0 ; s < 010017+1; s++) {
+ v = tty_baud_to_value(s);
+ if (!v) {
+ continue;
+ }
+ printf("v = %lu -- s = %0lo\n", v, (unsigned long) s);
+ }
+
+ return 0;
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/str_tolower.c b/cleopatre/busybox-1.11.1-spc300/libbb/str_tolower.c
new file mode 100644
index 0000000000..037f717c74
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/str_tolower.c
@@ -0,0 +1,13 @@
+/* vi set: sw=4 ts=4: */
+/* Convert string str to lowercase, return str.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+#include "libbb.h"
+char* str_tolower(char *str)
+{
+ char *c;
+ for (c = str; *c; ++c)
+ *c = tolower(*c);
+ return str;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/strrstr.c b/cleopatre/busybox-1.11.1-spc300/libbb/strrstr.c
new file mode 100644
index 0000000000..f61dd517fa
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/strrstr.c
@@ -0,0 +1,71 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2008 Bernhard Fischer
+ *
+ * Licensed under GPLv2 or later, see file License in this tarball for details.
+ */
+
+#ifdef __DO_STRRSTR_TEST
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#else
+#include "libbb.h"
+#endif
+
+/*
+ * The strrstr() function finds the last occurrence of the substring needle
+ * in the string haystack. The terminating nul characters are not compared.
+ */
+char* strrstr(const char *haystack, const char *needle)
+{
+ char *r = NULL;
+
+ if (!needle[0])
+ return (char*)haystack + strlen(haystack);
+ while (1) {
+ char *p = strstr(haystack, needle);
+ if (!p)
+ return r;
+ r = p;
+ haystack = p + 1;
+ }
+}
+
+#ifdef __DO_STRRSTR_TEST
+int main(int argc, char **argv)
+{
+ static const struct {
+ const char *h, *n;
+ int pos;
+ } test_array[] = {
+ /* 0123456789 */
+ { "baaabaaab", "aaa", 5 },
+ { "baaabaaaab", "aaa", 6 },
+ { "baaabaab", "aaa", 1 },
+ { "aaa", "aaa", 0 },
+ { "aaa", "a", 2 },
+ { "aaa", "bbb", -1 },
+ { "a", "aaa", -1 },
+ { "aaa", "", 3 },
+ { "", "aaa", -1 },
+ { "", "", 0 },
+ };
+
+ int i;
+
+ i = 0;
+ while (i < sizeof(test_array) / sizeof(test_array[0])) {
+ const char *r = strrstr(test_array[i].h, test_array[i].n);
+ printf("'%s' vs. '%s': '%s' - ", test_array[i].h, test_array[i].n, r);
+ if (r == NULL)
+ r = test_array[i].h - 1;
+ printf("%s\n", r == test_array[i].h + test_array[i].pos ? "PASSED" : "FAILED");
+ i++;
+ }
+
+ return 0;
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/time.c b/cleopatre/busybox-1.11.1-spc300/libbb/time.c
new file mode 100644
index 0000000000..07c0094175
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/time.c
@@ -0,0 +1,49 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2007 Denys Vlasenko
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+#if ENABLE_MONOTONIC_SYSCALL
+#include <sys/syscall.h>
+
+/* Old glibc (< 2.3.4) does not provide this constant. We use syscall
+ * directly so this definition is safe. */
+#ifndef CLOCK_MONOTONIC
+#define CLOCK_MONOTONIC 1
+#endif
+
+/* libc has incredibly messy way of doing this,
+ * typically requiring -lrt. We just skip all this mess */
+unsigned long long monotonic_us(void)
+{
+ struct timespec ts;
+ if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, &ts))
+ bb_error_msg_and_die("clock_gettime(MONOTONIC) failed");
+ return ts.tv_sec * 1000000ULL + ts.tv_nsec/1000;
+}
+unsigned monotonic_sec(void)
+{
+ struct timespec ts;
+ if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, &ts))
+ bb_error_msg_and_die("clock_gettime(MONOTONIC) failed");
+ return ts.tv_sec;
+}
+#else
+unsigned long long monotonic_us(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000000ULL + tv.tv_usec;
+}
+
+unsigned monotonic_sec(void)
+{
+ return time(NULL);
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/trim.c b/cleopatre/busybox-1.11.1-spc300/libbb/trim.c
new file mode 100644
index 0000000000..94ccaf7edd
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/trim.c
@@ -0,0 +1,31 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+void trim(char *s)
+{
+ size_t len = strlen(s);
+ size_t lws;
+
+ /* trim trailing whitespace */
+ while (len && isspace(s[len-1]))
+ --len;
+
+ /* trim leading whitespace */
+ if (len) {
+ lws = strspn(s, " \n\r\t\v");
+ if (lws) {
+ len -= lws;
+ memmove(s, s + lws, len);
+ }
+ }
+ s[len] = '\0';
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/u_signal_names.c b/cleopatre/busybox-1.11.1-spc300/libbb/u_signal_names.c
new file mode 100644
index 0000000000..1dcbf5f2d0
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/u_signal_names.c
@@ -0,0 +1,180 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Signal name/number conversion routines.
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* Believe it or not, but some arches have more than 32 SIGs!
+ * HPPA: SIGSTKFLT == 36. */
+
+static const char signals[][7] = {
+ // SUSv3 says kill must support these, and specifies the numerical values,
+ // http://www.opengroup.org/onlinepubs/009695399/utilities/kill.html
+ // {0, "EXIT"}, {1, "HUP"}, {2, "INT"}, {3, "QUIT"},
+ // {6, "ABRT"}, {9, "KILL"}, {14, "ALRM"}, {15, "TERM"}
+ // And Posix adds the following:
+ // {SIGILL, "ILL"}, {SIGTRAP, "TRAP"}, {SIGFPE, "FPE"}, {SIGUSR1, "USR1"},
+ // {SIGSEGV, "SEGV"}, {SIGUSR2, "USR2"}, {SIGPIPE, "PIPE"}, {SIGCHLD, "CHLD"},
+ // {SIGCONT, "CONT"}, {SIGSTOP, "STOP"}, {SIGTSTP, "TSTP"}, {SIGTTIN, "TTIN"},
+ // {SIGTTOU, "TTOU"}
+
+ [0] = "EXIT",
+#ifdef SIGHUP
+ [SIGHUP ] = "HUP",
+#endif
+#ifdef SIGINT
+ [SIGINT ] = "INT",
+#endif
+#ifdef SIGQUIT
+ [SIGQUIT ] = "QUIT",
+#endif
+#ifdef SIGILL
+ [SIGILL ] = "ILL",
+#endif
+#ifdef SIGTRAP
+ [SIGTRAP ] = "TRAP",
+#endif
+#ifdef SIGABRT
+ [SIGABRT ] = "ABRT",
+#endif
+#ifdef SIGBUS
+ [SIGBUS ] = "BUS",
+#endif
+#ifdef SIGFPE
+ [SIGFPE ] = "FPE",
+#endif
+#ifdef SIGKILL
+ [SIGKILL ] = "KILL",
+#endif
+#ifdef SIGUSR1
+ [SIGUSR1 ] = "USR1",
+#endif
+#ifdef SIGSEGV
+ [SIGSEGV ] = "SEGV",
+#endif
+#ifdef SIGUSR2
+ [SIGUSR2 ] = "USR2",
+#endif
+#ifdef SIGPIPE
+ [SIGPIPE ] = "PIPE",
+#endif
+#ifdef SIGALRM
+ [SIGALRM ] = "ALRM",
+#endif
+#ifdef SIGTERM
+ [SIGTERM ] = "TERM",
+#endif
+#ifdef SIGSTKFLT
+ [SIGSTKFLT] = "STKFLT",
+#endif
+#ifdef SIGCHLD
+ [SIGCHLD ] = "CHLD",
+#endif
+#ifdef SIGCONT
+ [SIGCONT ] = "CONT",
+#endif
+#ifdef SIGSTOP
+ [SIGSTOP ] = "STOP",
+#endif
+#ifdef SIGTSTP
+ [SIGTSTP ] = "TSTP",
+#endif
+#ifdef SIGTTIN
+ [SIGTTIN ] = "TTIN",
+#endif
+#ifdef SIGTTOU
+ [SIGTTOU ] = "TTOU",
+#endif
+#ifdef SIGURG
+ [SIGURG ] = "URG",
+#endif
+#ifdef SIGXCPU
+ [SIGXCPU ] = "XCPU",
+#endif
+#ifdef SIGXFSZ
+ [SIGXFSZ ] = "XFSZ",
+#endif
+#ifdef SIGVTALRM
+ [SIGVTALRM] = "VTALRM",
+#endif
+#ifdef SIGPROF
+ [SIGPROF ] = "PROF",
+#endif
+#ifdef SIGWINCH
+ [SIGWINCH ] = "WINCH",
+#endif
+#ifdef SIGPOLL
+ [SIGPOLL ] = "POLL",
+#endif
+#ifdef SIGPWR
+ [SIGPWR ] = "PWR",
+#endif
+#ifdef SIGSYS
+ [SIGSYS ] = "SYS",
+#endif
+};
+
+// Convert signal name to number.
+
+int get_signum(const char *name)
+{
+ unsigned i;
+
+ i = bb_strtou(name, NULL, 10);
+ if (!errno)
+ return i;
+ if (strncasecmp(name, "SIG", 3) == 0)
+ name += 3;
+ for (i = 0; i < ARRAY_SIZE(signals); i++)
+ if (strcasecmp(name, signals[i]) == 0)
+ return i;
+
+#if ENABLE_DESKTOP && (defined(SIGIOT) || defined(SIGIO))
+ /* SIGIO[T] are aliased to other names,
+ * thus cannot be stored in the signals[] array.
+ * Need special code to recognize them */
+ if ((name[0] | 0x20) == 'i' && (name[1] | 0x20) == 'o') {
+#ifdef SIGIO
+ if (!name[2])
+ return SIGIO;
+#endif
+#ifdef SIGIOT
+ if ((name[2] | 0x20) == 't' && !name[3])
+ return SIGIOT;
+#endif
+ }
+#endif
+
+ return -1;
+}
+
+// Convert signal number to name
+
+const char *get_signame(int number)
+{
+ if ((unsigned)number < ARRAY_SIZE(signals)) {
+ if (signals[number][0]) /* if it's not an empty str */
+ return signals[number];
+ }
+
+ return itoa(number);
+}
+
+
+// Print the whole signal list
+
+void print_signames(void)
+{
+ unsigned signo;
+
+ for (signo = 1; signo < ARRAY_SIZE(signals); signo++) {
+ const char *name = signals[signo];
+ if (name[0])
+ puts(name);
+ }
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/udp_io.c b/cleopatre/busybox-1.11.1-spc300/libbb/udp_io.c
new file mode 100644
index 0000000000..c99e516434
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/udp_io.c
@@ -0,0 +1,168 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2007 Denys Vlasenko
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/*
+ * This asks kernel to let us know dst addr/port of incoming packets
+ * We don't check for errors here. Not supported == won't be used
+ */
+void
+socket_want_pktinfo(int fd)
+{
+#ifdef IP_PKTINFO
+ setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &const_int_1, sizeof(int));
+#endif
+#if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
+ setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &const_int_1, sizeof(int));
+#endif
+}
+
+
+ssize_t
+send_to_from(int fd, void *buf, size_t len, int flags,
+ const struct sockaddr *to,
+ const struct sockaddr *from,
+ socklen_t tolen)
+{
+#ifndef IP_PKTINFO
+ return sendto(fd, buf, len, flags, to, tolen);
+#else
+ struct iovec iov[1];
+ struct msghdr msg;
+ union {
+ char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))];
+#if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
+ char cmsg6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+#endif
+ } u;
+ struct cmsghdr* cmsgptr;
+
+ if (from->sa_family != AF_INET
+#if ENABLE_FEATURE_IPV6
+ && from->sa_family != AF_INET6
+#endif
+ ) {
+ /* ANY local address */
+ return sendto(fd, buf, len, flags, to, tolen);
+ }
+
+ /* man recvmsg and man cmsg is needed to make sense of code below */
+
+ iov[0].iov_base = buf;
+ iov[0].iov_len = len;
+
+ memset(&u, 0, sizeof(u));
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = (void *)(struct sockaddr *)to; /* or compiler will annoy us */
+ msg.msg_namelen = tolen;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = &u;
+ msg.msg_controllen = sizeof(u);
+ msg.msg_flags = flags;
+
+ cmsgptr = CMSG_FIRSTHDR(&msg);
+ if (to->sa_family == AF_INET && from->sa_family == AF_INET) {
+ struct in_pktinfo *pktptr;
+ cmsgptr->cmsg_level = IPPROTO_IP;
+ cmsgptr->cmsg_type = IP_PKTINFO;
+ cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+ pktptr = (struct in_pktinfo *)(CMSG_DATA(cmsgptr));
+ /* pktptr->ipi_ifindex = 0; -- already done by memset(cbuf...) */
+ pktptr->ipi_spec_dst = ((struct sockaddr_in*)from)->sin_addr;
+ }
+#if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
+ else if (to->sa_family == AF_INET6 && from->sa_family == AF_INET6) {
+ struct in6_pktinfo *pktptr;
+ cmsgptr->cmsg_level = IPPROTO_IPV6;
+ cmsgptr->cmsg_type = IPV6_PKTINFO;
+ cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+ pktptr = (struct in6_pktinfo *)(CMSG_DATA(cmsgptr));
+ /* pktptr->ipi6_ifindex = 0; -- already done by memset(cbuf...) */
+ pktptr->ipi6_addr = ((struct sockaddr_in6*)from)->sin6_addr;
+ }
+#endif
+ msg.msg_controllen = cmsgptr->cmsg_len;
+
+ return sendmsg(fd, &msg, flags);
+#endif
+}
+
+/* NB: this will never set port# in 'to'!
+ * _Only_ IP/IPv6 address part of 'to' is _maybe_ modified.
+ * Typical usage is to preinit 'to' with "default" value
+ * before calling recv_from_to(). */
+ssize_t
+recv_from_to(int fd, void *buf, size_t len, int flags,
+ struct sockaddr *from, struct sockaddr *to,
+ socklen_t sa_size)
+{
+#ifndef IP_PKTINFO
+ return recvfrom(fd, buf, len, flags, from, &sa_size);
+#else
+ /* man recvmsg and man cmsg is needed to make sense of code below */
+ struct iovec iov[1];
+ union {
+ char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))];
+#if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
+ char cmsg6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+#endif
+ } u;
+ struct cmsghdr *cmsgptr;
+ struct msghdr msg;
+ ssize_t recv_length;
+
+ iov[0].iov_base = buf;
+ iov[0].iov_len = len;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = (struct sockaddr *)from;
+ msg.msg_namelen = sa_size;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = &u;
+ msg.msg_controllen = sizeof(u);
+
+ recv_length = recvmsg(fd, &msg, flags);
+ if (recv_length < 0)
+ return recv_length;
+
+ /* Here we try to retrieve destination IP and memorize it */
+ for (cmsgptr = CMSG_FIRSTHDR(&msg);
+ cmsgptr != NULL;
+ cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)
+ ) {
+ if (cmsgptr->cmsg_level == IPPROTO_IP
+ && cmsgptr->cmsg_type == IP_PKTINFO
+ ) {
+#define pktinfo(cmsgptr) ( (struct in_pktinfo*)(CMSG_DATA(cmsgptr)) )
+ to->sa_family = AF_INET;
+ ((struct sockaddr_in*)to)->sin_addr = pktinfo(cmsgptr)->ipi_addr;
+ /* ((struct sockaddr_in*)to)->sin_port = 123; */
+#undef pktinfo
+ break;
+ }
+#if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
+ if (cmsgptr->cmsg_level == IPPROTO_IPV6
+ && cmsgptr->cmsg_type == IPV6_PKTINFO
+ ) {
+#define pktinfo(cmsgptr) ( (struct in6_pktinfo*)(CMSG_DATA(cmsgptr)) )
+ to->sa_family = AF_INET6;
+ ((struct sockaddr_in6*)to)->sin6_addr = pktinfo(cmsgptr)->ipi6_addr;
+ /* ((struct sockaddr_in6*)to)->sin6_port = 123; */
+#undef pktinfo
+ break;
+ }
+#endif
+ }
+ return recv_length;
+#endif
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/update_passwd.c b/cleopatre/busybox-1.11.1-spc300/libbb/update_passwd.c
new file mode 100644
index 0000000000..d10e863c6c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/update_passwd.c
@@ -0,0 +1,153 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * update_passwd
+ *
+ * update_passwd is a common function for passwd and chpasswd applets;
+ * it is responsible for updating password file (i.e. /etc/passwd or
+ * /etc/shadow) for a given user and password.
+ *
+ * Moved from loginutils/passwd.c by Alexander Shishkin <virtuoso@slind.org>
+ */
+
+#include "libbb.h"
+
+#if ENABLE_SELINUX
+static void check_selinux_update_passwd(const char *username)
+{
+ security_context_t context;
+ char *seuser;
+
+ if (getuid() != (uid_t)0 || is_selinux_enabled() == 0)
+ return; /* No need to check */
+
+ if (getprevcon_raw(&context) < 0)
+ bb_perror_msg_and_die("getprevcon failed");
+ seuser = strtok(context, ":");
+ if (!seuser)
+ bb_error_msg_and_die("invalid context '%s'", context);
+ if (strcmp(seuser, username) != 0) {
+ if (checkPasswdAccess(PASSWD__PASSWD) != 0)
+ bb_error_msg_and_die("SELinux: access denied");
+ }
+ if (ENABLE_FEATURE_CLEAN_UP)
+ freecon(context);
+}
+#else
+#define check_selinux_update_passwd(username) ((void)0)
+#endif
+
+int update_passwd(const char *filename, const char *username,
+ const char *new_pw)
+{
+ struct stat sb;
+ struct flock lock;
+ FILE *old_fp;
+ FILE *new_fp;
+ char *fnamesfx;
+ char *sfx_char;
+ unsigned user_len;
+ int old_fd;
+ int new_fd;
+ int i;
+ int cnt = 0;
+ int ret = -1; /* failure */
+
+ filename = xmalloc_follow_symlinks(filename);
+ if (filename == NULL)
+ return -1;
+
+ check_selinux_update_passwd(username);
+
+ /* New passwd file, "/etc/passwd+" for now */
+ fnamesfx = xasprintf("%s+", filename);
+ sfx_char = &fnamesfx[strlen(fnamesfx)-1];
+ username = xasprintf("%s:", username);
+ user_len = strlen(username);
+
+ old_fp = fopen(filename, "r+");
+ if (!old_fp)
+ goto free_mem;
+ old_fd = fileno(old_fp);
+
+ selinux_preserve_fcontext(old_fd);
+
+ /* Try to create "/etc/passwd+". Wait if it exists. */
+ i = 30;
+ do {
+ // FIXME: on last iteration try w/o O_EXCL but with O_TRUNC?
+ new_fd = open(fnamesfx, O_WRONLY|O_CREAT|O_EXCL, 0600);
+ if (new_fd >= 0) goto created;
+ if (errno != EEXIST) break;
+ usleep(100000); /* 0.1 sec */
+ } while (--i);
+ bb_perror_msg("cannot create '%s'", fnamesfx);
+ goto close_old_fp;
+
+ created:
+ if (!fstat(old_fd, &sb)) {
+ fchmod(new_fd, sb.st_mode & 0777); /* ignore errors */
+ fchown(new_fd, sb.st_uid, sb.st_gid);
+ }
+ new_fp = fdopen(new_fd, "w");
+ if (!new_fp) {
+ close(new_fd);
+ goto unlink_new;
+ }
+
+ /* Backup file is "/etc/passwd-" */
+ *sfx_char = '-';
+ /* Delete old backup */
+ i = (unlink(fnamesfx) && errno != ENOENT);
+ /* Create backup as a hardlink to current */
+ if (i || link(filename, fnamesfx))
+ bb_perror_msg("warning: cannot create backup copy '%s'", fnamesfx);
+ *sfx_char = '+';
+
+ /* Lock the password file before updating */
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+ if (fcntl(old_fd, F_SETLK, &lock) < 0)
+ bb_perror_msg("warning: cannot lock '%s'", filename);
+ lock.l_type = F_UNLCK;
+
+ /* Read current password file, write updated /etc/passwd+ */
+ while (1) {
+ char *line = xmalloc_fgets(old_fp);
+ if (!line) break; /* EOF/error */
+ if (strncmp(username, line, user_len) == 0) {
+ /* we have a match with "username:"... */
+ const char *cp = line + user_len;
+ /* now cp -> old passwd, skip it: */
+ cp = strchrnul(cp, ':');
+ /* now cp -> ':' after old passwd or -> "" */
+ fprintf(new_fp, "%s%s%s", username, new_pw, cp);
+ cnt++;
+ } else
+ fputs(line, new_fp);
+ free(line);
+ }
+ fcntl(old_fd, F_SETLK, &lock);
+
+ /* We do want all of them to execute, thus | instead of || */
+ if ((ferror(old_fp) | fflush(new_fp) | fsync(new_fd) | fclose(new_fp))
+ || rename(fnamesfx, filename)
+ ) {
+ /* At least one of those failed */
+ goto unlink_new;
+ }
+ ret = cnt; /* whee, success! */
+
+ unlink_new:
+ if (ret < 0) unlink(fnamesfx);
+
+ close_old_fp:
+ fclose(old_fp);
+
+ free_mem:
+ free(fnamesfx);
+ free((char *)filename);
+ free((char *)username);
+ return ret;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/uuencode.c b/cleopatre/busybox-1.11.1-spc300/libbb/uuencode.c
new file mode 100644
index 0000000000..0aedf3387a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/uuencode.c
@@ -0,0 +1,71 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* Conversion table. for base 64 */
+const char bb_uuenc_tbl_base64[65 + 2] ALIGN1 = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+ 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3',
+ '4', '5', '6', '7', '8', '9', '+', '/',
+ '=' /* termination character */,
+ '\n', '\0' /* needed for uudecode.c */
+};
+
+const char bb_uuenc_tbl_std[65] ALIGN1 = {
+ '`', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+ '`' /* termination character */
+};
+
+/*
+ * Encode bytes at S of length LENGTH to uuencode or base64 format and place it
+ * to STORE. STORE will be 0-terminated, and must point to a writable
+ * buffer of at least 1+BASE64_LENGTH(length) bytes.
+ * where BASE64_LENGTH(len) = (4 * ((LENGTH + 2) / 3))
+ */
+void bb_uuencode(char *p, const void *src, int length, const char *tbl)
+{
+ const unsigned char *s = src;
+
+ /* Transform the 3x8 bits to 4x6 bits */
+ while (length > 0) {
+ unsigned s1, s2;
+
+ /* Are s[1], s[2] valid or should be assumed 0? */
+ s1 = s2 = 0;
+ length -= 3; /* can be >=0, -1, -2 */
+ if (length >= -1) {
+ s1 = s[1];
+ if (length >= 0)
+ s2 = s[2];
+ }
+ *p++ = tbl[s[0] >> 2];
+ *p++ = tbl[((s[0] & 3) << 4) + (s1 >> 4)];
+ *p++ = tbl[((s1 & 0xf) << 2) + (s2 >> 6)];
+ *p++ = tbl[s2 & 0x3f];
+ s += 3;
+ }
+ /* Zero-terminate */
+ *p = '\0';
+ /* If length is -2 or -1, pad last char or two */
+ while (length) {
+ *--p = tbl[64];
+ length++;
+ }
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/vdprintf.c b/cleopatre/busybox-1.11.1-spc300/libbb/vdprintf.c
new file mode 100644
index 0000000000..726d56374d
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/vdprintf.c
@@ -0,0 +1,21 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+#if defined(__GLIBC__) && __GLIBC__ < 2
+int vdprintf(int d, const char *format, va_list ap)
+{
+ char buf[BUF_SIZE];
+ int len;
+
+ len = vsnprintf(buf, BUF_SIZE, format, ap);
+ return write(d, buf, len);
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/verror_msg.c b/cleopatre/busybox-1.11.1-spc300/libbb/verror_msg.c
new file mode 100644
index 0000000000..5c6df48d42
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/verror_msg.c
@@ -0,0 +1,127 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include <syslog.h>
+
+smallint logmode = LOGMODE_STDIO;
+const char *msg_eol = "\n";
+
+void bb_verror_msg(const char *s, va_list p, const char* strerr)
+{
+ char *msg;
+ int applet_len, strerr_len, msgeol_len, used;
+
+ if (!logmode)
+ return;
+
+ if (!s) /* nomsg[_and_die] uses NULL fmt */
+ s = ""; /* some libc don't like printf(NULL) */
+
+ used = vasprintf(&msg, s, p);
+ if (used < 0)
+ return;
+
+ /* This is ugly and costs +60 bytes compared to multiple
+ * fprintf's, but is guaranteed to do a single write.
+ * This is needed for e.g. httpd logging, when multiple
+ * children can produce log messages simultaneously. */
+
+ applet_len = strlen(applet_name) + 2; /* "applet: " */
+ strerr_len = strerr ? strlen(strerr) : 0;
+ msgeol_len = strlen(msg_eol);
+ /* +3 is for ": " before strerr and for terminating NUL */
+ msg = xrealloc(msg, applet_len + used + strerr_len + msgeol_len + 3);
+ /* TODO: maybe use writev instead of memmoving? Need full_writev? */
+ memmove(msg + applet_len, msg, used);
+ used += applet_len;
+ strcpy(msg, applet_name);
+ msg[applet_len - 2] = ':';
+ msg[applet_len - 1] = ' ';
+ if (strerr) {
+ if (s[0]) { /* not perror_nomsg? */
+ msg[used++] = ':';
+ msg[used++] = ' ';
+ }
+ strcpy(&msg[used], strerr);
+ used += strerr_len;
+ }
+ strcpy(&msg[used], msg_eol);
+
+ if (logmode & LOGMODE_STDIO) {
+ fflush(stdout);
+ full_write(STDERR_FILENO, msg, used + msgeol_len);
+ }
+ if (logmode & LOGMODE_SYSLOG) {
+ syslog(LOG_ERR, "%s", msg + applet_len);
+ }
+ free(msg);
+}
+
+
+#ifdef VERSION_WITH_WRITEV
+
+/* Code size is approximately the same, but currently it's the only user
+ * of writev in entire bbox. __libc_writev in uclibc is ~50 bytes. */
+
+void bb_verror_msg(const char *s, va_list p, const char* strerr)
+{
+ int strerr_len, msgeol_len;
+ struct iovec iov[3];
+
+#define used (iov[2].iov_len)
+#define msgv (iov[2].iov_base)
+#define msgc ((char*)(iov[2].iov_base))
+#define msgptr (&(iov[2].iov_base))
+
+ if (!logmode)
+ return;
+
+ if (!s) /* nomsg[_and_die] uses NULL fmt */
+ s = ""; /* some libc don't like printf(NULL) */
+
+ /* Prevent "derefing type-punned ptr will break aliasing rules" */
+ used = vasprintf((char**)(void*)msgptr, s, p);
+ if (used < 0)
+ return;
+
+ /* This is ugly and costs +60 bytes compared to multiple
+ * fprintf's, but is guaranteed to do a single write.
+ * This is needed for e.g. httpd logging, when multiple
+ * children can produce log messages simultaneously. */
+
+ strerr_len = strerr ? strlen(strerr) : 0;
+ msgeol_len = strlen(msg_eol);
+ /* +3 is for ": " before strerr and for terminating NUL */
+ msgv = xrealloc(msgv, used + strerr_len + msgeol_len + 3);
+ if (strerr) {
+ msgc[used++] = ':';
+ msgc[used++] = ' ';
+ strcpy(msgc + used, strerr);
+ used += strerr_len;
+ }
+ strcpy(msgc + used, msg_eol);
+ used += msgeol_len;
+
+ if (logmode & LOGMODE_STDIO) {
+ iov[0].iov_base = (char*)applet_name;
+ iov[0].iov_len = strlen(applet_name);
+ iov[1].iov_base = (char*)": ";
+ iov[1].iov_len = 2;
+ /*iov[2].iov_base = msgc;*/
+ /*iov[2].iov_len = used;*/
+ fflush(stdout);
+ writev(2, iov, 3);
+ }
+ if (logmode & LOGMODE_SYSLOG) {
+ syslog(LOG_ERR, "%s", msgc);
+ }
+ free(msgc);
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/vfork_daemon_rexec.c b/cleopatre/busybox-1.11.1-spc300/libbb/vfork_daemon_rexec.c
new file mode 100644
index 0000000000..9624efbb95
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/vfork_daemon_rexec.c
@@ -0,0 +1,292 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Rexec program for system have fork() as vfork() with foreground option
+ *
+ * Copyright (C) Vladimir N. Oleynik <dzo@simtreas.ru>
+ * Copyright (C) 2003 Russ Dill <Russ.Dill@asu.edu>
+ *
+ * daemon() portion taken from uClibc:
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Modified for uClibc by Erik Andersen <andersee@debian.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include <paths.h>
+#include "busybox.h" /* uses applet tables */
+
+/* This does a fork/exec in one call, using vfork(). Returns PID of new child,
+ * -1 for failure. Runs argv[0], searching path if that has no / in it. */
+pid_t spawn(char **argv)
+{
+ /* Compiler should not optimize stores here */
+ volatile int failed;
+ pid_t pid;
+
+// Ain't it a good place to fflush(NULL)?
+
+ /* Be nice to nommu machines. */
+ failed = 0;
+ pid = vfork();
+ if (pid < 0) /* error */
+ return pid;
+ if (!pid) { /* child */
+ /* This macro is ok - it doesn't do NOEXEC/NOFORK tricks */
+ BB_EXECVP(argv[0], argv);
+
+ /* We are (maybe) sharing a stack with blocked parent,
+ * let parent know we failed and then exit to unblock parent
+ * (but don't run atexit() stuff, which would screw up parent.)
+ */
+ failed = errno;
+ _exit(111);
+ }
+ /* parent */
+ /* Unfortunately, this is not reliable: according to standards
+ * vfork() can be equivalent to fork() and we won't see value
+ * of 'failed'.
+ * Interested party can wait on pid and learn exit code.
+ * If 111 - then it (most probably) failed to exec */
+ if (failed) {
+ errno = failed;
+ return -1;
+ }
+ return pid;
+}
+
+/* Die with an error message if we can't spawn a child process. */
+pid_t xspawn(char **argv)
+{
+ pid_t pid = spawn(argv);
+ if (pid < 0)
+ bb_simple_perror_msg_and_die(*argv);
+ return pid;
+}
+
+int safe_waitpid(int pid, int *wstat, int options)
+{
+ int r;
+
+ do
+ r = waitpid(pid, wstat, options);
+ while ((r == -1) && (errno == EINTR));
+ return r;
+}
+
+int wait_any_nohang(int *wstat)
+{
+ return safe_waitpid(-1, wstat, WNOHANG);
+}
+
+// Wait for the specified child PID to exit, returning child's error return.
+int wait4pid(int pid)
+{
+ int status;
+
+ if (pid <= 0) {
+ /*errno = ECHILD; -- wrong. */
+ /* we expect errno to be already set from failed [v]fork/exec */
+ return -1;
+ }
+ if (safe_waitpid(pid, &status, 0) == -1)
+ return -1;
+ if (WIFEXITED(status))
+ return WEXITSTATUS(status);
+ if (WIFSIGNALED(status))
+ return WTERMSIG(status) + 1000;
+ return 0;
+}
+
+#if ENABLE_FEATURE_PREFER_APPLETS
+void save_nofork_data(struct nofork_save_area *save)
+{
+ memcpy(&save->die_jmp, &die_jmp, sizeof(die_jmp));
+ save->applet_name = applet_name;
+ save->xfunc_error_retval = xfunc_error_retval;
+ save->option_mask32 = option_mask32;
+ save->die_sleep = die_sleep;
+ save->saved = 1;
+}
+
+void restore_nofork_data(struct nofork_save_area *save)
+{
+ memcpy(&die_jmp, &save->die_jmp, sizeof(die_jmp));
+ applet_name = save->applet_name;
+ xfunc_error_retval = save->xfunc_error_retval;
+ option_mask32 = save->option_mask32;
+ die_sleep = save->die_sleep;
+}
+
+int run_nofork_applet_prime(struct nofork_save_area *old, int applet_no, char **argv)
+{
+ int rc, argc;
+
+ applet_name = APPLET_NAME(applet_no);
+ xfunc_error_retval = EXIT_FAILURE;
+
+ /* Special flag for xfunc_die(). If xfunc will "die"
+ * in NOFORK applet, xfunc_die() sees negative
+ * die_sleep and longjmp here instead. */
+ die_sleep = -1;
+
+ /* option_mask32 = 0; - not needed */
+
+ argc = 1;
+ while (argv[argc])
+ argc++;
+
+ rc = setjmp(die_jmp);
+ if (!rc) {
+ /* Some callers (xargs)
+ * need argv untouched because they free argv[i]! */
+ char *tmp_argv[argc+1];
+ memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0]));
+ /* Finally we can call NOFORK applet's main() */
+ rc = applet_main[applet_no](argc, tmp_argv);
+
+ /* The whole reason behind nofork_save_area is that <applet>_main
+ * may exit non-locally! For example, in hush Ctrl-Z tries
+ * (modulo bugs) to dynamically create a child (backgrounded task)
+ * if it detects that Ctrl-Z was pressed when a NOFORK was running.
+ * Testcase: interactive "rm -i".
+ * Don't fool yourself into thinking "and <applet>_main() returns
+ * quickly here" and removing "useless" nofork_save_area code. */
+
+ } else { /* xfunc died in NOFORK applet */
+ /* in case they meant to return 0... */
+ if (rc == -2222)
+ rc = 0;
+ }
+
+ /* Restoring globals */
+ restore_nofork_data(old);
+ return rc & 0xff; /* don't confuse people with "exitcodes" >255 */
+}
+
+int run_nofork_applet(int applet_no, char **argv)
+{
+ struct nofork_save_area old;
+
+ /* Saving globals */
+ save_nofork_data(&old);
+ return run_nofork_applet_prime(&old, applet_no, argv);
+}
+#endif /* FEATURE_PREFER_APPLETS */
+
+int spawn_and_wait(char **argv)
+{
+ int rc;
+#if ENABLE_FEATURE_PREFER_APPLETS
+ int a = find_applet_by_name(argv[0]);
+
+ if (a >= 0 && (APPLET_IS_NOFORK(a)
+#if BB_MMU
+ || APPLET_IS_NOEXEC(a) /* NOEXEC trick needs fork() */
+#endif
+ )) {
+#if BB_MMU
+ if (APPLET_IS_NOFORK(a))
+#endif
+ {
+ return run_nofork_applet(a, argv);
+ }
+#if BB_MMU
+ /* MMU only */
+ /* a->noexec is true */
+ rc = fork();
+ if (rc) /* parent or error */
+ return wait4pid(rc);
+ /* child */
+ xfunc_error_retval = EXIT_FAILURE;
+ run_applet_no_and_exit(a, argv);
+#endif
+ }
+#endif /* FEATURE_PREFER_APPLETS */
+ rc = spawn(argv);
+ return wait4pid(rc);
+}
+
+#if !BB_MMU
+void re_exec(char **argv)
+{
+ /* high-order bit of first char in argv[0] is a hidden
+ * "we have (already) re-execed, don't do it again" flag */
+ argv[0][0] |= 0x80;
+ execv(bb_busybox_exec_path, argv);
+ bb_perror_msg_and_die("exec %s", bb_busybox_exec_path);
+}
+
+void forkexit_or_rexec(char **argv)
+{
+ pid_t pid;
+ /* Maybe we are already re-execed and come here again? */
+ if (re_execed)
+ return;
+
+ pid = vfork();
+ if (pid < 0) /* wtf? */
+ bb_perror_msg_and_die("vfork");
+ if (pid) /* parent */
+ exit(EXIT_SUCCESS);
+ /* child - re-exec ourself */
+ re_exec(argv);
+}
+#else
+/* Dance around (void)...*/
+#undef forkexit_or_rexec
+void forkexit_or_rexec(void)
+{
+ pid_t pid;
+ pid = fork();
+ if (pid < 0) /* wtf? */
+ bb_perror_msg_and_die("fork");
+ if (pid) /* parent */
+ exit(EXIT_SUCCESS);
+ /* child */
+}
+#define forkexit_or_rexec(argv) forkexit_or_rexec()
+#endif
+
+/* Due to a #define in libbb.h on MMU systems we actually have 1 argument -
+ * char **argv "vanishes" */
+void bb_daemonize_or_rexec(int flags, char **argv)
+{
+ int fd;
+
+ if (flags & DAEMON_CHDIR_ROOT)
+ xchdir("/");
+
+ if (flags & DAEMON_DEVNULL_STDIO) {
+ close(0);
+ close(1);
+ close(2);
+ }
+
+ fd = xopen(bb_dev_null, O_RDWR);
+
+ while ((unsigned)fd < 2)
+ fd = dup(fd); /* have 0,1,2 open at least to /dev/null */
+
+ if (!(flags & DAEMON_ONLY_SANITIZE)) {
+ forkexit_or_rexec(argv);
+ /* if daemonizing, make sure we detach from stdio & ctty */
+ setsid();
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ }
+ while (fd > 2) {
+ close(fd--);
+ if (!(flags & DAEMON_CLOSE_EXTRA_FDS))
+ return;
+ /* else close everything after fd#2 */
+ }
+}
+
+void bb_sanitize_stdio(void)
+{
+ bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE, NULL);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/warn_ignoring_args.c b/cleopatre/busybox-1.11.1-spc300/libbb/warn_ignoring_args.c
new file mode 100644
index 0000000000..be78a44144
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/warn_ignoring_args.c
@@ -0,0 +1,17 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * warn_ignoring_args implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+void bb_warn_ignoring_args(int n)
+{
+ if (n) {
+ bb_error_msg("ignoring all arguments");
+ }
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/wfopen.c b/cleopatre/busybox-1.11.1-spc300/libbb/wfopen.c
new file mode 100644
index 0000000000..9248874a78
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/wfopen.c
@@ -0,0 +1,20 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+FILE *fopen_or_warn(const char *path, const char *mode)
+{
+ FILE *fp = fopen(path, mode);
+ if (!fp) {
+ bb_simple_perror_msg(path);
+ errno = 0;
+ }
+ return fp;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/wfopen_input.c b/cleopatre/busybox-1.11.1-spc300/libbb/wfopen_input.c
new file mode 100644
index 0000000000..a7c1c32f5e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/wfopen_input.c
@@ -0,0 +1,48 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * wfopen_input implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* A number of applets need to open a file for reading, where the filename
+ * is a command line arg. Since often that arg is '-' (meaning stdin),
+ * we avoid testing everywhere by consolidating things in this routine.
+ */
+
+#include "libbb.h"
+
+FILE *fopen_or_warn_stdin(const char *filename)
+{
+ FILE *fp = stdin;
+
+ if (filename != bb_msg_standard_input
+ && NOT_LONE_DASH(filename)
+ ) {
+ fp = fopen_or_warn(filename, "r");
+ }
+ return fp;
+}
+
+FILE *xfopen_stdin(const char *filename)
+{
+ FILE *fp = fopen_or_warn_stdin(filename);
+ if (fp)
+ return fp;
+ xfunc_die(); /* We already output an error message. */
+}
+
+int open_or_warn_stdin(const char *filename)
+{
+ int fd = STDIN_FILENO;
+
+ if (filename != bb_msg_standard_input
+ && NOT_LONE_DASH(filename)
+ ) {
+ fd = open_or_warn(filename, O_RDONLY);
+ }
+
+ return fd;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/write.c b/cleopatre/busybox-1.11.1-spc300/libbb/write.c
new file mode 100644
index 0000000000..b628b49bb9
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/write.c
@@ -0,0 +1,20 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2008 Bernhard Fischer
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* Open file and write string str to it, close file.
+ * Die on any open or write-error. */
+void xopen_xwrite_close(const char* file, const char* str)
+{
+ int fd = xopen(file, O_WRONLY);
+
+ xwrite(fd, str, strlen(str));
+ close(fd);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/xatonum.c b/cleopatre/busybox-1.11.1-spc300/libbb/xatonum.c
new file mode 100644
index 0000000000..a410ae9bcd
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/xatonum.c
@@ -0,0 +1,70 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * ascii-to-numbers implementations for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+#define type long long
+#define xstrtou(rest) xstrtoull##rest
+#define xstrto(rest) xstrtoll##rest
+#define xatou(rest) xatoull##rest
+#define xato(rest) xatoll##rest
+#define XSTR_UTYPE_MAX ULLONG_MAX
+#define XSTR_TYPE_MAX LLONG_MAX
+#define XSTR_TYPE_MIN LLONG_MIN
+#define XSTR_STRTOU strtoull
+#include "xatonum_template.c"
+
+#if ULONG_MAX != ULLONG_MAX
+#define type long
+#define xstrtou(rest) xstrtoul##rest
+#define xstrto(rest) xstrtol##rest
+#define xatou(rest) xatoul##rest
+#define xato(rest) xatol##rest
+#define XSTR_UTYPE_MAX ULONG_MAX
+#define XSTR_TYPE_MAX LONG_MAX
+#define XSTR_TYPE_MIN LONG_MIN
+#define XSTR_STRTOU strtoul
+#include "xatonum_template.c"
+#endif
+
+#if UINT_MAX != ULONG_MAX
+static ALWAYS_INLINE
+unsigned bb_strtoui(const char *str, char **end, int b)
+{
+ unsigned long v = strtoul(str, end, b);
+ if (v > UINT_MAX) {
+ errno = ERANGE;
+ return UINT_MAX;
+ }
+ return v;
+}
+#define type int
+#define xstrtou(rest) xstrtou##rest
+#define xstrto(rest) xstrtoi##rest
+#define xatou(rest) xatou##rest
+#define xato(rest) xatoi##rest
+#define XSTR_UTYPE_MAX UINT_MAX
+#define XSTR_TYPE_MAX INT_MAX
+#define XSTR_TYPE_MIN INT_MIN
+/* libc has no strtoui, so we need to create/use our own */
+#define XSTR_STRTOU bb_strtoui
+#include "xatonum_template.c"
+#endif
+
+/* A few special cases */
+
+int xatoi_u(const char *numstr)
+{
+ return xatou_range(numstr, 0, INT_MAX);
+}
+
+uint16_t xatou16(const char *numstr)
+{
+ return xatou_range(numstr, 0, 0xffff);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/xatonum_template.c b/cleopatre/busybox-1.11.1-spc300/libbb/xatonum_template.c
new file mode 100644
index 0000000000..9f9dc1102c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/xatonum_template.c
@@ -0,0 +1,187 @@
+/*
+You need to define the following (example):
+
+#define type long
+#define xstrtou(rest) xstrtoul##rest
+#define xstrto(rest) xstrtol##rest
+#define xatou(rest) xatoul##rest
+#define xato(rest) xatol##rest
+#define XSTR_UTYPE_MAX ULONG_MAX
+#define XSTR_TYPE_MAX LONG_MAX
+#define XSTR_TYPE_MIN LONG_MIN
+#define XSTR_STRTOU strtoul
+*/
+
+unsigned type xstrtou(_range_sfx)(const char *numstr, int base,
+ unsigned type lower,
+ unsigned type upper,
+ const struct suffix_mult *suffixes)
+{
+ unsigned type r;
+ int old_errno;
+ char *e;
+
+ /* Disallow '-' and any leading whitespace. Make sure we get the
+ * actual isspace function rather than a macro implementaion. */
+ if (*numstr == '-' || *numstr == '+' || (isspace)(*numstr))
+ goto inval;
+
+ /* Since this is a lib function, we're not allowed to reset errno to 0.
+ * Doing so could break an app that is deferring checking of errno.
+ * So, save the old value so that we can restore it if successful. */
+ old_errno = errno;
+ errno = 0;
+ r = XSTR_STRTOU(numstr, &e, base);
+ /* Do the initial validity check. Note: The standards do not
+ * guarantee that errno is set if no digits were found. So we
+ * must test for this explicitly. */
+ if (errno || numstr == e)
+ goto inval; /* error / no digits / illegal trailing chars */
+
+ errno = old_errno; /* Ok. So restore errno. */
+
+ /* Do optional suffix parsing. Allow 'empty' suffix tables.
+ * Note that we also allow nul suffixes with associated multipliers,
+ * to allow for scaling of the numstr by some default multiplier. */
+ if (suffixes) {
+ while (suffixes->mult) {
+ if (strcmp(suffixes->suffix, e) == 0) {
+ if (XSTR_UTYPE_MAX / suffixes->mult < r)
+ goto range; /* overflow! */
+ r *= suffixes->mult;
+ goto chk_range;
+ }
+ ++suffixes;
+ }
+ }
+
+ /* Note: trailing space is an error.
+ It would be easy enough to allow though if desired. */
+ if (*e)
+ goto inval;
+ chk_range:
+ /* Finally, check for range limits. */
+ if (r >= lower && r <= upper)
+ return r;
+ range:
+ bb_error_msg_and_die("number %s is not in %llu..%llu range",
+ numstr, (unsigned long long)lower,
+ (unsigned long long)upper);
+ inval:
+ bb_error_msg_and_die("invalid number '%s'", numstr);
+}
+
+unsigned type xstrtou(_range)(const char *numstr, int base,
+ unsigned type lower,
+ unsigned type upper)
+{
+ return xstrtou(_range_sfx)(numstr, base, lower, upper, NULL);
+}
+
+unsigned type xstrtou(_sfx)(const char *numstr, int base,
+ const struct suffix_mult *suffixes)
+{
+ return xstrtou(_range_sfx)(numstr, base, 0, XSTR_UTYPE_MAX, suffixes);
+}
+
+unsigned type xstrtou()(const char *numstr, int base)
+{
+ return xstrtou(_range_sfx)(numstr, base, 0, XSTR_UTYPE_MAX, NULL);
+}
+
+unsigned type xatou(_range_sfx)(const char *numstr,
+ unsigned type lower,
+ unsigned type upper,
+ const struct suffix_mult *suffixes)
+{
+ return xstrtou(_range_sfx)(numstr, 10, lower, upper, suffixes);
+}
+
+unsigned type xatou(_range)(const char *numstr,
+ unsigned type lower,
+ unsigned type upper)
+{
+ return xstrtou(_range_sfx)(numstr, 10, lower, upper, NULL);
+}
+
+unsigned type xatou(_sfx)(const char *numstr,
+ const struct suffix_mult *suffixes)
+{
+ return xstrtou(_range_sfx)(numstr, 10, 0, XSTR_UTYPE_MAX, suffixes);
+}
+
+unsigned type xatou()(const char *numstr)
+{
+ return xatou(_sfx)(numstr, NULL);
+}
+
+/* Signed ones */
+
+type xstrto(_range_sfx)(const char *numstr, int base,
+ type lower,
+ type upper,
+ const struct suffix_mult *suffixes)
+{
+ unsigned type u = XSTR_TYPE_MAX;
+ type r;
+ const char *p = numstr;
+
+ /* NB: if you'll decide to disallow '+':
+ * at least renice applet needs to allow it */
+ if (p[0] == '+' || p[0] == '-') {
+ ++p;
+ if (p[0] == '-')
+ ++u; /* = <type>_MIN (01111... + 1 == 10000...) */
+ }
+
+ r = xstrtou(_range_sfx)(p, base, 0, u, suffixes);
+
+ if (*numstr == '-') {
+ r = -r;
+ }
+
+ if (r < lower || r > upper) {
+ bb_error_msg_and_die("number %s is not in %lld..%lld range",
+ numstr, (long long)lower, (long long)upper);
+ }
+
+ return r;
+}
+
+type xstrto(_range)(const char *numstr, int base, type lower, type upper)
+{
+ return xstrto(_range_sfx)(numstr, base, lower, upper, NULL);
+}
+
+type xato(_range_sfx)(const char *numstr,
+ type lower,
+ type upper,
+ const struct suffix_mult *suffixes)
+{
+ return xstrto(_range_sfx)(numstr, 10, lower, upper, suffixes);
+}
+
+type xato(_range)(const char *numstr, type lower, type upper)
+{
+ return xstrto(_range_sfx)(numstr, 10, lower, upper, NULL);
+}
+
+type xato(_sfx)(const char *numstr, const struct suffix_mult *suffixes)
+{
+ return xstrto(_range_sfx)(numstr, 10, XSTR_TYPE_MIN, XSTR_TYPE_MAX, suffixes);
+}
+
+type xato()(const char *numstr)
+{
+ return xstrto(_range_sfx)(numstr, 10, XSTR_TYPE_MIN, XSTR_TYPE_MAX, NULL);
+}
+
+#undef type
+#undef xstrtou
+#undef xstrto
+#undef xatou
+#undef xato
+#undef XSTR_UTYPE_MAX
+#undef XSTR_TYPE_MAX
+#undef XSTR_TYPE_MIN
+#undef XSTR_STRTOU
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/xconnect.c b/cleopatre/busybox-1.11.1-spc300/libbb/xconnect.c
new file mode 100644
index 0000000000..950aee8264
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/xconnect.c
@@ -0,0 +1,386 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Connect to host at port using address resolution from getaddrinfo
+ *
+ */
+
+#include <netinet/in.h>
+#include "libbb.h"
+
+void setsockopt_reuseaddr(int fd)
+{
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &const_int_1, sizeof(const_int_1));
+}
+int setsockopt_broadcast(int fd)
+{
+ return setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &const_int_1, sizeof(const_int_1));
+}
+
+void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen)
+{
+ if (connect(s, s_addr, addrlen) < 0) {
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close(s);
+ if (s_addr->sa_family == AF_INET)
+ bb_perror_msg_and_die("%s (%s)",
+ "cannot connect to remote host",
+ inet_ntoa(((struct sockaddr_in *)s_addr)->sin_addr));
+ bb_perror_msg_and_die("cannot connect to remote host");
+ }
+}
+
+/* Return port number for a service.
+ * If "port" is a number use it as the port.
+ * If "port" is a name it is looked up in /etc/services, if it isnt found return
+ * default_port */
+unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default_port)
+{
+ unsigned port_nr = default_port;
+ if (port) {
+ int old_errno;
+
+ /* Since this is a lib function, we're not allowed to reset errno to 0.
+ * Doing so could break an app that is deferring checking of errno. */
+ old_errno = errno;
+ port_nr = bb_strtou(port, NULL, 10);
+ if (errno || port_nr > 65535) {
+ struct servent *tserv = getservbyname(port, protocol);
+ port_nr = default_port;
+ if (tserv)
+ port_nr = ntohs(tserv->s_port);
+ }
+ errno = old_errno;
+ }
+ return (uint16_t)port_nr;
+}
+
+
+/* "Old" networking API - only IPv4 */
+
+/*
+void bb_lookup_host(struct sockaddr_in *s_in, const char *host)
+{
+ struct hostent *he;
+
+ memset(s_in, 0, sizeof(struct sockaddr_in));
+ s_in->sin_family = AF_INET;
+ he = xgethostbyname(host);
+ memcpy(&(s_in->sin_addr), he->h_addr_list[0], he->h_length);
+}
+
+
+int xconnect_tcp_v4(struct sockaddr_in *s_addr)
+{
+ int s = xsocket(AF_INET, SOCK_STREAM, 0);
+ xconnect(s, (struct sockaddr*) s_addr, sizeof(*s_addr));
+ return s;
+}
+*/
+
+/* "New" networking API */
+
+
+int get_nport(const struct sockaddr *sa)
+{
+#if ENABLE_FEATURE_IPV6
+ if (sa->sa_family == AF_INET6) {
+ return ((struct sockaddr_in6*)sa)->sin6_port;
+ }
+#endif
+ if (sa->sa_family == AF_INET) {
+ return ((struct sockaddr_in*)sa)->sin_port;
+ }
+ /* What? UNIX socket? IPX?? :) */
+ return -1;
+}
+
+void set_nport(len_and_sockaddr *lsa, unsigned port)
+{
+#if ENABLE_FEATURE_IPV6
+ if (lsa->u.sa.sa_family == AF_INET6) {
+ lsa->u.sin6.sin6_port = port;
+ return;
+ }
+#endif
+ if (lsa->u.sa.sa_family == AF_INET) {
+ lsa->u.sin.sin_port = port;
+ return;
+ }
+ /* What? UNIX socket? IPX?? :) */
+}
+
+/* We hijack this constant to mean something else */
+/* It doesn't hurt because we will remove this bit anyway */
+#define DIE_ON_ERROR AI_CANONNAME
+
+/* host: "1.2.3.4[:port]", "www.google.com[:port]"
+ * port: if neither of above specifies port # */
+static len_and_sockaddr* str2sockaddr(
+ const char *host, int port,
+USE_FEATURE_IPV6(sa_family_t af,)
+ int ai_flags)
+{
+ int rc;
+ len_and_sockaddr *r = NULL;
+ struct addrinfo *result = NULL;
+ struct addrinfo *used_res;
+ const char *org_host = host; /* only for error msg */
+ const char *cp;
+ struct addrinfo hint;
+
+ /* Ugly parsing of host:addr */
+ if (ENABLE_FEATURE_IPV6 && host[0] == '[') {
+ /* Even uglier parsing of [xx]:nn */
+ host++;
+ cp = strchr(host, ']');
+ if (!cp || cp[1] != ':') { /* Malformed: must have [xx]:nn */
+ bb_error_msg("bad address '%s'", org_host);
+ if (ai_flags & DIE_ON_ERROR)
+ xfunc_die();
+ return NULL;
+ }
+ } else {
+ cp = strrchr(host, ':');
+ if (ENABLE_FEATURE_IPV6 && cp && strchr(host, ':') != cp) {
+ /* There is more than one ':' (e.g. "::1") */
+ cp = NULL; /* it's not a port spec */
+ }
+ }
+ if (cp) { /* points to ":" or "]:" */
+ int sz = cp - host + 1;
+ host = safe_strncpy(alloca(sz), host, sz);
+ if (ENABLE_FEATURE_IPV6 && *cp != ':')
+ cp++; /* skip ']' */
+ cp++; /* skip ':' */
+ port = bb_strtou(cp, NULL, 10);
+ if (errno || (unsigned)port > 0xffff) {
+ bb_error_msg("bad port spec '%s'", org_host);
+ if (ai_flags & DIE_ON_ERROR)
+ xfunc_die();
+ return NULL;
+ }
+ }
+
+ memset(&hint, 0 , sizeof(hint));
+#if !ENABLE_FEATURE_IPV6
+ hint.ai_family = AF_INET; /* do not try to find IPv6 */
+#else
+ hint.ai_family = af;
+#endif
+ /* Needed. Or else we will get each address thrice (or more)
+ * for each possible socket type (tcp,udp,raw...): */
+ hint.ai_socktype = SOCK_STREAM;
+ hint.ai_flags = ai_flags & ~DIE_ON_ERROR;
+ rc = getaddrinfo(host, NULL, &hint, &result);
+ if (rc || !result) {
+ bb_error_msg("bad address '%s'", org_host);
+ if (ai_flags & DIE_ON_ERROR)
+ xfunc_die();
+ goto ret;
+ }
+ used_res = result;
+#if ENABLE_FEATURE_PREFER_IPV4_ADDRESS
+ while (1) {
+ if (used_res->ai_family == AF_INET)
+ break;
+ used_res = used_res->ai_next;
+ if (!used_res) {
+ used_res = result;
+ break;
+ }
+ }
+#endif
+ r = xmalloc(offsetof(len_and_sockaddr, u.sa) + used_res->ai_addrlen);
+ r->len = used_res->ai_addrlen;
+ memcpy(&r->u.sa, used_res->ai_addr, used_res->ai_addrlen);
+ set_nport(r, htons(port));
+ ret:
+ freeaddrinfo(result);
+ return r;
+}
+#if !ENABLE_FEATURE_IPV6
+#define str2sockaddr(host, port, af, ai_flags) str2sockaddr(host, port, ai_flags)
+#endif
+
+#if ENABLE_FEATURE_IPV6
+len_and_sockaddr* host_and_af2sockaddr(const char *host, int port, sa_family_t af)
+{
+ return str2sockaddr(host, port, af, 0);
+}
+
+len_and_sockaddr* xhost_and_af2sockaddr(const char *host, int port, sa_family_t af)
+{
+ return str2sockaddr(host, port, af, DIE_ON_ERROR);
+}
+#endif
+
+len_and_sockaddr* host2sockaddr(const char *host, int port)
+{
+ return str2sockaddr(host, port, AF_UNSPEC, 0);
+}
+
+len_and_sockaddr* xhost2sockaddr(const char *host, int port)
+{
+ return str2sockaddr(host, port, AF_UNSPEC, DIE_ON_ERROR);
+}
+
+len_and_sockaddr* xdotted2sockaddr(const char *host, int port)
+{
+ return str2sockaddr(host, port, AF_UNSPEC, AI_NUMERICHOST | DIE_ON_ERROR);
+}
+
+#undef xsocket_type
+int xsocket_type(len_and_sockaddr **lsap, USE_FEATURE_IPV6(int family,) int sock_type)
+{
+ SKIP_FEATURE_IPV6(enum { family = AF_INET };)
+ len_and_sockaddr *lsa;
+ int fd;
+ int len;
+
+#if ENABLE_FEATURE_IPV6
+ if (family == AF_UNSPEC) {
+ fd = socket(AF_INET6, sock_type, 0);
+ if (fd >= 0) {
+ family = AF_INET6;
+ goto done;
+ }
+ family = AF_INET;
+ }
+#endif
+ fd = xsocket(family, sock_type, 0);
+ len = sizeof(struct sockaddr_in);
+#if ENABLE_FEATURE_IPV6
+ if (family == AF_INET6) {
+ done:
+ len = sizeof(struct sockaddr_in6);
+ }
+#endif
+ lsa = xzalloc(offsetof(len_and_sockaddr, u.sa) + len);
+ lsa->len = len;
+ lsa->u.sa.sa_family = family;
+ *lsap = lsa;
+ return fd;
+}
+
+int xsocket_stream(len_and_sockaddr **lsap)
+{
+ return xsocket_type(lsap, USE_FEATURE_IPV6(AF_UNSPEC,) SOCK_STREAM);
+}
+
+static int create_and_bind_or_die(const char *bindaddr, int port, int sock_type)
+{
+ int fd;
+ len_and_sockaddr *lsa;
+
+ if (bindaddr && bindaddr[0]) {
+ lsa = xdotted2sockaddr(bindaddr, port);
+ /* user specified bind addr dictates family */
+ fd = xsocket(lsa->u.sa.sa_family, sock_type, 0);
+ } else {
+ fd = xsocket_type(&lsa, USE_FEATURE_IPV6(AF_UNSPEC,) sock_type);
+ set_nport(lsa, htons(port));
+ }
+ setsockopt_reuseaddr(fd);
+ xbind(fd, &lsa->u.sa, lsa->len);
+ free(lsa);
+ return fd;
+}
+
+int create_and_bind_stream_or_die(const char *bindaddr, int port)
+{
+ return create_and_bind_or_die(bindaddr, port, SOCK_STREAM);
+}
+
+int create_and_bind_dgram_or_die(const char *bindaddr, int port)
+{
+ return create_and_bind_or_die(bindaddr, port, SOCK_DGRAM);
+}
+
+
+int create_and_connect_stream_or_die(const char *peer, int port)
+{
+ int fd;
+ len_and_sockaddr *lsa;
+
+ lsa = xhost2sockaddr(peer, port);
+ fd = xsocket(lsa->u.sa.sa_family, SOCK_STREAM, 0);
+ setsockopt_reuseaddr(fd);
+ xconnect(fd, &lsa->u.sa, lsa->len);
+ free(lsa);
+ return fd;
+}
+
+int xconnect_stream(const len_and_sockaddr *lsa)
+{
+ int fd = xsocket(lsa->u.sa.sa_family, SOCK_STREAM, 0);
+ xconnect(fd, &lsa->u.sa, lsa->len);
+ return fd;
+}
+
+/* We hijack this constant to mean something else */
+/* It doesn't hurt because we will add this bit anyway */
+#define IGNORE_PORT NI_NUMERICSERV
+static char* sockaddr2str(const struct sockaddr *sa, int flags)
+{
+ char host[128];
+ char serv[16];
+ int rc;
+ socklen_t salen;
+
+ salen = LSA_SIZEOF_SA;
+#if ENABLE_FEATURE_IPV6
+ if (sa->sa_family == AF_INET)
+ salen = sizeof(struct sockaddr_in);
+ if (sa->sa_family == AF_INET6)
+ salen = sizeof(struct sockaddr_in6);
+#endif
+ rc = getnameinfo(sa, salen,
+ host, sizeof(host),
+ /* can do ((flags & IGNORE_PORT) ? NULL : serv) but why bother? */
+ serv, sizeof(serv),
+ /* do not resolve port# into service _name_ */
+ flags | NI_NUMERICSERV
+ );
+ if (rc)
+ return NULL;
+ if (flags & IGNORE_PORT)
+ return xstrdup(host);
+#if ENABLE_FEATURE_IPV6
+ if (sa->sa_family == AF_INET6) {
+ if (strchr(host, ':')) /* heh, it's not a resolved hostname */
+ return xasprintf("[%s]:%s", host, serv);
+ /*return xasprintf("%s:%s", host, serv);*/
+ /* - fall through instead */
+ }
+#endif
+ /* For now we don't support anything else, so it has to be INET */
+ /*if (sa->sa_family == AF_INET)*/
+ return xasprintf("%s:%s", host, serv);
+ /*return xstrdup(host);*/
+}
+
+char* xmalloc_sockaddr2host(const struct sockaddr *sa)
+{
+ return sockaddr2str(sa, 0);
+}
+
+char* xmalloc_sockaddr2host_noport(const struct sockaddr *sa)
+{
+ return sockaddr2str(sa, IGNORE_PORT);
+}
+
+char* xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa)
+{
+ return sockaddr2str(sa, NI_NAMEREQD | IGNORE_PORT);
+}
+char* xmalloc_sockaddr2dotted(const struct sockaddr *sa)
+{
+ return sockaddr2str(sa, NI_NUMERICHOST);
+}
+
+char* xmalloc_sockaddr2dotted_noport(const struct sockaddr *sa)
+{
+ return sockaddr2str(sa, NI_NUMERICHOST | IGNORE_PORT);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/xfunc_die.c b/cleopatre/busybox-1.11.1-spc300/libbb/xfunc_die.c
new file mode 100644
index 0000000000..357494d34e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/xfunc_die.c
@@ -0,0 +1,40 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2008 by Denys Vlasenko <vda.linux@googlemail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+/* Keeping it separate allows to NOT suck in stdio for VERY small applets.
+ * Try building busybox with only "true" enabled... */
+
+#include "libbb.h"
+
+int die_sleep;
+#if ENABLE_FEATURE_PREFER_APPLETS || ENABLE_HUSH
+jmp_buf die_jmp;
+#endif
+
+void xfunc_die(void)
+{
+ if (die_sleep) {
+ if ((ENABLE_FEATURE_PREFER_APPLETS || ENABLE_HUSH)
+ && die_sleep < 0
+ ) {
+ /* Special case. We arrive here if NOFORK applet
+ * calls xfunc, which then decides to die.
+ * We don't die, but jump instead back to caller.
+ * NOFORK applets still cannot carelessly call xfuncs:
+ * p = xmalloc(10);
+ * q = xmalloc(10); // BUG! if this dies, we leak p!
+ */
+ /* -2222 means "zero" (longjmp can't pass 0)
+ * run_nofork_applet() catches -2222. */
+ longjmp(die_jmp, xfunc_error_retval ? xfunc_error_retval : -2222);
+ }
+ sleep(die_sleep);
+ }
+ exit(xfunc_error_retval);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/xfuncs.c b/cleopatre/busybox-1.11.1-spc300/libbb/xfuncs.c
new file mode 100644
index 0000000000..fe3c647d05
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/xfuncs.c
@@ -0,0 +1,291 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2006 Rob Landley
+ * Copyright (C) 2006 Denys Vlasenko
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+
+/* We need to have separate xfuncs.c and xfuncs_printf.c because
+ * with current linkers, even with section garbage collection,
+ * if *.o module references any of XXXprintf functions, you pull in
+ * entire printf machinery. Even if you do not use the function
+ * which uses XXXprintf.
+ *
+ * xfuncs.c contains functions (not necessarily xfuncs)
+ * which do not pull in printf, directly or indirectly.
+ * xfunc_printf.c contains those which do.
+ *
+ * TODO: move xmalloc() and xatonum() here.
+ */
+
+#include "libbb.h"
+
+/* Turn on nonblocking I/O on a fd */
+int ndelay_on(int fd)
+{
+ return fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) | O_NONBLOCK);
+}
+
+int ndelay_off(int fd)
+{
+ return fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) & ~O_NONBLOCK);
+}
+
+int close_on_exec_on(int fd)
+{
+ return fcntl(fd, F_SETFD, FD_CLOEXEC);
+}
+
+/* Convert unsigned long long value into compact 4-char
+ * representation. Examples: "1234", "1.2k", " 27M", "123T"
+ * String is not terminated (buf[4] is untouched) */
+void smart_ulltoa4(unsigned long long ul, char buf[5], const char *scale)
+{
+ const char *fmt;
+ char c;
+ unsigned v, u, idx = 0;
+
+ if (ul > 9999) { // do not scale if 9999 or less
+ ul *= 10;
+ do {
+ ul /= 1024;
+ idx++;
+ } while (ul >= 10000);
+ }
+ v = ul; // ullong divisions are expensive, avoid them
+
+ fmt = " 123456789";
+ u = v / 10;
+ v = v % 10;
+ if (!idx) {
+ // 9999 or less: use "1234" format
+ // u is value/10, v is last digit
+ c = buf[0] = " 123456789"[u/100];
+ if (c != ' ') fmt = "0123456789";
+ c = buf[1] = fmt[u/10%10];
+ if (c != ' ') fmt = "0123456789";
+ buf[2] = fmt[u%10];
+ buf[3] = "0123456789"[v];
+ } else {
+ // u is value, v is 1/10ths (allows for 9.2M format)
+ if (u >= 10) {
+ // value is >= 10: use "123M', " 12M" formats
+ c = buf[0] = " 123456789"[u/100];
+ if (c != ' ') fmt = "0123456789";
+ v = u % 10;
+ u = u / 10;
+ buf[1] = fmt[u%10];
+ } else {
+ // value is < 10: use "9.2M" format
+ buf[0] = "0123456789"[u];
+ buf[1] = '.';
+ }
+ buf[2] = "0123456789"[v];
+ buf[3] = scale[idx]; /* typically scale = " kmgt..." */
+ }
+}
+
+/* Convert unsigned long long value into compact 5-char representation.
+ * String is not terminated (buf[5] is untouched) */
+void smart_ulltoa5(unsigned long long ul, char buf[6], const char *scale)
+{
+ const char *fmt;
+ char c;
+ unsigned v, u, idx = 0;
+
+ if (ul > 99999) { // do not scale if 99999 or less
+ ul *= 10;
+ do {
+ ul /= 1024;
+ idx++;
+ } while (ul >= 100000);
+ }
+ v = ul; // ullong divisions are expensive, avoid them
+
+ fmt = " 123456789";
+ u = v / 10;
+ v = v % 10;
+ if (!idx) {
+ // 99999 or less: use "12345" format
+ // u is value/10, v is last digit
+ c = buf[0] = " 123456789"[u/1000];
+ if (c != ' ') fmt = "0123456789";
+ c = buf[1] = fmt[u/100%10];
+ if (c != ' ') fmt = "0123456789";
+ c = buf[2] = fmt[u/10%10];
+ if (c != ' ') fmt = "0123456789";
+ buf[3] = fmt[u%10];
+ buf[4] = "0123456789"[v];
+ } else {
+ // value has been scaled into 0..9999.9 range
+ // u is value, v is 1/10ths (allows for 92.1M format)
+ if (u >= 100) {
+ // value is >= 100: use "1234M', " 123M" formats
+ c = buf[0] = " 123456789"[u/1000];
+ if (c != ' ') fmt = "0123456789";
+ c = buf[1] = fmt[u/100%10];
+ if (c != ' ') fmt = "0123456789";
+ v = u % 10;
+ u = u / 10;
+ buf[2] = fmt[u%10];
+ } else {
+ // value is < 100: use "92.1M" format
+ c = buf[0] = " 123456789"[u/10];
+ if (c != ' ') fmt = "0123456789";
+ buf[1] = fmt[u%10];
+ buf[2] = '.';
+ }
+ buf[3] = "0123456789"[v];
+ buf[4] = scale[idx]; /* typically scale = " kmgt..." */
+ }
+}
+
+
+// Convert unsigned integer to ascii, writing into supplied buffer.
+// A truncated result contains the first few digits of the result ala strncpy.
+// Returns a pointer past last generated digit, does _not_ store NUL.
+void BUG_sizeof_unsigned_not_4(void);
+char *utoa_to_buf(unsigned n, char *buf, unsigned buflen)
+{
+ unsigned i, out, res;
+ if (sizeof(unsigned) != 4)
+ BUG_sizeof_unsigned_not_4();
+ if (buflen) {
+ out = 0;
+ for (i = 1000000000; i; i /= 10) {
+ res = n / i;
+ if (res || out || i == 1) {
+ if (!--buflen) break;
+ out++;
+ n -= res*i;
+ *buf++ = '0' + res;
+ }
+ }
+ }
+ return buf;
+}
+
+/* Convert signed integer to ascii, like utoa_to_buf() */
+char *itoa_to_buf(int n, char *buf, unsigned buflen)
+{
+ if (buflen && n < 0) {
+ n = -n;
+ *buf++ = '-';
+ buflen--;
+ }
+ return utoa_to_buf((unsigned)n, buf, buflen);
+}
+
+// The following two functions use a static buffer, so calling either one a
+// second time will overwrite previous results.
+//
+// The largest 32 bit integer is -2 billion plus null terminator, or 12 bytes.
+// It so happens that sizeof(int) * 3 is enough for 32+ bits.
+// (sizeof(int) * 3 + 2 is correct for any width, even 8-bit)
+
+static char local_buf[sizeof(int) * 3];
+
+// Convert unsigned integer to ascii using a static buffer (returned).
+char *utoa(unsigned n)
+{
+ *(utoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0';
+
+ return local_buf;
+}
+
+/* Convert signed integer to ascii using a static buffer (returned). */
+char *itoa(int n)
+{
+ *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0';
+
+ return local_buf;
+}
+
+/* Emit a string of hex representation of bytes */
+char *bin2hex(char *p, const char *cp, int count)
+{
+ while (count) {
+ unsigned char c = *cp++;
+ /* put lowercase hex digits */
+ *p++ = 0x20 | bb_hexdigits_upcase[c >> 4];
+ *p++ = 0x20 | bb_hexdigits_upcase[c & 0xf];
+ count--;
+ }
+ return p;
+}
+
+/* Return how long the file at fd is, if there's any way to determine it. */
+#ifdef UNUSED
+off_t fdlength(int fd)
+{
+ off_t bottom = 0, top = 0, pos;
+ long size;
+
+ // If the ioctl works for this, return it.
+
+ if (ioctl(fd, BLKGETSIZE, &size) >= 0) return size*512;
+
+ // FIXME: explain why lseek(SEEK_END) is not used here!
+
+ // If not, do a binary search for the last location we can read. (Some
+ // block devices don't do BLKGETSIZE right.)
+
+ do {
+ char temp;
+
+ pos = bottom + (top - bottom) / 2;
+
+ // If we can read from the current location, it's bigger.
+
+ if (lseek(fd, pos, SEEK_SET)>=0 && safe_read(fd, &temp, 1)==1) {
+ if (bottom == top) bottom = top = (top+1) * 2;
+ else bottom = pos;
+
+ // If we can't, it's smaller.
+
+ } else {
+ if (bottom == top) {
+ if (!top) return 0;
+ bottom = top/2;
+ }
+ else top = pos;
+ }
+ } while (bottom + 1 != top);
+
+ return pos + 1;
+}
+#endif
+
+/* It is perfectly ok to pass in a NULL for either width or for
+ * height, in which case that value will not be set. */
+int get_terminal_width_height(int fd, unsigned *width, unsigned *height)
+{
+ struct winsize win = { 0, 0, 0, 0 };
+ int ret = ioctl(fd, TIOCGWINSZ, &win);
+
+ if (height) {
+ if (!win.ws_row) {
+ char *s = getenv("LINES");
+ if (s) win.ws_row = atoi(s);
+ }
+ if (win.ws_row <= 1 || win.ws_row >= 30000)
+ win.ws_row = 24;
+ *height = (int) win.ws_row;
+ }
+
+ if (width) {
+ if (!win.ws_col) {
+ char *s = getenv("COLUMNS");
+ if (s) win.ws_col = atoi(s);
+ }
+ if (win.ws_col <= 1 || win.ws_col >= 30000)
+ win.ws_col = 80;
+ *width = (int) win.ws_col;
+ }
+
+ return ret;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/xfuncs_printf.c b/cleopatre/busybox-1.11.1-spc300/libbb/xfuncs_printf.c
new file mode 100644
index 0000000000..105939b5ef
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/xfuncs_printf.c
@@ -0,0 +1,521 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2006 Rob Landley
+ * Copyright (C) 2006 Denys Vlasenko
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+
+/* We need to have separate xfuncs.c and xfuncs_printf.c because
+ * with current linkers, even with section garbage collection,
+ * if *.o module references any of XXXprintf functions, you pull in
+ * entire printf machinery. Even if you do not use the function
+ * which uses XXXprintf.
+ *
+ * xfuncs.c contains functions (not necessarily xfuncs)
+ * which do not pull in printf, directly or indirectly.
+ * xfunc_printf.c contains those which do.
+ */
+
+#include "libbb.h"
+
+
+/* All the functions starting with "x" call bb_error_msg_and_die() if they
+ * fail, so callers never need to check for errors. If it returned, it
+ * succeeded. */
+
+#ifndef DMALLOC
+/* dmalloc provides variants of these that do abort() on failure.
+ * Since dmalloc's prototypes overwrite the impls here as they are
+ * included after these prototypes in libbb.h, all is well.
+ */
+// Warn if we can't allocate size bytes of memory.
+void *malloc_or_warn(size_t size)
+{
+ void *ptr = malloc(size);
+ if (ptr == NULL && size != 0)
+ bb_error_msg(bb_msg_memory_exhausted);
+ return ptr;
+}
+
+// Die if we can't allocate size bytes of memory.
+void *xmalloc(size_t size)
+{
+ void *ptr = malloc(size);
+ if (ptr == NULL && size != 0)
+ bb_error_msg_and_die(bb_msg_memory_exhausted);
+ return ptr;
+}
+
+// Die if we can't resize previously allocated memory. (This returns a pointer
+// to the new memory, which may or may not be the same as the old memory.
+// It'll copy the contents to a new chunk and free the old one if necessary.)
+void *xrealloc(void *ptr, size_t size)
+{
+ ptr = realloc(ptr, size);
+ if (ptr == NULL && size != 0)
+ bb_error_msg_and_die(bb_msg_memory_exhausted);
+ return ptr;
+}
+#endif /* DMALLOC */
+
+// Die if we can't allocate and zero size bytes of memory.
+void *xzalloc(size_t size)
+{
+ void *ptr = xmalloc(size);
+ memset(ptr, 0, size);
+ return ptr;
+}
+
+// Die if we can't copy a string to freshly allocated memory.
+char * xstrdup(const char *s)
+{
+ char *t;
+
+ if (s == NULL)
+ return NULL;
+
+ t = strdup(s);
+
+ if (t == NULL)
+ bb_error_msg_and_die(bb_msg_memory_exhausted);
+
+ return t;
+}
+
+// Die if we can't allocate n+1 bytes (space for the null terminator) and copy
+// the (possibly truncated to length n) string into it.
+char *xstrndup(const char *s, int n)
+{
+ int m;
+ char *t;
+
+ if (ENABLE_DEBUG && s == NULL)
+ bb_error_msg_and_die("xstrndup bug");
+
+ /* We can just xmalloc(n+1) and strncpy into it, */
+ /* but think about xstrndup("abc", 10000) wastage! */
+ m = n;
+ t = (char*) s;
+ while (m) {
+ if (!*t) break;
+ m--;
+ t++;
+ }
+ n -= m;
+ t = xmalloc(n + 1);
+ t[n] = '\0';
+
+ return memcpy(t, s, n);
+}
+
+// Die if we can't open a file and return a FILE * to it.
+// Notice we haven't got xfread(), This is for use with fscanf() and friends.
+FILE *xfopen(const char *path, const char *mode)
+{
+ FILE *fp = fopen(path, mode);
+ if (fp == NULL)
+ bb_perror_msg_and_die("can't open '%s'", path);
+ return fp;
+}
+
+// Die if we can't open a file and return a fd.
+int xopen3(const char *pathname, int flags, int mode)
+{
+ int ret;
+
+ ret = open(pathname, flags, mode);
+ if (ret < 0) {
+ bb_perror_msg_and_die("can't open '%s'", pathname);
+ }
+ return ret;
+}
+
+// Die if we can't open an existing file and return a fd.
+int xopen(const char *pathname, int flags)
+{
+ return xopen3(pathname, flags, 0666);
+}
+
+// Warn if we can't open a file and return a fd.
+int open3_or_warn(const char *pathname, int flags, int mode)
+{
+ int ret;
+
+ ret = open(pathname, flags, mode);
+ if (ret < 0) {
+ bb_perror_msg("can't open '%s'", pathname);
+ }
+ return ret;
+}
+
+// Warn if we can't open a file and return a fd.
+int open_or_warn(const char *pathname, int flags)
+{
+ return open3_or_warn(pathname, flags, 0666);
+}
+
+void xunlink(const char *pathname)
+{
+ if (unlink(pathname))
+ bb_perror_msg_and_die("can't remove file '%s'", pathname);
+}
+
+void xrename(const char *oldpath, const char *newpath)
+{
+ if (rename(oldpath, newpath))
+ bb_perror_msg_and_die("can't move '%s' to '%s'", oldpath, newpath);
+}
+
+int rename_or_warn(const char *oldpath, const char *newpath)
+{
+ int n = rename(oldpath, newpath);
+ if (n)
+ bb_perror_msg("can't move '%s' to '%s'", oldpath, newpath);
+ return n;
+}
+
+void xpipe(int filedes[2])
+{
+ if (pipe(filedes))
+ bb_perror_msg_and_die("can't create pipe");
+}
+
+void xdup2(int from, int to)
+{
+ if (dup2(from, to) != to)
+ bb_perror_msg_and_die("can't duplicate file descriptor");
+}
+
+// "Renumber" opened fd
+void xmove_fd(int from, int to)
+{
+ if (from == to)
+ return;
+ xdup2(from, to);
+ close(from);
+}
+
+// Die with an error message if we can't write the entire buffer.
+void xwrite(int fd, const void *buf, size_t count)
+{
+ if (count) {
+ ssize_t size = full_write(fd, buf, count);
+ if ((size_t)size != count)
+ bb_error_msg_and_die("short write");
+ }
+}
+
+// Die with an error message if we can't lseek to the right spot.
+off_t xlseek(int fd, off_t offset, int whence)
+{
+ off_t off = lseek(fd, offset, whence);
+ if (off == (off_t)-1) {
+ if (whence == SEEK_SET)
+ bb_perror_msg_and_die("lseek(%"OFF_FMT"u)", offset);
+ bb_perror_msg_and_die("lseek");
+ }
+ return off;
+}
+
+// Die with supplied filename if this FILE * has ferror set.
+void die_if_ferror(FILE *fp, const char *fn)
+{
+ if (ferror(fp)) {
+ /* ferror doesn't set useful errno */
+ bb_error_msg_and_die("%s: I/O error", fn);
+ }
+}
+
+// Die with an error message if stdout has ferror set.
+void die_if_ferror_stdout(void)
+{
+ die_if_ferror(stdout, bb_msg_standard_output);
+}
+
+// Die with an error message if we have trouble flushing stdout.
+void xfflush_stdout(void)
+{
+ if (fflush(stdout)) {
+ bb_perror_msg_and_die(bb_msg_standard_output);
+ }
+}
+
+
+int bb_putchar(int ch)
+{
+ /* time.c needs putc(ch, stdout), not putchar(ch).
+ * it does "stdout = stderr;", but then glibc's putchar()
+ * doesn't work as expected. bad glibc, bad */
+ return putc(ch, stdout);
+}
+
+/* Die with an error message if we can't copy an entire FILE * to stdout,
+ * then close that file. */
+void xprint_and_close_file(FILE *file)
+{
+ fflush(stdout);
+ // copyfd outputs error messages for us.
+ if (bb_copyfd_eof(fileno(file), 1) == -1)
+ xfunc_die();
+
+ fclose(file);
+}
+
+// Die with an error message if we can't malloc() enough space and do an
+// sprintf() into that space.
+char *xasprintf(const char *format, ...)
+{
+ va_list p;
+ int r;
+ char *string_ptr;
+
+#if 1
+ // GNU extension
+ va_start(p, format);
+ r = vasprintf(&string_ptr, format, p);
+ va_end(p);
+#else
+ // Bloat for systems that haven't got the GNU extension.
+ va_start(p, format);
+ r = vsnprintf(NULL, 0, format, p);
+ va_end(p);
+ string_ptr = xmalloc(r+1);
+ va_start(p, format);
+ r = vsnprintf(string_ptr, r+1, format, p);
+ va_end(p);
+#endif
+
+ if (r < 0)
+ bb_error_msg_and_die(bb_msg_memory_exhausted);
+ return string_ptr;
+}
+
+#if 0 /* If we will ever meet a libc which hasn't [f]dprintf... */
+int fdprintf(int fd, const char *format, ...)
+{
+ va_list p;
+ int r;
+ char *string_ptr;
+
+#if 1
+ // GNU extension
+ va_start(p, format);
+ r = vasprintf(&string_ptr, format, p);
+ va_end(p);
+#else
+ // Bloat for systems that haven't got the GNU extension.
+ va_start(p, format);
+ r = vsnprintf(NULL, 0, format, p) + 1;
+ va_end(p);
+ string_ptr = malloc(r);
+ if (string_ptr) {
+ va_start(p, format);
+ r = vsnprintf(string_ptr, r, format, p);
+ va_end(p);
+ }
+#endif
+
+ if (r >= 0) {
+ full_write(fd, string_ptr, r);
+ free(string_ptr);
+ }
+ return r;
+}
+#endif
+
+void xsetenv(const char *key, const char *value)
+{
+ if (setenv(key, value, 1))
+ bb_error_msg_and_die(bb_msg_memory_exhausted);
+}
+
+// Die with an error message if we can't set gid. (Because resource limits may
+// limit this user to a given number of processes, and if that fills up the
+// setgid() will fail and we'll _still_be_root_, which is bad.)
+void xsetgid(gid_t gid)
+{
+ if (setgid(gid)) bb_perror_msg_and_die("setgid");
+}
+
+// Die with an error message if we can't set uid. (See xsetgid() for why.)
+void xsetuid(uid_t uid)
+{
+ if (setuid(uid)) bb_perror_msg_and_die("setuid");
+}
+
+// Die if we can't chdir to a new path.
+void xchdir(const char *path)
+{
+ if (chdir(path))
+ bb_perror_msg_and_die("chdir(%s)", path);
+}
+
+void xchroot(const char *path)
+{
+ if (chroot(path))
+ bb_perror_msg_and_die("can't change root directory to %s", path);
+}
+
+// Print a warning message if opendir() fails, but don't die.
+DIR *warn_opendir(const char *path)
+{
+ DIR *dp;
+
+ dp = opendir(path);
+ if (!dp)
+ bb_perror_msg("can't open '%s'", path);
+ return dp;
+}
+
+// Die with an error message if opendir() fails.
+DIR *xopendir(const char *path)
+{
+ DIR *dp;
+
+ dp = opendir(path);
+ if (!dp)
+ bb_perror_msg_and_die("can't open '%s'", path);
+ return dp;
+}
+
+// Die with an error message if we can't open a new socket.
+int xsocket(int domain, int type, int protocol)
+{
+ int r = socket(domain, type, protocol);
+
+ if (r < 0) {
+ /* Hijack vaguely related config option */
+#if ENABLE_VERBOSE_RESOLUTION_ERRORS
+ const char *s = "INET";
+ if (domain == AF_PACKET) s = "PACKET";
+ if (domain == AF_NETLINK) s = "NETLINK";
+USE_FEATURE_IPV6(if (domain == AF_INET6) s = "INET6";)
+ bb_perror_msg_and_die("socket(AF_%s)", s);
+#else
+ bb_perror_msg_and_die("socket");
+#endif
+ }
+
+ return r;
+}
+
+// Die with an error message if we can't bind a socket to an address.
+void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen)
+{
+ if (bind(sockfd, my_addr, addrlen)) bb_perror_msg_and_die("bind");
+}
+
+// Die with an error message if we can't listen for connections on a socket.
+void xlisten(int s, int backlog)
+{
+ if (listen(s, backlog)) bb_perror_msg_and_die("listen");
+}
+
+/* Die with an error message if sendto failed.
+ * Return bytes sent otherwise */
+ssize_t xsendto(int s, const void *buf, size_t len, const struct sockaddr *to,
+ socklen_t tolen)
+{
+ ssize_t ret = sendto(s, buf, len, 0, to, tolen);
+ if (ret < 0) {
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close(s);
+ bb_perror_msg_and_die("sendto");
+ }
+ return ret;
+}
+
+// xstat() - a stat() which dies on failure with meaningful error message
+void xstat(const char *name, struct stat *stat_buf)
+{
+ if (stat(name, stat_buf))
+ bb_perror_msg_and_die("can't stat '%s'", name);
+}
+
+// selinux_or_die() - die if SELinux is disabled.
+void selinux_or_die(void)
+{
+#if ENABLE_SELINUX
+ int rc = is_selinux_enabled();
+ if (rc == 0) {
+ bb_error_msg_and_die("SELinux is disabled");
+ } else if (rc < 0) {
+ bb_error_msg_and_die("is_selinux_enabled() failed");
+ }
+#else
+ bb_error_msg_and_die("SELinux support is disabled");
+#endif
+}
+
+int ioctl_or_perror_and_die(int fd, unsigned request, void *argp, const char *fmt,...)
+{
+ int ret;
+ va_list p;
+
+ ret = ioctl(fd, request, argp);
+ if (ret < 0) {
+ va_start(p, fmt);
+ bb_verror_msg(fmt, p, strerror(errno));
+ /* xfunc_die can actually longjmp, so be nice */
+ va_end(p);
+ xfunc_die();
+ }
+ return ret;
+}
+
+int ioctl_or_perror(int fd, unsigned request, void *argp, const char *fmt,...)
+{
+ va_list p;
+ int ret = ioctl(fd, request, argp);
+
+ if (ret < 0) {
+ va_start(p, fmt);
+ bb_verror_msg(fmt, p, strerror(errno));
+ va_end(p);
+ }
+ return ret;
+}
+
+#if ENABLE_IOCTL_HEX2STR_ERROR
+int bb_ioctl_or_warn(int fd, unsigned request, void *argp, const char *ioctl_name)
+{
+ int ret;
+
+ ret = ioctl(fd, request, argp);
+ if (ret < 0)
+ bb_simple_perror_msg(ioctl_name);
+ return ret;
+}
+int bb_xioctl(int fd, unsigned request, void *argp, const char *ioctl_name)
+{
+ int ret;
+
+ ret = ioctl(fd, request, argp);
+ if (ret < 0)
+ bb_simple_perror_msg_and_die(ioctl_name);
+ return ret;
+}
+#else
+int bb_ioctl_or_warn(int fd, unsigned request, void *argp)
+{
+ int ret;
+
+ ret = ioctl(fd, request, argp);
+ if (ret < 0)
+ bb_perror_msg("ioctl %#x failed", request);
+ return ret;
+}
+int bb_xioctl(int fd, unsigned request, void *argp)
+{
+ int ret;
+
+ ret = ioctl(fd, request, argp);
+ if (ret < 0)
+ bb_perror_msg_and_die("ioctl %#x failed", request);
+ return ret;
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/xgetcwd.c b/cleopatre/busybox-1.11.1-spc300/libbb/xgetcwd.c
new file mode 100644
index 0000000000..c194e23037
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/xgetcwd.c
@@ -0,0 +1,41 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * xgetcwd.c -- return current directory with unlimited length
+ * Copyright (C) 1992, 1996 Free Software Foundation, Inc.
+ * Written by David MacKenzie <djm@gnu.ai.mit.edu>.
+ *
+ * Special function for busybox written by Vladimir Oleynik <dzo@simtreas.ru>
+*/
+
+#include "libbb.h"
+
+/* Return the current directory, newly allocated, arbitrarily long.
+ Return NULL and set errno on error.
+ If argument is not NULL (previous usage allocate memory), call free()
+*/
+
+char *
+xrealloc_getcwd_or_warn(char *cwd)
+{
+#define PATH_INCR 64
+
+ char *ret;
+ unsigned path_max;
+
+ path_max = 128; /* 128 + 64 should be enough for 99% of cases */
+
+ while (1) {
+ path_max += PATH_INCR;
+ cwd = xrealloc(cwd, path_max);
+ ret = getcwd(cwd, path_max);
+ if (ret == NULL) {
+ if (errno == ERANGE)
+ continue;
+ free(cwd);
+ bb_perror_msg("getcwd");
+ return NULL;
+ }
+ cwd = xrealloc(cwd, strlen(cwd) + 1);
+ return cwd;
+ }
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/xgethostbyname.c b/cleopatre/busybox-1.11.1-spc300/libbb/xgethostbyname.c
new file mode 100644
index 0000000000..3bb522d804
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/xgethostbyname.c
@@ -0,0 +1,19 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini xgethostbyname implementation.
+ *
+ * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+//#include <netdb.h>
+#include "libbb.h"
+
+struct hostent *xgethostbyname(const char *name)
+{
+ struct hostent *retval = gethostbyname(name);
+ if (!retval)
+ bb_herror_msg_and_die("%s", name);
+ return retval;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/xreadlink.c b/cleopatre/busybox-1.11.1-spc300/libbb/xreadlink.c
new file mode 100644
index 0000000000..0b961b6f90
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/xreadlink.c
@@ -0,0 +1,111 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * xreadlink.c - safe implementation of readlink.
+ * Returns a NULL on failure...
+ */
+
+#include "libbb.h"
+
+/*
+ * NOTE: This function returns a malloced char* that you will have to free
+ * yourself.
+ */
+char *xmalloc_readlink(const char *path)
+{
+ enum { GROWBY = 80 }; /* how large we will grow strings by */
+
+ char *buf = NULL;
+ int bufsize = 0, readsize = 0;
+
+ do {
+ bufsize += GROWBY;
+ buf = xrealloc(buf, bufsize);
+ readsize = readlink(path, buf, bufsize);
+ if (readsize == -1) {
+ free(buf);
+ return NULL;
+ }
+ } while (bufsize < readsize + 1);
+
+ buf[readsize] = '\0';
+
+ return buf;
+}
+
+/*
+ * This routine is not the same as realpath(), which
+ * canonicalizes the given path completely. This routine only
+ * follows trailing symlinks until a real file is reached and
+ * returns its name. If the path ends in a dangling link or if
+ * the target doesn't exist, the path is returned in any case.
+ * Intermediate symlinks in the path are not expanded -- only
+ * those at the tail.
+ * A malloced char* is returned, which must be freed by the caller.
+ */
+char *xmalloc_follow_symlinks(const char *path)
+{
+ char *buf;
+ char *lpc;
+ char *linkpath;
+ int bufsize;
+ int looping = MAXSYMLINKS + 1;
+
+ buf = xstrdup(path);
+ goto jump_in;
+
+ while (1) {
+ linkpath = xmalloc_readlink(buf);
+ if (!linkpath) {
+ /* not a symlink, or doesn't exist */
+ if (errno == EINVAL || errno == ENOENT)
+ return buf;
+ goto free_buf_ret_null;
+ }
+
+ if (!--looping) {
+ free(linkpath);
+ free_buf_ret_null:
+ free(buf);
+ return NULL;
+ }
+
+ if (*linkpath != '/') {
+ bufsize += strlen(linkpath);
+ buf = xrealloc(buf, bufsize);
+ lpc = bb_get_last_path_component_strip(buf);
+ strcpy(lpc, linkpath);
+ free(linkpath);
+ } else {
+ free(buf);
+ buf = linkpath;
+ jump_in:
+ bufsize = strlen(buf) + 1;
+ }
+ }
+}
+
+char *xmalloc_readlink_or_warn(const char *path)
+{
+ char *buf = xmalloc_readlink(path);
+ if (!buf) {
+ /* EINVAL => "file: Invalid argument" => puzzled user */
+ bb_error_msg("%s: cannot read link (not a symlink?)", path);
+ }
+ return buf;
+}
+
+/* UNUSED */
+#if 0
+char *xmalloc_realpath(const char *path)
+{
+#if defined(__GLIBC__) && !defined(__UCLIBC__)
+ /* glibc provides a non-standard extension */
+ return realpath(path, NULL);
+#else
+ char buf[PATH_MAX+1];
+
+ /* on error returns NULL (xstrdup(NULL) ==NULL) */
+ return xstrdup(realpath(path, buf));
+#endif
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/libbb/xregcomp.c b/cleopatre/busybox-1.11.1-spc300/libbb/xregcomp.c
new file mode 100644
index 0000000000..157132c1f8
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libbb/xregcomp.c
@@ -0,0 +1,32 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "xregex.h"
+
+char* regcomp_or_errmsg(regex_t *preg, const char *regex, int cflags)
+{
+ int ret = regcomp(preg, regex, cflags);
+ if (ret) {
+ int errmsgsz = regerror(ret, preg, NULL, 0);
+ char *errmsg = xmalloc(errmsgsz);
+ regerror(ret, preg, errmsg, errmsgsz);
+ return errmsg;
+ }
+ return NULL;
+}
+
+void xregcomp(regex_t *preg, const char *regex, int cflags)
+{
+ char *errmsg = regcomp_or_errmsg(preg, regex, cflags);
+ if (errmsg) {
+ bb_error_msg_and_die("xregcomp: %s", errmsg);
+ }
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libpwdgrp/Kbuild b/cleopatre/busybox-1.11.1-spc300/libpwdgrp/Kbuild
new file mode 100644
index 0000000000..f9f1ddbf3f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libpwdgrp/Kbuild
@@ -0,0 +1,9 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+lib-y := uidgid_get.o
+
+lib-$(CONFIG_USE_BB_PWD_GRP) += pwd_grp.o
diff --git a/cleopatre/busybox-1.11.1-spc300/libpwdgrp/pwd_grp.c b/cleopatre/busybox-1.11.1-spc300/libpwdgrp/pwd_grp.c
new file mode 100644
index 0000000000..3fe70f40c4
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libpwdgrp/pwd_grp.c
@@ -0,0 +1,1059 @@
+/* vi: set sw=4 ts=4: */
+/* Copyright (C) 2003 Manuel Novoa III
+ *
+ * Licensed under GPL v2, or later. See file LICENSE in this tarball.
+ */
+
+/* Nov 6, 2003 Initial version.
+ *
+ * NOTE: This implementation is quite strict about requiring all
+ * field seperators. It also does not allow leading whitespace
+ * except when processing the numeric fields. glibc is more
+ * lenient. See the various glibc difference comments below.
+ *
+ * TODO:
+ * Move to dynamic allocation of (currently statically allocated)
+ * buffers; especially for the group-related functions since
+ * large group member lists will cause error returns.
+ *
+ */
+
+#include "libbb.h"
+#include <features.h>
+#include <assert.h>
+
+#ifndef _PATH_SHADOW
+#define _PATH_SHADOW "/etc/shadow"
+#endif
+#ifndef _PATH_PASSWD
+#define _PATH_PASSWD "/etc/passwd"
+#endif
+#ifndef _PATH_GROUP
+#define _PATH_GROUP "/etc/group"
+#endif
+
+/**********************************************************************/
+/* Sizes for statically allocated buffers. */
+
+/* If you change these values, also change _SC_GETPW_R_SIZE_MAX and
+ * _SC_GETGR_R_SIZE_MAX in libc/unistd/sysconf.c to match */
+#define PWD_BUFFER_SIZE 256
+#define GRP_BUFFER_SIZE 256
+
+/**********************************************************************/
+/* Prototypes for internal functions. */
+
+static int bb__pgsreader(int (*parserfunc)(void *d, char *line), void *data,
+ char *__restrict line_buff, size_t buflen, FILE *f);
+
+static int bb__parsepwent(void *pw, char *line);
+static int bb__parsegrent(void *gr, char *line);
+#if ENABLE_USE_BB_SHADOW
+static int bb__parsespent(void *sp, char *line);
+#endif
+
+/**********************************************************************/
+/* We avoid having big global data. */
+
+struct statics {
+ /* Smaller things first */
+ struct passwd getpwuid_resultbuf;
+ struct group getgrgid_resultbuf;
+ struct passwd getpwnam_resultbuf;
+ struct group getgrnam_resultbuf;
+
+ char getpwuid_buffer[PWD_BUFFER_SIZE];
+ char getgrgid_buffer[GRP_BUFFER_SIZE];
+ char getpwnam_buffer[PWD_BUFFER_SIZE];
+ char getgrnam_buffer[GRP_BUFFER_SIZE];
+#if 0
+ struct passwd fgetpwent_resultbuf;
+ struct group fgetgrent_resultbuf;
+ struct spwd fgetspent_resultbuf;
+ char fgetpwent_buffer[PWD_BUFFER_SIZE];
+ char fgetgrent_buffer[GRP_BUFFER_SIZE];
+ char fgetspent_buffer[PWD_BUFFER_SIZE];
+#endif
+#if 0 //ENABLE_USE_BB_SHADOW
+ struct spwd getspuid_resultbuf;
+ struct spwd getspnam_resultbuf;
+ char getspuid_buffer[PWD_BUFFER_SIZE];
+ char getspnam_buffer[PWD_BUFFER_SIZE];
+#endif
+// Not converted - too small to bother
+//pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
+//FILE *pwf /*= NULL*/;
+//FILE *grf /*= NULL*/;
+//FILE *spf /*= NULL*/;
+#if 0
+ struct passwd getpwent_pwd;
+ struct group getgrent_gr;
+ char getpwent_line_buff[PWD_BUFFER_SIZE];
+ char getgrent_line_buff[GRP_BUFFER_SIZE];
+#endif
+#if 0 //ENABLE_USE_BB_SHADOW
+ struct spwd getspent_spwd;
+ struct spwd sgetspent_spwd;
+ char getspent_line_buff[PWD_BUFFER_SIZE];
+ char sgetspent_line_buff[PWD_BUFFER_SIZE];
+#endif
+};
+
+static struct statics *ptr_to_statics;
+
+static struct statics *get_S(void)
+{
+ if (!ptr_to_statics)
+ ptr_to_statics = xzalloc(sizeof(*ptr_to_statics));
+ return ptr_to_statics;
+}
+
+/* Always use in this order, get_S() must be called first */
+#define RESULTBUF(name) &((S = get_S())->name##_resultbuf)
+#define BUFFER(name) (S->name##_buffer)
+
+/**********************************************************************/
+/* For the various fget??ent_r funcs, return
+ *
+ * 0: success
+ * ENOENT: end-of-file encountered
+ * ERANGE: buflen too small
+ * other error values possible. See bb__pgsreader.
+ *
+ * Also, *result == resultbuf on success and NULL on failure.
+ *
+ * NOTE: glibc difference - For the ENOENT case, glibc also sets errno.
+ * We do not, as it really isn't an error if we reach the end-of-file.
+ * Doing so is analogous to having fgetc() set errno on EOF.
+ */
+/**********************************************************************/
+
+int fgetpwent_r(FILE *__restrict stream, struct passwd *__restrict resultbuf,
+ char *__restrict buffer, size_t buflen,
+ struct passwd **__restrict result)
+{
+ int rv;
+
+ *result = NULL;
+
+ rv = bb__pgsreader(bb__parsepwent, resultbuf, buffer, buflen, stream);
+ if (!rv) {
+ *result = resultbuf;
+ }
+
+ return rv;
+}
+
+int fgetgrent_r(FILE *__restrict stream, struct group *__restrict resultbuf,
+ char *__restrict buffer, size_t buflen,
+ struct group **__restrict result)
+{
+ int rv;
+
+ *result = NULL;
+
+ rv = bb__pgsreader(bb__parsegrent, resultbuf, buffer, buflen, stream);
+ if (!rv) {
+ *result = resultbuf;
+ }
+
+ return rv;
+}
+
+#if ENABLE_USE_BB_SHADOW
+int fgetspent_r(FILE *__restrict stream, struct spwd *__restrict resultbuf,
+ char *__restrict buffer, size_t buflen,
+ struct spwd **__restrict result)
+{
+ int rv;
+
+ *result = NULL;
+
+ rv = bb__pgsreader(bb__parsespent, resultbuf, buffer, buflen, stream);
+ if (!rv) {
+ *result = resultbuf;
+ }
+
+ return rv;
+}
+#endif
+
+/**********************************************************************/
+/* For the various fget??ent funcs, return NULL on failure and a
+ * pointer to the appropriate struct (statically allocated) on success.
+ * TODO: audit & stop using these in bbox, they pull in static buffers */
+/**********************************************************************/
+
+#if 0
+struct passwd *fgetpwent(FILE *stream)
+{
+ struct statics *S;
+ struct passwd *resultbuf = RESULTBUF(fgetpwent);
+ char *buffer = BUFFER(fgetpwent);
+ struct passwd *result;
+
+ fgetpwent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetpwent)), &result);
+ return result;
+}
+
+struct group *fgetgrent(FILE *stream)
+{
+ struct statics *S;
+ struct group *resultbuf = RESULTBUF(fgetgrent);
+ char *buffer = BUFFER(fgetgrent);
+ struct group *result;
+
+ fgetgrent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetgrent)), &result);
+ return result;
+}
+#endif
+
+#if ENABLE_USE_BB_SHADOW
+#if 0
+struct spwd *fgetspent(FILE *stream)
+{
+ struct statics *S;
+ struct spwd *resultbuf = RESULTBUF(fgetspent);
+ char *buffer = BUFFER(fgetspent);
+ struct spwd *result;
+
+ fgetspent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetspent)), &result);
+ return result;
+}
+#endif
+
+int sgetspent_r(const char *string, struct spwd *result_buf,
+ char *buffer, size_t buflen, struct spwd **result)
+{
+ int rv = ERANGE;
+
+ *result = NULL;
+
+ if (buflen < PWD_BUFFER_SIZE) {
+ DO_ERANGE:
+ errno=rv;
+ goto DONE;
+ }
+
+ if (string != buffer) {
+ if (strlen(string) >= buflen) {
+ goto DO_ERANGE;
+ }
+ strcpy(buffer, string);
+ }
+
+ rv = bb__parsespent(result_buf, buffer);
+ if (!rv) {
+ *result = result_buf;
+ }
+
+ DONE:
+ return rv;
+}
+#endif
+
+/**********************************************************************/
+
+#define GETXXKEY_R_FUNC getpwnam_r
+#define GETXXKEY_R_PARSER bb__parsepwent
+#define GETXXKEY_R_ENTTYPE struct passwd
+#define GETXXKEY_R_TEST(ENT) (!strcmp((ENT)->pw_name, key))
+#define GETXXKEY_R_KEYTYPE const char *__restrict
+#define GETXXKEY_R_PATHNAME _PATH_PASSWD
+#include "pwd_grp_internal.c"
+
+#define GETXXKEY_R_FUNC getgrnam_r
+#define GETXXKEY_R_PARSER bb__parsegrent
+#define GETXXKEY_R_ENTTYPE struct group
+#define GETXXKEY_R_TEST(ENT) (!strcmp((ENT)->gr_name, key))
+#define GETXXKEY_R_KEYTYPE const char *__restrict
+#define GETXXKEY_R_PATHNAME _PATH_GROUP
+#include "pwd_grp_internal.c"
+
+#if ENABLE_USE_BB_SHADOW
+#define GETXXKEY_R_FUNC getspnam_r
+#define GETXXKEY_R_PARSER bb__parsespent
+#define GETXXKEY_R_ENTTYPE struct spwd
+#define GETXXKEY_R_TEST(ENT) (!strcmp((ENT)->sp_namp, key))
+#define GETXXKEY_R_KEYTYPE const char *__restrict
+#define GETXXKEY_R_PATHNAME _PATH_SHADOW
+#include "pwd_grp_internal.c"
+#endif
+
+#define GETXXKEY_R_FUNC getpwuid_r
+#define GETXXKEY_R_PARSER bb__parsepwent
+#define GETXXKEY_R_ENTTYPE struct passwd
+#define GETXXKEY_R_TEST(ENT) ((ENT)->pw_uid == key)
+#define GETXXKEY_R_KEYTYPE uid_t
+#define GETXXKEY_R_PATHNAME _PATH_PASSWD
+#include "pwd_grp_internal.c"
+
+#define GETXXKEY_R_FUNC getgrgid_r
+#define GETXXKEY_R_PARSER bb__parsegrent
+#define GETXXKEY_R_ENTTYPE struct group
+#define GETXXKEY_R_TEST(ENT) ((ENT)->gr_gid == key)
+#define GETXXKEY_R_KEYTYPE gid_t
+#define GETXXKEY_R_PATHNAME _PATH_GROUP
+#include "pwd_grp_internal.c"
+
+/**********************************************************************/
+/* TODO: audit & stop using these in bbox, they pull in static buffers */
+
+/* This one has many users */
+struct passwd *getpwuid(uid_t uid)
+{
+ struct statics *S;
+ struct passwd *resultbuf = RESULTBUF(getpwuid);
+ char *buffer = BUFFER(getpwuid);
+ struct passwd *result;
+
+ getpwuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getpwuid)), &result);
+ return result;
+}
+
+/* This one has many users */
+struct group *getgrgid(gid_t gid)
+{
+ struct statics *S;
+ struct group *resultbuf = RESULTBUF(getgrgid);
+ char *buffer = BUFFER(getgrgid);
+ struct group *result;
+
+ getgrgid_r(gid, resultbuf, buffer, sizeof(BUFFER(getgrgid)), &result);
+ return result;
+}
+
+#if 0 //ENABLE_USE_BB_SHADOW
+/* This function is non-standard and is currently not built. It seems
+ * to have been created as a reentrant version of the non-standard
+ * functions getspuid. Why getspuid was added, I do not know. */
+int getspuid_r(uid_t uid, struct spwd *__restrict resultbuf,
+ char *__restrict buffer, size_t buflen,
+ struct spwd **__restrict result)
+{
+ int rv;
+ struct passwd *pp;
+ struct passwd password;
+ char pwd_buff[PWD_BUFFER_SIZE];
+
+ *result = NULL;
+ rv = getpwuid_r(uid, &password, pwd_buff, sizeof(pwd_buff), &pp);
+ if (!rv) {
+ rv = getspnam_r(password.pw_name, resultbuf, buffer, buflen, result);
+ }
+
+ return rv;
+}
+
+/* This function is non-standard and is currently not built.
+ * Why it was added, I do not know. */
+struct spwd *getspuid(uid_t uid)
+{
+ struct statics *S;
+ struct spwd *resultbuf = RESULTBUF(getspuid);
+ char *buffer = BUFFER(getspuid);
+ struct spwd *result;
+
+ getspuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getspuid)), &result);
+ return result;
+}
+#endif
+
+/* This one has many users */
+struct passwd *getpwnam(const char *name)
+{
+ struct statics *S;
+ struct passwd *resultbuf = RESULTBUF(getpwnam);
+ char *buffer = BUFFER(getpwnam);
+ struct passwd *result;
+
+ getpwnam_r(name, resultbuf, buffer, sizeof(BUFFER(getpwnam)), &result);
+ return result;
+}
+
+/* This one has many users */
+struct group *getgrnam(const char *name)
+{
+ struct statics *S;
+ struct group *resultbuf = RESULTBUF(getgrnam);
+ char *buffer = BUFFER(getgrnam);
+ struct group *result;
+
+ getgrnam_r(name, resultbuf, buffer, sizeof(BUFFER(getgrnam)), &result);
+ return result;
+}
+
+#if 0 //ENABLE_USE_BB_SHADOW
+struct spwd *getspnam(const char *name)
+{
+ struct statics *S;
+ struct spwd *resultbuf = RESULTBUF(getspnam);
+ char *buffer = BUFFER(getspnam);
+ struct spwd *result;
+
+ getspnam_r(name, resultbuf, buffer, sizeof(BUFFER(getspnam)), &result);
+ return result;
+}
+#endif
+
+/* This one doesn't use static buffers */
+int getpw(uid_t uid, char *buf)
+{
+ struct passwd resultbuf;
+ struct passwd *result;
+ char buffer[PWD_BUFFER_SIZE];
+
+ if (!buf) {
+ errno = EINVAL;
+ } else if (!getpwuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result)) {
+ if (sprintf(buf, "%s:%s:%lu:%lu:%s:%s:%s\n",
+ resultbuf.pw_name, resultbuf.pw_passwd,
+ (unsigned long)(resultbuf.pw_uid),
+ (unsigned long)(resultbuf.pw_gid),
+ resultbuf.pw_gecos, resultbuf.pw_dir,
+ resultbuf.pw_shell) >= 0
+ ) {
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+/**********************************************************************/
+
+/* FIXME: we don't have such CONFIG_xx - ?! */
+
+#if defined CONFIG_USE_BB_THREADSAFE_SHADOW && defined PTHREAD_MUTEX_INITIALIZER
+static pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
+# define LOCK pthread_mutex_lock(&mylock)
+# define UNLOCK pthread_mutex_unlock(&mylock);
+#else
+# define LOCK ((void) 0)
+# define UNLOCK ((void) 0)
+#endif
+
+static FILE *pwf /*= NULL*/;
+void setpwent(void)
+{
+ LOCK;
+ if (pwf) {
+ rewind(pwf);
+ }
+ UNLOCK;
+}
+
+void endpwent(void)
+{
+ LOCK;
+ if (pwf) {
+ fclose(pwf);
+ pwf = NULL;
+ }
+ UNLOCK;
+}
+
+
+int getpwent_r(struct passwd *__restrict resultbuf,
+ char *__restrict buffer, size_t buflen,
+ struct passwd **__restrict result)
+{
+ int rv;
+
+ LOCK;
+ *result = NULL; /* In case of error... */
+
+ if (!pwf) {
+ pwf = fopen(_PATH_PASSWD, "r");
+ if (!pwf) {
+ rv = errno;
+ goto ERR;
+ }
+ }
+
+ rv = bb__pgsreader(bb__parsepwent, resultbuf, buffer, buflen, pwf);
+ if (!rv) {
+ *result = resultbuf;
+ }
+
+ ERR:
+ UNLOCK;
+ return rv;
+}
+
+static FILE *grf /*= NULL*/;
+void setgrent(void)
+{
+ LOCK;
+ if (grf) {
+ rewind(grf);
+ }
+ UNLOCK;
+}
+
+void endgrent(void)
+{
+ LOCK;
+ if (grf) {
+ fclose(grf);
+ grf = NULL;
+ }
+ UNLOCK;
+}
+
+int getgrent_r(struct group *__restrict resultbuf,
+ char *__restrict buffer, size_t buflen,
+ struct group **__restrict result)
+{
+ int rv;
+
+ LOCK;
+ *result = NULL; /* In case of error... */
+
+ if (!grf) {
+ grf = fopen(_PATH_GROUP, "r");
+ if (!grf) {
+ rv = errno;
+ goto ERR;
+ }
+ }
+
+ rv = bb__pgsreader(bb__parsegrent, resultbuf, buffer, buflen, grf);
+ if (!rv) {
+ *result = resultbuf;
+ }
+
+ ERR:
+ UNLOCK;
+ return rv;
+}
+
+#if ENABLE_USE_BB_SHADOW
+static FILE *spf /*= NULL*/;
+void setspent(void)
+{
+ LOCK;
+ if (spf) {
+ rewind(spf);
+ }
+ UNLOCK;
+}
+
+void endspent(void)
+{
+ LOCK;
+ if (spf) {
+ fclose(spf);
+ spf = NULL;
+ }
+ UNLOCK;
+}
+
+int getspent_r(struct spwd *resultbuf, char *buffer,
+ size_t buflen, struct spwd **result)
+{
+ int rv;
+
+ LOCK;
+ *result = NULL; /* In case of error... */
+
+ if (!spf) {
+ spf = fopen(_PATH_SHADOW, "r");
+ if (!spf) {
+ rv = errno;
+ goto ERR;
+ }
+ }
+
+ rv = bb__pgsreader(bb__parsespent, resultbuf, buffer, buflen, spf);
+ if (!rv) {
+ *result = resultbuf;
+ }
+
+ ERR:
+ UNLOCK;
+ return rv;
+}
+#endif
+
+#if 0
+struct passwd *getpwent(void)
+{
+ static char line_buff[PWD_BUFFER_SIZE];
+ static struct passwd pwd;
+ struct passwd *result;
+
+ getpwent_r(&pwd, line_buff, sizeof(line_buff), &result);
+ return result;
+}
+
+struct group *getgrent(void)
+{
+ static char line_buff[GRP_BUFFER_SIZE];
+ static struct group gr;
+ struct group *result;
+
+ getgrent_r(&gr, line_buff, sizeof(line_buff), &result);
+ return result;
+}
+#endif
+
+#if 0 //ENABLE_USE_BB_SHADOW
+struct spwd *getspent(void)
+{
+ static char line_buff[PWD_BUFFER_SIZE];
+ static struct spwd spwd;
+ struct spwd *result;
+
+ getspent_r(&spwd, line_buff, sizeof(line_buff), &result);
+ return result;
+}
+
+struct spwd *sgetspent(const char *string)
+{
+ static char line_buff[PWD_BUFFER_SIZE];
+ static struct spwd spwd;
+ struct spwd *result;
+
+ sgetspent_r(string, &spwd, line_buff, sizeof(line_buff), &result);
+ return result;
+}
+#endif
+
+int initgroups(const char *user, gid_t gid)
+{
+ FILE *grfile;
+ gid_t *group_list;
+ int num_groups, rv;
+ char **m;
+ struct group group;
+ char buff[PWD_BUFFER_SIZE];
+
+ rv = -1;
+ grfile = fopen(_PATH_GROUP, "r");
+ if (grfile != NULL) {
+
+ /* We alloc space for 8 gids at a time. */
+ group_list = xmalloc(8 * sizeof(gid_t *));
+ *group_list = gid;
+ num_groups = 1;
+
+ while (!bb__pgsreader(bb__parsegrent, &group, buff, sizeof(buff), grfile)) {
+ assert(group.gr_mem); /* Must have at least a NULL terminator. */
+ if (group.gr_gid != gid) {
+ for (m = group.gr_mem; *m; m++) {
+ if (!strcmp(*m, user)) {
+ if (!(num_groups & 7)) {
+ gid_t *tmp = xrealloc(group_list,
+ (num_groups+8) * sizeof(gid_t *));
+ group_list = tmp;
+ }
+ group_list[num_groups++] = group.gr_gid;
+ break;
+ }
+ }
+ }
+ }
+
+ rv = setgroups(num_groups, group_list);
+ free(group_list);
+ fclose(grfile);
+ }
+
+ return rv;
+}
+
+int putpwent(const struct passwd *__restrict p, FILE *__restrict f)
+{
+ int rv = -1;
+
+ if (!p || !f) {
+ errno = EINVAL;
+ } else {
+ /* No extra thread locking is needed above what fprintf does. */
+ if (fprintf(f, "%s:%s:%lu:%lu:%s:%s:%s\n",
+ p->pw_name, p->pw_passwd,
+ (unsigned long)(p->pw_uid),
+ (unsigned long)(p->pw_gid),
+ p->pw_gecos, p->pw_dir, p->pw_shell) >= 0
+ ) {
+ rv = 0;
+ }
+ }
+
+ return rv;
+}
+
+int putgrent(const struct group *__restrict p, FILE *__restrict f)
+{
+ static const char format[] ALIGN1 = ",%s";
+
+ char **m;
+ const char *fmt;
+ int rv = -1;
+
+ if (!p || !f) { /* Sigh... glibc checks. */
+ errno = EINVAL;
+ } else {
+ if (fprintf(f, "%s:%s:%lu:",
+ p->gr_name, p->gr_passwd,
+ (unsigned long)(p->gr_gid)) >= 0
+ ) {
+
+ fmt = format + 1;
+
+ assert(p->gr_mem);
+ m = p->gr_mem;
+
+ do {
+ if (!*m) {
+ if (fputc('\n', f) >= 0) {
+ rv = 0;
+ }
+ break;
+ }
+ if (fprintf(f, fmt, *m) < 0) {
+ break;
+ }
+ ++m;
+ fmt = format;
+ } while (1);
+
+ }
+
+ }
+
+ return rv;
+}
+
+#if ENABLE_USE_BB_SHADOW
+static const unsigned char _sp_off[] ALIGN1 = {
+ offsetof(struct spwd, sp_lstchg), /* 2 - not a char ptr */
+ offsetof(struct spwd, sp_min), /* 3 - not a char ptr */
+ offsetof(struct spwd, sp_max), /* 4 - not a char ptr */
+ offsetof(struct spwd, sp_warn), /* 5 - not a char ptr */
+ offsetof(struct spwd, sp_inact), /* 6 - not a char ptr */
+ offsetof(struct spwd, sp_expire) /* 7 - not a char ptr */
+};
+
+int putspent(const struct spwd *p, FILE *stream)
+{
+ static const char ld_format[] ALIGN1 = "%ld:";
+
+ const char *f;
+ long x;
+ int i;
+ int rv = -1;
+
+ /* Unlike putpwent and putgrent, glibc does not check the args. */
+ if (fprintf(stream, "%s:%s:", p->sp_namp,
+ (p->sp_pwdp ? p->sp_pwdp : "")) < 0
+ ) {
+ goto DO_UNLOCK;
+ }
+
+ for (i = 0; i < sizeof(_sp_off); i++) {
+ f = ld_format;
+ x = *(const long *)(((const char *) p) + _sp_off[i]);
+ if (x == -1) {
+ f += 3;
+ }
+ if (fprintf(stream, f, x) < 0) {
+ goto DO_UNLOCK;
+ }
+ }
+
+ if ((p->sp_flag != ~0UL) && (fprintf(stream, "%lu", p->sp_flag) < 0)) {
+ goto DO_UNLOCK;
+ }
+
+ if (fputc('\n', stream) > 0) {
+ rv = 0;
+ }
+
+DO_UNLOCK:
+ return rv;
+}
+#endif
+
+/**********************************************************************/
+/* Internal uClibc functions. */
+/**********************************************************************/
+
+static const unsigned char pw_off[] ALIGN1 = {
+ offsetof(struct passwd, pw_name), /* 0 */
+ offsetof(struct passwd, pw_passwd), /* 1 */
+ offsetof(struct passwd, pw_uid), /* 2 - not a char ptr */
+ offsetof(struct passwd, pw_gid), /* 3 - not a char ptr */
+ offsetof(struct passwd, pw_gecos), /* 4 */
+ offsetof(struct passwd, pw_dir), /* 5 */
+ offsetof(struct passwd, pw_shell) /* 6 */
+};
+
+static int bb__parsepwent(void *data, char *line)
+{
+ char *endptr;
+ char *p;
+ int i;
+
+ i = 0;
+ do {
+ p = ((char *) ((struct passwd *) data)) + pw_off[i];
+
+ if ((i & 6) ^ 2) { /* i!=2 and i!=3 */
+ *((char **) p) = line;
+ if (i==6) {
+ return 0;
+ }
+ /* NOTE: glibc difference - glibc allows omission of
+ * ':' seperators after the gid field if all remaining
+ * entries are empty. We require all separators. */
+ line = strchr(line, ':');
+ if (!line) {
+ break;
+ }
+ } else {
+ unsigned long t = strtoul(line, &endptr, 10);
+ /* Make sure we had at least one digit, and that the
+ * failing char is the next field seperator ':'. See
+ * glibc difference note above. */
+ /* TODO: Also check for leading whitespace? */
+ if ((endptr == line) || (*endptr != ':')) {
+ break;
+ }
+ line = endptr;
+ if (i & 1) { /* i == 3 -- gid */
+ *((gid_t *) p) = t;
+ } else { /* i == 2 -- uid */
+ *((uid_t *) p) = t;
+ }
+ }
+
+ *line++ = 0;
+ ++i;
+ } while (1);
+
+ return -1;
+}
+
+/**********************************************************************/
+
+static const unsigned char gr_off[] ALIGN1 = {
+ offsetof(struct group, gr_name), /* 0 */
+ offsetof(struct group, gr_passwd), /* 1 */
+ offsetof(struct group, gr_gid) /* 2 - not a char ptr */
+};
+
+static int bb__parsegrent(void *data, char *line)
+{
+ char *endptr;
+ char *p;
+ int i;
+ char **members;
+ char *end_of_buf;
+
+ end_of_buf = ((struct group *) data)->gr_name; /* Evil hack! */
+ i = 0;
+ do {
+ p = ((char *) ((struct group *) data)) + gr_off[i];
+
+ if (i < 2) {
+ *((char **) p) = line;
+ line = strchr(line, ':');
+ if (!line) {
+ break;
+ }
+ *line++ = 0;
+ ++i;
+ } else {
+ *((gid_t *) p) = strtoul(line, &endptr, 10);
+
+ /* NOTE: glibc difference - glibc allows omission of the
+ * trailing colon when there is no member list. We treat
+ * this as an error. */
+
+ /* Make sure we had at least one digit, and that the
+ * failing char is the next field seperator ':'. See
+ * glibc difference note above. */
+ if ((endptr == line) || (*endptr != ':')) {
+ break;
+ }
+
+ i = 1; /* Count terminating NULL ptr. */
+ p = endptr;
+
+ if (p[1]) { /* We have a member list to process. */
+ /* Overwrite the last ':' with a ',' before counting.
+ * This allows us to test for initial ',' and adds
+ * one ',' so that the ',' count equals the member
+ * count. */
+ *p = ',';
+ do {
+ /* NOTE: glibc difference - glibc allows and trims leading
+ * (but not trailing) space. We treat this as an error. */
+ /* NOTE: glibc difference - glibc allows consecutive and
+ * trailing commas, and ignores "empty string" users. We
+ * treat this as an error. */
+ if (*p == ',') {
+ ++i;
+ *p = 0; /* nul-terminate each member string. */
+ if (!*++p || (*p == ',') || isspace(*p)) {
+ goto ERR;
+ }
+ }
+ } while (*++p);
+ }
+
+ /* Now align (p+1), rounding up. */
+ /* Assumes sizeof(char **) is a power of 2. */
+ members = (char **)( (((intptr_t) p) + sizeof(char **))
+ & ~((intptr_t)(sizeof(char **) - 1)) );
+
+ if (((char *)(members + i)) > end_of_buf) { /* No space. */
+ break;
+ }
+
+ ((struct group *) data)->gr_mem = members;
+
+ if (--i) {
+ p = endptr; /* Pointing to char prior to first member. */
+ do {
+ *members++ = ++p;
+ if (!--i) break;
+ while (*++p) {}
+ } while (1);
+ }
+ *members = NULL;
+
+ return 0;
+ }
+ } while (1);
+
+ ERR:
+ return -1;
+}
+
+/**********************************************************************/
+
+#if ENABLE_USE_BB_SHADOW
+static const unsigned char sp_off[] ALIGN1 = {
+ offsetof(struct spwd, sp_namp), /* 0 */
+ offsetof(struct spwd, sp_pwdp), /* 1 */
+ offsetof(struct spwd, sp_lstchg), /* 2 - not a char ptr */
+ offsetof(struct spwd, sp_min), /* 3 - not a char ptr */
+ offsetof(struct spwd, sp_max), /* 4 - not a char ptr */
+ offsetof(struct spwd, sp_warn), /* 5 - not a char ptr */
+ offsetof(struct spwd, sp_inact), /* 6 - not a char ptr */
+ offsetof(struct spwd, sp_expire), /* 7 - not a char ptr */
+ offsetof(struct spwd, sp_flag) /* 8 - not a char ptr */
+};
+
+static int bb__parsespent(void *data, char * line)
+{
+ char *endptr;
+ char *p;
+ int i;
+
+ i = 0;
+ do {
+ p = ((char *) ((struct spwd *) data)) + sp_off[i];
+ if (i < 2) {
+ *((char **) p) = line;
+ line = strchr(line, ':');
+ if (!line) {
+ break;
+ }
+ } else {
+ *((long *) p) = (long) strtoul(line, &endptr, 10);
+
+ if (endptr == line) {
+ *((long *) p) = ((i != 8) ? -1L : ((long)(~0UL)));
+ }
+
+ line = endptr;
+
+ if (i == 8) {
+ if (!*endptr) {
+ return 0;
+ }
+ break;
+ }
+
+ if (*endptr != ':') {
+ break;
+ }
+
+ }
+
+ *line++ = 0;
+ ++i;
+ } while (1);
+
+ return EINVAL;
+}
+#endif
+
+/**********************************************************************/
+
+/* Reads until if EOF, or until if finds a line which fits in the buffer
+ * and for which the parser function succeeds.
+ *
+ * Returns 0 on success and ENOENT for end-of-file (glibc concession).
+ */
+
+static int bb__pgsreader(int (*parserfunc)(void *d, char *line), void *data,
+ char *__restrict line_buff, size_t buflen, FILE *f)
+{
+ int line_len;
+ int skip;
+ int rv = ERANGE;
+
+ if (buflen < PWD_BUFFER_SIZE) {
+ errno = rv;
+ } else {
+ skip = 0;
+ do {
+ if (!fgets(line_buff, buflen, f)) {
+ if (feof(f)) {
+ rv = ENOENT;
+ }
+ break;
+ }
+
+ line_len = strlen(line_buff) - 1; /* strlen() must be > 0. */
+ if (line_buff[line_len] == '\n') {
+ line_buff[line_len] = 0;
+ } else if (line_len + 2 == buflen) { /* line too long */
+ ++skip;
+ continue;
+ }
+
+ if (skip) {
+ --skip;
+ continue;
+ }
+
+ /* NOTE: glibc difference - glibc strips leading whitespace from
+ * records. We do not allow leading whitespace. */
+
+ /* Skip empty lines, comment lines, and lines with leading
+ * whitespace. */
+ if (*line_buff && (*line_buff != '#') && !isspace(*line_buff)) {
+ if (parserfunc == bb__parsegrent) { /* Do evil group hack. */
+ /* The group entry parsing function needs to know where
+ * the end of the buffer is so that it can construct the
+ * group member ptr table. */
+ ((struct group *) data)->gr_name = line_buff + buflen;
+ }
+
+ if (!parserfunc(data, line_buff)) {
+ rv = 0;
+ break;
+ }
+ }
+ } while (1);
+
+ }
+
+ return rv;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/libpwdgrp/pwd_grp_internal.c b/cleopatre/busybox-1.11.1-spc300/libpwdgrp/pwd_grp_internal.c
new file mode 100644
index 0000000000..d55edc3493
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libpwdgrp/pwd_grp_internal.c
@@ -0,0 +1,62 @@
+/* vi: set sw=4 ts=4: */
+/* Copyright (C) 2003 Manuel Novoa III
+ *
+ * Licensed under GPL v2, or later. See file LICENSE in this tarball.
+ */
+
+/* Nov 6, 2003 Initial version.
+ *
+ * NOTE: This implementation is quite strict about requiring all
+ * field seperators. It also does not allow leading whitespace
+ * except when processing the numeric fields. glibc is more
+ * lenient. See the various glibc difference comments below.
+ *
+ * TODO:
+ * Move to dynamic allocation of (currently statically allocated)
+ * buffers; especially for the group-related functions since
+ * large group member lists will cause error returns.
+ *
+ */
+
+#ifndef GETXXKEY_R_FUNC
+#error GETXXKEY_R_FUNC is not defined!
+#endif
+
+int GETXXKEY_R_FUNC(GETXXKEY_R_KEYTYPE key,
+ GETXXKEY_R_ENTTYPE *__restrict resultbuf,
+ char *__restrict buffer, size_t buflen,
+ GETXXKEY_R_ENTTYPE **__restrict result)
+{
+ FILE *stream;
+ int rv;
+
+ *result = NULL;
+
+ stream = fopen(GETXXKEY_R_PATHNAME, "r");
+ if (!stream)
+ return errno;
+ while (1) {
+ rv = bb__pgsreader(GETXXKEY_R_PARSER, resultbuf, buffer, buflen, stream);
+ if (!rv) {
+ if (GETXXKEY_R_TEST(resultbuf)) { /* Found key? */
+ *result = resultbuf;
+ break;
+ }
+ } else {
+ if (rv == ENOENT) { /* end-of-file encountered. */
+ rv = 0;
+ }
+ break;
+ }
+ }
+ fclose(stream);
+
+ return rv;
+}
+
+#undef GETXXKEY_R_FUNC
+#undef GETXXKEY_R_PARSER
+#undef GETXXKEY_R_ENTTYPE
+#undef GETXXKEY_R_TEST
+#undef GETXXKEY_R_KEYTYPE
+#undef GETXXKEY_R_PATHNAME
diff --git a/cleopatre/busybox-1.11.1-spc300/libpwdgrp/uidgid_get.c b/cleopatre/busybox-1.11.1-spc300/libpwdgrp/uidgid_get.c
new file mode 100644
index 0000000000..b0085c423f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/libpwdgrp/uidgid_get.c
@@ -0,0 +1,133 @@
+/*
+Copyright (c) 2001-2006, Gerrit Pape
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "libbb.h"
+
+/* Always sets uid and gid */
+int get_uidgid(struct bb_uidgid_t *u, const char *ug, int numeric_ok)
+{
+ struct passwd *pwd;
+ struct group *gr;
+ char *user, *group;
+ unsigned n;
+
+ user = (char*)ug;
+ group = strchr(ug, ':');
+ if (group) {
+ int sz = (++group) - ug;
+ user = alloca(sz);
+ /* copies sz-1 bytes, stores terminating '\0' */
+ safe_strncpy(user, ug, sz);
+ }
+ if (numeric_ok) {
+ n = bb_strtou(user, NULL, 10);
+ if (!errno) {
+ u->uid = n;
+ pwd = getpwuid(n);
+ /* If we have e.g. "500" string without user */
+ /* with uid 500 in /etc/passwd, we set gid == uid */
+ u->gid = pwd ? pwd->pw_gid : n;
+ goto skip;
+ }
+ }
+ /* Either it is not numeric, or caller disallows numeric username */
+ pwd = getpwnam(user);
+ if (!pwd)
+ return 0;
+ u->uid = pwd->pw_uid;
+ u->gid = pwd->pw_gid;
+
+ skip:
+ if (group) {
+ if (numeric_ok) {
+ n = bb_strtou(group, NULL, 10);
+ if (!errno) {
+ u->gid = n;
+ return 1;
+ }
+ }
+ gr = getgrnam(group);
+ if (!gr) return 0;
+ u->gid = gr->gr_gid;
+ }
+ return 1;
+}
+
+/* chown-like:
+ * "user" sets uid only,
+ * ":group" sets gid only
+ * "user:" sets uid and gid (to user's primary group id)
+ * "user:group" sets uid and gid
+ * ('unset' uid or gid is actually set to -1)
+ */
+void parse_chown_usergroup_or_die(struct bb_uidgid_t *u, char *user_group)
+{
+ char *group;
+
+ u->uid = -1;
+ u->gid = -1;
+
+ /* Check if there is a group name */
+ group = strchr(user_group, '.'); /* deprecated? */
+ if (!group)
+ group = strchr(user_group, ':');
+ else
+ *group = ':'; /* replace '.' with ':' */
+
+ /* Parse "user[:[group]]" */
+ if (!group) { /* "user" */
+ u->uid = get_ug_id(user_group, xuname2uid);
+ } else if (group == user_group) { /* ":group" */
+ u->gid = get_ug_id(group + 1, xgroup2gid);
+ } else {
+ if (!group[1]) /* "user:" */
+ *group = '\0';
+ if (!get_uidgid(u, user_group, 1))
+ bb_error_msg_and_die("unknown user/group %s", user_group);
+ }
+}
+
+#if 0
+#include <stdio.h>
+int main()
+{
+ unsigned u;
+ struct bb_uidgid_t ug;
+ u = get_uidgid(&ug, "apache", 0);
+ printf("%u = %u:%u\n", u, ug.uid, ug.gid);
+ ug.uid = ug.gid = 1111;
+ u = get_uidgid(&ug, "apache", 0);
+ printf("%u = %u:%u\n", u, ug.uid, ug.gid);
+ ug.uid = ug.gid = 1111;
+ u = get_uidgid(&ug, "apache:users", 0);
+ printf("%u = %u:%u\n", u, ug.uid, ug.gid);
+ ug.uid = ug.gid = 1111;
+ u = get_uidgid(&ug, "apache:users", 0);
+ printf("%u = %u:%u\n", u, ug.uid, ug.gid);
+ return 0;
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/loginutils/Config.in b/cleopatre/busybox-1.11.1-spc300/loginutils/Config.in
new file mode 100644
index 0000000000..4ca1c25977
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/loginutils/Config.in
@@ -0,0 +1,283 @@
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Login/Password Management Utilities"
+
+config FEATURE_SHADOWPASSWDS
+ bool "Support for shadow passwords"
+ default n
+ help
+ Build support for shadow password in /etc/shadow. This file is only
+ readable by root and thus the encrypted passwords are no longer
+ publicly readable.
+
+config USE_BB_PWD_GRP
+ bool "Use internal password and group functions rather than system functions"
+ default n
+ help
+ If you leave this disabled, busybox will use the system's password
+ and group functions. And if you are using the GNU C library
+ (glibc), you will then need to install the /etc/nsswitch.conf
+ configuration file and the required /lib/libnss_* libraries in
+ order for the password and group functions to work. This generally
+ makes your embedded system quite a bit larger.
+
+ Enabling this option will cause busybox to directly access the
+ system's /etc/password, /etc/group files (and your system will be
+ smaller, and I will get fewer emails asking about how glibc NSS
+ works). When this option is enabled, you will not be able to use
+ PAM to access remote LDAP password servers and whatnot. And if you
+ want hostname resolution to work with glibc, you still need the
+ /lib/libnss_* libraries.
+
+ If you need to use glibc's nsswitch.conf mechanism
+ (e.g. if user/group database is NOT stored in /etc/passwd etc),
+ you must NOT use this option.
+
+ If you enable this option, it will add about 1.5k.
+
+config USE_BB_SHADOW
+ bool "Use internal shadow password functions"
+ default y
+ depends on USE_BB_PWD_GRP && FEATURE_SHADOWPASSWDS
+ help
+ If you leave this disabled, busybox will use the system's shadow
+ password handling functions. And if you are using the GNU C library
+ (glibc), you will then need to install the /etc/nsswitch.conf
+ configuration file and the required /lib/libnss_* libraries in
+ order for the shadow password functions to work. This generally
+ makes your embedded system quite a bit larger.
+
+ Enabling this option will cause busybox to directly access the
+ system's /etc/shadow file when handling shadow passwords. This
+ makes your system smaller (and I will get fewer emails asking about
+ how glibc NSS works). When this option is enabled, you will not be
+ able to use PAM to access shadow passwords from remote LDAP
+ password servers and whatnot.
+
+config USE_BB_CRYPT
+ bool "Use internal DES and MD5 crypt functions"
+ default y
+ help
+ Busybox has internal DES and MD5 crypt functions.
+ They produce results which are identical to corresponding
+ standard C library functions.
+
+ If you leave this disabled, busybox will use the system's
+ crypt functions. Most C libraries use large (~70k)
+ static buffers there, and also combine them with more general
+ DES encryption/decryption.
+
+ For busybox, having large static buffers is undesirable,
+ especially on NOMMU machines. Busybox also doesn't need
+ DES encryption/decryption and can do with smaller code.
+
+ If you enable this option, it will add about 4.8k of code
+ if you are building dynamically linked executable.
+ In static build, it makes code _smaller_ by about 1.2k,
+ and likely many kilobytes less of bss.
+
+config ADDGROUP
+ bool "addgroup"
+ default n
+ help
+ Utility for creating a new group account.
+
+config FEATURE_ADDUSER_TO_GROUP
+ bool "Support for adding users to groups"
+ default n
+ depends on ADDGROUP
+ help
+ If called with two non-option arguments,
+ addgroup will add an existing user to an
+ existing group.
+
+config DELGROUP
+ bool "delgroup"
+ default n
+ help
+ Utility for deleting a group account.
+
+config FEATURE_DEL_USER_FROM_GROUP
+ bool "Support for removing users from groups."
+ default n
+ depends on DELGROUP
+ help
+ If called with two non-option arguments, deluser
+ or delgroup will remove an user from a specified group.
+
+config FEATURE_CHECK_NAMES
+ bool "Enable sanity check on user/group names in adduser and addgroup"
+ default n
+ depends on ADDUSER || ADDGROUP
+ help
+ Enable sanity check on user and group names in adduser and addgroup.
+ To avoid problems, the user or group name should consist only of
+ letters, digits, underscores, periods, at signs and dashes,
+ and not start with a dash (as defined by IEEE Std 1003.1-2001).
+ For compatibility with Samba machine accounts "$" is also supported
+ at the end of the user or group name.
+
+config ADDUSER
+ bool "adduser"
+ default n
+ help
+ Utility for creating a new user account.
+
+config FEATURE_ADDUSER_LONG_OPTIONS
+ bool "Enable long options"
+ default n
+ depends on ADDUSER && GETOPT_LONG
+ help
+ Support long options for the adduser applet.
+
+config DELUSER
+ bool "deluser"
+ default n
+ help
+ Utility for deleting a user account.
+
+config GETTY
+ bool "getty"
+ default n
+ select FEATURE_SYSLOG
+ help
+ getty lets you log in on a tty, it is normally invoked by init.
+
+config FEATURE_UTMP
+ bool "Support utmp file"
+ depends on GETTY || LOGIN || SU || WHO
+ default n
+ help
+ The file /var/run/utmp is used to track who is currently logged in.
+
+config FEATURE_WTMP
+ bool "Support wtmp file"
+ depends on GETTY || LOGIN || SU || LAST
+ default n
+ select FEATURE_UTMP
+ help
+ The file /var/run/wtmp is used to track when user's have logged into
+ and logged out of the system.
+
+config LOGIN
+ bool "login"
+ default n
+ select FEATURE_SUID
+ select FEATURE_SYSLOG
+ help
+ login is used when signing onto a system.
+
+ Note that Busybox binary must be setuid root for this applet to
+ work properly.
+
+config PAM
+ bool "Support for PAM (Pluggable Authentication Modules)"
+ default n
+ depends on LOGIN
+ help
+ Use PAM in login(1) instead of direct access to password database.
+
+config LOGIN_SCRIPTS
+ bool "Support for login scripts"
+ depends on LOGIN
+ default n
+ help
+ Enable this if you want login to execute $LOGIN_PRE_SUID_SCRIPT
+ just prior to switching from root to logged-in user.
+
+config FEATURE_NOLOGIN
+ bool "Support for /etc/nologin"
+ default y
+ depends on LOGIN
+ help
+ The file /etc/nologin is used by (some versions of) login(1).
+ If it exists, non-root logins are prohibited.
+
+config FEATURE_SECURETTY
+ bool "Support for /etc/securetty"
+ default y
+ depends on LOGIN
+ help
+ The file /etc/securetty is used by (some versions of) login(1).
+ The file contains the device names of tty lines (one per line,
+ without leading /dev/) on which root is allowed to login.
+
+config PASSWD
+ bool "passwd"
+ default n
+ select FEATURE_SUID
+ select FEATURE_SYSLOG
+ help
+ passwd changes passwords for user and group accounts. A normal user
+ may only change the password for his/her own account, the super user
+ may change the password for any account. The administrator of a group
+ may change the password for the group.
+
+ Note that Busybox binary must be setuid root for this applet to
+ work properly.
+
+config FEATURE_PASSWD_WEAK_CHECK
+ bool "Check new passwords for weakness"
+ default y
+ depends on PASSWD
+ help
+ With this option passwd will refuse new passwords which are "weak".
+
+config CRYPTPW
+ bool "cryptpw"
+ default n
+ help
+ Applet for crypting a string.
+
+config CHPASSWD
+ bool "chpasswd"
+ default n
+ help
+ chpasswd reads a file of user name and password pairs from
+ standard input and uses this information to update a group of
+ existing users.
+
+config SU
+ bool "su"
+ default n
+ select FEATURE_SUID
+ select FEATURE_SYSLOG
+ help
+ su is used to become another user during a login session.
+ Invoked without a username, su defaults to becoming the super user.
+
+ Note that Busybox binary must be setuid root for this applet to
+ work properly.
+
+config FEATURE_SU_SYSLOG
+ bool "Enable su to write to syslog"
+ default y
+ depends on SU
+
+config FEATURE_SU_CHECKS_SHELLS
+ bool "Enable su to check user's shell to be listed in /etc/shells"
+ depends on SU
+ default y
+
+config SULOGIN
+ bool "sulogin"
+ default n
+ select FEATURE_SYSLOG
+ help
+ sulogin is invoked when the system goes into single user
+ mode (this is done through an entry in inittab).
+
+config VLOCK
+ bool "vlock"
+ default n
+ select FEATURE_SUID
+ help
+ Build the "vlock" applet which allows you to lock (virtual) terminals.
+
+ Note that Busybox binary must be setuid root for this applet to
+ work properly.
+
+endmenu
diff --git a/cleopatre/busybox-1.11.1-spc300/loginutils/Kbuild b/cleopatre/busybox-1.11.1-spc300/loginutils/Kbuild
new file mode 100644
index 0000000000..3d0d777e8d
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/loginutils/Kbuild
@@ -0,0 +1,19 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+lib-y:=
+lib-$(CONFIG_ADDGROUP) += addgroup.o
+lib-$(CONFIG_ADDUSER) += adduser.o
+lib-$(CONFIG_CRYPTPW) += cryptpw.o
+lib-$(CONFIG_CHPASSWD) += chpasswd.o
+lib-$(CONFIG_GETTY) += getty.o
+lib-$(CONFIG_LOGIN) += login.o
+lib-$(CONFIG_PASSWD) += passwd.o
+lib-$(CONFIG_SU) += su.o
+lib-$(CONFIG_SULOGIN) += sulogin.o
+lib-$(CONFIG_VLOCK) += vlock.o
+lib-$(CONFIG_DELUSER) += deluser.o
+lib-$(CONFIG_DELGROUP) += deluser.o
diff --git a/cleopatre/busybox-1.11.1-spc300/loginutils/addgroup.c b/cleopatre/busybox-1.11.1-spc300/loginutils/addgroup.c
new file mode 100644
index 0000000000..c9495b2c1b
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/loginutils/addgroup.c
@@ -0,0 +1,183 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * addgroup - add groups to /etc/group and /etc/gshadow
+ *
+ * Copyright (C) 1999 by Lineo, inc. and John Beppu
+ * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
+ * Copyright (C) 2007 by Tito Ragusa <farmatito@tiscali.it>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ */
+
+#include "libbb.h"
+
+static void xgroup_study(struct group *g)
+{
+ /* Make sure gr_name is unused */
+ if (getgrnam(g->gr_name)) {
+ goto error;
+ }
+
+ /* Check if the desired gid is free
+ * or find the first free one */
+ while (1) {
+ if (!getgrgid(g->gr_gid)) {
+ return; /* found free group: return */
+ }
+ if (option_mask32) {
+ /* -g N, cannot pick gid other than N: error */
+ g->gr_name = itoa(g->gr_gid);
+ goto error;
+ }
+ g->gr_gid++;
+ if (g->gr_gid <= 0) {
+ /* overflowed: error */
+ bb_error_msg_and_die("no gids left");
+ }
+ }
+
+ error:
+ /* exit */
+ bb_error_msg_and_die("group %s already exists", g->gr_name);
+}
+
+/* append a new user to the passwd file */
+static void new_group(char *group, gid_t gid)
+{
+ FILE *file;
+ struct group gr;
+
+ /* make sure gid and group haven't already been allocated */
+ gr.gr_gid = gid;
+ gr.gr_name = group;
+ xgroup_study(&gr);
+
+ /* add entry to group */
+ file = xfopen(bb_path_group_file, "a");
+ /* group:passwd:gid:userlist */
+ fprintf(file, "%s:x:%u:\n", group, (unsigned)gr.gr_gid);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ fclose(file);
+#if ENABLE_FEATURE_SHADOWPASSWDS
+ file = fopen_or_warn(bb_path_gshadow_file, "a");
+ if (file) {
+ fprintf(file, "%s:!::\n", group);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ fclose(file);
+ }
+#endif
+}
+
+#if ENABLE_FEATURE_ADDUSER_TO_GROUP
+static void add_user_to_group(char **args,
+ const char *path,
+ FILE *(*fopen_func)(const char *fileName, const char *mode))
+{
+ char *line;
+ int len = strlen(args[1]);
+ llist_t *plist = NULL;
+ FILE *group_file;
+
+ group_file = fopen_func(path, "r");
+
+ if (!group_file) return;
+
+ while ((line = xmalloc_fgetline(group_file)) != NULL) {
+ /* Find the group */
+ if (!strncmp(line, args[1], len)
+ && line[len] == ':'
+ ) {
+ /* Add the new user */
+ line = xasprintf("%s%s%s", line,
+ last_char_is(line, ':') ? "" : ",",
+ args[0]);
+ }
+ llist_add_to_end(&plist, line);
+ }
+
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ fclose(group_file);
+ group_file = fopen_func(path, "w");
+ while ((line = llist_pop(&plist))) {
+ if (group_file)
+ fprintf(group_file, "%s\n", line);
+ free(line);
+ }
+ if (group_file)
+ fclose(group_file);
+ } else {
+ group_file = fopen_func(path, "w");
+ if (group_file)
+ while ((line = llist_pop(&plist)))
+ fprintf(group_file, "%s\n", line);
+ }
+}
+#endif
+
+/*
+ * addgroup will take a login_name as its first parameter.
+ *
+ * gid can be customized via command-line parameters.
+ * If called with two non-option arguments, addgroup
+ * will add an existing user to an existing group.
+ */
+int addgroup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int addgroup_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ char *group;
+ gid_t gid = 0;
+
+ /* need to be root */
+ if (geteuid()) {
+ bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
+ }
+
+ /* Syntax:
+ * addgroup group
+ * addgroup -g num group
+ * addgroup user group
+ * Check for min, max and missing args */
+ opt_complementary = "-1:?2";
+ if (getopt32(argv, "g:", &group)) {
+ gid = xatoul_range(group, 0, ((unsigned long)(gid_t)ULONG_MAX) >> 1);
+ }
+ /* move past the commandline options */
+ argv += optind;
+ //argc -= optind;
+
+#if ENABLE_FEATURE_ADDUSER_TO_GROUP
+ if (argv[1]) {
+ struct group *gr;
+
+ if (option_mask32) {
+ /* -g was there, but "addgroup -g num user group"
+ * is a no-no */
+ bb_show_usage();
+ }
+
+ /* check if group and user exist */
+ xuname2uid(argv[0]); /* unknown user: exit */
+ xgroup2gid(argv[1]); /* unknown group: exit */
+ /* check if user is already in this group */
+ gr = getgrnam(argv[1]);
+ for (; *(gr->gr_mem) != NULL; (gr->gr_mem)++) {
+ if (!strcmp(argv[0], *(gr->gr_mem))) {
+ /* user is already in group: do nothing */
+ return EXIT_SUCCESS;
+ }
+ }
+ add_user_to_group(argv, bb_path_group_file, xfopen);
+#if ENABLE_FEATURE_SHADOWPASSWDS
+ add_user_to_group(argv, bb_path_gshadow_file, fopen_or_warn);
+#endif
+ } else
+#endif /* ENABLE_FEATURE_ADDUSER_TO_GROUP */
+ {
+ die_if_bad_username(argv[0]);
+ new_group(argv[0], gid);
+
+ }
+ /* Reached only on success */
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/loginutils/adduser.c b/cleopatre/busybox-1.11.1-spc300/loginutils/adduser.c
new file mode 100644
index 0000000000..cd68015d14
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/loginutils/adduser.c
@@ -0,0 +1,178 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * adduser - add users to /etc/passwd and /etc/shadow
+ *
+ * Copyright (C) 1999 by Lineo, inc. and John Beppu
+ * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+
+#define OPT_DONT_SET_PASS (1 << 4)
+#define OPT_SYSTEM_ACCOUNT (1 << 5)
+#define OPT_DONT_MAKE_HOME (1 << 6)
+
+
+/* remix */
+/* recoded such that the uid may be passed in *p */
+static void passwd_study(struct passwd *p)
+{
+ int max;
+
+ if (getpwnam(p->pw_name))
+ bb_error_msg_and_die("login '%s' is in use", p->pw_name);
+
+ if (option_mask32 & OPT_SYSTEM_ACCOUNT) {
+ p->pw_uid = 0;
+ max = 999;
+ } else {
+ p->pw_uid = 1000;
+ max = 64999;
+ }
+
+ /* check for a free uid (and maybe gid) */
+ while (getpwuid(p->pw_uid) || (!p->pw_gid && getgrgid(p->pw_uid)))
+ p->pw_uid++;
+
+ if (!p->pw_gid) {
+ /* new gid = uid */
+ p->pw_gid = p->pw_uid;
+ if (getgrnam(p->pw_name))
+ bb_error_msg_and_die("group name '%s' is in use", p->pw_name);
+ }
+
+ if (p->pw_uid > max)
+ bb_error_msg_and_die("no free uids left");
+}
+
+static void addgroup_wrapper(struct passwd *p)
+{
+ char *cmd;
+
+ cmd = xasprintf("addgroup -g %u '%s'", (unsigned)p->pw_gid, p->pw_name);
+ system(cmd);
+ free(cmd);
+}
+
+static void passwd_wrapper(const char *login) ATTRIBUTE_NORETURN;
+
+static void passwd_wrapper(const char *login)
+{
+ static const char prog[] ALIGN1 = "passwd";
+
+ BB_EXECLP(prog, prog, login, NULL);
+ bb_error_msg_and_die("cannot execute %s, you must set password manually", prog);
+}
+
+#if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS
+static const char adduser_longopts[] ALIGN1 =
+ "home\0" Required_argument "h"
+ "gecos\0" Required_argument "g"
+ "shell\0" Required_argument "s"
+ "ingroup\0" Required_argument "G"
+ "disabled-password\0" No_argument "D"
+ "empty-password\0" No_argument "D"
+ "system\0" No_argument "S"
+ "no-create-home\0" No_argument "H"
+ ;
+#endif
+
+/*
+ * adduser will take a login_name as its first parameter.
+ * home, shell, gecos:
+ * can be customized via command-line parameters.
+ */
+int adduser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int adduser_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ struct passwd pw;
+ const char *usegroup = NULL;
+ FILE *file;
+
+#if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS
+ applet_long_options = adduser_longopts;
+#endif
+
+ /* got root? */
+ if (geteuid()) {
+ bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
+ }
+
+ pw.pw_gecos = (char *)"Linux User,,,";
+ pw.pw_shell = (char *)DEFAULT_SHELL;
+ pw.pw_dir = NULL;
+
+ /* exactly one non-option arg */
+ opt_complementary = "=1";
+ getopt32(argv, "h:g:s:G:DSH", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup);
+ argv += optind;
+
+ /* fill in the passwd struct */
+ pw.pw_name = argv[0];
+ die_if_bad_username(pw.pw_name);
+ if (!pw.pw_dir) {
+ /* create string for $HOME if not specified already */
+ pw.pw_dir = xasprintf("/home/%s", argv[0]);
+ }
+ pw.pw_passwd = (char *)"x";
+ pw.pw_gid = usegroup ? xgroup2gid(usegroup) : 0; /* exits on failure */
+
+ /* make sure everything is kosher and setup uid && maybe gid */
+ passwd_study(&pw);
+
+ /* add to passwd */
+ file = xfopen(bb_path_passwd_file, "a");
+ //fseek(file, 0, SEEK_END); /* paranoia, "a" should ensure that anyway */
+ if (putpwent(&pw, file) != 0) {
+ bb_perror_nomsg_and_die();
+ }
+ /* do fclose even if !ENABLE_FEATURE_CLEAN_UP.
+ * We will exec passwd, files must be flushed & closed before that! */
+ fclose(file);
+
+#if ENABLE_FEATURE_SHADOWPASSWDS
+ /* add to shadow if necessary */
+ file = fopen_or_warn(bb_path_shadow_file, "a");
+ if (file) {
+ //fseek(file, 0, SEEK_END);
+ fprintf(file, "%s:!:%u:0:99999:7:::\n",
+ pw.pw_name, /* username */
+ (unsigned)(time(NULL) / 86400) /* sp->sp_lstchg */
+ /*0,*/ /* sp->sp_min */
+ /*99999,*/ /* sp->sp_max */
+ /*7*/ /* sp->sp_warn */
+ );
+ fclose(file);
+ }
+#endif
+
+ /* add to group */
+ /* addgroup should be responsible for dealing w/ gshadow */
+ /* if using a pre-existing group, don't create one */
+ if (!usegroup)
+ addgroup_wrapper(&pw);
+
+ /* Clear the umask for this process so it doesn't
+ * screw up the permissions on the mkdir and chown. */
+ umask(0);
+ if (!(option_mask32 & OPT_DONT_MAKE_HOME)) {
+ /* Set the owner and group so it is owned by the new user,
+ then fix up the permissions to 2755. Can't do it before
+ since chown will clear the setgid bit */
+ if (mkdir(pw.pw_dir, 0755)
+ || chown(pw.pw_dir, pw.pw_uid, pw.pw_gid)
+ || chmod(pw.pw_dir, 02755) /* set setgid bit on homedir */
+ ) {
+ bb_simple_perror_msg(pw.pw_dir);
+ }
+ }
+
+ if (!(option_mask32 & OPT_DONT_SET_PASS)) {
+ /* interactively set passwd */
+ passwd_wrapper(pw.pw_name);
+ }
+
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/loginutils/chpasswd.c b/cleopatre/busybox-1.11.1-spc300/loginutils/chpasswd.c
new file mode 100644
index 0000000000..7308596ad0
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/loginutils/chpasswd.c
@@ -0,0 +1,72 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * chpasswd.c
+ *
+ * Written for SLIND (from passwd.c) by Alexander Shishkin <virtuoso@slind.org>
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+#if ENABLE_GETOPT_LONG
+static const char chpasswd_longopts[] ALIGN1 =
+ "encrypted\0" No_argument "e"
+ "md5\0" No_argument "m"
+ ;
+#endif
+
+#define OPT_ENC 1
+#define OPT_MD5 2
+
+int chpasswd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int chpasswd_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ char *name, *pass;
+ char salt[sizeof("$N$XXXXXXXX")];
+ int opt, rc;
+ int rnd = rnd; /* we *want* it to be non-initialized! */
+
+ if (getuid())
+ bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
+
+ opt_complementary = "m--e:e--m";
+ USE_GETOPT_LONG(applet_long_options = chpasswd_longopts;)
+ opt = getopt32(argv, "em");
+
+ while ((name = xmalloc_fgetline(stdin)) != NULL) {
+ pass = strchr(name, ':');
+ if (!pass)
+ bb_error_msg_and_die("missing new password");
+ *pass++ = '\0';
+
+ xuname2uid(name); /* dies if there is no such user */
+
+ if (!(opt & OPT_ENC)) {
+ rnd = crypt_make_salt(salt, 1, rnd);
+ if (opt & OPT_MD5) {
+ strcpy(salt, "$1$");
+ rnd = crypt_make_salt(salt + 3, 4, rnd);
+ }
+ pass = pw_encrypt(pass, salt, 0);
+ }
+
+ /* This is rather complex: if user is not found in /etc/shadow,
+ * we try to find & change his passwd in /etc/passwd */
+#if ENABLE_FEATURE_SHADOWPASSWDS
+ rc = update_passwd(bb_path_shadow_file, name, pass);
+ if (rc == 0) /* no lines updated, no errors detected */
+#endif
+ rc = update_passwd(bb_path_passwd_file, name, pass);
+ /* LOGMODE_BOTH logs to syslog also */
+ logmode = LOGMODE_BOTH;
+ if (rc < 0)
+ bb_error_msg_and_die("an error occurred updating password for %s", name);
+ if (rc)
+ bb_info_msg("Password for '%s' changed", name);
+ logmode = LOGMODE_STDIO;
+ free(name);
+ free(pass);
+ }
+
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/loginutils/cryptpw.c b/cleopatre/busybox-1.11.1-spc300/loginutils/cryptpw.c
new file mode 100644
index 0000000000..901f6fcde7
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/loginutils/cryptpw.c
@@ -0,0 +1,58 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * cryptpw.c
+ *
+ * Cooked from passwd.c by Thomas Lundquist <thomasez@zelow.no>
+ */
+
+#include "libbb.h"
+
+#define TESTING 0
+
+/*
+set TESTING to 1 and pipe some file through this script
+if you played with bbox's crypt implementation.
+
+while read line; do
+ n=`./busybox cryptpw -a des -- "$line"`
+ o=`./busybox_org cryptpw -a des -- "$line"`
+ test "$n" != "$o" && {
+ echo n="$n"
+ echo o="$o"
+ exit
+ }
+ n=`./busybox cryptpw -- "$line"`
+ o=`./busybox_org cryptpw -- "$line"`
+ test "$n" != "$o" && {
+ echo n="$n"
+ echo o="$o"
+ exit
+ }
+done
+ */
+
+int cryptpw_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int cryptpw_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ char salt[sizeof("$N$XXXXXXXX")];
+ char *opt_a;
+
+ if (!getopt32(argv, "a:", &opt_a) || opt_a[0] != 'd') {
+ salt[0] = '$';
+ salt[1] = '1';
+ salt[2] = '$';
+ crypt_make_salt(salt + 3, 4, 0); /* md5 */
+#if TESTING
+ strcpy(salt + 3, "ajg./bcf");
+#endif
+ } else {
+ crypt_make_salt(salt, 1, 0); /* des */
+#if TESTING
+ strcpy(salt, "a.");
+#endif
+ }
+
+ puts(pw_encrypt(argv[optind] ? argv[optind] : xmalloc_fgetline(stdin), salt, 1));
+
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/loginutils/deluser.c b/cleopatre/busybox-1.11.1-spc300/loginutils/deluser.c
new file mode 100644
index 0000000000..c67ad72001
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/loginutils/deluser.c
@@ -0,0 +1,125 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * deluser/delgroup implementation for busybox
+ *
+ * Copyright (C) 1999 by Lineo, inc. and John Beppu
+ * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
+ * Copyright (C) 2007 by Tito Ragusa <farmatito@tiscali.it>
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ *
+ */
+
+#include "libbb.h"
+
+/* Status */
+#define STATUS_OK 0
+#define NAME_NOT_FOUND 1
+#define MEMBER_NOT_FOUND 2
+
+static void del_line_matching(char **args,
+ const char *filename,
+ FILE *(*fopen_func)(const char *fileName, const char *mode))
+{
+ FILE *passwd;
+ smallint error = NAME_NOT_FOUND;
+ char *name = (ENABLE_FEATURE_DEL_USER_FROM_GROUP && args[2]) ? args[2] : args[1];
+ char *line, *del;
+ char *new = xzalloc(1);
+
+ passwd = fopen_func(filename, "r");
+ if (passwd) {
+ while ((line = xmalloc_fgets(passwd))) {
+ int len = strlen(name);
+
+ if (strncmp(line, name, len) == 0
+ && line[len] == ':'
+ ) {
+ error = STATUS_OK;
+ if (ENABLE_FEATURE_DEL_USER_FROM_GROUP) {
+ struct group *gr;
+ char *p;
+ if (args[2]
+ /* There were two args on commandline */
+ && (gr = getgrnam(name))
+ /* The group was not deleted in the meanwhile */
+ && (p = strrchr(line, ':'))
+ /* We can find a pointer to the last ':' */
+ ) {
+ error = MEMBER_NOT_FOUND;
+ /* Move past ':' (worst case to '\0') and cut the line */
+ p[1] = '\0';
+ /* Reuse p */
+ for (p = xzalloc(1); *gr->gr_mem != NULL; gr->gr_mem++) {
+ /* Add all the other group members */
+ if (strcmp(args[1], *gr->gr_mem) != 0) {
+ del = p;
+ p = xasprintf("%s%s%s", p, p[0] ? "," : "", *gr->gr_mem);
+ free(del);
+ } else
+ error = STATUS_OK;
+ }
+ /* Recompose the line */
+ line = xasprintf("%s%s\n", line, p);
+ if (ENABLE_FEATURE_CLEAN_UP) free(p);
+ } else
+ goto skip;
+ }
+ }
+ del = new;
+ new = xasprintf("%s%s", new, line);
+ free(del);
+ skip:
+ free(line);
+ }
+
+ if (ENABLE_FEATURE_CLEAN_UP) fclose(passwd);
+
+ if (error) {
+ if (ENABLE_FEATURE_DEL_USER_FROM_GROUP && error == MEMBER_NOT_FOUND) {
+ /* Set the correct values for error message */
+ filename = name;
+ name = args[1];
+ }
+ bb_error_msg("can't find %s in %s", name, filename);
+ } else {
+ passwd = fopen_func(filename, "w");
+ if (passwd) {
+ fputs(new, passwd);
+ if (ENABLE_FEATURE_CLEAN_UP) fclose(passwd);
+ }
+ }
+ }
+ free(new);
+}
+
+int deluser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int deluser_main(int argc, char **argv)
+{
+ if (argc == 2
+ || (ENABLE_FEATURE_DEL_USER_FROM_GROUP
+ && (applet_name[3] == 'g' && argc == 3))
+ ) {
+ if (geteuid())
+ bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
+
+ if ((ENABLE_FEATURE_DEL_USER_FROM_GROUP && argc != 3)
+ || ENABLE_DELUSER
+ || (ENABLE_DELGROUP && ENABLE_DESKTOP)
+ ) {
+ if (ENABLE_DELUSER
+ && (!ENABLE_DELGROUP || applet_name[3] == 'u')
+ ) {
+ del_line_matching(argv, bb_path_passwd_file, xfopen);
+ if (ENABLE_FEATURE_SHADOWPASSWDS)
+ del_line_matching(argv, bb_path_shadow_file, fopen_or_warn);
+ } else if (ENABLE_DESKTOP && ENABLE_DELGROUP && getpwnam(argv[1]))
+ bb_error_msg_and_die("can't remove primary group of user %s", argv[1]);
+ }
+ del_line_matching(argv, bb_path_group_file, xfopen);
+ if (ENABLE_FEATURE_SHADOWPASSWDS)
+ del_line_matching(argv, bb_path_gshadow_file, fopen_or_warn);
+ return EXIT_SUCCESS;
+ } else
+ bb_show_usage();
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/loginutils/getty.c b/cleopatre/busybox-1.11.1-spc300/loginutils/getty.c
new file mode 100644
index 0000000000..13a8c0c6c0
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/loginutils/getty.c
@@ -0,0 +1,778 @@
+/* vi: set sw=4 ts=4: */
+/* agetty.c - another getty program for Linux. By W. Z. Venema 1989
+ * Ported to Linux by Peter Orbaek <poe@daimi.aau.dk>
+ * This program is freely distributable. The entire man-page used to
+ * be here. Now read the real man-page agetty.8 instead.
+ *
+ * option added by Eric Rasmussen <ear@usfirst.org> - 12/28/95
+ *
+ * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org>
+ * - added Native Language Support
+ *
+ * 1999-05-05 Thorsten Kranzkowski <dl8bcu@gmx.net>
+ * - enable hardware flow control before displaying /etc/issue
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include <syslog.h>
+
+#if ENABLE_FEATURE_UTMP
+#include <utmp.h>
+#endif
+
+/*
+ * Some heuristics to find out what environment we are in: if it is not
+ * System V, assume it is SunOS 4.
+ */
+#ifdef LOGIN_PROCESS /* defined in System V utmp.h */
+#include <sys/utsname.h>
+#include <time.h>
+#if ENABLE_FEATURE_WTMP
+extern void updwtmp(const char *filename, const struct utmp *ut);
+#endif
+#else /* if !sysV style, wtmp/utmp code is off */
+#undef ENABLE_FEATURE_UTMP
+#undef ENABLE_FEATURE_WTMP
+#define ENABLE_FEATURE_UTMP 0
+#define ENABLE_FEATURE_WTMP 0
+#endif /* LOGIN_PROCESS */
+
+/*
+ * Things you may want to modify.
+ *
+ * You may disagree with the default line-editing etc. characters defined
+ * below. Note, however, that DEL cannot be used for interrupt generation
+ * and for line editing at the same time.
+ */
+
+/* I doubt there are systems which still need this */
+#undef HANDLE_ALLCAPS
+#undef ANCIENT_BS_KILL_CHARS
+
+#define _PATH_LOGIN "/bin/login"
+
+/* If ISSUE is not defined, getty will never display the contents of the
+ * /etc/issue file. You will not want to spit out large "issue" files at the
+ * wrong baud rate.
+ */
+#define ISSUE "/etc/issue" /* displayed before the login prompt */
+
+/* Some shorthands for control characters. */
+#define CTL(x) ((x) ^ 0100) /* Assumes ASCII dialect */
+#define CR CTL('M') /* carriage return */
+#define NL CTL('J') /* line feed */
+#define BS CTL('H') /* back space */
+#define DEL CTL('?') /* delete */
+
+/* Defaults for line-editing etc. characters; you may want to change this. */
+#define DEF_ERASE DEL /* default erase character */
+#define DEF_INTR CTL('C') /* default interrupt character */
+#define DEF_QUIT CTL('\\') /* default quit char */
+#define DEF_KILL CTL('U') /* default kill char */
+#define DEF_EOF CTL('D') /* default EOF char */
+#define DEF_EOL '\n'
+#define DEF_SWITCH 0 /* default switch char */
+
+/*
+ * When multiple baud rates are specified on the command line, the first one
+ * we will try is the first one specified.
+ */
+#define MAX_SPEED 10 /* max. nr. of baud rates */
+
+/* Storage for command-line options. */
+struct options {
+ int flags; /* toggle switches, see below */
+ unsigned timeout; /* time-out period */
+ const char *login; /* login program */
+ const char *tty; /* name of tty */
+ const char *initstring; /* modem init string */
+ const char *issue; /* alternative issue file */
+ int numspeed; /* number of baud rates to try */
+ int speeds[MAX_SPEED]; /* baud rates to be tried */
+};
+
+/* Storage for things detected while the login name was read. */
+struct chardata {
+ unsigned char erase; /* erase character */
+ unsigned char kill; /* kill character */
+ unsigned char eol; /* end-of-line character */
+ unsigned char parity; /* what parity did we see */
+ /* (parity & 1): saw odd parity char with 7th bit set */
+ /* (parity & 2): saw even parity char with 7th bit set */
+ /* parity == 0: probably 7-bit, space parity? */
+ /* parity == 1: probably 7-bit, odd parity? */
+ /* parity == 2: probably 7-bit, even parity? */
+ /* parity == 3: definitely 8 bit, no parity! */
+ /* Hmm... with any value of "parity" 8 bit, no parity is possible */
+#ifdef HANDLE_ALLCAPS
+ unsigned char capslock; /* upper case without lower case */
+#endif
+};
+
+
+/* Initial values for the above. */
+static const struct chardata init_chardata = {
+ DEF_ERASE, /* default erase character */
+ DEF_KILL, /* default kill character */
+ 13, /* default eol char */
+ 0, /* space parity */
+#ifdef HANDLE_ALLCAPS
+ 0, /* no capslock */
+#endif
+};
+
+static const char opt_string[] ALIGN1 = "I:LH:f:hil:mt:wn";
+#define F_INITSTRING (1 << 0) /* -I initstring is set */
+#define F_LOCAL (1 << 1) /* -L force local */
+#define F_FAKEHOST (1 << 2) /* -H fake hostname */
+#define F_CUSTISSUE (1 << 3) /* -f give alternative issue file */
+#define F_RTSCTS (1 << 4) /* -h enable RTS/CTS flow control */
+#define F_ISSUE (1 << 5) /* -i display /etc/issue */
+#define F_LOGIN (1 << 6) /* -l non-default login program */
+#define F_PARSE (1 << 7) /* -m process modem status messages */
+#define F_TIMEOUT (1 << 8) /* -t time out */
+#define F_WAITCRLF (1 << 9) /* -w wait for CR or LF */
+#define F_NOPROMPT (1 << 10) /* -n don't ask for login name */
+
+
+#define line_buf bb_common_bufsiz1
+
+/* The following is used for understandable diagnostics. */
+#ifdef DEBUGGING
+static FILE *dbf;
+#define DEBUGTERM "/dev/ttyp0"
+#define debug(...) do { fprintf(dbf, __VA_ARGS__); fflush(dbf); } while (0)
+#else
+#define debug(...) ((void)0)
+#endif
+
+
+/* bcode - convert speed string to speed code; return <= 0 on failure */
+static int bcode(const char *s)
+{
+ int value = bb_strtou(s, NULL, 10); /* yes, int is intended! */
+ if (value < 0) /* bad terminating char, overflow, etc */
+ return value;
+ return tty_value_to_baud(value);
+}
+
+/* parse_speeds - parse alternate baud rates */
+static void parse_speeds(struct options *op, char *arg)
+{
+ char *cp;
+
+ /* NB: at least one iteration is always done */
+ debug("entered parse_speeds\n");
+ while ((cp = strsep(&arg, ",")) != NULL) {
+ op->speeds[op->numspeed] = bcode(cp);
+ if (op->speeds[op->numspeed] <= 0)
+ bb_error_msg_and_die("bad speed: %s", cp);
+ op->numspeed++;
+ if (op->numspeed > MAX_SPEED)
+ bb_error_msg_and_die("too many alternate speeds");
+ }
+ debug("exiting parse_speeds\n");
+}
+
+/* parse_args - parse command-line arguments */
+static void parse_args(char **argv, struct options *op, char **fakehost_p)
+{
+ char *ts;
+
+ opt_complementary = "-2:t+"; /* at least 2 args; -t N */
+ op->flags = getopt32(argv, opt_string,
+ &(op->initstring), fakehost_p, &(op->issue),
+ &(op->login), &op->timeout);
+ argv += optind;
+ if (op->flags & F_INITSTRING) {
+ const char *p = op->initstring;
+ char *q;
+
+ op->initstring = q = xstrdup(p);
+ /* copy optarg into op->initstring decoding \ddd
+ octal codes into chars */
+ while (*p) {
+ if (*p == '\\') {
+ p++;
+ *q++ = bb_process_escape_sequence(&p);
+ } else {
+ *q++ = *p++;
+ }
+ }
+ *q = '\0';
+ }
+ op->flags ^= F_ISSUE; /* invert flag "show /etc/issue" */
+ debug("after getopt\n");
+
+ /* we loosen up a bit and accept both "baudrate tty" and "tty baudrate" */
+ op->tty = argv[0]; /* tty name */
+ ts = argv[1]; /* baud rate(s) */
+ if (isdigit(argv[0][0])) {
+ /* a number first, assume it's a speed (BSD style) */
+ op->tty = ts; /* tty name is in argv[1] */
+ ts = argv[0]; /* baud rate(s) */
+ }
+ parse_speeds(op, ts);
+
+// TODO: if applet_name is set to "getty: TTY", bb_error_msg's get simpler!
+// grep for "%s:"
+
+ if (argv[2])
+ xsetenv("TERM", argv[2]);
+
+ debug("exiting parse_args\n");
+}
+
+/* open_tty - set up tty as standard { input, output, error } */
+static void open_tty(const char *tty)
+{
+ /* Set up new standard input, unless we are given an already opened port. */
+ if (NOT_LONE_DASH(tty)) {
+// struct stat st;
+// int cur_dir_fd;
+// int fd;
+
+ /* Sanity checks... */
+// cur_dir_fd = xopen(".", O_DIRECTORY | O_NONBLOCK);
+// xchdir("/dev");
+// xstat(tty, &st);
+// if ((st.st_mode & S_IFMT) != S_IFCHR)
+// bb_error_msg_and_die("%s: not a character device", tty);
+
+ if (tty[0] != '/')
+ tty = xasprintf("/dev/%s", tty); /* will leak it */
+
+ /* Open the tty as standard input. */
+ debug("open(2)\n");
+ close(0);
+ /*fd =*/ xopen(tty, O_RDWR | O_NONBLOCK); /* uses fd 0 */
+
+// /* Restore current directory */
+// fchdir(cur_dir_fd);
+
+ /* Open the tty as standard input, continued */
+// xmove_fd(fd, 0);
+// /* fd is >= cur_dir_fd, and cur_dir_fd gets closed too here: */
+// while (fd > 2)
+// close(fd--);
+
+ /* Set proper protections and ownership. */
+ fchown(0, 0, 0); /* 0:0 */
+ fchmod(0, 0620); /* crw--w---- */
+ } else {
+ /*
+ * Standard input should already be connected to an open port. Make
+ * sure it is open for read/write.
+ */
+ if ((fcntl(0, F_GETFL) & O_RDWR) != O_RDWR)
+ bb_error_msg_and_die("stdin is not open for read/write");
+ }
+}
+
+/* termios_init - initialize termios settings */
+static void termios_init(struct termios *tp, int speed, struct options *op)
+{
+ /*
+ * Initial termios settings: 8-bit characters, raw-mode, blocking i/o.
+ * Special characters are set after we have read the login name; all
+ * reads will be done in raw mode anyway. Errors will be dealt with
+ * later on.
+ */
+#ifdef __linux__
+ /* flush input and output queues, important for modems! */
+ ioctl(0, TCFLSH, TCIOFLUSH);
+#endif
+
+ tp->c_cflag = CS8 | HUPCL | CREAD | speed;
+ if (op->flags & F_LOCAL)
+ tp->c_cflag |= CLOCAL;
+
+ tp->c_iflag = tp->c_lflag = tp->c_line = 0;
+ tp->c_oflag = OPOST | ONLCR;
+ tp->c_cc[VMIN] = 1;
+ tp->c_cc[VTIME] = 0;
+
+ /* Optionally enable hardware flow control */
+#ifdef CRTSCTS
+ if (op->flags & F_RTSCTS)
+ tp->c_cflag |= CRTSCTS;
+#endif
+
+ ioctl(0, TCSETS, tp);
+
+ debug("term_io 2\n");
+}
+
+/* auto_baud - extract baud rate from modem status message */
+static void auto_baud(char *buf, unsigned size_buf, struct termios *tp)
+{
+ int speed;
+ int vmin;
+ unsigned iflag;
+ char *bp;
+ int nread;
+
+ /*
+ * This works only if the modem produces its status code AFTER raising
+ * the DCD line, and if the computer is fast enough to set the proper
+ * baud rate before the message has gone by. We expect a message of the
+ * following format:
+ *
+ * <junk><number><junk>
+ *
+ * The number is interpreted as the baud rate of the incoming call. If the
+ * modem does not tell us the baud rate within one second, we will keep
+ * using the current baud rate. It is advisable to enable BREAK
+ * processing (comma-separated list of baud rates) if the processing of
+ * modem status messages is enabled.
+ */
+
+ /*
+ * Use 7-bit characters, don't block if input queue is empty. Errors will
+ * be dealt with later on.
+ */
+ iflag = tp->c_iflag;
+ tp->c_iflag |= ISTRIP; /* enable 8th-bit stripping */
+ vmin = tp->c_cc[VMIN];
+ tp->c_cc[VMIN] = 0; /* don't block if queue empty */
+ ioctl(0, TCSETS, tp);
+
+ /*
+ * Wait for a while, then read everything the modem has said so far and
+ * try to extract the speed of the dial-in call.
+ */
+ sleep(1);
+ nread = safe_read(STDIN_FILENO, buf, size_buf - 1);
+ if (nread > 0) {
+ buf[nread] = '\0';
+ for (bp = buf; bp < buf + nread; bp++) {
+ if (isdigit(*bp)) {
+ speed = bcode(bp);
+ if (speed > 0) {
+ tp->c_cflag &= ~CBAUD;
+ tp->c_cflag |= speed;
+ }
+ break;
+ }
+ }
+ }
+
+ /* Restore terminal settings. Errors will be dealt with later on. */
+ tp->c_iflag = iflag;
+ tp->c_cc[VMIN] = vmin;
+ ioctl(0, TCSETS, tp);
+}
+
+/* do_prompt - show login prompt, optionally preceded by /etc/issue contents */
+static void do_prompt(struct options *op)
+{
+#ifdef ISSUE
+ print_login_issue(op->issue, op->tty);
+#endif
+ print_login_prompt();
+}
+
+#ifdef HANDLE_ALLCAPS
+/* all_is_upcase - string contains upper case without lower case */
+/* returns 1 if true, 0 if false */
+static int all_is_upcase(const char *s)
+{
+ while (*s)
+ if (islower(*s++))
+ return 0;
+ return 1;
+}
+#endif
+
+/* get_logname - get user name, establish parity, speed, erase, kill, eol;
+ * return NULL on BREAK, logname on success */
+static char *get_logname(char *logname, unsigned size_logname,
+ struct options *op, struct chardata *cp)
+{
+ char *bp;
+ char c; /* input character, full eight bits */
+ char ascval; /* low 7 bits of input character */
+ int bits; /* # of "1" bits per character */
+ int mask; /* mask with 1 bit up */
+ static const char erase[][3] = {/* backspace-space-backspace */
+ "\010\040\010", /* space parity */
+ "\010\040\010", /* odd parity */
+ "\210\240\210", /* even parity */
+ "\010\040\010", /* 8 bit no parity */
+ };
+
+ /* NB: *cp is pre-initialized with init_chardata */
+
+ /* Flush pending input (esp. after parsing or switching the baud rate). */
+ sleep(1);
+ ioctl(0, TCFLSH, TCIFLUSH);
+
+ /* Prompt for and read a login name. */
+ logname[0] = '\0';
+ while (!logname[0]) {
+ /* Write issue file and prompt, with "parity" bit == 0. */
+ do_prompt(op);
+
+ /* Read name, watch for break, parity, erase, kill, end-of-line. */
+ bp = logname;
+ cp->eol = '\0';
+ while (cp->eol == '\0') {
+
+ /* Do not report trivial EINTR/EIO errors. */
+ if (read(STDIN_FILENO, &c, 1) < 1) {
+ if (errno == EINTR || errno == EIO)
+ exit(EXIT_SUCCESS);
+ bb_perror_msg_and_die("%s: read", op->tty);
+ }
+
+ /* BREAK. If we have speeds to try,
+ * return NULL (will switch speeds and return here) */
+ if (c == '\0' && op->numspeed > 1)
+ return NULL;
+
+ /* Do parity bit handling. */
+ if (!(op->flags & F_LOCAL) && (c & 0x80)) { /* "parity" bit on? */
+ bits = 1;
+ mask = 1;
+ while (mask & 0x7f) {
+ if (mask & c)
+ bits++; /* count "1" bits */
+ mask <<= 1;
+ }
+ /* ... |= 2 - even, 1 - odd */
+ cp->parity |= 2 - (bits & 1);
+ }
+
+ /* Do erase, kill and end-of-line processing. */
+ ascval = c & 0x7f;
+ switch (ascval) {
+ case CR:
+ case NL:
+ *bp = '\0'; /* terminate logname */
+ cp->eol = ascval; /* set end-of-line char */
+ break;
+ case BS:
+ case DEL:
+#ifdef ANCIENT_BS_KILL_CHARS
+ case '#':
+#endif
+ cp->erase = ascval; /* set erase character */
+ if (bp > logname) {
+ full_write(STDOUT_FILENO, erase[cp->parity], 3);
+ bp--;
+ }
+ break;
+ case CTL('U'):
+#ifdef ANCIENT_BS_KILL_CHARS
+ case '@':
+#endif
+ cp->kill = ascval; /* set kill character */
+ while (bp > logname) {
+ full_write(STDOUT_FILENO, erase[cp->parity], 3);
+ bp--;
+ }
+ break;
+ case CTL('D'):
+ exit(EXIT_SUCCESS);
+ default:
+ if (!isascii(ascval) || !isprint(ascval)) {
+ /* ignore garbage characters */
+ } else if ((int)(bp - logname) >= size_logname - 1) {
+ bb_error_msg_and_die("%s: input overrun", op->tty);
+ } else {
+ full_write(STDOUT_FILENO, &c, 1); /* echo the character */
+ *bp++ = ascval; /* and store it */
+ }
+ break;
+ }
+ }
+ }
+ /* Handle names with upper case and no lower case. */
+
+#ifdef HANDLE_ALLCAPS
+ cp->capslock = all_is_upcase(logname);
+ if (cp->capslock) {
+ for (bp = logname; *bp; bp++)
+ if (isupper(*bp))
+ *bp = tolower(*bp); /* map name to lower case */
+ }
+#endif
+ return logname;
+}
+
+/* termios_final - set the final tty mode bits */
+static void termios_final(struct options *op, struct termios *tp, struct chardata *cp)
+{
+ /* General terminal-independent stuff. */
+ tp->c_iflag |= IXON | IXOFF; /* 2-way flow control */
+ tp->c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE;
+ /* no longer| ECHOCTL | ECHOPRT */
+ tp->c_oflag |= OPOST;
+ /* tp->c_cflag = 0; */
+ tp->c_cc[VINTR] = DEF_INTR; /* default interrupt */
+ tp->c_cc[VQUIT] = DEF_QUIT; /* default quit */
+ tp->c_cc[VEOF] = DEF_EOF; /* default EOF character */
+ tp->c_cc[VEOL] = DEF_EOL;
+ tp->c_cc[VSWTC] = DEF_SWITCH; /* default switch character */
+
+ /* Account for special characters seen in input. */
+ if (cp->eol == CR) {
+ tp->c_iflag |= ICRNL; /* map CR in input to NL */
+ tp->c_oflag |= ONLCR; /* map NL in output to CR-NL */
+ }
+ tp->c_cc[VERASE] = cp->erase; /* set erase character */
+ tp->c_cc[VKILL] = cp->kill; /* set kill character */
+
+ /* Account for the presence or absence of parity bits in input. */
+ switch (cp->parity) {
+ case 0: /* space (always 0) parity */
+// I bet most people go here - they use only 7-bit chars in usernames....
+ break;
+ case 1: /* odd parity */
+ tp->c_cflag |= PARODD;
+ /* FALLTHROUGH */
+ case 2: /* even parity */
+ tp->c_cflag |= PARENB;
+ tp->c_iflag |= INPCK | ISTRIP;
+ /* FALLTHROUGH */
+ case (1 | 2): /* no parity bit */
+ tp->c_cflag &= ~CSIZE;
+ tp->c_cflag |= CS7;
+// FIXME: wtf? case 3: we saw both even and odd 8-bit bytes -
+// it's probably some umlauts etc, but definitely NOT 7-bit!!!
+// Entire parity detection madness here just begs for deletion...
+ break;
+ }
+
+ /* Account for upper case without lower case. */
+#ifdef HANDLE_ALLCAPS
+ if (cp->capslock) {
+ tp->c_iflag |= IUCLC;
+ tp->c_lflag |= XCASE;
+ tp->c_oflag |= OLCUC;
+ }
+#endif
+ /* Optionally enable hardware flow control */
+#ifdef CRTSCTS
+ if (op->flags & F_RTSCTS)
+ tp->c_cflag |= CRTSCTS;
+#endif
+
+ /* Finally, make the new settings effective */
+ ioctl_or_perror_and_die(0, TCSETS, tp, "%s: TCSETS", op->tty);
+}
+
+#if ENABLE_FEATURE_UTMP
+static void touch(const char *filename)
+{
+ if (access(filename, R_OK | W_OK) == -1)
+ close(open(filename, O_WRONLY | O_CREAT, 0664));
+}
+
+/* update_utmp - update our utmp entry */
+static void update_utmp(const char *line, char *fakehost)
+{
+ struct utmp ut;
+ struct utmp *utp;
+ int mypid = getpid();
+
+ /* In case we won't find an entry below... */
+ memset(&ut, 0, sizeof(ut));
+ safe_strncpy(ut.ut_id, line + 3, sizeof(ut.ut_id));
+
+ /*
+ * The utmp file holds miscellaneous information about things started by
+ * /sbin/init and other system-related events. Our purpose is to update
+ * the utmp entry for the current process, in particular the process type
+ * and the tty line we are listening to. Return successfully only if the
+ * utmp file can be opened for update, and if we are able to find our
+ * entry in the utmp file.
+ */
+ touch(_PATH_UTMP);
+
+ utmpname(_PATH_UTMP);
+ setutent();
+ while ((utp = getutent()) != NULL) {
+ if (utp->ut_type == INIT_PROCESS && utp->ut_pid == mypid) {
+ memcpy(&ut, utp, sizeof(ut));
+ break;
+ }
+ }
+
+ strcpy(ut.ut_user, "LOGIN");
+ safe_strncpy(ut.ut_line, line, sizeof(ut.ut_line));
+ if (fakehost)
+ safe_strncpy(ut.ut_host, fakehost, sizeof(ut.ut_host));
+ ut.ut_tv.tv_sec = time(NULL);
+ ut.ut_type = LOGIN_PROCESS;
+ ut.ut_pid = mypid;
+
+ pututline(&ut);
+ endutent();
+
+#if ENABLE_FEATURE_WTMP
+ touch(bb_path_wtmp_file);
+ updwtmp(bb_path_wtmp_file, &ut);
+#endif
+}
+#endif /* CONFIG_FEATURE_UTMP */
+
+int getty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int getty_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ int n;
+ char *fakehost = NULL; /* Fake hostname for ut_host */
+ char *logname; /* login name, given to /bin/login */
+ /* Merging these into "struct local" may _seem_ to reduce
+ * parameter passing, but today's gcc will inline
+ * statics which are called once anyway, so don't do that */
+ struct chardata chardata; /* set by get_logname() */
+ struct termios termios; /* terminal mode bits */
+ struct options options;
+
+ chardata = init_chardata;
+
+ memset(&options, 0, sizeof(options));
+ options.login = _PATH_LOGIN; /* default login program */
+ options.tty = "tty1"; /* default tty line */
+ options.initstring = ""; /* modem init string */
+#ifdef ISSUE
+ options.issue = ISSUE; /* default issue file */
+#endif
+
+ /* Parse command-line arguments. */
+ parse_args(argv, &options, &fakehost);
+
+ logmode = LOGMODE_NONE;
+
+ /* Create new session, lose controlling tty, if any */
+ /* docs/ctty.htm says:
+ * "This is allowed only when the current process
+ * is not a process group leader" - is this a problem? */
+ setsid();
+ /* close stdio, and stray descriptors, just in case */
+ n = xopen(bb_dev_null, O_RDWR);
+ /* dup2(n, 0); - no, we need to handle "getty - 9600" too */
+ xdup2(n, 1);
+ xdup2(n, 2);
+ while (n > 2)
+ close(n--);
+
+ /* Logging. We want special flavor of error_msg_and_die */
+ die_sleep = 10;
+ msg_eol = "\r\n";
+ /* most likely will internally use fd #3 in CLOEXEC mode: */
+ openlog(applet_name, LOG_PID, LOG_AUTH);
+ logmode = LOGMODE_BOTH;
+
+#ifdef DEBUGGING
+ dbf = xfopen(DEBUGTERM, "w");
+ for (n = 1; argv[n]; n++) {
+ debug(argv[n]);
+ debug("\n");
+ }
+#endif
+
+ /* Open the tty as standard input, if it is not "-" */
+ /* If it's not "-" and not taken yet, it will become our ctty */
+ debug("calling open_tty\n");
+ open_tty(options.tty);
+ ndelay_off(0);
+ debug("duping\n");
+ xdup2(0, 1);
+ xdup2(0, 2);
+
+ /*
+ * The following ioctl will fail if stdin is not a tty, but also when
+ * there is noise on the modem control lines. In the latter case, the
+ * common course of action is (1) fix your cables (2) give the modem more
+ * time to properly reset after hanging up. SunOS users can achieve (2)
+ * by patching the SunOS kernel variable "zsadtrlow" to a larger value;
+ * 5 seconds seems to be a good value.
+ */
+ ioctl_or_perror_and_die(0, TCGETS, &termios, "%s: TCGETS", options.tty);
+
+#ifdef __linux__
+// FIXME: do we need this? Otherwise "-" case seems to be broken...
+ // /* Forcibly make fd 0 our controlling tty, even if another session
+ // * has it as a ctty. (Another session loses ctty). */
+ // ioctl(0, TIOCSCTTY, (void*)1);
+ /* Make ourself a foreground process group within our session */
+ tcsetpgrp(0, getpid());
+#endif
+
+#if ENABLE_FEATURE_UTMP
+ /* Update the utmp file. This tty is ours now! */
+ update_utmp(options.tty, fakehost);
+#endif
+
+ /* Initialize the termios settings (raw mode, eight-bit, blocking i/o). */
+ debug("calling termios_init\n");
+ termios_init(&termios, options.speeds[0], &options);
+
+ /* Write the modem init string and DON'T flush the buffers */
+ if (options.flags & F_INITSTRING) {
+ debug("writing init string\n");
+ full_write(STDOUT_FILENO, options.initstring, strlen(options.initstring));
+ }
+
+ /* Optionally detect the baud rate from the modem status message */
+ debug("before autobaud\n");
+ if (options.flags & F_PARSE)
+ auto_baud(line_buf, sizeof(line_buf), &termios);
+
+ /* Set the optional timer */
+ alarm(options.timeout); /* if 0, alarm is not set */
+
+ /* Optionally wait for CR or LF before writing /etc/issue */
+ if (options.flags & F_WAITCRLF) {
+ char ch;
+
+ debug("waiting for cr-lf\n");
+ while (safe_read(STDIN_FILENO, &ch, 1) == 1) {
+ debug("read %x\n", (unsigned char)ch);
+ ch &= 0x7f; /* strip "parity bit" */
+ if (ch == '\n' || ch == '\r')
+ break;
+ }
+ }
+
+ logname = NULL;
+ if (!(options.flags & F_NOPROMPT)) {
+ /* NB:termios_init already set line speed
+ * to options.speeds[0] */
+ int baud_index = 0;
+
+ while (1) {
+ /* Read the login name. */
+ debug("reading login name\n");
+ logname = get_logname(line_buf, sizeof(line_buf),
+ &options, &chardata);
+ if (logname)
+ break;
+ /* we are here only if options.numspeed > 1 */
+ baud_index = (baud_index + 1) % options.numspeed;
+ termios.c_cflag &= ~CBAUD;
+ termios.c_cflag |= options.speeds[baud_index];
+ ioctl(0, TCSETS, &termios);
+ }
+ }
+
+ /* Disable timer. */
+ alarm(0);
+
+ /* Finalize the termios settings. */
+ termios_final(&options, &termios, &chardata);
+
+ /* Now the newline character should be properly written. */
+ full_write(STDOUT_FILENO, "\n", 1);
+
+ /* Let the login program take care of password validation. */
+ /* We use PATH because we trust that root doesn't set "bad" PATH,
+ * and getty is not suid-root applet. */
+ /* With -n, logname == NULL, and login will ask for username instead */
+ BB_EXECLP(options.login, options.login, "--", logname, NULL);
+ bb_error_msg_and_die("%s: can't exec %s", options.tty, options.login);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/loginutils/login.c b/cleopatre/busybox-1.11.1-spc300/loginutils/login.c
new file mode 100644
index 0000000000..d9a2f8a419
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/loginutils/login.c
@@ -0,0 +1,502 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include <syslog.h>
+#include <utmp.h>
+#include <sys/resource.h>
+
+#if ENABLE_SELINUX
+#include <selinux/selinux.h> /* for is_selinux_enabled() */
+#include <selinux/get_context_list.h> /* for get_default_context() */
+#include <selinux/flask.h> /* for security class definitions */
+#endif
+
+#if ENABLE_PAM
+/* PAM may include <locale.h>. We may need to undefine bbox's stub define: */
+#undef setlocale
+/* For some obscure reason, PAM is not in pam/xxx, but in security/xxx.
+ * Apparently they like to confuse people. */
+#include <security/pam_appl.h>
+#include <security/pam_misc.h>
+static const struct pam_conv conv = {
+ misc_conv,
+ NULL
+};
+#endif
+
+enum {
+ TIMEOUT = 60,
+ EMPTY_USERNAME_COUNT = 10,
+ USERNAME_SIZE = 32,
+ TTYNAME_SIZE = 32,
+};
+
+static char* short_tty;
+
+#if ENABLE_FEATURE_UTMP
+/* vv Taken from tinylogin utmp.c vv */
+/*
+ * read_or_build_utent - see if utmp file is correct for this process
+ *
+ * System V is very picky about the contents of the utmp file
+ * and requires that a slot for the current process exist.
+ * The utmp file is scanned for an entry with the same process
+ * ID. If no entry exists the process exits with a message.
+ *
+ * The "picky" flag is for network and other logins that may
+ * use special flags. It allows the pid checks to be overridden.
+ * This means that getty should never invoke login with any
+ * command line flags.
+ */
+
+static void read_or_build_utent(struct utmp *utptr, int picky)
+{
+ struct utmp *ut;
+ pid_t pid = getpid();
+
+ setutent();
+
+ /* First, try to find a valid utmp entry for this process. */
+ while ((ut = getutent()))
+ if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] &&
+ (ut->ut_type == LOGIN_PROCESS || ut->ut_type == USER_PROCESS))
+ break;
+
+ /* If there is one, just use it, otherwise create a new one. */
+ if (ut) {
+ *utptr = *ut;
+ } else {
+ if (picky)
+ bb_error_msg_and_die("no utmp entry found");
+
+ memset(utptr, 0, sizeof(*utptr));
+ utptr->ut_type = LOGIN_PROCESS;
+ utptr->ut_pid = pid;
+ strncpy(utptr->ut_line, short_tty, sizeof(utptr->ut_line));
+ /* This one is only 4 chars wide. Try to fit something
+ * remotely meaningful by skipping "tty"... */
+ strncpy(utptr->ut_id, short_tty + 3, sizeof(utptr->ut_id));
+ strncpy(utptr->ut_user, "LOGIN", sizeof(utptr->ut_user));
+ utptr->ut_tv.tv_sec = time(NULL);
+ }
+ if (!picky) /* root login */
+ memset(utptr->ut_host, 0, sizeof(utptr->ut_host));
+}
+
+/*
+ * write_utent - put a USER_PROCESS entry in the utmp file
+ *
+ * write_utent changes the type of the current utmp entry to
+ * USER_PROCESS. the wtmp file will be updated as well.
+ */
+static void write_utent(struct utmp *utptr, const char *username)
+{
+ utptr->ut_type = USER_PROCESS;
+ strncpy(utptr->ut_user, username, sizeof(utptr->ut_user));
+ utptr->ut_tv.tv_sec = time(NULL);
+ /* other fields already filled in by read_or_build_utent above */
+ setutent();
+ pututline(utptr);
+ endutent();
+#if ENABLE_FEATURE_WTMP
+ if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) {
+ close(creat(bb_path_wtmp_file, 0664));
+ }
+ updwtmp(bb_path_wtmp_file, utptr);
+#endif
+}
+#else /* !ENABLE_FEATURE_UTMP */
+#define read_or_build_utent(utptr, picky) ((void)0)
+#define write_utent(utptr, username) ((void)0)
+#endif /* !ENABLE_FEATURE_UTMP */
+
+#if ENABLE_FEATURE_NOLOGIN
+static void die_if_nologin(void)
+{
+ FILE *fp;
+ int c;
+
+ if (access("/etc/nologin", F_OK))
+ return;
+
+ fp = fopen("/etc/nologin", "r");
+ if (fp) {
+ while ((c = getc(fp)) != EOF)
+ bb_putchar((c=='\n') ? '\r' : c);
+ fflush(stdout);
+ fclose(fp);
+ } else
+ puts("\r\nSystem closed for routine maintenance\r");
+ exit(EXIT_FAILURE);
+}
+#else
+static ALWAYS_INLINE void die_if_nologin(void) {}
+#endif
+
+#if ENABLE_FEATURE_SECURETTY && !ENABLE_PAM
+static int check_securetty(void)
+{
+ FILE *fp;
+ int i;
+ char buf[256];
+
+ fp = fopen("/etc/securetty", "r");
+ if (!fp) {
+ /* A missing securetty file is not an error. */
+ return 1;
+ }
+ while (fgets(buf, sizeof(buf)-1, fp)) {
+ for (i = strlen(buf)-1; i >= 0; --i) {
+ if (!isspace(buf[i]))
+ break;
+ }
+ buf[++i] = '\0';
+ if (!buf[0] || (buf[0] == '#'))
+ continue;
+ if (strcmp(buf, short_tty) == 0) {
+ fclose(fp);
+ return 1;
+ }
+ }
+ fclose(fp);
+ return 0;
+}
+#else
+static ALWAYS_INLINE int check_securetty(void) { return 1; }
+#endif
+
+static void get_username_or_die(char *buf, int size_buf)
+{
+ int c, cntdown;
+
+ cntdown = EMPTY_USERNAME_COUNT;
+ prompt:
+ print_login_prompt();
+ /* skip whitespace */
+ do {
+ c = getchar();
+ if (c == EOF) exit(EXIT_FAILURE);
+ if (c == '\n') {
+ if (!--cntdown) exit(EXIT_FAILURE);
+ goto prompt;
+ }
+ } while (isspace(c));
+
+ *buf++ = c;
+ if (!fgets(buf, size_buf-2, stdin))
+ exit(EXIT_FAILURE);
+ if (!strchr(buf, '\n'))
+ exit(EXIT_FAILURE);
+ while (isgraph(*buf)) buf++;
+ *buf = '\0';
+}
+
+static void motd(void)
+{
+ int fd;
+
+ fd = open(bb_path_motd_file, O_RDONLY);
+ if (fd >= 0) {
+ fflush(stdout);
+ bb_copyfd_eof(fd, STDOUT_FILENO);
+ close(fd);
+ }
+}
+
+static void alarm_handler(int sig ATTRIBUTE_UNUSED)
+{
+ /* This is the escape hatch! Poor serial line users and the like
+ * arrive here when their connection is broken.
+ * We don't want to block here */
+ ndelay_on(1);
+ printf("\r\nLogin timed out after %d seconds\r\n", TIMEOUT);
+ fflush(stdout);
+ /* unix API is brain damaged regarding O_NONBLOCK,
+ * we should undo it, or else we can affect other processes */
+ ndelay_off(1);
+ _exit(EXIT_SUCCESS);
+}
+
+int login_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int login_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ enum {
+ LOGIN_OPT_f = (1<<0),
+ LOGIN_OPT_h = (1<<1),
+ LOGIN_OPT_p = (1<<2),
+ };
+ char *fromhost;
+ char username[USERNAME_SIZE];
+ const char *tmp;
+ int amroot;
+ unsigned opt;
+ int count = 0;
+ struct passwd *pw;
+ char *opt_host = opt_host; /* for compiler */
+ char *opt_user = opt_user; /* for compiler */
+ char full_tty[TTYNAME_SIZE];
+ USE_SELINUX(security_context_t user_sid = NULL;)
+ USE_FEATURE_UTMP(struct utmp utent;)
+#if ENABLE_PAM
+ int pamret;
+ pam_handle_t *pamh;
+ const char *pamuser;
+ const char *failed_msg;
+ struct passwd pwdstruct;
+ char pwdbuf[256];
+#endif
+
+ short_tty = full_tty;
+ username[0] = '\0';
+ signal(SIGALRM, alarm_handler);
+ alarm(TIMEOUT);
+
+ /* More of suid paranoia if called by non-root */
+ amroot = !sanitize_env_if_suid(); /* Clear dangerous stuff, set PATH */
+
+ /* Mandatory paranoia for suid applet:
+ * ensure that fd# 0,1,2 are opened (at least to /dev/null)
+ * and any extra open fd's are closed.
+ * (The name of the function is misleading. Not daemonizing here.) */
+ bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE | DAEMON_CLOSE_EXTRA_FDS, NULL);
+
+ opt = getopt32(argv, "f:h:p", &opt_user, &opt_host);
+ if (opt & LOGIN_OPT_f) {
+ if (!amroot)
+ bb_error_msg_and_die("-f is for root only");
+ safe_strncpy(username, opt_user, sizeof(username));
+ }
+ argv += optind;
+ if (argv[0]) /* user from command line (getty) */
+ safe_strncpy(username, argv[0], sizeof(username));
+
+ /* Let's find out and memorize our tty */
+ if (!isatty(0) || !isatty(1) || !isatty(2))
+ return EXIT_FAILURE; /* Must be a terminal */
+ safe_strncpy(full_tty, "UNKNOWN", sizeof(full_tty));
+ tmp = ttyname(0);
+ if (tmp) {
+ safe_strncpy(full_tty, tmp, sizeof(full_tty));
+ if (strncmp(full_tty, "/dev/", 5) == 0)
+ short_tty = full_tty + 5;
+ }
+
+ read_or_build_utent(&utent, !amroot);
+
+ if (opt & LOGIN_OPT_h) {
+ USE_FEATURE_UTMP(
+ safe_strncpy(utent.ut_host, opt_host, sizeof(utent.ut_host));
+ )
+ fromhost = xasprintf(" on '%s' from '%s'", short_tty, opt_host);
+ } else
+ fromhost = xasprintf(" on '%s'", short_tty);
+
+ /* Was breaking "login <username>" from shell command line: */
+ /*bb_setpgrp();*/
+
+ openlog(applet_name, LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH);
+
+ while (1) {
+ /* flush away any type-ahead (as getty does) */
+ ioctl(0, TCFLSH, TCIFLUSH);
+
+ if (!username[0])
+ get_username_or_die(username, sizeof(username));
+
+#if ENABLE_PAM
+ pamret = pam_start("login", username, &conv, &pamh);
+ if (pamret != PAM_SUCCESS) {
+ failed_msg = "start";
+ goto pam_auth_failed;
+ }
+ /* set TTY (so things like securetty work) */
+ pamret = pam_set_item(pamh, PAM_TTY, short_tty);
+ if (pamret != PAM_SUCCESS) {
+ failed_msg = "set_item(TTY)";
+ goto pam_auth_failed;
+ }
+ pamret = pam_authenticate(pamh, 0);
+ if (pamret != PAM_SUCCESS) {
+ failed_msg = "authenticate";
+ goto pam_auth_failed;
+ /* TODO: or just "goto auth_failed"
+ * since user seems to enter wrong password
+ * (in this case pamret == 7)
+ */
+ }
+ /* check that the account is healthy */
+ pamret = pam_acct_mgmt(pamh, 0);
+ if (pamret != PAM_SUCCESS) {
+ failed_msg = "acct_mgmt";
+ goto pam_auth_failed;
+ }
+ /* read user back */
+ pamuser = NULL;
+ /* gcc: "dereferencing type-punned pointer breaks aliasing rules..."
+ * thus we cast to (void*) */
+ if (pam_get_item(pamh, PAM_USER, (void*)&pamuser) != PAM_SUCCESS) {
+ failed_msg = "get_item(USER)";
+ goto pam_auth_failed;
+ }
+ if (!pamuser || !pamuser[0])
+ goto auth_failed;
+ safe_strncpy(username, pamuser, sizeof(username));
+ /* Don't use "pw = getpwnam(username);",
+ * PAM is said to be capable of destroying static storage
+ * used by getpwnam(). We are using safe(r) function */
+ pw = NULL;
+ getpwnam_r(username, &pwdstruct, pwdbuf, sizeof(pwdbuf), &pw);
+ if (!pw)
+ goto auth_failed;
+ pamret = pam_open_session(pamh, 0);
+ if (pamret != PAM_SUCCESS) {
+ failed_msg = "open_session";
+ goto pam_auth_failed;
+ }
+ pamret = pam_setcred(pamh, PAM_ESTABLISH_CRED);
+ if (pamret != PAM_SUCCESS) {
+ failed_msg = "setcred";
+ goto pam_auth_failed;
+ }
+ break; /* success, continue login process */
+
+ pam_auth_failed:
+ bb_error_msg("pam_%s call failed: %s (%d)", failed_msg,
+ pam_strerror(pamh, pamret), pamret);
+ safe_strncpy(username, "UNKNOWN", sizeof(username));
+#else /* not PAM */
+ pw = getpwnam(username);
+ if (!pw) {
+ strcpy(username, "UNKNOWN");
+ goto fake_it;
+ }
+
+ if (pw->pw_passwd[0] == '!' || pw->pw_passwd[0] == '*')
+ goto auth_failed;
+
+ if (opt & LOGIN_OPT_f)
+ break; /* -f USER: success without asking passwd */
+
+ if (pw->pw_uid == 0 && !check_securetty())
+ goto auth_failed;
+
+ /* Don't check the password if password entry is empty (!) */
+ if (!pw->pw_passwd[0])
+ break;
+ fake_it:
+ /* authorization takes place here */
+ if (correct_password(pw))
+ break;
+#endif /* ENABLE_PAM */
+ auth_failed:
+ opt &= ~LOGIN_OPT_f;
+ bb_do_delay(FAIL_DELAY);
+ /* TODO: doesn't sound like correct English phrase to me */
+ puts("Login incorrect");
+ if (++count == 3) {
+ syslog(LOG_WARNING, "invalid password for '%s'%s",
+ username, fromhost);
+ return EXIT_FAILURE;
+ }
+ username[0] = '\0';
+ }
+
+ alarm(0);
+ if (!amroot)
+ die_if_nologin();
+
+ write_utent(&utent, username);
+
+#if ENABLE_SELINUX
+ if (is_selinux_enabled()) {
+ security_context_t old_tty_sid, new_tty_sid;
+
+ if (get_default_context(username, NULL, &user_sid)) {
+ bb_error_msg_and_die("cannot get SID for %s",
+ username);
+ }
+ if (getfilecon(full_tty, &old_tty_sid) < 0) {
+ bb_perror_msg_and_die("getfilecon(%s) failed",
+ full_tty);
+ }
+ if (security_compute_relabel(user_sid, old_tty_sid,
+ SECCLASS_CHR_FILE, &new_tty_sid) != 0) {
+ bb_perror_msg_and_die("security_change_sid(%s) failed",
+ full_tty);
+ }
+ if (setfilecon(full_tty, new_tty_sid) != 0) {
+ bb_perror_msg_and_die("chsid(%s, %s) failed",
+ full_tty, new_tty_sid);
+ }
+ }
+#endif
+ /* Try these, but don't complain if they fail.
+ * _f_chown is safe wrt race t=ttyname(0);...;chown(t); */
+ fchown(0, pw->pw_uid, pw->pw_gid);
+ fchmod(0, 0600);
+
+ /* We trust environment only if we run by root */
+ if (ENABLE_LOGIN_SCRIPTS && amroot) {
+ char *t_argv[2];
+
+ t_argv[0] = getenv("LOGIN_PRE_SUID_SCRIPT");
+ if (t_argv[0]) {
+ t_argv[1] = NULL;
+ xsetenv("LOGIN_TTY", full_tty);
+ xsetenv("LOGIN_USER", pw->pw_name);
+ xsetenv("LOGIN_UID", utoa(pw->pw_uid));
+ xsetenv("LOGIN_GID", utoa(pw->pw_gid));
+ xsetenv("LOGIN_SHELL", pw->pw_shell);
+ spawn_and_wait(t_argv); /* NOMMU-friendly */
+ unsetenv("LOGIN_TTY" );
+ unsetenv("LOGIN_USER" );
+ unsetenv("LOGIN_UID" );
+ unsetenv("LOGIN_GID" );
+ unsetenv("LOGIN_SHELL");
+ }
+ }
+
+ change_identity(pw);
+ tmp = pw->pw_shell;
+ if (!tmp || !*tmp)
+ tmp = DEFAULT_SHELL;
+ /* setup_environment params: shell, clear_env, change_env, pw */
+ setup_environment(tmp, !(opt & LOGIN_OPT_p), 1, pw);
+
+ motd();
+
+ if (pw->pw_uid == 0)
+ syslog(LOG_INFO, "root login%s", fromhost);
+#if ENABLE_SELINUX
+ /* well, a simple setexeccon() here would do the job as well,
+ * but let's play the game for now */
+ set_current_security_context(user_sid);
+#endif
+
+ // util-linux login also does:
+ // /* start new session */
+ // setsid();
+ // /* TIOCSCTTY: steal tty from other process group */
+ // if (ioctl(0, TIOCSCTTY, 1)) error_msg...
+ // BBox login used to do this (see above):
+ // bb_setpgrp();
+ // If this stuff is really needed, add it and explain why!
+
+ /* set signals to defaults */
+ signal(SIGALRM, SIG_DFL);
+ /* Is this correct? This way user can ctrl-c out of /etc/profile,
+ * potentially creating security breach (tested with bash 3.0).
+ * But without this, bash 3.0 will not enable ctrl-c either.
+ * Maybe bash is buggy?
+ * Need to find out what standards say about /bin/login -
+ * should it leave SIGINT etc enabled or disabled? */
+ signal(SIGINT, SIG_DFL);
+
+ /* Exec login shell with no additional parameters */
+ run_shell(tmp, 1, NULL, NULL);
+
+ /* return EXIT_FAILURE; - not reached */
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/loginutils/passwd.c b/cleopatre/busybox-1.11.1-spc300/loginutils/passwd.c
new file mode 100644
index 0000000000..0a31137cff
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/loginutils/passwd.c
@@ -0,0 +1,206 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include <syslog.h>
+
+static void nuke_str(char *str)
+{
+ if (str) memset(str, 0, strlen(str));
+}
+
+static char* new_password(const struct passwd *pw, uid_t myuid, int algo)
+{
+ char salt[sizeof("$N$XXXXXXXX")]; /* "$N$XXXXXXXX" or "XX" */
+ char *orig = (char*)"";
+ char *newp = NULL;
+ char *cp = NULL;
+ char *ret = NULL; /* failure so far */
+
+ if (myuid && pw->pw_passwd[0]) {
+ char *encrypted;
+
+ orig = bb_askpass(0, "Old password:"); /* returns ptr to static */
+ if (!orig)
+ goto err_ret;
+ encrypted = pw_encrypt(orig, pw->pw_passwd, 1); /* returns malloced str */
+ if (strcmp(encrypted, pw->pw_passwd) != 0) {
+ syslog(LOG_WARNING, "incorrect password for '%s'",
+ pw->pw_name);
+ bb_do_delay(FAIL_DELAY);
+ puts("Incorrect password");
+ goto err_ret;
+ }
+ if (ENABLE_FEATURE_CLEAN_UP) free(encrypted);
+ }
+ orig = xstrdup(orig); /* or else bb_askpass() will destroy it */
+ newp = bb_askpass(0, "New password:"); /* returns ptr to static */
+ if (!newp)
+ goto err_ret;
+ newp = xstrdup(newp); /* we are going to bb_askpass() again, so save it */
+ if (ENABLE_FEATURE_PASSWD_WEAK_CHECK
+ && obscure(orig, newp, pw) && myuid)
+ goto err_ret; /* non-root is not allowed to have weak passwd */
+
+ cp = bb_askpass(0, "Retype password:");
+ if (!cp)
+ goto err_ret;
+ if (strcmp(cp, newp)) {
+ puts("Passwords don't match");
+ goto err_ret;
+ }
+
+ crypt_make_salt(salt, 1, 0); /* des */
+ if (algo) { /* MD5 */
+ strcpy(salt, "$1$");
+ crypt_make_salt(salt + 3, 4, 0);
+ }
+ /* pw_encrypt returns malloced str */
+ ret = pw_encrypt(newp, salt, 1);
+ /* whee, success! */
+
+ err_ret:
+ nuke_str(orig);
+ if (ENABLE_FEATURE_CLEAN_UP) free(orig);
+ nuke_str(newp);
+ if (ENABLE_FEATURE_CLEAN_UP) free(newp);
+ nuke_str(cp);
+ return ret;
+}
+
+int passwd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int passwd_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ enum {
+ OPT_algo = 0x1, /* -a - password algorithm */
+ OPT_lock = 0x2, /* -l - lock account */
+ OPT_unlock = 0x4, /* -u - unlock account */
+ OPT_delete = 0x8, /* -d - delete password */
+ OPT_lud = 0xe,
+ STATE_ALGO_md5 = 0x10,
+ //STATE_ALGO_des = 0x20, not needed yet
+ };
+ unsigned opt;
+ int rc;
+ const char *opt_a = "";
+ const char *filename;
+ char *myname;
+ char *name;
+ char *newp;
+ struct passwd *pw;
+ uid_t myuid;
+ struct rlimit rlimit_fsize;
+ char c;
+#if ENABLE_FEATURE_SHADOWPASSWDS
+ /* Using _r function to avoid pulling in static buffers */
+ struct spwd spw;
+ char buffer[256];
+#endif
+
+ logmode = LOGMODE_BOTH;
+ openlog(applet_name, LOG_NOWAIT, LOG_AUTH);
+ opt = getopt32(argv, "a:lud", &opt_a);
+ //argc -= optind;
+ argv += optind;
+
+ if (strcasecmp(opt_a, "des") != 0) /* -a */
+ opt |= STATE_ALGO_md5;
+ //else
+ // opt |= STATE_ALGO_des;
+ myuid = getuid();
+ /* -l, -u, -d require root priv and username argument */
+ if ((opt & OPT_lud) && (myuid || !argv[0]))
+ bb_show_usage();
+
+ /* Will complain and die if username not found */
+ myname = xstrdup(bb_getpwuid(NULL, -1, myuid));
+ name = argv[0] ? argv[0] : myname;
+
+ pw = getpwnam(name);
+ if (!pw) bb_error_msg_and_die("unknown user %s", name);
+ if (myuid && pw->pw_uid != myuid) {
+ /* LOGMODE_BOTH */
+ bb_error_msg_and_die("%s can't change password for %s", myname, name);
+ }
+
+#if ENABLE_FEATURE_SHADOWPASSWDS
+ {
+ /* getspnam_r may return 0 yet set result to NULL.
+ * At least glibc 2.4 does this. Be extra paranoid here. */
+ struct spwd *result = NULL;
+ if (getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result)
+ || !result || strcmp(result->sp_namp, pw->pw_name) != 0) {
+ /* LOGMODE_BOTH */
+ bb_error_msg("no record of %s in %s, using %s",
+ name, bb_path_shadow_file,
+ bb_path_passwd_file);
+ } else {
+ pw->pw_passwd = result->sp_pwdp;
+ }
+ }
+#endif
+
+ /* Decide what the new password will be */
+ newp = NULL;
+ c = pw->pw_passwd[0] - '!';
+ if (!(opt & OPT_lud)) {
+ if (myuid && !c) { /* passwd starts with '!' */
+ /* LOGMODE_BOTH */
+ bb_error_msg_and_die("cannot change "
+ "locked password for %s", name);
+ }
+ printf("Changing password for %s\n", name);
+ newp = new_password(pw, myuid, opt & STATE_ALGO_md5);
+ if (!newp) {
+ logmode = LOGMODE_STDIO;
+ bb_error_msg_and_die("password for %s is unchanged", name);
+ }
+ } else if (opt & OPT_lock) {
+ if (!c) goto skip; /* passwd starts with '!' */
+ newp = xasprintf("!%s", pw->pw_passwd);
+ } else if (opt & OPT_unlock) {
+ if (c) goto skip; /* not '!' */
+ /* pw->pw_passwd points to static storage,
+ * strdup'ing to avoid nasty surprizes */
+ newp = xstrdup(&pw->pw_passwd[1]);
+ } else if (opt & OPT_delete) {
+ //newp = xstrdup("");
+ newp = (char*)"";
+ }
+
+ rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * 30000;
+ setrlimit(RLIMIT_FSIZE, &rlimit_fsize);
+ bb_signals(0
+ + (1 << SIGHUP)
+ + (1 << SIGINT)
+ + (1 << SIGQUIT)
+ , SIG_IGN);
+ umask(077);
+ xsetuid(0);
+
+#if ENABLE_FEATURE_SHADOWPASSWDS
+ filename = bb_path_shadow_file;
+ rc = update_passwd(bb_path_shadow_file, name, newp);
+ if (rc == 0) /* no lines updated, no errors detected */
+#endif
+ {
+ filename = bb_path_passwd_file;
+ rc = update_passwd(bb_path_passwd_file, name, newp);
+ }
+ /* LOGMODE_BOTH */
+ if (rc < 0)
+ bb_error_msg_and_die("cannot update password file %s",
+ filename);
+ bb_info_msg("Password for %s changed by %s", name, myname);
+
+ //if (ENABLE_FEATURE_CLEAN_UP) free(newp);
+ skip:
+ if (!newp) {
+ bb_error_msg_and_die("password for %s is already %slocked",
+ name, (opt & OPT_unlock) ? "un" : "");
+ }
+ if (ENABLE_FEATURE_CLEAN_UP) free(myname);
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/loginutils/su.c b/cleopatre/busybox-1.11.1-spc300/loginutils/su.c
new file mode 100644
index 0000000000..1a35f0e4fc
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/loginutils/su.c
@@ -0,0 +1,102 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini su implementation for busybox
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+#include <syslog.h>
+
+#define SU_OPT_mp (3)
+#define SU_OPT_l (4)
+
+int su_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int su_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ unsigned flags;
+ char *opt_shell = NULL;
+ char *opt_command = NULL;
+ const char *opt_username = "root";
+ struct passwd *pw;
+ uid_t cur_uid = getuid();
+ const char *tty;
+ char *old_user;
+
+ flags = getopt32(argv, "mplc:s:", &opt_command, &opt_shell);
+ //argc -= optind;
+ argv += optind;
+
+ if (argv[0] && LONE_DASH(argv[0])) {
+ flags |= SU_OPT_l;
+ argv++;
+ }
+
+ /* get user if specified */
+ if (argv[0]) {
+ opt_username = argv[0];
+ argv++;
+ }
+
+ if (ENABLE_FEATURE_SU_SYSLOG) {
+ /* The utmp entry (via getlogin) is probably the best way to identify
+ the user, especially if someone su's from a su-shell.
+ But getlogin can fail -- usually due to lack of utmp entry.
+ in this case resort to getpwuid. */
+ old_user = xstrdup(USE_FEATURE_UTMP(getlogin() ? : ) (pw = getpwuid(cur_uid)) ? pw->pw_name : "");
+ tty = ttyname(2) ? : "none";
+ openlog(applet_name, 0, LOG_AUTH);
+ }
+
+ pw = getpwnam(opt_username);
+ if (!pw)
+ bb_error_msg_and_die("unknown id: %s", opt_username);
+
+ /* Make sure pw->pw_shell is non-NULL. It may be NULL when NEW_USER
+ is a username that is retrieved via NIS (YP), but that doesn't have
+ a default shell listed. */
+ if (!pw->pw_shell || !pw->pw_shell[0])
+ pw->pw_shell = (char *)DEFAULT_SHELL;
+
+ if ((cur_uid == 0) || correct_password(pw)) {
+ if (ENABLE_FEATURE_SU_SYSLOG)
+ syslog(LOG_NOTICE, "%c %s %s:%s",
+ '+', tty, old_user, opt_username);
+ } else {
+ if (ENABLE_FEATURE_SU_SYSLOG)
+ syslog(LOG_NOTICE, "%c %s %s:%s",
+ '-', tty, old_user, opt_username);
+ bb_error_msg_and_die("incorrect password");
+ }
+
+ if (ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_SU_SYSLOG) {
+ closelog();
+ free(old_user);
+ }
+
+ if (!opt_shell && (flags & SU_OPT_mp))
+ opt_shell = getenv("SHELL");
+
+#if ENABLE_FEATURE_SU_CHECKS_SHELLS
+ if (opt_shell && cur_uid && restricted_shell(pw->pw_shell)) {
+ /* The user being su'd to has a nonstandard shell, and so is
+ probably a uucp account or has restricted access. Don't
+ compromise the account by allowing access with a standard
+ shell. */
+ bb_error_msg("using restricted shell");
+ opt_shell = NULL;
+ }
+#endif
+ if (!opt_shell)
+ opt_shell = pw->pw_shell;
+
+ change_identity(pw);
+ /* setup_environment params: shell, clear_env, change_env, pw */
+ setup_environment(opt_shell, flags & SU_OPT_l, !(flags & SU_OPT_mp), pw);
+ USE_SELINUX(set_current_security_context(NULL);)
+
+ /* Never returns */
+ run_shell(opt_shell, flags & SU_OPT_l, opt_command, (const char**)argv);
+
+ /* return EXIT_FAILURE; - not reached */
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/loginutils/sulogin.c b/cleopatre/busybox-1.11.1-spc300/loginutils/sulogin.c
new file mode 100644
index 0000000000..38812a6cc4
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/loginutils/sulogin.c
@@ -0,0 +1,116 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini sulogin implementation for busybox
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include <syslog.h>
+
+//static void catchalarm(int ATTRIBUTE_UNUSED junk)
+//{
+// exit(EXIT_FAILURE);
+//}
+
+
+int sulogin_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int sulogin_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ char *cp;
+ int timeout = 0;
+ struct passwd *pwd;
+ const char *shell;
+#if ENABLE_FEATURE_SHADOWPASSWDS
+ /* Using _r function to avoid pulling in static buffers */
+ char buffer[256];
+ struct spwd spw;
+#endif
+
+ logmode = LOGMODE_BOTH;
+ openlog(applet_name, 0, LOG_AUTH);
+
+ opt_complementary = "t+"; /* -t N */
+ getopt32(argv, "t:", &timeout);
+
+ if (argv[optind]) {
+ close(0);
+ close(1);
+ dup(xopen(argv[optind], O_RDWR));
+ close(2);
+ dup(0);
+ }
+
+ /* Malicious use like "sulogin /dev/sda"? */
+ if (!isatty(0) || !isatty(1) || !isatty(2)) {
+ logmode = LOGMODE_SYSLOG;
+ bb_error_msg_and_die("not a tty");
+ }
+
+ /* Clear dangerous stuff, set PATH */
+ sanitize_env_if_suid();
+
+// bb_askpass() already handles this
+// signal(SIGALRM, catchalarm);
+
+ pwd = getpwuid(0);
+ if (!pwd) {
+ goto auth_error;
+ }
+
+#if ENABLE_FEATURE_SHADOWPASSWDS
+ {
+ /* getspnam_r may return 0 yet set result to NULL.
+ * At least glibc 2.4 does this. Be extra paranoid here. */
+ struct spwd *result = NULL;
+ int r = getspnam_r(pwd->pw_name, &spw, buffer, sizeof(buffer), &result);
+ if (r || !result) {
+ goto auth_error;
+ }
+ pwd->pw_passwd = result->sp_pwdp;
+ }
+#endif
+
+ while (1) {
+ char *encrypted;
+ int r;
+
+ /* cp points to a static buffer that is zeroed every time */
+ cp = bb_askpass(timeout,
+ "Give root password for system maintenance\n"
+ "(or type Control-D for normal startup):");
+
+ if (!cp || !*cp) {
+ bb_info_msg("Normal startup");
+ return 0;
+ }
+ encrypted = pw_encrypt(cp, pwd->pw_passwd, 1);
+ r = strcmp(encrypted, pwd->pw_passwd);
+ free(encrypted);
+ if (r == 0) {
+ break;
+ }
+ bb_do_delay(FAIL_DELAY);
+ bb_error_msg("login incorrect");
+ }
+ memset(cp, 0, strlen(cp));
+// signal(SIGALRM, SIG_DFL);
+
+ bb_info_msg("System Maintenance Mode");
+
+ USE_SELINUX(renew_current_security_context());
+
+ shell = getenv("SUSHELL");
+ if (!shell)
+ shell = getenv("sushell");
+ if (!shell) {
+ shell = "/bin/sh";
+ if (pwd->pw_shell[0])
+ shell = pwd->pw_shell;
+ }
+ /* Exec login shell with no additional parameters. Never returns. */
+ run_shell(shell, 1, NULL, NULL);
+
+ auth_error:
+ bb_error_msg_and_die("no password entry for root");
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/loginutils/vlock.c b/cleopatre/busybox-1.11.1-spc300/loginutils/vlock.c
new file mode 100644
index 0000000000..3ce40dd625
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/loginutils/vlock.c
@@ -0,0 +1,106 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * vlock implementation for busybox
+ *
+ * Copyright (C) 2000 by spoon <spoon@ix.netcom.com>
+ * Written by spoon <spon@ix.netcom.com>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* Shoutz to Michael K. Johnson <johnsonm@redhat.com>, author of the
+ * original vlock. I snagged a bunch of his code to write this
+ * minimalistic vlock.
+ */
+/* Fixed by Erik Andersen to do passwords the tinylogin way...
+ * It now works with md5, sha1, etc passwords. */
+
+#include <sys/vt.h>
+#include "libbb.h"
+
+static void release_vt(int signo ATTRIBUTE_UNUSED)
+{
+ /* If -a, param is 0, which means:
+ * "no, kernel, we don't allow console switch away from us!" */
+ ioctl(STDIN_FILENO, VT_RELDISP, (unsigned long) !option_mask32);
+}
+
+static void acquire_vt(int signo ATTRIBUTE_UNUSED)
+{
+ /* ACK to kernel that switch to console is successful */
+ ioctl(STDIN_FILENO, VT_RELDISP, VT_ACKACQ);
+}
+
+int vlock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int vlock_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ struct vt_mode vtm;
+ struct termios term;
+ struct termios oterm;
+ struct vt_mode ovtm;
+ uid_t uid;
+ struct passwd *pw;
+
+ uid = getuid();
+ pw = getpwuid(uid);
+ if (pw == NULL)
+ bb_error_msg_and_die("unknown uid %d", (int)uid);
+
+ opt_complementary = "=0"; /* no params! */
+ getopt32(argv, "a");
+
+ /* Ignore some signals so that we don't get killed by them */
+ bb_signals(0
+ + (1 << SIGTSTP)
+ + (1 << SIGTTIN)
+ + (1 << SIGTTOU)
+ + (1 << SIGHUP )
+ + (1 << SIGCHLD) /* paranoia :) */
+ + (1 << SIGQUIT)
+ + (1 << SIGINT )
+ , SIG_IGN);
+
+ /* We will use SIGUSRx for console switch control: */
+ /* 1: set handlers */
+ signal_SA_RESTART_empty_mask(SIGUSR1, release_vt);
+ signal_SA_RESTART_empty_mask(SIGUSR2, acquire_vt);
+ /* 2: unmask them */
+ sig_unblock(SIGUSR1);
+ sig_unblock(SIGUSR2);
+
+ /* Revert stdin/out to our controlling tty
+ * (or die if we have none) */
+ xmove_fd(xopen(CURRENT_TTY, O_RDWR), STDIN_FILENO);
+ xdup2(STDIN_FILENO, STDOUT_FILENO);
+
+ xioctl(STDIN_FILENO, VT_GETMODE, &vtm);
+ ovtm = vtm;
+ /* "console switches are controlled by us, not kernel!" */
+ vtm.mode = VT_PROCESS;
+ vtm.relsig = SIGUSR1;
+ vtm.acqsig = SIGUSR2;
+ ioctl(STDIN_FILENO, VT_SETMODE, &vtm);
+
+ tcgetattr(STDIN_FILENO, &oterm);
+ term = oterm;
+ term.c_iflag &= ~BRKINT;
+ term.c_iflag |= IGNBRK;
+ term.c_lflag &= ~ISIG;
+ term.c_lflag &= ~(ECHO | ECHOCTL);
+ tcsetattr(STDIN_FILENO, TCSANOW, &term);
+
+ do {
+ printf("Virtual console%s locked by %s.\n",
+ option_mask32 /*o_lock_all*/ ? "s" : "",
+ pw->pw_name);
+ if (correct_password(pw)) {
+ break;
+ }
+ bb_do_delay(FAIL_DELAY);
+ puts("Password incorrect");
+ } while (1);
+
+ ioctl(STDIN_FILENO, VT_SETMODE, &ovtm);
+ tcsetattr(STDIN_FILENO, TCSANOW, &oterm);
+ fflush_stdout_and_exit(EXIT_SUCCESS);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/Config.in b/cleopatre/busybox-1.11.1-spc300/miscutils/Config.in
new file mode 100644
index 0000000000..c7dbee8992
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/Config.in
@@ -0,0 +1,520 @@
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Miscellaneous Utilities"
+
+config ADJTIMEX
+ bool "adjtimex"
+ default n
+ help
+ Adjtimex reads and optionally sets adjustment parameters for
+ the Linux clock adjustment algorithm.
+
+config BBCONFIG
+ bool "bbconfig"
+ default n
+ help
+ The bbconfig applet will print the config file with which
+ busybox was built.
+
+config CHAT
+ bool "chat"
+ default n
+ help
+ Simple chat utility.
+
+config FEATURE_CHAT_NOFAIL
+ bool "Enable NOFAIL expect strings"
+ depends on CHAT
+ default y
+ help
+ When enabled expect strings which are started with a dash trigger
+ no-fail mode. That is when expectation is not met within timeout
+ the script is not terminated but sends next SEND string and waits
+ for next EXPECT string. This allows to compose far more flexible
+ scripts.
+
+config FEATURE_CHAT_TTY_HIFI
+ bool "Force STDIN to be a TTY"
+ depends on CHAT
+ default n
+ help
+ Original chat always treats STDIN as a TTY device and sets for it
+ so-called raw mode. This option turns on such behaviour.
+
+config FEATURE_CHAT_IMPLICIT_CR
+ bool "Enable implicit Carriage Return"
+ depends on CHAT
+ default y
+ help
+ When enabled make chat to terminate all SEND strings with a "\r"
+ unless "\c" is met anywhere in the string.
+
+config FEATURE_CHAT_SWALLOW_OPTS
+ bool "Swallow options"
+ depends on CHAT
+ default n
+ help
+ Busybox chat require no options. To make it not fail when used
+ in place of original chat (which has a bunch of options) turn
+ this on.
+
+config FEATURE_CHAT_SEND_ESCAPES
+ bool "Support weird SEND escapes"
+ depends on CHAT
+ default n
+ help
+ Original chat uses some escape sequences in SEND arguments which
+ are not sent to device but rather performs special actions.
+ E.g. "\K" means to send a break sequence to device.
+ "\d" delays execution for a second, "\p" -- for a 1/100 of second.
+ Before turning this option on think twice: do you really need them?
+
+config FEATURE_CHAT_VAR_ABORT_LEN
+ bool "Support variable-length ABORT conditions"
+ depends on CHAT
+ default n
+ help
+ Original chat uses fixed 50-bytes length ABORT conditions. Say N here.
+
+config FEATURE_CHAT_CLR_ABORT
+ bool "Support revoking of ABORT conditions"
+ depends on CHAT
+ default n
+ help
+ Support CLR_ABORT directive.
+
+config CHRT
+ bool "chrt"
+ default n
+ help
+ manipulate real-time attributes of a process.
+ This requires sched_{g,s}etparam support in your libc.
+
+config CROND
+ bool "crond"
+ default n
+ select FEATURE_SUID
+ select FEATURE_SYSLOG
+ help
+ Crond is a background daemon that parses individual crontab
+ files and executes commands on behalf of the users in question.
+ This is a port of dcron from slackware. It uses files of the
+ format /var/spool/cron/crontabs/<username> files, for example:
+ $ cat /var/spool/cron/crontabs/root
+ # Run daily cron jobs at 4:40 every day:
+ 40 4 * * * /etc/cron/daily > /dev/null 2>&1
+
+config DEBUG_CROND_OPTION
+ bool "Support option -d to redirect output to stderr"
+ depends on CROND
+ default n
+ help
+ -d sets loglevel to 0 (most verbose) and directs all output to stderr.
+
+config FEATURE_CROND_CALL_SENDMAIL
+ bool "Using /usr/sbin/sendmail?"
+ default n
+ depends on CROND
+ help
+ Support calling /usr/sbin/sendmail for send cmd outputs.
+
+config CRONTAB
+ bool "crontab"
+ default n
+ select FEATURE_SUID
+ help
+ Crontab manipulates the crontab for a particular user. Only
+ the superuser may specify a different user and/or crontab directory.
+ Note that Busybox binary must be setuid root for this applet to
+ work properly.
+
+config DC
+ bool "dc"
+ default n
+ help
+ Dc is a reverse-polish desk calculator which supports unlimited
+ precision arithmetic.
+
+config DEVFSD
+ bool "devfsd (obsolete)"
+ default n
+ select FEATURE_SYSLOG
+ help
+ This is deprecated, and will be removed at the end of 2008.
+
+ Provides compatibility with old device names on a devfs systems.
+ You should set it to true if you have devfs enabled.
+ The following keywords in devsfd.conf are supported:
+ "CLEAR_CONFIG", "INCLUDE", "OPTIONAL_INCLUDE", "RESTORE",
+ "PERMISSIONS", "EXECUTE", "COPY", "IGNORE",
+ "MKOLDCOMPAT", "MKNEWCOMPAT","RMOLDCOMPAT", "RMNEWCOMPAT".
+
+ But only if they are written UPPERCASE!!!!!!!!
+
+config DEVFSD_MODLOAD
+ bool "Adds support for MODLOAD keyword in devsfd.conf"
+ default n
+ depends on DEVFSD
+ help
+ This actually doesn't work with busybox modutils but needs
+ the external modutils.
+
+config DEVFSD_FG_NP
+ bool "Enables the -fg and -np options"
+ default n
+ depends on DEVFSD
+ help
+ -fg Run the daemon in the foreground.
+ -np Exit after parsing the configuration file. Do not poll for events.
+
+config DEVFSD_VERBOSE
+ bool "Increases logging (and size)"
+ default n
+ depends on DEVFSD
+ help
+ Increases logging to stderr or syslog.
+
+config FEATURE_DEVFS
+ bool "Use devfs names for all devices (obsolete)"
+ default n
+ help
+ This is obsolete and will be going away at the end of 2008..
+
+ This tells busybox to look for names like /dev/loop/0 instead of
+ /dev/loop0. If your /dev directory has normal names instead of
+ devfs names, you don't want this.
+
+config EJECT
+ bool "eject"
+ default n
+ help
+ Used to eject cdroms. (defaults to /dev/cdrom)
+
+config FEATURE_EJECT_SCSI
+ bool "SCSI support"
+ default n
+ depends on EJECT
+ help
+ Add the -s option to eject, this allows to eject SCSI-Devices and
+ usb-storage devices.
+
+config FBSPLASH
+ bool "fbsplash"
+ default n
+ help
+ Shows splash image and progress bar on framebuffer device.
+ Can be used during boot phase of an embedded device. ~2kb.
+ Usage:
+ - use kernel option 'vga=xxx' or otherwise enable fb device.
+ - put somewhere fbsplash.cfg file and an image in .ppm format.
+ - $ setsid fbsplash [params] &
+ -c: hide cursor
+ -d /dev/fbN: framebuffer device (if not /dev/fb0)
+ -s path_to_image_file (can be "-" for stdin)
+ -i path_to_cfg_file (can be "-" for stdin)
+ -f path_to_fifo (can be "-" for stdin)
+ - if you want to run it only in presence of kernel parameter:
+ grep -q "fbsplash=on" </proc/cmdline && setsid fbsplash [params] &
+ - commands for fifo:
+ "NN" (ASCII decimal number) - percentage to show on progress bar
+ "exit" - well you guessed it
+
+config INOTIFYD
+ bool "inotifyd"
+ default n
+ help
+ Simple inotify daemon. Reports filesystem changes. Requires kernel >= 2.6.13
+
+config LAST
+ bool "last"
+ default n
+ select FEATURE_WTMP
+ help
+ 'last' displays a list of the last users that logged into the system.
+
+choice
+ prompt "Choose last implementation"
+ depends on LAST
+ default FEATURE_LAST_SMALL
+
+config FEATURE_LAST_SMALL
+ bool "small"
+ help
+ This is a small version of last with just the basic set of
+ features.
+
+config FEATURE_LAST_FANCY
+ bool "huge"
+ help
+ 'last' displays detailed information about the last users that
+ logged into the system (mimics sysvinit last). +900 bytes.
+endchoice
+
+config LESS
+ bool "less"
+ default n
+ help
+ 'less' is a pager, meaning that it displays text files. It possesses
+ a wide array of features, and is an improvement over 'more'.
+
+config FEATURE_LESS_MAXLINES
+ int "Max number of input lines less will try to eat"
+ default 9999999
+ depends on LESS
+
+config FEATURE_LESS_BRACKETS
+ bool "Enable bracket searching"
+ default y
+ depends on LESS
+ help
+ This option adds the capability to search for matching left and right
+ brackets, facilitating programming.
+
+config FEATURE_LESS_FLAGS
+ bool "Enable extra flags"
+ default y
+ depends on LESS
+ help
+ The extra flags provided do the following:
+
+ The -M flag enables a more sophisticated status line.
+ The -m flag enables a simpler status line with a percentage.
+
+config FEATURE_LESS_FLAGCS
+ bool "Enable flag changes"
+ default n
+ depends on LESS
+ help
+ This enables the ability to change command-line flags within
+ less itself.
+
+config FEATURE_LESS_MARKS
+ bool "Enable marks"
+ default n
+ depends on LESS
+ help
+ Marks enable positions in a file to be stored for easy reference.
+
+config FEATURE_LESS_REGEXP
+ bool "Enable regular expressions"
+ default n
+ depends on LESS
+ help
+ Enable regular expressions, allowing complex file searches.
+
+config HDPARM
+ bool "hdparm"
+ default n
+ help
+ Get/Set hard drive parameters. Primarily intended for ATA
+ drives. Adds about 13k (or around 30k if you enable the
+ FEATURE_HDPARM_GET_IDENTITY option)....
+
+config FEATURE_HDPARM_GET_IDENTITY
+ bool "Support obtaining detailed information directly from drives"
+ default y
+ depends on HDPARM
+ help
+ Enables the -I and -i options to obtain detailed information
+ directly from drives about their capabilities and supported ATA
+ feature set. If no device name is specified, hdparm will read
+ identify data from stdin. Enabling this option will add about 16k...
+
+config FEATURE_HDPARM_HDIO_SCAN_HWIF
+ bool "Register an IDE interface (DANGEROUS)"
+ default n
+ depends on HDPARM
+ help
+ Enables the 'hdparm -R' option to register an IDE interface.
+ This is dangerous stuff, so you should probably say N.
+
+config FEATURE_HDPARM_HDIO_UNREGISTER_HWIF
+ bool "Un-register an IDE interface (DANGEROUS)"
+ default n
+ depends on HDPARM
+ help
+ Enables the 'hdparm -U' option to un-register an IDE interface.
+ This is dangerous stuff, so you should probably say N.
+
+config FEATURE_HDPARM_HDIO_DRIVE_RESET
+ bool "perform device reset (DANGEROUS)"
+ default n
+ depends on HDPARM
+ help
+ Enables the 'hdparm -w' option to perform a device reset.
+ This is dangerous stuff, so you should probably say N.
+
+config FEATURE_HDPARM_HDIO_TRISTATE_HWIF
+ bool "tristate device for hotswap (DANGEROUS)"
+ default n
+ depends on HDPARM
+ help
+ Enables the 'hdparm -x' option to tristate device for hotswap,
+ and the '-b' option to get/set bus state. This is dangerous
+ stuff, so you should probably say N.
+
+config FEATURE_HDPARM_HDIO_GETSET_DMA
+ bool "get/set using_dma flag (DANGEROUS)"
+ default n
+ depends on HDPARM
+ help
+ Enables the 'hdparm -d' option to get/set using_dma flag.
+ This is dangerous stuff, so you should probably say N.
+
+config MAKEDEVS
+ bool "makedevs"
+ default n
+ help
+ 'makedevs' is a utility used to create a batch of devices with
+ one command.
+ .
+ There are two choices for command line behaviour, the interface
+ as used by LEAF/Linux Router Project, or a device table file.
+ .
+ 'leaf' is traditionally what busybox follows, it allows multiple
+ devices of a particluar type to be created per command.
+ e.g. /dev/hda[0-9]
+ Device properties are passed as command line arguments.
+ .
+ 'table' reads device properties from a file or stdin, allowing
+ a batch of unrelated devices to be made with one command.
+ User/group names are allowed as an alternative to uid/gid.
+
+choice
+ prompt "Choose makedevs behaviour"
+ depends on MAKEDEVS
+ default FEATURE_MAKEDEVS_TABLE
+
+config FEATURE_MAKEDEVS_LEAF
+ bool "leaf"
+
+config FEATURE_MAKEDEVS_TABLE
+ bool "table"
+
+endchoice
+
+config MAN
+ bool "man"
+ default n
+ help
+ Format and display manual pages.
+
+config MICROCOM
+ bool "microcom"
+ default n
+ help
+ The poor man's minicom utility for chatting with serial port devices.
+
+config MOUNTPOINT
+ bool "mountpoint"
+ default n
+ help
+ mountpoint checks if the directory is a mountpoint.
+
+config MT
+ bool "mt"
+ default n
+ help
+ mt is used to control tape devices. You can use the mt utility
+ to advance or rewind a tape past a specified number of archive
+ files on the tape.
+
+config RAIDAUTORUN
+ bool "raidautorun"
+ default n
+ help
+ raidautorun tells the kernel md driver to
+ search and start RAID arrays.
+
+config READAHEAD
+ bool "readahead"
+ default n
+ depends on LFS
+ help
+ Preload the files listed on the command line into RAM cache so that
+ subsequent reads on these files will not block on disk I/O.
+
+ This applet just calls the readahead(2) system call on each file.
+ It is mainly useful in system startup scripts to preload files
+ or executables before they are used. When used at the right time
+ (in particular when a CPU bound process is running) it can
+ significantly speed up system startup.
+
+ As readahead(2) blocks until each file has been read, it is best to
+ run this applet as a background job.
+
+config RUNLEVEL
+ bool "runlevel"
+ default n
+ help
+ find the current and previous system runlevel.
+
+ This applet uses utmp but does not rely on busybox supporing
+ utmp on purpose. It is used by e.g. emdebian via /etc/init.d/rc.
+
+config RX
+ bool "rx"
+ default n
+ help
+ Receive files using the Xmodem protocol.
+
+config SETSID
+ bool "setsid"
+ default n
+ help
+ setsid runs a program in a new session
+
+config STRINGS
+ bool "strings"
+ default n
+ help
+ strings prints the printable character sequences for each file
+ specified.
+
+config TASKSET
+ bool "taskset"
+ default n
+ help
+ Retrieve or set a processes's CPU affinity.
+ This requires sched_{g,s}etaffinity support in your libc.
+
+config FEATURE_TASKSET_FANCY
+ bool "Fancy output"
+ default y
+ depends on TASKSET
+ help
+ Add code for fancy output. This merely silences a compiler-warning
+ and adds about 135 Bytes. May be needed for machines with alot
+ of CPUs.
+
+config TIME
+ bool "time"
+ default n
+ help
+ The time command runs the specified program with the given arguments.
+ When the command finishes, time writes a message to standard output
+ giving timing statistics about this program run.
+
+config TTYSIZE
+ bool "ttysize"
+ default n
+ help
+ A replacement for "stty size". Unlike stty, can report only width,
+ only height, or both, in any order. It also does not complain on error,
+ but returns default 80x24. Usage in shell scripts: width=`ttysize w`.
+
+config WATCHDOG
+ bool "watchdog"
+ default n
+ help
+ The watchdog utility is used with hardware or software watchdog
+ device drivers. It opens the specified watchdog device special file
+ and periodically writes a magic character to the device. If the
+ watchdog applet ever fails to write the magic character within a
+ certain amount of time, the watchdog device assumes the system has
+ hung, and will cause the hardware to reboot.
+
+endmenu
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/Kbuild b/cleopatre/busybox-1.11.1-spc300/miscutils/Kbuild
new file mode 100644
index 0000000000..c12b12d423
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/Kbuild
@@ -0,0 +1,37 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+lib-y:=
+lib-$(CONFIG_ADJTIMEX) += adjtimex.o
+lib-$(CONFIG_BBCONFIG) += bbconfig.o
+lib-$(CONFIG_CHAT) += chat.o
+lib-$(CONFIG_CHRT) += chrt.o
+lib-$(CONFIG_CROND) += crond.o
+lib-$(CONFIG_CRONTAB) += crontab.o
+lib-$(CONFIG_DC) += dc.o
+lib-$(CONFIG_DEVFSD) += devfsd.o
+lib-$(CONFIG_EJECT) += eject.o
+lib-$(CONFIG_FBSPLASH) += fbsplash.o
+lib-$(CONFIG_HDPARM) += hdparm.o
+lib-$(CONFIG_INOTIFYD) += inotifyd.o
+lib-$(CONFIG_FEATURE_LAST_SMALL)+= last.o
+lib-$(CONFIG_FEATURE_LAST_FANCY)+= last_fancy.o
+lib-$(CONFIG_LESS) += less.o
+lib-$(CONFIG_MAKEDEVS) += makedevs.o
+lib-$(CONFIG_MAN) += man.o
+lib-$(CONFIG_MICROCOM) += microcom.o
+lib-$(CONFIG_MOUNTPOINT) += mountpoint.o
+lib-$(CONFIG_MT) += mt.o
+lib-$(CONFIG_RAIDAUTORUN) += raidautorun.o
+lib-$(CONFIG_READAHEAD) += readahead.o
+lib-$(CONFIG_RUNLEVEL) += runlevel.o
+lib-$(CONFIG_RX) += rx.o
+lib-$(CONFIG_SETSID) += setsid.o
+lib-$(CONFIG_STRINGS) += strings.o
+lib-$(CONFIG_TASKSET) += taskset.o
+lib-$(CONFIG_TIME) += time.o
+lib-$(CONFIG_TTYSIZE) += ttysize.o
+lib-$(CONFIG_WATCHDOG) += watchdog.o
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/adjtimex.c b/cleopatre/busybox-1.11.1-spc300/miscutils/adjtimex.c
new file mode 100644
index 0000000000..07f083428c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/adjtimex.c
@@ -0,0 +1,145 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * adjtimex.c - read, and possibly modify, the Linux kernel `timex' variables.
+ *
+ * Originally written: October 1997
+ * Last hack: March 2001
+ * Copyright 1997, 2000, 2001 Larry Doolittle <LRDoolittle@lbl.gov>
+ *
+ * busyboxed 20 March 2001, Larry Doolittle <ldoolitt@recycle.lbl.gov>
+ *
+ * Licensed under GPLv2 or later, see file License in this tarball for details.
+ */
+
+#include "libbb.h"
+#include <sys/timex.h>
+
+static const uint16_t statlist_bit[] = {
+ STA_PLL,
+ STA_PPSFREQ,
+ STA_PPSTIME,
+ STA_FLL,
+ STA_INS,
+ STA_DEL,
+ STA_UNSYNC,
+ STA_FREQHOLD,
+ STA_PPSSIGNAL,
+ STA_PPSJITTER,
+ STA_PPSWANDER,
+ STA_PPSERROR,
+ STA_CLOCKERR,
+ 0
+};
+static const char statlist_name[] =
+ "PLL" "\0"
+ "PPSFREQ" "\0"
+ "PPSTIME" "\0"
+ "FFL" "\0"
+ "INS" "\0"
+ "DEL" "\0"
+ "UNSYNC" "\0"
+ "FREQHOLD" "\0"
+ "PPSSIGNAL" "\0"
+ "PPSJITTER" "\0"
+ "PPSWANDER" "\0"
+ "PPSERROR" "\0"
+ "CLOCKERR"
+;
+
+static const char ret_code_descript[] =
+ "clock synchronized" "\0"
+ "insert leap second" "\0"
+ "delete leap second" "\0"
+ "leap second in progress" "\0"
+ "leap second has occurred" "\0"
+ "clock not synchronized"
+;
+
+int adjtimex_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int adjtimex_main(int argc, char **argv)
+{
+ enum {
+ OPT_quiet = 0x1
+ };
+ unsigned opt;
+ char *opt_o, *opt_f, *opt_p, *opt_t;
+ struct timex txc;
+ int i, ret;
+ const char *descript;
+ txc.modes=0;
+
+ opt = getopt32(argv, "qo:f:p:t:",
+ &opt_o, &opt_f, &opt_p, &opt_t);
+ //if (opt & 0x1) // -q
+ if (opt & 0x2) { // -o
+ txc.offset = xatol(opt_o);
+ txc.modes |= ADJ_OFFSET_SINGLESHOT;
+ }
+ if (opt & 0x4) { // -f
+ txc.freq = xatol(opt_f);
+ txc.modes |= ADJ_FREQUENCY;
+ }
+ if (opt & 0x8) { // -p
+ txc.constant = xatol(opt_p);
+ txc.modes |= ADJ_TIMECONST;
+ }
+ if (opt & 0x10) { // -t
+ txc.tick = xatol(opt_t);
+ txc.modes |= ADJ_TICK;
+ }
+ if (argc != optind) { /* no valid non-option parameters */
+ bb_show_usage();
+ }
+
+ ret = adjtimex(&txc);
+
+ if (ret < 0) {
+ bb_perror_nomsg_and_die();
+ }
+
+ if (!(opt & OPT_quiet)) {
+ int sep;
+ const char *name;
+
+ printf(
+ " mode: %d\n"
+ "-o offset: %ld\n"
+ "-f frequency: %ld\n"
+ " maxerror: %ld\n"
+ " esterror: %ld\n"
+ " status: %d (",
+ txc.modes, txc.offset, txc.freq, txc.maxerror,
+ txc.esterror, txc.status);
+
+ /* representative output of next code fragment:
+ "PLL | PPSTIME" */
+ name = statlist_name;
+ sep = 0;
+ for (i = 0; statlist_bit[i]; i++) {
+ if (txc.status & statlist_bit[i]) {
+ if (sep)
+ fputs(" | ", stdout);
+ fputs(name, stdout);
+ sep = 1;
+ }
+ name += strlen(name) + 1;
+ }
+
+ descript = "error";
+ if (ret <= 5)
+ descript = nth_string(ret_code_descript, ret);
+ printf(")\n"
+ "-p timeconstant: %ld\n"
+ " precision: %ld\n"
+ " tolerance: %ld\n"
+ "-t tick: %ld\n"
+ " time.tv_sec: %ld\n"
+ " time.tv_usec: %ld\n"
+ " return value: %d (%s)\n",
+ txc.constant,
+ txc.precision, txc.tolerance, txc.tick,
+ (long)txc.time.tv_sec, (long)txc.time.tv_usec, ret, descript);
+ }
+
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/bbconfig.c b/cleopatre/busybox-1.11.1-spc300/miscutils/bbconfig.c
new file mode 100644
index 0000000000..f3aef42e34
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/bbconfig.c
@@ -0,0 +1,12 @@
+/* vi: set sw=4 ts=4: */
+/* This file was released into the public domain by Paul Fox.
+ */
+#include "libbb.h"
+#include "bbconfigopts.h"
+
+int bbconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int bbconfig_main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
+{
+ printf(bbconfig_config);
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/chat.c b/cleopatre/busybox-1.11.1-spc300/miscutils/chat.c
new file mode 100644
index 0000000000..5bbbb688fc
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/chat.c
@@ -0,0 +1,444 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bare bones chat utility
+ * inspired by ppp's chat
+ *
+ * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+#include "libbb.h"
+
+/*
+#define ENABLE_FEATURE_CHAT_NOFAIL 1 // +126 bytes
+#define ENABLE_FEATURE_CHAT_TTY_HIFI 0 // + 70 bytes
+#define ENABLE_FEATURE_CHAT_IMPLICIT_CR 1 // + 44 bytes
+#define ENABLE_FEATURE_CHAT_SEND_ESCAPES 0 // +103 bytes
+#define ENABLE_FEATURE_CHAT_VAR_ABORT_LEN 0 // + 70 bytes
+#define ENABLE_FEATURE_CHAT_CLR_ABORT 0 // +113 bytes
+#define ENABLE_FEATURE_CHAT_SWALLOW_OPTS 0 // + 23 bytes
+*/
+
+// default timeout: 45 sec
+#define DEFAULT_CHAT_TIMEOUT 45*1000
+// max length of "abort string",
+// i.e. device reply which causes termination
+#define MAX_ABORT_LEN 50
+
+// possible exit codes
+enum {
+ ERR_OK = 0, // all's well
+ ERR_MEM, // read too much while expecting
+ ERR_IO, // signalled or I/O error
+ ERR_TIMEOUT, // timed out while expecting
+ ERR_ABORT, // first abort condition was met
+// ERR_ABORT2, // second abort condition was met
+// ...
+};
+
+// exit code
+// N.B> 10 bytes for volatile. Why all these signals?!
+static /*volatile*/ smallint exitcode;
+
+// trap for critical signals
+static void signal_handler(ATTRIBUTE_UNUSED int signo)
+{
+ // report I/O error condition
+ exitcode = ERR_IO;
+}
+
+#if !ENABLE_FEATURE_CHAT_IMPLICIT_CR
+#define unescape(s, nocr) unescape(s)
+#endif
+static size_t unescape(char *s, int *nocr)
+{
+ char *start = s;
+ char *p = s;
+
+ while (*s) {
+ char c = *s;
+ // do we need special processing?
+ // standard escapes + \s for space and \N for \0
+ // \c inhibits terminating \r for commands and is noop for expects
+ if ('\\' == c) {
+ c = *++s;
+ if (c) {
+#if ENABLE_FEATURE_CHAT_IMPLICIT_CR
+ if ('c' == c) {
+ *nocr = 1;
+ goto next;
+ }
+#endif
+ if ('N' == c) {
+ c = '\0';
+ } else if ('s' == c) {
+ c = ' ';
+#if ENABLE_FEATURE_CHAT_NOFAIL
+ // unescape leading dash only
+ // TODO: and only for expect, not command string
+ } else if ('-' == c && (start + 1 == s)) {
+ //c = '-';
+#endif
+ } else {
+ c = bb_process_escape_sequence((const char **)&s);
+ s--;
+ }
+ }
+ // ^A becomes \001, ^B -- \002 and so on...
+ } else if ('^' == c) {
+ c = *++s-'@';
+ }
+ // put unescaped char
+ *p++ = c;
+#if ENABLE_FEATURE_CHAT_IMPLICIT_CR
+ next:
+#endif
+ // next char
+ s++;
+ }
+ *p = '\0';
+
+ return p - start;
+}
+
+
+int chat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int chat_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+// should we dump device output? to what fd? by default no.
+// this can be controlled later via ECHO {ON|OFF} chat directive
+// int echo_fd;
+ bool echo = 0;
+ // collection of device replies which cause unconditional termination
+ llist_t *aborts = NULL;
+ // inactivity period
+ int timeout = DEFAULT_CHAT_TIMEOUT;
+ // maximum length of abort string
+#if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN
+ size_t max_abort_len = 0;
+#else
+#define max_abort_len MAX_ABORT_LEN
+#endif
+#if ENABLE_FEATURE_CHAT_TTY_HIFI
+ struct termios tio0, tio;
+#endif
+ // directive names
+ enum {
+ DIR_HANGUP = 0,
+ DIR_ABORT,
+#if ENABLE_FEATURE_CHAT_CLR_ABORT
+ DIR_CLR_ABORT,
+#endif
+ DIR_TIMEOUT,
+ DIR_ECHO,
+ DIR_SAY,
+ };
+
+ // make x* functions fail with correct exitcode
+ xfunc_error_retval = ERR_IO;
+
+ // trap vanilla signals to prevent process from being killed suddenly
+ bb_signals(0
+ + (1 << SIGHUP)
+ + (1 << SIGINT)
+ + (1 << SIGTERM)
+ + (1 << SIGPIPE)
+ , signal_handler);
+
+#if ENABLE_FEATURE_CHAT_TTY_HIFI
+ tcgetattr(STDIN_FILENO, &tio);
+ tio0 = tio;
+ cfmakeraw(&tio);
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio);
+#endif
+
+#if ENABLE_FEATURE_CHAT_SWALLOW_OPTS
+ getopt32(argv, "vVsSE");
+ argv += optind;
+#else
+ argv++; // goto first arg
+#endif
+ // handle chat expect-send pairs
+ while (*argv) {
+ // directive given? process it
+ int key = index_in_strings(
+ "HANGUP\0" "ABORT\0"
+#if ENABLE_FEATURE_CHAT_CLR_ABORT
+ "CLR_ABORT\0"
+#endif
+ "TIMEOUT\0" "ECHO\0" "SAY\0"
+ , *argv
+ );
+ if (key >= 0) {
+ // cache directive value
+ char *arg = *++argv;
+ // ON -> 1, anything else -> 0
+ bool onoff = !strcmp("ON", arg);
+ // process directive
+ if (DIR_HANGUP == key) {
+ // turn SIGHUP on/off
+ signal(SIGHUP, onoff ? signal_handler : SIG_IGN);
+ } else if (DIR_ABORT == key) {
+ // append the string to abort conditions
+#if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN
+ size_t len = strlen(arg);
+ if (len > max_abort_len)
+ max_abort_len = len;
+#endif
+ llist_add_to_end(&aborts, arg);
+#if ENABLE_FEATURE_CHAT_CLR_ABORT
+ } else if (DIR_CLR_ABORT == key) {
+ // remove the string from abort conditions
+ // N.B. gotta refresh maximum length too...
+#if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN
+ max_abort_len = 0;
+#endif
+ for (llist_t *l = aborts; l; l = l->link) {
+#if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN
+ size_t len = strlen(l->data);
+#endif
+ if (!strcmp(arg, l->data)) {
+ llist_unlink(&aborts, l);
+ continue;
+ }
+#if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN
+ if (len > max_abort_len)
+ max_abort_len = len;
+#endif
+ }
+#endif
+ } else if (DIR_TIMEOUT == key) {
+ // set new timeout
+ // -1 means OFF
+ timeout = atoi(arg) * 1000;
+ // 0 means default
+ // >0 means value in msecs
+ if (!timeout)
+ timeout = DEFAULT_CHAT_TIMEOUT;
+ } else if (DIR_ECHO == key) {
+ // turn echo on/off
+ // N.B. echo means dumping output
+ // from stdin (device) to stderr
+ echo = onoff;
+//TODO? echo_fd = onoff * STDERR_FILENO;
+//TODO? echo_fd = xopen(arg, O_WRONLY|O_CREAT|O_TRUNC);
+ } else if (DIR_SAY == key) {
+ // just print argument verbatim
+ fprintf(stderr, arg);
+ }
+ // next, please!
+ argv++;
+ // ordinary expect-send pair!
+ } else {
+ //-----------------------
+ // do expect
+ //-----------------------
+ int expect_len;
+ size_t buf_len = 0;
+ size_t max_len = max_abort_len;
+
+ struct pollfd pfd;
+#if ENABLE_FEATURE_CHAT_NOFAIL
+ int nofail = 0;
+#endif
+ char *expect = *argv++;
+
+ // sanity check: shall we really expect something?
+ if (!expect)
+ goto expect_done;
+
+#if ENABLE_FEATURE_CHAT_NOFAIL
+ // if expect starts with -
+ if ('-' == *expect) {
+ // swallow -
+ expect++;
+ // and enter nofail mode
+ nofail++;
+ }
+#endif
+
+#ifdef ___TEST___BUF___ // test behaviour with a small buffer
+# undef COMMON_BUFSIZE
+# define COMMON_BUFSIZE 6
+#endif
+ // expand escape sequences in expect
+ expect_len = unescape(expect, &expect_len /*dummy*/);
+ if (expect_len > max_len)
+ max_len = expect_len;
+ // sanity check:
+ // we should expect more than nothing but not more than input buffer
+ // TODO: later we'll get rid of fixed-size buffer
+ if (!expect_len)
+ goto expect_done;
+ if (max_len >= COMMON_BUFSIZE) {
+ exitcode = ERR_MEM;
+ goto expect_done;
+ }
+
+ // get reply
+ pfd.fd = STDIN_FILENO;
+ pfd.events = POLLIN;
+ while (!exitcode
+ && poll(&pfd, 1, timeout) > 0
+ && (pfd.revents & POLLIN)
+ ) {
+#define buf bb_common_bufsiz1
+ llist_t *l;
+ ssize_t delta;
+
+ // read next char from device
+ if (safe_read(STDIN_FILENO, buf+buf_len, 1) > 0) {
+ // dump device output if ECHO ON or RECORD fname
+//TODO? if (echo_fd > 0) {
+//TODO? full_write(echo_fd, buf+buf_len, 1);
+//TODO? }
+ if (echo > 0)
+ full_write(STDERR_FILENO, buf+buf_len, 1);
+ buf_len++;
+ // move input frame if we've reached higher bound
+ if (buf_len > COMMON_BUFSIZE) {
+ memmove(buf, buf+buf_len-max_len, max_len);
+ buf_len = max_len;
+ }
+ }
+ // N.B. rule of thumb: values being looked for can
+ // be found only at the end of input buffer
+ // this allows to get rid of strstr() and memmem()
+
+ // TODO: make expect and abort strings processed uniformly
+ // abort condition is met? -> bail out
+ for (l = aborts, exitcode = ERR_ABORT; l; l = l->link, ++exitcode) {
+ size_t len = strlen(l->data);
+ delta = buf_len-len;
+ if (delta >= 0 && !memcmp(buf+delta, l->data, len))
+ goto expect_done;
+ }
+ exitcode = ERR_OK;
+
+ // expected reply received? -> goto next command
+ delta = buf_len - expect_len;
+ if (delta >= 0 && !memcmp(buf+delta, expect, expect_len))
+ goto expect_done;
+#undef buf
+ }
+
+ // device timed out or unexpected reply received
+ exitcode = ERR_TIMEOUT;
+ expect_done:
+#if ENABLE_FEATURE_CHAT_NOFAIL
+ // on success and when in nofail mode
+ // we should skip following subsend-subexpect pairs
+ if (nofail) {
+ if (!exitcode) {
+ // find last send before non-dashed expect
+ while (*argv && argv[1] && '-' == argv[1][0])
+ argv += 2;
+ // skip the pair
+ // N.B. do we really need this?!
+ if (!*argv++ || !*argv++)
+ break;
+ }
+ // nofail mode also clears all but IO errors (or signals)
+ if (ERR_IO != exitcode)
+ exitcode = ERR_OK;
+ }
+#endif
+ // bail out unless we expected successfully
+ if (exitcode)
+ break;
+
+ //-----------------------
+ // do send
+ //-----------------------
+ if (*argv) {
+#if ENABLE_FEATURE_CHAT_IMPLICIT_CR
+ int nocr = 0; // inhibit terminating command with \r
+#endif
+ char *loaded = NULL; // loaded command
+ size_t len;
+ char *buf = *argv++;
+
+ // if command starts with @
+ // load "real" command from file named after @
+ if ('@' == *buf) {
+ // skip the @ and any following white-space
+ trim(++buf);
+ buf = loaded = xmalloc_xopen_read_close(buf, NULL);
+ }
+
+ // expand escape sequences in command
+ len = unescape(buf, &nocr);
+
+ // send command
+#if ENABLE_FEATURE_CHAT_SEND_ESCAPES
+ pfd.fd = STDOUT_FILENO;
+ pfd.events = POLLOUT;
+ while (len && !exitcode
+ && poll(&pfd, 1, timeout) > 0
+ && (pfd.revents & POLLOUT)
+ ) {
+ // ugly! ugly! ugly!
+ // gotta send char by char to achieve this!
+ // Brrr...
+ // "\\d" means 1 sec delay, "\\p" means 0.01 sec delay
+ // "\\K" means send BREAK
+ char c = *buf;
+ if ('\\' == c) {
+ c = *++buf;
+ if ('d' == c) {
+ sleep(1);
+ len--;
+ continue;
+ } else if ('p' == c) {
+ usleep(10000);
+ len--;
+ continue;
+ } else if ('K' == c) {
+ tcsendbreak(STDOUT_FILENO, 0);
+ len--;
+ continue;
+ } else {
+ buf--;
+ }
+ }
+ if (safe_write(STDOUT_FILENO, buf, 1) > 0) {
+ len--;
+ buf++;
+ } else
+ break;
+ }
+#else
+// if (len) {
+ alarm(timeout);
+ len -= full_write(STDOUT_FILENO, buf, len);
+ alarm(0);
+// }
+#endif
+
+ // report I/O error if there still exists at least one non-sent char
+ if (len)
+ exitcode = ERR_IO;
+
+ // free loaded command (if any)
+ if (loaded)
+ free(loaded);
+#if ENABLE_FEATURE_CHAT_IMPLICIT_CR
+ // or terminate command with \r (if not inhibited)
+ else if (!nocr)
+ xwrite(STDOUT_FILENO, "\r", 1);
+#endif
+
+ // bail out unless we sent command successfully
+ if (exitcode)
+ break;
+
+ }
+ }
+ }
+
+#if ENABLE_FEATURE_CHAT_TTY_HIFI
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio0);
+#endif
+
+ return exitcode;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/chrt.c b/cleopatre/busybox-1.11.1-spc300/miscutils/chrt.c
new file mode 100644
index 0000000000..a0f684bb3a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/chrt.c
@@ -0,0 +1,123 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * chrt - manipulate real-time attributes of a process
+ * Copyright (c) 2006-2007 Bernhard Fischer
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include <sched.h>
+#include "libbb.h"
+#ifndef _POSIX_PRIORITY_SCHEDULING
+#warning your system may be foobared
+#endif
+static const struct {
+ int policy;
+ char name[12];
+} policies[] = {
+ {SCHED_OTHER, "SCHED_OTHER"},
+ {SCHED_FIFO, "SCHED_FIFO"},
+ {SCHED_RR, "SCHED_RR"}
+};
+
+static void show_min_max(int pol)
+{
+ const char *fmt = "%s min/max priority\t: %d/%d\n\0%s not supported?\n";
+ int max, min;
+ max = sched_get_priority_max(pol);
+ min = sched_get_priority_min(pol);
+ if (max >= 0 && min >= 0)
+ printf(fmt, policies[pol].name, min, max);
+ else {
+ fmt += 29;
+ printf(fmt, policies[pol].name);
+ }
+}
+
+#define OPT_m (1<<0)
+#define OPT_p (1<<1)
+#define OPT_r (1<<2)
+#define OPT_f (1<<3)
+#define OPT_o (1<<4)
+
+int chrt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int chrt_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ pid_t pid = 0;
+ unsigned opt;
+ struct sched_param sp;
+ char *pid_str;
+ char *priority = priority; /* for compiler */
+ const char *current_new;
+ int policy = SCHED_RR;
+
+ /* at least 1 arg; only one policy accepted */
+ opt_complementary = "-1:r--fo:f--ro:r--fo";
+ opt = getopt32(argv, "+mprfo");
+ if (opt & OPT_r)
+ policy = SCHED_RR;
+ if (opt & OPT_f)
+ policy = SCHED_FIFO;
+ if (opt & OPT_o)
+ policy = SCHED_OTHER;
+ if (opt & OPT_m) { /* print min/max */
+ show_min_max(SCHED_FIFO);
+ show_min_max(SCHED_RR);
+ show_min_max(SCHED_OTHER);
+ fflush_stdout_and_exit(EXIT_SUCCESS);
+ }
+
+ argv += optind;
+ if (opt & OPT_p) {
+ pid_str = *argv++;
+ if (*argv) { /* "-p <priority> <pid> [...]" */
+ priority = pid_str;
+ pid_str = *argv;
+ }
+ /* else "-p <pid>", and *argv == NULL */
+ pid = xatoul_range(pid_str, 1, ((unsigned)(pid_t)ULONG_MAX) >> 1);
+ } else {
+ priority = *argv++;
+ if (!*argv)
+ bb_show_usage();
+ }
+
+ current_new = "current\0new";
+ if (opt & OPT_p) {
+ int pol;
+ print_rt_info:
+ pol = sched_getscheduler(pid);
+ if (pol < 0)
+ bb_perror_msg_and_die("can't %cet pid %d's policy", 'g', pid);
+ printf("pid %d's %s scheduling policy: %s\n",
+ pid, current_new, policies[pol].name);
+ if (sched_getparam(pid, &sp))
+ bb_perror_msg_and_die("can't get pid %d's attributes", pid);
+ printf("pid %d's %s scheduling priority: %d\n",
+ pid, current_new, sp.sched_priority);
+ if (!*argv) {
+ /* Either it was just "-p <pid>",
+ * or it was "-p <priority> <pid>" and we came here
+ * for the second time (see goto below) */
+ return EXIT_SUCCESS;
+ }
+ *argv = NULL;
+ current_new += 8;
+ }
+
+ /* from the manpage of sched_getscheduler:
+ [...] sched_priority can have a value in the range 0 to 99.
+ [...] SCHED_OTHER or SCHED_BATCH must be assigned static priority 0.
+ [...] SCHED_FIFO or SCHED_RR can have static priority in 1..99 range.
+ */
+ sp.sched_priority = xstrtou_range(priority, 0, policy != SCHED_OTHER ? 1 : 0, 99);
+
+ if (sched_setscheduler(pid, policy, &sp) < 0)
+ bb_perror_msg_and_die("can't %cet pid %d's policy", 's', pid);
+
+ if (!*argv) /* "-p <priority> <pid> [...]" */
+ goto print_rt_info;
+
+ BB_EXECVP(*argv, argv);
+ bb_simple_perror_msg_and_die(*argv);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/crond.c b/cleopatre/busybox-1.11.1-spc300/miscutils/crond.c
new file mode 100644
index 0000000000..2bed5a4b16
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/crond.c
@@ -0,0 +1,944 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * crond -d[#] -c <crondir> -f -b
+ *
+ * run as root, but NOT setuid root
+ *
+ * Copyright 1994 Matthew Dillon (dillon@apollo.west.oic.com)
+ * (version 2.3.2)
+ * Vladimir Oleynik <dzo@simtreas.ru> (C) 2002
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+#include <syslog.h>
+
+/* glibc frees previous setenv'ed value when we do next setenv()
+ * of the same variable. uclibc does not do this! */
+#if (defined(__GLIBC__) && !defined(__UCLIBC__)) /* || OTHER_SAFE_LIBC... */
+#define SETENV_LEAKS 0
+#else
+#define SETENV_LEAKS 1
+#endif
+
+
+#ifndef CRONTABS
+#define CRONTABS "/var/spool/cron/crontabs"
+#endif
+#ifndef TMPDIR
+#define TMPDIR "/var/spool/cron"
+#endif
+#ifndef SENDMAIL
+#define SENDMAIL "sendmail"
+#endif
+#ifndef SENDMAIL_ARGS
+# if ENABLE_SENDMAIL
+# define SENDMAIL_ARGS "localhost", line->cl_MailTo
+# else
+# define SENDMAIL_ARGS "-ti", "oem"
+# endif
+#endif
+#ifndef CRONUPDATE
+#define CRONUPDATE "cron.update"
+#endif
+#ifndef MAXLINES
+#define MAXLINES 256 /* max lines in non-root crontabs */
+#endif
+
+
+typedef struct CronFile {
+ struct CronFile *cf_Next;
+ struct CronLine *cf_LineBase;
+ char *cf_User; /* username */
+ smallint cf_Ready; /* bool: one or more jobs ready */
+ smallint cf_Running; /* bool: one or more jobs running */
+ smallint cf_Deleted; /* marked for deletion, ignore */
+} CronFile;
+
+typedef struct CronLine {
+ struct CronLine *cl_Next;
+ char *cl_Shell; /* shell command */
+ pid_t cl_Pid; /* running pid, 0, or armed (-1) */
+#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
+ int cl_MailPos; /* 'empty file' size */
+ smallint cl_MailFlag; /* running pid is for mail */
+ char *cl_MailTo; /* whom to mail results */
+#endif
+ /* ordered by size, not in natural order. makes code smaller: */
+ char cl_Dow[7]; /* 0-6, beginning sunday */
+ char cl_Mons[12]; /* 0-11 */
+ char cl_Hrs[24]; /* 0-23 */
+ char cl_Days[32]; /* 1-31 */
+ char cl_Mins[60]; /* 0-59 */
+} CronLine;
+
+
+#define DaemonUid 0
+
+
+enum {
+ OPT_l = (1 << 0),
+ OPT_L = (1 << 1),
+ OPT_f = (1 << 2),
+ OPT_b = (1 << 3),
+ OPT_S = (1 << 4),
+ OPT_c = (1 << 5),
+ OPT_d = (1 << 6) * ENABLE_DEBUG_CROND_OPTION,
+};
+#if ENABLE_DEBUG_CROND_OPTION
+#define DebugOpt (option_mask32 & OPT_d)
+#else
+#define DebugOpt 0
+#endif
+
+
+struct globals {
+ unsigned LogLevel; /* = 8; */
+ const char *LogFile;
+ const char *CDir; /* = CRONTABS; */
+ CronFile *FileBase;
+#if SETENV_LEAKS
+ char *env_var_user;
+ char *env_var_home;
+#endif
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+#define LogLevel (G.LogLevel )
+#define LogFile (G.LogFile )
+#define CDir (G.CDir )
+#define FileBase (G.FileBase )
+#define env_var_user (G.env_var_user )
+#define env_var_home (G.env_var_home )
+#define INIT_G() do { \
+ LogLevel = 8; \
+ CDir = CRONTABS; \
+} while (0)
+
+
+static void CheckUpdates(void);
+static void SynchronizeDir(void);
+static int TestJobs(time_t t1, time_t t2);
+static void RunJobs(void);
+static int CheckJobs(void);
+static void RunJob(const char *user, CronLine *line);
+#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
+static void EndJob(const char *user, CronLine *line);
+#else
+#define EndJob(user, line) ((line)->cl_Pid = 0)
+#endif
+static void DeleteFile(const char *userName);
+
+
+#define LVL5 "\x05"
+#define LVL7 "\x07"
+#define LVL8 "\x08"
+#define LVL9 "\x09"
+#define WARN9 "\x49"
+#define DIE9 "\xc9"
+/* level >= 20 is "error" */
+#define ERR20 "\x14"
+
+static void crondlog(const char *ctl, ...)
+{
+ va_list va;
+ int level = (ctl[0] & 0x1f);
+
+ va_start(va, ctl);
+ if (level >= (int)LogLevel) {
+ /* Debug mode: all to (non-redirected) stderr, */
+ /* Syslog mode: all to syslog (logmode = LOGMODE_SYSLOG), */
+ if (!DebugOpt && LogFile) {
+ /* Otherwise (log to file): we reopen log file at every write: */
+ int logfd = open3_or_warn(LogFile, O_WRONLY | O_CREAT | O_APPEND, 0600);
+ if (logfd >= 0)
+ xmove_fd(logfd, STDERR_FILENO);
+ }
+// TODO: ERR -> error, WARN -> warning, LVL -> info
+ bb_verror_msg(ctl + 1, va, /* strerr: */ NULL);
+ }
+ va_end(va);
+ if (ctl[0] & 0x80)
+ exit(20);
+}
+
+int crond_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int crond_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ unsigned opt;
+
+ INIT_G();
+
+ /* "-b after -f is ignored", and so on for every pair a-b */
+ opt_complementary = "f-b:b-f:S-L:L-S" USE_DEBUG_CROND_OPTION(":d-l")
+ ":l+:d+"; /* -l and -d have numeric param */
+ opt = getopt32(argv, "l:L:fbSc:" USE_DEBUG_CROND_OPTION("d:"),
+ &LogLevel, &LogFile, &CDir
+ USE_DEBUG_CROND_OPTION(,&LogLevel));
+ /* both -d N and -l N set the same variable: LogLevel */
+
+ if (!(opt & OPT_f)) {
+ /* close stdin, stdout, stderr.
+ * close unused descriptors - don't need them. */
+ bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv);
+ }
+
+ if (!DebugOpt && LogFile == NULL) {
+ /* logging to syslog */
+ openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON);
+ logmode = LOGMODE_SYSLOG;
+ }
+
+ xchdir(CDir);
+ //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */
+ setenv("SHELL", DEFAULT_SHELL, 1); /* once, for all future children */
+ crondlog(LVL9 "crond (busybox "BB_VER") started, log level %d", LogLevel);
+ SynchronizeDir();
+
+ /* main loop - synchronize to 1 second after the minute, minimum sleep
+ * of 1 second. */
+ {
+ time_t t1 = time(NULL);
+ time_t t2;
+ long dt;
+ int rescan = 60;
+ int sleep_time = 60;
+
+ write_pidfile("/var/run/crond.pid");
+ for (;;) {
+ sleep((sleep_time + 1) - (time(NULL) % sleep_time));
+
+ t2 = time(NULL);
+ dt = (long)t2 - (long)t1;
+
+ /*
+ * The file 'cron.update' is checked to determine new cron
+ * jobs. The directory is rescanned once an hour to deal
+ * with any screwups.
+ *
+ * check for disparity. Disparities over an hour either way
+ * result in resynchronization. A reverse-indexed disparity
+ * less then an hour causes us to effectively sleep until we
+ * match the original time (i.e. no re-execution of jobs that
+ * have just been run). A forward-indexed disparity less then
+ * an hour causes intermediate jobs to be run, but only once
+ * in the worst case.
+ *
+ * when running jobs, the inequality used is greater but not
+ * equal to t1, and less then or equal to t2.
+ */
+ if (--rescan == 0) {
+ rescan = 60;
+ SynchronizeDir();
+ }
+ CheckUpdates();
+ if (DebugOpt)
+ crondlog(LVL5 "wakeup dt=%ld", dt);
+ if (dt < -60 * 60 || dt > 60 * 60) {
+ crondlog(WARN9 "time disparity of %d minutes detected", dt / 60);
+ } else if (dt > 0) {
+ TestJobs(t1, t2);
+ RunJobs();
+ sleep(5);
+ if (CheckJobs() > 0) {
+ sleep_time = 10;
+ } else {
+ sleep_time = 60;
+ }
+ }
+ t1 = t2;
+ }
+ }
+ return 0; /* not reached */
+}
+
+#if SETENV_LEAKS
+/* We set environment *before* vfork (because we want to use vfork),
+ * so we cannot use setenv() - repeated calls to setenv() may leak memory!
+ * Using putenv(), and freeing memory after unsetenv() won't leak */
+static void safe_setenv4(char **pvar_val, const char *var, const char *val /*, int len*/)
+{
+ const int len = 4; /* both var names are 4 char long */
+ char *var_val = *pvar_val;
+
+ if (var_val) {
+ var_val[len] = '\0'; /* nuke '=' */
+ unsetenv(var_val);
+ free(var_val);
+ }
+ *pvar_val = xasprintf("%s=%s", var, val);
+ putenv(*pvar_val);
+}
+#endif
+
+static void SetEnv(struct passwd *pas)
+{
+#if SETENV_LEAKS
+ safe_setenv4(&env_var_user, "USER", pas->pw_name);
+ safe_setenv4(&env_var_home, "HOME", pas->pw_dir);
+ /* if we want to set user's shell instead: */
+ /*safe_setenv(env_var_user, "SHELL", pas->pw_shell, 5);*/
+#else
+ setenv("USER", pas->pw_name, 1);
+ setenv("HOME", pas->pw_dir, 1);
+#endif
+ /* currently, we use constant one: */
+ /*setenv("SHELL", DEFAULT_SHELL, 1); - done earlier */
+}
+
+static void ChangeUser(struct passwd *pas)
+{
+ /* careful: we're after vfork! */
+ change_identity(pas); /* - initgroups, setgid, setuid */
+ if (chdir(pas->pw_dir) < 0) {
+ crondlog(LVL9 "can't chdir(%s)", pas->pw_dir);
+ if (chdir(TMPDIR) < 0) {
+ crondlog(DIE9 "can't chdir(%s)", TMPDIR); /* exits */
+ }
+ }
+}
+
+static const char DowAry[] ALIGN1 =
+ "sun""mon""tue""wed""thu""fri""sat"
+ /* "Sun""Mon""Tue""Wed""Thu""Fri""Sat" */
+;
+
+static const char MonAry[] ALIGN1 =
+ "jan""feb""mar""apr""may""jun""jul""aug""sep""oct""nov""dec"
+ /* "Jan""Feb""Mar""Apr""May""Jun""Jul""Aug""Sep""Oct""Nov""Dec" */
+;
+
+static char *ParseField(char *user, char *ary, int modvalue, int off,
+ const char *names, char *ptr)
+/* 'names' is a pointer to a set of 3-char abbreviations */
+{
+ char *base = ptr;
+ int n1 = -1;
+ int n2 = -1;
+
+ if (base == NULL) {
+ return NULL;
+ }
+
+ while (!isspace(*ptr)) {
+ int skip = 0;
+
+ /* Handle numeric digit or symbol or '*' */
+ if (*ptr == '*') {
+ n1 = 0; /* everything will be filled */
+ n2 = modvalue - 1;
+ skip = 1;
+ ++ptr;
+ } else if (isdigit(*ptr)) {
+ if (n1 < 0) {
+ n1 = strtol(ptr, &ptr, 10) + off;
+ } else {
+ n2 = strtol(ptr, &ptr, 10) + off;
+ }
+ skip = 1;
+ } else if (names) {
+ int i;
+
+ for (i = 0; names[i]; i += 3) {
+ /* was using strncmp before... */
+ if (strncasecmp(ptr, &names[i], 3) == 0) {
+ ptr += 3;
+ if (n1 < 0) {
+ n1 = i / 3;
+ } else {
+ n2 = i / 3;
+ }
+ skip = 1;
+ break;
+ }
+ }
+ }
+
+ /* handle optional range '-' */
+ if (skip == 0) {
+ crondlog(WARN9 "user %s: parse error at %s", user, base);
+ return NULL;
+ }
+ if (*ptr == '-' && n2 < 0) {
+ ++ptr;
+ continue;
+ }
+
+ /*
+ * collapse single-value ranges, handle skipmark, and fill
+ * in the character array appropriately.
+ */
+ if (n2 < 0) {
+ n2 = n1;
+ }
+ if (*ptr == '/') {
+ skip = strtol(ptr + 1, &ptr, 10);
+ }
+
+ /*
+ * fill array, using a failsafe is the easiest way to prevent
+ * an endless loop
+ */
+ {
+ int s0 = 1;
+ int failsafe = 1024;
+
+ --n1;
+ do {
+ n1 = (n1 + 1) % modvalue;
+
+ if (--s0 == 0) {
+ ary[n1 % modvalue] = 1;
+ s0 = skip;
+ }
+ if (--failsafe == 0) {
+ crondlog(WARN9 "user %s: parse error at %s", user, base);
+ return NULL;
+ }
+ } while (n1 != n2);
+
+ }
+ if (*ptr != ',') {
+ break;
+ }
+ ++ptr;
+ n1 = -1;
+ n2 = -1;
+ }
+
+ if (!isspace(*ptr)) {
+ crondlog(WARN9 "user %s: parse error at %s", user, base);
+ return NULL;
+ }
+
+ if (DebugOpt && (LogLevel <= 5)) { /* like LVL5 */
+ /* can't use crondlog, it inserts '\n' */
+ int i;
+ for (i = 0; i < modvalue; ++i)
+ fprintf(stderr, "%d", (unsigned char)ary[i]);
+ fputc('\n', stderr);
+ }
+ return skip_whitespace(ptr);
+}
+
+static void FixDayDow(CronLine *line)
+{
+ unsigned i;
+ int weekUsed = 0;
+ int daysUsed = 0;
+
+ for (i = 0; i < ARRAY_SIZE(line->cl_Dow); ++i) {
+ if (line->cl_Dow[i] == 0) {
+ weekUsed = 1;
+ break;
+ }
+ }
+ for (i = 0; i < ARRAY_SIZE(line->cl_Days); ++i) {
+ if (line->cl_Days[i] == 0) {
+ daysUsed = 1;
+ break;
+ }
+ }
+ if (weekUsed != daysUsed) {
+ if (weekUsed)
+ memset(line->cl_Days, 0, sizeof(line->cl_Days));
+ else /* daysUsed */
+ memset(line->cl_Dow, 0, sizeof(line->cl_Dow));
+ }
+}
+
+static void SynchronizeFile(const char *fileName)
+{
+ FILE *fi;
+ struct stat sbuf;
+ int maxEntries;
+ int maxLines;
+ char buf[1024];
+#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
+ char *mailTo = NULL;
+#endif
+
+ if (!fileName)
+ return;
+
+ DeleteFile(fileName);
+ fi = fopen(fileName, "r");
+ if (!fi)
+ return;
+
+ maxEntries = MAXLINES;
+ if (strcmp(fileName, "root") == 0) {
+ maxEntries = 65535;
+ }
+ maxLines = maxEntries * 10;
+
+ if (fstat(fileno(fi), &sbuf) == 0 && sbuf.st_uid == DaemonUid) {
+ CronFile *file = xzalloc(sizeof(CronFile));
+ CronLine **pline;
+
+ file->cf_User = xstrdup(fileName);
+ pline = &file->cf_LineBase;
+
+ while (fgets(buf, sizeof(buf), fi) != NULL && --maxLines) {
+ CronLine *line;
+ char *ptr;
+
+ trim(buf);
+ if (buf[0] == '\0' || buf[0] == '#') {
+ continue;
+ }
+ if (--maxEntries == 0) {
+ break;
+ }
+ if (DebugOpt) {
+ crondlog(LVL5 "user:%s entry:%s", fileName, buf);
+ }
+ /* check if line is setting MAILTO= */
+ if (0 == strncmp("MAILTO=", buf, 7)) {
+#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
+ free(mailTo);
+ mailTo = (buf[7]) ? xstrdup(buf+7) : NULL;
+#endif /* otherwise just ignore such lines */
+ continue;
+ }
+ *pline = line = xzalloc(sizeof(CronLine));
+ /* parse date ranges */
+ ptr = ParseField(file->cf_User, line->cl_Mins, 60, 0, NULL, buf);
+ ptr = ParseField(file->cf_User, line->cl_Hrs, 24, 0, NULL, ptr);
+ ptr = ParseField(file->cf_User, line->cl_Days, 32, 0, NULL, ptr);
+ ptr = ParseField(file->cf_User, line->cl_Mons, 12, -1, MonAry, ptr);
+ ptr = ParseField(file->cf_User, line->cl_Dow, 7, 0, DowAry, ptr);
+ /* check failure */
+ if (ptr == NULL) {
+ free(line);
+ continue;
+ }
+ /*
+ * fix days and dow - if one is not "*" and the other
+ * is "*", the other is set to 0, and vise-versa
+ */
+ FixDayDow(line);
+#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
+ /* copy mailto (can be NULL) */
+ line->cl_MailTo = xstrdup(mailTo);
+#endif
+ /* copy command */
+ line->cl_Shell = xstrdup(ptr);
+ if (DebugOpt) {
+ crondlog(LVL5 " command:%s", ptr);
+ }
+ pline = &line->cl_Next;
+ }
+ *pline = NULL;
+
+ file->cf_Next = FileBase;
+ FileBase = file;
+
+ if (maxLines == 0 || maxEntries == 0) {
+ crondlog(WARN9 "user %s: too many lines", fileName);
+ }
+ }
+ fclose(fi);
+}
+
+static void CheckUpdates(void)
+{
+ FILE *fi;
+ char buf[256];
+
+ fi = fopen(CRONUPDATE, "r");
+ if (fi != NULL) {
+ unlink(CRONUPDATE);
+ while (fgets(buf, sizeof(buf), fi) != NULL) {
+ /* use first word only */
+ SynchronizeFile(strtok(buf, " \t\r\n"));
+ }
+ fclose(fi);
+ }
+}
+
+static void SynchronizeDir(void)
+{
+ CronFile *file;
+ /* Attempt to delete the database. */
+ again:
+ for (file = FileBase; file; file = file->cf_Next) {
+ if (!file->cf_Deleted) {
+ DeleteFile(file->cf_User);
+ goto again;
+ }
+ }
+
+ /*
+ * Remove cron update file
+ *
+ * Re-chdir, in case directory was renamed & deleted, or otherwise
+ * screwed up.
+ *
+ * scan directory and add associated users
+ */
+ unlink(CRONUPDATE);
+ if (chdir(CDir) < 0) {
+ crondlog(DIE9 "can't chdir(%s)", CDir);
+ }
+ {
+ DIR *dir = opendir(".");
+ struct dirent *den;
+
+ if (!dir)
+ crondlog(DIE9 "can't chdir(%s)", "."); /* exits */
+ while ((den = readdir(dir)) != NULL) {
+ if (strchr(den->d_name, '.') != NULL) {
+ continue;
+ }
+ if (getpwnam(den->d_name)) {
+ SynchronizeFile(den->d_name);
+ } else {
+ crondlog(LVL7 "ignoring %s", den->d_name);
+ }
+ }
+ closedir(dir);
+ }
+}
+
+/*
+ * DeleteFile() - delete user database
+ *
+ * Note: multiple entries for same user may exist if we were unable to
+ * completely delete a database due to running processes.
+ */
+static void DeleteFile(const char *userName)
+{
+ CronFile **pfile = &FileBase;
+ CronFile *file;
+
+ while ((file = *pfile) != NULL) {
+ if (strcmp(userName, file->cf_User) == 0) {
+ CronLine **pline = &file->cf_LineBase;
+ CronLine *line;
+
+ file->cf_Running = 0;
+ file->cf_Deleted = 1;
+
+ while ((line = *pline) != NULL) {
+ if (line->cl_Pid > 0) {
+ file->cf_Running = 1;
+ pline = &line->cl_Next;
+ } else {
+ *pline = line->cl_Next;
+ free(line->cl_Shell);
+ free(line);
+ }
+ }
+ if (file->cf_Running == 0) {
+ *pfile = file->cf_Next;
+ free(file->cf_User);
+ free(file);
+ } else {
+ pfile = &file->cf_Next;
+ }
+ } else {
+ pfile = &file->cf_Next;
+ }
+ }
+}
+
+/*
+ * TestJobs()
+ *
+ * determine which jobs need to be run. Under normal conditions, the
+ * period is about a minute (one scan). Worst case it will be one
+ * hour (60 scans).
+ */
+static int TestJobs(time_t t1, time_t t2)
+{
+ int nJobs = 0;
+ time_t t;
+
+ /* Find jobs > t1 and <= t2 */
+
+ for (t = t1 - t1 % 60; t <= t2; t += 60) {
+ struct tm *tp;
+ CronFile *file;
+ CronLine *line;
+
+ if (t <= t1)
+ continue;
+
+ tp = localtime(&t);
+ for (file = FileBase; file; file = file->cf_Next) {
+ if (DebugOpt)
+ crondlog(LVL5 "file %s:", file->cf_User);
+ if (file->cf_Deleted)
+ continue;
+ for (line = file->cf_LineBase; line; line = line->cl_Next) {
+ if (DebugOpt)
+ crondlog(LVL5 " line %s", line->cl_Shell);
+ if (line->cl_Mins[tp->tm_min] && line->cl_Hrs[tp->tm_hour]
+ && (line->cl_Days[tp->tm_mday] || line->cl_Dow[tp->tm_wday])
+ && line->cl_Mons[tp->tm_mon]
+ ) {
+ if (DebugOpt) {
+ crondlog(LVL5 " job: %d %s",
+ (int)line->cl_Pid, line->cl_Shell);
+ }
+ if (line->cl_Pid > 0) {
+ crondlog(LVL8 "user %s: process already running: %s",
+ file->cf_User, line->cl_Shell);
+ } else if (line->cl_Pid == 0) {
+ line->cl_Pid = -1;
+ file->cf_Ready = 1;
+ ++nJobs;
+ }
+ }
+ }
+ }
+ }
+ return nJobs;
+}
+
+static void RunJobs(void)
+{
+ CronFile *file;
+ CronLine *line;
+
+ for (file = FileBase; file; file = file->cf_Next) {
+ if (!file->cf_Ready)
+ continue;
+
+ file->cf_Ready = 0;
+ for (line = file->cf_LineBase; line; line = line->cl_Next) {
+ if (line->cl_Pid >= 0)
+ continue;
+
+ RunJob(file->cf_User, line);
+ crondlog(LVL8 "USER %s pid %3d cmd %s",
+ file->cf_User, (int)line->cl_Pid, line->cl_Shell);
+ if (line->cl_Pid < 0) {
+ file->cf_Ready = 1;
+ } else if (line->cl_Pid > 0) {
+ file->cf_Running = 1;
+ }
+ }
+ }
+}
+
+/*
+ * CheckJobs() - check for job completion
+ *
+ * Check for job completion, return number of jobs still running after
+ * all done.
+ */
+static int CheckJobs(void)
+{
+ CronFile *file;
+ CronLine *line;
+ int nStillRunning = 0;
+
+ for (file = FileBase; file; file = file->cf_Next) {
+ if (file->cf_Running) {
+ file->cf_Running = 0;
+
+ for (line = file->cf_LineBase; line; line = line->cl_Next) {
+ int status, r;
+ if (line->cl_Pid <= 0)
+ continue;
+
+ r = waitpid(line->cl_Pid, &status, WNOHANG);
+ if (r < 0 || r == line->cl_Pid) {
+ EndJob(file->cf_User, line);
+ if (line->cl_Pid) {
+ file->cf_Running = 1;
+ }
+ } else if (r == 0) {
+ file->cf_Running = 1;
+ }
+ }
+ }
+ nStillRunning += file->cf_Running;
+ }
+ return nStillRunning;
+}
+
+#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
+
+// TODO: sendmail should be _run-time_ option, not compile-time!
+
+static void
+ForkJob(const char *user, CronLine *line, int mailFd,
+ const char *prog, const char *cmd, const char *arg,
+ const char *mail_filename)
+{
+ struct passwd *pas;
+ pid_t pid;
+
+ /* prepare things before vfork */
+ pas = getpwnam(user);
+ if (!pas) {
+ crondlog(LVL9 "can't get uid for %s", user);
+ goto err;
+ }
+ SetEnv(pas);
+
+ pid = vfork();
+ if (pid == 0) {
+ /* CHILD */
+ /* change running state to the user in question */
+ ChangeUser(pas);
+ if (DebugOpt) {
+ crondlog(LVL5 "child running %s", prog);
+ }
+ if (mailFd >= 0) {
+ xmove_fd(mailFd, mail_filename ? 1 : 0);
+ dup2(1, 2);
+ }
+ execl(prog, prog, cmd, arg, NULL);
+ crondlog(ERR20 "can't exec, user %s cmd %s %s %s", user, prog, cmd, arg);
+ if (mail_filename) {
+ fdprintf(1, "Exec failed: %s -c %s\n", prog, arg);
+ }
+ _exit(EXIT_SUCCESS);
+ }
+
+ line->cl_Pid = pid;
+ if (pid < 0) {
+ /* FORK FAILED */
+ crondlog(ERR20 "can't vfork");
+ err:
+ line->cl_Pid = 0;
+ if (mail_filename) {
+ unlink(mail_filename);
+ }
+ } else if (mail_filename) {
+ /* PARENT, FORK SUCCESS
+ * rename mail-file based on pid of process
+ */
+ char mailFile2[128];
+
+ snprintf(mailFile2, sizeof(mailFile2), "%s/cron.%s.%d", TMPDIR, user, pid);
+ rename(mail_filename, mailFile2); // TODO: xrename?
+ }
+
+ /*
+ * Close the mail file descriptor.. we can't just leave it open in
+ * a structure, closing it later, because we might run out of descriptors
+ */
+ if (mailFd >= 0) {
+ close(mailFd);
+ }
+}
+
+static void RunJob(const char *user, CronLine *line)
+{
+ char mailFile[128];
+ int mailFd = -1;
+
+ line->cl_Pid = 0;
+ line->cl_MailFlag = 0;
+
+ if (line->cl_MailTo) {
+ /* open mail file - owner root so nobody can screw with it. */
+ snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", TMPDIR, user, getpid());
+ mailFd = open(mailFile, O_CREAT | O_TRUNC | O_WRONLY | O_EXCL | O_APPEND, 0600);
+
+ if (mailFd >= 0) {
+ line->cl_MailFlag = 1;
+ fdprintf(mailFd, "To: %s\nSubject: cron: %s\n\n", user,
+ line->cl_Shell);
+ line->cl_MailPos = lseek(mailFd, 0, SEEK_CUR);
+ } else {
+ crondlog(ERR20 "cannot create mail file %s for user %s, "
+ "discarding output", mailFile, user);
+ }
+ }
+
+ ForkJob(user, line, mailFd, DEFAULT_SHELL, "-c", line->cl_Shell, mailFile);
+}
+
+/*
+ * EndJob - called when job terminates and when mail terminates
+ */
+static void EndJob(const char *user, CronLine *line)
+{
+ int mailFd;
+ char mailFile[128];
+ struct stat sbuf;
+
+ /* No job */
+ if (line->cl_Pid <= 0) {
+ line->cl_Pid = 0;
+ return;
+ }
+
+ /*
+ * End of job and no mail file
+ * End of sendmail job
+ */
+ snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", TMPDIR, user, line->cl_Pid);
+ line->cl_Pid = 0;
+
+ if (line->cl_MailFlag == 0) {
+ return;
+ }
+ line->cl_MailFlag = 0;
+
+ /*
+ * End of primary job - check for mail file. If size has increased and
+ * the file is still valid, we sendmail it.
+ */
+ mailFd = open(mailFile, O_RDONLY);
+ unlink(mailFile);
+ if (mailFd < 0) {
+ return;
+ }
+
+ if (fstat(mailFd, &sbuf) < 0 || sbuf.st_uid != DaemonUid
+ || sbuf.st_nlink != 0 || sbuf.st_size == line->cl_MailPos
+ || !S_ISREG(sbuf.st_mode)
+ ) {
+ close(mailFd);
+ return;
+ }
+ if (line->cl_MailTo)
+ ForkJob(user, line, mailFd, SENDMAIL, SENDMAIL_ARGS, NULL);
+}
+
+#else /* crond without sendmail */
+
+static void RunJob(const char *user, CronLine *line)
+{
+ struct passwd *pas;
+ pid_t pid;
+
+ /* prepare things before vfork */
+ pas = getpwnam(user);
+ if (!pas) {
+ crondlog(LVL9 "can't get uid for %s", user);
+ goto err;
+ }
+ SetEnv(pas);
+
+ /* fork as the user in question and run program */
+ pid = vfork();
+ if (pid == 0) {
+ /* CHILD */
+ /* change running state to the user in question */
+ ChangeUser(pas);
+ if (DebugOpt) {
+ crondlog(LVL5 "child running %s", DEFAULT_SHELL);
+ }
+ execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", line->cl_Shell, NULL);
+ crondlog(ERR20 "can't exec, user %s cmd %s %s %s", user,
+ DEFAULT_SHELL, "-c", line->cl_Shell);
+ _exit(EXIT_SUCCESS);
+ }
+ if (pid < 0) {
+ /* FORK FAILED */
+ crondlog(ERR20 "can't vfork");
+ err:
+ pid = 0;
+ }
+ line->cl_Pid = pid;
+}
+
+#endif /* ENABLE_FEATURE_CROND_CALL_SENDMAIL */
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/crontab.c b/cleopatre/busybox-1.11.1-spc300/miscutils/crontab.c
new file mode 100644
index 0000000000..dc3179dac2
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/crontab.c
@@ -0,0 +1,234 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * CRONTAB
+ *
+ * usually setuid root, -c option only works if getuid() == geteuid()
+ *
+ * Copyright 1994 Matthew Dillon (dillon@apollo.west.oic.com)
+ * Vladimir Oleynik <dzo@simtreas.ru> (C) 2002
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+
+#ifndef CRONTABS
+#define CRONTABS "/var/spool/cron/crontabs"
+#endif
+#ifndef CRONUPDATE
+#define CRONUPDATE "cron.update"
+#endif
+
+static void change_user(const struct passwd *pas)
+{
+ setenv("USER", pas->pw_name, 1);
+ setenv("HOME", pas->pw_dir, 1);
+ setenv("SHELL", DEFAULT_SHELL, 1);
+
+ /* initgroups, setgid, setuid */
+ change_identity(pas);
+
+ if (chdir(pas->pw_dir) < 0) {
+ bb_perror_msg("chdir(%s) by %s failed",
+ pas->pw_dir, pas->pw_name);
+ xchdir("/tmp");
+ }
+}
+
+static void edit_file(const struct passwd *pas, const char *file)
+{
+ const char *ptr;
+ int pid = vfork();
+
+ if (pid < 0) /* failure */
+ bb_perror_msg_and_die("vfork");
+ if (pid) { /* parent */
+ wait4pid(pid);
+ return;
+ }
+
+ /* CHILD - change user and run editor */
+ change_user(pas);
+ ptr = getenv("VISUAL");
+ if (!ptr) {
+ ptr = getenv("EDITOR");
+ if (!ptr)
+ ptr = "vi";
+ }
+
+ BB_EXECLP(ptr, ptr, file, NULL);
+ bb_perror_msg_and_die("exec %s", ptr);
+}
+
+static int open_as_user(const struct passwd *pas, const char *file)
+{
+ pid_t pid;
+ char c;
+
+ pid = vfork();
+ if (pid < 0) /* ERROR */
+ bb_perror_msg_and_die("vfork");
+ if (pid) { /* PARENT */
+ if (wait4pid(pid) == 0) {
+ /* exitcode 0: child says it can read */
+ return open(file, O_RDONLY);
+ }
+ return -1;
+ }
+
+ /* CHILD */
+ /* initgroups, setgid, setuid */
+ change_identity(pas);
+ /* We just try to read one byte. If it works, file is readable
+ * under this user. We signal that by exiting with 0. */
+ _exit(safe_read(xopen(file, O_RDONLY), &c, 1) < 0);
+}
+
+int crontab_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int crontab_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ const struct passwd *pas;
+ const char *crontab_dir = CRONTABS;
+ char *tmp_fname;
+ char *new_fname;
+ char *user_name; /* -u USER */
+ int fd;
+ int opt_ler;
+
+ /* file [opts] Replace crontab from file
+ * - [opts] Replace crontab from stdin
+ * -u user User
+ * -c dir Crontab directory
+ * -l List crontab for user
+ * -e Edit crontab for user
+ * -r Delete crontab for user
+ * bbox also supports -d == -r, but most other crontab
+ * implementations do not. Deprecated.
+ */
+ enum {
+ OPT_u = (1 << 0),
+ OPT_c = (1 << 1),
+ OPT_l = (1 << 2),
+ OPT_e = (1 << 3),
+ OPT_r = (1 << 4),
+ OPT_ler = OPT_l + OPT_e + OPT_r,
+ };
+
+ opt_complementary = "?1:dr"; /* max one argument; -d implies -r */
+ opt_ler = getopt32(argv, "u:c:lerd", &user_name, &crontab_dir);
+ argv += optind;
+
+ if (sanitize_env_if_suid()) { /* Clears dangerous stuff, sets PATH */
+ /* run by non-root? */
+ if (opt_ler & (OPT_u|OPT_c))
+ bb_error_msg_and_die("only root can use -c or -u");
+ }
+
+ if (opt_ler & OPT_u) {
+ pas = getpwnam(user_name);
+ if (!pas)
+ bb_error_msg_and_die("user %s is not known", user_name);
+ } else {
+ uid_t my_uid = getuid();
+ pas = getpwuid(my_uid);
+ if (!pas)
+ bb_perror_msg_and_die("no user record for UID %u",
+ (unsigned)my_uid);
+ }
+
+#define user_name DONT_USE_ME_BEYOND_THIS_POINT
+
+ /* From now on, keep only -l, -e, -r bits */
+ opt_ler &= OPT_ler;
+ if ((opt_ler - 1) & opt_ler) /* more than one bit set? */
+ bb_show_usage();
+
+ /* Read replacement file under user's UID/GID/group vector */
+ if (!opt_ler) { /* Replace? */
+ if (!argv[0])
+ bb_show_usage();
+ if (NOT_LONE_DASH(argv[0])) {
+ fd = open_as_user(pas, argv[0]);
+ if (fd < 0)
+ bb_error_msg_and_die("user %s cannot read %s",
+ pas->pw_name, argv[0]);
+ xmove_fd(fd, STDIN_FILENO);
+ }
+ }
+
+ /* cd to our crontab directory */
+ xchdir(crontab_dir);
+
+ tmp_fname = NULL;
+
+ /* Handle requested operation */
+ switch (opt_ler) {
+
+ default: /* case OPT_r: Delete */
+ unlink(pas->pw_name);
+ break;
+
+ case OPT_l: /* List */
+ {
+ char *args[2] = { pas->pw_name, NULL };
+ return bb_cat(args);
+ /* list exits,
+ * the rest go play with cron update file */
+ }
+
+ case OPT_e: /* Edit */
+ tmp_fname = xasprintf("%s.%u", crontab_dir, (unsigned)getpid());
+ /* No O_EXCL: we don't want to be stuck if earlier crontabs
+ * were killed, leaving stale temp file behind */
+ fd = xopen3(tmp_fname, O_RDWR|O_CREAT|O_TRUNC, 0600);
+ xmove_fd(fd, STDIN_FILENO);
+ fchown(STDIN_FILENO, pas->pw_uid, pas->pw_gid);
+ fd = open(pas->pw_name, O_RDONLY);
+ if (fd >= 0) {
+ bb_copyfd_eof(fd, STDIN_FILENO);
+ close(fd);
+ }
+ edit_file(pas, tmp_fname);
+ xlseek(STDIN_FILENO, 0, SEEK_SET);
+ /* fall through */
+
+ case 0: /* Replace (no -l, -e, or -r were given) */
+ new_fname = xasprintf("%s.new", pas->pw_name);
+ fd = open(new_fname, O_WRONLY|O_CREAT|O_TRUNC|O_APPEND, 0600);
+ if (fd >= 0) {
+ bb_copyfd_eof(STDIN_FILENO, fd);
+ close(fd);
+ xrename(new_fname, pas->pw_name);
+ } else {
+ bb_error_msg("cannot create %s/%s",
+ crontab_dir, new_fname);
+ }
+ if (tmp_fname)
+ unlink(tmp_fname);
+ /*free(tmp_fname);*/
+ /*free(new_fname);*/
+
+ } /* switch */
+
+ /* Bump notification file. Handle window where crond picks file up
+ * before we can write our entry out.
+ */
+ while ((fd = open(CRONUPDATE, O_WRONLY|O_CREAT|O_APPEND, 0600)) >= 0) {
+ struct stat st;
+
+ fdprintf(fd, "%s\n", pas->pw_name);
+ if (fstat(fd, &st) != 0 || st.st_nlink != 0) {
+ /*close(fd);*/
+ break;
+ }
+ /* st.st_nlink == 0:
+ * file was deleted, maybe crond missed our notification */
+ close(fd);
+ /* loop */
+ }
+ if (fd < 0) {
+ bb_error_msg("cannot append to %s/%s",
+ crontab_dir, CRONUPDATE);
+ }
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/dc.c b/cleopatre/busybox-1.11.1-spc300/miscutils/dc.c
new file mode 100644
index 0000000000..bd93ef68bc
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/dc.c
@@ -0,0 +1,224 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include <math.h>
+
+/* Tiny RPN calculator, because "expr" didn't give me bitwise operations. */
+
+
+struct globals {
+ unsigned pointer;
+ unsigned base;
+ double stack[1];
+};
+enum { STACK_SIZE = (COMMON_BUFSIZE - offsetof(struct globals, stack)) / sizeof(double) };
+#define G (*(struct globals*)&bb_common_bufsiz1)
+#define pointer (G.pointer )
+#define base (G.base )
+#define stack (G.stack )
+#define INIT_G() do { } while (0)
+
+
+static void push(double a)
+{
+ if (pointer >= STACK_SIZE)
+ bb_error_msg_and_die("stack overflow");
+ stack[pointer++] = a;
+}
+
+static double pop(void)
+{
+ if (pointer == 0)
+ bb_error_msg_and_die("stack underflow");
+ return stack[--pointer];
+}
+
+static void add(void)
+{
+ push(pop() + pop());
+}
+
+static void sub(void)
+{
+ double subtrahend = pop();
+
+ push(pop() - subtrahend);
+}
+
+static void mul(void)
+{
+ push(pop() * pop());
+}
+
+static void power(void)
+{
+ double topower = pop();
+
+ push(pow(pop(), topower));
+}
+
+static void divide(void)
+{
+ double divisor = pop();
+
+ push(pop() / divisor);
+}
+
+static void mod(void)
+{
+ unsigned d = pop();
+
+ push((unsigned) pop() % d);
+}
+
+static void and(void)
+{
+ push((unsigned) pop() & (unsigned) pop());
+}
+
+static void or(void)
+{
+ push((unsigned) pop() | (unsigned) pop());
+}
+
+static void eor(void)
+{
+ push((unsigned) pop() ^ (unsigned) pop());
+}
+
+static void not(void)
+{
+ push(~(unsigned) pop());
+}
+
+static void set_output_base(void)
+{
+ base = (unsigned)pop();
+ if ((base != 10) && (base != 16)) {
+ bb_error_msg("error, base %d is not supported", base);
+ base = 10;
+ }
+}
+
+static void print_base(double print)
+{
+ if (base == 16)
+ printf("%x\n", (unsigned)print);
+ else
+ printf("%g\n", print);
+}
+
+static void print_stack_no_pop(void)
+{
+ unsigned i = pointer;
+ while (i)
+ print_base(stack[--i]);
+}
+
+static void print_no_pop(void)
+{
+ print_base(stack[pointer-1]);
+}
+
+struct op {
+ const char name[4];
+ void (*function) (void);
+};
+
+static const struct op operators[] = {
+ {"+", add},
+ {"add", add},
+ {"-", sub},
+ {"sub", sub},
+ {"*", mul},
+ {"mul", mul},
+ {"/", divide},
+ {"div", divide},
+ {"**", power},
+ {"exp", power},
+ {"pow", power},
+ {"%", mod},
+ {"mod", mod},
+ {"and", and},
+ {"or", or},
+ {"not", not},
+ {"eor", eor},
+ {"xor", eor},
+ {"p", print_no_pop},
+ {"f", print_stack_no_pop},
+ {"o", set_output_base},
+ { /* zero filled */ }
+};
+
+static void stack_machine(const char *argument)
+{
+ char *endPointer;
+ double d;
+ const struct op *o = operators;
+
+ if (argument == 0)
+ return;
+
+ d = strtod(argument, &endPointer);
+
+ if (endPointer != argument) {
+ push(d);
+ return;
+ }
+
+ while (o->name[0]) {
+ if (strcmp(o->name, argument) == 0) {
+ o->function();
+ return;
+ }
+ o++;
+ }
+ bb_error_msg_and_die("%s: syntax error", argument);
+}
+
+/* return pointer to next token in buffer and set *buffer to one char
+ * past the end of the above mentioned token
+ */
+static char *get_token(char **buffer)
+{
+ char *current = skip_whitespace(*buffer);
+ if (*current != '\0') {
+ *buffer = skip_non_whitespace(current);
+ return current;
+ }
+ return NULL;
+}
+
+int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int dc_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ INIT_G();
+
+ argv++;
+ if (!argv[0]) {
+ /* take stuff from stdin if no args are given */
+ char *line;
+ char *cursor;
+ char *token;
+ while ((line = xmalloc_fgetline(stdin)) != NULL) {
+ cursor = line;
+ while (1) {
+ token = get_token(&cursor);
+ if (!token) break;
+ *cursor++ = '\0';
+ stack_machine(token);
+ }
+ free(line);
+ }
+ } else {
+ if (argv[0][0] == '-')
+ bb_show_usage();
+ do {
+ stack_machine(*argv);
+ } while (*++argv);
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/devfsd.c b/cleopatre/busybox-1.11.1-spc300/miscutils/devfsd.c
new file mode 100644
index 0000000000..782457ac7f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/devfsd.c
@@ -0,0 +1,1801 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/*
+ devfsd implementation for busybox
+
+ Copyright (C) 2003 by Tito Ragusa <farmatito@tiscali.it>
+
+ Busybox version is based on some previous work and ideas
+ Copyright (C) [2003] by [Matteo Croce] <3297627799@wind.it>
+
+ devfsd.c
+
+ Main file for devfsd (devfs daemon for Linux).
+
+ Copyright (C) 1998-2002 Richard Gooch
+
+ devfsd.h
+
+ Header file for devfsd (devfs daemon for Linux).
+
+ Copyright (C) 1998-2000 Richard Gooch
+
+ compat_name.c
+
+ Compatibility name file for devfsd (build compatibility names).
+
+ Copyright (C) 1998-2002 Richard Gooch
+
+ expression.c
+
+ This code provides Borne Shell-like expression expansion.
+
+ Copyright (C) 1997-1999 Richard Gooch
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Richard Gooch may be reached by email at rgooch@atnf.csiro.au
+ The postal address is:
+ Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
+*/
+#include "libbb.h"
+#include "xregex.h"
+#include <syslog.h>
+
+#include <sys/un.h>
+#include <sys/sysmacros.h>
+
+/* Various defines taken from linux/major.h */
+#define IDE0_MAJOR 3
+#define IDE1_MAJOR 22
+#define IDE2_MAJOR 33
+#define IDE3_MAJOR 34
+#define IDE4_MAJOR 56
+#define IDE5_MAJOR 57
+#define IDE6_MAJOR 88
+#define IDE7_MAJOR 89
+#define IDE8_MAJOR 90
+#define IDE9_MAJOR 91
+
+
+/* Various defines taken from linux/devfs_fs.h */
+#define DEVFSD_PROTOCOL_REVISION_KERNEL 5
+#define DEVFSD_IOCTL_BASE 'd'
+/* These are the various ioctls */
+#define DEVFSDIOC_GET_PROTO_REV _IOR(DEVFSD_IOCTL_BASE, 0, int)
+#define DEVFSDIOC_SET_EVENT_MASK _IOW(DEVFSD_IOCTL_BASE, 2, int)
+#define DEVFSDIOC_RELEASE_EVENT_QUEUE _IOW(DEVFSD_IOCTL_BASE, 3, int)
+#define DEVFSDIOC_SET_CONFIG_DEBUG_MASK _IOW(DEVFSD_IOCTL_BASE, 4, int)
+#define DEVFSD_NOTIFY_REGISTERED 0
+#define DEVFSD_NOTIFY_UNREGISTERED 1
+#define DEVFSD_NOTIFY_ASYNC_OPEN 2
+#define DEVFSD_NOTIFY_CLOSE 3
+#define DEVFSD_NOTIFY_LOOKUP 4
+#define DEVFSD_NOTIFY_CHANGE 5
+#define DEVFSD_NOTIFY_CREATE 6
+#define DEVFSD_NOTIFY_DELETE 7
+#define DEVFS_PATHLEN 1024
+/* Never change this otherwise the binary interface will change */
+
+struct devfsd_notify_struct
+{ /* Use native C types to ensure same types in kernel and user space */
+ unsigned int type; /* DEVFSD_NOTIFY_* value */
+ unsigned int mode; /* Mode of the inode or device entry */
+ unsigned int major; /* Major number of device entry */
+ unsigned int minor; /* Minor number of device entry */
+ unsigned int uid; /* Uid of process, inode or device entry */
+ unsigned int gid; /* Gid of process, inode or device entry */
+ unsigned int overrun_count; /* Number of lost events */
+ unsigned int namelen; /* Number of characters not including '\0' */
+ /* The device name MUST come last */
+ char devname[DEVFS_PATHLEN]; /* This will be '\0' terminated */
+};
+
+#define BUFFER_SIZE 16384
+#define DEVFSD_VERSION "1.3.25"
+#define CONFIG_FILE "/etc/devfsd.conf"
+#define MODPROBE "/sbin/modprobe"
+#define MODPROBE_SWITCH_1 "-k"
+#define MODPROBE_SWITCH_2 "-C"
+#define CONFIG_MODULES_DEVFS "/etc/modules.devfs"
+#define MAX_ARGS (6 + 1)
+#define MAX_SUBEXPR 10
+#define STRING_LENGTH 255
+
+/* for get_uid_gid() */
+#define UID 0
+#define GID 1
+
+/* fork_and_execute() */
+# define DIE 1
+# define NO_DIE 0
+
+/* for dir_operation() */
+#define RESTORE 0
+#define SERVICE 1
+#define READ_CONFIG 2
+
+/* Update only after changing code to reflect new protocol */
+#define DEVFSD_PROTOCOL_REVISION_DAEMON 5
+
+/* Compile-time check */
+#if DEVFSD_PROTOCOL_REVISION_KERNEL != DEVFSD_PROTOCOL_REVISION_DAEMON
+#error protocol version mismatch. Update your kernel headers
+#endif
+
+#define AC_PERMISSIONS 0
+#define AC_MODLOAD 1
+#define AC_EXECUTE 2
+#define AC_MFUNCTION 3 /* not supported by busybox */
+#define AC_CFUNCTION 4 /* not supported by busybox */
+#define AC_COPY 5
+#define AC_IGNORE 6
+#define AC_MKOLDCOMPAT 7
+#define AC_MKNEWCOMPAT 8
+#define AC_RMOLDCOMPAT 9
+#define AC_RMNEWCOMPAT 10
+#define AC_RESTORE 11
+
+struct permissions_type
+{
+ mode_t mode;
+ uid_t uid;
+ gid_t gid;
+};
+
+struct execute_type
+{
+ char *argv[MAX_ARGS + 1]; /* argv[0] must always be the programme */
+};
+
+struct copy_type
+{
+ const char *source;
+ const char *destination;
+};
+
+struct action_type
+{
+ unsigned int what;
+ unsigned int when;
+};
+
+struct config_entry_struct
+{
+ struct action_type action;
+ regex_t preg;
+ union
+ {
+ struct permissions_type permissions;
+ struct execute_type execute;
+ struct copy_type copy;
+ }
+ u;
+ struct config_entry_struct *next;
+};
+
+struct get_variable_info
+{
+ const struct devfsd_notify_struct *info;
+ const char *devname;
+ char devpath[STRING_LENGTH];
+};
+
+static void dir_operation(int , const char * , int, unsigned long*);
+static void service(struct stat statbuf, char *path);
+static int st_expr_expand(char *, unsigned, const char *, const char *(*)(const char *, void *), void *);
+static const char *get_old_name(const char *, unsigned, char *, unsigned, unsigned);
+static int mksymlink(const char *oldpath, const char *newpath);
+static void read_config_file(char *path, int optional, unsigned long *event_mask);
+static void process_config_line(const char *, unsigned long *);
+static int do_servicing(int, unsigned long);
+static void service_name(const struct devfsd_notify_struct *);
+static void action_permissions(const struct devfsd_notify_struct *, const struct config_entry_struct *);
+static void action_execute(const struct devfsd_notify_struct *, const struct config_entry_struct *,
+ const regmatch_t *, unsigned);
+static void action_modload(const struct devfsd_notify_struct *info, const struct config_entry_struct *entry);
+static void action_copy(const struct devfsd_notify_struct *, const struct config_entry_struct *,
+ const regmatch_t *, unsigned);
+static void action_compat(const struct devfsd_notify_struct *, unsigned);
+static void free_config(void);
+static void restore(char *spath, struct stat source_stat, int rootlen);
+static int copy_inode(const char *, const struct stat *, mode_t, const char *, const struct stat *);
+static mode_t get_mode(const char *);
+static void signal_handler(int);
+static const char *get_variable(const char *, void *);
+static int make_dir_tree(const char *);
+static int expand_expression(char *, unsigned, const char *, const char *(*)(const char *, void *), void *,
+ const char *, const regmatch_t *, unsigned);
+static void expand_regexp(char *, size_t, const char *, const char *, const regmatch_t *, unsigned);
+static const char *expand_variable( char *, unsigned, unsigned *, const char *,
+ const char *(*)(const char *, void *), void *);
+static const char *get_variable_v2(const char *, const char *(*)(const char *, void *), void *);
+static char get_old_ide_name(unsigned , unsigned);
+static char *write_old_sd_name(char *, unsigned, unsigned, const char *);
+
+/* busybox functions */
+static int get_uid_gid(int flag, const char *string);
+static void safe_memcpy(char * dest, const char * src, int len);
+static unsigned int scan_dev_name_common(const char *d, unsigned int n, int addendum, const char *ptr);
+static unsigned int scan_dev_name(const char *d, unsigned int n, const char *ptr);
+
+/* Structs and vars */
+static struct config_entry_struct *first_config = NULL;
+static struct config_entry_struct *last_config = NULL;
+static char *mount_point = NULL;
+static volatile int caught_signal = FALSE;
+static volatile int caught_sighup = FALSE;
+static struct initial_symlink_struct {
+ const char *dest;
+ const char *name;
+} initial_symlinks[] = {
+ {"/proc/self/fd", "fd"},
+ {"fd/0", "stdin"},
+ {"fd/1", "stdout"},
+ {"fd/2", "stderr"},
+ {NULL, NULL},
+};
+
+static struct event_type {
+ unsigned int type; /* The DEVFSD_NOTIFY_* value */
+ const char *config_name; /* The name used in the config file */
+} event_types[] = {
+ {DEVFSD_NOTIFY_REGISTERED, "REGISTER"},
+ {DEVFSD_NOTIFY_UNREGISTERED, "UNREGISTER"},
+ {DEVFSD_NOTIFY_ASYNC_OPEN, "ASYNC_OPEN"},
+ {DEVFSD_NOTIFY_CLOSE, "CLOSE"},
+ {DEVFSD_NOTIFY_LOOKUP, "LOOKUP"},
+ {DEVFSD_NOTIFY_CHANGE, "CHANGE"},
+ {DEVFSD_NOTIFY_CREATE, "CREATE"},
+ {DEVFSD_NOTIFY_DELETE, "DELETE"},
+ {0xffffffff, NULL}
+};
+
+/* Busybox messages */
+
+static const char bb_msg_proto_rev[] ALIGN1 = "protocol revision";
+static const char bb_msg_bad_config[] ALIGN1 = "bad %s config file: %s";
+static const char bb_msg_small_buffer[] ALIGN1 = "buffer too small";
+static const char bb_msg_variable_not_found[] ALIGN1 = "variable: %s not found";
+
+/* Busybox stuff */
+#if ENABLE_DEVFSD_VERBOSE || ENABLE_DEBUG
+#define info_logger(p, fmt, args...) bb_info_msg(fmt, ## args)
+#define msg_logger(p, fmt, args...) bb_error_msg(fmt, ## args)
+#define msg_logger_and_die(p, fmt, args...) bb_error_msg_and_die(fmt, ## args)
+#define error_logger(p, fmt, args...) bb_perror_msg(fmt, ## args)
+#define error_logger_and_die(p, fmt, args...) bb_perror_msg_and_die(fmt, ## args)
+#else
+#define info_logger(p, fmt, args...)
+#define msg_logger(p, fmt, args...)
+#define msg_logger_and_die(p, fmt, args...) exit(EXIT_FAILURE)
+#define error_logger(p, fmt, args...)
+#define error_logger_and_die(p, fmt, args...) exit(EXIT_FAILURE)
+#endif
+
+static void safe_memcpy(char *dest, const char *src, int len)
+{
+ memcpy(dest , src, len);
+ dest[len] = '\0';
+}
+
+static unsigned int scan_dev_name_common(const char *d, unsigned int n, int addendum, const char *ptr)
+{
+ if (d[n - 4] == 'd' && d[n - 3] == 'i' && d[n - 2] == 's' && d[n - 1] == 'c')
+ return 2 + addendum;
+ if (d[n - 2] == 'c' && d[n - 1] == 'd')
+ return 3 + addendum;
+ if (ptr[0] == 'p' && ptr[1] == 'a' && ptr[2] == 'r' && ptr[3] == 't')
+ return 4 + addendum;
+ if (ptr[n - 2] == 'm' && ptr[n - 1] == 't')
+ return 5 + addendum;
+ return 0;
+}
+
+static unsigned int scan_dev_name(const char *d, unsigned int n, const char *ptr)
+{
+ if (d[0] == 's' && d[1] == 'c' && d[2] == 's' && d[3] == 'i' && d[4] == '/') {
+ if (d[n - 7] == 'g' && d[n - 6] == 'e' && d[n - 5] == 'n'
+ && d[n - 4] == 'e' && d[n - 3] == 'r' && d[n - 2] == 'i' && d[n - 1] == 'c'
+ )
+ return 1;
+ return scan_dev_name_common(d, n, 0, ptr);
+ }
+ if (d[0] == 'i' && d[1] == 'd' && d[2] == 'e' && d[3] == '/'
+ && d[4] == 'h' && d[5] == 'o' && d[6] == 's' && d[7] == 't'
+ )
+ return scan_dev_name_common(d, n, 4, ptr);
+ if (d[0] == 's' && d[1] == 'b' && d[2] == 'p' && d[3] == '/')
+ return 10;
+ if (d[0] == 'v' && d[1] == 'c' && d[2] == 'c' && d[3] == '/')
+ return 11;
+ if (d[0] == 'p' && d[1] == 't' && d[2] == 'y' && d[3] == '/')
+ return 12;
+ return 0;
+}
+
+/* Public functions follow */
+
+int devfsd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int devfsd_main(int argc, char **argv)
+{
+ int print_version = FALSE;
+ int do_daemon = TRUE;
+ int no_polling = FALSE;
+ int do_scan;
+ int fd, proto_rev, count;
+ unsigned long event_mask = 0;
+ struct sigaction new_action;
+ struct initial_symlink_struct *curr;
+
+ if (argc < 2)
+ bb_show_usage();
+
+ for (count = 2; count < argc; ++count) {
+ if (argv[count][0] == '-') {
+ if (argv[count][1] == 'v' && !argv[count][2]) /* -v */
+ print_version = TRUE;
+ else if (ENABLE_DEVFSD_FG_NP && argv[count][1] == 'f'
+ && argv[count][2] == 'g' && !argv[count][3]) /* -fg */
+ do_daemon = FALSE;
+ else if (ENABLE_DEVFSD_FG_NP && argv[count][1] == 'n'
+ && argv[count][2] == 'p' && !argv[count][3]) /* -np */
+ no_polling = TRUE;
+ else
+ bb_show_usage();
+ }
+ }
+
+ mount_point = bb_simplify_path(argv[1]);
+
+ xchdir(mount_point);
+
+ fd = xopen(".devfsd", O_RDONLY);
+ close_on_exec_on(fd);
+ xioctl(fd, DEVFSDIOC_GET_PROTO_REV, &proto_rev);
+
+ /*setup initial entries */
+ for (curr = initial_symlinks; curr->dest != NULL; ++curr)
+ symlink(curr->dest, curr->name);
+
+ /* NB: The check for CONFIG_FILE is done in read_config_file() */
+
+ if (print_version || (DEVFSD_PROTOCOL_REVISION_DAEMON != proto_rev)) {
+ printf("%s v%s\nDaemon %s:\t%d\nKernel-side %s:\t%d\n",
+ applet_name, DEVFSD_VERSION, bb_msg_proto_rev,
+ DEVFSD_PROTOCOL_REVISION_DAEMON, bb_msg_proto_rev, proto_rev);
+ if (DEVFSD_PROTOCOL_REVISION_DAEMON != proto_rev)
+ bb_error_msg_and_die("%s mismatch!", bb_msg_proto_rev);
+ exit(EXIT_SUCCESS); /* -v */
+ }
+ /* Tell kernel we are special(i.e. we get to see hidden entries) */
+ xioctl(fd, DEVFSDIOC_SET_EVENT_MASK, 0);
+
+ /* Set up SIGHUP and SIGUSR1 handlers */
+ sigemptyset(&new_action.sa_mask);
+ new_action.sa_flags = 0;
+ new_action.sa_handler = signal_handler;
+ sigaction_set(SIGHUP, &new_action);
+ sigaction_set(SIGUSR1, &new_action);
+
+ printf("%s v%s started for %s\n", applet_name, DEVFSD_VERSION, mount_point);
+
+ /* Set umask so that mknod(2), open(2) and mkdir(2) have complete control over permissions */
+ umask(0);
+ read_config_file((char*)CONFIG_FILE, FALSE, &event_mask);
+ /* Do the scan before forking, so that boot scripts see the finished product */
+ dir_operation(SERVICE, mount_point, 0, NULL);
+
+ if (ENABLE_DEVFSD_FG_NP && no_polling)
+ exit(EXIT_SUCCESS);
+
+ if (ENABLE_DEVFSD_VERBOSE || ENABLE_DEBUG)
+ logmode = LOGMODE_BOTH;
+ else if (do_daemon == TRUE)
+ logmode = LOGMODE_SYSLOG;
+ /* This is the default */
+ /*else
+ logmode = LOGMODE_STDIO; */
+
+ if (do_daemon) {
+ /* Release so that the child can grab it */
+ xioctl(fd, DEVFSDIOC_RELEASE_EVENT_QUEUE, 0);
+ bb_daemonize_or_rexec(0, argv);
+ } else if (ENABLE_DEVFSD_FG_NP) {
+ setpgid(0, 0); /* Become process group leader */
+ }
+
+ while (TRUE) {
+ do_scan = do_servicing(fd, event_mask);
+
+ free_config();
+ read_config_file((char*)CONFIG_FILE, FALSE, &event_mask);
+ if (do_scan)
+ dir_operation(SERVICE, mount_point, 0, NULL);
+ }
+ if (ENABLE_FEATURE_CLEAN_UP) free(mount_point);
+} /* End Function main */
+
+
+/* Private functions follow */
+
+static void read_config_file(char *path, int optional, unsigned long *event_mask)
+/* [SUMMARY] Read a configuration database.
+ <path> The path to read the database from. If this is a directory, all
+ entries in that directory will be read(except hidden entries).
+ <optional> If TRUE, the routine will silently ignore a missing config file.
+ <event_mask> The event mask is written here. This is not initialised.
+ [RETURNS] Nothing.
+*/
+{
+ struct stat statbuf;
+ FILE *fp;
+ char buf[STRING_LENGTH];
+ char *line = NULL;
+ char *p;
+
+ if (stat(path, &statbuf) == 0) {
+ /* Don't read 0 length files: ignored */
+ /*if (statbuf.st_size == 0)
+ return;*/
+ if (S_ISDIR(statbuf.st_mode)) {
+ p = bb_simplify_path(path);
+ dir_operation(READ_CONFIG, p, 0, event_mask);
+ free(p);
+ return;
+ }
+ fp = fopen(path, "r");
+ if (fp != NULL) {
+ while (fgets(buf, STRING_LENGTH, fp) != NULL) {
+ /* Skip whitespace */
+ line = buf;
+ line = skip_whitespace(line);
+ if (line[0] == '\0' || line[0] == '#')
+ continue;
+ process_config_line(line, event_mask);
+ }
+ fclose(fp);
+ } else {
+ goto read_config_file_err;
+ }
+ } else {
+read_config_file_err:
+ if (optional == 0 && errno == ENOENT)
+ error_logger_and_die(LOG_ERR, "read config file: %s", path);
+ }
+} /* End Function read_config_file */
+
+static void process_config_line(const char *line, unsigned long *event_mask)
+/* [SUMMARY] Process a line from a configuration file.
+ <line> The configuration line.
+ <event_mask> The event mask is written here. This is not initialised.
+ [RETURNS] Nothing.
+*/
+{
+ int num_args, count;
+ struct config_entry_struct *new;
+ char p[MAX_ARGS][STRING_LENGTH];
+ char when[STRING_LENGTH], what[STRING_LENGTH];
+ char name[STRING_LENGTH];
+ const char *msg = "";
+ char *ptr;
+ int i;
+
+ /* !!!! Only Uppercase Keywords in devsfd.conf */
+ static const char options[] ALIGN1 =
+ "CLEAR_CONFIG\0""INCLUDE\0""OPTIONAL_INCLUDE\0"
+ "RESTORE\0""PERMISSIONS\0""MODLOAD\0""EXECUTE\0"
+ "COPY\0""IGNORE\0""MKOLDCOMPAT\0""MKNEWCOMPAT\0"
+ "RMOLDCOMPAT\0""RMNEWCOMPAT\0";
+
+ for (count = 0; count < MAX_ARGS; ++count)
+ p[count][0] = '\0';
+ num_args = sscanf(line, "%s %s %s %s %s %s %s %s %s %s",
+ when, name, what,
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
+
+ i = index_in_strings(options, when);
+
+ /* "CLEAR_CONFIG" */
+ if (i == 0) {
+ free_config();
+ *event_mask = 0;
+ return;
+ }
+
+ if (num_args < 2)
+ goto process_config_line_err;
+
+ /* "INCLUDE" & "OPTIONAL_INCLUDE" */
+ if (i == 1 || i == 2) {
+ st_expr_expand(name, STRING_LENGTH, name, get_variable, NULL);
+ info_logger(LOG_INFO, "%sinclude: %s", (toupper(when[0]) == 'I') ? "": "optional_", name);
+ read_config_file(name, (toupper(when[0]) == 'I') ? FALSE : TRUE, event_mask);
+ return;
+ }
+ /* "RESTORE" */
+ if (i == 3) {
+ dir_operation(RESTORE, name, strlen(name),NULL);
+ return;
+ }
+ if (num_args < 3)
+ goto process_config_line_err;
+
+ new = xzalloc(sizeof *new);
+
+ for (count = 0; event_types[count].config_name != NULL; ++count) {
+ if (strcasecmp(when, event_types[count].config_name) != 0)
+ continue;
+ new->action.when = event_types[count].type;
+ break;
+ }
+ if (event_types[count].config_name == NULL) {
+ msg = "WHEN in";
+ goto process_config_line_err;
+ }
+
+ i = index_in_strings(options, what);
+
+ switch (i) {
+ case 4: /* "PERMISSIONS" */
+ new->action.what = AC_PERMISSIONS;
+ /* Get user and group */
+ ptr = strchr(p[0], '.');
+ if (ptr == NULL) {
+ msg = "UID.GID";
+ goto process_config_line_err; /*"missing '.' in UID.GID"*/
+ }
+
+ *ptr++ = '\0';
+ new->u.permissions.uid = get_uid_gid(UID, p[0]);
+ new->u.permissions.gid = get_uid_gid(GID, ptr);
+ /* Get mode */
+ new->u.permissions.mode = get_mode(p[1]);
+ break;
+ case 5: /* MODLOAD */
+ /*This action will pass "/dev/$devname"(i.e. "/dev/" prefixed to
+ the device name) to the module loading facility. In addition,
+ the /etc/modules.devfs configuration file is used.*/
+ if (ENABLE_DEVFSD_MODLOAD)
+ new->action.what = AC_MODLOAD;
+ break;
+ case 6: /* EXECUTE */
+ new->action.what = AC_EXECUTE;
+ num_args -= 3;
+
+ for (count = 0; count < num_args; ++count)
+ new->u.execute.argv[count] = xstrdup(p[count]);
+
+ new->u.execute.argv[num_args] = NULL;
+ break;
+ case 7: /* COPY */
+ new->action.what = AC_COPY;
+ num_args -= 3;
+ if (num_args != 2)
+ goto process_config_line_err; /* missing path and function in line */
+
+ new->u.copy.source = xstrdup(p[0]);
+ new->u.copy.destination = xstrdup(p[1]);
+ break;
+ case 8: /* IGNORE */
+ /* FALLTROUGH */
+ case 9: /* MKOLDCOMPAT */
+ /* FALLTROUGH */
+ case 10: /* MKNEWCOMPAT */
+ /* FALLTROUGH */
+ case 11:/* RMOLDCOMPAT */
+ /* FALLTROUGH */
+ case 12: /* RMNEWCOMPAT */
+ /* AC_IGNORE 6
+ AC_MKOLDCOMPAT 7
+ AC_MKNEWCOMPAT 8
+ AC_RMOLDCOMPAT 9
+ AC_RMNEWCOMPAT 10*/
+ new->action.what = i - 2;
+ break;
+ default:
+ msg = "WHAT in";
+ goto process_config_line_err;
+ /*esac*/
+ } /* switch (i) */
+
+ xregcomp(&new->preg, name, REG_EXTENDED);
+
+ *event_mask |= 1 << new->action.when;
+ new->next = NULL;
+ if (first_config == NULL)
+ first_config = new;
+ else
+ last_config->next = new;
+ last_config = new;
+ return;
+
+ process_config_line_err:
+ msg_logger_and_die(LOG_ERR, bb_msg_bad_config, msg , line);
+} /* End Function process_config_line */
+
+static int do_servicing(int fd, unsigned long event_mask)
+/* [SUMMARY] Service devfs changes until a signal is received.
+ <fd> The open control file.
+ <event_mask> The event mask.
+ [RETURNS] TRUE if SIGHUP was caught, else FALSE.
+*/
+{
+ ssize_t bytes;
+ struct devfsd_notify_struct info;
+
+ /* (void*) cast is only in order to match prototype */
+ xioctl(fd, DEVFSDIOC_SET_EVENT_MASK, (void*)event_mask);
+ while (!caught_signal) {
+ errno = 0;
+ bytes = read(fd,(char *) &info, sizeof info);
+ if (caught_signal)
+ break; /* Must test for this first */
+ if (errno == EINTR)
+ continue; /* Yes, the order is important */
+ if (bytes < 1)
+ break;
+ service_name(&info);
+ }
+ if (caught_signal) {
+ int c_sighup = caught_sighup;
+
+ caught_signal = FALSE;
+ caught_sighup = FALSE;
+ return c_sighup;
+ }
+ msg_logger_and_die(LOG_ERR, "read error on control file");
+} /* End Function do_servicing */
+
+static void service_name(const struct devfsd_notify_struct *info)
+/* [SUMMARY] Service a single devfs change.
+ <info> The devfs change.
+ [RETURNS] Nothing.
+*/
+{
+ unsigned int n;
+ regmatch_t mbuf[MAX_SUBEXPR];
+ struct config_entry_struct *entry;
+
+ if (ENABLE_DEBUG && info->overrun_count > 0)
+ msg_logger(LOG_ERR, "lost %u events", info->overrun_count);
+
+ /* Discard lookups on "/dev/log" and "/dev/initctl" */
+ if (info->type == DEVFSD_NOTIFY_LOOKUP
+ && ((info->devname[0] == 'l' && info->devname[1] == 'o'
+ && info->devname[2] == 'g' && !info->devname[3])
+ || (info->devname[0] == 'i' && info->devname[1] == 'n'
+ && info->devname[2] == 'i' && info->devname[3] == 't'
+ && info->devname[4] == 'c' && info->devname[5] == 't'
+ && info->devname[6] == 'l' && !info->devname[7]))
+ )
+ return;
+
+ for (entry = first_config; entry != NULL; entry = entry->next) {
+ /* First check if action matches the type, then check if name matches */
+ if (info->type != entry->action.when
+ || regexec(&entry->preg, info->devname, MAX_SUBEXPR, mbuf, 0) != 0)
+ continue;
+ for (n = 0;(n < MAX_SUBEXPR) && (mbuf[n].rm_so != -1); ++n)
+ /* VOID */;
+
+ switch (entry->action.what) {
+ case AC_PERMISSIONS:
+ action_permissions(info, entry);
+ break;
+ case AC_MODLOAD:
+ if (ENABLE_DEVFSD_MODLOAD)
+ action_modload(info, entry);
+ break;
+ case AC_EXECUTE:
+ action_execute(info, entry, mbuf, n);
+ break;
+ case AC_COPY:
+ action_copy(info, entry, mbuf, n);
+ break;
+ case AC_IGNORE:
+ return;
+ /*break;*/
+ case AC_MKOLDCOMPAT:
+ case AC_MKNEWCOMPAT:
+ case AC_RMOLDCOMPAT:
+ case AC_RMNEWCOMPAT:
+ action_compat(info, entry->action.what);
+ break;
+ default:
+ msg_logger_and_die(LOG_ERR, "Unknown action");
+ }
+ }
+} /* End Function service_name */
+
+static void action_permissions(const struct devfsd_notify_struct *info,
+ const struct config_entry_struct *entry)
+/* [SUMMARY] Update permissions for a device entry.
+ <info> The devfs change.
+ <entry> The config file entry.
+ [RETURNS] Nothing.
+*/
+{
+ struct stat statbuf;
+
+ if (stat(info->devname, &statbuf) != 0
+ || chmod(info->devname, (statbuf.st_mode & S_IFMT) | (entry->u.permissions.mode & ~S_IFMT)) != 0
+ || chown(info->devname, entry->u.permissions.uid, entry->u.permissions.gid) != 0
+ )
+ error_logger(LOG_ERR, "Can't chmod or chown: %s", info->devname);
+} /* End Function action_permissions */
+
+static void action_modload(const struct devfsd_notify_struct *info,
+ const struct config_entry_struct *entry ATTRIBUTE_UNUSED)
+/* [SUMMARY] Load a module.
+ <info> The devfs change.
+ <entry> The config file entry.
+ [RETURNS] Nothing.
+*/
+{
+ char *argv[6];
+
+ argv[0] = (char*)MODPROBE;
+ argv[1] = (char*)MODPROBE_SWITCH_1; /* "-k" */
+ argv[2] = (char*)MODPROBE_SWITCH_2; /* "-C" */
+ argv[3] = (char*)CONFIG_MODULES_DEVFS;
+ argv[4] = concat_path_file("/dev", info->devname); /* device */
+ argv[5] = NULL;
+
+ wait4pid(xspawn(argv));
+ free(argv[4]);
+} /* End Function action_modload */
+
+static void action_execute(const struct devfsd_notify_struct *info,
+ const struct config_entry_struct *entry,
+ const regmatch_t *regexpr, unsigned int numexpr)
+/* [SUMMARY] Execute a programme.
+ <info> The devfs change.
+ <entry> The config file entry.
+ <regexpr> The number of subexpression(start, end) offsets within the
+ device name.
+ <numexpr> The number of elements within <<regexpr>>.
+ [RETURNS] Nothing.
+*/
+{
+ unsigned int count;
+ struct get_variable_info gv_info;
+ char *argv[MAX_ARGS + 1];
+ char largv[MAX_ARGS + 1][STRING_LENGTH];
+
+ gv_info.info = info;
+ gv_info.devname = info->devname;
+ snprintf(gv_info.devpath, sizeof(gv_info.devpath), "%s/%s", mount_point, info->devname);
+ for (count = 0; entry->u.execute.argv[count] != NULL; ++count) {
+ expand_expression(largv[count], STRING_LENGTH,
+ entry->u.execute.argv[count],
+ get_variable, &gv_info,
+ gv_info.devname, regexpr, numexpr);
+ argv[count] = largv[count];
+ }
+ argv[count] = NULL;
+ wait4pid(spawn(argv));
+} /* End Function action_execute */
+
+
+static void action_copy(const struct devfsd_notify_struct *info,
+ const struct config_entry_struct *entry,
+ const regmatch_t *regexpr, unsigned int numexpr)
+/* [SUMMARY] Copy permissions.
+ <info> The devfs change.
+ <entry> The config file entry.
+ <regexpr> This list of subexpression(start, end) offsets within the
+ device name.
+ <numexpr> The number of elements in <<regexpr>>.
+ [RETURNS] Nothing.
+*/
+{
+ mode_t new_mode;
+ struct get_variable_info gv_info;
+ struct stat source_stat, dest_stat;
+ char source[STRING_LENGTH], destination[STRING_LENGTH];
+ int ret = 0;
+
+ dest_stat.st_mode = 0;
+
+ if ((info->type == DEVFSD_NOTIFY_CHANGE) && S_ISLNK(info->mode))
+ return;
+ gv_info.info = info;
+ gv_info.devname = info->devname;
+
+ snprintf(gv_info.devpath, sizeof(gv_info.devpath), "%s/%s", mount_point, info->devname);
+ expand_expression(source, STRING_LENGTH, entry->u.copy.source,
+ get_variable, &gv_info, gv_info.devname,
+ regexpr, numexpr);
+
+ expand_expression(destination, STRING_LENGTH, entry->u.copy.destination,
+ get_variable, &gv_info, gv_info.devname,
+ regexpr, numexpr);
+
+ if (!make_dir_tree(destination) || lstat(source, &source_stat) != 0)
+ return;
+ lstat(destination, &dest_stat);
+ new_mode = source_stat.st_mode & ~S_ISVTX;
+ if (info->type == DEVFSD_NOTIFY_CREATE)
+ new_mode |= S_ISVTX;
+ else if ((info->type == DEVFSD_NOTIFY_CHANGE) &&(dest_stat.st_mode & S_ISVTX))
+ new_mode |= S_ISVTX;
+ ret = copy_inode(destination, &dest_stat, new_mode, source, &source_stat);
+ if (ENABLE_DEBUG && ret && (errno != EEXIST))
+ error_logger(LOG_ERR, "copy_inode: %s to %s", source, destination);
+} /* End Function action_copy */
+
+static void action_compat(const struct devfsd_notify_struct *info, unsigned int action)
+/* [SUMMARY] Process a compatibility request.
+ <info> The devfs change.
+ <action> The action to take.
+ [RETURNS] Nothing.
+*/
+{
+ int ret;
+ const char *compat_name = NULL;
+ const char *dest_name = info->devname;
+ const char *ptr;
+ char compat_buf[STRING_LENGTH], dest_buf[STRING_LENGTH];
+ int mode, host, bus, target, lun;
+ unsigned int i;
+ char rewind_;
+ /* 1 to 5 "scsi/" , 6 to 9 "ide/host" */
+ static const char *const fmt[] = {
+ NULL ,
+ "sg/c%db%dt%du%d", /* scsi/generic */
+ "sd/c%db%dt%du%d", /* scsi/disc */
+ "sr/c%db%dt%du%d", /* scsi/cd */
+ "sd/c%db%dt%du%dp%d", /* scsi/part */
+ "st/c%db%dt%du%dm%d%c", /* scsi/mt */
+ "ide/hd/c%db%dt%du%d", /* ide/host/disc */
+ "ide/cd/c%db%dt%du%d", /* ide/host/cd */
+ "ide/hd/c%db%dt%du%dp%d", /* ide/host/part */
+ "ide/mt/c%db%dt%du%d%s", /* ide/host/mt */
+ NULL
+ };
+
+ /* First construct compatibility name */
+ switch (action) {
+ case AC_MKOLDCOMPAT:
+ case AC_RMOLDCOMPAT:
+ compat_name = get_old_name(info->devname, info->namelen, compat_buf, info->major, info->minor);
+ break;
+ case AC_MKNEWCOMPAT:
+ case AC_RMNEWCOMPAT:
+ ptr = bb_basename(info->devname);
+ i = scan_dev_name(info->devname, info->namelen, ptr);
+
+ /* nothing found */
+ if (i == 0 || i > 9)
+ return;
+
+ sscanf(info->devname + ((i < 6) ? 5 : 4), "host%d/bus%d/target%d/lun%d/", &host, &bus, &target, &lun);
+ snprintf(dest_buf, sizeof(dest_buf), "../%s", info->devname + (( i > 5) ? 4 : 0));
+ dest_name = dest_buf;
+ compat_name = compat_buf;
+
+
+ /* 1 == scsi/generic 2 == scsi/disc 3 == scsi/cd 6 == ide/host/disc 7 == ide/host/cd */
+ if (i == 1 || i == 2 || i == 3 || i == 6 || i ==7)
+ sprintf(compat_buf, fmt[i], host, bus, target, lun);
+
+ /* 4 == scsi/part 8 == ide/host/part */
+ if (i == 4 || i == 8)
+ sprintf(compat_buf, fmt[i], host, bus, target, lun, atoi(ptr + 4));
+
+ /* 5 == scsi/mt */
+ if (i == 5) {
+ rewind_ = info->devname[info->namelen - 1];
+ if (rewind_ != 'n')
+ rewind_ = '\0';
+ mode=0;
+ if (ptr[2] == 'l' /*108*/ || ptr[2] == 'm'/*109*/)
+ mode = ptr[2] - 107; /* 1 or 2 */
+ if (ptr[2] == 'a')
+ mode = 3;
+ sprintf(compat_buf, fmt[i], host, bus, target, lun, mode, rewind_);
+ }
+
+ /* 9 == ide/host/mt */
+ if (i == 9)
+ snprintf(compat_buf, sizeof(compat_buf), fmt[i], host, bus, target, lun, ptr + 2);
+ /* esac */
+ } /* switch (action) */
+
+ if (compat_name == NULL)
+ return;
+
+ /* Now decide what to do with it */
+ switch (action) {
+ case AC_MKOLDCOMPAT:
+ case AC_MKNEWCOMPAT:
+ mksymlink(dest_name, compat_name);
+ break;
+ case AC_RMOLDCOMPAT:
+ case AC_RMNEWCOMPAT:
+ ret = unlink(compat_name);
+ if (ENABLE_DEBUG && ret)
+ error_logger(LOG_ERR, "unlink: %s", compat_name);
+ break;
+ /*esac*/
+ } /* switch (action) */
+} /* End Function action_compat */
+
+static void restore(char *spath, struct stat source_stat, int rootlen)
+{
+ char *dpath;
+ struct stat dest_stat;
+
+ dest_stat.st_mode = 0;
+ dpath = concat_path_file(mount_point, spath + rootlen);
+ lstat(dpath, &dest_stat);
+ free(dpath);
+ if (S_ISLNK(source_stat.st_mode) || (source_stat.st_mode & S_ISVTX))
+ copy_inode(dpath, &dest_stat,(source_stat.st_mode & ~S_ISVTX) , spath, &source_stat);
+
+ if (S_ISDIR(source_stat.st_mode))
+ dir_operation(RESTORE, spath, rootlen,NULL);
+}
+
+
+static int copy_inode(const char *destpath, const struct stat *dest_stat,
+ mode_t new_mode,
+ const char *sourcepath, const struct stat *source_stat)
+/* [SUMMARY] Copy an inode.
+ <destpath> The destination path. An existing inode may be deleted.
+ <dest_stat> The destination stat(2) information.
+ <new_mode> The desired new mode for the destination.
+ <sourcepath> The source path.
+ <source_stat> The source stat(2) information.
+ [RETURNS] TRUE on success, else FALSE.
+*/
+{
+ int source_len, dest_len;
+ char source_link[STRING_LENGTH], dest_link[STRING_LENGTH];
+ int fd, val;
+ struct sockaddr_un un_addr;
+ char symlink_val[STRING_LENGTH];
+
+ if ((source_stat->st_mode & S_IFMT) ==(dest_stat->st_mode & S_IFMT)) {
+ /* Same type */
+ if (S_ISLNK(source_stat->st_mode)) {
+ source_len = readlink(sourcepath, source_link, STRING_LENGTH - 1);
+ if ((source_len < 0)
+ || (dest_len = readlink(destpath, dest_link, STRING_LENGTH - 1)) < 0
+ )
+ return FALSE;
+ source_link[source_len] = '\0';
+ dest_link[dest_len] = '\0';
+ if ((source_len != dest_len) || (strcmp(source_link, dest_link) != 0)) {
+ unlink(destpath);
+ symlink(source_link, destpath);
+ }
+ return TRUE;
+ } /* Else not a symlink */
+ chmod(destpath, new_mode & ~S_IFMT);
+ chown(destpath, source_stat->st_uid, source_stat->st_gid);
+ return TRUE;
+ }
+ /* Different types: unlink and create */
+ unlink(destpath);
+ switch (source_stat->st_mode & S_IFMT) {
+ case S_IFSOCK:
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0)
+ break;
+ un_addr.sun_family = AF_UNIX;
+ snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s", destpath);
+ val = bind(fd,(struct sockaddr *) &un_addr,(int) sizeof un_addr);
+ close(fd);
+ if (val != 0 || chmod(destpath, new_mode & ~S_IFMT) != 0)
+ break;
+ goto do_chown;
+ case S_IFLNK:
+ val = readlink(sourcepath, symlink_val, STRING_LENGTH - 1);
+ if (val < 0)
+ break;
+ symlink_val[val] = '\0';
+ if (symlink(symlink_val, destpath) == 0)
+ return TRUE;
+ break;
+ case S_IFREG:
+ fd = open(destpath, O_RDONLY | O_CREAT, new_mode & ~S_IFMT);
+ if (fd < 0)
+ break;
+ close(fd);
+ if (chmod(destpath, new_mode & ~S_IFMT) != 0)
+ break;
+ goto do_chown;
+ case S_IFBLK:
+ case S_IFCHR:
+ case S_IFIFO:
+ if (mknod(destpath, new_mode, source_stat->st_rdev) != 0)
+ break;
+ goto do_chown;
+ case S_IFDIR:
+ if (mkdir(destpath, new_mode & ~S_IFMT) != 0)
+ break;
+do_chown:
+ if (chown(destpath, source_stat->st_uid, source_stat->st_gid) == 0)
+ return TRUE;
+ /*break;*/
+ }
+ return FALSE;
+} /* End Function copy_inode */
+
+static void free_config(void)
+/* [SUMMARY] Free the configuration information.
+ [RETURNS] Nothing.
+*/
+{
+ struct config_entry_struct *c_entry;
+ void *next;
+
+ for (c_entry = first_config; c_entry != NULL; c_entry = next) {
+ unsigned int count;
+
+ next = c_entry->next;
+ regfree(&c_entry->preg);
+ if (c_entry->action.what == AC_EXECUTE) {
+ for (count = 0; count < MAX_ARGS; ++count) {
+ if (c_entry->u.execute.argv[count] == NULL)
+ break;
+ free(c_entry->u.execute.argv[count]);
+ }
+ }
+ free(c_entry);
+ }
+ first_config = NULL;
+ last_config = NULL;
+} /* End Function free_config */
+
+static int get_uid_gid(int flag, const char *string)
+/* [SUMMARY] Convert a string to a UID or GID value.
+ <flag> "UID" or "GID".
+ <string> The string.
+ [RETURNS] The UID or GID value.
+*/
+{
+ struct passwd *pw_ent;
+ struct group *grp_ent;
+ static const char *msg;
+
+ if (ENABLE_DEVFSD_VERBOSE)
+ msg = "user";
+
+ if (isdigit(string[0]) ||((string[0] == '-') && isdigit(string[1])))
+ return atoi(string);
+
+ if (flag == UID && (pw_ent = getpwnam(string)) != NULL)
+ return pw_ent->pw_uid;
+
+ if (flag == GID && (grp_ent = getgrnam(string)) != NULL)
+ return grp_ent->gr_gid;
+ else if (ENABLE_DEVFSD_VERBOSE)
+ msg = "group";
+
+ if (ENABLE_DEVFSD_VERBOSE)
+ msg_logger(LOG_ERR,"unknown %s: %s, defaulting to %cid=0", msg, string, msg[0]);
+ return 0;
+}/* End Function get_uid_gid */
+
+static mode_t get_mode(const char *string)
+/* [SUMMARY] Convert a string to a mode value.
+ <string> The string.
+ [RETURNS] The mode value.
+*/
+{
+ mode_t mode;
+ int i;
+
+ if (isdigit(string[0]))
+ return strtoul(string, NULL, 8);
+ if (strlen(string) != 9)
+ msg_logger_and_die(LOG_ERR, "bad mode: %s", string);
+
+ mode = 0;
+ i = S_IRUSR;
+ while (i > 0) {
+ if (string[0] == 'r' || string[0] == 'w' || string[0] == 'x')
+ mode += i;
+ i = i / 2;
+ string++;
+ }
+ return mode;
+} /* End Function get_mode */
+
+static void signal_handler(int sig)
+{
+ caught_signal = TRUE;
+ if (sig == SIGHUP)
+ caught_sighup = TRUE;
+
+ info_logger(LOG_INFO, "Caught signal %d", sig);
+} /* End Function signal_handler */
+
+static const char *get_variable(const char *variable, void *info)
+{
+ static char sbuf[sizeof(int)*3 + 2]; /* sign and NUL */
+ static char *hostname;
+
+ struct get_variable_info *gv_info = info;
+ const char *field_names[] = {
+ "hostname", "mntpt", "devpath", "devname",
+ "uid", "gid", "mode", hostname, mount_point,
+ gv_info->devpath, gv_info->devname, NULL
+ };
+ int i;
+
+ if (!hostname)
+ hostname = safe_gethostname();
+ /* index_in_str_array returns i>=0 */
+ i = index_in_str_array(field_names, variable);
+
+ if (i > 6 || i < 0 || (i > 1 && gv_info == NULL))
+ return NULL;
+ if (i >= 0 && i <= 3)
+ return field_names[i + 7];
+
+ if (i == 4)
+ sprintf(sbuf, "%u", gv_info->info->uid);
+ else if (i == 5)
+ sprintf(sbuf, "%u", gv_info->info->gid);
+ else if (i == 6)
+ sprintf(sbuf, "%o", gv_info->info->mode);
+ return sbuf;
+} /* End Function get_variable */
+
+static void service(struct stat statbuf, char *path)
+{
+ struct devfsd_notify_struct info;
+
+ memset(&info, 0, sizeof info);
+ info.type = DEVFSD_NOTIFY_REGISTERED;
+ info.mode = statbuf.st_mode;
+ info.major = major(statbuf.st_rdev);
+ info.minor = minor(statbuf.st_rdev);
+ info.uid = statbuf.st_uid;
+ info.gid = statbuf.st_gid;
+ snprintf(info.devname, sizeof(info.devname), "%s", path + strlen(mount_point) + 1);
+ info.namelen = strlen(info.devname);
+ service_name(&info);
+ if (S_ISDIR(statbuf.st_mode))
+ dir_operation(SERVICE, path, 0, NULL);
+}
+
+static void dir_operation(int type, const char * dir_name, int var, unsigned long *event_mask)
+/* [SUMMARY] Scan a directory tree and generate register events on leaf nodes.
+ <flag> To choose which function to perform
+ <dp> The directory pointer. This is closed upon completion.
+ <dir_name> The name of the directory.
+ <rootlen> string length parameter.
+ [RETURNS] Nothing.
+*/
+{
+ struct stat statbuf;
+ DIR *dp;
+ struct dirent *de;
+ char *path;
+
+ dp = warn_opendir(dir_name);
+ if (dp == NULL)
+ return;
+
+ while ((de = readdir(dp)) != NULL) {
+
+ if (de->d_name && DOT_OR_DOTDOT(de->d_name))
+ continue;
+ path = concat_path_file(dir_name, de->d_name);
+ if (lstat(path, &statbuf) == 0) {
+ switch (type) {
+ case SERVICE:
+ service(statbuf, path);
+ break;
+ case RESTORE:
+ restore(path, statbuf, var);
+ break;
+ case READ_CONFIG:
+ read_config_file(path, var, event_mask);
+ break;
+ }
+ }
+ free(path);
+ }
+ closedir(dp);
+} /* End Function do_scan_and_service */
+
+static int mksymlink(const char *oldpath, const char *newpath)
+/* [SUMMARY] Create a symlink, creating intervening directories as required.
+ <oldpath> The string contained in the symlink.
+ <newpath> The name of the new symlink.
+ [RETURNS] 0 on success, else -1.
+*/
+{
+ if (!make_dir_tree(newpath))
+ return -1;
+
+ if (symlink(oldpath, newpath) != 0) {
+ if (errno != EEXIST)
+ return -1;
+ }
+ return 0;
+} /* End Function mksymlink */
+
+
+static int make_dir_tree(const char *path)
+/* [SUMMARY] Creating intervening directories for a path as required.
+ <path> The full pathname(including the leaf node).
+ [RETURNS] TRUE on success, else FALSE.
+*/
+{
+ if (bb_make_directory(dirname((char *)path), -1, FILEUTILS_RECUR) == -1)
+ return FALSE;
+ return TRUE;
+} /* End Function make_dir_tree */
+
+static int expand_expression(char *output, unsigned int outsize,
+ const char *input,
+ const char *(*get_variable_func)(const char *variable, void *info),
+ void *info,
+ const char *devname,
+ const regmatch_t *ex, unsigned int numexp)
+/* [SUMMARY] Expand environment variables and regular subexpressions in string.
+ <output> The output expanded expression is written here.
+ <length> The size of the output buffer.
+ <input> The input expression. This may equal <<output>>.
+ <get_variable> A function which will be used to get variable values. If
+ this returns NULL, the environment is searched instead. If this is NULL,
+ only the environment is searched.
+ <info> An arbitrary pointer passed to <<get_variable>>.
+ <devname> Device name; specifically, this is the string that contains all
+ of the regular subexpressions.
+ <ex> Array of start / end offsets into info->devname for each subexpression
+ <numexp> Number of regular subexpressions found in <<devname>>.
+ [RETURNS] TRUE on success, else FALSE.
+*/
+{
+ char temp[STRING_LENGTH];
+
+ if (!st_expr_expand(temp, STRING_LENGTH, input, get_variable_func, info))
+ return FALSE;
+ expand_regexp(output, outsize, temp, devname, ex, numexp);
+ return TRUE;
+} /* End Function expand_expression */
+
+static void expand_regexp(char *output, size_t outsize, const char *input,
+ const char *devname,
+ const regmatch_t *ex, unsigned int numex)
+/* [SUMMARY] Expand all occurrences of the regular subexpressions \0 to \9.
+ <output> The output expanded expression is written here.
+ <outsize> The size of the output buffer.
+ <input> The input expression. This may NOT equal <<output>>, because
+ supporting that would require yet another string-copy. However, it's not
+ hard to write a simple wrapper function to add this functionality for those
+ few cases that need it.
+ <devname> Device name; specifically, this is the string that contains all
+ of the regular subexpressions.
+ <ex> An array of start and end offsets into <<devname>>, one for each
+ subexpression
+ <numex> Number of subexpressions in the offset-array <<ex>>.
+ [RETURNS] Nothing.
+*/
+{
+ const char last_exp = '0' - 1 + numex;
+ int c = -1;
+
+ /* Guarantee NULL termination by writing an explicit '\0' character into
+ the very last byte */
+ if (outsize)
+ output[--outsize] = '\0';
+ /* Copy the input string into the output buffer, replacing '\\' with '\'
+ and '\0' .. '\9' with subexpressions 0 .. 9, if they exist. Other \x
+ codes are deleted */
+ while ((c != '\0') && (outsize != 0)) {
+ c = *input;
+ ++input;
+ if (c == '\\') {
+ c = *input;
+ ++input;
+ if (c != '\\') {
+ if ((c >= '0') && (c <= last_exp)) {
+ const regmatch_t *subexp = ex + (c - '0');
+ unsigned int sublen = subexp->rm_eo - subexp->rm_so;
+
+ /* Range checking */
+ if (sublen > outsize)
+ sublen = outsize;
+ strncpy(output, devname + subexp->rm_so, sublen);
+ output += sublen;
+ outsize -= sublen;
+ }
+ continue;
+ }
+ }
+ *output = c;
+ ++output;
+ --outsize;
+ } /* while */
+} /* End Function expand_regexp */
+
+
+/* from compat_name.c */
+
+struct translate_struct
+{
+ const char *match; /* The string to match to(up to length) */
+ const char *format; /* Format of output, "%s" takes data past match string,
+ NULL is effectively "%s"(just more efficient) */
+};
+
+static struct translate_struct translate_table[] =
+{
+ {"sound/", NULL},
+ {"printers/", "lp%s"},
+ {"v4l/", NULL},
+ {"parports/", "parport%s"},
+ {"fb/", "fb%s"},
+ {"netlink/", NULL},
+ {"loop/", "loop%s"},
+ {"floppy/", "fd%s"},
+ {"rd/", "ram%s"},
+ {"md/", "md%s"}, /* Meta-devices */
+ {"vc/", "tty%s"},
+ {"misc/", NULL},
+ {"isdn/", NULL},
+ {"pg/", "pg%s"}, /* Parallel port generic ATAPI interface*/
+ {"i2c/", "i2c-%s"},
+ {"staliomem/", "staliomem%s"}, /* Stallion serial driver control */
+ {"tts/E", "ttyE%s"}, /* Stallion serial driver */
+ {"cua/E", "cue%s"}, /* Stallion serial driver callout */
+ {"tts/R", "ttyR%s"}, /* Rocketport serial driver */
+ {"cua/R", "cur%s"}, /* Rocketport serial driver callout */
+ {"ip2/", "ip2%s"}, /* Computone serial driver control */
+ {"tts/F", "ttyF%s"}, /* Computone serial driver */
+ {"cua/F", "cuf%s"}, /* Computone serial driver callout */
+ {"tts/C", "ttyC%s"}, /* Cyclades serial driver */
+ {"cua/C", "cub%s"}, /* Cyclades serial driver callout */
+ {"tts/", "ttyS%s"}, /* Generic serial: must be after others */
+ {"cua/", "cua%s"}, /* Generic serial: must be after others */
+ {"input/js", "js%s"}, /* Joystick driver */
+ {NULL, NULL}
+};
+
+const char *get_old_name(const char *devname, unsigned int namelen,
+ char *buffer, unsigned int major, unsigned int minor)
+/* [SUMMARY] Translate a kernel-supplied name into an old name.
+ <devname> The device name provided by the kernel.
+ <namelen> The length of the name.
+ <buffer> A buffer that may be used. This should be at least 128 bytes long.
+ <major> The major number for the device.
+ <minor> The minor number for the device.
+ [RETURNS] A pointer to the old name if known, else NULL.
+*/
+{
+ const char *compat_name = NULL;
+ const char *ptr;
+ struct translate_struct *trans;
+ unsigned int i;
+ char mode;
+ int indexx;
+ const char *pty1;
+ const char *pty2;
+ size_t len;
+ /* 1 to 5 "scsi/" , 6 to 9 "ide/host", 10 sbp/, 11 vcc/, 12 pty/ */
+ static const char *const fmt[] = {
+ NULL ,
+ "sg%u", /* scsi/generic */
+ NULL, /* scsi/disc */
+ "sr%u", /* scsi/cd */
+ NULL, /* scsi/part */
+ "nst%u%c", /* scsi/mt */
+ "hd%c" , /* ide/host/disc */
+ "hd%c" , /* ide/host/cd */
+ "hd%c%s", /* ide/host/part */
+ "%sht%d", /* ide/host/mt */
+ "sbpcd%u", /* sbp/ */
+ "vcs%s", /* vcc/ */
+ "%cty%c%c", /* pty/ */
+ NULL
+ };
+
+ for (trans = translate_table; trans->match != NULL; ++trans) {
+ len = strlen(trans->match);
+
+ if (strncmp(devname, trans->match, len) == 0) {
+ if (trans->format == NULL)
+ return devname + len;
+ sprintf(buffer, trans->format, devname + len);
+ return buffer;
+ }
+ }
+
+ ptr = bb_basename(devname);
+ i = scan_dev_name(devname, namelen, ptr);
+
+ if (i > 0 && i < 13)
+ compat_name = buffer;
+ else
+ return NULL;
+
+ /* 1 == scsi/generic, 3 == scsi/cd, 10 == sbp/ */
+ if (i == 1 || i == 3 || i == 10)
+ sprintf(buffer, fmt[i], minor);
+
+ /* 2 ==scsi/disc, 4 == scsi/part */
+ if (i == 2 || i == 4)
+ compat_name = write_old_sd_name(buffer, major, minor,((i == 2) ? "" : (ptr + 4)));
+
+ /* 5 == scsi/mt */
+ if (i == 5) {
+ mode = ptr[2];
+ if (mode == 'n')
+ mode = '\0';
+ sprintf(buffer, fmt[i], minor & 0x1f, mode);
+ if (devname[namelen - 1] != 'n')
+ ++compat_name;
+ }
+ /* 6 == ide/host/disc, 7 == ide/host/cd, 8 == ide/host/part */
+ if (i == 6 || i == 7 || i == 8)
+ /* last arg should be ignored for i == 6 or i== 7 */
+ sprintf(buffer, fmt[i] , get_old_ide_name(major, minor), ptr + 4);
+
+ /* 9 == ide/host/mt */
+ if (i == 9)
+ sprintf(buffer, fmt[i], ptr + 2, minor & 0x7f);
+
+ /* 11 == vcc/ */
+ if (i == 11) {
+ sprintf(buffer, fmt[i], devname + 4);
+ if (buffer[3] == '0')
+ buffer[3] = '\0';
+ }
+ /* 12 == pty/ */
+ if (i == 12) {
+ pty1 = "pqrstuvwxyzabcde";
+ pty2 = "0123456789abcdef";
+ indexx = atoi(devname + 5);
+ sprintf(buffer, fmt[i], (devname[4] == 'm') ? 'p' : 't', pty1[indexx >> 4], pty2[indexx & 0x0f]);
+ }
+ return compat_name;
+} /* End Function get_old_name */
+
+static char get_old_ide_name(unsigned int major, unsigned int minor)
+/* [SUMMARY] Get the old IDE name for a device.
+ <major> The major number for the device.
+ <minor> The minor number for the device.
+ [RETURNS] The drive letter.
+*/
+{
+ char letter = 'y'; /* 121 */
+ char c = 'a'; /* 97 */
+ int i = IDE0_MAJOR;
+
+ /* I hope it works like the previous code as it saves a few bytes. Tito ;P */
+ do {
+ if (i == IDE0_MAJOR || i == IDE1_MAJOR || i == IDE2_MAJOR
+ || i == IDE3_MAJOR || i == IDE4_MAJOR || i == IDE5_MAJOR
+ || i == IDE6_MAJOR || i == IDE7_MAJOR || i == IDE8_MAJOR
+ || i == IDE9_MAJOR
+ ) {
+ if ((unsigned int)i == major) {
+ letter = c;
+ break;
+ }
+ c += 2;
+ }
+ i++;
+ } while (i <= IDE9_MAJOR);
+
+ if (minor > 63)
+ ++letter;
+ return letter;
+} /* End Function get_old_ide_name */
+
+static char *write_old_sd_name(char *buffer,
+ unsigned int major, unsigned int minor,
+ const char *part)
+/* [SUMMARY] Write the old SCSI disc name to a buffer.
+ <buffer> The buffer to write to.
+ <major> The major number for the device.
+ <minor> The minor number for the device.
+ <part> The partition string. Must be "" for a whole-disc entry.
+ [RETURNS] A pointer to the buffer on success, else NULL.
+*/
+{
+ unsigned int disc_index;
+
+ if (major == 8) {
+ sprintf(buffer, "sd%c%s", 'a' + (minor >> 4), part);
+ return buffer;
+ }
+ if ((major > 64) && (major < 72)) {
+ disc_index = ((major - 64) << 4) +(minor >> 4);
+ if (disc_index < 26)
+ sprintf(buffer, "sd%c%s", 'a' + disc_index, part);
+ else
+ sprintf(buffer, "sd%c%c%s", 'a' +(disc_index / 26) - 1, 'a' + disc_index % 26, part);
+ return buffer;
+ }
+ return NULL;
+} /* End Function write_old_sd_name */
+
+
+/* expression.c */
+
+/*EXPERIMENTAL_FUNCTION*/
+
+int st_expr_expand(char *output, unsigned int length, const char *input,
+ const char *(*get_variable_func)(const char *variable,
+ void *info),
+ void *info)
+/* [SUMMARY] Expand an expression using Borne Shell-like unquoted rules.
+ <output> The output expanded expression is written here.
+ <length> The size of the output buffer.
+ <input> The input expression. This may equal <<output>>.
+ <get_variable> A function which will be used to get variable values. If
+ this returns NULL, the environment is searched instead. If this is NULL,
+ only the environment is searched.
+ <info> An arbitrary pointer passed to <<get_variable>>.
+ [RETURNS] TRUE on success, else FALSE.
+*/
+{
+ char ch;
+ unsigned int len;
+ unsigned int out_pos = 0;
+ const char *env;
+ const char *ptr;
+ struct passwd *pwent;
+ char buffer[BUFFER_SIZE], tmp[STRING_LENGTH];
+
+ if (length > BUFFER_SIZE)
+ length = BUFFER_SIZE;
+ for (; TRUE; ++input) {
+ switch (ch = *input) {
+ case '$':
+ /* Variable expansion */
+ input = expand_variable(buffer, length, &out_pos, ++input, get_variable_func, info);
+ if (input == NULL)
+ return FALSE;
+ break;
+ case '~':
+ /* Home directory expansion */
+ ch = input[1];
+ if (isspace(ch) ||(ch == '/') ||(ch == '\0')) {
+ /* User's own home directory: leave separator for next time */
+ env = getenv("HOME");
+ if (env == NULL) {
+ info_logger(LOG_INFO, bb_msg_variable_not_found, "HOME");
+ return FALSE;
+ }
+ len = strlen(env);
+ if (len + out_pos >= length)
+ goto st_expr_expand_out;
+ memcpy(buffer + out_pos, env, len + 1);
+ out_pos += len;
+ continue;
+ }
+ /* Someone else's home directory */
+ for (ptr = ++input; !isspace(ch) && (ch != '/') && (ch != '\0'); ch = *++ptr)
+ /* VOID */;
+ len = ptr - input;
+ if (len >= sizeof tmp)
+ goto st_expr_expand_out;
+ safe_memcpy(tmp, input, len);
+ input = ptr - 1;
+ pwent = getpwnam(tmp);
+ if (pwent == NULL) {
+ info_logger(LOG_INFO, "no pwent for: %s", tmp);
+ return FALSE;
+ }
+ len = strlen(pwent->pw_dir);
+ if (len + out_pos >= length)
+ goto st_expr_expand_out;
+ memcpy(buffer + out_pos, pwent->pw_dir, len + 1);
+ out_pos += len;
+ break;
+ case '\0':
+ /* Falltrough */
+ default:
+ if (out_pos >= length)
+ goto st_expr_expand_out;
+ buffer[out_pos++] = ch;
+ if (ch == '\0') {
+ memcpy(output, buffer, out_pos);
+ return TRUE;
+ }
+ break;
+ /* esac */
+ }
+ }
+ return FALSE;
+st_expr_expand_out:
+ info_logger(LOG_INFO, bb_msg_small_buffer);
+ return FALSE;
+} /* End Function st_expr_expand */
+
+
+/* Private functions follow */
+
+static const char *expand_variable(char *buffer, unsigned int length,
+ unsigned int *out_pos, const char *input,
+ const char *(*func)(const char *variable,
+ void *info),
+ void *info)
+/* [SUMMARY] Expand a variable.
+ <buffer> The buffer to write to.
+ <length> The length of the output buffer.
+ <out_pos> The current output position. This is updated.
+ <input> A pointer to the input character pointer.
+ <func> A function which will be used to get variable values. If this
+ returns NULL, the environment is searched instead. If this is NULL, only
+ the environment is searched.
+ <info> An arbitrary pointer passed to <<func>>.
+ <errfp> Diagnostic messages are written here.
+ [RETURNS] A pointer to the end of this subexpression on success, else NULL.
+*/
+{
+ char ch;
+ int len;
+ unsigned int open_braces;
+ const char *env, *ptr;
+ char tmp[STRING_LENGTH];
+
+ ch = input[0];
+ if (ch == '$') {
+ /* Special case for "$$": PID */
+ sprintf(tmp, "%d",(int) getpid());
+ len = strlen(tmp);
+ if (len + *out_pos >= length)
+ goto expand_variable_out;
+
+ memcpy(buffer + *out_pos, tmp, len + 1);
+ out_pos += len;
+ return input;
+ }
+ /* Ordinary variable expansion, possibly in braces */
+ if (ch != '{') {
+ /* Simple variable expansion */
+ for (ptr = input; isalnum(ch) || (ch == '_') || (ch == ':'); ch = *++ptr)
+ /* VOID */;
+ len = ptr - input;
+ if ((size_t)len >= sizeof tmp)
+ goto expand_variable_out;
+
+ safe_memcpy(tmp, input, len);
+ input = ptr - 1;
+ env = get_variable_v2(tmp, func, info);
+ if (env == NULL) {
+ info_logger(LOG_INFO, bb_msg_variable_not_found, tmp);
+ return NULL;
+ }
+ len = strlen(env);
+ if (len + *out_pos >= length)
+ goto expand_variable_out;
+
+ memcpy(buffer + *out_pos, env, len + 1);
+ *out_pos += len;
+ return input;
+ }
+ /* Variable in braces: check for ':' tricks */
+ ch = *++input;
+ for (ptr = input; isalnum(ch) || (ch == '_'); ch = *++ptr)
+ /* VOID */;
+ if (ch == '}') {
+ /* Must be simple variable expansion with "${var}" */
+ len = ptr - input;
+ if ((size_t)len >= sizeof tmp)
+ goto expand_variable_out;
+
+ safe_memcpy(tmp, input, len);
+ ptr = expand_variable(buffer, length, out_pos, tmp, func, info);
+ if (ptr == NULL)
+ return NULL;
+ return input + len;
+ }
+ if (ch != ':' || ptr[1] != '-') {
+ info_logger(LOG_INFO, "illegal char in var name");
+ return NULL;
+ }
+ /* It's that handy "${var:-word}" expression. Check if var is defined */
+ len = ptr - input;
+ if ((size_t)len >= sizeof tmp)
+ goto expand_variable_out;
+
+ safe_memcpy(tmp, input, len);
+ /* Move input pointer to ':' */
+ input = ptr;
+ /* First skip to closing brace, taking note of nested expressions */
+ ptr += 2;
+ ch = ptr[0];
+ for (open_braces = 1; open_braces > 0; ch = *++ptr) {
+ switch (ch) {
+ case '{':
+ ++open_braces;
+ break;
+ case '}':
+ --open_braces;
+ break;
+ case '\0':
+ info_logger(LOG_INFO,"\"}\" not found in: %s", input);
+ return NULL;
+ default:
+ break;
+ }
+ }
+ --ptr;
+ /* At this point ptr should point to closing brace of "${var:-word}" */
+ env = get_variable_v2(tmp, func, info);
+ if (env != NULL) {
+ /* Found environment variable, so skip the input to the closing brace
+ and return the variable */
+ input = ptr;
+ len = strlen(env);
+ if (len + *out_pos >= length)
+ goto expand_variable_out;
+
+ memcpy(buffer + *out_pos, env, len + 1);
+ *out_pos += len;
+ return input;
+ }
+ /* Environment variable was not found, so process word. Advance input
+ pointer to start of word in "${var:-word}" */
+ input += 2;
+ len = ptr - input;
+ if ((size_t)len >= sizeof tmp)
+ goto expand_variable_out;
+
+ safe_memcpy(tmp, input, len);
+ input = ptr;
+ if (!st_expr_expand(tmp, STRING_LENGTH, tmp, func, info))
+ return NULL;
+ len = strlen(tmp);
+ if (len + *out_pos >= length)
+ goto expand_variable_out;
+
+ memcpy(buffer + *out_pos, tmp, len + 1);
+ *out_pos += len;
+ return input;
+expand_variable_out:
+ info_logger(LOG_INFO, bb_msg_small_buffer);
+ return NULL;
+} /* End Function expand_variable */
+
+
+static const char *get_variable_v2(const char *variable,
+ const char *(*func)(const char *variable, void *info),
+ void *info)
+/* [SUMMARY] Get a variable from the environment or .
+ <variable> The variable name.
+ <func> A function which will be used to get the variable. If this returns
+ NULL, the environment is searched instead. If this is NULL, only the
+ environment is searched.
+ [RETURNS] The value of the variable on success, else NULL.
+*/
+{
+ const char *value;
+
+ if (func != NULL) {
+ value = (*func)(variable, info);
+ if (value != NULL)
+ return value;
+ }
+ return getenv(variable);
+} /* End Function get_variable */
+
+/* END OF CODE */
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/eject.c b/cleopatre/busybox-1.11.1-spc300/miscutils/eject.c
new file mode 100644
index 0000000000..aa22a3a420
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/eject.c
@@ -0,0 +1,116 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * eject implementation for busybox
+ *
+ * Copyright (C) 2004 Peter Willis <psyphreak@phreaker.net>
+ * Copyright (C) 2005 Tito Ragusa <farmatito@tiscali.it>
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+/*
+ * This is a simple hack of eject based on something Erik posted in #uclibc.
+ * Most of the dirty work blatantly ripped off from cat.c =)
+ */
+
+#include "libbb.h"
+
+/* various defines swiped from linux/cdrom.h */
+#define CDROMCLOSETRAY 0x5319 /* pendant of CDROMEJECT */
+#define CDROMEJECT 0x5309 /* Ejects the cdrom media */
+#define CDROM_DRIVE_STATUS 0x5326 /* Get tray position, etc. */
+/* drive status possibilities returned by CDROM_DRIVE_STATUS ioctl */
+#define CDS_TRAY_OPEN 2
+
+#define dev_fd 3
+
+/* Code taken from the original eject (http://eject.sourceforge.net/),
+ * refactored it a bit for busybox (ne-bb@nicoerfurth.de) */
+
+#include <scsi/sg.h>
+#include <scsi/scsi.h>
+
+static void eject_scsi(const char *dev)
+{
+ static const char sg_commands[3][6] = {
+ { ALLOW_MEDIUM_REMOVAL, 0, 0, 0, 0, 0 },
+ { START_STOP, 0, 0, 0, 1, 0 },
+ { START_STOP, 0, 0, 0, 2, 0 }
+ };
+
+ unsigned i;
+ unsigned char sense_buffer[32];
+ unsigned char inqBuff[2];
+ sg_io_hdr_t io_hdr;
+
+ if ((ioctl(dev_fd, SG_GET_VERSION_NUM, &i) < 0) || (i < 30000))
+ bb_error_msg_and_die("not a sg device or old sg driver");
+
+ memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = 6;
+ io_hdr.mx_sb_len = sizeof(sense_buffer);
+ io_hdr.dxfer_direction = SG_DXFER_NONE;
+ /* io_hdr.dxfer_len = 0; */
+ io_hdr.dxferp = inqBuff;
+ io_hdr.sbp = sense_buffer;
+ io_hdr.timeout = 2000;
+
+ for (i = 0; i < 3; i++) {
+ io_hdr.cmdp = (void *)sg_commands[i];
+ ioctl_or_perror_and_die(dev_fd, SG_IO, (void *)&io_hdr, "%s", dev);
+ }
+
+ /* force kernel to reread partition table when new disc is inserted */
+ ioctl(dev_fd, BLKRRPART);
+}
+
+#define FLAG_CLOSE 1
+#define FLAG_SMART 2
+#define FLAG_SCSI 4
+
+static void eject_cdrom(unsigned flags, const char *dev)
+{
+ int cmd = CDROMEJECT;
+
+ if (flags & FLAG_CLOSE
+ || (flags & FLAG_SMART && ioctl(dev_fd, CDROM_DRIVE_STATUS) == CDS_TRAY_OPEN)
+ ) {
+ cmd = CDROMCLOSETRAY;
+ }
+
+ ioctl_or_perror_and_die(dev_fd, cmd, NULL, "%s", dev);
+}
+
+int eject_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int eject_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ unsigned flags;
+ const char *device;
+
+ opt_complementary = "?1:t--T:T--t";
+ flags = getopt32(argv, "tT" USE_FEATURE_EJECT_SCSI("s"));
+ device = argv[optind] ? argv[optind] : "/dev/cdrom";
+
+ /* We used to do "umount <device>" here, but it was buggy
+ if something was mounted OVER cdrom and
+ if cdrom is mounted many times.
+
+ This works equally well (or better):
+ #!/bin/sh
+ umount /dev/cdrom
+ eject /dev/cdrom
+ */
+
+ xmove_fd(xopen(device, O_RDONLY|O_NONBLOCK), dev_fd);
+
+ if (ENABLE_FEATURE_EJECT_SCSI && (flags & FLAG_SCSI))
+ eject_scsi(device);
+ else
+ eject_cdrom(flags, device);
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close(dev_fd);
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/fbsplash.c b/cleopatre/busybox-1.11.1-spc300/miscutils/fbsplash.c
new file mode 100644
index 0000000000..07350b0cc0
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/fbsplash.c
@@ -0,0 +1,437 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2008 Michele Sanges <michele.sanges@otomelara.it>,
+ * <michele.sanges@gmail.it>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ * Usage:
+ * - use kernel option 'vga=xxx' or otherwise enable framebuffer device.
+ * - put somewhere fbsplash.cfg file and an image in .ppm format.
+ * - run applet: $ setsid fbsplash [params] &
+ * -c: hide cursor
+ * -d /dev/fbN: framebuffer device (if not /dev/fb0)
+ * -s path_to_image_file (can be "-" for stdin)
+ * -i path_to_cfg_file
+ * -f path_to_fifo (can be "-" for stdin)
+ * - if you want to run it only in presence of a kernel parameter
+ * (for example fbsplash=on), use:
+ * grep -q "fbsplash=on" </proc/cmdline && setsid fbsplash [params]
+ * - commands for fifo:
+ * "NN" (ASCII decimal number) - percentage to show on progress bar.
+ * "exit" (or just close fifo) - well you guessed it.
+ */
+
+#include "libbb.h"
+#include <linux/fb.h>
+
+/* If you want logging messages on /tmp/fbsplash.log... */
+#define DEBUG 0
+
+#define BYTES_PER_PIXEL 2
+
+typedef unsigned short DATA;
+
+struct globals {
+#if DEBUG
+ bool bdebug_messages; // enable/disable logging
+ FILE *logfile_fd; // log file
+#endif
+ unsigned char *addr; // pointer to framebuffer memory
+ unsigned nbar_width; // progress bar width
+ unsigned nbar_height; // progress bar height
+ unsigned nbar_posx; // progress bar horizontal position
+ unsigned nbar_posy; // progress bar vertical position
+ unsigned char nbar_colr; // progress bar color red component
+ unsigned char nbar_colg; // progress bar color green component
+ unsigned char nbar_colb; // progress bar color blue component
+ const char *image_filename;
+ struct fb_var_screeninfo scr_var;
+ struct fb_fix_screeninfo scr_fix;
+};
+#define G (*ptr_to_globals)
+#define INIT_G() do { \
+ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
+} while (0)
+
+
+#if DEBUG
+#define DEBUG_MESSAGE(strMessage, args...) \
+ if (G.bdebug_messages) { \
+ fprintf(G.logfile_fd, "[%s][%s] - %s\n", \
+ __FILE__, __FUNCTION__, strMessage); \
+ }
+#else
+#define DEBUG_MESSAGE(...) ((void)0)
+#endif
+
+
+/**
+ * Open and initialize the framebuffer device
+ * \param *strfb_device pointer to framebuffer device
+ */
+static void fb_open(const char *strfb_device)
+{
+ int fbfd = xopen(strfb_device, O_RDWR);
+
+ // framebuffer properties
+ xioctl(fbfd, FBIOGET_VSCREENINFO, &G.scr_var);
+ xioctl(fbfd, FBIOGET_FSCREENINFO, &G.scr_fix);
+
+ if (G.scr_var.bits_per_pixel != 16)
+ bb_error_msg_and_die("only 16 bpp is supported");
+
+ // map the device in memory
+ G.addr = mmap(NULL,
+ G.scr_var.xres * G.scr_var.yres
+ * BYTES_PER_PIXEL /*(G.scr_var.bits_per_pixel / 8)*/ ,
+ PROT_WRITE, MAP_SHARED, fbfd, 0);
+ if (G.addr == MAP_FAILED)
+ bb_perror_msg_and_die("can't mmap %s", strfb_device);
+ close(fbfd);
+}
+
+
+/**
+ * Draw hollow rectangle on framebuffer
+ */
+static void fb_drawrectangle(void)
+{
+ int cnt;
+ DATA thispix;
+ DATA *ptr1, *ptr2;
+ unsigned char nred = G.nbar_colr/2;
+ unsigned char ngreen = G.nbar_colg/2;
+ unsigned char nblue = G.nbar_colb/2;
+
+ nred >>= 3; // 5-bit red
+ ngreen >>= 2; // 6-bit green
+ nblue >>= 3; // 5-bit blue
+ thispix = nblue + (ngreen << 5) + (nred << (5+6));
+
+ // horizontal lines
+ ptr1 = (DATA*)(G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * BYTES_PER_PIXEL);
+ ptr2 = (DATA*)(G.addr + ((G.nbar_posy + G.nbar_height - 1) * G.scr_var.xres + G.nbar_posx) * BYTES_PER_PIXEL);
+ cnt = G.nbar_width - 1;
+ do {
+ *ptr1++ = thispix;
+ *ptr2++ = thispix;
+ } while (--cnt >= 0);
+
+ // vertical lines
+ ptr1 = (DATA*)(G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * BYTES_PER_PIXEL);
+ ptr2 = (DATA*)(G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx + G.nbar_width - 1) * BYTES_PER_PIXEL);
+ cnt = G.nbar_posy + G.nbar_height - 1 - G.nbar_posy;
+ do {
+ *ptr1 = thispix; ptr1 += G.scr_var.xres;
+ *ptr2 = thispix; ptr2 += G.scr_var.xres;
+ } while (--cnt >= 0);
+}
+
+
+/**
+ * Draw filled rectangle on framebuffer
+ * \param nx1pos,ny1pos upper left position
+ * \param nx2pos,ny2pos down right position
+ * \param nred,ngreen,nblue rgb color
+ */
+static void fb_drawfullrectangle(int nx1pos, int ny1pos, int nx2pos, int ny2pos,
+ unsigned char nred, unsigned char ngreen, unsigned char nblue)
+{
+ int cnt1, cnt2, nypos;
+ DATA thispix;
+ DATA *ptr;
+
+ nred >>= 3; // 5-bit red
+ ngreen >>= 2; // 6-bit green
+ nblue >>= 3; // 5-bit blue
+ thispix = nblue + (ngreen << 5) + (nred << (5+6));
+
+ cnt1 = ny2pos - ny1pos;
+ nypos = ny1pos;
+ do {
+ ptr = (DATA*)(G.addr + (nypos * G.scr_var.xres + nx1pos) * BYTES_PER_PIXEL);
+ cnt2 = nx2pos - nx1pos;
+ do {
+ *ptr++ = thispix;
+ } while (--cnt2 >= 0);
+
+ nypos++;
+ } while (--cnt1 >= 0);
+}
+
+
+/**
+ * Draw a progress bar on framebuffer
+ * \param percent percentage of loading
+ */
+static void fb_drawprogressbar(unsigned percent)
+{
+ int i, left_x, top_y, width, height;
+
+ // outer box
+ left_x = G.nbar_posx;
+ top_y = G.nbar_posy;
+ width = G.nbar_width - 1;
+ height = G.nbar_height - 1;
+ if ((height | width) < 0)
+ return;
+ // NB: "width" of 1 actually makes rect with width of 2!
+ fb_drawrectangle();
+
+ // inner "empty" rectangle
+ left_x++;
+ top_y++;
+ width -= 2;
+ height -= 2;
+ if ((height | width) < 0)
+ return;
+ fb_drawfullrectangle(
+ left_x, top_y,
+ left_x + width, top_y + height,
+ G.nbar_colr, G.nbar_colg, G.nbar_colb);
+
+ if (percent > 0) {
+ // actual progress bar
+ width = width * percent / 100;
+ i = height;
+ if (height == 0)
+ height++; // divide by 0 is bad
+ while (i >= 0) {
+ // draw one-line thick "rectangle"
+ // top line will have gray lvl 200, bottom one 100
+ unsigned gray_level = 100 + i*100/height;
+ fb_drawfullrectangle(
+ left_x, top_y, left_x + width, top_y,
+ gray_level, gray_level, gray_level);
+ top_y++;
+ i--;
+ }
+ }
+}
+
+
+/**
+ * Draw image from PPM file
+ */
+static void fb_drawimage(void)
+{
+ char head[256];
+ char s[80];
+ FILE *theme_file;
+ unsigned char *pixline;
+ unsigned i, j, width, height, line_size;
+
+ memset(head, 0, sizeof(head));
+ theme_file = xfopen_stdin(G.image_filename);
+
+ // parse ppm header
+ while (1) {
+ if (fgets(s, sizeof(s), theme_file) == NULL)
+ bb_error_msg_and_die("bad PPM file '%s'", G.image_filename);
+
+ if (s[0] == '#')
+ continue;
+
+ if (strlen(head) + strlen(s) >= sizeof(head))
+ bb_error_msg_and_die("bad PPM file '%s'", G.image_filename);
+
+ strcat(head, s);
+ if (head[0] != 'P' || head[1] != '6')
+ bb_error_msg_and_die("bad PPM file '%s'", G.image_filename);
+
+ // width, height, max_color_val
+ if (sscanf(head, "P6 %u %u %u", &width, &height, &i) == 3)
+ break;
+// TODO: i must be <= 255!
+ }
+
+ line_size = width*3;
+ if (width > G.scr_var.xres)
+ width = G.scr_var.xres;
+ if (height > G.scr_var.yres)
+ height = G.scr_var.yres;
+
+ pixline = xmalloc(line_size);
+ for (j = 0; j < height; j++) {
+ unsigned char *pixel = pixline;
+ DATA *src = (DATA *)(G.addr + j * G.scr_fix.line_length);
+
+ if (fread(pixline, 1, line_size, theme_file) != line_size)
+ bb_error_msg_and_die("bad PPM file '%s'", G.image_filename);
+ for (i = 0; i < width; i++) {
+ unsigned thispix;
+ thispix = (((unsigned)pixel[0] << 8) & 0xf800)
+ | (((unsigned)pixel[1] << 3) & 0x07e0)
+ | (((unsigned)pixel[2] >> 3));
+ *src++ = thispix;
+ pixel += 3;
+ }
+ }
+ free(pixline);
+ fclose(theme_file);
+}
+
+
+/**
+ * Parse configuration file
+ * \param *cfg_filename name of the configuration file
+ */
+static void init(const char *cfg_filename)
+{
+ static const char const param_names[] ALIGN1 =
+ "BAR_LEFT\0" "BAR_TOP\0"
+ "BAR_WIDTH\0" "BAR_HEIGHT\0"
+ "BAR_R\0" "BAR_G\0" "BAR_B\0"
+#if DEBUG
+ "DEBUG\0"
+#endif
+ ;
+
+ FILE *inifile;
+ char *buf;
+
+ inifile = xfopen_stdin(cfg_filename);
+
+ while ((buf = xmalloc_fgetline(inifile)) != NULL) {
+ char *value_str;
+ int val;
+
+ if (*buf == '#') { // it's a comment
+ free(buf);
+ continue;
+ }
+
+ value_str = strchr(buf, '=');
+ if (!value_str)
+ goto err;
+ *value_str++ = '\0';
+ val = xatoi_u(value_str);
+
+ switch (index_in_strings(param_names, buf)) {
+ case 0:
+ // progress bar horizontal position
+ G.nbar_posx = val;
+ break;
+ case 1:
+ // progress bar vertical position
+ G.nbar_posy = val;
+ break;
+ case 2:
+ // progress bar width
+ G.nbar_width = val;
+ break;
+ case 3:
+ // progress bar height
+ G.nbar_height = val;
+ break;
+ case 4:
+ // progress bar color - red component
+ G.nbar_colr = val;
+ break;
+ case 5:
+ // progress bar color - green component
+ G.nbar_colg = val;
+ break;
+ case 6:
+ // progress bar color - blue component
+ G.nbar_colb = val;
+ break;
+#if DEBUG
+ case 7:
+ G.bdebug_messages = val;
+ if (G.bdebug_messages)
+ G.logfile_fd = xfopen("/tmp/fbsplash.log", "w");
+ break;
+#endif
+ err:
+ default:
+ bb_error_msg_and_die("syntax error: '%s'", buf);
+ }
+ free(buf);
+ }
+ fclose(inifile);
+}
+
+
+int fbsplash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int fbsplash_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ const char *fb_device, *cfg_filename, *fifo_filename;
+ FILE *fp = fp; // for compiler
+ char *num_buf;
+ unsigned num;
+ bool bCursorOff;
+
+ INIT_G();
+
+ // parse command line options
+ fb_device = "/dev/fb0";
+ cfg_filename = NULL;
+ fifo_filename = NULL;
+ bCursorOff = 1 & getopt32(argv, "cs:d:i:f:",
+ &G.image_filename, &fb_device, &cfg_filename, &fifo_filename);
+
+ // parse configuration file
+ if (cfg_filename)
+ init(cfg_filename);
+
+ // We must have -s IMG
+ if (!G.image_filename)
+ bb_show_usage();
+
+ fb_open(fb_device);
+
+ if (fifo_filename && bCursorOff) {
+ // hide cursor (BEFORE any fb ops)
+ full_write(STDOUT_FILENO, "\x1b" "[?25l", 6);
+ }
+
+ fb_drawimage();
+
+ if (!fifo_filename)
+ return EXIT_SUCCESS;
+
+ fp = xfopen_stdin(fifo_filename);
+ if (fp != stdin) {
+ // For named pipes, we want to support this:
+ // mkfifo cmd_pipe
+ // fbsplash -f cmd_pipe .... &
+ // ...
+ // echo 33 >cmd_pipe
+ // ...
+ // echo 66 >cmd_pipe
+ // This means that we don't want fbsplash to get EOF
+ // when last writer closes input end.
+ // The simplest way is to open fifo for writing too
+ // and become an additional writer :)
+ open(fifo_filename, O_WRONLY); // errors are ignored
+ }
+
+ fb_drawprogressbar(0);
+ // Block on read, waiting for some input.
+ // Use of <stdio.h> style I/O allows to correctly
+ // handle a case when we have many buffered lines
+ // already in the pipe
+ while ((num_buf = xmalloc_fgetline(fp)) != NULL) {
+ if (strncmp(num_buf, "exit", 4) == 0) {
+ DEBUG_MESSAGE("exit");
+ break;
+ }
+ num = atoi(num_buf);
+ if (isdigit(num_buf[0]) && (num <= 100)) {
+#if DEBUG
+ char strVal[10];
+ sprintf(strVal, "%d", num);
+ DEBUG_MESSAGE(strVal);
+#endif
+ fb_drawprogressbar(num);
+ }
+ free(num_buf);
+ }
+
+ if (bCursorOff) // restore cursor
+ full_write(STDOUT_FILENO, "\x1b" "[?25h", 6);
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/fbsplash.cfg b/cleopatre/busybox-1.11.1-spc300/miscutils/fbsplash.cfg
new file mode 100644
index 0000000000..b6cf607ebc
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/fbsplash.cfg
@@ -0,0 +1,9 @@
+# progress bar position
+BAR_LEFT=170
+BAR_TOP=300
+BAR_WIDTH=300
+BAR_HEIGHT=20
+# progress bar color
+BAR_R=80
+BAR_G=80
+BAR_B=130
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/hdparm.c b/cleopatre/busybox-1.11.1-spc300/miscutils/hdparm.c
new file mode 100644
index 0000000000..a5d5b05cd9
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/hdparm.c
@@ -0,0 +1,2063 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * hdparm implementation for busybox
+ *
+ * Copyright (C) [2003] by [Matteo Croce] <3297627799@wind.it>
+ * Hacked by Tito <farmatito@tiscali.it> for size optimization.
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ *
+ * This program is based on the source code of hdparm: see below...
+ * hdparm.c - Command line interface to get/set hard disk parameters
+ * - by Mark Lord (C) 1994-2002 -- freely distributable
+ */
+
+#include "libbb.h"
+#include <linux/hdreg.h>
+
+/* device types */
+/* ------------ */
+#define NO_DEV 0xffff
+#define ATA_DEV 0x0000
+#define ATAPI_DEV 0x0001
+
+/* word definitions */
+/* ---------------- */
+#define GEN_CONFIG 0 /* general configuration */
+#define LCYLS 1 /* number of logical cylinders */
+#define CONFIG 2 /* specific configuration */
+#define LHEADS 3 /* number of logical heads */
+#define TRACK_BYTES 4 /* number of bytes/track (ATA-1) */
+#define SECT_BYTES 5 /* number of bytes/sector (ATA-1) */
+#define LSECTS 6 /* number of logical sectors/track */
+#define START_SERIAL 10 /* ASCII serial number */
+#define LENGTH_SERIAL 10 /* 10 words (20 bytes or characters) */
+#define BUF_TYPE 20 /* buffer type (ATA-1) */
+#define BUFFER__SIZE 21 /* buffer size (ATA-1) */
+#define RW_LONG 22 /* extra bytes in R/W LONG cmd ( < ATA-4)*/
+#define START_FW_REV 23 /* ASCII firmware revision */
+#define LENGTH_FW_REV 4 /* 4 words (8 bytes or characters) */
+#define START_MODEL 27 /* ASCII model number */
+#define LENGTH_MODEL 20 /* 20 words (40 bytes or characters) */
+#define SECTOR_XFER_MAX 47 /* r/w multiple: max sectors xfered */
+#define DWORD_IO 48 /* can do double-word IO (ATA-1 only) */
+#define CAPAB_0 49 /* capabilities */
+#define CAPAB_1 50
+#define PIO_MODE 51 /* max PIO mode supported (obsolete)*/
+#define DMA_MODE 52 /* max Singleword DMA mode supported (obs)*/
+#define WHATS_VALID 53 /* what fields are valid */
+#define LCYLS_CUR 54 /* current logical cylinders */
+#define LHEADS_CUR 55 /* current logical heads */
+#define LSECTS_CUR 56 /* current logical sectors/track */
+#define CAPACITY_LSB 57 /* current capacity in sectors */
+#define CAPACITY_MSB 58
+#define SECTOR_XFER_CUR 59 /* r/w multiple: current sectors xfered */
+#define LBA_SECTS_LSB 60 /* LBA: total number of user */
+#define LBA_SECTS_MSB 61 /* addressable sectors */
+#define SINGLE_DMA 62 /* singleword DMA modes */
+#define MULTI_DMA 63 /* multiword DMA modes */
+#define ADV_PIO_MODES 64 /* advanced PIO modes supported */
+ /* multiword DMA xfer cycle time: */
+#define DMA_TIME_MIN 65 /* - minimum */
+#define DMA_TIME_NORM 66 /* - manufacturer's recommended */
+ /* minimum PIO xfer cycle time: */
+#define PIO_NO_FLOW 67 /* - without flow control */
+#define PIO_FLOW 68 /* - with IORDY flow control */
+#define PKT_REL 71 /* typical #ns from PKT cmd to bus rel */
+#define SVC_NBSY 72 /* typical #ns from SERVICE cmd to !BSY */
+#define CDR_MAJOR 73 /* CD ROM: major version number */
+#define CDR_MINOR 74 /* CD ROM: minor version number */
+#define QUEUE_DEPTH 75 /* queue depth */
+#define MAJOR 80 /* major version number */
+#define MINOR 81 /* minor version number */
+#define CMDS_SUPP_0 82 /* command/feature set(s) supported */
+#define CMDS_SUPP_1 83
+#define CMDS_SUPP_2 84
+#define CMDS_EN_0 85 /* command/feature set(s) enabled */
+#define CMDS_EN_1 86
+#define CMDS_EN_2 87
+#define ULTRA_DMA 88 /* ultra DMA modes */
+ /* time to complete security erase */
+#define ERASE_TIME 89 /* - ordinary */
+#define ENH_ERASE_TIME 90 /* - enhanced */
+#define ADV_PWR 91 /* current advanced power management level
+ in low byte, 0x40 in high byte. */
+#define PSWD_CODE 92 /* master password revision code */
+#define HWRST_RSLT 93 /* hardware reset result */
+#define ACOUSTIC 94 /* acoustic mgmt values ( >= ATA-6) */
+#define LBA_LSB 100 /* LBA: maximum. Currently only 48 */
+#define LBA_MID 101 /* bits are used, but addr 103 */
+#define LBA_48_MSB 102 /* has been reserved for LBA in */
+#define LBA_64_MSB 103 /* the future. */
+#define RM_STAT 127 /* removable media status notification feature set support */
+#define SECU_STATUS 128 /* security status */
+#define CFA_PWR_MODE 160 /* CFA power mode 1 */
+#define START_MEDIA 176 /* media serial number */
+#define LENGTH_MEDIA 20 /* 20 words (40 bytes or characters)*/
+#define START_MANUF 196 /* media manufacturer I.D. */
+#define LENGTH_MANUF 10 /* 10 words (20 bytes or characters) */
+#define INTEGRITY 255 /* integrity word */
+
+/* bit definitions within the words */
+/* -------------------------------- */
+
+/* many words are considered valid if bit 15 is 0 and bit 14 is 1 */
+#define VALID 0xc000
+#define VALID_VAL 0x4000
+/* many words are considered invalid if they are either all-0 or all-1 */
+#define NOVAL_0 0x0000
+#define NOVAL_1 0xffff
+
+/* word 0: gen_config */
+#define NOT_ATA 0x8000
+#define NOT_ATAPI 0x4000 /* (check only if bit 15 == 1) */
+#define MEDIA_REMOVABLE 0x0080
+#define DRIVE_NOT_REMOVABLE 0x0040 /* bit obsoleted in ATA 6 */
+#define INCOMPLETE 0x0004
+#define CFA_SUPPORT_VAL 0x848a /* 848a=CFA feature set support */
+#define DRQ_RESPONSE_TIME 0x0060
+#define DRQ_3MS_VAL 0x0000
+#define DRQ_INTR_VAL 0x0020
+#define DRQ_50US_VAL 0x0040
+#define PKT_SIZE_SUPPORTED 0x0003
+#define PKT_SIZE_12_VAL 0x0000
+#define PKT_SIZE_16_VAL 0x0001
+#define EQPT_TYPE 0x1f00
+#define SHIFT_EQPT 8
+
+#define CDROM 0x0005
+
+/* word 1: number of logical cylinders */
+#define LCYLS_MAX 0x3fff /* maximum allowable value */
+
+/* word 2: specific configuration
+ * (a) require SET FEATURES to spin-up
+ * (b) require spin-up to fully reply to IDENTIFY DEVICE
+ */
+#define STBY_NID_VAL 0x37c8 /* (a) and (b) */
+#define STBY_ID_VAL 0x738c /* (a) and not (b) */
+#define PWRD_NID_VAL 0x8c73 /* not (a) and (b) */
+#define PWRD_ID_VAL 0xc837 /* not (a) and not (b) */
+
+/* words 47 & 59: sector_xfer_max & sector_xfer_cur */
+#define SECTOR_XFER 0x00ff /* sectors xfered on r/w multiple cmds*/
+#define MULTIPLE_SETTING_VALID 0x0100 /* 1=multiple sector setting is valid */
+
+/* word 49: capabilities 0 */
+#define STD_STBY 0x2000 /* 1=standard values supported (ATA); 0=vendor specific values */
+#define IORDY_SUP 0x0800 /* 1=support; 0=may be supported */
+#define IORDY_OFF 0x0400 /* 1=may be disabled */
+#define LBA_SUP 0x0200 /* 1=Logical Block Address support */
+#define DMA_SUP 0x0100 /* 1=Direct Memory Access support */
+#define DMA_IL_SUP 0x8000 /* 1=interleaved DMA support (ATAPI) */
+#define CMD_Q_SUP 0x4000 /* 1=command queuing support (ATAPI) */
+#define OVLP_SUP 0x2000 /* 1=overlap operation support (ATAPI) */
+#define SWRST_REQ 0x1000 /* 1=ATA SW reset required (ATAPI, obsolete */
+
+/* word 50: capabilities 1 */
+#define MIN_STANDBY_TIMER 0x0001 /* 1=device specific standby timer value minimum */
+
+/* words 51 & 52: PIO & DMA cycle times */
+#define MODE 0xff00 /* the mode is in the MSBs */
+
+/* word 53: whats_valid */
+#define OK_W88 0x0004 /* the ultra_dma info is valid */
+#define OK_W64_70 0x0002 /* see above for word descriptions */
+#define OK_W54_58 0x0001 /* current cyl, head, sector, cap. info valid */
+
+/*word 63,88: dma_mode, ultra_dma_mode*/
+#define MODE_MAX 7 /* bit definitions force udma <=7 (when
+ * udma >=8 comes out it'll have to be
+ * defined in a new dma_mode word!) */
+
+/* word 64: PIO transfer modes */
+#define PIO_SUP 0x00ff /* only bits 0 & 1 are used so far, */
+#define PIO_MODE_MAX 8 /* but all 8 bits are defined */
+
+/* word 75: queue_depth */
+#define DEPTH_BITS 0x001f /* bits used for queue depth */
+
+/* words 80-81: version numbers */
+/* NOVAL_0 or NOVAL_1 means device does not report version */
+
+/* word 81: minor version number */
+#define MINOR_MAX 0x22
+/* words 82-84: cmds/feats supported */
+#define CMDS_W82 0x77ff /* word 82: defined command locations*/
+#define CMDS_W83 0x3fff /* word 83: defined command locations*/
+#define CMDS_W84 0x002f /* word 83: defined command locations*/
+#define SUPPORT_48_BIT 0x0400
+#define NUM_CMD_FEAT_STR 48
+
+/* words 85-87: cmds/feats enabled */
+/* use cmd_feat_str[] to display what commands and features have
+ * been enabled with words 85-87
+ */
+
+/* words 89, 90, SECU ERASE TIME */
+#define ERASE_BITS 0x00ff
+
+/* word 92: master password revision */
+/* NOVAL_0 or NOVAL_1 means no support for master password revision */
+
+/* word 93: hw reset result */
+#define CBLID 0x2000 /* CBLID status */
+#define RST0 0x0001 /* 1=reset to device #0 */
+#define DEV_DET 0x0006 /* how device num determined */
+#define JUMPER_VAL 0x0002 /* device num determined by jumper */
+#define CSEL_VAL 0x0004 /* device num determined by CSEL_VAL */
+
+/* word 127: removable media status notification feature set support */
+#define RM_STAT_BITS 0x0003
+#define RM_STAT_SUP 0x0001
+
+/* word 128: security */
+#define SECU_ENABLED 0x0002
+#define SECU_LEVEL 0x0010
+#define NUM_SECU_STR 6
+
+/* word 160: CFA power mode */
+#define VALID_W160 0x8000 /* 1=word valid */
+#define PWR_MODE_REQ 0x2000 /* 1=CFA power mode req'd by some cmds*/
+#define PWR_MODE_OFF 0x1000 /* 1=CFA power moded disabled */
+#define MAX_AMPS 0x0fff /* value = max current in ma */
+
+/* word 255: integrity */
+#define SIG 0x00ff /* signature location */
+#define SIG_VAL 0x00a5 /* signature value */
+
+#define TIMING_BUF_MB 1
+#define TIMING_BUF_BYTES (TIMING_BUF_MB * 1024 * 1024)
+
+#undef DO_FLUSHCACHE /* under construction: force cache flush on -W0 */
+
+
+enum { fd = 3 };
+
+
+struct globals {
+ smallint get_identity, get_geom;
+ smallint do_flush;
+ smallint do_ctimings, do_timings;
+ smallint reread_partn;
+ smallint set_piomode, noisy_piomode;
+ smallint set_readahead, get_readahead;
+ smallint set_readonly, get_readonly;
+ smallint set_unmask, get_unmask;
+ smallint set_mult, get_mult;
+#ifdef HDIO_GET_QDMA
+ smallint get_dma_q;
+#ifdef HDIO_SET_QDMA
+ smallint set_dma_q;
+#endif
+#endif
+ smallint set_nowerr, get_nowerr;
+ smallint set_keep, get_keep;
+ smallint set_io32bit, get_io32bit;
+ int piomode;
+ unsigned long Xreadahead;
+ unsigned long readonly;
+ unsigned long unmask;
+ unsigned long mult;
+#ifdef HDIO_SET_QDMA
+ unsigned long dma_q;
+#endif
+ unsigned long nowerr;
+ unsigned long keep;
+ unsigned long io32bit;
+#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
+ unsigned long dma;
+ smallint set_dma, get_dma;
+#endif
+#ifdef HDIO_DRIVE_CMD
+ smallint set_xfermode, get_xfermode;
+ smallint set_dkeep, get_dkeep;
+ smallint set_standby, get_standby;
+ smallint set_lookahead, get_lookahead;
+ smallint set_prefetch, get_prefetch;
+ smallint set_defects, get_defects;
+ smallint set_wcache, get_wcache;
+ smallint set_doorlock, get_doorlock;
+ smallint set_seagate, get_seagate;
+ smallint set_standbynow, get_standbynow;
+ smallint set_sleepnow, get_sleepnow;
+ smallint get_powermode;
+ smallint set_apmmode, get_apmmode;
+ int xfermode_requested;
+ unsigned long dkeep;
+ unsigned long standby_requested; /* 0..255 */
+ unsigned long lookahead;
+ unsigned long prefetch;
+ unsigned long defects;
+ unsigned long wcache;
+ unsigned long doorlock;
+ unsigned long apmmode;
+#endif
+ USE_FEATURE_HDPARM_GET_IDENTITY( smallint get_IDentity;)
+ USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( smallint set_busstate, get_busstate;)
+ USE_FEATURE_HDPARM_HDIO_DRIVE_RESET( smallint perform_reset;)
+ USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( smallint perform_tristate;)
+ USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(smallint unregister_hwif;)
+ USE_FEATURE_HDPARM_HDIO_SCAN_HWIF( smallint scan_hwif;)
+ USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( unsigned long busstate;)
+ USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( unsigned long tristate;)
+ USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(unsigned long hwif;)
+#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
+ unsigned long hwif_data;
+ unsigned long hwif_ctrl;
+ unsigned long hwif_irq;
+#endif
+#ifdef DO_FLUSHCACHE
+ unsigned char flushcache[4] = { WIN_FLUSHCACHE, 0, 0, 0 };
+#endif
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+struct BUG_G_too_big {
+ char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
+};
+#define get_identity (G.get_identity )
+#define get_geom (G.get_geom )
+#define do_flush (G.do_flush )
+#define do_ctimings (G.do_ctimings )
+#define do_timings (G.do_timings )
+#define reread_partn (G.reread_partn )
+#define set_piomode (G.set_piomode )
+#define noisy_piomode (G.noisy_piomode )
+#define set_readahead (G.set_readahead )
+#define get_readahead (G.get_readahead )
+#define set_readonly (G.set_readonly )
+#define get_readonly (G.get_readonly )
+#define set_unmask (G.set_unmask )
+#define get_unmask (G.get_unmask )
+#define set_mult (G.set_mult )
+#define get_mult (G.get_mult )
+#define set_dma_q (G.set_dma_q )
+#define get_dma_q (G.get_dma_q )
+#define set_nowerr (G.set_nowerr )
+#define get_nowerr (G.get_nowerr )
+#define set_keep (G.set_keep )
+#define get_keep (G.get_keep )
+#define set_io32bit (G.set_io32bit )
+#define get_io32bit (G.get_io32bit )
+#define piomode (G.piomode )
+#define Xreadahead (G.Xreadahead )
+#define readonly (G.readonly )
+#define unmask (G.unmask )
+#define mult (G.mult )
+#define dma_q (G.dma_q )
+#define nowerr (G.nowerr )
+#define keep (G.keep )
+#define io32bit (G.io32bit )
+#define dma (G.dma )
+#define set_dma (G.set_dma )
+#define get_dma (G.get_dma )
+#define set_xfermode (G.set_xfermode )
+#define get_xfermode (G.get_xfermode )
+#define set_dkeep (G.set_dkeep )
+#define get_dkeep (G.get_dkeep )
+#define set_standby (G.set_standby )
+#define get_standby (G.get_standby )
+#define set_lookahead (G.set_lookahead )
+#define get_lookahead (G.get_lookahead )
+#define set_prefetch (G.set_prefetch )
+#define get_prefetch (G.get_prefetch )
+#define set_defects (G.set_defects )
+#define get_defects (G.get_defects )
+#define set_wcache (G.set_wcache )
+#define get_wcache (G.get_wcache )
+#define set_doorlock (G.set_doorlock )
+#define get_doorlock (G.get_doorlock )
+#define set_seagate (G.set_seagate )
+#define get_seagate (G.get_seagate )
+#define set_standbynow (G.set_standbynow )
+#define get_standbynow (G.get_standbynow )
+#define set_sleepnow (G.set_sleepnow )
+#define get_sleepnow (G.get_sleepnow )
+#define get_powermode (G.get_powermode )
+#define set_apmmode (G.set_apmmode )
+#define get_apmmode (G.get_apmmode )
+#define xfermode_requested (G.xfermode_requested )
+#define dkeep (G.dkeep )
+#define standby_requested (G.standby_requested )
+#define lookahead (G.lookahead )
+#define prefetch (G.prefetch )
+#define defects (G.defects )
+#define wcache (G.wcache )
+#define doorlock (G.doorlock )
+#define apmmode (G.apmmode )
+#define get_IDentity (G.get_IDentity )
+#define set_busstate (G.set_busstate )
+#define get_busstate (G.get_busstate )
+#define perform_reset (G.perform_reset )
+#define perform_tristate (G.perform_tristate )
+#define unregister_hwif (G.unregister_hwif )
+#define scan_hwif (G.scan_hwif )
+#define busstate (G.busstate )
+#define tristate (G.tristate )
+#define hwif (G.hwif )
+#define hwif_data (G.hwif_data )
+#define hwif_ctrl (G.hwif_ctrl )
+#define hwif_irq (G.hwif_irq )
+
+
+/* Busybox messages and functions */
+#if ENABLE_IOCTL_HEX2STR_ERROR
+static int ioctl_alt_func(/*int fd,*/ int cmd, unsigned char *args, int alt, const char *string)
+{
+ if (!ioctl(fd, cmd, args))
+ return 0;
+ args[0] = alt;
+ return bb_ioctl_or_warn(fd, cmd, args, string);
+}
+#define ioctl_alt_or_warn(cmd,args,alt) ioctl_alt_func(cmd,args,alt,#cmd)
+#else
+static int ioctl_alt_func(/*int fd,*/ int cmd, unsigned char *args, int alt)
+{
+ if (!ioctl(fd, cmd, args))
+ return 0;
+ args[0] = alt;
+ return bb_ioctl_or_warn(fd, cmd, args);
+}
+#define ioctl_alt_or_warn(cmd,args,alt) ioctl_alt_func(cmd,args,alt)
+#endif
+
+static void on_off(int value)
+{
+ puts(value ? " (on)" : " (off)");
+}
+
+static void print_flag_on_off(int get_arg, const char *s, unsigned long arg)
+{
+ if (get_arg) {
+ printf(" setting %s to %ld", s, arg);
+ on_off(arg);
+ }
+}
+
+static void print_value_on_off(const char *str, unsigned long argp)
+{
+ printf(" %s\t= %2ld", str, argp);
+ on_off(argp != 0);
+}
+
+#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
+static void print_ascii(const char *p, int length)
+{
+#if BB_BIG_ENDIAN
+#define LE_ONLY(x)
+ enum { ofs = 0 };
+#else
+#define LE_ONLY(x) x
+ /* every 16bit word is big-endian (i.e. inverted) */
+ /* accessing bytes in 1,0, 3,2, 5,4... sequence */
+ int ofs = 1;
+#endif
+
+ length *= 2;
+ /* find first non-space & print it */
+ while (length && p[ofs] != ' ') {
+ p++;
+ LE_ONLY(ofs = -ofs;)
+ length--;
+ }
+ while (length && p[ofs]) {
+ bb_putchar(p[ofs]);
+ p++;
+ LE_ONLY(ofs = -ofs;)
+ length--;
+ }
+ bb_putchar('\n');
+#undef LE_ONLY
+}
+
+static void xprint_ascii(uint16_t *val, int i, const char *string, int n)
+{
+ if (val[i]) {
+ printf("\t%-20s", string);
+ print_ascii((void*)&val[i], n);
+ }
+}
+
+static uint8_t mode_loop(uint16_t mode_sup, uint16_t mode_sel, int cc, uint8_t *have_mode)
+{
+ uint16_t ii;
+ uint8_t err_dma = 0;
+
+ for (ii = 0; ii <= MODE_MAX; ii++) {
+ if (mode_sel & 0x0001) {
+ printf("*%cdma%u ", cc, ii);
+ if (*have_mode)
+ err_dma = 1;
+ *have_mode = 1;
+ } else if (mode_sup & 0x0001)
+ printf("%cdma%u ", cc, ii);
+
+ mode_sup >>= 1;
+ mode_sel >>= 1;
+ }
+ return err_dma;
+}
+
+static const char pkt_str[] ALIGN1 =
+ "Direct-access device" "\0" /* word 0, bits 12-8 = 00 */
+ "Sequential-access device" "\0" /* word 0, bits 12-8 = 01 */
+ "Printer" "\0" /* word 0, bits 12-8 = 02 */
+ "Processor" "\0" /* word 0, bits 12-8 = 03 */
+ "Write-once device" "\0" /* word 0, bits 12-8 = 04 */
+ "CD-ROM" "\0" /* word 0, bits 12-8 = 05 */
+ "Scanner" "\0" /* word 0, bits 12-8 = 06 */
+ "Optical memory" "\0" /* word 0, bits 12-8 = 07 */
+ "Medium changer" "\0" /* word 0, bits 12-8 = 08 */
+ "Communications device" "\0" /* word 0, bits 12-8 = 09 */
+ "ACS-IT8 device" "\0" /* word 0, bits 12-8 = 0a */
+ "ACS-IT8 device" "\0" /* word 0, bits 12-8 = 0b */
+ "Array controller" "\0" /* word 0, bits 12-8 = 0c */
+ "Enclosure services" "\0" /* word 0, bits 12-8 = 0d */
+ "Reduced block command device" "\0" /* word 0, bits 12-8 = 0e */
+ "Optical card reader/writer" "\0" /* word 0, bits 12-8 = 0f */
+;
+
+static const char ata1_cfg_str[] ALIGN1 = /* word 0 in ATA-1 mode */
+ "reserved" "\0" /* bit 0 */
+ "hard sectored" "\0" /* bit 1 */
+ "soft sectored" "\0" /* bit 2 */
+ "not MFM encoded " "\0" /* bit 3 */
+ "head switch time > 15us" "\0" /* bit 4 */
+ "spindle motor control option" "\0" /* bit 5 */
+ "fixed drive" "\0" /* bit 6 */
+ "removable drive" "\0" /* bit 7 */
+ "disk xfer rate <= 5Mbs" "\0" /* bit 8 */
+ "disk xfer rate > 5Mbs, <= 10Mbs" "\0" /* bit 9 */
+ "disk xfer rate > 5Mbs" "\0" /* bit 10 */
+ "rotational speed tol." "\0" /* bit 11 */
+ "data strobe offset option" "\0" /* bit 12 */
+ "track offset option" "\0" /* bit 13 */
+ "format speed tolerance gap reqd" "\0" /* bit 14 */
+ "ATAPI" /* bit 14 */
+;
+
+static const char minor_str[] ALIGN1 =
+ /* word 81 value: */
+ "Unspecified" "\0" /* 0x0000 */
+ "ATA-1 X3T9.2 781D prior to rev.4" "\0" /* 0x0001 */
+ "ATA-1 published, ANSI X3.221-1994" "\0" /* 0x0002 */
+ "ATA-1 X3T9.2 781D rev.4" "\0" /* 0x0003 */
+ "ATA-2 published, ANSI X3.279-1996" "\0" /* 0x0004 */
+ "ATA-2 X3T10 948D prior to rev.2k" "\0" /* 0x0005 */
+ "ATA-3 X3T10 2008D rev.1" "\0" /* 0x0006 */
+ "ATA-2 X3T10 948D rev.2k" "\0" /* 0x0007 */
+ "ATA-3 X3T10 2008D rev.0" "\0" /* 0x0008 */
+ "ATA-2 X3T10 948D rev.3" "\0" /* 0x0009 */
+ "ATA-3 published, ANSI X3.298-199x" "\0" /* 0x000a */
+ "ATA-3 X3T10 2008D rev.6" "\0" /* 0x000b */
+ "ATA-3 X3T13 2008D rev.7 and 7a" "\0" /* 0x000c */
+ "ATA/ATAPI-4 X3T13 1153D rev.6" "\0" /* 0x000d */
+ "ATA/ATAPI-4 T13 1153D rev.13" "\0" /* 0x000e */
+ "ATA/ATAPI-4 X3T13 1153D rev.7" "\0" /* 0x000f */
+ "ATA/ATAPI-4 T13 1153D rev.18" "\0" /* 0x0010 */
+ "ATA/ATAPI-4 T13 1153D rev.15" "\0" /* 0x0011 */
+ "ATA/ATAPI-4 published, ANSI INCITS 317-1998" "\0" /* 0x0012 */
+ "ATA/ATAPI-5 T13 1321D rev.3" "\0" /* 0x0013 */
+ "ATA/ATAPI-4 T13 1153D rev.14" "\0" /* 0x0014 */
+ "ATA/ATAPI-5 T13 1321D rev.1" "\0" /* 0x0015 */
+ "ATA/ATAPI-5 published, ANSI INCITS 340-2000" "\0" /* 0x0016 */
+ "ATA/ATAPI-4 T13 1153D rev.17" "\0" /* 0x0017 */
+ "ATA/ATAPI-6 T13 1410D rev.0" "\0" /* 0x0018 */
+ "ATA/ATAPI-6 T13 1410D rev.3a" "\0" /* 0x0019 */
+ "ATA/ATAPI-7 T13 1532D rev.1" "\0" /* 0x001a */
+ "ATA/ATAPI-6 T13 1410D rev.2" "\0" /* 0x001b */
+ "ATA/ATAPI-6 T13 1410D rev.1" "\0" /* 0x001c */
+ "ATA/ATAPI-7 published, ANSI INCITS 397-2005" "\0" /* 0x001d */
+ "ATA/ATAPI-7 T13 1532D rev.0" "\0" /* 0x001e */
+ "reserved" "\0" /* 0x001f */
+ "reserved" "\0" /* 0x0020 */
+ "ATA/ATAPI-7 T13 1532D rev.4a" "\0" /* 0x0021 */
+ "ATA/ATAPI-6 published, ANSI INCITS 361-2002" "\0" /* 0x0022 */
+ "reserved" /* 0x0023-0xfffe */
+;
+static const char actual_ver[MINOR_MAX + 2] ALIGN1 = {
+ /* word 81 value: */
+ 0, /* 0x0000 WARNING: actual_ver[] array */
+ 1, /* 0x0001 WARNING: corresponds */
+ 1, /* 0x0002 WARNING: *exactly* */
+ 1, /* 0x0003 WARNING: to the ATA/ */
+ 2, /* 0x0004 WARNING: ATAPI version */
+ 2, /* 0x0005 WARNING: listed in */
+ 3, /* 0x0006 WARNING: the */
+ 2, /* 0x0007 WARNING: minor_str */
+ 3, /* 0x0008 WARNING: array */
+ 2, /* 0x0009 WARNING: above. */
+ 3, /* 0x000a WARNING: */
+ 3, /* 0x000b WARNING: If you change */
+ 3, /* 0x000c WARNING: that one, */
+ 4, /* 0x000d WARNING: change this one */
+ 4, /* 0x000e WARNING: too!!! */
+ 4, /* 0x000f */
+ 4, /* 0x0010 */
+ 4, /* 0x0011 */
+ 4, /* 0x0012 */
+ 5, /* 0x0013 */
+ 4, /* 0x0014 */
+ 5, /* 0x0015 */
+ 5, /* 0x0016 */
+ 4, /* 0x0017 */
+ 6, /* 0x0018 */
+ 6, /* 0x0019 */
+ 7, /* 0x001a */
+ 6, /* 0x001b */
+ 6, /* 0x001c */
+ 7, /* 0x001d */
+ 7, /* 0x001e */
+ 0, /* 0x001f */
+ 0, /* 0x0020 */
+ 7, /* 0x0021 */
+ 6, /* 0x0022 */
+ 0 /* 0x0023-0xfffe */
+};
+
+static const char cmd_feat_str[] ALIGN1 =
+ "" "\0" /* word 82 bit 15: obsolete */
+ "NOP cmd" "\0" /* word 82 bit 14 */
+ "READ BUFFER cmd" "\0" /* word 82 bit 13 */
+ "WRITE BUFFER cmd" "\0" /* word 82 bit 12 */
+ "" "\0" /* word 82 bit 11: obsolete */
+ "Host Protected Area feature set" "\0" /* word 82 bit 10 */
+ "DEVICE RESET cmd" "\0" /* word 82 bit 9 */
+ "SERVICE interrupt" "\0" /* word 82 bit 8 */
+ "Release interrupt" "\0" /* word 82 bit 7 */
+ "Look-ahead" "\0" /* word 82 bit 6 */
+ "Write cache" "\0" /* word 82 bit 5 */
+ "PACKET command feature set" "\0" /* word 82 bit 4 */
+ "Power Management feature set" "\0" /* word 82 bit 3 */
+ "Removable Media feature set" "\0" /* word 82 bit 2 */
+ "Security Mode feature set" "\0" /* word 82 bit 1 */
+ "SMART feature set" "\0" /* word 82 bit 0 */
+ /* -------------- */
+ "" "\0" /* word 83 bit 15: !valid bit */
+ "" "\0" /* word 83 bit 14: valid bit */
+ "FLUSH CACHE EXT cmd" "\0" /* word 83 bit 13 */
+ "Mandatory FLUSH CACHE cmd " "\0" /* word 83 bit 12 */
+ "Device Configuration Overlay feature set " "\0"
+ "48-bit Address feature set " "\0" /* word 83 bit 10 */
+ "" "\0"
+ "SET MAX security extension" "\0" /* word 83 bit 8 */
+ "Address Offset Reserved Area Boot" "\0" /* word 83 bit 7 */
+ "SET FEATURES subcommand required to spinup after power up" "\0"
+ "Power-Up In Standby feature set" "\0" /* word 83 bit 5 */
+ "Removable Media Status Notification feature set" "\0"
+ "Adv. Power Management feature set" "\0" /* word 83 bit 3 */
+ "CFA feature set" "\0" /* word 83 bit 2 */
+ "READ/WRITE DMA QUEUED" "\0" /* word 83 bit 1 */
+ "DOWNLOAD MICROCODE cmd" "\0" /* word 83 bit 0 */
+ /* -------------- */
+ "" "\0" /* word 84 bit 15: !valid bit */
+ "" "\0" /* word 84 bit 14: valid bit */
+ "" "\0" /* word 84 bit 13: reserved */
+ "" "\0" /* word 84 bit 12: reserved */
+ "" "\0" /* word 84 bit 11: reserved */
+ "" "\0" /* word 84 bit 10: reserved */
+ "" "\0" /* word 84 bit 9: reserved */
+ "" "\0" /* word 84 bit 8: reserved */
+ "" "\0" /* word 84 bit 7: reserved */
+ "" "\0" /* word 84 bit 6: reserved */
+ "General Purpose Logging feature set" "\0" /* word 84 bit 5 */
+ "" "\0" /* word 84 bit 4: reserved */
+ "Media Card Pass Through Command feature set " "\0"
+ "Media serial number " "\0" /* word 84 bit 2 */
+ "SMART self-test " "\0" /* word 84 bit 1 */
+ "SMART error logging " /* word 84 bit 0 */
+;
+
+static const char secu_str[] ALIGN1 =
+ "supported" "\0" /* word 128, bit 0 */
+ "enabled" "\0" /* word 128, bit 1 */
+ "locked" "\0" /* word 128, bit 2 */
+ "frozen" "\0" /* word 128, bit 3 */
+ "expired: security count" "\0" /* word 128, bit 4 */
+ "supported: enhanced erase" /* word 128, bit 5 */
+;
+
+// Parse 512 byte disk identification block and print much crap.
+static void identify(uint16_t *val) ATTRIBUTE_NORETURN;
+static void identify(uint16_t *val)
+{
+ uint16_t ii, jj, kk;
+ uint16_t like_std = 1, std = 0, min_std = 0xffff;
+ uint16_t dev = NO_DEV, eqpt = NO_DEV;
+ uint8_t have_mode = 0, err_dma = 0;
+ uint8_t chksum = 0;
+ uint32_t ll, mm, nn, oo;
+ uint64_t bbbig; /* (:) */
+ const char *strng;
+#if BB_BIG_ENDIAN
+ uint16_t buf[256];
+
+ // Adjust for endianness
+ swab(val, buf, sizeof(buf));
+ val = buf;
+#endif
+ /* check if we recognise the device type */
+ bb_putchar('\n');
+ if (!(val[GEN_CONFIG] & NOT_ATA)) {
+ dev = ATA_DEV;
+ printf("ATA device, with ");
+ } else if (val[GEN_CONFIG]==CFA_SUPPORT_VAL) {
+ dev = ATA_DEV;
+ like_std = 4;
+ printf("CompactFlash ATA device, with ");
+ } else if (!(val[GEN_CONFIG] & NOT_ATAPI)) {
+ dev = ATAPI_DEV;
+ eqpt = (val[GEN_CONFIG] & EQPT_TYPE) >> SHIFT_EQPT;
+ printf("ATAPI %s, with ", eqpt <= 0xf ? nth_string(pkt_str, eqpt) : "unknown");
+ like_std = 3;
+ } else
+ /* "Unknown device type:\n\tbits 15&14 of general configuration word 0 both set to 1.\n" */
+ bb_error_msg_and_die("unknown device type");
+
+ printf("%sremovable media\n", !(val[GEN_CONFIG] & MEDIA_REMOVABLE) ? "non-" : "");
+ /* Info from the specific configuration word says whether or not the
+ * ID command completed correctly. It is only defined, however in
+ * ATA/ATAPI-5 & 6; it is reserved (value theoretically 0) in prior
+ * standards. Since the values allowed for this word are extremely
+ * specific, it should be safe to check it now, even though we don't
+ * know yet what standard this device is using.
+ */
+ if ((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==STBY_ID_VAL)
+ || (val[CONFIG]==PWRD_NID_VAL) || (val[CONFIG]==PWRD_ID_VAL)
+ ) {
+ like_std = 5;
+ if ((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==STBY_ID_VAL))
+ printf("powers-up in standby; SET FEATURES subcmd spins-up.\n");
+ if (((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==PWRD_NID_VAL)) && (val[GEN_CONFIG] & INCOMPLETE))
+ printf("\n\tWARNING: ID response incomplete.\n\tFollowing data may be incorrect.\n\n");
+ }
+
+ /* output the model and serial numbers and the fw revision */
+ xprint_ascii(val, START_MODEL, "Model Number:", LENGTH_MODEL);
+ xprint_ascii(val, START_SERIAL, "Serial Number:", LENGTH_SERIAL);
+ xprint_ascii(val, START_FW_REV, "Firmware Revision:", LENGTH_FW_REV);
+ xprint_ascii(val, START_MEDIA, "Media Serial Num:", LENGTH_MEDIA);
+ xprint_ascii(val, START_MANUF, "Media Manufacturer:", LENGTH_MANUF);
+
+ /* major & minor standards version number (Note: these words were not
+ * defined until ATA-3 & the CDROM std uses different words.) */
+ printf("Standards:");
+ if (eqpt != CDROM) {
+ if (val[MINOR] && (val[MINOR] <= MINOR_MAX)) {
+ if (like_std < 3) like_std = 3;
+ std = actual_ver[val[MINOR]];
+ if (std) printf("\n\tUsed: %s ", nth_string(minor_str, val[MINOR]));
+
+ }
+ /* looks like when they up-issue the std, they obsolete one;
+ * thus, only the newest 4 issues need be supported. (That's
+ * what "kk" and "min_std" are all about.) */
+ if (val[MAJOR] && (val[MAJOR] != NOVAL_1)) {
+ printf("\n\tSupported: ");
+ jj = val[MAJOR] << 1;
+ kk = like_std >4 ? like_std-4: 0;
+ for (ii = 14; (ii >0)&&(ii>kk); ii--) {
+ if (jj & 0x8000) {
+ printf("%u ", ii);
+ if (like_std < ii) {
+ like_std = ii;
+ kk = like_std >4 ? like_std-4: 0;
+ }
+ if (min_std > ii) min_std = ii;
+ }
+ jj <<= 1;
+ }
+ if (like_std < 3) like_std = 3;
+ }
+ /* Figure out what standard the device is using if it hasn't told
+ * us. If we know the std, check if the device is using any of
+ * the words from the next level up. It happens.
+ */
+ if (like_std < std) like_std = std;
+
+ if (((std == 5) || (!std && (like_std < 6))) &&
+ ((((val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
+ (( val[CMDS_SUPP_1] & CMDS_W83) > 0x00ff)) ||
+ ((( val[CMDS_SUPP_2] & VALID) == VALID_VAL) &&
+ ( val[CMDS_SUPP_2] & CMDS_W84) ) )
+ ) {
+ like_std = 6;
+ } else if (((std == 4) || (!std && (like_std < 5))) &&
+ ((((val[INTEGRITY] & SIG) == SIG_VAL) && !chksum) ||
+ (( val[HWRST_RSLT] & VALID) == VALID_VAL) ||
+ ((( val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
+ (( val[CMDS_SUPP_1] & CMDS_W83) > 0x001f)) ) )
+ {
+ like_std = 5;
+ } else if (((std == 3) || (!std && (like_std < 4))) &&
+ ((((val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
+ ((( val[CMDS_SUPP_1] & CMDS_W83) > 0x0000) ||
+ (( val[CMDS_SUPP_0] & CMDS_W82) > 0x000f))) ||
+ (( val[CAPAB_1] & VALID) == VALID_VAL) ||
+ (( val[WHATS_VALID] & OK_W88) && val[ULTRA_DMA]) ||
+ (( val[RM_STAT] & RM_STAT_BITS) == RM_STAT_SUP) )
+ ) {
+ like_std = 4;
+ } else if (((std == 2) || (!std && (like_std < 3)))
+ && ((val[CMDS_SUPP_1] & VALID) == VALID_VAL)
+ ) {
+ like_std = 3;
+ } else if (((std == 1) || (!std && (like_std < 2))) &&
+ ((val[CAPAB_0] & (IORDY_SUP | IORDY_OFF)) ||
+ (val[WHATS_VALID] & OK_W64_70)) )
+ {
+ like_std = 2;
+ }
+
+ if (!std)
+ printf("\n\tLikely used: %u\n", like_std);
+ else if (like_std > std)
+ printf("& some of %u\n", like_std);
+ else
+ bb_putchar('\n');
+ } else {
+ /* TBD: do CDROM stuff more thoroughly. For now... */
+ kk = 0;
+ if (val[CDR_MINOR] == 9) {
+ kk = 1;
+ printf("\n\tUsed: ATAPI for CD-ROMs, SFF-8020i, r2.5");
+ }
+ if (val[CDR_MAJOR] && (val[CDR_MAJOR] !=NOVAL_1)) {
+ kk = 1;
+ printf("\n\tSupported: CD-ROM ATAPI");
+ jj = val[CDR_MAJOR] >> 1;
+ for (ii = 1; ii < 15; ii++) {
+ if (jj & 0x0001) printf("-%u ", ii);
+ jj >>= 1;
+ }
+ }
+ puts(kk ? "" : "\n\tLikely used CD-ROM ATAPI-1");
+ /* the cdrom stuff is more like ATA-2 than anything else, so: */
+ like_std = 2;
+ }
+
+ if (min_std == 0xffff)
+ min_std = like_std > 4 ? like_std - 3 : 1;
+
+ printf("Configuration:\n");
+ /* more info from the general configuration word */
+ if ((eqpt != CDROM) && (like_std == 1)) {
+ jj = val[GEN_CONFIG] >> 1;
+ for (ii = 1; ii < 15; ii++) {
+ if (jj & 0x0001)
+ printf("\t%s\n", nth_string(ata1_cfg_str, ii));
+ jj >>=1;
+ }
+ }
+ if (dev == ATAPI_DEV) {
+ if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_3MS_VAL)
+ strng = "3ms";
+ else if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_INTR_VAL)
+ strng = "<=10ms with INTRQ";
+ else if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_50US_VAL)
+ strng ="50us";
+ else
+ strng = "unknown";
+ printf("\tDRQ response: %s\n\tPacket size: ", strng); /* Data Request (DRQ) */
+
+ if ((val[GEN_CONFIG] & PKT_SIZE_SUPPORTED) == PKT_SIZE_12_VAL)
+ strng = "12 bytes";
+ else if ((val[GEN_CONFIG] & PKT_SIZE_SUPPORTED) == PKT_SIZE_16_VAL)
+ strng = "16 bytes";
+ else
+ strng = "unknown";
+ puts(strng);
+ } else {
+ /* addressing...CHS? See section 6.2 of ATA specs 4 or 5 */
+ ll = (uint32_t)val[LBA_SECTS_MSB] << 16 | val[LBA_SECTS_LSB];
+ mm = 0; bbbig = 0;
+ if ((ll > 0x00FBFC10) && (!val[LCYLS]))
+ printf("\tCHS addressing not supported\n");
+ else {
+ jj = val[WHATS_VALID] & OK_W54_58;
+ printf("\tLogical\t\tmax\tcurrent\n\tcylinders\t%u\t%u\n\theads\t\t%u\t%u\n\tsectors/track\t%u\t%u\n\t--\n",
+ val[LCYLS],jj?val[LCYLS_CUR]:0, val[LHEADS],jj?val[LHEADS_CUR]:0, val[LSECTS],jj?val[LSECTS_CUR]:0);
+
+ if ((min_std == 1) && (val[TRACK_BYTES] || val[SECT_BYTES]))
+ printf("\tbytes/track: %u\tbytes/sector: %u\n", val[TRACK_BYTES], val[SECT_BYTES]);
+
+ if (jj) {
+ mm = (uint32_t)val[CAPACITY_MSB] << 16 | val[CAPACITY_LSB];
+ if (like_std < 3) {
+ /* check Endian of capacity bytes */
+ nn = val[LCYLS_CUR] * val[LHEADS_CUR] * val[LSECTS_CUR];
+ oo = (uint32_t)val[CAPACITY_LSB] << 16 | val[CAPACITY_MSB];
+ if (abs(mm - nn) > abs(oo - nn))
+ mm = oo;
+ }
+ printf("\tCHS current addressable sectors:%11u\n", mm);
+ }
+ }
+ /* LBA addressing */
+ printf("\tLBA user addressable sectors:%11u\n", ll);
+ if (((val[CMDS_SUPP_1] & VALID) == VALID_VAL)
+ && (val[CMDS_SUPP_1] & SUPPORT_48_BIT)
+ ) {
+ bbbig = (uint64_t)val[LBA_64_MSB] << 48 |
+ (uint64_t)val[LBA_48_MSB] << 32 |
+ (uint64_t)val[LBA_MID] << 16 |
+ val[LBA_LSB];
+ printf("\tLBA48 user addressable sectors:%11"PRIu64"\n", bbbig);
+ }
+
+ if (!bbbig)
+ bbbig = (uint64_t)(ll>mm ? ll : mm); /* # 512 byte blocks */
+ printf("\tdevice size with M = 1024*1024: %11"PRIu64" MBytes\n", bbbig>>11);
+ bbbig = (bbbig << 9) / 1000000;
+ printf("\tdevice size with M = 1000*1000: %11"PRIu64" MBytes ", bbbig);
+
+ if (bbbig > 1000)
+ printf("(%"PRIu64" GB)\n", bbbig/1000);
+ else
+ bb_putchar('\n');
+ }
+
+ /* hw support of commands (capabilities) */
+ printf("Capabilities:\n\t");
+
+ if (dev == ATAPI_DEV) {
+ if (eqpt != CDROM && (val[CAPAB_0] & CMD_Q_SUP)) printf("Cmd queuing, ");
+ if (val[CAPAB_0] & OVLP_SUP) printf("Cmd overlap, ");
+ }
+ if (val[CAPAB_0] & LBA_SUP) printf("LBA, ");
+
+ if (like_std != 1) {
+ printf("IORDY%s(can%s be disabled)\n",
+ !(val[CAPAB_0] & IORDY_SUP) ? "(may be)" : "",
+ (val[CAPAB_0] & IORDY_OFF) ? "" :"not");
+ } else
+ printf("no IORDY\n");
+
+ if ((like_std == 1) && val[BUF_TYPE]) {
+ printf("\tBuffer type: %04x: %s%s\n", val[BUF_TYPE],
+ (val[BUF_TYPE] < 2) ? "single port, single-sector" : "dual port, multi-sector",
+ (val[BUF_TYPE] > 2) ? " with read caching ability" : "");
+ }
+
+ if ((min_std == 1) && (val[BUFFER__SIZE] && (val[BUFFER__SIZE] != NOVAL_1))) {
+ printf("\tBuffer size: %.1fkB\n", (float)val[BUFFER__SIZE]/2);
+ }
+ if ((min_std < 4) && (val[RW_LONG])) {
+ printf("\tbytes avail on r/w long: %u\n", val[RW_LONG]);
+ }
+ if ((eqpt != CDROM) && (like_std > 3)) {
+ printf("\tQueue depth: %u\n", (val[QUEUE_DEPTH] & DEPTH_BITS) + 1);
+ }
+
+ if (dev == ATA_DEV) {
+ if (like_std == 1)
+ printf("\tCan%s perform double-word IO\n", (!val[DWORD_IO]) ? "not" : "");
+ else {
+ printf("\tStandby timer values: spec'd by %s", (val[CAPAB_0] & STD_STBY) ? "Standard" : "Vendor");
+ if ((like_std > 3) && ((val[CAPAB_1] & VALID) == VALID_VAL))
+ printf(", %s device specific minimum\n", (val[CAPAB_1] & MIN_STANDBY_TIMER) ? "with" : "no");
+ else
+ bb_putchar('\n');
+ }
+ printf("\tR/W multiple sector transfer: ");
+ if ((like_std < 3) && !(val[SECTOR_XFER_MAX] & SECTOR_XFER))
+ printf("not supported\n");
+ else {
+ printf("Max = %u\tCurrent = ", val[SECTOR_XFER_MAX] & SECTOR_XFER);
+ if (val[SECTOR_XFER_CUR] & MULTIPLE_SETTING_VALID)
+ printf("%u\n", val[SECTOR_XFER_CUR] & SECTOR_XFER);
+ else
+ printf("?\n");
+ }
+ if ((like_std > 3) && (val[CMDS_SUPP_1] & 0x0008)) {
+ /* We print out elsewhere whether the APM feature is enabled or
+ not. If it's not enabled, let's not repeat the info; just print
+ nothing here. */
+ printf("\tAdvancedPM level: ");
+ if ((val[ADV_PWR] & 0xFF00) == 0x4000) {
+ uint8_t apm_level = val[ADV_PWR] & 0x00FF;
+ printf("%u (0x%x)\n", apm_level, apm_level);
+ }
+ else
+ printf("unknown setting (0x%04x)\n", val[ADV_PWR]);
+ }
+ if (like_std > 5 && val[ACOUSTIC]) {
+ printf("\tRecommended acoustic management value: %u, current value: %u\n",
+ (val[ACOUSTIC] >> 8) & 0x00ff, val[ACOUSTIC] & 0x00ff);
+ }
+ } else {
+ /* ATAPI */
+ if (eqpt != CDROM && (val[CAPAB_0] & SWRST_REQ))
+ printf("\tATA sw reset required\n");
+
+ if (val[PKT_REL] || val[SVC_NBSY]) {
+ printf("\tOverlap support:");
+ if (val[PKT_REL]) printf(" %uus to release bus.", val[PKT_REL]);
+ if (val[SVC_NBSY]) printf(" %uus to clear BSY after SERVICE cmd.", val[SVC_NBSY]);
+ bb_putchar('\n');
+ }
+ }
+
+ /* DMA stuff. Check that only one DMA mode is selected. */
+ printf("\tDMA: ");
+ if (!(val[CAPAB_0] & DMA_SUP))
+ printf("not supported\n");
+ else {
+ if (val[DMA_MODE] && !val[SINGLE_DMA] && !val[MULTI_DMA])
+ printf(" sdma%u\n", (val[DMA_MODE] & MODE) >> 8);
+ if (val[SINGLE_DMA]) {
+ jj = val[SINGLE_DMA];
+ kk = val[SINGLE_DMA] >> 8;
+ err_dma += mode_loop(jj, kk, 's', &have_mode);
+ }
+ if (val[MULTI_DMA]) {
+ jj = val[MULTI_DMA];
+ kk = val[MULTI_DMA] >> 8;
+ err_dma += mode_loop(jj, kk, 'm', &have_mode);
+ }
+ if ((val[WHATS_VALID] & OK_W88) && val[ULTRA_DMA]) {
+ jj = val[ULTRA_DMA];
+ kk = val[ULTRA_DMA] >> 8;
+ err_dma += mode_loop(jj, kk, 'u', &have_mode);
+ }
+ if (err_dma || !have_mode) printf("(?)");
+ bb_putchar('\n');
+
+ if ((dev == ATAPI_DEV) && (eqpt != CDROM) && (val[CAPAB_0] & DMA_IL_SUP))
+ printf("\t\tInterleaved DMA support\n");
+
+ if ((val[WHATS_VALID] & OK_W64_70)
+ && (val[DMA_TIME_MIN] || val[DMA_TIME_NORM])
+ ) {
+ printf("\t\tCycle time:");
+ if (val[DMA_TIME_MIN]) printf(" min=%uns", val[DMA_TIME_MIN]);
+ if (val[DMA_TIME_NORM]) printf(" recommended=%uns", val[DMA_TIME_NORM]);
+ bb_putchar('\n');
+ }
+ }
+
+ /* Programmed IO stuff */
+ printf("\tPIO: ");
+ /* If a drive supports mode n (e.g. 3), it also supports all modes less
+ * than n (e.g. 3, 2, 1 and 0). Print all the modes. */
+ if ((val[WHATS_VALID] & OK_W64_70) && (val[ADV_PIO_MODES] & PIO_SUP)) {
+ jj = ((val[ADV_PIO_MODES] & PIO_SUP) << 3) | 0x0007;
+ for (ii = 0; ii <= PIO_MODE_MAX; ii++) {
+ if (jj & 0x0001) printf("pio%d ", ii);
+ jj >>=1;
+ }
+ bb_putchar('\n');
+ } else if (((min_std < 5) || (eqpt == CDROM)) && (val[PIO_MODE] & MODE)) {
+ for (ii = 0; ii <= val[PIO_MODE]>>8; ii++)
+ printf("pio%d ", ii);
+ bb_putchar('\n');
+ } else
+ puts("unknown");
+
+ if (val[WHATS_VALID] & OK_W64_70) {
+ if (val[PIO_NO_FLOW] || val[PIO_FLOW]) {
+ printf("\t\tCycle time:");
+ if (val[PIO_NO_FLOW]) printf(" no flow control=%uns", val[PIO_NO_FLOW]);
+ if (val[PIO_FLOW]) printf(" IORDY flow control=%uns", val[PIO_FLOW]);
+ bb_putchar('\n');
+ }
+ }
+
+ if ((val[CMDS_SUPP_1] & VALID) == VALID_VAL) {
+ printf("Commands/features:\n\tEnabled\tSupported:\n");
+ jj = val[CMDS_SUPP_0];
+ kk = val[CMDS_EN_0];
+ for (ii = 0; ii < NUM_CMD_FEAT_STR; ii++) {
+ const char *feat_str = nth_string(cmd_feat_str, ii);
+ if ((jj & 0x8000) && (*feat_str != '\0')) {
+ printf("\t%s\t%s\n", (kk & 0x8000) ? " *" : "", feat_str);
+ }
+ jj <<= 1;
+ kk <<= 1;
+ if (ii % 16 == 15) {
+ jj = val[CMDS_SUPP_0+1+(ii/16)];
+ kk = val[CMDS_EN_0+1+(ii/16)];
+ }
+ if (ii == 31) {
+ if ((val[CMDS_SUPP_2] & VALID) != VALID_VAL)
+ ii +=16;
+ }
+ }
+ }
+ /* Removable Media Status Notification feature set */
+ if ((val[RM_STAT] & RM_STAT_BITS) == RM_STAT_SUP)
+ printf("\t%s supported\n", nth_string(cmd_feat_str, 27));
+
+ /* security */
+ if ((eqpt != CDROM) && (like_std > 3)
+ && (val[SECU_STATUS] || val[ERASE_TIME] || val[ENH_ERASE_TIME])
+ ) {
+ printf("Security:\n");
+ if (val[PSWD_CODE] && (val[PSWD_CODE] != NOVAL_1))
+ printf("\tMaster password revision code = %u\n", val[PSWD_CODE]);
+ jj = val[SECU_STATUS];
+ if (jj) {
+ for (ii = 0; ii < NUM_SECU_STR; ii++) {
+ printf("\t%s\t%s\n", (!(jj & 0x0001)) ? "not" : "", nth_string(secu_str, ii));
+ jj >>=1;
+ }
+ if (val[SECU_STATUS] & SECU_ENABLED) {
+ printf("\tSecurity level %s\n", (val[SECU_STATUS] & SECU_LEVEL) ? "maximum" : "high");
+ }
+ }
+ jj = val[ERASE_TIME] & ERASE_BITS;
+ kk = val[ENH_ERASE_TIME] & ERASE_BITS;
+ if (jj || kk) {
+ bb_putchar('\t');
+ if (jj) printf("%umin for %sSECURITY ERASE UNIT. ", jj==ERASE_BITS ? 508 : jj<<1, "");
+ if (kk) printf("%umin for %sSECURITY ERASE UNIT. ", kk==ERASE_BITS ? 508 : kk<<1, "ENHANCED ");
+ bb_putchar('\n');
+ }
+ }
+
+ /* reset result */
+ jj = val[HWRST_RSLT];
+ if ((jj & VALID) == VALID_VAL) {
+ oo = (jj & RST0);
+ if (!oo)
+ jj >>= 8;
+ if ((jj & DEV_DET) == JUMPER_VAL)
+ strng = " determined by the jumper";
+ else if ((jj & DEV_DET) == CSEL_VAL)
+ strng = " determined by CSEL";
+ else
+ strng = "";
+ printf("HW reset results:\n\tCBLID- %s Vih\n\tDevice num = %i%s\n",
+ (val[HWRST_RSLT] & CBLID) ? "above" : "below", !(oo), strng);
+ }
+
+ /* more stuff from std 5 */
+ if ((like_std > 4) && (eqpt != CDROM)) {
+ if (val[CFA_PWR_MODE] & VALID_W160) {
+ printf("CFA power mode 1:\n\t%s%s\n", (val[CFA_PWR_MODE] & PWR_MODE_OFF) ? "disabled" : "enabled",
+ (val[CFA_PWR_MODE] & PWR_MODE_REQ) ? " and required by some commands" : "");
+
+ if (val[CFA_PWR_MODE] & MAX_AMPS)
+ printf("\tMaximum current = %uma\n", val[CFA_PWR_MODE] & MAX_AMPS);
+ }
+ if ((val[INTEGRITY] & SIG) == SIG_VAL) {
+ printf("Checksum: %scorrect\n", chksum ? "in" : "");
+ }
+ }
+
+ exit(EXIT_SUCCESS);
+}
+#endif
+
+// Historically, if there was no HDIO_OBSOLETE_IDENTITY, then
+// then the HDIO_GET_IDENTITY only returned 142 bytes.
+// Otherwise, HDIO_OBSOLETE_IDENTITY returns 142 bytes,
+// and HDIO_GET_IDENTITY returns 512 bytes. But the latest
+// 2.5.xx kernels no longer define HDIO_OBSOLETE_IDENTITY
+// (which they should, but they should just return -EINVAL).
+//
+// So.. we must now assume that HDIO_GET_IDENTITY returns 512 bytes.
+// On a really old system, it will not, and we will be confused.
+// Too bad, really.
+
+#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
+static const char cfg_str[] ALIGN1 =
+ """\0" "HardSect""\0" "SoftSect""\0" "NotMFM""\0"
+ "HdSw>15uSec""\0" "SpinMotCtl""\0" "Fixed""\0" "Removeable""\0"
+ "DTR<=5Mbs""\0" "DTR>5Mbs""\0" "DTR>10Mbs""\0" "RotSpdTol>.5%""\0"
+ "dStbOff""\0" "TrkOff""\0" "FmtGapReq""\0" "nonMagnetic"
+;
+
+static const char BuffType[] ALIGN1 =
+ "unknown""\0" "1Sect""\0" "DualPort""\0" "DualPortCache"
+;
+
+static void dump_identity(const struct hd_driveid *id)
+{
+ int i;
+ const unsigned short *id_regs = (const void*) id;
+
+ printf("\n Model=%.40s, FwRev=%.8s, SerialNo=%.20s\n Config={",
+ id->model, id->fw_rev, id->serial_no);
+ for (i = 0; i <= 15; i++) {
+ if (id->config & (1<<i))
+ printf(" %s", nth_string(cfg_str, i));
+ }
+ printf(" }\n RawCHS=%u/%u/%u, TrkSize=%u, SectSize=%u, ECCbytes=%u\n"
+ " BuffType=(%u) %s, BuffSize=%ukB, MaxMultSect=%u",
+ id->cyls, id->heads, id->sectors, id->track_bytes,
+ id->sector_bytes, id->ecc_bytes,
+ id->buf_type, nth_string(BuffType, (id->buf_type > 3) ? 0 : id->buf_type),
+ id->buf_size/2, id->max_multsect);
+ if (id->max_multsect) {
+ printf(", MultSect=");
+ if (!(id->multsect_valid & 1))
+ printf("?%u?", id->multsect);
+ else if (id->multsect)
+ printf("%u", id->multsect);
+ else
+ printf("off");
+ }
+ bb_putchar('\n');
+
+ if (!(id->field_valid & 1))
+ printf(" (maybe):");
+
+ printf(" CurCHS=%u/%u/%u, CurSects=%lu, LBA=%s", id->cur_cyls, id->cur_heads,
+ id->cur_sectors,
+ (BB_BIG_ENDIAN) ?
+ (unsigned long)(id->cur_capacity0 << 16) | id->cur_capacity1 :
+ (unsigned long)(id->cur_capacity1 << 16) | id->cur_capacity0,
+ ((id->capability&2) == 0) ? "no" : "yes");
+
+ if (id->capability & 2)
+ printf(", LBAsects=%u", id->lba_capacity);
+
+ printf("\n IORDY=%s", (id->capability & 8) ? (id->capability & 4) ? "on/off" : "yes" : "no");
+
+ if (((id->capability & 8) || (id->field_valid & 2)) && (id->field_valid & 2))
+ printf(", tPIO={min:%u,w/IORDY:%u}", id->eide_pio, id->eide_pio_iordy);
+
+ if ((id->capability & 1) && (id->field_valid & 2))
+ printf(", tDMA={min:%u,rec:%u}", id->eide_dma_min, id->eide_dma_time);
+
+ printf("\n PIO modes: ");
+ if (id->tPIO <= 5) {
+ printf("pio0 ");
+ if (id->tPIO >= 1) printf("pio1 ");
+ if (id->tPIO >= 2) printf("pio2 ");
+ }
+ if (id->field_valid & 2) {
+ static const masks_labels_t pio_modes = {
+ .masks = { 1, 2, ~3 },
+ .labels = "pio3 \0""pio4 \0""pio? \0",
+ };
+ print_flags(&pio_modes, id->eide_pio_modes);
+ }
+ if (id->capability & 1) {
+ if (id->dma_1word | id->dma_mword) {
+ static const int dma_wmode_masks[] = { 0x100, 1, 0x200, 2, 0x400, 4, 0xf800, 0xf8 };
+ printf("\n DMA modes: ");
+ print_flags_separated(dma_wmode_masks,
+ "*\0""sdma0 \0""*\0""sdma1 \0""*\0""sdma2 \0""*\0""sdma? \0",
+ id->dma_1word, NULL);
+ print_flags_separated(dma_wmode_masks,
+ "*\0""mdma0\0""*\0""mdma1\0""*\0""mdma2\0""*\0""mdma?\0",
+ id->dma_mword, NULL);
+ }
+ }
+ if (((id->capability & 8) || (id->field_valid & 2)) && id->field_valid & 4) {
+ static const masks_labels_t ultra_modes1 = {
+ .masks = { 0x100, 0x001, 0x200, 0x002, 0x400, 0x004 },
+ .labels = "*\0""udma0 \0""*\0""udma1 \0""*\0""udma2 \0",
+ };
+
+ printf("\n UDMA modes: ");
+ print_flags(&ultra_modes1, id->dma_ultra);
+#ifdef __NEW_HD_DRIVE_ID
+ if (id->hw_config & 0x2000) {
+#else /* !__NEW_HD_DRIVE_ID */
+ if (id->word93 & 0x2000) {
+#endif /* __NEW_HD_DRIVE_ID */
+ static const masks_labels_t ultra_modes2 = {
+ .masks = { 0x0800, 0x0008, 0x1000, 0x0010,
+ 0x2000, 0x0020, 0x4000, 0x0040,
+ 0x8000, 0x0080 },
+ .labels = "*\0""udma3 \0""*\0""udma4 \0"
+ "*\0""udma5 \0""*\0""udma6 \0"
+ "*\0""udma7 \0"
+ };
+ print_flags(&ultra_modes2, id->dma_ultra);
+ }
+ }
+ printf("\n AdvancedPM=%s", (!(id_regs[83] & 8)) ? "no" : "yes");
+ if (id_regs[83] & 8) {
+ if (!(id_regs[86] & 8))
+ printf(": disabled (255)");
+ else if ((id_regs[91] & 0xFF00) != 0x4000)
+ printf(": unknown setting");
+ else
+ printf(": mode=0x%02X (%u)", id_regs[91] & 0xFF, id_regs[91] & 0xFF);
+ }
+ if (id_regs[82] & 0x20)
+ printf(" WriteCache=%s", (id_regs[85] & 0x20) ? "enabled" : "disabled");
+#ifdef __NEW_HD_DRIVE_ID
+ if ((id->minor_rev_num && id->minor_rev_num <= 31)
+ || (id->major_rev_num && id->minor_rev_num <= 31)
+ ) {
+ printf("\n Drive conforms to: %s: ", (id->minor_rev_num <= 31) ? nth_string(minor_str, id->minor_rev_num) : "unknown");
+ if (id->major_rev_num != 0x0000 && /* NOVAL_0 */
+ id->major_rev_num != 0xFFFF) { /* NOVAL_1 */
+ for (i = 0; i <= 15; i++) {
+ if (id->major_rev_num & (1<<i))
+ printf(" ATA/ATAPI-%u", i);
+ }
+ }
+ }
+#endif /* __NEW_HD_DRIVE_ID */
+ printf("\n\n * current active mode\n\n");
+}
+#endif
+
+static void flush_buffer_cache(/*int fd*/ void)
+{
+ fsync(fd); /* flush buffers */
+ ioctl_or_warn(fd, BLKFLSBUF, NULL); /* do it again, big time */
+#ifdef HDIO_DRIVE_CMD
+ sleep(1);
+ if (ioctl(fd, HDIO_DRIVE_CMD, NULL) && errno != EINVAL) { /* await completion */
+ if (ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn */
+ bb_perror_msg("HDIO_DRIVE_CMD");
+ else
+ bb_perror_msg("ioctl %#x failed", HDIO_DRIVE_CMD);
+ }
+#endif
+}
+
+static void seek_to_zero(/*int fd*/ void)
+{
+ xlseek(fd, (off_t) 0, SEEK_SET);
+}
+
+static void read_big_block(/*int fd,*/ char *buf)
+{
+ int i;
+
+ xread(fd, buf, TIMING_BUF_BYTES);
+ /* access all sectors of buf to ensure the read fully completed */
+ for (i = 0; i < TIMING_BUF_BYTES; i += 512)
+ buf[i] &= 1;
+}
+
+static unsigned dev_size_mb(/*int fd*/ void)
+{
+ union {
+ unsigned long long blksize64;
+ unsigned blksize32;
+ } u;
+
+ if (0 == ioctl(fd, BLKGETSIZE64, &u.blksize64)) { // bytes
+ u.blksize64 /= (1024 * 1024);
+ } else {
+ xioctl(fd, BLKGETSIZE, &u.blksize32); // sectors
+ u.blksize64 = u.blksize32 / (2 * 1024);
+ }
+ if (u.blksize64 > UINT_MAX)
+ return UINT_MAX;
+ return u.blksize64;
+}
+
+static void print_timing(unsigned m, unsigned elapsed_us)
+{
+ unsigned sec = elapsed_us / 1000000;
+ unsigned hs = (elapsed_us % 1000000) / 10000;
+
+ printf("%5u MB in %u.%02u seconds = %u kB/s\n",
+ m, sec, hs,
+ /* "| 1" prevents div-by-0 */
+ (unsigned) ((unsigned long long)m * (1024 * 1000000) / (elapsed_us | 1))
+ // ~= (m * 1024) / (elapsed_us / 1000000)
+ // = kb / elapsed_sec
+ );
+}
+
+static void do_time(int cache /*,int fd*/)
+/* cache=1: time cache: repeatedly read N MB at offset 0
+ * cache=0: time device: linear read, starting at offset 0
+ */
+{
+ unsigned max_iterations, iterations;
+ unsigned start; /* doesn't need to be long long */
+ unsigned elapsed, elapsed2;
+ unsigned total_MB;
+ char *buf = xmalloc(TIMING_BUF_BYTES);
+
+ if (mlock(buf, TIMING_BUF_BYTES))
+ bb_perror_msg_and_die("mlock");
+
+ /* Clear out the device request queues & give them time to complete.
+ * NB: *small* delay. User is expected to have a clue and to not run
+ * heavy io in parallel with measurements. */
+ sync();
+ sleep(1);
+ if (cache) { /* Time cache */
+ seek_to_zero();
+ read_big_block(buf);
+ printf("Timing buffer-cache reads: ");
+ } else { /* Time device */
+ printf("Timing buffered disk reads:");
+ }
+ fflush(stdout);
+
+ /* Now do the timing */
+ iterations = 0;
+ /* Max time to run (small for cache, avoids getting
+ * huge total_MB which can overlow unsigned type) */
+ elapsed2 = 510000; /* cache */
+ max_iterations = UINT_MAX;
+ if (!cache) {
+ elapsed2 = 3000000; /* not cache */
+ /* Don't want to read past the end! */
+ max_iterations = dev_size_mb() / TIMING_BUF_MB;
+ }
+ start = monotonic_us();
+ do {
+ if (cache)
+ seek_to_zero();
+ read_big_block(buf);
+ elapsed = (unsigned)monotonic_us() - start;
+ ++iterations;
+ } while (elapsed < elapsed2 && iterations < max_iterations);
+ total_MB = iterations * TIMING_BUF_MB;
+ //printf(" elapsed:%u iterations:%u ", elapsed, iterations);
+ if (cache) {
+ /* Cache: remove lseek() and monotonic_us() overheads
+ * from elapsed */
+ start = monotonic_us();
+ do {
+ seek_to_zero();
+ elapsed2 = (unsigned)monotonic_us() - start;
+ } while (--iterations);
+ //printf(" elapsed2:%u ", elapsed2);
+ elapsed -= elapsed2;
+ total_MB *= 2; // BUFCACHE_FACTOR (why?)
+ flush_buffer_cache();
+ }
+ print_timing(total_MB, elapsed);
+ munlock(buf, TIMING_BUF_BYTES);
+ free(buf);
+}
+
+#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
+static void bus_state_value(unsigned value)
+{
+ if (value == BUSSTATE_ON)
+ on_off(1);
+ else if (value == BUSSTATE_OFF)
+ on_off(0);
+ else if (value == BUSSTATE_TRISTATE)
+ printf(" (tristate)\n");
+ else
+ printf(" (unknown: %d)\n", value);
+}
+#endif
+
+#ifdef HDIO_DRIVE_CMD
+static void interpret_standby(uint8_t standby)
+{
+ printf(" (");
+ if (standby == 0) {
+ printf("off");
+ } else if (standby <= 240 || standby == 252 || standby == 255) {
+ /* standby is in 5 sec units */
+ printf("%u minutes %u seconds", standby / 12, (standby*5) % 60);
+ } else if (standby <= 251) {
+ unsigned t = (standby - 240); /* t is in 30 min units */;
+ printf("%u.%c hours", t / 2, (t & 1) ? '0' : '5');
+ }
+ if (standby == 253)
+ printf("vendor-specific");
+ if (standby == 254)
+ printf("reserved");
+ printf(")\n");
+}
+
+static const uint8_t xfermode_val[] ALIGN1 = {
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 64, 65, 66, 67, 68, 69, 70, 71
+};
+/* NB: we save size by _not_ storing terninating NUL! */
+static const char xfermode_name[][5] ALIGN1 = {
+ "pio0", "pio1", "pio2", "pio3", "pio4", "pio5", "pio6", "pio7",
+ "sdma0","sdma1","sdma2","sdma3","sdma4","sdma5","sdma6","sdma7",
+ "mdma0","mdma1","mdma2","mdma3","mdma4","mdma5","mdma6","mdma7",
+ "udma0","udma1","udma2","udma3","udma4","udma5","udma6","udma7"
+};
+
+static int translate_xfermode(const char *name)
+{
+ int val;
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(xfermode_val); i++) {
+ if (!strncmp(name, xfermode_name[i], 5))
+ if (strlen(name) <= 5)
+ return xfermode_val[i];
+ }
+ /* Negative numbers are invalid and are caught later */
+ val = bb_strtoi(name, NULL, 10);
+ if (!errno)
+ return val;
+ return -1;
+}
+
+static void interpret_xfermode(unsigned xfermode)
+{
+ printf(" (");
+ if (xfermode == 0)
+ printf("default PIO mode");
+ else if (xfermode == 1)
+ printf("default PIO mode, disable IORDY");
+ else if (xfermode >= 8 && xfermode <= 15)
+ printf("PIO flow control mode%u", xfermode - 8);
+ else if (xfermode >= 16 && xfermode <= 23)
+ printf("singleword DMA mode%u", xfermode - 16);
+ else if (xfermode >= 32 && xfermode <= 39)
+ printf("multiword DMA mode%u", xfermode - 32);
+ else if (xfermode >= 64 && xfermode <= 71)
+ printf("UltraDMA mode%u", xfermode - 64);
+ else
+ printf("unknown");
+ printf(")\n");
+}
+#endif /* HDIO_DRIVE_CMD */
+
+static void print_flag(int flag, const char *s, unsigned long value)
+{
+ if (flag)
+ printf(" setting %s to %ld\n", s, value);
+}
+
+static void process_dev(char *devname)
+{
+ /*int fd;*/
+ long parm, multcount;
+#ifndef HDIO_DRIVE_CMD
+ int force_operation = 0;
+#endif
+ /* Please restore args[n] to these values after each ioctl
+ except for args[2] */
+ unsigned char args[4] = { WIN_SETFEATURES, 0, 0, 0 };
+ const char *fmt = " %s\t= %2ld";
+
+ /*fd = xopen(devname, O_RDONLY | O_NONBLOCK);*/
+ xmove_fd(xopen(devname, O_RDONLY | O_NONBLOCK), fd);
+ printf("\n%s:\n", devname);
+
+ if (set_readahead) {
+ print_flag(get_readahead, "fs readahead", Xreadahead);
+ ioctl_or_warn(fd, BLKRASET, (int *)Xreadahead);
+ }
+#if ENABLE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF
+ if (unregister_hwif) {
+ printf(" attempting to unregister hwif#%lu\n", hwif);
+ ioctl_or_warn(fd, HDIO_UNREGISTER_HWIF, (int *)(unsigned long)hwif);
+ }
+#endif
+#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
+ if (scan_hwif) {
+ printf(" attempting to scan hwif (0x%lx, 0x%lx, %lu)\n", hwif_data, hwif_ctrl, hwif_irq);
+ args[0] = hwif_data;
+ args[1] = hwif_ctrl;
+ args[2] = hwif_irq;
+ ioctl_or_warn(fd, HDIO_SCAN_HWIF, args);
+ args[0] = WIN_SETFEATURES;
+ args[1] = 0;
+ }
+#endif
+ if (set_piomode) {
+ if (noisy_piomode) {
+ printf(" attempting to ");
+ if (piomode == 255)
+ printf("auto-tune PIO mode\n");
+ else if (piomode < 100)
+ printf("set PIO mode to %d\n", piomode);
+ else if (piomode < 200)
+ printf("set MDMA mode to %d\n", (piomode-100));
+ else
+ printf("set UDMA mode to %d\n", (piomode-200));
+ }
+ ioctl_or_warn(fd, HDIO_SET_PIO_MODE, (int *)(unsigned long)piomode);
+ }
+ if (set_io32bit) {
+ print_flag(get_io32bit, "32-bit IO_support flag", io32bit);
+ ioctl_or_warn(fd, HDIO_SET_32BIT, (int *)io32bit);
+ }
+ if (set_mult) {
+ print_flag(get_mult, "multcount", mult);
+#ifdef HDIO_DRIVE_CMD
+ ioctl_or_warn(fd, HDIO_SET_MULTCOUNT, (void *)mult);
+#else
+ force_operation |= (!ioctl_or_warn(fd, HDIO_SET_MULTCOUNT, (void *)mult));
+#endif
+ }
+ if (set_readonly) {
+ print_flag_on_off(get_readonly, "readonly", readonly);
+ ioctl_or_warn(fd, BLKROSET, &readonly);
+ }
+ if (set_unmask) {
+ print_flag_on_off(get_unmask, "unmaskirq", unmask);
+ ioctl_or_warn(fd, HDIO_SET_UNMASKINTR, (int *)unmask);
+ }
+#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
+ if (set_dma) {
+ print_flag_on_off(get_dma, "using_dma", dma);
+ ioctl_or_warn(fd, HDIO_SET_DMA, (int *)dma);
+ }
+#endif /* FEATURE_HDPARM_HDIO_GETSET_DMA */
+#ifdef HDIO_SET_QDMA
+ if (set_dma_q) {
+ print_flag_on_off(get_dma_q, "DMA queue_depth", dma_q);
+ ioctl_or_warn(fd, HDIO_SET_QDMA, (int *)dma_q);
+ }
+#endif
+ if (set_nowerr) {
+ print_flag_on_off(get_nowerr, "nowerr", nowerr);
+ ioctl_or_warn(fd, HDIO_SET_NOWERR, (int *)nowerr);
+ }
+ if (set_keep) {
+ print_flag_on_off(get_keep, "keep_settings", keep);
+ ioctl_or_warn(fd, HDIO_SET_KEEPSETTINGS, (int *)keep);
+ }
+#ifdef HDIO_DRIVE_CMD
+ if (set_doorlock) {
+ args[0] = doorlock ? WIN_DOORLOCK : WIN_DOORUNLOCK;
+ args[2] = 0;
+ print_flag_on_off(get_doorlock, "drive doorlock", doorlock);
+ ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
+ args[0] = WIN_SETFEATURES;
+ }
+ if (set_dkeep) {
+ /* lock/unlock the drive's "feature" settings */
+ print_flag_on_off(get_dkeep, "drive keep features", dkeep);
+ args[2] = dkeep ? 0x66 : 0xcc;
+ ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
+ }
+ if (set_defects) {
+ args[2] = defects ? 0x04 : 0x84;
+ print_flag(get_defects, "drive defect-mgmt", defects);
+ ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
+ }
+ if (set_prefetch) {
+ args[1] = prefetch;
+ args[2] = 0xab;
+ print_flag(get_prefetch, "drive prefetch", prefetch);
+ ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
+ args[1] = 0;
+ }
+ if (set_xfermode) {
+ args[1] = xfermode_requested;
+ args[2] = 3;
+ if (get_xfermode) {
+ print_flag(1, "xfermode", xfermode_requested);
+ interpret_xfermode(xfermode_requested);
+ }
+ ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
+ args[1] = 0;
+ }
+ if (set_lookahead) {
+ args[2] = lookahead ? 0xaa : 0x55;
+ print_flag_on_off(get_lookahead, "drive read-lookahead", lookahead);
+ ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
+ }
+ if (set_apmmode) {
+ args[2] = (apmmode == 255) ? 0x85 /* disable */ : 0x05 /* set */; /* feature register */
+ args[1] = apmmode; /* sector count register 1-255 */
+ if (get_apmmode)
+ printf(" setting APM level to %s 0x%02lX (%ld)\n", (apmmode == 255) ? "disabled" : "", apmmode, apmmode);
+ ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
+ args[1] = 0;
+ }
+ if (set_wcache) {
+#ifdef DO_FLUSHCACHE
+#ifndef WIN_FLUSHCACHE
+#define WIN_FLUSHCACHE 0xe7
+#endif
+#endif /* DO_FLUSHCACHE */
+ args[2] = wcache ? 0x02 : 0x82;
+ print_flag_on_off(get_wcache, "drive write-caching", wcache);
+#ifdef DO_FLUSHCACHE
+ if (!wcache)
+ ioctl_or_warn(fd, HDIO_DRIVE_CMD, &flushcache);
+#endif /* DO_FLUSHCACHE */
+ ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
+#ifdef DO_FLUSHCACHE
+ if (!wcache)
+ ioctl_or_warn(fd, HDIO_DRIVE_CMD, &flushcache);
+#endif /* DO_FLUSHCACHE */
+ }
+
+ /* In code below, we do not preserve args[0], but the rest
+ is preserved, including args[2] */
+ args[2] = 0;
+
+ if (set_standbynow) {
+#ifndef WIN_STANDBYNOW1
+#define WIN_STANDBYNOW1 0xE0
+#endif
+#ifndef WIN_STANDBYNOW2
+#define WIN_STANDBYNOW2 0x94
+#endif
+ if (get_standbynow) printf(" issuing standby command\n");
+ args[0] = WIN_STANDBYNOW1;
+ ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_STANDBYNOW2);
+ }
+ if (set_sleepnow) {
+#ifndef WIN_SLEEPNOW1
+#define WIN_SLEEPNOW1 0xE6
+#endif
+#ifndef WIN_SLEEPNOW2
+#define WIN_SLEEPNOW2 0x99
+#endif
+ if (get_sleepnow) printf(" issuing sleep command\n");
+ args[0] = WIN_SLEEPNOW1;
+ ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_SLEEPNOW2);
+ }
+ if (set_seagate) {
+ args[0] = 0xfb;
+ if (get_seagate) printf(" disabling Seagate auto powersaving mode\n");
+ ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
+ }
+ if (set_standby) {
+ args[0] = WIN_SETIDLE1;
+ args[1] = standby_requested;
+ if (get_standby) {
+ print_flag(1, "standby", standby_requested);
+ interpret_standby(standby_requested);
+ }
+ ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
+ args[1] = 0;
+ }
+#else /* HDIO_DRIVE_CMD */
+ if (force_operation) {
+ char buf[512];
+ flush_buffer_cache();
+ if (-1 == read(fd, buf, sizeof(buf)))
+ bb_perror_msg("read(%d bytes) failed (rc=-1)", sizeof(buf));
+ }
+#endif /* HDIO_DRIVE_CMD */
+
+ if (get_mult || get_identity) {
+ multcount = -1;
+ if (ioctl(fd, HDIO_GET_MULTCOUNT, &multcount)) {
+ if (get_mult && ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn. */
+ bb_perror_msg("HDIO_GET_MULTCOUNT");
+ else
+ bb_perror_msg("ioctl %#x failed", HDIO_GET_MULTCOUNT);
+ } else if (get_mult) {
+ printf(fmt, "multcount", multcount);
+ on_off(multcount != 0);
+ }
+ }
+ if (get_io32bit) {
+ if (!ioctl_or_warn(fd, HDIO_GET_32BIT, &parm)) {
+ printf(" IO_support\t=%3ld (", parm);
+ if (parm == 0)
+ printf("default 16-bit)\n");
+ else if (parm == 2)
+ printf("16-bit)\n");
+ else if (parm == 1)
+ printf("32-bit)\n");
+ else if (parm == 3)
+ printf("32-bit w/sync)\n");
+ else if (parm == 8)
+ printf("Request-Queue-Bypass)\n");
+ else
+ printf("\?\?\?)\n");
+ }
+ }
+ if (get_unmask) {
+ if(!ioctl_or_warn(fd, HDIO_GET_UNMASKINTR, &parm))
+ print_value_on_off("unmaskirq", parm);
+ }
+
+
+#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
+ if (get_dma) {
+ if (!ioctl_or_warn(fd, HDIO_GET_DMA, &parm)) {
+ printf(fmt, "using_dma", parm);
+ if (parm == 8)
+ printf(" (DMA-Assisted-PIO)\n");
+ else
+ on_off(parm != 0);
+ }
+ }
+#endif
+#ifdef HDIO_GET_QDMA
+ if (get_dma_q) {
+ if(!ioctl_or_warn(fd, HDIO_GET_QDMA, &parm))
+ print_value_on_off("queue_depth", parm);
+ }
+#endif
+ if (get_keep) {
+ if(!ioctl_or_warn(fd, HDIO_GET_KEEPSETTINGS, &parm))
+ print_value_on_off("keepsettings", parm);
+ }
+
+ if (get_nowerr) {
+ if(!ioctl_or_warn(fd, HDIO_GET_NOWERR, &parm))
+ print_value_on_off("nowerr", parm);
+ }
+ if (get_readonly) {
+ if(!ioctl_or_warn(fd, BLKROGET, &parm))
+ print_value_on_off("readonly", parm);
+ }
+ if (get_readahead) {
+ if(!ioctl_or_warn(fd, BLKRAGET, &parm))
+ print_value_on_off("readahead", parm);
+ }
+ if (get_geom) {
+ if (!ioctl_or_warn(fd, BLKGETSIZE, &parm)) {
+ struct hd_geometry g;
+
+ if (!ioctl_or_warn(fd, HDIO_GETGEO, &g))
+ printf(" geometry\t= %u/%u/%u, sectors = %ld, start = %ld\n",
+ g.cylinders, g.heads, g.sectors, parm, g.start);
+ }
+ }
+#ifdef HDIO_DRIVE_CMD
+ if (get_powermode) {
+#ifndef WIN_CHECKPOWERMODE1
+#define WIN_CHECKPOWERMODE1 0xE5
+#endif
+#ifndef WIN_CHECKPOWERMODE2
+#define WIN_CHECKPOWERMODE2 0x98
+#endif
+ const char *state;
+
+ args[0] = WIN_CHECKPOWERMODE1;
+ if (ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_CHECKPOWERMODE2)) {
+ if (errno != EIO || args[0] != 0 || args[1] != 0)
+ state = "unknown";
+ else
+ state = "sleeping";
+ } else
+ state = (args[2] == 255) ? "active/idle" : "standby";
+ args[1] = args[2] = 0;
+
+ printf(" drive state is: %s\n", state);
+ }
+#endif
+#if ENABLE_FEATURE_HDPARM_HDIO_DRIVE_RESET
+ if (perform_reset) {
+ ioctl_or_warn(fd, HDIO_DRIVE_RESET, NULL);
+ }
+#endif /* FEATURE_HDPARM_HDIO_DRIVE_RESET */
+#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
+ if (perform_tristate) {
+ args[0] = 0;
+ args[1] = tristate;
+ ioctl_or_warn(fd, HDIO_TRISTATE_HWIF, &args);
+ }
+#endif /* FEATURE_HDPARM_HDIO_TRISTATE_HWIF */
+#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
+ if (get_identity) {
+ struct hd_driveid id;
+
+ if (!ioctl(fd, HDIO_GET_IDENTITY, &id)) {
+ if (multcount != -1) {
+ id.multsect = multcount;
+ id.multsect_valid |= 1;
+ } else
+ id.multsect_valid &= ~1;
+ dump_identity(&id);
+ } else if (errno == -ENOMSG)
+ printf(" no identification info available\n");
+ else if (ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn */
+ bb_perror_msg("HDIO_GET_IDENTITY");
+ else
+ bb_perror_msg("ioctl %#x failed", HDIO_GET_IDENTITY);
+ }
+
+ if (get_IDentity) {
+ unsigned char args1[4+512]; /* = { ... } will eat 0.5k of rodata! */
+
+ memset(args1, 0, sizeof(args1));
+ args1[0] = WIN_IDENTIFY;
+ args1[3] = 1;
+ if (!ioctl_alt_or_warn(HDIO_DRIVE_CMD, args1, WIN_PIDENTIFY))
+ identify((void *)(args1 + 4));
+ }
+#endif
+#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
+ if (set_busstate) {
+ if (get_busstate) {
+ print_flag(1, "bus state", busstate);
+ bus_state_value(busstate);
+ }
+ ioctl_or_warn(fd, HDIO_SET_BUSSTATE, (int *)(unsigned long)busstate);
+ }
+ if (get_busstate) {
+ if (!ioctl_or_warn(fd, HDIO_GET_BUSSTATE, &parm)) {
+ printf(fmt, "bus state", parm);
+ bus_state_value(parm);
+ }
+ }
+#endif
+ if (reread_partn)
+ ioctl_or_warn(fd, BLKRRPART, NULL);
+
+ if (do_ctimings)
+ do_time(1 /*,fd*/); /* time cache */
+ if (do_timings)
+ do_time(0 /*,fd*/); /* time device */
+ if (do_flush)
+ flush_buffer_cache();
+ close(fd);
+}
+
+#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
+static int fromhex(unsigned char c)
+{
+ if (isdigit(c))
+ return (c - '0');
+ if (c >= 'a' && c <= 'f')
+ return (c - ('a' - 10));
+ bb_error_msg_and_die("bad char: '%c' 0x%02x", c, c);
+}
+
+static void identify_from_stdin(void) ATTRIBUTE_NORETURN;
+static void identify_from_stdin(void)
+{
+ uint16_t sbuf[256];
+ unsigned char buf[1280];
+ unsigned char *b = (unsigned char *)buf;
+ int i;
+
+ xread(STDIN_FILENO, buf, 1280);
+
+ // Convert the newline-separated hex data into an identify block.
+
+ for (i = 0; i < 256; i++) {
+ int j;
+ for (j = 0; j < 4; j++)
+ sbuf[i] = (sbuf[i] << 4) + fromhex(*(b++));
+ }
+
+ // Parse the data.
+
+ identify(sbuf);
+}
+#else
+void identify_from_stdin(void);
+#endif
+
+/* busybox specific stuff */
+static void parse_opts(smallint *get, smallint *set, unsigned long *value, int min, int max)
+{
+ if (get) {
+ *get = 1;
+ }
+ if (optarg) {
+ *set = 1;
+ *value = xatol_range(optarg, min, max);
+ }
+}
+
+static void parse_xfermode(int flag, smallint *get, smallint *set, int *value)
+{
+ if (flag) {
+ *get = 1;
+ if (optarg) {
+ *value = translate_xfermode(optarg);
+ *set = (*value > -1);
+ }
+ }
+}
+
+/*------- getopt short options --------*/
+static const char hdparm_options[] ALIGN1 =
+ "gfu::n::p:r::m::c::k::a::B:tT"
+ USE_FEATURE_HDPARM_GET_IDENTITY("iI")
+ USE_FEATURE_HDPARM_HDIO_GETSET_DMA("d::")
+#ifdef HDIO_DRIVE_CMD
+ "S:D:P:X:K:A:L:W:CyYzZ"
+#endif
+ USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF("U:")
+#ifdef HDIO_GET_QDMA
+#ifdef HDIO_SET_QDMA
+ "Q:"
+#else
+ "Q"
+#endif
+#endif
+ USE_FEATURE_HDPARM_HDIO_DRIVE_RESET("w")
+ USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF("x::b:")
+ USE_FEATURE_HDPARM_HDIO_SCAN_HWIF("R:");
+/*-------------------------------------*/
+
+/* our main() routine: */
+int hdparm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int hdparm_main(int argc, char **argv)
+{
+ int c;
+ int flagcount = 0;
+
+ while ((c = getopt(argc, argv, hdparm_options)) >= 0) {
+ flagcount++;
+ USE_FEATURE_HDPARM_GET_IDENTITY(get_IDentity |= (c == 'I'));
+ USE_FEATURE_HDPARM_GET_IDENTITY(get_identity |= (c == 'i'));
+ get_geom |= (c == 'g');
+ do_flush |= (c == 'f');
+ if (c == 'u') parse_opts(&get_unmask, &set_unmask, &unmask, 0, 1);
+ USE_FEATURE_HDPARM_HDIO_GETSET_DMA(if (c == 'd') parse_opts(&get_dma, &set_dma, &dma, 0, 9));
+ if (c == 'n') parse_opts(&get_nowerr, &set_nowerr, &nowerr, 0, 1);
+ parse_xfermode((c == 'p'), &noisy_piomode, &set_piomode, &piomode);
+ if (c == 'r') parse_opts(&get_readonly, &set_readonly, &readonly, 0, 1);
+ if (c == 'm') parse_opts(&get_mult, &set_mult, &mult, 0, INT_MAX /*32*/);
+ if (c == 'c') parse_opts(&get_io32bit, &set_io32bit, &io32bit, 0, INT_MAX /*8*/);
+ if (c == 'k') parse_opts(&get_keep, &set_keep, &keep, 0, 1);
+ if (c == 'a') parse_opts(&get_readahead, &set_readahead, &Xreadahead, 0, INT_MAX);
+ if (c == 'B') parse_opts(&get_apmmode, &set_apmmode, &apmmode, 1, 255);
+ do_flush |= do_timings |= (c == 't');
+ do_flush |= do_ctimings |= (c == 'T');
+#ifdef HDIO_DRIVE_CMD
+ if (c == 'S') parse_opts(&get_standby, &set_standby, &standby_requested, 0, 255);
+ if (c == 'D') parse_opts(&get_defects, &set_defects, &defects, 0, INT_MAX);
+ if (c == 'P') parse_opts(&get_prefetch, &set_prefetch, &prefetch, 0, INT_MAX);
+ parse_xfermode((c == 'X'), &get_xfermode, &set_xfermode, &xfermode_requested);
+ if (c == 'K') parse_opts(&get_dkeep, &set_dkeep, &prefetch, 0, 1);
+ if (c == 'A') parse_opts(&get_lookahead, &set_lookahead, &lookahead, 0, 1);
+ if (c == 'L') parse_opts(&get_doorlock, &set_doorlock, &doorlock, 0, 1);
+ if (c == 'W') parse_opts(&get_wcache, &set_wcache, &wcache, 0, 1);
+ get_powermode |= (c == 'C');
+ get_standbynow = set_standbynow |= (c == 'y');
+ get_sleepnow = set_sleepnow |= (c == 'Y');
+ reread_partn |= (c == 'z');
+ get_seagate = set_seagate |= (c == 'Z');
+#endif
+ USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(if (c == 'U') parse_opts(NULL, &unregister_hwif, &hwif, 0, INT_MAX));
+#ifdef HDIO_GET_QDMA
+ if (c == 'Q') {
+#ifdef HDIO_SET_QDMA
+ parse_opts(&get_dma_q, &set_dma_q, &dma_q, 0, INT_MAX);
+#else
+ parse_opts(&get_dma_q, NULL, NULL, 0, 0);
+#endif
+ }
+#endif
+ USE_FEATURE_HDPARM_HDIO_DRIVE_RESET(perform_reset = (c == 'r'));
+ USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'x') parse_opts(NULL, &perform_tristate, &tristate, 0, 1));
+ USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'b') parse_opts(&get_busstate, &set_busstate, &busstate, 0, 2));
+#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
+ if (c == 'R') {
+ parse_opts(NULL, &scan_hwif, &hwif_data, 0, INT_MAX);
+ hwif_ctrl = xatoi_u((argv[optind]) ? argv[optind] : "");
+ hwif_irq = xatoi_u((argv[optind+1]) ? argv[optind+1] : "");
+ /* Move past the 2 additional arguments */
+ argv += 2;
+ argc -= 2;
+ }
+#endif
+ }
+ /* When no flags are given (flagcount = 0), -acdgkmnru is assumed. */
+ if (!flagcount) {
+ get_mult = get_io32bit = get_unmask = get_keep = get_readonly = get_readahead = get_geom = 1;
+ USE_FEATURE_HDPARM_HDIO_GETSET_DMA(get_dma = 1);
+ }
+ argv += optind;
+
+ if (!*argv) {
+ if (ENABLE_FEATURE_HDPARM_GET_IDENTITY && !isatty(STDIN_FILENO))
+ identify_from_stdin(); /* EXIT */
+ bb_show_usage();
+ }
+
+ do {
+ process_dev(*argv++);
+ } while (*argv);
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/inotifyd.c b/cleopatre/busybox-1.11.1-spc300/miscutils/inotifyd.c
new file mode 100644
index 0000000000..0d7ad2a9d5
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/inotifyd.c
@@ -0,0 +1,152 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * simple inotify daemon
+ * reports filesystem changes via userspace agent
+ *
+ * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+/*
+ * Use as follows:
+ * # inotifyd /user/space/agent dir/or/file/being/watched[:mask] ...
+ *
+ * When a filesystem event matching the specified mask is occured on specified file (or directory)
+ * a userspace agent is spawned and given the following parameters:
+ * $1. actual event(s)
+ * $2. file (or directory) name
+ * $3. name of subfile (if any), in case of watching a directory
+ *
+ * E.g. inotifyd ./dev-watcher /dev:n
+ *
+ * ./dev-watcher can be, say:
+ * #!/bin/sh
+ * echo "We have new device in here! Hello, $3!"
+ *
+ * See below for mask names explanation.
+ */
+
+#include "libbb.h"
+#include <linux/inotify.h>
+
+static volatile smallint signalled;
+
+static void signal_handler(int signo)
+{
+ signalled = signo;
+}
+
+static const char mask_names[] ALIGN1 =
+ "a" // 0x00000001 File was accessed
+ "c" // 0x00000002 File was modified
+ "e" // 0x00000004 Metadata changed
+ "w" // 0x00000008 Writtable file was closed
+ "0" // 0x00000010 Unwrittable file closed
+ "r" // 0x00000020 File was opened
+ "m" // 0x00000040 File was moved from X
+ "y" // 0x00000080 File was moved to Y
+ "n" // 0x00000100 Subfile was created
+ "d" // 0x00000200 Subfile was deleted
+ "D" // 0x00000400 Self was deleted
+ "M" // 0x00000800 Self was moved
+;
+
+extern int inotify_init(void);
+extern int inotify_add_watch(int fd, const char *path, uint32_t mask);
+
+int inotifyd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int inotifyd_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ unsigned mask = IN_ALL_EVENTS; // assume we want all events
+ struct pollfd pfd;
+ char **watched = ++argv; // watched name list
+ const char *args[] = { *argv, NULL, NULL, NULL, NULL };
+
+ // sanity check: agent and at least one watch must be given
+ if (!argv[1])
+ bb_show_usage();
+
+ // open inotify
+ pfd.fd = inotify_init();
+ if (pfd.fd < 0)
+ bb_perror_msg_and_die("no kernel support");
+
+ // setup watched
+ while (*++argv) {
+ char *path = *argv;
+ char *masks = strchr(path, ':');
+ int wd; // watch descriptor
+ // if mask is specified ->
+ if (masks) {
+ *masks = '\0'; // split path and mask
+ // convert mask names to mask bitset
+ mask = 0;
+ while (*++masks) {
+ int i = strchr(mask_names, *masks) - mask_names;
+ if (i >= 0) {
+ mask |= (1 << i);
+ }
+ }
+ }
+ // add watch
+ wd = inotify_add_watch(pfd.fd, path, mask);
+ if (wd < 0) {
+ bb_perror_msg_and_die("add watch (%s) failed", path);
+// } else {
+// bb_error_msg("added %d [%s]:%4X", wd, path, mask);
+ }
+ }
+
+ // setup signals
+ bb_signals(0
+ + (1 << SIGHUP)
+ + (1 << SIGINT)
+ + (1 << SIGTERM)
+ + (1 << SIGPIPE)
+ , signal_handler);
+
+ // do watch
+
+// pfd.fd = fd;
+ pfd.events = POLLIN;
+
+ while (!signalled && poll(&pfd, 1, -1) > 0) {
+ ssize_t len;
+ void *buf;
+ struct inotify_event *ie;
+
+ // read out all pending events
+ xioctl(pfd.fd, FIONREAD, &len);
+#define eventbuf bb_common_bufsiz1
+ ie = buf = (len <= sizeof(eventbuf)) ? eventbuf : xmalloc(len);
+ len = full_read(pfd.fd, buf, len);
+ // process events. N.B. events may vary in length
+ while (len > 0) {
+ int i;
+ char events[12];
+ char *s = events;
+ unsigned m = ie->mask;
+
+ for (i = 0; i < 12; ++i, m >>= 1) {
+ if (m & 1) {
+ *s++ = mask_names[i];
+ }
+ }
+ *s = '\0';
+// bb_error_msg("exec %s %08X\t%s\t%s\t%s", agent, ie->mask, events, watched[ie->wd], ie->len ? ie->name : "");
+ args[1] = events;
+ args[2] = watched[ie->wd];
+ args[3] = ie->len ? ie->name : NULL;
+ xspawn((char **)args);
+ // next event
+ i = sizeof(struct inotify_event) + ie->len;
+ len -= i;
+ ie = (void*)((char*)ie + i);
+ }
+ if (eventbuf != buf)
+ free(buf);
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/last.c b/cleopatre/busybox-1.11.1-spc300/miscutils/last.c
new file mode 100644
index 0000000000..da353fbb11
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/last.c
@@ -0,0 +1,133 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * last implementation for busybox
+ *
+ * Copyright (C) 2003-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under the GPL version 2, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+#include <utmp.h>
+
+/* NB: ut_name and ut_user are the same field, use only one name (ut_user)
+ * to reduce confusion */
+
+#ifndef SHUTDOWN_TIME
+# define SHUTDOWN_TIME 254
+#endif
+
+/* Grr... utmp char[] members do not have to be nul-terminated.
+ * Do what we can while still keeping this reasonably small.
+ * Note: We are assuming the ut_id[] size is fixed at 4. */
+
+#if defined UT_LINESIZE \
+ && ((UT_LINESIZE != 32) || (UT_NAMESIZE != 32) || (UT_HOSTSIZE != 256))
+#error struct utmp member char[] size(s) have changed!
+#elif defined __UT_LINESIZE \
+ && ((__UT_LINESIZE != 32) || (__UT_NAMESIZE != 64) || (__UT_HOSTSIZE != 256))
+#error struct utmp member char[] size(s) have changed!
+#endif
+
+#if EMPTY != 0 || RUN_LVL != 1 || BOOT_TIME != 2 || NEW_TIME != 3 || \
+ OLD_TIME != 4
+#error Values for the ut_type field of struct utmp changed
+#endif
+
+int last_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int last_main(int argc, char **argv ATTRIBUTE_UNUSED)
+{
+ struct utmp ut;
+ int n, file = STDIN_FILENO;
+ time_t t_tmp;
+ off_t pos;
+ static const char _ut_usr[] ALIGN1 =
+ "runlevel\0" "reboot\0" "shutdown\0";
+ static const char _ut_lin[] ALIGN1 =
+ "~\0" "{\0" "|\0" /* "LOGIN\0" "date\0" */;
+ enum {
+ TYPE_RUN_LVL = RUN_LVL, /* 1 */
+ TYPE_BOOT_TIME = BOOT_TIME, /* 2 */
+ TYPE_SHUTDOWN_TIME = SHUTDOWN_TIME
+ };
+ enum {
+ _TILDE = EMPTY, /* 0 */
+ TYPE_NEW_TIME, /* NEW_TIME, 3 */
+ TYPE_OLD_TIME /* OLD_TIME, 4 */
+ };
+
+ if (argc > 1) {
+ bb_show_usage();
+ }
+ file = xopen(bb_path_wtmp_file, O_RDONLY);
+
+ printf("%-10s %-14s %-18s %-12.12s %s\n",
+ "USER", "TTY", "HOST", "LOGIN", "TIME");
+ /* yikes. We reverse over the file and that is a not too elegant way */
+ pos = xlseek(file, 0, SEEK_END);
+ pos = lseek(file, pos - sizeof(ut), SEEK_SET);
+ while ((n = full_read(file, &ut, sizeof(ut))) > 0) {
+ if (n != sizeof(ut)) {
+ bb_perror_msg_and_die("short read");
+ }
+ n = index_in_strings(_ut_lin, ut.ut_line);
+ if (n == _TILDE) { /* '~' */
+#if 1
+/* do we really need to be cautious here? */
+ n = index_in_strings(_ut_usr, ut.ut_user);
+ if (++n > 0)
+ ut.ut_type = n != 3 ? n : SHUTDOWN_TIME;
+#else
+ if (strncmp(ut.ut_user, "shutdown", 8) == 0)
+ ut.ut_type = SHUTDOWN_TIME;
+ else if (strncmp(ut.ut_user, "reboot", 6) == 0)
+ ut.ut_type = BOOT_TIME;
+ else if (strncmp(ut.ut_user, "runlevel", 8) == 0)
+ ut.ut_type = RUN_LVL;
+#endif
+ } else {
+ if (ut.ut_user[0] == '\0' || strcmp(ut.ut_user, "LOGIN") == 0) {
+ /* Don't bother. This means we can't find how long
+ * someone was logged in for. Oh well. */
+ goto next;
+ }
+ if (ut.ut_type != DEAD_PROCESS
+ && ut.ut_user[0] && ut.ut_line[0]
+ ) {
+ ut.ut_type = USER_PROCESS;
+ }
+ if (strcmp(ut.ut_user, "date") == 0) {
+ if (n == TYPE_OLD_TIME) { /* '|' */
+ ut.ut_type = OLD_TIME;
+ }
+ if (n == TYPE_NEW_TIME) { /* '{' */
+ ut.ut_type = NEW_TIME;
+ }
+ }
+ }
+
+ if (ut.ut_type != USER_PROCESS) {
+ switch (ut.ut_type) {
+ case OLD_TIME:
+ case NEW_TIME:
+ case RUN_LVL:
+ case SHUTDOWN_TIME:
+ goto next;
+ case BOOT_TIME:
+ strcpy(ut.ut_line, "system boot");
+ }
+ }
+ /* manpages say ut_tv.tv_sec *is* time_t,
+ * but some systems have it wrong */
+ t_tmp = (time_t)ut.ut_tv.tv_sec;
+ printf("%-10s %-14s %-18s %-12.12s\n",
+ ut.ut_user, ut.ut_line, ut.ut_host, ctime(&t_tmp) + 4);
+ next:
+ pos -= sizeof(ut);
+ if (pos <= 0)
+ break; /* done. */
+ xlseek(file, pos, SEEK_SET);
+ }
+
+ fflush_stdout_and_exit(EXIT_SUCCESS);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/last_fancy.c b/cleopatre/busybox-1.11.1-spc300/miscutils/last_fancy.c
new file mode 100644
index 0000000000..d4d35b19a7
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/last_fancy.c
@@ -0,0 +1,297 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * (sysvinit like) last implementation
+ *
+ * Copyright (C) 2008 by Patricia Muscalu <patricia.muscalu@axis.com>
+ *
+ * Licensed under the GPLv2 or later, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+#include <utmp.h>
+
+/* NB: ut_name and ut_user are the same field, use only one name (ut_user)
+ * to reduce confusion */
+
+#ifndef SHUTDOWN_TIME
+# define SHUTDOWN_TIME 254
+#endif
+
+#define HEADER_FORMAT "%-8.8s %-12.12s %-*.*s %-16.16s %-7.7s %s\n"
+#define HEADER_LINE "USER", "TTY", \
+ INET_ADDRSTRLEN, INET_ADDRSTRLEN, "HOST", "LOGIN", " TIME", ""
+#define HEADER_LINE_WIDE "USER", "TTY", \
+ INET6_ADDRSTRLEN, INET6_ADDRSTRLEN, "HOST", "LOGIN", " TIME", ""
+
+enum {
+ NORMAL,
+ LOGGED,
+ DOWN,
+ REBOOT,
+ CRASH,
+ GONE
+};
+
+enum {
+ LAST_OPT_W = (1 << 0), /* -W wide */
+ LAST_OPT_f = (1 << 1), /* -f input file */
+ LAST_OPT_H = (1 << 2), /* -H header */
+};
+
+#define show_wide (option_mask32 & LAST_OPT_W)
+
+static void show_entry(struct utmp *ut, int state, time_t dur_secs)
+{
+ unsigned days, hours, mins;
+ char duration[32];
+ char login_time[17];
+ char logout_time[8];
+ const char *logout_str;
+ const char *duration_str;
+ time_t tmp;
+
+ /* manpages say ut_tv.tv_sec *is* time_t,
+ * but some systems have it wrong */
+ tmp = ut->ut_tv.tv_sec;
+ safe_strncpy(login_time, ctime(&tmp), 17);
+ snprintf(logout_time, 8, "- %s", ctime(&dur_secs) + 11);
+
+ dur_secs = MAX(dur_secs - (time_t)ut->ut_tv.tv_sec, (time_t)0);
+ /* unsigned int is easier to divide than time_t (which may be signed long) */
+ mins = dur_secs / 60;
+ days = mins / (24*60);
+ mins = mins % (24*60);
+ hours = mins / 60;
+ mins = mins % 60;
+
+// if (days) {
+ sprintf(duration, "(%u+%02u:%02u)", days, hours, mins);
+// } else {
+// sprintf(duration, " (%02u:%02u)", hours, mins);
+// }
+
+ logout_str = logout_time;
+ duration_str = duration;
+ switch (state) {
+ case NORMAL:
+ break;
+ case LOGGED:
+ logout_str = " still";
+ duration_str = "logged in";
+ break;
+ case DOWN:
+ logout_str = "- down ";
+ break;
+ case REBOOT:
+ break;
+ case CRASH:
+ logout_str = "- crash";
+ break;
+ case GONE:
+ logout_str = " gone";
+ duration_str = "- no logout";
+ break;
+ }
+
+ printf(HEADER_FORMAT,
+ ut->ut_user,
+ ut->ut_line,
+ show_wide ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN,
+ show_wide ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN,
+ ut->ut_host,
+ login_time,
+ logout_str,
+ duration_str);
+}
+
+static int get_ut_type(struct utmp *ut)
+{
+ if (ut->ut_line[0] == '~') {
+ if (strcmp(ut->ut_user, "shutdown") == 0) {
+ return SHUTDOWN_TIME;
+ }
+ if (strcmp(ut->ut_user, "reboot") == 0) {
+ return BOOT_TIME;
+ }
+ if (strcmp(ut->ut_user, "runlevel") == 0) {
+ return RUN_LVL;
+ }
+ return ut->ut_type;
+ }
+
+ if (ut->ut_user[0] == 0) {
+ return DEAD_PROCESS;
+ }
+
+ if ((ut->ut_type != DEAD_PROCESS)
+ && (strcmp(ut->ut_user, "LOGIN") != 0)
+ && ut->ut_user[0]
+ && ut->ut_line[0]
+ ) {
+ ut->ut_type = USER_PROCESS;
+ }
+
+ if (strcmp(ut->ut_user, "date") == 0) {
+ if (ut->ut_line[0] == '|') {
+ return OLD_TIME;
+ }
+ if (ut->ut_line[0] == '{') {
+ return NEW_TIME;
+ }
+ }
+ return ut->ut_type;
+}
+
+static int is_runlevel_shutdown(struct utmp *ut)
+{
+ if (((ut->ut_pid & 255) == '0') || ((ut->ut_pid & 255) == '6')) {
+ return 1;
+ }
+
+ return 0;
+}
+
+int last_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int last_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ struct utmp ut;
+ const char *filename = _PATH_WTMP;
+ llist_t *zlist;
+ off_t pos;
+ time_t start_time;
+ time_t boot_time;
+ time_t down_time;
+ int file;
+ unsigned opt;
+ smallint going_down;
+ smallint boot_down;
+
+ opt = getopt32(argv, "Wf:" /* "H" */, &filename);
+#ifdef BUT_UTIL_LINUX_LAST_HAS_NO_SUCH_OPT
+ if (opt & LAST_OPT_H) {
+ /* Print header line */
+ if (opt & LAST_OPT_W) {
+ printf(HEADER_FORMAT, HEADER_LINE_WIDE);
+ } else {
+ printf(HEADER_FORMAT, HEADER_LINE);
+ }
+ }
+#endif
+
+ file = xopen(filename, O_RDONLY);
+ {
+ /* in case the file is empty... */
+ struct stat st;
+ fstat(file, &st);
+ start_time = st.st_ctime;
+ }
+
+ time(&down_time);
+ going_down = 0;
+ boot_down = NORMAL; /* 0 */
+ zlist = NULL;
+ boot_time = 0;
+ /* get file size, rounding down to last full record */
+ pos = xlseek(file, 0, SEEK_END) / sizeof(ut) * sizeof(ut);
+ for (;;) {
+ pos -= (off_t)sizeof(ut);
+ if (pos < 0) {
+ /* Beyond the beginning of the file boundary =>
+ * the whole file has been read. */
+ break;
+ }
+ xlseek(file, pos, SEEK_SET);
+ xread(file, &ut, sizeof(ut));
+ /* rewritten by each record, eventially will have
+ * first record's ut_tv.tv_sec: */
+ start_time = ut.ut_tv.tv_sec;
+
+ switch (get_ut_type(&ut)) {
+ case SHUTDOWN_TIME:
+ down_time = ut.ut_tv.tv_sec;
+ boot_down = DOWN;
+ going_down = 1;
+ break;
+ case RUN_LVL:
+ if (is_runlevel_shutdown(&ut)) {
+ down_time = ut.ut_tv.tv_sec;
+ going_down = 1;
+ boot_down = DOWN;
+ }
+ break;
+ case BOOT_TIME:
+ strcpy(ut.ut_line, "system boot");
+ show_entry(&ut, REBOOT, down_time);
+ boot_down = CRASH;
+ going_down = 1;
+ break;
+ case DEAD_PROCESS:
+ if (!ut.ut_line[0]) {
+ break;
+ }
+ /* add_entry */
+ llist_add_to(&zlist, memcpy(xmalloc(sizeof(ut)), &ut, sizeof(ut)));
+ break;
+ case USER_PROCESS: {
+ int show;
+
+ if (!ut.ut_line[0]) {
+ break;
+ }
+ /* find_entry */
+ show = 1;
+ {
+ llist_t *el, *next;
+ for (el = zlist; el; el = next) {
+ struct utmp *up = (struct utmp *)el->data;
+ next = el->link;
+ if (strncmp(up->ut_line, ut.ut_line, UT_LINESIZE) == 0) {
+ if (show) {
+ show_entry(&ut, NORMAL, up->ut_tv.tv_sec);
+ show = 0;
+ }
+ llist_unlink(&zlist, el);
+ free(el->data);
+ free(el);
+ }
+ }
+ }
+
+ if (show) {
+ int state = boot_down;
+
+ if (boot_time == 0) {
+ state = LOGGED;
+ /* Check if the process is alive */
+ if ((ut.ut_pid > 0)
+ && (kill(ut.ut_pid, 0) != 0)
+ && (errno == ESRCH)) {
+ state = GONE;
+ }
+ }
+ show_entry(&ut, state, boot_time);
+ }
+ /* add_entry */
+ llist_add_to(&zlist, memcpy(xmalloc(sizeof(ut)), &ut, sizeof(ut)));
+ break;
+ }
+ }
+
+ if (going_down) {
+ boot_time = ut.ut_tv.tv_sec;
+ llist_free(zlist, free);
+ zlist = NULL;
+ going_down = 0;
+ }
+ }
+
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ llist_free(zlist, free);
+ }
+
+ printf("\nwtmp begins %s", ctime(&start_time));
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close(file);
+ fflush_stdout_and_exit(EXIT_SUCCESS);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/less.c b/cleopatre/busybox-1.11.1-spc300/miscutils/less.c
new file mode 100644
index 0000000000..ecdb9ae60d
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/less.c
@@ -0,0 +1,1412 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini less implementation for busybox
+ *
+ * Copyright (C) 2005 by Rob Sullivan <cogito.ergo.cogito@gmail.com>
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+/*
+ * TODO:
+ * - Add more regular expression support - search modifiers, certain matches, etc.
+ * - Add more complex bracket searching - currently, nested brackets are
+ * not considered.
+ * - Add support for "F" as an input. This causes less to act in
+ * a similar way to tail -f.
+ * - Allow horizontal scrolling.
+ *
+ * Notes:
+ * - the inp file pointer is used so that keyboard input works after
+ * redirected input has been read from stdin
+ */
+
+#include <sched.h> /* sched_yield() */
+
+#include "libbb.h"
+#if ENABLE_FEATURE_LESS_REGEXP
+#include "xregex.h"
+#endif
+
+/* FIXME: currently doesn't work right */
+#undef ENABLE_FEATURE_LESS_FLAGCS
+#define ENABLE_FEATURE_LESS_FLAGCS 0
+
+/* The escape codes for highlighted and normal text */
+#define HIGHLIGHT "\033[7m"
+#define NORMAL "\033[0m"
+/* The escape code to clear the screen */
+#define CLEAR "\033[H\033[J"
+/* The escape code to clear to end of line */
+#define CLEAR_2_EOL "\033[K"
+
+/* These are the escape sequences corresponding to special keys */
+enum {
+ REAL_KEY_UP = 'A',
+ REAL_KEY_DOWN = 'B',
+ REAL_KEY_RIGHT = 'C',
+ REAL_KEY_LEFT = 'D',
+ REAL_PAGE_UP = '5',
+ REAL_PAGE_DOWN = '6',
+ REAL_KEY_HOME = '7', // vt100? linux vt? or what?
+ REAL_KEY_END = '8',
+ REAL_KEY_HOME_ALT = '1', // ESC [1~ (vt100? linux vt? or what?)
+ REAL_KEY_END_ALT = '4', // ESC [4~
+ REAL_KEY_HOME_XTERM = 'H',
+ REAL_KEY_END_XTERM = 'F',
+
+/* These are the special codes assigned by this program to the special keys */
+ KEY_UP = 20,
+ KEY_DOWN = 21,
+ KEY_RIGHT = 22,
+ KEY_LEFT = 23,
+ PAGE_UP = 24,
+ PAGE_DOWN = 25,
+ KEY_HOME = 26,
+ KEY_END = 27,
+
+/* Absolute max of lines eaten */
+ MAXLINES = CONFIG_FEATURE_LESS_MAXLINES,
+
+/* This many "after the end" lines we will show (at max) */
+ TILDES = 1,
+};
+
+/* Command line options */
+enum {
+ FLAG_E = 1,
+ FLAG_M = 1 << 1,
+ FLAG_m = 1 << 2,
+ FLAG_N = 1 << 3,
+ FLAG_TILDE = 1 << 4,
+/* hijack command line options variable for internal state vars */
+ LESS_STATE_MATCH_BACKWARDS = 1 << 15,
+};
+
+#if !ENABLE_FEATURE_LESS_REGEXP
+enum { pattern_valid = 0 };
+#endif
+
+struct globals {
+ int cur_fline; /* signed */
+ int kbd_fd; /* fd to get input from */
+ int less_gets_pos;
+/* last position in last line, taking into account tabs */
+ size_t linepos;
+ unsigned max_displayed_line;
+ unsigned max_fline;
+ unsigned max_lineno; /* this one tracks linewrap */
+ unsigned width;
+ ssize_t eof_error; /* eof if 0, error if < 0 */
+ ssize_t readpos;
+ ssize_t readeof; /* must be signed */
+ const char **buffer;
+ const char **flines;
+ const char *empty_line_marker;
+ unsigned num_files;
+ unsigned current_file;
+ char *filename;
+ char **files;
+#if ENABLE_FEATURE_LESS_MARKS
+ unsigned num_marks;
+ unsigned mark_lines[15][2];
+#endif
+#if ENABLE_FEATURE_LESS_REGEXP
+ unsigned *match_lines;
+ int match_pos; /* signed! */
+ int wanted_match; /* signed! */
+ int num_matches;
+ regex_t pattern;
+ smallint pattern_valid;
+#endif
+ smallint terminated;
+ struct termios term_orig, term_less;
+};
+#define G (*ptr_to_globals)
+#define cur_fline (G.cur_fline )
+#define kbd_fd (G.kbd_fd )
+#define less_gets_pos (G.less_gets_pos )
+#define linepos (G.linepos )
+#define max_displayed_line (G.max_displayed_line)
+#define max_fline (G.max_fline )
+#define max_lineno (G.max_lineno )
+#define width (G.width )
+#define eof_error (G.eof_error )
+#define readpos (G.readpos )
+#define readeof (G.readeof )
+#define buffer (G.buffer )
+#define flines (G.flines )
+#define empty_line_marker (G.empty_line_marker )
+#define num_files (G.num_files )
+#define current_file (G.current_file )
+#define filename (G.filename )
+#define files (G.files )
+#define num_marks (G.num_marks )
+#define mark_lines (G.mark_lines )
+#if ENABLE_FEATURE_LESS_REGEXP
+#define match_lines (G.match_lines )
+#define match_pos (G.match_pos )
+#define num_matches (G.num_matches )
+#define wanted_match (G.wanted_match )
+#define pattern (G.pattern )
+#define pattern_valid (G.pattern_valid )
+#endif
+#define terminated (G.terminated )
+#define term_orig (G.term_orig )
+#define term_less (G.term_less )
+#define INIT_G() do { \
+ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
+ less_gets_pos = -1; \
+ empty_line_marker = "~"; \
+ num_files = 1; \
+ current_file = 1; \
+ eof_error = 1; \
+ terminated = 1; \
+ USE_FEATURE_LESS_REGEXP(wanted_match = -1;) \
+} while (0)
+
+/* Reset terminal input to normal */
+static void set_tty_cooked(void)
+{
+ fflush(stdout);
+ tcsetattr(kbd_fd, TCSANOW, &term_orig);
+}
+
+/* Move the cursor to a position (x,y), where (0,0) is the
+ top-left corner of the console */
+static void move_cursor(int line, int row)
+{
+ printf("\033[%u;%uH", line, row);
+}
+
+static void clear_line(void)
+{
+ printf("\033[%u;0H" CLEAR_2_EOL, max_displayed_line + 2);
+}
+
+static void print_hilite(const char *str)
+{
+ printf(HIGHLIGHT"%s"NORMAL, str);
+}
+
+static void print_statusline(const char *str)
+{
+ clear_line();
+ printf(HIGHLIGHT"%.*s"NORMAL, width - 1, str);
+}
+
+/* Exit the program gracefully */
+static void less_exit(int code)
+{
+ set_tty_cooked();
+ clear_line();
+ if (code < 0)
+ kill_myself_with_sig(- code); /* does not return */
+ exit(code);
+}
+
+#if ENABLE_FEATURE_LESS_REGEXP
+static void fill_match_lines(unsigned pos);
+#else
+#define fill_match_lines(pos) ((void)0)
+#endif
+
+/* Devilishly complex routine.
+ *
+ * Has to deal with EOF and EPIPE on input,
+ * with line wrapping, with last line not ending in '\n'
+ * (possibly not ending YET!), with backspace and tabs.
+ * It reads input again if last time we got an EOF (thus supporting
+ * growing files) or EPIPE (watching output of slow process like make).
+ *
+ * Variables used:
+ * flines[] - array of lines already read. Linewrap may cause
+ * one source file line to occupy several flines[n].
+ * flines[max_fline] - last line, possibly incomplete.
+ * terminated - 1 if flines[max_fline] is 'terminated'
+ * (if there was '\n' [which isn't stored itself, we just remember
+ * that it was seen])
+ * max_lineno - last line's number, this one doesn't increment
+ * on line wrap, only on "real" new lines.
+ * readbuf[0..readeof-1] - small preliminary buffer.
+ * readbuf[readpos] - next character to add to current line.
+ * linepos - screen line position of next char to be read
+ * (takes into account tabs and backspaces)
+ * eof_error - < 0 error, == 0 EOF, > 0 not EOF/error
+ */
+static void read_lines(void)
+{
+#define readbuf bb_common_bufsiz1
+ char *current_line, *p;
+ int w = width;
+ char last_terminated = terminated;
+#if ENABLE_FEATURE_LESS_REGEXP
+ unsigned old_max_fline = max_fline;
+ time_t last_time = 0;
+ unsigned seconds_p1 = 3; /* seconds_to_loop + 1 */
+#endif
+
+ if (option_mask32 & FLAG_N)
+ w -= 8;
+
+ USE_FEATURE_LESS_REGEXP(again0:)
+
+ p = current_line = xmalloc(w);
+ max_fline += last_terminated;
+ if (!last_terminated) {
+ const char *cp = flines[max_fline];
+ if (option_mask32 & FLAG_N)
+ cp += 8;
+ strcpy(current_line, cp);
+ p += strlen(current_line);
+ free((char*)flines[max_fline]);
+ /* linepos is still valid from previous read_lines() */
+ } else {
+ linepos = 0;
+ }
+
+ while (1) { /* read lines until we reach cur_fline or wanted_match */
+ *p = '\0';
+ terminated = 0;
+ while (1) { /* read chars until we have a line */
+ char c;
+ /* if no unprocessed chars left, eat more */
+ if (readpos >= readeof) {
+ ndelay_on(0);
+ eof_error = safe_read(STDIN_FILENO, readbuf, sizeof(readbuf));
+ ndelay_off(0);
+ readpos = 0;
+ readeof = eof_error;
+ if (eof_error <= 0)
+ goto reached_eof;
+ }
+ c = readbuf[readpos];
+ /* backspace? [needed for manpages] */
+ /* <tab><bs> is (a) insane and */
+ /* (b) harder to do correctly, so we refuse to do it */
+ if (c == '\x8' && linepos && p[-1] != '\t') {
+ readpos++; /* eat it */
+ linepos--;
+ /* was buggy (p could end up <= current_line)... */
+ *--p = '\0';
+ continue;
+ }
+ {
+ size_t new_linepos = linepos + 1;
+ if (c == '\t') {
+ new_linepos += 7;
+ new_linepos &= (~7);
+ }
+ if ((int)new_linepos >= w)
+ break;
+ linepos = new_linepos;
+ }
+ /* ok, we will eat this char */
+ readpos++;
+ if (c == '\n') {
+ terminated = 1;
+ linepos = 0;
+ break;
+ }
+ /* NUL is substituted by '\n'! */
+ if (c == '\0') c = '\n';
+ *p++ = c;
+ *p = '\0';
+ } /* end of "read chars until we have a line" loop */
+ /* Corner case: linewrap with only "" wrapping to next line */
+ /* Looks ugly on screen, so we do not store this empty line */
+ if (!last_terminated && !current_line[0]) {
+ last_terminated = 1;
+ max_lineno++;
+ continue;
+ }
+ reached_eof:
+ last_terminated = terminated;
+ flines = xrealloc(flines, (max_fline+1) * sizeof(char *));
+ if (option_mask32 & FLAG_N) {
+ /* Width of 7 preserves tab spacing in the text */
+ flines[max_fline] = xasprintf(
+ (max_lineno <= 9999999) ? "%7u %s" : "%07u %s",
+ max_lineno % 10000000, current_line);
+ free(current_line);
+ if (terminated)
+ max_lineno++;
+ } else {
+ flines[max_fline] = xrealloc(current_line, strlen(current_line)+1);
+ }
+ if (max_fline >= MAXLINES) {
+ eof_error = 0; /* Pretend we saw EOF */
+ break;
+ }
+ if (max_fline > cur_fline + max_displayed_line) {
+#if !ENABLE_FEATURE_LESS_REGEXP
+ break;
+#else
+ if (wanted_match >= num_matches) { /* goto_match called us */
+ fill_match_lines(old_max_fline);
+ old_max_fline = max_fline;
+ }
+ if (wanted_match < num_matches)
+ break;
+#endif
+ }
+ if (eof_error <= 0) {
+ if (eof_error < 0) {
+ if (errno == EAGAIN) {
+ /* not yet eof or error, reset flag (or else
+ * we will hog CPU - select() will return
+ * immediately */
+ eof_error = 1;
+ } else {
+ print_statusline("read error");
+ }
+ }
+#if !ENABLE_FEATURE_LESS_REGEXP
+ break;
+#else
+ if (wanted_match < num_matches) {
+ break;
+ } else { /* goto_match called us */
+ time_t t = time(NULL);
+ if (t != last_time) {
+ last_time = t;
+ if (--seconds_p1 == 0)
+ break;
+ }
+ sched_yield();
+ goto again0; /* go loop again (max 2 seconds) */
+ }
+#endif
+ }
+ max_fline++;
+ current_line = xmalloc(w);
+ p = current_line;
+ linepos = 0;
+ } /* end of "read lines until we reach cur_fline" loop */
+ fill_match_lines(old_max_fline);
+#if ENABLE_FEATURE_LESS_REGEXP
+ /* prevent us from being stuck in search for a match */
+ wanted_match = -1;
+#endif
+#undef readbuf
+}
+
+#if ENABLE_FEATURE_LESS_FLAGS
+/* Interestingly, writing calc_percent as a function saves around 32 bytes
+ * on my build. */
+static int calc_percent(void)
+{
+ unsigned p = (100 * (cur_fline+max_displayed_line+1) + max_fline/2) / (max_fline+1);
+ return p <= 100 ? p : 100;
+}
+
+/* Print a status line if -M was specified */
+static void m_status_print(void)
+{
+ int percentage;
+
+ if (less_gets_pos >= 0) /* don't touch statusline while input is done! */
+ return;
+
+ clear_line();
+ printf(HIGHLIGHT"%s", filename);
+ if (num_files > 1)
+ printf(" (file %i of %i)", current_file, num_files);
+ printf(" lines %i-%i/%i ",
+ cur_fline + 1, cur_fline + max_displayed_line + 1,
+ max_fline + 1);
+ if (cur_fline >= (int)(max_fline - max_displayed_line)) {
+ printf("(END)"NORMAL);
+ if (num_files > 1 && current_file != num_files)
+ printf(HIGHLIGHT" - next: %s"NORMAL, files[current_file]);
+ return;
+ }
+ percentage = calc_percent();
+ printf("%i%%"NORMAL, percentage);
+}
+#endif
+
+/* Print the status line */
+static void status_print(void)
+{
+ const char *p;
+
+ if (less_gets_pos >= 0) /* don't touch statusline while input is done! */
+ return;
+
+ /* Change the status if flags have been set */
+#if ENABLE_FEATURE_LESS_FLAGS
+ if (option_mask32 & (FLAG_M|FLAG_m)) {
+ m_status_print();
+ return;
+ }
+ /* No flags set */
+#endif
+
+ clear_line();
+ if (cur_fline && cur_fline < (int)(max_fline - max_displayed_line)) {
+ bb_putchar(':');
+ return;
+ }
+ p = "(END)";
+ if (!cur_fline)
+ p = filename;
+ if (num_files > 1) {
+ printf(HIGHLIGHT"%s (file %i of %i)"NORMAL,
+ p, current_file, num_files);
+ return;
+ }
+ print_hilite(p);
+}
+
+static void cap_cur_fline(int nlines)
+{
+ int diff;
+ if (cur_fline < 0)
+ cur_fline = 0;
+ if (cur_fline + max_displayed_line > max_fline + TILDES) {
+ cur_fline -= nlines;
+ if (cur_fline < 0)
+ cur_fline = 0;
+ diff = max_fline - (cur_fline + max_displayed_line) + TILDES;
+ /* As the number of lines requested was too large, we just move
+ to the end of the file */
+ if (diff > 0)
+ cur_fline += diff;
+ }
+}
+
+static const char controls[] ALIGN1 =
+ /* NUL: never encountered; TAB: not converted */
+ /**/"\x01\x02\x03\x04\x05\x06\x07\x08" "\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x7f\x9b"; /* DEL and infamous Meta-ESC :( */
+static const char ctrlconv[] ALIGN1 =
+ /* '\n': it's a former NUL - subst with '@', not 'J' */
+ "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x40\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f";
+
+#if ENABLE_FEATURE_LESS_REGEXP
+static void print_found(const char *line)
+{
+ int match_status;
+ int eflags;
+ char *growline;
+ regmatch_t match_structs;
+
+ char buf[width];
+ const char *str = line;
+ char *p = buf;
+ size_t n;
+
+ while (*str) {
+ n = strcspn(str, controls);
+ if (n) {
+ if (!str[n]) break;
+ memcpy(p, str, n);
+ p += n;
+ str += n;
+ }
+ n = strspn(str, controls);
+ memset(p, '.', n);
+ p += n;
+ str += n;
+ }
+ strcpy(p, str);
+
+ /* buf[] holds quarantined version of str */
+
+ /* Each part of the line that matches has the HIGHLIGHT
+ and NORMAL escape sequences placed around it.
+ NB: we regex against line, but insert text
+ from quarantined copy (buf[]) */
+ str = buf;
+ growline = NULL;
+ eflags = 0;
+ goto start;
+
+ while (match_status == 0) {
+ char *new = xasprintf("%s%.*s"HIGHLIGHT"%.*s"NORMAL,
+ growline ? : "",
+ match_structs.rm_so, str,
+ match_structs.rm_eo - match_structs.rm_so,
+ str + match_structs.rm_so);
+ free(growline); growline = new;
+ str += match_structs.rm_eo;
+ line += match_structs.rm_eo;
+ eflags = REG_NOTBOL;
+ start:
+ /* Most of the time doesn't find the regex, optimize for that */
+ match_status = regexec(&pattern, line, 1, &match_structs, eflags);
+ /* if even "" matches, treat it as "not a match" */
+ if (match_structs.rm_so >= match_structs.rm_eo)
+ match_status = 1;
+ }
+
+ if (!growline) {
+ printf(CLEAR_2_EOL"%s\n", str);
+ return;
+ }
+ printf(CLEAR_2_EOL"%s%s\n", growline, str);
+ free(growline);
+}
+#else
+void print_found(const char *line);
+#endif
+
+static void print_ascii(const char *str)
+{
+ char buf[width];
+ char *p;
+ size_t n;
+
+ printf(CLEAR_2_EOL);
+ while (*str) {
+ n = strcspn(str, controls);
+ if (n) {
+ if (!str[n]) break;
+ printf("%.*s", (int) n, str);
+ str += n;
+ }
+ n = strspn(str, controls);
+ p = buf;
+ do {
+ if (*str == 0x7f)
+ *p++ = '?';
+ else if (*str == (char)0x9b)
+ /* VT100's CSI, aka Meta-ESC. Who's inventor? */
+ /* I want to know who committed this sin */
+ *p++ = '{';
+ else
+ *p++ = ctrlconv[(unsigned char)*str];
+ str++;
+ } while (--n);
+ *p = '\0';
+ print_hilite(buf);
+ }
+ puts(str);
+}
+
+/* Print the buffer */
+static void buffer_print(void)
+{
+ unsigned i;
+
+ move_cursor(0, 0);
+ for (i = 0; i <= max_displayed_line; i++)
+ if (pattern_valid)
+ print_found(buffer[i]);
+ else
+ print_ascii(buffer[i]);
+ status_print();
+}
+
+static void buffer_fill_and_print(void)
+{
+ unsigned i;
+ for (i = 0; i <= max_displayed_line && cur_fline + i <= max_fline; i++) {
+ buffer[i] = flines[cur_fline + i];
+ }
+ for (; i <= max_displayed_line; i++) {
+ buffer[i] = empty_line_marker;
+ }
+ buffer_print();
+}
+
+/* Move the buffer up and down in the file in order to scroll */
+static void buffer_down(int nlines)
+{
+ cur_fline += nlines;
+ read_lines();
+ cap_cur_fline(nlines);
+ buffer_fill_and_print();
+}
+
+static void buffer_up(int nlines)
+{
+ cur_fline -= nlines;
+ if (cur_fline < 0) cur_fline = 0;
+ read_lines();
+ buffer_fill_and_print();
+}
+
+static void buffer_line(int linenum)
+{
+ if (linenum < 0)
+ linenum = 0;
+ cur_fline = linenum;
+ read_lines();
+ if (linenum + max_displayed_line > max_fline)
+ linenum = max_fline - max_displayed_line + TILDES;
+ if (linenum < 0)
+ linenum = 0;
+ cur_fline = linenum;
+ buffer_fill_and_print();
+}
+
+static void open_file_and_read_lines(void)
+{
+ if (filename) {
+ int fd = xopen(filename, O_RDONLY);
+ dup2(fd, 0);
+ if (fd) close(fd);
+ } else {
+ /* "less" with no arguments in argv[] */
+ /* For status line only */
+ filename = xstrdup(bb_msg_standard_input);
+ }
+ readpos = 0;
+ readeof = 0;
+ linepos = 0;
+ terminated = 1;
+ read_lines();
+}
+
+/* Reinitialize everything for a new file - free the memory and start over */
+static void reinitialize(void)
+{
+ unsigned i;
+
+ if (flines) {
+ for (i = 0; i <= max_fline; i++)
+ free((void*)(flines[i]));
+ free(flines);
+ flines = NULL;
+ }
+
+ max_fline = -1;
+ cur_fline = 0;
+ max_lineno = 0;
+ open_file_and_read_lines();
+ buffer_fill_and_print();
+}
+
+static ssize_t getch_nowait(char* input, int sz)
+{
+ ssize_t rd;
+ struct pollfd pfd[2];
+
+ pfd[0].fd = STDIN_FILENO;
+ pfd[0].events = POLLIN;
+ pfd[1].fd = kbd_fd;
+ pfd[1].events = POLLIN;
+ again:
+ tcsetattr(kbd_fd, TCSANOW, &term_less);
+ /* NB: select/poll returns whenever read will not block. Therefore:
+ * if eof is reached, select/poll will return immediately
+ * because read will immediately return 0 bytes.
+ * Even if select/poll says that input is available, read CAN block
+ * (switch fd into O_NONBLOCK'ed mode to avoid it)
+ */
+ rd = 1;
+ if (max_fline <= cur_fline + max_displayed_line
+ && eof_error > 0 /* did NOT reach eof yet */
+ ) {
+ /* We are interested in stdin */
+ rd = 0;
+ }
+ /* position cursor if line input is done */
+ if (less_gets_pos >= 0)
+ move_cursor(max_displayed_line + 2, less_gets_pos + 1);
+ fflush(stdout);
+ safe_poll(pfd + rd, 2 - rd, -1);
+
+ input[0] = '\0';
+ rd = safe_read(kbd_fd, input, sz); /* NB: kbd_fd is in O_NONBLOCK mode */
+ if (rd < 0 && errno == EAGAIN) {
+ /* No keyboard input -> we have input on stdin! */
+ read_lines();
+ buffer_fill_and_print();
+ goto again;
+ }
+ set_tty_cooked();
+ return rd;
+}
+
+/* Grab a character from input without requiring the return key. If the
+ * character is ASCII \033, get more characters and assign certain sequences
+ * special return codes. Note that this function works best with raw input. */
+static int less_getch(int pos)
+{
+ unsigned char input[16];
+ unsigned i;
+
+ again:
+ less_gets_pos = pos;
+ memset(input, 0, sizeof(input));
+ getch_nowait((char *)input, sizeof(input));
+ less_gets_pos = -1;
+
+ /* Detect escape sequences (i.e. arrow keys) and handle
+ * them accordingly */
+ if (input[0] == '\033' && input[1] == '[') {
+ i = input[2] - REAL_KEY_UP;
+ if (i < 4)
+ return 20 + i;
+ i = input[2] - REAL_PAGE_UP;
+ if (i < 4)
+ return 24 + i;
+ if (input[2] == REAL_KEY_HOME_XTERM)
+ return KEY_HOME;
+ if (input[2] == REAL_KEY_HOME_ALT)
+ return KEY_HOME;
+ if (input[2] == REAL_KEY_END_XTERM)
+ return KEY_END;
+ if (input[2] == REAL_KEY_END_ALT)
+ return KEY_END;
+ return 0;
+ }
+ /* Reject almost all control chars */
+ i = input[0];
+ if (i < ' ' && i != 0x0d && i != 8)
+ goto again;
+ return i;
+}
+
+static char* less_gets(int sz)
+{
+ char c;
+ unsigned i = 0;
+ char *result = xzalloc(1);
+
+ while (1) {
+ c = '\0';
+ less_gets_pos = sz + i;
+ getch_nowait(&c, 1);
+ if (c == 0x0d) {
+ result[i] = '\0';
+ less_gets_pos = -1;
+ return result;
+ }
+ if (c == 0x7f)
+ c = 8;
+ if (c == 8 && i) {
+ printf("\x8 \x8");
+ i--;
+ }
+ if (c < ' ')
+ continue;
+ if (i >= width - sz - 1)
+ continue; /* len limit */
+ bb_putchar(c);
+ result[i++] = c;
+ result = xrealloc(result, i+1);
+ }
+}
+
+static void examine_file(void)
+{
+ char *new_fname;
+
+ print_statusline("Examine: ");
+ new_fname = less_gets(sizeof("Examine: ") - 1);
+ if (!new_fname[0]) {
+ status_print();
+ err:
+ free(new_fname);
+ return;
+ }
+ if (access(new_fname, R_OK) != 0) {
+ print_statusline("Cannot read this file");
+ goto err;
+ }
+ free(filename);
+ filename = new_fname;
+ /* files start by = argv. why we assume that argv is infinitely long??
+ files[num_files] = filename;
+ current_file = num_files + 1;
+ num_files++; */
+ files[0] = filename;
+ num_files = current_file = 1;
+ reinitialize();
+}
+
+/* This function changes the file currently being paged. direction can be one of the following:
+ * -1: go back one file
+ * 0: go to the first file
+ * 1: go forward one file */
+static void change_file(int direction)
+{
+ if (current_file != ((direction > 0) ? num_files : 1)) {
+ current_file = direction ? current_file + direction : 1;
+ free(filename);
+ filename = xstrdup(files[current_file - 1]);
+ reinitialize();
+ } else {
+ print_statusline(direction > 0 ? "No next file" : "No previous file");
+ }
+}
+
+static void remove_current_file(void)
+{
+ unsigned i;
+
+ if (num_files < 2)
+ return;
+
+ if (current_file != 1) {
+ change_file(-1);
+ for (i = 3; i <= num_files; i++)
+ files[i - 2] = files[i - 1];
+ num_files--;
+ } else {
+ change_file(1);
+ for (i = 2; i <= num_files; i++)
+ files[i - 2] = files[i - 1];
+ num_files--;
+ current_file--;
+ }
+}
+
+static void colon_process(void)
+{
+ int keypress;
+
+ /* Clear the current line and print a prompt */
+ print_statusline(" :");
+
+ keypress = less_getch(2);
+ switch (keypress) {
+ case 'd':
+ remove_current_file();
+ break;
+ case 'e':
+ examine_file();
+ break;
+#if ENABLE_FEATURE_LESS_FLAGS
+ case 'f':
+ m_status_print();
+ break;
+#endif
+ case 'n':
+ change_file(1);
+ break;
+ case 'p':
+ change_file(-1);
+ break;
+ case 'q':
+ less_exit(EXIT_SUCCESS);
+ break;
+ case 'x':
+ change_file(0);
+ break;
+ }
+}
+
+#if ENABLE_FEATURE_LESS_REGEXP
+static void normalize_match_pos(int match)
+{
+ if (match >= num_matches)
+ match = num_matches - 1;
+ if (match < 0)
+ match = 0;
+ match_pos = match;
+}
+
+static void goto_match(int match)
+{
+ if (!pattern_valid)
+ return;
+ if (match < 0)
+ match = 0;
+ /* Try to find next match if eof isn't reached yet */
+ if (match >= num_matches && eof_error > 0) {
+ wanted_match = match; /* "I want to read until I see N'th match" */
+ read_lines();
+ }
+ if (num_matches) {
+ normalize_match_pos(match);
+ buffer_line(match_lines[match_pos]);
+ } else {
+ print_statusline("No matches found");
+ }
+}
+
+static void fill_match_lines(unsigned pos)
+{
+ if (!pattern_valid)
+ return;
+ /* Run the regex on each line of the current file */
+ while (pos <= max_fline) {
+ /* If this line matches */
+ if (regexec(&pattern, flines[pos], 0, NULL, 0) == 0
+ /* and we didn't match it last time */
+ && !(num_matches && match_lines[num_matches-1] == pos)
+ ) {
+ match_lines = xrealloc(match_lines, (num_matches+1) * sizeof(int));
+ match_lines[num_matches++] = pos;
+ }
+ pos++;
+ }
+}
+
+static void regex_process(void)
+{
+ char *uncomp_regex, *err;
+
+ /* Reset variables */
+ free(match_lines);
+ match_lines = NULL;
+ match_pos = 0;
+ num_matches = 0;
+ if (pattern_valid) {
+ regfree(&pattern);
+ pattern_valid = 0;
+ }
+
+ /* Get the uncompiled regular expression from the user */
+ clear_line();
+ bb_putchar((option_mask32 & LESS_STATE_MATCH_BACKWARDS) ? '?' : '/');
+ uncomp_regex = less_gets(1);
+ if (!uncomp_regex[0]) {
+ free(uncomp_regex);
+ buffer_print();
+ return;
+ }
+
+ /* Compile the regex and check for errors */
+ err = regcomp_or_errmsg(&pattern, uncomp_regex, 0);
+ free(uncomp_regex);
+ if (err) {
+ print_statusline(err);
+ free(err);
+ return;
+ }
+
+ pattern_valid = 1;
+ match_pos = 0;
+ fill_match_lines(0);
+ while (match_pos < num_matches) {
+ if ((int)match_lines[match_pos] > cur_fline)
+ break;
+ match_pos++;
+ }
+ if (option_mask32 & LESS_STATE_MATCH_BACKWARDS)
+ match_pos--;
+
+ /* It's possible that no matches are found yet.
+ * goto_match() will read input looking for match,
+ * if needed */
+ goto_match(match_pos);
+}
+#endif
+
+static void number_process(int first_digit)
+{
+ unsigned i;
+ int num;
+ char num_input[sizeof(int)*4]; /* more than enough */
+ char keypress;
+
+ num_input[0] = first_digit;
+
+ /* Clear the current line, print a prompt, and then print the digit */
+ clear_line();
+ printf(":%c", first_digit);
+
+ /* Receive input until a letter is given */
+ i = 1;
+ while (i < sizeof(num_input)-1) {
+ num_input[i] = less_getch(i + 1);
+ if (!num_input[i] || !isdigit(num_input[i]))
+ break;
+ bb_putchar(num_input[i]);
+ i++;
+ }
+
+ /* Take the final letter out of the digits string */
+ keypress = num_input[i];
+ num_input[i] = '\0';
+ num = bb_strtou(num_input, NULL, 10);
+ /* on format error, num == -1 */
+ if (num < 1 || num > MAXLINES) {
+ buffer_print();
+ return;
+ }
+
+ /* We now know the number and the letter entered, so we process them */
+ switch (keypress) {
+ case KEY_DOWN: case 'z': case 'd': case 'e': case ' ': case '\015':
+ buffer_down(num);
+ break;
+ case KEY_UP: case 'b': case 'w': case 'y': case 'u':
+ buffer_up(num);
+ break;
+ case 'g': case '<': case 'G': case '>':
+ cur_fline = num + max_displayed_line;
+ read_lines();
+ buffer_line(num - 1);
+ break;
+ case 'p': case '%':
+ num = num * (max_fline / 100); /* + max_fline / 2; */
+ cur_fline = num + max_displayed_line;
+ read_lines();
+ buffer_line(num);
+ break;
+#if ENABLE_FEATURE_LESS_REGEXP
+ case 'n':
+ goto_match(match_pos + num);
+ break;
+ case '/':
+ option_mask32 &= ~LESS_STATE_MATCH_BACKWARDS;
+ regex_process();
+ break;
+ case '?':
+ option_mask32 |= LESS_STATE_MATCH_BACKWARDS;
+ regex_process();
+ break;
+#endif
+ }
+}
+
+#if ENABLE_FEATURE_LESS_FLAGCS
+static void flag_change(void)
+{
+ int keypress;
+
+ clear_line();
+ bb_putchar('-');
+ keypress = less_getch(1);
+
+ switch (keypress) {
+ case 'M':
+ option_mask32 ^= FLAG_M;
+ break;
+ case 'm':
+ option_mask32 ^= FLAG_m;
+ break;
+ case 'E':
+ option_mask32 ^= FLAG_E;
+ break;
+ case '~':
+ option_mask32 ^= FLAG_TILDE;
+ break;
+ }
+}
+
+static void show_flag_status(void)
+{
+ int keypress;
+ int flag_val;
+
+ clear_line();
+ bb_putchar('_');
+ keypress = less_getch(1);
+
+ switch (keypress) {
+ case 'M':
+ flag_val = option_mask32 & FLAG_M;
+ break;
+ case 'm':
+ flag_val = option_mask32 & FLAG_m;
+ break;
+ case '~':
+ flag_val = option_mask32 & FLAG_TILDE;
+ break;
+ case 'N':
+ flag_val = option_mask32 & FLAG_N;
+ break;
+ case 'E':
+ flag_val = option_mask32 & FLAG_E;
+ break;
+ default:
+ flag_val = 0;
+ break;
+ }
+
+ clear_line();
+ printf(HIGHLIGHT"The status of the flag is: %u"NORMAL, flag_val != 0);
+}
+#endif
+
+static void save_input_to_file(void)
+{
+ const char *msg = "";
+ char *current_line;
+ unsigned i;
+ FILE *fp;
+
+ print_statusline("Log file: ");
+ current_line = less_gets(sizeof("Log file: ")-1);
+ if (current_line[0]) {
+ fp = fopen(current_line, "w");
+ if (!fp) {
+ msg = "Error opening log file";
+ goto ret;
+ }
+ for (i = 0; i <= max_fline; i++)
+ fprintf(fp, "%s\n", flines[i]);
+ fclose(fp);
+ msg = "Done";
+ }
+ ret:
+ print_statusline(msg);
+ free(current_line);
+}
+
+#if ENABLE_FEATURE_LESS_MARKS
+static void add_mark(void)
+{
+ int letter;
+
+ print_statusline("Mark: ");
+ letter = less_getch(sizeof("Mark: ") - 1);
+
+ if (isalpha(letter)) {
+ /* If we exceed 15 marks, start overwriting previous ones */
+ if (num_marks == 14)
+ num_marks = 0;
+
+ mark_lines[num_marks][0] = letter;
+ mark_lines[num_marks][1] = cur_fline;
+ num_marks++;
+ } else {
+ print_statusline("Invalid mark letter");
+ }
+}
+
+static void goto_mark(void)
+{
+ int letter;
+ int i;
+
+ print_statusline("Go to mark: ");
+ letter = less_getch(sizeof("Go to mark: ") - 1);
+ clear_line();
+
+ if (isalpha(letter)) {
+ for (i = 0; i <= num_marks; i++)
+ if (letter == mark_lines[i][0]) {
+ buffer_line(mark_lines[i][1]);
+ break;
+ }
+ if (num_marks == 14 && letter != mark_lines[14][0])
+ print_statusline("Mark not set");
+ } else
+ print_statusline("Invalid mark letter");
+}
+#endif
+
+#if ENABLE_FEATURE_LESS_BRACKETS
+static char opp_bracket(char bracket)
+{
+ switch (bracket) {
+ case '{': case '[': /* '}' == '{' + 2. Same for '[' */
+ bracket++;
+ case '(': /* ')' == '(' + 1 */
+ bracket++;
+ break;
+ case '}': case ']':
+ bracket--;
+ case ')':
+ bracket--;
+ break;
+ };
+ return bracket;
+}
+
+static void match_right_bracket(char bracket)
+{
+ unsigned i;
+
+ if (strchr(flines[cur_fline], bracket) == NULL) {
+ print_statusline("No bracket in top line");
+ return;
+ }
+ bracket = opp_bracket(bracket);
+ for (i = cur_fline + 1; i < max_fline; i++) {
+ if (strchr(flines[i], bracket) != NULL) {
+ buffer_line(i);
+ return;
+ }
+ }
+ print_statusline("No matching bracket found");
+}
+
+static void match_left_bracket(char bracket)
+{
+ int i;
+
+ if (strchr(flines[cur_fline + max_displayed_line], bracket) == NULL) {
+ print_statusline("No bracket in bottom line");
+ return;
+ }
+
+ bracket = opp_bracket(bracket);
+ for (i = cur_fline + max_displayed_line; i >= 0; i--) {
+ if (strchr(flines[i], bracket) != NULL) {
+ buffer_line(i);
+ return;
+ }
+ }
+ print_statusline("No matching bracket found");
+}
+#endif /* FEATURE_LESS_BRACKETS */
+
+static void keypress_process(int keypress)
+{
+ switch (keypress) {
+ case KEY_DOWN: case 'e': case 'j': case 0x0d:
+ buffer_down(1);
+ break;
+ case KEY_UP: case 'y': case 'k':
+ buffer_up(1);
+ break;
+ case PAGE_DOWN: case ' ': case 'z': case 'f':
+ buffer_down(max_displayed_line + 1);
+ break;
+ case PAGE_UP: case 'w': case 'b':
+ buffer_up(max_displayed_line + 1);
+ break;
+ case 'd':
+ buffer_down((max_displayed_line + 1) / 2);
+ break;
+ case 'u':
+ buffer_up((max_displayed_line + 1) / 2);
+ break;
+ case KEY_HOME: case 'g': case 'p': case '<': case '%':
+ buffer_line(0);
+ break;
+ case KEY_END: case 'G': case '>':
+ cur_fline = MAXLINES;
+ read_lines();
+ buffer_line(cur_fline);
+ break;
+ case 'q': case 'Q':
+ less_exit(EXIT_SUCCESS);
+ break;
+#if ENABLE_FEATURE_LESS_MARKS
+ case 'm':
+ add_mark();
+ buffer_print();
+ break;
+ case '\'':
+ goto_mark();
+ buffer_print();
+ break;
+#endif
+ case 'r': case 'R':
+ buffer_print();
+ break;
+ /*case 'R':
+ full_repaint();
+ break;*/
+ case 's':
+ save_input_to_file();
+ break;
+ case 'E':
+ examine_file();
+ break;
+#if ENABLE_FEATURE_LESS_FLAGS
+ case '=':
+ m_status_print();
+ break;
+#endif
+#if ENABLE_FEATURE_LESS_REGEXP
+ case '/':
+ option_mask32 &= ~LESS_STATE_MATCH_BACKWARDS;
+ regex_process();
+ break;
+ case 'n':
+ goto_match(match_pos + 1);
+ break;
+ case 'N':
+ goto_match(match_pos - 1);
+ break;
+ case '?':
+ option_mask32 |= LESS_STATE_MATCH_BACKWARDS;
+ regex_process();
+ break;
+#endif
+#if ENABLE_FEATURE_LESS_FLAGCS
+ case '-':
+ flag_change();
+ buffer_print();
+ break;
+ case '_':
+ show_flag_status();
+ break;
+#endif
+#if ENABLE_FEATURE_LESS_BRACKETS
+ case '{': case '(': case '[':
+ match_right_bracket(keypress);
+ break;
+ case '}': case ')': case ']':
+ match_left_bracket(keypress);
+ break;
+#endif
+ case ':':
+ colon_process();
+ break;
+ }
+
+ if (isdigit(keypress))
+ number_process(keypress);
+}
+
+static void sig_catcher(int sig)
+{
+ less_exit(- sig);
+}
+
+int less_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int less_main(int argc, char **argv)
+{
+ int keypress;
+
+ INIT_G();
+
+ /* TODO: -x: do not interpret backspace, -xx: tab also */
+ /* -xxx: newline also */
+ /* -w N: assume width N (-xxx -w 32: hex viewer of sorts) */
+ getopt32(argv, "EMmN~");
+ argc -= optind;
+ argv += optind;
+ num_files = argc;
+ files = argv;
+
+ /* Another popular pager, most, detects when stdout
+ * is not a tty and turns into cat. This makes sense. */
+ if (!isatty(STDOUT_FILENO))
+ return bb_cat(argv);
+ kbd_fd = open(CURRENT_TTY, O_RDONLY);
+ if (kbd_fd < 0)
+ return bb_cat(argv);
+ ndelay_on(kbd_fd);
+
+ if (!num_files) {
+ if (isatty(STDIN_FILENO)) {
+ /* Just "less"? No args and no redirection? */
+ bb_error_msg("missing filename");
+ bb_show_usage();
+ }
+ } else
+ filename = xstrdup(files[0]);
+
+ get_terminal_width_height(kbd_fd, &width, &max_displayed_line);
+ /* 20: two tabstops + 4 */
+ if (width < 20 || max_displayed_line < 3)
+ return bb_cat(argv);
+ max_displayed_line -= 2;
+
+ buffer = xmalloc((max_displayed_line+1) * sizeof(char *));
+ if (option_mask32 & FLAG_TILDE)
+ empty_line_marker = "";
+
+ tcgetattr(kbd_fd, &term_orig);
+ term_less = term_orig;
+ term_less.c_lflag &= ~(ICANON | ECHO);
+ term_less.c_iflag &= ~(IXON | ICRNL);
+ /*term_less.c_oflag &= ~ONLCR;*/
+ term_less.c_cc[VMIN] = 1;
+ term_less.c_cc[VTIME] = 0;
+
+ /* We want to restore term_orig on exit */
+ bb_signals(BB_FATAL_SIGS, sig_catcher);
+
+ reinitialize();
+ while (1) {
+ keypress = less_getch(-1); /* -1: do not position cursor */
+ keypress_process(keypress);
+ }
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/makedevs.c b/cleopatre/busybox-1.11.1-spc300/miscutils/makedevs.c
new file mode 100644
index 0000000000..3b45d70b4f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/makedevs.c
@@ -0,0 +1,231 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * public domain -- Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
+ *
+ * makedevs
+ * Make ranges of device files quickly.
+ * known bugs: can't deal with alpha ranges
+ */
+
+#include "libbb.h"
+
+#if ENABLE_FEATURE_MAKEDEVS_LEAF
+int makedevs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int makedevs_main(int argc, char **argv)
+{
+ mode_t mode;
+ char *basedev, *type, *nodname, buf[255];
+ int Smajor, Sminor, S, E;
+
+ if (argc < 7 || *argv[1]=='-')
+ bb_show_usage();
+
+ basedev = argv[1];
+ type = argv[2];
+ Smajor = xatoi_u(argv[3]);
+ Sminor = xatoi_u(argv[4]);
+ S = xatoi_u(argv[5]);
+ E = xatoi_u(argv[6]);
+ nodname = argc == 8 ? basedev : buf;
+
+ mode = 0660;
+
+ switch (type[0]) {
+ case 'c':
+ mode |= S_IFCHR;
+ break;
+ case 'b':
+ mode |= S_IFBLK;
+ break;
+ case 'f':
+ mode |= S_IFIFO;
+ break;
+ default:
+ bb_show_usage();
+ }
+
+ while (S <= E) {
+ int sz;
+
+ sz = snprintf(buf, sizeof(buf), "%s%d", basedev, S);
+ if (sz < 0 || sz >= sizeof(buf)) /* libc different */
+ bb_error_msg_and_die("%s too large", basedev);
+
+ /* if mode != S_IFCHR and != S_IFBLK third param in mknod() ignored */
+
+ if (mknod(nodname, mode, makedev(Smajor, Sminor)))
+ bb_error_msg("failed to create: %s", nodname);
+
+ if (nodname == basedev) /* ex. /dev/hda - to /dev/hda1 ... */
+ nodname = buf;
+ S++;
+ Sminor++;
+ }
+
+ return 0;
+}
+
+#elif ENABLE_FEATURE_MAKEDEVS_TABLE
+
+/* Licensed under the GPL v2 or later, see the file LICENSE in this tarball. */
+
+int makedevs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int makedevs_main(int argc, char **argv)
+{
+ FILE *table = stdin;
+ char *rootdir = NULL;
+ char *line = NULL;
+ int linenum = 0;
+ int ret = EXIT_SUCCESS;
+
+ getopt32(argv, "d:", &line);
+ if (line)
+ table = xfopen(line, "r");
+
+ if (optind >= argc || (rootdir=argv[optind])==NULL) {
+ bb_error_msg_and_die("root directory not specified");
+ }
+
+ xchdir(rootdir);
+
+ umask(0);
+
+ printf("rootdir=%s\n", rootdir);
+ if (line) {
+ printf("table='%s'\n", line);
+ } else {
+ printf("table=<stdin>\n");
+ }
+
+ while ((line = xmalloc_fgetline(table)) != NULL) {
+ char type;
+ unsigned mode = 0755;
+ unsigned major = 0;
+ unsigned minor = 0;
+ unsigned count = 0;
+ unsigned increment = 0;
+ unsigned start = 0;
+ char name[41];
+ char user[41];
+ char group[41];
+ char *full_name;
+ uid_t uid;
+ gid_t gid;
+
+ linenum++;
+
+ if ((2 > sscanf(line, "%40s %c %o %40s %40s %u %u %u %u %u", name,
+ &type, &mode, user, group, &major,
+ &minor, &start, &increment, &count)) ||
+ ((major | minor | start | count | increment) > 255))
+ {
+ if (*line=='\0' || *line=='#' || isspace(*line))
+ continue;
+ bb_error_msg("invalid line %d: '%s'", linenum, line);
+ ret = EXIT_FAILURE;
+ continue;
+ }
+ if (name[0] == '#') {
+ continue;
+ }
+
+ gid = (*group) ? get_ug_id(group, xgroup2gid) : getgid();
+ uid = (*user) ? get_ug_id(user, xuname2uid) : getuid();
+ full_name = concat_path_file(rootdir, name);
+
+ if (type == 'd') {
+ bb_make_directory(full_name, mode | S_IFDIR, FILEUTILS_RECUR);
+ if (chown(full_name, uid, gid) == -1) {
+ bb_perror_msg("line %d: chown failed for %s", linenum, full_name);
+ ret = EXIT_FAILURE;
+ goto loop;
+ }
+ if (chmod(full_name, mode) < 0) {
+ bb_perror_msg("line %d: chmod failed for %s", linenum, full_name);
+ ret = EXIT_FAILURE;
+ goto loop;
+ }
+ } else if (type == 'f') {
+ struct stat st;
+ if ((stat(full_name, &st) < 0 || !S_ISREG(st.st_mode))) {
+ bb_perror_msg("line %d: regular file '%s' does not exist", linenum, full_name);
+ ret = EXIT_FAILURE;
+ goto loop;
+ }
+ if (chown(full_name, uid, gid) == -1) {
+ bb_perror_msg("line %d: chown failed for %s", linenum, full_name);
+ ret = EXIT_FAILURE;
+ goto loop;
+ }
+ if (chmod(full_name, mode) < 0) {
+ bb_perror_msg("line %d: chmod failed for %s", linenum, full_name);
+ ret = EXIT_FAILURE;
+ goto loop;
+ }
+ } else {
+ dev_t rdev;
+
+ if (type == 'p') {
+ mode |= S_IFIFO;
+ }
+ else if (type == 'c') {
+ mode |= S_IFCHR;
+ }
+ else if (type == 'b') {
+ mode |= S_IFBLK;
+ } else {
+ bb_error_msg("line %d: unsupported file type %c", linenum, type);
+ ret = EXIT_FAILURE;
+ goto loop;
+ }
+
+ if (count > 0) {
+ unsigned i;
+ char *full_name_inc;
+
+ full_name_inc = xmalloc(strlen(full_name) + 4);
+ for (i = start; i < count; i++) {
+ sprintf(full_name_inc, "%s%d", full_name, i);
+ rdev = makedev(major, minor + (i * increment - start));
+ if (mknod(full_name_inc, mode, rdev) == -1) {
+ bb_perror_msg("line %d: cannot create node %s", linenum, full_name_inc);
+ ret = EXIT_FAILURE;
+ }
+ else if (chown(full_name_inc, uid, gid) == -1) {
+ bb_perror_msg("line %d: chown failed for %s", linenum, full_name_inc);
+ ret = EXIT_FAILURE;
+ }
+ if (chmod(full_name_inc, mode) < 0) {
+ bb_perror_msg("line %d: chmod failed for %s", linenum, full_name_inc);
+ ret = EXIT_FAILURE;
+ }
+ }
+ free(full_name_inc);
+ } else {
+ rdev = makedev(major, minor);
+ if (mknod(full_name, mode, rdev) == -1) {
+ bb_perror_msg("line %d: cannot create node %s", linenum, full_name);
+ ret = EXIT_FAILURE;
+ }
+ else if (chown(full_name, uid, gid) == -1) {
+ bb_perror_msg("line %d: chown failed for %s", linenum, full_name);
+ ret = EXIT_FAILURE;
+ }
+ if (chmod(full_name, mode) < 0) {
+ bb_perror_msg("line %d: chmod failed for %s", linenum, full_name);
+ ret = EXIT_FAILURE;
+ }
+ }
+ }
+loop:
+ free(line);
+ free(full_name);
+ }
+ fclose(table);
+
+ return ret;
+}
+
+#else
+# error makedevs configuration error, either leaf or table must be selected
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/man.c b/cleopatre/busybox-1.11.1-spc300/miscutils/man.c
new file mode 100644
index 0000000000..dc8fa449db
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/man.c
@@ -0,0 +1,163 @@
+/* mini man implementation for busybox
+ * Copyright (C) 2008 Denys Vlasenko <vda.linux@googlemail.com>
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+enum {
+ OPT_a = 1, /* all */
+ OPT_w = 2, /* print path */
+};
+
+/* This is what I see on my desktop system deing executed:
+
+(
+echo ".ll 12.4i"
+echo ".nr LL 12.4i"
+echo ".pl 1100i"
+gunzip -c '/usr/man/man1/bzip2.1.gz'
+echo ".\\\""
+echo ".pl \n(nlu+10"
+) | gtbl | nroff -Tlatin1 -mandoc | less
+
+*/
+
+static int run_pipe(const char *unpacker, const char *pager, char *man_filename)
+{
+ char *cmd;
+
+ if (access(man_filename, R_OK) != 0)
+ return 0;
+
+ if (option_mask32 & OPT_w) {
+ puts(man_filename);
+ return 1;
+ }
+
+ cmd = xasprintf("%s '%s' | gtbl | nroff -Tlatin1 -mandoc | %s",
+ unpacker, man_filename, pager);
+ system(cmd);
+ free(cmd);
+ return 1;
+}
+
+/* man_filename is of the form "/dir/dir/dir/name.s.bz2" */
+static int show_manpage(const char *pager, char *man_filename)
+{
+ int len;
+
+ if (run_pipe("bunzip2 -c", pager, man_filename))
+ return 1;
+
+ len = strlen(man_filename) - 1;
+
+ man_filename[len] = '\0'; /* ".bz2" -> ".gz" */
+ man_filename[len - 2] = 'g';
+ if (run_pipe("gunzip -c", pager, man_filename))
+ return 1;
+
+ man_filename[len - 3] = '\0'; /* ".gz" -> "" */
+ if (run_pipe("cat", pager, man_filename))
+ return 1;
+
+ return 0;
+}
+
+int man_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int man_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ FILE *cf;
+ const char *pager;
+ char **man_path_list;
+ char *sec_list;
+ char *cur_path, *cur_sect;
+ char *line, *value;
+ int count_mp, cur_mp;
+ int opt;
+
+ opt_complementary = "-1"; /* at least one argument */
+ opt = getopt32(argv, "+aw");
+ argv += optind;
+
+ sec_list = xstrdup("1:2:3:4:5:6:7:8:9");
+ /* Last valid man_path_list[] is [0x10] */
+ man_path_list = xzalloc(0x11 * sizeof(man_path_list[0]));
+ count_mp = 0;
+ man_path_list[0] = xstrdup(getenv("MANPATH"));
+ if (man_path_list[0])
+ count_mp++;
+ pager = getenv("MANPAGER");
+ if (!pager) {
+ pager = getenv("PAGER");
+ if (!pager)
+ pager = "more";
+ }
+
+ /* Parse man.conf */
+ cf = fopen_or_warn("/etc/man.conf", "r");
+ if (cf) {
+ /* go through man configuration file and search relevant paths, sections */
+ while ((line = xmalloc_fgetline(cf)) != NULL) {
+ trim(line); /* remove whitespace at the beginning/end */
+ if (isspace(line[7])) {
+ line[7] = '\0';
+ value = skip_whitespace(&line[8]);
+ *skip_non_whitespace(value) = '\0';
+ if (strcmp("MANPATH", line) == 0) {
+ man_path_list[count_mp] = xstrdup(value);
+ count_mp++;
+ /* man_path_list is NULL terminated */
+ man_path_list[count_mp] = NULL;
+ if (!(count_mp & 0xf)) { /* 0x10, 0x20 etc */
+ /* so that last valid man_path_list[] is [count_mp + 0x10] */
+ man_path_list = xrealloc(man_path_list,
+ (count_mp + 0x11) * sizeof(man_path_list[0]));
+ }
+ }
+ if (strcmp("MANSECT", line) == 0) {
+ free(sec_list);
+ sec_list = xstrdup(value);
+ }
+ }
+ free(line);
+ }
+ fclose(cf);
+ }
+
+ do { /* for each argv[] */
+ cur_mp = 0;
+ while ((cur_path = man_path_list[cur_mp++]) != NULL) {
+ /* for each MANPATH */
+ do { /* for each MANPATH item */
+ char *next_path = strchrnul(cur_path, ':');
+ int path_len = next_path - cur_path;
+ cur_sect = sec_list;
+ do { /* for each section */
+ char *next_sect = strchrnul(cur_sect, ':');
+ int sect_len = next_sect - cur_sect;
+
+ char *man_filename = xasprintf("%.*s/man%.*s/%s.%.*s" ".bz2",
+ path_len, cur_path,
+ sect_len, cur_sect,
+ *argv,
+ sect_len, cur_sect);
+ int found = show_manpage(pager, man_filename);
+ free(man_filename);
+ if (found && !(opt & OPT_a))
+ goto next_arg;
+ cur_sect = next_sect;
+ while (*cur_sect == ':')
+ cur_sect++;
+ } while (*cur_sect);
+ cur_path = next_path;
+ while (*cur_path == ':')
+ cur_path++;
+ } while (*cur_path);
+ }
+ next_arg:
+ argv++;
+ } while (*argv);
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/microcom.c b/cleopatre/busybox-1.11.1-spc300/miscutils/microcom.c
new file mode 100644
index 0000000000..1608960e95
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/microcom.c
@@ -0,0 +1,179 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bare bones 'talk to modem' program - similar to 'cu -l $device'
+ * inspired by mgetty's microcom
+ *
+ * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+#include "libbb.h"
+
+/* All known arches use small ints for signals */
+static volatile smallint signalled;
+
+static void signal_handler(int signo)
+{
+ signalled = signo;
+}
+
+// set raw tty mode
+static void xget1(int fd, struct termios *t, struct termios *oldt)
+{
+ tcgetattr(fd, oldt);
+ *t = *oldt;
+ cfmakeraw(t);
+// t->c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
+// t->c_iflag &= ~(BRKINT|IXON|ICRNL);
+// t->c_oflag &= ~(ONLCR);
+// t->c_cc[VMIN] = 1;
+// t->c_cc[VTIME] = 0;
+}
+
+static int xset1(int fd, struct termios *tio, const char *device)
+{
+ int ret = tcsetattr(fd, TCSAFLUSH, tio);
+
+ if (ret) {
+ bb_perror_msg("can't tcsetattr for %s", device);
+ }
+ return ret;
+}
+
+int microcom_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int microcom_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ int sfd;
+ int nfd;
+ struct pollfd pfd[2];
+ struct termios tio0, tiosfd, tio;
+ char *device_lock_file;
+ enum {
+ OPT_X = 1 << 0, // do not respect Ctrl-X, Ctrl-@
+ OPT_s = 1 << 1, // baudrate
+ OPT_d = 1 << 2, // wait for device response, ms
+ OPT_t = 1 << 3, // timeout, ms
+ };
+ speed_t speed = 9600;
+ int delay = -1;
+ int timeout = -1;
+ unsigned opts;
+
+ // fetch options
+ opt_complementary = "=1:s+:d+:t+"; // exactly one arg, numeric options
+ opts = getopt32(argv, "Xs:d:t:", &speed, &delay, &timeout);
+// argc -= optind;
+ argv += optind;
+
+ // try to create lock file in /var/lock
+ device_lock_file = (char *)bb_basename(argv[0]);
+ device_lock_file = xasprintf("/var/lock/LCK..%s", device_lock_file);
+ sfd = open(device_lock_file, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0644);
+ if (sfd < 0) {
+ // device already locked -> bail out
+ if (errno == EEXIST)
+ bb_perror_msg_and_die("can't create %s", device_lock_file);
+ // can't create lock -> don't care
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(device_lock_file);
+ device_lock_file = NULL;
+ } else {
+ // %4d to make concurrent mgetty (if any) happy.
+ // Mgetty treats 4-bytes lock files as binary,
+ // not text, PID. Making 5+ char file. Brrr...
+ fdprintf(sfd, "%4d\n", getpid());
+ close(sfd);
+ }
+
+ // setup signals
+ bb_signals(0
+ + (1 << SIGHUP)
+ + (1 << SIGINT)
+ + (1 << SIGTERM)
+ + (1 << SIGPIPE)
+ , signal_handler);
+
+ // error exit code if we fail to open the device
+ signalled = 1;
+
+ // open device
+ sfd = open_or_warn(argv[0], O_RDWR | O_NOCTTY | O_NONBLOCK);
+ if (sfd < 0)
+ goto done;
+ fcntl(sfd, F_SETFL, 0);
+
+ // put device to "raw mode"
+ xget1(sfd, &tio, &tiosfd);
+ // set device speed
+ cfsetspeed(&tio, tty_value_to_baud(speed));
+ if (xset1(sfd, &tio, argv[0]))
+ goto done;
+
+ // put stdin to "raw mode" (if stdin is a TTY),
+ // handle one character at a time
+ if (isatty(STDIN_FILENO)) {
+ xget1(STDIN_FILENO, &tio, &tio0);
+ if (xset1(STDIN_FILENO, &tio, "stdin"))
+ goto done;
+ }
+
+ // main loop: check with poll(), then read/write bytes across
+ pfd[0].fd = sfd;
+ pfd[0].events = POLLIN;
+ pfd[1].fd = STDIN_FILENO;
+ pfd[1].events = POLLIN;
+
+ signalled = 0;
+ nfd = 2;
+ while (!signalled && safe_poll(pfd, nfd, timeout) > 0) {
+ if (nfd > 1 && pfd[1].revents) {
+ char c;
+ // read from stdin -> write to device
+ if (safe_read(STDIN_FILENO, &c, 1) < 1) {
+ // don't poll stdin anymore if we got EOF/error
+ nfd--;
+ goto skip_write;
+ }
+ // do we need special processing?
+ if (!(opts & OPT_X)) {
+ // ^@ sends Break
+ if (VINTR == c) {
+ tcsendbreak(sfd, 0);
+ goto skip_write;
+ }
+ // ^X exits
+ if (24 == c)
+ break;
+ }
+ write(sfd, &c, 1);
+ if (delay >= 0)
+ safe_poll(pfd, 1, delay);
+skip_write: ;
+ }
+ if (pfd[0].revents) {
+#define iobuf bb_common_bufsiz1
+ ssize_t len;
+ // read from device -> write to stdout
+ len = safe_read(sfd, iobuf, sizeof(iobuf));
+ if (len > 0)
+ full_write(STDOUT_FILENO, iobuf, len);
+ else {
+ // EOF/error -> bail out
+ signalled = SIGHUP;
+ break;
+ }
+ }
+ }
+
+ // restore device mode
+ tcsetattr(sfd, TCSAFLUSH, &tiosfd);
+
+ if (isatty(STDIN_FILENO))
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio0);
+
+done:
+ if (device_lock_file)
+ unlink(device_lock_file);
+
+ return signalled;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/mountpoint.c b/cleopatre/busybox-1.11.1-spc300/miscutils/mountpoint.c
new file mode 100644
index 0000000000..5647e4c5b2
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/mountpoint.c
@@ -0,0 +1,66 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * mountpoint implementation for busybox
+ *
+ * Copyright (C) 2005 Bernhard Fischer
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ *
+ * Based on sysvinit's mountpoint
+ */
+
+#include "libbb.h"
+
+int mountpoint_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int mountpoint_main(int argc, char **argv)
+{
+ struct stat st;
+ char *arg;
+ int opt = getopt32(argv, "qdx");
+#define OPT_q (1)
+#define OPT_d (2)
+#define OPT_x (4)
+
+ if (optind != argc - 1)
+ bb_show_usage();
+
+ arg = argv[optind];
+
+ if ( (opt & OPT_x && stat(arg, &st) == 0) || (lstat(arg, &st) == 0) ) {
+ if (opt & OPT_x) {
+ if (S_ISBLK(st.st_mode)) {
+ printf("%u:%u\n", major(st.st_rdev),
+ minor(st.st_rdev));
+ return EXIT_SUCCESS;
+ } else {
+ if (opt & OPT_q)
+ bb_putchar('\n');
+ else
+ bb_error_msg("%s: not a block device", arg);
+ }
+ return EXIT_FAILURE;
+ } else
+ if (S_ISDIR(st.st_mode)) {
+ dev_t st_dev = st.st_dev;
+ ino_t st_ino = st.st_ino;
+ char *p = xasprintf("%s/..", arg);
+
+ if (stat(p, &st) == 0) {
+ int ret = (st_dev != st.st_dev) ||
+ (st_dev == st.st_dev && st_ino == st.st_ino);
+ if (opt & OPT_d)
+ printf("%u:%u\n", major(st_dev), minor(st_dev));
+ else if (!(opt & OPT_q))
+ printf("%s is %sa mountpoint\n", arg, ret?"":"not ");
+ return !ret;
+ }
+ } else {
+ if (!(opt & OPT_q))
+ bb_error_msg("%s: not a directory", arg);
+ return EXIT_FAILURE;
+ }
+ }
+ if (!(opt & OPT_q))
+ bb_simple_perror_msg(arg);
+ return EXIT_FAILURE;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/mt.c b/cleopatre/busybox-1.11.1-spc300/miscutils/mt.c
new file mode 100644
index 0000000000..c56a8e0caa
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/mt.c
@@ -0,0 +1,140 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include <sys/mtio.h>
+
+/* missing: eod/seod, stoptions, stwrthreshold, densities */
+static const short opcode_value[] = {
+ MTBSF,
+ MTBSFM,
+ MTBSR,
+ MTBSS,
+ MTCOMPRESSION,
+ MTEOM,
+ MTERASE,
+ MTFSF,
+ MTFSFM,
+ MTFSR,
+ MTFSS,
+ MTLOAD,
+ MTLOCK,
+ MTMKPART,
+ MTNOP,
+ MTOFFL,
+ MTOFFL,
+ MTRAS1,
+ MTRAS2,
+ MTRAS3,
+ MTRESET,
+ MTRETEN,
+ MTREW,
+ MTSEEK,
+ MTSETBLK,
+ MTSETDENSITY,
+ MTSETDRVBUFFER,
+ MTSETPART,
+ MTTELL,
+ MTWSM,
+ MTUNLOAD,
+ MTUNLOCK,
+ MTWEOF,
+ MTWEOF
+};
+
+static const char opcode_name[] ALIGN1 =
+ "bsf" "\0"
+ "bsfm" "\0"
+ "bsr" "\0"
+ "bss" "\0"
+ "datacompression" "\0"
+ "eom" "\0"
+ "erase" "\0"
+ "fsf" "\0"
+ "fsfm" "\0"
+ "fsr" "\0"
+ "fss" "\0"
+ "load" "\0"
+ "lock" "\0"
+ "mkpart" "\0"
+ "nop" "\0"
+ "offline" "\0"
+ "rewoffline" "\0"
+ "ras1" "\0"
+ "ras2" "\0"
+ "ras3" "\0"
+ "reset" "\0"
+ "retension" "\0"
+ "rewind" "\0"
+ "seek" "\0"
+ "setblk" "\0"
+ "setdensity" "\0"
+ "drvbuffer" "\0"
+ "setpart" "\0"
+ "tell" "\0"
+ "wset" "\0"
+ "unload" "\0"
+ "unlock" "\0"
+ "eof" "\0"
+ "weof" "\0";
+
+int mt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int mt_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ const char *file = "/dev/tape";
+ struct mtop op;
+ struct mtpos position;
+ int fd, mode, idx;
+
+ if (!argv[1]) {
+ bb_show_usage();
+ }
+
+ if (strcmp(argv[1], "-f") == 0) {
+ if (!argv[2] || !argv[3])
+ bb_show_usage();
+ file = argv[2];
+ argv += 2;
+ }
+
+ idx = index_in_strings(opcode_name, argv[1]);
+
+ if (idx < 0)
+ bb_error_msg_and_die("unrecognized opcode %s", argv[1]);
+
+ op.mt_op = opcode_value[idx];
+ if (argv[2])
+ op.mt_count = xatoi_u(argv[2]);
+ else
+ op.mt_count = 1; /* One, not zero, right? */
+
+ switch (opcode_value[idx]) {
+ case MTWEOF:
+ case MTERASE:
+ case MTWSM:
+ case MTSETDRVBUFFER:
+ mode = O_WRONLY;
+ break;
+
+ default:
+ mode = O_RDONLY;
+ break;
+ }
+
+ fd = xopen(file, mode);
+
+ switch (opcode_value[idx]) {
+ case MTTELL:
+ ioctl_or_perror_and_die(fd, MTIOCPOS, &position, "%s", file);
+ printf("At block %d\n", (int) position.mt_blkno);
+ break;
+
+ default:
+ ioctl_or_perror_and_die(fd, MTIOCTOP, &op, "%s", file);
+ break;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/raidautorun.c b/cleopatre/busybox-1.11.1-spc300/miscutils/raidautorun.c
new file mode 100644
index 0000000000..2766245dba
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/raidautorun.c
@@ -0,0 +1,25 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * raidautorun implementation for busybox
+ *
+ * Copyright (C) 2006 Bernhard Fischer
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ *
+ */
+
+#include "libbb.h"
+
+#include <linux/major.h>
+#include <linux/raid/md_u.h>
+
+int raidautorun_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int raidautorun_main(int argc, char **argv)
+{
+ if (argc != 2)
+ bb_show_usage();
+
+ xioctl(xopen(argv[1], O_RDONLY), RAID_AUTORUN, NULL);
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/readahead.c b/cleopatre/busybox-1.11.1-spc300/miscutils/readahead.c
new file mode 100644
index 0000000000..fb71ce85f0
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/readahead.c
@@ -0,0 +1,40 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * readahead implementation for busybox
+ *
+ * Preloads the given files in RAM, to reduce access time.
+ * Does this by calling the readahead(2) system call.
+ *
+ * Copyright (C) 2006 Michael Opdenacker <michael@free-electrons.com>
+ *
+ * Licensed under GPLv2 or later, see file License in this tarball for details.
+ */
+
+#include "libbb.h"
+
+int readahead_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int readahead_main(int argc, char **argv)
+{
+ int retval = EXIT_SUCCESS;
+
+ if (argc == 1) bb_show_usage();
+
+ while (*++argv) {
+ int fd = open_or_warn(*argv, O_RDONLY);
+ if (fd >= 0) {
+ off_t len;
+ int r;
+
+ /* fdlength was reported to be unreliable - use seek */
+ len = xlseek(fd, 0, SEEK_END);
+ xlseek(fd, 0, SEEK_SET);
+ r = readahead(fd, 0, len);
+ close(fd);
+ if (r >= 0)
+ continue;
+ }
+ retval = EXIT_FAILURE;
+ }
+
+ return retval;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/runlevel.c b/cleopatre/busybox-1.11.1-spc300/miscutils/runlevel.c
new file mode 100644
index 0000000000..04064ee73d
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/runlevel.c
@@ -0,0 +1,43 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * runlevel Prints out the previous and the current runlevel.
+ *
+ * Version: @(#)runlevel 1.20 16-Apr-1997 MvS
+ *
+ * This file is part of the sysvinit suite,
+ * Copyright 1991-1997 Miquel van Smoorenburg.
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ *
+ * initially busyboxified by Bernhard Fischer
+ */
+
+#include <utmp.h>
+#include "libbb.h"
+
+int runlevel_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int runlevel_main(int argc, char **argv)
+{
+ struct utmp *ut;
+ char prev;
+
+ if (argc > 1) utmpname(argv[1]);
+
+ setutent();
+ while ((ut = getutent()) != NULL) {
+ if (ut->ut_type == RUN_LVL) {
+ prev = ut->ut_pid / 256;
+ if (prev == 0) prev = 'N';
+ printf("%c %c\n", prev, ut->ut_pid % 256);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ endutent();
+ return 0;
+ }
+ }
+
+ puts("unknown");
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ endutent();
+ return 1;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/rx.c b/cleopatre/busybox-1.11.1-spc300/miscutils/rx.c
new file mode 100644
index 0000000000..48867b83c9
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/rx.c
@@ -0,0 +1,254 @@
+/* vi: set sw=4 ts=4: */
+/*-------------------------------------------------------------------------
+ * Filename: xmodem.c
+ * Copyright: Copyright (C) 2001, Hewlett-Packard Company
+ * Author: Christopher Hoover <ch@hpl.hp.com>
+ * Description: xmodem functionality for uploading of kernels
+ * and the like
+ * Created at: Thu Dec 20 01:58:08 PST 2001
+ *-----------------------------------------------------------------------*/
+/*
+ * xmodem.c: xmodem functionality for uploading of kernels and
+ * the like
+ *
+ * Copyright (C) 2001 Hewlett-Packard Laboratories
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ * This was originally written for blob and then adapted for busybox.
+ */
+
+#include "libbb.h"
+
+#define SOH 0x01
+#define STX 0x02
+#define EOT 0x04
+#define ACK 0x06
+#define NAK 0x15
+#define BS 0x08
+
+/*
+Cf:
+ http://www.textfiles.com/apple/xmodem
+ http://www.phys.washington.edu/~belonis/xmodem/docxmodem.txt
+ http://www.phys.washington.edu/~belonis/xmodem/docymodem.txt
+ http://www.phys.washington.edu/~belonis/xmodem/modmprot.col
+*/
+
+#define TIMEOUT 1
+#define TIMEOUT_LONG 10
+#define MAXERRORS 10
+
+#define read_fd STDIN_FILENO
+#define write_fd STDOUT_FILENO
+
+static int read_byte(unsigned timeout)
+{
+ char buf[1];
+ int n;
+
+ alarm(timeout);
+ /* NOT safe_read! We want ALRM to interrupt us */
+ n = read(read_fd, buf, 1);
+ alarm(0);
+ if (n == 1)
+ return (unsigned char)buf[0];
+ return -1;
+}
+
+static int receive(/*int read_fd, */int file_fd)
+{
+ unsigned char blockBuf[1024];
+ unsigned errors = 0;
+ unsigned wantBlockNo = 1;
+ unsigned length = 0;
+ int do_crc = 1;
+ char nak = 'C';
+ unsigned timeout = TIMEOUT_LONG;
+
+ /* Flush pending input */
+ tcflush(read_fd, TCIFLUSH);
+
+ /* Ask for CRC; if we get errors, we will go with checksum */
+ full_write(write_fd, &nak, 1);
+
+ for (;;) {
+ int blockBegin;
+ int blockNo, blockNoOnesCompl;
+ int blockLength;
+ int cksum_crc; /* cksum OR crc */
+ int expected;
+ int i,j;
+
+ blockBegin = read_byte(timeout);
+ if (blockBegin < 0)
+ goto timeout;
+
+ timeout = TIMEOUT;
+ nak = NAK;
+
+ switch (blockBegin) {
+ case SOH:
+ case STX:
+ break;
+
+ case EOT:
+ nak = ACK;
+ full_write(write_fd, &nak, 1);
+ return length;
+
+ default:
+ goto error;
+ }
+
+ /* block no */
+ blockNo = read_byte(TIMEOUT);
+ if (blockNo < 0)
+ goto timeout;
+
+ /* block no one's compliment */
+ blockNoOnesCompl = read_byte(TIMEOUT);
+ if (blockNoOnesCompl < 0)
+ goto timeout;
+
+ if (blockNo != (255 - blockNoOnesCompl)) {
+ bb_error_msg("bad block ones compl");
+ goto error;
+ }
+
+ blockLength = (blockBegin == SOH) ? 128 : 1024;
+
+ for (i = 0; i < blockLength; i++) {
+ int cc = read_byte(TIMEOUT);
+ if (cc < 0)
+ goto timeout;
+ blockBuf[i] = cc;
+ }
+
+ if (do_crc) {
+ cksum_crc = read_byte(TIMEOUT);
+ if (cksum_crc < 0)
+ goto timeout;
+ cksum_crc = (cksum_crc << 8) | read_byte(TIMEOUT);
+ if (cksum_crc < 0)
+ goto timeout;
+ } else {
+ cksum_crc = read_byte(TIMEOUT);
+ if (cksum_crc < 0)
+ goto timeout;
+ }
+
+ if (blockNo == ((wantBlockNo - 1) & 0xff)) {
+ /* a repeat of the last block is ok, just ignore it. */
+ /* this also ignores the initial block 0 which is */
+ /* meta data. */
+ goto next;
+ }
+ if (blockNo != (wantBlockNo & 0xff)) {
+ bb_error_msg("unexpected block no, 0x%08x, expecting 0x%08x", blockNo, wantBlockNo);
+ goto error;
+ }
+
+ expected = 0;
+ if (do_crc) {
+ for (i = 0; i < blockLength; i++) {
+ expected = expected ^ blockBuf[i] << 8;
+ for (j = 0; j < 8; j++) {
+ if (expected & 0x8000)
+ expected = expected << 1 ^ 0x1021;
+ else
+ expected = expected << 1;
+ }
+ }
+ expected &= 0xffff;
+ } else {
+ for (i = 0; i < blockLength; i++)
+ expected += blockBuf[i];
+ expected &= 0xff;
+ }
+ if (cksum_crc != expected) {
+ bb_error_msg(do_crc ? "crc error, expected 0x%04x, got 0x%04x"
+ : "checksum error, expected 0x%02x, got 0x%02x",
+ expected, cksum_crc);
+ goto error;
+ }
+
+ wantBlockNo++;
+ length += blockLength;
+
+ errno = 0;
+ if (full_write(file_fd, blockBuf, blockLength) != blockLength) {
+ bb_perror_msg("can't write to file");
+ goto fatal;
+ }
+ next:
+ errors = 0;
+ nak = ACK;
+ full_write(write_fd, &nak, 1);
+ continue;
+ error:
+ timeout:
+ errors++;
+ if (errors == MAXERRORS) {
+ /* Abort */
+
+ /* if were asking for crc, try again w/o crc */
+ if (nak == 'C') {
+ nak = NAK;
+ errors = 0;
+ do_crc = 0;
+ goto timeout;
+ }
+ bb_error_msg("too many errors; giving up");
+ fatal:
+ /* 5 CAN followed by 5 BS. Don't try too hard... */
+ safe_write(write_fd, "\030\030\030\030\030\010\010\010\010\010", 10);
+ return -1;
+ }
+
+ /* Flush pending input */
+ tcflush(read_fd, TCIFLUSH);
+
+ full_write(write_fd, &nak, 1);
+ } /* for (;;) */
+}
+
+static void sigalrm_handler(int ATTRIBUTE_UNUSED signum)
+{
+}
+
+int rx_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int rx_main(int argc, char **argv)
+{
+ struct termios tty, orig_tty;
+ int termios_err;
+ int file_fd;
+ int n;
+
+ if (argc != 2)
+ bb_show_usage();
+
+ /* Disabled by vda:
+ * why we can't receive from stdin? Why we *require*
+ * controlling tty?? */
+ /*read_fd = xopen(CURRENT_TTY, O_RDWR);*/
+ file_fd = xopen(argv[1], O_RDWR|O_CREAT|O_TRUNC);
+
+ termios_err = tcgetattr(read_fd, &tty);
+ if (termios_err == 0) {
+ orig_tty = tty;
+ cfmakeraw(&tty);
+ tcsetattr(read_fd, TCSAFLUSH, &tty);
+ }
+
+ /* No SA_RESTART: we want ALRM to interrupt read() */
+ signal_no_SA_RESTART_empty_mask(SIGALRM, sigalrm_handler);
+
+ n = receive(file_fd);
+
+ if (termios_err == 0)
+ tcsetattr(read_fd, TCSAFLUSH, &orig_tty);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close(file_fd);
+ fflush_stdout_and_exit(n >= 0);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/setsid.c b/cleopatre/busybox-1.11.1-spc300/miscutils/setsid.c
new file mode 100644
index 0000000000..014de51e51
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/setsid.c
@@ -0,0 +1,35 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * setsid.c -- execute a command in a new session
+ * Rick Sladkey <jrs@world.std.com>
+ * In the public domain.
+ *
+ * 1999-02-22 Arkadiusz Mickiewicz <misiek@pld.ORG.PL>
+ * - added Native Language Support
+ *
+ * 2001-01-18 John Fremlin <vii@penguinpowered.com>
+ * - fork in case we are process group leader
+ *
+ * 2004-11-12 Paul Fox
+ * - busyboxed
+ */
+
+#include "libbb.h"
+
+int setsid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int setsid_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ if (!argv[1])
+ bb_show_usage();
+
+ /* setsid() is allowed only when we are not a process group leader.
+ * Otherwise our PID serves as PGID of some existing process group
+ * and cannot be used as PGID of a new process group. */
+ if (getpgrp() == getpid())
+ forkexit_or_rexec(argv);
+
+ setsid(); /* no error possible */
+
+ BB_EXECVP(argv[1], argv + 1);
+ bb_simple_perror_msg_and_die(argv[1]);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/strings.c b/cleopatre/busybox-1.11.1-spc300/miscutils/strings.c
new file mode 100644
index 0000000000..1474137413
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/strings.c
@@ -0,0 +1,84 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * strings implementation for busybox
+ *
+ * Copyright Tito Ragusa <farmatito@tiscali.it>
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+
+#define WHOLE_FILE 1
+#define PRINT_NAME 2
+#define PRINT_OFFSET 4
+#define SIZE 8
+
+int strings_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int strings_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ int n, c, status = EXIT_SUCCESS;
+ unsigned opt;
+ unsigned count;
+ off_t offset;
+ FILE *file;
+ char *string;
+ const char *fmt = "%s: ";
+ const char *n_arg = "4";
+
+ opt = getopt32(argv, "afon:", &n_arg);
+ /* -a is our default behaviour */
+ /*argc -= optind;*/
+ argv += optind;
+
+ n = xatou_range(n_arg, 1, INT_MAX);
+ string = xzalloc(n + 1);
+ n--;
+
+ if (!*argv) {
+ fmt = "{%s}: ";
+ *--argv = (char *)bb_msg_standard_input;
+ }
+
+ do {
+ file = fopen_or_warn_stdin(*argv);
+ if (!file) {
+ status = EXIT_FAILURE;
+ continue;
+ }
+ offset = 0;
+ count = 0;
+ do {
+ c = fgetc(file);
+ if (isprint(c) || c == '\t') {
+ if (count > n) {
+ bb_putchar(c);
+ } else {
+ string[count] = c;
+ if (count == n) {
+ if (opt & PRINT_NAME) {
+ printf(fmt, *argv);
+ }
+ if (opt & PRINT_OFFSET) {
+ printf("%7"OFF_FMT"o ", offset - n);
+ }
+ fputs(string, stdout);
+ }
+ count++;
+ }
+ } else {
+ if (count > n) {
+ bb_putchar('\n');
+ }
+ count = 0;
+ }
+ offset++;
+ } while (c != EOF);
+ fclose_if_not_stdin(file);
+ } while (*++argv);
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(string);
+
+ fflush_stdout_and_exit(status);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/taskset.c b/cleopatre/busybox-1.11.1-spc300/miscutils/taskset.c
new file mode 100644
index 0000000000..708abd9f27
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/taskset.c
@@ -0,0 +1,115 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * taskset - retrieve or set a processes' CPU affinity
+ * Copyright (c) 2006 Bernhard Fischer
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include <sched.h>
+#include "libbb.h"
+
+#if ENABLE_FEATURE_TASKSET_FANCY
+#define TASKSET_PRINTF_MASK "%s"
+#define from_cpuset(x) __from_cpuset(&x)
+/* craft a string from the mask */
+static char *__from_cpuset(cpu_set_t *mask)
+{
+ int i;
+ char *ret = 0, *str = xzalloc(9);
+
+ for (i = CPU_SETSIZE - 4; i >= 0; i -= 4) {
+ char val = 0;
+ int off;
+ for (off = 0; off <= 3; ++off)
+ if (CPU_ISSET(i+off, mask))
+ val |= 1<<off;
+
+ if (!ret && val)
+ ret = str;
+ *str++ = (val-'0'<=9) ? (val+48) : (val+87);
+ }
+ return ret;
+}
+#else
+#define TASKSET_PRINTF_MASK "%x"
+/* (void*) cast is for battling gcc: */
+/* "dereferencing type-punned pointer will break strict-aliasing rules" */
+#define from_cpuset(mask) (*(unsigned*)(void*)&(mask))
+#endif
+
+
+int taskset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int taskset_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ cpu_set_t mask;
+ pid_t pid = 0;
+ unsigned opt_p;
+ const char *current_new;
+ char *pid_str;
+ char *aff = aff; /* for compiler */
+
+ /* NB: we mimic util-linux's taskset: -p does not take
+ * an argument, i.e., "-pN" is NOT valid, only "-p N"!
+ * Indeed, util-linux-2.13-pre7 uses:
+ * getopt_long(argc, argv, "+pchV", ...), not "...p:..." */
+
+ opt_complementary = "-1"; /* at least 1 arg */
+ opt_p = getopt32(argv, "+p");
+ argv += optind;
+
+ if (opt_p) {
+ pid_str = *argv++;
+ if (*argv) { /* "-p <aff> <pid> ...rest.is.ignored..." */
+ aff = pid_str;
+ pid_str = *argv; /* NB: *argv != NULL in this case */
+ }
+ /* else it was just "-p <pid>", and *argv == NULL */
+ pid = xatoul_range(pid_str, 1, ((unsigned)(pid_t)ULONG_MAX) >> 1);
+ } else {
+ aff = *argv++; /* <aff> <cmd...> */
+ if (!*argv)
+ bb_show_usage();
+ }
+
+ current_new = "current\0new";
+ if (opt_p) {
+ print_aff:
+ if (sched_getaffinity(pid, sizeof(mask), &mask) < 0)
+ bb_perror_msg_and_die("can't %cet pid %d's affinity", 'g', pid);
+ printf("pid %d's %s affinity mask: "TASKSET_PRINTF_MASK"\n",
+ pid, current_new, from_cpuset(mask));
+ if (!*argv) {
+ /* Either it was just "-p <pid>",
+ * or it was "-p <aff> <pid>" and we came here
+ * for the second time (see goto below) */
+ return EXIT_SUCCESS;
+ }
+ *argv = NULL;
+ current_new += 8; /* "new" */
+ }
+
+ { /* Affinity was specified, translate it into cpu_set_t */
+ unsigned i;
+ /* Do not allow zero mask: */
+ unsigned long long m = xstrtoull_range(aff, 0, 1, ULLONG_MAX);
+ enum { CNT_BIT = CPU_SETSIZE < sizeof(m)*8 ? CPU_SETSIZE : sizeof(m)*8 };
+
+ CPU_ZERO(&mask);
+ for (i = 0; i < CNT_BIT; i++) {
+ unsigned long long bit = (1ULL << i);
+ if (bit & m)
+ CPU_SET(i, &mask);
+ }
+ }
+
+ /* Set pid's or our own (pid==0) affinity */
+ if (sched_setaffinity(pid, sizeof(mask), &mask))
+ bb_perror_msg_and_die("can't %cet pid %d's affinity", 's', pid);
+
+ if (!*argv) /* "-p <aff> <pid> [...ignored...]" */
+ goto print_aff; /* print new affinity and exit */
+
+ BB_EXECVP(*argv, argv);
+ bb_simple_perror_msg_and_die(*argv);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/time.c b/cleopatre/busybox-1.11.1-spc300/miscutils/time.c
new file mode 100644
index 0000000000..a6d158c53d
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/time.c
@@ -0,0 +1,428 @@
+/* vi: set sw=4 ts=4: */
+/* 'time' utility to display resource usage of processes.
+ Copyright (C) 1990, 91, 92, 93, 96 Free Software Foundation, Inc.
+
+ Licensed under GPL version 2, see file LICENSE in this tarball for details.
+*/
+/* Originally written by David Keppel <pardo@cs.washington.edu>.
+ Heavily modified by David MacKenzie <djm@gnu.ai.mit.edu>.
+ Heavily modified for busybox by Erik Andersen <andersen@codepoet.org>
+*/
+
+#include "libbb.h"
+
+/* Information on the resources used by a child process. */
+typedef struct {
+ int waitstatus;
+ struct rusage ru;
+ unsigned elapsed_ms; /* Wallclock time of process. */
+} resource_t;
+
+/* msec = milliseconds = 1/1,000 (1*10e-3) second.
+ usec = microseconds = 1/1,000,000 (1*10e-6) second. */
+
+#define UL unsigned long
+
+static const char default_format[] ALIGN1 = "real\t%E\nuser\t%u\nsys\t%T";
+
+/* The output format for the -p option .*/
+static const char posix_format[] ALIGN1 = "real %e\nuser %U\nsys %S";
+
+/* Format string for printing all statistics verbosely.
+ Keep this output to 24 lines so users on terminals can see it all.*/
+static const char long_format[] ALIGN1 =
+ "\tCommand being timed: \"%C\"\n"
+ "\tUser time (seconds): %U\n"
+ "\tSystem time (seconds): %S\n"
+ "\tPercent of CPU this job got: %P\n"
+ "\tElapsed (wall clock) time (h:mm:ss or m:ss): %E\n"
+ "\tAverage shared text size (kbytes): %X\n"
+ "\tAverage unshared data size (kbytes): %D\n"
+ "\tAverage stack size (kbytes): %p\n"
+ "\tAverage total size (kbytes): %K\n"
+ "\tMaximum resident set size (kbytes): %M\n"
+ "\tAverage resident set size (kbytes): %t\n"
+ "\tMajor (requiring I/O) page faults: %F\n"
+ "\tMinor (reclaiming a frame) page faults: %R\n"
+ "\tVoluntary context switches: %w\n"
+ "\tInvoluntary context switches: %c\n"
+ "\tSwaps: %W\n"
+ "\tFile system inputs: %I\n"
+ "\tFile system outputs: %O\n"
+ "\tSocket messages sent: %s\n"
+ "\tSocket messages received: %r\n"
+ "\tSignals delivered: %k\n"
+ "\tPage size (bytes): %Z\n"
+ "\tExit status: %x";
+
+/* Wait for and fill in data on child process PID.
+ Return 0 on error, 1 if ok. */
+/* pid_t is short on BSDI, so don't try to promote it. */
+static void resuse_end(pid_t pid, resource_t *resp)
+{
+ pid_t caught;
+
+ /* Ignore signals, but don't ignore the children. When wait3
+ returns the child process, set the time the command finished. */
+ while ((caught = wait3(&resp->waitstatus, 0, &resp->ru)) != pid) {
+ if (caught == -1 && errno != EINTR) {
+ bb_perror_msg("wait");
+ return;
+ }
+ }
+ resp->elapsed_ms = (monotonic_us() / 1000) - resp->elapsed_ms;
+}
+
+static void printargv(char *const *argv)
+{
+ const char *fmt = " %s" + 1;
+ do {
+ printf(fmt, *argv);
+ fmt = " %s";
+ } while (*++argv);
+}
+
+/* Return the number of kilobytes corresponding to a number of pages PAGES.
+ (Actually, we use it to convert pages*ticks into kilobytes*ticks.)
+
+ Try to do arithmetic so that the risk of overflow errors is minimized.
+ This is funky since the pagesize could be less than 1K.
+ Note: Some machines express getrusage statistics in terms of K,
+ others in terms of pages. */
+static unsigned long ptok(unsigned pagesize, unsigned long pages)
+{
+ unsigned long tmp;
+
+ /* Conversion. */
+ if (pages > (LONG_MAX / pagesize)) { /* Could overflow. */
+ tmp = pages / 1024; /* Smaller first, */
+ return tmp * pagesize; /* then larger. */
+ }
+ /* Could underflow. */
+ tmp = pages * pagesize; /* Larger first, */
+ return tmp / 1024; /* then smaller. */
+}
+
+/* summarize: Report on the system use of a command.
+
+ Print the FMT argument except that `%' sequences
+ have special meaning, and `\n' and `\t' are translated into
+ newline and tab, respectively, and `\\' is translated into `\'.
+
+ The character following a `%' can be:
+ (* means the tcsh time builtin also recognizes it)
+ % == a literal `%'
+ C == command name and arguments
+* D == average unshared data size in K (ru_idrss+ru_isrss)
+* E == elapsed real (wall clock) time in [hour:]min:sec
+* F == major page faults (required physical I/O) (ru_majflt)
+* I == file system inputs (ru_inblock)
+* K == average total mem usage (ru_idrss+ru_isrss+ru_ixrss)
+* M == maximum resident set size in K (ru_maxrss)
+* O == file system outputs (ru_oublock)
+* P == percent of CPU this job got (total cpu time / elapsed time)
+* R == minor page faults (reclaims; no physical I/O involved) (ru_minflt)
+* S == system (kernel) time (seconds) (ru_stime)
+* T == system time in [hour:]min:sec
+* U == user time (seconds) (ru_utime)
+* u == user time in [hour:]min:sec
+* W == times swapped out (ru_nswap)
+* X == average amount of shared text in K (ru_ixrss)
+ Z == page size
+* c == involuntary context switches (ru_nivcsw)
+ e == elapsed real time in seconds
+* k == signals delivered (ru_nsignals)
+ p == average unshared stack size in K (ru_isrss)
+* r == socket messages received (ru_msgrcv)
+* s == socket messages sent (ru_msgsnd)
+ t == average resident set size in K (ru_idrss)
+* w == voluntary context switches (ru_nvcsw)
+ x == exit status of command
+
+ Various memory usages are found by converting from page-seconds
+ to kbytes by multiplying by the page size, dividing by 1024,
+ and dividing by elapsed real time.
+
+ FMT is the format string, interpreted as described above.
+ COMMAND is the command and args that are being summarized.
+ RESP is resource information on the command. */
+
+#ifndef TICKS_PER_SEC
+#define TICKS_PER_SEC 100
+#endif
+
+static void summarize(const char *fmt, char **command, resource_t *resp)
+{
+ unsigned vv_ms; /* Elapsed virtual (CPU) milliseconds */
+ unsigned cpu_ticks; /* Same, in "CPU ticks" */
+ unsigned pagesize = getpagesize();
+
+ /* Impossible: we do not use WUNTRACED flag in wait()...
+ if (WIFSTOPPED(resp->waitstatus))
+ printf("Command stopped by signal %u\n",
+ WSTOPSIG(resp->waitstatus));
+ else */
+ if (WIFSIGNALED(resp->waitstatus))
+ printf("Command terminated by signal %u\n",
+ WTERMSIG(resp->waitstatus));
+ else if (WIFEXITED(resp->waitstatus) && WEXITSTATUS(resp->waitstatus))
+ printf("Command exited with non-zero status %u\n",
+ WEXITSTATUS(resp->waitstatus));
+
+ vv_ms = (resp->ru.ru_utime.tv_sec + resp->ru.ru_stime.tv_sec) * 1000
+ + (resp->ru.ru_utime.tv_usec + resp->ru.ru_stime.tv_usec) / 1000;
+
+#if (1000 / TICKS_PER_SEC) * TICKS_PER_SEC == 1000
+ /* 1000 is exactly divisible by TICKS_PER_SEC (typical) */
+ cpu_ticks = vv_ms / (1000 / TICKS_PER_SEC);
+#else
+ cpu_ticks = vv_ms * (unsigned long long)TICKS_PER_SEC / 1000;
+#endif
+ if (!cpu_ticks) cpu_ticks = 1; /* we divide by it, must be nonzero */
+
+ while (*fmt) {
+ /* Handle leading literal part */
+ int n = strcspn(fmt, "%\\");
+ if (n) {
+ printf("%.*s", n, fmt);
+ fmt += n;
+ continue;
+ }
+
+ switch (*fmt) {
+#ifdef NOT_NEEDED
+ /* Handle literal char */
+ /* Usually we optimize for size, but there is a limit
+ * for everything. With this we do a lot of 1-byte writes */
+ default:
+ bb_putchar(*fmt);
+ break;
+#endif
+
+ case '%':
+ switch (*++fmt) {
+#ifdef NOT_NEEDED_YET
+ /* Our format strings do not have these */
+ /* and we do not take format str from user */
+ default:
+ bb_putchar('%');
+ /*FALLTHROUGH*/
+ case '%':
+ if (!*fmt) goto ret;
+ bb_putchar(*fmt);
+ break;
+#endif
+ case 'C': /* The command that got timed. */
+ printargv(command);
+ break;
+ case 'D': /* Average unshared data size. */
+ printf("%lu",
+ (ptok(pagesize, (UL) resp->ru.ru_idrss) +
+ ptok(pagesize, (UL) resp->ru.ru_isrss)) / cpu_ticks);
+ break;
+ case 'E': { /* Elapsed real (wall clock) time. */
+ unsigned seconds = resp->elapsed_ms / 1000;
+ if (seconds >= 3600) /* One hour -> h:m:s. */
+ printf("%uh %um %02us",
+ seconds / 3600,
+ (seconds % 3600) / 60,
+ seconds % 60);
+ else
+ printf("%um %u.%02us", /* -> m:s. */
+ seconds / 60,
+ seconds % 60,
+ (unsigned)(resp->elapsed_ms / 10) % 100);
+ break;
+ }
+ case 'F': /* Major page faults. */
+ printf("%lu", resp->ru.ru_majflt);
+ break;
+ case 'I': /* Inputs. */
+ printf("%lu", resp->ru.ru_inblock);
+ break;
+ case 'K': /* Average mem usage == data+stack+text. */
+ printf("%lu",
+ (ptok(pagesize, (UL) resp->ru.ru_idrss) +
+ ptok(pagesize, (UL) resp->ru.ru_isrss) +
+ ptok(pagesize, (UL) resp->ru.ru_ixrss)) / cpu_ticks);
+ break;
+ case 'M': /* Maximum resident set size. */
+ printf("%lu", ptok(pagesize, (UL) resp->ru.ru_maxrss));
+ break;
+ case 'O': /* Outputs. */
+ printf("%lu", resp->ru.ru_oublock);
+ break;
+ case 'P': /* Percent of CPU this job got. */
+ /* % cpu is (total cpu time)/(elapsed time). */
+ if (resp->elapsed_ms > 0)
+ printf("%u%%", (unsigned)(vv_ms * 100 / resp->elapsed_ms));
+ else
+ printf("?%%");
+ break;
+ case 'R': /* Minor page faults (reclaims). */
+ printf("%lu", resp->ru.ru_minflt);
+ break;
+ case 'S': /* System time. */
+ printf("%u.%02u",
+ (unsigned)resp->ru.ru_stime.tv_sec,
+ (unsigned)(resp->ru.ru_stime.tv_usec / 10000));
+ break;
+ case 'T': /* System time. */
+ if (resp->ru.ru_stime.tv_sec >= 3600) /* One hour -> h:m:s. */
+ printf("%uh %um %02us",
+ (unsigned)(resp->ru.ru_stime.tv_sec / 3600),
+ (unsigned)(resp->ru.ru_stime.tv_sec % 3600) / 60,
+ (unsigned)(resp->ru.ru_stime.tv_sec % 60));
+ else
+ printf("%um %u.%02us", /* -> m:s. */
+ (unsigned)(resp->ru.ru_stime.tv_sec / 60),
+ (unsigned)(resp->ru.ru_stime.tv_sec % 60),
+ (unsigned)(resp->ru.ru_stime.tv_usec / 10000));
+ break;
+ case 'U': /* User time. */
+ printf("%u.%02u",
+ (unsigned)resp->ru.ru_utime.tv_sec,
+ (unsigned)(resp->ru.ru_utime.tv_usec / 10000));
+ break;
+ case 'u': /* User time. */
+ if (resp->ru.ru_utime.tv_sec >= 3600) /* One hour -> h:m:s. */
+ printf("%uh %um %02us",
+ (unsigned)(resp->ru.ru_utime.tv_sec / 3600),
+ (unsigned)(resp->ru.ru_utime.tv_sec % 3600) / 60,
+ (unsigned)(resp->ru.ru_utime.tv_sec % 60));
+ else
+ printf("%um %u.%02us", /* -> m:s. */
+ (unsigned)(resp->ru.ru_utime.tv_sec / 60),
+ (unsigned)(resp->ru.ru_utime.tv_sec % 60),
+ (unsigned)(resp->ru.ru_utime.tv_usec / 10000));
+ break;
+ case 'W': /* Times swapped out. */
+ printf("%lu", resp->ru.ru_nswap);
+ break;
+ case 'X': /* Average shared text size. */
+ printf("%lu", ptok(pagesize, (UL) resp->ru.ru_ixrss) / cpu_ticks);
+ break;
+ case 'Z': /* Page size. */
+ printf("%u", getpagesize());
+ break;
+ case 'c': /* Involuntary context switches. */
+ printf("%lu", resp->ru.ru_nivcsw);
+ break;
+ case 'e': /* Elapsed real time in seconds. */
+ printf("%u.%02u",
+ (unsigned)resp->elapsed_ms / 1000,
+ (unsigned)(resp->elapsed_ms / 10) % 100);
+ break;
+ case 'k': /* Signals delivered. */
+ printf("%lu", resp->ru.ru_nsignals);
+ break;
+ case 'p': /* Average stack segment. */
+ printf("%lu", ptok(pagesize, (UL) resp->ru.ru_isrss) / cpu_ticks);
+ break;
+ case 'r': /* Incoming socket messages received. */
+ printf("%lu", resp->ru.ru_msgrcv);
+ break;
+ case 's': /* Outgoing socket messages sent. */
+ printf("%lu", resp->ru.ru_msgsnd);
+ break;
+ case 't': /* Average resident set size. */
+ printf("%lu", ptok(pagesize, (UL) resp->ru.ru_idrss) / cpu_ticks);
+ break;
+ case 'w': /* Voluntary context switches. */
+ printf("%lu", resp->ru.ru_nvcsw);
+ break;
+ case 'x': /* Exit status. */
+ printf("%u", WEXITSTATUS(resp->waitstatus));
+ break;
+ }
+ break;
+
+#ifdef NOT_NEEDED_YET
+ case '\\': /* Format escape. */
+ switch (*++fmt) {
+ default:
+ bb_putchar('\\');
+ /*FALLTHROUGH*/
+ case '\\':
+ if (!*fmt) goto ret;
+ bb_putchar(*fmt);
+ break;
+ case 't':
+ bb_putchar('\t');
+ break;
+ case 'n':
+ bb_putchar('\n');
+ break;
+ }
+ break;
+#endif
+ }
+ ++fmt;
+ }
+ /* ret: */
+ bb_putchar('\n');
+}
+
+/* Run command CMD and return statistics on it.
+ Put the statistics in *RESP. */
+static void run_command(char *const *cmd, resource_t *resp)
+{
+ pid_t pid; /* Pid of child. */
+ void (*interrupt_signal)(int);
+ void (*quit_signal)(int);
+
+ resp->elapsed_ms = monotonic_us() / 1000;
+ pid = vfork(); /* Run CMD as child process. */
+ if (pid < 0)
+ bb_error_msg_and_die("cannot fork");
+ if (pid == 0) { /* If child. */
+ /* Don't cast execvp arguments; that causes errors on some systems,
+ versus merely warnings if the cast is left off. */
+ BB_EXECVP(cmd[0], cmd);
+ xfunc_error_retval = (errno == ENOENT ? 127 : 126);
+ bb_error_msg_and_die("cannot run %s", cmd[0]);
+ }
+
+ /* Have signals kill the child but not self (if possible). */
+//TODO: just block all sigs? and reenable them in the very end in main?
+ interrupt_signal = signal(SIGINT, SIG_IGN);
+ quit_signal = signal(SIGQUIT, SIG_IGN);
+
+ resuse_end(pid, resp);
+
+ /* Re-enable signals. */
+ signal(SIGINT, interrupt_signal);
+ signal(SIGQUIT, quit_signal);
+}
+
+int time_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int time_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ resource_t res;
+ const char *output_format = default_format;
+ int opt;
+
+ /* "+": stop on first non-option */
+ opt = getopt32(argv, "+vp");
+ argv += optind;
+ if (opt & 1)
+ output_format = long_format;
+ if (opt & 2)
+ output_format = posix_format;
+
+ run_command(argv, &res);
+
+ /* Cheat. printf's are shorter :) */
+ /* (but see bb_putchar() body for additional wrinkle!) */
+ xdup2(2, 1); /* just in case libc does something silly :( */
+ stdout = stderr;
+ summarize(output_format, argv, &res);
+
+ if (WIFSTOPPED(res.waitstatus))
+ return WSTOPSIG(res.waitstatus);
+ if (WIFSIGNALED(res.waitstatus))
+ return WTERMSIG(res.waitstatus);
+ if (WIFEXITED(res.waitstatus))
+ return WEXITSTATUS(res.waitstatus);
+ fflush_stdout_and_exit(EXIT_SUCCESS);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/ttysize.c b/cleopatre/busybox-1.11.1-spc300/miscutils/ttysize.c
new file mode 100644
index 0000000000..05455543df
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/ttysize.c
@@ -0,0 +1,44 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Replacement for "stty size", which is awkward for shell script use.
+ * - Allows to request width, height, or both, in any order.
+ * - Does not complain on error, but returns width 80, height 24.
+ * - Size: less than 200 bytes
+ *
+ * Copyright (C) 2007 by Denys Vlasenko <vda.linux@googlemail.com>
+ *
+ * Licensed under the GPL v2, see the file LICENSE in this tarball.
+ */
+#include "libbb.h"
+
+int ttysize_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int ttysize_main(int argc, char **argv)
+{
+ unsigned w, h;
+ struct winsize wsz;
+
+ w = 80;
+ h = 24;
+ if (!ioctl(0, TIOCGWINSZ, &wsz)) {
+ w = wsz.ws_col;
+ h = wsz.ws_row;
+ }
+
+ if (argc == 1) {
+ printf("%u %u", w, h);
+ } else {
+ const char *fmt, *arg;
+
+ fmt = "%u %u" + 3; /* "%u" */
+ while ((arg = *++argv) != NULL) {
+ char c = arg[0];
+ if (c == 'w')
+ printf(fmt, w);
+ if (c == 'h')
+ printf(fmt, h);
+ fmt = "%u %u" + 2; /* " %u" */
+ }
+ }
+ bb_putchar('\n');
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/miscutils/watchdog.c b/cleopatre/busybox-1.11.1-spc300/miscutils/watchdog.c
new file mode 100644
index 0000000000..4ad21cbc9f
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/miscutils/watchdog.c
@@ -0,0 +1,71 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini watchdog implementation for busybox
+ *
+ * Copyright (C) 2003 Paul Mundt <lethal@linux-sh.org>
+ * Copyright (C) 2006 Bernhard Fischer <busybox@busybox.net>
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+
+#define OPT_FOREGROUND 0x01
+#define OPT_TIMER 0x02
+
+static void watchdog_shutdown(int sig ATTRIBUTE_UNUSED)
+{
+ static const char V = 'V';
+
+ write(3, &V, 1); /* Magic, see watchdog-api.txt in kernel */
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close(3);
+ exit(EXIT_SUCCESS);
+}
+
+int watchdog_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int watchdog_main(int argc, char **argv)
+{
+ unsigned opts;
+ unsigned timer_duration = 30000; /* Userspace timer duration, in milliseconds */
+ char *t_arg;
+
+ opt_complementary = "=1"; /* must have 1 argument */
+ opts = getopt32(argv, "Ft:", &t_arg);
+
+ if (opts & OPT_TIMER) {
+ static const struct suffix_mult suffixes[] = {
+ { "ms", 1 },
+ { "", 1000 },
+ { }
+ };
+ timer_duration = xatou_sfx(t_arg, suffixes);
+ }
+
+ if (!(opts & OPT_FOREGROUND)) {
+ bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv);
+ }
+
+ bb_signals(BB_FATAL_SIGS, watchdog_shutdown);
+
+ /* Use known fd # - avoid needing global 'int fd' */
+ xmove_fd(xopen(argv[argc - 1], O_WRONLY), 3);
+
+// TODO?
+// if (!(opts & OPT_TIMER)) {
+// if (ioctl(fd, WDIOC_GETTIMEOUT, &timer_duration) == 0)
+// timer_duration *= 500;
+// else
+// timer_duration = 30000;
+// }
+
+ while (1) {
+ /*
+ * Make sure we clear the counter before sleeping, as the counter value
+ * is undefined at this point -- PFM
+ */
+ write(3, "", 1); /* write zero byte */
+ usleep(timer_duration * 1000L);
+ }
+ return EXIT_SUCCESS; /* - not reached, but gcc 4.2.1 is too dumb! */
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/modutils/Config.in b/cleopatre/busybox-1.11.1-spc300/modutils/Config.in
new file mode 100644
index 0000000000..2b0bcdd6ea
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/modutils/Config.in
@@ -0,0 +1,218 @@
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Linux Module Utilities"
+
+config DEPMOD
+ bool "depmod"
+ default n
+ help
+ depmod generates modules.dep (FIXME: elaborate)
+
+config FEATURE_DEPMOD_PRUNE_FANCY
+ bool "fancy dependency pruning"
+ default n
+ depends on DEPMOD
+ help
+ By default modules.dep contains all dependencies as listed by
+ the modules.
+ If you enable this option then we remove implied modules from
+ the dependencies.
+ This makes depmod somewhat bigger but generates a smaller
+ modules.dep file.
+
+ If unsure, say N.
+
+config FEATURE_DEPMOD_ALIAS
+ bool "alias support"
+ default n
+ depends on DEPMOD
+ help
+ By default modules.dep does not contain alias information.
+ Enable this to emit aliases of the form:
+
+ alias pcmcia:m*c*f03fn*pfn*pa*pb*pc*pd* parport_cs
+
+config INSMOD
+ bool "insmod"
+ default n
+ help
+ insmod is used to load specified modules in the running kernel.
+
+config FEATURE_INSMOD_VERSION_CHECKING
+ bool "Module version checking"
+ default n
+ depends on INSMOD && FEATURE_2_4_MODULES
+ help
+ Support checking of versions for modules. This is used to
+ ensure that the kernel and module are made for each other.
+
+config FEATURE_INSMOD_KSYMOOPS_SYMBOLS
+ bool "Add module symbols to kernel symbol table"
+ default n
+ depends on INSMOD && FEATURE_2_4_MODULES
+ help
+ By adding module symbols to the kernel symbol table, Oops messages
+ occuring within kernel modules can be properly debugged. By enabling
+ this feature, module symbols will always be added to the kernel symbol
+ table for properly debugging support. If you are not interested in
+ Oops messages from kernel modules, say N.
+
+config FEATURE_INSMOD_LOADINKMEM
+ bool "In kernel memory optimization (uClinux only)"
+ default n
+ depends on INSMOD && FEATURE_2_4_MODULES
+ help
+ This is a special uClinux only memory optimization that lets insmod
+ load the specified kernel module directly into kernel space, reducing
+ memory usage by preventing the need for two copies of the module
+ being loaded into memory.
+
+config FEATURE_INSMOD_LOAD_MAP
+ bool "Enable load map (-m) option"
+ default n
+ depends on INSMOD && ( FEATURE_2_4_MODULES || FEATURE_2_6_MODULES )
+ help
+ Enabling this, one would be able to get a load map
+ output on stdout. This makes kernel module debugging
+ easier.
+ If you don't plan to debug kernel modules, you
+ don't need this option.
+
+config FEATURE_INSMOD_LOAD_MAP_FULL
+ bool "Symbols in load map"
+ default y
+ depends on FEATURE_INSMOD_LOAD_MAP
+ help
+ Without this option, -m will only output section
+ load map. With this option, -m will also output
+ symbols load map.
+
+config RMMOD
+ bool "rmmod"
+ default n
+ help
+ rmmod is used to unload specified modules from the kernel.
+
+config LSMOD
+ bool "lsmod"
+ default n
+ help
+ lsmod is used to display a list of loaded modules.
+
+config FEATURE_LSMOD_PRETTY_2_6_OUTPUT
+ bool "Pretty output for 2.6.x Linux kernels"
+ default n
+ depends on LSMOD
+ help
+ This option makes output format of lsmod adjusted to
+ the format of module-init-tools for Linux kernel 2.6.
+
+config MODPROBE
+ bool "modprobe"
+ default n
+ help
+ Handle the loading of modules, and their dependencies on a high
+ level.
+
+ Note that in the state, modprobe does not understand multiple
+ module options from the configuration file. See option below.
+
+config FEATURE_MODPROBE_MULTIPLE_OPTIONS
+ bool
+ prompt "Multiple options parsing"
+ default y
+ depends on MODPROBE
+ help
+ Allow modprobe to understand more than one option to pass to
+ modules.
+
+ This is a WIP, while waiting for a common argument parsing
+ common amongst all BB applets (shell, modprobe, etc...) and
+ adds around 600 bytes on x86, 700 bytes on ARM. The code is
+ biggish and uggly, but just works.
+
+ Saying Y here is not a bad idea if you're not that short
+ on storage capacity.
+
+config FEATURE_MODPROBE_FANCY_ALIAS
+ bool
+ prompt "Fancy alias parsing"
+ default y
+ depends on MODPROBE && FEATURE_2_6_MODULES
+ help
+ Say 'y' here to enable parsing of aliases with underscore/dash
+ mismatch between module name and file name, along with bus-specific
+ aliases (such as pci:... or usb:... aliases).
+
+config FEATURE_MODPROBE_BLACKLIST
+ bool
+ prompt "Blacklist support"
+ default n
+ depends on MODPROBE && FEATURE_2_6_MODULES
+ help
+ Say 'y' here to enable support for the 'blacklist' command in
+ modprobe.conf. This prevents the alias resolver to resolve
+ blacklisted modules. This is useful if you want to prevent your
+ hardware autodetection scripts to load modules like evdev, frame
+ buffer drivers etc.
+
+comment "Options common to multiple modutils"
+ depends on INSMOD || RMMOD || MODPROBE || LSMOD || DEPMOD
+
+config FEATURE_CHECK_TAINTED_MODULE
+ # Simulate indentation
+ bool "Support tainted module checking with new kernels"
+ default y
+ depends on INSMOD || LSMOD
+ help
+ Support checking for tainted modules. These are usually binary
+ only modules that will make the linux-kernel list ignore your
+ support request.
+ This option is required to support GPLONLY modules.
+
+config FEATURE_2_4_MODULES
+ # Simulate indentation
+ bool "Support version 2.2.x to 2.4.x Linux kernels"
+ default y
+ depends on INSMOD || RMMOD || MODPROBE
+ help
+ Support module loading for 2.2.x and 2.4.x Linux kernels.
+
+ Note:
+ This is automatically enabled if 2.6 modules are not enabled.
+
+config FEATURE_2_6_MODULES
+ # Simulate indentation
+ bool "Support version 2.6.x Linux kernels"
+ default y
+ depends on INSMOD || RMMOD || MODPROBE
+ help
+ Support module loading for newer 2.6.x Linux kernels.
+
+config DEFAULT_MODULES_DIR
+ # Simulate indentation
+ string "Default directory containing modules"
+ default "/lib/modules"
+ depends on INSMOD || RMMOD || MODPROBE || DEPMOD
+ help
+ Directory that contains kernel modules.
+ Defaults to "/lib/modules"
+
+config DEFAULT_DEPMOD_FILE
+ # Simulate indentation
+ string "Default name of modules.dep"
+ default "modules.dep"
+ depends on INSMOD || RMMOD || MODPROBE || DEPMOD
+ help
+ Filename that contains kernel modules dependencies.
+ Defaults to "modules.dep"
+
+config FEATURE_QUERY_MODULE_INTERFACE
+ bool
+ default y
+ depends on FEATURE_2_4_MODULES && !FEATURE_2_6_MODULES
+
+endmenu
diff --git a/cleopatre/busybox-1.11.1-spc300/modutils/Kbuild b/cleopatre/busybox-1.11.1-spc300/modutils/Kbuild
new file mode 100644
index 0000000000..40ea0efbe2
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/modutils/Kbuild
@@ -0,0 +1,12 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+lib-y:=
+lib-$(CONFIG_DEPMOD) += depmod.o
+lib-$(CONFIG_INSMOD) += insmod.o
+lib-$(CONFIG_LSMOD) += lsmod.o
+lib-$(CONFIG_MODPROBE) += modprobe.o
+lib-$(CONFIG_RMMOD) += rmmod.o
diff --git a/cleopatre/busybox-1.11.1-spc300/modutils/depmod.c b/cleopatre/busybox-1.11.1-spc300/modutils/depmod.c
new file mode 100644
index 0000000000..fdeb7dcf18
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/modutils/depmod.c
@@ -0,0 +1,288 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * depmod - generate modules.dep
+ * Copyright (c) 2008 Bernhard Fischer
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#undef _GNU_SOURCE
+#define _GNU_SOURCE
+#include <libbb.h>
+#include <sys/utsname.h> /* uname() */
+/*
+ * Theory of operation:
+ * - iterate over all modules and record their full path
+ * - iterate over all modules looking for "depends=" entries
+ * for each depends, look through our list of full paths and emit if found
+ */
+
+typedef struct dep_lst_t {
+ char *name;
+ llist_t *dependencies;
+ llist_t *aliases;
+ struct dep_lst_t *next;
+} dep_lst_t;
+
+struct globals {
+ dep_lst_t *lst; /* modules without their corresponding extension */
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+/* We have to zero it out because of NOEXEC */
+#define INIT_G() memset(&G, 0, sizeof(G))
+
+static char* find_keyword(void *the_module, size_t len, const char * const word)
+{
+ char *ptr = the_module;
+ do {
+ /* search for the first char in word */
+ ptr = memchr(ptr, *word, len - (ptr - (char*)the_module));
+ if (ptr == NULL) /* no occurance left, done */
+ return NULL;
+ if (!strncmp(ptr, word, strlen(word))) {
+ ptr += strlen(word);
+ break;
+ }
+ ++ptr;
+ } while (1);
+ return ptr;
+}
+static int fileAction(const char *fname, struct stat *sb,
+ void ATTRIBUTE_UNUSED *data, int ATTRIBUTE_UNUSED depth)
+{
+ size_t len = sb->st_size;
+ void *the_module;
+ char *ptr;
+ int fd;
+ char *depends, *deps;
+ dep_lst_t *this;
+
+ if (strrstr(fname, ".ko") == NULL) /* not a module */
+ goto skip;
+
+/*XXX: FIXME: does not handle compressed modules!
+ * There should be a function that looks at the extension and sets up
+ * open_transformer for us.
+ */
+ fd = xopen(fname, O_RDONLY);
+ the_module = mmap(NULL, len, PROT_READ, MAP_SHARED
+#if defined MAP_POPULATE
+ |MAP_POPULATE
+#endif
+ , fd, 0);
+ close(fd);
+ if (the_module == MAP_FAILED)
+ bb_perror_msg_and_die("mmap");
+
+ this = xzalloc(sizeof(dep_lst_t));
+ this->name = xstrdup(fname);
+ this->next = G.lst;
+ G.lst = this;
+//bb_info_msg("fname='%s'", fname);
+ ptr = find_keyword(the_module, len, "depends=");
+ if (!*ptr)
+ goto d_none;
+ deps = depends = xstrdup(ptr);
+//bb_info_msg(" depends='%s'", depends);
+ while (deps) {
+ ptr = strsep(&deps, ",");
+//bb_info_msg("[%s] -> '%s'", fname, (char*)ptr);
+ llist_add_to_end(&this->dependencies, xstrdup(ptr));
+ }
+ free(depends);
+ d_none:
+ if (ENABLE_FEATURE_DEPMOD_ALIAS)
+ {
+ size_t pos = 0;
+ do {
+ ptr = find_keyword(the_module + pos, len - pos, "alias=");
+ if (ptr) {
+//bb_info_msg("[%s] alias '%s'", fname, (char*)ptr);
+ llist_add_to_end(&this->aliases, xstrdup(ptr));
+ } else
+ break;
+ pos = (ptr - (char*)the_module);
+ } while (1);
+ }
+ munmap(the_module, sb->st_size);
+ skip:
+ return TRUE;
+}
+
+int depmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int depmod_main(int ATTRIBUTE_UNUSED argc, char **argv)
+{
+ int ret;
+ size_t moddir_base_len = 0; /* length of the "-b basedir" */
+ char *moddir_base = NULL, *moddir, *system_map, *chp;
+ FILE *filedes = stdout;
+ enum {
+ ARG_a = (1<<0), /* All modules, ignore mods in argv */
+ ARG_A = (1<<1), /* Only emit .ko that are newer than modules.dep file */
+ ARG_b = (1<<2), /* not /lib/modules/$(uname -r)/ but this base-dir */
+ ARG_e = (1<<3), /* with -F, print unresolved symbols */
+ ARG_F = (1<<4), /* System.map that contains the symbols */
+ ARG_n = (1<<5) /* dry-run, print to stdout only */
+ };
+ INIT_G();
+
+ getopt32(argv, "aAb:eF:n", &moddir_base, &system_map);
+ argv += optind;
+
+ /* If a version is provided, then that kernel version’s module directory
+ * is used, rather than the current kernel version (as returned by
+ * "uname -r"). */
+ if (*argv && (sscanf(*argv, "%d.%d.%d", &ret, &ret, &ret) == 3)) {
+ moddir = concat_path_file(CONFIG_DEFAULT_MODULES_DIR, *argv++);
+ } else {
+ struct utsname uts;
+ if (uname(&uts) < 0)
+ bb_simple_perror_msg_and_die("uname");
+ moddir = concat_path_file(CONFIG_DEFAULT_MODULES_DIR, uts.release);
+ }
+ /* If no modules are given on the command-line, -a is on per default. */
+ option_mask32 |= *argv == NULL;
+
+ if (option_mask32 & ARG_b) {
+ moddir_base_len = strlen(moddir_base) + 1;
+ xchdir(moddir_base);
+ }
+
+ if (!(option_mask32 & ARG_n)) { /* --dry-run */
+ chp = concat_path_file(moddir, CONFIG_DEFAULT_DEPMOD_FILE);
+ filedes = xfopen(chp, "w");
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(chp);
+ }
+ ret = EXIT_SUCCESS;
+ do {
+ chp = option_mask32 & ARG_a ? moddir : (*argv + moddir_base_len);
+
+ if (!recursive_action(chp,
+ ACTION_RECURSE, /* flags */
+ fileAction, /* file action */
+ NULL, /* dir action */
+ NULL, /* user data */
+ 0)) { /* depth */
+ ret = EXIT_FAILURE;
+ }
+ } while (!(option_mask32 & ARG_a) && *++argv);
+
+ {
+ dep_lst_t *mods = G.lst;
+
+ /* Fixup the module names in the depends list */
+ while (mods) {
+ llist_t *deps = NULL, *old_deps = mods->dependencies;
+
+ while (old_deps) {
+ dep_lst_t *all = G.lst;
+ char *longname = NULL;
+ char *shortname = llist_pop(&old_deps);
+
+ while (all) {
+ char *nam =
+ xstrdup(bb_get_last_path_component_nostrip(all->name));
+ char *tmp = strrstr(nam, ".ko");
+
+ *tmp = '\0';
+ if (!strcmp(nam, shortname)) {
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(nam);
+ longname = all->name;
+ break;
+ }
+ free(nam);
+ all = all->next;
+ }
+ llist_add_to_end(&deps, longname);
+ }
+ mods->dependencies = deps;
+ mods = mods->next;
+ }
+
+#if ENABLE_FEATURE_DEPMOD_PRUNE_FANCY
+ /* modprobe allegedly wants dependencies without duplicates, i.e.
+ * mod1: mod2 mod3
+ * mod2: mod3
+ * mod3:
+ * implies that mod1 directly depends on mod2 and _not_ mod3 as mod3 is
+ * already implicitely pulled in via mod2. This leaves us with:
+ * mod1: mod2
+ * mod2: mod3
+ * mod3:
+ */
+ mods = G.lst;
+ while (mods) {
+ llist_t *deps = mods->dependencies;
+ while (deps) {
+ dep_lst_t *all = G.lst;
+ while (all) {
+ if (!strcmp(all->name, deps->data)) {
+ llist_t *implied = all->dependencies;
+ while (implied) {
+ /* XXX:FIXME: erm, it would be nicer to just
+ * llist_unlink(&mods->dependencies, implied) */
+ llist_t *prune = mods->dependencies;
+ while (prune) {
+ if (!strcmp(implied->data, prune->data))
+ break;
+ prune = prune->link;
+ }
+//if (prune) bb_info_msg("[%s] '%s' implies '%s', removing", mods->name, all->name, implied->data);
+ llist_unlink(&mods->dependencies, prune);
+ implied = implied->link;
+ }
+ }
+ all = all->next;
+ }
+ deps = deps->link;
+ }
+ mods = mods->next;
+ }
+#endif
+
+ mods = G.lst;
+ /* Finally print them. */
+ while (mods) {
+ fprintf(filedes, "%s:", mods->name);
+ /* If we did not resolve all modules, then it's likely that we just did
+ * not see the names of all prerequisites (which will be NULL in this
+ * case). */
+ while (mods->dependencies) {
+ char *the_dep = llist_pop(&mods->dependencies);
+ if (the_dep)
+ fprintf(filedes, " %s", the_dep);
+ }
+ fprintf(filedes, "\n");
+ if (ENABLE_FEATURE_DEPMOD_ALIAS)
+ {
+ char *shortname =
+ xstrdup(bb_get_last_path_component_nostrip(mods->name));
+ char *tmp = strrstr(shortname, ".ko");
+
+ *tmp = '\0';
+
+ while (mods->aliases) {
+ fprintf(filedes, "alias %s %s\n",
+ (char*)llist_pop(&mods->aliases),
+ shortname);
+ }
+ free(shortname);
+ }
+ mods = mods->next;
+ }
+ }
+
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ fclose_if_not_stdin(filedes);
+ free(moddir);
+ while (G.lst) {
+ dep_lst_t *old = G.lst;
+ G.lst = G.lst->next;
+ free(old->name);
+ free(old);
+ }
+ }
+ return ret;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/modutils/insmod.c b/cleopatre/busybox-1.11.1-spc300/modutils/insmod.c
new file mode 100644
index 0000000000..3fbb02b75c
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/modutils/insmod.c
@@ -0,0 +1,4274 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini insmod implementation for busybox
+ *
+ * This version of insmod supports ARM, CRIS, H8/300, x86, ia64, x86_64,
+ * m68k, MIPS, PowerPC, S390, SH3/4/5, Sparc, v850e, and x86_64.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * and Ron Alder <alder@lineo.com>
+ *
+ * Rodney Radford <rradford@mindspring.com> 17-Aug-2004.
+ * Added x86_64 support.
+ *
+ * Miles Bader <miles@gnu.org> added NEC V850E support.
+ *
+ * Modified by Bryan Rittmeyer <bryan@ixiacom.com> to support SH4
+ * and (theoretically) SH3. I have only tested SH4 in little endian mode.
+ *
+ * Modified by Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and
+ * Nicolas Ferre <nicolas.ferre@alcove.fr> to support ARM7TDMI. Only
+ * very minor changes required to also work with StrongArm and presumably
+ * all ARM based systems.
+ *
+ * Yoshinori Sato <ysato@users.sourceforge.jp> 19-May-2004.
+ * added Renesas H8/300 support.
+ *
+ * Paul Mundt <lethal@linux-sh.org> 08-Aug-2003.
+ * Integrated support for sh64 (SH-5), from preliminary modutils
+ * patches from Benedict Gaster <benedict.gaster@superh.com>.
+ * Currently limited to support for 32bit ABI.
+ *
+ * Magnus Damm <damm@opensource.se> 22-May-2002.
+ * The plt and got code are now using the same structs.
+ * Added generic linked list code to fully support PowerPC.
+ * Replaced the mess in arch_apply_relocation() with architecture blocks.
+ * The arch_create_got() function got cleaned up with architecture blocks.
+ * These blocks should be easy maintain and sync with obj_xxx.c in modutils.
+ *
+ * Magnus Damm <damm@opensource.se> added PowerPC support 20-Feb-2001.
+ * PowerPC specific code stolen from modutils-2.3.16,
+ * written by Paul Mackerras, Copyright 1996, 1997 Linux International.
+ * I've only tested the code on mpc8xx platforms in big-endian mode.
+ * Did some cleanup and added USE_xxx_ENTRIES...
+ *
+ * Quinn Jensen <jensenq@lineo.com> added MIPS support 23-Feb-2001.
+ * based on modutils-2.4.2
+ * MIPS specific support for Elf loading and relocation.
+ * Copyright 1996, 1997 Linux International.
+ * Contributed by Ralf Baechle <ralf@gnu.ai.mit.edu>
+ *
+ * Based almost entirely on the Linux modutils-2.3.11 implementation.
+ * Copyright 1996, 1997 Linux International.
+ * New implementation contributed by Richard Henderson <rth@tamu.edu>
+ * Based on original work by Bjorn Ekwall <bj0rn@blox.se>
+ * Restructured (and partly rewritten) by:
+ * Björn Ekwall <bj0rn@blox.se> February 1999
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include <libgen.h>
+#include <sys/utsname.h>
+
+#if !ENABLE_FEATURE_2_4_MODULES && !ENABLE_FEATURE_2_6_MODULES
+#undef ENABLE_FEATURE_2_4_MODULES
+#define ENABLE_FEATURE_2_4_MODULES 1
+#endif
+
+/*
+ * Big piece of 2.4-specific code
+ */
+#if ENABLE_FEATURE_2_4_MODULES
+
+#if ENABLE_FEATURE_2_6_MODULES
+static int insmod_ng_main(int argc, char **argv);
+#endif
+
+#if ENABLE_FEATURE_INSMOD_LOADINKMEM
+#define LOADBITS 0
+#else
+#define LOADBITS 1
+#endif
+
+/* Alpha */
+#if defined(__alpha__)
+#define MATCH_MACHINE(x) (x == EM_ALPHA)
+#define SHT_RELM SHT_RELA
+#define Elf64_RelM Elf64_Rela
+#define ELFCLASSM ELFCLASS64
+#endif
+
+/* ARM support */
+#if defined(__arm__)
+#define MATCH_MACHINE(x) (x == EM_ARM)
+#define SHT_RELM SHT_REL
+#define Elf32_RelM Elf32_Rel
+#define ELFCLASSM ELFCLASS32
+#define USE_PLT_ENTRIES
+#define PLT_ENTRY_SIZE 8
+#define USE_GOT_ENTRIES
+#define GOT_ENTRY_SIZE 8
+#define USE_SINGLE
+#endif
+
+/* blackfin */
+#if defined(BFIN)
+#define MATCH_MACHINE(x) (x == EM_BLACKFIN)
+#define SHT_RELM SHT_RELA
+#define Elf32_RelM Elf32_Rela
+#define ELFCLASSM ELFCLASS32
+#endif
+
+/* CRIS */
+#if defined(__cris__)
+#define MATCH_MACHINE(x) (x == EM_CRIS)
+#define SHT_RELM SHT_RELA
+#define Elf32_RelM Elf32_Rela
+#define ELFCLASSM ELFCLASS32
+#ifndef EM_CRIS
+#define EM_CRIS 76
+#define R_CRIS_NONE 0
+#define R_CRIS_32 3
+#endif
+#endif
+
+/* H8/300 */
+#if defined(__H8300H__) || defined(__H8300S__)
+#define MATCH_MACHINE(x) (x == EM_H8_300)
+#define SHT_RELM SHT_RELA
+#define Elf32_RelM Elf32_Rela
+#define ELFCLASSM ELFCLASS32
+#define USE_SINGLE
+#define SYMBOL_PREFIX "_"
+#endif
+
+/* PA-RISC / HP-PA */
+#if defined(__hppa__)
+#define MATCH_MACHINE(x) (x == EM_PARISC)
+#define SHT_RELM SHT_RELA
+#if defined(__LP64__)
+#define Elf64_RelM Elf64_Rela
+#define ELFCLASSM ELFCLASS64
+#else
+#define Elf32_RelM Elf32_Rela
+#define ELFCLASSM ELFCLASS32
+#endif
+#endif
+
+/* x86 */
+#if defined(__i386__)
+#ifndef EM_486
+#define MATCH_MACHINE(x) (x == EM_386)
+#else
+#define MATCH_MACHINE(x) (x == EM_386 || x == EM_486)
+#endif
+#define SHT_RELM SHT_REL
+#define Elf32_RelM Elf32_Rel
+#define ELFCLASSM ELFCLASS32
+#define USE_GOT_ENTRIES
+#define GOT_ENTRY_SIZE 4
+#define USE_SINGLE
+#endif
+
+/* IA64, aka Itanium */
+#if defined(__ia64__)
+#define MATCH_MACHINE(x) (x == EM_IA_64)
+#define SHT_RELM SHT_RELA
+#define Elf64_RelM Elf64_Rela
+#define ELFCLASSM ELFCLASS64
+#endif
+
+/* m68k */
+#if defined(__mc68000__)
+#define MATCH_MACHINE(x) (x == EM_68K)
+#define SHT_RELM SHT_RELA
+#define Elf32_RelM Elf32_Rela
+#define ELFCLASSM ELFCLASS32
+#define USE_GOT_ENTRIES
+#define GOT_ENTRY_SIZE 4
+#define USE_SINGLE
+#endif
+
+/* Microblaze */
+#if defined(__microblaze__)
+#define USE_SINGLE
+#include <linux/elf-em.h>
+#define MATCH_MACHINE(x) (x == EM_XILINX_MICROBLAZE)
+#define SHT_RELM SHT_RELA
+#define Elf32_RelM Elf32_Rela
+#define ELFCLASSM ELFCLASS32
+#endif
+
+/* MIPS */
+#if defined(__mips__)
+#define MATCH_MACHINE(x) (x == EM_MIPS || x == EM_MIPS_RS3_LE)
+#define SHT_RELM SHT_REL
+#define Elf32_RelM Elf32_Rel
+#define ELFCLASSM ELFCLASS32
+/* Account for ELF spec changes. */
+#ifndef EM_MIPS_RS3_LE
+#ifdef EM_MIPS_RS4_BE
+#define EM_MIPS_RS3_LE EM_MIPS_RS4_BE
+#else
+#define EM_MIPS_RS3_LE 10
+#endif
+#endif /* !EM_MIPS_RS3_LE */
+#define ARCHDATAM "__dbe_table"
+#endif
+
+/* Nios II */
+#if defined(__nios2__)
+#define MATCH_MACHINE(x) (x == EM_ALTERA_NIOS2)
+#define SHT_RELM SHT_RELA
+#define Elf32_RelM Elf32_Rela
+#define ELFCLASSM ELFCLASS32
+#endif
+
+/* PowerPC */
+#if defined(__powerpc64__)
+#define MATCH_MACHINE(x) (x == EM_PPC64)
+#define SHT_RELM SHT_RELA
+#define Elf64_RelM Elf64_Rela
+#define ELFCLASSM ELFCLASS64
+#elif defined(__powerpc__)
+#define MATCH_MACHINE(x) (x == EM_PPC)
+#define SHT_RELM SHT_RELA
+#define Elf32_RelM Elf32_Rela
+#define ELFCLASSM ELFCLASS32
+#define USE_PLT_ENTRIES
+#define PLT_ENTRY_SIZE 16
+#define USE_PLT_LIST
+#define LIST_ARCHTYPE ElfW(Addr)
+#define USE_LIST
+#define ARCHDATAM "__ftr_fixup"
+#endif
+
+/* S390 */
+#if defined(__s390__)
+#define MATCH_MACHINE(x) (x == EM_S390)
+#define SHT_RELM SHT_RELA
+#define Elf32_RelM Elf32_Rela
+#define ELFCLASSM ELFCLASS32
+#define USE_PLT_ENTRIES
+#define PLT_ENTRY_SIZE 8
+#define USE_GOT_ENTRIES
+#define GOT_ENTRY_SIZE 8
+#define USE_SINGLE
+#endif
+
+/* SuperH */
+#if defined(__sh__)
+#define MATCH_MACHINE(x) (x == EM_SH)
+#define SHT_RELM SHT_RELA
+#define Elf32_RelM Elf32_Rela
+#define ELFCLASSM ELFCLASS32
+#define USE_GOT_ENTRIES
+#define GOT_ENTRY_SIZE 4
+#define USE_SINGLE
+/* the SH changes have only been tested in =little endian= mode */
+/* I'm not sure about big endian, so let's warn: */
+#if defined(__sh__) && BB_BIG_ENDIAN
+# error insmod.c may require changes for use on big endian SH
+#endif
+/* it may or may not work on the SH1/SH2... Error on those also */
+#if ((!(defined(__SH3__) || defined(__SH4__) || defined(__SH5__)))) && (defined(__sh__))
+#error insmod.c may require changes for SH1 or SH2 use
+#endif
+#endif
+
+/* Sparc */
+#if defined(__sparc__)
+#define MATCH_MACHINE(x) (x == EM_SPARC)
+#define SHT_RELM SHT_RELA
+#define Elf32_RelM Elf32_Rela
+#define ELFCLASSM ELFCLASS32
+#endif
+
+/* v850e */
+#if defined(__v850e__)
+#define MATCH_MACHINE(x) ((x) == EM_V850 || (x) == EM_CYGNUS_V850)
+#define SHT_RELM SHT_RELA
+#define Elf32_RelM Elf32_Rela
+#define ELFCLASSM ELFCLASS32
+#define USE_PLT_ENTRIES
+#define PLT_ENTRY_SIZE 8
+#define USE_SINGLE
+#ifndef EM_CYGNUS_V850 /* grumble */
+#define EM_CYGNUS_V850 0x9080
+#endif
+#define SYMBOL_PREFIX "_"
+#endif
+
+/* X86_64 */
+#if defined(__x86_64__)
+#define MATCH_MACHINE(x) (x == EM_X86_64)
+#define SHT_RELM SHT_RELA
+#define USE_GOT_ENTRIES
+#define GOT_ENTRY_SIZE 8
+#define USE_SINGLE
+#define Elf64_RelM Elf64_Rela
+#define ELFCLASSM ELFCLASS64
+#endif
+
+#ifndef SHT_RELM
+#error Sorry, but insmod.c does not yet support this architecture...
+#endif
+
+
+//----------------------------------------------------------------------------
+//--------modutils module.h, lines 45-242
+//----------------------------------------------------------------------------
+
+/* Definitions for the Linux module syscall interface.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+
+#ifndef MODUTILS_MODULE_H
+
+/*======================================================================*/
+/* For sizeof() which are related to the module platform and not to the
+ environment isnmod is running in, use sizeof_xx instead of sizeof(xx). */
+
+#define tgt_sizeof_char sizeof(char)
+#define tgt_sizeof_short sizeof(short)
+#define tgt_sizeof_int sizeof(int)
+#define tgt_sizeof_long sizeof(long)
+#define tgt_sizeof_char_p sizeof(char *)
+#define tgt_sizeof_void_p sizeof(void *)
+#define tgt_long long
+
+#if defined(__sparc__) && !defined(__sparc_v9__) && defined(ARCH_sparc64)
+#undef tgt_sizeof_long
+#undef tgt_sizeof_char_p
+#undef tgt_sizeof_void_p
+#undef tgt_long
+enum {
+ tgt_sizeof_long = 8,
+ tgt_sizeof_char_p = 8,
+ tgt_sizeof_void_p = 8
+};
+#define tgt_long long long
+#endif
+
+/*======================================================================*/
+/* The structures used in Linux 2.1. */
+
+/* Note: new_module_symbol does not use tgt_long intentionally */
+struct new_module_symbol {
+ unsigned long value;
+ unsigned long name;
+};
+
+struct new_module_persist;
+
+struct new_module_ref {
+ unsigned tgt_long dep; /* kernel addresses */
+ unsigned tgt_long ref;
+ unsigned tgt_long next_ref;
+};
+
+struct new_module {
+ unsigned tgt_long size_of_struct; /* == sizeof(module) */
+ unsigned tgt_long next;
+ unsigned tgt_long name;
+ unsigned tgt_long size;
+
+ tgt_long usecount;
+ unsigned tgt_long flags; /* AUTOCLEAN et al */
+
+ unsigned nsyms;
+ unsigned ndeps;
+
+ unsigned tgt_long syms;
+ unsigned tgt_long deps;
+ unsigned tgt_long refs;
+ unsigned tgt_long init;
+ unsigned tgt_long cleanup;
+ unsigned tgt_long ex_table_start;
+ unsigned tgt_long ex_table_end;
+#ifdef __alpha__
+ unsigned tgt_long gp;
+#endif
+ /* Everything after here is extension. */
+ unsigned tgt_long persist_start;
+ unsigned tgt_long persist_end;
+ unsigned tgt_long can_unload;
+ unsigned tgt_long runsize;
+ const char *kallsyms_start; /* All symbols for kernel debugging */
+ const char *kallsyms_end;
+ const char *archdata_start; /* arch specific data for module */
+ const char *archdata_end;
+ const char *kernel_data; /* Reserved for kernel internal use */
+};
+
+#ifdef ARCHDATAM
+#define ARCHDATA_SEC_NAME ARCHDATAM
+#else
+#define ARCHDATA_SEC_NAME "__archdata"
+#endif
+#define KALLSYMS_SEC_NAME "__kallsyms"
+
+
+struct new_module_info {
+ unsigned long addr;
+ unsigned long size;
+ unsigned long flags;
+ long usecount;
+};
+
+/* Bits of module.flags. */
+enum {
+ NEW_MOD_RUNNING = 1,
+ NEW_MOD_DELETED = 2,
+ NEW_MOD_AUTOCLEAN = 4,
+ NEW_MOD_VISITED = 8,
+ NEW_MOD_USED_ONCE = 16
+};
+
+int init_module(const char *name, const struct new_module *);
+int query_module(const char *name, int which, void *buf,
+ size_t bufsize, size_t *ret);
+
+/* Values for query_module's which. */
+enum {
+ QM_MODULES = 1,
+ QM_DEPS = 2,
+ QM_REFS = 3,
+ QM_SYMBOLS = 4,
+ QM_INFO = 5
+};
+
+/*======================================================================*/
+/* The system calls unchanged between 2.0 and 2.1. */
+
+unsigned long create_module(const char *, size_t);
+int delete_module(const char *module, unsigned int flags);
+
+
+#endif /* module.h */
+
+//----------------------------------------------------------------------------
+//--------end of modutils module.h
+//----------------------------------------------------------------------------
+
+
+
+//----------------------------------------------------------------------------
+//--------modutils obj.h, lines 253-462
+//----------------------------------------------------------------------------
+
+/* Elf object file loading and relocation routines.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+
+#ifndef MODUTILS_OBJ_H
+
+/* The relocatable object is manipulated using elfin types. */
+
+#include <elf.h>
+#include <endian.h>
+
+#ifndef ElfW
+# if ELFCLASSM == ELFCLASS32
+# define ElfW(x) Elf32_ ## x
+# define ELFW(x) ELF32_ ## x
+# else
+# define ElfW(x) Elf64_ ## x
+# define ELFW(x) ELF64_ ## x
+# endif
+#endif
+
+/* For some reason this is missing from some ancient C libraries.... */
+#ifndef ELF32_ST_INFO
+# define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
+#endif
+
+#ifndef ELF64_ST_INFO
+# define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
+#endif
+
+#define ELF_ST_BIND(info) ELFW(ST_BIND)(info)
+#define ELF_ST_TYPE(info) ELFW(ST_TYPE)(info)
+#define ELF_ST_INFO(bind, type) ELFW(ST_INFO)(bind, type)
+#define ELF_R_TYPE(val) ELFW(R_TYPE)(val)
+#define ELF_R_SYM(val) ELFW(R_SYM)(val)
+
+struct obj_string_patch;
+struct obj_symbol_patch;
+
+struct obj_section
+{
+ ElfW(Shdr) header;
+ const char *name;
+ char *contents;
+ struct obj_section *load_next;
+ int idx;
+};
+
+struct obj_symbol
+{
+ struct obj_symbol *next; /* hash table link */
+ const char *name;
+ unsigned long value;
+ unsigned long size;
+ int secidx; /* the defining section index/module */
+ int info;
+ int ksymidx; /* for export to the kernel symtab */
+ int referenced; /* actually used in the link */
+};
+
+/* Hardcode the hash table size. We shouldn't be needing so many
+ symbols that we begin to degrade performance, and we get a big win
+ by giving the compiler a constant divisor. */
+
+#define HASH_BUCKETS 521
+
+struct obj_file {
+ ElfW(Ehdr) header;
+ ElfW(Addr) baseaddr;
+ struct obj_section **sections;
+ struct obj_section *load_order;
+ struct obj_section **load_order_search_start;
+ struct obj_string_patch *string_patches;
+ struct obj_symbol_patch *symbol_patches;
+ int (*symbol_cmp)(const char *, const char *);
+ unsigned long (*symbol_hash)(const char *);
+ unsigned long local_symtab_size;
+ struct obj_symbol **local_symtab;
+ struct obj_symbol *symtab[HASH_BUCKETS];
+};
+
+enum obj_reloc {
+ obj_reloc_ok,
+ obj_reloc_overflow,
+ obj_reloc_dangerous,
+ obj_reloc_unhandled
+};
+
+struct obj_string_patch {
+ struct obj_string_patch *next;
+ int reloc_secidx;
+ ElfW(Addr) reloc_offset;
+ ElfW(Addr) string_offset;
+};
+
+struct obj_symbol_patch {
+ struct obj_symbol_patch *next;
+ int reloc_secidx;
+ ElfW(Addr) reloc_offset;
+ struct obj_symbol *sym;
+};
+
+
+/* Generic object manipulation routines. */
+
+static unsigned long obj_elf_hash(const char *);
+
+static unsigned long obj_elf_hash_n(const char *, unsigned long len);
+
+static struct obj_symbol *obj_find_symbol(struct obj_file *f,
+ const char *name);
+
+static ElfW(Addr) obj_symbol_final_value(struct obj_file *f,
+ struct obj_symbol *sym);
+
+#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
+static void obj_set_symbol_compare(struct obj_file *f,
+ int (*cmp)(const char *, const char *),
+ unsigned long (*hash)(const char *));
+#endif
+
+static struct obj_section *obj_find_section(struct obj_file *f,
+ const char *name);
+
+static void obj_insert_section_load_order(struct obj_file *f,
+ struct obj_section *sec);
+
+static struct obj_section *obj_create_alloced_section(struct obj_file *f,
+ const char *name,
+ unsigned long align,
+ unsigned long size);
+
+static struct obj_section *obj_create_alloced_section_first(struct obj_file *f,
+ const char *name,
+ unsigned long align,
+ unsigned long size);
+
+static void *obj_extend_section(struct obj_section *sec, unsigned long more);
+
+static void obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
+ const char *string);
+
+static void obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
+ struct obj_symbol *sym);
+
+static void obj_check_undefineds(struct obj_file *f);
+
+static void obj_allocate_commons(struct obj_file *f);
+
+static unsigned long obj_load_size(struct obj_file *f);
+
+static int obj_relocate(struct obj_file *f, ElfW(Addr) base);
+
+static struct obj_file *obj_load(FILE *f, int loadprogbits);
+
+static int obj_create_image(struct obj_file *f, char *image);
+
+/* Architecture specific manipulation routines. */
+
+static struct obj_file *arch_new_file(void);
+
+static struct obj_section *arch_new_section(void);
+
+static struct obj_symbol *arch_new_symbol(void);
+
+static enum obj_reloc arch_apply_relocation(struct obj_file *f,
+ struct obj_section *targsec,
+ /*struct obj_section *symsec,*/
+ struct obj_symbol *sym,
+ ElfW(RelM) *rel, ElfW(Addr) value);
+
+static void arch_create_got(struct obj_file *f);
+#if ENABLE_FEATURE_CHECK_TAINTED_MODULE
+static int obj_gpl_license(struct obj_file *f, const char **license);
+#endif /* FEATURE_CHECK_TAINTED_MODULE */
+#endif /* obj.h */
+//----------------------------------------------------------------------------
+//--------end of modutils obj.h
+//----------------------------------------------------------------------------
+
+
+/* SPFX is always a string, so it can be concatenated to string constants. */
+#ifdef SYMBOL_PREFIX
+#define SPFX SYMBOL_PREFIX
+#else
+#define SPFX ""
+#endif
+
+enum { STRVERSIONLEN = 64 };
+
+/*======================================================================*/
+
+#define OPTION_STR "sLo:fkvqx" USE_FEATURE_INSMOD_LOAD_MAP("m")
+enum {
+ OPT_s = 0x1, // -s /* log to syslog */
+ /* Not supported but kernel needs this for request_module(),
+ as this calls: modprobe -k -s -- <module>
+ so silently ignore this flag */
+ OPT_L = 0x2, // -L /* Stub warning */
+ /* Compatibility with modprobe.
+ In theory, this does locking, but we don't do
+ that. So be careful and plan your life around not
+ loading the same module 50 times concurrently. */
+ OPT_o = 0x4, // -o /* name the output module */
+ OPT_f = 0x8, // -f /* force loading */
+ OPT_k = 0x10, // -k /* module loaded by kerneld, auto-cleanable */
+ OPT_v = 0x20, // -v /* verbose output */
+ OPT_q = 0x40, // -q /* silent */
+ OPT_x = 0x80, // -x /* do not export externs */
+ OPT_m = 0x100, // -m /* print module load map */
+};
+#define flag_force_load (option_mask32 & OPT_f)
+#define flag_autoclean (option_mask32 & OPT_k)
+#define flag_verbose (option_mask32 & OPT_v)
+#define flag_quiet (option_mask32 & OPT_q)
+#define flag_noexport (option_mask32 & OPT_x)
+#if ENABLE_FEATURE_INSMOD_LOAD_MAP
+#define flag_print_load_map (option_mask32 & OPT_m)
+#else
+#define flag_print_load_map 0
+#endif
+
+/*======================================================================*/
+
+#if defined(USE_LIST)
+
+struct arch_list_entry
+{
+ struct arch_list_entry *next;
+ LIST_ARCHTYPE addend;
+ int offset;
+ int inited : 1;
+};
+
+#endif
+
+#if defined(USE_SINGLE)
+
+struct arch_single_entry
+{
+ int offset;
+ int inited : 1;
+ int allocated : 1;
+};
+
+#endif
+
+#if defined(__mips__)
+struct mips_hi16
+{
+ struct mips_hi16 *next;
+ ElfW(Addr) *addr;
+ ElfW(Addr) value;
+};
+#endif
+
+struct arch_file {
+ struct obj_file root;
+#if defined(USE_PLT_ENTRIES)
+ struct obj_section *plt;
+#endif
+#if defined(USE_GOT_ENTRIES)
+ struct obj_section *got;
+#endif
+#if defined(__mips__)
+ struct mips_hi16 *mips_hi16_list;
+#endif
+};
+
+struct arch_symbol {
+ struct obj_symbol root;
+#if defined(USE_PLT_ENTRIES)
+#if defined(USE_PLT_LIST)
+ struct arch_list_entry *pltent;
+#else
+ struct arch_single_entry pltent;
+#endif
+#endif
+#if defined(USE_GOT_ENTRIES)
+ struct arch_single_entry gotent;
+#endif
+};
+
+
+struct external_module {
+ const char *name;
+ ElfW(Addr) addr;
+ int used;
+ size_t nsyms;
+ struct new_module_symbol *syms;
+};
+
+static struct new_module_symbol *ksyms;
+static size_t nksyms;
+
+static struct external_module *ext_modules;
+static int n_ext_modules;
+static int n_ext_modules_used;
+
+static char *m_filename;
+static char *m_fullName;
+
+
+/*======================================================================*/
+
+
+static int check_module_name_match(const char *filename,
+ struct stat *statbuf ATTRIBUTE_UNUSED,
+ void *userdata, int depth ATTRIBUTE_UNUSED)
+{
+ char *fullname = (char *) userdata;
+ char *tmp;
+
+ if (fullname[0] == '\0')
+ return FALSE;
+
+ tmp = bb_get_last_path_component_nostrip(filename);
+ if (strcmp(tmp, fullname) == 0) {
+ /* Stop searching if we find a match */
+ m_filename = xstrdup(filename);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+/*======================================================================*/
+
+static struct obj_file *arch_new_file(void)
+{
+ struct arch_file *f;
+ f = xzalloc(sizeof(*f));
+ return &f->root; /* it's a first member */
+}
+
+static struct obj_section *arch_new_section(void)
+{
+ return xzalloc(sizeof(struct obj_section));
+}
+
+static struct obj_symbol *arch_new_symbol(void)
+{
+ struct arch_symbol *sym;
+ sym = xzalloc(sizeof(*sym));
+ return &sym->root;
+}
+
+static enum obj_reloc
+arch_apply_relocation(struct obj_file *f,
+ struct obj_section *targsec,
+ /*struct obj_section *symsec,*/
+ struct obj_symbol *sym,
+ ElfW(RelM) *rel, ElfW(Addr) v)
+{
+#if defined(__arm__) || defined(__i386__) || defined(__mc68000__) \
+ || defined(__sh__) || defined(__s390__) || defined(__x86_64__)
+ struct arch_file *ifile = (struct arch_file *) f;
+#endif
+ enum obj_reloc ret = obj_reloc_ok;
+ ElfW(Addr) *loc = (ElfW(Addr) *) (targsec->contents + rel->r_offset);
+#if defined(__arm__) || defined(__H8300H__) || defined(__H8300S__) \
+ || defined(__i386__) || defined(__mc68000__) || defined(__microblaze__) \
+ || defined(__mips__) || defined(__nios2__) || defined(__powerpc__) \
+ || defined(__s390__) || defined(__sh__) || defined(__x86_64__)
+ ElfW(Addr) dot = targsec->header.sh_addr + rel->r_offset;
+#endif
+#if defined(USE_GOT_ENTRIES) || defined(USE_PLT_ENTRIES)
+ struct arch_symbol *isym = (struct arch_symbol *) sym;
+#endif
+#if defined(__arm__) || defined(__i386__) || defined(__mc68000__) \
+ || defined(__sh__) || defined(__s390__)
+#if defined(USE_GOT_ENTRIES)
+ ElfW(Addr) got = ifile->got ? ifile->got->header.sh_addr : 0;
+#endif
+#endif
+#if defined(USE_PLT_ENTRIES)
+ ElfW(Addr) plt = ifile->plt ? ifile->plt->header.sh_addr : 0;
+ unsigned long *ip;
+# if defined(USE_PLT_LIST)
+ struct arch_list_entry *pe;
+# else
+ struct arch_single_entry *pe;
+# endif
+#endif
+
+ switch (ELF_R_TYPE(rel->r_info)) {
+
+#if defined(__arm__)
+
+ case R_ARM_NONE:
+ break;
+
+ case R_ARM_ABS32:
+ *loc += v;
+ break;
+
+ case R_ARM_GOT32:
+ goto bb_use_got;
+
+ case R_ARM_GOTPC:
+ /* relative reloc, always to _GLOBAL_OFFSET_TABLE_
+ * (which is .got) similar to branch,
+ * but is full 32 bits relative */
+
+ *loc += got - dot;
+ break;
+
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ goto bb_use_plt;
+
+ case R_ARM_GOTOFF: /* address relative to the got */
+ *loc += v - got;
+ break;
+
+#elif defined(__cris__)
+
+ case R_CRIS_NONE:
+ break;
+
+ case R_CRIS_32:
+ /* CRIS keeps the relocation value in the r_addend field and
+ * should not use whats in *loc at all
+ */
+ *loc = v;
+ break;
+
+#elif defined(__H8300H__) || defined(__H8300S__)
+
+ case R_H8_DIR24R8:
+ loc = (ElfW(Addr) *)((ElfW(Addr))loc - 1);
+ *loc = (*loc & 0xff000000) | ((*loc & 0xffffff) + v);
+ break;
+ case R_H8_DIR24A8:
+ *loc += v;
+ break;
+ case R_H8_DIR32:
+ case R_H8_DIR32A16:
+ *loc += v;
+ break;
+ case R_H8_PCREL16:
+ v -= dot + 2;
+ if ((ElfW(Sword))v > 0x7fff ||
+ (ElfW(Sword))v < -(ElfW(Sword))0x8000)
+ ret = obj_reloc_overflow;
+ else
+ *(unsigned short *)loc = v;
+ break;
+ case R_H8_PCREL8:
+ v -= dot + 1;
+ if ((ElfW(Sword))v > 0x7f ||
+ (ElfW(Sword))v < -(ElfW(Sword))0x80)
+ ret = obj_reloc_overflow;
+ else
+ *(unsigned char *)loc = v;
+ break;
+
+#elif defined(__i386__)
+
+ case R_386_NONE:
+ break;
+
+ case R_386_32:
+ *loc += v;
+ break;
+
+ case R_386_PLT32:
+ case R_386_PC32:
+ case R_386_GOTOFF:
+ *loc += v - dot;
+ break;
+
+ case R_386_GLOB_DAT:
+ case R_386_JMP_SLOT:
+ *loc = v;
+ break;
+
+ case R_386_RELATIVE:
+ *loc += f->baseaddr;
+ break;
+
+ case R_386_GOTPC:
+ *loc += got - dot;
+ break;
+
+ case R_386_GOT32:
+ goto bb_use_got;
+ break;
+
+#elif defined(__microblaze__)
+ case R_MICROBLAZE_NONE:
+ case R_MICROBLAZE_64_NONE:
+ case R_MICROBLAZE_32_SYM_OP_SYM:
+ case R_MICROBLAZE_32_PCREL:
+ break;
+
+ case R_MICROBLAZE_64_PCREL: {
+ /* dot is the address of the current instruction.
+ * v is the target symbol address.
+ * So we need to extract the offset in the code,
+ * adding v, then subtrating the current address
+ * of this instruction.
+ * Ex: "IMM 0xFFFE bralid 0x0000" = "bralid 0xFFFE0000"
+ */
+
+ /* Get split offset stored in code */
+ unsigned int temp = (loc[0] & 0xFFFF) << 16 |
+ (loc[1] & 0xFFFF);
+
+ /* Adjust relative offset. -4 adjustment required
+ * because dot points to the IMM insn, but branch
+ * is computed relative to the branch instruction itself.
+ */
+ temp += v - dot - 4;
+
+ /* Store back into code */
+ loc[0] = (loc[0] & 0xFFFF0000) | temp >> 16;
+ loc[1] = (loc[1] & 0xFFFF0000) | (temp & 0xFFFF);
+
+ break;
+ }
+
+ case R_MICROBLAZE_32:
+ *loc += v;
+ break;
+
+ case R_MICROBLAZE_64: {
+ /* Get split pointer stored in code */
+ unsigned int temp1 = (loc[0] & 0xFFFF) << 16 |
+ (loc[1] & 0xFFFF);
+
+ /* Add reloc offset */
+ temp1+=v;
+
+ /* Store back into code */
+ loc[0] = (loc[0] & 0xFFFF0000) | temp1 >> 16;
+ loc[1] = (loc[1] & 0xFFFF0000) | (temp1 & 0xFFFF);
+
+ break;
+ }
+
+ case R_MICROBLAZE_32_PCREL_LO:
+ case R_MICROBLAZE_32_LO:
+ case R_MICROBLAZE_SRO32:
+ case R_MICROBLAZE_SRW32:
+ ret = obj_reloc_unhandled;
+ break;
+
+#elif defined(__mc68000__)
+
+ case R_68K_NONE:
+ break;
+
+ case R_68K_32:
+ *loc += v;
+ break;
+
+ case R_68K_8:
+ if (v > 0xff) {
+ ret = obj_reloc_overflow;
+ }
+ *(char *)loc = v;
+ break;
+
+ case R_68K_16:
+ if (v > 0xffff) {
+ ret = obj_reloc_overflow;
+ }
+ *(short *)loc = v;
+ break;
+
+ case R_68K_PC8:
+ v -= dot;
+ if ((ElfW(Sword))v > 0x7f ||
+ (ElfW(Sword))v < -(ElfW(Sword))0x80) {
+ ret = obj_reloc_overflow;
+ }
+ *(char *)loc = v;
+ break;
+
+ case R_68K_PC16:
+ v -= dot;
+ if ((ElfW(Sword))v > 0x7fff ||
+ (ElfW(Sword))v < -(ElfW(Sword))0x8000) {
+ ret = obj_reloc_overflow;
+ }
+ *(short *)loc = v;
+ break;
+
+ case R_68K_PC32:
+ *(int *)loc = v - dot;
+ break;
+
+ case R_68K_GLOB_DAT:
+ case R_68K_JMP_SLOT:
+ *loc = v;
+ break;
+
+ case R_68K_RELATIVE:
+ *(int *)loc += f->baseaddr;
+ break;
+
+ case R_68K_GOT32:
+ goto bb_use_got;
+
+# ifdef R_68K_GOTOFF
+ case R_68K_GOTOFF:
+ *loc += v - got;
+ break;
+# endif
+
+#elif defined(__mips__)
+
+ case R_MIPS_NONE:
+ break;
+
+ case R_MIPS_32:
+ *loc += v;
+ break;
+
+ case R_MIPS_26:
+ if (v % 4)
+ ret = obj_reloc_dangerous;
+ if ((v & 0xf0000000) != ((dot + 4) & 0xf0000000))
+ ret = obj_reloc_overflow;
+ *loc =
+ (*loc & ~0x03ffffff) | ((*loc + (v >> 2)) &
+ 0x03ffffff);
+ break;
+
+ case R_MIPS_HI16:
+ {
+ struct mips_hi16 *n;
+
+ /* We cannot relocate this one now because we don't know the value
+ of the carry we need to add. Save the information, and let LO16
+ do the actual relocation. */
+ n = xmalloc(sizeof *n);
+ n->addr = loc;
+ n->value = v;
+ n->next = ifile->mips_hi16_list;
+ ifile->mips_hi16_list = n;
+ break;
+ }
+
+ case R_MIPS_LO16:
+ {
+ unsigned long insnlo = *loc;
+ ElfW(Addr) val, vallo;
+
+ /* Sign extend the addend we extract from the lo insn. */
+ vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
+
+ if (ifile->mips_hi16_list != NULL) {
+ struct mips_hi16 *l;
+
+ l = ifile->mips_hi16_list;
+ while (l != NULL) {
+ struct mips_hi16 *next;
+ unsigned long insn;
+
+ /* Do the HI16 relocation. Note that we actually don't
+ need to know anything about the LO16 itself, except where
+ to find the low 16 bits of the addend needed by the LO16. */
+ insn = *l->addr;
+ val =
+ ((insn & 0xffff) << 16) +
+ vallo;
+ val += v;
+
+ /* Account for the sign extension that will happen in the
+ low bits. */
+ val =
+ ((val >> 16) +
+ ((val & 0x8000) !=
+ 0)) & 0xffff;
+
+ insn = (insn & ~0xffff) | val;
+ *l->addr = insn;
+
+ next = l->next;
+ free(l);
+ l = next;
+ }
+
+ ifile->mips_hi16_list = NULL;
+ }
+
+ /* Ok, we're done with the HI16 relocs. Now deal with the LO16. */
+ val = v + vallo;
+ insnlo = (insnlo & ~0xffff) | (val & 0xffff);
+ *loc = insnlo;
+ break;
+ }
+
+#elif defined(__nios2__)
+
+ case R_NIOS2_NONE:
+ break;
+
+ case R_NIOS2_BFD_RELOC_32:
+ *loc += v;
+ break;
+
+ case R_NIOS2_BFD_RELOC_16:
+ if (v > 0xffff) {
+ ret = obj_reloc_overflow;
+ }
+ *(short *)loc = v;
+ break;
+
+ case R_NIOS2_BFD_RELOC_8:
+ if (v > 0xff) {
+ ret = obj_reloc_overflow;
+ }
+ *(char *)loc = v;
+ break;
+
+ case R_NIOS2_S16:
+ {
+ Elf32_Addr word;
+
+ if ((Elf32_Sword)v > 0x7fff ||
+ (Elf32_Sword)v < -(Elf32_Sword)0x8000) {
+ ret = obj_reloc_overflow;
+ }
+
+ word = *loc;
+ *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) |
+ (word & 0x3f);
+ }
+ break;
+
+ case R_NIOS2_U16:
+ {
+ Elf32_Addr word;
+
+ if (v > 0xffff) {
+ ret = obj_reloc_overflow;
+ }
+
+ word = *loc;
+ *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) |
+ (word & 0x3f);
+ }
+ break;
+
+ case R_NIOS2_PCREL16:
+ {
+ Elf32_Addr word;
+
+ v -= dot + 4;
+ if ((Elf32_Sword)v > 0x7fff ||
+ (Elf32_Sword)v < -(Elf32_Sword)0x8000) {
+ ret = obj_reloc_overflow;
+ }
+
+ word = *loc;
+ *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | (word & 0x3f);
+ }
+ break;
+
+ case R_NIOS2_GPREL:
+ {
+ Elf32_Addr word, gp;
+ /* get _gp */
+ gp = obj_symbol_final_value(f, obj_find_symbol(f, SPFX "_gp"));
+ v-=gp;
+ if ((Elf32_Sword)v > 0x7fff ||
+ (Elf32_Sword)v < -(Elf32_Sword)0x8000) {
+ ret = obj_reloc_overflow;
+ }
+
+ word = *loc;
+ *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | (word & 0x3f);
+ }
+ break;
+
+ case R_NIOS2_CALL26:
+ if (v & 3)
+ ret = obj_reloc_dangerous;
+ if ((v >> 28) != (dot >> 28))
+ ret = obj_reloc_overflow;
+ *loc = (*loc & 0x3f) | ((v >> 2) << 6);
+ break;
+
+ case R_NIOS2_IMM5:
+ {
+ Elf32_Addr word;
+
+ if (v > 0x1f) {
+ ret = obj_reloc_overflow;
+ }
+
+ word = *loc & ~0x7c0;
+ *loc = word | ((v & 0x1f) << 6);
+ }
+ break;
+
+ case R_NIOS2_IMM6:
+ {
+ Elf32_Addr word;
+
+ if (v > 0x3f) {
+ ret = obj_reloc_overflow;
+ }
+
+ word = *loc & ~0xfc0;
+ *loc = word | ((v & 0x3f) << 6);
+ }
+ break;
+
+ case R_NIOS2_IMM8:
+ {
+ Elf32_Addr word;
+
+ if (v > 0xff) {
+ ret = obj_reloc_overflow;
+ }
+
+ word = *loc & ~0x3fc0;
+ *loc = word | ((v & 0xff) << 6);
+ }
+ break;
+
+ case R_NIOS2_HI16:
+ {
+ Elf32_Addr word;
+
+ word = *loc;
+ *loc = ((((word >> 22) << 16) | ((v >>16) & 0xffff)) << 6) |
+ (word & 0x3f);
+ }
+ break;
+
+ case R_NIOS2_LO16:
+ {
+ Elf32_Addr word;
+
+ word = *loc;
+ *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) |
+ (word & 0x3f);
+ }
+ break;
+
+ case R_NIOS2_HIADJ16:
+ {
+ Elf32_Addr word1, word2;
+
+ word1 = *loc;
+ word2 = ((v >> 16) + ((v >> 15) & 1)) & 0xffff;
+ *loc = ((((word1 >> 22) << 16) | word2) << 6) |
+ (word1 & 0x3f);
+ }
+ break;
+
+#elif defined(__powerpc64__)
+ /* PPC64 needs a 2.6 kernel, 2.4 module relocation irrelevant */
+
+#elif defined(__powerpc__)
+
+ case R_PPC_ADDR16_HA:
+ *(unsigned short *)loc = (v + 0x8000) >> 16;
+ break;
+
+ case R_PPC_ADDR16_HI:
+ *(unsigned short *)loc = v >> 16;
+ break;
+
+ case R_PPC_ADDR16_LO:
+ *(unsigned short *)loc = v;
+ break;
+
+ case R_PPC_REL24:
+ goto bb_use_plt;
+
+ case R_PPC_REL32:
+ *loc = v - dot;
+ break;
+
+ case R_PPC_ADDR32:
+ *loc = v;
+ break;
+
+#elif defined(__s390__)
+
+ case R_390_32:
+ *(unsigned int *) loc += v;
+ break;
+ case R_390_16:
+ *(unsigned short *) loc += v;
+ break;
+ case R_390_8:
+ *(unsigned char *) loc += v;
+ break;
+
+ case R_390_PC32:
+ *(unsigned int *) loc += v - dot;
+ break;
+ case R_390_PC16DBL:
+ *(unsigned short *) loc += (v - dot) >> 1;
+ break;
+ case R_390_PC16:
+ *(unsigned short *) loc += v - dot;
+ break;
+
+ case R_390_PLT32:
+ case R_390_PLT16DBL:
+ /* find the plt entry and initialize it. */
+ pe = (struct arch_single_entry *) &isym->pltent;
+ if (pe->inited == 0) {
+ ip = (unsigned long *)(ifile->plt->contents + pe->offset);
+ ip[0] = 0x0d105810; /* basr 1,0; lg 1,10(1); br 1 */
+ ip[1] = 0x100607f1;
+ if (ELF_R_TYPE(rel->r_info) == R_390_PLT16DBL)
+ ip[2] = v - 2;
+ else
+ ip[2] = v;
+ pe->inited = 1;
+ }
+
+ /* Insert relative distance to target. */
+ v = plt + pe->offset - dot;
+ if (ELF_R_TYPE(rel->r_info) == R_390_PLT32)
+ *(unsigned int *) loc = (unsigned int) v;
+ else if (ELF_R_TYPE(rel->r_info) == R_390_PLT16DBL)
+ *(unsigned short *) loc = (unsigned short) ((v + 2) >> 1);
+ break;
+
+ case R_390_GLOB_DAT:
+ case R_390_JMP_SLOT:
+ *loc = v;
+ break;
+
+ case R_390_RELATIVE:
+ *loc += f->baseaddr;
+ break;
+
+ case R_390_GOTPC:
+ *(unsigned long *) loc += got - dot;
+ break;
+
+ case R_390_GOT12:
+ case R_390_GOT16:
+ case R_390_GOT32:
+ if (!isym->gotent.inited)
+ {
+ isym->gotent.inited = 1;
+ *(ElfW(Addr) *)(ifile->got->contents + isym->gotent.offset) = v;
+ }
+ if (ELF_R_TYPE(rel->r_info) == R_390_GOT12)
+ *(unsigned short *) loc |= (*(unsigned short *) loc + isym->gotent.offset) & 0xfff;
+ else if (ELF_R_TYPE(rel->r_info) == R_390_GOT16)
+ *(unsigned short *) loc += isym->gotent.offset;
+ else if (ELF_R_TYPE(rel->r_info) == R_390_GOT32)
+ *(unsigned int *) loc += isym->gotent.offset;
+ break;
+
+# ifndef R_390_GOTOFF32
+# define R_390_GOTOFF32 R_390_GOTOFF
+# endif
+ case R_390_GOTOFF32:
+ *loc += v - got;
+ break;
+
+#elif defined(__sh__)
+
+ case R_SH_NONE:
+ break;
+
+ case R_SH_DIR32:
+ *loc += v;
+ break;
+
+ case R_SH_REL32:
+ *loc += v - dot;
+ break;
+
+ case R_SH_PLT32:
+ *loc = v - dot;
+ break;
+
+ case R_SH_GLOB_DAT:
+ case R_SH_JMP_SLOT:
+ *loc = v;
+ break;
+
+ case R_SH_RELATIVE:
+ *loc = f->baseaddr + rel->r_addend;
+ break;
+
+ case R_SH_GOTPC:
+ *loc = got - dot + rel->r_addend;
+ break;
+
+ case R_SH_GOT32:
+ goto bb_use_got;
+
+ case R_SH_GOTOFF:
+ *loc = v - got;
+ break;
+
+# if defined(__SH5__)
+ case R_SH_IMM_MEDLOW16:
+ case R_SH_IMM_LOW16:
+ {
+ ElfW(Addr) word;
+
+ if (ELF_R_TYPE(rel->r_info) == R_SH_IMM_MEDLOW16)
+ v >>= 16;
+
+ /*
+ * movi and shori have the format:
+ *
+ * | op | imm | reg | reserved |
+ * 31..26 25..10 9.. 4 3 .. 0
+ *
+ * so we simply mask and or in imm.
+ */
+ word = *loc & ~0x3fffc00;
+ word |= (v & 0xffff) << 10;
+
+ *loc = word;
+
+ break;
+ }
+
+ case R_SH_IMM_MEDLOW16_PCREL:
+ case R_SH_IMM_LOW16_PCREL:
+ {
+ ElfW(Addr) word;
+
+ word = *loc & ~0x3fffc00;
+
+ v -= dot;
+
+ if (ELF_R_TYPE(rel->r_info) == R_SH_IMM_MEDLOW16_PCREL)
+ v >>= 16;
+
+ word |= (v & 0xffff) << 10;
+
+ *loc = word;
+
+ break;
+ }
+# endif /* __SH5__ */
+
+#elif defined(__v850e__)
+
+ case R_V850_NONE:
+ break;
+
+ case R_V850_32:
+ /* We write two shorts instead of a long because even
+ 32-bit insns only need half-word alignment, but
+ 32-bit data needs to be long-word aligned. */
+ v += ((unsigned short *)loc)[0];
+ v += ((unsigned short *)loc)[1] << 16;
+ ((unsigned short *)loc)[0] = v & 0xffff;
+ ((unsigned short *)loc)[1] = (v >> 16) & 0xffff;
+ break;
+
+ case R_V850_22_PCREL:
+ goto bb_use_plt;
+
+#elif defined(__x86_64__)
+
+ case R_X86_64_NONE:
+ break;
+
+ case R_X86_64_64:
+ *loc += v;
+ break;
+
+ case R_X86_64_32:
+ *(unsigned int *) loc += v;
+ if (v > 0xffffffff)
+ {
+ ret = obj_reloc_overflow; /* Kernel module compiled without -mcmodel=kernel. */
+ /* error("Possibly is module compiled without -mcmodel=kernel!"); */
+ }
+ break;
+
+ case R_X86_64_32S:
+ *(signed int *) loc += v;
+ break;
+
+ case R_X86_64_16:
+ *(unsigned short *) loc += v;
+ break;
+
+ case R_X86_64_8:
+ *(unsigned char *) loc += v;
+ break;
+
+ case R_X86_64_PC32:
+ *(unsigned int *) loc += v - dot;
+ break;
+
+ case R_X86_64_PC16:
+ *(unsigned short *) loc += v - dot;
+ break;
+
+ case R_X86_64_PC8:
+ *(unsigned char *) loc += v - dot;
+ break;
+
+ case R_X86_64_GLOB_DAT:
+ case R_X86_64_JUMP_SLOT:
+ *loc = v;
+ break;
+
+ case R_X86_64_RELATIVE:
+ *loc += f->baseaddr;
+ break;
+
+ case R_X86_64_GOT32:
+ case R_X86_64_GOTPCREL:
+ goto bb_use_got;
+# if 0
+ if (!isym->gotent.reloc_done)
+ {
+ isym->gotent.reloc_done = 1;
+ *(Elf64_Addr *)(ifile->got->contents + isym->gotent.offset) = v;
+ }
+ /* XXX are these really correct? */
+ if (ELF64_R_TYPE(rel->r_info) == R_X86_64_GOTPCREL)
+ *(unsigned int *) loc += v + isym->gotent.offset;
+ else
+ *loc += isym->gotent.offset;
+ break;
+# endif
+
+#else
+# warning "no idea how to handle relocations on your arch"
+#endif
+
+ default:
+ printf("Warning: unhandled reloc %d\n",(int)ELF_R_TYPE(rel->r_info));
+ ret = obj_reloc_unhandled;
+ break;
+
+#if defined(USE_PLT_ENTRIES)
+
+bb_use_plt:
+
+ /* find the plt entry and initialize it if necessary */
+
+#if defined(USE_PLT_LIST)
+ for (pe = isym->pltent; pe != NULL && pe->addend != rel->r_addend;)
+ pe = pe->next;
+#else
+ pe = &isym->pltent;
+#endif
+
+ if (! pe->inited) {
+ ip = (unsigned long *) (ifile->plt->contents + pe->offset);
+
+ /* generate some machine code */
+
+#if defined(__arm__)
+ ip[0] = 0xe51ff004; /* ldr pc,[pc,#-4] */
+ ip[1] = v; /* sym@ */
+#endif
+#if defined(__powerpc__)
+ ip[0] = 0x3d600000 + ((v + 0x8000) >> 16); /* lis r11,sym@ha */
+ ip[1] = 0x396b0000 + (v & 0xffff); /* addi r11,r11,sym@l */
+ ip[2] = 0x7d6903a6; /* mtctr r11 */
+ ip[3] = 0x4e800420; /* bctr */
+#endif
+#if defined(__v850e__)
+ /* We have to trash a register, so we assume that any control
+ transfer more than 21-bits away must be a function call
+ (so we can use a call-clobbered register). */
+ ip[0] = 0x0621 + ((v & 0xffff) << 16); /* mov sym, r1 ... */
+ ip[1] = ((v >> 16) & 0xffff) + 0x610000; /* ...; jmp r1 */
+#endif
+ pe->inited = 1;
+ }
+
+ /* relative distance to target */
+ v -= dot;
+ /* if the target is too far away.... */
+#if defined(__arm__) || defined(__powerpc__)
+ if ((int)v < -0x02000000 || (int)v >= 0x02000000)
+#elif defined(__v850e__)
+ if ((ElfW(Sword))v > 0x1fffff || (ElfW(Sword))v < (ElfW(Sword))-0x200000)
+#endif
+ /* go via the plt */
+ v = plt + pe->offset - dot;
+
+#if defined(__v850e__)
+ if (v & 1)
+#else
+ if (v & 3)
+#endif
+ ret = obj_reloc_dangerous;
+
+ /* merge the offset into the instruction. */
+#if defined(__arm__)
+ /* Convert to words. */
+ v >>= 2;
+
+ *loc = (*loc & ~0x00ffffff) | ((v + *loc) & 0x00ffffff);
+#endif
+#if defined(__powerpc__)
+ *loc = (*loc & ~0x03fffffc) | (v & 0x03fffffc);
+#endif
+#if defined(__v850e__)
+ /* We write two shorts instead of a long because even 32-bit insns
+ only need half-word alignment, but the 32-bit data write needs
+ to be long-word aligned. */
+ ((unsigned short *)loc)[0] =
+ (*(unsigned short *)loc & 0xffc0) /* opcode + reg */
+ | ((v >> 16) & 0x3f); /* offs high part */
+ ((unsigned short *)loc)[1] =
+ (v & 0xffff); /* offs low part */
+#endif
+ break;
+#endif /* USE_PLT_ENTRIES */
+
+#if defined(USE_GOT_ENTRIES)
+bb_use_got:
+
+ /* needs an entry in the .got: set it, once */
+ if (!isym->gotent.inited) {
+ isym->gotent.inited = 1;
+ *(ElfW(Addr) *) (ifile->got->contents + isym->gotent.offset) = v;
+ }
+ /* make the reloc with_respect_to_.got */
+#if defined(__sh__)
+ *loc += isym->gotent.offset + rel->r_addend;
+#elif defined(__i386__) || defined(__arm__) || defined(__mc68000__)
+ *loc += isym->gotent.offset;
+#endif
+ break;
+
+#endif /* USE_GOT_ENTRIES */
+ }
+
+ return ret;
+}
+
+
+#if defined(USE_LIST)
+
+static int arch_list_add(ElfW(RelM) *rel, struct arch_list_entry **list,
+ int offset, int size)
+{
+ struct arch_list_entry *pe;
+
+ for (pe = *list; pe != NULL; pe = pe->next) {
+ if (pe->addend == rel->r_addend) {
+ break;
+ }
+ }
+
+ if (pe == NULL) {
+ pe = xmalloc(sizeof(struct arch_list_entry));
+ pe->next = *list;
+ pe->addend = rel->r_addend;
+ pe->offset = offset;
+ pe->inited = 0;
+ *list = pe;
+ return size;
+ }
+ return 0;
+}
+
+#endif
+
+#if defined(USE_SINGLE)
+
+static int arch_single_init(/*ElfW(RelM) *rel,*/ struct arch_single_entry *single,
+ int offset, int size)
+{
+ if (single->allocated == 0) {
+ single->allocated = 1;
+ single->offset = offset;
+ single->inited = 0;
+ return size;
+ }
+ return 0;
+}
+
+#endif
+
+#if defined(USE_GOT_ENTRIES) || defined(USE_PLT_ENTRIES)
+
+static struct obj_section *arch_xsect_init(struct obj_file *f, const char *name,
+ int offset, int size)
+{
+ struct obj_section *myrelsec = obj_find_section(f, name);
+
+ if (offset == 0) {
+ offset += size;
+ }
+
+ if (myrelsec) {
+ obj_extend_section(myrelsec, offset);
+ } else {
+ myrelsec = obj_create_alloced_section(f, name,
+ size, offset);
+ }
+
+ return myrelsec;
+}
+
+#endif
+
+static void arch_create_got(struct obj_file *f)
+{
+#if defined(USE_GOT_ENTRIES) || defined(USE_PLT_ENTRIES)
+ struct arch_file *ifile = (struct arch_file *) f;
+ int i;
+#if defined(USE_GOT_ENTRIES)
+ int got_offset = 0, got_needed = 0, got_allocate;
+#endif
+#if defined(USE_PLT_ENTRIES)
+ int plt_offset = 0, plt_needed = 0, plt_allocate;
+#endif
+ struct obj_section *relsec, *symsec, *strsec;
+ ElfW(RelM) *rel, *relend;
+ ElfW(Sym) *symtab, *extsym;
+ const char *strtab, *name;
+ struct arch_symbol *intsym;
+
+ for (i = 0; i < f->header.e_shnum; ++i) {
+ relsec = f->sections[i];
+ if (relsec->header.sh_type != SHT_RELM)
+ continue;
+
+ symsec = f->sections[relsec->header.sh_link];
+ strsec = f->sections[symsec->header.sh_link];
+
+ rel = (ElfW(RelM) *) relsec->contents;
+ relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM)));
+ symtab = (ElfW(Sym) *) symsec->contents;
+ strtab = (const char *) strsec->contents;
+
+ for (; rel < relend; ++rel) {
+ extsym = &symtab[ELF_R_SYM(rel->r_info)];
+
+#if defined(USE_GOT_ENTRIES)
+ got_allocate = 0;
+#endif
+#if defined(USE_PLT_ENTRIES)
+ plt_allocate = 0;
+#endif
+
+ switch (ELF_R_TYPE(rel->r_info)) {
+#if defined(__arm__)
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ plt_allocate = 1;
+ break;
+
+ case R_ARM_GOTOFF:
+ case R_ARM_GOTPC:
+ got_needed = 1;
+ continue;
+
+ case R_ARM_GOT32:
+ got_allocate = 1;
+ break;
+
+#elif defined(__i386__)
+ case R_386_GOTPC:
+ case R_386_GOTOFF:
+ got_needed = 1;
+ continue;
+
+ case R_386_GOT32:
+ got_allocate = 1;
+ break;
+
+#elif defined(__powerpc__)
+ case R_PPC_REL24:
+ plt_allocate = 1;
+ break;
+
+#elif defined(__mc68000__)
+ case R_68K_GOT32:
+ got_allocate = 1;
+ break;
+
+#ifdef R_68K_GOTOFF
+ case R_68K_GOTOFF:
+ got_needed = 1;
+ continue;
+#endif
+
+#elif defined(__sh__)
+ case R_SH_GOT32:
+ got_allocate = 1;
+ break;
+
+ case R_SH_GOTPC:
+ case R_SH_GOTOFF:
+ got_needed = 1;
+ continue;
+
+#elif defined(__v850e__)
+ case R_V850_22_PCREL:
+ plt_needed = 1;
+ break;
+
+#endif
+ default:
+ continue;
+ }
+
+ if (extsym->st_name != 0) {
+ name = strtab + extsym->st_name;
+ } else {
+ name = f->sections[extsym->st_shndx]->name;
+ }
+ intsym = (struct arch_symbol *) obj_find_symbol(f, name);
+#if defined(USE_GOT_ENTRIES)
+ if (got_allocate) {
+ got_offset += arch_single_init(
+ /*rel,*/ &intsym->gotent,
+ got_offset, GOT_ENTRY_SIZE);
+
+ got_needed = 1;
+ }
+#endif
+#if defined(USE_PLT_ENTRIES)
+ if (plt_allocate) {
+#if defined(USE_PLT_LIST)
+ plt_offset += arch_list_add(
+ rel, &intsym->pltent,
+ plt_offset, PLT_ENTRY_SIZE);
+#else
+ plt_offset += arch_single_init(
+ /*rel,*/ &intsym->pltent,
+ plt_offset, PLT_ENTRY_SIZE);
+#endif
+ plt_needed = 1;
+ }
+#endif
+ }
+ }
+
+#if defined(USE_GOT_ENTRIES)
+ if (got_needed) {
+ ifile->got = arch_xsect_init(f, ".got", got_offset,
+ GOT_ENTRY_SIZE);
+ }
+#endif
+
+#if defined(USE_PLT_ENTRIES)
+ if (plt_needed) {
+ ifile->plt = arch_xsect_init(f, ".plt", plt_offset,
+ PLT_ENTRY_SIZE);
+ }
+#endif
+
+#endif /* defined(USE_GOT_ENTRIES) || defined(USE_PLT_ENTRIES) */
+}
+
+/*======================================================================*/
+
+/* Standard ELF hash function. */
+static unsigned long obj_elf_hash_n(const char *name, unsigned long n)
+{
+ unsigned long h = 0;
+ unsigned long g;
+ unsigned char ch;
+
+ while (n > 0) {
+ ch = *name++;
+ h = (h << 4) + ch;
+ g = (h & 0xf0000000);
+ if (g != 0) {
+ h ^= g >> 24;
+ h &= ~g;
+ }
+ n--;
+ }
+ return h;
+}
+
+static unsigned long obj_elf_hash(const char *name)
+{
+ return obj_elf_hash_n(name, strlen(name));
+}
+
+#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
+/* String comparison for non-co-versioned kernel and module. */
+
+static int ncv_strcmp(const char *a, const char *b)
+{
+ size_t alen = strlen(a), blen = strlen(b);
+
+ if (blen == alen + 10 && b[alen] == '_' && b[alen + 1] == 'R')
+ return strncmp(a, b, alen);
+ else if (alen == blen + 10 && a[blen] == '_' && a[blen + 1] == 'R')
+ return strncmp(a, b, blen);
+ else
+ return strcmp(a, b);
+}
+
+/* String hashing for non-co-versioned kernel and module. Here
+ we are simply forced to drop the crc from the hash. */
+
+static unsigned long ncv_symbol_hash(const char *str)
+{
+ size_t len = strlen(str);
+ if (len > 10 && str[len - 10] == '_' && str[len - 9] == 'R')
+ len -= 10;
+ return obj_elf_hash_n(str, len);
+}
+
+static void
+obj_set_symbol_compare(struct obj_file *f,
+ int (*cmp) (const char *, const char *),
+ unsigned long (*hash) (const char *))
+{
+ if (cmp)
+ f->symbol_cmp = cmp;
+ if (hash) {
+ struct obj_symbol *tmptab[HASH_BUCKETS], *sym, *next;
+ int i;
+
+ f->symbol_hash = hash;
+
+ memcpy(tmptab, f->symtab, sizeof(tmptab));
+ memset(f->symtab, 0, sizeof(f->symtab));
+
+ for (i = 0; i < HASH_BUCKETS; ++i)
+ for (sym = tmptab[i]; sym; sym = next) {
+ unsigned long h = hash(sym->name) % HASH_BUCKETS;
+ next = sym->next;
+ sym->next = f->symtab[h];
+ f->symtab[h] = sym;
+ }
+ }
+}
+
+#endif /* FEATURE_INSMOD_VERSION_CHECKING */
+
+static struct obj_symbol *
+obj_add_symbol(struct obj_file *f, const char *name,
+ unsigned long symidx, int info,
+ int secidx, ElfW(Addr) value,
+ unsigned long size)
+{
+ struct obj_symbol *sym;
+ unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS;
+ int n_type = ELF_ST_TYPE(info);
+ int n_binding = ELF_ST_BIND(info);
+
+ for (sym = f->symtab[hash]; sym; sym = sym->next) {
+ if (f->symbol_cmp(sym->name, name) == 0) {
+ int o_secidx = sym->secidx;
+ int o_info = sym->info;
+ int o_type = ELF_ST_TYPE(o_info);
+ int o_binding = ELF_ST_BIND(o_info);
+
+ /* A redefinition! Is it legal? */
+
+ if (secidx == SHN_UNDEF)
+ return sym;
+ else if (o_secidx == SHN_UNDEF)
+ goto found;
+ else if (n_binding == STB_GLOBAL && o_binding == STB_LOCAL) {
+ /* Cope with local and global symbols of the same name
+ in the same object file, as might have been created
+ by ld -r. The only reason locals are now seen at this
+ level at all is so that we can do semi-sensible things
+ with parameters. */
+
+ struct obj_symbol *nsym, **p;
+
+ nsym = arch_new_symbol();
+ nsym->next = sym->next;
+ nsym->ksymidx = -1;
+
+ /* Excise the old (local) symbol from the hash chain. */
+ for (p = &f->symtab[hash]; *p != sym; p = &(*p)->next)
+ continue;
+ *p = sym = nsym;
+ goto found;
+ } else if (n_binding == STB_LOCAL) {
+ /* Another symbol of the same name has already been defined.
+ Just add this to the local table. */
+ sym = arch_new_symbol();
+ sym->next = NULL;
+ sym->ksymidx = -1;
+ f->local_symtab[symidx] = sym;
+ goto found;
+ } else if (n_binding == STB_WEAK)
+ return sym;
+ else if (o_binding == STB_WEAK)
+ goto found;
+ /* Don't unify COMMON symbols with object types the programmer
+ doesn't expect. */
+ else if (secidx == SHN_COMMON
+ && (o_type == STT_NOTYPE || o_type == STT_OBJECT))
+ return sym;
+ else if (o_secidx == SHN_COMMON
+ && (n_type == STT_NOTYPE || n_type == STT_OBJECT))
+ goto found;
+ else {
+ /* Don't report an error if the symbol is coming from
+ the kernel or some external module. */
+ if (secidx <= SHN_HIRESERVE)
+ bb_error_msg("%s multiply defined", name);
+ return sym;
+ }
+ }
+ }
+
+ /* Completely new symbol. */
+ sym = arch_new_symbol();
+ sym->next = f->symtab[hash];
+ f->symtab[hash] = sym;
+ sym->ksymidx = -1;
+ if (ELF_ST_BIND(info) == STB_LOCAL && symidx != (unsigned long)(-1)) {
+ if (symidx >= f->local_symtab_size)
+ bb_error_msg("local symbol %s with index %ld exceeds local_symtab_size %ld",
+ name, (long) symidx, (long) f->local_symtab_size);
+ else
+ f->local_symtab[symidx] = sym;
+ }
+
+found:
+ sym->name = name;
+ sym->value = value;
+ sym->size = size;
+ sym->secidx = secidx;
+ sym->info = info;
+
+ return sym;
+}
+
+static struct obj_symbol *
+obj_find_symbol(struct obj_file *f, const char *name)
+{
+ struct obj_symbol *sym;
+ unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS;
+
+ for (sym = f->symtab[hash]; sym; sym = sym->next)
+ if (f->symbol_cmp(sym->name, name) == 0)
+ return sym;
+
+ return NULL;
+}
+
+static ElfW(Addr) obj_symbol_final_value(struct obj_file * f, struct obj_symbol * sym)
+{
+ if (sym) {
+ if (sym->secidx >= SHN_LORESERVE)
+ return sym->value;
+
+ return sym->value + f->sections[sym->secidx]->header.sh_addr;
+ } else {
+ /* As a special case, a NULL sym has value zero. */
+ return 0;
+ }
+}
+
+static struct obj_section *obj_find_section(struct obj_file *f, const char *name)
+{
+ int i, n = f->header.e_shnum;
+
+ for (i = 0; i < n; ++i)
+ if (strcmp(f->sections[i]->name, name) == 0)
+ return f->sections[i];
+
+ return NULL;
+}
+
+static int obj_load_order_prio(struct obj_section *a)
+{
+ unsigned long af, ac;
+
+ af = a->header.sh_flags;
+
+ ac = 0;
+ if (a->name[0] != '.' || strlen(a->name) != 10 ||
+ strcmp(a->name + 5, ".init"))
+ ac |= 32;
+ if (af & SHF_ALLOC)
+ ac |= 16;
+ if (!(af & SHF_WRITE))
+ ac |= 8;
+ if (af & SHF_EXECINSTR)
+ ac |= 4;
+ if (a->header.sh_type != SHT_NOBITS)
+ ac |= 2;
+
+ return ac;
+}
+
+static void
+obj_insert_section_load_order(struct obj_file *f, struct obj_section *sec)
+{
+ struct obj_section **p;
+ int prio = obj_load_order_prio(sec);
+ for (p = f->load_order_search_start; *p; p = &(*p)->load_next)
+ if (obj_load_order_prio(*p) < prio)
+ break;
+ sec->load_next = *p;
+ *p = sec;
+}
+
+static struct obj_section *obj_create_alloced_section(struct obj_file *f,
+ const char *name,
+ unsigned long align,
+ unsigned long size)
+{
+ int newidx = f->header.e_shnum++;
+ struct obj_section *sec;
+
+ f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec));
+ f->sections[newidx] = sec = arch_new_section();
+
+ sec->header.sh_type = SHT_PROGBITS;
+ sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
+ sec->header.sh_size = size;
+ sec->header.sh_addralign = align;
+ sec->name = name;
+ sec->idx = newidx;
+ if (size)
+ sec->contents = xmalloc(size);
+
+ obj_insert_section_load_order(f, sec);
+
+ return sec;
+}
+
+static struct obj_section *obj_create_alloced_section_first(struct obj_file *f,
+ const char *name,
+ unsigned long align,
+ unsigned long size)
+{
+ int newidx = f->header.e_shnum++;
+ struct obj_section *sec;
+
+ f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec));
+ f->sections[newidx] = sec = arch_new_section();
+
+ sec->header.sh_type = SHT_PROGBITS;
+ sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
+ sec->header.sh_size = size;
+ sec->header.sh_addralign = align;
+ sec->name = name;
+ sec->idx = newidx;
+ if (size)
+ sec->contents = xmalloc(size);
+
+ sec->load_next = f->load_order;
+ f->load_order = sec;
+ if (f->load_order_search_start == &f->load_order)
+ f->load_order_search_start = &sec->load_next;
+
+ return sec;
+}
+
+static void *obj_extend_section(struct obj_section *sec, unsigned long more)
+{
+ unsigned long oldsize = sec->header.sh_size;
+ if (more) {
+ sec->contents = xrealloc(sec->contents, sec->header.sh_size += more);
+ }
+ return sec->contents + oldsize;
+}
+
+
+/* Conditionally add the symbols from the given symbol set to the
+ new module. */
+
+static int
+add_symbols_from( struct obj_file *f,
+ int idx, struct new_module_symbol *syms, size_t nsyms)
+{
+ struct new_module_symbol *s;
+ size_t i;
+ int used = 0;
+#ifdef SYMBOL_PREFIX
+ char *name_buf = 0;
+ size_t name_alloced_size = 0;
+#endif
+#if ENABLE_FEATURE_CHECK_TAINTED_MODULE
+ int gpl;
+
+ gpl = obj_gpl_license(f, NULL) == 0;
+#endif
+ for (i = 0, s = syms; i < nsyms; ++i, ++s) {
+ /* Only add symbols that are already marked external.
+ If we override locals we may cause problems for
+ argument initialization. We will also create a false
+ dependency on the module. */
+ struct obj_symbol *sym;
+ char *name;
+
+ /* GPL licensed modules can use symbols exported with
+ * EXPORT_SYMBOL_GPL, so ignore any GPLONLY_ prefix on the
+ * exported names. Non-GPL modules never see any GPLONLY_
+ * symbols so they cannot fudge it by adding the prefix on
+ * their references.
+ */
+ if (strncmp((char *)s->name, "GPLONLY_", 8) == 0) {
+#if ENABLE_FEATURE_CHECK_TAINTED_MODULE
+ if (gpl)
+ s->name += 8;
+ else
+#endif
+ continue;
+ }
+ name = (char *)s->name;
+
+#ifdef SYMBOL_PREFIX
+ /* Prepend SYMBOL_PREFIX to the symbol's name (the
+ kernel exports `C names', but module object files
+ reference `linker names'). */
+ size_t extra = sizeof SYMBOL_PREFIX;
+ size_t name_size = strlen(name) + extra;
+ if (name_size > name_alloced_size) {
+ name_alloced_size = name_size * 2;
+ name_buf = alloca(name_alloced_size);
+ }
+ strcpy(name_buf, SYMBOL_PREFIX);
+ strcpy(name_buf + extra - 1, name);
+ name = name_buf;
+#endif /* SYMBOL_PREFIX */
+
+ sym = obj_find_symbol(f, name);
+ if (sym && !(ELF_ST_BIND(sym->info) == STB_LOCAL)) {
+#ifdef SYMBOL_PREFIX
+ /* Put NAME_BUF into more permanent storage. */
+ name = xmalloc(name_size);
+ strcpy(name, name_buf);
+#endif
+ sym = obj_add_symbol(f, name, -1,
+ ELF_ST_INFO(STB_GLOBAL,
+ STT_NOTYPE),
+ idx, s->value, 0);
+ /* Did our symbol just get installed? If so, mark the
+ module as "used". */
+ if (sym->secidx == idx)
+ used = 1;
+ }
+ }
+
+ return used;
+}
+
+static void add_kernel_symbols(struct obj_file *f)
+{
+ struct external_module *m;
+ int i, nused = 0;
+
+ /* Add module symbols first. */
+
+ for (i = 0, m = ext_modules; i < n_ext_modules; ++i, ++m) {
+ if (m->nsyms
+ && add_symbols_from(f, SHN_HIRESERVE + 2 + i, m->syms, m->nsyms)
+ ) {
+ m->used = 1;
+ ++nused;
+ }
+ }
+
+ n_ext_modules_used = nused;
+
+ /* And finally the symbols from the kernel proper. */
+
+ if (nksyms)
+ add_symbols_from(f, SHN_HIRESERVE + 1, ksyms, nksyms);
+}
+
+static char *get_modinfo_value(struct obj_file *f, const char *key)
+{
+ struct obj_section *sec;
+ char *p, *v, *n, *ep;
+ size_t klen = strlen(key);
+
+ sec = obj_find_section(f, ".modinfo");
+ if (sec == NULL)
+ return NULL;
+ p = sec->contents;
+ ep = p + sec->header.sh_size;
+ while (p < ep) {
+ v = strchr(p, '=');
+ n = strchr(p, '\0');
+ if (v) {
+ if (p + klen == v && strncmp(p, key, klen) == 0)
+ return v + 1;
+ } else {
+ if (p + klen == n && strcmp(p, key) == 0)
+ return n;
+ }
+ p = n + 1;
+ }
+
+ return NULL;
+}
+
+
+/*======================================================================*/
+/* Functions relating to module loading after 2.1.18. */
+
+static void
+new_process_module_arguments(struct obj_file *f, int argc, char **argv)
+{
+ while (argc > 0) {
+ char *p, *q, *key, *sym_name;
+ struct obj_symbol *sym;
+ char *contents, *loc;
+ int min, max, n;
+
+ p = *argv;
+ q = strchr(p, '=');
+ if (q == NULL) {
+ argc--;
+ continue;
+ }
+
+ key = alloca(q - p + 6);
+ memcpy(key, "parm_", 5);
+ memcpy(key + 5, p, q - p);
+ key[q - p + 5] = 0;
+
+ p = get_modinfo_value(f, key);
+ key += 5;
+ if (p == NULL) {
+ bb_error_msg_and_die("invalid parameter %s", key);
+ }
+
+#ifdef SYMBOL_PREFIX
+ sym_name = alloca(strlen(key) + sizeof SYMBOL_PREFIX);
+ strcpy(sym_name, SYMBOL_PREFIX);
+ strcat(sym_name, key);
+#else
+ sym_name = key;
+#endif
+ sym = obj_find_symbol(f, sym_name);
+
+ /* Also check that the parameter was not resolved from the kernel. */
+ if (sym == NULL || sym->secidx > SHN_HIRESERVE) {
+ bb_error_msg_and_die("symbol for parameter %s not found", key);
+ }
+
+ if (isdigit(*p)) {
+ min = strtoul(p, &p, 10);
+ if (*p == '-')
+ max = strtoul(p + 1, &p, 10);
+ else
+ max = min;
+ } else
+ min = max = 1;
+
+ contents = f->sections[sym->secidx]->contents;
+ loc = contents + sym->value;
+ n = (*++q != '\0');
+
+ while (1) {
+ if ((*p == 's') || (*p == 'c')) {
+ char *str;
+
+ /* Do C quoting if we begin with a ", else slurp the lot. */
+ if (*q == '"') {
+ char *r;
+
+ str = alloca(strlen(q));
+ for (r = str, q++; *q != '"'; ++q, ++r) {
+ if (*q == '\0')
+ bb_error_msg_and_die("improperly terminated string argument for %s",
+ key);
+ if (*q == '\\')
+ switch (*++q) {
+ case 'a':
+ *r = '\a';
+ break;
+ case 'b':
+ *r = '\b';
+ break;
+ case 'e':
+ *r = '\033';
+ break;
+ case 'f':
+ *r = '\f';
+ break;
+ case 'n':
+ *r = '\n';
+ break;
+ case 'r':
+ *r = '\r';
+ break;
+ case 't':
+ *r = '\t';
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ int c = *q - '0';
+ if (q[1] >= '0' && q[1] <= '7') {
+ c = (c * 8) + *++q - '0';
+ if (q[1] >= '0' && q[1] <= '7')
+ c = (c * 8) + *++q - '0';
+ }
+ *r = c;
+ }
+ break;
+
+ default:
+ *r = *q;
+ break;
+ }
+ else
+ *r = *q;
+ }
+ *r = '\0';
+ ++q;
+ } else {
+ char *r;
+
+ /* In this case, the string is not quoted. We will break
+ it using the coma (like for ints). If the user wants to
+ include comas in a string, he just has to quote it */
+
+ /* Search the next coma */
+ r = strchr(q, ',');
+
+ /* Found ? */
+ if (r != (char *) NULL) {
+ /* Recopy the current field */
+ str = alloca(r - q + 1);
+ memcpy(str, q, r - q);
+
+ /* I don't know if it is useful, as the previous case
+ doesn't nul terminate the string ??? */
+ str[r - q] = '\0';
+
+ /* Keep next fields */
+ q = r;
+ } else {
+ /* last string */
+ str = q;
+ q = (char*)"";
+ }
+ }
+
+ if (*p == 's') {
+ /* Normal string */
+ obj_string_patch(f, sym->secidx, loc - contents, str);
+ loc += tgt_sizeof_char_p;
+ } else {
+ /* Array of chars (in fact, matrix!) */
+ unsigned long charssize; /* size of each member */
+
+ /* Get the size of each member */
+ /* Probably we should do that outside the loop ? */
+ if (!isdigit(*(p + 1))) {
+ bb_error_msg_and_die("parameter type 'c' for %s must be followed by"
+ " the maximum size", key);
+ }
+ charssize = strtoul(p + 1, (char **) NULL, 10);
+
+ /* Check length */
+ if (strlen(str) >= charssize) {
+ bb_error_msg_and_die("string too long for %s (max %ld)", key,
+ charssize - 1);
+ }
+
+ /* Copy to location */
+ strcpy((char *) loc, str);
+ loc += charssize;
+ }
+ } else {
+ long v = strtoul(q, &q, 0);
+ switch (*p) {
+ case 'b':
+ *loc++ = v;
+ break;
+ case 'h':
+ *(short *) loc = v;
+ loc += tgt_sizeof_short;
+ break;
+ case 'i':
+ *(int *) loc = v;
+ loc += tgt_sizeof_int;
+ break;
+ case 'l':
+ *(long *) loc = v;
+ loc += tgt_sizeof_long;
+ break;
+
+ default:
+ bb_error_msg_and_die("unknown parameter type '%c' for %s", *p, key);
+ }
+ }
+ retry_end_of_value:
+ switch (*q) {
+ case '\0':
+ goto end_of_arg;
+
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ ++q;
+ goto retry_end_of_value;
+
+ case ',':
+ if (++n > max) {
+ bb_error_msg_and_die("too many values for %s (max %d)", key, max);
+ }
+ ++q;
+ break;
+
+ default:
+ bb_error_msg_and_die("invalid argument syntax for %s", key);
+ }
+ }
+ end_of_arg:
+ if (n < min) {
+ bb_error_msg_and_die("too few values for %s (min %d)", key, min);
+ }
+
+ argc--;
+ argv++;
+ }
+}
+
+#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
+static int new_is_module_checksummed(struct obj_file *f)
+{
+ const char *p = get_modinfo_value(f, "using_checksums");
+ if (p)
+ return xatoi(p);
+ return 0;
+}
+
+/* Get the module's kernel version in the canonical integer form. */
+
+static int
+new_get_module_version(struct obj_file *f, char str[STRVERSIONLEN])
+{
+ char *p, *q;
+ int a, b, c;
+
+ p = get_modinfo_value(f, "kernel_version");
+ if (p == NULL)
+ return -1;
+ safe_strncpy(str, p, STRVERSIONLEN);
+
+ a = strtoul(p, &p, 10);
+ if (*p != '.')
+ return -1;
+ b = strtoul(p + 1, &p, 10);
+ if (*p != '.')
+ return -1;
+ c = strtoul(p + 1, &q, 10);
+ if (p + 1 == q)
+ return -1;
+
+ return a << 16 | b << 8 | c;
+}
+
+#endif /* FEATURE_INSMOD_VERSION_CHECKING */
+
+
+/* Fetch the loaded modules, and all currently exported symbols. */
+
+static void new_get_kernel_symbols(void)
+{
+ char *module_names, *mn;
+ struct external_module *modules, *m;
+ struct new_module_symbol *syms, *s;
+ size_t ret, bufsize, nmod, nsyms, i, j;
+
+ /* Collect the loaded modules. */
+
+ bufsize = 256;
+ module_names = xmalloc(bufsize);
+
+ retry_modules_load:
+ if (query_module(NULL, QM_MODULES, module_names, bufsize, &ret)) {
+ if (errno == ENOSPC && bufsize < ret) {
+ bufsize = ret;
+ module_names = xrealloc(module_names, bufsize);
+ goto retry_modules_load;
+ }
+ bb_perror_msg_and_die("QM_MODULES");
+ }
+
+ n_ext_modules = nmod = ret;
+
+ /* Collect the modules' symbols. */
+
+ if (nmod) {
+ ext_modules = modules = xmalloc(nmod * sizeof(*modules));
+ memset(modules, 0, nmod * sizeof(*modules));
+ for (i = 0, mn = module_names, m = modules;
+ i < nmod; ++i, ++m, mn += strlen(mn) + 1) {
+ struct new_module_info info;
+
+ if (query_module(mn, QM_INFO, &info, sizeof(info), &ret)) {
+ if (errno == ENOENT) {
+ /* The module was removed out from underneath us. */
+ continue;
+ }
+ bb_perror_msg_and_die("query_module: QM_INFO: %s", mn);
+ }
+
+ bufsize = 1024;
+ syms = xmalloc(bufsize);
+ retry_mod_sym_load:
+ if (query_module(mn, QM_SYMBOLS, syms, bufsize, &ret)) {
+ switch (errno) {
+ case ENOSPC:
+ bufsize = ret;
+ syms = xrealloc(syms, bufsize);
+ goto retry_mod_sym_load;
+ case ENOENT:
+ /* The module was removed out from underneath us. */
+ continue;
+ default:
+ bb_perror_msg_and_die("query_module: QM_SYMBOLS: %s", mn);
+ }
+ }
+ nsyms = ret;
+
+ m->name = mn;
+ m->addr = info.addr;
+ m->nsyms = nsyms;
+ m->syms = syms;
+
+ for (j = 0, s = syms; j < nsyms; ++j, ++s) {
+ s->name += (unsigned long) syms;
+ }
+ }
+ }
+
+ /* Collect the kernel's symbols. */
+
+ syms = xmalloc(bufsize = 16 * 1024);
+ retry_kern_sym_load:
+ if (query_module(NULL, QM_SYMBOLS, syms, bufsize, &ret)) {
+ if (errno == ENOSPC && bufsize < ret) {
+ syms = xrealloc(syms, bufsize = ret);
+ goto retry_kern_sym_load;
+ }
+ bb_perror_msg_and_die("kernel: QM_SYMBOLS");
+ }
+ nksyms = nsyms = ret;
+ ksyms = syms;
+
+ for (j = 0, s = syms; j < nsyms; ++j, ++s) {
+ s->name += (unsigned long) syms;
+ }
+}
+
+
+/* Return the kernel symbol checksum version, or zero if not used. */
+
+static int new_is_kernel_checksummed(void)
+{
+ struct new_module_symbol *s;
+ size_t i;
+
+ /* Using_Versions is not the first symbol, but it should be in there. */
+
+ for (i = 0, s = ksyms; i < nksyms; ++i, ++s)
+ if (strcmp((char *) s->name, "Using_Versions") == 0)
+ return s->value;
+
+ return 0;
+}
+
+
+static void new_create_this_module(struct obj_file *f, const char *m_name)
+{
+ struct obj_section *sec;
+
+ sec = obj_create_alloced_section_first(f, ".this", tgt_sizeof_long,
+ sizeof(struct new_module));
+ memset(sec->contents, 0, sizeof(struct new_module));
+
+ obj_add_symbol(f, SPFX "__this_module", -1,
+ ELF_ST_INFO(STB_LOCAL, STT_OBJECT), sec->idx, 0,
+ sizeof(struct new_module));
+
+ obj_string_patch(f, sec->idx, offsetof(struct new_module, name),
+ m_name);
+}
+
+#if ENABLE_FEATURE_INSMOD_KSYMOOPS_SYMBOLS
+/* add an entry to the __ksymtab section, creating it if necessary */
+static void new_add_ksymtab(struct obj_file *f, struct obj_symbol *sym)
+{
+ struct obj_section *sec;
+ ElfW(Addr) ofs;
+
+ /* ensure __ksymtab is allocated, EXPORT_NOSYMBOLS creates a non-alloc section.
+ * If __ksymtab is defined but not marked alloc, x out the first character
+ * (no obj_delete routine) and create a new __ksymtab with the correct
+ * characteristics.
+ */
+ sec = obj_find_section(f, "__ksymtab");
+ if (sec && !(sec->header.sh_flags & SHF_ALLOC)) {
+ *((char *)(sec->name)) = 'x'; /* override const */
+ sec = NULL;
+ }
+ if (!sec)
+ sec = obj_create_alloced_section(f, "__ksymtab",
+ tgt_sizeof_void_p, 0);
+ if (!sec)
+ return;
+ sec->header.sh_flags |= SHF_ALLOC;
+ /* Empty section might be byte-aligned */
+ sec->header.sh_addralign = tgt_sizeof_void_p;
+ ofs = sec->header.sh_size;
+ obj_symbol_patch(f, sec->idx, ofs, sym);
+ obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p, sym->name);
+ obj_extend_section(sec, 2 * tgt_sizeof_char_p);
+}
+#endif /* FEATURE_INSMOD_KSYMOOPS_SYMBOLS */
+
+static int new_create_module_ksymtab(struct obj_file *f)
+{
+ struct obj_section *sec;
+ int i;
+
+ /* We must always add the module references. */
+
+ if (n_ext_modules_used) {
+ struct new_module_ref *dep;
+ struct obj_symbol *tm;
+
+ sec = obj_create_alloced_section(f, ".kmodtab", tgt_sizeof_void_p,
+ (sizeof(struct new_module_ref)
+ * n_ext_modules_used));
+ if (!sec)
+ return 0;
+
+ tm = obj_find_symbol(f, SPFX "__this_module");
+ dep = (struct new_module_ref *) sec->contents;
+ for (i = 0; i < n_ext_modules; ++i)
+ if (ext_modules[i].used) {
+ dep->dep = ext_modules[i].addr;
+ obj_symbol_patch(f, sec->idx,
+ (char *) &dep->ref - sec->contents, tm);
+ dep->next_ref = 0;
+ ++dep;
+ }
+ }
+
+ if (!flag_noexport && !obj_find_section(f, "__ksymtab")) {
+ size_t nsyms;
+ int *loaded;
+
+ sec = obj_create_alloced_section(f, "__ksymtab", tgt_sizeof_void_p, 0);
+
+ /* We don't want to export symbols residing in sections that
+ aren't loaded. There are a number of these created so that
+ we make sure certain module options don't appear twice. */
+
+ loaded = alloca(sizeof(int) * (i = f->header.e_shnum));
+ while (--i >= 0)
+ loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0;
+
+ for (nsyms = i = 0; i < HASH_BUCKETS; ++i) {
+ struct obj_symbol *sym;
+ for (sym = f->symtab[i]; sym; sym = sym->next)
+ if (ELF_ST_BIND(sym->info) != STB_LOCAL
+ && sym->secidx <= SHN_HIRESERVE
+ && (sym->secidx >= SHN_LORESERVE
+ || loaded[sym->secidx])) {
+ ElfW(Addr) ofs = nsyms * 2 * tgt_sizeof_void_p;
+
+ obj_symbol_patch(f, sec->idx, ofs, sym);
+ obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p,
+ sym->name);
+
+ nsyms++;
+ }
+ }
+
+ obj_extend_section(sec, nsyms * 2 * tgt_sizeof_char_p);
+ }
+
+ return 1;
+}
+
+
+static int
+new_init_module(const char *m_name, struct obj_file *f, unsigned long m_size)
+{
+ struct new_module *module;
+ struct obj_section *sec;
+ void *image;
+ int ret;
+ tgt_long m_addr;
+
+ sec = obj_find_section(f, ".this");
+ if (!sec || !sec->contents) {
+ bb_perror_msg_and_die("corrupt module %s?",m_name);
+ }
+ module = (struct new_module *) sec->contents;
+ m_addr = sec->header.sh_addr;
+
+ module->size_of_struct = sizeof(*module);
+ module->size = m_size;
+ module->flags = flag_autoclean ? NEW_MOD_AUTOCLEAN : 0;
+
+ sec = obj_find_section(f, "__ksymtab");
+ if (sec && sec->header.sh_size) {
+ module->syms = sec->header.sh_addr;
+ module->nsyms = sec->header.sh_size / (2 * tgt_sizeof_char_p);
+ }
+
+ if (n_ext_modules_used) {
+ sec = obj_find_section(f, ".kmodtab");
+ module->deps = sec->header.sh_addr;
+ module->ndeps = n_ext_modules_used;
+ }
+
+ module->init =
+ obj_symbol_final_value(f, obj_find_symbol(f, SPFX "init_module"));
+ module->cleanup =
+ obj_symbol_final_value(f, obj_find_symbol(f, SPFX "cleanup_module"));
+
+ sec = obj_find_section(f, "__ex_table");
+ if (sec) {
+ module->ex_table_start = sec->header.sh_addr;
+ module->ex_table_end = sec->header.sh_addr + sec->header.sh_size;
+ }
+
+ sec = obj_find_section(f, ".text.init");
+ if (sec) {
+ module->runsize = sec->header.sh_addr - m_addr;
+ }
+ sec = obj_find_section(f, ".data.init");
+ if (sec) {
+ if (!module->runsize ||
+ module->runsize > sec->header.sh_addr - m_addr)
+ module->runsize = sec->header.sh_addr - m_addr;
+ }
+ sec = obj_find_section(f, ARCHDATA_SEC_NAME);
+ if (sec && sec->header.sh_size) {
+ module->archdata_start = (void*)sec->header.sh_addr;
+ module->archdata_end = module->archdata_start + sec->header.sh_size;
+ }
+ sec = obj_find_section(f, KALLSYMS_SEC_NAME);
+ if (sec && sec->header.sh_size) {
+ module->kallsyms_start = (void*)sec->header.sh_addr;
+ module->kallsyms_end = module->kallsyms_start + sec->header.sh_size;
+ }
+
+ /* Whew! All of the initialization is complete. Collect the final
+ module image and give it to the kernel. */
+
+ image = xmalloc(m_size);
+ obj_create_image(f, image);
+
+ ret = init_module(m_name, (struct new_module *) image);
+ if (ret)
+ bb_perror_msg("init_module: %s", m_name);
+
+ free(image);
+
+ return ret == 0;
+}
+
+
+/*======================================================================*/
+
+static void
+obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
+ const char *string)
+{
+ struct obj_string_patch *p;
+ struct obj_section *strsec;
+ size_t len = strlen(string) + 1;
+ char *loc;
+
+ p = xmalloc(sizeof(*p));
+ p->next = f->string_patches;
+ p->reloc_secidx = secidx;
+ p->reloc_offset = offset;
+ f->string_patches = p;
+
+ strsec = obj_find_section(f, ".kstrtab");
+ if (strsec == NULL) {
+ strsec = obj_create_alloced_section(f, ".kstrtab", 1, len);
+ p->string_offset = 0;
+ loc = strsec->contents;
+ } else {
+ p->string_offset = strsec->header.sh_size;
+ loc = obj_extend_section(strsec, len);
+ }
+ memcpy(loc, string, len);
+}
+
+static void
+obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
+ struct obj_symbol *sym)
+{
+ struct obj_symbol_patch *p;
+
+ p = xmalloc(sizeof(*p));
+ p->next = f->symbol_patches;
+ p->reloc_secidx = secidx;
+ p->reloc_offset = offset;
+ p->sym = sym;
+ f->symbol_patches = p;
+}
+
+static void obj_check_undefineds(struct obj_file *f)
+{
+ unsigned i;
+
+ for (i = 0; i < HASH_BUCKETS; ++i) {
+ struct obj_symbol *sym;
+ for (sym = f->symtab[i]; sym; sym = sym->next)
+ if (sym->secidx == SHN_UNDEF) {
+ if (ELF_ST_BIND(sym->info) == STB_WEAK) {
+ sym->secidx = SHN_ABS;
+ sym->value = 0;
+ } else {
+ if (!flag_quiet)
+ bb_error_msg_and_die("unresolved symbol %s", sym->name);
+ }
+ }
+ }
+}
+
+static void obj_allocate_commons(struct obj_file *f)
+{
+ struct common_entry {
+ struct common_entry *next;
+ struct obj_symbol *sym;
+ } *common_head = NULL;
+
+ unsigned long i;
+
+ for (i = 0; i < HASH_BUCKETS; ++i) {
+ struct obj_symbol *sym;
+ for (sym = f->symtab[i]; sym; sym = sym->next)
+ if (sym->secidx == SHN_COMMON) {
+ /* Collect all COMMON symbols and sort them by size so as to
+ minimize space wasted by alignment requirements. */
+ {
+ struct common_entry **p, *n;
+ for (p = &common_head; *p; p = &(*p)->next)
+ if (sym->size <= (*p)->sym->size)
+ break;
+
+ n = alloca(sizeof(*n));
+ n->next = *p;
+ n->sym = sym;
+ *p = n;
+ }
+ }
+ }
+
+ for (i = 1; i < f->local_symtab_size; ++i) {
+ struct obj_symbol *sym = f->local_symtab[i];
+ if (sym && sym->secidx == SHN_COMMON) {
+ struct common_entry **p, *n;
+ for (p = &common_head; *p; p = &(*p)->next)
+ if (sym == (*p)->sym)
+ break;
+ else if (sym->size < (*p)->sym->size) {
+ n = alloca(sizeof(*n));
+ n->next = *p;
+ n->sym = sym;
+ *p = n;
+ break;
+ }
+ }
+ }
+
+ if (common_head) {
+ /* Find the bss section. */
+ for (i = 0; i < f->header.e_shnum; ++i)
+ if (f->sections[i]->header.sh_type == SHT_NOBITS)
+ break;
+
+ /* If for some reason there hadn't been one, create one. */
+ if (i == f->header.e_shnum) {
+ struct obj_section *sec;
+
+ f->sections = xrealloc(f->sections, (i + 1) * sizeof(sec));
+ f->sections[i] = sec = arch_new_section();
+ f->header.e_shnum = i + 1;
+
+ sec->header.sh_type = SHT_PROGBITS;
+ sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
+ sec->name = ".bss";
+ sec->idx = i;
+ }
+
+ /* Allocate the COMMONS. */
+ {
+ ElfW(Addr) bss_size = f->sections[i]->header.sh_size;
+ ElfW(Addr) max_align = f->sections[i]->header.sh_addralign;
+ struct common_entry *c;
+
+ for (c = common_head; c; c = c->next) {
+ ElfW(Addr) align = c->sym->value;
+
+ if (align > max_align)
+ max_align = align;
+ if (bss_size & (align - 1))
+ bss_size = (bss_size | (align - 1)) + 1;
+
+ c->sym->secidx = i;
+ c->sym->value = bss_size;
+
+ bss_size += c->sym->size;
+ }
+
+ f->sections[i]->header.sh_size = bss_size;
+ f->sections[i]->header.sh_addralign = max_align;
+ }
+ }
+
+ /* For the sake of patch relocation and parameter initialization,
+ allocate zeroed data for NOBITS sections now. Note that after
+ this we cannot assume NOBITS are really empty. */
+ for (i = 0; i < f->header.e_shnum; ++i) {
+ struct obj_section *s = f->sections[i];
+ if (s->header.sh_type == SHT_NOBITS) {
+ if (s->header.sh_size != 0)
+ s->contents = memset(xmalloc(s->header.sh_size),
+ 0, s->header.sh_size);
+ else
+ s->contents = NULL;
+
+ s->header.sh_type = SHT_PROGBITS;
+ }
+ }
+}
+
+static unsigned long obj_load_size(struct obj_file *f)
+{
+ unsigned long dot = 0;
+ struct obj_section *sec;
+
+ /* Finalize the positions of the sections relative to one another. */
+
+ for (sec = f->load_order; sec; sec = sec->load_next) {
+ ElfW(Addr) align;
+
+ align = sec->header.sh_addralign;
+ if (align && (dot & (align - 1)))
+ dot = (dot | (align - 1)) + 1;
+
+ sec->header.sh_addr = dot;
+ dot += sec->header.sh_size;
+ }
+
+ return dot;
+}
+
+static int obj_relocate(struct obj_file *f, ElfW(Addr) base)
+{
+ int i, n = f->header.e_shnum;
+ int ret = 1;
+
+ /* Finalize the addresses of the sections. */
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+
+ /* And iterate over all of the relocations. */
+
+ for (i = 0; i < n; ++i) {
+ struct obj_section *relsec, *symsec, *targsec, *strsec;
+ ElfW(RelM) * rel, *relend;
+ ElfW(Sym) * symtab;
+ const char *strtab;
+
+ relsec = f->sections[i];
+ if (relsec->header.sh_type != SHT_RELM)
+ continue;
+
+ symsec = f->sections[relsec->header.sh_link];
+ targsec = f->sections[relsec->header.sh_info];
+ strsec = f->sections[symsec->header.sh_link];
+
+ rel = (ElfW(RelM) *) relsec->contents;
+ relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM)));
+ symtab = (ElfW(Sym) *) symsec->contents;
+ strtab = (const char *) strsec->contents;
+
+ for (; rel < relend; ++rel) {
+ ElfW(Addr) value = 0;
+ struct obj_symbol *intsym = NULL;
+ unsigned long symndx;
+ ElfW(Sym) * extsym = 0;
+ const char *errmsg;
+
+ /* Attempt to find a value to use for this relocation. */
+
+ symndx = ELF_R_SYM(rel->r_info);
+ if (symndx) {
+ /* Note we've already checked for undefined symbols. */
+
+ extsym = &symtab[symndx];
+ if (ELF_ST_BIND(extsym->st_info) == STB_LOCAL) {
+ /* Local symbols we look up in the local table to be sure
+ we get the one that is really intended. */
+ intsym = f->local_symtab[symndx];
+ } else {
+ /* Others we look up in the hash table. */
+ const char *name;
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ intsym = obj_find_symbol(f, name);
+ }
+
+ value = obj_symbol_final_value(f, intsym);
+ intsym->referenced = 1;
+ }
+#if SHT_RELM == SHT_RELA
+#if defined(__alpha__) && defined(AXP_BROKEN_GAS)
+ /* Work around a nasty GAS bug, that is fixed as of 2.7.0.9. */
+ if (!extsym || !extsym->st_name ||
+ ELF_ST_BIND(extsym->st_info) != STB_LOCAL)
+#endif
+ value += rel->r_addend;
+#endif
+
+ /* Do it! */
+ switch (arch_apply_relocation
+ (f, targsec, /*symsec,*/ intsym, rel, value)
+ ) {
+ case obj_reloc_ok:
+ break;
+
+ case obj_reloc_overflow:
+ errmsg = "Relocation overflow";
+ goto bad_reloc;
+ case obj_reloc_dangerous:
+ errmsg = "Dangerous relocation";
+ goto bad_reloc;
+ case obj_reloc_unhandled:
+ errmsg = "Unhandled relocation";
+bad_reloc:
+ if (extsym) {
+ bb_error_msg("%s of type %ld for %s", errmsg,
+ (long) ELF_R_TYPE(rel->r_info),
+ strtab + extsym->st_name);
+ } else {
+ bb_error_msg("%s of type %ld", errmsg,
+ (long) ELF_R_TYPE(rel->r_info));
+ }
+ ret = 0;
+ break;
+ }
+ }
+ }
+
+ /* Finally, take care of the patches. */
+
+ if (f->string_patches) {
+ struct obj_string_patch *p;
+ struct obj_section *strsec;
+ ElfW(Addr) strsec_base;
+ strsec = obj_find_section(f, ".kstrtab");
+ strsec_base = strsec->header.sh_addr;
+
+ for (p = f->string_patches; p; p = p->next) {
+ struct obj_section *targsec = f->sections[p->reloc_secidx];
+ *(ElfW(Addr) *) (targsec->contents + p->reloc_offset)
+ = strsec_base + p->string_offset;
+ }
+ }
+
+ if (f->symbol_patches) {
+ struct obj_symbol_patch *p;
+
+ for (p = f->symbol_patches; p; p = p->next) {
+ struct obj_section *targsec = f->sections[p->reloc_secidx];
+ *(ElfW(Addr) *) (targsec->contents + p->reloc_offset)
+ = obj_symbol_final_value(f, p->sym);
+ }
+ }
+
+ return ret;
+}
+
+static int obj_create_image(struct obj_file *f, char *image)
+{
+ struct obj_section *sec;
+ ElfW(Addr) base = f->baseaddr;
+
+ for (sec = f->load_order; sec; sec = sec->load_next) {
+ char *secimg;
+
+ if (sec->contents == 0 || sec->header.sh_size == 0)
+ continue;
+
+ secimg = image + (sec->header.sh_addr - base);
+
+ /* Note that we allocated data for NOBITS sections earlier. */
+ memcpy(secimg, sec->contents, sec->header.sh_size);
+ }
+
+ return 1;
+}
+
+/*======================================================================*/
+
+static struct obj_file *obj_load(FILE * fp, int loadprogbits ATTRIBUTE_UNUSED)
+{
+ struct obj_file *f;
+ ElfW(Shdr) * section_headers;
+ size_t shnum, i;
+ char *shstrtab;
+
+ /* Read the file header. */
+
+ f = arch_new_file();
+ f->symbol_cmp = strcmp;
+ f->symbol_hash = obj_elf_hash;
+ f->load_order_search_start = &f->load_order;
+
+ fseek(fp, 0, SEEK_SET);
+ if (fread(&f->header, sizeof(f->header), 1, fp) != 1) {
+ bb_perror_msg_and_die("error reading ELF header");
+ }
+
+ if (f->header.e_ident[EI_MAG0] != ELFMAG0
+ || f->header.e_ident[EI_MAG1] != ELFMAG1
+ || f->header.e_ident[EI_MAG2] != ELFMAG2
+ || f->header.e_ident[EI_MAG3] != ELFMAG3) {
+ bb_error_msg_and_die("not an ELF file");
+ }
+ if (f->header.e_ident[EI_CLASS] != ELFCLASSM
+ || f->header.e_ident[EI_DATA] != (BB_BIG_ENDIAN
+ ? ELFDATA2MSB : ELFDATA2LSB)
+ || f->header.e_ident[EI_VERSION] != EV_CURRENT
+ || !MATCH_MACHINE(f->header.e_machine)) {
+ bb_error_msg_and_die("ELF file not for this architecture");
+ }
+ if (f->header.e_type != ET_REL) {
+ bb_error_msg_and_die("ELF file not a relocatable object");
+ }
+
+ /* Read the section headers. */
+
+ if (f->header.e_shentsize != sizeof(ElfW(Shdr))) {
+ bb_error_msg_and_die("section header size mismatch: %lu != %lu",
+ (unsigned long) f->header.e_shentsize,
+ (unsigned long) sizeof(ElfW(Shdr)));
+ }
+
+ shnum = f->header.e_shnum;
+ f->sections = xmalloc(sizeof(struct obj_section *) * shnum);
+ memset(f->sections, 0, sizeof(struct obj_section *) * shnum);
+
+ section_headers = alloca(sizeof(ElfW(Shdr)) * shnum);
+ fseek(fp, f->header.e_shoff, SEEK_SET);
+ if (fread(section_headers, sizeof(ElfW(Shdr)), shnum, fp) != shnum) {
+ bb_perror_msg_and_die("error reading ELF section headers");
+ }
+
+ /* Read the section data. */
+
+ for (i = 0; i < shnum; ++i) {
+ struct obj_section *sec;
+
+ f->sections[i] = sec = arch_new_section();
+
+ sec->header = section_headers[i];
+ sec->idx = i;
+
+ if (sec->header.sh_size) {
+ switch (sec->header.sh_type) {
+ case SHT_NULL:
+ case SHT_NOTE:
+ case SHT_NOBITS:
+ /* ignore */
+ break;
+
+ case SHT_PROGBITS:
+#if LOADBITS
+ if (!loadprogbits) {
+ sec->contents = NULL;
+ break;
+ }
+#endif
+ case SHT_SYMTAB:
+ case SHT_STRTAB:
+ case SHT_RELM:
+ if (sec->header.sh_size > 0) {
+ sec->contents = xmalloc(sec->header.sh_size);
+ fseek(fp, sec->header.sh_offset, SEEK_SET);
+ if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) {
+ bb_perror_msg_and_die("error reading ELF section data");
+ }
+ } else {
+ sec->contents = NULL;
+ }
+ break;
+
+#if SHT_RELM == SHT_REL
+ case SHT_RELA:
+ bb_error_msg_and_die("RELA relocations not supported on this architecture");
+#else
+ case SHT_REL:
+ bb_error_msg_and_die("REL relocations not supported on this architecture");
+#endif
+ default:
+ if (sec->header.sh_type >= SHT_LOPROC) {
+ /* Assume processor specific section types are debug
+ info and can safely be ignored. If this is ever not
+ the case (Hello MIPS?), don't put ifdefs here but
+ create an arch_load_proc_section(). */
+ break;
+ }
+
+ bb_error_msg_and_die("can't handle sections of type %ld",
+ (long) sec->header.sh_type);
+ }
+ }
+ }
+
+ /* Do what sort of interpretation as needed by each section. */
+
+ shstrtab = f->sections[f->header.e_shstrndx]->contents;
+
+ for (i = 0; i < shnum; ++i) {
+ struct obj_section *sec = f->sections[i];
+ sec->name = shstrtab + sec->header.sh_name;
+ }
+
+ for (i = 0; i < shnum; ++i) {
+ struct obj_section *sec = f->sections[i];
+
+ /* .modinfo should be contents only but gcc has no attribute for that.
+ * The kernel may have marked .modinfo as ALLOC, ignore this bit.
+ */
+ if (strcmp(sec->name, ".modinfo") == 0)
+ sec->header.sh_flags &= ~SHF_ALLOC;
+
+ if (sec->header.sh_flags & SHF_ALLOC)
+ obj_insert_section_load_order(f, sec);
+
+ switch (sec->header.sh_type) {
+ case SHT_SYMTAB:
+ {
+ unsigned long nsym, j;
+ char *strtab;
+ ElfW(Sym) * sym;
+
+ if (sec->header.sh_entsize != sizeof(ElfW(Sym))) {
+ bb_error_msg_and_die("symbol size mismatch: %lu != %lu",
+ (unsigned long) sec->header.sh_entsize,
+ (unsigned long) sizeof(ElfW(Sym)));
+ }
+
+ nsym = sec->header.sh_size / sizeof(ElfW(Sym));
+ strtab = f->sections[sec->header.sh_link]->contents;
+ sym = (ElfW(Sym) *) sec->contents;
+
+ /* Allocate space for a table of local symbols. */
+ j = f->local_symtab_size = sec->header.sh_info;
+ f->local_symtab = xzalloc(j * sizeof(struct obj_symbol *));
+
+ /* Insert all symbols into the hash table. */
+ for (j = 1, ++sym; j < nsym; ++j, ++sym) {
+ ElfW(Addr) val = sym->st_value;
+ const char *name;
+ if (sym->st_name)
+ name = strtab + sym->st_name;
+ else if (sym->st_shndx < shnum)
+ name = f->sections[sym->st_shndx]->name;
+ else
+ continue;
+#if defined(__SH5__)
+ /*
+ * For sh64 it is possible that the target of a branch
+ * requires a mode switch (32 to 16 and back again).
+ *
+ * This is implied by the lsb being set in the target
+ * address for SHmedia mode and clear for SHcompact.
+ */
+ val |= sym->st_other & 4;
+#endif
+ obj_add_symbol(f, name, j, sym->st_info, sym->st_shndx,
+ val, sym->st_size);
+ }
+ }
+ break;
+
+ case SHT_RELM:
+ if (sec->header.sh_entsize != sizeof(ElfW(RelM))) {
+ bb_error_msg_and_die("relocation entry size mismatch: %lu != %lu",
+ (unsigned long) sec->header.sh_entsize,
+ (unsigned long) sizeof(ElfW(RelM)));
+ }
+ break;
+ /* XXX Relocation code from modutils-2.3.19 is not here.
+ * Why? That's about 20 lines of code from obj/obj_load.c,
+ * which gets done in a second pass through the sections.
+ * This BusyBox insmod does similar work in obj_relocate(). */
+ }
+ }
+
+ return f;
+}
+
+#if ENABLE_FEATURE_INSMOD_LOADINKMEM
+/*
+ * load the unloaded sections directly into the memory allocated by
+ * kernel for the module
+ */
+
+static int obj_load_progbits(FILE * fp, struct obj_file* f, char* imagebase)
+{
+ ElfW(Addr) base = f->baseaddr;
+ struct obj_section* sec;
+
+ for (sec = f->load_order; sec; sec = sec->load_next) {
+
+ /* section already loaded? */
+ if (sec->contents != NULL)
+ continue;
+
+ if (sec->header.sh_size == 0)
+ continue;
+
+ sec->contents = imagebase + (sec->header.sh_addr - base);
+ fseek(fp, sec->header.sh_offset, SEEK_SET);
+ if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) {
+ bb_perror_msg("error reading ELF section data");
+ return 0;
+ }
+
+ }
+ return 1;
+}
+#endif
+
+static void hide_special_symbols(struct obj_file *f)
+{
+ static const char *const specials[] = {
+ SPFX "cleanup_module",
+ SPFX "init_module",
+ SPFX "kernel_version",
+ NULL
+ };
+
+ struct obj_symbol *sym;
+ const char *const *p;
+
+ for (p = specials; *p; ++p) {
+ sym = obj_find_symbol(f, *p);
+ if (sym != NULL)
+ sym->info = ELF_ST_INFO(STB_LOCAL, ELF_ST_TYPE(sym->info));
+ }
+}
+
+
+#if ENABLE_FEATURE_CHECK_TAINTED_MODULE
+static int obj_gpl_license(struct obj_file *f, const char **license)
+{
+ struct obj_section *sec;
+ /* This list must match *exactly* the list of allowable licenses in
+ * linux/include/linux/module.h. Checking for leading "GPL" will not
+ * work, somebody will use "GPL sucks, this is proprietary".
+ */
+ static const char *const gpl_licenses[] = {
+ "GPL",
+ "GPL v2",
+ "GPL and additional rights",
+ "Dual BSD/GPL",
+ "Dual MPL/GPL"
+ };
+
+ sec = obj_find_section(f, ".modinfo");
+ if (sec) {
+ const char *value, *ptr, *endptr;
+ ptr = sec->contents;
+ endptr = ptr + sec->header.sh_size;
+ while (ptr < endptr) {
+ value = strchr(ptr, '=');
+ if (value && strncmp(ptr, "license", value-ptr) == 0) {
+ unsigned i;
+ if (license)
+ *license = value+1;
+ for (i = 0; i < ARRAY_SIZE(gpl_licenses); ++i) {
+ if (strcmp(value+1, gpl_licenses[i]) == 0)
+ return 0;
+ }
+ return 2;
+ }
+ ptr = strchr(ptr, '\0');
+ if (ptr)
+ ptr++;
+ else
+ ptr = endptr;
+ }
+ }
+ return 1;
+}
+
+#define TAINT_FILENAME "/proc/sys/kernel/tainted"
+#define TAINT_PROPRIETORY_MODULE (1 << 0)
+#define TAINT_FORCED_MODULE (1 << 1)
+#define TAINT_UNSAFE_SMP (1 << 2)
+#define TAINT_URL "http://www.tux.org/lkml/#export-tainted"
+
+static void set_tainted(int fd, char *m_name,
+ int kernel_has_tainted, int taint, const char *text1, const char *text2)
+{
+ static smallint printed_info;
+
+ char buf[80];
+ int oldval;
+
+ if (fd < 0 && !kernel_has_tainted)
+ return; /* New modutils on old kernel */
+ printf("Warning: loading %s will taint the kernel: %s%s\n",
+ m_name, text1, text2);
+ if (!printed_info) {
+ printf(" See %s for information about tainted modules\n", TAINT_URL);
+ printed_info = 1;
+ }
+ if (fd >= 0) {
+ read(fd, buf, sizeof(buf)-1);
+ buf[sizeof(buf)-1] = '\0';
+ oldval = strtoul(buf, NULL, 10);
+ sprintf(buf, "%d\n", oldval | taint);
+ write(fd, buf, strlen(buf));
+ }
+}
+
+/* Check if loading this module will taint the kernel. */
+static void check_tainted_module(struct obj_file *f, char *m_name)
+{
+ static const char tainted_file[] ALIGN1 = TAINT_FILENAME;
+
+ int fd, kernel_has_tainted;
+ const char *ptr;
+
+ kernel_has_tainted = 1;
+ fd = open(tainted_file, O_RDWR);
+ if (fd < 0) {
+ if (errno == ENOENT)
+ kernel_has_tainted = 0;
+ else if (errno == EACCES)
+ kernel_has_tainted = 1;
+ else {
+ perror(tainted_file);
+ kernel_has_tainted = 0;
+ }
+ }
+
+ switch (obj_gpl_license(f, &ptr)) {
+ case 0:
+ break;
+ case 1:
+ set_tainted(fd, m_name, kernel_has_tainted, TAINT_PROPRIETORY_MODULE, "no license", "");
+ break;
+ case 2:
+ /* The module has a non-GPL license so we pretend that the
+ * kernel always has a taint flag to get a warning even on
+ * kernels without the proc flag.
+ */
+ set_tainted(fd, m_name, 1, TAINT_PROPRIETORY_MODULE, "non-GPL license - ", ptr);
+ break;
+ default:
+ set_tainted(fd, m_name, 1, TAINT_PROPRIETORY_MODULE, "Unexpected return from obj_gpl_license", "");
+ break;
+ }
+
+ if (flag_force_load)
+ set_tainted(fd, m_name, 1, TAINT_FORCED_MODULE, "forced load", "");
+
+ if (fd >= 0)
+ close(fd);
+}
+#else /* FEATURE_CHECK_TAINTED_MODULE */
+#define check_tainted_module(x, y) do { } while (0);
+#endif /* FEATURE_CHECK_TAINTED_MODULE */
+
+#if ENABLE_FEATURE_INSMOD_KSYMOOPS_SYMBOLS
+/* add module source, timestamp, kernel version and a symbol for the
+ * start of some sections. this info is used by ksymoops to do better
+ * debugging.
+ */
+#if !ENABLE_FEATURE_INSMOD_VERSION_CHECKING
+#define get_module_version(f, str) get_module_version(str)
+#endif
+static int
+get_module_version(struct obj_file *f, char str[STRVERSIONLEN])
+{
+#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
+ return new_get_module_version(f, str);
+#else /* FEATURE_INSMOD_VERSION_CHECKING */
+ strncpy(str, "???", sizeof(str));
+ return -1;
+#endif /* FEATURE_INSMOD_VERSION_CHECKING */
+}
+
+/* add module source, timestamp, kernel version and a symbol for the
+ * start of some sections. this info is used by ksymoops to do better
+ * debugging.
+ */
+static void
+add_ksymoops_symbols(struct obj_file *f, const char *filename,
+ const char *m_name)
+{
+ static const char symprefix[] ALIGN1 = "__insmod_";
+ static const char section_names[][8] = {
+ ".text",
+ ".rodata",
+ ".data",
+ ".bss",
+ ".sbss"
+ };
+
+ struct obj_section *sec;
+ struct obj_symbol *sym;
+ char *name, *absolute_filename;
+ char str[STRVERSIONLEN];
+ unsigned i;
+ int l, lm_name, lfilename, use_ksymtab, version;
+ struct stat statbuf;
+
+ /* WARNING: was using realpath, but replaced by readlink to stop using
+ * lots of stack. But here it seems to be able to cause problems? */
+ absolute_filename = xmalloc_readlink(filename);
+ if (!absolute_filename)
+ absolute_filename = xstrdup(filename);
+
+ lm_name = strlen(m_name);
+ lfilename = strlen(absolute_filename);
+
+ /* add to ksymtab if it already exists or there is no ksymtab and other symbols
+ * are not to be exported. otherwise leave ksymtab alone for now, the
+ * "export all symbols" compatibility code will export these symbols later.
+ */
+ use_ksymtab = obj_find_section(f, "__ksymtab") || flag_noexport;
+
+ sec = obj_find_section(f, ".this");
+ if (sec) {
+ /* tag the module header with the object name, last modified
+ * timestamp and module version. worst case for module version
+ * is 0xffffff, decimal 16777215. putting all three fields in
+ * one symbol is less readable but saves kernel space.
+ */
+ l = sizeof(symprefix) + /* "__insmod_" */
+ lm_name + /* module name */
+ 2 + /* "_O" */
+ lfilename + /* object filename */
+ 2 + /* "_M" */
+ 2 * sizeof(statbuf.st_mtime) + /* mtime in hex */
+ 2 + /* "_V" */
+ 8 + /* version in dec */
+ 1; /* nul */
+ name = xmalloc(l);
+ if (stat(absolute_filename, &statbuf) != 0)
+ statbuf.st_mtime = 0;
+ version = get_module_version(f, str); /* -1 if not found */
+ snprintf(name, l, "%s%s_O%s_M%0*lX_V%d",
+ symprefix, m_name, absolute_filename,
+ (int)(2 * sizeof(statbuf.st_mtime)), statbuf.st_mtime,
+ version);
+ sym = obj_add_symbol(f, name, -1,
+ ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE),
+ sec->idx, sec->header.sh_addr, 0);
+ if (use_ksymtab)
+ new_add_ksymtab(f, sym);
+ }
+ free(absolute_filename);
+#ifdef _NOT_SUPPORTED_
+ /* record where the persistent data is going, same address as previous symbol */
+
+ if (f->persist) {
+ l = sizeof(symprefix) + /* "__insmod_" */
+ lm_name + /* module name */
+ 2 + /* "_P" */
+ strlen(f->persist) + /* data store */
+ 1; /* nul */
+ name = xmalloc(l);
+ snprintf(name, l, "%s%s_P%s",
+ symprefix, m_name, f->persist);
+ sym = obj_add_symbol(f, name, -1, ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE),
+ sec->idx, sec->header.sh_addr, 0);
+ if (use_ksymtab)
+ new_add_ksymtab(f, sym);
+ }
+#endif /* _NOT_SUPPORTED_ */
+ /* tag the desired sections if size is non-zero */
+
+ for (i = 0; i < ARRAY_SIZE(section_names); ++i) {
+ sec = obj_find_section(f, section_names[i]);
+ if (sec && sec->header.sh_size) {
+ l = sizeof(symprefix) + /* "__insmod_" */
+ lm_name + /* module name */
+ 2 + /* "_S" */
+ strlen(sec->name) + /* section name */
+ 2 + /* "_L" */
+ 8 + /* length in dec */
+ 1; /* nul */
+ name = xmalloc(l);
+ snprintf(name, l, "%s%s_S%s_L%ld",
+ symprefix, m_name, sec->name,
+ (long)sec->header.sh_size);
+ sym = obj_add_symbol(f, name, -1, ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE),
+ sec->idx, sec->header.sh_addr, 0);
+ if (use_ksymtab)
+ new_add_ksymtab(f, sym);
+ }
+ }
+}
+#endif /* FEATURE_INSMOD_KSYMOOPS_SYMBOLS */
+
+#if ENABLE_FEATURE_INSMOD_LOAD_MAP
+static void print_load_map(struct obj_file *f)
+{
+ struct obj_section *sec;
+#if ENABLE_FEATURE_INSMOD_LOAD_MAP_FULL
+ struct obj_symbol **all, **p;
+ int i, nsyms, *loaded;
+ struct obj_symbol *sym;
+#endif
+ /* Report on the section layout. */
+
+ printf("Sections: Size %-*s Align\n",
+ (int) (2 * sizeof(void *)), "Address");
+
+ for (sec = f->load_order; sec; sec = sec->load_next) {
+ int a;
+ unsigned long tmp;
+
+ for (a = -1, tmp = sec->header.sh_addralign; tmp; ++a)
+ tmp >>= 1;
+ if (a == -1)
+ a = 0;
+
+ printf("%-15s %08lx %0*lx 2**%d\n",
+ sec->name,
+ (long)sec->header.sh_size,
+ (int) (2 * sizeof(void *)),
+ (long)sec->header.sh_addr,
+ a);
+ }
+#if ENABLE_FEATURE_INSMOD_LOAD_MAP_FULL
+ /* Quick reference which section indicies are loaded. */
+
+ i = f->header.e_shnum;
+ loaded = alloca(sizeof(int) * i);
+ while (--i >= 0)
+ loaded[i] = ((f->sections[i]->header.sh_flags & SHF_ALLOC) != 0);
+
+ /* Collect the symbols we'll be listing. */
+
+ for (nsyms = i = 0; i < HASH_BUCKETS; ++i)
+ for (sym = f->symtab[i]; sym; sym = sym->next)
+ if (sym->secidx <= SHN_HIRESERVE
+ && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx]))
+ ++nsyms;
+
+ all = alloca(nsyms * sizeof(struct obj_symbol *));
+
+ for (i = 0, p = all; i < HASH_BUCKETS; ++i)
+ for (sym = f->symtab[i]; sym; sym = sym->next)
+ if (sym->secidx <= SHN_HIRESERVE
+ && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx]))
+ *p++ = sym;
+
+ /* And list them. */
+ printf("\nSymbols:\n");
+ for (p = all; p < all + nsyms; ++p) {
+ char type = '?';
+ unsigned long value;
+
+ sym = *p;
+ if (sym->secidx == SHN_ABS) {
+ type = 'A';
+ value = sym->value;
+ } else if (sym->secidx == SHN_UNDEF) {
+ type = 'U';
+ value = 0;
+ } else {
+ sec = f->sections[sym->secidx];
+
+ if (sec->header.sh_type == SHT_NOBITS)
+ type = 'B';
+ else if (sec->header.sh_flags & SHF_ALLOC) {
+ if (sec->header.sh_flags & SHF_EXECINSTR)
+ type = 'T';
+ else if (sec->header.sh_flags & SHF_WRITE)
+ type = 'D';
+ else
+ type = 'R';
+ }
+ value = sym->value + sec->header.sh_addr;
+ }
+
+ if (ELF_ST_BIND(sym->info) == STB_LOCAL)
+ type = tolower(type);
+
+ printf("%0*lx %c %s\n", (int) (2 * sizeof(void *)), value,
+ type, sym->name);
+ }
+#endif
+}
+#else /* !FEATURE_INSMOD_LOAD_MAP */
+void print_load_map(struct obj_file *f);
+#endif
+
+int insmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int insmod_main(int argc, char **argv)
+{
+ char *opt_o, *arg1;
+ int len;
+ int k_crcs;
+ char *tmp, *tmp1;
+ unsigned long m_size;
+ ElfW(Addr) m_addr;
+ struct obj_file *f;
+ struct stat st;
+ char *m_name = NULL;
+ int exit_status = EXIT_FAILURE;
+ int m_has_modinfo;
+#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
+ struct utsname uts_info;
+ char m_strversion[STRVERSIONLEN];
+ int m_version, m_crcs;
+#endif
+#if ENABLE_FEATURE_CLEAN_UP
+ FILE *fp = NULL;
+#else
+ FILE *fp;
+#endif
+ int k_version = 0;
+ struct utsname myuname;
+
+ /* Parse any options */
+ getopt32(argv, OPTION_STR, &opt_o);
+ arg1 = argv[optind];
+ if (option_mask32 & OPT_o) { // -o /* name the output module */
+ free(m_name);
+ m_name = xstrdup(opt_o);
+ }
+
+ if (arg1 == NULL) {
+ bb_show_usage();
+ }
+
+ /* Grab the module name */
+ tmp1 = xstrdup(arg1);
+ tmp = basename(tmp1);
+ len = strlen(tmp);
+
+ if (uname(&myuname) == 0) {
+ if (myuname.release[0] == '2') {
+ k_version = myuname.release[2] - '0';
+ }
+ }
+
+#if ENABLE_FEATURE_2_6_MODULES
+ if (k_version > 4 && len > 3 && tmp[len - 3] == '.'
+ && tmp[len - 2] == 'k' && tmp[len - 1] == 'o'
+ ) {
+ len -= 3;
+ tmp[len] = '\0';
+ } else
+#endif
+ if (len > 2 && tmp[len - 2] == '.' && tmp[len - 1] == 'o') {
+ len -= 2;
+ tmp[len] = '\0';
+ }
+
+
+#if ENABLE_FEATURE_2_6_MODULES
+ if (k_version > 4)
+ m_fullName = xasprintf("%s.ko", tmp);
+ else
+#endif
+ m_fullName = xasprintf("%s.o", tmp);
+
+ if (!m_name) {
+ m_name = tmp;
+ } else {
+ free(tmp1);
+ tmp1 = NULL; /* flag for free(m_name) before exit() */
+ }
+
+ /* Get a filedesc for the module. Check that we have a complete path */
+ if (stat(arg1, &st) < 0 || !S_ISREG(st.st_mode)
+ || (fp = fopen(arg1, "r")) == NULL
+ ) {
+ /* Hmm. Could not open it. First search under /lib/modules/`uname -r`,
+ * but do not error out yet if we fail to find it... */
+ if (k_version) { /* uname succeedd */
+ char *module_dir;
+ char *tmdn;
+
+ tmdn = concat_path_file(CONFIG_DEFAULT_MODULES_DIR, myuname.release);
+ /* Jump through hoops in case /lib/modules/`uname -r`
+ * is a symlink. We do not want recursive_action to
+ * follow symlinks, but we do want to follow the
+ * /lib/modules/`uname -r` dir, So resolve it ourselves
+ * if it is a link... */
+ module_dir = xmalloc_readlink(tmdn);
+ if (!module_dir)
+ module_dir = xstrdup(tmdn);
+ recursive_action(module_dir, ACTION_RECURSE,
+ check_module_name_match, NULL, m_fullName, 0);
+ free(module_dir);
+ free(tmdn);
+ }
+
+ /* Check if we have found anything yet */
+ if (!m_filename || ((fp = fopen(m_filename, "r")) == NULL)) {
+ int r;
+ char *module_dir;
+
+ free(m_filename);
+ m_filename = NULL;
+ module_dir = xmalloc_readlink(CONFIG_DEFAULT_MODULES_DIR);
+ if (!module_dir)
+ module_dir = xstrdup(CONFIG_DEFAULT_MODULES_DIR);
+ /* No module found under /lib/modules/`uname -r`, this
+ * time cast the net a bit wider. Search /lib/modules/ */
+ r = recursive_action(module_dir, ACTION_RECURSE,
+ check_module_name_match, NULL, m_fullName, 0);
+ if (r)
+ bb_error_msg_and_die("%s: module not found", m_fullName);
+ free(module_dir);
+ if (m_filename == NULL
+ || ((fp = fopen(m_filename, "r")) == NULL)
+ ) {
+ bb_error_msg_and_die("%s: module not found", m_fullName);
+ }
+ }
+ } else
+ m_filename = xstrdup(arg1);
+
+ if (flag_verbose)
+ printf("Using %s\n", m_filename);
+
+#if ENABLE_FEATURE_2_6_MODULES
+ if (k_version > 4) {
+ argv[optind] = m_filename;
+ optind--;
+ return insmod_ng_main(argc - optind, argv + optind);
+ }
+#endif
+
+ f = obj_load(fp, LOADBITS);
+
+ if (get_modinfo_value(f, "kernel_version") == NULL)
+ m_has_modinfo = 0;
+ else
+ m_has_modinfo = 1;
+
+#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
+ /* Version correspondence? */
+ if (!flag_quiet) {
+ if (uname(&uts_info) < 0)
+ uts_info.release[0] = '\0';
+ if (m_has_modinfo) {
+ m_version = new_get_module_version(f, m_strversion);
+ if (m_version == -1) {
+ bb_error_msg_and_die("cannot find the kernel version the module was "
+ "compiled for");
+ }
+ }
+
+ if (strncmp(uts_info.release, m_strversion, STRVERSIONLEN) != 0) {
+ bb_error_msg("%skernel-module version mismatch\n"
+ "\t%s was compiled for kernel version %s\n"
+ "\twhile this kernel is version %s",
+ flag_force_load ? "warning: " : "",
+ m_filename, m_strversion, uts_info.release);
+ if (!flag_force_load)
+ goto out;
+ }
+ }
+ k_crcs = 0;
+#endif /* FEATURE_INSMOD_VERSION_CHECKING */
+
+ if (query_module(NULL, 0, NULL, 0, NULL))
+ bb_error_msg_and_die("not configured to support old kernels");
+ new_get_kernel_symbols();
+ k_crcs = new_is_kernel_checksummed();
+
+#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
+ m_crcs = 0;
+ if (m_has_modinfo)
+ m_crcs = new_is_module_checksummed(f);
+
+ if (m_crcs != k_crcs)
+ obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash);
+#endif /* FEATURE_INSMOD_VERSION_CHECKING */
+
+ /* Let the module know about the kernel symbols. */
+ add_kernel_symbols(f);
+
+ /* Allocate common symbols, symbol tables, and string tables. */
+
+ new_create_this_module(f, m_name);
+ obj_check_undefineds(f);
+ obj_allocate_commons(f);
+ check_tainted_module(f, m_name);
+
+ /* done with the module name, on to the optional var=value arguments */
+ ++optind;
+ if (optind < argc) {
+ new_process_module_arguments(f, argc - optind, argv + optind);
+ }
+
+ arch_create_got(f);
+ hide_special_symbols(f);
+
+#if ENABLE_FEATURE_INSMOD_KSYMOOPS_SYMBOLS
+ add_ksymoops_symbols(f, m_filename, m_name);
+#endif /* FEATURE_INSMOD_KSYMOOPS_SYMBOLS */
+
+ new_create_module_ksymtab(f);
+
+ /* Find current size of the module */
+ m_size = obj_load_size(f);
+
+ m_addr = create_module(m_name, m_size);
+ if (m_addr == (ElfW(Addr))(-1)) switch (errno) {
+ case EEXIST:
+ bb_error_msg_and_die("a module named %s already exists", m_name);
+ case ENOMEM:
+ bb_error_msg_and_die("can't allocate kernel memory for module; needed %lu bytes",
+ m_size);
+ default:
+ bb_perror_msg_and_die("create_module: %s", m_name);
+ }
+
+#if !LOADBITS
+ /*
+ * the PROGBITS section was not loaded by the obj_load
+ * now we can load them directly into the kernel memory
+ */
+ if (!obj_load_progbits(fp, f, (char*)m_addr)) {
+ delete_module(m_name, 0);
+ goto out;
+ }
+#endif
+
+ if (!obj_relocate(f, m_addr)) {
+ delete_module(m_name, 0);
+ goto out;
+ }
+
+ if (!new_init_module(m_name, f, m_size)) {
+ delete_module(m_name, 0);
+ goto out;
+ }
+
+ if (flag_print_load_map)
+ print_load_map(f);
+
+ exit_status = EXIT_SUCCESS;
+
+ out:
+#if ENABLE_FEATURE_CLEAN_UP
+ if (fp)
+ fclose(fp);
+ free(tmp1);
+ if (!tmp1)
+ free(m_name);
+ free(m_filename);
+#endif
+ return exit_status;
+}
+
+#endif /* ENABLE_FEATURE_2_4_MODULES */
+/*
+ * End of big piece of 2.4-specific code
+ */
+
+
+#if ENABLE_FEATURE_2_6_MODULES
+
+#include <sys/mman.h>
+
+#if defined __UCLIBC__ && !ENABLE_FEATURE_2_4_MODULES
+/* big time suckage. The old prototype above renders our nice fwd-decl wrong */
+extern int init_module(void *module, unsigned long len, const char *options);
+#else
+#include <asm/unistd.h>
+#include <sys/syscall.h>
+#define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts)
+#endif
+
+/* We use error numbers in a loose translation... */
+static const char *moderror(int err)
+{
+ switch (err) {
+ case ENOEXEC:
+ return "invalid module format";
+ case ENOENT:
+ return "unknown symbol in module";
+ case ESRCH:
+ return "module has wrong symbol version";
+ case EINVAL:
+ return "invalid parameters";
+ default:
+ return strerror(err);
+ }
+}
+
+#if !ENABLE_FEATURE_2_4_MODULES
+int insmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int insmod_main(int argc ATTRIBUTE_UNUSED, char **argv)
+#else
+static int insmod_ng_main(int argc ATTRIBUTE_UNUSED, char **argv)
+#endif
+{
+ size_t len;
+ int optlen;
+ void *map;
+ char *filename, *options;
+
+ filename = *++argv;
+ if (!filename)
+ bb_show_usage();
+
+ /* Rest is options */
+ options = xzalloc(1);
+ optlen = 0;
+ while (*++argv) {
+ options = xrealloc(options, optlen + 2 + strlen(*argv) + 2);
+ /* Spaces handled by "" pairs, but no way of escaping quotes */
+ optlen += sprintf(options + optlen, (strchr(*argv,' ') ? "\"%s\" " : "%s "), *argv);
+ }
+
+#if 0
+ /* Any special reason why mmap? It isn't performance critical. -vda */
+ /* Yes, xmalloc'ing can use *alot* of RAM. Don't forget that there are
+ * modules out there that are half a megabyte! mmap()ing is way nicer
+ * for small mem boxes, i guess. */
+ /* But after load, these modules will take up that 0.5mb in kernel
+ * anyway. Using malloc here causes only a transient spike to 1mb,
+ * after module is loaded, we go back to normal 0.5mb usage
+ * (in kernel). Also, mmap isn't magic - when we touch mapped data,
+ * we use memory. -vda */
+ int fd;
+ struct stat st;
+ unsigned long len;
+ fd = xopen(filename, O_RDONLY);
+ fstat(fd, &st);
+ len = st.st_size;
+ map = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (map == MAP_FAILED) {
+ bb_perror_msg_and_die("cannot mmap '%s'", filename);
+ }
+
+ /* map == NULL on Blackfin, probably on other MMU-less systems too. Workaround. */
+ if (map == NULL) {
+ map = xmalloc(len);
+ xread(fd, map, len);
+ }
+#else
+ len = MAXINT(ssize_t);
+ map = xmalloc_open_read_close(filename, &len);
+#endif
+
+ if (init_module(map, len, options) != 0)
+ bb_error_msg_and_die("cannot insert '%s': %s",
+ filename, moderror(errno));
+ return 0;
+}
+
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/modutils/lsmod.c b/cleopatre/busybox-1.11.1-spc300/modutils/lsmod.c
new file mode 100644
index 0000000000..a2330fe984
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/modutils/lsmod.c
@@ -0,0 +1,194 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini lsmod implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Modified by Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and
+ * Nicolas Ferre <nicolas.ferre@alcove.fr> to support pre 2.1 kernels
+ * (which lack the query_module() interface).
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+
+#if !ENABLE_FEATURE_CHECK_TAINTED_MODULE
+static void check_tainted(void) { bb_putchar('\n'); }
+#else
+#define TAINT_FILENAME "/proc/sys/kernel/tainted"
+#define TAINT_PROPRIETORY_MODULE (1<<0)
+#define TAINT_FORCED_MODULE (1<<1)
+#define TAINT_UNSAFE_SMP (1<<2)
+
+static void check_tainted(void)
+{
+ int tainted;
+ FILE *f;
+
+ tainted = 0;
+ f = fopen(TAINT_FILENAME, "r");
+ if (f) {
+ fscanf(f, "%d", &tainted);
+ fclose(f);
+ }
+ if (tainted) {
+ printf(" Tainted: %c%c%c\n",
+ tainted & TAINT_PROPRIETORY_MODULE ? 'P' : 'G',
+ tainted & TAINT_FORCED_MODULE ? 'F' : ' ',
+ tainted & TAINT_UNSAFE_SMP ? 'S' : ' ');
+ } else {
+ printf(" Not tainted\n");
+ }
+}
+#endif
+
+#if ENABLE_FEATURE_QUERY_MODULE_INTERFACE
+
+struct module_info
+{
+ unsigned long addr;
+ unsigned long size;
+ unsigned long flags;
+ long usecount;
+};
+
+
+int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret);
+
+enum {
+/* Values for query_module's which. */
+ QM_MODULES = 1,
+ QM_DEPS = 2,
+ QM_REFS = 3,
+ QM_SYMBOLS = 4,
+ QM_INFO = 5,
+
+/* Bits of module.flags. */
+ NEW_MOD_RUNNING = 1,
+ NEW_MOD_DELETED = 2,
+ NEW_MOD_AUTOCLEAN = 4,
+ NEW_MOD_VISITED = 8,
+ NEW_MOD_USED_ONCE = 16,
+ NEW_MOD_INITIALIZING = 64
+};
+
+int lsmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int lsmod_main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
+{
+ struct module_info info;
+ char *module_names, *mn, *deps, *dn;
+ size_t bufsize, depsize, nmod, count, i, j;
+
+ module_names = deps = NULL;
+ bufsize = depsize = 0;
+ while (query_module(NULL, QM_MODULES, module_names, bufsize, &nmod)) {
+ if (errno != ENOSPC) bb_perror_msg_and_die("QM_MODULES");
+ module_names = xmalloc(bufsize = nmod);
+ }
+
+ deps = xmalloc(depsize = 256);
+ printf("Module\t\t\tSize Used by");
+ check_tainted();
+
+ for (i = 0, mn = module_names; i < nmod; mn += strlen(mn) + 1, i++) {
+ if (query_module(mn, QM_INFO, &info, sizeof(info), &count)) {
+ if (errno == ENOENT) {
+ /* The module was removed out from underneath us. */
+ continue;
+ }
+ /* else choke */
+ bb_perror_msg_and_die("module %s: QM_INFO", mn);
+ }
+ while (query_module(mn, QM_REFS, deps, depsize, &count)) {
+ if (errno == ENOENT) {
+ /* The module was removed out from underneath us. */
+ continue;
+ } else if (errno != ENOSPC)
+ bb_perror_msg_and_die("module %s: QM_REFS", mn);
+ deps = xrealloc(deps, count);
+ }
+ printf("%-20s%8lu%4ld", mn, info.size, info.usecount);
+ if (info.flags & NEW_MOD_DELETED)
+ printf(" (deleted)");
+ else if (info.flags & NEW_MOD_INITIALIZING)
+ printf(" (initializing)");
+ else if (!(info.flags & NEW_MOD_RUNNING))
+ printf(" (uninitialized)");
+ else {
+ if (info.flags & NEW_MOD_AUTOCLEAN)
+ printf(" (autoclean) ");
+ if (!(info.flags & NEW_MOD_USED_ONCE))
+ printf(" (unused)");
+ }
+ if (count)
+ printf(" [");
+ for (j = 0, dn = deps; j < count; dn += strlen(dn) + 1, j++) {
+ printf("%s%s", dn, (j==count-1)? "":" ");
+ }
+ if (count)
+ bb_putchar(']');
+
+ bb_putchar('\n');
+ }
+
+#if ENABLE_FEATURE_CLEAN_UP
+ free(module_names);
+#endif
+
+ return 0;
+}
+
+#else /* CONFIG_FEATURE_QUERY_MODULE_INTERFACE */
+
+int lsmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int lsmod_main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
+{
+ FILE *file = xfopen("/proc/modules", "r");
+
+ printf("Module Size Used by");
+ check_tainted();
+#if ENABLE_FEATURE_LSMOD_PRETTY_2_6_OUTPUT
+ {
+ char *line;
+ while ((line = xmalloc_fgets(file)) != NULL) {
+ char *tok;
+
+ tok = strtok(line, " \t");
+ printf("%-19s", tok);
+ tok = strtok(NULL, " \t\n");
+ printf(" %8s", tok);
+ tok = strtok(NULL, " \t\n");
+ /* Null if no module unloading support. */
+ if (tok) {
+ printf(" %s", tok);
+ tok = strtok(NULL, "\n");
+ if (!tok)
+ tok = (char*)"";
+ /* New-style has commas, or -. If so,
+ truncate (other fields might follow). */
+ else if (strchr(tok, ',')) {
+ tok = strtok(tok, "\t ");
+ /* Strip trailing comma. */
+ if (tok[strlen(tok)-1] == ',')
+ tok[strlen(tok)-1] = '\0';
+ } else if (tok[0] == '-'
+ && (tok[1] == '\0' || isspace(tok[1]))
+ ) {
+ tok = (char*)"";
+ }
+ printf(" %s", tok);
+ }
+ bb_putchar('\n');
+ free(line);
+ }
+ fclose(file);
+ }
+#else
+ xprint_and_close_file(file);
+#endif /* CONFIG_FEATURE_2_6_MODULES */
+ return EXIT_SUCCESS;
+}
+
+#endif /* CONFIG_FEATURE_QUERY_MODULE_INTERFACE */
diff --git a/cleopatre/busybox-1.11.1-spc300/modutils/modprobe.c b/cleopatre/busybox-1.11.1-spc300/modutils/modprobe.c
new file mode 100644
index 0000000000..3ac5a81a55
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/modutils/modprobe.c
@@ -0,0 +1,915 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Modprobe written from scratch for BusyBox
+ *
+ * Copyright (c) 2002 by Robert Griebl, griebl@gmx.de
+ * Copyright (c) 2003 by Andrew Dennison, andrew.dennison@motec.com.au
+ * Copyright (c) 2005 by Jim Bauer, jfbauer@nfr.com
+ *
+ * Portions Copyright (c) 2005 by Yann E. MORIN, yann.morin.1998@anciens.enib.fr
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+*/
+
+#include "libbb.h"
+#include <sys/utsname.h>
+#include <fnmatch.h>
+
+#define line_buffer bb_common_bufsiz1
+
+struct mod_opt_t { /* one-way list of options to pass to a module */
+ char * m_opt_val;
+ struct mod_opt_t * m_next;
+};
+
+struct dep_t { /* one-way list of dependency rules */
+ /* a dependency rule */
+ char * m_name; /* the module name*/
+ char * m_path; /* the module file path */
+ struct mod_opt_t * m_options; /* the module options */
+
+ unsigned int m_isalias :1; /* the module is an alias */
+ unsigned int m_isblacklisted:1; /* the module is blacklisted */
+ unsigned int m_reserved :14; /* stuffin' */
+
+ unsigned int m_depcnt :16; /* the number of dependable module(s) */
+ char ** m_deparr; /* the list of dependable module(s) */
+
+ struct dep_t * m_next; /* the next dependency rule */
+};
+
+struct mod_list_t { /* two-way list of modules to process */
+ /* a module description */
+ const char * m_name;
+ char * m_path;
+ struct mod_opt_t * m_options;
+
+ struct mod_list_t * m_prev;
+ struct mod_list_t * m_next;
+};
+
+
+static struct dep_t *depend;
+
+#define MAIN_OPT_STR "acdklnqrst:vVC:"
+#define INSERT_ALL 1 /* a */
+#define DUMP_CONF_EXIT 2 /* c */
+#define D_OPT_IGNORED 4 /* d */
+#define AUTOCLEAN_FLG 8 /* k */
+#define LIST_ALL 16 /* l */
+#define SHOW_ONLY 32 /* n */
+#define QUIET 64 /* q */
+#define REMOVE_OPT 128 /* r */
+#define DO_SYSLOG 256 /* s */
+#define RESTRICT_DIR 512 /* t */
+#define VERBOSE 1024 /* v */
+#define VERSION_ONLY 2048 /* V */
+#define CONFIG_FILE 4096 /* C */
+
+#define autoclean (option_mask32 & AUTOCLEAN_FLG)
+#define show_only (option_mask32 & SHOW_ONLY)
+#define quiet (option_mask32 & QUIET)
+#define remove_opt (option_mask32 & REMOVE_OPT)
+#define do_syslog (option_mask32 & DO_SYSLOG)
+#define verbose (option_mask32 & VERBOSE)
+
+static int parse_tag_value(char *buffer, char **ptag, char **pvalue)
+{
+ char *tag, *value;
+
+ buffer = skip_whitespace(buffer);
+ tag = value = buffer;
+ while (!isspace(*value)) {
+ if (!*value)
+ return 0;
+ value++;
+ }
+ *value++ = '\0';
+ value = skip_whitespace(value);
+ if (!*value)
+ return 0;
+
+ *ptag = tag;
+ *pvalue = value;
+
+ return 1;
+}
+
+/*
+ * This function appends an option to a list
+ */
+static struct mod_opt_t *append_option(struct mod_opt_t *opt_list, char *opt)
+{
+ struct mod_opt_t *ol = opt_list;
+
+ if (ol) {
+ while (ol->m_next) {
+ ol = ol->m_next;
+ }
+ ol->m_next = xzalloc(sizeof(struct mod_opt_t));
+ ol = ol->m_next;
+ } else {
+ ol = opt_list = xzalloc(sizeof(struct mod_opt_t));
+ }
+
+ ol->m_opt_val = xstrdup(opt);
+ /*ol->m_next = NULL; - done by xzalloc*/
+
+ return opt_list;
+}
+
+#if ENABLE_FEATURE_MODPROBE_MULTIPLE_OPTIONS
+/* static char* parse_command_string(char* src, char **dst);
+ * src: pointer to string containing argument
+ * dst: pointer to where to store the parsed argument
+ * return value: the pointer to the first char after the parsed argument,
+ * NULL if there was no argument parsed (only trailing spaces).
+ * Note that memory is allocated with xstrdup when a new argument was
+ * parsed. Don't forget to free it!
+ */
+#define ARG_EMPTY 0x00
+#define ARG_IN_DQUOTES 0x01
+#define ARG_IN_SQUOTES 0x02
+static char *parse_command_string(char *src, char **dst)
+{
+ int opt_status = ARG_EMPTY;
+ char* tmp_str;
+
+ /* Dumb you, I have nothing to do... */
+ if (src == NULL) return src;
+
+ /* Skip leading spaces */
+ while (*src == ' ') {
+ src++;
+ }
+ /* Is the end of string reached? */
+ if (*src == '\0') {
+ return NULL;
+ }
+ /* Reached the start of an argument
+ * By the way, we duplicate a little too much
+ * here but what is too much is freed later. */
+ *dst = tmp_str = xstrdup(src);
+ /* Get to the end of that argument */
+ while (*tmp_str != '\0'
+ && (*tmp_str != ' ' || (opt_status & (ARG_IN_DQUOTES | ARG_IN_SQUOTES)))
+ ) {
+ switch (*tmp_str) {
+ case '\'':
+ if (opt_status & ARG_IN_DQUOTES) {
+ /* Already in double quotes, keep current char as is */
+ } else {
+ /* shift left 1 char, until end of string: get rid of the opening/closing quotes */
+ memmove(tmp_str, tmp_str + 1, strlen(tmp_str));
+ /* mark me: we enter or leave single quotes */
+ opt_status ^= ARG_IN_SQUOTES;
+ /* Back one char, as we need to re-scan the new char there. */
+ tmp_str--;
+ }
+ break;
+ case '"':
+ if (opt_status & ARG_IN_SQUOTES) {
+ /* Already in single quotes, keep current char as is */
+ } else {
+ /* shift left 1 char, until end of string: get rid of the opening/closing quotes */
+ memmove(tmp_str, tmp_str + 1, strlen(tmp_str));
+ /* mark me: we enter or leave double quotes */
+ opt_status ^= ARG_IN_DQUOTES;
+ /* Back one char, as we need to re-scan the new char there. */
+ tmp_str--;
+ }
+ break;
+ case '\\':
+ if (opt_status & ARG_IN_SQUOTES) {
+ /* Between single quotes: keep as is. */
+ } else {
+ switch (*(tmp_str+1)) {
+ case 'a':
+ case 'b':
+ case 't':
+ case 'n':
+ case 'v':
+ case 'f':
+ case 'r':
+ case '0':
+ /* We escaped a special character. For now, keep
+ * both the back-slash and the following char. */
+ tmp_str++;
+ src++;
+ break;
+ default:
+ /* We escaped a space or a single or double quote,
+ * or a back-slash, or a non-escapable char. Remove
+ * the '\' and keep the new current char as is. */
+ memmove(tmp_str, tmp_str + 1, strlen(tmp_str));
+ break;
+ }
+ }
+ break;
+ /* Any other char that is special shall appear here.
+ * Example: $ starts a variable
+ case '$':
+ do_variable_expansion();
+ break;
+ * */
+ default:
+ /* any other char is kept as is. */
+ break;
+ }
+ tmp_str++; /* Go to next char */
+ src++; /* Go to next char to find the end of the argument. */
+ }
+ /* End of string, but still no ending quote */
+ if (opt_status & (ARG_IN_DQUOTES | ARG_IN_SQUOTES)) {
+ bb_error_msg_and_die("unterminated (single or double) quote in options list: %s", src);
+ }
+ *tmp_str++ = '\0';
+ *dst = xrealloc(*dst, (tmp_str - *dst));
+ return src;
+}
+#else
+#define parse_command_string(src, dst) (0)
+#endif /* ENABLE_FEATURE_MODPROBE_MULTIPLE_OPTIONS */
+
+static int is_conf_command(char *buffer, const char *command)
+{
+ int len = strlen(command);
+ return ((strstr(buffer, command) == buffer) &&
+ isspace(buffer[len]));
+}
+
+/*
+ * This function reads aliases and default module options from a configuration file
+ * (/etc/modprobe.conf syntax). It supports includes (only files, no directories).
+ */
+static void include_conf(struct dep_t **first, struct dep_t **current, char *buffer, int buflen, int fd)
+{
+ int continuation_line = 0;
+
+ // alias parsing is not 100% correct (no correct handling of continuation lines within an alias)!
+
+ while (reads(fd, buffer, buflen)) {
+ int l;
+
+ *strchrnul(buffer, '#') = '\0';
+
+ l = strlen(buffer);
+
+ while (l && isspace(buffer[l-1])) {
+ buffer[l-1] = '\0';
+ l--;
+ }
+
+ if (l == 0) {
+ continuation_line = 0;
+ continue;
+ }
+
+ if (continuation_line)
+ continue;
+
+ if (is_conf_command(buffer, "alias")) {
+ char *alias, *mod;
+
+ if (parse_tag_value(buffer + 6, &alias, &mod)) {
+ /* handle alias as a module dependent on the aliased module */
+ if (!*current) {
+ (*first) = (*current) = xzalloc(sizeof(struct dep_t));
+ } else {
+ (*current)->m_next = xzalloc(sizeof(struct dep_t));
+ (*current) = (*current)->m_next;
+ }
+ (*current)->m_name = xstrdup(alias);
+ (*current)->m_isalias = 1;
+
+ if ((strcmp(mod, "off") == 0) || (strcmp(mod, "null") == 0)) {
+ /*(*current)->m_depcnt = 0; - done by xzalloc */
+ /*(*current)->m_deparr = 0;*/
+ } else {
+ (*current)->m_depcnt = 1;
+ (*current)->m_deparr = xmalloc(sizeof(char *));
+ (*current)->m_deparr[0] = xstrdup(mod);
+ }
+ /*(*current)->m_next = NULL; - done by xzalloc */
+ }
+ } else if (is_conf_command(buffer, "options")) {
+ char *mod, *opt;
+
+ /* split the line in the module/alias name, and options */
+ if (parse_tag_value(buffer + 8, &mod, &opt)) {
+ struct dep_t *dt;
+
+ /* find the corresponding module */
+ for (dt = *first; dt; dt = dt->m_next) {
+ if (strcmp(dt->m_name, mod) == 0)
+ break;
+ }
+ if (dt) {
+ if (ENABLE_FEATURE_MODPROBE_MULTIPLE_OPTIONS) {
+ char* new_opt = NULL;
+ while ((opt = parse_command_string(opt, &new_opt))) {
+ dt->m_options = append_option(dt->m_options, new_opt);
+ }
+ } else {
+ dt->m_options = append_option(dt->m_options, opt);
+ }
+ }
+ }
+ } else if (is_conf_command(buffer, "include")) {
+ int fdi;
+ char *filename;
+
+ filename = skip_whitespace(buffer + 8);
+ fdi = open(filename, O_RDONLY);
+ if (fdi >= 0) {
+ include_conf(first, current, buffer, buflen, fdi);
+ close(fdi);
+ }
+ } else if (ENABLE_FEATURE_MODPROBE_BLACKLIST &&
+ (is_conf_command(buffer, "blacklist"))) {
+ char *mod;
+ struct dep_t *dt;
+
+ mod = skip_whitespace(buffer + 10);
+ for (dt = *first; dt; dt = dt->m_next) {
+ if (strcmp(dt->m_name, mod) == 0)
+ break;
+ }
+ if (dt)
+ dt->m_isblacklisted = 1;
+ }
+ } /* while (reads(...)) */
+}
+
+/*
+ * This function builds a list of dependency rules from /lib/modules/`uname -r`/modules.dep.
+ * It then fills every modules and aliases with their default options, found by parsing
+ * modprobe.conf (or modules.conf, or conf.modules).
+ */
+static struct dep_t *build_dep(void)
+{
+ int fd;
+ struct utsname un;
+ struct dep_t *first = NULL;
+ struct dep_t *current = NULL;
+ char *filename;
+ int continuation_line = 0;
+ int k_version;
+
+ if (uname(&un))
+ bb_error_msg_and_die("can't determine kernel version");
+
+ k_version = 0;
+ if (un.release[0] == '2') {
+ k_version = un.release[2] - '0';
+ }
+
+ filename = xasprintf(CONFIG_DEFAULT_MODULES_DIR"/%s/"CONFIG_DEFAULT_DEPMOD_FILE, un.release);
+ fd = open(filename, O_RDONLY);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(filename);
+ if (fd < 0) {
+ /* Ok, that didn't work. Fall back to looking in /lib/modules */
+ fd = open(CONFIG_DEFAULT_MODULES_DIR"/"CONFIG_DEFAULT_DEPMOD_FILE, O_RDONLY);
+ if (fd < 0) {
+ bb_error_msg_and_die("cannot parse " CONFIG_DEFAULT_DEPMOD_FILE);
+ }
+ }
+
+ while (reads(fd, line_buffer, sizeof(line_buffer))) {
+ int l = strlen(line_buffer);
+ char *p = 0;
+
+ while (l > 0 && isspace(line_buffer[l-1])) {
+ line_buffer[l-1] = '\0';
+ l--;
+ }
+
+ if (l == 0) {
+ continuation_line = 0;
+ continue;
+ }
+
+ /* Is this a new module dep description? */
+ if (!continuation_line) {
+ /* find the dep beginning */
+ char *col = strchr(line_buffer, ':');
+ char *dot = col;
+
+ if (col) {
+ /* This line is a dep description */
+ const char *mods;
+ char *modpath;
+ char *mod;
+
+ /* Find the beginning of the module file name */
+ *col = '\0';
+ mods = bb_basename(line_buffer);
+
+ /* find the path of the module */
+ modpath = strchr(line_buffer, '/'); /* ... and this is the path */
+ if (!modpath)
+ modpath = line_buffer; /* module with no path */
+ /* find the end of the module name in the file name */
+ if (ENABLE_FEATURE_2_6_MODULES &&
+ (k_version > 4) && (col[-3] == '.') &&
+ (col[-2] == 'k') && (col[-1] == 'o'))
+ dot = col - 3;
+ else if ((col[-2] == '.') && (col[-1] == 'o'))
+ dot = col - 2;
+
+ mod = xstrndup(mods, dot - mods);
+
+ /* enqueue new module */
+ if (!current) {
+ first = current = xzalloc(sizeof(struct dep_t));
+ } else {
+ current->m_next = xzalloc(sizeof(struct dep_t));
+ current = current->m_next;
+ }
+ current->m_name = mod;
+ current->m_path = xstrdup(modpath);
+ /*current->m_options = NULL; - xzalloc did it*/
+ /*current->m_isalias = 0;*/
+ /*current->m_depcnt = 0;*/
+ /*current->m_deparr = 0;*/
+ /*current->m_next = 0;*/
+
+ p = col + 1;
+ } else
+ /* this line is not a dep description */
+ p = NULL;
+ } else
+ /* It's a dep description continuation */
+ p = line_buffer;
+
+ /* p points to the first dependable module; if NULL, no dependable module */
+ if (p && (p = skip_whitespace(p))[0] != '\0') {
+ char *end = &line_buffer[l-1];
+ const char *deps;
+ char *dep;
+ char *next;
+ int ext = 0;
+
+ while (isblank(*end) || (*end == '\\'))
+ end--;
+
+ do {
+ /* search the end of the dependency */
+ next = strchr(p, ' ');
+ if (next) {
+ *next = '\0';
+ next--;
+ } else
+ next = end;
+
+ /* find the beginning of the module file name */
+ deps = bb_basename(p);
+ if (deps == p)
+ deps = skip_whitespace(deps);
+
+ /* find the end of the module name in the file name */
+ if (ENABLE_FEATURE_2_6_MODULES
+ && (k_version > 4) && (next[-2] == '.')
+ && (next[-1] == 'k') && (next[0] == 'o'))
+ ext = 3;
+ else if ((next[-1] == '.') && (next[0] == 'o'))
+ ext = 2;
+
+ /* Cope with blank lines */
+ if ((next-deps-ext+1) <= 0)
+ continue;
+ dep = xstrndup(deps, next - deps - ext + 1);
+
+ /* Add the new dependable module name */
+ current->m_depcnt++;
+ current->m_deparr = xrealloc(current->m_deparr,
+ sizeof(char *) * current->m_depcnt);
+ current->m_deparr[current->m_depcnt - 1] = dep;
+
+ p = next + 2;
+ } while (next < end);
+ }
+
+ /* is there other dependable module(s) ? */
+ continuation_line = (line_buffer[l-1] == '\\');
+ } /* while (reads(...)) */
+ close(fd);
+
+ /*
+ * First parse system-specific options and aliases
+ * as they take precedence over the kernel ones.
+ * >=2.6: we only care about modprobe.conf
+ * <=2.4: we care about modules.conf and conf.modules
+ */
+ if (ENABLE_FEATURE_2_6_MODULES
+ && (fd = open("/etc/modprobe.conf", O_RDONLY)) < 0)
+ if (ENABLE_FEATURE_2_4_MODULES
+ && (fd = open("/etc/modules.conf", O_RDONLY)) < 0)
+ if (ENABLE_FEATURE_2_4_MODULES)
+ fd = open("/etc/conf.modules", O_RDONLY);
+
+ if (fd >= 0) {
+ include_conf(&first, &current, line_buffer, sizeof(line_buffer), fd);
+ close(fd);
+ }
+
+ /* Only 2.6 has a modules.alias file */
+ if (ENABLE_FEATURE_2_6_MODULES) {
+ /* Parse kernel-declared module aliases */
+ filename = xasprintf(CONFIG_DEFAULT_MODULES_DIR"/%s/modules.alias", un.release);
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ /* Ok, that didn't work. Fall back to looking in /lib/modules */
+ fd = open(CONFIG_DEFAULT_MODULES_DIR"/modules.alias", O_RDONLY);
+ }
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(filename);
+
+ if (fd >= 0) {
+ include_conf(&first, &current, line_buffer, sizeof(line_buffer), fd);
+ close(fd);
+ }
+
+ /* Parse kernel-declared symbol aliases */
+ filename = xasprintf(CONFIG_DEFAULT_MODULES_DIR"/%s/modules.symbols", un.release);
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ /* Ok, that didn't work. Fall back to looking in /lib/modules */
+ fd = open(CONFIG_DEFAULT_MODULES_DIR"/modules.symbols", O_RDONLY);
+ }
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(filename);
+
+ if (fd >= 0) {
+ include_conf(&first, &current, line_buffer, sizeof(line_buffer), fd);
+ close(fd);
+ }
+ }
+
+ return first;
+}
+
+/* return 1 = loaded, 0 = not loaded, -1 = can't tell */
+static int already_loaded(const char *name)
+{
+ int fd, ret = 0;
+
+ fd = open("/proc/modules", O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ while (reads(fd, line_buffer, sizeof(line_buffer))) {
+ char *p;
+
+ p = strchr(line_buffer, ' ');
+ if (p) {
+ const char *n;
+
+ // Truncate buffer at first space and check for matches, with
+ // the idiosyncrasy that _ and - are interchangeable because the
+ // 2.6 kernel does weird things.
+
+ *p = '\0';
+ for (p = line_buffer, n = name; ; p++, n++) {
+ if (*p != *n) {
+ if ((*p == '_' || *p == '-') && (*n == '_' || *n == '-'))
+ continue;
+ break;
+ }
+ // If we made it to the end, that's a match.
+ if (!*p) {
+ ret = 1;
+ goto done;
+ }
+ }
+ }
+ }
+ done:
+ close(fd);
+ return ret;
+}
+
+static int mod_process(const struct mod_list_t *list, int do_insert)
+{
+ int rc = 0;
+ char **argv = NULL;
+ struct mod_opt_t *opts;
+ int argc_malloc; /* never used when CONFIG_FEATURE_CLEAN_UP not defined */
+ int argc;
+
+ while (list) {
+ argc = 0;
+ if (ENABLE_FEATURE_CLEAN_UP)
+ argc_malloc = 0;
+ /* If CONFIG_FEATURE_CLEAN_UP is not defined, then we leak memory
+ * each time we allocate memory for argv.
+ * But it is (quite) small amounts of memory that leak each
+ * time a module is loaded, and it is reclaimed when modprobe
+ * exits anyway (even when standalone shell?).
+ * This could become a problem when loading a module with LOTS of
+ * dependencies, with LOTS of options for each dependencies, with
+ * very little memory on the target... But in that case, the module
+ * would not load because there is no more memory, so there's no
+ * problem. */
+ /* enough for minimal insmod (5 args + NULL) or rmmod (3 args + NULL) */
+ argv = xmalloc(6 * sizeof(char*));
+ if (do_insert) {
+ if (already_loaded(list->m_name) != 1) {
+ argv[argc++] = (char*)"insmod";
+ if (ENABLE_FEATURE_2_4_MODULES) {
+ if (do_syslog)
+ argv[argc++] = (char*)"-s";
+ if (autoclean)
+ argv[argc++] = (char*)"-k";
+ if (quiet)
+ argv[argc++] = (char*)"-q";
+ else if (verbose) /* verbose and quiet are mutually exclusive */
+ argv[argc++] = (char*)"-v";
+ }
+ argv[argc++] = list->m_path;
+ if (ENABLE_FEATURE_CLEAN_UP)
+ argc_malloc = argc;
+ opts = list->m_options;
+ while (opts) {
+ /* Add one more option */
+ argc++;
+ argv = xrealloc(argv, (argc + 1) * sizeof(char*));
+ argv[argc-1] = opts->m_opt_val;
+ opts = opts->m_next;
+ }
+ }
+ } else {
+ /* modutils uses short name for removal */
+ if (already_loaded(list->m_name) != 0) {
+ argv[argc++] = (char*)"rmmod";
+ if (do_syslog)
+ argv[argc++] = (char*)"-s";
+ argv[argc++] = (char*)list->m_name;
+ if (ENABLE_FEATURE_CLEAN_UP)
+ argc_malloc = argc;
+ }
+ }
+ argv[argc] = NULL;
+
+ if (argc) {
+ if (verbose) {
+ printf("%s module %s\n", do_insert?"Loading":"Unloading", list->m_name);
+ }
+ if (!show_only) {
+ int rc2 = wait4pid(spawn(argv));
+
+ if (do_insert) {
+ rc = rc2; /* only last module matters */
+ } else if (!rc2) {
+ rc = 0; /* success if remove any mod */
+ }
+ }
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ /* the last value in the array has index == argc, but
+ * it is the terminating NULL, so we must not free it. */
+ while (argc_malloc < argc) {
+ free(argv[argc_malloc++]);
+ }
+ }
+ }
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ free(argv);
+ argv = NULL;
+ }
+ list = do_insert ? list->m_prev : list->m_next;
+ }
+ return (show_only) ? 0 : rc;
+}
+
+/*
+ * Check the matching between a pattern and a module name.
+ * We need this as *_* is equivalent to *-*, even in pattern matching.
+ */
+static int check_pattern(const char* pat_src, const char* mod_src)
+{
+ int ret;
+
+ if (ENABLE_FEATURE_MODPROBE_FANCY_ALIAS) {
+ char* pat;
+ char* mod;
+ char* p;
+
+ pat = xstrdup(pat_src);
+ mod = xstrdup(mod_src);
+
+ for (p = pat; (p = strchr(p, '-')); *p++ = '_');
+ for (p = mod; (p = strchr(p, '-')); *p++ = '_');
+
+ ret = fnmatch(pat, mod, 0);
+
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ free(pat);
+ free(mod);
+ }
+
+ return ret;
+ }
+ return fnmatch(pat_src, mod_src, 0);
+}
+
+/*
+ * Builds the dependency list (aka stack) of a module.
+ * head: the highest module in the stack (last to insmod, first to rmmod)
+ * tail: the lowest module in the stack (first to insmod, last to rmmod)
+ */
+static void check_dep(char *mod, struct mod_list_t **head, struct mod_list_t **tail)
+{
+ struct mod_list_t *find;
+ struct dep_t *dt;
+ struct mod_opt_t *opt = NULL;
+ char *path = NULL;
+
+ /* Search for the given module name amongst all dependency rules.
+ * The module name in a dependency rule can be a shell pattern,
+ * so try to match the given module name against such a pattern.
+ * Of course if the name in the dependency rule is a plain string,
+ * then we consider it a pattern, and matching will still work. */
+ for (dt = depend; dt; dt = dt->m_next) {
+ if (check_pattern(dt->m_name, mod) == 0) {
+ break;
+ }
+ }
+
+ if (!dt) {
+ bb_error_msg("module %s not found", mod);
+ return;
+ }
+
+ // resolve alias names
+ while (dt->m_isalias) {
+ if (dt->m_depcnt == 1) {
+ struct dep_t *adt;
+
+ for (adt = depend; adt; adt = adt->m_next) {
+ if (check_pattern(adt->m_name, dt->m_deparr[0]) == 0 &&
+ !(ENABLE_FEATURE_MODPROBE_BLACKLIST &&
+ adt->m_isblacklisted))
+ break;
+ }
+ if (adt) {
+ /* This is the module we are aliased to */
+ struct mod_opt_t *opts = dt->m_options;
+ /* Option of the alias are appended to the options of the module */
+ while (opts) {
+ adt->m_options = append_option(adt->m_options, opts->m_opt_val);
+ opts = opts->m_next;
+ }
+ dt = adt;
+ } else {
+ bb_error_msg("module %s not found", mod);
+ return;
+ }
+ } else {
+ bb_error_msg("bad alias %s", dt->m_name);
+ return;
+ }
+ }
+
+ mod = dt->m_name;
+ path = dt->m_path;
+ opt = dt->m_options;
+
+ // search for duplicates
+ for (find = *head; find; find = find->m_next) {
+ if (strcmp(mod, find->m_name) == 0) {
+ // found -> dequeue it
+
+ if (find->m_prev)
+ find->m_prev->m_next = find->m_next;
+ else
+ *head = find->m_next;
+
+ if (find->m_next)
+ find->m_next->m_prev = find->m_prev;
+ else
+ *tail = find->m_prev;
+
+ break; // there can be only one duplicate
+ }
+ }
+
+ if (!find) { // did not find a duplicate
+ find = xzalloc(sizeof(struct mod_list_t));
+ find->m_name = mod;
+ find->m_path = path;
+ find->m_options = opt;
+ }
+
+ // enqueue at tail
+ if (*tail)
+ (*tail)->m_next = find;
+ find->m_prev = *tail;
+ find->m_next = NULL; /* possibly NOT done by xzalloc! */
+
+ if (!*head)
+ *head = find;
+ *tail = find;
+
+ if (dt) {
+ int i;
+
+ /* Add all dependable module for that new module */
+ for (i = 0; i < dt->m_depcnt; i++)
+ check_dep(dt->m_deparr[i], head, tail);
+ }
+}
+
+static int mod_insert(char *mod, int argc, char **argv)
+{
+ struct mod_list_t *tail = NULL;
+ struct mod_list_t *head = NULL;
+ int rc;
+
+ // get dep list for module mod
+ check_dep(mod, &head, &tail);
+
+ rc = 1;
+ if (head && tail) {
+ if (argc) {
+ int i;
+ // append module args
+ for (i = 0; i < argc; i++)
+ head->m_options = append_option(head->m_options, argv[i]);
+ }
+
+ // process tail ---> head
+ rc = mod_process(tail, 1);
+ if (rc) {
+ /*
+ * In case of using udev, multiple instances of modprobe can be
+ * spawned to load the same module (think of two same usb devices,
+ * for example; or cold-plugging at boot time). Thus we shouldn't
+ * fail if the module was loaded, and not by us.
+ */
+ if (already_loaded(mod))
+ rc = 0;
+ }
+ }
+ return rc;
+}
+
+static int mod_remove(char *mod)
+{
+ int rc;
+ static const struct mod_list_t rm_a_dummy = { "-a", NULL, NULL, NULL, NULL };
+
+ struct mod_list_t *head = NULL;
+ struct mod_list_t *tail = NULL;
+
+ if (mod)
+ check_dep(mod, &head, &tail);
+ else // autoclean
+ head = tail = (struct mod_list_t*) &rm_a_dummy;
+
+ rc = 1;
+ if (head && tail)
+ rc = mod_process(head, 0); // process head ---> tail
+ return rc;
+}
+
+int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int modprobe_main(int argc, char **argv)
+{
+ int rc = EXIT_SUCCESS;
+ char *unused;
+
+ opt_complementary = "q-v:v-q";
+ getopt32(argv, MAIN_OPT_STR, &unused, &unused);
+
+ if (option_mask32 & (DUMP_CONF_EXIT | LIST_ALL))
+ return EXIT_SUCCESS;
+ if (option_mask32 & (RESTRICT_DIR | CONFIG_FILE))
+ bb_error_msg_and_die("-t and -C not supported");
+
+ depend = build_dep();
+
+ if (!depend)
+ bb_error_msg_and_die("cannot parse "CONFIG_DEFAULT_DEPMOD_FILE);
+
+ if (remove_opt) {
+ do {
+ /* argv[optind] can be NULL here */
+ if (mod_remove(argv[optind])) {
+ bb_error_msg("failed to %s module %s", "remove",
+ argv[optind]);
+ rc = EXIT_FAILURE;
+ }
+ } while (++optind < argc);
+ } else {
+ if (optind >= argc)
+ bb_error_msg_and_die("no module or pattern provided");
+
+ if (mod_insert(argv[optind], argc - optind - 1, argv + optind + 1))
+ bb_error_msg_and_die("failed to %s module %s", "load", argv[optind]);
+ }
+
+ /* Here would be a good place to free up memory allocated during the dependencies build. */
+
+ return rc;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/modutils/rmmod.c b/cleopatre/busybox-1.11.1-spc300/modutils/rmmod.c
new file mode 100644
index 0000000000..a96a27457a
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/modutils/rmmod.c
@@ -0,0 +1,100 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini rmmod implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+#ifdef __UCLIBC__
+extern int delete_module(const char *module, unsigned int flags);
+#else
+# include <sys/syscall.h>
+# define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags)
+#endif
+
+#if ENABLE_FEATURE_2_6_MODULES
+static inline void filename2modname(char *modname, const char *afterslash)
+{
+ unsigned int i;
+ int kr_chk = 1;
+
+ if (ENABLE_FEATURE_2_4_MODULES
+ && get_linux_version_code() <= KERNEL_VERSION(2,6,0))
+ kr_chk = 0;
+
+ /* Convert to underscores, stop at first . */
+ for (i = 0; afterslash[i] && afterslash[i] != '.'; i++) {
+ if (kr_chk && (afterslash[i] == '-'))
+ modname[i] = '_';
+ else
+ modname[i] = afterslash[i];
+ }
+ modname[i] = '\0';
+}
+#else
+void filename2modname(char *modname, const char *afterslash);
+#endif
+
+// There really should be a header file for this...
+
+int query_module(const char *name, int which, void *buf,
+ size_t bufsize, size_t *ret);
+
+int rmmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int rmmod_main(int argc, char **argv)
+{
+ int n, ret = EXIT_SUCCESS;
+ unsigned int flags = O_NONBLOCK|O_EXCL;
+
+#define misc_buf bb_common_bufsiz1
+
+ /* Parse command line. */
+ n = getopt32(argv, "wfa");
+ if (n & 1) // --wait
+ flags &= ~O_NONBLOCK;
+ if (n & 2) // --force
+ flags |= O_TRUNC;
+ if (n & 4) {
+ /* Unload _all_ unused modules via NULL delete_module() call */
+ /* until the number of modules does not change */
+ size_t nmod = 0; /* number of modules */
+ size_t pnmod = -1; /* previous number of modules */
+
+ while (nmod != pnmod) {
+ if (delete_module(NULL, flags) != 0) {
+ if (errno == EFAULT)
+ return ret;
+ bb_perror_msg_and_die("rmmod");
+ }
+ pnmod = nmod;
+ // the 1 here is QM_MODULES.
+ if (ENABLE_FEATURE_QUERY_MODULE_INTERFACE && query_module(NULL,
+ 1, misc_buf, sizeof(misc_buf),
+ &nmod))
+ {
+ bb_perror_msg_and_die("QM_MODULES");
+ }
+ }
+ return EXIT_SUCCESS;
+ }
+
+ if (optind == argc)
+ bb_show_usage();
+
+ for (n = optind; n < argc; n++) {
+ if (ENABLE_FEATURE_2_6_MODULES) {
+ filename2modname(misc_buf, bb_basename(argv[n]));
+ }
+
+ if (delete_module(ENABLE_FEATURE_2_6_MODULES ? misc_buf : argv[n], flags)) {
+ bb_simple_perror_msg(argv[n]);
+ ret = EXIT_FAILURE;
+ }
+ }
+
+ return ret;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/networking/Config.in b/cleopatre/busybox-1.11.1-spc300/networking/Config.in
new file mode 100644
index 0000000000..fb6988b417
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/networking/Config.in
@@ -0,0 +1,911 @@
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Networking Utilities"
+
+config FEATURE_IPV6
+ bool "Enable IPv6 support"
+ default n
+ help
+ Enable IPv6 support in busybox.
+ This adds IPv6 support in the networking applets.
+
+config FEATURE_PREFER_IPV4_ADDRESS
+ bool "Preferentially use IPv4 addresses from DNS queries"
+ default y
+ depends on FEATURE_IPV6
+ help
+ Use IPv4 address of network host if it has one.
+
+ If this option is off, the first returned address will be used.
+ This may cause problems when your DNS server is IPv6-capable and
+ is returning IPv6 host addresses too. If IPv6 address
+ precedes IPv4 one in DNS reply, busybox network applets
+ (e.g. wget) will use IPv6 address. On an IPv6-incapable host
+ or network applets will fail to connect to the host
+ using IPv6 address.
+
+config VERBOSE_RESOLUTION_ERRORS
+ bool "Verbose resolution errors"
+ default n
+ help
+ Enable if you are not satisfied with simplistic
+ "can't resolve 'hostname.com'" and want to know more.
+ This may increase size of your executable a bit.
+
+config ARP
+ bool "arp"
+ default n
+ help
+ Manipulate the system ARP cache.
+
+config ARPING
+ bool "arping"
+ default n
+ help
+ Ping hosts by ARP packets.
+
+config BRCTL
+ bool "brctl"
+ default n
+ help
+ Manage ethernet bridges.
+ Supports addbr/delbr and addif/delif.
+
+config FEATURE_BRCTL_FANCY
+ bool "Fancy options"
+ default n
+ depends on BRCTL
+ help
+ Add support for extended option like:
+ setageing, setfd, sethello, setmaxage,
+ setpathcost, setportprio, setbridgeprio,
+ stp
+ This adds about 600 bytes.
+
+config FEATURE_BRCTL_SHOW
+ bool "Support show, showmac and showstp"
+ default n
+ depends on BRCTL && FEATURE_BRCTL_FANCY
+ help
+ Add support for option which prints the current config:
+ showmacs, showstp, show
+
+config DNSD
+ bool "dnsd"
+ default n
+ help
+ Small and static DNS server daemon.
+
+config ETHER_WAKE
+ bool "ether-wake"
+ default n
+ help
+ Send a magic packet to wake up sleeping machines.
+
+config FAKEIDENTD
+ bool "fakeidentd"
+ default n
+ select FEATURE_SYSLOG
+ help
+ fakeidentd listens on the ident port and returns a predefined
+ fake value on any query.
+
+config FTPGET
+ bool "ftpget"
+ default n
+ help
+ Retrieve a remote file via FTP.
+
+config FTPPUT
+ bool "ftpput"
+ default n
+ help
+ Store a remote file via FTP.
+
+config FEATURE_FTPGETPUT_LONG_OPTIONS
+ bool "Enable long options in ftpget/ftpput"
+ default n
+ depends on GETOPT_LONG && (FTPGET || FTPPUT)
+ help
+ Support long options for the ftpget/ftpput applet.
+
+config HOSTNAME
+ bool "hostname"
+ default n
+ help
+ Show or set the system's host name.
+
+config HTTPD
+ bool "httpd"
+ default n
+ help
+ Serve web pages via an HTTP server.
+
+config FEATURE_HTTPD_RANGES
+ bool "Support 'Ranges:' header"
+ default n
+ depends on HTTPD
+ help
+ Makes httpd emit "Accept-Ranges: bytes" header and understand
+ "Range: bytes=NNN-[MMM]" header. Allows for resuming interrupted
+ downloads, seeking in multimedia players etc.
+
+config FEATURE_HTTPD_USE_SENDFILE
+ bool "Use sendfile system call"
+ default n
+ depends on HTTPD
+ help
+ When enabled, httpd will use the kernel sendfile() function
+ instead of read/write loop.
+
+config FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
+ bool "Support reloading of global config file on HUP signal"
+ default n
+ depends on HTTPD
+ help
+ This option enables processing of SIGHUP to reload cached
+ configuration settings.
+
+config FEATURE_HTTPD_SETUID
+ bool "Enable -u <user> option"
+ default n
+ depends on HTTPD
+ help
+ This option allows the server to run as a specific user
+ rather than defaulting to the user that starts the server.
+ Use of this option requires special privileges to change to a
+ different user.
+
+config FEATURE_HTTPD_BASIC_AUTH
+ bool "Enable Basic http Authentication"
+ default y
+ depends on HTTPD
+ help
+ Utilizes password settings from /etc/httpd.conf for basic
+ authentication on a per url basis.
+
+config FEATURE_HTTPD_AUTH_MD5
+ bool "Support MD5 crypted passwords for http Authentication"
+ default n
+ depends on FEATURE_HTTPD_BASIC_AUTH
+ help
+ Enables basic per URL authentication from /etc/httpd.conf
+ using md5 passwords.
+
+config FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
+ bool "Support loading additional MIME types at run-time"
+ default n
+ depends on HTTPD
+ help
+ This option enables support for additional MIME types at
+ run-time to be specified in the configuration file.
+
+config FEATURE_HTTPD_CGI
+ bool "Support Common Gateway Interface (CGI)"
+ default y
+ depends on HTTPD
+ help
+ This option allows scripts and executables to be invoked
+ when specific URLs are requested.
+
+config FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
+ bool "Support for running scripts through an interpreter"
+ default n
+ depends on FEATURE_HTTPD_CGI
+ help
+ This option enables support for running scripts through an
+ interpreter. Turn this on if you want PHP scripts to work
+ properly. You need to supply an additional line in your httpd
+ config file:
+ *.php:/path/to/your/php
+
+config FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV
+ bool "Set REMOTE_PORT environment variable for CGI"
+ default n
+ depends on FEATURE_HTTPD_CGI
+ help
+ Use of this option can assist scripts in generating
+ references that contain a unique port number.
+
+config FEATURE_HTTPD_ENCODE_URL_STR
+ bool "Enable -e option (useful for CGIs written as shell scripts)"
+ default y
+ depends on HTTPD
+ help
+ This option allows html encoding of arbitrary strings for display
+ by the browser. Output goes to stdout.
+ For example, httpd -e "<Hello World>" produces
+ "&#60Hello&#32World&#62".
+
+config FEATURE_HTTPD_ERROR_PAGES
+ bool "Support for custom error pages"
+ default n
+ depends on HTTPD
+ help
+ This option allows you to define custom error pages in
+ the configuration file instead of the default HTTP status
+ error pages. For instance, if you add the line:
+ E404:/path/e404.html
+ in the config file, the server will respond the specified
+ '/path/e404.html' file instead of the terse '404 NOT FOUND'
+ message.
+
+config FEATURE_HTTPD_PROXY
+ bool "Support for reverse proxy"
+ default n
+ depends on HTTPD
+ help
+ This option allows you to define URLs that will be forwarded
+ to another HTTP server. To setup add the following line to the
+ configuration file
+ P:/url/:http://hostname[:port]/new/path/
+ Then a request to /url/myfile will be forwarded to
+ http://hostname[:port]/new/path/myfile.
+
+config IFCONFIG
+ bool "ifconfig"
+ default n
+ help
+ Ifconfig is used to configure the kernel-resident network interfaces.
+
+config FEATURE_IFCONFIG_STATUS
+ bool "Enable status reporting output (+7k)"
+ default y
+ depends on IFCONFIG
+ help
+ If ifconfig is called with no arguments it will display the status
+ of the currently active interfaces.
+
+config FEATURE_IFCONFIG_SLIP
+ bool "Enable slip-specific options \"keepalive\" and \"outfill\""
+ default n
+ depends on IFCONFIG
+ help
+ Allow "keepalive" and "outfill" support for SLIP. If you're not
+ planning on using serial lines, leave this unchecked.
+
+config FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
+ bool "Enable options \"mem_start\", \"io_addr\", and \"irq\""
+ default n
+ depends on IFCONFIG
+ help
+ Allow the start address for shared memory, start address for I/O,
+ and/or the interrupt line used by the specified device.
+
+config FEATURE_IFCONFIG_HW
+ bool "Enable option \"hw\" (ether only)"
+ default y
+ depends on IFCONFIG
+ help
+ Set the hardware address of this interface, if the device driver
+ supports this operation. Currently, we only support the 'ether'
+ class.
+
+config FEATURE_IFCONFIG_BROADCAST_PLUS
+ bool "Set the broadcast automatically"
+ default n
+ depends on IFCONFIG
+ help
+ Setting this will make ifconfig attempt to find the broadcast
+ automatically if the value '+' is used.
+
+config IFENSLAVE
+ bool "ifenslave"
+ default n
+ help
+ Userspace application to bind several interfaces
+ to a logical interface (use with kernel bonding driver).
+
+config IFUPDOWN
+ bool "ifupdown"
+ default n
+ help
+ Activate or deactivate the specified interfaces. This applet makes
+ use of either "ifconfig" and "route" or the "ip" command to actually
+ configure network interfaces. Therefore, you will probably also want
+ to enable either IFCONFIG and ROUTE, or enable
+ FEATURE_IFUPDOWN_IP and the various IP options. Of
+ course you could use non-busybox versions of these programs, so
+ against my better judgement (since this will surely result in plenty
+ of support questions on the mailing list), I do not force you to
+ enable these additional options. It is up to you to supply either
+ "ifconfig", "route" and "run-parts" or the "ip" command, either
+ via busybox or via standalone utilities.
+
+config IFUPDOWN_IFSTATE_PATH
+ string "Absolute path to ifstate file"
+ default "/var/run/ifstate"
+ depends on IFUPDOWN
+ help
+ ifupdown keeps state information in a file called ifstate.
+ Typically it is located in /var/run/ifstate, however
+ some distributions tend to put it in other places
+ (debian, for example, uses /etc/network/run/ifstate).
+ This config option defines location of ifstate.
+
+config FEATURE_IFUPDOWN_IP
+ bool "Use ip applet"
+ default n
+ depends on IFUPDOWN
+ help
+ Use the iproute "ip" command to implement "ifup" and "ifdown", rather
+ than the default of using the older 'ifconfig' and 'route' utilities.
+
+config FEATURE_IFUPDOWN_IP_BUILTIN
+ bool "Use busybox ip applet"
+ default y
+ depends on FEATURE_IFUPDOWN_IP
+ select IP
+ select FEATURE_IP_ADDRESS
+ select FEATURE_IP_LINK
+ select FEATURE_IP_ROUTE
+ help
+ Use the busybox iproute "ip" applet to implement "ifupdown".
+
+ If left disabled, you must install the full-blown iproute2
+ utility or the "ifup" and "ifdown" applets will not work.
+
+config FEATURE_IFUPDOWN_IFCONFIG_BUILTIN
+ bool "Use busybox ifconfig and route applets"
+ default y
+ depends on IFUPDOWN && !FEATURE_IFUPDOWN_IP
+ select IFCONFIG
+ select ROUTE
+ help
+ Use the busybox iproute "ifconfig" and "route" applets to
+ implement the "ifup" and "ifdown" utilities.
+
+ If left disabled, you must install the full-blown ifconfig
+ and route utilities, or the "ifup" and "ifdown" applets will not
+ work.
+
+config FEATURE_IFUPDOWN_IPV4
+ bool "Support for IPv4"
+ default y
+ depends on IFUPDOWN
+ help
+ If you want ifup/ifdown to talk IPv4, leave this on.
+
+config FEATURE_IFUPDOWN_IPV6
+ bool "Support for IPv6"
+ default n
+ depends on IFUPDOWN && FEATURE_IPV6
+ help
+ If you need support for IPv6, turn this option on.
+
+### UNUSED
+###config FEATURE_IFUPDOWN_IPX
+### bool "Support for IPX"
+### default n
+### depends on IFUPDOWN
+### help
+### If this option is selected you can use busybox to work with IPX
+### networks.
+
+config FEATURE_IFUPDOWN_MAPPING
+ bool "Enable mapping support"
+ default n
+ depends on IFUPDOWN
+ help
+ This enables support for the "mapping" stanza, unless you have
+ a weird network setup you don't need it.
+
+config FEATURE_IFUPDOWN_EXTERNAL_DHCP
+ bool "Support for external dhcp clients"
+ default n
+ depends on IFUPDOWN
+ help
+ This enables support for the external dhcp clients. Clients are
+ tried in the following order: dhcpcd, dhclient, pump and udhcpc.
+ Otherwise, if udhcpc applet is enabled, it is used.
+ Otherwise, ifup/ifdown will have no support for DHCP.
+
+config INETD
+ bool "inetd"
+ default n
+ select FEATURE_SYSLOG
+ help
+ Internet superserver daemon
+
+config FEATURE_INETD_SUPPORT_BUILTIN_ECHO
+ bool "Support echo service"
+ default y
+ depends on INETD
+ help
+ Echo received data internal inetd service
+
+config FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
+ bool "Support discard service"
+ default y
+ depends on INETD
+ help
+ Internet /dev/null internal inetd service
+
+config FEATURE_INETD_SUPPORT_BUILTIN_TIME
+ bool "Support time service"
+ default y
+ depends on INETD
+ help
+ Return 32 bit time since 1900 internal inetd service
+
+config FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
+ bool "Support daytime service"
+ default y
+ depends on INETD
+ help
+ Return human-readable time internal inetd service
+
+config FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
+ bool "Support chargen service"
+ default y
+ depends on INETD
+ help
+ Familiar character generator internal inetd service
+
+config FEATURE_INETD_RPC
+ bool "Support RPC services"
+ default n
+ depends on INETD
+ select FEATURE_HAVE_RPC
+ help
+ Support Sun-RPC based services
+
+config IP
+ bool "ip"
+ default n
+ help
+ The "ip" applet is a TCP/IP interface configuration and routing
+ utility. You generally don't need "ip" to use busybox with
+ TCP/IP.
+
+config FEATURE_IP_ADDRESS
+ bool "ip address"
+ default y
+ depends on IP
+ help
+ Address manipulation support for the "ip" applet.
+
+config FEATURE_IP_LINK
+ bool "ip link"
+ default y
+ depends on IP
+ help
+ Configure network devices with "ip".
+
+config FEATURE_IP_ROUTE
+ bool "ip route"
+ default y
+ depends on IP
+ help
+ Add support for routing table management to "ip".
+
+config FEATURE_IP_TUNNEL
+ bool "ip tunnel"
+ default n
+ depends on IP
+ help
+ Add support for tunneling commands to "ip".
+
+config FEATURE_IP_RULE
+ bool "ip rule"
+ default n
+ depends on IP
+ help
+ Add support for rule commands to "ip".
+
+config FEATURE_IP_SHORT_FORMS
+ bool "Support short forms of ip commands"
+ default n
+ depends on IP
+ help
+ Also support short-form of ip <OBJECT> commands:
+ ip addr -> ipaddr
+ ip link -> iplink
+ ip route -> iproute
+ ip tunnel -> iptunnel
+ ip rule -> iprule
+
+ Say N unless you desparately need the short form of the ip
+ object commands.
+
+config FEATURE_IP_RARE_PROTOCOLS
+ bool "Support displaying rarely used link types"
+ default n
+ depends on IP
+ help
+ If you are not going to use links of type "frad", "econet",
+ "bif" etc, you probably don't need to enable this.
+ Ethernet, wireless, infrared, ppp/slip, ip tunnelling
+ link types are supported without this option selected.
+
+config IPADDR
+ bool
+ default y
+ depends on FEATURE_IP_SHORT_FORMS && FEATURE_IP_ADDRESS
+
+config IPLINK
+ bool
+ default y
+ depends on FEATURE_IP_SHORT_FORMS && FEATURE_IP_LINK
+
+config IPROUTE
+ bool
+ default y
+ depends on FEATURE_IP_SHORT_FORMS && FEATURE_IP_ROUTE
+
+config IPTUNNEL
+ bool
+ default y
+ depends on FEATURE_IP_SHORT_FORMS && FEATURE_IP_TUNNEL
+
+config IPRULE
+ bool
+ default y
+ depends on FEATURE_IP_SHORT_FORMS && FEATURE_IP_RULE
+
+config IPCALC
+ bool "ipcalc"
+ default n
+ help
+ ipcalc takes an IP address and netmask and calculates the
+ resulting broadcast, network, and host range.
+
+config FEATURE_IPCALC_FANCY
+ bool "Fancy IPCALC, more options, adds 1 kbyte"
+ default y
+ depends on IPCALC
+ help
+ Adds the options hostname, prefix and silent to the output of "ipcalc".
+
+config FEATURE_IPCALC_LONG_OPTIONS
+ bool "Enable long options"
+ default n
+ depends on IPCALC && GETOPT_LONG
+ help
+ Support long options for the ipcalc applet.
+
+config NAMEIF
+ bool "nameif"
+ default n
+ select FEATURE_SYSLOG
+ help
+ nameif is used to rename network interface by its MAC address.
+ Renamed interfaces MUST be in the down state.
+ It is possible to use a file (default: /etc/mactab)
+ with list of new interface names and MACs.
+ Maximum interface name length: IFNAMSIZ = 16
+ File fields are separated by space or tab.
+ File format:
+ # Comment
+ new_interface_name XX:XX:XX:XX:XX:XX
+
+config FEATURE_NAMEIF_EXTENDED
+ bool "Extended nameif"
+ default n
+ depends on NAMEIF
+ help
+ This extends the nameif syntax to support the bus_info and driver
+ checks. The syntax is compatible to the normal nameif.
+ File format:
+ new_interface_name driver=asix bus=usb-0000:00:08.2-3
+ new_interface_name bus=usb-0000:00:08.2-3 00:80:C8:38:91:B5
+ new_interface_name mac=00:80:C8:38:91:B5
+ new_interface_name 00:80:C8:38:91:B5
+
+config NC
+ bool "nc"
+ default n
+ help
+ A simple Unix utility which reads and writes data across network
+ connections.
+
+config NC_SERVER
+ bool "Netcat server options (-l)"
+ default n
+ depends on NC
+ help
+ Allow netcat to act as a server.
+
+config NC_EXTRA
+ bool "Netcat extensions (-eiw and filename)"
+ default n
+ depends on NC
+ help
+ Add -e (support for executing the rest of the command line after
+ making or receiving a successful connection), -i (delay interval for
+ lines sent), -w (timeout for initial connection).
+
+config NETSTAT
+ bool "netstat"
+ default n
+ help
+ netstat prints information about the Linux networking subsystem.
+
+config FEATURE_NETSTAT_WIDE
+ bool "Enable wide netstat output"
+ default n
+ depends on NETSTAT
+ help
+ Add support for wide columns. Useful when displaying IPv6 addresses
+ (-W option).
+
+config NSLOOKUP
+ bool "nslookup"
+ default n
+ help
+ nslookup is a tool to query Internet name servers.
+
+config PING
+ bool "ping"
+ default n
+ help
+ ping uses the ICMP protocol's mandatory ECHO_REQUEST datagram to
+ elicit an ICMP ECHO_RESPONSE from a host or gateway.
+
+config PING6
+ bool "ping6"
+ default n
+ depends on FEATURE_IPV6 && PING
+ help
+ This will give you a ping that can talk IPv6.
+
+config FEATURE_FANCY_PING
+ bool "Enable fancy ping output"
+ default y
+ depends on PING
+ help
+ Make the output from the ping applet include statistics, and at the
+ same time provide full support for ICMP packets.
+
+config PSCAN
+ bool "pscan"
+ default n
+ help
+ Simple network port scanner.
+
+config ROUTE
+ bool "route"
+ default n
+ help
+ Route displays or manipulates the kernel's IP routing tables.
+
+config SENDMAIL
+ bool "sendmail"
+ default n
+ help
+ Barebones sendmail.
+
+config FETCHMAIL
+ bool "fetchmail"
+ default n
+ help
+ Barebones fetchmail.
+
+config SLATTACH
+ bool "slattach"
+ default n
+ help
+ slattach is a small utility to attach network interfaces to serial lines.
+
+config TELNET
+ bool "telnet"
+ default n
+ help
+ Telnet is an interface to the TELNET protocol, but is also commonly
+ used to test other simple protocols.
+
+config FEATURE_TELNET_TTYPE
+ bool "Pass TERM type to remote host"
+ default y
+ depends on TELNET
+ help
+ Setting this option will forward the TERM environment variable to the
+ remote host you are connecting to. This is useful to make sure that
+ things like ANSI colors and other control sequences behave.
+
+config FEATURE_TELNET_AUTOLOGIN
+ bool "Pass USER type to remote host"
+ default y
+ depends on TELNET
+ help
+ Setting this option will forward the USER environment variable to the
+ remote host you are connecting to. This is useful when you need to
+ log into a machine without telling the username (autologin). This
+ option enables `-a' and `-l USER' arguments.
+
+config TELNETD
+ bool "telnetd"
+ default n
+ select FEATURE_SYSLOG
+ help
+ A daemon for the TELNET protocol, allowing you to log onto the host
+ running the daemon. Please keep in mind that the TELNET protocol
+ sends passwords in plain text. If you can't afford the space for an
+ SSH daemon and you trust your network, you may say 'y' here. As a
+ more secure alternative, you should seriously consider installing the
+ very small Dropbear SSH daemon instead:
+ http://matt.ucc.asn.au/dropbear/dropbear.html
+
+ Note that for busybox telnetd to work you need several things:
+ First of all, your kernel needs:
+ UNIX98_PTYS=y
+ DEVPTS_FS=y
+
+ Next, you need a /dev/pts directory on your root filesystem:
+
+ $ ls -ld /dev/pts
+ drwxr-xr-x 2 root root 0 Sep 23 13:21 /dev/pts/
+
+ Next you need the pseudo terminal master multiplexer /dev/ptmx:
+
+ $ ls -la /dev/ptmx
+ crw-rw-rw- 1 root tty 5, 2 Sep 23 13:55 /dev/ptmx
+
+ Any /dev/ttyp[0-9]* files you may have can be removed.
+ Next, you need to mount the devpts filesystem on /dev/pts using:
+
+ mount -t devpts devpts /dev/pts
+
+ You need to be sure that Busybox has LOGIN and
+ FEATURE_SUID enabled. And finally, you should make
+ certain that Busybox has been installed setuid root:
+
+ chown root.root /bin/busybox
+ chmod 4755 /bin/busybox
+
+ with all that done, telnetd _should_ work....
+
+
+config FEATURE_TELNETD_STANDALONE
+ bool "Support standalone telnetd (not inetd only)"
+ default n
+ depends on TELNETD
+ help
+ Selecting this will make telnetd able to run standalone.
+
+config TFTP
+ bool "tftp"
+ default n
+ help
+ This enables the Trivial File Transfer Protocol client program. TFTP
+ is usually used for simple, small transfers such as a root image
+ for a network-enabled bootloader.
+
+config TFTPD
+ bool "tftpd"
+ default n
+ help
+ This enables the Trivial File Transfer Protocol server program.
+ It expects that stdin is a datagram socket and a packet
+ is already pending on it. It will exit after one transfer.
+ In other words: it should be run from inetd in nowait mode,
+ or from udpsvd. Example: "udpsvd -E 0 69 tftpd DIR"
+
+config FEATURE_TFTP_GET
+ bool "Enable \"get\" command"
+ default y
+ depends on TFTP || TFTPD
+ help
+ Add support for the GET command within the TFTP client. This allows
+ a client to retrieve a file from a TFTP server.
+ Also enable upload support in tftpd, if tftpd is selected.
+
+config FEATURE_TFTP_PUT
+ bool "Enable \"put\" command"
+ default y
+ depends on TFTP || TFTPD
+ help
+ Add support for the PUT command within the TFTP client. This allows
+ a client to transfer a file to a TFTP server.
+ Also enable download support in tftpd, if tftpd is selected.
+
+config FEATURE_TFTP_BLOCKSIZE
+ bool "Enable \"blksize\" protocol option"
+ default n
+ depends on TFTP || TFTPD
+ help
+ Allow tftp to specify block size, and tftpd to understand
+ "blksize" option.
+
+config DEBUG_TFTP
+ bool "Enable debug"
+ default n
+ depends on TFTP
+ help
+ Enable debug settings for tftp. This is useful if you're running
+ into problems with tftp as the protocol doesn't help you much when
+ you run into problems.
+
+config TRACEROUTE
+ bool "traceroute"
+ default n
+ help
+ Utility to trace the route of IP packets
+
+config FEATURE_TRACEROUTE_VERBOSE
+ bool "Enable verbose output"
+ default n
+ depends on TRACEROUTE
+ help
+ Add some verbosity to traceroute. This includes amongst other things
+ hostnames and ICMP response types.
+
+config FEATURE_TRACEROUTE_SOURCE_ROUTE
+ bool "Enable loose source route"
+ default n
+ depends on TRACEROUTE
+ help
+ Add option to specify a loose source route gateway
+ (8 maximum).
+
+config FEATURE_TRACEROUTE_USE_ICMP
+ bool "Use ICMP instead of UDP"
+ default n
+ depends on TRACEROUTE
+ help
+ Add feature to allow for ICMP ECHO instead of UDP datagrams.
+
+source networking/udhcp/Config.in
+
+config VCONFIG
+ bool "vconfig"
+ default n
+ help
+ Creates, removes, and configures VLAN interfaces
+
+config WGET
+ bool "wget"
+ default n
+ help
+ wget is a utility for non-interactive download of files from HTTP,
+ HTTPS, and FTP servers.
+
+config FEATURE_WGET_STATUSBAR
+ bool "Enable a nifty process meter (+2k)"
+ default y
+ depends on WGET
+ help
+ Enable the transfer progress bar for wget transfers.
+
+config FEATURE_WGET_AUTHENTICATION
+ bool "Enable HTTP authentication"
+ default y
+ depends on WGET
+ help
+ Support authenticated HTTP transfers.
+
+config FEATURE_WGET_LONG_OPTIONS
+ bool "Enable long options"
+ default n
+ depends on WGET && GETOPT_LONG
+ help
+ Support long options for the wget applet.
+
+config ZCIP
+ bool "zcip"
+ default n
+ select FEATURE_SYSLOG
+ help
+ ZCIP provides ZeroConf IPv4 address selection, according to RFC 3927.
+ It's a daemon that allocates and defends a dynamically assigned
+ address on the 169.254/16 network, requiring no system administrator.
+
+ See http://www.zeroconf.org for further details, and "zcip.script"
+ in the busybox examples.
+
+config TCPSVD
+ bool "tcpsvd"
+ default n
+ help
+ tcpsvd listens on a TCP port and runs a program for each new connection
+
+config UDPSVD
+ bool "udpsvd"
+ default n
+ help
+ udpsvd listens on an UDP port and runs a program for each new connection
+
+endmenu
diff --git a/cleopatre/busybox-1.11.1-spc300/networking/Kbuild b/cleopatre/busybox-1.11.1-spc300/networking/Kbuild
new file mode 100644
index 0000000000..be2ef94ddd
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/networking/Kbuild
@@ -0,0 +1,45 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+lib-y:=
+lib-$(CONFIG_ARP) += arp.o interface.o
+lib-$(CONFIG_ARPING) += arping.o
+lib-$(CONFIG_BRCTL) += brctl.o
+lib-$(CONFIG_DNSD) += dnsd.o
+lib-$(CONFIG_ETHER_WAKE) += ether-wake.o
+lib-$(CONFIG_FAKEIDENTD) += isrv_identd.o isrv.o
+lib-$(CONFIG_FETCHMAIL) += sendmail.o
+lib-$(CONFIG_FTPGET) += ftpgetput.o
+lib-$(CONFIG_FTPPUT) += ftpgetput.o
+lib-$(CONFIG_HOSTNAME) += hostname.o
+lib-$(CONFIG_HTTPD) += httpd.o
+lib-$(CONFIG_IFCONFIG) += ifconfig.o interface.o
+lib-$(CONFIG_IFENSLAVE) += ifenslave.o interface.o
+lib-$(CONFIG_IFUPDOWN) += ifupdown.o
+lib-$(CONFIG_INETD) += inetd.o
+lib-$(CONFIG_IP) += ip.o
+lib-$(CONFIG_IPCALC) += ipcalc.o
+lib-$(CONFIG_NAMEIF) += nameif.o
+lib-$(CONFIG_NC) += nc.o
+lib-$(CONFIG_NETSTAT) += netstat.o
+lib-$(CONFIG_NSLOOKUP) += nslookup.o
+lib-$(CONFIG_PING) += ping.o
+lib-$(CONFIG_PING6) += ping.o
+lib-$(CONFIG_PSCAN) += pscan.o
+lib-$(CONFIG_ROUTE) += route.o
+lib-$(CONFIG_SENDMAIL) += sendmail.o
+lib-$(CONFIG_SLATTACH) += slattach.o
+lib-$(CONFIG_TELNET) += telnet.o
+lib-$(CONFIG_TELNETD) += telnetd.o
+lib-$(CONFIG_TFTP) += tftp.o
+lib-$(CONFIG_TFTPD) += tftp.o
+lib-$(CONFIG_TRACEROUTE) += traceroute.o
+lib-$(CONFIG_VCONFIG) += vconfig.o
+lib-$(CONFIG_WGET) += wget.o
+lib-$(CONFIG_ZCIP) += zcip.o
+
+lib-$(CONFIG_TCPSVD) += tcpudp.o tcpudp_perhost.o
+lib-$(CONFIG_UDPSVD) += tcpudp.o tcpudp_perhost.o
diff --git a/cleopatre/busybox-1.11.1-spc300/networking/arp.c b/cleopatre/busybox-1.11.1-spc300/networking/arp.c
new file mode 100644
index 0000000000..ae1bb1a2e3
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/networking/arp.c
@@ -0,0 +1,497 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * arp.c - Manipulate the system ARP cache
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Author: Fred N. van Kempen, <waltje at uwalt.nl.mugnet.org>
+ * Busybox port: Paul van Gool <pvangool at mimotech.com>
+ *
+ * modified for getopt32 by Arne Bernin <arne [at] alamut.de>
+ */
+
+#include "libbb.h"
+#include "inet_common.h"
+
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/ether.h>
+#include <netpacket/packet.h>
+
+#define DEBUG 0
+
+#define DFLT_AF "inet"
+#define DFLT_HW "ether"
+
+#define ARP_OPT_A (0x1)
+#define ARP_OPT_p (0x2)
+#define ARP_OPT_H (0x4)
+#define ARP_OPT_t (0x8)
+#define ARP_OPT_i (0x10)
+#define ARP_OPT_a (0x20)
+#define ARP_OPT_d (0x40)
+#define ARP_OPT_n (0x80) /* do not resolve addresses */
+#define ARP_OPT_D (0x100) /* HW-address is devicename */
+#define ARP_OPT_s (0x200)
+#define ARP_OPT_v (0x400 * DEBUG) /* debugging output flag */
+
+
+static const struct aftype *ap; /* current address family */
+static const struct hwtype *hw; /* current hardware type */
+static int sockfd; /* active socket descriptor */
+static smallint hw_set; /* flag if hw-type was set (-H) */
+static const char *device = ""; /* current device */
+
+static const char options[] ALIGN1 =
+ "pub\0"
+ "priv\0"
+ "temp\0"
+ "trail\0"
+ "dontpub\0"
+ "auto\0"
+ "dev\0"
+ "netmask\0";
+
+/* Delete an entry from the ARP cache. */
+/* Called only from main, once */
+static int arp_del(char **args)
+{
+ char *host;
+ struct arpreq req;
+ struct sockaddr sa;
+ int flags = 0;
+ int err;
+
+ memset(&req, 0, sizeof(req));
+
+ /* Resolve the host name. */
+ host = *args;
+ if (ap->input(host, &sa) < 0) {
+ bb_herror_msg_and_die("%s", host);
+ }
+
+ /* If a host has more than one address, use the correct one! */
+ memcpy(&req.arp_pa, &sa, sizeof(struct sockaddr));
+
+ if (hw_set)
+ req.arp_ha.sa_family = hw->type;
+
+ req.arp_flags = ATF_PERM;
+ args++;
+ while (*args != NULL) {
+ switch (index_in_strings(options, *args)) {
+ case 0: /* "pub" */
+ flags |= 1;
+ args++;
+ break;
+ case 1: /* "priv" */
+ flags |= 2;
+ args++;
+ break;
+ case 2: /* "temp" */
+ req.arp_flags &= ~ATF_PERM;
+ args++;
+ break;
+ case 3: /* "trail" */
+ req.arp_flags |= ATF_USETRAILERS;
+ args++;
+ break;
+ case 4: /* "dontpub" */
+#ifdef HAVE_ATF_DONTPUB
+ req.arp_flags |= ATF_DONTPUB;
+#else
+ bb_error_msg("feature ATF_DONTPUB is not supported");
+#endif
+ args++;
+ break;
+ case 5: /* "auto" */
+#ifdef HAVE_ATF_MAGIC
+ req.arp_flags |= ATF_MAGIC;
+#else
+ bb_error_msg("feature ATF_MAGIC is not supported");
+#endif
+ args++;
+ break;
+ case 6: /* "dev" */
+ if (*++args == NULL)
+ bb_show_usage();
+ device = *args;
+ args++;
+ break;
+ case 7: /* "netmask" */
+ if (*++args == NULL)
+ bb_show_usage();
+ if (strcmp(*args, "255.255.255.255") != 0) {
+ host = *args;
+ if (ap->input(host, &sa) < 0) {
+ bb_herror_msg_and_die("%s", host);
+ }
+ memcpy(&req.arp_netmask, &sa, sizeof(struct sockaddr));
+ req.arp_flags |= ATF_NETMASK;
+ }
+ args++;
+ break;
+ default:
+ bb_show_usage();
+ break;
+ }
+ }
+ if (flags == 0)
+ flags = 3;
+
+ strncpy(req.arp_dev, device, sizeof(req.arp_dev));
+
+ err = -1;
+
+ /* Call the kernel. */
+ if (flags & 2) {
+ if (option_mask32 & ARP_OPT_v)
+ bb_error_msg("SIOCDARP(nopub)");
+ err = ioctl(sockfd, SIOCDARP, &req);
+ if (err < 0) {
+ if (errno == ENXIO) {
+ if (flags & 1)
+ goto nopub;
+ printf("No ARP entry for %s\n", host);
+ return -1;
+ }
+ bb_perror_msg_and_die("SIOCDARP(priv)");
+ }
+ }
+ if ((flags & 1) && err) {
+ nopub:
+ req.arp_flags |= ATF_PUBL;
+ if (option_mask32 & ARP_OPT_v)
+ bb_error_msg("SIOCDARP(pub)");
+ if (ioctl(sockfd, SIOCDARP, &req) < 0) {
+ if (errno == ENXIO) {
+ printf("No ARP entry for %s\n", host);
+ return -1;
+ }
+ bb_perror_msg_and_die("SIOCDARP(pub)");
+ }
+ }
+ return 0;
+}
+
+/* Get the hardware address to a specified interface name */
+static void arp_getdevhw(char *ifname, struct sockaddr *sa,
+ const struct hwtype *hwt)
+{
+ struct ifreq ifr;
+ const struct hwtype *xhw;
+
+ strcpy(ifr.ifr_name, ifname);
+ ioctl_or_perror_and_die(sockfd, SIOCGIFHWADDR, &ifr,
+ "cant get HW-Address for '%s'", ifname);
+ if (hwt && (ifr.ifr_hwaddr.sa_family != hw->type)) {
+ bb_error_msg_and_die("protocol type mismatch");
+ }
+ memcpy(sa, &(ifr.ifr_hwaddr), sizeof(struct sockaddr));
+
+ if (option_mask32 & ARP_OPT_v) {
+ xhw = get_hwntype(ifr.ifr_hwaddr.sa_family);
+ if (!xhw || !xhw->print) {
+ xhw = get_hwntype(-1);
+ }
+ bb_error_msg("device '%s' has HW address %s '%s'",
+ ifname, xhw->name,
+ xhw->print((unsigned char *) &ifr.ifr_hwaddr.sa_data));
+ }
+}
+
+/* Set an entry in the ARP cache. */
+/* Called only from main, once */
+static int arp_set(char **args)
+{
+ char *host;
+ struct arpreq req;
+ struct sockaddr sa;
+ int flags;
+
+ memset(&req, 0, sizeof(req));
+
+ host = *args++;
+ if (ap->input(host, &sa) < 0) {
+ bb_herror_msg_and_die("%s", host);
+ }
+ /* If a host has more than one address, use the correct one! */
+ memcpy(&req.arp_pa, &sa, sizeof(struct sockaddr));
+
+ /* Fetch the hardware address. */
+ if (*args == NULL) {
+ bb_error_msg_and_die("need hardware address");
+ }
+ if (option_mask32 & ARP_OPT_D) {
+ arp_getdevhw(*args++, &req.arp_ha, hw_set ? hw : NULL);
+ } else {
+ if (hw->input(*args++, &req.arp_ha) < 0) {
+ bb_error_msg_and_die("invalid hardware address");
+ }
+ }
+
+ /* Check out any modifiers. */
+ flags = ATF_PERM | ATF_COM;
+ while (*args != NULL) {
+ switch (index_in_strings(options, *args)) {
+ case 0: /* "pub" */
+ flags |= ATF_PUBL;
+ args++;
+ break;
+ case 1: /* "priv" */
+ flags &= ~ATF_PUBL;
+ args++;
+ break;
+ case 2: /* "temp" */
+ flags &= ~ATF_PERM;
+ args++;
+ break;
+ case 3: /* "trail" */
+ flags |= ATF_USETRAILERS;
+ args++;
+ break;
+ case 4: /* "dontpub" */
+#ifdef HAVE_ATF_DONTPUB
+ flags |= ATF_DONTPUB;
+#else
+ bb_error_msg("feature ATF_DONTPUB is not supported");
+#endif
+ args++;
+ break;
+ case 5: /* "auto" */
+#ifdef HAVE_ATF_MAGIC
+ flags |= ATF_MAGIC;
+#else
+ bb_error_msg("feature ATF_MAGIC is not supported");
+#endif
+ args++;
+ break;
+ case 6: /* "dev" */
+ if (*++args == NULL)
+ bb_show_usage();
+ device = *args;
+ args++;
+ break;
+ case 7: /* "netmask" */
+ if (*++args == NULL)
+ bb_show_usage();
+ if (strcmp(*args, "255.255.255.255") != 0) {
+ host = *args;
+ if (ap->input(host, &sa) < 0) {
+ bb_herror_msg_and_die("%s", host);
+ }
+ memcpy(&req.arp_netmask, &sa, sizeof(struct sockaddr));
+ flags |= ATF_NETMASK;
+ }
+ args++;
+ break;
+ default:
+ bb_show_usage();
+ break;
+ }
+ }
+
+ /* Fill in the remainder of the request. */
+ req.arp_flags = flags;
+
+ strncpy(req.arp_dev, device, sizeof(req.arp_dev));
+
+ /* Call the kernel. */
+ if (option_mask32 & ARP_OPT_v)
+ bb_error_msg("SIOCSARP()");
+ xioctl(sockfd, SIOCSARP, &req);
+ return 0;
+}
+
+
+/* Print the contents of an ARP request block. */
+static void
+arp_disp(const char *name, char *ip, int type, int arp_flags,
+ char *hwa, char *mask, char *dev)
+{
+ static const int arp_masks[] = {
+ ATF_PERM, ATF_PUBL,
+#ifdef HAVE_ATF_MAGIC
+ ATF_MAGIC,
+#endif
+#ifdef HAVE_ATF_DONTPUB
+ ATF_DONTPUB,
+#endif
+ ATF_USETRAILERS,
+ };
+ static const char arp_labels[] ALIGN1 = "PERM\0""PUP\0"
+#ifdef HAVE_ATF_MAGIC
+ "AUTO\0"
+#endif
+#ifdef HAVE_ATF_DONTPUB
+ "DONTPUB\0"
+#endif
+ "TRAIL\0"
+ ;
+
+ const struct hwtype *xhw;
+
+ xhw = get_hwntype(type);
+ if (xhw == NULL)
+ xhw = get_hwtype(DFLT_HW);
+
+ printf("%s (%s) at ", name, ip);
+
+ if (!(arp_flags & ATF_COM)) {
+ if (arp_flags & ATF_PUBL)
+ printf("* ");
+ else
+ printf("<incomplete> ");
+ } else {
+ printf("%s [%s] ", hwa, xhw->name);
+ }
+
+ if (arp_flags & ATF_NETMASK)
+ printf("netmask %s ", mask);
+
+ print_flags_separated(arp_masks, arp_labels, arp_flags, " ");
+ printf(" on %s\n", dev);
+}
+
+/* Display the contents of the ARP cache in the kernel. */
+/* Called only from main, once */
+static int arp_show(char *name)
+{
+ const char *host;
+ const char *hostname;
+ FILE *fp;
+ struct sockaddr sa;
+ int type, flags;
+ int num;
+ unsigned entries = 0, shown = 0;
+ char ip[128];
+ char hwa[128];
+ char mask[128];
+ char line[128];
+ char dev[128];
+
+ host = NULL;
+ if (name != NULL) {
+ /* Resolve the host name. */
+ if (ap->input(name, &sa) < 0) {
+ bb_herror_msg_and_die("%s", name);
+ }
+ host = xstrdup(ap->sprint(&sa, 1));
+ }
+ fp = xfopen("/proc/net/arp", "r");
+ /* Bypass header -- read one line */
+ fgets(line, sizeof(line), fp);
+
+ /* Read the ARP cache entries. */
+ while (fgets(line, sizeof(line), fp)) {
+
+ mask[0] = '-'; mask[1] = '\0';
+ dev[0] = '-'; dev[1] = '\0';
+ /* All these strings can't overflow
+ * because fgets above reads limited amount of data */
+ num = sscanf(line, "%s 0x%x 0x%x %s %s %s\n",
+ ip, &type, &flags, hwa, mask, dev);
+ if (num < 4)
+ break;
+
+ entries++;
+ /* if the user specified hw-type differs, skip it */
+ if (hw_set && (type != hw->type))
+ continue;
+
+ /* if the user specified address differs, skip it */
+ if (host && strcmp(ip, host) != 0)
+ continue;
+
+ /* if the user specified device differs, skip it */
+ if (device[0] && strcmp(dev, device) != 0)
+ continue;
+
+ shown++;
+ /* This IS ugly but it works -be */
+ hostname = "?";
+ if (!(option_mask32 & ARP_OPT_n)) {
+ if (ap->input(ip, &sa) < 0)
+ hostname = ip;
+ else
+ hostname = ap->sprint(&sa, (option_mask32 & ARP_OPT_n) | 0x8000);
+ if (strcmp(hostname, ip) == 0)
+ hostname = "?";
+ }
+
+ arp_disp(hostname, ip, type, flags, hwa, mask, dev);
+ }
+ if (option_mask32 & ARP_OPT_v)
+ printf("Entries: %d\tSkipped: %d\tFound: %d\n",
+ entries, entries - shown, shown);
+
+ if (!shown) {
+ if (hw_set || host || device[0])
+ printf("No match found in %d entries\n", entries);
+ }
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ free((char*)host);
+ fclose(fp);
+ }
+ return 0;
+}
+
+int arp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int arp_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ char *hw_type;
+ char *protocol;
+
+ /* Initialize variables... */
+ ap = get_aftype(DFLT_AF);
+ if (!ap)
+ bb_error_msg_and_die("%s: %s not supported", DFLT_AF, "address family");
+
+ getopt32(argv, "A:p:H:t:i:adnDsv", &protocol, &protocol,
+ &hw_type, &hw_type, &device);
+ argv += optind;
+ if (option_mask32 & ARP_OPT_A || option_mask32 & ARP_OPT_p) {
+ ap = get_aftype(protocol);
+ if (ap == NULL)
+ bb_error_msg_and_die("%s: unknown %s", protocol, "address family");
+ }
+ if (option_mask32 & ARP_OPT_A || option_mask32 & ARP_OPT_p) {
+ hw = get_hwtype(hw_type);
+ if (hw == NULL)
+ bb_error_msg_and_die("%s: unknown %s", hw_type, "hardware type");
+ hw_set = 1;
+ }
+ //if (option_mask32 & ARP_OPT_i)... -i
+
+ if (ap->af != AF_INET) {
+ bb_error_msg_and_die("%s: kernel only supports 'inet'", ap->name);
+ }
+
+ /* If no hw type specified get default */
+ if (!hw) {
+ hw = get_hwtype(DFLT_HW);
+ if (!hw)
+ bb_error_msg_and_die("%s: %s not supported", DFLT_HW, "hardware type");
+ }
+
+ if (hw->alen <= 0) {
+ bb_error_msg_and_die("%s: %s without ARP support",
+ hw->name, "hardware type");
+ }
+ sockfd = xsocket(AF_INET, SOCK_DGRAM, 0);
+
+ /* Now see what we have to do here... */
+ if (option_mask32 & (ARP_OPT_d|ARP_OPT_s)) {
+ if (argv[0] == NULL)
+ bb_error_msg_and_die("need host name");
+ if (option_mask32 & ARP_OPT_s)
+ return arp_set(argv);
+ return arp_del(argv);
+ }
+ //if (option_mask32 & ARP_OPT_a) - default
+ return arp_show(argv[0]);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/networking/arping.c b/cleopatre/busybox-1.11.1-spc300/networking/arping.c
new file mode 100644
index 0000000000..0a444f15ce
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/networking/arping.c
@@ -0,0 +1,402 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * arping.c - Ping hosts by ARP requests/replies
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ * Author: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
+ * Busybox port: Nick Fedchik <nick@fedchik.org.ua>
+ */
+
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netinet/ether.h>
+#include <netpacket/packet.h>
+
+#include "libbb.h"
+
+/* We don't expect to see 1000+ seconds delay, unsigned is enough */
+#define MONOTONIC_US() ((unsigned)monotonic_us())
+
+enum {
+ DAD = 1,
+ UNSOLICITED = 2,
+ ADVERT = 4,
+ QUIET = 8,
+ QUIT_ON_REPLY = 16,
+ BCAST_ONLY = 32,
+ UNICASTING = 64
+};
+
+struct globals {
+ struct in_addr src;
+ struct in_addr dst;
+ struct sockaddr_ll me;
+ struct sockaddr_ll he;
+ int sock_fd;
+
+ int count; // = -1;
+ unsigned last;
+ unsigned timeout_us;
+ unsigned start;
+
+ unsigned sent;
+ unsigned brd_sent;
+ unsigned received;
+ unsigned brd_recv;
+ unsigned req_recv;
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+#define src (G.src )
+#define dst (G.dst )
+#define me (G.me )
+#define he (G.he )
+#define sock_fd (G.sock_fd )
+#define count (G.count )
+#define last (G.last )
+#define timeout_us (G.timeout_us)
+#define start (G.start )
+#define sent (G.sent )
+#define brd_sent (G.brd_sent )
+#define received (G.received )
+#define brd_recv (G.brd_recv )
+#define req_recv (G.req_recv )
+#define INIT_G() do { \
+ count = -1; \
+} while (0)
+
+// If GNUisms are not available...
+//static void *mempcpy(void *_dst, const void *_src, int n)
+//{
+// memcpy(_dst, _src, n);
+// return (char*)_dst + n;
+//}
+
+static int send_pack(struct in_addr *src_addr,
+ struct in_addr *dst_addr, struct sockaddr_ll *ME,
+ struct sockaddr_ll *HE)
+{
+ int err;
+ unsigned char buf[256];
+ struct arphdr *ah = (struct arphdr *) buf;
+ unsigned char *p = (unsigned char *) (ah + 1);
+
+ ah->ar_hrd = htons(ARPHRD_ETHER);
+ ah->ar_pro = htons(ETH_P_IP);
+ ah->ar_hln = ME->sll_halen;
+ ah->ar_pln = 4;
+ ah->ar_op = option_mask32 & ADVERT ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST);
+
+ p = mempcpy(p, &ME->sll_addr, ah->ar_hln);
+ p = mempcpy(p, src_addr, 4);
+
+ if (option_mask32 & ADVERT)
+ p = mempcpy(p, &ME->sll_addr, ah->ar_hln);
+ else
+ p = mempcpy(p, &HE->sll_addr, ah->ar_hln);
+
+ p = mempcpy(p, dst_addr, 4);
+
+ err = sendto(sock_fd, buf, p - buf, 0, (struct sockaddr *) HE, sizeof(*HE));
+ if (err == p - buf) {
+ last = MONOTONIC_US();
+ sent++;
+ if (!(option_mask32 & UNICASTING))
+ brd_sent++;
+ }
+ return err;
+}
+
+static void finish(void) ATTRIBUTE_NORETURN;
+static void finish(void)
+{
+ if (!(option_mask32 & QUIET)) {
+ printf("Sent %u probe(s) (%u broadcast(s))\n"
+ "Received %u repl%s"
+ " (%u request(s), %u broadcast(s))\n",
+ sent, brd_sent,
+ received, (received == 1) ? "ies" : "y",
+ req_recv, brd_recv);
+ }
+ if (option_mask32 & DAD)
+ exit(!!received);
+ if (option_mask32 & UNSOLICITED)
+ exit(EXIT_SUCCESS);
+ exit(!received);
+}
+
+static void catcher(void)
+{
+ unsigned now;
+
+ now = MONOTONIC_US();
+ if (start == 0)
+ start = now;
+
+ if (count == 0 || (timeout_us && (now - start) > timeout_us))
+ finish();
+
+ /* count < 0 means "infinite count" */
+ if (count > 0)
+ count--;
+
+ if (last == 0 || (now - last) > 500000) {
+ send_pack(&src, &dst, &me, &he);
+ if (count == 0 && (option_mask32 & UNSOLICITED))
+ finish();
+ }
+ alarm(1);
+}
+
+static bool recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
+{
+ struct arphdr *ah = (struct arphdr *) buf;
+ unsigned char *p = (unsigned char *) (ah + 1);
+ struct in_addr src_ip, dst_ip;
+
+ /* Filter out wild packets */
+ if (FROM->sll_pkttype != PACKET_HOST
+ && FROM->sll_pkttype != PACKET_BROADCAST
+ && FROM->sll_pkttype != PACKET_MULTICAST)
+ return false;
+
+ /* Only these types are recognised */
+ if (ah->ar_op != htons(ARPOP_REQUEST) && ah->ar_op != htons(ARPOP_REPLY))
+ return false;
+
+ /* ARPHRD check and this darned FDDI hack here :-( */
+ if (ah->ar_hrd != htons(FROM->sll_hatype)
+ && (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER)))
+ return false;
+
+ /* Protocol must be IP. */
+ if (ah->ar_pro != htons(ETH_P_IP)
+ || (ah->ar_pln != 4)
+ || (ah->ar_hln != me.sll_halen)
+ || (len < (int)(sizeof(*ah) + 2 * (4 + ah->ar_hln))))
+ return false;
+
+ memcpy(&src_ip, p + ah->ar_hln, 4);
+ memcpy(&dst_ip, p + ah->ar_hln + 4 + ah->ar_hln, 4);
+
+ if (dst.s_addr != src_ip.s_addr)
+ return false;
+ if (!(option_mask32 & DAD)) {
+ if ((src.s_addr != dst_ip.s_addr)
+ || (memcmp(p + ah->ar_hln + 4, &me.sll_addr, ah->ar_hln)))
+ return false;
+ } else {
+ /* DAD packet was:
+ src_ip = 0 (or some src)
+ src_hw = ME
+ dst_ip = tested address
+ dst_hw = <unspec>
+
+ We fail, if receive request/reply with:
+ src_ip = tested_address
+ src_hw != ME
+ if src_ip in request was not zero, check
+ also that it matches to dst_ip, otherwise
+ dst_ip/dst_hw do not matter.
+ */
+ if ((memcmp(p, &me.sll_addr, me.sll_halen) == 0)
+ || (src.s_addr && src.s_addr != dst_ip.s_addr))
+ return false;
+ }
+ if (!(option_mask32 & QUIET)) {
+ int s_printed = 0;
+
+ printf("%scast re%s from %s [%s]",
+ FROM->sll_pkttype == PACKET_HOST ? "Uni" : "Broad",
+ ah->ar_op == htons(ARPOP_REPLY) ? "ply" : "quest",
+ inet_ntoa(src_ip),
+ ether_ntoa((struct ether_addr *) p));
+ if (dst_ip.s_addr != src.s_addr) {
+ printf("for %s ", inet_ntoa(dst_ip));
+ s_printed = 1;
+ }
+ if (memcmp(p + ah->ar_hln + 4, me.sll_addr, ah->ar_hln)) {
+ if (!s_printed)
+ printf("for ");
+ printf("[%s]",
+ ether_ntoa((struct ether_addr *) p + ah->ar_hln + 4));
+ }
+
+ if (last) {
+ unsigned diff = MONOTONIC_US() - last;
+ printf(" %u.%03ums\n", diff / 1000, diff % 1000);
+ } else {
+ printf(" UNSOLICITED?\n");
+ }
+ fflush(stdout);
+ }
+ received++;
+ if (FROM->sll_pkttype != PACKET_HOST)
+ brd_recv++;
+ if (ah->ar_op == htons(ARPOP_REQUEST))
+ req_recv++;
+ if (option_mask32 & QUIT_ON_REPLY)
+ finish();
+ if (!(option_mask32 & BCAST_ONLY)) {
+ memcpy(he.sll_addr, p, me.sll_halen);
+ option_mask32 |= UNICASTING;
+ }
+ return true;
+}
+
+int arping_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int arping_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ const char *device = "eth0";
+ char *source = NULL;
+ char *target;
+ unsigned char *packet;
+ char *err_str;
+
+ INIT_G();
+
+ sock_fd = xsocket(AF_PACKET, SOCK_DGRAM, 0);
+
+ // Drop suid root privileges
+ // Need to remove SUID_NEVER from applets.h for this to work
+ //xsetuid(getuid());
+
+ err_str = xasprintf("interface %s %%s", device);
+ {
+ unsigned opt;
+ char *str_timeout;
+
+ /* Dad also sets quit_on_reply.
+ * Advert also sets unsolicited.
+ */
+ opt_complementary = "=1:Df:AU:c+";
+ opt = getopt32(argv, "DUAqfbc:w:I:s:",
+ &count, &str_timeout, &device, &source);
+ if (opt & 0x80) /* -w: timeout */
+ timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000 + 500000;
+ //if (opt & 0x200) /* -s: source */
+ option_mask32 &= 0x3f; /* set respective flags */
+ }
+
+ target = argv[optind];
+
+ xfunc_error_retval = 2;
+
+ {
+ struct ifreq ifr;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name) - 1);
+ /* We use ifr.ifr_name in error msg so that problem
+ * with truncated name will be visible */
+ ioctl_or_perror_and_die(sock_fd, SIOCGIFINDEX, &ifr, err_str, "not found");
+ me.sll_ifindex = ifr.ifr_ifindex;
+
+ xioctl(sock_fd, SIOCGIFFLAGS, (char *) &ifr);
+
+ if (!(ifr.ifr_flags & IFF_UP)) {
+ bb_error_msg_and_die(err_str, "is down");
+ }
+ if (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) {
+ bb_error_msg(err_str, "is not ARPable");
+ return (option_mask32 & DAD ? 0 : 2);
+ }
+ }
+
+ /* if (!inet_aton(target, &dst)) - not needed */ {
+ len_and_sockaddr *lsa;
+ lsa = xhost_and_af2sockaddr(target, 0, AF_INET);
+ memcpy(&dst, &lsa->u.sin.sin_addr.s_addr, 4);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(lsa);
+ }
+
+ if (source && !inet_aton(source, &src)) {
+ bb_error_msg_and_die("invalid source address %s", source);
+ }
+
+ if ((option_mask32 & (DAD|UNSOLICITED)) == UNSOLICITED && src.s_addr == 0)
+ src = dst;
+
+ if (!(option_mask32 & DAD) || src.s_addr) {
+ struct sockaddr_in saddr;
+ int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0);
+
+ if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device) + 1) == -1)
+ bb_perror_msg("cannot bind to device %s", device);
+ memset(&saddr, 0, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ if (src.s_addr) {
+ /* Check that this is indeed our IP */
+ saddr.sin_addr = src;
+ xbind(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr));
+ } else { /* !(option_mask32 & DAD) case */
+ /* Find IP address on this iface */
+ socklen_t alen = sizeof(saddr);
+
+ saddr.sin_port = htons(1025);
+ saddr.sin_addr = dst;
+
+ if (setsockopt(probe_fd, SOL_SOCKET, SO_DONTROUTE, &const_int_1, sizeof(const_int_1)) == -1)
+ bb_perror_msg("setsockopt(SO_DONTROUTE)");
+ xconnect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr));
+ if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == -1) {
+ bb_perror_msg_and_die("getsockname");
+ }
+ if (saddr.sin_family != AF_INET)
+ bb_error_msg_and_die("no IP address configured");
+ src = saddr.sin_addr;
+ }
+ close(probe_fd);
+ }
+
+ me.sll_family = AF_PACKET;
+ //me.sll_ifindex = ifindex; - done before
+ me.sll_protocol = htons(ETH_P_ARP);
+ xbind(sock_fd, (struct sockaddr *) &me, sizeof(me));
+
+ {
+ socklen_t alen = sizeof(me);
+
+ if (getsockname(sock_fd, (struct sockaddr *) &me, &alen) == -1) {
+ bb_perror_msg_and_die("getsockname");
+ }
+ }
+ if (me.sll_halen == 0) {
+ bb_error_msg(err_str, "is not ARPable (no ll address)");
+ return (option_mask32 & DAD ? 0 : 2);
+ }
+ he = me;
+ memset(he.sll_addr, -1, he.sll_halen);
+
+ if (!(option_mask32 & QUIET)) {
+ /* inet_ntoa uses static storage, can't use in same printf */
+ printf("ARPING to %s", inet_ntoa(dst));
+ printf(" from %s via %s\n", inet_ntoa(src), device);
+ }
+
+ signal_SA_RESTART_empty_mask(SIGINT, (void (*)(int))finish);
+ signal_SA_RESTART_empty_mask(SIGALRM, (void (*)(int))catcher);
+
+ catcher();
+
+ packet = xmalloc(4096);
+ while (1) {
+ sigset_t sset, osset;
+ struct sockaddr_ll from;
+ socklen_t alen = sizeof(from);
+ int cc;
+
+ cc = recvfrom(sock_fd, packet, 4096, 0, (struct sockaddr *) &from, &alen);
+ if (cc < 0) {
+ bb_perror_msg("recvfrom");
+ continue;
+ }
+ sigemptyset(&sset);
+ sigaddset(&sset, SIGALRM);
+ sigaddset(&sset, SIGINT);
+ sigprocmask(SIG_BLOCK, &sset, &osset);
+ recv_pack(packet, cc, &from);
+ sigprocmask(SIG_SETMASK, &osset, NULL);
+ }
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/networking/brctl.c b/cleopatre/busybox-1.11.1-spc300/networking/brctl.c
new file mode 100644
index 0000000000..acc789722e
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/networking/brctl.c
@@ -0,0 +1,272 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Small implementation of brctl for busybox.
+ *
+ * Copyright (C) 2008 by Bernhard Fischer
+ *
+ * Some helper functions from bridge-utils are
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+/* This applet currently uses only the ioctl interface and no sysfs at all.
+ * At the time of this writing this was considered a feature.
+ */
+#include "libbb.h"
+#include <linux/sockios.h>
+#include <net/if.h>
+
+/* Maximum number of ports supported per bridge interface. */
+#ifndef MAX_PORTS
+#define MAX_PORTS 32
+#endif
+
+/* Use internal number parsing and not the "exact" conversion. */
+/* #define BRCTL_USE_INTERNAL 0 */ /* use exact conversion */
+#define BRCTL_USE_INTERNAL 1
+
+#if ENABLE_FEATURE_BRCTL_FANCY
+#include <linux/if_bridge.h>
+
+/* FIXME: These 4 funcs are not really clean and could be improved */
+static ALWAYS_INLINE void strtotimeval(struct timeval *tv,
+ const char *time_str)
+{
+ double secs;
+#if BRCTL_USE_INTERNAL
+ secs = /*bb_*/strtod(time_str, NULL);
+ if (!secs)
+#else
+ if (sscanf(time_str, "%lf", &secs) != 1)
+#endif
+ bb_error_msg_and_die (bb_msg_invalid_arg, time_str, "timespec");
+ tv->tv_sec = secs;
+ tv->tv_usec = 1000000 * (secs - tv->tv_sec);
+}
+
+static ALWAYS_INLINE unsigned long __tv_to_jiffies(const struct timeval *tv)
+{
+ unsigned long long jif;
+
+ jif = 1000000ULL * tv->tv_sec + tv->tv_usec;
+
+ return jif/10000;
+}
+# if 0
+static void __jiffies_to_tv(struct timeval *tv, unsigned long jiffies)
+{
+ unsigned long long tvusec;
+
+ tvusec = 10000ULL*jiffies;
+ tv->tv_sec = tvusec/1000000;
+ tv->tv_usec = tvusec - 1000000 * tv->tv_sec;
+}
+# endif
+static unsigned long str_to_jiffies(const char *time_str)
+{
+ struct timeval tv;
+ strtotimeval(&tv, time_str);
+ return __tv_to_jiffies(&tv);
+}
+
+static void arm_ioctl(unsigned long *args,
+ unsigned long arg0, unsigned long arg1, unsigned long arg2)
+{
+ args[0] = arg0;
+ args[1] = arg1;
+ args[2] = arg2;
+ args[3] = 0;
+}
+#endif
+
+
+int brctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int brctl_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ static const char keywords[] ALIGN1 =
+ "addbr\0" "delbr\0" "addif\0" "delif\0"
+ USE_FEATURE_BRCTL_FANCY(
+ "stp\0"
+ "setageing\0" "setfd\0" "sethello\0" "setmaxage\0"
+ "setpathcost\0" "setportprio\0" "setbridgeprio\0"
+ )
+ USE_FEATURE_BRCTL_SHOW("showmacs\0" "show\0");
+
+ enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif
+ USE_FEATURE_BRCTL_FANCY(,
+ ARG_stp,
+ ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage,
+ ARG_setpathcost, ARG_setportprio, ARG_setbridgeprio
+ )
+ USE_FEATURE_BRCTL_SHOW(, ARG_showmacs, ARG_show)
+ };
+
+ int fd;
+ smallint key;
+ struct ifreq ifr;
+ char *br, *brif;
+
+ argv++;
+ while (*argv) {
+#if ENABLE_FEATURE_BRCTL_FANCY
+ int ifidx[MAX_PORTS];
+ unsigned long args[4];
+ ifr.ifr_data = (char *) &args;
+#endif
+
+ key = index_in_strings(keywords, *argv);
+ if (key == -1) /* no match found in keywords array, bail out. */
+ bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name);
+ argv++;
+ fd = xsocket(AF_INET, SOCK_STREAM, 0);
+
+#if ENABLE_FEATURE_BRCTL_SHOW
+ if (key == ARG_show) { /* show */
+ char brname[IFNAMSIZ];
+ int bridx[MAX_PORTS];
+ int i, num;
+ arm_ioctl(args, BRCTL_GET_BRIDGES,
+ (unsigned long) bridx, MAX_PORTS);
+ num = xioctl(fd, SIOCGIFBR, args);
+ printf("bridge name\tbridge id\t\tSTP enabled\tinterfaces\n");
+ for (i = 0; i < num; i++) {
+ char ifname[IFNAMSIZ];
+ int j, tabs;
+ struct __bridge_info bi;
+ unsigned char *x;
+
+ if (!if_indextoname(bridx[i], brname))
+ bb_perror_msg_and_die("can't get bridge name for index %d", i);
+ strncpy(ifr.ifr_name, brname, IFNAMSIZ);
+
+ arm_ioctl(args, BRCTL_GET_BRIDGE_INFO,
+ (unsigned long) &bi, 0);
+ xioctl(fd, SIOCDEVPRIVATE, &ifr);
+ printf("%s\t\t", brname);
+
+ /* print bridge id */
+ x = (unsigned char *) &bi.bridge_id;
+ for (j = 0; j < 8; j++) {
+ printf("%.2x", x[j]);
+ if (j == 1)
+ bb_putchar('.');
+ }
+ printf(bi.stp_enabled ? "\tyes" : "\tno");
+
+ /* print interface list */
+ arm_ioctl(args, BRCTL_GET_PORT_LIST,
+ (unsigned long) ifidx, MAX_PORTS);
+ xioctl(fd, SIOCDEVPRIVATE, &ifr);
+ tabs = 0;
+ for (j = 0; j < MAX_PORTS; j++) {
+ if (!ifidx[j])
+ continue;
+ if (!if_indextoname(ifidx[j], ifname))
+ bb_perror_msg_and_die("can't get interface name for index %d", j);
+ if (tabs)
+ printf("\t\t\t\t\t");
+ else
+ tabs = 1;
+ printf("\t\t%s\n", ifname);
+ }
+ if (!tabs) /* bridge has no interfaces */
+ bb_putchar('\n');
+ }
+ goto done;
+ }
+#endif
+
+ if (!*argv) /* all but 'show' need at least one argument */
+ bb_show_usage();
+
+ br = *argv++;
+
+ if (key == ARG_addbr || key == ARG_delbr) { /* addbr or delbr */
+ ioctl_or_perror_and_die(fd,
+ key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR,
+ br, "bridge %s", br);
+ goto done;
+ }
+
+ if (!*argv) /* all but 'addif/delif' need at least two arguments */
+ bb_show_usage();
+
+ strncpy(ifr.ifr_name, br, IFNAMSIZ);
+ if (key == ARG_addif || key == ARG_delif) { /* addif or delif */
+ brif = *argv;
+ ifr.ifr_ifindex = if_nametoindex(brif);
+ if (!ifr.ifr_ifindex) {
+ bb_perror_msg_and_die("iface %s", brif);
+ }
+ ioctl_or_perror_and_die(fd,
+ key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF,
+ &ifr, "bridge %s", br);
+ goto done_next_argv;
+ }
+#if ENABLE_FEATURE_BRCTL_FANCY
+ if (key == ARG_stp) { /* stp */
+ /* FIXME: parsing yes/y/on/1 versus no/n/off/0 is too involved */
+ arm_ioctl(args, BRCTL_SET_BRIDGE_STP_STATE,
+ (unsigned)(**argv - '0'), 0);
+ goto fire;
+ }
+ if ((unsigned)(key - ARG_setageing) < 4) { /* time related ops */
+ static const uint8_t ops[] ALIGN1 = {
+ BRCTL_SET_AGEING_TIME, /* ARG_setageing */
+ BRCTL_SET_BRIDGE_FORWARD_DELAY, /* ARG_setfd */
+ BRCTL_SET_BRIDGE_HELLO_TIME, /* ARG_sethello */
+ BRCTL_SET_BRIDGE_MAX_AGE /* ARG_setmaxage */
+ };
+ arm_ioctl(args, ops[key - ARG_setageing], str_to_jiffies(*argv), 0);
+ goto fire;
+ }
+ if (key == ARG_setpathcost
+ || key == ARG_setportprio
+ || key == ARG_setbridgeprio
+ ) {
+ static const uint8_t ops[] ALIGN1 = {
+ BRCTL_SET_PATH_COST, /* ARG_setpathcost */
+ BRCTL_SET_PORT_PRIORITY, /* ARG_setportprio */
+ BRCTL_SET_BRIDGE_PRIORITY /* ARG_setbridgeprio */
+ };
+ int port = -1;
+ unsigned arg1, arg2;
+
+ if (key != ARG_setbridgeprio) {
+ /* get portnum */
+ unsigned i;
+
+ port = if_nametoindex(*argv++);
+ if (!port)
+ bb_error_msg_and_die(bb_msg_invalid_arg, *argv, "port");
+ memset(ifidx, 0, sizeof ifidx);
+ arm_ioctl(args, BRCTL_GET_PORT_LIST, (unsigned long)ifidx,
+ MAX_PORTS);
+ xioctl(fd, SIOCDEVPRIVATE, &ifr);
+ for (i = 0; i < MAX_PORTS; i++) {
+ if (ifidx[i] == port) {
+ port = i;
+ break;
+ }
+ }
+ }
+ arg1 = port;
+ arg2 = xatoi_u(*argv);
+ if (key == ARG_setbridgeprio) {
+ arg1 = arg2;
+ arg2 = 0;
+ }
+ arm_ioctl(args, ops[key - ARG_setpathcost], arg1, arg2);
+ }
+ fire:
+ /* Execute the previously set command */
+ xioctl(fd, SIOCDEVPRIVATE, &ifr);
+#endif
+ done_next_argv:
+ argv++;
+ done:
+ close(fd);
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/networking/dnsd.c b/cleopatre/busybox-1.11.1-spc300/networking/dnsd.c
new file mode 100644
index 0000000000..97ba2dc6af
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/networking/dnsd.c
@@ -0,0 +1,409 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini DNS server implementation for busybox
+ *
+ * Copyright (C) 2005 Roberto A. Foglietta (me@roberto.foglietta.name)
+ * Copyright (C) 2005 Odd Arild Olsen (oao at fibula dot no)
+ * Copyright (C) 2003 Paul Sheer
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ * Odd Arild Olsen started out with the sheerdns [1] of Paul Sheer and rewrote
+ * it into a shape which I believe is both easier to understand and maintain.
+ * I also reused the input buffer for output and removed services he did not
+ * need. [1] http://threading.2038bug.com/sheerdns/
+ *
+ * Some bugfix and minor changes was applied by Roberto A. Foglietta who made
+ * the first porting of oao' scdns to busybox also.
+ */
+
+#include "libbb.h"
+#include <syslog.h>
+
+//#define DEBUG 1
+#define DEBUG 0
+
+enum {
+ MAX_HOST_LEN = 16, // longest host name allowed is 15
+ IP_STRING_LEN = 18, // .xxx.xxx.xxx.xxx\0
+
+//must be strlen('.in-addr.arpa') larger than IP_STRING_LEN
+ MAX_NAME_LEN = (IP_STRING_LEN + 13),
+
+/* Cannot get bigger packets than 512 per RFC1035
+ In practice this can be set considerably smaller:
+ Length of response packet is header (12B) + 2*type(4B) + 2*class(4B) +
+ ttl(4B) + rlen(2B) + r (MAX_NAME_LEN =21B) +
+ 2*querystring (2 MAX_NAME_LEN= 42B), all together 90 Byte
+*/
+ MAX_PACK_LEN = 512,
+
+ DEFAULT_TTL = 30, // increase this when not testing?
+
+ REQ_A = 1,
+ REQ_PTR = 12
+};
+
+struct dns_head { // the message from client and first part of response mag
+ uint16_t id;
+ uint16_t flags;
+ uint16_t nquer; // accepts 0
+ uint16_t nansw; // 1 in response
+ uint16_t nauth; // 0
+ uint16_t nadd; // 0
+};
+struct dns_prop {
+ uint16_t type;
+ uint16_t class;
+};
+struct dns_entry { // element of known name, ip address and reversed ip address
+ struct dns_entry *next;
+ char ip[IP_STRING_LEN]; // dotted decimal IP
+ char rip[IP_STRING_LEN]; // length decimal reversed IP
+ char name[MAX_HOST_LEN];
+};
+
+static struct dns_entry *dnsentry;
+static uint32_t ttl = DEFAULT_TTL;
+
+static const char *fileconf = "/etc/dnsd.conf";
+
+// Must match getopt32 call
+#define OPT_daemon (option_mask32 & 0x10)
+#define OPT_verbose (option_mask32 & 0x20)
+
+
+/*
+ * Convert host name from C-string to dns length/string.
+ */
+static void convname(char *a, uint8_t *q)
+{
+ int i = (q[0] == '.') ? 0 : 1;
+ for (; i < MAX_HOST_LEN-1 && *q; i++, q++)
+ a[i] = tolower(*q);
+ a[0] = i - 1;
+ a[i] = 0;
+}
+
+/*
+ * Insert length of substrings instead of dots
+ */
+static void undot(uint8_t * rip)
+{
+ int i = 0, s = 0;
+ while (rip[i])
+ i++;
+ for (--i; i >= 0; i--) {
+ if (rip[i] == '.') {
+ rip[i] = s;
+ s = 0;
+ } else s++;
+ }
+}
+
+/*
+ * Read one line of hostname/IP from file
+ * Returns 0 for each valid entry read, -1 at EOF
+ * Assumes all host names are lower case only
+ * Hostnames with more than one label are not handled correctly.
+ * Presently the dot is copied into name without
+ * converting to a length/string substring for that label.
+ */
+static int getfileentry(FILE * fp, struct dns_entry *s)
+{
+ unsigned int a,b,c,d;
+ char *line, *r, *name;
+
+ restart:
+ line = r = xmalloc_fgets(fp);
+ if (!r)
+ return -1;
+ while (*r == ' ' || *r == '\t') {
+ r++;
+ if (!*r || *r == '#' || *r == '\n') {
+ free(line);
+ goto restart; /* skipping empty/blank and commented lines */
+ }
+ }
+ name = r;
+ while (*r != ' ' && *r != '\t')
+ r++;
+ *r++ = '\0';
+ if (sscanf(r, ".%u.%u.%u.%u"+1, &a, &b, &c, &d) != 4) {
+ free(line);
+ goto restart; /* skipping wrong lines */
+ }
+
+ sprintf(s->ip, ".%u.%u.%u.%u"+1, a, b, c, d);
+ sprintf(s->rip, ".%u.%u.%u.%u", d, c, b, a);
+ undot((uint8_t*)s->rip);
+ convname(s->name, (uint8_t*)name);
+
+ if (OPT_verbose)
+ fprintf(stderr, "\tname:%s, ip:%s\n", &(s->name[1]),s->ip);
+
+ free(line);
+ return 0;
+}
+
+/*
+ * Read hostname/IP records from file
+ */
+static void dnsentryinit(void)
+{
+ FILE *fp;
+ struct dns_entry *m, *prev;
+
+ prev = dnsentry = NULL;
+ fp = xfopen(fileconf, "r");
+
+ while (1) {
+ m = xzalloc(sizeof(*m));
+ /*m->next = NULL;*/
+ if (getfileentry(fp, m))
+ break;
+
+ if (prev == NULL)
+ dnsentry = m;
+ else
+ prev->next = m;
+ prev = m;
+ }
+ fclose(fp);
+}
+
+/*
+ * Look query up in dns records and return answer if found
+ * qs is the query string, first byte the string length
+ */
+static int table_lookup(uint16_t type, uint8_t * as, uint8_t * qs)
+{
+ int i;
+ struct dns_entry *d = dnsentry;
+
+ do {
+#if DEBUG
+ char *p,*q;
+ q = (char *)&(qs[1]);
+ p = &(d->name[1]);
+ fprintf(stderr, "\n%s: %d/%d p:%s q:%s %d",
+ __FUNCTION__, (int)strlen(p), (int)(d->name[0]),
+ p, q, (int)strlen(q));
+#endif
+ if (type == REQ_A) { /* search by host name */
+ for (i = 1; i <= (int)(d->name[0]); i++)
+ if (tolower(qs[i]) != d->name[i])
+ break;
+ if (i > (int)(d->name[0]) ||
+ (d->name[0] == 1 && d->name[1] == '*')) {
+ strcpy((char *)as, d->ip);
+#if DEBUG
+ fprintf(stderr, " OK as:%s\n", as);
+#endif
+ return 0;
+ }
+ } else if (type == REQ_PTR) { /* search by IP-address */
+ if ((d->name[0] != 1 || d->name[1] != '*') &&
+ !strncmp((char*)&d->rip[1], (char*)&qs[1], strlen(d->rip)-1)) {
+ strcpy((char *)as, d->name);
+ return 0;
+ }
+ }
+ d = d->next;
+ } while (d);
+ return -1;
+}
+
+/*
+ * Decode message and generate answer
+ */
+static int process_packet(uint8_t *buf)
+{
+ uint8_t answstr[MAX_NAME_LEN + 1];
+ struct dns_head *head;
+ struct dns_prop *qprop;
+ uint8_t *from, *answb;
+ uint16_t outr_rlen;
+ uint16_t outr_flags;
+ uint16_t flags;
+ int lookup_result, type, packet_len;
+ int querystr_len;
+
+ answstr[0] = '\0';
+
+ head = (struct dns_head *)buf;
+ if (head->nquer == 0) {
+ bb_error_msg("no queries");
+ return -1;
+ }
+
+ if (head->flags & 0x8000) {
+ bb_error_msg("ignoring response packet");
+ return -1;
+ }
+
+ from = (void *)&head[1]; // start of query string
+//FIXME: strlen of untrusted data??!
+ querystr_len = strlen((char *)from) + 1 + sizeof(struct dns_prop);
+ answb = from + querystr_len; // where to append answer block
+
+ outr_rlen = 0;
+ outr_flags = 0;
+
+ qprop = (struct dns_prop *)(answb - 4);
+ type = ntohs(qprop->type);
+
+ // only let REQ_A and REQ_PTR pass
+ if (!(type == REQ_A || type == REQ_PTR)) {
+ goto empty_packet; /* we can't handle the query type */
+ }
+
+ if (ntohs(qprop->class) != 1 /* class INET */ ) {
+ outr_flags = 4; /* not supported */
+ goto empty_packet;
+ }
+ /* we only support standard queries */
+
+ if ((ntohs(head->flags) & 0x7800) != 0)
+ goto empty_packet;
+
+ // We have a standard query
+ bb_info_msg("%s", (char *)from);
+ lookup_result = table_lookup(type, answstr, from);
+ if (lookup_result != 0) {
+ outr_flags = 3 | 0x0400; // name do not exist and auth
+ goto empty_packet;
+ }
+ if (type == REQ_A) { // return an address
+ struct in_addr a; // NB! its "struct { unsigned __long__ s_addr; }"
+ uint32_t v32;
+ if (!inet_aton((char*)answstr, &a)) { //dotted dec to long conv
+ outr_flags = 1; /* Frmt err */
+ goto empty_packet;
+ }
+ v32 = a.s_addr; /* in case long != int */
+ memcpy(answstr, &v32, 4);
+ outr_rlen = 4; // uint32_t IP
+ } else
+ outr_rlen = strlen((char *)answstr) + 1; // a host name
+ outr_flags |= 0x0400; /* authority-bit */
+ // we have an answer
+ head->nansw = htons(1);
+
+ // copy query block to answer block
+ memcpy(answb, from, querystr_len);
+ answb += querystr_len;
+
+ // and append answer rr
+// FIXME: unaligned accesses??
+ *(uint32_t *) answb = htonl(ttl);
+ answb += 4;
+ *(uint16_t *) answb = htons(outr_rlen);
+ answb += 2;
+ memcpy(answb, answstr, outr_rlen);
+ answb += outr_rlen;
+
+ empty_packet:
+
+ flags = ntohs(head->flags);
+ // clear rcode and RA, set responsebit and our new flags
+ flags |= (outr_flags & 0xff80) | 0x8000;
+ head->flags = htons(flags);
+ head->nauth = head->nadd = 0;
+ head->nquer = htons(1);
+
+ packet_len = answb - buf;
+ return packet_len;
+}
+
+/*
+ * Exit on signal
+ */
+static void interrupt(int sig)
+{
+ /* unlink("/var/run/dnsd.lock"); */
+ bb_error_msg("interrupt, exiting\n");
+ kill_myself_with_sig(sig);
+}
+
+int dnsd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int dnsd_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ const char *listen_interface = "0.0.0.0";
+ char *sttl, *sport;
+ len_and_sockaddr *lsa, *from, *to;
+ unsigned lsa_size;
+ int udps;
+ uint16_t port = 53;
+ /* Paranoid sizing: querystring x2 + ttl + outr_rlen + answstr */
+ /* I'd rather see process_packet() fixed instead... */
+ uint8_t buf[MAX_PACK_LEN * 2 + 4 + 2 + (MAX_NAME_LEN+1)];
+
+ getopt32(argv, "i:c:t:p:dv", &listen_interface, &fileconf, &sttl, &sport);
+ //if (option_mask32 & 0x1) // -i
+ //if (option_mask32 & 0x2) // -c
+ if (option_mask32 & 0x4) // -t
+ ttl = xatou_range(sttl, 1, 0xffffffff);
+ if (option_mask32 & 0x8) // -p
+ port = xatou_range(sport, 1, 0xffff);
+
+ if (OPT_verbose) {
+ bb_info_msg("listen_interface: %s", listen_interface);
+ bb_info_msg("ttl: %d, port: %d", ttl, port);
+ bb_info_msg("fileconf: %s", fileconf);
+ }
+
+ if (OPT_daemon) {
+ bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv);
+ openlog(applet_name, LOG_PID, LOG_DAEMON);
+ logmode = LOGMODE_SYSLOG;
+ }
+
+ dnsentryinit();
+
+ signal(SIGINT, interrupt);
+ bb_signals(0
+ /* why? + (1 << SIGPIPE) */
+ + (1 << SIGHUP)
+#ifdef SIGTSTP
+ + (1 << SIGTSTP)
+#endif
+#ifdef SIGURG
+ + (1 << SIGURG)
+#endif
+ , SIG_IGN);
+
+ lsa = xdotted2sockaddr(listen_interface, port);
+ udps = xsocket(lsa->u.sa.sa_family, SOCK_DGRAM, 0);
+ xbind(udps, &lsa->u.sa, lsa->len);
+ socket_want_pktinfo(udps); /* needed for recv_from_to to work */
+ lsa_size = LSA_LEN_SIZE + lsa->len;
+ from = xzalloc(lsa_size);
+ to = xzalloc(lsa_size);
+
+ bb_info_msg("Accepting UDP packets on %s",
+ xmalloc_sockaddr2dotted(&lsa->u.sa));
+
+ while (1) {
+ int r;
+ /* Try to get *DEST* address (to which of our addresses
+ * this query was directed), and reply from the same address.
+ * Or else we can exhibit usual UDP ugliness:
+ * [ip1.multihomed.ip2] <= query to ip1 <= peer
+ * [ip1.multihomed.ip2] => reply from ip2 => peer (confused) */
+ memcpy(to, lsa, lsa_size);
+ r = recv_from_to(udps, buf, MAX_PACK_LEN + 1, 0, &from->u.sa, &to->u.sa, lsa->len);
+ if (r < 12 || r > MAX_PACK_LEN) {
+ bb_error_msg("invalid packet size");
+ continue;
+ }
+ if (OPT_verbose)
+ bb_info_msg("Got UDP packet");
+ buf[r] = '\0'; /* paranoia */
+ r = process_packet(buf);
+ if (r <= 0)
+ continue;
+ send_to_from(udps, buf, r, 0, &from->u.sa, &to->u.sa, lsa->len);
+ }
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/networking/ether-wake.c b/cleopatre/busybox-1.11.1-spc300/networking/ether-wake.c
new file mode 100644
index 0000000000..fcd7dd2bcb
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/networking/ether-wake.c
@@ -0,0 +1,276 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * ether-wake.c - Send a magic packet to wake up sleeping machines.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ * Author: Donald Becker, http://www.scyld.com/"; http://www.scyld.com/wakeonlan.html
+ * Busybox port: Christian Volkmann <haveaniceday@online.de>
+ * Used version of ether-wake.c: v1.09 11/12/2003 Donald Becker, http://www.scyld.com/";
+ */
+
+/* full usage according Donald Becker
+ * usage: ether-wake [-i <ifname>] [-p aa:bb:cc:dd[:ee:ff]] 00:11:22:33:44:55\n"
+ *
+ * This program generates and transmits a Wake-On-LAN (WOL)\n"
+ * \"Magic Packet\", used for restarting machines that have been\n"
+ * soft-powered-down (ACPI D3-warm state).\n"
+ * It currently generates the standard AMD Magic Packet format, with\n"
+ * an optional password appended.\n"
+ *
+ * The single required parameter is the Ethernet MAC (station) address\n"
+ * of the machine to wake or a host ID with known NSS 'ethers' entry.\n"
+ * The MAC address may be found with the 'arp' program while the target\n"
+ * machine is awake.\n"
+ *
+ * Options:\n"
+ * -b Send wake-up packet to the broadcast address.\n"
+ * -D Increase the debug level.\n"
+ * -i ifname Use interface IFNAME instead of the default 'eth0'.\n"
+ * -p <pw> Append the four or six byte password PW to the packet.\n"
+ * A password is only required for a few adapter types.\n"
+ * The password may be specified in ethernet hex format\n"
+ * or dotted decimal (Internet address)\n"
+ * -p 00:22:44:66:88:aa\n"
+ * -p 192.168.1.1\n";
+ *
+ *
+ * This program generates and transmits a Wake-On-LAN (WOL) "Magic Packet",
+ * used for restarting machines that have been soft-powered-down
+ * (ACPI D3-warm state). It currently generates the standard AMD Magic Packet
+ * format, with an optional password appended.
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License, incorporated herein by reference.
+ * Contact the author for use under other terms.
+ *
+ * This source file was originally part of the network tricks package, and
+ * is now distributed to support the Scyld Beowulf system.
+ * Copyright 1999-2003 Donald Becker and Scyld Computing Corporation.
+ *
+ * The author may be reached as becker@scyld, or C/O
+ * Scyld Computing Corporation
+ * 914 Bay Ridge Road, Suite 220
+ * Annapolis MD 21403
+ *
+ * Notes:
+ * On some systems dropping root capability allows the process to be
+ * dumped, traced or debugged.
+ * If someone traces this program, they get control of a raw socket.
+ * Linux handles this safely, but beware when porting this program.
+ *
+ * An alternative to needing 'root' is using a UDP broadcast socket, however
+ * doing so only works with adapters configured for unicast+broadcast Rx
+ * filter. That configuration consumes more power.
+*/
+
+
+#include <netpacket/packet.h>
+#include <net/ethernet.h>
+#include <netinet/ether.h>
+#include <linux/if.h>
+
+#include "libbb.h"
+
+/* Note: PF_INET, SOCK_DGRAM, IPPROTO_UDP would allow SIOCGIFHWADDR to
+ * work as non-root, but we need SOCK_PACKET to specify the Ethernet
+ * destination address.
+ */
+#ifdef PF_PACKET
+# define whereto_t sockaddr_ll
+# define make_socket() xsocket(PF_PACKET, SOCK_RAW, 0)
+#else
+# define whereto_t sockaddr
+# define make_socket() xsocket(AF_INET, SOCK_PACKET, SOCK_PACKET)
+#endif
+
+#ifdef DEBUG
+# define bb_debug_msg(fmt, args...) fprintf(stderr, fmt, ## args)
+void bb_debug_dump_packet(unsigned char *outpack, int pktsize)
+{
+ int i;
+ printf("packet dump:\n");
+ for (i = 0; i < pktsize; ++i) {
+ printf("%2.2x ", outpack[i]);
+ if (i % 20 == 19) bb_putchar('\n');
+ }
+ printf("\n\n");
+}
+#else
+# define bb_debug_msg(fmt, args...) ((void)0)
+# define bb_debug_dump_packet(outpack, pktsize) ((void)0)
+#endif
+
+/* Convert the host ID string to a MAC address.
+ * The string may be a:
+ * Host name
+ * IP address string
+ * MAC address string
+*/
+static void get_dest_addr(const char *hostid, struct ether_addr *eaddr)
+{
+ struct ether_addr *eap;
+
+ eap = ether_aton(hostid);
+ if (eap) {
+ *eaddr = *eap;
+ bb_debug_msg("The target station address is %s\n\n", ether_ntoa(eaddr));
+#if !defined(__UCLIBC__)
+ } else if (ether_hostton(hostid, eaddr) == 0) {
+ bb_debug_msg("Station address for hostname %s is %s\n\n", hostid, ether_ntoa(eaddr));
+#endif
+ } else
+ bb_show_usage();
+}
+
+static int get_fill(unsigned char *pkt, struct ether_addr *eaddr, int broadcast)
+{
+ int i;
+ unsigned char *station_addr = eaddr->ether_addr_octet;
+
+ memset(pkt, 0xff, 6);
+ if (!broadcast)
+ memcpy(pkt, station_addr, 6);
+ pkt += 6;
+
+ memcpy(pkt, station_addr, 6); /* 6 */
+ pkt += 6;
+
+ *pkt++ = 0x08; /* 12 */ /* Or 0x0806 for ARP, 0x8035 for RARP */
+ *pkt++ = 0x42; /* 13 */
+
+ memset(pkt, 0xff, 6); /* 14 */
+
+ for (i = 0; i < 16; ++i) {
+ pkt += 6;
+ memcpy(pkt, station_addr, 6); /* 20,26,32,... */
+ }
+
+ return 20 + 16*6; /* length of packet */
+}
+
+static int get_wol_pw(const char *ethoptarg, unsigned char *wol_passwd)
+{
+ unsigned passwd[6];
+ int byte_cnt, i;
+
+ /* handle MAC format */
+ byte_cnt = sscanf(ethoptarg, "%2x:%2x:%2x:%2x:%2x:%2x",
+ &passwd[0], &passwd[1], &passwd[2],
+ &passwd[3], &passwd[4], &passwd[5]);
+ /* handle IP format */
+// FIXME: why < 4?? should it be < 6?
+ if (byte_cnt < 4)
+ byte_cnt = sscanf(ethoptarg, "%u.%u.%u.%u",
+ &passwd[0], &passwd[1], &passwd[2], &passwd[3]);
+ if (byte_cnt < 4) {
+ bb_error_msg("cannot read Wake-On-LAN pass");
+ return 0;
+ }
+// TODO: check invalid numbers >255??
+ for (i = 0; i < byte_cnt; ++i)
+ wol_passwd[i] = passwd[i];
+
+ bb_debug_msg("password: %2.2x %2.2x %2.2x %2.2x (%d)\n\n",
+ wol_passwd[0], wol_passwd[1], wol_passwd[2], wol_passwd[3],
+ byte_cnt);
+
+ return byte_cnt;
+}
+
+int ether_wake_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int ether_wake_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ const char *ifname = "eth0";
+ char *pass;
+ unsigned flags;
+ unsigned char wol_passwd[6];
+ int wol_passwd_sz = 0;
+ int s; /* Raw socket */
+ int pktsize;
+ unsigned char outpack[1000];
+
+ struct ether_addr eaddr;
+ struct whereto_t whereto; /* who to wake up */
+
+ /* handle misc user options */
+ opt_complementary = "=1";
+ flags = getopt32(argv, "bi:p:", &ifname, &pass);
+ if (flags & 4) /* -p */
+ wol_passwd_sz = get_wol_pw(pass, wol_passwd);
+ flags &= 1; /* we further interested only in -b [bcast] flag */
+
+ /* create the raw socket */
+ s = make_socket();
+
+ /* now that we have a raw socket we can drop root */
+ /* xsetuid(getuid()); - but save on code size... */
+
+ /* look up the dest mac address */
+ get_dest_addr(argv[optind], &eaddr);
+
+ /* fill out the header of the packet */
+ pktsize = get_fill(outpack, &eaddr, flags /* & 1 OPT_BROADCAST */);
+
+ bb_debug_dump_packet(outpack, pktsize);
+
+ /* Fill in the source address, if possible. */
+#ifdef __linux__
+ {
+ struct ifreq if_hwaddr;
+
+ strncpy(if_hwaddr.ifr_name, ifname, sizeof(if_hwaddr.ifr_name));
+ ioctl_or_perror_and_die(s, SIOCGIFHWADDR, &if_hwaddr, "SIOCGIFHWADDR on %s failed", ifname);
+
+ memcpy(outpack+6, if_hwaddr.ifr_hwaddr.sa_data, 6);
+
+# ifdef DEBUG
+ {
+ unsigned char *hwaddr = if_hwaddr.ifr_hwaddr.sa_data;
+ printf("The hardware address (SIOCGIFHWADDR) of %s is type %d "
+ "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n\n", ifname,
+ if_hwaddr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1],
+ hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
+ }
+# endif
+ }
+#endif /* __linux__ */
+
+ bb_debug_dump_packet(outpack, pktsize);
+
+ /* append the password if specified */
+ if (wol_passwd_sz > 0) {
+ memcpy(outpack+pktsize, wol_passwd, wol_passwd_sz);
+ pktsize += wol_passwd_sz;
+ }
+
+ bb_debug_dump_packet(outpack, pktsize);
+
+ /* This is necessary for broadcasts to work */
+ if (flags /* & 1 OPT_BROADCAST */) {
+ if (setsockopt_broadcast(s) != 0)
+ bb_perror_msg("SO_BROADCAST");
+ }
+
+#if defined(PF_PACKET)
+ {
+ struct ifreq ifr;
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ xioctl(s, SIOCGIFINDEX, &ifr);
+ memset(&whereto, 0, sizeof(whereto));
+ whereto.sll_family = AF_PACKET;
+ whereto.sll_ifindex = ifr.ifr_ifindex;
+ /* The manual page incorrectly claims the address must be filled.
+ We do so because the code may change to match the docs. */
+ whereto.sll_halen = ETH_ALEN;
+ memcpy(whereto.sll_addr, outpack, ETH_ALEN);
+ }
+#else
+ whereto.sa_family = 0;
+ strcpy(whereto.sa_data, ifname);
+#endif
+ xsendto(s, outpack, pktsize, (struct sockaddr *)&whereto, sizeof(whereto));
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close(s);
+ return EXIT_SUCCESS;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/networking/ftpgetput.c b/cleopatre/busybox-1.11.1-spc300/networking/ftpgetput.c
new file mode 100644
index 0000000000..f732d02a47
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/networking/ftpgetput.c
@@ -0,0 +1,325 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * ftpget
+ *
+ * Mini implementation of FTP to retrieve a remote file.
+ *
+ * Copyright (C) 2002 Jeff Angielski, The PTR Group <jeff@theptrgroup.com>
+ * Copyright (C) 2002 Glenn McGrath
+ *
+ * Based on wget.c by Chip Rosenthal Covad Communications
+ * <chip@laserlink.net>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+struct globals {
+ const char *user;
+ const char *password;
+ struct len_and_sockaddr *lsa;
+ FILE *control_stream;
+ int verbose_flag;
+ int do_continue;
+ char buf[1]; /* actually [BUFSZ] */
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+enum { BUFSZ = COMMON_BUFSIZE - offsetof(struct globals, buf) };
+struct BUG_G_too_big {
+ char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
+};
+#define user (G.user )
+#define password (G.password )
+#define lsa (G.lsa )
+#define control_stream (G.control_stream)
+#define verbose_flag (G.verbose_flag )
+#define do_continue (G.do_continue )
+#define buf (G.buf )
+#define INIT_G() do { } while (0)
+
+
+static void ftp_die(const char *msg) ATTRIBUTE_NORETURN;
+static void ftp_die(const char *msg)
+{
+ char *cp = buf; /* buf holds peer's response */
+
+ /* Guard against garbage from remote server */
+ while (*cp >= ' ' && *cp < '\x7f')
+ cp++;
+ *cp = '\0';
+ bb_error_msg_and_die("unexpected server response%s%s: %s",
+ (msg ? " to " : ""), (msg ? msg : ""), buf);
+}
+
+static int ftpcmd(const char *s1, const char *s2)
+{
+ unsigned n;
+
+ if (verbose_flag) {
+ bb_error_msg("cmd %s %s", s1, s2);
+ }
+
+ if (s1) {
+ fprintf(control_stream, (s2 ? "%s %s\r\n" : "%s %s\r\n"+3),
+ s1, s2);
+ fflush(control_stream);
+ }
+
+ do {
+ strcpy(buf, "EOF");
+ if (fgets(buf, BUFSZ - 2, control_stream) == NULL) {
+ ftp_die(NULL);
+ }
+ } while (!isdigit(buf[0]) || buf[3] != ' ');
+
+ buf[3] = '\0';
+ n = xatou(buf);
+ buf[3] = ' ';
+ return n;
+}
+
+static void ftp_login(void)
+{
+ /* Connect to the command socket */
+ control_stream = fdopen(xconnect_stream(lsa), "r+");
+ if (control_stream == NULL) {
+ /* fdopen failed - extremely unlikely */
+ bb_perror_nomsg_and_die();
+ }
+
+ if (ftpcmd(NULL, NULL) != 220) {
+ ftp_die(NULL);
+ }
+
+ /* Login to the server */
+ switch (ftpcmd("USER", user)) {
+ case 230:
+ break;
+ case 331:
+ if (ftpcmd("PASS", password) != 230) {
+ ftp_die("PASS");
+ }
+ break;
+ default:
+ ftp_die("USER");
+ }
+
+ ftpcmd("TYPE I", NULL);
+}
+
+static int xconnect_ftpdata(void)
+{
+ char *buf_ptr;
+ unsigned port_num;
+
+/*
+TODO: PASV command will not work for IPv6. RFC2428 describes
+IPv6-capable "extended PASV" - EPSV.
+
+"EPSV [protocol]" asks server to bind to and listen on a data port
+in specified protocol. Protocol is 1 for IPv4, 2 for IPv6.
+If not specified, defaults to "same as used for control connection".
+If server understood you, it should answer "229 <some text>(|||port|)"
+where "|" are literal pipe chars and "port" is ASCII decimal port#.
+
+There is also an IPv6-capable replacement for PORT (EPRT),
+but we don't need that.
+
+NB: PASV may still work for some servers even over IPv6.
+For example, vsftp happily answers
+"227 Entering Passive Mode (0,0,0,0,n,n)" and proceeds as usual.
+
+TODO2: need to stop ignoring IP address in PASV response.
+*/
+
+ if (ftpcmd("PASV", NULL) != 227) {
+ ftp_die("PASV");
+ }
+
+ /* Response is "NNN garbageN1,N2,N3,N4,P1,P2[)garbage]
+ * Server's IP is N1.N2.N3.N4 (we ignore it)
+ * Server's port for data connection is P1*256+P2 */
+ buf_ptr = strrchr(buf, ')');
+ if (buf_ptr) *buf_ptr = '\0';
+
+ buf_ptr = strrchr(buf, ',');
+ *buf_ptr = '\0';
+ port_num = xatoul_range(buf_ptr + 1, 0, 255);
+
+ buf_ptr = strrchr(buf, ',');
+ *buf_ptr = '\0';
+ port_num += xatoul_range(buf_ptr + 1, 0, 255) * 256;
+
+ set_nport(lsa, htons(port_num));
+ return xconnect_stream(lsa);
+}
+
+static int pump_data_and_QUIT(int from, int to)
+{
+ /* copy the file */
+ if (bb_copyfd_eof(from, to) == -1) {
+ /* error msg is already printed by bb_copyfd_eof */
+ return EXIT_FAILURE;
+ }
+
+ /* close data connection */
+ close(from); /* don't know which one is that, so we close both */
+ close(to);
+
+ /* does server confirm that transfer is finished? */
+ if (ftpcmd(NULL, NULL) != 226) {
+ ftp_die(NULL);
+ }
+ ftpcmd("QUIT", NULL);
+
+ return EXIT_SUCCESS;
+}
+
+#if !ENABLE_FTPGET
+int ftp_receive(const char *local_path, char *server_path);
+#else
+static
+int ftp_receive(const char *local_path, char *server_path)
+{
+ int fd_data;
+ int fd_local = -1;
+ off_t beg_range = 0;
+
+ /* connect to the data socket */
+ fd_data = xconnect_ftpdata();
+
+ if (ftpcmd("SIZE", server_path) != 213) {
+ do_continue = 0;
+ }
+
+ if (LONE_DASH(local_path)) {
+ fd_local = STDOUT_FILENO;
+ do_continue = 0;
+ }
+
+ if (do_continue) {
+ struct stat sbuf;
+ /* lstat would be wrong here! */
+ if (stat(local_path, &sbuf) < 0) {
+ bb_perror_msg_and_die("stat");
+ }
+ if (sbuf.st_size > 0) {
+ beg_range = sbuf.st_size;
+ } else {
+ do_continue = 0;
+ }
+ }
+
+ if (do_continue) {
+ sprintf(buf, "REST %"OFF_FMT"d", beg_range);
+ if (ftpcmd(buf, NULL) != 350) {
+ do_continue = 0;
+ }
+ }
+
+ if (ftpcmd("RETR", server_path) > 150) {
+ ftp_die("RETR");
+ }
+
+ /* create local file _after_ we know that remote file exists */
+ if (fd_local == -1) {
+ fd_local = xopen(local_path,
+ do_continue ? (O_APPEND | O_WRONLY)
+ : (O_CREAT | O_TRUNC | O_WRONLY)
+ );
+ }
+
+ return pump_data_and_QUIT(fd_data, fd_local);
+}
+#endif
+
+#if !ENABLE_FTPPUT
+int ftp_send(const char *server_path, char *local_path);
+#else
+static
+int ftp_send(const char *server_path, char *local_path)
+{
+ int fd_data;
+ int fd_local;
+ int response;
+
+ /* connect to the data socket */
+ fd_data = xconnect_ftpdata();
+
+ /* get the local file */
+ fd_local = STDIN_FILENO;
+ if (NOT_LONE_DASH(local_path))
+ fd_local = xopen(local_path, O_RDONLY);
+
+ response = ftpcmd("STOR", server_path);
+ switch (response) {
+ case 125:
+ case 150:
+ break;
+ default:
+ ftp_die("STOR");
+ }
+
+ return pump_data_and_QUIT(fd_local, fd_data);
+}
+#endif
+
+#if ENABLE_FEATURE_FTPGETPUT_LONG_OPTIONS
+static const char ftpgetput_longopts[] ALIGN1 =
+ "continue\0" Required_argument "c"
+ "verbose\0" No_argument "v"
+ "username\0" Required_argument "u"
+ "password\0" Required_argument "p"
+ "port\0" Required_argument "P"
+ ;
+#endif
+
+int ftpgetput_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int ftpgetput_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ unsigned opt;
+ const char *port = "ftp";
+ /* socket to ftp server */
+
+#if ENABLE_FTPPUT && !ENABLE_FTPGET
+# define ftp_action ftp_send
+#elif ENABLE_FTPGET && !ENABLE_FTPPUT
+# define ftp_action ftp_receive
+#else
+ int (*ftp_action)(const char *, char *) = ftp_send;
+
+ /* Check to see if the command is ftpget or ftput */
+ if (applet_name[3] == 'g') {
+ ftp_action = ftp_receive;
+ }
+#endif
+
+ INIT_G();
+ /* Set default values */
+ user = "anonymous";
+ password = "busybox@";
+
+ /*
+ * Decipher the command line
+ */
+#if ENABLE_FEATURE_FTPGETPUT_LONG_OPTIONS
+ applet_long_options = ftpgetput_longopts;
+#endif
+ opt_complementary = "=3:vv:cc"; /* must have 3 params; -v and -c count */
+ opt = getopt32(argv, "cvu:p:P:", &user, &password, &port,
+ &verbose_flag, &do_continue);
+ argv += optind;
+
+ /* We want to do exactly _one_ DNS lookup, since some
+ * sites (i.e. ftp.us.debian.org) use round-robin DNS
+ * and we want to connect to only one IP... */
+ lsa = xhost2sockaddr(argv[0], bb_lookup_port(port, "tcp", 21));
+ if (verbose_flag) {
+ printf("Connecting to %s (%s)\n", argv[0],
+ xmalloc_sockaddr2dotted(&lsa->u.sa));
+ }
+
+ ftp_login();
+ return ftp_action(argv[1], argv[2]);
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/networking/hostname.c b/cleopatre/busybox-1.11.1-spc300/networking/hostname.c
new file mode 100644
index 0000000000..93cbc961f8
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/networking/hostname.c
@@ -0,0 +1,102 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini hostname implementation for busybox
+ *
+ * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
+ *
+ * adjusted by Erik Andersen <andersen@codepoet.org> to remove
+ * use of long options and GNU getopt. Improved the usage info.
+ *
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+static void do_sethostname(char *s, int isfile)
+{
+ FILE *f;
+
+ if (!s)
+ return;
+ if (!isfile) {
+ if (sethostname(s, strlen(s)) < 0) {
+ if (errno == EPERM)
+ bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
+ bb_perror_msg_and_die("sethostname");
+ }
+ } else {
+ f = xfopen(s, "r");
+#define strbuf bb_common_bufsiz1
+ while (fgets(strbuf, sizeof(strbuf), f) != NULL) {
+ if (strbuf[0] == '#') {
+ continue;
+ }
+ chomp(strbuf);
+ do_sethostname(strbuf, 0);
+ }
+ if (ENABLE_FEATURE_CLEAN_UP)
+ fclose(f);
+ }
+}
+
+int hostname_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int hostname_main(int argc, char **argv)
+{
+ enum {
+ OPT_d = 0x1,
+ OPT_f = 0x2,
+ OPT_i = 0x4,
+ OPT_s = 0x8,
+ OPT_F = 0x10,
+ OPT_dfis = 0xf,
+ };
+
+ char *buf;
+ char *hostname_str;
+
+ if (argc < 1)
+ bb_show_usage();
+
+ getopt32(argv, "dfisF:", &hostname_str);
+ argv += optind;
+ buf = safe_gethostname();
+
+ /* Output in desired format */
+ if (option_mask32 & OPT_dfis) {
+ struct hostent *hp;
+ char *p;
+ hp = xgethostbyname(buf);
+ p = strchr(hp->h_name, '.');
+ if (option_mask32 & OPT_f) {
+ puts(hp->h_name);
+ } else if (option_mask32 & OPT_s) {
+ if (p)
+ *p = '\0';
+ puts(hp->h_name);
+ } else if (option_mask32 & OPT_d) {
+ if (p)
+ puts(p + 1);
+ } else if (option_mask32 & OPT_i) {
+ while (hp->h_addr_list[0]) {
+ printf("%s ", inet_ntoa(*(struct in_addr *) (*hp->h_addr_list++)));
+ }
+ bb_putchar('\n');
+ }
+ }
+ /* Set the hostname */
+ else if (option_mask32 & OPT_F) {
+ do_sethostname(hostname_str, 1);
+ } else if (argv[0]) {
+ do_sethostname(argv[0], 0);
+ }
+ /* Or if all else fails,
+ * just print the current hostname */
+ else {
+ puts(buf);
+ }
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(buf);
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/networking/httpd.c b/cleopatre/busybox-1.11.1-spc300/networking/httpd.c
new file mode 100644
index 0000000000..9b4b7172d7
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/networking/httpd.c
@@ -0,0 +1,2411 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * httpd implementation for busybox
+ *
+ * Copyright (C) 2002,2003 Glenn Engel <glenne@engel.org>
+ * Copyright (C) 2003-2006 Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * simplify patch stolen from libbb without using strdup
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ *****************************************************************************
+ *
+ * Typical usage:
+ * for non root user
+ * httpd -p 8080 -h $HOME/public_html
+ * or for daemon start from rc script with uid=0:
+ * httpd -u www
+ * This is equivalent if www user have uid=80 to
+ * httpd -p 80 -u 80 -h /www -c /etc/httpd.conf -r "Web Server Authentication"
+ *
+ *
+ * When a url starts by "/cgi-bin/" it is assumed to be a cgi script. The
+ * server changes directory to the location of the script and executes it
+ * after setting QUERY_STRING and other environment variables.
+ *
+ * Doc:
+ * "CGI Environment Variables": http://hoohoo.ncsa.uiuc.edu/cgi/env.html
+ *
+ * The applet can also be invoked as a url arg decoder and html text encoder
+ * as follows:
+ * foo=`httpd -d $foo` # decode "Hello%20World" as "Hello World"
+ * bar=`httpd -e "<Hello World>"` # encode as "&#60Hello&#32World&#62"
+ * Note that url encoding for arguments is not the same as html encoding for
+ * presentation. -d decodes a url-encoded argument while -e encodes in html
+ * for page display.
+ *
+ * httpd.conf has the following format:
+ *
+ * A:172.20. # Allow address from 172.20.0.0/16
+ * A:10.0.0.0/25 # Allow any address from 10.0.0.0-10.0.0.127
+ * A:10.0.0.0/255.255.255.128 # Allow any address that previous set
+ * A:127.0.0.1 # Allow local loopback connections
+ * D:* # Deny from other IP connections
+ * E404:/path/e404.html # /path/e404.html is the 404 (not found) error page
+ * I:index.html # Show index.html when a directory is requested
+ *
+ * P:/url:[http://]hostname[:port]/new/path
+ * # When /urlXXXXXX is requested, reverse proxy
+ * # it to http://hostname[:port]/new/pathXXXXXX
+ *
+ * /cgi-bin:foo:bar # Require user foo, pwd bar on urls starting with /cgi-bin/
+ * /adm:admin:setup # Require user admin, pwd setup on urls starting with /adm/
+ * /adm:toor:PaSsWd # or user toor, pwd PaSsWd on urls starting with /adm/
+ * .au:audio/basic # additional mime type for audio.au files
+ * *.php:/path/php # running cgi.php scripts through an interpreter
+ *
+ * A/D may be as a/d or allow/deny - only first char matters.
+ * Deny/Allow IP logic:
+ * - Default is to allow all (Allow all (A:*) is a no-op).
+ * - Deny rules take precedence over allow rules.
+ * - "Deny all" rule (D:*) is applied last.
+ *
+ * Example:
+ * 1. Allow only specified addresses
+ * A:172.20 # Allow any address that begins with 172.20.
+ * A:10.10. # Allow any address that begins with 10.10.
+ * A:127.0.0.1 # Allow local loopback connections
+ * D:* # Deny from other IP connections
+ *
+ * 2. Only deny specified addresses
+ * D:1.2.3. # deny from 1.2.3.0 - 1.2.3.255
+ * D:2.3.4. # deny from 2.3.4.0 - 2.3.4.255
+ * A:* # (optional line added for clarity)
+ *
+ * If a sub directory contains a config file it is parsed and merged with
+ * any existing settings as if it was appended to the original configuration.
+ *
+ * subdir paths are relative to the containing subdir and thus cannot
+ * affect the parent rules.
+ *
+ * Note that since the sub dir is parsed in the forked thread servicing the
+ * subdir http request, any merge is discarded when the process exits. As a
+ * result, the subdir settings only have a lifetime of a single request.
+ *
+ * Custom error pages can contain an absolute path or be relative to
+ * 'home_httpd'. Error pages are to be static files (no CGI or script). Error
+ * page can only be defined in the root configuration file and are not taken
+ * into account in local (directories) config files.
+ *
+ * If -c is not set, an attempt will be made to open the default
+ * root configuration file. If -c is set and the file is not found, the
+ * server exits with an error.
+ *
+ */
+
+#include "libbb.h"
+#if ENABLE_FEATURE_HTTPD_USE_SENDFILE
+#include <sys/sendfile.h>
+#endif
+
+//#define DEBUG 1
+#define DEBUG 0
+
+#define IOBUF_SIZE 8192 /* IO buffer */
+
+/* amount of buffering in a pipe */
+#ifndef PIPE_BUF
+# define PIPE_BUF 4096
+#endif
+#if PIPE_BUF >= IOBUF_SIZE
+# error "PIPE_BUF >= IOBUF_SIZE"
+#endif
+
+#define HEADER_READ_TIMEOUT 60
+
+static const char default_path_httpd_conf[] ALIGN1 = "/etc";
+static const char httpd_conf[] ALIGN1 = "httpd.conf";
+static const char HTTP_200[] ALIGN1 = "HTTP/1.0 200 OK\r\n";
+
+typedef struct has_next_ptr {
+ struct has_next_ptr *next;
+} has_next_ptr;
+
+/* Must have "next" as a first member */
+typedef struct Htaccess {
+ struct Htaccess *next;
+ char *after_colon;
+ char before_colon[1]; /* really bigger, must be last */
+} Htaccess;
+
+/* Must have "next" as a first member */
+typedef struct Htaccess_IP {
+ struct Htaccess_IP *next;
+ unsigned ip;
+ unsigned mask;
+ int allow_deny;
+} Htaccess_IP;
+
+/* Must have "next" as a first member */
+typedef struct Htaccess_Proxy {
+ struct Htaccess_Proxy *next;
+ char *url_from;
+ char *host_port;
+ char *url_to;
+} Htaccess_Proxy;
+
+enum {
+ HTTP_OK = 200,
+ HTTP_PARTIAL_CONTENT = 206,
+ HTTP_MOVED_TEMPORARILY = 302,
+ HTTP_BAD_REQUEST = 400, /* malformed syntax */
+ HTTP_UNAUTHORIZED = 401, /* authentication needed, respond with auth hdr */
+ HTTP_NOT_FOUND = 404,
+ HTTP_FORBIDDEN = 403,
+ HTTP_REQUEST_TIMEOUT = 408,
+ HTTP_NOT_IMPLEMENTED = 501, /* used for unrecognized requests */
+ HTTP_INTERNAL_SERVER_ERROR = 500,
+ HTTP_CONTINUE = 100,
+#if 0 /* future use */
+ HTTP_SWITCHING_PROTOCOLS = 101,
+ HTTP_CREATED = 201,
+ HTTP_ACCEPTED = 202,
+ HTTP_NON_AUTHORITATIVE_INFO = 203,
+ HTTP_NO_CONTENT = 204,
+ HTTP_MULTIPLE_CHOICES = 300,
+ HTTP_MOVED_PERMANENTLY = 301,
+ HTTP_NOT_MODIFIED = 304,
+ HTTP_PAYMENT_REQUIRED = 402,
+ HTTP_BAD_GATEWAY = 502,
+ HTTP_SERVICE_UNAVAILABLE = 503, /* overload, maintenance */
+ HTTP_RESPONSE_SETSIZE = 0xffffffff
+#endif
+};
+
+static const uint16_t http_response_type[] ALIGN2 = {
+ HTTP_OK,
+#if ENABLE_FEATURE_HTTPD_RANGES
+ HTTP_PARTIAL_CONTENT,
+#endif
+ HTTP_MOVED_TEMPORARILY,
+ HTTP_REQUEST_TIMEOUT,
+ HTTP_NOT_IMPLEMENTED,
+#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
+ HTTP_UNAUTHORIZED,
+#endif
+ HTTP_NOT_FOUND,
+ HTTP_BAD_REQUEST,
+ HTTP_FORBIDDEN,
+ HTTP_INTERNAL_SERVER_ERROR,
+#if 0 /* not implemented */
+ HTTP_CREATED,
+ HTTP_ACCEPTED,
+ HTTP_NO_CONTENT,
+ HTTP_MULTIPLE_CHOICES,
+ HTTP_MOVED_PERMANENTLY,
+ HTTP_NOT_MODIFIED,
+ HTTP_BAD_GATEWAY,
+ HTTP_SERVICE_UNAVAILABLE,
+#endif
+};
+
+static const struct {
+ const char *name;
+ const char *info;
+} http_response[ARRAY_SIZE(http_response_type)] = {
+ { "OK", NULL },
+#if ENABLE_FEATURE_HTTPD_RANGES
+ { "Partial Content", NULL },
+#endif
+ { "Found", NULL },
+ { "Request Timeout", "No request appeared within 60 seconds" },
+ { "Not Implemented", "The requested method is not recognized" },
+#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
+ { "Unauthorized", "" },
+#endif
+ { "Not Found", "The requested URL was not found" },
+ { "Bad Request", "Unsupported method" },
+ { "Forbidden", "" },
+ { "Internal Server Error", "Internal Server Error" },
+#if 0 /* not implemented */
+ { "Created" },
+ { "Accepted" },
+ { "No Content" },
+ { "Multiple Choices" },
+ { "Moved Permanently" },
+ { "Not Modified" },
+ { "Bad Gateway", "" },
+ { "Service Unavailable", "" },
+#endif
+};
+
+
+struct globals {
+ int verbose; /* must be int (used by getopt32) */
+ smallint flg_deny_all;
+
+ unsigned rmt_ip; /* used for IP-based allow/deny rules */
+ time_t last_mod;
+ char *rmt_ip_str; /* for $REMOTE_ADDR and $REMOTE_PORT */
+ const char *bind_addr_or_port;
+
+ const char *g_query;
+ const char *configFile;
+ const char *home_httpd;
+ const char *index_page;
+
+ const char *found_mime_type;
+ const char *found_moved_temporarily;
+ Htaccess_IP *ip_a_d; /* config allow/deny lines */
+
+ USE_FEATURE_HTTPD_BASIC_AUTH(const char *g_realm;)
+ USE_FEATURE_HTTPD_BASIC_AUTH(char *remoteuser;)
+ USE_FEATURE_HTTPD_CGI(char *referer;)
+ USE_FEATURE_HTTPD_CGI(char *user_agent;)
+
+ off_t file_size; /* -1 - unknown */
+#if ENABLE_FEATURE_HTTPD_RANGES
+ off_t range_start;
+ off_t range_end;
+ off_t range_len;
+#endif
+
+#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
+ Htaccess *g_auth; /* config user:password lines */
+#endif
+#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
+ Htaccess *mime_a; /* config mime types */
+#endif
+#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
+ Htaccess *script_i; /* config script interpreters */
+#endif
+ char *iobuf; /* [IOBUF_SIZE] */
+#define hdr_buf bb_common_bufsiz1
+ char *hdr_ptr;
+ int hdr_cnt;
+#if ENABLE_FEATURE_HTTPD_ERROR_PAGES
+ const char *http_error_page[ARRAY_SIZE(http_response_type)];
+#endif
+#if ENABLE_FEATURE_HTTPD_PROXY
+ Htaccess_Proxy *proxy;
+#endif
+};
+#define G (*ptr_to_globals)
+#define verbose (G.verbose )
+#define flg_deny_all (G.flg_deny_all )
+#define rmt_ip (G.rmt_ip )
+#define bind_addr_or_port (G.bind_addr_or_port)
+#define g_query (G.g_query )
+#define configFile (G.configFile )
+#define home_httpd (G.home_httpd )
+#define index_page (G.index_page )
+#define found_mime_type (G.found_mime_type )
+#define found_moved_temporarily (G.found_moved_temporarily)
+#define last_mod (G.last_mod )
+#define ip_a_d (G.ip_a_d )
+#define g_realm (G.g_realm )
+#define remoteuser (G.remoteuser )
+#define referer (G.referer )
+#define user_agent (G.user_agent )
+#define file_size (G.file_size )
+#if ENABLE_FEATURE_HTTPD_RANGES
+#define range_start (G.range_start )
+#define range_end (G.range_end )
+#define range_len (G.range_len )
+#endif
+#define rmt_ip_str (G.rmt_ip_str )
+#define g_auth (G.g_auth )
+#define mime_a (G.mime_a )
+#define script_i (G.script_i )
+#define iobuf (G.iobuf )
+#define hdr_ptr (G.hdr_ptr )
+#define hdr_cnt (G.hdr_cnt )
+#define http_error_page (G.http_error_page )
+#define proxy (G.proxy )
+#define INIT_G() do { \
+ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
+ USE_FEATURE_HTTPD_BASIC_AUTH(g_realm = "Web Server Authentication";) \
+ bind_addr_or_port = "80"; \
+ index_page = "index.html"; \
+ file_size = -1; \
+} while (0)
+
+#if !ENABLE_FEATURE_HTTPD_RANGES
+enum {
+ range_start = 0,
+ range_end = MAXINT(off_t) - 1,
+ range_len = MAXINT(off_t),
+};
+#endif
+
+
+#define STRNCASECMP(a, str) strncasecmp((a), (str), sizeof(str)-1)
+
+/* Prototypes */
+enum {
+ SEND_HEADERS = (1 << 0),
+ SEND_BODY = (1 << 1),
+ SEND_HEADERS_AND_BODY = SEND_HEADERS + SEND_BODY,
+};
+static void send_file_and_exit(const char *url, int what) ATTRIBUTE_NORETURN;
+
+static void free_llist(has_next_ptr **pptr)
+{
+ has_next_ptr *cur = *pptr;
+ while (cur) {
+ has_next_ptr *t = cur;
+ cur = cur->next;
+ free(t);
+ }
+ *pptr = NULL;
+}
+
+#if ENABLE_FEATURE_HTTPD_BASIC_AUTH \
+ || ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \
+ || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
+static ALWAYS_INLINE void free_Htaccess_list(Htaccess **pptr)
+{
+ free_llist((has_next_ptr**)pptr);
+}
+#endif
+
+static ALWAYS_INLINE void free_Htaccess_IP_list(Htaccess_IP **pptr)
+{
+ free_llist((has_next_ptr**)pptr);
+}
+
+/* Returns presumed mask width in bits or < 0 on error.
+ * Updates strp, stores IP at provided pointer */
+static int scan_ip(const char **strp, unsigned *ipp, unsigned char endc)
+{
+ const char *p = *strp;
+ int auto_mask = 8;
+ unsigned ip = 0;
+ int j;
+
+ if (*p == '/')
+ return -auto_mask;
+
+ for (j = 0; j < 4; j++) {
+ unsigned octet;
+
+ if ((*p < '0' || *p > '9') && *p != '/' && *p)
+ return -auto_mask;
+ octet = 0;
+ while (*p >= '0' && *p <= '9') {
+ octet *= 10;
+ octet += *p - '0';
+ if (octet > 255)
+ return -auto_mask;
+ p++;
+ }
+ if (*p == '.')
+ p++;
+ if (*p != '/' && *p)
+ auto_mask += 8;
+ ip = (ip << 8) | octet;
+ }
+ if (*p) {
+ if (*p != endc)
+ return -auto_mask;
+ p++;
+ if (*p == '\0')
+ return -auto_mask;
+ }
+ *ipp = ip;
+ *strp = p;
+ return auto_mask;
+}
+
+/* Returns 0 on success. Stores IP and mask at provided pointers */
+static int scan_ip_mask(const char *str, unsigned *ipp, unsigned *maskp)
+{
+ int i;
+ unsigned mask;
+ char *p;
+
+ i = scan_ip(&str, ipp, '/');
+ if (i < 0)
+ return i;
+
+ if (*str) {
+ /* there is /xxx after dotted-IP address */
+ i = bb_strtou(str, &p, 10);
+ if (*p == '.') {
+ /* 'xxx' itself is dotted-IP mask, parse it */
+ /* (return 0 (success) only if it has N.N.N.N form) */
+ return scan_ip(&str, maskp, '\0') - 32;
+ }
+ if (*p)
+ return -1;
+ }
+
+ if (i > 32)
+ return -1;
+
+ if (sizeof(unsigned) == 4 && i == 32) {
+ /* mask >>= 32 below may not work */
+ mask = 0;
+ } else {
+ mask = 0xffffffff;
+ mask >>= i;
+ }
+ /* i == 0 -> *maskp = 0x00000000
+ * i == 1 -> *maskp = 0x80000000
+ * i == 4 -> *maskp = 0xf0000000
+ * i == 31 -> *maskp = 0xfffffffe
+ * i == 32 -> *maskp = 0xffffffff */
+ *maskp = (uint32_t)(~mask);
+ return 0;
+}
+
+/*
+ * Parse configuration file into in-memory linked list.
+ *
+ * The first non-white character is examined to determine if the config line
+ * is one of the following:
+ * .ext:mime/type # new mime type not compiled into httpd
+ * [adAD]:from # ip address allow/deny, * for wildcard
+ * /path:user:pass # username/password
+ * Ennn:error.html # error page for status nnn
+ * P:/url:[http://]hostname[:port]/new/path # reverse proxy
+ *
+ * Any previous IP rules are discarded.
+ * If the flag argument is not SUBDIR_PARSE then all /path and mime rules
+ * are also discarded. That is, previous settings are retained if flag is
+ * SUBDIR_PARSE.
+ * Error pages are only parsed on the main config file.
+ *
+ * path Path where to look for httpd.conf (without filename).
+ * flag Type of the parse request.
+ */
+/* flag */
+#define FIRST_PARSE 0
+#define SUBDIR_PARSE 1
+#define SIGNALED_PARSE 2
+#define FIND_FROM_HTTPD_ROOT 3
+static void parse_conf(const char *path, int flag)
+{
+ FILE *f;
+#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
+ Htaccess *prev;
+#endif
+#if ENABLE_FEATURE_HTTPD_BASIC_AUTH \
+ || ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \
+ || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
+ Htaccess *cur;
+#endif
+ const char *filename = configFile;
+ char buf[160];
+ char *p, *p0;
+ char *after_colon;
+ Htaccess_IP *pip;
+
+ /* discard old rules */
+ free_Htaccess_IP_list(&ip_a_d);
+ flg_deny_all = 0;
+#if ENABLE_FEATURE_HTTPD_BASIC_AUTH \
+ || ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \
+ || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
+ /* retain previous auth and mime config only for subdir parse */
+ if (flag != SUBDIR_PARSE) {
+#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
+ free_Htaccess_list(&g_auth);
+#endif
+#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
+ free_Htaccess_list(&mime_a);
+#endif
+#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
+ free_Htaccess_list(&script_i);
+#endif
+ }
+#endif
+
+ if (flag == SUBDIR_PARSE || filename == NULL) {
+ filename = alloca(strlen(path) + sizeof(httpd_conf) + 2);
+ sprintf((char *)filename, "%s/%s", path, httpd_conf);
+ }
+
+ while ((f = fopen(filename, "r")) == NULL) {
+ if (flag == SUBDIR_PARSE || flag == FIND_FROM_HTTPD_ROOT) {
+ /* config file not found, no changes to config */
+ return;
+ }
+ if (configFile && flag == FIRST_PARSE) /* if -c option given */
+ bb_simple_perror_msg_and_die(filename);
+ flag = FIND_FROM_HTTPD_ROOT;
+ filename = httpd_conf;
+ }
+
+#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
+ prev = g_auth;
+#endif
+ /* This could stand some work */
+ while ((p0 = fgets(buf, sizeof(buf), f)) != NULL) {
+ after_colon = NULL;
+ for (p = p0; *p0 != '\0' && *p0 != '#'; p0++) {
+ if (!isspace(*p0)) {
+ *p++ = *p0;
+ if (*p0 == ':' && after_colon == NULL)
+ after_colon = p;
+ }
+ }
+ *p = '\0';
+
+ /* test for empty or strange line */
+ if (after_colon == NULL || *after_colon == '\0')
+ continue;
+ p0 = buf;
+ if (*p0 == 'd' || *p0 == 'a')
+ *p0 -= 0x20; /* a/d -> A/D */
+ if (*after_colon == '*') {
+ if (*p0 == 'D') {
+ /* memorize "deny all" */
+ flg_deny_all = 1;
+ }
+ /* skip assumed "A:*", it is a default anyway */
+ continue;
+ }
+
+ if (*p0 == 'A' || *p0 == 'D') {
+ /* storing current config IP line */
+ pip = xzalloc(sizeof(Htaccess_IP));
+ if (scan_ip_mask(after_colon, &(pip->ip), &(pip->mask))) {
+ /* IP{/mask} syntax error detected, protect all */
+ *p0 = 'D';
+ pip->mask = 0;
+ }
+ pip->allow_deny = *p0;
+ if (*p0 == 'D') {
+ /* Deny:from_IP - prepend */
+ pip->next = ip_a_d;
+ ip_a_d = pip;
+ } else {
+ /* A:from_IP - append (thus D precedes A) */
+ Htaccess_IP *prev_IP = ip_a_d;
+ if (prev_IP == NULL) {
+ ip_a_d = pip;
+ } else {
+ while (prev_IP->next)
+ prev_IP = prev_IP->next;
+ prev_IP->next = pip;
+ }
+ }
+ continue;
+ }
+
+#if ENABLE_FEATURE_HTTPD_ERROR_PAGES
+ if (flag == FIRST_PARSE && *p0 == 'E') {
+ unsigned i;
+ int status = atoi(++p0); /* error status code */
+ if (status < HTTP_CONTINUE) {
+ bb_error_msg("config error '%s' in '%s'", buf, filename);
+ continue;
+ }
+ /* then error page; find matching status */
+ for (i = 0; i < ARRAY_SIZE(http_response_type); i++) {
+ if (http_response_type[i] == status) {
+ /* We chdir to home_httpd, thus no need to
+ * concat_path_file(home_httpd, after_colon)
+ * here */
+ http_error_page[i] = xstrdup(after_colon);
+ break;
+ }
+ }
+ continue;
+ }
+#endif
+
+#if ENABLE_FEATURE_HTTPD_PROXY
+ if (flag == FIRST_PARSE && *p0 == 'P') {
+ /* P:/url:[http://]hostname[:port]/new/path */
+ char *url_from, *host_port, *url_to;
+ Htaccess_Proxy *proxy_entry;
+
+ url_from = after_colon;
+ host_port = strchr(after_colon, ':');
+ if (host_port == NULL) {
+ bb_error_msg("config error '%s' in '%s'", buf, filename);
+ continue;
+ }
+ *host_port++ = '\0';
+ if (strncmp(host_port, "http://", 7) == 0)
+ host_port += 7;
+ if (*host_port == '\0') {
+ bb_error_msg("config error '%s' in '%s'", buf, filename);
+ continue;
+ }
+ url_to = strchr(host_port, '/');
+ if (url_to == NULL) {
+ bb_error_msg("config error '%s' in '%s'", buf, filename);
+ continue;
+ }
+ *url_to = '\0';
+ proxy_entry = xzalloc(sizeof(Htaccess_Proxy));
+ proxy_entry->url_from = xstrdup(url_from);
+ proxy_entry->host_port = xstrdup(host_port);
+ *url_to = '/';
+ proxy_entry->url_to = xstrdup(url_to);
+ proxy_entry->next = proxy;
+ proxy = proxy_entry;
+ continue;
+ }
+#endif
+
+#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
+ if (*p0 == '/') {
+ /* make full path from httpd root / current_path / config_line_path */
+ const char *tp = (flag == SUBDIR_PARSE ? path : "");
+ p0 = xmalloc(strlen(tp) + (after_colon - buf) + 2 + strlen(after_colon));
+ after_colon[-1] = '\0';
+ sprintf(p0, "/%s%s", tp, buf);
+
+ /* looks like bb_simplify_path... */
+ tp = p = p0;
+ do {
+ if (*p == '/') {
+ if (*tp == '/') { /* skip duplicate (or initial) slash */
+ continue;
+ }
+ if (*tp == '.') {
+ if (tp[1] == '/' || tp[1] == '\0') { /* remove extra '.' */
+ continue;
+ }
+ if ((tp[1] == '.') && (tp[2] == '/' || tp[2] == '\0')) {
+ ++tp;
+ if (p > p0) {
+ while (*--p != '/') /* omit previous dir */
+ continue;
+ }
+ continue;
+ }
+ }
+ }
+ *++p = *tp;
+ } while (*++tp);
+
+ if ((p == p0) || (*p != '/')) { /* not a trailing slash */
+ ++p; /* so keep last character */
+ }
+ *p = ':';
+ strcpy(p + 1, after_colon);
+ }
+#endif
+ if (*p0 == 'I') {
+ index_page = xstrdup(after_colon);
+ continue;
+ }
+
+#if ENABLE_FEATURE_HTTPD_BASIC_AUTH \
+ || ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \
+ || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
+ /* storing current config line */
+ cur = xzalloc(sizeof(Htaccess) + strlen(p0));
+ strcpy(cur->before_colon, p0);
+#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
+ if (*p0 == '/') /* was malloced - see above */
+ free(p0);
+#endif
+ cur->after_colon = strchr(cur->before_colon, ':');
+ *cur->after_colon++ = '\0';
+#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
+ if (cur->before_colon[0] == '.') {
+ /* .mime line: prepend to mime_a list */
+ cur->next = mime_a;
+ mime_a = cur;
+ continue;
+ }
+#endif
+#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
+ if (cur->before_colon[0] == '*' && cur->before_colon[1] == '.') {
+ /* script interpreter line: prepend to script_i list */
+ cur->next = script_i;
+ script_i = cur;
+ continue;
+ }
+#endif
+#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
+//TODO: we do not test for leading "/"??
+//also, do we leak cur if BASIC_AUTH is off?
+ if (prev == NULL) {
+ /* first line */
+ g_auth = prev = cur;
+ } else {
+ /* sort path, if current length eq or bigger then move up */
+ Htaccess *prev_hti = g_auth;
+ size_t l = strlen(cur->before_colon);
+ Htaccess *hti;
+
+ for (hti = prev_hti; hti; hti = hti->next) {
+ if (l >= strlen(hti->before_colon)) {
+ /* insert before hti */
+ cur->next = hti;
+ if (prev_hti != hti) {
+ prev_hti->next = cur;
+ } else {
+ /* insert as top */
+ g_auth = cur;
+ }
+ break;
+ }
+ if (prev_hti != hti)
+ prev_hti = prev_hti->next;
+ }
+ if (!hti) { /* not inserted, add to bottom */
+ prev->next = cur;
+ prev = cur;
+ }
+ }
+#endif /* BASIC_AUTH */
+#endif /* BASIC_AUTH || MIME_TYPES || SCRIPT_INTERPR */
+ } /* while (fgets) */
+ fclose(f);
+}
+
+#if ENABLE_FEATURE_HTTPD_ENCODE_URL_STR
+/*
+ * Given a string, html-encode special characters.
+ * This is used for the -e command line option to provide an easy way
+ * for scripts to encode result data without confusing browsers. The
+ * returned string pointer is memory allocated by malloc().
+ *
+ * Returns a pointer to the encoded string (malloced).
+ */
+static char *encodeString(const char *string)
+{
+ /* take the simple route and encode everything */
+ /* could possibly scan once to get length. */
+ int len = strlen(string);
+ char *out = xmalloc(len * 6 + 1);
+ char *p = out;
+ char ch;
+
+ while ((ch = *string++)) {
+ /* very simple check for what to encode */
+ if (isalnum(ch))
+ *p++ = ch;
+ else
+ p += sprintf(p, "&#%d;", (unsigned char) ch);
+ }
+ *p = '\0';
+ return out;
+}
+#endif /* FEATURE_HTTPD_ENCODE_URL_STR */
+
+/*
+ * Given a URL encoded string, convert it to plain ascii.
+ * Since decoding always makes strings smaller, the decode is done in-place.
+ * Thus, callers should xstrdup() the argument if they do not want the
+ * argument modified. The return is the original pointer, allowing this
+ * function to be easily used as arguments to other functions.
+ *
+ * string The first string to decode.
+ * option_d 1 if called for httpd -d
+ *
+ * Returns a pointer to the decoded string (same as input).
+ */
+static unsigned hex_to_bin(unsigned char c)
+{
+ unsigned v;
+
+ v = c - '0';
+ if (v <= 9)
+ return v;
+ /* c | 0x20: letters to lower case, non-letters
+ * to (potentially different) non-letters */
+ v = (unsigned)(c | 0x20) - 'a';
+ if (v <= 5)
+ return v + 10;
+ return ~0;
+}
+/* For testing:
+void t(char c) { printf("'%c'(%u) %u\n", c, c, hex_to_bin(c)); }
+int main() { t(0x10); t(0x20); t('0'); t('9'); t('A'); t('F'); t('a'); t('f');
+t('0'-1); t('9'+1); t('A'-1); t('F'+1); t('a'-1); t('f'+1); return 0; }
+*/
+static char *decodeString(char *orig, int option_d)
+{
+ /* note that decoded string is always shorter than original */
+ char *string = orig;
+ char *ptr = string;
+ char c;
+
+ while ((c = *ptr++) != '\0') {
+ unsigned v;
+
+ if (option_d && c == '+') {
+ *string++ = ' ';
+ continue;
+ }
+ if (c != '%') {
+ *string++ = c;
+ continue;
+ }
+ v = hex_to_bin(ptr[0]);
+ if (v > 15) {
+ bad_hex:
+ if (!option_d)
+ return NULL;
+ *string++ = '%';
+ continue;
+ }
+ v = (v * 16) | hex_to_bin(ptr[1]);
+ if (v > 255)
+ goto bad_hex;
+ if (!option_d && (v == '/' || v == '\0')) {
+ /* caller takes it as indication of invalid
+ * (dangerous wrt exploits) chars */
+ return orig + 1;
+ }
+ *string++ = v;
+ ptr += 2;
+ }
+ *string = '\0';
+ return orig;
+}
+
+#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
+/*
+ * Decode a base64 data stream as per rfc1521.
+ * Note that the rfc states that non base64 chars are to be ignored.
+ * Since the decode always results in a shorter size than the input,
+ * it is OK to pass the input arg as an output arg.
+ * Parameter: a pointer to a base64 encoded string.
+ * Decoded data is stored in-place.
+ */
+static void decodeBase64(char *Data)
+{
+ const unsigned char *in = (const unsigned char *)Data;
+ /* The decoded size will be at most 3/4 the size of the encoded */
+ unsigned ch = 0;
+ int i = 0;
+
+ while (*in) {
+ int t = *in++;
+
+ if (t >= '0' && t <= '9')
+ t = t - '0' + 52;
+ else if (t >= 'A' && t <= 'Z')
+ t = t - 'A';
+ else if (t >= 'a' && t <= 'z')
+ t = t - 'a' + 26;
+ else if (t == '+')
+ t = 62;
+ else if (t == '/')
+ t = 63;
+ else if (t == '=')
+ t = 0;
+ else
+ continue;
+
+ ch = (ch << 6) | t;
+ i++;
+ if (i == 4) {
+ *Data++ = (char) (ch >> 16);
+ *Data++ = (char) (ch >> 8);
+ *Data++ = (char) ch;
+ i = 0;
+ }
+ }
+ *Data = '\0';
+}
+#endif
+
+/*
+ * Create a listen server socket on the designated port.
+ */
+static int openServer(void)
+{
+ unsigned n = bb_strtou(bind_addr_or_port, NULL, 10);
+ if (!errno && n && n <= 0xffff)
+ n = create_and_bind_stream_or_die(NULL, n);
+ else
+ n = create_and_bind_stream_or_die(bind_addr_or_port, 80);
+ xlisten(n, 9);
+ return n;
+}
+
+/*
+ * Log the connection closure and exit.
+ */
+static void log_and_exit(void) ATTRIBUTE_NORETURN;
+static void log_and_exit(void)
+{
+ /* Paranoia. IE said to be buggy. It may send some extra data
+ * or be confused by us just exiting without SHUT_WR. Oh well. */
+ shutdown(1, SHUT_WR);
+ /* Why??
+ (this also messes up stdin when user runs httpd -i from terminal)
+ ndelay_on(0);
+ while (read(STDIN_FILENO, iobuf, IOBUF_SIZE) > 0)
+ continue;
+ */
+
+ if (verbose > 2)
+ bb_error_msg("closed");
+ _exit(xfunc_error_retval);
+}
+
+/*
+ * Create and send HTTP response headers.
+ * The arguments are combined and sent as one write operation. Note that
+ * IE will puke big-time if the headers are not sent in one packet and the
+ * second packet is delayed for any reason.
+ * responseNum - the result code to send.
+ */
+static void send_headers(int responseNum)
+{
+ static const char RFC1123FMT[] ALIGN1 = "%a, %d %b %Y %H:%M:%S GMT";
+
+ const char *responseString = "";
+ const char *infoString = NULL;
+ const char *mime_type;
+#if ENABLE_FEATURE_HTTPD_ERROR_PAGES
+ const char *error_page = NULL;
+#endif
+ unsigned i;
+ time_t timer = time(0);
+ char tmp_str[80];
+ int len;
+
+ for (i = 0; i < ARRAY_SIZE(http_response_type); i++) {
+ if (http_response_type[i] == responseNum) {
+ responseString = http_response[i].name;
+ infoString = http_response[i].info;
+#if ENABLE_FEATURE_HTTPD_ERROR_PAGES
+ error_page = http_error_page[i];
+#endif
+ break;
+ }
+ }
+ /* error message is HTML */
+ mime_type = responseNum == HTTP_OK ?
+ found_mime_type : "text/html";
+
+ if (verbose)
+ bb_error_msg("response:%u", responseNum);
+
+ /* emit the current date */
+ strftime(tmp_str, sizeof(tmp_str), RFC1123FMT, gmtime(&timer));
+ len = sprintf(iobuf,
+ "HTTP/1.0 %d %s\r\nContent-type: %s\r\n"
+ "Date: %s\r\nConnection: close\r\n",
+ responseNum, responseString, mime_type, tmp_str);
+
+#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
+ if (responseNum == HTTP_UNAUTHORIZED) {
+ len += sprintf(iobuf + len,
+ "WWW-Authenticate: Basic realm=\"%s\"\r\n",
+ g_realm);
+ }
+#endif
+ if (responseNum == HTTP_MOVED_TEMPORARILY) {
+ len += sprintf(iobuf + len, "Location: %s/%s%s\r\n",
+ found_moved_temporarily,
+ (g_query ? "?" : ""),
+ (g_query ? g_query : ""));
+ }
+
+#if ENABLE_FEATURE_HTTPD_ERROR_PAGES
+ if (error_page && access(error_page, R_OK) == 0) {
+ strcat(iobuf, "\r\n");
+ len += 2;
+
+ if (DEBUG)
+ fprintf(stderr, "headers: '%s'\n", iobuf);
+ full_write(STDOUT_FILENO, iobuf, len);
+ if (DEBUG)
+ fprintf(stderr, "writing error page: '%s'\n", error_page);
+ return send_file_and_exit(error_page, SEND_BODY);
+ }
+#endif
+
+ if (file_size != -1) { /* file */
+ strftime(tmp_str, sizeof(tmp_str), RFC1123FMT, gmtime(&last_mod));
+#if ENABLE_FEATURE_HTTPD_RANGES
+ if (responseNum == HTTP_PARTIAL_CONTENT) {
+ len += sprintf(iobuf + len, "Content-Range: bytes %"OFF_FMT"d-%"OFF_FMT"d/%"OFF_FMT"d\r\n",
+ range_start,
+ range_end,
+ file_size);
+ file_size = range_end - range_start + 1;
+ }
+#endif
+ len += sprintf(iobuf + len,
+#if ENABLE_FEATURE_HTTPD_RANGES
+ "Accept-Ranges: bytes\r\n"
+#endif
+ "Last-Modified: %s\r\n%s %"OFF_FMT"d\r\n",
+ tmp_str,
+ "Content-length:",
+ file_size
+ );
+ }
+ iobuf[len++] = '\r';
+ iobuf[len++] = '\n';
+ if (infoString) {
+ len += sprintf(iobuf + len,
+ "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\n"
+ "<BODY><H1>%d %s</H1>\n%s\n</BODY></HTML>\n",
+ responseNum, responseString,
+ responseNum, responseString, infoString);
+ }
+ if (DEBUG)
+ fprintf(stderr, "headers: '%s'\n", iobuf);
+ if (full_write(STDOUT_FILENO, iobuf, len) != len) {
+ if (verbose > 1)
+ bb_perror_msg("error");
+ log_and_exit();
+ }
+}
+
+static void send_headers_and_exit(int responseNum) ATTRIBUTE_NORETURN;
+static void send_headers_and_exit(int responseNum)
+{
+ send_headers(responseNum);
+ log_and_exit();
+}
+
+/*
+ * Read from the socket until '\n' or EOF. '\r' chars are removed.
+ * '\n' is replaced with NUL.
+ * Return number of characters read or 0 if nothing is read
+ * ('\r' and '\n' are not counted).
+ * Data is returned in iobuf.
+ */
+static int get_line(void)
+{
+ int count = 0;
+ char c;
+
+ while (1) {
+ if (hdr_cnt <= 0) {
+ hdr_cnt = safe_read(STDIN_FILENO, hdr_buf, sizeof(hdr_buf));
+ if (hdr_cnt <= 0)
+ break;
+ hdr_ptr = hdr_buf;
+ }
+ iobuf[count] = c = *hdr_ptr++;
+ hdr_cnt--;
+
+ if (c == '\r')
+ continue;
+ if (c == '\n') {
+ iobuf[count] = '\0';
+ return count;
+ }
+ if (count < (IOBUF_SIZE - 1)) /* check overflow */
+ count++;
+ }
+ return count;
+}
+
+#if ENABLE_FEATURE_HTTPD_CGI || ENABLE_FEATURE_HTTPD_PROXY
+
+/* gcc 4.2.1 fares better with NOINLINE */
+static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post_len) ATTRIBUTE_NORETURN;
+static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post_len)
+{
+ enum { FROM_CGI = 1, TO_CGI = 2 }; /* indexes in pfd[] */
+ struct pollfd pfd[3];
+ int out_cnt; /* we buffer a bit of initial CGI output */
+ int count;
+
+ /* iobuf is used for CGI -> network data,
+ * hdr_buf is for network -> CGI data (POSTDATA) */
+
+ /* If CGI dies, we still want to correctly finish reading its output
+ * and send it to the peer. So please no SIGPIPEs! */
+ signal(SIGPIPE, SIG_IGN);
+
+ // We inconsistently handle a case when more POSTDATA from network
+ // is coming than we expected. We may give *some part* of that
+ // extra data to CGI.
+
+ //if (hdr_cnt > post_len) {
+ // /* We got more POSTDATA from network than we expected */
+ // hdr_cnt = post_len;
+ //}
+ post_len -= hdr_cnt;
+ /* post_len - number of POST bytes not yet read from network */
+
+ /* NB: breaking out of this loop jumps to log_and_exit() */
+ out_cnt = 0;
+ while (1) {
+ memset(pfd, 0, sizeof(pfd));
+
+ pfd[FROM_CGI].fd = fromCgi_rd;
+ pfd[FROM_CGI].events = POLLIN;
+
+ if (toCgi_wr) {
+ pfd[TO_CGI].fd = toCgi_wr;
+ if (hdr_cnt > 0) {
+ pfd[TO_CGI].events = POLLOUT;
+ } else if (post_len > 0) {
+ pfd[0].events = POLLIN;
+ } else {
+ /* post_len <= 0 && hdr_cnt <= 0:
+ * no more POST data to CGI,
+ * let CGI see EOF on CGI's stdin */
+ close(toCgi_wr);
+ toCgi_wr = 0;
+ }
+ }
+
+ /* Now wait on the set of sockets */
+ count = safe_poll(pfd, 3, -1);
+ if (count <= 0) {
+#if 0
+ if (safe_waitpid(pid, &status, WNOHANG) <= 0) {
+ /* Weird. CGI didn't exit and no fd's
+ * are ready, yet poll returned?! */
+ continue;
+ }
+ if (DEBUG && WIFEXITED(status))
+ bb_error_msg("CGI exited, status=%d", WEXITSTATUS(status));
+ if (DEBUG && WIFSIGNALED(status))
+ bb_error_msg("CGI killed, signal=%d", WTERMSIG(status));
+#endif
+ break;
+ }
+
+ if (pfd[TO_CGI].revents) {
+ /* hdr_cnt > 0 here due to the way pfd[TO_CGI].events set */
+ /* Have data from peer and can write to CGI */
+ count = safe_write(toCgi_wr, hdr_ptr, hdr_cnt);
+ /* Doesn't happen, we dont use nonblocking IO here
+ *if (count < 0 && errno == EAGAIN) {
+ * ...
+ *} else */
+ if (count > 0) {
+ hdr_ptr += count;
+ hdr_cnt -= count;
+ } else {
+ /* EOF/broken pipe to CGI, stop piping POST data */
+ hdr_cnt = post_len = 0;
+ }
+ }
+
+ if (pfd[0].revents) {
+ /* post_len > 0 && hdr_cnt == 0 here */
+ /* We expect data, prev data portion is eaten by CGI
+ * and there *is* data to read from the peer
+ * (POSTDATA) */
+ //count = post_len > (int)sizeof(hdr_buf) ? (int)sizeof(hdr_buf) : post_len;
+ //count = safe_read(STDIN_FILENO, hdr_buf, count);
+ count = safe_read(STDIN_FILENO, hdr_buf, sizeof(hdr_buf));
+ if (count > 0) {
+ hdr_cnt = count;
+ hdr_ptr = hdr_buf;
+ post_len -= count;
+ } else {
+ /* no more POST data can be read */
+ post_len = 0;
+ }
+ }
+
+ if (pfd[FROM_CGI].revents) {
+ /* There is something to read from CGI */
+ char *rbuf = iobuf;
+
+ /* Are we still buffering CGI output? */
+ if (out_cnt >= 0) {
+ /* HTTP_200[] has single "\r\n" at the end.
+ * According to http://hoohoo.ncsa.uiuc.edu/cgi/out.html,
+ * CGI scripts MUST send their own header terminated by
+ * empty line, then data. That's why we have only one
+ * <cr><lf> pair here. We will output "200 OK" line
+ * if needed, but CGI still has to provide blank line
+ * between header and body */
+
+ /* Must use safe_read, not full_read, because
+ * CGI may output a few first bytes and then wait
+ * for POSTDATA without closing stdout.
+ * With full_read we may wait here forever. */
+ count = safe_read(fromCgi_rd, rbuf + out_cnt, PIPE_BUF - 8);
+ if (count <= 0) {
+ /* eof (or error) and there was no "HTTP",
+ * so write it, then write received data */
+ if (out_cnt) {
+ full_write(STDOUT_FILENO, HTTP_200, sizeof(HTTP_200)-1);
+ full_write(STDOUT_FILENO, rbuf, out_cnt);
+ }
+ break; /* CGI stdout is closed, exiting */
+ }
+ out_cnt += count;
+ count = 0;
+ /* "Status" header format is: "Status: 302 Redirected\r\n" */
+ if (out_cnt >= 8 && memcmp(rbuf, "Status: ", 8) == 0) {
+ /* send "HTTP/1.0 " */
+ if (full_write(STDOUT_FILENO, HTTP_200, 9) != 9)
+ break;
+ rbuf += 8; /* skip "Status: " */
+ count = out_cnt - 8;
+ out_cnt = -1; /* buffering off */
+ } else if (out_cnt >= 4) {
+ /* Did CGI add "HTTP"? */
+ if (memcmp(rbuf, HTTP_200, 4) != 0) {
+ /* there is no "HTTP", do it ourself */
+ if (full_write(STDOUT_FILENO, HTTP_200, sizeof(HTTP_200)-1) != sizeof(HTTP_200)-1)
+ break;
+ }
+ /* Commented out:
+ if (!strstr(rbuf, "ontent-")) {
+ full_write(s, "Content-type: text/plain\r\n\r\n", 28);
+ }
+ * Counter-example of valid CGI without Content-type:
+ * echo -en "HTTP/1.0 302 Found\r\n"
+ * echo -en "Location: http://www.busybox.net\r\n"
+ * echo -en "\r\n"
+ */
+ count = out_cnt;
+ out_cnt = -1; /* buffering off */
+ }
+ } else {
+ count = safe_read(fromCgi_rd, rbuf, PIPE_BUF);
+ if (count <= 0)
+ break; /* eof (or error) */
+ }
+ if (full_write(STDOUT_FILENO, rbuf, count) != count)
+ break;
+ if (DEBUG)
+ fprintf(stderr, "cgi read %d bytes: '%.*s'\n", count, count, rbuf);
+ } /* if (pfd[FROM_CGI].revents) */
+ } /* while (1) */
+ log_and_exit();
+}
+#endif
+
+#if ENABLE_FEATURE_HTTPD_CGI
+
+static void setenv1(const char *name, const char *value)
+{
+ setenv(name, value ? value : "", 1);
+}
+
+/*
+ * Spawn CGI script, forward CGI's stdin/out <=> network
+ *
+ * Environment variables are set up and the script is invoked with pipes
+ * for stdin/stdout. If a POST is being done the script is fed the POST
+ * data in addition to setting the QUERY_STRING variable (for GETs or POSTs).
+ *
+ * Parameters:
+ * const char *url The requested URL (with leading /).
+ * int post_len Length of the POST body.
+ * const char *cookie For set HTTP_COOKIE.
+ * const char *content_type For set CONTENT_TYPE.
+ */
+static void send_cgi_and_exit(
+ const char *url,
+ const char *request,
+ int post_len,
+ const char *cookie,
+ const char *content_type) ATTRIBUTE_NORETURN;
+static void send_cgi_and_exit(
+ const char *url,
+ const char *request,
+ int post_len,
+ const char *cookie,
+ const char *content_type)
+{
+ struct fd_pair fromCgi; /* CGI -> httpd pipe */
+ struct fd_pair toCgi; /* httpd -> CGI pipe */
+ char *script;
+ int pid;
+
+ /* Make a copy. NB: caller guarantees:
+ * url[0] == '/', url[1] != '/' */
+ url = xstrdup(url);
+
+ /*
+ * We are mucking with environment _first_ and then vfork/exec,
+ * this allows us to use vfork safely. Parent doesn't care about
+ * these environment changes anyway.
+ */
+
+ /* Check for [dirs/]script.cgi/PATH_INFO */
+ script = (char*)url;
+ while ((script = strchr(script + 1, '/')) != NULL) {
+ struct stat sb;
+
+ *script = '\0';
+ if (!is_directory(url + 1, 1, &sb)) {
+ /* not directory, found script.cgi/PATH_INFO */
+ *script = '/';
+ break;
+ }
+ *script = '/'; /* is directory, find next '/' */
+ }
+ setenv1("PATH_INFO", script); /* set to /PATH_INFO or "" */
+ setenv1("REQUEST_METHOD", request);
+ if (g_query) {
+ putenv(xasprintf("%s=%s?%s", "REQUEST_URI", url, g_query));
+ } else {
+ setenv1("REQUEST_URI", url);
+ }
+ if (script != NULL)
+ *script = '\0'; /* cut off /PATH_INFO */
+
+ /* SCRIPT_FILENAME is required by PHP in CGI mode */
+ if (home_httpd[0] == '/') {
+ char *fullpath = concat_path_file(home_httpd, url);
+ setenv1("SCRIPT_FILENAME", fullpath);
+ }
+ /* set SCRIPT_NAME as full path: /cgi-bin/dirs/script.cgi */
+ setenv1("SCRIPT_NAME", url);
+ /* http://hoohoo.ncsa.uiuc.edu/cgi/env.html:
+ * QUERY_STRING: The information which follows the ? in the URL
+ * which referenced this script. This is the query information.
+ * It should not be decoded in any fashion. This variable
+ * should always be set when there is query information,
+ * regardless of command line decoding. */
+ /* (Older versions of bbox seem to do some decoding) */
+ setenv1("QUERY_STRING", g_query);
+ putenv((char*)"SERVER_SOFTWARE=busybox httpd/"BB_VER);
+ putenv((char*)"SERVER_PROTOCOL=HTTP/1.0");
+ putenv((char*)"GATEWAY_INTERFACE=CGI/1.1");
+ /* Having _separate_ variables for IP and port defeats
+ * the purpose of having socket abstraction. Which "port"
+ * are you using on Unix domain socket?
+ * IOW - REMOTE_PEER="1.2.3.4:56" makes much more sense.
+ * Oh well... */
+ {
+ char *p = rmt_ip_str ? rmt_ip_str : (char*)"";
+ char *cp = strrchr(p, ':');
+ if (ENABLE_FEATURE_IPV6 && cp && strchr(cp, ']'))
+ cp = NULL;
+ if (cp) *cp = '\0'; /* delete :PORT */
+ setenv1("REMOTE_ADDR", p);
+ if (cp) {
+ *cp = ':';
+#if ENABLE_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV
+ setenv1("REMOTE_PORT", cp + 1);
+#endif
+ }
+ }
+ setenv1("HTTP_USER_AGENT", user_agent);
+ if (post_len)
+ putenv(xasprintf("CONTENT_LENGTH=%d", post_len));
+ if (cookie)
+ setenv1("HTTP_COOKIE", cookie);
+ if (content_type)
+ setenv1("CONTENT_TYPE", content_type);
+#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
+ if (remoteuser) {
+ setenv1("REMOTE_USER", remoteuser);
+ putenv((char*)"AUTH_TYPE=Basic");
+ }
+#endif
+ if (referer)
+ setenv1("HTTP_REFERER", referer);
+
+ xpiped_pair(fromCgi);
+ xpiped_pair(toCgi);
+
+ pid = vfork();
+ if (pid < 0) {
+ /* TODO: log perror? */
+ log_and_exit();
+ }
+
+ if (!pid) {
+ /* Child process */
+ char *argv[3];
+
+ xfunc_error_retval = 242;
+
+ /* NB: close _first_, then move fds! */
+ close(toCgi.wr);
+ close(fromCgi.rd);
+ xmove_fd(toCgi.rd, 0); /* replace stdin with the pipe */
+ xmove_fd(fromCgi.wr, 1); /* replace stdout with the pipe */
+ /* User seeing stderr output can be a security problem.
+ * If CGI really wants that, it can always do dup itself. */
+ /* dup2(1, 2); */
+
+ /* Chdiring to script's dir */
+ script = strrchr(url, '/');
+ if (script != url) { /* paranoia */
+ *script = '\0';
+ if (chdir(url + 1) != 0) {
+ bb_perror_msg("chdir %s", url + 1);
+ goto error_execing_cgi;
+ }
+ // not needed: *script = '/';
+ }
+ script++;
+
+ /* set argv[0] to name without path */
+ argv[0] = script;
+ argv[1] = NULL;
+
+#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
+ {
+ char *suffix = strrchr(script, '.');
+
+ if (suffix) {
+ Htaccess *cur;
+ for (cur = script_i; cur; cur = cur->next) {
+ if (strcmp(cur->before_colon + 1, suffix) == 0) {
+ /* found interpreter name */
+ argv[0] = cur->after_colon;
+ argv[1] = script;
+ argv[2] = NULL;
+ break;
+ }
+ }
+ }
+ }
+#endif
+ /* restore default signal dispositions for CGI process */
+ bb_signals(0
+ | (1 << SIGCHLD)
+ | (1 << SIGPIPE)
+ | (1 << SIGHUP)
+ , SIG_DFL);
+
+ /* _NOT_ execvp. We do not search PATH. argv[0] is a filename
+ * without any dir components and will only match a file
+ * in the current directory */
+ execv(argv[0], argv);
+ if (verbose)
+ bb_perror_msg("exec %s", argv[0]);
+ error_execing_cgi:
+ /* send to stdout
+ * (we are CGI here, our stdout is pumped to the net) */
+ send_headers_and_exit(HTTP_NOT_FOUND);
+ } /* end child */
+
+ /* Parent process */
+
+ /* Restore variables possibly changed by child */
+ xfunc_error_retval = 0;
+
+ /* Pump data */
+ close(fromCgi.wr);
+ close(toCgi.rd);
+ cgi_io_loop_and_exit(fromCgi.rd, toCgi.wr, post_len);
+}
+
+#endif /* FEATURE_HTTPD_CGI */
+
+/*
+ * Send a file response to a HTTP request, and exit
+ *
+ * Parameters:
+ * const char *url The requested URL (with leading /).
+ * what What to send (headers/body/both).
+ */
+static void send_file_and_exit(const char *url, int what)
+{
+ static const char *const suffixTable[] = {
+ /* Warning: shorter equivalent suffix in one line must be first */
+ ".htm.html", "text/html",
+ ".jpg.jpeg", "image/jpeg",
+ ".gif", "image/gif",
+ ".png", "image/png",
+ ".txt.h.c.cc.cpp", "text/plain",
+ ".css", "text/css",
+ ".wav", "audio/wav",
+ ".avi", "video/x-msvideo",
+ ".qt.mov", "video/quicktime",
+ ".mpe.mpeg", "video/mpeg",
+ ".mid.midi", "audio/midi",
+ ".mp3", "audio/mpeg",
+#if 0 /* unpopular */
+ ".au", "audio/basic",
+ ".pac", "application/x-ns-proxy-autoconfig",
+ ".vrml.wrl", "model/vrml",
+#endif
+ NULL
+ };
+
+ char *suffix;
+ int f;
+ const char *const *table;
+ const char *try_suffix;
+ ssize_t count;
+#if ENABLE_FEATURE_HTTPD_USE_SENDFILE
+ off_t offset;
+#endif
+
+ /* If you want to know about EPIPE below
+ * (happens if you abort downloads from local httpd): */
+ signal(SIGPIPE, SIG_IGN);
+
+ suffix = strrchr(url, '.');
+
+ /* If not found, set default as "application/octet-stream"; */
+ found_mime_type = "application/octet-stream";
+ if (suffix) {
+#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
+ Htaccess *cur;
+#endif
+ for (table = suffixTable; *table; table += 2) {
+ try_suffix = strstr(table[0], suffix);
+ if (try_suffix) {
+ try_suffix += strlen(suffix);
+ if (*try_suffix == '\0' || *try_suffix == '.') {
+ found_mime_type = table[1];
+ break;
+ }
+ }
+ }
+#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
+ for (cur = mime_a; cur; cur = cur->next) {
+ if (strcmp(cur->before_colon, suffix) == 0) {
+ found_mime_type = cur->after_colon;
+ break;
+ }
+ }
+#endif
+ }
+
+ if (DEBUG)
+ bb_error_msg("sending file '%s' content-type: %s",
+ url, found_mime_type);
+
+ f = open(url, O_RDONLY);
+ if (f < 0) {
+ if (DEBUG)
+ bb_perror_msg("cannot open '%s'", url);
+ /* Error pages are sent by using send_file_and_exit(SEND_BODY).
+ * IOW: it is unsafe to call send_headers_and_exit
+ * if what is SEND_BODY! Can recurse! */
+ if (what != SEND_BODY)
+ send_headers_and_exit(HTTP_NOT_FOUND);
+ log_and_exit();
+ }
+#if ENABLE_FEATURE_HTTPD_RANGES
+ if (what == SEND_BODY)
+ range_start = 0; /* err pages and ranges don't mix */
+ range_len = MAXINT(off_t);
+ if (range_start) {
+ if (!range_end) {
+ range_end = file_size - 1;
+ }
+ if (range_end < range_start
+ || lseek(f, range_start, SEEK_SET) != range_start
+ ) {
+ lseek(f, 0, SEEK_SET);
+ range_start = 0;
+ } else {
+ range_len = range_end - range_start + 1;
+ send_headers(HTTP_PARTIAL_CONTENT);
+ what = SEND_BODY;
+ }
+ }
+#endif
+
+ if (what & SEND_HEADERS)
+ send_headers(HTTP_OK);
+
+#if ENABLE_FEATURE_HTTPD_USE_SENDFILE
+ offset = range_start;
+ do {
+ /* sz is rounded down to 64k */
+ ssize_t sz = MAXINT(ssize_t) - 0xffff;
+ USE_FEATURE_HTTPD_RANGES(if (sz > range_len) sz = range_len;)
+ count = sendfile(1, f, &offset, sz);
+ if (count < 0) {
+ if (offset == range_start)
+ goto fallback;
+ goto fin;
+ }
+ USE_FEATURE_HTTPD_RANGES(range_len -= sz;)
+ } while (count > 0 && range_len);
+ log_and_exit();
+
+ fallback:
+#endif
+ while ((count = safe_read(f, iobuf, IOBUF_SIZE)) > 0) {
+ ssize_t n;
+ USE_FEATURE_HTTPD_RANGES(if (count > range_len) count = range_len;)
+ n = full_write(STDOUT_FILENO, iobuf, count);
+ if (count != n)
+ break;
+ USE_FEATURE_HTTPD_RANGES(range_len -= count;)
+ if (!range_len)
+ break;
+ }
+#if ENABLE_FEATURE_HTTPD_USE_SENDFILE
+ fin:
+#endif
+ if (count < 0 && verbose > 1)
+ bb_perror_msg("error");
+ log_and_exit();
+}
+
+static int checkPermIP(void)
+{
+ Htaccess_IP *cur;
+
+ for (cur = ip_a_d; cur; cur = cur->next) {
+#if DEBUG
+ fprintf(stderr,
+ "checkPermIP: '%s' ? '%u.%u.%u.%u/%u.%u.%u.%u'\n",
+ rmt_ip_str,
+ (unsigned char)(cur->ip >> 24),
+ (unsigned char)(cur->ip >> 16),
+ (unsigned char)(cur->ip >> 8),
+ (unsigned char)(cur->ip),
+ (unsigned char)(cur->mask >> 24),
+ (unsigned char)(cur->mask >> 16),
+ (unsigned char)(cur->mask >> 8),
+ (unsigned char)(cur->mask)
+ );
+#endif
+ if ((rmt_ip & cur->mask) == cur->ip)
+ return (cur->allow_deny == 'A'); /* A -> 1 */
+ }
+
+ return !flg_deny_all; /* depends on whether we saw "D:*" */
+}
+
+#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
+/*
+ * Config file entries are of the form "/<path>:<user>:<passwd>".
+ * If config file has no prefix match for path, access is allowed.
+ *
+ * path The file path
+ * user_and_passwd "user:passwd" to validate
+ *
+ * Returns 1 if user_and_passwd is OK.
+ */
+static int check_user_passwd(const char *path, const char *user_and_passwd)
+{
+ Htaccess *cur;
+ const char *prev = NULL;
+
+ for (cur = g_auth; cur; cur = cur->next) {
+ const char *dir_prefix;
+ size_t len;
+
+ dir_prefix = cur->before_colon;
+
+ /* WHY? */
+ /* If already saw a match, don't accept other different matches */
+ if (prev && strcmp(prev, dir_prefix) != 0)
+ continue;
+
+ if (DEBUG)
+ fprintf(stderr, "checkPerm: '%s' ? '%s'\n", dir_prefix, user_and_passwd);
+
+ /* If it's not a prefix match, continue searching */
+ len = strlen(dir_prefix);
+ if (len != 1 /* dir_prefix "/" matches all, don't need to check */
+ && (strncmp(dir_prefix, path, len) != 0
+ || (path[len] != '/' && path[len] != '\0'))
+ ) {
+ continue;
+ }
+
+ /* Path match found */
+ prev = dir_prefix;
+
+ if (ENABLE_FEATURE_HTTPD_AUTH_MD5) {
+ char *md5_passwd;
+
+ md5_passwd = strchr(cur->after_colon, ':');
+ if (md5_passwd && md5_passwd[1] == '$' && md5_passwd[2] == '1'
+ && md5_passwd[3] == '$' && md5_passwd[4]
+ ) {
+ char *encrypted;
+ int r, user_len_p1;
+
+ md5_passwd++;
+ user_len_p1 = md5_passwd - cur->after_colon;
+ /* comparing "user:" */
+ if (strncmp(cur->after_colon, user_and_passwd, user_len_p1) != 0) {
+ continue;
+ }
+
+ encrypted = pw_encrypt(
+ user_and_passwd + user_len_p1 /* cleartext pwd from user */,
+ md5_passwd /*salt */, 1 /* cleanup */);
+ r = strcmp(encrypted, md5_passwd);
+ free(encrypted);
+ if (r == 0)
+ goto set_remoteuser_var; /* Ok */
+ continue;
+ }
+ }
+
+ /* Comparing plaintext "user:pass" in one go */
+ if (strcmp(cur->after_colon, user_and_passwd) == 0) {
+ set_remoteuser_var:
+ remoteuser = xstrndup(user_and_passwd,
+ strchrnul(user_and_passwd, ':') - user_and_passwd);
+ return 1; /* Ok */
+ }
+ } /* for */
+
+ /* 0(bad) if prev is set: matches were found but passwd was wrong */
+ return (prev == NULL);
+}
+#endif /* FEATURE_HTTPD_BASIC_AUTH */
+
+#if ENABLE_FEATURE_HTTPD_PROXY
+static Htaccess_Proxy *find_proxy_entry(const char *url)
+{
+ Htaccess_Proxy *p;
+ for (p = proxy; p; p = p->next) {
+ if (strncmp(url, p->url_from, strlen(p->url_from)) == 0)
+ return p;
+ }
+ return NULL;
+}
+#endif
+
+/*
+ * Handle timeouts
+ */
+static void exit_on_signal(int sig) ATTRIBUTE_NORETURN;
+static void exit_on_signal(int sig ATTRIBUTE_UNUSED)
+{
+ send_headers_and_exit(HTTP_REQUEST_TIMEOUT);
+}
+
+/*
+ * Handle an incoming http request and exit.
+ */
+static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) ATTRIBUTE_NORETURN;
+static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
+{
+ static const char request_GET[] ALIGN1 = "GET";
+ struct stat sb;
+ char *urlcopy;
+ char *urlp;
+ char *tptr;
+#if ENABLE_FEATURE_HTTPD_CGI
+ static const char request_HEAD[] ALIGN1 = "HEAD";
+ const char *prequest;
+ char *cookie = NULL;
+ char *content_type = NULL;
+ unsigned long length = 0;
+#elif ENABLE_FEATURE_HTTPD_PROXY
+#define prequest request_GET
+ unsigned long length = 0;
+#endif
+#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
+ smallint authorized = -1;
+#endif
+ smallint ip_allowed;
+ char http_major_version;
+#if ENABLE_FEATURE_HTTPD_PROXY
+ char http_minor_version;
+ char *header_buf = header_buf; /* for gcc */
+ char *header_ptr = header_ptr;
+ Htaccess_Proxy *proxy_entry;
+#endif
+
+ /* Allocation of iobuf is postponed until now
+ * (IOW, server process doesn't need to waste 8k) */
+ iobuf = xmalloc(IOBUF_SIZE);
+
+ rmt_ip = 0;
+ if (fromAddr->u.sa.sa_family == AF_INET) {
+ rmt_ip = ntohl(fromAddr->u.sin.sin_addr.s_addr);
+ }
+#if ENABLE_FEATURE_IPV6
+ if (fromAddr->u.sa.sa_family == AF_INET6
+ && fromAddr->u.sin6.sin6_addr.s6_addr32[0] == 0
+ && fromAddr->u.sin6.sin6_addr.s6_addr32[1] == 0
+ && ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[2]) == 0xffff)
+ rmt_ip = ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[3]);
+#endif
+ if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) {
+ /* NB: can be NULL (user runs httpd -i by hand?) */
+ rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr->u.sa);
+ }
+ if (verbose) {
+ /* this trick makes -v logging much simpler */
+ if (rmt_ip_str)
+ applet_name = rmt_ip_str;
+ if (verbose > 2)
+ bb_error_msg("connected");
+ }
+
+ /* Install timeout handler */
+ signal_no_SA_RESTART_empty_mask(SIGALRM, exit_on_signal);
+ alarm(HEADER_READ_TIMEOUT);
+
+ if (!get_line()) /* EOF or error or empty line */
+ send_headers_and_exit(HTTP_BAD_REQUEST);
+
+ /* Determine type of request (GET/POST) */
+ urlp = strpbrk(iobuf, " \t");
+ if (urlp == NULL)
+ send_headers_and_exit(HTTP_BAD_REQUEST);
+ *urlp++ = '\0';
+#if ENABLE_FEATURE_HTTPD_CGI
+ prequest = request_GET;
+ if (strcasecmp(iobuf, prequest) != 0) {
+ prequest = request_HEAD;
+ if (strcasecmp(iobuf, prequest) != 0) {
+ prequest = "POST";
+ if (strcasecmp(iobuf, prequest) != 0)
+ send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
+ }
+ }
+#else
+ if (strcasecmp(iobuf, request_GET) != 0)
+ send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
+#endif
+ urlp = skip_whitespace(urlp);
+ if (urlp[0] != '/')
+ send_headers_and_exit(HTTP_BAD_REQUEST);
+
+ /* Find end of URL and parse HTTP version, if any */
+ http_major_version = '0';
+ USE_FEATURE_HTTPD_PROXY(http_minor_version = '0';)
+ tptr = strchrnul(urlp, ' ');
+ /* Is it " HTTP/"? */
+ if (tptr[0] && strncmp(tptr + 1, HTTP_200, 5) == 0) {
+ http_major_version = tptr[6];
+ USE_FEATURE_HTTPD_PROXY(http_minor_version = tptr[8];)
+ }
+ *tptr = '\0';
+
+ /* Copy URL from after "GET "/"POST " to stack-allocated char[] */
+ urlcopy = alloca((tptr - urlp) + 2 + strlen(index_page));
+ /*if (urlcopy == NULL)
+ * send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);*/
+ strcpy(urlcopy, urlp);
+ /* NB: urlcopy ptr is never changed after this */
+
+ /* Extract url args if present */
+ g_query = NULL;
+ tptr = strchr(urlcopy, '?');
+ if (tptr) {
+ *tptr++ = '\0';
+ g_query = tptr;
+ }
+
+ /* Decode URL escape sequences */
+ tptr = decodeString(urlcopy, 0);
+ if (tptr == NULL)
+ send_headers_and_exit(HTTP_BAD_REQUEST);
+ if (tptr == urlcopy + 1) {
+ /* '/' or NUL is encoded */
+ send_headers_and_exit(HTTP_NOT_FOUND);
+ }
+
+ /* Canonicalize path */
+ /* Algorithm stolen from libbb bb_simplify_path(),
+ * but don't strdup, retain trailing slash, protect root */
+ urlp = tptr = urlcopy;
+ do {
+ if (*urlp == '/') {
+ /* skip duplicate (or initial) slash */
+ if (*tptr == '/') {
+ continue;
+ }
+ if (*tptr == '.') {
+ /* skip extra "/./" */
+ if (tptr[1] == '/' || !tptr[1]) {
+ continue;
+ }
+ /* "..": be careful */
+ if (tptr[1] == '.' && (tptr[2] == '/' || !tptr[2])) {
+ ++tptr;
+ if (urlp == urlcopy) /* protect root */
+ send_headers_and_exit(HTTP_BAD_REQUEST);
+ while (*--urlp != '/') /* omit previous dir */;
+ continue;
+ }
+ }
+ }
+ *++urlp = *tptr;
+ } while (*++tptr);
+ *++urlp = '\0'; /* terminate after last character */
+
+ /* If URL is a directory, add '/' */
+ if (urlp[-1] != '/') {
+ if (is_directory(urlcopy + 1, 1, &sb)) {
+ found_moved_temporarily = urlcopy;
+ }
+ }
+
+ /* Log it */
+ if (verbose > 1)
+ bb_error_msg("url:%s", urlcopy);
+
+ tptr = urlcopy;
+ ip_allowed = checkPermIP();
+ while (ip_allowed && (tptr = strchr(tptr + 1, '/')) != NULL) {
+ /* have path1/path2 */
+ *tptr = '\0';
+ if (is_directory(urlcopy + 1, 1, &sb)) {
+ /* may have subdir config */
+ parse_conf(urlcopy + 1, SUBDIR_PARSE);
+ ip_allowed = checkPermIP();
+ }
+ *tptr = '/';
+ }
+
+#if ENABLE_FEATURE_HTTPD_PROXY
+ proxy_entry = find_proxy_entry(urlcopy);
+ if (proxy_entry)
+ header_buf = header_ptr = xmalloc(IOBUF_SIZE);
+#endif
+
+ if (http_major_version >= '0') {
+ /* Request was with "... HTTP/nXXX", and n >= 0 */
+
+ /* Read until blank line for HTTP version specified, else parse immediate */
+ while (1) {
+ alarm(HEADER_READ_TIMEOUT);
+ if (!get_line())
+ break; /* EOF or error or empty line */
+ if (DEBUG)
+ bb_error_msg("header: '%s'", iobuf);
+
+#if ENABLE_FEATURE_HTTPD_PROXY
+ /* We need 2 more bytes for yet another "\r\n" -
+ * see near fdprintf(proxy_fd...) further below */
+ if (proxy_entry && (header_ptr - header_buf) < IOBUF_SIZE - 2) {
+ int len = strlen(iobuf);
+ if (len > IOBUF_SIZE - (header_ptr - header_buf) - 4)
+ len = IOBUF_SIZE - (header_ptr - header_buf) - 4;
+ memcpy(header_ptr, iobuf, len);
+ header_ptr += len;
+ header_ptr[0] = '\r';
+ header_ptr[1] = '\n';
+ header_ptr += 2;
+ }
+#endif
+
+#if ENABLE_FEATURE_HTTPD_CGI || ENABLE_FEATURE_HTTPD_PROXY
+ /* Try and do our best to parse more lines */
+ if ((STRNCASECMP(iobuf, "Content-length:") == 0)) {
+ /* extra read only for POST */
+ if (prequest != request_GET
+#if ENABLE_FEATURE_HTTPD_CGI
+ && prequest != request_HEAD
+#endif
+ ) {
+ tptr = skip_whitespace(iobuf + sizeof("Content-length:") - 1);
+ if (!tptr[0])
+ send_headers_and_exit(HTTP_BAD_REQUEST);
+ /* not using strtoul: it ignores leading minus! */
+ length = bb_strtou(tptr, NULL, 10);
+ /* length is "ulong", but we need to pass it to int later */
+ if (errno || length > INT_MAX)
+ send_headers_and_exit(HTTP_BAD_REQUEST);
+ }
+ }
+#endif
+#if ENABLE_FEATURE_HTTPD_CGI
+ else if (STRNCASECMP(iobuf, "Cookie:") == 0) {
+ cookie = xstrdup(skip_whitespace(iobuf + sizeof("Cookie:")-1));
+ } else if (STRNCASECMP(iobuf, "Content-Type:") == 0) {
+ content_type = xstrdup(skip_whitespace(iobuf + sizeof("Content-Type:")-1));
+ } else if (STRNCASECMP(iobuf, "Referer:") == 0) {
+ referer = xstrdup(skip_whitespace(iobuf + sizeof("Referer:")-1));
+ } else if (STRNCASECMP(iobuf, "User-Agent:") == 0) {
+ user_agent = xstrdup(skip_whitespace(iobuf + sizeof("User-Agent:")-1));
+ }
+#endif
+#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
+ if (STRNCASECMP(iobuf, "Authorization:") == 0) {
+ /* We only allow Basic credentials.
+ * It shows up as "Authorization: Basic <user>:<passwd>" where
+ * "<user>:<passwd>" is base64 encoded.
+ */
+ tptr = skip_whitespace(iobuf + sizeof("Authorization:")-1);
+ if (STRNCASECMP(tptr, "Basic") != 0)
+ continue;
+ tptr += sizeof("Basic")-1;
+ /* decodeBase64() skips whitespace itself */
+ decodeBase64(tptr);
+ authorized = check_user_passwd(urlcopy, tptr);
+ }
+#endif
+#if ENABLE_FEATURE_HTTPD_RANGES
+ if (STRNCASECMP(iobuf, "Range:") == 0) {
+ /* We know only bytes=NNN-[MMM] */
+ char *s = skip_whitespace(iobuf + sizeof("Range:")-1);
+ if (strncmp(s, "bytes=", 6) == 0) {
+ s += sizeof("bytes=")-1;
+ range_start = BB_STRTOOFF(s, &s, 10);
+ if (s[0] != '-' || range_start < 0) {
+ range_start = 0;
+ } else if (s[1]) {
+ range_end = BB_STRTOOFF(s+1, NULL, 10);
+ if (errno || range_end < range_start)
+ range_start = 0;
+ }
+ }
+ }
+#endif
+ } /* while extra header reading */
+ }
+
+ /* We are done reading headers, disable peer timeout */
+ alarm(0);
+
+ if (strcmp(bb_basename(urlcopy), httpd_conf) == 0 || !ip_allowed) {
+ /* protect listing [/path]/httpd_conf or IP deny */
+ send_headers_and_exit(HTTP_FORBIDDEN);
+ }
+
+#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
+ /* Case: no "Authorization:" was seen, but page does require passwd.
+ * Check that with dummy user:pass */
+ if (authorized < 0)
+ authorized = check_user_passwd(urlcopy, ":");
+ if (!authorized)
+ send_headers_and_exit(HTTP_UNAUTHORIZED);
+#endif
+
+ if (found_moved_temporarily) {
+ send_headers_and_exit(HTTP_MOVED_TEMPORARILY);
+ }
+
+#if ENABLE_FEATURE_HTTPD_PROXY
+ if (proxy_entry != NULL) {
+ int proxy_fd;
+ len_and_sockaddr *lsa;
+
+ proxy_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (proxy_fd < 0)
+ send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);
+ lsa = host2sockaddr(proxy_entry->host_port, 80);
+ if (lsa == NULL)
+ send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);
+ if (connect(proxy_fd, &lsa->u.sa, lsa->len) < 0)
+ send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);
+ fdprintf(proxy_fd, "%s %s%s%s%s HTTP/%c.%c\r\n",
+ prequest, /* GET or POST */
+ proxy_entry->url_to, /* url part 1 */
+ urlcopy + strlen(proxy_entry->url_from), /* url part 2 */
+ (g_query ? "?" : ""), /* "?" (maybe) */
+ (g_query ? g_query : ""), /* query string (maybe) */
+ http_major_version, http_minor_version);
+ header_ptr[0] = '\r';
+ header_ptr[1] = '\n';
+ header_ptr += 2;
+ write(proxy_fd, header_buf, header_ptr - header_buf);
+ free(header_buf); /* on the order of 8k, free it */
+ /* cgi_io_loop_and_exit needs to have two disctinct fds */
+ cgi_io_loop_and_exit(proxy_fd, dup(proxy_fd), length);
+ }
+#endif
+
+ tptr = urlcopy + 1; /* skip first '/' */
+
+#if ENABLE_FEATURE_HTTPD_CGI
+ if (strncmp(tptr, "cgi-bin/", 8) == 0) {
+ if (tptr[8] == '\0') {
+ /* protect listing "cgi-bin/" */
+ send_headers_and_exit(HTTP_FORBIDDEN);
+ }
+ send_cgi_and_exit(urlcopy, prequest, length, cookie, content_type);
+ }
+#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
+ {
+ char *suffix = strrchr(tptr, '.');
+ if (suffix) {
+ Htaccess *cur;
+ for (cur = script_i; cur; cur = cur->next) {
+ if (strcmp(cur->before_colon + 1, suffix) == 0) {
+ send_cgi_and_exit(urlcopy, prequest, length, cookie, content_type);
+ }
+ }
+ }
+ }
+#endif
+ if (prequest != request_GET && prequest != request_HEAD) {
+ send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
+ }
+#endif /* FEATURE_HTTPD_CGI */
+
+ if (urlp[-1] == '/')
+ strcpy(urlp, index_page);
+ if (stat(tptr, &sb) == 0) {
+ file_size = sb.st_size;
+ last_mod = sb.st_mtime;
+ }
+#if ENABLE_FEATURE_HTTPD_CGI
+ else if (urlp[-1] == '/') {
+ /* It's a dir URL and there is no index.html
+ * Try cgi-bin/index.cgi */
+ if (access("/cgi-bin/index.cgi"+1, X_OK) == 0) {
+ urlp[0] = '\0';
+ g_query = urlcopy;
+ send_cgi_and_exit("/cgi-bin/index.cgi", prequest, length, cookie, content_type);
+ }
+ }
+#endif
+ /* else {
+ * fall through to send_file, it errors out if open fails
+ * }
+ */
+
+ send_file_and_exit(tptr,
+#if ENABLE_FEATURE_HTTPD_CGI
+ (prequest != request_HEAD ? SEND_HEADERS_AND_BODY : SEND_HEADERS)
+#else
+ SEND_HEADERS_AND_BODY
+#endif
+ );
+}
+
+/*
+ * The main http server function.
+ * Given a socket, listen for new connections and farm out
+ * the processing as a [v]forked process.
+ * Never returns.
+ */
+#if BB_MMU
+static void mini_httpd(int server_socket) ATTRIBUTE_NORETURN;
+static void mini_httpd(int server_socket)
+{
+ /* NB: it's best to not use xfuncs in this loop before fork().
+ * Otherwise server may die on transient errors (temporary
+ * out-of-memory condition, etc), which is Bad(tm).
+ * Try to do any dangerous calls after fork.
+ */
+ while (1) {
+ int n;
+ len_and_sockaddr fromAddr;
+
+ /* Wait for connections... */
+ fromAddr.len = LSA_SIZEOF_SA;
+ n = accept(server_socket, &fromAddr.u.sa, &fromAddr.len);
+
+ if (n < 0)
+ continue;
+ /* set the KEEPALIVE option to cull dead connections */
+ setsockopt(n, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
+
+ if (fork() == 0) {
+ /* child */
+#if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
+ /* Do not reload config on HUP */
+ signal(SIGHUP, SIG_IGN);
+#endif
+ close(server_socket);
+ xmove_fd(n, 0);
+ xdup2(0, 1);
+
+ handle_incoming_and_exit(&fromAddr);
+ }
+ /* parent, or fork failed */
+ close(n);
+ } /* while (1) */
+ /* never reached */
+}
+#else
+static void mini_httpd_nommu(int server_socket, int argc, char **argv) ATTRIBUTE_NORETURN;
+static void mini_httpd_nommu(int server_socket, int argc, char **argv)
+{
+ char *argv_copy[argc + 2];
+
+ argv_copy[0] = argv[0];
+ argv_copy[1] = (char*)"-i";
+ memcpy(&argv_copy[2], &argv[1], argc * sizeof(argv[0]));
+
+ /* NB: it's best to not use xfuncs in this loop before vfork().
+ * Otherwise server may die on transient errors (temporary
+ * out-of-memory condition, etc), which is Bad(tm).
+ * Try to do any dangerous calls after fork.
+ */
+ while (1) {
+ int n;
+ len_and_sockaddr fromAddr;
+
+ /* Wait for connections... */
+ fromAddr.len = LSA_SIZEOF_SA;
+ n = accept(server_socket, &fromAddr.u.sa, &fromAddr.len);
+
+ if (n < 0)
+ continue;
+ /* set the KEEPALIVE option to cull dead connections */
+ setsockopt(n, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
+
+ if (vfork() == 0) {
+ /* child */
+#if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
+ /* Do not reload config on HUP */
+ signal(SIGHUP, SIG_IGN);
+#endif
+ close(server_socket);
+ xmove_fd(n, 0);
+ xdup2(0, 1);
+
+ /* Run a copy of ourself in inetd mode */
+ re_exec(argv_copy);
+ }
+ /* parent, or vfork failed */
+ close(n);
+ } /* while (1) */
+ /* never reached */
+}
+#endif
+
+/*
+ * Process a HTTP connection on stdin/out.
+ * Never returns.
+ */
+static void mini_httpd_inetd(void) ATTRIBUTE_NORETURN;
+static void mini_httpd_inetd(void)
+{
+ len_and_sockaddr fromAddr;
+
+ memset(&fromAddr, 0, sizeof(fromAddr));
+ fromAddr.len = LSA_SIZEOF_SA;
+ /* NB: can fail if user runs it by hand and types in http cmds */
+ getpeername(0, &fromAddr.u.sa, &fromAddr.len);
+ handle_incoming_and_exit(&fromAddr);
+}
+
+#if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
+static void sighup_handler(int sig)
+{
+ parse_conf(default_path_httpd_conf, sig == SIGHUP ? SIGNALED_PARSE : FIRST_PARSE);
+
+ signal_SA_RESTART_empty_mask(SIGHUP, sighup_handler);
+}
+#endif
+
+enum {
+ c_opt_config_file = 0,
+ d_opt_decode_url,
+ h_opt_home_httpd,
+ USE_FEATURE_HTTPD_ENCODE_URL_STR(e_opt_encode_url,)
+ USE_FEATURE_HTTPD_BASIC_AUTH( r_opt_realm ,)
+ USE_FEATURE_HTTPD_AUTH_MD5( m_opt_md5 ,)
+ USE_FEATURE_HTTPD_SETUID( u_opt_setuid ,)
+ p_opt_port ,
+ p_opt_inetd ,
+ p_opt_foreground,
+ p_opt_verbose ,
+ OPT_CONFIG_FILE = 1 << c_opt_config_file,
+ OPT_DECODE_URL = 1 << d_opt_decode_url,
+ OPT_HOME_HTTPD = 1 << h_opt_home_httpd,
+ OPT_ENCODE_URL = USE_FEATURE_HTTPD_ENCODE_URL_STR((1 << e_opt_encode_url)) + 0,
+ OPT_REALM = USE_FEATURE_HTTPD_BASIC_AUTH( (1 << r_opt_realm )) + 0,
+ OPT_MD5 = USE_FEATURE_HTTPD_AUTH_MD5( (1 << m_opt_md5 )) + 0,
+ OPT_SETUID = USE_FEATURE_HTTPD_SETUID( (1 << u_opt_setuid )) + 0,
+ OPT_PORT = 1 << p_opt_port,
+ OPT_INETD = 1 << p_opt_inetd,
+ OPT_FOREGROUND = 1 << p_opt_foreground,
+ OPT_VERBOSE = 1 << p_opt_verbose,
+};
+
+
+int httpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int httpd_main(int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ int server_socket = server_socket; /* for gcc */
+ unsigned opt;
+ char *url_for_decode;
+ USE_FEATURE_HTTPD_ENCODE_URL_STR(const char *url_for_encode;)
+ USE_FEATURE_HTTPD_SETUID(const char *s_ugid = NULL;)
+ USE_FEATURE_HTTPD_SETUID(struct bb_uidgid_t ugid;)
+ USE_FEATURE_HTTPD_AUTH_MD5(const char *pass;)
+
+ INIT_G();
+
+#if ENABLE_LOCALE_SUPPORT
+ /* Undo busybox.c: we want to speak English in http (dates etc) */
+ setlocale(LC_TIME, "C");
+#endif
+
+ home_httpd = xrealloc_getcwd_or_warn(NULL);
+ /* -v counts, -i implies -f */
+ opt_complementary = "vv:if";
+ /* We do not "absolutize" path given by -h (home) opt.
+ * If user gives relative path in -h,
+ * $SCRIPT_FILENAME will not be set. */
+ opt = getopt32(argv, "c:d:h:"
+ USE_FEATURE_HTTPD_ENCODE_URL_STR("e:")
+ USE_FEATURE_HTTPD_BASIC_AUTH("r:")
+ USE_FEATURE_HTTPD_AUTH_MD5("m:")
+ USE_FEATURE_HTTPD_SETUID("u:")
+ "p:ifv",
+ &configFile, &url_for_decode, &home_httpd
+ USE_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode)
+ USE_FEATURE_HTTPD_BASIC_AUTH(, &g_realm)
+ USE_FEATURE_HTTPD_AUTH_MD5(, &pass)
+ USE_FEATURE_HTTPD_SETUID(, &s_ugid)
+ , &bind_addr_or_port
+ , &verbose
+ );
+ if (opt & OPT_DECODE_URL) {
+ fputs(decodeString(url_for_decode, 1), stdout);
+ return 0;
+ }
+#if ENABLE_FEATURE_HTTPD_ENCODE_URL_STR
+ if (opt & OPT_ENCODE_URL) {
+ fputs(encodeString(url_for_encode), stdout);
+ return 0;
+ }
+#endif
+#if ENABLE_FEATURE_HTTPD_AUTH_MD5
+ if (opt & OPT_MD5) {
+ puts(pw_encrypt(pass, "$1$", 1));
+ return 0;
+ }
+#endif
+#if ENABLE_FEATURE_HTTPD_SETUID
+ if (opt & OPT_SETUID) {
+ if (!get_uidgid(&ugid, s_ugid, 1))
+ bb_error_msg_and_die("unknown user[:group] "
+ "name '%s'", s_ugid);
+ }
+#endif
+
+#if !BB_MMU
+ if (!(opt & OPT_FOREGROUND)) {
+ bb_daemonize_or_rexec(0, argv); /* don't change current directory */
+ }
+#endif
+
+ xchdir(home_httpd);
+ if (!(opt & OPT_INETD)) {
+ signal(SIGCHLD, SIG_IGN);
+ server_socket = openServer();
+#if ENABLE_FEATURE_HTTPD_SETUID
+ /* drop privileges */
+ if (opt & OPT_SETUID) {
+ if (ugid.gid != (gid_t)-1) {
+ if (setgroups(1, &ugid.gid) == -1)
+ bb_perror_msg_and_die("setgroups");
+ xsetgid(ugid.gid);
+ }
+ xsetuid(ugid.uid);
+ }
+#endif
+ }
+
+#if 0 /*was #if ENABLE_FEATURE_HTTPD_CGI*/
+ /* User can do it himself: 'env - PATH="$PATH" httpd'
+ * We don't do it because we don't want to screw users
+ * which want to do
+ * 'env - VAR1=val1 VAR2=val2 httpd'
+ * and have VAR1 and VAR2 values visible in their CGIs.
+ * Besides, it is also smaller. */
+ {
+ char *p = getenv("PATH");
+ /* env strings themself are not freed, no need to xstrdup(p): */
+ clearenv();
+ if (p)
+ putenv(p - 5);
+// if (!(opt & OPT_INETD))
+// setenv_long("SERVER_PORT", ???);
+ }
+#endif
+
+#if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
+ if (!(opt & OPT_INETD))
+ sighup_handler(0);
+#endif
+ parse_conf(default_path_httpd_conf, FIRST_PARSE);
+
+ xfunc_error_retval = 0;
+ if (opt & OPT_INETD)
+ mini_httpd_inetd();
+#if BB_MMU
+ if (!(opt & OPT_FOREGROUND))
+ bb_daemonize(0); /* don't change current directory */
+ mini_httpd(server_socket); /* never returns */
+#else
+ mini_httpd_nommu(server_socket, argc, argv); /* never returns */
+#endif
+ /* return 0; */
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/networking/httpd_indexcgi.c b/cleopatre/busybox-1.11.1-spc300/networking/httpd_indexcgi.c
new file mode 100644
index 0000000000..94c6a692a6
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/networking/httpd_indexcgi.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2007 Denys Vlasenko <vda.linux@googlemail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+/*
+ * This program is a CGI application. It outputs directory index page.
+ * Put it into cgi-bin/index.cgi and chmod 0755.
+ */
+
+/* Build a-la
+i486-linux-uclibc-gcc \
+-static -static-libgcc \
+-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 \
+-Wall -Wshadow -Wwrite-strings -Wundef -Wstrict-prototypes -Werror \
+-Wold-style-definition -Wdeclaration-after-statement -Wno-pointer-sign \
+-Wmissing-prototypes -Wmissing-declarations \
+-Os -fno-builtin-strlen -finline-limit=0 -fomit-frame-pointer \
+-ffunction-sections -fdata-sections -fno-guess-branch-probability \
+-funsigned-char \
+-falign-functions=1 -falign-jumps=1 -falign-labels=1 -falign-loops=1 \
+-march=i386 -mpreferred-stack-boundary=2 \
+-Wl,-Map -Wl,link.map -Wl,--warn-common -Wl,--sort-common -Wl,--gc-sections \
+httpd_indexcgi.c -o index.cgi
+*/
+
+/* We don't use printf, as it pulls in >12 kb of code from uclibc (i386). */
+/* Currently malloc machinery is the biggest part of libc we pull in. */
+/* We have only one realloc and one strdup, any idea how to do without? */
+/* Size (i386, approximate):
+ * text data bss dec hex filename
+ * 13036 44 3052 16132 3f04 index.cgi
+ * 2576 4 2048 4628 1214 index.cgi.o
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <time.h>
+
+/* Appearance of the table is controlled by style sheet *ONLY*,
+ * formatting code uses <TAG class=CLASS> to apply style
+ * to elements. Edit stylesheet to your liking and recompile. */
+
+#define STYLE_STR \
+"<style>" "\n"\
+"table {" "\n"\
+ "width:100%;" "\n"\
+ "background-color:#fff5ee;" "\n"\
+ "border-width:1px;" /* 1px 1px 1px 1px; */ "\n"\
+ "border-spacing:2px;" "\n"\
+ "border-style:solid;" /* solid solid solid solid; */ "\n"\
+ "border-color:black;" /* black black black black; */ "\n"\
+ "border-collapse:collapse;" "\n"\
+"}" "\n"\
+"th {" "\n"\
+ "border-width:1px;" /* 1px 1px 1px 1px; */ "\n"\
+ "padding:1px;" /* 1px 1px 1px 1px; */ "\n"\
+ "border-style:solid;" /* solid solid solid solid; */ "\n"\
+ "border-color:black;" /* black black black black; */ "\n"\
+"}" "\n"\
+"td {" "\n"\
+ /* top right bottom left */ \
+ "border-width:0px 1px 0px 1px;" "\n"\
+ "padding:1px;" /* 1px 1px 1px 1px; */ "\n"\
+ "border-style:solid;" /* solid solid solid solid; */ "\n"\
+ "border-color:black;" /* black black black black; */ "\n"\
+ "white-space:nowrap;" "\n"\
+"}" "\n"\
+"tr.hdr { background-color:#eee5de; }" "\n"\
+"tr.o { background-color:#ffffff; }" "\n"\
+/* tr.e { ... } - for even rows (currently none) */ \
+"tr.foot { background-color:#eee5de; }" "\n"\
+"th.cnt { text-align:left; }" "\n"\
+"th.sz { text-align:right; }" "\n"\
+"th.dt { text-align:right; }" "\n"\
+"td.sz { text-align:right; }" "\n"\
+"td.dt { text-align:right; }" "\n"\
+"col.nm { width:98%; }" "\n"\
+"col.sz { width:1%; }" "\n"\
+"col.dt { width:1%; }" "\n"\
+"</style>" "\n"\
+
+typedef struct dir_list_t {
+ char *dl_name;
+ mode_t dl_mode;
+ off_t dl_size;
+ time_t dl_mtime;
+} dir_list_t;
+
+static int compare_dl(dir_list_t *a, dir_list_t *b)
+{
+ /* ".." is 'less than' any other dir entry */
+ if (strcmp(a->dl_name, "..") == 0) {
+ return -1;
+ }
+ if (strcmp(b->dl_name, "..") == 0) {
+ return 1;
+ }
+ if (S_ISDIR(a->dl_mode) != S_ISDIR(b->dl_mode)) {
+ /* 1 if b is a dir (and thus a is 'after' b, a > b),
+ * else -1 (a < b) */
+ return (S_ISDIR(b->dl_mode) != 0) ? 1 : -1;
+ }
+ return strcmp(a->dl_name, b->dl_name);
+}
+
+static char buffer[2*1024 > sizeof(STYLE_STR) ? 2*1024 : sizeof(STYLE_STR)];
+static char *dst = buffer;
+enum {
+ BUFFER_SIZE = sizeof(buffer),
+ HEADROOM = 64,
+};
+
+/* After this call, you have at least size + HEADROOM bytes available
+ * ahead of dst */
+static void guarantee(int size)
+{
+ if (buffer + (BUFFER_SIZE-HEADROOM) - dst >= size)
+ return;
+ write(STDOUT_FILENO, buffer, dst - buffer);
+ dst = buffer;
+}
+
+/* NB: formatters do not store terminating NUL! */
+
+/* HEADROOM bytes are available after dst after this call */
+static void fmt_str(/*char *dst,*/ const char *src)
+{
+ unsigned len = strlen(src);
+ guarantee(len);
+ memcpy(dst, src, len);
+ dst += len;
+}
+
+/* HEADROOM bytes after dst are available after this call */
+static void fmt_url(/*char *dst,*/ const char *name)
+{
+ while (*name) {
+ unsigned c = *name++;
+ guarantee(3);
+ *dst = c;
+ if ((c - '0') > 9 /* not a digit */
+ && ((c|0x20) - 'a') > 26 /* not A-Z or a-z */
+ && !strchr("._-+@", c)
+ ) {
+ *dst++ = '%';
+ *dst++ = "0123456789ABCDEF"[c >> 4];
+ *dst = "0123456789ABCDEF"[c & 0xf];
+ }
+ dst++;
+ }
+}
+
+/* HEADROOM bytes are available after dst after this call */
+static void fmt_html(/*char *dst,*/ const char *name)
+{
+ while (*name) {
+ char c = *name++;
+ if (c == '<')
+ fmt_str("&lt;");
+ else if (c == '>')
+ fmt_str("&gt;");
+ else if (c == '&') {
+ fmt_str("&amp;");
+ } else {
+ guarantee(1);
+ *dst++ = c;
+ continue;
+ }
+ }
+}
+
+/* HEADROOM bytes are available after dst after this call */
+static void fmt_ull(/*char *dst,*/ unsigned long long n)
+{
+ char buf[sizeof(n)*3 + 2];
+ char *p;
+
+ p = buf + sizeof(buf) - 1;
+ *p = '\0';
+ do {
+ *--p = (n % 10) + '0';
+ n /= 10;
+ } while (n);
+ fmt_str(/*dst,*/ p);
+}
+
+/* Does not call guarantee - eats into headroom instead */
+static void fmt_02u(/*char *dst,*/ unsigned n)
+{
+ /* n %= 100; - not needed, callers don't pass big n */
+ dst[0] = (n / 10) + '0';
+ dst[1] = (n % 10) + '0';
+ dst += 2;
+}
+
+/* Does not call guarantee - eats into headroom instead */
+static void fmt_04u(/*char *dst,*/ unsigned n)
+{
+ /* n %= 10000; - not needed, callers don't pass big n */
+ fmt_02u(n / 100);
+ fmt_02u(n % 100);
+}
+
+int main(void)
+{
+ dir_list_t *dir_list;
+ dir_list_t *cdir;
+ unsigned dir_list_count;
+ unsigned count_dirs;
+ unsigned count_files;
+ unsigned long long size_total;
+ int odd;
+ DIR *dirp;
+ char *QUERY_STRING;
+
+ QUERY_STRING = getenv("QUERY_STRING");
+ if (!QUERY_STRING
+ || QUERY_STRING[0] != '/'
+ || strstr(QUERY_STRING, "/../")
+ || strcmp(strrchr(QUERY_STRING, '/'), "/..") == 0
+ ) {
+ return 1;
+ }
+
+ if (chdir("..")
+ || (QUERY_STRING[1] && chdir(QUERY_STRING + 1))
+ ) {
+ return 1;
+ }
+
+ dirp = opendir(".");
+ if (!dirp)
+ return 1;
+ dir_list = NULL;
+ dir_list_count = 0;
+ while (1) {
+ struct dirent *dp;
+ struct stat sb;
+
+ dp = readdir(dirp);
+ if (!dp)
+ break;
+ if (dp->d_name[0] == '.' && !dp->d_name[1])
+ continue;
+ if (stat(dp->d_name, &sb) != 0)
+ continue;
+ dir_list = realloc(dir_list, (dir_list_count + 1) * sizeof(dir_list[0]));
+ dir_list[dir_list_count].dl_name = strdup(dp->d_name);
+ dir_list[dir_list_count].dl_mode = sb.st_mode;
+ dir_list[dir_list_count].dl_size = sb.st_size;
+ dir_list[dir_list_count].dl_mtime = sb.st_mtime;
+ dir_list_count++;
+ }
+ closedir(dirp);
+
+ qsort(dir_list, dir_list_count, sizeof(dir_list[0]), (void*)compare_dl);
+
+ fmt_str(
+ "" /* Additional headers (currently none) */
+ "\r\n" /* Mandatory empty line after headers */
+ "<html><head><title>Index of ");
+ /* Guard against directories with &, > etc */
+ fmt_html(QUERY_STRING);
+ fmt_str(
+ "</title>\n"
+ STYLE_STR
+ "</head>" "\n"
+ "<body>" "\n"
+ "<h1>Index of ");
+ fmt_html(QUERY_STRING);
+ fmt_str(
+ "</h1>" "\n"
+ "<table>" "\n"
+ "<col class=nm><col class=sz><col class=dt>" "\n"
+ "<tr class=hdr><th class=cnt>Name<th class=sz>Size<th class=dt>Last modified" "\n");
+
+ odd = 0;
+ count_dirs = 0;
+ count_files = 0;
+ size_total = 0;
+ cdir = dir_list;
+ while (dir_list_count--) {
+ struct tm *tm;
+
+ if (S_ISDIR(cdir->dl_mode)) {
+ count_dirs++;
+ } else if (S_ISREG(cdir->dl_mode)) {
+ count_files++;
+ size_total += cdir->dl_size;
+ } else
+ goto next;
+
+ fmt_str("<tr class=");
+ *dst++ = (odd ? 'o' : 'e');
+ fmt_str("><td class=nm><a href='");
+ fmt_url(cdir->dl_name); /* %20 etc */
+ if (S_ISDIR(cdir->dl_mode))
+ *dst++ = '/';
+ fmt_str("'>");
+ fmt_html(cdir->dl_name); /* &lt; etc */
+ if (S_ISDIR(cdir->dl_mode))
+ *dst++ = '/';
+ fmt_str("</a><td class=sz>");
+ if (S_ISREG(cdir->dl_mode))
+ fmt_ull(cdir->dl_size);
+ fmt_str("<td class=dt>");
+ tm = gmtime(&cdir->dl_mtime);
+ fmt_04u(1900 + tm->tm_year); *dst++ = '-';
+ fmt_02u(tm->tm_mon + 1); *dst++ = '-';
+ fmt_02u(tm->tm_mday); *dst++ = ' ';
+ fmt_02u(tm->tm_hour); *dst++ = ':';
+ fmt_02u(tm->tm_min); *dst++ = ':';
+ fmt_02u(tm->tm_sec);
+ *dst++ = '\n';
+
+ odd = 1 - odd;
+ next:
+ cdir++;
+ }
+
+ fmt_str("<tr class=foot><th class=cnt>Files: ");
+ fmt_ull(count_files);
+ /* count_dirs - 1: we don't want to count ".." */
+ fmt_str(", directories: ");
+ fmt_ull(count_dirs - 1);
+ fmt_str("<th class=sz>");
+ fmt_ull(size_total);
+ fmt_str("<th class=dt>\n");
+ /* "</table></body></html>" - why bother? */
+ guarantee(BUFFER_SIZE * 2); /* flush */
+
+ return 0;
+}
diff --git a/cleopatre/busybox-1.11.1-spc300/networking/httpd_post_upload.txt b/cleopatre/busybox-1.11.1-spc300/networking/httpd_post_upload.txt
new file mode 100644
index 0000000000..a53b114677
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/networking/httpd_post_upload.txt
@@ -0,0 +1,76 @@
+POST upload example:
+
+post_upload.htm
+===============
+<html>
+<body>
+<form action=/cgi-bin/post_upload.cgi method=post enctype=multipart/form-data>
+File to upload: <input type=file name=file1> <input type=submit>
+</form>
+
+
+post_upload.cgi
+===============
+#!/bin/sh
+
+# POST upload format:
+# -----------------------------29995809218093749221856446032^M
+# Content-Disposition: form-data; name="file1"; filename="..."^M
+# Content-Type: application/octet-stream^M
+# ^M <--------- headers end with empty line
+# file contents
+# file contents
+# file contents
+# ^M <--------- extra empty line
+# -----------------------------29995809218093749221856446032--^M
+
+# Beware: bashism $'\r' is used to handle ^M
+
+file=/tmp/$$-$RANDOM
+
+# CGI output must start with at least empty line (or headers)
+printf '\r\n'
+
+IFS=$'\r'
+read -r delim_line
+
+IFS=''
+delim_line="${delim_line}--"$'\r'
+
+while read -r line; do
+ test "$line" = '' && break
+ test "$line" = $'\r' && break
+done
+
+# This will not work well for binary files: bash 3.2 is upset
+# by reading NUL bytes and loses chunks of data.
+# If you are not bothered by having junk appended to the uploaded file,
+# consider using simple "cat >file" instead of the entire
+# fragment below.
+
+while read -r line; do
+
+ while test "$line" = $'\r'; do
+ read -r line
+ test "$line" = "$delim_line" && {
+ # Aha! Empty line + delimiter! All done
+ cat <<EOF
+<html>
+<body>
+File upload has been accepted
+EOF
+ exit 0
+ }
+ # Empty line + NOT delimiter. Save empty line,
+ # and go check next line
+ printf "%s\n" $'\r' -vC >&3
+ done
+ # Not empty line - just save
+ printf "%s\n" "$line" -vC >&3
+done 3>"$file"
+
+cat <<EOF
+<html>
+<body>
+File upload was not terminated with '$delim_line' - ??!
+EOF
diff --git a/cleopatre/busybox-1.11.1-spc300/networking/ifconfig.c b/cleopatre/busybox-1.11.1-spc300/networking/ifconfig.c
new file mode 100644
index 0000000000..e999741d12
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/networking/ifconfig.c
@@ -0,0 +1,540 @@
+/* vi: set sw=4 ts=4: */
+/* ifconfig
+ *
+ * Similar to the standard Unix ifconfig, but with only the necessary
+ * parts for AF_INET, and without any printing of if info (for now).
+ *
+ * Bjorn Wesen, Axis Communications AB
+ *
+ *
+ * Authors of the original ifconfig was:
+ * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/*
+ * Heavily modified by Manuel Novoa III Mar 6, 2001
+ *
+ * From initial port to busybox, removed most of the redundancy by
+ * converting to a table-driven approach. Added several (optional)
+ * args missing from initial port.
+ *
+ * Still missing: media, tunnel.
+ *
+ * 2002-04-20
+ * IPV6 support added by Bart Visscher <magick@linux-fan.com>
+ */
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#if defined(__GLIBC__) && __GLIBC__ >=2 && __GLIBC_MINOR__ >= 1
+#include <netpacket/packet.h>
+#include <net/ethernet.h>
+#else
+#include <sys/types.h>
+#include <netinet/if_ether.h>
+#endif
+#include "inet_common.h"
+#include "libbb.h"
+
+#if ENABLE_FEATURE_IFCONFIG_SLIP
+# include <net/if_slip.h>
+#endif
+
+/* I don't know if this is needed for busybox or not. Anyone? */
+#define QUESTIONABLE_ALIAS_CASE
+
+
+/* Defines for glibc2.0 users. */
+#ifndef SIOCSIFTXQLEN
+# define SIOCSIFTXQLEN 0x8943
+# define SIOCGIFTXQLEN 0x8942
+#endif
+
+/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
+#ifndef ifr_qlen
+# define ifr_qlen ifr_ifru.ifru_mtu
+#endif
+
+#ifndef IFF_DYNAMIC
+# define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
+#endif
+
+#if ENABLE_FEATURE_IPV6
+struct in6_ifreq {
+ struct in6_addr ifr6_addr;
+ uint32_t ifr6_prefixlen;
+ int ifr6_ifindex;
+};
+#endif
+
+/*
+ * Here are the bit masks for the "flags" member of struct options below.
+ * N_ signifies no arg prefix; M_ signifies arg prefixed by '-'.
+ * CLR clears the flag; SET sets the flag; ARG signifies (optional) arg.
+ */
+#define N_CLR 0x01
+#define M_CLR 0x02
+#define N_SET 0x04
+#define M_SET 0x08
+#define N_ARG 0x10
+#define M_ARG 0x20
+
+#define M_MASK (M_CLR | M_SET | M_ARG)
+#define N_MASK (N_CLR | N_SET | N_ARG)
+#define SET_MASK (N_SET | M_SET)
+#define CLR_MASK (N_CLR | M_CLR)
+#define SET_CLR_MASK (SET_MASK | CLR_MASK)
+#define ARG_MASK (M_ARG | N_ARG)
+
+/*
+ * Here are the bit masks for the "arg_flags" member of struct options below.
+ */
+
+/*
+ * cast type:
+ * 00 int
+ * 01 char *
+ * 02 HOST_COPY in_ether
+ * 03 HOST_COPY INET_resolve
+ */
+#define A_CAST_TYPE 0x03
+/*
+ * map type:
+ * 00 not a map type (mem_start, io_addr, irq)
+ * 04 memstart (unsigned long)
+ * 08 io_addr (unsigned short)
+ * 0C irq (unsigned char)
+ */
+#define A_MAP_TYPE 0x0C
+#define A_ARG_REQ 0x10 /* Set if an arg is required. */
+#define A_NETMASK 0x20 /* Set if netmask (check for multiple sets). */
+#define A_SET_AFTER 0x40 /* Set a flag at the end. */
+#define A_COLON_CHK 0x80 /* Is this needed? See below. */
+#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS
+#define A_HOSTNAME 0x100 /* Set if it is ip addr. */
+#define A_BROADCAST 0x200 /* Set if it is broadcast addr. */
+#else
+#define A_HOSTNAME 0
+#define A_BROADCAST 0
+#endif
+
+/*
+ * These defines are for dealing with the A_CAST_TYPE field.
+ */
+#define A_CAST_CHAR_PTR 0x01
+#define A_CAST_RESOLVE 0x01
+#define A_CAST_HOST_COPY 0x02
+#define A_CAST_HOST_COPY_IN_ETHER A_CAST_HOST_COPY
+#define A_CAST_HOST_COPY_RESOLVE (A_CAST_HOST_COPY | A_CAST_RESOLVE)
+
+/*
+ * These defines are for dealing with the A_MAP_TYPE field.
+ */
+#define A_MAP_ULONG 0x04 /* memstart */
+#define A_MAP_USHORT 0x08 /* io_addr */
+#define A_MAP_UCHAR 0x0C /* irq */
+
+/*
+ * Define the bit masks signifying which operations to perform for each arg.
+ */
+
+#define ARG_METRIC (A_ARG_REQ /*| A_CAST_INT*/)
+#define ARG_MTU (A_ARG_REQ /*| A_CAST_INT*/)
+#define ARG_TXQUEUELEN (A_ARG_REQ /*| A_CAST_INT*/)
+#define ARG_MEM_START (A_ARG_REQ | A_MAP_ULONG)
+#define ARG_IO_ADDR (A_ARG_REQ | A_MAP_ULONG)
+#define ARG_IRQ (A_ARG_REQ | A_MAP_UCHAR)
+#define ARG_DSTADDR (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE)
+#define ARG_NETMASK (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_NETMASK)
+#define ARG_BROADCAST (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_BROADCAST)
+#define ARG_HW (A_ARG_REQ | A_CAST_HOST_COPY_IN_ETHER)
+#define ARG_POINTOPOINT (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER)
+#define ARG_KEEPALIVE (A_ARG_REQ | A_CAST_CHAR_PTR)
+#define ARG_OUTFILL (A_ARG_REQ | A_CAST_CHAR_PTR)
+#define ARG_HOSTNAME (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_COLON_CHK | A_HOSTNAME)
+#define ARG_ADD_DEL (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER)
+
+
+/*
+ * Set up the tables. Warning! They must have corresponding order!
+ */
+
+struct arg1opt {
+ const char *name;
+ unsigned short selector;
+ unsigned short ifr_offset;
+};
+
+struct options {
+ const char *name;
+#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS
+ const unsigned int flags:6;
+ const unsigned int arg_flags:10;
+#else
+ const unsigned char flags;
+ const unsigned char arg_flags;
+#endif
+ const unsigned short selector;
+};
+
+#define ifreq_offsetof(x) offsetof(struct ifreq, x)
+
+static const struct arg1opt Arg1Opt[] = {
+ { "SIFMETRIC", SIOCSIFMETRIC, ifreq_offsetof(ifr_metric) },
+ { "SIFMTU", SIOCSIFMTU, ifreq_offsetof(ifr_mtu) },
+ { "SIFTXQLEN", SIOCSIFTXQLEN, ifreq_offsetof(ifr_qlen) },
+ { "SIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr) },
+ { "SIFNETMASK", SIOCSIFNETMASK, ifreq_offsetof(ifr_netmask) },
+ { "SIFBRDADDR", SIOCSIFBRDADDR, ifreq_offsetof(ifr_broadaddr) },
+#if ENABLE_FEATURE_IFCONFIG_HW
+ { "SIFHWADDR", SIOCSIFHWADDR, ifreq_offsetof(ifr_hwaddr) },
+#endif
+ { "SIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr) },
+#ifdef SIOCSKEEPALIVE
+ { "SKEEPALIVE", SIOCSKEEPALIVE, ifreq_offsetof(ifr_data) },
+#endif
+#ifdef SIOCSOUTFILL
+ { "SOUTFILL", SIOCSOUTFILL, ifreq_offsetof(ifr_data) },
+#endif
+#if ENABLE_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
+ { "SIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.mem_start) },
+ { "SIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.base_addr) },
+ { "SIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.irq) },
+#endif
+ /* Last entry if for unmatched (possibly hostname) arg. */
+#if ENABLE_FEATURE_IPV6
+ { "SIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr) }, /* IPv6 version ignores the offset */
+ { "DIFADDR", SIOCDIFADDR, ifreq_offsetof(ifr_addr) }, /* IPv6 version ignores the offset */
+#endif
+ { "SIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr) },
+};
+
+static const struct options OptArray[] = {
+ { "metric", N_ARG, ARG_METRIC, 0 },
+ { "mtu", N_ARG, ARG_MTU, 0 },
+ { "txqueuelen", N_ARG, ARG_TXQUEUELEN, 0 },
+ { "dstaddr", N_ARG, ARG_DSTADDR, 0 },
+ { "netmask", N_ARG, ARG_NETMASK, 0 },
+ { "broadcast", N_ARG | M_CLR, ARG_BROADCAST, IFF_BROADCAST },
+#if ENABLE_FEATURE_IFCONFIG_HW
+ { "hw", N_ARG, ARG_HW, 0 },
+#endif
+ { "pointopoint", N_ARG | M_CLR, ARG_POINTOPOINT, IFF_POINTOPOINT },
+#ifdef SIOCSKEEPALIVE
+ { "keepalive", N_ARG, ARG_KEEPALIVE, 0 },
+#endif
+#ifdef SIOCSOUTFILL
+ { "outfill", N_ARG, ARG_OUTFILL, 0 },
+#endif
+#if ENABLE_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
+ { "mem_start", N_ARG, ARG_MEM_START, 0 },
+ { "io_addr", N_ARG, ARG_IO_ADDR, 0 },
+ { "irq", N_ARG, ARG_IRQ, 0 },
+#endif
+#if ENABLE_FEATURE_IPV6
+ { "add", N_ARG, ARG_ADD_DEL, 0 },
+ { "del", N_ARG, ARG_ADD_DEL, 0 },
+#endif
+ { "arp", N_CLR | M_SET, 0, IFF_NOARP },
+ { "trailers", N_CLR | M_SET, 0, IFF_NOTRAILERS },
+ { "promisc", N_SET | M_CLR, 0, IFF_PROMISC },
+ { "multicast", N_SET | M_CLR, 0, IFF_MULTICAST },
+ { "allmulti", N_SET | M_CLR, 0, IFF_ALLMULTI },
+ { "dynamic", N_SET | M_CLR, 0, IFF_DYNAMIC },
+ { "up", N_SET, 0, (IFF_UP | IFF_RUNNING) },
+ { "down", N_CLR, 0, IFF_UP },
+ { NULL, 0, ARG_HOSTNAME, (IFF_UP | IFF_RUNNING) }
+};
+
+/*
+ * A couple of prototypes.
+ */
+#if ENABLE_FEATURE_IFCONFIG_HW
+static int in_ether(const char *bufp, struct sockaddr *sap);
+#endif
+
+/*
+ * Our main function.
+ */
+int ifconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int ifconfig_main(int argc, char **argv)
+{
+ struct ifreq ifr;
+ struct sockaddr_in sai;
+#if ENABLE_FEATURE_IFCONFIG_HW
+ struct sockaddr sa;
+#endif
+ const struct arg1opt *a1op;
+ const struct options *op;
+ int sockfd; /* socket fd we use to manipulate stuff with */
+ int selector;
+#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS
+ unsigned int mask;
+ unsigned int did_flags;
+ unsigned int sai_hostname, sai_netmask;
+#else
+ unsigned char mask;
+ unsigned char did_flags;
+#endif
+ char *p;
+ /*char host[128];*/
+ const char *host = NULL; /* make gcc happy */
+
+ did_flags = 0;
+#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS
+ sai_hostname = 0;
+ sai_netmask = 0;
+#endif
+
+ /* skip argv[0] */
+ ++argv;
+ --argc;
+
+#if ENABLE_FEATURE_IFCONFIG_STATUS
+ if (argc > 0 && (argv[0][0] == '-' && argv[0][1] == 'a' && !argv[0][2])) {
+ interface_opt_a = 1;
+ --argc;
+ ++argv;
+ }
+#endif
+
+ if (argc <= 1) {
+#if ENABLE_FEATURE_IFCONFIG_STATUS
+ return display_interfaces(argc ? *argv : NULL);
+#else
+ bb_error_msg_and_die("no support for status display");
+#endif
+ }
+
+ /* Create a channel to the NET kernel. */
+ sockfd = xsocket(AF_INET, SOCK_DGRAM, 0);
+
+ /* get interface name */
+ strncpy(ifr.ifr_name, *argv, IFNAMSIZ);
+
+ /* Process the remaining arguments. */
+ while (*++argv != (char *) NULL) {
+ p = *argv;
+ mask = N_MASK;
+ if (*p == '-') { /* If the arg starts with '-'... */
+ ++p; /* advance past it and */
+ mask = M_MASK; /* set the appropriate mask. */
+ }
+ for (op = OptArray; op->name; op++) { /* Find table entry. */
+ if (strcmp(p, op->name) == 0) { /* If name matches... */
+ mask &= op->flags;
+ if (mask) /* set the mask and go. */
+ goto FOUND_ARG;
+ /* If we get here, there was a valid arg with an */
+ /* invalid '-' prefix. */
+ bb_error_msg_and_die("bad: '%s'", p-1);
+ }
+ }
+
+ /* We fell through, so treat as possible hostname. */
+ a1op = Arg1Opt + ARRAY_SIZE(Arg1Opt) - 1;
+ mask = op->arg_flags;
+ goto HOSTNAME;
+
+ FOUND_ARG:
+ if (mask & ARG_MASK) {
+ mask = op->arg_flags;
+ a1op = Arg1Opt + (op - OptArray);
+ if (mask & A_NETMASK & did_flags)
+ bb_show_usage();
+ if (*++argv == NULL) {
+ if (mask & A_ARG_REQ)
+ bb_show_usage();
+ --argv;
+ mask &= A_SET_AFTER; /* just for broadcast */
+ } else { /* got an arg so process it */
+ HOSTNAME:
+ did_flags |= (mask & (A_NETMASK|A_HOSTNAME));
+ if (mask & A_CAST_HOST_COPY) {
+#if ENABLE_FEATURE_IFCONFIG_HW
+ if (mask & A_CAST_RESOLVE) {
+#endif
+#if ENABLE_FEATURE_IPV6
+ char *prefix;
+ int prefix_len = 0;
+#endif
+ /*safe_strncpy(host, *argv, (sizeof host));*/
+ host = *argv;
+#if ENABLE_FEATURE_IPV6
+ prefix = strchr(host, '/');
+ if (prefix) {
+ prefix_len = xatou_range(prefix + 1, 0, 128);
+ *prefix = '\0';
+ }
+#endif
+ sai.sin_family = AF_INET;
+ sai.sin_port = 0;
+ if (!strcmp(host, bb_str_default)) {
+ /* Default is special, meaning 0.0.0.0. */
+ sai.sin_addr.s_addr = INADDR_ANY;
+ }
+#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS
+ else if ((host[0] == '+' && !host[1]) && (mask & A_BROADCAST)
+ && (did_flags & (A_NETMASK|A_HOSTNAME)) == (A_NETMASK|A_HOSTNAME)
+ ) {
+ /* + is special, meaning broadcast is derived. */
+ sai.sin_addr.s_addr = (~sai_netmask) | (sai_hostname & sai_netmask);
+ }
+#endif
+ else {
+ len_and_sockaddr *lsa;
+ if (strcmp(host, "inet") == 0)
+ continue; /* compat stuff */
+ lsa = xhost2sockaddr(host, 0);
+#if ENABLE_FEATURE_IPV6
+ if (lsa->u.sa.sa_family == AF_INET6) {
+ int sockfd6;
+ struct in6_ifreq ifr6;
+
+ memcpy((char *) &ifr6.ifr6_addr,
+ (char *) &(lsa->u.sin6.sin6_addr),
+ sizeof(struct in6_addr));
+
+ /* Create a channel to the NET kernel. */
+ sockfd6 = xsocket(AF_INET6, SOCK_DGRAM, 0);
+ xioctl(sockfd6, SIOGIFINDEX, &ifr);
+ ifr6.ifr6_ifindex = ifr.ifr_ifindex;
+ ifr6.ifr6_prefixlen = prefix_len;
+ ioctl_or_perror_and_die(sockfd6, a1op->selector, &ifr6, "SIOC%s", a1op->name);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(lsa);
+ continue;
+ }
+#endif
+ sai.sin_addr = lsa->u.sin.sin_addr;
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(lsa);
+ }
+#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS
+ if (mask & A_HOSTNAME)
+ sai_hostname = sai.sin_addr.s_addr;
+ if (mask & A_NETMASK)
+ sai_netmask = sai.sin_addr.s_addr;
+#endif
+ p = (char *) &sai;
+#if ENABLE_FEATURE_IFCONFIG_HW
+ } else { /* A_CAST_HOST_COPY_IN_ETHER */
+ /* This is the "hw" arg case. */
+ smalluint hw_class= index_in_substrings("ether\0"
+ USE_FEATURE_HWIB("infiniband\0"), *argv) + 1;
+ if (!hw_class || !*++argv)
+ bb_show_usage();
+ /*safe_strncpy(host, *argv, sizeof(host));*/
+ host = *argv;
+ if (hw_class == 1 ? in_ether(host, &sa) : in_ib(host, &sa))
+ bb_error_msg_and_die("invalid hw-addr %s", host);
+ p = (char *) &sa;
+ }
+#endif
+ memcpy( (((char *)&ifr) + a1op->ifr_offset),
+ p, sizeof(struct sockaddr));
+ } else {
+ /* FIXME: error check?? */
+ unsigned long i = strtoul(*argv, NULL, 0);
+ p = ((char *)&ifr) + a1op->ifr_offset;
+#if ENABLE_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
+ if (mask & A_MAP_TYPE) {
+ xioctl(sockfd, SIOCGIFMAP, &ifr);
+ if ((mask & A_MAP_UCHAR) == A_MAP_UCHAR)
+ *((unsigned char *) p) = i;
+ else if (mask & A_MAP_USHORT)
+ *((unsigned short *) p) = i;
+ else
+ *((unsigned long *) p) = i;
+ } else
+#endif
+ if (mask & A_CAST_CHAR_PTR)
+ *((caddr_t *) p) = (caddr_t) i;
+ else /* A_CAST_INT */
+ *((int *) p) = i;
+ }
+
+ ioctl_or_perror_and_die(sockfd, a1op->selector, &ifr, "SIOC%s", a1op->name);
+#ifdef QUESTIONABLE_ALIAS_CASE
+ if (mask & A_COLON_CHK) {
+ /*
+ * Don't do the set_flag() if the address is an alias with
+ * a '-' at the end, since it's deleted already! - Roman
+ *
+ * Should really use regex.h here, not sure though how well
+ * it'll go with the cross-platform support etc.
+ */
+ char *ptr;
+ short int found_colon = 0;
+ for (ptr = ifr.ifr_name; *ptr; ptr++)
+ if (*ptr == ':')
+ found_colon++;
+ if (found_colon && ptr[-1] == '-')
+ continue;
+ }
+#endif
+ }
+ if (!(mask & A_SET_AFTER))
+ continue;
+ mask = N_SET;
+ }
+
+ xioctl(sockfd, SIOCGIFFLAGS, &ifr);
+ selector = op->selector;
+ if (mask & SET_MASK)
+ ifr.ifr_flags |= selector;
+ else
+ ifr.ifr_flags &= ~selector;
+ xioctl(sockfd, SIOCSIFFLAGS, &ifr);
+ } /* while () */
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close(sockfd);
+ return 0;
+}
+
+#if ENABLE_FEATURE_IFCONFIG_HW
+/* Input an Ethernet address and convert to binary. */
+static int in_ether(const char *bufp, struct sockaddr *sap)
+{
+ char *ptr;
+ int i, j;
+ unsigned char val;
+ unsigned char c;
+
+ sap->sa_family = ARPHRD_ETHER;
+ ptr = (char *) sap->sa_data;
+
+ i = 0;
+ do {
+ j = val = 0;
+
+ /* We might get a semicolon here - not required. */
+ if (i && (*bufp == ':')) {
+ bufp++;
+ }
+
+ do {
+ c = *bufp;
+ if (((unsigned char)(c - '0')) <= 9) {
+ c -= '0';
+ } else if (((unsigned char)((c|0x20) - 'a')) <= 5) {
+ c = (c|0x20) - ('a'-10);
+ } else if (j && (c == ':' || c == 0)) {
+ break;
+ } else {
+ return -1;
+ }
+ ++bufp;
+ val <<= 4;
+ val += c;
+ } while (++j < 2);
+ *ptr++ = val;
+ } while (++i < ETH_ALEN);
+
+ return *bufp; /* Error if we don't end at end of string. */
+}
+#endif
diff --git a/cleopatre/busybox-1.11.1-spc300/networking/ifenslave.c b/cleopatre/busybox-1.11.1-spc300/networking/ifenslave.c
new file mode 100644
index 0000000000..4c7eadc83b
--- /dev/null
+++ b/cleopatre/busybox-1.11.1-spc300/networking/ifenslave.c
@@ -0,0 +1,592 @@
+/* Mode: C;
+ *
+ * Mini ifenslave implementation for busybox
+ * Copyright (C) 2005 by Marc Leeman <marc.leeman@barco.com>
+ *
+ * ifenslave.c: Configure network interfaces for parallel routing.
+ *
+ * This program controls the Linux implementation of running multiple
+ * network interfaces in parallel.
+ *
+ * Author: Donald Becker <becker@cesdis.gsfc.nasa.gov>
+ * Copyright 1994-1996 Donald Becker
+ *
+ * This program is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+ * Center of Excellence in Space Data and Information Sciences
+ * Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+ *
+ * Changes :
+ * - 2000/10/02 Willy Tarreau <willy at meta-x.org> :
+ * - few fixes. Master's MAC address is now correctly taken from
+ * the first device when not previously set ;
+ * - detach support : call BOND_RELEASE to detach an enslaved interface.
+ * - give a mini-howto from command-line help : # ifenslave -h
+ *
+ * - 2001/02/16 Chad N. Tindel <ctindel at ieee dot org> :
+ * - Master is now brought down before setting the MAC address. In
+ * the 2.4 kernel you can't change the MAC address while the device is
+ * up because you get EBUSY.
+ *
+ * - 2001/09/13 Takao Indoh <indou dot takao at jp dot fujitsu dot com>
+ * - Added the ability to change the active interface on a mode 1 bond
+ * at runtime.
+ *
+ * - 2001/10/23 Chad N. Tindel <ctindel at ieee dot org> :
+ * - No longer set the MAC address of the master. The bond device will
+ * take care of this itself
+ * - Try the SIOC*** versions of the bonding ioctls before using the
+ * old versions
+ * - 2002/02/18 Erik Habbinga <erik_habbinga @ hp dot com> :
+ * - ifr2.ifr_flags was not initialized in the hwaddr_notset case,
+ * SIOCGIFFLAGS now called before hwaddr_notset test
+ *
+ * - 2002/10/31 Tony Cureington <tony.cureington * hp_com> :
+ * - If the master does not have a hardware address when the first slave
+ * is enslaved, the master is assigned the hardware address of that
+ * slave - there is a comment in bonding.c stating "ifenslave takes
+ * care of this now." This corrects the problem of slaves having
+ * different hardware addresses in active-backup mode when
+ * multiple interfaces are specified on a single ifenslave command
+ * (ifenslave bond0 eth0 eth1).
+ *
+ * - 2003/03/18 - Tsippy Mendelson <tsippy.mendelson at intel dot com> and
+ * Shmulik Hen <shmulik.hen at intel dot com>
+ * - Moved setting the slave's mac address and openning it, from
+ * the application to the driver. This enables support of modes
+ * that need to use the unique mac address of each slave.
+ * The driver also takes care of closing the slave and restoring its
+ * original mac address upon release.
+ * In addition, block possibility of enslaving before the master is up.
+ * This prevents putting the system in an undefined state.
+ *
+ * - 2003/05/01 - Amir Noam <amir.noam at intel dot com>
+ * - Added ABI version control to restore compatibility between
+ * new/old ifenslave and new/old bonding.
+ * - Prevent adding an adapter that is already a slave.
+ * Fixes the problem of stalling the transmission and leaving
+ * the slave in a down state.
+ *
+ * - 2003/05/01 - Shmulik Hen <shmulik.hen at intel dot com>
+ * - Prevent enslaving if the bond device is down.
+ * Fixes the problem of leaving the system in unstable state and
+ * halting when trying to remove the module.
+ * - Close socket on all abnormal exists.
+ * - Add versioning scheme that follows that of the bonding driver.
+ * current version is 1.0.0 as a base line.
+ *
+ * - 2003/05/22 - Jay Vosburgh <fubar at us dot ibm dot com>
+ * - ifenslave -c was broken; it's now fixed
+ * - Fixed problem with routes vanishing from master during enslave
+ * processing.
+ *
+ * - 2003/05/27 - Amir Noam <amir.noam at intel dot com>
+ * - Fix backward compatibility issues:
+ * For drivers not using ABI versions, slave was set down while
+ * it should be left up before enslaving.
+ * Also, master was not set down and the default set_mac_address()
+ * would fail and generate an error message in the system log.
+ * - For opt_c: slave should not be set to the master's setting
+ * while it is running. It was already set during enslave. To
+ * simplify things, it is now handeled separately.
+ *
+ * - 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
+ * - Code cleanup and style changes
+ * set version to 1.1.0
+ */
+
+#include "libbb.h"
+
+#include <net/if_arp.h>
+#include <linux/if_bonding.h>
+#include <linux/sockios.h>
+
+typedef unsigned long long u64; /* hack, so we may include kernel's ethtool.h */
+typedef uint32_t u32; /* ditto */
+typedef uint16_t u16; /* ditto */
+typedef uint8_t u8; /* ditto */
+#include <linux/ethtool.h>
+
+
+struct dev_data {
+ struct ifreq mtu, flags, hwaddr;
+};
+
+
+enum { skfd = 3 }; /* AF_INET socket for ioctl() calls. */
+struct globals {
+ unsigned abi_ver; /* userland - kernel ABI version */
+ smallint hwaddr_set; /* Master's hwaddr is set */
+ struct dev_data master;
+ struct dev_data slave;
+};
+#define G (*ptr_to_globals)
+#define abi_ver (G.abi_ver )
+#define hwaddr_set (G.hwaddr_set)
+#define master (G.master )
+#define slave (G.slave )
+#define INIT_G() do { \
+ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
+} while (0)
+
+
+/* NOINLINEs are placed where it results in smaller code (gcc 4.3.1) */
+
+static void strncpy_IFNAMSIZ(char *dst, const char *src)
+{
+ strncpy(dst, src, IFNAMSIZ);
+}
+
+static int ioctl_on_skfd(unsigned request, struct ifreq *ifr)
+{
+ return ioctl(skfd, request, ifr);
+}
+
+static int set_ifrname_and_do_ioctl(unsigned request, struct ifreq *ifr, const char *ifname)
+{
+ strncpy_IFNAMSIZ(ifr->ifr_name, ifname);
+ return ioctl_on_skfd(request, ifr);
+}
+
+static int get_if_settings(char *ifname, struct dev_data *dd)
+{
+ int res;
+
+ res = set_ifrname_and_do_ioctl(SIOCGIFMTU, &dd->mtu, ifname);
+ res |= set_ifrname_and_do_ioctl(SIOCGIFFLAGS, &dd->flags, ifname);
+ res |= set_ifrname_and_do_ioctl(SIOCGIFHWADDR, &dd->hwaddr, ifname);
+
+ return res;
+}
+
+static int get_slave_flags(char *slave_ifname)
+{
+ return set_ifrname_and_